0

我正在尝试使我的 D3 图表可拖动,但是当我拖动应用程序时崩溃了。

使用 d3-3d 使其拖动。

错误:

在此处输入图像描述

编码:

let sum;

      var j = 10,
        scale = 8,
        scatter = [],
        xLine = [],
        yLine = [],
        zLine = [],
        beta = 0,
        alpha = 0,
        key = function (d) {
          return d.id;
        },
        startAngle = Math.PI / 4,
        h = 300,
        w = 367,
        backgroundDots = [];
      var origin = [w * 0.4, h / 2];
      var svg = d3
        .select(node)
        .append("svg")
        .attr("class", "nnsContainer")
        .attr("width", w)
        .attr("height", h)
        .on("mouseover", hoverStart)
        .on("mouseout", hoverEnd)
        .call(
          d3.drag()
            .on("drag", (event) => dragged(event))
            .on("start", (event) =>  dragStart(event))
            .on("end", (event) => dragEnd(event))
        )
        .append("g");
      var mx, my, mouseX, mouseY;

      var borderPath = svg
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("height", h)
        .attr("width", w)
        .style("stroke", "black")
        .style("fill", "none")
        .style("stroke-width", 0.3);

      // center origin at target word or centroid of points
      var center;
      if (!this.state.query_word) {
        center = {};
        for (const dim of ["x", "y", "z"]) {
          sum = radarChartData.query[dim];
          for (const nn of radarChartData.neighbors) {
            sum += nn[dim];
          }
          center[dim] = sum / (radarChartData.neighbors.length + 1);
        }
      } else {
        center = {
          x: radarChartData.query.x,
          y: radarChartData.query.y,
          z: radarChartData.query.z,
        };
      }
      for (const dim of ["x", "y", "z"]) {
        radarChartData.query[dim] -= center[dim];
        for (var i = 0; i < radarChartData.neighbors.length; i++) {
          radarChartData.neighbors[i][dim] -= center[dim];
        }
      }

      var cursorStatus = {
        hovering: false,
        dragging: false,
      };
      var cursorUpdate = function (cursorStatus) {
        if (cursorStatus.dragging) {
          document.querySelector("html, body").style.cursor = "grabbing";
        } else if (cursorStatus.hovering) {
          document.querySelector("html, body").style.cursor = "grab";
        } else {
          document.querySelector("html, body").style.cursor = "auto";
        }
      };

      // scale zoom level for size of viz, and range of data
      var query_magnitude = Math.sqrt(
        this.state.radarChartData.query.x ** 2 +
          this.state.radarChartData.query.y ** 2 +
          this.state.radarChartData.query.z ** 2
      );
      var mag_max = query_magnitude;
      for (var i = 0; i < this.state.radarChartData.neighbors.length; i++) {
        var pt = this.state.radarChartData.neighbors[i];
        var magnitude = Math.sqrt(pt.x ** 2 + pt.y ** 2 + pt.z ** 2);
        if (magnitude > mag_max) {
          mag_max = magnitude;
        }
      }
      var zoom_scale = d3.scaleLinear().domain([100, 300]).range([50, 150]);
      scale = zoom_scale(h) / mag_max;

      // scale dots & labels for size of viz and distance from camera
      var minFontScale = d3.scaleLinear().domain([80, 160]).range([7, 10]);
      minFontScale.clamp(true);
      var maxFontScale = d3.scaleLinear().domain([80, 208]).range([11, 19]);
      maxFontScale.clamp(true);
      var zToFont = d3
        .scaleLinear()
        .domain([-mag_max, mag_max])
        .range([minFontScale(h), maxFontScale(h)]);
      // 100 is just arbitrary high val, we just need to clamp min size
      var positive = d3.scaleLinear().domain([0.5, 100]).range([0.5, 100]);
      positive.clamp(true);
      var fontSize = function (d) {
        return positive(zToFont(d.rotated.z));
      };
      var pointSize = function (d) {
        return fontSize(d) / 3;
      };


      var point3d = _3d()
        .x(function (d) {
          return d.x;
        })
        .y(function (d) {
          return d.y;
        })
        .z(function (d) {
          return d.z;
        })
        .origin(origin)
        .rotateY(startAngle)
        .rotateX(-startAngle)
        .scale(scale);

      var yScale3d = _3d()
        .shape("LINE_STRIP")
        .origin(origin)
        .rotateY(startAngle)
        .rotateX(-startAngle)
        .scale(scale);


      function processData(data, tt) {
        console.log(data)

        /* ----------- POINTS ----------- */

        var points = svg.selectAll("circle.main").data(data[0], key);

        points
          .enter()
          .append("circle")
          .attr("class", "_3d main")
          .attr("opacity", 0)
          .attr("cx", posPointX)
          .attr("cy", posPointY)
          .merge(points)
          .attr("r", function (d) {
            return pointSize(d) + "px";
          })
          .style("fill", function (d) {
            if (d.id == "point_0") {
              return "#8525e5";
            } else {
              return "#4e3864";
            }
          })
          .attr("opacity", 0.7)
          .attr("cx", posPointX)
          .attr("cy", posPointY);

        points.exit().remove();

        /* ----------- GRAY BG POINTS ----------- */

        var pointsBG = svg.selectAll("circle.bg").data(data[4], key);

        pointsBG
          .enter()
          .append("circle")
          .attr("class", "_3d bg")
          .attr("opacity", 0)
          .attr("cx", posPointX)
          .attr("cy", posPointY)
          .merge(pointsBG)
          .attr("r", function (d) {
            return pointSize(d) + "px";
          })
          .attr("fill", "#4e3864")
          // disappear the points if they're closer than origin
          .attr("opacity", function (d) {
            if (d.rotated.z < 0) {
              return 0.25;
            } else {
              return 0;
            }
          })
          .attr("cx", posPointX)
          .attr("cy", posPointY);

        pointsBG.exit().remove();

        /* ----------- POINT TEXT ----------- */

        var pointText = svg.selectAll("g.pointText").data(data[0]);

        pointText
          .enter()
          .append("g")
          .attr("class", "_3d pointText")
          .merge(pointText)
          .attr("transform", function (d) {
            return "translate(" + d.projected.x + ", " + d.projected.y + ")";
          })
          .selectAll("*")
          .remove();

        pointText
          .append("text")
          .attr("dx", function (d) {
            return pointSize(d) * 1.2 + "px";
          })
          .attr("dy", function (d) {
            return pointSize(d) * 1.2 + "px";
          })
          .attr("class", "shadow")
          .text(function (d) {
            return d.label;
          })
          .attr("font-size", function (d) {
            return fontSize(d) + "px";
          });

        pointText
          .append("text")
          .attr("dx", function (d) {
            return pointSize(d) * 1.2 + "px";
          })
          .attr("dy", function (d) {
            return pointSize(d) * 1.2 + "px";
          })
          .text(function (d) {
            return d.label;
          })
          .attr("font-size", function (d) {
            return fontSize(d) + "px";
          })
          .style("fill", "#fff");

        pointText.exit().remove();

        /* ----------- x-Scale ----------- */

        var xScale = svg.selectAll("path.xScale").data(data[1]);

        xScale
          .enter()
          .append("path")
          .attr("class", "_3d xScale")
          .merge(xScale)
          .attr("stroke", "red")
          .attr("stroke-width", 0.75)
          .attr("opacity", 0.5)
          .attr("d", yScale3d.draw);

        xScale.exit().remove();

        /* ----------- y-Scale ----------- */

        var yScale = svg.selectAll("path.yScale").data(data[2]);

        yScale
          .enter()
          .append("path")
          .attr("class", "_3d yScale")
          .merge(yScale)
          .attr("stroke", "green")
          .attr("stroke-width", 0.75)
          .attr("opacity", 0.5)
          .attr("d", yScale3d.draw);

        yScale.exit().remove();

        /* ----------- z-Scale ----------- */

        var zScale = svg.selectAll("path.zScale").data(data[3]);

        zScale
          .enter()
          .append("path")
          .attr("class", "_3d zScale")
          .merge(zScale)
          .attr("stroke", "blue")
          .attr("stroke-width", 0.75)
          .attr("opacity", 0.5)
          .attr("d", yScale3d.draw);

        zScale.exit().remove();

        svg.selectAll("._3d").sort(_3d().sort);
      }

      function posPointX(d) {
        return d.projected.x;
      }

      function posPointY(d) {
        return d.projected.y;
      }

      function init() {
        var cnt = 0,
          scatter = [],
          yLine = [];

        console.log(radarChartData, "init2");

        scatter.push({
          x: radarChartData.query.x,
          y: radarChartData.query.y,
          z: radarChartData.query.z,
          label: radarChartData.query.word,
          id: "point_0",
        });

        for (var i = 0; i < radarChartData.neighbors.length; i++) {
          scatter.push({
            x: radarChartData.neighbors[i].x,
            y: radarChartData.neighbors[i].y,
            z: radarChartData.neighbors[i].z,
            label: radarChartData.neighbors[i].word,
            id: "point_" + (i + 1),
          });
        }

        backgroundDots = [];

        function backgroundDotRange() {
          return (Math.random() * mag_max * 2 - mag_max) * 4;
        }

        for (var i = 0; i < 10; i++) {
          backgroundDots.push({
            x: backgroundDotRange(),
            y: backgroundDotRange(),
            z: backgroundDotRange(),
          });
        }

        xLine = [
          [0, 0, 0],
          [j, 0, 0],
        ];
        yLine = [
          [0, 0, 0],
          [0, -j, 0],
        ];
        zLine = [
          [0, 0, 0],
          [0, 0, j],
        ];

        var data = [
          point3d(scatter),
          yScale3d([xLine]),
          yScale3d([yLine]),
          yScale3d([zLine]),
          point3d(backgroundDots),
        ];

        processData(data, 1000);
        processData(data, 1000);
        // text wasn't appearing until dragged, so added this extra rotate
        point3d.rotateY(startAngle).rotateX(startAngle)(scatter);
      }

      function hoverStart() {
        cursorStatus.hovering = true;
        cursorUpdate(cursorStatus);
      }

      function hoverEnd() {
        cursorStatus.hovering = false;
        cursorUpdate(cursorStatus);
      }

      function dragStart(event) {
        mx = d3.event.x;
        my = d3.event.y;
        console.log(event, 'event1')
        cursorStatus.dragging = true;
        cursorUpdate(cursorStatus);
      }

      function dragged(event) {
        let mouseX = mouseX || 0;
        let mouseY = mouseY || 0;
        let beta = ((d3.event.x - mx + mouseX) * Math.PI) / 230;
        let alpha = (((d3.event.y - my + mouseY) * Math.PI) / 230) * -1;
        console.log(beta, alpha)
        var data = [
          point3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)(scatter),
          yScale3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)([xLine]),
          yScale3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)([yLine]),
          yScale3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)([zLine]),
          point3d.rotateY(beta + startAngle).rotateX(alpha - startAngle)(backgroundDots)
        ];
        processData(data, 0);
      }

      function dragEnd(event) {
        mouseX = d3.event.x - mx + mouseX;
        mouseY = d3.event.y - my + mouseY;
        cursorStatus.dragging = false;
        cursorUpdate(cursorStatus);
      }

      init();

向组件添加图表:<RD3Component data={this.state.d3} />

我想这些问题涉及到React,因为我正在传输纯JS代码,所以效果很好。

也许有人面临上述问题?

版本:

  • D3 4.0.0
  • 反应 16
  • React-D3-库 1.1.8
4

0 回答 0