如何使用缩放和平移在 d3.js 中绘制网格线
How do I draw gridlines in d3.js with zoom and pan
我已经能够制作具有缩放和平移功能的散点图,其中轴可以正确缩放并且一切正常。现在我想弄清楚如何添加网格线,但是 运行 遇到了一些问题。我开始只添加 x 轴网格线来解决问题。我附上了一个 fiddle 和一个可以构建的工作示例。
我在生成图表时注释掉了初始网格线,因为它们在缩放后会保留下来导致混乱,稍后我会在工作正常时将它们添加回来。缩放时网格线似乎正确绘制,但它们与 x 轴标签不匹配,并且 x 轴标签在缩放或平移后消失。
如果您注释掉第 163 行并取消注释第 164 行,您可以看到没有任何网格线的基本图形。单击绘图按钮将始终生成一个新图形。我留下了一些注释掉的代码,这些代码是我尝试通过 Whosebug 搜索的不同内容。
示例使用 d3.js - 5.9.2
JSFiddle:https://jsfiddle.net/eysLvqkh/11/
HTML:
<div id="reg_plot"></div>
<button id="b" class="myButton">plot</button>
Javascript:
var theButton = document.getElementById("b");
theButton.onclick = createSvg;
function createSvg() {
// clear old chart when 'plot' is clicked
document.getElementById('reg_plot').innerHTML = ""
// dimensions
var margin = {top: 20, right: 20, bottom: 30, left: 55},
svg_dx = 1200,
svg_dy =600,
chart_dx = svg_dx - margin.right - margin.left,
chart_dy = svg_dy - margin.top - margin.bottom;
// data
var y = d3.randomNormal(400, 100);
var x_jitter = d3.randomUniform(-100, 1400);
var d = d3.range(1000)
.map(function() {
return [x_jitter(), y()];
});
// fill
var colorScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([0, 1]);
// y position
var yScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([chart_dy, margin.top]);
// x position
var xScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[0]; }))
.range([margin.right, chart_dx]);
// y-axis
var yAxis = d3.axisLeft(yScale);
// x-axis
var xAxis = d3.axisBottom(xScale);
// append svg to div element 'reg_plot' and set zoom to our function named 'zoom'
var svg = d3.select("#reg_plot")
.append("svg")
.attr("width", svg_dx)
.attr("height", svg_dy);
svg.call(d3.zoom().on("zoom", zoom));
// clip path - sets boundaries so points will not show outside of the axes when zooming/panning
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(75, 0)")
.attr("clip-path", "url(#clip)")
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
// add y-axis
var y_axis = svg.append("g")
.attr("id", "y_axis")
.attr("transform", "translate(75,0)")
.call(yAxis).style("font-size", "10px")
// add x-axis
var x_axis = svg.append("g")
.attr("id", "x_axis")
.attr("transform", `translate(${margin.left}, ${svg_dy - margin.bottom - margin.top})`)
.call(xAxis).style("font-size", "10px")
// add x and y grid lines
x_axis.call(xAxis.scale(xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(yScale).ticks(20).tickSize(-chart_dx));
function zoom(e) {
// re-scale y axis during zoom
y_axis.transition()
.duration(50)
.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
// re-scale x axis during zoom
x_axis.transition()
.duration(50)
.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
// re-draw circles using new scales
var new_xScale = d3.event.transform.rescaleX(xScale);
var new_yScale = d3.event.transform.rescaleY(yScale);
// re-scale axes and gridlines
x_axis.call(xAxis.scale(new_xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(new_yScale).ticks(20).tickSize(-chart_dx));
circles.data(d)
.attr('cx', function(d) {return new_xScale(d[0])})
.attr('cy', function(d) {return new_yScale(d[1])});
}
}
对于任何正在寻找的人,我已经解决了这个问题。我已经更新了原来的post中的javascript,并更新了jsfiddle。如果您将此代码复制到您使用 d3.js 7.4.4 或更高版本的本地计算机,那么您需要将 d3.event.transform... 的行更改为 e.transform。
我已经能够制作具有缩放和平移功能的散点图,其中轴可以正确缩放并且一切正常。现在我想弄清楚如何添加网格线,但是 运行 遇到了一些问题。我开始只添加 x 轴网格线来解决问题。我附上了一个 fiddle 和一个可以构建的工作示例。
我在生成图表时注释掉了初始网格线,因为它们在缩放后会保留下来导致混乱,稍后我会在工作正常时将它们添加回来。缩放时网格线似乎正确绘制,但它们与 x 轴标签不匹配,并且 x 轴标签在缩放或平移后消失。
如果您注释掉第 163 行并取消注释第 164 行,您可以看到没有任何网格线的基本图形。单击绘图按钮将始终生成一个新图形。我留下了一些注释掉的代码,这些代码是我尝试通过 Whosebug 搜索的不同内容。
示例使用 d3.js - 5.9.2
JSFiddle:https://jsfiddle.net/eysLvqkh/11/
HTML:
<div id="reg_plot"></div>
<button id="b" class="myButton">plot</button>
Javascript:
var theButton = document.getElementById("b");
theButton.onclick = createSvg;
function createSvg() {
// clear old chart when 'plot' is clicked
document.getElementById('reg_plot').innerHTML = ""
// dimensions
var margin = {top: 20, right: 20, bottom: 30, left: 55},
svg_dx = 1200,
svg_dy =600,
chart_dx = svg_dx - margin.right - margin.left,
chart_dy = svg_dy - margin.top - margin.bottom;
// data
var y = d3.randomNormal(400, 100);
var x_jitter = d3.randomUniform(-100, 1400);
var d = d3.range(1000)
.map(function() {
return [x_jitter(), y()];
});
// fill
var colorScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([0, 1]);
// y position
var yScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([chart_dy, margin.top]);
// x position
var xScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[0]; }))
.range([margin.right, chart_dx]);
// y-axis
var yAxis = d3.axisLeft(yScale);
// x-axis
var xAxis = d3.axisBottom(xScale);
// append svg to div element 'reg_plot' and set zoom to our function named 'zoom'
var svg = d3.select("#reg_plot")
.append("svg")
.attr("width", svg_dx)
.attr("height", svg_dy);
svg.call(d3.zoom().on("zoom", zoom));
// clip path - sets boundaries so points will not show outside of the axes when zooming/panning
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(75, 0)")
.attr("clip-path", "url(#clip)")
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
// add y-axis
var y_axis = svg.append("g")
.attr("id", "y_axis")
.attr("transform", "translate(75,0)")
.call(yAxis).style("font-size", "10px")
// add x-axis
var x_axis = svg.append("g")
.attr("id", "x_axis")
.attr("transform", `translate(${margin.left}, ${svg_dy - margin.bottom - margin.top})`)
.call(xAxis).style("font-size", "10px")
// add x and y grid lines
x_axis.call(xAxis.scale(xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(yScale).ticks(20).tickSize(-chart_dx));
function zoom(e) {
// re-scale y axis during zoom
y_axis.transition()
.duration(50)
.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
// re-scale x axis during zoom
x_axis.transition()
.duration(50)
.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
// re-draw circles using new scales
var new_xScale = d3.event.transform.rescaleX(xScale);
var new_yScale = d3.event.transform.rescaleY(yScale);
// re-scale axes and gridlines
x_axis.call(xAxis.scale(new_xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(new_yScale).ticks(20).tickSize(-chart_dx));
circles.data(d)
.attr('cx', function(d) {return new_xScale(d[0])})
.attr('cy', function(d) {return new_yScale(d[1])});
}
}
对于任何正在寻找的人,我已经解决了这个问题。我已经更新了原来的post中的javascript,并更新了jsfiddle。如果您将此代码复制到您使用 d3.js 7.4.4 或更高版本的本地计算机,那么您需要将 d3.event.transform... 的行更改为 e.transform。