如何使用d3js画分帧画一棵树

来源:互联网 发布:注会考试网络培训哪好 编辑:程序博客网 时间:2024/06/06 08:00

最近用d3js写了一个把树可视化的工具,但是遇到一个问题,当树的结点非常多的时候,加载整棵树会卡一段时间,体验不是很好,所以想是不是能用分帧加载的方法,不要一次加载整棵树,而是隔一段时间加载一部分。
这是老套路了,本来觉得应该挺简单的,但是网上查了半天也找到符合需求的文章,又去查API,发现也没有可用的。期间也发现了一个看起来可以用的,先贴一下链接:http://jsfiddle.net/cyril123/sef9udod/ 。但是当我用过才发现,这是个花架子,中看不中用,它的缺点是每次都要重新生成数据,数据量小的时候当然怎样都好,但是对于我当前要解决的问题并没有什么帮助。
看了一下源码,没看懂……有些关键代码不知道隐藏到什么地方去了,而且我只是想做个工具,不想研究太深。没办法,只能看看有没有什么黑科技了,一搬生成树的数据的时候,会有这样一个代码:

var tree = d3.layout.tree().size([width - 50,height - 50])                .separation(function(a,b){ return (a.parent == b.parent ? 1 : 2); });var diagonal = d3.svg.diagonal()                .projection(function(d){return [d.x, d.y]});var svg = d3.select('#display').append('svg')                .attr('width',width)                .attr('height', height)                .append('g')                .attr('transform', 'translate(0,10)');var nodes = tree.nodes(target);var node = svg.selectAll('.node')            .data(nodes)            .enter()            .append('g')            .attr('class','node')            .attr('transform', function(d) {return 'translate(' + d.x + ',' + d.y + ')';})

其实我的目的呢,就是分步去执行代码中append(‘g’)以及后面一系列操作,但是这个操作d3js是不支持的,所以我把执行到enter()的结果打印出来,发现这是一个数组+一些其他额外的属性,之前尝试把数组中的数拆开,未果,最后想了个招,把这个数组中的每个元素,也就是每个结点都拿出来,用形成一堆数组,只不过这些数组中只有一个元素罢了,这样我虽然不知道这个源码怎么实现,但是我只要每次去调对应的函数就好了,因为我把这些属性都copy下来,形成一个新的对象了。也得亏是js这种原型模式,其他语言不一定会出现什么奇怪的bug……

最后贴一下代码:

