【问题标题】:Transition path length with marker in D3.js makes markers vanishD3.js 中带有标记的过渡路径长度使标记消失
【发布时间】:2017-10-31 13:42:41
【问题描述】:

我有this graph of nodes and shapes created with D3.js,我在制作动画时遇到了问题。我想做的是转换路径的长度,但是当我这样做时,pathmarker-end 消失了。

我已经设法使用append()svg:animate 元素来完成几乎相同的事情,但我认为最好使用D3 的transition() 来实际设置pathd 属性。谁能告诉我为什么标记在使用transition() 制作动画时会从路径中消失?

var graph = d3.select('.graph')
    .append('svg')
    .attr('width', window.innerWidth)
    .attr('height', window.innerHeight);

var defs = graph.append('svg:defs');

var blueGradient = defs.append('svg:linearGradient')
    .attr('id', 'b')
    .attr('x1', 0)
    .attr('y1', 0)
    .attr('x2', 0)
    .attr('y2', 1)
    .attr('spreadMethod', 'pad');

blueGradient.append('svg:stop')
    .attr('offset', '0%')
    .attr('stop-color', '#e4f5fc')
    .attr('stop-opacity', 1);

blueGradient.append('svg:stop')
    .attr('offset', '100%')
    .attr('stop-color', '#2ab0ed')
    .attr('stop-opacity', 1);

var orangeGradient = defs.append('svg:linearGradient')
    .attr('id', 'o')
    .attr('x1', 0)
    .attr('y1', 0)
    .attr('x2', 0)
    .attr('y2', 1)
    .attr('spreadMethod', 'pad');

orangeGradient.append('svg:stop')
    .attr('offset', 0)
    .attr('stop-color', '#f6e6b4')
    .attr('stop-opacity', 1);

orangeGradient.append('svg:stop')
    .attr('offset', '100%')
    .attr('stop-color', '#ed9017')
    .attr('stop-opacity', 1);

var arrow = defs.append('svg:marker')
    .attr('id', 'arrow')
    .attr('orient', 'auto')
    .attr('markerWidth', 2)
    .attr('markerHeight', 4)
    .attr('refX', 0.1)
    .attr('refY', 2);

arrow.append('path')
    .attr('d', 'M0,0 V4 L2,2 Z')
    .attr('fill', '#aaa');

var line = d3.line()
    .x(function(d) { console.log(d); return d.x; })
    .y(function(d) { console.log(d); return d.y; });

var appended = false;
var step = -1;

document.addEventListener('keydown', drawGraph);
document.addEventListener('click', drawGraph);

drawGraph();

