javascript - 链接转换

标签 javascript d3.js

我正在尝试在 D3 中链接一个转换,但我不太清楚如何使其正常工作。我已经阅读了一些示例,我觉得我在选择方面遗漏了一些东西(可能是因为我的选择跨越了不同的图层)。

您可以在下面看到一个示例,单击“目标”应将光脉冲动画发送到“服务”节点。一旦脉冲到达,我希望服务节点通过过渡填充为橙色。目前我知道我的选择将填满两个圆圈 - 我很快就会解决这个问题。

然而,当脉冲到达时,什么也没有发生:

var t0 = svg.transition();

var t1 = t0.selectAll(".pulse")
    .duration(2000)
    .ease("easeInOutSine")
    .attr("cx", function(d) { return d.x2; })
    .attr("cy", function(d) { return d.y2; });

t1.selectAll(".node")
  .style("fill", "#F79646");

我似乎能够进行更改的唯一方法是将代码的最后一点更改为:

t0.selectAll(".node")
  .style("fill", "#F79646");

然而,这会导致节点立即填充,而不是等待脉冲到达。感觉选择并没有“扩展”来选择 .node 实例,但我不太确定

var nodes = [
    { x: 105, y: 105, r: 55, color: "#3BAF4A", title: "Objectives" }, 
    { x: 305, y: 505, r: 35, color: "#F79646", title: "Service" }
];
var links = [
    { x1: 105, y1: 105, x2: 305, y2: 505 }   
];

var svg = d3.select("svg");
var relationshipLayer =svg.append("g").attr("id", "relationships");
var nodeLayer = svg.append("g").attr("id", "nodes");

// Add the nodes
var nodeEnter = nodeLayer.selectAll("circle").data(nodes).enter();
    
var nodes = nodeEnter.append("g")
                     .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")";})
                     .on("click", function (d) {
                         d3.select(this)
                            .select("circle")
                             .transition()
                             .style("stroke", "#397F42")
                             .style("fill", "#3BAF4A");
                         
                         pulse(d); 
                     });

var circles = nodes.append("circle")
                    .attr("class", "node")
                    .attr("r", function (d) { return d.r; })
                    .style("fill", "#1C1C1C")
                    .style("stroke-width", "4px")
                    .style("stroke", function (d) { return d.color; });

var texts = nodes.append("text")
                 .text(function (d) { return d.title; })
                 .attr("dx", function(d) { return -d.r / 2; })
                 .style("fill", "white");

function pulse(d) {
    function distanceFunction(x1, y1, x2, y2) {
      var a = (x2 - x1)  * (x2 - x1);
      var b = (y2 - y1) * (y2 - y1);
      return Math.sqrt(a + b);
    };
    
    var lineFunction = d3.svg.line()
        .x(function (d) { return d.x; })
        .y(function (d) { return d.y; })
        .interpolate("linear");   
    
    var lines = relationshipLayer
                    .selectAll("line")
    .data(links)
    .enter()
    .append("line")
    .attr("x1", function(d) { return d.x1; })
    .attr("y1", function(d) { return d.y1; })
    .attr("x2", function(d) { return d.x2; })
    .attr("y2", function(d) { return d.y2; })
    .attr("stroke-dasharray", function(d) { return distanceFunction(d.x1, d.y1, d.x2, d.y2); })
    .attr("stroke-dashoffset", function(d) { return distanceFunction(d.x1, d.y1, d.x2, d.y2); });
    
    var pulse = relationshipLayer
            .selectAll(".pulse")
            .data(links)
            .enter()
            .append("circle")
            .attr("class", "pulse")
            .attr("cx", function(d) { return d.x1; })
            .attr("cy", function(d) { return d.y1; })
            .attr("r", 50);
    
    lines.transition()
        .duration(2000)
        .ease("easeInOutSine")
        .attr("stroke-dashoffset", 0);
    
    var t0 = svg.transition();
        
    var t1 = t0.selectAll(".pulse")
        .duration(2000)
        .ease("easeInOutSine")
        .attr("cx", function(d) { return d.x2; })
        .attr("cy", function(d) { return d.y2; });
    
    t1.selectAll(".node")
      .style("fill", "#F79646");
};
svg {
    background: #222234;
    width: 600px;
    height: 600px;
    font-size: 10px;
    text-align: center;
    font-family: 'Open Sans', Arial, sans-serif;
}
circle {
    fill: url(#grad1);
}
line {
    fill: none;
    stroke: #fff;
    stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg id="svg">
    <defs>
        <radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
            <stop offset="5%" style="stop-color:rgb(255,255,255); stop-opacity:1" />
            <stop offset="10%" style="stop-color:rgb(255,255,255); stop-opacity:0.8" />
            <stop offset="20%" style="stop-color:rgb(255,255,255); stop-opacity:0.6" />
            <stop offset="60%" style="stop-color:rgb(255,255,255);stop-opacity:0.0" />
        </radialGradient>
    </defs>
</svg>

最佳答案

您没有看到第二次转换发生变化的原因是它没有应用于任何内容。您的第一个转换的选择包含类 pulse 的所有元素,然后您将从第一个选择的元素中选择类 node 的元素.没有元素同时具有这两个类,因此您的选择为空,并且更改不会应用于任何元素。

一般来说,您无法以当前在更改选择时使用的方式链接过渡。相反,请使用 .each()转换的事件处理程序,它允许您安装转换完成时执行的处理程序函数。在您的情况下,这看起来像这样:

svg.selectAll(".pulse")
    .transition()
    .duration(2000)
    .ease("easeInOutSine")
    .attr("cx", function(d) { return d.x2; })
    .attr("cy", function(d) { return d.y2; })
    .each("end", function() {
        svg.selectAll(".node")
            .transition()
            .duration(2000)
            .style("fill", "#F79646");
    });

这将选择所有具有 node 类的元素,并将其填充更改为带有过渡的橙色。

上面的代码有两个问题——首先,正如您已经观察到的,它改变了所有节点的填充,而不仅仅是目标,第二,结束 事件处理程序针对转换中的每个元素执行,而不仅仅是一次。对于您的特定示例,这不是问题,因为您只有一个动画链接,但如果有多个链接,则该函数(以及转换)将被执行多次。

使用相同的代码可以很容易地解决这两个问题。这个想法是过滤 node 元素的选择以仅包含该行的目标。执行此操作的一种方法是将线的目标坐标与选择中元素的坐标进行比较:

svg.selectAll(".pulse")
    .transition()
    .duration(2000)
    .ease("easeInOutSine")
    .attr("cx", function(d) { return d.x2; })
    .attr("cy", function(d) { return d.y2; })
    .each("end", function(d) {
        svg.selectAll(".node")
            .filter(function(e) {
                return e.x == d.x2 && e.y == d.y2;
            })
            .transition()
            .duration(2000)
            .style("fill", "#F79646");
    });

处理函数的参数d是绑定(bind)到正在转换的元素的数据,其中包含目标坐标。在 filter() 行之后,选择将仅包含该行移动到的圆圈。只要目标不同,对多行多次执行此代码是安全的。

完整演示 here .

关于javascript - 链接转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28066052/

相关文章:

javascript - Sails js 中的文件名生成器

javascript - d3.js:将匿名函数作为参数传递给居中力?

svg - 使用 d3 获取 inkscape 属性

javascript - d3.js v4 拖动缩放元素跳跃鼠标

Javascript 倒计时从上午 8 点到晚上 9 点

javascript - 如何使 JS 错误不会阻止 Trix 工作?

javascript - 如何在第二次倒计时后停止 Javascript 计时器?

javascript - 通过计算和比较添加两个表单变量

html - 鼠标悬停在 d3 圆环图上时图例文本背景发生变化

javascript - 在文本标签内添加一个 div