var NODE_NUM = 10000;var MAX_CHILD = 50;var updateTimeout = null;var Node = function() {    this.index = 0;    this.parent = {};    this.children = [];    this.history = "";}//随机生成一棵树function generalRandomTreeObject(total_number, max_child, idx) {    var tree = {name:idx + 1};    if (total_number == 1) {        return tree;    }    tree.children = [];    total_number -= 1;    idx += 1;    var child_number = Math.floor(Math.random()*max_child + 1);    child_number = Math.min(child_number, total_number);    var child_counts = new Array(child_number);    for (var i = 0;i < child_number; ++i) {        child_counts[i] = Math.floor(Math.random()*total_number + 1);    }    child_counts.sort();    var selected_number = 0;    for (var i = 0;i < child_number; i++) {        var now_number = child_counts[i] - selected_number;        now_number = Math.max(now_number, 1);        if (total_number - now_number < child_number - i - 1) {            now_number = total_number - (child_number - i - 1);        }        if (i == child_number - 1) {            now_number = total_number;        }        var child = generalRandomTreeObject(now_number, max_child, idx);        tree.children.push(child);        total_number -= now_number;        selected_number += now_number;        idx += now_number;    }    return tree;}function drawTree(target, width, height, flag) {    clearTimeout(self.updateTimeout);    var ds = $('#display');    $('#display')[0].innerHTML = "";    console.log(ds);    if (flag) {        return;    }    var tree = d3.layout.tree().size([width - 50,height - 50])                .separation(function(a,b){ return (a.parent == b.parent ? 1 : 2); });    var diagonal = d3.svg.diagonal()                .projection(function(d){return [d.x, d.y]});    var svg = d3.select('#display').append('svg')                .attr('width',width)                .attr('height', height)                .append('g')                .attr('transform', 'translate(0,10)');    var nodes = tree.nodes(target);    var links = tree.links(nodes);    ////---------------复制引用分帧加载---------------------    var node = svg.selectAll('.node')                    .data(nodes).enter();    var link = svg.selectAll('.link')                    .data(links)                    .enter();    var nodeSpliter = [];    var linkSpliter = [];    var addNodeOnceTime = 500;    var addLinkOnceTime = 600;    function autoOpenTree(pos,nodeAddCount, linkAddCount) {        if(linkAddCount < link[0].length) {            var ob1 = [];            ob1.__proto__ = link.__proto__;            for (var i = 0;i < addLinkOnceTime && linkAddCount < link[0].length; ++i) {                var ob2 = [];                ob2.__proto__ = link[0].__proto__;                ob2.parentNode = link[0].parentNode;                ob2.update = link[0].update;                ob2.push(link[0][linkAddCount]);                ob1.push(ob2);                linkAddCount += 1;            }            linkSpliter.push(ob1);            linkSpliter[pos].append('path')                .attr('class','link')                .attr('d', diagonal);        }        if (nodeAddCount < node[0].length) {            var ob1 = [];            ob1.__proto__ = node.__proto__;            for (var i = 0;i < addNodeOnceTime && nodeAddCount < node[0].length; ++i) {                var ob2 = [];                ob2.__proto__ = node[0].__proto__;                ob2.parentNode = node[0].parentNode;                ob2.update = node[0].update;                ob2.push(node[0][nodeAddCount]);                ob1.push(ob2);                nodeAddCount += 1;            }            nodeSpliter.push(ob1);            var p = nodeSpliter[pos].append('g')                    .attr('class','node')                    .attr('transform', function(d) {                        return 'translate(' + d.x + ',' + d.y + ')';});            p.append('circle')                .attr('r',4.5)                .attr('stroke','steelblue')                .attr('stroke-width','1.5px');            p.append("text")              .attr("dx", function(d) { return d.children ? 14 : 0; })              .attr("dy", 16)              .style("text-anchor", function(d) { return d.children ? "end" : "start"; })              .text(function(d) { return d.name; });        }        if(linkAddCount < link[0].length || nodeAddCount < node[0].length) {            self.updateTimeout=setTimeout(function(){                autoOpenTree(pos + 1,nodeAddCount, linkAddCount);            }, 30);        }    }    autoOpenTree(0,0, 0);    //--------正常画树方法------------------    // 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.x + ',' + d.y + ')';})    // node.append('circle').attr('r',4.5);    // node.append("text")    //   .attr("dx", function(d) { return d.children ? 14 : 0; })    //   .attr("dy", 16)    //   .style("text-anchor", function(d) { return d.children ? "end" : "start"; })    //   .text(function(d) { return d.name; });}function test() {    var source_tree = generalRandomTreeObject(NODE_NUM,MAX_CHILD,0);    $(document).ready(function(){        drawTree(source_tree, 1000, 600);        $('#btn_random').click(function(){            source_tree = generalRandomTreeObject(NODE_NUM,MAX_CHILD, 0);            drawTree(source_tree, 1000, 600);        });    });}test();

html代码也贴一下好了:

<!Doctype html><html xmlns:svg="http://www.w3.org/2000/svg">    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        <meta property="qc:admins" content="465267610762567726375" />        <meta name="viewport" content="width=device-width, initial-scale=1.0" />          <title>tree view</title>    </head>    <div>        <button type='button' id='btn_random' style='width:100px;height: 33px'>draw new tree</button>        <!-- <button type='button' id='btn_next' style='width:100px;height: 33px'>next</button> -->    </div>    <div name='all' id='display'>    </div>    <style>        .node circle {          fill: #fff;          stroke: steelblue;          stroke-width: 1.5px;        }        .node {          font: 12px sans-serif;        }        .link {          fill: none;          stroke: #ccc;          stroke-width: 1.5px;        }    </style>    <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" type="text/javascript"></script>    <script type="text/javascript" src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>    <script type="text/javascript" src="framing_load_tree.js"></script></html>
0 0