D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jo6gauri
Full window
Github gist
Assignment 5 - Interaction in D3
<!DOCTYPE html> <!-- Example based on https://blockbuilder.org/mbostock/3884955 --> <!-- Example based on https://bl.ocks.org/mbostock/8033015 --> <!-- Example based on https://bl.ocks.org/mbostock/4015254 --> <!-- Example based on https://bl.ocks.org/davidshinn/7917466 --> <!-- Example based on https://bl.ocks.org/Matthew-Weber/5645518 --> <!-- Example based on https://bl.ocks.org/lorenzopub/6a56e17551d59278631dffd7f65a0cda --> <!-- Example based on https://bl.ocks.org/EfratVil/92f894ac0ba265192411e73f633a3e2f --> <!-- Example based on https://bl.ocks.org/natemiller/7dec148bb6aab897e561 --> <meta charset="utf-8"> <div id="chart"></div> <style> .axis--x path { display: none; } .line { fill: none; stroke: steelblue; stroke-width: 1.5px; } .brush .extent { stroke: #fff; fill-opacity: .125; shape-rendering: crispEdges; } .line.highlight { fill-opacity: 1; stroke-opacity: 1; } .line.fadeout { fill-opacity: 0.2; stroke-opacity: 0.2; } .city--hover { stroke: #000; stroke-width: 4px; } button { position: absolute; top: 500px; left: 80px; } .focus text { text-anchor: middle; text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff; fill: darkmagenta; } .voronoi path { fill: none; pointer-events: all; } .voronoi--show path { stroke: darkslategray; stroke-opacity: 0.3; } #form { position: absolute; top: 503px; left: 200px; } </style> <svg width="960" height="500"></svg> <body> <button>Reset</button> <label id="form" for="show-voronoi"> Show Voronoi <input type="checkbox" id="show-voronoi" disabled> </label> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var margin = { top: 20, right: 80, bottom: 50, left: 50 }, width = 1000 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var svg = d3.select('#chart') .append("svg:svg") .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append("svg:g") .attr("id", "group"), g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var parseTime = d3.timeParse("%Y%m%d"); bisectDate = d3.bisector(function (d) { return d.dt; }).left; var x = d3.scaleTime().range([0, width]), y = d3.scaleLinear().range([height, 0]), z = d3.scaleOrdinal(d3.schemeCategory10); var line = d3.line() .curve(d3.curveBasis) .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.temperature); }); var voronoi = d3.voronoi() .x(function (d) { return x(d.dt); }) .y(function (d) { return y(d.temperature); }) .extent([ [-margin.left, -margin.top], [width + margin.right, height + margin.bottom] ]); function transformData(data) { var newData = []; data.forEach(function (d) { for (key in d) { if (key !== 'date' && newData.indexOf(key) === -1) { newData.push({ city: key, dt: d.date, temperature: d[key] }); } } }); return newData; } d3.tsv("data.tsv", type, function (error, data) { if (error) throw error; var structuredData = transformData(data); var cities = data.columns.slice(1).map(function (id) { return { id: id, values: data.map(function (d) { return { date: d.date, temperature: d[id] }; }) }; }); var date_max = d3.max(structuredData, function (d) { return d.dt; }); x.domain(d3.extent(data, function (d) { return d.date; })); y.domain([ d3.min(cities, function (c) { return d3.min(c.values, function (d) { return d.temperature; }); }), d3.max(cities, function (c) { return d3.max(c.values, function (d) { return d.temperature; }); }) ]); z.domain(cities.map(function (c) { return c.id; })); var zoom = d3.zoom() .scaleExtent([0.75, 15000]) .translateExtent([ [-100000, -100000], [100000, 100000] ]) .on("zoom", zoomed); var xAxis = d3.axisBottom(x) .ticks((width + 2) / (height + 2) * 5) .tickSize(-height) .tickPadding(10); var yAxis = d3.axisRight(y) .ticks(5) .tickSize(width) .tickPadding(-20 - width); g.append("text") .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.top + 20) + ")") .style("font-size", "12px") .style("font-family", "sans-serif") .style("text-anchor", "middle") .text("Date"); g.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 - margin.left / 1.2) .attr("x", 0 - (height / 2)) .attr("dy", "1em") .style("font-size", "12px") .style("text-anchor", "middle") .text("Temperature, ºF"); var gX = g.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") .call(xAxis); var gY = g.append("g") .attr("class", "axis axis--y") .call(yAxis); g.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).ticks(0)); g.append("g") .call(d3.axisLeft(y).ticks(0)); var city = g.selectAll(".city") .data(cities) .enter().append("g") .attr("class", "city"); city.append("path") .attr("class", "line") .style("stroke", function (d) { return z(d.id); }) .attr("id", function (d) { return 'tag' + d.id.replace(/\s+/g, '') }) // assign ID .attr("d", function (d) { return line(d.values); }) .attr("clip-path", "url(#clip)"); city.append("text") .datum(function (d) { return { id: d.id, value: d.values[d.values.length - 1] }; }) .attr("class", "label") .attr("transform", function (d) { return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")"; }) .attr("x", 3) .attr("dy", "0.35em") .style("font", "10px sans-serif") .style("fill", function (d) { // Add the colours dynamically return z(d.id); }) .text(function (d) { return d.id; }) .on("mouseover", textMouseover) .on("mouseout", textMouseout) .on("click", function (d) { // Determine if current line is visible var active = d.active ? false : true, newOpacity = active ? 0 : 1; // Hide or show the elements based on the ID d3.select("#tag" + d.id.replace(/\s+/g, '')) .transition().duration(100) .style("opacity", newOpacity); // Update whether or not the elements are active d.active = active; }); g.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var focus = g.append("g") .attr("transform", "translate(-100,-100)") .attr("class", "focus"); focus.append("circle") .attr("r", 3.5); focus.append("text") .attr("y", -10); var voronoiGroup = g.append("g") .attr("class", "voronoiParent") .append("g") .attr("class", "voronoi") .attr("clip-path", "url(#clip)"); voronoiGroup.selectAll("path") .data(voronoi.polygons(structuredData)) .enter() .append("path") .attr("d", function (d) { return d ? "M" + d.join("L") + "Z" : null; }) .on("mouseover", mouseover) .on("mouseout", mouseout); d3.select(".voronoiParent").call(zoom); d3.select("button").on("click", resetted); d3.select("#show-voronoi") .property("disabled", false) .on("change", function () { voronoiGroup.classed("voronoi--show", this.checked); }); function textMouseover(data) { // class lines to highlight and fadeout selected city var cityName = data.id; d3.selectAll('path.line') .classed("highlight", function (d) { return d.id === cityName; }) .classed("fadeout", function (d) { return d.id !== cityName; }); // focus brush on specific city var values = cities.filter(function (d) { return d.id === cityName; })[0].values; brushed(750) } // remove highlighting classes function textMouseout(data) { var cityName = data.id; d3.selectAll('path.line') .classed("highlight", false) .classed("fadeout", false); } function zoomed() { gX.call(xAxis.scale(d3.event.transform.rescaleX(x))); gY.call(yAxis.scale(d3.event.transform.rescaleY(y))); var t = d3.event.transform, xt = t.rescaleX(x), yt = t.rescaleY(y) x_date = mouseDate(xt); var temperatureSeries2 = d3.line() .defined(function (d) { return d.temperature != 0; }) .x(function (d) { return xt(d.dt); }) .y(function (d) { return yt(d.temperature); }); var line2 = d3.line() .curve(d3.curveBasis) .x(function (d) { return xt(d.date); }) .y(function (d) { return yt(d.temperature); }); var voronoi2 = d3.voronoi() .x(function (d) { return xt(d.dt); }) .y(function (d) { return yt(d.temperature); }) .extent([ [-margin.left, -margin.top], [width + margin.right, height + margin.bottom] ]); city.selectAll(".city") .data(cities); city.select("path") .attr("d", function (d) { return line2(d.values); }) .attr("id", function (d) { return 'tag' + d.id.replace(/\s+/g, '') }); voronoiGroup .attr("transform", d3.event.transform) } function mouseover(d) { d3.select(d.data.city).classed("city--hover", true); focus.attr("transform", "translate(" + x(d.data.dt) + "," + y(d.data.temperature) + ")"); focus.select("text").text(d.data.temperature); } function mouseout(d) { d3.select(d.data.city).classed("city--hover", false); focus.attr("transform", "translate(-100,-100)"); } function mouseDate(scale) { var g = d3.select("#group")._groups[0][0] var x0 = scale.invert(d3.mouse(g)[0]) i = bisectDate(structuredData, x0, 1) d0 = structuredData[i - 1]; if (d0.dt === date_max) { d = d0; } else { var d1 = structuredData[i] d = x0 - d0.dt > d1.dt - x0 ? d1 : d0; } return d; } function resetted() { d3.select(".voronoiParent").transition() .duration(750) .call(zoom.transform, d3.zoomIdentity); } }); function brushed(duration) { if (!duration) { duration = 0; } } function type(d, _, columns) { d.date = parseTime(d.date); for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c]; return d; } </script> </body>
https://d3js.org/d3.v4.min.js