使用包含数字数组和对象数组的拖动时的不同行为

时间:2017-09-02 23:09:51

标签: javascript d3.js

我是使用D3和JavaScript的新手,所以希望这是一个让我可以清理的简单点。

我使用与this堆栈溢出问题非常相似的代码制作带有可拖动点的散点图。当我将数据集作为[x, y]对数组生成并将其称为d[0]d[1]时,代码将按预期工作。但是,当我创建一个具有属性xy的对象数组时,将它们称为d.xd.y,该绘图将像以前一样显示但拖动行为没有工作 - 被点击的点在x轴下方射击。

所以这段代码有效:



<!DOCTYPE html>
<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

    let svg = d3.select("svg"),
        margin = {top: 20, right: 20, bottom: 30, left: 50},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;
    //Make the fake data as an array of [x, y] pairs
    let m=3.0, c=15.0;
    let points = d3.range(1, 10).map(function(i) {
        let x=i * width / 10;
        let noise=Math.random()*500;
        let y=m*x+c + noise;
        return [x, y];
    });






    let x = d3.scaleLinear()
        .rangeRound([0, width]);

    let y = d3.scaleLinear()
        .rangeRound([height, 0]);

    let xAxis = d3.axisBottom(x),
        yAxis = d3.axisLeft(y);

    let line = d3.line()
        .x(function(d) { return x(d[0]); })
        .y(function(d) { return y(d[1]); });

    let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);

    svg.append('rect')
        .attr('class', 'zoom')
        .attr('cursor', 'move')
        .attr('fill', 'none')
        .attr('pointer-events', 'all')
        .attr('width', width)
        .attr('height', height)
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

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

    x.domain(d3.extent(points, function(d) { return d[0]; }));
    y.domain(d3.extent(points, function(d) { return d[1]; }));

    focus.append("path")
        .datum(points)
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("stroke-width", 1.5)
        .attr("d", line);

    focus.selectAll('circle')
        .data(points)
        .enter()
        .append('circle')
        .attr('r', 5.0)
        .attr('cx', function(d) { return x(d[0]);  })
        .attr('cy', function(d) { return y(d[1]); })
        .style('cursor', 'pointer')
        .style('fill', 'steelblue');

    focus.selectAll('circle')
        .call(drag);

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

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

    function dragstarted(d) {
        d3.select(this).raise().classed('active', true);
    }

    function dragged(d) {
        d[0] = x.invert(d3.event.x);
        d[1] = y.invert(d3.event.y);
        d3.select(this)
            .attr('cx', x(d[0]))
            .attr('cy', y(d[1]))
        focus.select('path').attr('d', line);
    }

    function dragended(d) {
        d3.select(this).classed('active', false);
    }

</script>
&#13;
&#13;
&#13;

但是这个代码在拖动点时会产生奇怪的行为:

&#13;
&#13;
<!DOCTYPE html>
<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

    let svg = d3.select("svg"),
        margin = {top: 20, right: 20, bottom: 30, left: 50},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;
    //Make the fake data as an array of objects, with attributes x and y
    let m=3.0, c=15.0;
    let points = d3.range(1, 10).map(function(i) {
        let x_val=i * width / 10;
        let noise=Math.random()*500;
        let y_val=m*x_val+c + noise;
        return {
            x:x_val,
            y:y_val

        };
    });






    let x = d3.scaleLinear()
        .rangeRound([0, width]);

    let y = d3.scaleLinear()
        .rangeRound([height, 0]);

    let xAxis = d3.axisBottom(x),
        yAxis = d3.axisLeft(y);

    let line = d3.line()
        .x(function(d) { return x(d.x); })
        .y(function(d) { return y(d.y); });

    let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended);

    svg.append('rect')
        .attr('class', 'zoom')
        .attr('cursor', 'move')
        .attr('fill', 'none')
        .attr('pointer-events', 'all')
        .attr('width', width)
        .attr('height', height)
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

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

    x.domain(d3.extent(points, function(d) { return d.x; }));
    y.domain(d3.extent(points, function(d) { return d.y; }));

    focus.append("path")
        .datum(points)
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("stroke-width", 1.5)
        .attr("d", line);

    focus.selectAll('circle')
        .data(points)
        .enter()
        .append('circle')
        .attr('r', 5.0)
        .attr('cx', function(d) { return x(d.x);  })
        .attr('cy', function(d) { return y(d.y); })
        .style('cursor', 'pointer')
        .style('fill', 'steelblue');

    focus.selectAll('circle')
        .call(drag);

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

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

    function dragstarted(d) {
        d3.select(this).raise().classed('active', true);
    }

    function dragged(d) {
        d.x = x.invert(d3.event.x);
        d.y = y.invert(d3.event.y);
        d3.select(this)
            .attr('cx', x(d.x))
            .attr('cy', y(d.y));
        focus.select('path').attr('d', line);
    }

    function dragended(d) {
        d3.select(this).classed('active', false);
    }

</script>
&#13;
&#13;
&#13;

当我所有改变的是数据结构时,有人能解释为什么他们会给出不同的结果吗?谢谢!

1 个答案:

答案 0 :(得分:0)

数据上的xy属性混淆了默认值(主题访问者)[https://github.com/d3/d3-drag#drag_subject]。明确地说它会解决问题:

    let drag = d3.drag()
        .on('start', dragstarted)
        .on('drag', dragged)
        .subject(function(d){ return {x: x(d.x), y: y(d.y)} })
        .on('end', dragended);