Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
380 views
in Technique[技术] by (71.8m points)

reactjs - Conditionally adding additional elements in D3

I've built out a heatmap with D3 in React and the basic result works fine: the rects are rendering and so are the conditional color values, based on my data.

Here is roughly what it looks like:

const dayRects = bounds.selectAll("rect").data(processed)

dayRects
  .join("rect")
  .attr("x", d => xScale(d.exampleData))
  .attr("width", ordinalScale.bandwidth)
  .attr("y", d => yScale(d.exampleData))
  .attr("height", ordinalScale.bandwidth)
  .attr("rx", 3)
  .style("fill", d => colorScale(d.moreData))

What I'm struggling to do and cannot find guidance for online, is to conditionally add elements based on data. For example, I'm trying to add an additional rect for items in my array of data that meet certain conditions. This additional rect would be slightly larger than the above rects, have a transparent fill, and a different colored stroke - resulting in, for example, something like this: enter image description here

When I attempt to do this with something like below the above code

const dayStarted = bounds
   .select("rect")
   .data(processed.filter(i => i.value === desiredValue))
   .join("rect")
   .attr("x", d => xScale(d.exampleData))
   .attr("width", ordinalScale.bandwidth)
   .attr("y", d => yScale(d.exampleData))
   .attr("rx", 20)

... it just manipulates the first rect element in the first set of rects (dayRects).

question from:https://stackoverflow.com/questions/65621682/conditionally-adding-additional-elements-in-d3

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should bind your data to a g element, position that and then add the rects as sibling in the g.

Here's a quick example:

<!DOCTYPE html>

<html>
  <head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
  </head>

  <body>
    <svg width="125" height="125"></svg>
    <script>
      var processed = [
        { x: Math.random() * 100, y: Math.random() * 100, value: 1 },
        { x: Math.random() * 100, y: Math.random() * 100, value: 0 },
      ];

      var bounds = d3.select('svg');

      const g = bounds
        .selectAll('g')
        .data(processed)
        .join('g')
        .attr('transform', (d) => {
          // use your scales to position g
          return "translate(" + d.x + "," + d.y + ")";
        });

      g.append('rect') // first rect
        .attr('width', 20)
        .attr('height', 20)
        .attr('rx', 3)
        .style('fill', 'orange');

      g.filter( d => d.value == 1) //apply filter on g for ones that get 2nd rect
        .append('rect')
        .attr('width', 20)
        .attr('height', 20)
        .attr('rx', 3)
        .style('fill', 'none')
        .style('stroke', 'steelblue')
        .style('stroke-width', '3px');
    </script>
  </body>
</html>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...