首页 > 解决方案 > 在D3 js中通过给定方向移动一条线?

问题描述

我使用 d3.js 创建了 x,y,z 平面,我想通过初始方向移动每个轴。例如:x 轴 - 水平,y 轴 - 垂直和 z 轴 - 给定方向。我可以更改代码以水平移动 x 轴和垂直移动 y 轴。但我不能为另一个(z)轴做到这一点。我需要更改代码以通过初始方向移动 z 轴。

下面是我的 d3.js 代码。完整代码在这里,x,y,z 平面

var width = 600,
    height = 600,
    activeClassName = 'active-d3-item';

var svg = d3.select('.plane').append('svg');
svg.attr('width', width);
svg.attr('height', height);

//The data for our lines and endpoints
var data = [
    {
        'x1': 100,
        'y1': 300,
        'x2': 100,
        'y2': 50
    },
    {
        'x1': 100,
        'y1': 300,
        'x2': 300,
        'y2': 300
    },
    {
        'x1': 100,
        'y1': 300,
        'x2': 39,
        'y2': 239
    }
];

// Generating the svg lines attributes
var lineAttributes = {
    'x1': function(d) {
        return d.x1;
    },
    'y1': function(d) {
        return d.y1;
    },
    'x2': function(d) {
        return d.x2;
    },
    'y2': function(d) {
        return d.y2;
    }
};

// Pointer to the d3 lines
var lines = svg
    .selectAll('line')
    .data(data)
    .enter()
    .append('line')
    .attr(lineAttributes);

var topEndPoints = data.map(function(line, i) {
    return {
        'x': line.x1,
        'y': line.y1,
        'marker': 'marker-start',
        'lineIndex': i
    };
});

var bottomEndPoints = data.map(function(line, i) {
    return {
        'x': line.x2,
        'y': line.y2,
        'marker': 'marker-end',
        'lineIndex': i
    };
});

var endPointsData = bottomEndPoints;

// Generating the svg circle attributes
var endPointsAttributtes = {
    'r': 7,
    'cx': function(d) {
        return d.x;
    },
    'cy': function(d) {
        return d.y;
    }
};

var drag = d3.behavior.drag()
    .origin(function(d) { return d; })
    .on('dragstart', dragstarted)
    .on('drag', dragged)
    .on('dragend', dragended);

// Pointer to d3 circles
var endPoints = svg
    .selectAll('circle')
    .data(endPointsData)
    .enter()
    .append('circle')
    .attr(endPointsAttributtes)
    .call(drag);

function dragstarted() {
    d3.select(this).classed(activeClassName, true);
}

function dragged(d, i) {
    var marker = d3.select(this);

    // Update the marker properties
    if(d.lineIndex === 0) { 
        marker.attr('cy', d.y = d3.event.y); //Drag line 1 only through y axis.
    } else if(d.lineIndex === 1) {
        marker.attr('cx', d.x = d3.event.x); //Drag line 2 only through x axis.
    } else if(d.lineIndex === 2) {
            marker.attr('cx', d.x = d3.event.x).attr('cy', d.y = d3.event.y);
    }

    // Update the line properties
    lines
        .filter(function(lineData, lineIndex) {

            return lineIndex === d.lineIndex;
        }).attr('x1', function(lineData) {
             return d.marker === 'marker-start' ? lineData.x1 = d.x : lineData.x1;
         }).attr('y1', function(lineData) {
            return d.marker === 'marker-start' ? lineData.y1 = d.y : lineData.y1;
        })
        .attr('x2', function(lineData) {
            return d.marker === 'marker-end' ? lineData.x2 = d.x : lineData.x2;
        }).attr('y2', function(lineData) {
         return d.marker === 'marker-end' ? lineData.y2 = d.y : lineData.y2;
     });
}

function dragended() {
    d3.select(this).classed(activeClassName, false);
}

我只想通过初始方向移动 z 轴。

标签: javascriptd3.js

解决方案


您必须将鼠标位置的矢量从原点投影到轴的单位矢量上;看看https://en.wikipedia.org/wiki/Vector_projection

<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body {
      margin: 0;
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
    }
  </style>
</head>

<body>
  <script>
    var start = [0, 0];
    var end = [100, 20];

    var length = Math.sqrt(Math.pow(start[0] - end[0], 2) +
      Math.pow(start[1] - end[1], 2));

    var dirUnitVector = [
      (end[0] - start[0]) / length,
      (end[1] - start[1]) / length
    ];

    var svg = d3.select("body").append("svg")
      .attr("width", 300)
      .attr("height", 200)
      .attr('viewBox', '-10 0 120 20')
      .style('stroke', "black");

    svg.append('line')
      .attr('x1', start[0])
      .attr('y1', start[1])
      .attr('x2', end[0])
      .attr('y2', end[1]);

    var c = svg.append('circle')
      .attr('cx', start[0])
      .attr('cy', start[1])
      .attr('r', 2)
      .style('fill', 'blue')
      .call(d3.drag().on("drag", function() {
        var mouseVector = [
          d3.event.x - start[0],
          d3.event.y - start[1]
        ];
        var projection =
          mouseVector[0] * dirUnitVector[0] +
          mouseVector[1] * dirUnitVector[1];
        c.attr('cx', start[0] + dirUnitVector[0] * projection);
        c.attr('cy', start[1] + dirUnitVector[1] * projection);
      }));
  </script>
</body>


推荐阅读