d3 使用画布偏移时缩放不同步

问题描述 投票:0回答:1

我正在尝试创建一个具有缩放和边距的画布图,以便我有空间来绘制轴。但是我注意到,当我添加较大的左边距时,例如

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>

注意:我想要在画布本身内留出边距的原因是这样我可以在其上绘制轴(我将其省略以最小化示例代码)

d3.js canvas
1个回答
0
投票

修复方法是考虑利润,如下所示:


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);
}
© www.soinside.com 2019 - 2024. All rights reserved.