在面积图d3中将一条线附加到路径的末端

问题描述

我正在尝试在面积图路径的末尾添加一条线。我所在地区最困难的部分是动画。我有一个clipPath,其宽度从width: 0转换为width: 960,并且末尾的行也随之而行,因此应该保持同步。此外,该行顶部的文本也需要不断更新。

所需的输出

enter image description here

我最初的想法是建立一个图表区域并添加一个clipPath,然后在该区域图内添加一个条形图,以便我可以根据附加的条形更新文本,但是条形图不在我的区域图内。将条形图放置在面积图内是我做错了什么,还是有更好的解决方案?

// Area chart width and height
const width1 = 1000,height1 = 100;

// Define x and y scale for area chart
const xScale1 = d3.scaleTime().range([0,width1]);
const yScale1 = d3.scaleLinear().range([height1,0]);

// Define x and y range for bar chart
let xScale2 = d3.scaleBand().range([0,width1]);
let yScale2 = d3.scaleLinear().range([height1,0]);

// Add SVG to #areachart
const svg1 = d3
  .select('#areachart')
  .append('svg')
  .attr('viewBox',`0 0 ${width1} ${height1}`)
  .attr('transform','translate(' + 0 + ',' + -50 + ')');

const g1 = svg1.append('g');

// Fetch data
d3.json(
    'https://api.coronavirus.data.gov.uk/v1/data?filters=areaName=United%2520Kingdom;areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newCasesByPublishDate%22:%22newCasesByPublishDate%22,%22cumCasesByPublishDate%22:%22cumCasesByPublishDate%22%7D&format=json'
  )
  .then(function(data) {
    console.log('DATES SLICED ----->',data.data.slice(30,281));

    //Define xScale1 & yScale1 domain after data loaded
    yScale1.domain([
      0,d3.max(data.data,function(d) {
        return +d.cumCasesByPublishDate;
      }),]);

    xScale1.domain(
      d3.extent(data.data,function(d) {
        return new Date(d.date);
      })
    );

    // Area  generator
    const area = d3
      .area()
      .curve(d3.curveStepAfter)
      .x((d) => xScale1(new Date(d.date)))
      .y1((d) => yScale1(+d.cumCasesByPublishDate))
      .y0(yScale1(0));

    g1.append('path')
      .datum(data.data.slice(30,200))
      .attr('d',area)
      .classed('placeholder-layer',true)
      .style('fill','#dadada')
      .style('opacity','0.3');

    // clipPath for areachart fill animation
    const clip = g1.append('clipPath').attr('id','clip');
    const clipRect = clip.append('rect').attr('width',0).attr('height',750);

    g1.append('path')
      .datum(data.data.slice(30,area)
      .attr('clip-path','url(#clip)')
      .classed('overlay-layer','yellow')
      .style('opacity','0.3');

    g1.append('line').attr('stroke-width',960).style('stroke','yellow');

    clipRect
      .transition()
      .duration(10000)
      .ease(d3.easeLinear)
      .attr('width',960);

    //x and y domain for bar chart
    xScale2.domain(data.data.slice(30,200).map((d) => new Date(d.date)));
    yScale2.domain([
      0,]);

    g1.selectAll('rect')
      .data(data.data.slice(30,200))
      .enter()
      .append('rect')
      .style('fill','red')
      .attr('width',xScale2.bandwidth() * 10)
      .attr('height',(d) => yScale2(+d.cumCasesByPublishDate))
      .attr('x',0)
      .attr('y',function(d) {
        return yScale2(+d.cumCasesByPublishDate);
      })
      .transition()
      .delay(function(d,i) {
        return i * 30;
      })
      .attr('x',function(d) {
        return xScale2(new Date(d.date));
      })
      .duration(100);
  })
  // if there's an error,log it
  .catch((error) => console.log(error));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<section id="map">
  <div id="visualisation-container">
    <div id="visualisation"></div>
    <div id="areachart"></div>
  </div>
</section>

解决方法

我只用一条线,没有横杠,然后将transition.tweend3.interpolateDate一起使用来进行文本更改。

// Area chart width and height
const width1 = 800,height1 = 250,marginBottom = 50

// Define x and y scale for area chart
const xScale1 = d3.scaleTime().range([0,width1]);
const yScale1 = d3.scaleLinear().range([height1,marginBottom]);

// Define x and y range for bar chart
let xScale2 = d3.scaleBand().range([0,width1]);
let yScale2 = d3.scaleLinear().range([height1,marginBottom]);

// Add SVG to #areachart
const svg1 = d3
  .select('#areachart')
  .append('svg')
  .attr('width',width1)
  .attr('height',height1);

const g1 = svg1.append('g');

// Fetch data
d3.json(
    'https://api.coronavirus.data.gov.uk/v1/data?filters=areaName=United%2520Kingdom;areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newCasesByPublishDate%22:%22newCasesByPublishDate%22,%22cumCasesByPublishDate%22:%22cumCasesByPublishDate%22%7D&format=json'
  )
  .then(data => {
    data.data.forEach(d => {
      d.cumCasesByPublishDate = +d.cumCasesByPublishDate;
      d.date = new Date(d.date);
    });
    return data.data.slice(30,200);
  })
  .then(function(data) {
    //Define xScale1 & yScale1 domain after data loaded
    yScale1.domain([
      0,d3.max(data,d => d.cumCasesByPublishDate),]);

    xScale1.domain(
      d3.extent(data,d => d.date)
    );

    // Area  generator
    const area = d3
      .area()
      .curve(d3.curveStepAfter)
      .x((d) => xScale1(d.date))
      .y1((d) => yScale1(d.cumCasesByPublishDate))
      .y0(yScale1(0));

    g1.append('path')
      .datum(data)
      .attr('d',area)
      .classed('placeholder-layer',true)
      .style('fill','#dadada')
      .style('opacity','0.3');

    // clipPath for areachart fill animation
    const clip = g1.append('clipPath').attr('id','clip');
    const clipRect = clip.append('rect').attr('width',0).attr('height',750);

    g1.append('path')
      .datum(data)
      .attr('d',area)
      .attr('clip-path','url(#clip)')
      .classed('overlay-layer','yellow')
      .style('opacity','0.3');

    const format = d3.timeFormat("%B %d,%Y");
    const duration = 10000;
    g1.append('line')
      .attr('stroke-width',5)
      .style('stroke','black')
      .attr('x1',xScale1.range()[0])
      .attr('x2',xScale1.range()[0])
      .attr('y1',yScale1.range()[0])
      .attr('y2',yScale1.range()[1])
      .transition()
      .duration(duration)
      .ease(d3.easeLinear)
      .attr('x1',xScale1.range()[1])
      .attr('x2',xScale1.range()[1])

    g1.append('text')
      .attr('x',xScale1.range()[0])
      .attr('y',marginBottom / 2)
      .attr('text-anchor','middle')
      .transition()
      .duration(duration)
      .ease(d3.easeLinear)
      .attr('x',xScale1.range()[1])
      .tween('text',function() {
        const i = d3.interpolateDate(xScale1.domain()[0],xScale1.domain()[1]);
        return (t) => d3.select(this).text(format(i(t)));
      })
  })
  // if there's an error,log it
  .catch((error) => console.log(error));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<section id="map">
  <div id="visualisation-container">
    <div id="visualisation"></div>
    <div id="areachart"></div>
  </div>
</section>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...