}
然后开始编写JavaScript代码:
横向树状图:
var width = 700,
height = 700;
var cluster = d3.layout.cluster()
.size([width, height - 200]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,0)");
d3.json("d3.json", function(error, root) {
var nodes = cluster.nodes(root);
var links = cluster.links(nodes);
console.log(nodes);
console.log(links);
var link = svg.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dx", function(d) { return d.children ? -8 : 8; })
.attr("dy", 3)
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.name; });
圆形树状图(这个需要用到投影,稍微麻烦一点,不详细解释了):
//图像区域大小
var R = 600;
//定义一个Tree对象,定义旋转角度和最大半径
var tree = d3.layout.tree()
.size([360,R/2-120])
.separation(function(a,b) { return a.parent == b.parent ? 1 : 2;});
//定义布局方向
var diagonal = d3.svg.diagonal()
.projection(function(d) {
var r = d.y, a = (d.x-90) / 180 * Math.PI;
return [r * Math.cos(a), r * Math.sin(a)];
//新建画布,移动到圆心位置
var svg = d3.select("#showTree").append("svg")
.attr("width", R)
.attr("height", R)
.append("g")
.attr("transform", function(d){ return "translate("+R/2+"," + R/2 + ")";});
//根据JSON数据生成树
d3.json("d3.json", function(error, data) {
//根据数据生成nodes集合
var nodes = tree.nodes(data);
//获取node集合的关系集合
var links = tree.links(nodes);
//为关系集合设置贝塞尔曲线连接
var link=svg.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d",diagonal);
//根据node集合生成节点
var node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform",function(d){return "rotate(" + (d.x-90) + ")translate(" + d.y + ")"; });
//为节点添加圆形标记,如果有子节点为红色,否则绿色
node.append("circle")
.attr("fill",function(d){return d.children==null?"#0F0":"#F00";})
.attr("r", 5);
//为节点添加说明文字
node.append("text")
.attr("dy", ".4em")
.text(function(d){return d.name;})
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; });
D3的d3.json(url,callback)方法可以读取json文件,然后构造树状图。
如果不想把数据写入json文件,直接在后台构造好json数据结构然后传到前台要怎么弄?
其实d3.json(url,callback)方法的url是发起一个get请求,返回一个json字符串,然后进入callback进行处理,本质上跟ajax差不多
所以当我们不想读取文件时,修改一下d3.json(url,callback)的url参数,发起一个get请求到控制器,然后你在控制器里面构造相应的json数据结构,然后返回过来就可以了
但是这里的url不能直接带中文参数,比如:
url = "json.html?word=关键词";
这样的请求发到后台,后台接收的是这样的一段乱码字符串:
å
³é®è¯
那有人说先将这个中文做一次编码,然后在传到后台不就行了?
确实,我们一般在js里面如果要传中文参数到后台都会先进行编码然后再传的,所以我当时也是这么想的,心想这下应该不会出问题了吧,然并卵,后台接收然后解码得到的依然是那串乱码,然后没办法,我只能进d3.js的文件去查看源码,奈何才疏学浅,压根看不懂,也没找到它哪里对这个url做了什么编码或解码操作。后来想到以前见到过在前台进行多次编码然后再传到后台的,我也尝试了一下在js里面进行了两次编码,然后再传到后台,到后台接收然后解码一次,发现能够得到正确的中文参数
第一行是后台接收的参数,第二行是对参数解码一次得到的结果。
问题是解决了,但是我还是不知道这是为什么,只注意到d3.json这个方法里面发送的是get请求,后来查资料还有问其他人才知道在浏览器地址栏里,浏览器认为%是个转义字符,浏览器会把%与%之间的编码,两位两位取出后进行解码,然后再传递给处理页面,然后由处理页面进行再次解码,而get请求的中文参数就是显示在浏览器地址栏,所以在js里面参数只进行一次编码的话,参数经过浏览器的解码,传到后台的就是没编码的中文,这个当然就会变成乱码,所以在js里面对中文做两次编码然后通过get请求传到后台,后台只需做一次解码就能得到正确的中文参数