d3.js - 如何创建具有垂直线和不同背景的折线图?
问题描述
我需要创建一个带有显示边框的垂直线的折线图。左边应该涂成红色,右边涂成绿色,分别:
我开始在库中寻找示例,但没有示例……我在 D3 上做了一个相似之处。但我只能绘制图形和垂直线,无法填充部分并显示图例。请告诉我,如何创建这种类型的时间表?有没有现成的实施方案?我的代码中没有涂漆的区域并且没有图例。
// https://plnkr.co/edit/9tnP6l15dqmCaOAK8Ojm?p=preview
function drawChart(data) {
var svgWidth = 600,
svgHeight = 400;
var margin = { top: 20, right: 20, bottom: 30, left: 50 };
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select('svg')
.attr("width", svgWidth)
.attr("height", svgHeight);
// Grouping element with margins
var g = svg.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")"
);
var x = d3.scaleLinear().rangeRound([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date)})
.y(function(d) { return y(d.value)})
x.domain(d3.extent(data, function(d) { return d.date }));
y.domain(d3.extent(data, function(d) { return d.value }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(0)")
.attr("y", 0)
.attr("dx", "50em")
.attr("dy", "-0.5em")
.attr("text-anchor", "start")
.text("Title ($)");
// Text for Y axes
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1)
.attr("d", line);
g.append("line")
.attr("x1", 300)
.attr("y1", 0)
.attr("x2", 300)
.attr("y2", 350)
.style("stroke-width", 2)
.style("stroke", "red")
.style("fill", "black");
}
document.addEventListener("DOMContentLoaded", function(event) {
var parsedData = [{
date: 0,
value: 10
}, {
date: 0,
value: 1000
}, {
date: 200,
value: 2400
}, {
date: 300,
value: 4600
}, {
date: 400,
value: 5600
}, {
date: 500,
value: 7777
}];
drawChart(parsedData);
});
解决方案
有不同的方法来创建它,比如用相同的数据绘制两条路径并使用一个<clipPath>
例子。
但我认为最简单的方法就是为每条路径使用不同的数据。按照这种方法,我们只需要设置区域生成器...
var area = d3.area()
.x(function(d) { return x(d.date)})
.y1(function(d) { return y(d.value)})
.y0(y(0));
...并附加路径,根据边界过滤数据(此处命名为border
):
g.append("path")
.datum(data.filter(function(d) {
return d.date <= border;
}))
.attr("fill", "red")
.attr("d", area);
g.append("path")
.datum(data.filter(function(d) {
return d.date >= border;
}))
.attr("fill", "green")
.attr("d", area);
这是使用您的代码的演示:
var data = [{
date: 0,
value: 1000
}, {
date: 200,
value: 2400
}, {
date: 300,
value: 4600
}, {
date: 400,
value: 5600
}, {
date: 500,
value: 7777
}];
var svgWidth = 600,
svgHeight = 400;
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
};
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select('svg')
.attr("width", svgWidth)
.attr("height", svgHeight);
// Grouping element with margins
var g = svg.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")"
);
var x = d3.scaleLinear().rangeRound([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var border = 300;
var line = d3.line()
.x(function(d) {
return x(d.date)
})
.y(function(d) {
return y(d.value)
});
var area = d3.area()
.x(function(d) {
return x(d.date)
})
.y1(function(d) {
return y(d.value)
})
.y0(y(0));
x.domain(d3.extent(data, function(d) {
return d.date
}));
y.domain([0, d3.max(data, function(d) {
return d.value
})]);
g.append("path")
.datum(data.filter(function(d) {
return d.date <= border;
}))
.attr("fill", "red")
.attr("d", area);
g.append("path")
.datum(data.filter(function(d) {
return d.date >= border;
}))
.attr("fill", "green")
.attr("d", area);
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 2)
.attr("d", line);
g.append("line")
.attr("x1", x(border))
.attr("y1", 0)
.attr("x2", x(border))
.attr("y2", 350)
.style("stroke-width", 2)
.style("stroke", "blue");
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(0)")
.attr("y", 0)
.attr("dx", "50em")
.attr("dy", "-0.5em")
.attr("text-anchor", "start")
.text("Title ($)");
// Text for Y axes
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
请记住,这个简单的代码有效,因为在您的示例中,限制(即300
)实际上是一个数据点。如果不是这种情况(例如,限制是280
但两个相邻数据点是250
和300
),您将需要一个更复杂的算法来创建两个单独的数据集。
推荐阅读
- java - Java搜索字符串然后复制和替换
- android - 具有约束布局的 ScrollView
- azure - 将 Azure 虚拟网络移动到另一个资源组
- acumatica - 将 PXUIFieldAttribute.SetEnabled 重写为 PXUIEnabledAttribute
- c# - 如何基于反序列化的 json 设置类?
- javascript - 访问 JSON-LD 对象会产生错误是 Google 结构数据测试工具
- php - 带有 LIKE 的 Symfony Sonata SEO 自定义 sql 查询
- qt - 在 qlabel 中画圆(显示图像流相机)
- javascript - 修复了容器中的右侧边栏,引导程序
- spring-batch - 如何在春季批处理中阅读带有注释的行#