Advertisement
Guest User

Untitled

a guest
Mar 17th, 2020
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2.  
  3. <body>
  4.  
  5. <script src="https://d3js.org/d3.v5.js"></script>
  6.  
  7. <script>
  8.  
  9. chart = {
  10.   const svg = d3.create("svg")
  11.       .attr("viewBox", [0, 0, width, height])
  12.       .style("overflow", "visible");
  13.  
  14.   svg.append("g")
  15.       .call(xAxis);
  16.  
  17.   svg.append("g")
  18.       .call(yAxis);
  19.  
  20.   const path = svg.append("g")
  21.       .attr("fill", "none")
  22.       .attr("stroke", "steelblue")
  23.       .attr("stroke-width", 1.5)
  24.       .attr("stroke-linejoin", "round")
  25.       .attr("stroke-linecap", "round")
  26.     .selectAll("path")
  27.     .data(data.series)
  28.     .join("path")
  29.       .style("mix-blend-mode", "multiply")
  30.       .attr("d", d => line(d.values));
  31.  
  32.   svg.call(hover, path);
  33.  
  34.   return svg.node();
  35. }
  36.  
  37. data = {
  38.   const data = d3.tsvParse(await FileAttachment("unemployment.tsv").text());
  39.   const columns = data.columns.slice(1);
  40.   return {
  41.     y: "% Unemployment",
  42.     series: data.map(d => ({
  43.       name: d.name.replace(/, ([\w-]+).*/, " $1"),
  44.       values: columns.map(k => +d[k])
  45.     })),
  46.     dates: columns.map(d3.utcParse("%Y-%m"))
  47.   };
  48. }
  49.  
  50. function hover(svg, path) {
  51.  
  52.   if ("ontouchstart" in document) svg
  53.       .style("-webkit-tap-highlight-color", "transparent")
  54.       .on("touchmove", moved)
  55.       .on("touchstart", entered)
  56.       .on("touchend", left)
  57.   else svg
  58.       .on("mousemove", moved)
  59.       .on("mouseenter", entered)
  60.       .on("mouseleave", left);
  61.  
  62.   const dot = svg.append("g")
  63.       .attr("display", "none");
  64.  
  65.   dot.append("circle")
  66.       .attr("r", 2.5);
  67.  
  68.   dot.append("text")
  69.       .attr("font-family", "sans-serif")
  70.       .attr("font-size", 10)
  71.       .attr("text-anchor", "middle")
  72.       .attr("y", -8);
  73.  
  74.   function moved() {
  75.     d3.event.preventDefault();
  76.     const ym = y.invert(d3.event.layerY);
  77.     const xm = x.invert(d3.event.layerX);
  78.     const i1 = d3.bisectLeft(data.dates, xm, 1);
  79.     const i0 = i1 - 1;
  80.     const i = xm - data.dates[i0] > data.dates[i1] - xm ? i1 : i0;
  81.     const s = d3.least(data.series, d => Math.abs(d.values[i] - ym));
  82.     path.attr("stroke", d => d === s ? null : "#ddd").filter(d => d === s).raise();
  83.     dot.attr("transform", `translate(${x(data.dates[i])},${y(s.values[i])})`);
  84.     dot.select("text").text(s.name);
  85.   }
  86.  
  87.   function entered() {
  88.     path.style("mix-blend-mode", null).attr("stroke", "#ddd");
  89.     dot.attr("display", null);
  90.   }
  91.  
  92.   function left() {
  93.     path.style("mix-blend-mode", "multiply").attr("stroke", null);
  94.     dot.attr("display", "none");
  95.   }
  96. }
  97.  
  98. height = 600
  99.  
  100. margin = ({top: 20, right: 20, bottom: 30, left: 30})
  101.  
  102. x = d3.scaleUtc()
  103.     .domain(d3.extent(data.dates))
  104.     .range([margin.left, width - margin.right])
  105.    
  106. y = d3.scaleLinear()
  107.     .domain([0, d3.max(data.series, d => d3.max(d.values))]).nice()
  108.     .range([height - margin.bottom, margin.top])
  109.    
  110. xAxis = g => g
  111.     .attr("transform", `translate(0,${height - margin.bottom})`)
  112.     .call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0))    
  113.  
  114. yAxis = g => g
  115.     .attr("transform", `translate(${margin.left},0)`)
  116.     .call(d3.axisLeft(y))
  117.     .call(g => g.select(".domain").remove())
  118.     .call(g => g.select(".tick:last-of-type text").clone()
  119.         .attr("x", 3)
  120.         .attr("text-anchor", "start")
  121.         .attr("font-weight", "bold")
  122.         .text(data.y))
  123.        
  124. line = d3.line()
  125.     .defined(d => !isNaN(d))
  126.     .x((d, i) => x(data.dates[i]))
  127.     .y(d => y(d))
  128.  
  129. d3 = require("d3@5", "d3-array@2")    
  130.  
  131. </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement