我正在尝试手动创建两个所需节点之间的链接(借助鼠标指针)。为此我一个接一个地从鼠标中选择两个节点。从第一个选定节点创建链接(路径)。此链接将跟随鼠标指针。如果我点击任何其他节点,将在该节点和第一个节点之间创建一个链接。
但是链接(路径)存在问题。如果SVG被转换(翻译和缩放),它实际上并不跟随鼠标指针。
图1:路径从单击的节点位置开始并跟随鼠标指针。此处SVG未转换(未应用缩放)。
图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>
答案 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);
}
});