javascript - 使用带有合并的通用更新模式输入元素时的 D3 V4 转换

标签 javascript d3.js transition

据我所知,不可能在 standard enter/append/merge chain 中的输入元素上包含过渡。 ,因为这样做会将输入元素选择替换为无法与更新选择合并的过渡。 (请参阅 here,了解选择和转换之间的区别)。

(根据评论编辑问题)

如果想要的效果是顺序过渡,一个在合并之前,一个在合并之后,可以按如下方式完成:

// 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

我想知道是否有一种方法可以在不破坏输入/附加/合并链的情况下执行此操作。

最佳答案

毫无疑问,您必须在方法链中至少有一个中断,因为您需要保留对更新选择的引用以便稍后能够将其合并到输入选择中。如果您对此没有意见,那么有一种方法可以在初始中断后保持链条完好无损。

我在我的 answer 中列出了这个工作的基本原则至 "Can you chain a function after a transition without it being a part of the transition?" .这使用 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>

关于javascript - 使用带有合并的通用更新模式输入元素时的 D3 V4 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49707737/

相关文章:

javascript - d3 : Adding and removing force. 基于 slider 值的节点

C#如何在winform中创建一个简单的图片幻灯片放映?

html - 在不定义关键帧的情况下动画位置变化

forEach 循环中的 Javascript API 队列

javascript - Meteor 用户帐户 - 内部状态

javascript - 表格单元格为空时显示警告框

javascript - 如何在 D3 可缩放包布局中隐藏标签的重叠文本?

HTML SVG : show element on top of all elements

javascript - 在显示谷歌地图时隐藏 UiWebview 的地址栏

css - 框阴影悬停过渡闪烁