function drawGraph(event) {
    var nodes = [
        {
            x: 200,
            y: 50,
            c: 'b',
        },
        {
            x: 400,
            y: 50,
            c: 'b'
        },
        {
            x: 600,
            y: 50,
            c: 'b'
        },
        {
            x: 725,
            y: 175,
            c: 'b'
        },
        {
            x: 600,
            y: 300,
            c: 'o'
        },
        {
            x: 400,
            y: 300,
            c: 'o'
        },
        {
            x: 200,
            y: 300,
            c: 'o'
        },
        {
            x: 75,
            y: 175,
            c: 'o'
        }
    ];

    switch (step) {
        case -1:
            var paths;

            if (!appended) {
                paths = graph.selectAll('path.nodes')
                    .data(nodes)
                    .enter()
                    .append('path')
                    .attr('stroke', '#aaa')
                    .attr('stroke-width', 10)
                    .attr('fill', 'none')
                    .attr('marker-end', 'url(#arrow)');

                graph.selectAll('circle.nodes')
                    .data(nodes)
                    .enter()
                    .append('svg:circle')
                    .attr('cx', function(d) {
                        return d.x;
                    })
                    .attr('cy', function(d) {
                        return d.y;
                    })
                    .attr('r', 19)
                    .attr('fill', function(d) {
                        return 'url(#' + d.c + ')';
                    })
                    .attr('stroke', function(d) {
                        switch (d.c) {
                            case 'b':
                                return '#2E75B6';
                            case 'o':
                                return '#BF9000';
                        }
                    });
            } else {
                paths = graph.selectAll('path')
                    .transition();
            }

            paths.attr('d', function(currentNode, i) {
                if (!currentNode) {
                    return;
                }

                if (appended) {
                    // For some reason, the index is base 0 when the elements
                    // are appended, then 1 based afterwards.
                    i--;
                }

                currentNode = nodes[i];

                var nextNode = i < nodes.length - 1 ?
                    nodes[i + 1] :
                    nodes[0];

                startPath = {
                    x: currentNode.x,
                    y: currentNode.y,
                    c: currentNode.c
                };

                endPath = {
                    x: nextNode.x,
                    y: nextNode.y,
                    c: nextNode.c
                };

                return line([startPath, endPath]);
            });

            appended = true;
            step++;
            break;

        case 0:
            graph.selectAll('path')
                .transition()
                .attr('d', function(currentNode, i) {
                    if (!currentNode) {
                        return;
                    }

                    // For some reason, the index is suddenly base 1, not 0.
                    i--;

                    var nextNode = i < nodes.length - 1 ?
                        nodes[i + 1] :
                        nodes[0];

                    startPath = {
                        x: currentNode.x,
                        y: currentNode.y,
                        c: currentNode.c
                    };

                    endPath = {
                        x: nextNode.x,
                        y: nextNode.y,
                        c: nextNode.c
                    };
                    var diff = {
                        x: nextNode.x - currentNode.x,
                        y: nextNode.y - currentNode.y
                    };

                    var margins = {
                        current: {
                            x: 0,
                            y: 0
                        },
                        next: {
                            x: 0,
                            y: 0
                        }
                    };

                    if (diff.x > 0 && diff.y === 0) {
                        margins.current.x = 30;
                    } else if (diff.x < 0 && diff.y === 0) {
                        margins.current.x = -30;
                    } else if (diff.x > 0) {
                        margins.current.x = 20;
                    } else if (diff.x < 0) {
                        margins.current.x = -20;
                    }

                    if (diff.y > 0 && diff.x === 0) {
                        margins.current.y = 30;
                    } else if (diff.y < 0 && diff.x === 0) {
                        margins.current.y = -30;
                    } else if (diff.y > 0) {
                        margins.current.y = 20;
                    } else if (diff.y < 0) {
                        margins.current.y = -20;
                    }

                    if (margins.current.x != 0) {
                        margins.next.x = margins.current.x < 0 ?
                            Math.abs(margins.current.x * 1.5) :
                            margins.current.x * -1.5;
                    }

                    if (margins.current.y != 0) {
                        margins.next.y = margins.current.y < 0 ?
                            Math.abs(margins.current.y * 1.5) :
                            margins.current.y * -1.5;
                    }

                    startPath.x += margins.current.x;
                    startPath.y += margins.current.y;
                    endPath.x += margins.next.x;
                    endPath.y += margins.next.y;

                    return line([startPath, endPath]);
                });

            step--;
            break;
    }
}

【问题讨论】:

    标签: javascript d3.js svg transition


    【解决方案1】:

    当您在else 条件下执行此操作时...

    paths = graph.selectAll('path')
    

    ...您也在选择标记,这不是您想要的。

    解决方案:给你的路径一个类...

    .attr("class", "nodes")
    

    ...并按该类选择:

    paths = graph.selectAll('.nodes')
    

    或者,创建一个适当的“更新”选择(查看下面的 Post Scriptum)。

    这是一个更新的小提琴:https://jsfiddle.net/khukeh13/

    PS:我做了一个缓慢的过渡,只是为了让你看到标记在移动。但是,该代码中仍然存在很多问题(查看控制台中的错误),与当前问题无关,可能值得提出一个新问题。这些错误与switchif 的奇怪组合有关,我建议您摆脱它。您不需要这样做:只需创建一个基本的“进入”、“更新”和“退出”选择,这就是 D3 的惯用方式。

    【讨论】:

    • 我了解代码并不理想,但我之所以拥有 switch 是因为代码取自 Reveal.js 演示文稿,其中幻灯片中的每个“片段步骤”都将执行推进图的状态。另外,我不太明白.selectAll('path') 如何选择未命名为path 的元素。你能解释一下吗?最后,过渡现在减少了通向虚无的道路。在添加类名之前没有发生这种情况。你能解释一下为什么吗?
    • 但是箭头一条路径。在你的代码中看看这个:arrow.append('path').attr('d', 'M0,0 V4 L2,2 Z').attr('fill', '#aaa');.
    • selectAll("path") 选择选择中的所有path 元素。关于过渡,正如我在 PS 中告诉你的,那是因为你在 switch 中使用的计数器有一些问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    • 2015-04-18
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多