首页 > 解决方案 > 显示图表(使用 d3.js)

问题描述

我得到下面的 js 文件,我必须对其进行一些更改,这是使用 d3.js 库的 Javascript 代码,目标是从 JSON 数据中获取类似此屏幕截图的图表。首先,我想显示图表。我知道 javascript 代码正在运行,问题一定出在我的 html 文件中,但我真的不明白为什么什么也没发生。感谢您的帮助 !

var orgChart = (function() {
  var oldSelNode = null,
    oldSelID = null,
    oldSelColor = null,
    selNode = null,
    _x = 0,
    _y = 0,
    nodeID = -1,
    nodePID = -1;

  var _margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    },
    _root = {},
    _nodes = [],
    _counter = 0,
    _svgroot = null,
    _svg = null,
    _tree = null,
    _diagonal = null,
    _lineFunction = null,
    _loadFunction = null,
    /* Configuration */
    _duration = 500,
    /* Duration of the animations */
    _rectW = 250,
    /* Width of the rectangle */
    _rectH = 50,
    /* Height of the rectangle */
    _rectSpacing = 20 /* Spacing between the rectangles */
  _fixedDepth = 40, /* Height of the line for child nodes */
    _mode = "diagonal", /* Choose the values "line" or "diagonal" */
    _callerNode = null,
    _callerMode = 0,
    _scale = 0.3,
    _zoomEnabled = false,
    _dragEnabled = true,
    defLinearGradient = function(id, x1, y1, x2, y2, stopsdata) {
      var gradient = _svgroot.append("svg:defs")
        .append("svg:linearGradient")
        .attr("id", id)
        .attr("x1", x1)
        .attr("y1", y1)
        .attr("x2", x2)
        .attr("y2", y2)
        .attr("spreadMethod", "pad");
      $.each(stopsdata, function(index, value) {
        gradient.append("svg:stop")
          .attr("offset", value.offset)
          .attr("stop-color", value.color)
          .attr("stop-opacity", value.opacity);
      });
    },
    defBoxShadow = function(id) {
      var filter = _svgroot.append("svg:defs")
        .append("svg:filter")
        .attr("id", id).attr("height", "150%").attr("width", "150%");

      filter.append("svg:feOffset")
        .attr("dx", "2").attr("dy", "2").attr("result", "offOut"); // how much to offset
      filter.append("svg:feGaussianBlur")
        .attr("in", "offOut").attr("result", "blurOut").attr("stdDeviation", "2"); // stdDeviation is how much to blur
      filter.append("svg:feBlend")
        .attr("in", "SourceGraphic").attr("in2", "blurOut").attr("mode", "normal");
    },
    collapse = function(d) {
      if (d.children) {

      }

    },

    update = function(source) {
      // Compute the new tree layout.
      _nodes = _tree.nodes(_root).reverse();
      var links = _tree.links(_nodes);
      // Normalize for fixed-depth.
      _nodes.forEach(function(d) {
        d.y = d.depth * _fixedDepth;
      });
      // Update the nodes
      var node = _svg.selectAll("g.node")
        .data(_nodes, function(d) {
          return d.id || (d.id = ++_counter);
        });
      // Enter any new nodes at the parent's previous position.
      var nodeEnter = node.enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) {
          return "translate(" + source.x0 + "," + source.y0 + ")";
        })
        .on("click", nodeclick)
        .on("contextmenu", contextmenuclick);

      nodeEnter.append("rect")
        .attr("width", _rectW)
        .attr("height", _rectH)
        .attr("fill", "#898989")
        .attr("filter", "url(#boxShadow)");

      nodeEnter.append("rect")
        .attr("width", _rectW)
        .attr("height", _rectH)
        .attr("id", function(d) {
          return d.id;
        })
        .attr("fill", function(d) {
          return d.fill
        })
        .style("cursor", "pointer")
        .attr("class", "box");

      nodeEnter.append("text")
        .attr("x", _rectW / 2)
        .attr("y", _rectH / 2)
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .attr("fill", "#FFFF")
        .style("cursor", "pointer")
        .text(function(d) {
          return d.desc;
        });
      // Transition nodes to their new position.
      var nodeUpdate = node.transition()
        .duration(_duration)
        .attr("transform", function(d) {
          return "translate(" + d.x + "," + d.y + ")";
        });
      nodeUpdate.select("#_" + _canvasObj.nm + " rect.box")
        .attr("fill", function(d) {
          return (d.fill);
        });
      // Transition exiting nodes to the parent's new position.
      var nodeExit = node.exit().transition()
        .duration(_duration)
        .attr("transform", function(d) {
          return "translate(" + source.x + "," + source.y + ")";
        })
        .remove();

      // Update the links
      var link = _svg.selectAll("path.link")
        .data(links, function(d) {
          return d.target.id;
        });

      if (_mode === "line") {
        // Enter any new links at the parent's previous position.
        link.enter().append("path", "g")
          .attr("class", "link")
          .attr("d", function(d) {
            var u_line = (function(d) {
              var u_linedata = [{
                "x": d.source.x0 + parseInt(_rectW / 2),
                "y": d.source.y0 + _rectH + 2
              }, {
                "x": d.source.x0 + parseInt(_rectW / 2),
                "y": d.source.y0 + _rectH + 2
              }, {
                "x": d.source.x0 + parseInt(_rectW / 2),
                "y": d.source.y0 + _rectH + 2
              }, {
                "x": d.source.x0 + parseInt(_rectW / 2),
                "y": d.source.y0 + _rectH + 2
              }];
              return u_linedata;
            })(d);
            return _lineFunction(u_line);
          });

        // Transition links to their new position.
        link.transition()
          .duration(_duration)
          .attr("d", function(d) {
            var u_line = (function(d) {
              var u_linedata = [{
                "x": d.source.x + parseInt(_rectW / 2),
                "y": d.source.y + _rectH
              }, {
                "x": d.source.x + parseInt(_rectW / 2),
                "y": d.target.y - _margin.top / 2
              }, {
                "x": d.target.x + parseInt(_rectW / 2),
                "y": d.target.y - _margin.top / 2
              }, {
                "x": d.target.x + parseInt(_rectW / 2),
                "y": d.target.y
              }];
              return u_linedata;
            })(d);
            return _lineFunction(u_line);
          });

        // Transition exiting nodes to the parent's new position.
        link.exit().transition()
          .duration(_duration)
          .attr("d", function(d) {
            /* This is needed to draw the lines right back to the caller */
            var u_line = (function(d) {
              var u_linedata = [{
                "x": _callerNode.x + parseInt(_rectW / 2),
                "y": _callerNode.y + _rectH + 2
              }, {
                "x": _callerNode.x + parseInt(_rectW / 2),
                "y": _callerNode.y + _rectH + 2
              }, {
                "x": _callerNode.x + parseInt(_rectW / 2),
                "y": _callerNode.y + _rectH + 2
              }, {
                "x": _callerNode.x + parseInt(_rectW / 2),
                "y": _callerNode.y + _rectH + 2
              }];
              return u_linedata;
            })(d);
            return _lineFunction(u_line);
          }).each("end", function() {
            _callerNode = null; /* After transition clear the caller node variable */
          });
      } else if (_mode === "diagonal") {
        // Enter any new links at the parent's previous position.
        link.enter().insert("path", "g")
          .attr("class", "link")
          .attr("x", _rectW / 2)
          .attr("y", _rectH / 2)
          .attr("d", function(d) {
            var o = {
              x: source.x0,
              y: source.y0
            };
            return _diagonal({
              source: o,
              target: o
            });
          });

        // Transition links to their new position.
        link.transition()
          .duration(_duration)
          .attr("d", _diagonal);

        // Transition exiting nodes to the parent's new position.
        link.exit().transition()
          .duration(_duration)
          .attr("d", function(d) {
            var o = {
              x: source.x,
              y: source.y
            };
            return _diagonal({
              source: o,
              target: o
            });
          })
          .remove();
      }
      // Stash the old positions for transition.
      _nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });
    },

    // Toggle children on click.
    nodeclick = function(d) {
      selNode = d;
      d3.selectAll("#_" + _canvasObj.nm + " rect.box").style("fill", function(d) {
        return d.fill
      });

      d3.select(this.childNodes[1]).style("fill", "red");
      oldSelNode = this.childNodes[1];

      nodeID = d.id;
      if (d.parent && d.parent.id) {
        nodePID = d.parent.id
      } else {
        nodePID = -1
      };
      ajaxRequest(_canvasObj, "_nodeclick", ["nodeID=" + nodeID, "nodePID=" + nodePID, "nodeText=" + d.desc], false);

      pn = d.parent;
      dd = function(d) {
        Ext.get(pn.id).dom.style.fill = "yellow";
      }
      while (pn) {
        dd(pn);
        pn = pn.parent;
      }

    },
    // contextmenu
    contextmenuclick = function(d) {
      selNode = d;

      d3.selectAll("#_" + _canvasObj.nm + " rect.box").style("fill", function(d) {
        return d.fill
      });

      function getScreenCoords(x, y, ctm) {
        var xn = ctm.e + x * ctm.a + y * ctm.c;
        var yn = ctm.f + x * ctm.b + y * ctm.d;
        return {
          x: xn,
          y: yn
        };
      }

      var _node = this,
        cx = +_node.getAttribute('cx'),
        cy = +_node.getAttribute('cy'),
        ctm = _node.getCTM(),
        coords = getScreenCoords(cx, cy, ctm);

      _x = parseInt(coords.x) + parseInt(_canvasObj.x) + parseInt(_rectW + 5),
        _y = parseInt(coords.y) + parseInt(_rectH + 25);

      d3.select(this.childNodes[1]).style("fill", "red");
      oldSelNode = this.childNodes[1];

      nodeID = d.id;
      if (d.parent && d.parent.id) {
        nodePID = d.parent.id
      } else {
        nodePID = -1
      };
      ajaxRequest(_canvasObj, "_contextmenu", ["x=" + _x, "y=" + _y, "nodeID=" + nodeID, "nodePID=" + nodePID, "nodeText=" + d.desc], false);

      pn = d.parent;
      dd = function(d) {
        Ext.get(pn.id).dom.style.fill = "yellow";
      }
      while (pn) {
        dd(pn);
        pn = pn.parent;
      }

    },

    // delete Node
    deleteNode = function(event) {
      if (selNode.parent) {
        var tSelNode = selNode;
        selNode = selNode.parent;
        addRemoveNode(event, -1);
        selNode = tSelNode;
        simulateClick(selNode.parent);
      }
    }

  // rename Node
  renameNode = function(newValue) {
    d = selNode;
    nodeID = d.id;
    d.desc = newValue;
    d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
      if (n.childNodes[1].id == nodeID) n.childNodes[2].textContent = newValue
    })
  }

  // add Node
  addNode = function(event, id) {
    if (selNode.parent) {
      var tSelNode = selNode;
      selNode = selNode.parent;
      addRemoveNode(event, id);
      selNode = tSelNode;
    }
  }

  // simulateClick
  function simulateClick(elem, id) {
    var evt = document.createEvent("MouseEvents");
    evt.initMouseEvent(
      "click", /* type */
      true, /* canBubble */
      true, /* cancelable */
      window, /* view */
      0, /* detail */
      0, /* screenX */
      0, /* screenY */
      0, /* clientX */
      0, /* clientY */
      false, /* ctrlKey */
      false, /* altKey */
      false, /* shiftKey */
      false, /* metaKey */
      0, /* button */
      null); /* relatedTarget */
    if (elem != null) {
      d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
        if (n.childNodes[1].id == elem.id) n.dispatchEvent(evt)
      });
    } else {
      d3.selectAll("#_" + _canvasObj.nm + " .node")[0].forEach(function(n) {
        if (n.childNodes[1].id == id) n.dispatchEvent(evt)
      })
    }
  }

  // add Child Node
  addRemoveNode = function(event, id) {
      var xhrPopup = new XMLHttpRequest();
      var formDataEmpty = new FormData();

      d = selNode;
      nodeID = d.id;

      xhrPopup.open("POST", "/HandleEvent?Evt=" + event + "&IsEvent=1&Obj=" + _canvasObj.nm + "&" + _S_ID + "&nodeID=" + nodeID, false);


      xhrPopup.onreadystatechange = function() {
        if (xhrPopup.readyState == 4) {
          var _res = xhrPopup.response;

          var response = {
            id: d.id,
            desc: d.desc,
            children: JSON.parse(_res)
          };

          response.children.forEach(function(child) {
            if (!_tree.nodes(d)[0]._children) {
              _tree.nodes(d)[0]._children = [];
            }

            child.x = d.x;
            child.y = d.y;
            child.x0 = d.x0;
            child.y0 = d.y0;
            _tree.nodes(d)[0]._children.push(child);
          });

          _callerNode = null;
          _callerMode = 1; // Expand
          d.children = d._children;
          d._children = null;

          update(d);

          if (id != -1) {
            simulateClick(null, id)
          }
        }
      };

      xhrPopup.send(formDataEmpty);
    },

    //refill

    refill = function(v) {
      selNode.fill = v;
    },

    //Redraw for zoom
    redraw = function() {
      _svg.attr("transform", "translate(" + d3.event.translate + ")" +
        " scale(" + d3.event.scale.toFixed(_scale) + ")");
    },
    initTree = function(options) {
      //oldSelColor = null;
      //oldSelNode = null;

      oldSelID = -1;
      var u_opts = $.extend({
            id: "",
            data: {},
            modus: "line",
            canvasObj: null,
            rectW: 250,
            rectH: 50,
            loadFunc: function() {}
          },
          options),
        id = u_opts.id;
      _loadFunction = u_opts.loadFunc;
      _mode = u_opts.modus;
      _root = u_opts.data;

      _rectW = u_opts.rectW;
      _rectH = u_opts.rectH;

      _fixedDepth = _rectH * 2.5;

      _canvasObj = u_opts.canvasObj;

      /*if(_mode == "line") {
         _fixedDepth = 80;
      } else {
         _fixedDepth = 110;
      }*/

      $(id).html(""); // Reset
      var width = $(id).innerWidth() - _margin.left - _margin.right,
        height = $(id).innerHeight() - _margin.top - _margin.bottom;
      _tree = d3.layout.tree().nodeSize([_rectW + _rectSpacing, _rectH + _rectSpacing]);
      /* Basic Setup for the diagonal function. _mode = "diagonal" */
      _diagonal = d3.svg.diagonal()
        .projection(function(d) {
          return [d.x + _rectW / 2, d.y + _rectH / 2];
        });
      /* Basic setup for the line function. _mode = "line" */
      _lineFunction = d3.svg.line()
        .x(function(d) {
          return d.x;
        })
        .y(function(d) {
          return d.y;
        })
        .interpolate("linear");
      var u_childwidth = parseInt((_root.children.length * _rectW) / 2);
      _svgroot = d3.select(id).append("svg").attr("width", width).attr("height", height).attr("id", "_" + _canvasObj.nm) //.attr("viewBox", "0,0,150,420")
        //.call(zm = d3.behavior.zoom().scaleExtent([0.15,3]).on("zoom", null));
        .call(zm = d3.behavior.zoom().scaleExtent([0.15, 3]).on("zoom", redraw)).on('dblclick.zoom', null);;

      _svg = _svgroot.append("g")
        .attr("transform", "translate(" + parseInt(u_childwidth + ((width - u_childwidth * 2) / 2) - _margin.left / 2) + "," + 20 + ")");
      var u_stops = [{
        offset: "0%",
        color: "#03A9F4",
        opacity: 1
      }, {
        offset: "100%",
        color: "#0288D1",
        opacity: 1
      }];
      defLinearGradient("gradientnochilds", "0%", "0%", "0%", "100%", u_stops);
      var u_stops = [{
        offset: "0%",
        color: "#8BC34A",
        opacity: 1
      }, {
        offset: "100%",
        color: "#689F38",
        opacity: 1
      }];
      defLinearGradient("gradientchilds", "0%", "0%", "0%", "100%", u_stops);

      defBoxShadow("boxShadow");

      //necessary so that zoom knows where to zoom and unzoom from
      zm.translate([parseInt(u_childwidth + ((width - u_childwidth * 2) / 2) - _margin.left / 2), 20]);
      //zm.translate([0, 10]);
      _root.x0 = 0; // the root is already centered
      _root.y0 = 0; // draw & animate from center
      _root.children.forEach(collapse);
      update(_root);
      d3.select(id).style("height", height + _margin.top + _margin.bottom);
    };
  return {
    initTree: initTree,
    addRemoveNode: addRemoveNode,
    renameNode: renameNode,
    addNode: addNode,
    deleteNode: deleteNode,
    refill: refill
  };
})();
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Titre</title>
  <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
  <script src="d3.v3.min.js"></script>
  <script src="orgChart.js"></script>
  <script type="text/javascript">
    var canv = document.createElement('canvas');
    canv.id = "CursorLayer";
    canv.width = 1224;
    canv.height = 768;
    canv.style.zIndex = 8;
    canv.style.position = "absolute";
    canv.style.border = "1px solid";
    var _jsonstr = JSON.parse("{\"id\":\"11\", \"desc\":\"5\", \"children\":[{\"id\":\"12\", \"desc\":\"5.1\"},{\"id\":\"13\", \"desc\":\"5.2\"},{\"id\":\"14\", \"desc\":\"5.3\", \"children\":[{\"id\":\"15\", \"desc\":\"5.3.1\"},{\"id\":\"16\", \"desc\":\"5.3.2\", \"children\":[{\"id\":\"17\", \"desc\":\"5.3.2.1\"},{\"id\":\"18\", \"desc\":\"5.3.2.2\"}]},{\"id\":\"19\", \"desc\":\"5.3.3\"}]},{\"id\":\"20\", \"desc\":\"5.4\", \"children\":[{\"id\":\"21\", \"desc\":\"5.4.1\"},{\"id\":\"22\", \"desc\":\"5.4.2\", \"children\":[{\"id\":\"23\", \"desc\":\"5.4.2.1\"},{\"id\":\"24\", \"desc\":\"5.4.2.2\", \"children\":[{\"id\":\"25\", \"desc\":\"5.4.2.2.1\"},{\"id\":\"26\", \"desc\":\"5.4.2.2.2\", \"children\":[{\"id\":\"27\", \"desc\":\"5.4.2.2.2.1\"}]}]},{\"id\":\"28\", \"desc\":\"5.4.2.3\"},{\"id\":\"29\", \"desc\":\"5.4.2.4\"}]},{\"id\":\"30\", \"desc\":\"5.4.3\"}]}]}");
    orgChart.initTree({
      id: "#O13_id-innerCt",
      data: _jsonstr,
      modus: "diagonal",
      canvasObj: canv,
      loadFunc: function() {}
    });
  </script>
</head>

<body>
</body>

</html>

标签: javascripthtmljsond3.js

解决方案


这是显示某些内容的第一步(所有更改都在最后一个<script>标签内):

1) 尽管有名字,但它看起来canvasObj应该是<svg>. 所以,更换

var canv = document.createElement('canvas');

var canv = document.createElement('div');

2) 通过查看以下行:d3.selectAll("#_" + _canvasObj.nm + " rect.box")我们可以推断,canvas id 必须以开头_并且.nm属性必须等于没有 的 id _,因此您可以这样声明:

canv.id = '_CursorLayer';
canv.nm = 'CursorLayer';

您还必须替换id: "#O13_id-innerCt",id: "#_CursorLayer"

3)SVG尺寸取自canvsize。由于div没有widthheight属性,你应该通过css指定它们:

canv.style.width = '1224px';
canv.style.height = '768px';

4)我们需要附加canvbody才能看到它:

document.body.appendChild(canv);

为了document.body在最后一次执行期间可用<script>,我建议将最后一个<script>标签移到<body>.


推荐阅读