本文實例 demo http://www.jq22.com/jquery-info21370
d3中文版 https://d3js.org.cn
官方API https://github.com/d3/d3/blob/master/API.md
官方API v3 https://github.com/d3/d3-3.x-api-reference/blob/master/API-Reference.md
官方示例: https://github.com/d3/d3/wiki/Gallery
可搜索示例:https://blockbuilder.org/search?d3version=v4&text=tree
w3cschool 字典 https://www.w3cschool.cn/dict/
d3 v4 https://www.w3cschool.cn/doc_d3_4/dict
d3 v3 https://www.w3cschool.cn/doc_d3_3/dict
使用D3和FileReader在線生成樹形圖 https://blog.csdn.net/u014291497/article/details/70991125
d3.v3 和 d3.v4 的變換 中英文版
https://github.com/d3/d3/blob/master/CHANGES.md#hierarchies-d3-hierarchy
https://github.com/xswei/d3js_doc/blob/master/API_Reference/CHANGES.md
本人d3 只製作了tree樹狀圖,別的不太瞭解,調接口的沒有總結,下面這個 demo 是原生的,3.x
d3 需要英語好,纔好入門。
echarts 中有樹狀圖 可以先參考一下。
https://echarts.baidu.com/examples/editor.html?c=tree-basic
這邊有一個別人的在線demo https://codepen.io/zhulinpinyu/pen/EaZrmM/?editors=0010
雙向樹狀圖 線是直線
http://bl.ocks.org/jdarling/2503502
d3.js 中文版 3.x 轉自別人的翻譯
http://blog.mn886.net/chenjianhua/show/773c07b3abce/index.html
D3.js拖放,Zoomable,平移,可摺疊樹與自動調整大小。在線demo
http://bl.ocks.org/robschmuecker/7880033
收藏轉自: 有重複,以供參考
https://www.cnblogs.com/wanyong-wy/p/7603123.html
https://www.cnblogs.com/quyixuanblog/p/5754129.html
https://blog.csdn.net/songqiang2011/article/details/86521194
https://blog.csdn.net/lzhlzz/article/details/38561737
https://www.jianshu.com/p/909a241acfdd
https://www.jianshu.com/p/6ef01845854f
https://blog.csdn.net/loveljy_19901114/article/details/81530222
http://www.cleey.com/blog/single/id/705.html
https://www.cnblogs.com/shihuc/p/6150526.html
https://godbasin.github.io/2018/03/10/d3-tree-notes-8-add-path-click/
http://d3.godbasin.com/8-add-path-click/index.html
域名過期 // http://www.ourd3js.com/wordpress/865/#more-865
snap.svg 轉自張鑫旭 可以參考一下
https://www.zhangxinxu.com/GitHub/demo-Snap.svg/demo/basic/Snap.hsl.php
設置線
function line_1 (d) { // 直線
// 需要兩個參數,分別是一個點的x軸和y軸座標,L命令將會在當前位置和新位置(L前面畫筆所在的點)之間畫一條線段。
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
return `M ${x0},${y0} L ${x1},${y1}`;
}
function line_2 (d) { // 弧線
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
let dx = x1 - x0,
dy = y1 - y0,
dr = Math.sqrt(dx * dx + dy * dy);
return `M ${x0},${y0} A ${dr},${dr},0,0,1 ${x1},${y1}`;
}
function line_3 (d) { // 垂直對角線
// 三次貝塞爾曲線需要定義一個點和兩個控制點,所以用C命令創建三次貝塞爾曲線,
// 需要設置三組座標參數:C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy),
// 最後一個座標(x,y)表示的是曲線的終點,另外兩個座標是控制點,(x1,y1)是起點的控制點,(x2,y2)是終點的控制點。
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
let r = y1 - y0;
return `M ${x0},${y0} C ${x0},${y0 + r / 2} ${x1},${y0 + r / 2} ${x1},${y1}`;
}
function line_4 (d) { // 水平對角線
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
let r = x1 - x0;
return `M ${x0},${y0} C ${x0 + r / 2},${y0} ${x0 + r / 2},${y1} ${x1},${y1}`;
}
function line_5 (d) { // 水平折線
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
let dx = x1 - x0,
dy = y1 - y0;
return `M ${x0},${y0} H ${dx / 2}, V ${dy} H ${x1}`;
}
function line_6 (d) { // 垂直折線
let x0 = d.source.x,
y0 = d.source.y,
x1 = d.target.x,
y1 = d.target.y;
let dx = x1 - x0,
dy = y1 - y0;
return `M ${x0},${y0} V ${dy / 2}, H ${dx} V ${x1}`;
}
function line_7 () { // 徑向對角線是基於垂直對角線製作
let arc0 = 0, r0 = 0,
arc1 = 45 * Math.PI / 180, r1 = 100;
let x0 = r0 * Math.cos(arc0),
y0 = r0 * Math.sin(arc0),
x1 = r1 * Math.cos(arc1),
y1 = r1 * Math.sin(arc1);
return line_3({
"source": { "x": x0, "y": y0 },
"target": { "x": x1, "y": y1 }
})
}
<!DOCTYPE html>
<!--suppress ALL -->
<html>
<head>
<meta charset="utf-8">
<title>3</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
body, html {
width: 100%;
height: 100%;
margin: 0;
box-sizing: border-box;
overflow: hidden;
}
.node {
cursor: pointer;
}
.node circle {
fill: none;
stroke: #fff;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.tree {
height: 100%;
margin: 0 auto;
background: #E0E0E0;
box-sizing: border-box;
}
.tree svg {
width: 100%;
height: 100%;
}
.chartTooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
box-sizing: border-box;
background-color: white;
border-radius: 5px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
}
.chartTooltip.hidden {
display: none;
}
.chartTooltip p {
margin: 0;
font-size: 14px;
line-height: 20px;
word-wrap: break-word;
}
</style>
</head>
<body>
<div class="chartTooltip hidden">
<p>
<strong class="name"></strong>
</p>
</div>
<div class="tree" id="tree">
</div>
<script type="text/javascript">
//位置參數
tree();
function tree(){
var width = document.getElementById("tree").offsetWidth;
var height = document.getElementById("tree").offsetHeight;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree().size([height, width])
// tree.nodeSize([50,0]) // 子節點之間的距離
var diagonal = d3.svg.diagonal() .projection(function (d) { return [d.y, d.x]; });
var zoom = d3.behavior.zoom().scaleExtent([0.1, 100]).on("zoom", zoomed);//添加放大縮小事件
var svg = d3.select("body").select("#tree").append("svg")
.call(zoom)//給svg綁定zoom事件
.append("g")
.attr("transform", "translate(150, 0)")
zoom.translate([150,0])
function zoomed() {
svg.attr("transform",
"translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")"
);
}
d3.json("tree2.json", function (error, flare) {
// 根節點和位置
root = flare;
root.x0 = height / 2;
root.y0 = 0;
//(1) 摺疊函數,遞歸調用,有子孫的就把children(顯示)給_children(不顯示)暫存,便於摺疊,
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
// 摺疊根節點的每個孩子
root.children.forEach(collapse);
// console.log(root) // 打印一箇中國
// 摺疊之後要重繪
update(root);
//(2) 更新佈局
function update(source) {
// console.log(source)// 獲取到中國 children 8個
// (2-1) 計算新樹的佈局
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// (2-2) 樹的深度這裏樹d.y。樹的寬度最大720,要分四層,所以每層就乘180
nodes.forEach(function (d) {
d.y = d.depth * 180;// 樹的x,y倒置了,所以這裏Y其實是橫向的
// console.log(d ); // 獲取到 展示的所有 中國浙江等
});
// (2-3) 數據連接,根據id綁定數據
var node = svg.selectAll("g.node")
.data(nodes, function (d) {
return d.id //最初新點開的節點都沒有id
|| (d.id = ++i); //爲沒有id的節點添加上ID
});
var div = d3.select('.chartTooltip').style("opacity", 0)
var timer = null;
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.style("cursor","pointer")
.attr("transform", function (d) {
return "translate(" + source.y0 + "," + source.x0 + ")"
})
.on("mouseover", d => {
if(timer) clearTimeout(timer)
d3.select('.chartTooltip').transition().duration(300).style('opacity', 1).style('display', 'block')
// 從d3.event獲取鼠標的位置
var transform = d3.event;
var yPosition = transform.offsetY + 20;
var xPosition = transform.offsetX + 20;
// 將浮層位置設置爲鼠標位置
var chartTooltip = d3
.select(".chartTooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px");
// 更新浮層內容
chartTooltip.select(".name").text(d.name);
// 移除浮層hidden樣式,展示浮層
chartTooltip.classed("hidden", false);
})
// 添加mouseover事件
.on("mouseout", () => {
// 添加浮層hidden樣式,隱藏浮層
timer = setTimeout(function(){
d3.select('.chartTooltip').style('opacity', 0).style('display', 'none')
// d3.select('.chartTooltip').style('opacity', 0)
},400);
})
.on("click", function(d) {
click(d)
});
d3.select('.chartTooltip').on('mouseover', function() {
if(timer) clearTimeout(timer)
d3.select('.chartTooltip').transition().duration(300).style('opacity', 1).style('display', 'block')
}).on('mouseout', function() {
timer = setTimeout(function(){
d3.select('.chartTooltip').style('opacity', 0).style('display', 'none')
},400);
})
// 原點
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function (d) {
return d._children ? "#f00" : "#fff";
});
//文字 1
nodeEnter.append("text")
.attr("x", function (d) {
return d.children || d._children ? 50 : 30;
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.children || d._children ? "end" : "start";
})
.text(function (d) {
return d.name;
})
.style("fill-opacity", 1)
.style("font-size", "12px");
//文字 1
nodeEnter.append("text")
.attr("x", function (d) {
return d.children || d._children ? 20 : 0;
})
.attr("y", function (d) {
return d.children || d._children ? 25 : 20;
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.children || d._children ? "end" : "start";
})
.text(function (d) {
return d.name
})
.style("fill-opacity", 1)
.style("font-size", "12px");
// (2-5) 原有節點更新到新位置
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", 4.5)
.attr("r", function (d) {
return d._children ? "5" : "5";
})
.style("fill", function (d) {
return d._children ? "#f00" : "#f90";
});
nodeUpdate.select("text")
.style("fill-opacity", 1);
// (2-6) 摺疊節點的子節點收縮回來
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1);
// (2-7) 數據連接,根據目標節點的id綁定數據
var link = svg.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// (2-8) 增加新連接
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function (d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// (2-9) 原有連接更新位置
link.transition()
.duration(duration)
.attr("d", diagonal);
// (2-10) 摺疊的鏈接,收縮到源節點處
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;
});
}
// (3) 切換摺疊與否
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);// 重新渲染
}
});
}
</script>
</body>
</html>
{
"name":"中國",
"children":
[
{
"name":"廣西" ,
"children":
[
{
"name":"桂林"
},
{"name":"南寧"},
{"name":"柳州"},
{"name":"防城港"},
{
"name":"浙江"
}
]
},
{
"name":"浙江4" ,
"children":
[
{"name":"杭州",
"children":[
{"name":"寧波",
"children":[
{"name":"寧波",
"children":[
{"name":"溫州",
"children":[
{"name":"溫州",
"children":[
{"name":"溫州",
"children":[
{"name":"寧波"
},
{"name":"溫州" },
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"溫州"},
{"name":"紹興"}
]
},
{"name":"溫州" }
]
},
{"name":"寧波" },
{"name":"溫州" },
{"name":"紹興" }
]
},
{
"name":"浙江5" ,
"children":
[
{"name":"杭州",
"children":[
{"name":"寧波",
"children":[
{"name":"寧波",
"children":[
{"name":"溫州",
"children":[
{"name":"溫州",
"children":[
{"name":"溫州",
"children":[
{"name":"寧波"
},
{"name":"溫州"},
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"紹興"}
]
},
{"name":"溫州"},
{"name":"紹興"}
]
},
{"name":"溫州" }
]
},
{"name":"寧波"},
{"name":"溫州" },
{"name":"紹興" }
]
},
{
"name":"新疆6" ,
"children":
[
{"name":"烏魯木齊"},
{"name":"克拉瑪依"},
{"name":"吐魯番"},
{"name":"哈密"}
]
}
]
}