如何将值传递给D3中的行生成函数 [英] How to pass a value to line generation function in D3
问题描述
以下代码用于在D3中生成行:
Following code is used to generate lines in D3:
var lineFn = d3.line()
.x((d) => this.base.xAxis.scale(d.x))
.y((d) => this.base.yAxes[0].scale(d.y));
// series is a collection of lines I want to plot
series = [
{
data: [{x: 10, y: 20}, {x: 20, y: 30}],
yAxis: 0, // this indicates which y-axis to use
color: red
},
...
];
_.forEach(series, (line) => {
this.base.chart.append("path")
.datum(line.data)
.attr("class", "line")
.attr("d", lineFn)
.style("stroke", line.color)
});
我的图表使用d3.axisLeft()
和d3.axisRight()
使用双y轴.
My chart uses dual y-axes using d3.axisLeft()
and d3.axisRight()
.
现在,我正在硬编码要在lineFn
中使用的y-axis
的值.
Right now, I am hardcoding the value of which y-axis
to use in the lineFn
.
.y((d) => this.base.yAxes[0].scale(d.y)); // 0-left axis, 1-right axis
我想做的就是在调用line函数时传递该值,例如:
What I would like to do is pass that value when I call the line function, something like:
.attr("d", lineFn(line.yAxis))
有什么办法可以做到这一点?
Is there any way to achieve this?
谢谢.
推荐答案
最简单的方法是创建两个不同的行生成器.
The easiest way to achieve what you want is simply creating two different line generators.
但是,由于您问(不是逐字)在调用行生成器时是否可以动态定义比例尺?" ,答案是:是的,有可能.让我们看看如何做到这一点.
However, since you asked (not verbatim) "is it possible to define the scale dynamically when calling the line generator?", the answer is: yes, it is possible. Let's see how to do it.
在此示例中,我使用一个对象来存储不同的比例尺:
In this example, I'm using an object to store the different scales:
var scales = {
yScaleLeft: d3.scaleLinear()
.domain([0, 100])
.range([170, 30]),
yScaleRight: d3.scaleLinear()
.domain([0, 200])
.range([170, 30])
};
然后,在数据集中,定义每行应使用的比例尺和颜色,就像您做的一样:
And, in the dataset, defining which scale and color should be used for each line, just as you did:
var data = [{
data: [{
x: 1,
y: 20
}, {
...
}, {
x: 8,
y: 50
}],
yAxis: "yScaleLeft",
color: "red"
}, {
data: [{
x: 3,
y: 120
}, {
...
}, {
x: 9,
y: 180
}],
yAxis: "yScaleRight",
color: "blue"
}];
然后,当调用行生成器时,我们设置一个变量(在本例中为thisScale
)来指定比例尺:
Then, when calling the line generator, we set a variable (in this case, thisScale
) to specify the scale:
var thisScale;
paths.attr("stroke", d => d.color)
.attr("d", d => {
thisScale = scales[d.yAxis]
return line(d.data);
})
.attr("fill", "none");
这里是演示,红线使用从0到100的比例尺,蓝线使用从0到200的比例尺.
Here is the demo, the red line uses a scale going from 0 to 100, the blue line uses a scale going from 0 to 200:
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 200);
var thisScale;
var line = d3.line()
.x(d => xScale(d.x))
.y(d => thisScale(d.y))
.curve(d3.curveMonotoneX);
var data = [{
data: [{
x: 1,
y: 20
}, {
x: 2,
y: 30
}, {
x: 3,
y: 10
}, {
x: 4,
y: 60
}, {
x: 5,
y: 70
}, {
x: 6,
y: 80
}, {
x: 7,
y: 40
}, {
x: 8,
y: 50
}],
yAxis: "yScaleLeft",
color: "red"
}, {
data: [{
x: 3,
y: 120
}, {
x: 4,
y: 130
}, {
x: 5,
y: 10
}, {
x: 6,
y: 120
}, {
x: 7,
y: 40
}, {
x: 8,
y: 130
}, {
x: 9,
y: 180
}],
yAxis: "yScaleRight",
color: "blue"
}];
var scales = {
yScaleLeft: d3.scaleLinear()
.domain([0, 100])
.range([170, 30]),
yScaleRight: d3.scaleLinear()
.domain([0, 200])
.range([170, 30])
};
var xScale = d3.scalePoint()
.domain(d3.range(11))
.range([30, 470])
var paths = svg.selectAll("foo")
.data(data)
.enter()
.append("path");
paths.attr("stroke", d => d.color)
.attr("d", d => {
thisScale = scales[d.yAxis]
return line(d.data);
})
.attr("fill", "none");
var xAxis = d3.axisBottom(xScale);
var yAxisLeft = d3.axisLeft(scales.yScaleLeft);
var yAxisRight = d3.axisRight(scales.yScaleRight);
var gX = svg.append("g").attr("transform", "translate(0,170)").call(xAxis);
var gY = svg.append("g").attr("transform", "translate(30,0)").call(yAxisLeft);
var gY2 = svg.append("g").attr("transform", "translate(470,0)").call(yAxisRight);
<script src="https://d3js.org/d3.v4.min.js"></script>
这里是相同的解决方案,只是使用数组(而不是对象)来存储比例,如您在问题中所问的那样:
And here the same solution, but using an array (instead of an object) to store the scales, as you asked in your question:
yAxis: 0//indicates the left axis
yAxis: 1//indicates the right axis
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 200);
var thisScale;
var line = d3.line()
.x(d => xScale(d.x))
.y(d => thisScale(d.y))
.curve(d3.curveMonotoneX);
var data = [{
data: [{
x: 1,
y: 20
}, {
x: 2,
y: 30
}, {
x: 3,
y: 10
}, {
x: 4,
y: 60
}, {
x: 5,
y: 70
}, {
x: 6,
y: 80
}, {
x: 7,
y: 40
}, {
x: 8,
y: 50
}],
yAxis: 0,
color: "red"
}, {
data: [{
x: 3,
y: 120
}, {
x: 4,
y: 130
}, {
x: 5,
y: 10
}, {
x: 6,
y: 120
}, {
x: 7,
y: 40
}, {
x: 8,
y: 130
}, {
x: 9,
y: 180
}],
yAxis: 1,
color: "blue"
}];
var scales = [d3.scaleLinear()
.domain([0, 100])
.range([170, 30]), d3.scaleLinear()
.domain([0, 200])
.range([170, 30])
];
var xScale = d3.scalePoint()
.domain(d3.range(11))
.range([30, 470])
var paths = svg.selectAll("foo")
.data(data)
.enter()
.append("path");
paths.attr("stroke", d => d.color)
.attr("d", d => {
thisScale = scales[d.yAxis]
return line(d.data);
})
.attr("fill", "none");
var xAxis = d3.axisBottom(xScale);
var yAxisLeft = d3.axisLeft(scales[0]);
var yAxisRight = d3.axisRight(scales[1]);
var gX = svg.append("g").attr("transform", "translate(0,170)").call(xAxis);
var gY = svg.append("g").attr("transform", "translate(30,0)").call(yAxisLeft);
var gY2 = svg.append("g").attr("transform", "translate(470,0)").call(yAxisRight);
<script src="https://d3js.org/d3.v4.min.js"></script>
这篇关于如何将值传递给D3中的行生成函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!