【问题标题】:How to link D3 zoom and pan controls如何链接 D3 缩放和平移控件
【发布时间】:2023-03-08 23:14:02
【问题描述】:

我想将多个图表的缩放和平移控件链接在一起,以便在启用图表平移和缩放控件之一时,它们都可以一起平移和缩放。

我尝试创建单个缩放对象并将其传递给图表,但只有最后一个图表实际平移和缩放。即使我放大他们的区域,其他人仍然保持静止。

这是图表的快照。每个图表都有一个概览图表,其中包含一个也可以移动的视口。我想将所有控件链接在一起,以便每个图表上的视口也相同。

那么,如何在多个图表上链接平移和缩放控件?

这是此代码的 jsfiddle:https://jsfiddle.net/babazaroni/a52oukzn/

这是我的代码:

整体图表创建者。这段代码制作了 3 个图表。

define([
    'd3',
    'components/sl',
    'MockData',
    'components/candlestickSeries',
    'Chart'
], function (d3, sl, MockData,candlestickSeries,Chart) {
    'use strict';




    function generateData()
    {

      var data = new MockData(0.1, 0.1, 100, 50, function (moment) {
        return !(moment.day() === 0 || moment.day() === 6);
      })
      .generateOHLC(new Date(2014, 1, 1), new Date(2014, 8, 1));

      return data;
    }


    var data = generateData();


  	d3.select('#chart1')
      	.datum(data)
    	.call(Chart());

     data = generateData();



    d3.select('#chart1')
        .datum(data)
      .call(Chart());

         data = generateData();


          d3.select('#chart1')
        .datum(data)
      .call(Chart());




});

图表代码如下:

define([
    'd3',
    'components/sl',
    'MockData',
    'components/candlestickSeries'
], function (d3, sl, MockData) {
    'use strict';

    function timeSeriesChart() {

        function chart(selection)
        {
            selection.each(function(data) {


                var minDate = new Date(d3.min(data, function (d) { return d.date; }).getTime() - 8.64e7);
                var maxDate = new Date(d3.max(data, function (d) { return d.date; }).getTime() + 8.64e7);
                var yMin = d3.min(data, function (d) { return d.low; });
                var yMax = d3.max(data, function (d) { return d.high; });



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // The primary chart

                // Set up the drawing area
    
                var margin = {top: 20, right: 20, bottom: 30, left: 35},
                    width = 600 - margin.left - margin.right,
                    height = 200 - margin.top - margin.bottom;

                var plotChart = d3.select(this).classed('chart', true).append('svg')
                    .attr('width', width + margin.left + margin.right)
                    .attr('height', height + margin.top + margin.bottom)
                    .append('g')
                    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

                var plotArea = plotChart.append('g')
                    .attr('clip-path', 'url(#plotAreaClip)');

                plotArea.append('clipPath')
                    .attr('id', 'plotAreaClip')
                    .append('rect')
                    .attr({ width: width, height: height });

                // Scales

                var xScale = d3.time.scale(),
                    yScale = d3.scale.linear();



                // Set scale domains
                xScale.domain([minDate, maxDate]);
                yScale.domain([yMin, yMax]).nice();

                // Set scale ranges
                xScale.range([0, width]);
                yScale.range([height, 0]);

                // Axes

                var xAxis = d3.svg.axis()
                    .scale(xScale)
                    .orient('bottom')
                    .ticks(10);

                var yAxis = d3.svg.axis()
                    .scale(yScale)
                    .orient('left');

                plotChart.append('g')
                    .attr('class', 'x axis')
                    .attr('transform', 'translate(0,' + height + ')')
                    .call(xAxis);

                plotChart.append('g')
                    .attr('class', 'y axis')
                    .call(yAxis);

                plotChart.append("text")
                    .attr("x", (width / 2))             
                    .attr("y", 1 - (margin.top / 2))
                    .attr("text-anchor", "middle")  
                    .style("font-size", "16px") 
                    .style("text-decoration", "underline")  
                    .text("Your title goes here");

                // Data series

                var series = sl.series.candlestick()
                    .xScale(xScale)
                    .yScale(yScale);

                var dataSeries = plotArea.append('g')
                    .attr('class', 'series')
                    .datum(data)
                    .call(series);



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Navigation chart

                var navWidth = width,
                    navHeight = 100 - margin.top - margin.bottom;

                // Set up the drawing area

                var navChart = d3.select(this).classed('chart', true).append('svg')
                    .classed('navigator', true)
                    .attr('width', navWidth + margin.left + margin.right)
                    .attr('height', navHeight + margin.top + margin.bottom)
                    .append('g')
                    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

                // Scales

                var navXScale = d3.time.scale()
                        .domain([
                            new Date(minDate.getTime() - 8.64e7),
                            new Date(maxDate.getTime() + 8.64e7)
                        ])
                        .range([0, navWidth]),
                    navYScale = d3.scale.linear()
                        .domain([yMin, yMax])
                        .range([navHeight, 0]);

                // Axes

                var navXAxis = d3.svg.axis()
                    .scale(navXScale)
                    .orient('bottom');

                navChart.append('g')
                    .attr('class', 'x axis')
                    .attr('transform', 'translate(0,' + navHeight + ')')
                    .call(navXAxis);

                // Data series

                var navData = d3.svg.area()
                    .x(function (d) { return navXScale(d.date); })
                    .y0(navHeight)
                    .y1(function (d) { return navYScale(d.close); });

                var navLine = d3.svg.line()
                    .x(function (d) { return navXScale(d.date); })
                    .y(function (d) { return navYScale(d.close); });

                navChart.append('path')
                    .attr('class', 'data')
                    .attr('d', navData(data));

                navChart.append('path')
                    .attr('class', 'line')
                    .attr('d', navLine(data));



                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Viewport

                function redrawChart() {

                    dataSeries.call(series);
                    plotChart.select('.x.axis').call(xAxis);
                }

                function updateZoomFromChart() {

                    var fullDomain = maxDate - minDate,
                        currentDomain = xScale.domain()[1] - xScale.domain()[0];

                    var minScale = currentDomain / fullDomain,
                        maxScale = minScale * 20;

                    zoom.x(xScale)
                        .scaleExtent([minScale, maxScale]);
                }


                var viewport = d3.svg.brush()
                    .x(navXScale)
                    .on("brush", function () {
                        xScale.domain(viewport.empty() ? navXScale.domain() : viewport.extent());
                        redrawChart();
                    })
                    .on("brushend", function () {
                        updateZoomFromChart();
                    });

                navChart.append("g")
                    .attr("class", "viewport")
                    .call(viewport)
                    .selectAll("rect")
                    .attr("height", navHeight);


                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Zooming and panning

                function updateViewpointFromChart() {

                    if ((xScale.domain()[0] <= minDate) && (xScale.domain()[1] >= maxDate)) {

                        viewport.clear();
                    }
                    else {

                        viewport.extent(xScale.domain());
                    }

                    navChart.select('.viewport').call(viewport);
                }



                var zoom = d3.behavior.zoom()
                    .x(xScale)
                    .on('zoom', function() {
                        if (xScale.domain()[0] < minDate) {
                            zoom.translate([zoom.translate()[0] - xScale(minDate) + xScale.range()[0], 0]);
                        } else if (xScale.domain()[1] > maxDate) {
                            zoom.translate([zoom.translate()[0] - xScale(maxDate) + xScale.range()[1], 0]);
                        }
                        redrawChart();
                        updateViewpointFromChart();
                    });

                var overlay = d3.svg.area()
                    .x(function (d) { return xScale(d.date); })
                    .y0(0)
                    .y1(height);

                plotArea.append('path')
                    .attr('class', 'overlay')
                    .attr('d', overlay(data))
                .call(zoom);

                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Setup

                var daysShown = 30;

                xScale.domain([
                    data[data.length - daysShown - 1].date,
                    data[data.length - 1].date
                ]);

                redrawChart();

                updateViewpointFromChart();

                updateZoomFromChart();


                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Helper methods

            });

        }
 //      alert("here we are again and again");
        return chart;
    }
    return timeSeriesChart;
});

【问题讨论】:

  • 您的代码运行不正常。做一个小提琴,让我们看看。但我要做的是调用缩放函数,在这个函数中(你在 svg 上调整大小/翻译),我会同时调用每个容器
  • 好的,我会做一个小提琴。
  • 我之前没有做过小提琴,所以我不知道如何制作一个使用 require 和 code 分布在多个文件中的小提琴。会继续努力。
  • @thisOneGuy 我为此代码创建了一个小提琴。主图表在开头,配置代码在底部。我不得不在中间添加一些库代码,因为我无法从外部资源中获取一些库来工作。你能给我一些关于如何访问所有控件以便同时更新它们的更多线索吗?

标签: d3.js


【解决方案1】:

从这个例子:http://bl.ocks.org/mbostock/6123708

创建缩放:

var zoom = d3.behavior.zoom()
    .scaleExtent([1, 10])
    .on("zoom", zoomed);

function zoomed() {
  container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

在您的容器上调用缩放:

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
    .call(zoom); //<<<<<HERE

这就是它在单个画布上的样子,但在你的情况下,它看起来像这样:

创建缩放:

var zoom = d3.behavior.zoom()
    .scaleExtent([1, 10])
    .on("zoom", zoomed);

转换每个画布/容器

    function zoomed() {
      container1.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
container2.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
container3.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }

在所有容器上调用 zoom :

    var svg1 = d3.select("body").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
        .call(zoom); //<<<<<HERE

var svg2 = d3.select("body").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
        .call(zoom); //<<<<<HERE

var svg3 = d3.select("body").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
        .call(zoom); //<<<<<HERE

类似的东西应该可以工作,但没有任何例子就无法测试它。

【讨论】:

  • 谢谢,很有帮助。
猜你喜欢
  • 2019-07-25
  • 2013-05-16
  • 1970-01-01
  • 2022-09-29
  • 2018-01-04
  • 2019-01-15
  • 2021-10-01
  • 2017-08-22
  • 1970-01-01
相关资源
最近更新 更多