在区域图 d3 中的路径末尾附加一条线
Append a line to an end of a path in area chart d3
我正在尝试将一条线附加到面积图路径的末尾。我所在领域最困难的部分是动画。我有一个 clipPath,其宽度从 width: 0
转换为 width: 960
,末尾的行也随之同步,因此应该同步。此外,该行顶部的文本需要在其进行时进行更新。
期望的输出:
我最初的想法是建立一个图表区域并添加一个 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, 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>
我只使用一条线,没有横条,然后使用 transition.tween
with d3.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', 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>
我正在尝试将一条线附加到面积图路径的末尾。我所在领域最困难的部分是动画。我有一个 clipPath,其宽度从 width: 0
转换为 width: 960
,末尾的行也随之同步,因此应该同步。此外,该行顶部的文本需要在其进行时进行更新。
期望的输出:
我最初的想法是建立一个图表区域并添加一个 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, 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>
我只使用一条线,没有横条,然后使用 transition.tween
with d3.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', 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>