d3.mouse在转换的SVG上无法正常工作

时间:2018-04-06 05:16:56

标签: javascript jquery d3.js

我正在尝试手动创建两个所需节点之间的链接(借助鼠标指针)。为此我一个接一个地从鼠标中选择两个节点。从第一个选定节点创建链接(路径)。此链接将跟随鼠标指针。如果我点击任何其他节点,将在该节点和第一个节点之间创建一个链接。

但是链接(路径)存在问题。如果SVG被转换(翻译和缩放),它实际上并不跟随鼠标指针。

Path is correctly following mouse pointer if the SVG is not Transformed

图1:路径从单击的节点位置开始并跟随鼠标指针。此处SVG未转换(未应用缩放)。

Path is not properly following mouse pointer if the SVG is Zoomed in (Transformed) 图2:路径从单击的节点位置开始,但没有正确跟随鼠标指针。这里SVG已转换(此处应用缩放)。

下面是在另一个SVG中创建一个SVG的示例代码。这是我的项目要求以后的目的。

我尝试了很多但不了解问题的位置。这是我的代码: JSFiddle

var dnodes = [];
var dlinks = [];
var default_link_color = "#bbb";
var link_default_width = 2;
var min_zoom = 0.1;
var max_zoom = 7;


function initdiagram(el) {
var im = this;
var w = $(el).innerWidth();
var h = $(el).innerHeight();

var connector = d3.svg.line().interpolate("linear");

var zoom = d3.behavior.zoom().scaleExtent([min_zoom, max_zoom]);

var selectedNode1 = null;
var selectedNode2 = null;

var mainsvg = d3.select(el).append("svg")
    .attr("class","mainsvg")
    .attr("width", w)
    .attr("height", h)
    .on("mousemove", function(){
      if(selectedNode1 !== null)
      {
        var cm = d3.mouse(this);
        templink.attr("d",function(){
          return connector([[selectedNode1.x  , selectedNode1.y ], [ cm[0]  , cm[1]]]);
        });
      }
      if((selectedNode1 !== null) && (selectedNode2 !== null))
      {
        templink.attr("d",null);
      }

    });

var svg = mainsvg.append("svg")
      .attr("class","svg")
      .attr("viewBox", "0 0 " + w + " " + h)
      .attr("preserveAspectRatio", "xMidYMid");
var g = svg.append("g")
      .attr('width', w)
              .attr('height', h);


zoom.on("zoom", function() {
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
      });

mainsvg.call(zoom).on("dblclick.zoom", null); //Disabling zoom on double click

function findNode(id) {
    for (var i in dnodes) {
        if (dnodes[i]["id"] === id) return dnodes[i];
    }
}

this.addNode = function(id) {
  var newNode = findNode(id);
  if (newNode == undefined) {
    dnodes.push({
      "id": id,
      fixed:false
    });
  }
}

this.addLink = function(sourceId, targetId) {
  var sourceNode = findNode(sourceId);
  var targetNode = findNode(targetId);
  if ((sourceNode !== undefined) && (targetNode !== undefined)) {
      dlinks.push({
        "source": sourceNode,
        "target": targetNode
      });
  }
}

var force = self.force = d3.layout.force()
      .linkDistance(160)
      .charge(-2000)
  .on("tick",tick)
  .size([w, h]);

  var nodes = force.nodes(dnodes);
  var links = force.links(dlinks);


this.forcestart = function(){
  force.start();
} 

function tick() {
  node.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")";});
  link.attr('d', function(d) { var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y; return path});  
}


this.forceupdate = function(){
  update(dnodes, dlinks);
}


var node = null;
var link = null;
var templink = null;

function update(dnodes, dlinks) {
  g.selectAll(".link").remove(); 
      g.selectAll(".node").remove();
  g.selectAll(".templink").remove();

  link = g.selectAll(".link")
    .attr("class", "link")
          .data(dlinks)
          .enter()
    .append('path')
    .attr('d', function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;})
    .attr("class","edgepath")
    .attr('id', function(d,i) {return 'edgepath'+i;})
    .style("stroke",default_link_color)
    .style("stroke-width",link_default_width)
    .style("pointer-events", "none");


templink = g.append("path")
    .attr("class","templink")
    .attr("d",null)
    .style("stroke","green")
    .style("stroke-width",link_default_width+1)
    .style("stroke-dasharray","5, 5")
    .style("fill","none");	

node = g.selectAll(".node")
    .data(dnodes)
    .enter().append("g")
    .attr("class", "node");

node.append("rect")
    .attr("width", 20)
    .attr("height", 20)
    .attr("x", -10)
    .attr("y", -10)
    .style("fill", "blue");

node.on("mouseup", function(d) { 
    if(selectedNode1 == null)
    {
      selectedNode1 = d;
    }

  });

  }
return this;
}

var di = new initdiagram("#graph");

di.addNode("i0");
di.addNode("i1");
di.addNode("i2");

di.addLink("i0", "i1");
di.addLink("i1", "i2");

di.forceupdate();
di.forcestart();
text {
  font-family: sans-serif;
  pointer-events: none;
}
html,body { width:100%; height:100%; margin:none; padding:none; }
#graph { width:100%;height:100%; margin:auto; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="graph"></div>

2 个答案:

答案 0 :(得分:0)

尝试计算如下所示的坐标。

  

SVGPoint matrixTransform应用2x3矩阵变换   在此SVGPoint对象上,返回一个新的,已转换的SVGPoint   对象

     

SVGGraphicsElement.getCTM()返回表示的DOMMatrix   将当前元素的坐标系转换为的矩阵   它的SVG视口的坐标系。

