cursor freeze elements when added zoom on D3 map - javascript

I would like to add zoom on my D3 map but when I click on a node, drag and drop this, my cursor fix all elements. I added .call(d3.zoom()) but
code component from angular 4 :
ngOnInit(){
}
ngAfterViewInit(){
//this.svg = d3.select("svg");
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function (event) {
let g = d3.select('svg > g');
g.attr("transform", d3.event.transform);
}))
.append("g");
let width = d3.select('svg').style("width");
let height = d3.select('svg').style("height");
width = width.substring(0, width.length - 2);
height = height.substring(0, height.length - 2);
this.color = d3.scaleOrdinal(d3.schemeCategory20);
this.simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
this.render(miserables);
}
ticked() {
this.link
.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; });
this.node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
render(graph){
this.link = this.svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
this.node = this.svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", (d)=> { return this.color(d.group); })
.call(d3.drag()
.on("start", (d)=>{return this.dragstarted(d)})
.on("drag", (d)=>{return this.dragged(d)})
.on("end", (d)=>{return this.dragended(d)}));
this.node.append("title")
.text(function(d) { return d.id; });
this.simulation
.nodes(graph.nodes)
.on("tick", ()=>{return this.ticked()});
this.simulation.force("link")
.links(graph.links);
}
dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
dragended(d) {
if (!d3.event.active) this.simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
dragstarted(d) {
if (!d3.event.active) this.simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
ngOnDestroy(){
}
If I replace this :
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%");
by this :
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function (event) {
let g = d3.select('svg > g');
g.attr("transform", d3.event.transform);
}))
.append("g");
Zoom works, but I have a problem when I selected a node to drag and drop, the cursor fix on all elements
My problem :
https://angular-tspcs9.stackblitz.io/
To edit :
https://stackblitz.com/edit/angular-tspcs9

I added :
.on("mousedown", function() {
d3.event.stopPropagation();
});
on my svg declaration :
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function (event) {
let g = d3.select('svg > g');
g.attr("transform", d3.event.transform);
}))
.append("g")
.on("mousedown", function() {
d3.event.stopPropagation();
});

Related

D3 nodes floating out of the frame

