primers

Following the seventh chapter of Learn D3: Animation, only English translation, the part of modifiable code is replaced by static pictures. For real-time interaction, please read the original text.

The body of the

If you are familiar with D3 in this tutorial, you might be surprised at how little the D3 selector is mentioned.

That’s because you probably don’t need them!

The D3 selector is suitable for a special positioning: rapid, incremental updates to dynamic charts. If you focus on static charts, or charts that can be redrawn from scratch every frame, you may prefer a different abstraction. On the other hand, if you want to animate transitions or extract the best performance from modern browsers, selectors are for you.

(Even if you decide not to use a selector, keep in mind that D3 has plenty of other useful visualization tools. Scale, shapes, interpolators, colors, map projections, and many other features are available for Canvas, WebGL, or other DOM abstractions, such as the HTML tag template text of an Observable, React, or Svelte. D3 can also assist in data cleansing and analysis using statistical, grouping and aggregation, time series and analytic methods.)

In essence, the D3 selector specifies transformations rather than representations. Instead of representing the desired state of the diagram (DOM), you can specify the changes (insert, update, and delete) that are made to convert the current state to the desired state. This can be tedious at times, but allows you to set up transition animations and minimize changes to the DOM to improve performance.

Let’s see how we can do that.

Suppose we want to display letters of the alphabet. It’s not very intuitive, but we’ll keep it simple to focus on the technology (see the animation and Interaction section of the D3 gallery for a practical example).

This diagram is static because it is created from scratch each time the unit runs, making D3 code essentially equivalent to HTML text.

So why use a selector? Yes, there’s no reason to do that with static charts.

But suppose you want to update this chart to respond 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 what you need, and remove what you don’t. Simply move the above code into a method that is called when the data changes and you can get high-performance incremental updates! 😲

Let’s take a look at the code.

Text is a set of text elements, initially empty, whose parent is an SVG element. This parent determines where the input text element will be appended later.

Text is bound to a new data array, letters, by calling selection.data. This computes three subsets of the Text selection set: The Enter selection set represents what is left in the new data after the intersection of existing elements with the new data is removed; The update selection set represents the intersection of new data with existing elements; The exit selection set represents the remaining elements in the existing element after the intersection between the existing element and the new data has been removed.

As illustrated below:

(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 selection sets.)

We can handle all three cases manually, but selection. Join is handy. Enter the selection set is added; The exit selection set is removed. Finally, the Update and Enter selection sets are merged, sorted, and returned. We can then assign attributes and text to these add or update elements.

We observed that as long as the association between letters and text elements remained constant, it was more efficient to not reassign certain attributes and text content when updating elements. To preserve this association, selection.data requires a key function; For precise operations on Enter, update, and exit, selection.join requires the corresponding function. If update is more common than Enter and exit, this will greatly improve performance!

As before, selection.join returns the combined Enter and Update selection sets, so we can share code that applies to both, such as setting the X property.

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

If no key function is specified, the data is bound by index: the first data is bound to the first element, and so on. As an exercise, try rewriting the above code to join by index. You’ll also want to swap the set X property with the set text content!

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

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

Good transitions are not just about making charts “dance” for attention; They help viewers understand how the data is changing through movement.

Good transitions preserve object constancy: diagram elements that represent specific things (such as the letter C) before the transition should represent the same things throughout and after the transition, allowing the viewer to follow continuously. Conversely, if the meaning of a given element changes during the transition, the change is meaningless.

How about a more practical example?

The chart below shows the top ten states (and Washington, D.C., non-residents) by percentage of the population in a particular age group. This suggests that Utah’s population is disproportionately young and reflects the LDS Church’s emphasis on raising families. Florida, by contrast, has a large population of retirees, many of whom are 70 or older.

As you change the selected age group, watch how the chart is reordered to reflect the change in ranking. The X-axis also rescales to fit the new data.

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))); }}); }Copy the code

Only the first 10 are visible because the rest are hidden below the chart. Therefore, selection.join is not needed because there are no bars to join or remove, they just update. This not only simplifies the code, but also makes the transition more meaningful, since the speed at which bars are entered or exited now indicates their location outside the display.

An animated transition is usually triggered by a reader clicking or clicking while looking for an answer. Next, let’s look at how to make a chart respond to such queries.

Next

The appendix

The attached

According to the source code, the platform dependence was removed and the main code was extracted, with the following examples:

  • Example 1
  • Example 2

The resources

wastebasket

The Witcher 3’s main plot was difficult to complete, but it had a tragic ending.

Go to see other people’s strategy, only to find a lot of tasks in front of the choice have affected the outcome.

What I thought was the right choice ended in tragedy.

The mood is still a little depressed, in the choice of time obviously into their own ideas.

The Witcher 3 game native file art set.