gpt4 book ai didi

animation - 如何同步路径和区域的动画?

转载 作者:行者123 更新时间:2023-12-04 21:45:28 25 4
gpt4 key购买 nike

我被 卡住了D3.js v4 动画双线 & 区域 :

  • 线和面分开做动画就可以了
  • 当 2 个动画组合在一起时,即使在相同的过渡持续时间内,它们也不会一起发生。
  • 出于造型的原因,我不能放弃这条线。

  • 请参阅下图:
    enter image description here

    为了使事情像上面一样,我做了两个大步骤:
  • 通过设置属性为线做动画stroke-dasharrowstroke-dashoffset . (灵感来自 Visual Cinnamon)
  • 通过调整 d3.area() 函数的参数来制作区域动画(灵感来自 other Stackoverlfow post)

  • 结果相当令人失望,因为下面的线和区域没有平行出现。

    我的目标是模仿 Highchart 库,看一个例子 here ,及其图示如下:

    enter image description here

    Highchart 库似乎使用了不同的动画技术,因为在 DOM 检查期间,动画中的 DOM 路径没有任何变化的迹象。

    如果有人可以向我建议一些可以尝试的想法,我们将不胜感激。

    我的代码示例如下:

    let animationDuration = 5000;
    // set the dimensions and margins of the graph
    var margin = { top: 20, right: 20, bottom: 30, left: 50 },
    width = 480 - margin.left - margin.right,
    height = 250 - margin.top - margin.bottom;

    // parse the date / time
    var parseTime = d3.timeParse("%d-%b-%y");

    // set the ranges
    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    // define the area
    var area = function (datum, boolean) {
    return d3.area()
    .y0(height)
    .y1(function (d) { return boolean ? y(d.close) : y(d.close); })
    .x(function (d) { return boolean ? x(d.date) : 0; })
    (datum);
    }

    // define the line
    var valueline = d3.line()
    .x(function (d) { return x(d.date); })
    .y(function (d) { return y(d.close); });

    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

    var data = d3.csvParse(d3.select("pre#data").text());

    data.reverse();

    // format the data
    data.forEach(function (d) {
    d.date = parseTime(d.date);
    d.close = +d.close;
    });

    // scale the range of the data
    x.domain(d3.extent(data, function (d) { return d.date; }));
    y.domain([0, d3.max(data, function (d) { return d.close; })]);

    // add the area
    svg.append("path")
    .data([data])
    .attr("class", "area")
    .attr("d", d => area(d, false))
    .attr("fill", "lightsteelblue")
    .transition()
    .duration(animationDuration)
    .attr("d", d => area(d, true));

    // add the valueline path.
    svg.append("path")
    .data([data])
    .attr("class", "line")
    .attr("d", valueline)
    .style("stroke-dasharray", d => {
    let path = document.querySelector(".line");
    const totalLength = path.getTotalLength();

    return `${totalLength} ${totalLength}`;
    })
    .style("stroke-dashoffset", d => {
    let path = document.querySelector(".line");
    const totalLength = path.getTotalLength();
    return `${totalLength}`;
    })
    .transition()
    .duration(animationDuration)
    .style("stroke-dashoffset", 0);

    // add the X Axis
    svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

    // add the Y Axis
    svg.append("g")
    .call(d3.axisLeft(y));
    .line {
    fill: none;
    stroke: steelblue;
    stroke-width: 2px;
    }

    pre#data {display:none;}
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <pre id="data">
    date,close
    1-May-12,58.13
    30-Apr-12,53.98
    27-Apr-12,67.00
    26-Apr-12,89.70
    25-Apr-12,99.00
    24-Apr-12,130.28
    23-Apr-12,166.70
    20-Apr-12,234.98
    19-Apr-12,345.44
    18-Apr-12,443.34
    17-Apr-12,543.70
    16-Apr-12,580.13
    13-Apr-12,605.23
    12-Apr-12,622.77
    11-Apr-12,626.20
    10-Apr-12,628.44
    9-Apr-12,636.23
    5-Apr-12,633.68
    4-Apr-12,624.31
    3-Apr-12,629.32
    2-Apr-12,618.63
    30-Mar-12,599.55
    29-Mar-12,609.86
    28-Mar-12,617.62
    27-Mar-12,614.48
    26-Mar-12,606.98
    </pre>

    最佳答案

    有一种方法可以使用自定义插值器为线条和区域设置动画。

    但是,由于您的目标是模仿 Highcharts animation you linked ,有一个更简单的方式 替代方案:使用 <clipPath> .

    在我提出的解决方案中,我们以常规方式创建区域和线。但是,我们引用了一个剪切路径...

    .attr("clip-path", "url(#clip)");

    ...在区域和线中。剪切路径是用 0 创建的宽度:
    var clip = svg.append("clipPath")
    .attr("id", "clip");
    var clipRect = clip.append("rect")
    .attr("width", 0)

    然后,在此之后,只需将过渡应用于剪切路径即可:
    clipRect.transition()
    .duration(5000)
    .ease(d3.easeLinear)
    .attr("width", someValue)

    这是一个演示:

    var svg = d3.select("svg");
    var data = d3.range(30).map(d => Math.random() * 150);
    var clip = svg.append("clipPath")
    .attr("id", "clip");
    var clipRect = clip.append("rect")
    .attr("width", 0)
    .attr("height", 150)
    var lineGenerator = d3.line()
    .x((_, i) => i * 10)
    .y(d => d)
    .curve(d3.curveMonotoneX)
    var areaGenerator = d3.area()
    .x((_, i) => i * 10)
    .y1(d => d)
    .y0(150)
    .curve(d3.curveMonotoneX)
    svg.append("path")
    .attr("d", areaGenerator(data))
    .attr("class", "area")
    .attr("clip-path", "url(#clip)");
    svg.append("path")
    .attr("d", lineGenerator(data))
    .attr("class", "line")
    .attr("clip-path", "url(#clip)");
    clipRect.transition()
    .duration(5000)
    .ease(d3.easeLinear)
    .attr("width", 300)
    .line {
    fill: none;
    stroke: #222;
    stroke-width: 2px;
    }

    .area {
    fill: limegreen;
    stroke: none;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg></svg>


    这是带有这些更改的代码:

    let animationDuration = 5000;
    // set the dimensions and margins of the graph
    var margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 50
    },
    width = 480 - margin.left - margin.right,
    height = 250 - margin.top - margin.bottom;

    // parse the date / time
    var parseTime = d3.timeParse("%d-%b-%y");

    // set the ranges
    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    // define the area
    var area = function(datum, boolean) {
    return d3.area()
    .y0(height)
    .y1(function(d) {
    return boolean ? y(d.close) : y(d.close);
    })
    .x(function(d) {
    return boolean ? x(d.date) : 0;
    })
    (datum);
    }

    // define the line
    var valueline = d3.line()
    .x(function(d) {
    return x(d.date);
    })
    .y(function(d) {
    return y(d.close);
    });

    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

    var clip = svg.append("clipPath")
    .attr("id", "clip");
    var clipRect = clip.append("rect")
    .attr("width", 0)
    .attr("height", height);

    var data = d3.csvParse(d3.select("pre#data").text());

    data.reverse();

    // format the data
    data.forEach(function(d) {
    d.date = parseTime(d.date);
    d.close = +d.close;
    });

    // scale the range of the data
    x.domain(d3.extent(data, function(d) {
    return d.date;
    }));
    y.domain([0, d3.max(data, function(d) {
    return d.close;
    })]);

    // add the area
    svg.append("path")
    .data([data])
    .attr("class", "area")
    .attr("d", d => area(d, true))
    .attr("fill", "lightsteelblue")
    .attr("clip-path", "url(#clip)");

    // add the valueline path.
    svg.append("path")
    .data([data])
    .attr("class", "line")
    .attr("d", valueline)
    .attr("clip-path", "url(#clip)");

    // add the X Axis
    svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

    // add the Y Axis
    svg.append("g")
    .call(d3.axisLeft(y));

    clipRect.transition()
    .duration(5000)
    .ease(d3.easeLinear)
    .attr("width", width)
    .line {
    fill: none;
    stroke: steelblue;
    stroke-width: 2px;
    }

    pre#data {
    display: none;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <pre id="data">
    date,close
    1-May-12,58.13
    30-Apr-12,53.98
    27-Apr-12,67.00
    26-Apr-12,89.70
    25-Apr-12,99.00
    24-Apr-12,130.28
    23-Apr-12,166.70
    20-Apr-12,234.98
    19-Apr-12,345.44
    18-Apr-12,443.34
    17-Apr-12,543.70
    16-Apr-12,580.13
    13-Apr-12,605.23
    12-Apr-12,622.77
    11-Apr-12,626.20
    10-Apr-12,628.44
    9-Apr-12,636.23
    5-Apr-12,633.68
    4-Apr-12,624.31
    3-Apr-12,629.32
    2-Apr-12,618.63
    30-Mar-12,599.55
    29-Mar-12,609.86
    28-Mar-12,617.62
    27-Mar-12,614.48
    26-Mar-12,606.98
    </pre>

    关于animation - 如何同步路径和区域的动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47986520/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com