Javascript d3.js散点图-缩放/拖动边界、缩放按钮、重置缩放、计算中值

Javascript d3.js散点图-缩放/拖动边界、缩放按钮、重置缩放、计算中值,javascript,d3.js,zooming,drag,scatter-plot,Javascript,D3.js,Zooming,Drag,Scatter Plot,我已经构建了一个具有缩放/平移功能的d3.js散点图。您可以在此处查看全部内容(单击“在新窗口中打开”查看全部内容): 有几个功能我还没弄清楚,如果有人能给我指出正确的方向,我希望能帮我一把: 我想将X/Y缩放/平移边界应用于该区域,以便您不能将其拖动到某个点(例如零)以下 我也尝试过创建谷歌地图风格的+/-缩放按钮,但没有成功。有什么想法吗 更不重要的是,我也在几个方面找到了解决方案,但非常粗糙,因此如果您有更好的解决方案,请务必让我知道: 我添加了一个“重置缩放”按钮,但它只是删除图形并在

我已经构建了一个具有缩放/平移功能的d3.js散点图。您可以在此处查看全部内容(单击“在新窗口中打开”查看全部内容):

有几个功能我还没弄清楚,如果有人能给我指出正确的方向,我希望能帮我一把:

  • 我想将X/Y缩放/平移边界应用于该区域,以便您不能将其拖动到某个点(例如零)以下
  • 我也尝试过创建谷歌地图风格的+/-缩放按钮,但没有成功。有什么想法吗
  • 更不重要的是,我也在几个方面找到了解决方案,但非常粗糙,因此如果您有更好的解决方案,请务必让我知道:

  • 我添加了一个“重置缩放”按钮,但它只是删除图形并在其位置生成一个新的,而不是实际缩放对象。理想情况下,它应该实际重置缩放
  • 我已经编写了自己的函数来计算X和Y数据的中值。然而,我相信一定有更好的方法来做到这一点d3.median,但我不知道如何使它的工作

    var xMed = median(_.map(data,function(d){ return d.TotalEmployed2011;}));
    var yMed = median(_.map(data,function(d){ return d.MedianSalary2011;}));
    
    function median(values) {
        values.sort( function(a,b) {return a - b;} );
        var half = Math.floor(values.length/2);
    
        if(values.length % 2)
            return values[half];
        else
            return (parseFloat(values[half-1]) + parseFloat(values[half])) / 2.0;
    };
    
  • 下面是JS的一个非常简化(即旧)的版本。您可以在以下位置找到完整的脚本:

    任何帮助都将不胜感激。谢谢

    编辑:以下是我根据Superboggly的建议使用的修复程序的摘要:

        // Zoom in/out buttons:
        d3.select('#zoomIn').on('click',function(){
            d3.event.preventDefault();
            if (zm.scale()< maxScale) {
                zm.translate([trans(0,-10),trans(1,-350)]);
                zm.scale(zm.scale()*2);
                zoom();
            }
        });
        d3.select('#zoomOut').on('click',function(){
            d3.event.preventDefault();
            if (zm.scale()> minScale) {
                zm.scale(zm.scale()*0.5);
                zm.translate([trans(0,10),trans(1,350)]);
                zoom();
            }
        });
        // Reset zoom button:
        d3.select('#zoomReset').on('click',function(){
            d3.event.preventDefault();
            zm.scale(1);
            zm.translate([0,0]);
            zoom();
        });
    
    
        function zoom() {
    
            // To restrict translation to 0 value
            if(y.domain()[0] < 0 && x.domain()[0] < 0) {
                zm.translate([0, height * (1 - zm.scale())]);
            } else if(y.domain()[0] < 0) {
                zm.translate([d3.event.translate[0], height * (1 - zm.scale())]);
            } else if(x.domain()[0] < 0) {
                zm.translate([0, d3.event.translate[1]]);
            }
            ...
        };
    
    //放大/缩小按钮:
    d3.选择('zoomIn')。打开('click',函数(){
    d3.event.preventDefault();
    如果(zm.scale()minScale){
    zm.刻度(zm.刻度()*0.5);
    翻译([trans(0,10),trans(1350)]);
    缩放();
    }
    });
    //重置缩放按钮:
    d3.选择(“#zoomReset”)。在('单击',函数()上{
    d3.event.preventDefault();
    zm.标度(1);
    zm.translate([0,0]);
    缩放();
    });
    函数zoom(){
    //将转换限制为0值的步骤
    如果(y.domain()[0]<0和&x.domain()[0]<0){
    zm.translate([0,高度*(1-zm.scale())]);
    }如果(y.domain()[0]<0),则为else{
    zm.translate([d3.event.translate[0],height*(1-zm.scale())]);
    }else if(x.domain()[0]<0){
    zm.translate([0,d3.event.translate[1]]);
    }
    ...
    };
    

    我使用的缩放平移是非常特别的,基本上使用了一个常量来保持定位在正确的位置。这并不理想,我愿意接受关于更普遍的声音技术的建议。但是,它在这种情况下工作得足够好。

    从中值函数开始,只需要一个数组和一个可选的访问器。因此,您可以像使用max一样使用它:

    var med = d3.median(data, function(d) { return +d.TotalEmployed2011; });
    
    至于其他人,如果你拿出你的缩放行为,你可以更好地控制它一点。所以,比如说

    var svg = d3.select()...call(d3.behavior.zoom()...) 
    
    尝试:

    然后可以直接设置缩放级别和平移:

    function zoomIn() {
       zm.scale(zm.scale()*2);
       // probably need to compute a new translation also
    }
    
    function reset() {
       zm.scale(1);
       zm.translate([0,0]);
    }
    
    限制平移范围有点棘手。当缩放功能中的平移或缩放不符合您的喜好时,您可以简单地不进行更新(或将缩放的“平移”设置为您需要的值)。比如(我想在你的情况下):

    函数缩放(){
    如果(y.domain()[0]<0){
    //将转换限制为0值的步骤
    zm.translate([d3.event.translate[0],height*(1-zm.scale())]);
    }
    ....
    }        
    
    请记住,如果您希望放大以允许轴上出现负片,但不希望平移,则会发现您陷入一些棘手的场景

    这可能是过时的,但请检查


    还要注意,缩放行为确实具有限制平移和缩放的功能。但是代码在稍后的一段时间内被删除。

    我不喜欢重新发明轮子。我正在搜索允许缩放的散点图。Highcharts是其中之一,但是plotly是基于D3的,不仅允许缩放,而且散点图上也可以有线条数据集,我希望我的一些数据集可以使用散点图,这在其他绘图库中很难找到。我想试试:


    使用这么好的库可以为您节省大量的时间和痛苦。

    再次非常感谢!缩放/重置代码似乎有效,但缩放比例仅在下一次缩放事件(即拖动或鼠标滚轮)时更改。我很难在点击按钮时更新内容。这一定很简单,但我就是想不出来。我的按钮点击代码是:d3.select('#zoomIn').call(zoom).on('click',function(){d3.event.preventDefault();zm.scale(zm.scale()*2);});我尝试了.call()、zoom()和.on()的各种用法,但都没有效果。我在我的屏幕底部添加了一个快速的蓝色小缩放方块。您所缺少的只是在设置比例后调用zoom()。将您提供的缩放功能想象为应用由行为计算的缩放状态。好的!分类!事实证明,这正是我正在做的,但对我来说并不奏效。。。长话短说:当我使用版本2时,你使用的是d3版本3,这就是为什么当我在代码中删除你的蓝色方块时,它不起作用。已经升级到v3,现在可以使用了。干杯:)啊,很高兴知道!我知道他们重写了缩放行为,但我不想检查版本!不用担心:)。顺便说一句,我现在几乎已经发布了它,但是为了将来的参考(万一有人无意中发现了这个页面,想知道我是如何做到的,或者可以提出改进建议):我在计算translate函数时遇到了一些麻烦,所以我最后敲入了一些任意常数。它似乎工作得很好:函数trans(xy,constant){return zm.translate()[xy]+(constant*(zm.scale());}zm.translate([trans(0,-10),trans(1,-350)
    var zm = d3.behavior.zoom().x(x).y(y).scaleExtent([1, 8]).on("zoom", zoom);
    var svg = d3.select()...call(zm);
    
    function zoomIn() {
       zm.scale(zm.scale()*2);
       // probably need to compute a new translation also
    }
    
    function reset() {
       zm.scale(1);
       zm.translate([0,0]);
    }
    
    function zoom() {
        if(y.domain()[0] < 0) {
            // To restrict translation to 0 value
            zm.translate([d3.event.translate[0], height * (1 - zm.scale())]);
        }
        ....
    }