javascript - 带有粒子的D3.js Sankey图

标签 javascript d3.js syntax-error constants sankey-diagram

我一直在使用d3 Javascript库试验sankey图。我最近在bl.ocks上遇到了一个非常漂亮的sankey图。

https://bl.ocks.org/micahstubbs/ae0946f9efe18fc4f67460e7387abc0b

在将其应用于自己的sankey图之前,我要做的第一件事是复制bl.ocks页面上的所有代码,并在自己的代码编辑器(Dreamweaver)中进行尝试。问题是,每当我尝试加载sankey时,都会出现以下控制台错误:

SyntaxError: missing = in const declaration

我不太了解这里发生的情况,因为在bl.ocks页面上似乎工作正常。这段代码应该在下面:
for (const x in particles) {
  if ({}.hasOwnProperty.call(particles, x)) {
    const currentTime = elapsed - particles[x].time;
    // var currentPercent = currentTime / 1000 * particles[x].path.getTotalLength();
    particles[x].current = currentTime * 0.15 * particles[x].speed;
    const currentPos = particles[x].path.getPointAtLength(particles[x].current);
    context.beginPath();
    context.fillStyle = particles[x].link.particleColor(0);
    context.arc(currentPos.x, currentPos.y + particles[x].offset, particles[x].link.particleSize, 0, 2 * Math.PI);
    context.fill();
  }
}

它在vis.js代码的底部。谁能帮助我使此代码正常工作?我喜欢视觉效果,并想学习使用它。谢谢。

最佳答案

从MDN:
常数是程序在正常执行期间无法更改的值。它不能通过重新分配进行更改,也不能重新声明。在JavaScript中,使用const关键字声明常量。需要一个常量的初始化程序;也就是说,您必须在声明它的同一条语句中指定它的值(这很有意义,因为以后不能更改)。

您的数据(能量)可能未正确加载。除非您发布整个代码,否则我无法告诉您哪里出了问题。但是我将下面的bl.ocks.org中的图表代码进行了组合。它也适用于Codepen。

<html lang='en'>

<head>
  <meta charset='utf-8' />
  <title>Sankey Particles</title>
  <style>
    .node rect {
      cursor: move;
      fill-opacity: .9;
      shape-rendering: crispEdges;
    }
    
    .node text {
      pointer-events: none;
      text-shadow: 0 1px 0 #fff;
    }
    
    .link {
      fill: none;
      stroke: #000;
      stroke-opacity: .15;
    }
    
    .link:hover {
      stroke-opacity: .25;
    }
    
    svg {
      position: absolute;
    }
    
    canvas {
      position: absolute;
    }
  </style>
</head>