var pt = this.createSVGPoint();
pt.x = d3.event.x;
pt.y = d3.event.y;
pt = pt.matrixTransform(g.node().getCTM().inverse());
templink.attr("d", function() {
    return connector([
       [selectedNode1.x, selectedNode1.y],
       [pt.x, pt.y]
    ]);
});

var dnodes = [];
var dlinks = [];
var default_link_color = "#bbb";
var link_default_width = 2;
var min_zoom = 0.1;
var max_zoom = 7;


function initdiagram(el) {
  var im = this;
  var w = $(el).innerWidth();
  var h = $(el).innerHeight();

  var connector = d3.svg.line().interpolate("linear");

  var zoom = d3.behavior.zoom().scaleExtent([min_zoom, max_zoom]);

  var selectedNode1 = null;
  var selectedNode2 = null;

  var mainsvg = d3.select(el).append("svg")
    .attr("class", "mainsvg")
    .attr("width", w)
    .attr("height", h)
    .on("mousemove", function() {
      if (selectedNode1 !== null) {       
        var pt = this.createSVGPoint();
        pt.x = d3.mouse(this)[0];
        pt.y = d3.mouse(this)[1];
        pt = pt.matrixTransform(g.node().getCTM().inverse());
        templink.attr("d", function() {
          return connector([
            [selectedNode1.x, selectedNode1.y],
            [pt.x, pt.y]
          ]);
        });
      }
      if ((selectedNode1 !== null) && (selectedNode2 !== null)) {
        templink.attr("d", null);
      }

    });

  var svg = mainsvg.append("svg")
    .attr("class", "svg")
    .attr("viewBox", "0 0 " + w + " " + h)
    .attr("preserveAspectRatio", "xMidYMid");
  var g = svg.append("g")
    .attr('width', w)
    .attr('height', h);


  zoom.on("zoom", function() {
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  });

  mainsvg.call(zoom).on("dblclick.zoom", null); //Disabling zoom on double click

  function findNode(id) {
    for (var i in dnodes) {
      if (dnodes[i]["id"] === id) return dnodes[i];
    }
  }

  this.addNode = function(id) {
    var newNode = findNode(id);
    if (newNode == undefined) {
      dnodes.push({
        "id": id,
        fixed: false
      });
    }
  }

  this.addLink = function(sourceId, targetId) {
    var sourceNode = findNode(sourceId);
    var targetNode = findNode(targetId);
    if ((sourceNode !== undefined) && (targetNode !== undefined)) {
      dlinks.push({
        "source": sourceNode,
        "target": targetNode
      });
    }
  }

  var force = self.force = d3.layout.force()
    .linkDistance(160)
    .charge(-2000)
    .on("tick", tick)
    .size([w, h]);

  var nodes = force.nodes(dnodes);
  var links = force.links(dlinks);


  this.forcestart = function() {
    force.start();
  }

  function tick() {
    node.attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });
    link.attr('d', function(d) {
      var path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
      return path
    });
  }


  this.forceupdate = function() {
    update(dnodes, dlinks);
  }


  var node = null;
  var link = null;
  var templink = null;

  function update(dnodes, dlinks) {
    g.selectAll(".link").remove();
    g.selectAll(".node").remove();
    g.selectAll(".templink").remove();

    link = g.selectAll(".link")
      .attr("class", "link")
      .data(dlinks)
      .enter()
      .append('path')
      .attr('d', function(d) {
        return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
      })
      .attr("class", "edgepath")
      .attr('id', function(d, i) {
        return 'edgepath' + i;
      })
      .style("stroke", default_link_color)
      .style("stroke-width", link_default_width)
      .style("pointer-events", "none");


    templink = g.append("path")
      .attr("class", "templink")
      .attr("d", null)
      .style("stroke", "green")
      .style("stroke-width", link_default_width + 1)
      .style("stroke-dasharray", "5, 5")
      .style("fill", "none");

    node = g.selectAll(".node")
      .data(dnodes)
      .enter().append("g")
      .attr("class", "node");

    node.append("rect")
      .attr("width", 20)
      .attr("height", 20)
      .attr("x", -10)
      .attr("y", -10)
      .style("fill", "blue");

    node.on("mouseup", function(d) {
      if (selectedNode1 == null) {
        selectedNode1 = d;
      }

    });

  }
  return this;
}

var di = new initdiagram("#graph");

di.addNode("i0");
di.addNode("i1");
di.addNode("i2");

di.addLink("i0", "i1");
di.addLink("i1", "i2");

di.forceupdate();
di.forcestart();
text {
  font-family: sans-serif;
  pointer-events: none;
}

html,
body {
  width: 100%;
  height: 100%;
  margin: none;
  padding: none;
}

#graph {
  width: 100%;
  height: 100%;
  margin: auto;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="graph"></div>

答案 1 :(得分:0)

从这个post得到解决问题的想法。

以下是更新的JSFiddle

zoom.on("zoom", function() {
    translateVar[0] = d3.event.translate[0];
    translateVar[1] = d3.event.translate[1];
    scaleVar = d3.event.scale;
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  });

var mainsvg = d3.select(el).append("svg")
.attr("class","mainsvg")
.attr("width", w)
.attr("height", h)
.on("mousemove", function(){
  if(selectedNode1 !== null)
  {
    var cm = d3.mouse(this);
    var newX = cm[0] - translateVar[0] ;
    var newY = cm[1] - translateVar[1] ;
    if(scaleVar > 0)
    {
        newX = newX / scaleVar;
        newY = newY / scaleVar;
    }
    templink.attr("d",function(){
      return connector([[selectedNode1.x  , selectedNode1.y ], [ newX  , newY]]);
    });
  }
  if((selectedNode1 !== null) && (selectedNode2 !== null))
  {
    templink.attr("d",null);
  }

});