现实生活场景:我需要在两线图上绘制收入/支出,我需要将上个月的线点缀,以表明它尚未确定,并且可以改变。下面的数据和代码基本上遵循mbostock的多线图示例,有两条路径。
现在,问题是使最后一段加点。我读过关于stroke-dasharrays的内容,并认为这是一个明智的想法,但我不知道如何获得路径中的最后一行“,我发现的每个教程都建议使用行代替,但我不能为我的生活重构我的代码使用我的数据集行。
任何帮助,或重构代码的指示,将不胜感激!谢谢,伙计们。
数据如下所示:
data =
{
{
'type': 'Expense',
'data': [{ 'date': '201401', 'value': 456 }, {}, ...]
},
{
'type': 'Income',
'data': [{ 'date': '201401', 'value': 456 }, {}, ...]
}
}
我使用了mbostock的教程,我的代码如下:
function(data)
{
var self = this;
this.graphWidth = this.container.width() - 200 - this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
this.svg = d3.select('#graphsContainer svg')
.attr('width', this.graphWidth + this.margin.left + this.margin.right)
.attr('height', this.graphHeight + this.margin.top + this.margin.bottom)
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
this.x = d3.time.scale().range([0, this.graphWidth]);
this.y = d3.scale.linear().range([this.graphHeight, 0]);
this.xAxis = d3.svg.axis().scale(this.x).orient('bottom');
this.yAxis = d3.svg.axis().scale(this.y).orient('left');
var parseDate = d3.time.format('%Y%m').parse;
var line = d3.svg.line()
.interpolate('basis')
.x(function(d) { return self.x(d.date); })
.y(function(d) { return self.y(d.value); });
data.forEach(function(kv)
{
kv.data.forEach(function(d) { d.date = parseDate(d.date); });
});
var minX = d3.min(data, function (kv) { return d3.min(kv.data, function (d) { return d.date; }) });
var maxX = d3.max(data, function (kv) { return d3.max(kv.data, function (d) { return d.date; }) });
var minY = d3.min(data, function (kv) { return d3.min(kv.data, function (d) { return d.value; }) });
var maxY = d3.max(data, function (kv) { return d3.max(kv.data, function (d) { return d.value; }) });
this.x.domain([minX, maxX]);
this.y.domain([minY, maxY]);
// x axis
this.svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + this.graphHeight + ')')
.call(this.xAxis);
// y axis
this.svg.append('g')
.attr('class', 'y axis')
.call(this.yAxis);
var value = this.svg.selectAll('.value')
.data(data)
.enter().append('g')
.attr('class', 'value');
var path = value.append('path')
.attr('class', 'line')
.attr('d', function(d) { return line(d.data); })
.style('stroke', function(d) { return d.type == 'Income' ? '#006600' : '#CC0000'; });
value.append('text')
.datum(function(d)
{
return {
name: d.type,
date: d.data[d.data.length - 1].date,
value: d.data[d.data.length - 1].value
};
})
.attr('transform', function(d) { return 'translate(' + self.x(d.date) + ',' + self.y(d.value) + ')'; })
.attr('x', 3)
.attr('dy', '.35em')
.text(function(d) { return d.name; });
},
答案 0 :(得分:0)
从理论上讲,只需设置正确的笔划字符串数组字符串即可解决此问题。像dash-array: 200 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4;
这样的东西。这些显然只是样本值,但想法是有一个非常长的短划线(在这个例子中为200),从时间开始到第二个月到最后一个月结束,然后有一系列破折号( 4 4 4 ...)在路径的其余部分。但是,确定长划线结束的位置可能会变得棘手。您可以使用SVG路径方法getTotalLength()
计算整个路径的长度,然后以某种方式确定沿此长度转换为破折号的位置(即" 200"实际上应该等于)。请记住,这是沿着行的长度,而不是沿着x轴,所以确定找到该点需要考虑到这一点,并且实际上只有在虚线的上个月段是直线时才有效。你可以尝试一下。
或者,d3方式可能是分割路径,而不是2,你有4条路径 - 其中2条路径只是上个月的数据:
expenses = {
'type': 'Expense',
'period': 'past',
'data': [{ 'date': '201401', 'value': 456 }, {}, ...]
}
income = {
'type': 'Expense',
'period': 'past',
'data': [{ 'date': '201401', 'value': 456 }, {}, ...]
}
expensesLast = {
'type': 'Expense',
'period': 'current',
'data': [
expenses.data[expenses.data.length - 2],
expenses.data.pop()// this ALSO removes the last entry from the array above
]
}
incomeLast = {
'type': 'Income'
'period': 'current',
'data': [
income.data[income.data.length - 2],
income.data.pop()// this ALSO removes the last entry from the array above
]
}
data = [ expenses, income, expensesLast, incomeLast]
使用新的data
,您可以像现在一样绘制线条,然后根据它的周期分配stroke-dasharray
:
var path = value.append('path')
.attr('class', 'line')
.attr('d', function(d) { return line(d.data); })
.style('stroke', function(d) {return d.type == 'Income' ? '#006600' : '#CC0000'; });
.style('stroke-dasharray', function(d) {
return d.period == 'current' ? '4 4' : ''; // <--- That!
});