D3js(三):force實例

Data-Driven Documents理解

首先它是js,js本質就是dom(Document Object Model,簡稱DOM)的增刪查改,dom的本質就是一棵樹,d3本質也是對一棵樹進行操作。

selections

對dom操作,最開始就是定位,也就是選擇哪一塊,哪一顆子樹

d3.selectAll("p").style("color", "blue");

selections操作

// Update…
var p = d3.select("body")
  .selectAll("p")
  .data([4, 8, 15, 16, 23, 42])
    .text(function(d) { return d; });

// Enter…
p.enter().append("p")
    .text(function(d) { return d; });

// Exit…
p.exit().remove();

直接上碼:

導入庫,這裏使用d3.v3,d3.v5可能有差異:

<script src="http://d3js.org/d3.v3.min.js"></script>

建立畫布,並把畫布svg添加到html的body或者div裏

    var width = 960,
        height = 960

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);

建立力矩圖

    var force = d3.layout.force()
        .gravity(.05)
        .charge(-240)
        .linkDistance(160)
        .size([width, height]);

讀取json數據

    d3.json("graph.json", function(error, json) {

        if (error) throw error;
        }

把數據放進force裏,force就可以直接使用自己的數據了

        force.nodes(json.nodes)
            .links(json.links)
            .start();

依次把邊添加到svg

selectAll(".link")相當於佔位符,添加"line"標籤,設置該line標籤的屬性

        var link = svg.selectAll(".link")
            .data(json.links)
            .enter().append("line")
            .attr("class", "link")
            .attr("stroke-width", function(d) { return Math.sqrt(d.value); });

依次把節點添加到svg

節點包括node和text兩部分,使用group包起來,先添加g標籤再添加circle和text標籤

        var node = svg.selectAll(".node")
            .data(json.nodes)
            .enter().append('g')
            .attr("class", "node")
            .style("fill","red")
            .on("mouseover", mouseover)
            .on("mouseout", mouseout)
            .call(force.drag);

        node.append("circle")
            .attr("r", 8);
        
        node.append("text")
            .attr("dy", ".35em")
            .text(function(d) { return d.name; });

定義事件 mouseover, mouseout

mouseover, mouseout爲基本事件
transition變換過渡效果

        function mouseover() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 80);
        }

        function mouseout() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 8);
        }

定義事件 tick

實際就是補充div的屬性


        force.on("tick", tick);
        function tick() {
            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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        };

拖拽固定

相當於重寫了drag函數

        var node_drag = d3.behavior.drag()
            .on("dragstart", dragstart)
            .on("drag", dragmove)
            .on("dragend", dragend);

        var node = svg.selectAll(".node")
            .data(json.nodes)
            .enter().append('g')
            .attr("class", "node")
            .style("fill","red")
            .on("mouseover", mouseover)
            .on("mouseout", mouseout)
            //.call(force.drag);
            .call(node_drag);
        function dragstart(d, i) {
            force.stop() // stops the force auto positioning before you start dragging
        }

        function dragmove(d, i) {
            d.px += d3.event.dx;
            d.py += d3.event.dy;
            d.x += d3.event.dx;
            d.y += d3.event.dy;
            tick(); // this is the key to make it work together with updating both px,py,x,y on d !
        }

        function dragend(d, i) {
            d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
            tick();
            force.resume();
        }

zoom

        var zoom = d3.behavior.zoom()
            .scaleExtent([1, 10])
            .on("zoom", zoomed);

        var svg = d3.select("body").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
            .call(zoom);

        //specify what to do when zoom event listener is triggered
        function zoomed() {
            g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
        }

完整code:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    .link {
        stroke: #777;
        stroke-opacity: 0.5;
    }

</style>
<body>

<script src="http://d3js.org/d3.v3.min.js"></script>
<script>



    d3.json("graph.json", function(error, json) {

        if (error) throw error;

        var margin = {top: -5, right: -5, bottom: -5, left: -5},
            width = 960 - margin.left - margin.right,
            height = 960 - margin.top - margin.bottom;

        var zoom = d3.behavior.zoom()
            .scaleExtent([1, 10])
            .on("zoom", zoomed);

        var svg = d3.select("body").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
            .call(zoom);

        var force = d3.layout.force()
            .gravity(.05)
            .charge(-240)
            .linkDistance(160)
            .size([width, height]);


        force.nodes(json.nodes)
            .links(json.links)
            .start();

        var g = svg.append("g")
            .attr("class", "everything");

        var link = g.append("g")
            .attr("class", "links")
            .selectAll(".link")
            .data(json.links)
            .enter().append("line")
            .attr("class", "link")
            .attr("stroke-width", function(d) { return Math.sqrt(d.value); });

        // var node_drag = d3.behavior.drag()
        //     .on("dragstart", dragstart)
        //     .on("drag", dragmove)
        //     .on("dragend", dragend);

        var node = g.append("g")
            .attr("class", "nodes")
            .selectAll(".node")
            .data(json.nodes)
            .enter().append('g')
            .attr("class", "node")
            .style("fill","red")
            .on("mouseover", mouseover)
            .on("mouseout", mouseout)
            .call(force.drag);
            //.call(node_drag);

        node.append("circle")
            .attr("r", 8);

        node.append("text")
            .attr("dy", ".35em")
            .text(function(d) { return d.name; });


        force.on("tick", tick);

        function tick() {
            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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        };


        function mouseover() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 80);
        }

        function mouseout() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 8);
        }


        // function dragstart(d, i) {
        //     force.stop() // stops the force auto positioning before you start dragging
        // }
        //
        // function dragmove(d, i) {
        //     d.px += d3.event.dx;
        //     d.py += d3.event.dy;
        //     d.x += d3.event.dx;
        //     d.y += d3.event.dy;
        //     tick(); // this is the key to make it work together with updating both px,py,x,y on d !
        // }
        //
        // function dragend(d, i) {
        //     d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
        //     tick();
        //     force.resume();
        // }

        //specify what to do when zoom event listener is triggered
        function zoomed() {
            g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
        }


    });


</script>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章