Reputation: 14299
All the other examples have mouse events with svg.append().... I don't know where to "enter" to get the arcs in a canvas renderer and add .on('click', function(){})
in v4 style. I want to click to get the value of d
. Where do I add the handler in this example? I understand the old way below this example.
Might something like this work? d3.select(canvas).call(d3.mouse()).on("click", ...)
link to working example
var links = d3.range(nodes.length - 1).map(function(i) {
return {
source: Math.floor(Math.sqrt(i)),
target: i + 1
};
});
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody())
.force("link", d3.forceLink(links).distance(20).strength(1))
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", ticked);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
width = canvas.width,
height = canvas.height;
d3.select(canvas)
.call(d3.drag()
.container(canvas)
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function ticked() {
context.clearRect(0, 0, width, height);
context.save();
context.translate(width / 2, height / 2);
context.beginPath();
links.forEach(drawLink);
context.strokeStyle = "#aaa";
context.stroke();
context.beginPath();
nodes.forEach(drawNode);
context.fill();
context.strokeStyle = "#fff";
context.stroke();
context.restore();
}
function dragsubject() {
return simulation.find(d3.event.x - width / 2, d3.event.y - height / 2);
}
function dragstarted() {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d3.event.subject.fx = d3.event.subject.x;
d3.event.subject.fy = d3.event.subject.y;
}
function dragged() {
d3.event.subject.fx = d3.event.x;
d3.event.subject.fy = d3.event.y;
}
function dragended() {
if (!d3.event.active) simulation.alphaTarget(0);
d3.event.subject.fx = null;
d3.event.subject.fy = null;
}
function drawLink(d) {
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
}
function drawNode(d) {
context.moveTo(d.x + 3, d.y);
context.arc(d.x, d.y, 3, 0, 2 * Math.PI);
}
old way
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 8)
.attr("fill", function(d) { return color(d.group); })
.on("click", togglenode)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
Upvotes: 2
Views: 2528
Reputation: 1115
Expanded FlavorScape's hack with double click
d3.select(canvas)
.call(d3.drag()
.container(canvas)
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var clickDate = new Date();
var difference_ms;
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d3.event.subject.fx = d3.event.subject.x;
d3.event.subject.fy = d3.event.subject.y;
difference_ms = (new Date()).getTime() - clickDate.getTime();
clickDate = new Date();
//if clicks less than 200ms apart (double click)
if(difference_ms < 200)
console.log( d3.event.subject );
}
Upvotes: 1
Reputation: 14299
Since I used the canvas renderer, I just cheated and used the d3 dragstart event already in the example. There's probably a way to do it like this I'd like to know.
d3.select(canvas)
.call(d3.drag()
.container(canvas)
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d3.event.subject.fx = d3.event.subject.x;
d3.event.subject.fy = d3.event.subject.y;
//broadcast the selection to parent
emitter.emit( d3.event.subject );
}
Upvotes: 2
Reputation: 102194
In D3 v4.x, you add a click event pretty much the same way you do in v3.x:
selection.on("click", function(d){
//do whatever you want with the datum
});
The problem in your question is not v3 versus v4, that's not the issue in the code you shared. The problem with that code is that it uses HTML canvas, not SVG, to render the dataviz.
Unlike SVG, canvas doesn't have a node tree of elements. You cannot "select something" and add an event handler to it.
Think of canvas as a raster image, like a BMP or a JPEG. You can find on what x and y position you clicked, you can even find the colour of that pixel, but you cannot select a given node element, because canvas has none.
For instance, check this tutorial from Nadieh Bremer to see how complicated is to get the circle the user clicks on when you use HTML canvas.
Upvotes: 3