D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
michalskop
Full window
Github gist
CZ senate cartogram
<script src="https://d3js.org/d3.v3.min.js"></script> <p id="chart"> <script> // set margins, size var margin = {top: 0, right: 0, bottom: 0, left: 0}, width = 1040 - margin.left - margin.right, height = 620 - margin.top - margin.bottom; // append the svg canvas to the page var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // set up scales var x = d3.scale.linear() .domain([-260,260]) .range([0, width]) var y = d3.scale.linear() .domain([-145, 165]) .range([height, 0]) var r = d3.scale.linear() .domain([0,50]) .range([0,100]) d3.csv("centroids.csv", function (error, data) { data.forEach(function(d) { d.x = parseFloat(d.x); d.y = parseFloat(d.y); d.x_original = d.x; d.y_original = d.y; d.x_next = d.x; d.y_next = d.y; d.r = 20; }) var circles = svg.selectAll(".circle") .data(data) .enter() .append("circle") .attr("cx", function(d) { return x(d.x) }) .attr("cy", function(d) { return y(d.y) }) .attr("r", function(d) { return r(d.r*.8) }) .attr("fill", function(d) { return d.color }) .attr("stroke",function(d) { return "#000" }) .attr("stroke-width",function(d) { if (d.region == 'Praha' || d.region == 'Brno' || d.region == 'Ostrava' || d.region == 'Plze') return 10 else return 2 }) .attr("fill-opacity",function(d, i) { return .5 }) .attr("title", function(d) { return d.name + ": " + d.senator }) function distance(d1, d2){ return Math.sqrt((d1.x-d2.x)*(d1.x-d2.x) + (d1.y-d2.y)*(d1.y-d2.y)) } function unitvector(d1, d2) { var distx = d1.x - d2.x; var disty = d1.y - d2.y; var size = Math.sqrt(distx*distx + disty*disty); if (size > 0) { return [distx/size, disty/size] } else { return [0, 0] } } function repulsive(d1, d2, a=0.05) { var gap = distance(d1, d2) - d1.r - d2.r; if (gap < 0) { var unitv = unitvector(d1, d2); return {'dx': -1*unitv[0]*gap*a, 'dy': -1*unitv[1]*gap*a } } else { return {'dx': 0, 'dy': 0} } } function attractive(d, b=0.1) { var orig = {'x': d.x_original, 'y': d.y_original} var dist = distance(d, orig); var unitv = unitvector(d, orig); return {'dx': -1*unitv[0]*dist*b, 'dy': -1*unitv[1]*dist*b } } conflicted = [] for (k=0; k<1000; k++) { for (var i=0; i<data.length; i++) { data[i].x_next = data[i].x; data[i].y_next = data[i].y; } for (var i=0; i<data.length; i++) { conflicted[i] = false; for (var j=i+1; j<data.length; j++) { repuls = repulsive(data[i], data[j]) data[i]['x_next'] += repuls['dx']; data[i]['y_next'] += repuls['dy']; data[j]['x_next'] += -1*repuls['dx']; data[j]['y_next'] += -1*repuls['dy']; if (repuls['dx'] != 0 || repuls['dy'] != 0) { conflicted[i] = true; conflicted[j] = true; } } } for (var i=0; i<data.length; i++) { if (conflicted[i]) { attract = attractive(data[i], 0.01); } else { attract = attractive(data[i]) } data[i]['x_next'] += attract['dx']; data[i]['y_next'] += attract['dy']; } for (var i=0; i<data.length; i++) { data[i].x = data[i].x_next; data[i].y = data[i].y_next; } d3.selectAll("circle") .transition() .duration(100) .delay(function() { return k * 50 }) .attr("cx", function(d) { return x(d.x) }) .attr("cy", function(d) { return y(d.y) }) } nothing = 0 }) </script>
Modified
http://d3js.org/d3.v3.min.js
to a secure url
https://d3js.org/d3.v3.min.js