效果图:
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>>