Adding buttons on d3.js charts





This document provides information on how to add buttons with d3.js. It is composed by several interactive examples, allowing to play with the code to understand better how it works.

Button types offered in HTML


Buttons are natively offered by the html language, thanks to the input tag. Their type is controlled by the type attribute. Here is an overview of the main button types. Following code snippets only create buttons. We'll see later how to use d3.js to actually make them do something.

<!-- Clickable button -->
<button type="button">Click Me!</button>

<!-- Radio button: one item selected only -->
<br><br><br>
<div>
  <input type="radio" name="gender" value="male"> Male<br>
  <input type="radio" name="gender" value="female"> Female<br>
  <input type="radio" name="gender" value="other"> Other<br>
</div>

<!-- Text input -->
<br><br><br>
<input type="text" name="usrname" value="initial value">

<!-- Check box: Selection of several item is possible -->
<br><br><br>
<div>
  <input type="checkbox" name="myCheckBox" checked>
  <label for="myCheckBox">Option 1</label>
  <input type="checkbox" name="myCheckBox2" checked>
  <label for="myCheckBox2">Option 2</label>
</div>

<!-- File picker -->
<br><br><br><br><br><br><br>
<input type="file" name="usrname">

<!-- Number -->
<br><br><br><br>
<input type="number" name="usrname" value=13>

<!-- Slider -->
<br><br><br><br>
<input type="range" name="usrname">

<!-- Dropdown button -->
<br><br><br><br>
<select>
  <option value="o1">Option 1</option>
  <option value="o2">Option 2</option>
  <option value="o3">Option 3</option>
  <option value="o4">Whatever</option>
</select>

Trigger function in html with onclick().



Steps:

  • Here, the button is created in html, and an onclick attribute is added.

  • Thus, a click will trigger the changeColor() function.

  • onclick is not the only method, try also onchange, onmouseover, and more. See more here
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Add 2 buttons-->
<button type="button" onclick="changeColor('blue')">Blue</button>
<button type="button" onclick="changeColor('red')">Red</button>

<!-- Create a div where the circle will take place -->
<div id="dataviz_buttonTriger"></div>

<script>

// Initialize a circle
var myCircle = d3.select("#dataviz_buttonTriger")
  .append("svg")
  .append("circle")
    .attr("cx", 100)
    .attr("cy", 70)
    .attr("r", 50)
    .attr("stroke", "black")

// A function that update the color circle
var changeColor = function(color){
  myCircle
    .style("fill", color)
}

</script>

Event listener in javascript



Steps:

  • Here the button is created in html, but is made active thanks to javascript.

  • The button is selected thanks to this id and an event listener is setup: .on("input", changeSize ). Each type the input of the button changes, the changeSize function is triggered.

  • The event listener syntax is different depending on the button type. Use input to listen to a numeric input button. But listen to change for a dropdown button. This is a bit tricky and a small example of each type is provided in the application part of this document.
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Add  button-->
<input type="number" id="buttonSize" value=13>

<!-- Create a div where the circle will take place -->
<div id="dataviz_buttonEventListener"></div>

<script>

// Initialize a circle
var theCircle = d3.select("#dataviz_buttonEventListener")
  .append("svg")
  .append("circle")
    .attr("cx", 100)
    .attr("cy", 70)
    .attr("stroke", "black")
    .style("fill", "#69b3a2")
    .attr("r", 20)

// A function that update the color circle
function changeSize() {
  theCircle
    .attr("r", this.value)
}

// Add an event listener to the button created in the html part
d3.select("#buttonSize").on("input", changeSize )

</script>

Build buttons in d3.js



Steps:

  • Sometimes it is handy to build the button in javascript. It is typically the case with dropdown button: the list of option often depends on the data itself.

  • Note the use of the this magic variable to recover the option that has been chosen before calling the updateChart() function,
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the circle will take place -->
<div id="dataviz_builtWithD3"></div>

<script>

// Create data = list of groups
var allGroup = ["yellow", "blue", "red", "green", "purple", "black"]

// Initialize the button
var dropdownButton = d3.select("#dataviz_builtWithD3")
  .append('select')

// add the options to the button
dropdownButton // Add a button
  .selectAll('myOptions') // Next 4 lines add 6 options = 6 colors
 	.data(allGroup)
  .enter()
	.append('option')
  .text(function (d) { return d; }) // text showed in the menu
  .attr("value", function (d) { return d; }) // corresponding value returned by the button

// Initialize a circle
var zeCircle = d3.select("#dataviz_builtWithD3")
  .append("svg")
  .append("circle")
    .attr("cx", 100)
    .attr("cy", 70)
    .attr("stroke", "black")
    .style("fill", "yellow")
    .attr("r", 20)

// A function that update the color of the circle
function updateChart(mycolor) {
  zeCircle
    .transition()
    .duration(1000)
    .style("fill", mycolor)
}

// When the button is changed, run the updateChart function
dropdownButton.on("change", function(d) {

    // recover the option that has been chosen
    var selectedOption = d3.select(this).property("value")

    // run the updateChart function with this selected option
    updateChart(selectedOption)
})




</script>

Change button style with Bootstrap



Steps:

  • Changing button style using pure css is a real pain as far as I know.

  • There are workaround: hiding the button and building a better one of top of it as described here.

  • I personally prefer to rely on the bootstrap framework, that offers specific ready-to-go class for good looking buttons. You need to load it in your document like you load d3.

  • Main useful class:
    • btn transforms any input in a button
    • btn-primary and btn-secondary
    • active
    • btn
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load bootstrap -->
<link href="../vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>


<!-- Simple button -->
<br><br>
<h6>Basic button</h6>
<a class="btn btn-secondary" href="https://github.com/holtzy/data_to_viz">link to something</a>

<!-- Radio button: one choice only -->
<br><br>
<h6>Radio button</h6>
<form id="form" class="btn-group btn-group-toggle" data-toggle="buttons">
  <label class="btn btn-secondary active">
    <input type="radio" name="controlHeatmapType" value="MRR" checked>Option 1<br>
  </label>
  <label class="btn btn-secondary">
    <input type="radio" name="controlHeatmapType" value="LYL">Option 2<br>
  </label>
</form>

<!-- Text input -->
<br><br>
<h6>Text input</h6>
<input class="btn" type="text" name="usrname" value="initial value">

<!-- Check box -->
<br><br>
<h6>Checkbox button</h6>
<form id="form" class="btn-group btn-group-toggle" data-toggle="buttons">
  <label class="btn btn-secondary active">
    <input type="checkbox" name="myCheckBox" value="banana" checked>Banana<br>
  </label>
  <label class="btn btn-secondary">
    <input type="checkbox" name="myCheckBox" value="orange">Orange<br>
  </label>
  <label class="btn btn-secondary active">
    <input type="checkbox" name="myCheckBox" value="lemon">Lemon<br>
  </label>
  <label class="btn btn-secondary">
    <input type="checkbox" name="myCheckBox" value="apple">Apple<br>
  </label>
</form>

<!-- Number input -->
<br><br>
<h6>Number input</h6>
<input class="btn btn-secondary" type="number" name="usrname" value=13>

<!-- Slider-->

<!-- Dropdown -->
<br><br>
<h6>Dropdown button</h6>
<div class="dropdown">
  <button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown">
    Dropdown button
  </button>
  <div class="dropdown-menu">
    <p>Yooo</p>
    <a href="toot">link</a>
    <input type="checkbox" name="myCheckBox" value="lemon">Lemon<br>
    <input type="checkbox" name="myCheckBox" value="lemon">Lemon<br>
  </div>
</div>

<br><br>

<script>

</script>

Simple button


Radio buttons


This example shows how to create a radio button and an event listener to it. This event listener is able to figure out when the radio button state changes. Then, the trickiest part is to recover the current value of the radio button.

<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create the radio button -->
<div id="colorButton">
  <input type="radio" name="colorButton" value="red" checked> Red<br>
  <input type="radio" name="colorButton" value="blue"> Blue<br>
  <input type="radio" name="colorButton" value="green"> Green<br>
</div>

<!-- Create a svg area-->
<svg id="dataviz_delay" width="400px" height="200px"></svg>

<script>

// Position of the circles on the X axis
var position = [50, 150, 250, 350]

// Add circles at the top
var theCircles = d3.select("#dataviz_delay")
  .selectAll("mycircles")
  .data(position)
  .enter()
  .append("circle")
    .attr("cx", function(d){return d} )
    .attr("cy", 100)
    .attr("r", 10)

// Function that change a color
function changeColor() {
  var radioValue = $("input[name='colorButton']:active");
  console.log(radioValue)
  theCircles
    .transition()
    .style("fill", radioValue)
}

// Event listener to the radio button
d3.select("#colorButton").on("change", changeColor )

</script>

Text input








Sliders


This example shows how to create a slider that controls circle size. An event listener constantly checks if the slider value is modified thanks to an on("change",..) statement. Recovering the slider value is simple using this.value.

<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create the radio button -->
<input type="range" name="mySlider" id=mySlider min="2" max="40" value="10">

<!-- Create a svg area-->
<svg id="dataviz_mySlider" width="400px" height="200px"></svg>

<script>

// Position of the circles on the X axis
var position = [50, 150, 250, 350]

// Add circles at the top
var theCircles = d3.select("#dataviz_mySlider")
  .selectAll("mycircles")
  .data(position)
  .enter()
  .append("circle")
    .attr("cx", function(d){return d} )
    .attr("cy", 100)
    .attr("r", 10)

// Function that change a color
function changeSize(size) {
  theCircles
    .attr('r',size)
}

// Listen to the slider?
d3.select("#mySlider").on("change", function(d){
  selectedValue = this.value
  changeSize(selectedValue)
})

</script>


Other examples involving sliders

Check box


Numeric input