I got several nodes and links in place. Unfortunately those are "floating" out of the canvas. I am using D3.V4.js and found several guides how to solve the problem with D3.v3.js. Unfortuantely those doesn´t seem to work. Ideally a hidden or transparent frame would be arranged around the canvas area. I am new building D3 graphs, so I couldn´t figure it out yet.
Maybe you guys could help me to adjust the correct line in my code.
Thanks
var svg = d3.select("svg"),
width = window.innerWidth,
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(100))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force("attraceForce",d3.forceManyBody().strength(-2));
var opacity = 0.25;
d3.json("datav2.json", function(error, graph) {
if (error) throw error;
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.style("stroke-width", 3)
.style("stroke-linecap", "round")
.attr("linkGroup",function(d) {return d.linkGroup; })
.attr("stroke-width", function(d) { return d.value; })
;
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 15)
.attr("fill", "#ffffff")
.style("stroke-width", 2)
.style("stroke", function(d) { return color(d.group); })
.attr("nodeGroup",function(d) {return d.nodeGroup; })
.on("click", function(d) {
// This is to toggle visibility - need to do it on the nodes and links
d3.selectAll("line:not([linkGroup='"+d.nodeGroup+"'])")
.style("opacity", function() {
currentDisplay = d3.select(this).style("opacity");
currentDisplay = currentDisplay == "1" ? "0.1" : "1";
return currentDisplay;
});
d3.selectAll("circle:not([nodeGroup='"+d.nodeGroup+"'])")
.style("opacity",function() {
currentDisplay = d3.select(this).style("opacity");
currentDisplay = currentDisplay == "1" ? "0.1" : "1";
return currentDisplay;
});
d3.selectAll("text:not([nodeGroup='"+d.nodeGroup+"'])")
.style("opacity",function() {
currentDisplay = d3.select(this).style("opacity");
currentDisplay = currentDisplay == "1" ? "0.1" : "1";
return currentDisplay;
});
})
.on("mouseover", function(d) {
d3.select(this).style("cursor", "crosshair");
})
.on("mouseout", function(d) {
d3.select(this).style("cursor", "default");
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
// This is the label for each node
var text = svg.append("g").selectAll("text")
.data(graph.nodes)
.enter().append("text")
.attr("dy",-25)
.text(function(d) { return d.name;})
.attr("text-anchor", "middle")
.attr("nodeGroup",function(d) {return d.nodeGroup;} ) ;
node.append("title")
.text(function(d) { return d.name; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function neighboring(a, b) {
return graph.links.some(function(d) {
return (d.source.id === a.source.id && d.target.id === b.target.id)
|| (d.source.id === b.source.id && d.target.id === a.target.id);
});
}
function ticked() {
link
.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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
//.attr("cx2", function(d) { return d.x = Math.max(d.width, Math.min(width - d.width, d.x)); })
//.attr("cy2", function(d) { return d.y = Math.max(d.height, Math.min(height - heightDelta - d.height, d.y)); });
text
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
Ok I found the issue and added a radius var with a size which fits to the nodes and modified the following line:
node
.attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); })

Center visualization in viewbow D3

I created a D3 visualization, but after the complete load, my visualisation isn't center :
I would like to have this result :
I use Angular 5 to execute my D3 visualization. My Data is loaded, it's work, but my visualization is on the left and not center. I would like to center my visualization. My code from my component :
export class BrainPageHomeComponent implements OnInit, AfterViewInit, OnDestroy {
public name: string;
public svg;
public color;
public simulation;
public link;
public node;
public miserables;
public tooltip;
constructor(
private brainService: BrainService,
) {
}
ngOnInit() {
}
ngAfterViewInit() {
this.loadBrain();
}
//Load Brain
public loadBrain() {
d3.select("svg").remove();
this.brainService.getBrain().subscribe(
data => {
this.miserables = data['data'];
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function () {
let g = d3.select('svg > g');
g.attr("transform", d3.event.transform);
}))
.append("g");
let width = +this.svg.attr("width");
let height = +this.svg.attr("height");
this.color = d3.scaleOrdinal(d3.schemeCategory20);
this.simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
this.render(this.miserables);
},
error => {
console.log(error);
});
}
ticked() {
this.link
.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;
});
this.node
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
}
render(graph) {
let tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip-message")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden");
this.link = this.svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function (d) {
return Math.sqrt(d.value);
});
this.node = this.svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", (d) => {
return this.color(d.group);
})
//npm .on("click", function(d, i) { alert("Hello world"); })
.on("mouseover", function(node){
console.log(node);
tooltip.text(node.title);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function(){return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");})
.call(d3.drag()
.on("start", (d) => {
return this.dragstarted(d)
})
.on("drag", (d) => {
return this.dragged(d)
})
.on("end", (d) => {
return this.dragended(d)
}));
this.node.append("title")
.text(function (d) {
return d.id;
});
this.simulation
.nodes(graph.nodes)
.on("tick", (nodes) => {
return this.ticked()
})
.stop();
this.simulation.force("link")
.links(graph.links);
this.simulation.restart();
}
dragstarted(d) {
if (!d3.event.active) this.simulation.alphaTarget(0.3).restart();
d.fx = d.x, d.fy = d.y;
}
dragged(d) {
d.fx = d3.event.x, d.fy = d3.event.y;
}
dragended(d) {
if (!d3.event.active) this.simulation.alphaTarget(0);
d.fx = null, d.fy = null;
}
ngOnDestroy() {
}
}
I tried many things :
Added viewBox attribute :
this.svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function () {
let g = d3.select('svg > g');
g.attr("transform", d3.event.transform);
}))
.attr("viewBox", "0 0 " + "100%" + " " + "100%" )
.attr("preserveAspectRatio", "xMidYMid meet");
.append("g");
Added restart simulation :
this.simulation.restart();
But my visualization is always on the left and not center.
I fixed my problem :
I replaced :
let width = +this.svg.attr("width");
let height = +this.svg.attr("height");
by :
let width = d3.select('svg').style("width");
let height = d3.select('svg').style("height");
width = width.substring(0, width.length - 2);
height = height.substring(0, height.length - 2);

D3 assigning nodes labels

