const scores = [ { name: "Alice", score: 96 }, { name: "Billy", score: 83 }, { name: "Cindy", score: 81 }, { name: "David", score: 96 }, { name: "Emily", score: 88 } ]; function scaleBar(selection, scale) { selection.style('transform', `scaleX(${scale})`); } function fade(selection, opacity) { selection.style('fill-opacity', opacity); } function setFill(selection, color) { selection.style('fill', color); } const bar = d3.select(".chart") .append('svg') .attr('width', 225) .attr('height', 300) // 5 * 33 = 165 < 300 .selectAll("g") .data(scores) .enter() // In D3, the SVG is used as a generic container like a HTML
. .append("g") // D3 convention: d for data, i for index. // doesn't support x,y, but needs transform. // translate take a comma-separated list of x,y coordinates. .attr('transform', (d, i) => 'translate(0, ' + i * 33 + ')'); // Notice how we don't pass data again or use a loop: they are included in the selection. bar.append('rect') .style("width", d => d.score) .text(d => d.name) .attr("class", "bar") .on('mouseover', function (d, i, elements) { d3.select(this) .call(scaleBar, 1.5) .call(setFill, 'orange'); d3.selectAll(elements) .filter(':not(:hover)') .call(fade, 0.2); }) .on('mouseout', function (d, i, elements) { d3.select(this) .call(scaleBar, 1) // call returns the (modified) selection. .call(setFill, 'palegreen'); // ...which allows chaining. d3.selectAll(elements) .call(fade, 1); }) .on('click', (who) => console.log(`hi ${who.name}`)); bar.append('text') .attr('y', 20) .text(d => d.name);