我正在尝试创建一个具有缩放和边距的画布图,以便我有空间来绘制轴。但是我注意到,当我添加较大的左边距时,例如
const margin = { top: 20, right: 20, bottom: 40, left: 600 };
并尝试放大,变焦完全关闭。当我尝试放大左侧时(例如尝试放大第一个正弦波的顶部),这一点尤其明显。有明显的偏移。我不知道这里可能出了什么问题/如何修复它。我想我可能必须考虑 onZoom
函数中变换对象的边距,但不知道如何做到这一点。
这是一个最小的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<canvas id="lineCanvas"></canvas>
<script>
const canvas = document.getElementById('lineCanvas');
const context = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const margin = { top: 20, right: 20, bottom: 40, left: 600 };
const width = canvas.width - margin.left - margin.right;
const height = canvas.height - margin.top - margin.bottom;
const data = Array.from({ length: 1000 }, (_, i) => ({
x: i / 100,
y: Math.sin(i / 100)
}));
const xScale = d3.scaleLinear().domain([0, 10]).range([0, width]);
const yScale = d3.scaleLinear().domain([-1, 1]).range([height, 0]);
const zoom = d3.zoom()
.scaleExtent([0.5, 100])
.on("zoom", onZoom);
d3.select(canvas).call(zoom);
function drawPlot(transform = d3.zoomIdentity) {
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(margin.left, margin.top);
const zoomedXScale = transform.rescaleX(xScale);
const zoomedYScale = transform.rescaleY(yScale);
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "steelblue";
data.forEach((point, i) => {
const x = zoomedXScale(point.x);
const y = zoomedYScale(point.y);
if (i === 0) {
context.moveTo(x, y);
} else {
context.lineTo(x, y);
}
});
context.stroke();
context.restore();
}
function onZoom(event) {
drawPlot(event.transform);
}
drawPlot();
</script>
</body>
</html>
注意:我想要在画布本身内留出边距的原因是这样我可以在其上绘制轴(我将其省略以最小化示例代码)
修复方法是考虑利润,如下所示:
function onZoom(event) {
const transform = d3.zoomIdentity
.translate(event.transform.x + ((margin.left * event.transform.k) - margin.left),
event.transform.y + ((margin.top * event.transform.k) - margin.top))
.scale(event.transform.k);
drawPlot(transform);
}