I'm trying to make a d3 force graph, however I can't manage to let the labels work. Sometimes text pops up in the top of the screen. How do I assign each node a label (the label being its id).
JSFIDDLE
This is what i've tried:
var label = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("text")
.attr("class", "label")
.text("test")
And an extra question, how do I get arrowheads on my lines?
Group circle and text inside a group element. You can use marker-end property to add end markers to the line.
There are marker-mid and marker-start configs too.
var graph = JSON.parse('{"nodes":[{"id":"0","color":"#4444E5"},{"id":"1","color":"#4444E5"},{"id":"2","color":"#CCCCCC"},{"id":"3","color":"#CCCCCC"},{"id":"4","color":"#CCCCCC"},{"id":"5","color":"#CCCCCC"},{"id":"6","color":"#CCCCCC"},{"id":"7","color":"#CCCCCC"},{"id":"8","color":"#CCCCCC"},{"id":"9","color":"#CCCCCC"},{"id":"10","color":"#cc0000"},{"id":"11","color":"#CCCCCC"},{"id":"12","color":"#CCCCCC"},{"id":"13","color":"#CCCCCC"},{"id":"14","color":"#CCCCCC"},{"id":"15","color":"#cc0000"}],"links":[{"source":1,"target":15,"weight":-0.7582412523901727},{"source":0,"target":6,"weight":-0.08179822732917646},{"source":6,"target":10,"weight":0.0939757437427291},{"source":3,"target":4,"weight":0.436380368086641},{"source":4,"target":5,"weight":-0.5385567058738547},{"source":1,"target":2,"weight":-0.277729004201837},{"source":2,"target":3,"weight":0.7675128737907505},{"source":13,"target":14,"weight":0.5519067984674436},{"source":14,"target":15,"weight":0.832660697502495},{"source":5,"target":7,"weight":0.8607887414383458},{"source":7,"target":8,"weight":-0.8965760877371078},{"source":8,"target":9,"weight":-0.2488791800975232},{"source":9,"target":10,"weight":-0.646075500567235},{"source":12,"target":13,"weight":0.40622804770087395},{"source":0,"target":11,"weight":0.24806004723386413},{"source":11,"target":12,"weight":0.8035303834469385}]}');
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var defs = svg.append("defs")
var marker = defs
.append("svg:marker")
.attr("id", "arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
marker.append("path")
.attr("d", "M0,-5L10,0L0,5")
.attr("class", "arrowHead");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) {
return Math.sqrt(d.weight);
}).attr("marker-end", "url(#arrow)")
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("g");
node.append("circle")
.attr("r", 5)
.attr("fill", function(d) {
return d3.color(d.color);
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var label = node.append("text")
.attr("class", "label")
.text("test")
node.append("title")
.text(function(d) {
return d.id;
});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
link
.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 + ")";
});
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
line {
stroke: black;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="600"></svg>
Your texts are not part of the simulation. Besides that, when you do...
var label = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("text")
... your "enter" selection will have one element less, because there is already a <g> element with class node in that SVG.
Solution: append both circles and texts to groups:
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("foo")
.data(graph.nodes)
.enter().append("g");
var circles = node.append("circle")
.attr("r", 5)
.attr("fill", function(d) {
return d3.color(d.color);
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var label = node.append("text")
.attr("class", "label")
.text("test");
And use transform in the ticked function:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
Here is your updated code:
var graph = JSON.parse('{"nodes":[{"id":"0","color":"#4444E5"},{"id":"1","color":"#4444E5"},{"id":"2","color":"#CCCCCC"},{"id":"3","color":"#CCCCCC"},{"id":"4","color":"#CCCCCC"},{"id":"5","color":"#CCCCCC"},{"id":"6","color":"#CCCCCC"},{"id":"7","color":"#CCCCCC"},{"id":"8","color":"#CCCCCC"},{"id":"9","color":"#CCCCCC"},{"id":"10","color":"#cc0000"},{"id":"11","color":"#CCCCCC"},{"id":"12","color":"#CCCCCC"},{"id":"13","color":"#CCCCCC"},{"id":"14","color":"#CCCCCC"},{"id":"15","color":"#cc0000"}],"links":[{"source":1,"target":15,"weight":-0.7582412523901727},{"source":0,"target":6,"weight":-0.08179822732917646},{"source":6,"target":10,"weight":0.0939757437427291},{"source":3,"target":4,"weight":0.436380368086641},{"source":4,"target":5,"weight":-0.5385567058738547},{"source":1,"target":2,"weight":-0.277729004201837},{"source":2,"target":3,"weight":0.7675128737907505},{"source":13,"target":14,"weight":0.5519067984674436},{"source":14,"target":15,"weight":0.832660697502495},{"source":5,"target":7,"weight":0.8607887414383458},{"source":7,"target":8,"weight":-0.8965760877371078},{"source":8,"target":9,"weight":-0.2488791800975232},{"source":9,"target":10,"weight":-0.646075500567235},{"source":12,"target":13,"weight":0.40622804770087395},{"source":0,"target":11,"weight":0.24806004723386413},{"source":11,"target":12,"weight":0.8035303834469385}]}');
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) {
return Math.sqrt(d.weight);
})
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("foo")
.data(graph.nodes)
.enter().append("g");
var circles = node.append("circle")
.attr("r", 5)
.attr("fill", function(d) {
return d3.color(d.color);
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var label = node.append("text")
.attr("class", "label")
.text("test");
node.append("title")
.text(function(d) {
return d.id;
});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
link
.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 + ")";
})
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="400"></svg>

D3.js - Labeling nodes with image in Force-Layout

I have the following code in my Codepen that's able to render the sprites flags (from CSS), yet it's not in the position where it should be based on the nodes's position.
In fact, I am able to drag the nodes from the flags sprites from the top!
Looking at some console.logs, it seems that d.x and d.y position from function ticked() is not passing when the nodes are called.
I am not sure how to fix this issue
const width = w - (margin.left + margin.right);
const height = h - (margin.top + margin.bottom);
let flagNodes = d3.select("#canvas")
.append("div")
.classed("flag-nodes",true)
let svg = d3.select("#canvas")
.append("svg")
.attr("id","chart")
.attr("width", w)
.attr("height", h)
let chart = svg.append("g")
.classed("display", true)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d,i) {
return i;
}))
.force("charge", d3.forceManyBody().strength(-4))
.force("center", d3.forceCenter(width/2, height/2))
let node = flagNodes.selectAll(".flag-nodes")
.data(data.nodes)
.enter()
.append("div")
.attr("class", function(d,i){
return `flag flag-${d.code}`
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
)
let link = chart.append("g")
.classed("links",true)
.selectAll("line")
.data(data.links)
.enter()
.append("line")
node.append("title")
.text(function(d) { return d.country; });
simulation
.nodes(data.nodes)
.on("tick", ticked);
simulation.force("link")
.links(data.links);
//functions provided by D3.js
//
function ticked() {
link
.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
.style("left", function(d) {return d.x})
.style("top", function(d) {return d.y});
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
Codepen
You are super close! This took me quite a while to figure out.
I ended up creating a flag folder filled with country pngs in my project directory. Then dynamically loaded them using the country code.
Here is how I solved the problem:
const node = svg.selectAll(".flag")
.data(data.nodes)
.enter().append("image")
.attr("xlink:href", d => require(`./flag/${d.code}.png`))
.attr("width", radius)
.attr("height", radius)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))

