繁体   English   中英

D3 V4使用带有合并的常规更新模式进入元素时进行转换

[英]D3 V4 Transition on entering elements using General Update Pattern with merge

据我所知,不可能在标准输入/附加/合并链中包含对输入元素的转换,因为这样做会将输入元素选择替换为无法与更新选择合并的转换。 (请参阅此处选择和转换之间的区别)。

(针对评论编辑的问题)

如果所需的效果是顺序转换,合并之前和合并之后,可以按如下方式完成:

// Join data, store update selection      
      circ = svg.selectAll("circle")
          .data(dataset);

// Add new circle and store entering circle selection        
      var newcirc = circ.enter().append("circle")
         *attributes*

// Entering circle transition        
      newcirc    
          .transition()
          .duration(1000)
          *modify attributes*
          .on("end", function () {

// Merge entering circle with existing circles, transition all        
      circ = newcirc.merge(circ)
          .transition()
          .duration(1000)
          *modify attributes*
      });

的jsfiddle

我想知道是否有办法在不破坏输入/追加/合并链的情况下执行此操作。

毫无疑问,您必须在方法链中至少有一个中断,因为您需要保留对更新选择的引用,以便稍后可以将其合并到输入选择中。 如果您对此感觉不错,可以在初始休息后保持链完好无损。

我在这个问题的答案中列出了这个基本原理: “你可以在过渡后链接一个函数而不是过渡的一部分吗?” 这使用transition.selection() ,它允许您从当前转换中解脱出来并访问启动转换的基础选择。 但是,您的代码更复杂,因为链式转换会增加复杂性。

第一部分是像以前一样存储更新选择:

// Join data, store update selection      
const circUpd = svg.selectAll("circle")
  .data(dataset);

第二个不间断的部分是这样的:

const circ = circUpd              // 2. Store merged selection from 1.
  .enter().append("circle")
    // .attr()...
  .transition()
    // .duration(1000)
    // .attr()...
    .on("end", function () {
      circ.transition()           // 3. Use merged selection from 2.
        // .duration(1000)
        // .attr()...
    })
    .selection().merge(circUpd);  // 1. Merge stored update into enter selection.

这可能需要对上面编号的步骤进行一些进一步的解释:

  1. 最后一行是最重要的一个 - 在开始转换之后,代码使用.selection()来保持转换所基于的选择,即输入选择,这反过来可以用来轻松合并将更新选择存储到其中。

  2. 包含输入和更新选择的合并选择是整个链的结果,然后存储在circ

  3. 这是棘手的部分! 重要的是要理解,提供给.on("end", function() {...})是一个在转换结束之前不执行的回调。 尽管这一行在选择合并之前出现,但它实际上是合并之后执行的。 然而,通过引用circ ,它会关闭过度捕获,如果你愿意的话 - 引用circ 这样,当实际执行回调时, circ将已经引用先前合并的选择。

看看以下工作片段:

 var w = 250; var h = 250; // Create SVG var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); // Create background rectangle svg.append("rect") .attr("x", "0") .attr("y", "0") .attr("width", w) .attr("height", h) .attr("fill", "aliceblue"); var dataset = [170, 220, 40, 120, 0, 300]; var xScale = d3.scaleBand() .domain(d3.range(dataset.length)) .range([0, w]); var yScale = d3.scaleLinear() .domain([0, 300]) .range([75, 200]) var rad = xScale.bandwidth()/2 // Join data var circ = svg.selectAll("circle") .data(dataset); // Create initial circles circ.enter().append("circle") .attr("cx", (d, i) => xScale(i)+rad) .attr("cy", d => yScale(d)) .attr("r", rad) .attr("fill", "blue"); // Trigger update on click d3.select("h3") .on("click", function () { // Create new data value var newvalue = Math.floor(Math.random()*300); dataset.push(newvalue); xScale.domain(d3.range(dataset.length)); rad = xScale.bandwidth()/2; // Join data, store update selection const circUpd = svg.selectAll("circle") .data(dataset); // Add new circle and store entering circle selection const circ = circUpd // 2. Store merged selection from 1. .enter().append("circle") .attr("cx", "0") .attr("cy", "25") .attr("r", rad) .attr("fill", "red") .transition() .duration(1000) .attr("cx", (d, i) => xScale(i)+rad) .on("end", function () { circ.transition() // 3. Use merged selection from 2. .duration(1000) .attr("cx", (d, i) => xScale(i)+rad) .attr("cy", d => yScale(d)) .attr("r", rad) .attr("fill", "blue"); }) .selection().merge(circUpd); // 1. Merge stored update into enter selection. }); 
 <script src="https://d3js.org/d3.v4.js"></script> <h3>Add a circle</h3> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM