【问题标题】:d3js v4: independent multiple axes scaling and panningd3js v4:独立的多轴缩放和平移
【发布时间】:2017-01-15 18:59:05
【问题描述】:

我正在尝试实现一个图表框架,该框架能够为每个方向创建具有多个轴的折线图和面积图,即左侧 2-y 轴、右侧 1-y 轴和底部 1-x 轴。

我必须工作。我的下一个任务是实现图表的缩放行为。我缩进了全局缩放行为,如果用户在绘图区域内使用鼠标,则会触发该行为。显示的系列将重新缩放,并且可以平移绘图。这个我也得上班。

此外,我希望每个轴都有一个独立的缩放/缩放。我得到了缩放,但是全局缩放和平移仍然存在问题。如果我缩放一个轴,绘图区域中的相关系列会重新缩放,但平移不起作用。在轴的独立缩放之后,如果我使用全局重新缩放,缩放会重置,然后通过全局缩放行为进行缩放。

在 d3.js 页面上,我找到了一个简单的 example 用于独立和全局缩放和平移,但使用 d3v3 编写。

我以这种方式更改了示例,以便它显示我的问题jsfiddle demo。在坐标轴和绘图区域中使用鼠标。

<!DOCTYPE html>
<html>
  <head>
    <title>TODO supply a title</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Independent Axis Zooms on x, y, or xy</title>
    <script src="//d3js.org/d3.v4.min.js"></script>
    <style>
        .axis path, .axis line {
            fill: none;
            stroke: #000;
            shape-rendering: crispEdges;
        }
    </style>
</head>
<body>
    <div id="chart"></div>
    <script>


        var data = [];
        for (var i = 0; i < 100; i++) {
            data.push([Math.random(), Math.random()]);
        }
        var svg = d3.select('#chart')
                .append("svg")
                .attr("width", window.innerWidth).attr("height", window.innerHeight);

        function example(svg, data) {
            var svg;
            var margin = {
                top: 60,
                bottom: 80,
                left: 60,
                right: 0
            };
            var width = 500;
            var height = 400;
            var xaxis = d3.axisBottom();
            var yaxis = d3.axisLeft();
            var xscale = d3.scaleLinear();
            var yscale = d3.scaleLinear();
            var xcopyScale, ycopyScale;
            var xyzoom, xzoom, yzoom;
            updateZooms();





            function update() {

                var gs = svg.select("g.scatter");

                var circle = gs.selectAll("circle")
                        .data(data);

                circle.enter().append("svg:circle")
                        .attr("class", "points")
                        .style("fill", "steelblue")
                        .attr("cx", function (d) {
                            return X(d);
                        })
                        .attr("cy", function (d) {
                            return Y(d);
                        })
                        .attr("r", 4);

                circle.attr("cx", function (d) {
                    return X(d);
                })
                        .attr("cy", function (d) {
                            return Y(d);
                        });

                circle.exit().remove();
            }

            function updateZooms() {
                xyzoom = d3.zoom()
                        .on("zoom", function () {
                            xaxis.scale(d3.event.transform.rescaleX(xscale));
                            yaxis.scale(d3.event.transform.rescaleY(yscale));
                            draw();
                        });

                xzoom = d3.zoom()
                        .on("zoom", function () {
                            xaxis.scale(d3.event.transform.rescaleX(xscale));
                            draw();
                        });

                yzoom = d3.zoom()
                        .on("zoom", function () {
                            yaxis.scale(d3.event.transform.rescaleY(yscale));
                            draw();
                        });
            }

            function draw() {
                svg.select('g.x.axis').call(xaxis);
                svg.select('g.y.axis').call(yaxis);
                update();
                // After every draw, we reinitialize zoom. After every zoom, we reexecute draw, which will reinitialize zoom.
                // This is how we can apply multiple independent zoom behaviors to the scales.
                // (Note that the zoom behaviors will always end up with zoom at around 1.0, and translate at around [0,0])
                svg.select('rect.zoom.xy.box').call(xyzoom);
                svg.select('rect.zoom.x.box').call(xzoom);
                svg.select('rect.zoom.y.box').call(yzoom);
            }
            // X value to scale
            function X(d) {
                return xaxis.scale() !== undefined && xaxis.scale() !== null
                        ? xaxis.scale()(d[0])
                        : xscale(d[0]);
            }

            // Y value to scale
            function Y(d) {
                return yaxis.scale() !== undefined && yaxis.scale() !== null
                        ? yaxis.scale()(d[1])
                        : yscale(d[1]);
            }


            var g = svg.append('g')
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            g.append("defs").append("clipPath")
                    .attr("id", "clip")
                    .append("rect")
                    .attr("width", width - margin.left - margin.right)
                    .attr("height", height - margin.top - margin.bottom);

            g.append("svg:rect")
                    .attr("class", "border")
                    .attr("width", width - margin.left - margin.right)
                    .attr("height", height - margin.top - margin.bottom)
                    .style("stroke", "black")
                    .style("fill", "none");

            g.append("g").attr("class", "x axis")
                    .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")");

            g.append("g").attr("class", "y axis");

            g.append("g")
                    .attr("class", "scatter")
                    .attr("clip-path", "url(#clip)");

            g
                    .append("svg:rect")
                    .attr("class", "zoom xy box")
                    .attr("width", width - margin.left - margin.right)
                    .attr("height", height - margin.top - margin.bottom)
                    .style("visibility", "hidden")
                    .attr("pointer-events", "all")
                    .call(xyzoom);

            g
                    .append("svg:rect")
                    .attr("class", "zoom x box")
                    .attr("width", width - margin.left - margin.right)
                    .attr("height", height - margin.top - margin.bottom)
                    .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")")
                    .style("visibility", "hidden")
                    .attr("pointer-events", "all")
                    .call(xzoom);

            g
                    .append("svg:rect")
                    .attr("class", "zoom y box")
                    .attr("width", margin.left)
                    .attr("height", height - margin.top - margin.bottom)
                    .attr("transform", "translate(" + -margin.left + "," + 0 + ")")
                    .style("visibility", "hidden")
                    .attr("pointer-events", "all")
                    .call(yzoom);

            // Update the x-axis
            xscale.domain(d3.extent(data, function (d) {
                return d[0];
            })).range([0, width - margin.left - margin.right]);

            xaxis.scale(xscale)
                    .tickPadding(10);

            svg.select('g.x.axis').call(xaxis);

            // Update the y-scale.
            yscale.domain(d3.extent(data, function (d) {
                return d[1];
            })).range([height - margin.top - margin.bottom, 0]);

            yaxis.scale(yscale)
                    .tickPadding(10);

            svg.select('g.y.axis').call(yaxis);

            draw();

        }

        var exampleChart = example(svg, data);
    </script>
  </body>
</html>

简而言之:如何通过使用 d3v4 创建具有多个轴且具有全局和独立缩放和平移行为的图表来解决我的问题?

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    截至目前,d3v4 的当前版本本身并不支持多个独立的缩放行为。

    一种可能的解决方案是重置存储在您调用适当缩放行为的选择中的内部转换状态。 这个论点已经有一个open issue,我鼓励你去阅读它并提供你的意见。

    祝你好运!

    【讨论】:

      【解决方案2】:

      似乎没有正确的解决方案(见https://github.com/d3/d3-zoom/issues/48)。

      But if you clear the scale after each zoom it seems to work (见https://jsfiddle.net/DaWa/dLmp8zk8/2/)。

      【讨论】:

        猜你喜欢
        • 2018-01-23
        • 1970-01-01
        • 2021-12-22
        • 1970-01-01
        • 2015-10-21
        • 2017-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多