强制布局拖动行为

强制布局拖动行为

本文介绍了强制布局拖动行为,在缩放时进行转换,但拖动时没有转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
> 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>

这篇关于强制布局拖动行为,在缩放时进行转换,但拖动时没有转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 21:23