您好, 我正在通过d3.js数据绘图。下图提供了两个更好理解的示例。考虑到我试图在特定区域(红色区域)上绘制数据。在图1中,我很容易在d3中指定范围,
var x = d3.scale.linear().domain([a,b]).range([0, 100 ])
var y = d3.scale.linear().domain([a,b]).range([100, 0 ])
使用该范围,我可以在红色内的任何区域绘制数据,用于图一。
但同样的范围机制不能用于绘制第二图的红色区域,因为顶部的x值与底部的x值不同。
有没有办法指定d3的区域范围来在这些自定义形状上绘制数据?
答案 0 :(得分:0)
这是一个非常有趣的问题。不幸的是,D3没有本地方法来做你想要的。但是,这可以创建自定义函数,根据x
位置返回修改后的y
位置。
有几种不同的方法可以做到这一点。在我的解决方案中,我将以这种格式传递给函数一个完整的对象:
{x: someValue, y: someValue}
您可能需要根据数据结构更改功能,这并不重要。这里重要的是一般的想法。
嗯,这是功能:
function calculateXPos(obj) {
var verticalScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 20]);
var horizontalScale = d3.scaleLinear()
.domain([0, 100]);
horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);
return horizontalScale(obj.x);
}
它做了什么?
如您所见,该函数将参数作为参数,具有两个属性x
和y
。使用线性D3刻度......
var verticalScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 20]);
...该函数根据点的y
位置计算范围的变化......
horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);
...并返回具有自定义范围的x
位置:
return horizontalScale(obj.x);
正如您所看到的,该函数中有许多硬编码值,如垂直标度的范围和水平标度中的差异(也作为范围)。同样,这只是为了证明一般的想法,价值可以改变。
让我们看看它有效。第一步是在上述结构中创建数据。为此,我有这两个循环:
var data = [];
for (var i = 0; i < 11; i++) {
for (var j = 0; j < 11; j++) {
data.push({
x: i * 10,
y: j * 10
});
}
}
这会创建一个方阵。如果我们只是使用正常的常规D3比例绘制这些点,这就是我们得到的结果:
var svg = d3.select("svg");
var data = [];
for (var i = 0; i < 11; i++) {
for (var j = 0; j < 11; j++) {
data.push({
x: i * 10,
y: j * 10
});
}
}
var yScale = d3.scaleLinear()
.domain([0, 100])
.range([100, 0]);
var xScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 100]);
var gX = svg.append("g").attr("transform", "translate(30,130)").call(d3.axisBottom(xScale).ticks(5));
var gY = svg.append("g").attr("transform", "translate(30,30)").call(d3.axisLeft(yScale).ticks(5));
var g = svg.append("g").attr("transform", "translate(30,30)");
var points = g.selectAll("foo")
.data(data)
.enter()
.append("circle")
.attr("fill", "firebrick")
.attr("r", 2)
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
但是,如果我们使用我们的函数(传递整个对象d
),这就是我们得到的:
var svg = d3.select("svg");
var data = [];
for (var i = 0; i < 11; i++) {
for (var j = 0; j < 11; j++) {
data.push({
x: i * 10,
y: j * 10
});
}
}
var yScale = d3.scaleLinear()
.domain([0, 100])
.range([100, 0]);
var xScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 100]);
var gX = svg.append("g").attr("transform", "translate(30,130)").call(d3.axisBottom(xScale).ticks(5));
var gY = svg.append("g").attr("transform", "translate(30,30)").call(d3.axisLeft(yScale).ticks(5));
var g = svg.append("g").attr("transform", "translate(30,30)");
var points = g.selectAll("foo")
.data(data)
.enter()
.append("circle")
.attr("fill", "firebrick")
.attr("r", 2)
.attr("cx", d => calculateXPos(d))
.attr("cy", d => yScale(d.y));
function calculateXPos(obj) {
var verticalScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 20]);
var horizontalScale = d3.scaleLinear()
.domain([0, 100]);
horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);
return horizontalScale(obj.x);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
您在问题中描述的是梯形。