D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
oikonang
Full window
Github gist
Greece D3js
<!DOCTYPE html> <meta charset="utf-8"> <style> @import url(style.css); </style> <body> <script src="//d3js.org/d3.v3.min.js"></script> <script src="//d3js.org/queue.v1.min.js"></script> <body> <!-- Table to hold the data table, map and legend --> <table border="0" cellpadding="10" style="overflow-y: scroll;"> <tr> <td><div id="table_container" class="csvTable"></div></td> <td><div id="map_container"></div></td> <td><div id="legend_container"></div></td> </tr> </table> <script> var mw = 500; // map container width var mh = 600; // map container height var main_chart_svg = d3.select("#map_container") .append("svg") .attr({ "width":mw, "height":mh, }); var legend_svg = d3.select("#legend_container") .append("svg") .attr({ "width":200, "height":600, }); var hue = "g"; /* b=blue, g=green, r=red colours - from ColorBrewer */ /* break the data values into 9 ranges of €100 each */ /* max and min values already known so 400-1300 works */ var quantize = d3.scale.quantize() .domain([400, 1300]) .range(d3.range(9).map(function(i) { return hue + i + "-9"; })); /* declare locale so we can format values with euro symbol */ var ie = d3.locale({ "decimal": ".", "thousands": ",", "grouping": [3], "currency": ["€", ""], "dateTime": "%a %b %e %X %Y", "date": "%d/%m/%Y", "time": "%H:%M:%S", "periods": ["AM", "PM"], "days": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], "shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], "months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], "shortMonths": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] }); var rateById = d3.map(); var lastActive = ""; var ireland; var data; var defaultScale = 0.6; /* default scale of map - fits nicely on standard screen */ var scale = 3; /* maximum size to zoom county */ var format = ie.numberFormat("$, #,##0d"); /* Thanks to https://stackoverflow.com/users/3128209/ameliabr for tips on creating a quantized legend */ var legend = legend_svg.selectAll('g.legendEntry') .data(quantize.range()) .enter() .append('g').attr('class', 'legendEntry'); legend .append('rect') .attr("x", 20) .attr("y", function(d, i) { return i * 25 + 20; }) .attr("width", 15) .attr("height", 15) .attr("class", function(d){ return d;}) .style("stroke", "black") .style("stroke-width", 1) .on("click", function(d) { if (lastActive == "") { resetAll(); d3.select(ireland).selectAll("." + d).attr("class", "highlight"); /* Highlight all counties in range selected */ } }); legend .append('text') .attr("x", 40) //leave 5 pixel space after the <rect> .attr("y", function(d, i) { return i * 25 + 20; }) .attr("dy", "0.8em") //place text one line *below* the x,y point .text(function(d,i) { var extent = quantize.invertExtent(d); //extent will be a two-element array, format it however you want: return format(extent[0]) + " - " + format(+extent[1]) }) .style("font-family", "sans-serif") .style("font-size", "12px"); /* Data has key "county" and value "rental" - i.e. average rental price per county */ queue() .defer(d3.csv, "rentals-2015-bycounty.csv", data) .await(ready); function ready(error, data) { if (error) throw error; d3.map(data, function(d) {rateById.set(d.county, +d.rental)}); /* create the data map */ d3.xml("greece.svg", "image/svg+xml", function(error, xml) { /* embed the SVG map */ if (error) throw error; var countyTable = tabulate(data, ["county", "rental"]); /* render the data table */ var svgMap = xml.getElementsByTagName("g")[0]; /* set svgMap to root g */ ireland = main_chart_svg.node().appendChild(svgMap); /* island of Ireland map */ d3.select(ireland).selectAll("#NI") /* Group Northern Ireland together */ .attr("class", "region NI"); d3.select(ireland).selectAll("#republic") /* Group Republic of Ireland together */ .attr("class", "region republic"); d3.select(ireland).selectAll("#republic").selectAll("path") /* Map Republic counties to rental data */ .attr("class", function(d) { return quantize(rateById.get(this.id)); }) .append("title").text(function(d) { /* add title = name of each county and average rental */ return this.parentNode.id + ", " + format(rateById.get(this.parentNode.id)) }); d3.select(ireland).selectAll("#republic").selectAll("path") .on("mouseover", function(d) { if (d3.select(this).classed("active")) return; /* no need to change class when county is already selected */ d3.select(this).attr("class", "hover"); }) .on("mouseout", function(d) { if (d3.select(this).classed("active")) return; d3.select(this).attr("class", function(d) { /* reset county color to quantize range */ return quantize(rateById.get(this.id)) }); }) .on("click", function (d) { zoomed(d3.select(this)); }); /* Let's add an id to each group that wraps a path */ d3.select(ireland).selectAll("#republic").selectAll("path") .each(function(d) { d3.select(this.parentNode).attr("id", this.id); }); /* Now add a text box to the group with content equal to the id of the group */ d3.select(ireland).selectAll("#republic").selectAll("g") .append("svg:text") .text(function(d){ return this.parentNode.id; }) .attr("x", function(d){ console.log(d3.select(this.parentNode).select("path").attr("d")); //return 600; //d3.select(ireland).select("path") return getBoundingBox(d3.select(this.parentNode).select("path"))[4]; }) .attr("y", function(d){ return getBoundingBox(d3.select(this.parentNode).select("path"))[5]; }) // .attr("text-anchor","middle") // .attr("font-family", "sans-serif") // .attr("stroke-width", 0.5) .classed("text", true) // .attr("fill", "#333") // .attr('font-size','10pt') ; }); } /* Thanks to https://bl.ocks.org/phil-pedruco/7557092 for the table code */ /* and style - and what a coincidence he also used a map of Ireland! */ function tabulate(data, columns) { var table = d3.select("#table_container").append("table") thead = table.append("thead"), tbody = table.append("tbody"); // append the header row thead.append("tr") .selectAll("th") .data(columns) .enter() .append("th") .text(function(column) { return column; }); // create a row for each object in the data var rows = tbody.selectAll("tr") .data(data) .enter() .append("tr") .on("click", function (d) { tableRowClicked(d)}); // create a cell in each row for each column var cells = rows.selectAll("td") .data(function(row) { return columns.map(function(column) { return {column: column, value: row[column]}; }); }) .enter() .append("td") // .attr("style", "font-family: Courier") // sets the font style .html(function(d) { if (d.column == "rental") return format(d.value); else return d.value; }); return table; } function zoomed(d) { /* Thanks to https://complextosimple.blogspot.ie/2012/10/zoom-and-center-with-d3.html */ /* for a simple explanation of transform scale and translation */ /* This function centers the county's bounding box in the map container */ /* The scale is set to the minimum value that enables the county to fit in the */ /* container, horizontally or vertically, up to a maximum value of 3. */ /* If the full width of container is not required, the county is horizontally centred */ /* Likewise, if the full height of the container is not required, the county is */ /* vertically centred. */ var xy = getBoundingBox(d); /* get top left co-ordinates and width and height */ if (d.classed("active")) { /* if county is active reset map scale and county colour */ d.attr("class", function(d) { return quantize(rateById.get(this.id)) }); main_chart_svg.selectAll("#viewport") .transition().duration(750).attr("transform", "scale(" + defaultScale + ")"); lastActive = ""; } else { /* zoom into new county */ resetAll(); /* reset county colors */ /* scale is the max number of times bounding box will fit into container, capped at 3 times */ scale = Math.min(mw/xy[1], mh/xy[3], 3); /* tx and ty are the translations of the x and y co-ordinates */ /* the translation centers the bounding box in the container */ var tx = -xy[0] + (mw - xy[1]*scale)/(2*scale); var ty = -xy[2] + (mh - xy[3]*scale)/(2*scale); main_chart_svg.selectAll("#viewport") .transition().duration(750).attr("transform", "scale(" + scale + ")translate("+ tx +"," + ty + ")"); d.attr("class", "active"); lastActive = d.attr("id"); } } function reset(selection) { /* resets the color of a single county */ if (selection != "") d3.select(ireland).select("#" + selection).attr("class", function(d) { return quantize(rateById.get(this.id)) }); } function resetAll() { /* resets the color of all counties */ d3.select(ireland).selectAll("#republic").selectAll("path") .attr("class", function(d) { return quantize(rateById.get(this.id)) }); } function tableRowClicked(x) { /* resets colors and zooms into new county */ resetAll(); lastActive = x.county; zoomed(d3.select(ireland).selectAll("#" + x.county).select("path")); } function getBoundingBox(selection) { /* get x,y co-ordinates of top-left of bounding box and width and height */ var element = selection.node(), bbox = element.getBBox(); cx = bbox.x + bbox.width/2; cy = bbox.y + bbox.height/2; return [bbox.x, bbox.width, bbox.y, bbox.height, cx, cy]; } d3.select(self.frameElement).style("height", "650px"); </script>
https://d3js.org/d3.v3.min.js
https://d3js.org/queue.v1.min.js