Chapter 01Modifying Elements

Once we have a d3.selection object that contains zero or more elements, we can modify the elements in the selection in unison by calling the d3.selection methods shown below.

As you can see, each of the methods above can be used to set, remove, or get a characteristic (e.g. attribute, class, inner HTML) of an element. Since the API is similar in many cases, we’ll look at the first three methods together, then selection.classed, and finally the last two methods.

Chaining Method Calls

Many of the methods above return a d3.selection object. Since we call these methods on a selection object and they also return a selection object, we can chain multiple selection method calls together in a single statement. So, rather than writing something like this:

let sel = d3.selectAll("circle");
sel.attr("r", "30");
sel.attr("fill", "pink");

We can, instead, chain the method calls together and write an equivalent statement like the one below.

let sel = d3.selectAll("circle")
            .attr("r", "30")
            .attr("fill", "pink");

Modifying Attributes, Styles, and Properties

The library’s author designed selection.attr, selection.style, and selection.property so that they are called and behave in a consistent manner. Notice that each of them has an optional value argument. Whether or not a method sets, removes, or gets a characteristic depends on what is passed in for the value argument. The pattern is as follows:

Setting Attr, Style, and Property Values

When the value argument is a non-null value or a function, the methods are used as setters. If the value argument is a constant, then the characteristic of every element in the selection will be set using the same value.

Below is an example of how we can use selection.style to apply the same style to a set of elements. In the example, boxes are created using div elements with classes named box and pink-box (the CSS is hidden). The button handler selects all of the boxes and uses selection.style to add a border-radius property to each element in the selection.

<script>
  function addStyle() {
    d3.selectAll("#styleExampleSVG .box")
      .style("border-radius", "10px");
  }
</script>

<div id="styleExampleSVG" style="display: inline-block;">
    <div class="box blue-box"></div>
    <div class="box pink-box"></div>
    <div class="box pink-box"></div>
</div>
<button id="styleExampleButton" onclick="addStyle()">&#x394; Style</button>

If the argument is a function then the function is called for each element in the selection and the values returned from the function are used to set the characteristic of the elements. When the function is called, it is called with the current datum (d), the current index (i), and the current group (nodes) being passed to the function.

For example, the code below sets the radius of the circle elements to 10, 20, and 30, respectively, by using the index that is passed to the function (0, 1, and 2, respectively) in the radius computation.

<script>
  function setRadii() {
    d3.selectAll("#setterExampleSVG circle")
      .attr("r", (d,i,nodes) => 10 + (10 * i));
  }
</script>

<svg id="setterExampleSVG" width="250" height="100">
  <circle cx="50" cy="50" r="25" fill="lightblue" />
  <circle cx="125" cy="50" r="25" fill="lightblue" />
  <circle cx="200" cy="50" r="25" fill="lightblue" />
</svg>
<button id="setterExampleButton" onclick="setRadii()">Set Radii</button>

Deleting Attr, Style, and Property Values

When selection.attr, selection.style, or selection.property is passed null as the value argument, then the named attribute, style, or property (respectively) specified in the first argument is removed from each element in the selection.

In the example below we select the blue box and remove the border-radius property from its style attribute by passing null as the second argument to selection.style.

<script>
  function removeStyle() {
    d3.selectAll("#removeStyleExampleSVG .blue-box")
      .style("border-radius", null);
  }
</script>

<div id="removeStyleExampleSVG" style="display: inline-block;">
    <div class="box blue-box" style="border-radius: 25px;"></div>
    <div class="box pink-box" style="border-radius: 25px;"></div>
    <div class="box pink-box" style="border-radius: 25px;"></div>
</div>
<button id="styleExampleButton" onclick="removeStyle()">&#x394; Style</button>

Getting Attr, Style, and Property Values

When selection.attr, selection.style, or selection.property is called without a value argument, the method returns the attribute, style property, or raw property (respectively) associated with the name argument of the first non-null element in the selection.

Modifying Classes

The value argument of selection.classed is a boolean. If the value argument is true, the class names that are provided as a first argument are added to the class attribute of each element in the selection. If the value argument is false, then the classes are removed.

In the example below we have a class named lightblue that defines the fill property as lightblue.  In the function addClass we select all of the circle elements using selectAll(), then chain a call to classed() to add the lightblue class to each of the circle elements.

<script>
  function addClass() {
    d3.selectAll("#classedExampleSVG circle")
      .classed("lightblue", true);
    classedExampleButtonHandler = removeClass;
    d3.select("#classedExampleButton").text('Remove Class');
  }
  function removeClass() {
      d3.selectAll("#classedExampleSVG circle")
        .classed("lightblue", false);
      classedExampleButtonHandler = addClass;
      d3.select("#classedExampleButton").text('Add Class');
  }
  var classedExampleButtonHandler = addClass;
</script>

<svg id="classedExampleSVG" width="250" height="100">
  <circle id="blue" cx="50" cy="50" r="25" fill="lightblue" />
  <circle cx="125" cy="50" r="25" fill="pink" />
  <circle cx="200" cy="50" r="25" fill="pink" />
</svg>
<button id="classedExampleButton" onclick="classedExampleButtonHandler()">Add Class</button>

When selection.classed is called without a value argument, the method returns true if the first non-null element in the selection has the classes specified in the name argument, otherwise it returns false.

Modifying Text and InnerHTML

When selection.text and selection.html are passed a non-null value for the value argument, they behave similar to selection.attr. That is, if the value is a constant, then all elements in the selection will have their text or inner HTML, respectively, set to the same value. If the value is a function then the function is called for each element in the selection and the values returned from the function are used to set the characteristic of the elements. When the function is called, it is called with the current datum (d), the current index (i), and the current group (nodes) being passed to the function.

When selection.text and selection.html are passed null as a value argument, then the text content and inner HTML, respectively, are cleared for each element in the selection.

When selection.text or selection.html is called without a value argument, the method returns the text or inner HTML, respectively, of the first non-null element in the selection.

The example below shows how reverse the letters in an element’s text node by using selection.text without any arguments to retrieve the text, and using selection.text again with a non-null argument to set the text.

To begin we select the box with the class named box and retrieve it’s text using selection.text, storing the string in the variable named str. We then reverse the order of the letters in the string and store the result back in str. Last, we select the same box again and set it’s text by passing str to selection.text.

<script>
  function reverseText() {
    let str = d3.select("#textContainer .box").text();
    str = str.split("").reverse().join("");
    d3.select("#textContainer .box").text(str);
  }
</script>

<div id="textContainer" style="display: inline-block;">
  <div class="box blue-box">BOX</div>
</div>
<button id="changeTextButton" onclick="reverseText()">Reverse Text</button>
<br><br>