含有 窗口缩放时自适应自动缩放
//如果动态请求数据并更新,可以先粗暴的吧整个SVG节点以及内部节点全部移除掉,然后在重新绘制
//如果不移除掉,直接更新数据调用update,无效果,数据无法更新
// remove svg节点
d3.select('svg').remove(); //删除整个SVG
d3.select('#spread')
.selectAll('*')
.remove(); //清空SVG中的内容
// recharts (重)绘图 ——(如果绘制完毕后,无需切换数据,则不需要上面的remove节点步骤)
var width = 380,
height = 280,//设置绘制范围的宽高
root;//定义数据,如果用vue,可以直接用this.XXX(数据传入,无需定义)
var force = d3.layout.force()
.size([width, height])
.on("tick", tick);
var svg = d3.select("#spread").append("svg")
// 如果需要窗口缩放时,自动缩放,绘制SVG时候代码改为如下:
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("viewBox", "0 0 380 280");//从左到右依次为:x坐标点起始位置,y坐标点起始位置,视图宽度,视图高度
//而不是常规的设置宽高:
// .attr("width", width)
// .attr("height", height);
//添加svg下面的线,字,圆点等节点
var link = svg.selectAll(".link"),
node = svg.selectAll(".node"),
text = svg.selectAll(".text")
root = this.obj//因为我是vue项目,所以root赋值为axios取到的this.obj数据
update();//更新视图,绘制节点
function radius() {
return 1;
};
//注意注意注意!!!!各位童鞋请注意!!!我要扔炸弹了!!!
//在原生或者jq类的开发项目中,函数中不用var声明变量,直接使用 node=124,为定义全局变量
//但在vue项目中,不在外部声明变量,直接在update函数中node=124,绘制不出图,也没报错。(可能有的童鞋会报错undefined???)
//找了好久问题,发现是需要再函数外部声明一下变量,好坑啊……
//所以加了下面var nodes, links这行代码
var nodes, links;
function update() {
nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// links.forEach(item => {
// item.value = 100
// })
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.charge(-390)//斥力,负值越大,斥力越大。正值为吸力,向一起聚
.linkDistance(12)//线的距离长度
.start();
// Update the links… 向节点添加数据
link = link.data(links, function (d) {
return d.target.id;
});
// Exit any old links.
link.exit().remove();
// Enter any new links.
link.enter().insert("line", ".node")
.attr("class", "link")
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
})
.style('stroke-width', 1)//连接线的宽度(粗细)
.style('stroke', '#ffffff80');//线的颜色
// Update the nodes…
node = node.data(nodes, function (d) {
return d.id;
}).style("fill", color);//圆点的颜色(我的带边框,如果不设置边框颜色,2860*1920的时候边框会很明显,不知道大家是不是都是这样默认带边框的)
text = node.data(nodes, function (d) {
return d.id;
});
// Exit any old nodes.
node.exit().remove();
// Enter any new nodes.
node.enter().append("circle")
.attr("class", "node")
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
})
.attr("r", function (d) {
return Math.sqrt(d.size) || 10;
})
.style("fill", color)//圆点颜色
.style('stroke', color)//圆点边框颜色
// Exit any old nodes.
text.exit().remove();
text.enter().append("text")
.style("text-anchor", "middle")//字体居中显示
.style('fill', '#FFFFFF')//字体颜色
.attr('dy', '.35em')//字体垂直居中显示
.attr("font-size", 10)//字体大小
.text(function (d) {
return d.name;
});
}
function tick() {
nodes.forEach(function (d) {
//x轴 超过宽度380,回弹到380坐标轴区域位置。 ——作用为:超出范围的回弹到视图宽度范围内
if (d.x >= 380) {
d.x = 380
}
//y轴 超过高度280,回弹到280坐标轴区域位置。 ——作用为:超出范围的回弹到视图高度范围内
if (d.y >= 280) {
d.y = 280
}
if (d.x <= 20) {
d.x = 20
}
if (d.y <= 20) {
d.y = 20
}
})
link.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
text.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
});
}
//#49d8ff 为二级节点颜色 , #287dab为三级节点颜色
function color(d) {
return d._children ? "#ffffff" : d.children ? "#49d8ff" : "#287dab";
}
// Toggle children on click.
function click(d) {
if (!d3.event.defaultPrevented) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [],
i = 0;
function recurse(node) {
if (node.children) node.children.forEach(recurse);
if (!node.id) node.id = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}