1

Introduction

Following the Learn D3: Animation , it is only an English translation. The part of the code that can be modified is replaced with a static image. If you want to interact in real time, please read the original text.

text

If you are familiar with D3 in this tutorial, you may be surprised that the D3 selector is mentioned so little.

That's because you may not need them!

The D3 selector applies a special positioning: fast, incremental updates of dynamic charts. If you are focusing on static charts, or charts that can be redrawn from scratch every frame, then you might prefer a different abstraction. On the other hand, if you want animated transitions or squeeze the best performance from modern browsers, the selector is for you.

(Even if you decide not to use selectors, please remember that D3 has plenty of other useful visualization tools. Scale, shape, interpolator, color, map projection and many other functions can be used for Canvas, WebGL or other DOM abstractions, such as Observable's HTML markup template text, React or Svelte. D3 can also use statistics, grouping and aggregation, time series and analysis methods to assist in data cleaning and analysis.)

Essentially, the D3 selector specifies convert instead of represent . You can specify the changes (insert, update, and delete) made to transform the current state into the desired state instead of representing the desired state of the chart (DOM). This can be tedious at times, but allows you to set up transition animations and minimize changes to the DOM, thereby improving performance.

Let's see how to do it.

Suppose we want to display the letters of the alphabet. Although not very intuitive, we will keep it simple to focus on the technology (for practical examples, see the animation and interaction section of the D3 Gallery

92-1

This chart is static because it is created from scratch each time the unit is run, which makes D3 code essentially equivalent to HTML text.

92-2

So, why use selectors? Yes, for static charts, there is no reason to do this.

But suppose you want to update this chart in response to changing data. And you don't want to redraw from scratch, you want to apply the smallest update set to reflect the new data. You want to reuse existing elements, add elements you need, and delete elements you don't need. Just move the above code to a method that is called when the data changes, and you can get high-performance incremental updates! 😲

92-3

Let's analyze the code.

text is a set of text elements, initially empty, and its parent element is an SVG element. This parent determines where the entered text element will be appended later.

By calling selection , text is bound to a new data array letters . This will calculate the three subsets of the text enter selection set represents the remaining data after removing the intersection of the existing elements and the new data in the new data; update selection set represents the new data and the existing data. The intersection of the existing elements; exit selection set represents the remaining elements after removing the intersection of the existing elements and the new data among the existing elements.

As an illustration as follows:

92-4

(These selection sets are hidden in the code: selection .data returns the update selection set, from which you can call selection .enter or selection .exit to access other selections 1614a801fd9458 .exit.)

We can handle these three cases manually, but selection.join can be handled conveniently. enter selection set is added; exit selection set is removed; finally, update and enter selection set is merged, sorted and returned. Then, we can assign attributes and text to these added or updated elements.

We observed that as long as the association between letters and text elements remains unchanged, there is no need to reassign certain attributes and text content when updating elements, which can be more efficient. To keep this association, Selection .data requires a function key; To Enter , Update , Exit precise operation, Selection .join needs corresponding function. If update is more common than enter and exit, this will greatly improve performance!

92-5

As before, selection .join returns the merged enter and update selection sets, so we can share the code that applies to both, such as setting x properties.

The key function passed to selection .data is used to calculate the (string) key of each new data and selected element data, and determine which data is bound to which element: if the element and data have the same key, the data Bind to the element, and the element is put into the update selection set. Letters are good keys, so the identification function (d => d) is appropriate here.

(If the key function is not specified, the data is bound by the index: the first data is bound to the first element, and so on. As an exercise, try to rewrite the code above to join by index. You will also want to Set x attributes and set text content exchange!)

However, where the selector really shines is the transition! ✨

Below, the letters enter from the top, slide horizontally when updating, and then exit from the bottom. This is easier to understand than the instantaneous transition above.

92-6

Good transition is not just to attract attention and let the chart "Dancing"; they help the viewer understand by changes how the data is changed .

Good transition holding object constancy : the transition before represents a specific object (e.g., the letter C) graph element should be throughout the transition process and transition after represent the same thing, so as to allow a viewer to continuously track. Conversely, if the meaning of a given element changes during the transition, the change will be meaningless.

How about a more practical example?

The chart below shows the top ten states (and Washington, DC, out-of-town residents) ranked by percentage of population in a particular age group. This shows that the proportion of young people in Utah is too high, reflecting the importance of LDS churches on raising families. In contrast, Florida has a large retired population, many of whom are 70 or older.

When you change the selected age group, please observe how the chart is reordered to reflect the change in ranking. x axis is simultaneously rescaled to fit the new data.

92-7

chart = {
  const svg = d3.create("svg")
      .attr("viewBox", [0, 0, width, height]);
  console.info(data)

  // For the initial render, reference the current age non-reactively.
  const agedata = viewof agedata.value;

  const x = d3.scaleLinear()
      .domain([0, d3.max(agedata, d => d.value)])
      .rangeRound([margin.left, width - margin.right]);

  const y = d3.scaleBand()
      .domain(agedata.map(d => d.name))
      .rangeRound([margin.top, margin.top + 20 * data.names.length]);

  let bar = svg.append("g")
      .attr("fill", "steelblue")
    .selectAll("rect")
    .data(agedata, d => d.name)
    .join("rect")
      .style("mix-blend-mode", "multiply")
      .attr("x", x(0))
      .attr("y", d => y(d.name))
      .attr("width", d => x(d.value) - x(0))
      .attr("height", y.bandwidth() - 1);

  const gx = svg.append("g")
      .call(xAxis, x);

  const gy = svg.append("g")
      .call(yAxis, y);

  return Object.assign(svg.node(), {
    update(agedata) {
      const t = svg.transition().duration(750);

      gx.transition(t)
          .call(xAxis, x.domain([0, d3.max(agedata, d => d.value)]));

      gy.transition(t)
          .call(yAxis, y.domain(agedata.map(d => d.name)));

      bar = bar
        .data(agedata, d => d.name)
        .call(bar => bar.transition(t)
          .attr("width", d => x(d.value) - x(0))
          .attr("y", d => y(d.name)));
    }
  });
}

92-9

Only the first 10 items are visible because the rest are hidden under the chart. Therefore, selection .join is not needed, because there are no bars added or removed, they will only be updated. This not only simplifies the code, but also makes the transition more meaningful, because the speed of entering or exiting the bar graph now implies their position outside the display.

Animated transitions are usually triggered by the reader clicking or clicking while looking for an answer. Next, let us see how to make the chart respond to such queries.

Next

appendix

92-10

Attached

According to the source code, the platform dependency is removed, and the main code is extracted. The following examples are shown:

Reference


XXHolic
363 声望1.1k 粉丝

[链接]