I'm trying to change the cursor when I drag on a SVG but the cursor change only fires when the mouse button is released. Works perfectly, however, in Firefox.
I'm using Chrome Version 50.0.2661.102 m.
This is the jQuery I'm using:
$('#map')
.mousedown(function(){
$(this).css( 'cursor', 'move' );
})
.mouseup(function(){
$(this).css( 'cursor', 'auto' );
});
BUT the code snippet I added below actually works as it should, yet the fiddle I created doesn't, nor does my actual code on the site I'm building.
How can I do this differently for Chrome so it works always?
var graph = {
"nodes":[
{"name":"1","rating":90,"id":2951},
{"name":"2","rating":80,"id":654654},
{"name":"3","rating":80,"id":6546544},
{"name":"4","rating":1,"id":68987978},
{"name":"5","rating":1,"id":9878933},
{"name":"6","rating":1,"id":6161},
{"name":"7","rating":1,"id":64654},
{"name":"8","rating":20,"id":354654},
{"name":"9","rating":50,"id":8494},
{"name":"10","rating":1,"id":6846874},
{"name":"11","rating":1,"id":5487},
{"name":"12","rating":80,"id":"parfum_kenzo"},
{"name":"13","rating":1,"id":65465465},
{"name":"14","rating":90,"id":"jungle_de_kenzo"},
{"name":"15","rating":20,"id":313514},
{"name":"16","rating":40,"id":36543614},
{"name":"17","rating":100,"id":"Yann_YA645"},
{"name":"18","rating":1,"id":97413},
{"name":"19","rating":1,"id":97414},
{"name":"20","rating":100,"id":976431231},
{"name":"21","rating":1,"id":9416},
{"name":"22","rating":1,"id":998949},
{"name":"23","rating":100,"id":984941},
{"name":"24","rating":100,"id":"99843"},
{"name":"25","rating":1,"id":94915},
{"name":"26","rating":1,"id":913134},
{"name":"27","rating":1,"id":9134371}
],
"links":[
{"source":6,"target":5,"value":6, "label":"publishedOn"},
{"source":8,"target":5,"value":6, "label":"publishedOn"},
{"source":7,"target":1,"value":4, "label":"containsKeyword"},
{"source":8,"target":10,"value":3, "label":"containsKeyword"},
{"source":7,"target":14,"value":4, "label":"publishedBy"},
{"source":8,"target":15,"value":6, "label":"publishedBy"},
{"source":9,"target":1,"value":6, "label":"depicts"},
{"source":10,"target":1,"value":6, "label":"depicts"},
{"source":16,"target":1,"value":6, "label":"manageWebsite"},
{"source":16,"target":2,"value":5, "label":"manageWebsite"},
{"source":16,"target":3,"value":6, "label":"manageWebsite"},
{"source":16,"target":4,"value":6, "label":"manageWebsite"},
{"source":19,"target":18,"value":2, "label":"postedOn"},
{"source":18,"target":1,"value":6, "label":"childOf"},
{"source":17,"target":19,"value":8, "label":"describes"},
{"source":18,"target":11,"value":6, "label":"containsKeyword"},
{"source":17,"target":13,"value":3, "label":"containsKeyword"},
{"source":20,"target":13,"value":3, "label":"containsKeyword"},
{"source":20,"target":21,"value":3, "label":"postedOn"},
{"source":22,"target":20,"value":3, "label":"postedOn"},
{"source":23,"target":21,"value":3, "label":"manageWebsite"},
{"source":23,"target":24,"value":3, "label":"manageWebsite"},
{"source":23,"target":25,"value":3, "label":"manageWebsite"},
{"source":23,"target":26,"value":3, "label":"manageWebsite"}
]
}
var margin = {top: -5, right: -5, bottom: -5, left: -5};
var width = 500 - margin.left - margin.right,
height = 400- margin.top - margin.bottom;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("#map").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "svg")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
//d3.json('http://blt909.free.fr/wd/map2.json', function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.call(drag);
node.append("circle")
.attr("r", function(d) { return d.weight * 2+ 12; })
.style("fill", function(d) { return color(1/d.rating); });
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 + ")"; });
});
var linkedByIndex = {};
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
}
node.on("mouseover", function(d){
node.classed("node-active", function(o) {
thisOpacity = isConnected(d, o) ? true : false;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.classed("link-active", function(o) {
return o.source === d || o.target === d ? true : false;
});
d3.select(this).classed("node-active", true);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", (d.weight * 2+ 12)*1.5);
})
.on("mouseout", function(d){
node.classed("node-active", false);
link.classed("link-active", false);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", d.weight * 2+ 12);
});
function dottype(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
force.start();
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
$('#map')
.mousedown(function(){
$(this).css( 'cursor', 'move' );
})
.mouseup(function(){
$(this).css( 'cursor', 'auto' );
});
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.node-active{
stroke: #555;
stroke-width: 1.5px;
}
.link {
stroke: #555;
stroke-opacity: .3;
}
.link-active {
stroke-opacity: 1;
}
.overlay {
fill: none;
pointer-events: all;
}
#map{
border: 2px #555 dashed;
width:500px;
height:400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<body>
<div id="map"></div>
</body>
(sample SVG code borrowed from http://jsfiddle.net/JSDavi/qvco2Ljy/)
If anyone else comes up against this...this was my scenario:
If you have your Chrome inspector open, that is what causes this to fail, if you close the inspector for the page you're creating this effect on, it works perfectly.
You have:
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
force.start();
}
That call to stopPropagation seems to prevent mouse down event. Unfortunately, changing it to preventDefault changes how drag&drop works (it moves whole graph around, instead of moving single nodes).
If it is only the cursor you need to change, why not use CSS for that? You already seem to change class of node to dragging, so you should be able to simply use following CSS:
.node.dragging {
cursor: move;
}
If you want cursor to change also when whole graph is dragged, you can add dragged class to the #map too:
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
$("#map").addClass("dragging");
d3.select(this).classed("dragging", true);
force.start();
}
// ...
function dragended(d) {
$("#map").removeClass("dragging");
d3.select(this).classed("dragging", false);
}
and then add CSS for that:
#map.dragging {
cursor: move;
}
var graph = {
"nodes":[
{"name":"1","rating":90,"id":2951},
{"name":"2","rating":80,"id":654654},
{"name":"3","rating":80,"id":6546544},
{"name":"4","rating":1,"id":68987978},
{"name":"5","rating":1,"id":9878933},
{"name":"6","rating":1,"id":6161},
{"name":"7","rating":1,"id":64654},
{"name":"8","rating":20,"id":354654},
{"name":"9","rating":50,"id":8494},
{"name":"10","rating":1,"id":6846874},
{"name":"11","rating":1,"id":5487},
{"name":"12","rating":80,"id":"parfum_kenzo"},
{"name":"13","rating":1,"id":65465465},
{"name":"14","rating":90,"id":"jungle_de_kenzo"},
{"name":"15","rating":20,"id":313514},
{"name":"16","rating":40,"id":36543614},
{"name":"17","rating":100,"id":"Yann_YA645"},
{"name":"18","rating":1,"id":97413},
{"name":"19","rating":1,"id":97414},
{"name":"20","rating":100,"id":976431231},
{"name":"21","rating":1,"id":9416},
{"name":"22","rating":1,"id":998949},
{"name":"23","rating":100,"id":984941},
{"name":"24","rating":100,"id":"99843"},
{"name":"25","rating":1,"id":94915},
{"name":"26","rating":1,"id":913134},
{"name":"27","rating":1,"id":9134371}
],
"links":[
{"source":6,"target":5,"value":6, "label":"publishedOn"},
{"source":8,"target":5,"value":6, "label":"publishedOn"},
{"source":7,"target":1,"value":4, "label":"containsKeyword"},
{"source":8,"target":10,"value":3, "label":"containsKeyword"},
{"source":7,"target":14,"value":4, "label":"publishedBy"},
{"source":8,"target":15,"value":6, "label":"publishedBy"},
{"source":9,"target":1,"value":6, "label":"depicts"},
{"source":10,"target":1,"value":6, "label":"depicts"},
{"source":16,"target":1,"value":6, "label":"manageWebsite"},
{"source":16,"target":2,"value":5, "label":"manageWebsite"},
{"source":16,"target":3,"value":6, "label":"manageWebsite"},
{"source":16,"target":4,"value":6, "label":"manageWebsite"},
{"source":19,"target":18,"value":2, "label":"postedOn"},
{"source":18,"target":1,"value":6, "label":"childOf"},
{"source":17,"target":19,"value":8, "label":"describes"},
{"source":18,"target":11,"value":6, "label":"containsKeyword"},
{"source":17,"target":13,"value":3, "label":"containsKeyword"},
{"source":20,"target":13,"value":3, "label":"containsKeyword"},
{"source":20,"target":21,"value":3, "label":"postedOn"},
{"source":22,"target":20,"value":3, "label":"postedOn"},
{"source":23,"target":21,"value":3, "label":"manageWebsite"},
{"source":23,"target":24,"value":3, "label":"manageWebsite"},
{"source":23,"target":25,"value":3, "label":"manageWebsite"},
{"source":23,"target":26,"value":3, "label":"manageWebsite"}
]
}
var margin = {top: -5, right: -5, bottom: -5, left: -5};
var width = 500 - margin.left - margin.right,
height = 400- margin.top - margin.bottom;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("#map").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "svg")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
//d3.json('http://blt909.free.fr/wd/map2.json', function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.call(drag);
node.append("circle")
.attr("r", function(d) { return d.weight * 2+ 12; })
.style("fill", function(d) { return color(1/d.rating); });
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 + ")"; });
});
var linkedByIndex = {};
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
}
node.on("mouseover", function(d){
node.classed("node-active", function(o) {
thisOpacity = isConnected(d, o) ? true : false;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.classed("link-active", function(o) {
return o.source === d || o.target === d ? true : false;
});
d3.select(this).classed("node-active", true);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", (d.weight * 2+ 12)*1.5);
})
.on("mouseout", function(d){
node.classed("node-active", false);
link.classed("link-active", false);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", d.weight * 2+ 12);
});
function dottype(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
$("#map").addClass("dragging");
d3.select(this).classed("dragging", true);
force.start();
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
$("#map").removeClass("dragging");
d3.select(this).classed("dragging", false);
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.node.dragging,
#map.dragging {
cursor: move;
}
.node-active{
stroke: #555;
stroke-width: 1.5px;
}
.link {
stroke: #555;
stroke-opacity: .3;
}
.link-active {
stroke-opacity: 1;
}
.overlay {
fill: none;
pointer-events: all;
}
#map{
border: 2px #555 dashed;
width:500px;
height:400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<body>
<div id="map"></div>
</body>
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/