d3.js: Drag is disabled when use zoom with force layout

I have seen this question: Is there a way to zoom into a D3 force layout graph?
But I got some unexpected behaivor from my graph - after few drags or zoom or pan all nodes just freezes and drag stop working.
I created this fiddle: http://jsfiddle.net/7gpweae9/9/
SO asked for code, so here is main part:
var svg = d3.select("#graph")
.append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-event", "all")
.append("svg:g")
.call(d3.behavior.zoom().on("zoom", zoom))
.append("svg:g");
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr('fill', 'white');
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([width,height])
.linkDistance(100)
.charge(-400)
.start();
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(drag);
node.append("circle")
.attr("class", "node-circle")
.attr("r", 12);
node.append("text")
.attr("x", 12)
.attr("y", ".35em")
.text(function(d) { return d.word; });
link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
force.on("tick", function() {
link.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 + ")";
});
});
function zoom() {
svg.attr("transform",
"translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("x", d.x = d3.event.x).attr("y", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
Perhaps I missed something, I never used d3 before.
UPD: It seems that freezing occurs after a certain period of time.
I replaced d3.layout.force() to force.drag() and now it works almost fine.
var nodes;
var links;
prepareData();
var graph = document.querySelectorAll("#graph")[0];
var height = 500;
var width = 500;
var svg = d3.select("#graph").append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-event", "all")
.append("svg:g")
.call(d3.behavior.zoom().on("zoom", zoom))
.append("svg:g");
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr('fill', 'white');
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([width,height])
.linkDistance(100)
.charge(-400)
.start();
var drag = force.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(drag);
node.append("circle")
.attr("class", "node-circle")
.attr("r", 12);
node.append("text")
.attr("x", 12)
.attr("y", ".35em")
.text(function(d) { return d.word; });
link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
force.on("tick", function() {
link.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 + ")"; });
});
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
}
function dragged(d) {
d3.select(this).attr("x", d.x = d3.event.x).attr("y", d.y = d3.event.y);
}
function prepareData() {
nodes = [{"index":0,"word":"edit"},{"index":1,"word":"course","sentences":[29859]},{"index":2,"word":"needs","sentences":[29859]},{"index":3,"word":"fit","sentences":[29859]},{"index":4,"word":"slides","sentences":[29859]},{"index":5,"word":"print","sentences":[29859]},{"index":6,"word":"can","sentences":[29859]}];
links = [{"source":0,"target":1},{"source":0,"target":2},{"source":0,"target":3},{"source":0,"target":4},{"source":0,"target":5},{"source":0,"target":6}]
}
svg {
border: 1px solid black;
}
.link {
stroke: #000;
stroke-width: 1px;
}
.node-circle {
cursor: move;
fill: #ccc;
stroke: #000;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div id="graph"></div>
</body>
You had to make your drag variable a function and change d3.behaviour.drag to force.drag :
function drag(){
return force.drag()
// .origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
}
Ive updated your fiddle
Working JSFIDDLE : http://jsfiddle.net/7gpweae9/15/

Categories