<body>
  <canvas width='960' height='960'></canvas>
  <svg width='960' height='960'></svg>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.js' charset='utf-8' type='text/javascript'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/d3-sankey/0.4.2/d3-sankey.js' charset='utf-8' type='text/javascript'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/d3-timer/1.0.5/d3-timer.js' charset='utf-8' type='text/javascript'></script>
  <script src='vis.js'></script>
  <script>
    const margin = { top: 1, right: 1, bottom: 6, left: 1 };
    const width = 960 - margin.left - margin.right;
    const height = 500 - margin.top - margin.bottom;
    const formatNumber = d3.format(",.0f");
    const format = d => `${formatNumber(d)} TWh`;
    const color = d3.scaleOrdinal(d3.schemeCategory20);
    
    const svg = d3
      .select("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", `translate(${margin.left},${margin.top})`);
    
    const sankey = d3.sankey().nodeWidth(15).nodePadding(10).size([width, height]);
    
    const path = sankey.link();
    
    const freqCounter = 1;
    
    var energy = {
      nodes: [
        { name: "Agricultural 'waste'" },
        { name: "Bio-conversion" },
        { name: "Liquid" },
        { name: "Losses" },
        { name: "Solid" },
        { name: "Gas" },
        { name: "Biofuel imports" },
        { name: "Biomass imports" },
        { name: "Coal imports" },
        { name: "Coal" },
        { name: "Coal reserves" },
        { name: "District heating" },
        { name: "Industry" },
        { name: "Heating and cooling - commercial" },
        { name: "Heating and cooling - homes" },
        { name: "Electricity grid" },
        { name: "Over generation / exports" },
        { name: "H2 conversion" },
        { name: "Road transport" },
        { name: "Agriculture" },
        { name: "Rail transport" },
        { name: "Lighting & appliances - commercial" },
        { name: "Lighting & appliances - homes" },
        { name: "Gas imports" },
        { name: "Ngas" },
        { name: "Gas reserves" },
        { name: "Thermal generation" },
        { name: "Geothermal" },
        { name: "H2" },
        { name: "Hydro" },
        { name: "International shipping" },
        { name: "Domestic aviation" },
        { name: "International aviation" },
        { name: "National navigation" },
        { name: "Marine algae" },
        { name: "Nuclear" },
        { name: "Oil imports" },
        { name: "Oil" },
        { name: "Oil reserves" },
        { name: "Other waste" },
        { name: "Pumped heat" },
        { name: "Solar PV" },
        { name: "Solar Thermal" },
        { name: "Solar" },
        { name: "Tidal" },
        { name: "UK land based bioenergy" },
        { name: "Wave" },
        { name: "Wind" }
      ],
      links: [
        { source: 0, target: 1, value: 124.729 },
        { source: 1, target: 2, value: 0.597 },
        { source: 1, target: 3, value: 26.862 },
        { source: 1, target: 4, value: 280.322 },
        { source: 1, target: 5, value: 81.144 },
        { source: 6, target: 2, value: 35 },
        { source: 7, target: 4, value: 35 },
        { source: 8, target: 9, value: 11.606 },
        { source: 10, target: 9, value: 63.965 },
        { source: 9, target: 4, value: 75.571 },
        { source: 11, target: 12, value: 10.639 },
        { source: 11, target: 13, value: 22.505 },
        { source: 11, target: 14, value: 46.184 },
        { source: 15, target: 16, value: 104.453 },
        { source: 15, target: 14, value: 113.726 },
        { source: 15, target: 17, value: 27.14 },
        { source: 15, target: 12, value: 342.165 },
        { source: 15, target: 18, value: 37.797 },
        { source: 15, target: 19, value: 4.412 },
        { source: 15, target: 13, value: 40.858 },
        { source: 15, target: 3, value: 56.691 },
        { source: 15, target: 20, value: 7.863 },
        { source: 15, target: 21, value: 90.008 },
        { source: 15, target: 22, value: 93.494 },
        { source: 23, target: 24, value: 40.719 },
        { source: 25, target: 24, value: 82.233 },
        { source: 5, target: 13, value: 0.129 },
        { source: 5, target: 3, value: 1.401 },
        { source: 5, target: 26, value: 151.891 },
        { source: 5, target: 19, value: 2.096 },
        { source: 5, target: 12, value: 48.58 },
        { source: 27, target: 15, value: 7.013 },
        { source: 17, target: 28, value: 20.897 },
        { source: 17, target: 3, value: 6.242 },
        { source: 28, target: 18, value: 20.897 },
        { source: 29, target: 15, value: 6.995 },
        { source: 2, target: 12, value: 121.066 },
        { source: 2, target: 30, value: 128.69 },
        { source: 2, target: 18, value: 135.835 },
        { source: 2, target: 31, value: 14.458 },
        { source: 2, target: 32, value: 206.267 },
        { source: 2, target: 19, value: 3.64 },
        { source: 2, target: 33, value: 33.218 },
        { source: 2, target: 20, value: 4.413 },
        { source: 34, target: 1, value: 4.375 },
        { source: 24, target: 5, value: 122.952 },
        { source: 35, target: 26, value: 839.978 },
        { source: 36, target: 37, value: 504.287 },
        { source: 38, target: 37, value: 107.703 },
        { source: 37, target: 2, value: 611.99 },
        { source: 39, target: 4, value: 56.587 },
        { source: 39, target: 1, value: 77.81 },
        { source: 40, target: 14, value: 193.026 },
        { source: 40, target: 13, value: 70.672 },
        { source: 41, target: 15, value: 59.901 },
        { source: 42, target: 14, value: 19.263 },
        { source: 43, target: 42, value: 19.263 },
        { source: 43, target: 41, value: 59.901 },
        { source: 4, target: 19, value: 0.882 },
        { source: 4, target: 26, value: 400.12 },
        { source: 4, target: 12, value: 46.477 },
        { source: 26, target: 15, value: 525.531 },
        { source: 26, target: 3, value: 787.129 },
        { source: 26, target: 11, value: 79.329 },
        { source: 44, target: 15, value: 9.452 },
        { source: 45, target: 1, value: 182.01 },
        { source: 46, target: 15, value: 19.013 },
        { source: 47, target: 15, value: 289.366 }
      ]
    };
    
    sankey.nodes(energy.nodes).links(energy.links).layout(32);
    
    const link = svg
      .append("g")
      .selectAll(".link")
      .data(energy.links)
      .enter()
      .append("path")
      .attr("class", "link")
      .attr("d", path)
      .style("stroke-width", d => Math.max(1, d.dy))
      .sort((a, b) => b.dy - a.dy);
    
    link
      .append("title")
      .text(d => `${d.source.name} → ${d.target.name}\n${format(d.value)}`);
    
    const node = svg
      .append("g")
      .selectAll(".node")
      .data(energy.nodes)
      .enter()
      .append("g")
      .attr("class", "node")
      .attr("transform", d => `translate(${d.x},${d.y})`)
      .call(
        d3
          .drag()
          .subject(d => d)
          .on("start", function() {
            this.parentNode.appendChild(this);
          })
          .on("drag", dragmove)
      );
    
    node
      .append("rect")
      .attr("height", d => d.dy)
      .attr("width", sankey.nodeWidth())
      .style("fill", d => {
        d.color = color(d.name.replace(/ .*/, ""));
        return d.color;
      })
      .style("stroke", "none")
      .append("title")
      .text(d => `${d.name}\n${format(d.value)}`);
    
    node
      .append("text")
      .attr("x", -6)
      .attr("y", d => d.dy / 2)
      .attr("dy", ".35em")
      .attr("text-anchor", "end")
      .attr("transform", null)
      .text(d => d.name)
      .filter(d => d.x < width / 2)
      .attr("x", 6 + sankey.nodeWidth())
      .attr("text-anchor", "start");
    
    function dragmove(d) {
      d3
        .select(this)
        .attr(
          "transform",
          `translate(${d.x},${(d.y = Math.max(
            0,
            Math.min(height - d.dy, d3.event.y)
          ))})`
        );
      sankey.relayout();
      link.attr("d", path);
    }
    
    const linkExtent = d3.extent(energy.links, d => d.value);
    const frequencyScale = d3.scaleLinear().domain(linkExtent).range([0.05, 1]);
    const particleSize = d3.scaleLinear().domain(linkExtent).range([1, 5]);
    
    energy.links.forEach(link => {
      link.freq = frequencyScale(link.value);
      link.particleSize = 2;
      link.particleColor = d3
        .scaleLinear()
        .domain([0, 1])
        .range([link.source.color, link.target.color]);
    });
    
    const t = d3.timer(tick, 1000);
    let particles = [];
    
    function tick(elapsed, time) {
      particles = particles.filter(d => d.current < d.path.getTotalLength());
    
      d3.selectAll("path.link").each(function(d) {
        // if (d.freq < 1) {
        for (let x = 0; x < 2; x += 1) {
          const offset = (Math.random() - 0.5) * (d.dy - 4);
          if (Math.random() < d.freq) {
            const length = this.getTotalLength();
            particles.push({
              link: d,
              time: elapsed,
              offset,
              path: this,
              length,
              animateTime: length,
              speed: 0.5 + Math.random()
            });
          }
        }
        // }
        /*    
                else {
                  for (var x = 0; x<d.freq; x++) {
                    var offset = (Math.random() - .5) * d.dy;
                    particles.push({link: d, time: elapsed, offset: offset, path: this})
                  }
                } 
            */
      });
    
      particleEdgeCanvasPath(elapsed);
    }
    
    function particleEdgeCanvasPath(elapsed) {
      const context = d3.select("canvas").node().getContext("2d");
    
      context.clearRect(0, 0, 1000, 1000);
    
      context.fillStyle = "gray";
      context.lineWidth = "1px";
      for (const x in particles) {
        if ({}.hasOwnProperty.call(particles, x)) {
          const currentTime = elapsed - particles[x].time;
          // var currentPercent = currentTime / 1000 * particles[x].path.getTotalLength();
          particles[x].current = currentTime * 0.15 * particles[x].speed;
          const currentPos = particles[x].path.getPointAtLength(
            particles[x].current
          );
          context.beginPath();
          context.fillStyle = particles[x].link.particleColor(0);
          context.arc(
            currentPos.x,
            currentPos.y + particles[x].offset,
            particles[x].link.particleSize,
            0,
            2 * Math.PI
          );
          context.fill();
        }
      }
    }
  </script>
</body>

</html>

关于javascript - 带有粒子的D3.js Sankey图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46347159/

相关文章:

javascript - 在 d3 Canvas map 上绘制圆弧时出现问题

python - 无效类型,必须是字符串或 Tensor [TensorFlow]

javascript - 如何从 json 字符串中递归获取父 ID

javascript - 未知提供商factoryprovider <- 工厂<- Controller Angular js

javascript - D3.js 将父对象粘在 svg 中间

javascript - AngularJS无法读取未定义的属性 'forEach'

visual-studio - Visual Basic输入错误消息

javascript - 无法检索 html 形式的性别单选输入值

javascript - 如何将 rowGroup 与 DataTables 一起使用,以便 rowGroup 分隔符右对齐?

json - d3 : us states in topojson format filesize is way too large