股权结构图 vue2+d3.js

效果图:

1.安装d3.js 此处采用的是v3版本

npm i d3@3.5.6

2.在模块中引入d3

import * as d3 from "d3"

3.使用

// 股权架构图
<template>
  <div id="borrow">
    <div class="functionBox">
      <div
        class="functionItem"
        :class="isFullscreen ? 'el-icon-plus' : 'el-icon-minus'"
        @click="toggleFullScreen"
      ></div>
      <div
        class="functionItem el-icon-download"
        @click="downloadImpByChart"
      ></div>
    </div>
    <div id="mountNode"></div>
  </div>
</template>
 
<script>
import * as d3 from "d3";
export default {
  data() {
    return {
      isFullscreen: true, //全屏
      rootData: {
        downward: {
          direction: "down", //向下
          name: "origin",
          children: [
            {
              name: "公司名称1号", //名称
              amount: "100", //认缴金额
              ratio: "55%", //控股百分比
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2, //有无背景色
              hasNode: 1,
              children: [
                {
                  name: "公司名字1-1号",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司名字1-2号",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
              ],
            },
            {
              name: "公司名称2号",
              amount: "100",
              isHoldingCompany: true,
              ratio: "55%",
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: "公司名字2-1",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司名字2-2",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
              ],
            },
            {
              name: "公司名称3号",
              amount: "100",
              isHoldingCompany: true,
              ratio: "55%",
              hasHumanholding: true,
              hasChildren: true,
              isExpand: false,
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: "公司名字3-1",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司名字3-2",
                  hasHumanholding: false,
                  hasChildren: true,
                  amount: "100",
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
              ],
            },
            {
              name: "公司名称4号",
              hasHumanholding: false,
              hasChildren: true,
              amount: "100",
              ratio: "55%",
              type: 2,
              children: [],
            },
            {
              name: "公司名称5号",
              hasHumanholding: false,
              hasChildren: true,
              isExpand: false,
              amount: "100",
              ratio: "55%",
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: "公司或股东名字11",
                  hasHumanholding: false,
                  amount: "100",
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司或股东名字22",
                  hasHumanholding: false,
                  amount: "100",
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司或股东名字33",
                  hasHumanholding: false,
                  amount: "100",
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
                {
                  name: "公司或股东名字44",
                  hasHumanholding: false,
                  amount: "100",
                  ratio: "55%",
                  type: 2,
                  children: [],
                },
              ],
            },
          ],
        },
        upward: {
          direction: "up",
          name: "origin",
          children: [
            {
              name: "1号(有限合伙)",
              hasHumanholding: false,
              amount: "100",
              isHoldingCompany: true,
              ratio: "55%",
              type: 2,
            },
            {
              name: "2号(有限合伙)",
              hasHumanholding: false,
              amount: "100",
              isHoldingCompany: true,
              ratio: "55%",
              type: 2,
              hasNode: 1,
              children: [
                {
                  name: "公司或股东名字",
                  hasHumanholding: false,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 1,
                  children: [],
                  isFHolder: true,
                  holderPercent: "5%",
                },
                {
                  name: "公司或股东名字",
                  hasHumanholding: false,
                  isExpand: false,
                  amount: "100",
                  isHoldingCompany: true,
                  ratio: "55%",
                  type: 2,
                  hasNode: 1,
                  children: [
                    {
                      name: "公司或股东名字",
                      hasHumanholding: false,
                      amount: "100",
                      isHoldingCompany: true,
                      ratio: "55%",
                      type: 1,
                      isFHolder: true,
                      isActualController: true,
                      holderPercent: "95%",
                      children: [],
                    },
                    {
                      name: "公司或股东名字",
                      hasHumanholding: false,
                      amount: "100",
                      ratio: "55%",
                      type: 2,
                      children: [],
                    },
                  ],
                },
                {
                  name: "公司或股东名字",
                  hasHumanholding: false,
                  amount: "100",
                  ratio: "55%",
                  type: 1,
                  children: [],
                },
              ],
            },
          ],
        },
      },
      rootName: "", //根名字
      beijingCrid: "98682337095519887",
    };
  },
  mounted() {
    this.getInitData();
    let that = this;
    window.addEventListener("resize", function () {
      //ESC退出全屏改变图表
      if (!that.checkFull()) {
        that.isFullscreen = true;
      }
      const svg = document.getElementById("svg");
      svg.setAttribute("height", window.innerHeight);
    });
  },
  methods: {
    //初始化-配置根公司名字
    getInitData() {
      this.rootName = "公司名称";
      this.drawing();
    },
    //配置方法
    drawing() {
      const width = document.getElementById("mountNode").scrollWidth;
      const height = document.getElementById("mountNode").scrollHeight || 600;
      const strokeColor = {
        isActualController: "#FBC6C3",
        isFHolder: "#F3DDB6",
        person: "#0084FF",
        default: "#CCC",
      };
      const lineColor = {
        isActualController: "#FA6B64",
        isFHolder: "#F1B03A",
        person: "#0084FF",
        default: "#919191",
      };
      var _this = this;
      var rootRectWidth = 0; //根节点rect的宽度
      var downwardLength = 0,
        upwardLength = 0;
      var forUpward = true;

      var treeChart = function (d3Object) {
        this.d3 = d3Object;
        this.directions = ["upward", "downward"];
      };
      // 绘制图源数据
      treeChart.prototype.drawChart = function () {
        // 获取两个方向的树数据.
        this.treeData = {};
        var self = this;
        self.directions.forEach(function (direction) {
          self.treeData[direction] = _this.rootData[direction];
        });
        //根节点的宽度 字数*15+60 px
        rootRectWidth = _this.rootName.length * 15 + 60;
        //获得upward第一级节点的个数
        upwardLength = _this.rootData.upward.children.length;
        //获得downward第一级节点的个数
        downwardLength = _this.rootData.downward.children.length;
        self.graphTree(self.getTreeConfig());
      };
      //树 设置
      treeChart.prototype.getTreeConfig = function () {
        var treeConfig = {
          margin: {
            top: 10,
            right: 5,
            bottom: 0,
            left: 30,
          },
        };
        treeConfig.chartWidth =
          width - treeConfig.margin.right - treeConfig.margin.left;
        treeConfig.chartHeight =
          height - treeConfig.margin.top - treeConfig.margin.bottom;
        treeConfig.centralHeight = treeConfig.chartHeight / 2;
        treeConfig.centralWidth = treeConfig.chartWidth / 2;
        treeConfig.linkLength = 160;
        treeConfig.duration = 500; //动画时间
        return treeConfig;
      };

      treeChart.prototype.graphTree = function (config) {
        var self = this;
        var d3 = this.d3;
        var linkLength = config.linkLength;
        var duration = config.duration;
        var hasChildNodeArr = [];
        var id = 0;
        var diagonal = function (obj) {
          //折线

          var s = obj.source;
          var t = obj.target;
          let multiplier = s.x > t.x ? -1 : s.x < t.x ? 1 : 0;
          let path =
            s.y > t.y ? s.y / 3 + (t.y * 2) / 3 : s.y / 3 + (t.y * 2) / 3 + 15;
          return (
            "M" +
            s.x +
            "," +
            (s.y + 12) +
            "L" +
            s.x +
            "," +
            path +
            "L" +
            t.x +
            "," +
            path +
            // pathA+
            "L" +
            t.x +
            "," +
            t.y
          );
        };
        // 放大缩小 限制范围
        var zoom = d3.behavior.zoom().scaleExtent([0.5, 2]).on("zoom", redraw);

        var svg = d3
          .select("#mountNode")
          .append("svg")
          .attr("id", "svg")
          .attr(
            "width",
            config.chartWidth + config.margin.right + config.margin.left
          )
          .attr(
            "height",
            config.chartHeight + config.margin.top + config.margin.bottom
          )
          .attr("xmlns", "http://www.w3.org/2000/svg")
          .on("mousedown", disableRightClick)
          .call(zoom)
          .on("dblclick.zoom", null);
        var treeG = svg
          .append("g")
          .attr("class", "gbox")
          .attr(
            "transform",
            "translate(" + config.margin.left + "," + config.margin.top + ")"
          );

        d3.select("#reset").on("click", function (d) {
          interpolateZoom([0, 0], 1);
        });
        function interpolateZoom(translate, scale) {
          var self = this;
          return d3
            .transition()
            .duration(350)
            .tween("zoom", function () {
              var iTranslate = d3.interpolate(zoom.translate(), translate),
                iScale = d3.interpolate(zoom.scale(), scale);
              return function (t) {
                zoom.scale(iScale(t)).translate(iTranslate(t));
                redraw();
              };
            });
        }

        function zoomClick() {
          var clicked = d3.event.target,
            direction = 1,
            factor = 0.2,
            target_zoom = 1,
            center = [width / 2, height / 2],
            extent = zoom.scaleExtent(),
            translate = zoom.translate(),
            translate0 = [],
            l = [],
            view = { x: translate[0], y: translate[1], k: zoom.scale() };

          d3.event.preventDefault();
          direction = this.id === "zoomOut" ? 1 : -1;

          target_zoom = Number(zoom.scale() + factor * direction).toFixed(1);

          if (target_zoom === extent[0] || target_zoom === extent[1]) {
            return false;
          }
          if (target_zoom < extent[0]) {
            target_zoom = extent[0];
          }
          if (target_zoom > extent[1]) {
            target_zoom = extent[1];
          }
          translate0 = [
            (center[0] - view.x) / view.k,
            (center[1] - view.y) / view.k,
          ];
          view.k = target_zoom;
          l = [
            translate0[0] * view.k + view.x,
            translate0[1] * view.k + view.y,
          ];

          view.x += center[0] - l[0];
          view.y += center[1] - l[1];

          interpolateZoom([view.x, view.y], view.k);
        }
        d3.select("#zoomIn").on("click", zoomClick);
        d3.select("#zoomOut").on("click", zoomClick);
        for (var d in this.directions) {
          var direction = this.directions[d];
          var data = self.treeData[direction];
          data.x0 = config.centralWidth;
          data.y0 = config.centralHeight;
          data.children.forEach(collapse);
          update(data, data, treeG);
        }

        function update(source, originalData, g) {
          var direction = originalData["direction"];
          forUpward = direction == "up";
          var node_class = direction + "Node";
          var link_class = direction + "Link";
          var downwardSign = forUpward ? -1 : 1;
          var nodeColor = forUpward ? "#37592b" : "#8b4513";

          var isExpand = false;
          var statusUp = true;
          var statusDown = true;
          var nodeSpace = 210;
          var tree = d3.layout.tree().sort(sortByDate).nodeSize([nodeSpace, 0]);
          var nodes = tree.nodes(originalData);
          var links = tree.links(nodes);
          var offsetX = -config.centralWidth;
          nodes.forEach(function (d) {
            d.y = downwardSign * (d.depth * linkLength) + config.centralHeight;
            d.x = d.x - offsetX;
            if (d.name == "origin") {
              d.x = config.centralWidth;
              d.y += downwardSign * 0; // 上下两树图根节点之间的距离
            }
          });

          var node = g.selectAll("g." + node_class).data(nodes, function (d) {
            return d.id || (d.id = ++id);
          });
          var nodeEnter = node
            .enter()
            .append("g")
            .attr("class", node_class)
            .attr("transform", function (d) {
              return "translate(" + source.x0 + "," + source.y0 + ")";
            })
            .style("cursor", function (d) {
              return d.name == "origin"
                ? ""
                : d.children || d._children
                ? "pointer"
                : "";
            })
            .on("click", (d) => {
              if (d.type == 2) {
                if (
                  (d.direction == "up" && d.beijingCrid) ||
                  (d.direction == "down" && d.pbeijingCrid)
                ) {
                  _this.$router.push({
                    path: "/search/detail",
                    name: "search-detail",
                    query: {
                      companyId:
                        d.direction == "up" ? d.beijingCrid : d.pbeijingCrid,
                    },
                  });
                }
              }
            })
            .on("mouseover", (d) => {
              if (d.name === "origin") {
                return false;
              }
              let hoverLinkArr = [d.id];
              let sColor = strokeColor.default;
              let lColor = lineColor.default;
              if (d.isActualController) {
                sColor = strokeColor.isActualController;
                lColor = lineColor.isActualController;
              } else if (d.isFHolder) {
                sColor = strokeColor.isFHolder;
                lColor = lineColor.isFHolder;
              } else {
                sColor = strokeColor.person;
                lColor = lineColor.person;
              }
              getRelationLink(d.id, lColor);
              d3.selectAll("marker#resolved" + d.id)
                .selectAll("path")
                .attr("fill", lColor);
              let link;
              if (d.direction == "up") {
                link = d3.selectAll(".upLink");
              } else {
                link = d3.selectAll(".downLink");
              }
              link.sort(function (a, b) {
                if (a.target.id === d.id) {
                  return 1;
                } else {
                  return -1;
                }
              });
              rect
                .style("stroke-width", function (r) {
                  if (r.id === d.id) {
                    return "2";
                  }
                })
                .style("stroke", function (r) {
                  if (r.id === d.id) {
                    if (r.type == 2) {
                      return "#0084FF";
                    } else {
                      if (r.type == 1) {
                        if (r.isActualController) {
                          return "#FA6B64";
                        } else if (r.isFHolder) {
                          return "#F1B03A";
                        } else {
                          return "#0084FF";
                        }
                      } else {
                        return "#CCC";
                      }
                    }
                  } else {
                    if (r.type == 1) {
                      if (r.isActualController) {
                        return "#FBC6C3";
                      } else if (r.isFHolder) {
                        return "#F3DDB6";
                      } else {
                        return "#83C6FF";
                      }
                    } else if (r.name === "origin") {
                      return "#0E78DB";
                    } else {
                      return "#CCC";
                    }
                  }
                });
            })
            .on("mouseout", (d) => {
              if (d.name === "origin") {
                return false;
              }
              d3.selectAll("marker#resolved" + d.id)
                .selectAll("path")
                .attr("fill", lineColor.default);
              link
                .style("stroke", function (l) {
                  return "#919191";
                })
                .style("stroke-width", function (l) {
                  return 1;
                });
              rect
                .style("stroke-width", function (r) {
                  if (r.id === d.id) {
                    return "1";
                  }
                })
                .style("stroke", function (r) {
                  if (r.type == 1) {
                    if (r.isActualController) {
                      return "#FBC6C3";
                    } else if (r.isFHolder) {
                      return "#F3DDB6";
                    } else {
                      return "#83C6FF";
                    }
                  } else if (r.name === "origin") {
                    return "#0E78DB";
                  } else {
                    return "#CCC";
                  }
                });
            });
          function getRelationLink(id, color) {
            if (id == 1) {
              return false;
            }
            let sourceId = "";
            link
              .style("stroke", function (l) {
                if (id === l.target.id) {
                  sourceId = l.source.id;
                  return color;
                }
              })
              .style("stroke-width", function (l) {
                if (id === l.target.id) {
                  return 2;
                }
              });
          }
          const rect = nodeEnter
            .append("svg:rect")
            .attr("x", function (d) {
              return d.name == "origin" ? -(rootRectWidth / 2) : -100;
            })
            .attr("y", function (d) {
              return d.name == "origin" ? -20 : forUpward ? -52 : 12;
            })
            .attr("width", function (d) {
              return d.name == "origin" ? rootRectWidth : 200;
            })
            .attr("height", function (d) {
              return d.name == "origin" ? 40 : 80;
            })
            .attr("rx", 0)
            .style("cursor", "pointer")
            .style("stroke", function (d) {
              if (d.name == "origin") {
                return "#0E78DB";
              } else if (d.type == 1) {
                if (d.isActualController) {
                  return "#FBC6C3";
                } else if (d.isFHolder) {
                  return "#F3DDB6";
                } else {
                  return "#83C6FF";
                }
              } else {
                return "#CCC";
              }
            })
            .style("fill", function (d) {
              if (d.name == "origin") {
                return "#0084FF";
              } else if (d.type == 1) {
                if (d.isActualController) {
                  return "#FFFBFB";
                } else if (d.isFHolder) {
                  return "#FEFBF3";
                } else {
                  return "#F5FAFF";
                }
              } else {
                return "#fff";
              }
            });

          const personTopRect = nodeEnter
            .append("svg:rect")
            .attr("x", function (d) {
              return -100;
            })
            .attr("y", function (d) {
              return !d.isFHolder ? 0 : d.isActualController ? -102 : -82;
            })
            .attr("width", function (d) {
              return d.isFHolder ? 200 : 0;
            })
            .attr("height", function (d) {
              return !d.isFHolder ? 0 : d.isActualController ? 50 : 30;
            })
            .attr("rx", 2)
            .style("stroke", function (d) {
              return d.isActualController ? "#FA6B64" : "#F1B03A";
            })
            .style("fill", function (d) {
              return d.isActualController ? "#FA6B64" : "#F1B03A"; //节点背景色
            });
          nodeEnter
            .append("svg:path")
            .attr("fill", (d) => {
              return d.isActualController ? "#FA6B64" : "#F1B03A";
            })
            .attr("d", function (d) {
              if (d.isFHolder) {
                return "M0 -44 L-10 -54 L10 -54 Z";
              } else {
                return "";
              }
            });
          //控股  - 样式
          const holdingCompanyRect = nodeEnter
            .append("svg:rect")
            .attr("x", "-40")
            .attr("y", function (d) {
              return d.name == "origin" ? ".35em" : forUpward ? "31" : "-9";
            })
            .attr("rx", 2)
            .attr("width", function (d) {
              return d.isHoldingCompany ? 30 : 0;
            })
            .attr("height", function (d) {
              return d.isHoldingCompany ? 20 : 0;
            })
            .style("fill", "#EBF5FF");
          nodeEnter
            .append("text")
            .attr("x", "-35")
            .attr("dy", function (d) {
              return d.name == "origin" ? ".35em" : forUpward ? "45" : "5";
            })
            .attr("text-anchor", "start")
            .style("fill", "#0084FF")
            .style("font-size", 10)
            .text(function (d) {
              return d.isHoldingCompany ? "控股" : "";
            });
          nodeEnter.append("circle").attr("r", 1e-6);
          nodeEnter
            .append("text")
            .attr("x", function (d) {
              return "0";
            })
            .attr("dy", function (d) {
              return d.name == "origin" ? ".35em" : forUpward ? "-24" : "40";
            })
            .attr("text-anchor", function (d) {
              return "middle";
            })
            .text(function (d) {
              if (d.name == "origin") {
                return _this.rootName;
              }
              if (d.repeated) {
                return "[Recurring] " + d.name;
              }
              return d.name.length > 12 ? d.name.substr(0, 12) : d.name;
            })
            .style({
              fill: function (d) {
                if (d.name == "origin") {
                  return "#fff";
                } else {
                  return "#333";
                }
              },
              "font-size": function (d) {
                return d.name == "origin" ? 16 : 14;
              },
              cursor: "pointer",
            })
            .on("click", Change_modal)
            .append("svg:title")
            .text((d) => d.name);
          nodeEnter
            .append("text")
            .attr("x", "0")
            .attr("dy", function (d) {
              return d.name == "origin" ? ".35em" : forUpward ? "-5" : "59";
            })
            .attr("text-anchor", function () {
              return "middle";
            })
            .attr("fill", "#333")
            .text(function (d) {
              return d.name.length > 24
                ? d.name.substr(12, 12) + "..."
                : d.name.substr(12, d.name.length);
            })
            .style({
              "font-size": function (d) {
                return d.name == "origin" ? 16 : 14;
              },
              cursor: "pointer",
            })
            .append("svg:title")
            .text((d) => d.name);
          // 认缴金额
          nodeEnter
            .append("text")
            .attr("x", "0")
            .attr("dy", function (d) {
              if (d.name === "origin") {
                return ".35em";
              } else {
                if (forUpward) {
                  if (d.name.length > 12) {
                    return "16";
                  } else {
                    return "6";
                  }
                } else {
                  if (d.name.length > 12) {
                    return "80";
                  } else {
                    return "70";
                  }
                }
              }
            })
            .attr("text-anchor", "middle")
            .attr("class", "linkname")
            .style("fill", "#666")
            .style("cursor", "pointer")
            .style("font-size", 12)
            .text(function (d) {
              var str =
                d.name == "origin" ? "" : "认缴金额:" + d.amount + "万人民币";
              return str.length > 18 ? str.substr(0, 18) + ".." : str;
            });
          nodeEnter
            .append("text")
            .attr("x", "10")
            .attr("dy", function (d) {
              return d.name == "origin" ? ".35em" : forUpward ? "45" : "5";
            })
            .attr("text-anchor", "start")
            .attr("class", "linkname")
            .style("fill", "#0084FF")
            .style("font-size", 10)
            .text(function (d) {
              return d.name == "origin" ? "" : d.ratio;
            });
          // 疑似实际控制人
          nodeEnter
            .append("text")
            .attr("x", "0")
            .attr("dy", function (d) {
              return d.isActualController ? -87 : -72;
            })
            .attr("text-anchor", "middle")
            .style("fill", "#fff")
            .style("font-size", 12)
            .text(function (d) {
              return d.isActualController ? "疑似实际控制人" : "";
            });
          //最终受益人:
          nodeEnter
            .append("text")
            .attr("x", "0")
            .attr("dy", function (d) {
              return d.isActualController ? -65 : -63;
            })
            .attr("text-anchor", "middle")
            .style("fill", "#fff")
            .style("font-size", 12)
            .text(function (d) {
              return d.isFHolder ? "最终受益人:" + d.holderPercent : "";
            });
          var nodeUpdate = node
            .transition()
            .duration(duration)
            .attr("transform", function (d) {
              return "translate(" + d.x + "," + d.y + ")";
            });
          nodeUpdate
            .select("circle")
            .attr("r", function (d) {
              return d.hasNode == 1 ? 10 : 0;
            })
            .attr("cy", function (d) {
              return d.name == "origin" ? -20 : forUpward ? -63 : 103;
            })
            .style("fill", function (d) {
              return d.hasNode == 1 ? "#9CD0FF" : "";
            })
            .style("stroke", function (d) {
              return d.hasNode == 1 ? "#9CD0FF" : "";
            })
            .style("stroke-width", function (d) {
              if (d.repeated) {
                return 5;
              }
            });
          //代表是否展开的+-号
          nodeEnter
            .append("svg:text")
            .attr("class", "isExpand")
            .attr("x", "0")
            .attr("dy", function (d) {
              return forUpward ? -57 : 109;
            })
            .attr("text-anchor", "middle")
            .style("fill", "#fff")
            .style("font-size", "20px")
            .style("cursor", "pointer")
            .text(function (d) {
              if (d.name == "origin") {
                return "";
              }
              return d.hasNode == 1 ? "+" : "";
            })
            .on("click", click);

          nodeUpdate.select("text").style("fill-opacity", 1);

          var nodeExit = node
            .exit()
            .transition()
            .duration(duration)
            .attr("transform", function (d) {
              return "translate(" + source.x + "," + source.y + ")";
            })
            .remove();
          nodeExit.select("circle").attr("r", 1e-6);
          nodeExit.select("text").style("fill-opacity", 1e-6);

          var link = g
            .selectAll("path." + link_class)
            .data(links, function (d) {
              return d.target.id;
            });

          link
            .enter()
            .insert("path", "g")
            .attr("class", link_class)
            .attr("stroke", function (d) {
              // return '#8b4513'
              return "#919191";
            })
            .attr("fill", "none")
            .attr("stroke-width", "1px")
            // .attr('opacity', 0.5)
            .attr("d", function (d) {
              var o = {
                x: source.x0,
                y: source.y0,
              };
              return diagonal({
                source: o,
                target: o,
              });
            })
            .attr("marker-end", function (d, i) {
              return forUpward
                ? getMarkerUpArrow(d, i)
                : getMarkerDownArrow(d, i);
            })
            .attr("id", function (d, i) {
              return "mypath" + "-" + d.source.id + "-" + d.target.id;
            });
          link.transition().duration(duration).attr("d", diagonal);
          link
            .exit()
            .transition()
            .duration(duration)
            .attr("d", function (d) {
              var o = {
                x: source.x,
                y: source.y,
              };
              return diagonal({
                source: o,
                target: o,
              });
            })
            .remove();
          nodes.forEach(function (d) {
            d.x0 = d.x;
            d.y0 = d.y;
          });
          function getMarkerUpArrow(d, i) {
            svg
              .append("defs")
              .append("marker") //箭头
              .attr("id", "resolved" + d.target.id)
              .attr("markerUnits", "strokeWidth") //设置为strokeWidth箭头会随着线的粗细发生变化
              .attr("markerUnits", "userSpaceOnUse")
              .attr("viewBox", "0 -5 10 10") //坐标系的区域
              .attr("refX", -28) //箭头坐标
              .attr("refY", 0)
              .attr("markerWidth", 12) //标识的大小
              .attr("markerHeight", 12)
              .attr("orient", "90") //绘制方向,可设定为:auto(自动确认方向)和 角度值
              .attr("stroke-width", 2) //箭头宽度
              .append("path")
              .attr("d", "M0,-5L10,0L0,5") //箭头的路径
              .attr("fill", "#919191"); //箭头颜色
            return "url(#resolved" + d.target.id + ")";
          }
          function getMarkerDownArrow(d, i) {
            svg
              .append("defs")
              .append("marker") //箭头
              .attr("id", "resolved" + d.target.id)
              .attr("markerUnits", "strokeWidth") //设置为strokeWidth箭头会随着线的粗细发生变化
              .attr("markerUnits", "userSpaceOnUse")
              .attr("viewBox", "0 -5 10 10") //坐标系的区域
              .attr("refX", 0) //箭头坐标
              .attr("refY", 0)
              .attr("markerWidth", 12) //标识的大小
              .attr("markerHeight", 12)
              .attr("orient", "90") //绘制方向,可设定为:auto(自动确认方向)和 角度值
              .attr("stroke-width", 2) //箭头宽度
              .append("path")
              .attr("d", "M0,-5L10,0L0,5") //箭头的路径
              .attr("fill", "#919191");
            return "url(#resolved" + d.target.id + ")";
          }
          function Change_modal() {
            _this.Modal = true;
          }
          function click(d) {
            event.stopPropagation();
            if (forUpward) {
            } else {
              if (d._children) {
                console.log("对外投资--ok");
              } else {
                console.log("对外投资--no");
              }
            }
            isExpand = !isExpand;
            if (d.name == "origin") {
              return;
            }
            if (d.children) {
              d._children = d.children;
              d.children = null;
              d3.select(this).text("+");
              update(d, originalData, g);
            } else {
              if (d._children && d._children.length > 0) {
                d.children = d._children;
                d._children = null;
                if (d.name == "origin") {
                  d.children.forEach(expand);
                }
                d3.select(this).text("-");
                update(d, originalData, g);
              } else {
                gqctt({
                  beijingCrid:
                    d.direction == "up" ? d.beijingCrid : d.pbeijingCrid,
                  direction: d.direction,
                }).then((res) => {
                  if (res.code === 0) {
                    if (d.direction == "up") {
                      d.children = res.result.investorList;
                      d.children.map((item) => {
                        item.amount = Number(item.subConAm).toFixed(2);
                        item.isFHolder = true;
                        item.ratio =
                          item.subComBl.length > 6
                            ? calculation
                                .accMul(item.subComBl, 100)
                                .toFixed(2) + "%"
                            : calculation.accMul(item.subComBl, 100) + "%";
                        item.name = item.entName;
                        item.type = item.bz === "企业" ? 2 : 1;
                        item.isHoldingCompany =
                          item.isHolding == 1 ? true : false;
                        item.isFHolder =
                          item.subComBl >= 0.25 && item.type == 1;
                        item.direction = direction;
                        item.holderPercent = item.ratio;
                      });
                    } else {
                      d.children = res.result.holderList;
                      d.children.map((item) => {
                        item.amount = Number(item.subConAm).toFixed(2);
                        item.isFHolder = true;
                        item.ratio =
                          item.subComBl.length > 6
                            ? calculation
                                .accMul(item.subComBl, 100)
                                .toFixed(2) + "%"
                            : calculation.accMul(item.subComBl, 100) + "%";
                        item.name = item.pentName;
                        item.type = item.bz === "企业" ? 2 : 1;
                        item.isHoldingCompany =
                          item.isHolding == 1 ? true : false;
                        item.isFHolder =
                          item.subComBl >= 0.25 && item.type == 1;
                        item.direction = direction;
                        item.holderPercent = item.ratio;
                      });
                    }
                    d._children = null;
                    if (d.name == "origin") {
                      d.children.forEach(expand);
                    }
                    d3.select(this).text("-");
                    update(d, originalData, g);
                  }
                });
              }
            }
          }
        }
        function expand(d) {
          if (d._children) {
            d.children = d._children;
            d.children.forEach(expand);
            d._children = null;
          }
        }

        function collapse(d) {
          if (d.children && d.children.length != 0) {
            d._children = d.children;
            d._children.forEach(collapse);
            d.children = null;
            hasChildNodeArr.push(d);
          }
        }

        function redraw() {
          treeG.attr(
            "transform",
            "translate(" +
              zoom.translate() +
              ")" +
              " scale(" +
              zoom.scale() +
              ")"
          );
        }

        function disableRightClick() {
          // stop zoom
          console.log(d3.event.button);
          if (d3.event.button == 2) {
            console.log("No right click allowed");
            d3.event.stopImmediatePropagation();
          }
        }

        function sortByDate(a, b) {
          var aNum = a.name.substr(a.name.lastIndexOf("(") + 1, 4);
          var bNum = b.name.substr(b.name.lastIndexOf("(") + 1, 4);
          return (
            d3.ascending(aNum, bNum) ||
            d3.ascending(a.name, b.name) ||
            d3.ascending(a.id, b.id)
          );
        }
      };

      var d3GenerationChart = new treeChart(d3);
      d3GenerationChart.drawChart();
    },
    //下载
    downloadImpByChart(chartName) {
      //得到svg的真实大小
      let box = document.querySelector("svg").getBBox(),
        x = box.x,
        y = box.y,
        width = box.width,
        height = box.height;
      //克隆svg
      var node = svg.cloneNode(true);
      //重新设置svg的width,height,viewbox
      node.setAttribute("width", width);
      node.setAttribute("height", height);
      node.setAttribute("viewBox", [x, y, width, height]);
      this.downloadSvgFn(node, width, height, this.rootName);
    },
    //下载
    downloadSvgFn(svg, width, height, rootName) {
      var serializer = new XMLSerializer();
      var source =
        '<?xml version="1.0" standalone="no"?>\r\n' +
        serializer.serializeToString(svg);
      var image = new Image();
      image.src =
        "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
      image.onload = function () {
        var canvas = document.createElement("canvas");
        canvas.width = width + 40;
        canvas.height = height + 40;
        var context = canvas.getContext("2d");
        context.rect(0, 0, width + 40, height + 40);
        context.fillStyle = "#fff";
        context.fill();
        context.drawImage(image, 20, 20);
        var url = canvas.toDataURL("image/png");
        var a = document.createElement("a");
        a.download = `${rootName}-股权架构图.png`;
        a.href = url;
        a.click();
        return;
      };
    },
    //全屏
    fullele() {
      return (
        document.fullscreenElement ||
        document.webkitFullscreenElement ||
        document.msFullscreenElement ||
        document.mozFullScreenElement ||
        null
      );
    },
    //判断是否为全屏
    checkFull() {
      return !!(document.webkitIsFullScreen || this.fullele());
    },
    //全屏-退出全屏
    FullScreen(el) {
      if (this.isFullscreen) {
        //退出全屏
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        } else if (!document.msRequestFullscreen) {
          document.msExitFullscreen();
        }
      } else {
        //进入全屏
        if (el.requestFullscreen) {
          el.requestFullscreen();
        } else if (el.mozRequestFullScreen) {
          el.mozRequestFullScreen();
        } else if (el.webkitRequestFullscreen) {
          //改变平面图在google浏览器上面的样式问题
          el.webkitRequestFullscreen();
        } else if (el.msRequestFullscreen) {
          this.isFullscreen = true;
          el.msRequestFullscreen();
        }
      }
    },
    //全屏-退出全屏
    toggleFullScreen(e) {
      this.isFullscreen = !this.isFullscreen;
      this.FullScreen(document.getElementById("borrow"));
    },
  },
};
</script>
<style lang="scss" scoped>
#borrow {
  background: #fff;
}
.functionBox:hover{
  opacity: 1;
}
.functionBox {
  opacity: 0.3;
  background: #fff;
  position: fixed;
  right: 10px;
  bottom: 150px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border: 1px solid #444;
  width: 40px;
  transition:all linear 0.2s;

  .functionItem {
    color: #444;
    border-bottom: 1px solid #444;
    height: 40px;
    width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 40px;
    text-align: center;
    cursor: pointer;
  }
  .functionItem:last-of-type {
    border-bottom: none;
  }
}
</style>>

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值