choropleth.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. Shiny.addCustomMessageHandler("choropleth_values", function(message) {
  2. var dataset = message;
  3. var width = 800;
  4. var height = 600;
  5. var tooltip = d3.select("body")
  6. .append("div")
  7. .style("position", "absolute")
  8. //.style("z-index", "10")
  9. .style("visibility", "hidden")
  10. .style("color", "white")
  11. .style("padding", "8px")
  12. .style("background-color", "rgba(0, 0, 0, 0.75)")
  13. .style("border-radius", "6px")
  14. .style("font", "12px sans-serif")
  15. .text("tooltip");
  16. var projection = d3.geoEquirectangular()
  17. .translate([0, 0]);
  18. var path = d3.geoPath()
  19. .projection(projection);
  20. var x = d3.scaleLinear()
  21. .domain(dataset.percent)
  22. .rangeRound([600, 860]);
  23. var dataDomain = [];
  24. function getDomain (l){
  25. /*for (var i = 0; i < l.length; i++){
  26. dataDomain[i] = l[i * 3];
  27. }
  28. return dataDomain.sort(function(a, b){return (a - b);});*/
  29. var v = d3.max(l) / 9;
  30. return [v, v*2, v*3, v*4, v*5, v*6, v*7, v*8];
  31. }
  32. var color = d3.scaleThreshold()
  33. .domain(getDomain(dataset.percent)).range(d3.schemeBlues[9]);
  34. /*.range(['#fff7f3','#fde0dd','#fcc5c0','#fa9fb5',
  35. '#f768a1','#dd3497','#ae017e','#7a0177',
  36. '#49006a','#ffffff','#f0f0f0','#d9d9d9',
  37. '#bdbdbd','#969696','#737373','#525252',
  38. '#252525','#000000']);*/
  39. var choropleth = d3.select("#choropleth_area")
  40. .append("svg")
  41. .attr("width", width)
  42. .attr("height", height);
  43. var g = choropleth.append("g")
  44. .attr("class", "key")
  45. .attr("transform", "translate(0,40)");
  46. g.selectAll("rect")
  47. .data(color.range().map(function(d) {
  48. d = color.invertExtent(d);
  49. if (d[0] == null) d[0] = x.domain()[0];
  50. if (d[1] == null) d[1] = x.domain()[1];
  51. return d;
  52. }))
  53. .enter().append("rect")
  54. .attr("height", 8)
  55. .attr("x", function(d) { return x(d[0]); })
  56. .attr("width", function(d) { return x(d[1]) - x(d[0]); })
  57. .attr("fill", function(d) { return color(d[0]); });
  58. g.append("text")
  59. .attr("class", "caption")
  60. .attr("x", x.range()[0])
  61. .attr("y", -6)
  62. .attr("fill", "#000")
  63. .attr("text-anchor", "start")
  64. .attr("font-weight", "bold")
  65. .text("Acidentes");
  66. /*g.call(d3.axisBottom(x)
  67. .tickSize(13)
  68. .tickFormat(function(x) { return x; })
  69. .tickValues(color.domain()))
  70. .select(".domain")
  71. .remove();*/
  72. var zooming = function() {
  73. var offset = [d3.event.transform.x, d3.event.transform.y];
  74. var newScale = d3.event.transform.k * 2000;
  75. projection.translate(offset)
  76. .scale(newScale);
  77. choropleth.selectAll("path")
  78. .style("stroke", "black")
  79. .style("stroke-width", 1)
  80. .attr("d", path);
  81. };
  82. var zoom = d3.zoom()
  83. .on("zoom", zooming);
  84. var center = projection([-12.1, -50.6]);
  85. var map = choropleth.append("g")
  86. .attr("id", "map")
  87. .call(zoom)
  88. .call(zoom.transform, d3.zoomIdentity
  89. .translate(width, height/2)
  90. .scale(0.25)
  91. .translate(-center[0], -center[1]));
  92. //invisible rect covering all svg, so we can drag anywhere
  93. map.append("rect")
  94. .attr("x", 0)
  95. .attr("y", 0)
  96. .attr("width", width)
  97. .attr("height", height)
  98. .attr("opacity", 0);
  99. d3.json("uf.json").then(function(json) {
  100. for (var i = 0; i < dataset.uf.length; i++) {
  101. var dataState = dataset.uf[i];
  102. var dataValue = parseFloat(dataset.percent[i]);
  103. for (var j = 0; j < json.features.length; j++) {
  104. var jsonState = json.features[j].properties.NOME_UF;
  105. if (dataState == jsonState) {
  106. json.features[j].properties.value = dataValue;
  107. break;
  108. }
  109. }
  110. }
  111. map.selectAll("path")
  112. .data(json.features)
  113. .enter()
  114. .append("path")
  115. .attr("d", path)
  116. .style("stroke", "black")
  117. .style("stroke-width", 1)
  118. .style("fill",function(d) {
  119. var value = d.properties.value;
  120. if (value) {
  121. return color(value);
  122. //return "rgb(0, 0, " + Math.round(Math.log2(value) * 11) + ")";
  123. } else {
  124. return "#ccc";
  125. }
  126. })
  127. .on("mouseover", function(d){
  128. d3.select(this).style("stroke", "orange")
  129. .style("stroke-width", 2);})
  130. .on("mouseout", function(d){
  131. d3.select(this).style("stroke", "black")
  132. .style("stroke-width", 1);});
  133. EnablePan();
  134. });
  135. var EnablePan = function() {
  136. // TODO fix this ugly hack, we shouldn't need to select the body
  137. d3.select("body").on("keydown", function() {
  138. var moveAmount = 50;
  139. var key = d3.event.key;
  140. var x = 0;
  141. var y = 0;
  142. switch(key) {
  143. case "ArrowUp":
  144. y += moveAmount;
  145. break;
  146. case "ArrowDown":
  147. y -= moveAmount;
  148. break;
  149. case "ArrowLeft":
  150. x += moveAmount;
  151. break;
  152. case "ArrowRight":
  153. x -= moveAmount;
  154. break;
  155. default:
  156. break;
  157. }
  158. map.transition()
  159. .call(zoom.translateBy, x, y);
  160. });
  161. };
  162. });