简体   繁体   中英

Append a line to an end of a path in area chart d3

I'm trying to append a line to an end of an area chart path. The most difficult part my area is animated. I have a clipPath which width being transformed from width: 0 to width: 960 and the line at the end goes along with it so shoud be synchronised. Also the text on top of that line needs to be updated while it goes along.

Desired output:

在此处输入图片说明

My initial idea was to build a chart area and add a clipPath and then add a bar chart inside of area chart so I can update my text based on the bar appended, however bars are not inside my area chart. What am I doing wrong to place bars inside area chart or is there a better solution to this?

 // 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, 200)) .attr('d', area) .attr('clip-path', 'url(#clip)') .classed('overlay-layer', true) .style('fill', '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, d3.max(data.data, function(d) { return +d.cumCasesByPublishDate; }), ]); 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>

I'd just use a line, no bars, and use transition.tween with d3.interpolateDate to make the text change.

 // 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', true) .style('fill', '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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM