Event handling
selection.on()
const countries = [
{name: "Germany", population: 84_270_625},
{name: "France", population: 68_042_591},
{name: "Spain", population: 47_222_613},
{name: "the Netherlands", population: 17_882_900},
{name: "Sweden", population: 10_481_937},
];
const scaleFactor = 1/1000000;
const largestPopulation = d3.max(countries, d => d.population);
const display = d3.select("#display");
const svg = d3.select("body")
.insert("svg", "#display")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", `0 0 ${countries.length * (Math.sqrt(scaleFactor * largestPopulation) + 1)} ${Math.sqrt(scaleFactor * largestPopulation)}`);
const rects = svg.selectAll("rect")
.data(countries)
.join("rect")
.attr("x", (d, i) => i * (Math.sqrt(scaleFactor * largestPopulation) + 1) )
.attr("width", (d, i) => Math.sqrt(scaleFactor * d.population) )
.attr("height", (d, i) => Math.sqrt(scaleFactor * d.population) )
.on("click", (e, d) => display.text(`You clicked on ${d.name}`) )
.on("mouseover", function (e, d) {
d3.select(this)
.style('fill', 'orange');
})
.on("mouseout", function (e, d) {
d3.select(this)
.style('fill', 'steelblue');
});
Result:
Note that this
is a DOM element and not a D3 selection; it needs d3.select(this)
first to turn it into a selection.
And also note that this
in an arrow function event handler refers to the global object (or to undefined
in strict mode).
pointer()
Next example uses the native JavaScript properties pageX
and pageY
of the
MouseEvent
interface.
const vehicles = [
{ name: "Dump truck", pathAttr: "M0 …" },
{ name: "Excavator", pathAttr: "M16.997 …" },
{ name: "Car", pathAttr: "M23.5 …" },
{ name: "Bus", pathAttr: "M8.829 …" },
];
const colorScale = d3.scaleOrdinal().range(d3.schemeSet1); // *) see below
const tooltip = d3.select('body')
.append("span")
.style("position", "absolute");
const svg = d3.select("#tooltipSVG");
svg.selectAll("path")
.data(vehicles)
.join("path")
.attr("d", d => d.pathAttr)
.style("fill", (d,i) => colorScale(i))
.attr("transform", (d,i) => `translate(${i*35},0)`)
.on('mouseover', function(e, d) {
tooltip.text(d.name);
})
.on("mousemove", function(e, d) {
tooltip
.style('left', e.pageX + 'px')
.style('top', e.pageY - 30 + 'px');
})
.on("mouseout", function(e, d) {
tooltip.text(" ");
});
Result:
Hover over the figures:
SVG graphics from iconmonstr.
*): Scales will be covered later. The used color scale in this example is a Ordinal scale.
pageX
and pageY
return the x and y coordinates (in pixels) of the mouse position,
relative to the top-left corner of the entire document. This includes any portion of the document not currently visible.
d3.pointer
represents the coordinates of the specified event relative to the specified target:
const display = d3.select("#display");
d3.select("body")
.insert("svg", "#display")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 200 50")
.style("background", "tan")
.style("cursor", "crosshair")
.on("mousemove", function(e, d) {
const [x, y] = d3.pointer(e); // (array destructuring)
display.text(`${Math.round(x)}, ${Math.round(y)}`);
})
.on("mouseout", function(e, d) {
display.text("Hover over the square...");
});
Result: