本文介绍了强制布局拖动行为,在缩放时进行转换,但拖动时没有转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
> b $ b var width = 600,height = 200-16,margin = {top:25,right:5,bottom:5,left:5},w = width - margin.left - margin.right,h = height - margin.top - margin.bottom,zoom = d3.behavior.zoom()。scaleExtent([0.4,4]).on(zoom,zoomed),svg = d3.select(#viz)。attr({width:width,height:height}).append(g).attr(transform,translate(+ margin.left + margin.top +)).call(zoom),transText = svg.append(text).text(transform = translate(margin.left,margin.top)).style(fill #5c5c5c).attr(dy,-.35em)surface = svg.append(rect).attr({width:w,height:h}).style({pointer-events: all,fill:#ccc,stroke-width:3,stroke:#fff}),surfaceText = svg.append(text).text(pointer-events:all ).style(fill,#5c5c5c).attr({dy:1em,dx:.2em})content = svg.append(g)。attr ,content).attr(transform,translate(0,0)),contentText = content.append(text).text(transform = translate(d3.event.translate) .event.scale)).style(fill,#5c5c5c).attr({dy:50,dx:20})content.selectAll(rect).data [[20 ,{60},[140,60]]).enter()。append(rect).attr({height:50,width:50} :#ccc}).each(function(d){d3.select(this).attr({x:d [0],y:d [1] }); function zoomStart(){} function zoomed(){return d3.event.sourceEvent.buttons? zoomDrag.call(this):zoomScale.call(this)} function zoomDrag(){var t = d3.transform(content.attr(transform)); t.translate = d3.event.translate; content.attr(transform,t.toString()); } function zoomScale(){var t = d3.transform(content.attr(transform)); t.translate = d3.event.translate; t.scale = d3.event.scale; content.transition()。duration(450).attr(transform,t.toString()); }
svg {outline:1px solid#282f51; pointer-events:all; } g {outline:1px solid red; shape-rednering:geometricPrecision; }
< script src =https:// cdnjs .cloudflare.com / ajax / libs / d3 / 3.4.11 / d3.min.js>< / script>< svg id =viz>< / svg>
第二阶段
合并FDG
由于FDG必须位于画布容器内,因此必须停止节点级事件从传播到画布。这是在OP代码中通过使用自定义拖动行为,停止传播在 dragstart 并添加一些 force.drag
行为设置 d.fixed
= true )。这是伟大的,如果你不介意失去一些
force.drag 功能像粘贴节点鼠标悬停。这是很好的捕获小,精力充沛的节点。所以,为了获得两个世界的最好的,你可以钩子
force.drag'行为。
策略
- 应用与第一阶段相同的原则,但对鼠标滚轮事件进行跨浏览器测试。
- 将
force.drag
添加到节点 - 将
force.drag 添加自定义行为
- 仅修复 -drag (或-drag (or -dragend)
- for touch devices, also fix nodes if touches > 1 at dragstart
The last two points allow fixed nodes to be easily released if desired.
force.drag hook //hook force.drag behaviour
var stdDragStart = force.drag().on("dragstart.force");
force.drag()
.on("dragstart", function(d){
//prevent dragging on the nodes from dragging the canvas
d3.event.sourceEvent.stopPropagation();
stdDragStart.call(this, d);
});
Working example
//debug panel/////////////////////////////////////////////////////////////////////////////
var alpha = d3.select("#alpha").text("waiting..."),
cog = d3.select("#wrapAlpha").insert("i", "#fdg").classed("fa fa-cog fa-spin", true).datum({instID: null}),
fdgInst = d3.select("#fdg");
elapsedTime = ElapsedTime("#panel", {margin: 0, padding: 0})
.message(function (id) {
return 'fps : ' + d3.format(" >8.3f")(1/this.aveLap())
});
elapsedTime.consoleOn = true;
alpha.log = function(e, instID) {
elapsedTime.mark().timestamp();
alpha.text(d3.format(" >8.4f")(e.alpha));
fdgInst.text("fdg instance: " + instID);
};
d3.select("#update").on("click", (function() {
var dataSet = false;
return function() {
//fdg.force.stop();
fdg(dataSets[(dataSet = !dataSet, +dataSet)])
}
})());
//////////////////////////////////////////////////////////////////////////////////////////
var dataSets = [{
"nodes" : [
{"name": "node1", "r": 10},
{"name": "node2", "r": 10},
{"name": "node3", "r": 30},
{"name": "node4", "r": 15}
],
"edges": [
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3}
]
},
{
"nodes":[
{"name": "node1", "r": 20},
{"name": "node2", "r": 10},
{"name": "node3", "r": 30},
{"name": "node4", "r": 15},
{"name": "node5", "r": 10},
{"name": "node6", "r": 10}
],
"edges":[
{"source": 2, "target": 0},
{"source": 2, "target": 1},
{"source": 2, "target": 3},
{"source": 2, "target": 4},
{"source": 2, "target": 5}
]
}
],
svg = SVG({width: 600, height: 200-34, margin: {top: 25, right: 5, bottom: 5, left: 5}}, "#viz"),
fdg = FDG(svg, alpha.log);
fdg(dataSets[0]);
function SVG (size, selector){
//delivers an svg background with zoom/drag context in the selector element
//if height or width is NaN, assume it is a valid length but ignore margin
var margin = size.margin || {top: 0, right: 0, bottom: 0, left: 0},
unitW = isNaN(size.width), unitH = isNaN(size.height),
w = unitW ? size.width : size.width - margin.left - margin.right,
h = unitH ? size.height : size.height - margin.top - margin.bottom,
zoomed = function(){return this},
zoom = d3.behavior.zoom().scaleExtent([0.4, 4])
.on("zoom", function(d, i, j){
zoomed.call(this, d, i, j);
}),
svg = d3.select(selector).selectAll("svg").data([["transform root"]]);
svg.enter().append("svg");
svg.attr({width: size.width, height: size.height});
var g = svg.selectAll("#zoom").data(id),
gEnter = g.enter().append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom)
.attr({class: "outline", id: "zoom"}),
zoomText = gEnter.append("text")
.text("transform = translate ( margin.left , margin.top )")
.style("fill", "#5c5c5c")
.attr("dy", "-.35em"),
surface = gEnter.append("rect")
.attr({width: w, height: h})
.style({"pointer-events": "all", fill: "#ccc", "stroke-width": 3, "stroke": "#fff"}),
surfaceText = gEnter.append("text")
.text("pointer-events: none")
.style("fill", "#5c5c5c")
.attr({"dy": "1em", "dx": ".2em"});
g.h = h;
g.w = w;
g.onZoom = function(cb){zoomed = cb;};
return g;
}
function FDG (svg, tickLog) {
var instID = Date.now();
force = d3.layout.force()
.size([svg.w, svg.h])
.charge(-1000)
.linkDistance(50)
.on("end", function(){
// manage dead instances of force
// only stop if this instance is the current owner
if(cog.datum().instID != instID) return true;
cog.classed("fa-spin", false);
elapsedTime.stop();
})
.on("start", function(){
// mark as active and brand the insID to establish ownership
cog.classed("fa-spin", true).datum().instID = instID;
elapsedTime.start();
});
function fdg(data) {
force
.nodes(data.nodes)
.links(data.edges)
.on("tick", (function(instID) {
return function(e) {
if(tickLog) tickLog.call(this, e, instID);
lines.attr("x1", function(d) {
return d.source.x;
}).attr("y1", function(d) {
return d.source.y;
}).attr("x2", function(d) {
return d.target.x;
}).attr("y2", function(d) {
return d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")"
});
}
})(instID))
.start();
svg.onZoom(zoomed);
hookDrag(force.drag(), "dragstart.force", function(d) {
// prevent dragging on the nodes from dragging the canvas
var e = d3.event.sourceEvent;
e.stopPropagation();
d.fixed = e.shiftKey || e.touches && (e.touches.length > 1);
});
hookDrag(force.drag(), "dragend.force", function(d) {
// prevent dragging on the nodes from dragging the canvas
var e = d3.event.sourceEvent;
d.fixed = e.shiftKey || d.fixed;
});
var content = svg.selectAll("g#fdg").data([data]);
content.enter().append("g").attr({"id": "fdg", class: "outline"});
var contentText = content.selectAll(".contentText")
.data(["transform = translate ( d3.event.translate ) scale ( d3.event.scale )"])
.enter().append("text").classed("contentText", true)
.text(id)
.style("fill", "#5c5c5c")
.attr({"dy": 20, "dx": 20});
var lines = content.selectAll(".links")
.data(linksData),
linesEnter = lines.enter()
.insert("line", d3.select("#nodes") ? "#nodes" : null)
.attr("class", "links")
.attr({stroke: "steelblue", "stroke-width": 3});
var nodes = content.selectAll("#nodes")
.data(nodesData),
nodesEnter = nodes.enter().append("g")
.attr("id", "nodes"),
node = nodes.selectAll(".node")
.data(id),
newNode = node.enter().append("g")
.attr("class", "node")
.call(force.drag),
circles = newNode.append("circle")
.attr({class: "content"})
.attr("r", function(d) {return d.r})
.style({"fill": "red", opacity: 0.8});
lines.exit().remove();
node.exit().remove();
function nodesData(d) {
return [d.nodes];
}
function linksData(d) {
return d.edges;
}
function hookDrag(target, event, hook) {
//hook force.drag behaviour
var stdDragStart = target.on(event);
target.on(event, function(d) {
hook.call(this, d);
stdDragStart.call(this, d);
});
}
function zoomed(){
var e = d3.event.sourceEvent,
isWheel = e && ((e.type == "mousewheel") || (e.type == "wheel"));
force.alpha(0.01);
return isWheel ? zoomWheel.call(this) : zoomInst.call(this)
}
function zoomInst(){
var t = d3.transform(content.attr("transform"));
t.translate = d3.event.translate; t.scale = d3.event.scale;
content.attr("transform", t.toString());
}
function zoomWheel(){
var t = d3.transform(content.attr("transform"));
t.translate = d3.event.translate; t.scale = d3.event.scale;
content.transition().duration(450).attr("transform", t.toString());
}
fdg.force = force;
};
return fdg
}
function id(d){return d;}
svg {
outline: 1px solid #282f51;
pointer-events: all;
overflow: visible;
}
g.outline {
outline: 1px solid red;
}
#panel div {
display: inline-block;
margin: 0 .25em 3px 0;
}
#panel div div {
white-space: pre;
}
div#inputDiv {
white-space: normal;
display: inline-block;
}
.node {
cursor: default;
}
text {
font-size: 8px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://gitcdn.xyz/repo/cool-Blue/40e550b1507cca31b0bb/raw/b83ceb0f8b4a2b6256f079f5887fc5243baedd4f/elapsed%2520time%25201.0.js"></script>
<div id="panel">
<div id="inputDiv">
<input id="update" type="button" value="update">
</div>
<div id="wrapAlpha">alpha:
<div id="alpha"></div>
</div>
<div id="fdg">
</div>
<div id="viz"></div>
这篇关于强制布局拖动行为,在缩放时进行转换,但拖动时没有转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!