【问题标题】:How to implement D3 code into a react project如何在 React 项目中实现 D3 代码
【发布时间】:2020-12-10 05:43:34
【问题描述】:

我正在尝试将this D3 code 实施到一个空的反应项目中,但图形没有显示在浏览器上。我已经尝试过以下代码。我还使用 npm i d3@3 安装了 D3 第 3 版

当我尝试使用 vanilla html 和 vanilla JS 实现时,它仍然无法在本地浏览器上运行。我不确定为什么它不起作用。作者部署的项目似乎运行良好。

import React from "react";
import * as d3 from "d3";

class Aroma extends React.Component {

  componentDidMount(){

    var margin = {top: 650, right: 650, bottom: 650, left: 650},
        radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) - 168;

    function filter_min_arc_size_text(d, i) {return (d.dx*d.depth*radius/1)>14};

    var hue = d3.scale.category10();

    var luminance = d3.scale.sqrt()
        .domain([0, 1e6])
        .clamp(true)
        .range([80, 20]);

    var svg = d3.select("body").append("svg")
        .attr("width", margin.left + margin.right)
        .attr("height", margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var partition = d3.layout.partition()
        .sort(function(a, b) { return d3.ascending(a.name, b.name); })
        .size([2 * Math.PI, radius]);

    var arc = d3.svg.arc()
        .startAngle(function(d) { return d.x; })
        .endAngle(function(d) { return d.x + d.dx - .01 / (d.depth + .5); })
        .innerRadius(function(d) { return (radius + 6) / 3 * d.depth; })
        .outerRadius(function(d) { return (radius + 6) / 3 * (d.depth + 1.) - 1; });

    svg.append("image")
      .attr("xlink:href", "images/grapes.png")
      .attr("x", -650)
      .attr("y", -650);

    //Tooltip description
    var tooltip = d3.select("body")
        .append("div")
        .attr("id", "tooltip")
        .style("position", "absolute")
        .style("z-index", "10")
        .style("opacity", 0);

    function format_number(x) {
      return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }


    function format_description(d) {
      var description = d.description;
          return  '<b>' + d.name + '</b></br>'+ d.description + '<br> (' + format_number(d.value) + ')';
    }

    function computeTextRotation(d) {
        var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
        return {
            global: rotation,
            correction: rotation > 90 ? 180 : 0
        };
    }

    function isRotated(d) {
        var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
        return rotation > 90 ? true : false
    }

    function mouseOverArc(d) {
          d3.select(this).attr("stroke","black")
              tooltip.html(format_description(d));
              return tooltip.transition()
                .duration(50)
                .style("opacity", 0.9);
            }

    function mouseOutArc(){
      d3.select(this).attr("stroke","")
      return tooltip.style("opacity", 0);
    }

    function mouseMoveArc (d) {
              return tooltip
                .style("top", (d3.event.pageY-10)+"px")
                .style("left", (d3.event.pageX+10)+"px");
    }

    var root_ = null;
    d3.json("data/davis-aroma-wheel.json", function(error, root) {
      if (error) return console.warn(error);
      // Compute the initial layout on the entire tree to sum sizes.
      // Also compute the full name and fill color for each node,
      // and stash the children so they can be restored as we descend.

      partition
          .value(function(d) { return d.size; })
          .nodes(root)
          .forEach(function(d) {
            d._children = d.children;
            d.sum = d.value;
            d.key = key(d);
            d.fill = fill(d);
          });

      // Now redefine the value function to use the previously-computed sum.
      partition
          .children(function(d, depth) { return depth < 3 ? d._children : null; })
          .value(function(d) { return d.sum; });

      var center = svg.append("circle")
          .attr("r", radius / 3)
          .on("click", zoomOut);

      center.append("title")
          .text("Zoom Out");


      var partitioned_data = partition.nodes(root).slice(1)

      var path = svg.selectAll("path")
          .data(partitioned_data)
          .enter().append("path")
          .attr("d", arc)
          .style("fill", function(d) { return d.fill; })
          .each(function(d) { this._current = updateArc(d); })
          .on("click", zoomIn)
          .on("mouseover", mouseOverArc)
          .on("mousemove", mouseMoveArc)
          .on("mouseout", mouseOutArc);

      var texts = svg.selectAll("text")
          .data(partitioned_data)
          .enter().append("text")
          .filter(filter_min_arc_size_text)
          .attr("transform", function(d)
            {
              var r = computeTextRotation(d);
              return "rotate(" + r.global + ")"
                + "translate(" + radius / 3. * d.depth + ")"
                + "rotate(" + -r.correction + ")";
            })
          .style("font-weight", "bold")
          .style("text-anchor", "middle")
          .attr("dx", function(d) {return isRotated(d) ? "-85" : "85"}) //margin
          .attr("dy", ".35em") // vertical-align
          .on("click", zoomIn)
          .text(function(d,i) {return d.name})

      function zoomIn(p) {
        if (p.depth > 1) p = p.parent;
        if (!p.children) return;
        zoom(p, p);
      }

      function zoomOut(p) {
        if (!p.parent) return;
        zoom(p.parent, p);
      }

      // Zoom to the specified new root.
      function zoom(root, p) {
        if (document.documentElement.__transition__) return;

        // Rescale outside angles to match the new layout.
        var enterArc,
            exitArc,
            outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);

        function insideArc(d) {
          return p.key > d.key
              ? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
              ? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
              : {depth: 0, x: 0, dx: 2 * Math.PI};
        }

        function outsideArc(d) {
          return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)};
        }

        center.datum(root);

        // When zooming in, arcs enter from the outside and exit to the inside.
        // Entering outside arcs start from the old layout.
        
        
        //commented //if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);

      var new_data=partition.nodes(root).slice(1)

        path = path.data(new_data, function(d) { return d.key; });

      // When zooming out, arcs enter from the inside and exit to the outside.
        // Exiting outside arcs transition to the new layout.
       
       
        //commented// if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);

        d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
          path.exit().transition()
              .style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
              .attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); })
              .remove();

          path.enter().append("path")
            .style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; })
            .style("fill", function(d) { return d.fill; })
            .on("click", zoomIn)
            .on("mouseover", mouseOverArc)
            .on("mousemove", mouseMoveArc)
            .on("mouseout", mouseOutArc)
            .each(function(d) { this._current = enterArc(d); });


          path.transition()
              .style("fill-opacity", 1)
              .attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); });
        });


      texts = texts.data(new_data, function(d) { return d.key; })

        texts.exit()
          .remove()
        texts.enter()
          .append("text")

        texts.style("opacity", 0)
          .attr("transform", function(d) {
            var r = computeTextRotation(d);
            return "rotate(" + r.global + ")"
            + "translate(" + radius / 3 * d.depth + ",0)"
            + "rotate(" + -r.correction + ")";
          })
          .style("font-weight", "bold")
          .style("text-anchor", "middle")
          .attr("dx", function(d) {return isRotated(d) ? "-85" : "85"}) //margin
          .attr("dy", ".35em") // vertical-align
          .filter(filter_min_arc_size_text)
          .on("click", zoomIn)
          .text(function(d,i) {return d.name})
          .transition().delay(750).style("opacity", 1)

      }
    });

    function key(d) {
      var k = [], p = d;
      //while (p.depth) k.push(p.name), p = p.parent;
      return k.reverse().join(".");
    }

    function fill(d) {
      var p = d;
      while (p.depth > 1) p = p.parent;
      var c = d3.lab(hue(p.name));
      c.l = luminance(d.sum);
      return c;
    }

    function arcTween(b) {
      var i = d3.interpolate(this._current, b);
      this._current = i(0);
      return function(t) {
        return arc(i(t));
      };
    }

    function updateArc(d) {
      return {depth: d.depth, x: d.x, dx: d.dx};
    }

  d3.select(this.frameElement).style("height", margin.top + margin.bottom + "px");

  }

  render(){
  return <p id="aroma" />;
  }
}

export default Aroma;

【问题讨论】:

    标签: reactjs d3.js


    【解决方案1】:

    我给最初的 D3 repo 作者发了电子邮件,他很友好地回复我,提到 d3 版本 3 存在错误,需要更长时间的调查。他将 3 年前用于构建项目的所有资源都发给了我。

    所以我只是决定遵循这个行动。 Zoomable sunburst chart shows only two layers of the hierarchy at a time in React JS

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-28
      • 2022-11-21
      • 2019-04-05
      • 2020-08-25
      • 1970-01-01
      相关资源
      最近更新 更多