d3.js散点图 - 缩放/拖动边界,变焦按钮,复位变焦,计算中位数(d3.js scatter p

2019-07-20 12:35发布

我已经建立了与缩放/平移功能的d3.js散点图。 你可以在这里看到完整的东西(点击“打开一个新窗口”看到了整个事情): http://bl.ocks.org/129f64bfa2b0d48d27c9

有一对夫妇的功能,我一直无法弄清楚,我会爱一个手,如果有人能在正确的方向指向我:

  1. 我想X / Y缩放/平移边界适用于该地区,因此,你不能将它拖到低于某个点(如零)。
  2. 我也做了创造谷歌地图风格+/-变焦按钮一刺,没有任何成功。 有任何想法吗?

更不用说重要的是,也有几个在那里我已经想出了一个解决方案领域,但它是非常粗糙的,所以如果你有一个更好的解决方案,那么请不要让我知道:

  1. 我添加了一个“重置缩放”按钮,但它仅仅是删除了图,并生成在其位置一个新的,而不是实际缩放的对象。 理想情况下,实际上应该重新变焦。
  2. 我写我自己的函数来计算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的非常简化的(即旧)版本如下。 你可以找到完整的脚本https://gist.github.com/richardwestenra/129f64bfa2b0d48d27c9#file-main-js

d3.csv("js/AllOccupations.csv", function(data) {

    var margin = {top: 30, right: 10, bottom: 50, left: 60},
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var xMax = d3.max(data, function(d) { return +d.TotalEmployed2011; }),
        xMin = 0,
        yMax = d3.max(data, function(d) { return +d.MedianSalary2011; }),
        yMin = 0;

    //Define scales
    var x = d3.scale.linear()
        .domain([xMin, xMax])
        .range([0, width]);

    var y = d3.scale.linear()
        .domain([yMin, yMax])
        .range([height, 0]);

    var colourScale = function(val){
        var colours = ['#9d3d38','#c5653a','#f9b743','#9bd6d7'];
        if (val > 30) {
            return colours[0];
        } else if (val > 10) {
            return colours[1];
        } else if (val > 0) {
            return colours[2];
        } else {
            return colours[3];
        }
    };


    //Define X axis
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickSize(-height)
        .tickFormat(d3.format("s"));

    //Define Y axis
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(5)
        .tickSize(-width)
        .tickFormat(d3.format("s"));

    var svg = d3.select("#chart").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 + ")")
        .call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 8]).on("zoom", zoom));

    svg.append("rect")
        .attr("width", width)
        .attr("height", height);

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

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

    // Create points
    svg.selectAll("polygon")
        .data(data)
        .enter()
        .append("polygon")
        .attr("transform", function(d, i) {
            return "translate("+x(d.TotalEmployed2011)+","+y(d.MedianSalary2011)+")";
        })
        .attr('points','4.569,2.637 0,5.276 -4.569,2.637 -4.569,-2.637 0,-5.276 4.569,-2.637')
        .attr("opacity","0.8")
        .attr("fill",function(d) {
            return colourScale(d.ProjectedGrowth2020);
        });

    // Create X Axis label
    svg.append("text")
        .attr("class", "x label")
        .attr("text-anchor", "end")
        .attr("x", width)
        .attr("y", height + margin.bottom - 10)
        .text("Total Employment in 2011");

    // Create Y Axis label
    svg.append("text")
        .attr("class", "y label")
        .attr("text-anchor", "end")
        .attr("y", -margin.left)
        .attr("x", 0)
        .attr("dy", ".75em")
        .attr("transform", "rotate(-90)")
        .text("Median Annual Salary in 2011 ($)");


    function zoom() {
      svg.select(".x.axis").call(xAxis);
      svg.select(".y.axis").call(yAxis);
      svg.selectAll("polygon")
            .attr("transform", function(d) {
                return "translate("+x(d.TotalEmployed2011)+","+y(d.MedianSalary2011)+")";
            });
    };
    }
});

任何帮助将大规模赞赏。 谢谢!

编辑:这是我使用的,基于以下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]]);
        }
        ...
    };

我使用了变焦的翻译是非常特别和基本使用abitrary常量保持定位或多或少在正确的地方。 这不是理想的,并且我会愿意接受一个更普遍的声音的技术建议。 然而,它的工作原理在这种情况下不够好。

Answer 1:

为了与中位机能开始只是需要一个数组和一个可选的访问。 所以,你可以使用它,你最大使用同样的方法:

var med = d3.median(data, function(d) { return +d.TotalEmployed2011; });

至于其他人,如果你拿出你的缩放行为,你可以控制它好一点。 因此,例如,而不是

var svg = d3.select()...call(d3.behavior.zoom()...) 

尝试:

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())]);
    }
    ....
}        

请记住,如果你要放大到允许在轴负,但不是平移来,你会发现你进入一些棘手的场景。

这可能是过时的,但检查出限制域缩放或平移D3.js时

还要注意的是,缩放行为确实有限制平移和缩放在功能一个点 。 但代码取出在以后的更新 。



Answer 2:

我不喜欢推倒重来。 我在寻找它允许缩放散点图。 Highcharts是其中之一,但有plotly,这是基于D3,而不是只允许缩放,但你也可以拥有线数据集太散点图上,我与我的一些数据集的愿望,这是很难找到其他积库。 我给它一试:

https://plot.ly/javascript/line-and-scatter/

https://github.com/plotly/plotly.js

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



文章来源: d3.js scatter plot - zoom/drag boundaries, zoom buttons, reset zoom, calculate median