背景
前段時(shí)間接到公司需求,參考企查查開(kāi)發(fā)=>企業(yè)圖譜孤个。最開(kāi)始定的是使用Relation Graph實(shí)現(xiàn)剃允,用了一段時(shí)間后發(fā)現(xiàn)這個(gè)插件對(duì)于一些個(gè)性化的需求支持不足,無(wú)奈只能另辟新徑齐鲤,后來(lái)發(fā)現(xiàn)了d3.js這個(gè)新大陸斥废。
由于這是第一次接觸d3,剛開(kāi)始真是一臉懵,后來(lái)通過(guò)翻閱資料给郊,先是了解了一下svg牡肉,然后又把d3.js常用的一些api看了看算是有個(gè)初步的了解。
技術(shù)點(diǎn)
使用d3主要需要掌握svg淆九,jquery和d3這幾個(gè)知識(shí)點(diǎn)统锤。
本次使用的是 d3.v5版本的。
案例
實(shí)現(xiàn)效果
實(shí)現(xiàn)代碼
HTML
<template>
<div class="tree04">
<div class="seeTree-page" id="app">
<div id="treeRoot"></div>
</div>
</div>
</template>
JS
<script>
import companyJson from "./DLJSON/companyJson.json";
import $ from "./js/jquery-3.1.1.min";
import * as d3 from "./js/d3.v5";
let svg;
let dirRight;
let forUpward;
let leng;
// var u = navigator.userAgent
// app = navigator.appVersion;
// var isAndroid = u.indexOf("Android") > -1 || u.indexOf("Linux") > -1; //g
// var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
// var ua = navigator.userAgent.toLowerCase();
// var ualower = navigator.userAgent.toLocaleLowerCase();
// //var treeData =
// var width = document.body.clientWidth,
// height = document.body.clientHeight;
let toggle = true;
let circlewidth1;
let circlewidth2;
let circlewidth3;
let margin1 = { top: 50, right: 20, bottom: -20, left: 0 };
export default {
data() {
return {
container: null, //容器svg>g
duration: 500, //動(dòng)畫(huà)持續(xù)時(shí)間
scaleRange: [0.2, 2], //container縮放范圍
direction: ["r", "l"], //分為左右2個(gè)方向
centralPoint: [0, 0], //畫(huà)布中心點(diǎn)坐標(biāo)x,y
root: { r: {}, l: {} }, //左右2塊數(shù)據(jù)源
rootNodeLength: 0, //根節(jié)點(diǎn)名稱(chēng)長(zhǎng)度
rootName: ["昆侖數(shù)智", ""], //根節(jié)點(diǎn)名稱(chēng)
textSpace: 15, //多行文字間距
themeColor: "#2196F3", //主色
nodeSize: [50, 100], //節(jié)點(diǎn)間距(高/水平)
fontSize: 14, //字體大小炭庙,也是單字所占寬高
rectMinWidth: 50, //節(jié)點(diǎn)方框默認(rèn)最小饲窿,
textPadding: 5, //文字與方框間距,注:固定值5
circleR: 5, //圓圈半徑
dirRight: "",
treeData: [],
};
},
created() {},
mounted() {
this.getData();
},
computed: {
treeMap() {
return d3
.tree()
.nodeSize(this.nodeSize)
.separation((a, b) => {
let result =
a.parent === b.parent && !a.children && !b.children ? 1 : 2;
return result;
});
},
},
watch: {},
methods: {
getData() {
// var mynodes;
// $.ajax({
// url: "first.json",
// contentType: "application/json;charset=UTF-8",
// type: "POST",
// dataType: "json",
// success: function (data) {
this.rootName = [companyJson.data.rootName, ""];
let data = companyJson.data;
console.log(data, "原始數(shù)據(jù)");
let left = data.l;
let right = data.r;
let mynodes;
for (var i = 0; i < left.children.length; i++) {
if (left.children[i].children.length > 2) {
mynodes = left.children[i].children;
left.children[i].children = left.children[i].children.slice(0, 2);
left.children[i].children[2] = {
name: "更多",
type: -1,
val: mynodes.length - 2,
childrend: mynodes.slice(0, mynodes.length),
};
}
}
for (var i = 0; i < right.children.length; i++) {
if (right.children[i].children.length > 2) {
mynodes = right.children[i].children;
right.children[i].children = right.children[i].children.slice(0, 2);
right.children[i].children[2] = {
name: "更多",
type: -1,
val: mynodes.length - 2,
childrend: mynodes.slice(0, mynodes.length),
};
}
}
// console.log(data, "初始化");
this.treeInit(data);
// }
// })
},
uuid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return (
s4() +
s4() +
"-" +
s4() +
"-" +
s4() +
"-" +
s4() +
"-" +
s4() +
s4() +
s4()
);
},
//初始化
treeInit(data) {
const margin = { top: 0, right: 0, bottom: 0, left: 0 };
let treeWidth = d3.select("#treeRoot")._parents[0].clientWidth;
let treeHeight = d3.select("#treeRoot")._parents[0].clientHeight;
// const treeWidth = document.body.clientWidth - margin.left - margin.right; //tree容器寬
// const treeHeight = document.body.clientHeight - margin.top - margin.bottom; //tree容器高
const centralY = treeWidth / 2 + margin.left;
const centralX = treeHeight / 2 + margin.top;
this.centralPoint = [centralX, centralY]; //中心點(diǎn)坐標(biāo)
//根節(jié)點(diǎn)字符所占寬度
this.rootNodeLength = this.rootName[0].length * this.fontSize + 50;
//svg標(biāo)簽
svg = d3
.select("#treeRoot")
.append("svg")
.attr("class", "tree-svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("width", treeWidth)
.attr("height", treeHeight)
.attr("font-size", this.fontSize)
.attr("fill", "#555");
//g標(biāo)簽
this.container = svg
.append("g")
.attr("class", "container1")
.attr(
"transform",
"translate(" + margin1.left + "," + margin1.top + ")scale(0.8)"
);
//畫(huà)出根節(jié)點(diǎn)
this.drawRoot();
//指定縮放范圍
const zoom = d3
.zoom()
.scaleExtent(this.scaleRange)
.on("zoom", this.zoomFn);
//動(dòng)畫(huà)持續(xù)時(shí)間
this.container
.transition()
.duration(this.duration)
.call(zoom.transform, d3.zoomIdentity);
svg.call(zoom);
//數(shù)據(jù)處理
// console.log(data, "數(shù)據(jù)處理");
this.dealData(data);
},
zoomFn() {
var weizhi = document.getElementsByClassName("container1")[0];
weizhi.style.transform = ""; //偏移位置
let zoom = d3.event.transform;
return this.container.attr(
"transform",
"translate(" +
(Number(zoom.x) + Number(margin1.left)) +
"," +
(zoom.y + margin1.top) +
")scale(" +
zoom.k * 0.8 +
")"
);
},
//數(shù)據(jù)重組
DataReor(d, direction, source, appendData) {
var setDepth = function (node, num, appendLeaf) {
//重新設(shè)置depth
node.depth = num;
if (node.children && node.children.length) {
//遍歷children
node.children.forEach(function (item) {
setDepth(item, num + 1, appendLeaf);
});
} else {
appendLeaf.push(node);
}
};
var setHeight = function (arr, num) {
//重新設(shè)置height
var parent = [];
arr.forEach(function (node) {
node.height = Math.max(num, node.height);
if (node.parent && parent.indexOf(node.parent) == -1) {
parent.push(node.parent);
}
});
if (parent.length) {
setHeight(parent, num + 1);
}
};
var appendLeaf = []; //增加的葉子節(jié)點(diǎn)
if (appendData.children.length) {
d.children = [];
appendData.children.forEach(function (item, index) {
var newNode = d3.hierarchy(item);
newNode.parent = d;
newNode.height = -1;
setDepth(newNode, d.depth + 1, appendLeaf);
d.children.push(newNode);
});
}
if (appendLeaf.length) {
setHeight(appendLeaf, 0);
}
if (source.data.name == "更多") {
source.parent.descendants().forEach((d) => {
d._children = d.children;
d.id = direction + this.uuid();
});
} else {
source.descendants().forEach((d) => {
d._children = d.children;
d.id = direction + this.uuid();
});
}
this.update(d, direction);
},
getNode(d, direction, source, type) {
let mynodes;
// 注釋ly---start
// if (!d.data.isNextNode && d.data.type != -1) {
// return;
// }
// 注釋ly---end
// console.log("重組數(shù)據(jù)");
if (d.data.name == "更多") {
var num = d.data.val / 5;
if (num <= 5) {
var arr = d.data.childrend;
} else {
var arr = d.data.childrend.slice(0, d.parent.children.length + 4);
arr[d.parent.children.length + 4] = {
nodeName: "更多",
type: -1,
val: d.data.childrend.length - d.parent.children.length + 4,
childrend: d.data.childrend,
};
}
var appendData = {
children: arr,
};
this.DataReor(d.parent, direction, source, appendData);
} else if (type == 1) {
var appendData = {
children: [],
};
this.DataReor(d, direction, source, appendData);
} else {
//請(qǐng)求數(shù)據(jù)
// console.log(d.data, "請(qǐng)求數(shù)據(jù)參數(shù) update");
$("#loading,.shaow").show();
let data = [];
$("#loading,.shaow").hide();
if (data.length == 0) {
html =
'<div class="tk"><p style="font-size: 14px;color: #359ffb">' +
d.data.name +
"</p><span>暫無(wú)數(shù)據(jù)</span></div>";
$(".shaow").show();
$("body").append(html);
return;
}
mynodes = data;
if (data.length > 10) {
data = data.slice(0, 10);
data[11] = {
name: "更多",
type: -1,
val: mynodes.length - 10,
childrend: mynodes.slice(0, mynodes.length),
};
}
var appendData = {
children: data,
};
this.DataReor(d, direction, source, appendData);
}
},
//數(shù)據(jù)處理
dealData(data) {
this.direction.forEach((item) => {
this.root[item] = d3.hierarchy(data[item]);
this.root[item].x0 = this.centralPoint[0]; //根節(jié)點(diǎn)x坐標(biāo)
this.root[item].y0 = this.centralPoint[1]; //根節(jié)點(diǎn)Y坐標(biāo)
this.porData(this.root[item], item);
});
},
//遍歷
porData(obj, item) {
obj.descendants().forEach((d) => {
d._children = d.children;
d.id = item + this.uuid();
});
this.update(obj, item);
},
//畫(huà)根節(jié)點(diǎn)
drawRoot() {
const title = this.container
.append("g")
.attr("id", "rootTitle")
.attr(
"transform",
`translate(${this.centralPoint[1]},${this.centralPoint[0]})`
);
title
.append("svg:rect")
.attr("class", "rootTitle")
.attr("y", 0)
.attr("x", -this.rootNodeLength / 2)
.attr("width", this.rootNodeLength)
.attr("height", 0)
.attr("rx", 5) //圓角
.style("fill", this.themeColor);
this.rootName.forEach((name, index) => {
title
.append("text")
.attr("fill", "white")
.attr("y", function () {
return 5;
})
.attr("text-anchor", "middle")
.style("font-size", function () {
if (index == 1) {
return "10px";
} else {
return "15px";
}
})
.text(name);
let lineHeight = (index + 2) * this.textSpace;
d3.select("#rootTitle rect")
.attr("height", lineHeight)
.attr("y", -lineHeight / 2);
});
},
seat(newArr, dirRight, data) {
for (var j = 0; j < newArr.length; j++) {
if (j != 0) {
for (var i = 0; i < data[j].length; i++) {
data[j][i].y = data[j - 1][0].y + newArr[j - 1] - 40;
}
}
}
},
testLength(data, dirRight) {
var level = [],
width1,
width2;
for (var i = 0; i < data.length; i++) {
var newArr = new Array();
for (var j = 0; j < data[i].length; j++) {
if (data[i][j].data.attName) {
svg
.append("text")
.style("font-size", this.fontSize)
.text((d) => "(" + data[i][j].data.attName + ")")
.attr("class", "test")
.attr("width", function (d) {
width3 = d3.select(this.getComputedTextLength())._groups[0][0];
console.log(width3,"width3");
});
}
if (data[i][j].data.ratio) {
svg
.append("text")
.style("font-size", this.fontSize)
.text(function (d) {
const len = data[i][j].data.name.length;
if (len > 20) {
return data[i][j].data.name.substring(0, 20) + "...";
} else {
return data[i][j].data.name;
}
})
.attr("class", "test")
.attr("width", function (d) {
width1 = d3.select(this.getComputedTextLength())._groups[0][0];
});
svg
.append("text")
.style("font-size", this.fontSize)
.text((d) => data[i][j].data.ratio)
.attr("class", "test")
.attr("width", function (d) {
width2 = d3.select(this.getComputedTextLength())._groups[0][0];
});
$(".test").remove();
if (data[i][j].data.attName) {
if (Number(width1) + Number(width3) > Number(width2)) {
newArr.push(Number(width1) + Number(width3) + 100);
} else {
newArr.push(Number(width2) + 100);
}
} else {
if (Number(width1) > Number(width2)) {
newArr.push(Number(width1) + 100);
} else {
newArr.push(Number(width2) + 100);
}
}
} else {
svg
.append("text")
.style("font-size", this.fontSize)
.text(function (d) {
if (data[i][j].data.name) {
const len = data[i][j].data.name.length;
if (len > 20) {
return data[i][j].data.name.substring(0, 20) + "...";
} else {
return data[i][j].data.name;
}
}
})
.attr("class", "test")
.attr("width", function (d) {
width1 = d3.select(this.getComputedTextLength())._groups[0];
newArr.push(Number(width1) + 100);
data.width1 = d3.select(
this.getComputedTextLength()
)._groups[0];
});
$(".test").remove();
}
}
level.push(Math.max.apply(null, newArr));
}
this.seat(level, dirRight, data);
},
//開(kāi)始繪圖
update(source, direction) {
// console.log(source, direction, "update");
let that = this;
dirRight = direction === "r" ? 1 : -1; //方向?yàn)橛?左
forUpward = direction == "r";
let className = `${direction}gNode`;
let tree = this.treeMap(this.root[direction]);
let nodes = tree.descendants();
let links = tree.links();
var data = [];
if (nodes.length > 1) {
for (var i = 0; i < nodes.length; i++) {
if (!data[nodes[i].depth]) {
var arr = [];
arr.push(nodes[i]);
data[nodes[i].depth] = arr;
} else {
data[nodes[i].depth].push(nodes[i]);
}
}
//檢測(cè)最大長(zhǎng)度
this.testLength(data, dirRight);
}
nodes.forEach((d) => {
d.y = dirRight * (d.y + this.rootNodeLength / 2) + this.centralPoint[1];
d.x = d.x + this.centralPoint[0];
});
//根據(jù)class名稱(chēng)獲取左或者右的g節(jié)點(diǎn),達(dá)到分塊更新
const node = this.container
.selectAll(`g.${className}`)
.data(nodes, (d) => d.id);
//新增節(jié)點(diǎn)焕蹄,tree會(huì)根據(jù)數(shù)據(jù)內(nèi)的children擴(kuò)展相關(guān)節(jié)點(diǎn)
const nodeEnter = node
.enter()
.append("g")
.attr("id", (d) => `g${d.id}`)
.attr("class", className)
.attr("transform", (d) => `translate(${source.y0},${source.x0})`)
.attr("fill-opacity", 0)
.attr("stroke-opacity", 0)
.on("click", function (d) {
d3.select(this)
.selectAll(".node-circle .node-circle-vertical")
.transition()
.duration(that.duration)
.attr("stroke-width", function (d) {
if (d.children) {
return 1;
} else {
return 0;
}
});
if (d.data.name == "更多") {
return that.clickNode(d, direction, source);
} else if (d.depth !== 0) {
return that.clickNode(d, direction, source);
}
});
nodeEnter.each((d) => {
if (d.depth > 0) {
this.drawText(`g${d.id}`, dirRight);
if (d.data.attName) {
this.drawCodeText(`g${d.id}`, dirRight);
}
if (d.data.ratio) {
this.drawTsText(`g${d.id}`, dirRight);
}
this.drawRect(`g${d.id}`, dirRight);
this.marker(`g${d.id}`, dirRight);
}
if (d.depth > 0) {
const width = Math.min(d.data.name.length * 14, this.rectMinWidth);
let right = dirRight > 0;
let xDistance = right ? width : -width;
this.drawCircle(`g${d.id}`, dirRight, source, direction);
this.drawSign(`g${d.id}`, dirRight); //畫(huà)標(biāo)記
}
//畫(huà)節(jié)點(diǎn)數(shù)量
// console.log(d, "畫(huà)節(jié)點(diǎn)數(shù)量");
if (d.data && d.data.type == -1) {
this.drawLength(`g${d.id}`, dirRight);
}
});
// 更新節(jié)點(diǎn):節(jié)點(diǎn)enter和exit時(shí)都會(huì)觸發(fā)tree更新
const nodeUpdate = node
.merge(nodeEnter)
.transition()
.duration(this.duration)
.attr("transform", function (d) {
if (d.data && d.data.isNextNode) {
d3.select(this)
.selectAll(".node-circle .node-circle-vertical")
.transition()
.duration(this.duration)
.attr("stroke-width", function (d) {
if (d.children) {
return 0;
} else {
return 1;
}
});
}
var index = 0;
return "translate(" + d.y + "," + d.x + ")";
})
.attr("fill-opacity", 1)
.attr("stroke-opacity", 1);
// 移除節(jié)點(diǎn):tree移除掉數(shù)據(jù)內(nèi)不包含的節(jié)點(diǎn)(即逾雄,children = false)
const nodeExit = node
.exit()
.transition()
.duration(this.duration)
.remove()
.attr("transform", (d) => `translate(${source.y},${source.x})`)
.attr("fill-opacity", 0)
.attr("stroke-opacity", 0);
// Update the links 根據(jù) className來(lái)實(shí)現(xiàn)分塊更新
const link = this.container
.selectAll(`path.${className}`)
.data(links, (d) => d.target.id);
// Enter any new links at the parent's previous position.
//insert是在g標(biāo)簽前面插入,防止連接線擋住G節(jié)點(diǎn)內(nèi)容
const linkEnter = link
.enter()
.insert("path", "g")
.attr("class", className)
.attr("d", (d) => {
const o = { x: source.x0, y: source.y0 };
return this.diagonal({ source: o, target: o });
})
.attr("fill", "none")
.attr("stroke-width", 0.5)
.attr("stroke", "#D8D8D8");
// Transition links to their new position.
link
.merge(linkEnter)
.transition()
.duration(this.duration)
.attr("d", this.diagonal);
// Transition exiting nodes to the parent's new position.
link
.exit()
.transition()
.duration(this.duration)
.remove()
.attr("d", (d) => {
const o = { x: source.x, y: source.y };
return this.diagonal({ source: o, target: o });
});
// Stash the old positions for transition.
this.root[direction].eachBefore((d) => {
d.x0 = d.x;
d.y0 = d.y;
});
},
//畫(huà)連接線
diagonal({ source, target }) {
let s = source,
d = target;
if (forUpward) {
return (
"M" +
s.y +
"," +
s.x +
"L" +
(s.y + (d.y - s.y) - 20) +
"," +
s.x +
"L" +
(s.y + (d.y - s.y) - 20) +
"," +
d.x +
"L" +
d.y +
"," +
d.x
);
} else {
return (
"M" +
s.y +
"," +
s.x +
"L" +
(s.y + (d.y - s.y) + 20) +
"," +
s.x +
"L" +
(s.y + (d.y - s.y) + 20) +
"," +
d.x +
"L" +
d.y +
"," +
d.x
);
}
},
//畫(huà)箭頭
marker(id, dirRight) {
let gMark = d3
.select(`#${id}`)
.append("g")
.attr(
"transform",
dirRight > 0 ? "translate(-20,0)" : "translate(12,0)"
);
return gMark
.insert("path", "text")
.attr("d", function (d) {
if (d.data.nodeType == 0 && dirRight > 0) {
return "M0,0L0,3L9,0L0,-3Z";
} else if (d.data.nodeType == 0 && dirRight < 0) {
return "M0,0L9,-3L9,3Z";
}
})
.style("fill", (d) => this.getRectStorke(d.data.name));
},
//華標(biāo)記
drawSign(id, dirRight) {
return d3
.select(`#${id}`)
.insert("circle", "text")
.attr("cx", dirRight > 0 ? -5 : 5)
.attr("y", -2.5)
.attr("r", function (d) {
if (d.data.nodeType == 0) {
return 4;
}
})
.style("fill", (d) => this.getRectStorke(d.data.name));
},
//畫(huà)文本
drawText(id, dirRight) {
let that = this;
dirRight = dirRight > 0; //右為1腻脏,左為-1
return d3
.select(`#${id}`)
.append("text")
.attr("y", function (d) {
if (d.data.ratio) {
return that.textPadding - 8;
} else {
return that.textPadding;
}
})
.attr("x", (d) => (dirRight ? that.textPadding : -that.textPadding))
.attr("text-anchor", dirRight ? "start" : "end")
.style("font-size", that.fontSize)
.text(function (d) {
const len = d.data.name.length;
if (len > 20) {
return d.data.name.substring(0, 20) + "...";
} else {
return d.data.name;
}
})
.attr("fill", function (d) {
if (d.data.nodeType == -1) {
return "rgb(33, 150, 243)";
} else if (d.data.nodeType == 0 || d.data.attName) {
return "#000";
} else {
return "#333";
}
})
.attr("width", function (d) {
circlewidth1 = d3.select(this.getComputedTextLength())._groups[0][0];
return d3.select(this.getComputedTextLength())._groups[0][0];
});
},
//畫(huà)子文本
drawTsText(id, dirRight) {
let that = this;
return d3
.select(`#${id} text`)
.append("tspan")
.attr("fill", (d) => (d.data.attName ? "#fff" : "#999"))
.attr("y", function (d) {
if (d.data.ratio) {
return that.textPadding + 8;
}
})
.attr("x", function (d) {
if (dirRight > 0) {
return that.textPadding;
} else {
return -5;
}
})
.style("font-size", "11px")
.text(function (d) {
return d.data.ratio;
})
.attr("width", function (d) {
circlewidth2 = d3.select(this.getComputedTextLength())._groups[0][0];
return d3.select(this.getComputedTextLength())._groups[0][0];
});
},
//畫(huà)股票代碼
drawCodeText(id, dirRight) {
return d3
.select(`#${id} text`)
.append("tspan")
.attr("fill", (d) => "#fff")
.attr("y", function (d) {
if (d.data.ratio) {
return this.textPadding + 8;
}
})
.style("font-size", "11px")
.attr("x", function (d) {
if (dirRight > 0) {
return this.textPadding;
} else {
return -5;
}
})
.text(function (d) {
return d.data.attName + " ";
})
.attr("width", function (d) {
circlewidth3 = d3.select(this.getComputedTextLength())._groups[0][0];
return d3.select(this.getComputedTextLength())._groups[0][0];
});
},
//節(jié)點(diǎn)數(shù)量
drawLength(id) {
return d3
.select(`#${id} text`)
.append("tspan")
.attr("fill", (d) => "#999")
.text(function (d) {
if (d.data.type == -1) {
return " (" + d.data.val + ")";
}
return " [" + d.data.ratio + "]";
})
.attr("fill", "rgb(33, 150, 243)")
.attr("width", function (d) {
return d3.select(this.getComputedTextLength())._groups[0];
});
},
//畫(huà)方框陰影
drawFilter(id) {
return d3
.select(`#${id}`)
.insert("defs", "rect")
.append("filter")
.attr("id", `f${id}`)
.attr("x", 0)
.attr("y", 0)
.append("feGaussianBlur")
.attr("in", "SourceGraphic")
.attr("stdDeviation", "5");
},
//畫(huà)方框
drawRect(id, dirRight) {
let that = this;
let realw = document.getElementById(id).getBBox().width + 25; //獲取g實(shí)際寬度后鸦泳,設(shè)置rect寬度
if (document.getElementById(id).getBBox().width > 400) {
realw = 400;
}
return d3
.select(`#${id}`)
.insert("rect", "text")
.attr("x", function (d) {
if (dirRight < 0) {
return -realw;
} else {
0;
}
})
.attr("y", function (d) {
if (d.data.ratio) {
return -that.textSpace + that.textPadding - 11;
} else {
return -that.textSpace + that.textPadding - 4;
}
})
.attr("width", function (d) {
// if (d.data.isNextNode) {//判斷是否有下級(jí)節(jié)點(diǎn)
// return realw
// } else {
// return realw - 15
// }
return realw;
})
.attr("height", function (d) {
if (d.data.ratio) {
return that.textSpace + that.textPadding + 22;
} else {
return that.textSpace + that.textPadding + 8;
}
})
.attr("stroke-width", (d) =>
d.data.nodeType == 0 || d.data.type == -1 || d.data.attName ? 0 : 0.5
)
.attr("rx", 2) //圓角
.style("stroke", (d) =>
d.data.nodeType == -1 ? "" : that.getRectStorke(d.parent.data.name)
)
.style("fill", function (d) {
if (d.data.nodeType == -1) {
return "rgb(241, 241, 241)";
} else if (d.data.nodeType == 0) {
return that.getRectStorke(d.data.name);
} else if (d.data.attName) {
return "rgb(33, 150, 243)";
} else {
return "#fff";
}
});
},
//畫(huà)circle
drawCircle(id, dirRight, source, direction) {
let gMark = d3
.select(`#${id}`)
.append("g")
.attr("class", "node-circle")
.attr("stroke", "rgb(153, 153, 153)")
.attr("transform", function (d) {
if (d.data.ratio) {
if (circlewidth1 > circlewidth2) {
leng = Number(circlewidth1) + 15;
} else {
leng = Number(circlewidth2) + 15;
}
//leng = Number(circlewidth1) + Number(circlewidth2) + 25;
if (leng > 390) {
leng = 390;
}
if (dirRight == 1) {
return "translate(" + leng + ",0)";
} else {
return "translate(" + -leng + ",0)";
}
} else {
leng = Number(circlewidth1) + 15;
if (dirRight == 1) {
return "translate(" + leng + ",0)";
} else {
return "translate(" + -leng + ",0)";
}
}
})
// .attr('stroke-width', d => d.data.isNextNode ? 1 : 0); 判斷是否有下級(jí)節(jié)點(diǎn)
.attr("stroke-width", (d) => (d.data.type == "-1" ? 0 : 1));
gMark
.append("circle")
.attr("fill", "none")
.attr("r", function (d) {
if (d.data.type == "-1") {
return 0;
}
return 5;
}) //根節(jié)點(diǎn)不設(shè)置圓圈
.attr("fill", "#ffffff");
let padding = this.circleR - 2;
gMark.append("path").attr("d", `m -${padding} 0 l ${2 * padding} 0`); //橫線
gMark
.append("path") //豎線,根據(jù)展開(kāi)/收縮動(dòng)態(tài)控制顯示
.attr("d", `m 0 -${padding} l 0 ${2 * padding}`)
.attr("stroke-width", function (d) {
if (d.data.type == "-1") {
return 0;
}
return 1;
})
.attr("class", "node-circle-vertical");
return gMark;
},
//點(diǎn)擊某個(gè)節(jié)點(diǎn)
// clickNode(d, direction, source) {
// if (d.children) {
// d._children = d.children;
// d.children = null;
// this.getNode(d, direction, source, 1);
// } else {
// d.children = d._children;
// d._children = [];
// this.getNode(d, direction, source); //原注
// }
// if (d.data.name == "更多") {
// this.getNode(d, direction, source);
// return;
// }
// this.update(d, direction); //原注
// },
expand(d, direction, source) {
if (d.data.name == "更多") {
this.getNode(d, direction, source);
return;
}
if (d._children) {
d.children = d._children;
d._children = null;
this.update(d, direction);
}
},
collapse(d, direction, obj) {
if (d.children) {
d._children = d.children;
d.children = null;
console.log(d._children, "_children");
}
if (obj == 1) {
this.update(d, direction);
}
},
//點(diǎn)擊某個(gè)節(jié)點(diǎn)ly
clickNode(d, direction, source) {
if (d.children || d.children) {
this.collapse(d, direction, 1);
} else {
this.expand(d, direction, source);
}
},
getTsTextColor(name) {
switch (name) {
case "股東":
return "darkgray";
case "供應(yīng)商":
return "#FF9800";
case "合伙人":
return "green";
default:
return "black";
}
},
//末 節(jié)點(diǎn) 邊框顏色
getRectStorke(name) {
switch (name) {
case "分支機(jī)構(gòu)":
return "rgb(255, 234, 218)";
case "對(duì)外投資":
return "rgb(215, 236, 255)";
case "股東":
return "rgb(211, 234, 241)";
case "高管":
return "rgb(237, 227, 244)";
default:
return "rgb(133, 165, 255)";
}
},
isNull(val) {
return val ? val : "";
},
},
};
</script>
style
.tree04 {
background: #fff;
touch-action: none;
padding: 0;
margin: 0;
height: 100%;
max-width: 100%;
overflow: hidden;
font-family: "PingFangSC-Regular", "PingFangSC-Light", "PingFang SC",
sans-serif, "Microsoft YaHei";
}
總結(jié)
本次開(kāi)發(fā)使得對(duì)于d3有一個(gè)進(jìn)一步的了解永品,雖然主要復(fù)雜的功能是參考別人的做鹰,但是通過(guò)此次使用過(guò)后對(duì)于一些細(xì)枝末節(jié)的地方還是可以持續(xù)更新優(yōu)化!
寫(xiě)這個(gè)文檔主要是為了記錄一下過(guò)程鼎姐,并且日后也方便查看钾麸。
持續(xù)更新更振。。喂走。