【问题标题】:Convert d3v6 Observable example using zoom.center使用 zoom.center 转换 d3v6 Observable 示例
【发布时间】:2021-10-02 10:41:14
【问题描述】:

我有一个项目,我正在尝试缩放到特定点。在 d3v3 中,我可以用这个函数做到这一点

function zoomTo(place, pscale) {
  
  projection = d3.geo.mercator()
        .scale((1 << pscale) / 2 / Math.PI)
        .translate([width / 2, height / 2])
    
  center = projection(place);

return zoom
  .scale(projection.scale() * 2 * Math.PI)
  .translate([width - center[0], height - center[1]]);

}

不过,Zoom 已经改变,这在 d3v6 中不再有效。

我在 Observable 上找到了一个使用 d3v6 完全符合我要求的示例: https://observablehq.com/d/9035ed7049aaa8c6

但是,我不确定如何将其翻译成原版 javascript。 下面是我的尝试。我收到此错误:

d3.zoom(...).scaleExtent(...).on(...).center is not a function

不过,它在 Observable 中运行良好,所以很明显我遗漏了一些东西。任何帮助将不胜感激! (另外,我不需要 Observable 示例顶部的按钮,所以我将它们注释掉。)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Zoom to Point</title>
    <script src="https://files-7y4qaclbi.vercel.app/d3-zoom.js"></script>
    <script src="https://d3js.org/d3.v6.min.js"></script>

</head>

<body>
    <script>

        // const form = html`<form>
        //   <button name="in" type="button">Zoom In</button>
        //   <button name="out" type="button">Zoom Out</button>
        //   <button name="random" type="button">Random</button>
        //   <button name="reset" type="button">Reset</button>
        // </form>`;
        //   form.in.onclick = () => chart.zoomIn();
        //   form.out.onclick = () => chart.zoomOut();
        //   form.random.onclick = () => chart.zoomRandom();
        //   form.reset.onclick = () => chart.zoomReset();
        //   return form;

        const radius = 6

        const step = radius * 5

        const width = 500
        const height = 500

        const theta = Math.PI * (3 - Math.sqrt(5))

        const data = Array.from({ length: 1000 }, (_, i) => {
            const radius = step * Math.sqrt(i += 0.5), a = theta * i;
            return [
                width / 2 + radius * Math.cos(a),
                height / 2 + radius * Math.sin(a)
            ];
        })

        const quadtree = d3.quadtree()
            .addAll(data)

        // let mutable debug = undefined;

        let focussed;

        function findCloser(that, coords) {
            const p = d3.zoomTransform(that).invert(coords);
            focussed = quadtree.find(p[0], p[1]);
            return d3.zoomTransform(that).apply(focussed);
        }

        const zoom = d3
            .zoom()
            .scaleExtent([1, 40])
            .on("zoom", zoomed)
            .center(function (event, d) {
                // mutable debug = { event, d, r: Math.random() };
                let coords = d3.pointer(event, this);
                focussed = null;

                if (event.deltaY < 0) {
                    coords = findCloser(this, coords);
                }

                g.selectAll("circle").attr("r", p =>
                    p == focussed ? radius + 3 : radius
                );

                return coords;
            });

        const svg = d3.select('body').append("svg")
            .attr('width', width)
            .attr('height', height)
            .on("click", reset);

        const g = svg.append("g");

        g.selectAll("circle")
            .data(data)
            .join("circle")
            .attr("cx", ([x]) => x)
            .attr("cy", ([, y]) => y)
            .attr("r", radius)
            .attr("fill", (d, i) => d3.interpolateRainbow(i / 360))
            .on("click", clicked);

        svg.datum("I'm your worst datum").call(zoom); //.on("mousemove", mousemove);

        function random() {
            const [x, y] = data[Math.floor(Math.random() * data.length)];
            svg
                .transition()
                .duration(2500)
                .call(
                    zoom.transform,
                    d3.zoomIdentity
                        .translate(width / 2, height / 2)
                        .scale(40)
                        .translate(-x, -y)
                );
        }

        function reset() {
            svg
                .transition()
                .duration(750)
                .call(
                    zoom.transform,
                    d3.zoomIdentity,
                    d3.zoomTransform(svg.node()).invert([width / 2, height / 2])
                );
        }

        function clicked(event, [x, y]) {
            event.stopPropagation();
            svg
                .transition()
                .duration(750)
                .call(
                    zoom.transform,
                    d3.zoomIdentity
                        .translate(width / 2, height / 2)
                        .scale(40)
                        .translate(-x, -y),
                    d3.pointer(event, svg.node())
                );
        }

        function zoomed(event) {
            g.attr("transform", event.transform);
        }

        // return Object.assign(svg.node(), {
        //     zoomIn: () =>
        //         svg
        //             .transition()
        //             .call(zoom.scaleBy, 2, findCloser(svg.node(), [width / 2, height / 2])),
        //     zoomOut: () => svg.transition().call(zoom.scaleBy, 0.5),
        //     zoomRandom: random,
        //     zoomReset: reset
        // });
    </script>

</body>

</html>

如果有帮助,它也在 Plunker 中:https://plnkr.co/edit/JaiKhTgEXzIFWiar?open=lib%2Fscript.js

【问题讨论】:

    标签: javascript d3.js zooming


    【解决方案1】:

    在任何 d3-zoom 版本中都没有 zoom.center,从第一个版本到当前版本(撰写本文时为 v3.0.0)。

    zoom.center 方法是由 Observable 的作者创建的,该作者为 D3 (see here) 做出了积极贡献。您可以在此处查看提案:https://github.com/d3/d3-zoom/pull/212

    但是,如果您检查the code the author is using,您会发现添加自己的center 方法并不复杂。您只需要:

    zoom.center = function(_) {
        return arguments.length ? (center = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), zoom) : center;
      };
    

    ...和...

    function defaultCenter(event) {
      return d3Selection.pointer(event, this);
    }
    

    您可以通过查看该文件找到几个center.apply(this, arguments)

    【讨论】:

    • 好吧,好吧,我知道你写了 in any d3-zoom release .不过,为了完整起见,公平地注意到 v3 中有一个 zoom.center() 方法用于处理鼠标滚轮动作。该方法看起来类似于您提到的实现,但只能处理常量值。
    猜你喜欢
    • 2018-02-22
    • 2021-04-08
    • 2020-04-02
    • 2019-03-24
    • 2021-05-24
    • 1970-01-01
    • 2021-06-22
    • 2019-07-27
    • 1970-01-01
    相关资源
    最近更新 更多