LoginSignup
10
11

More than 5 years have passed since last update.

D3.jsを使ってみる

Last updated at Posted at 2015-04-04

概要

Force Layoutを使いたいがためだけに使い方を覚える。
D3とはData Driven Docuement。
データを視覚化するライブラリ。

サンプル

Hello D3.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <p>Hello 1</p>
    <p>Hello 2</p>
    <p>Hello 3</p>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        d3.select('body').selectAll('p').text('hello from d3!');
    </script>
</body>
</html>

要素の取得、テキスト/スタイルの変更

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <p>Hello 1</p>
    <p>Hello 2</p>
    <p>Hello 3</p>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var p = d3.select('body').selectAll('p')
        p.text('hello from d3!');
        p.style('font-size', '28px');

        p.text('hello from d3!')
            .style('font-size', '28px')
            .style('font-weight', 'bold');

        p.text('hello from d3!')
            .style({
                'font-size': '28px',
                'font-weight': 'bold'
            });

        // alert(p.style('font-size'));

        p.style('font-size', function() {
            return Math.floor(Math.random() * 32) + 'px';
        });
    </script>
</body>
</html>

要素の削除

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <p>Hello 1</p>
    <p>Hello 2</p>
    <p>Hello 3</p>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var obj = d3.select('body').append('p').text('hello 4');
        obj.remove();
    </script>
</body>
</html>

dataを使ってみる

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <p>Hello 1</p>
    <p>Hello 2</p>
    <p>Hello 3</p>
    <span></span>
    <span></span>
    <span></span>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36];
        var p = d3.select('body').selectAll('p');
        p.data(dataset).text(function(d) {
            return d;
        });
        p.data(dataset).text(function(d, index) {
            return index + "番目は" + d;
        });

        var dataset2 = [{name: 'aki', age: 1},{name: 'mii', age: 2},{name: 'akiton', age: 3}];
        var span = d3.select('body').selectAll('span');
        span.data(dataset2).text(function(d, index) {
            return d.name + '(' + d.age + ')';
        });
    </script>
</body>
</html>

update, enter, exit

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <p>Hello 1</p>
    <p>Hello 2</p>
    <p>Hello 3</p>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48];
        var p = d3.select('body').selectAll('p');

        var update = p.data(dataset);
        var enter = update.enter();
        var exit = update.exit();

        update.text(function(d, index) {
            return "update: " + d;
        });
        enter.append('p').text(function(d, index) {
            return "enter: " + d;
        });
        exit.style('color', 'red').remove();
    </script>
</body>
</html>

データから図形を描画する

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48, 33];
        var w = 640;
        var h = 480;

        var svg = d3.select('body').append('svg').attr({
            width: w,
            height: h
        });

        svg.selectAll('circle')
            .data(dataset)
            .enter()
            .append('circle')
            .attr({
                cx: function(d, i) { return 50 + (i * 100); },
                cy: h / 2,
                r: function(d) { return d; },
                fill: 'red'
            });
    </script>
</body>
</html>

図形描画時にアニメーションさせてみる

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48, 33];
        var w = 640;
        var h = 480;

        var svg = d3.select('body').append('svg').attr({
            width: w,
            height: h
        });

        svg.selectAll('circle')
            .data(dataset)
            .enter()
            .append('circle')
            .attr({
                cx: function(d, i) { return 50 + (i * 100); },
                cy: h / 2,
                r: 0,
                fill: 'red'
            })
            .transition()
            .delay(function(d, i) {
                return 300 * i;
            })
            .duration(1000)
            .ease('bounce')
            .attr({
                r: function(d) { return d; }
            });
    </script>
</body>
</html>

eachを使ってアニメーションを制御してみる

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48, 33];
        var w = 640;
        var h = 480;

        var svg = d3.select('body').append('svg').attr({
            width: w,
            height: h
        });

        svg.selectAll('circle')
            .data(dataset)
            .enter()
            .append('circle')
            .transition()
            .delay(function(d, i) {
                return 300 * i;
            })
            .duration(1000)
            .ease('bounce')
            .each('start', function() {
                d3.select(this).attr({
                    fill: 'green',
                    r: 0,
                    cy: h
                });
            })
            .attr({
                cx: function(d, i) { return 50 + (i * 100); },
                cy: h / 2,
                r: function(d) { return d; },
                fill: 'red'
            })
            .each('end', function() {
                d3.select(this)
                    .transition()
                    .duration(800)
                    .attr({
                        fill: 'pink',
                        cy: 0,
                        r: 0
                    });
            });
    </script>
</body>
</html>

イベントを取得する

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48, 33];
        var w = 640;
        var h = 480;

        var svg = d3.select('body').append('svg').attr({
            width: w,
            height: h
        });

        svg.selectAll('circle')
            .data(dataset)
            .enter()
            .append('circle')
            .on('mouseover', function(d) {
                d3.select(this).attr('fill', 'orange');
            })
            .on('mouseout', function(d) {
                d3.select(this).attr('fill', 'red');
            })
            .on('mousedown', function(d) {
                var rs = d3.select(this).attr('r');
                alert(d + ':' + rs);
            })
            .attr({
                cx: function(d, i) { return 50 + (i * 100); },
                cy: h / 2,
                r: function(d) { return d; },
                fill: 'red'
            })
    </script>
</body>
</html>

棒グラフを書く

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Test</title>
    <style>
        .axis path, .axis line {
            fill: none;
            stroke: black;
        }
        .axis text {
            font-size: 11px;
        }
    </style>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var dataset = [12, 24, 36, 48, 33];
        var w = 640;
        var h = 480;
        var padding = 20;

        var xScale = d3.scale.linear()
            .domain([0, d3.max(dataset)])
            .range([padding, w - padding])
            .nice();

        var svg = d3.select('body').append('svg').attr({
            width: w,
            height: h
        });

        var xAxis = d3.svg.axis()
            .scale(xScale)
            .orient('bottom');

        svg.append('g')
            .attr({
                class: 'axis',
                transform: 'translate(0, 180)'
            })
            .call(xAxis);

        svg.selectAll('rect')
            .data(dataset)
            .enter()
            .append('rect')
            .attr({
                x: padding,
                y: function(d, i) { return i * 25; },
                width: function(d) { return xScale(d) - padding; },
                height: 20,
                fill: 'red'
            });
    </script>
</body>
</html>

後からノード追加して動かしたり

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3.js Force Layout</title>
</head>
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script>
        var width = 640;
        var height = 480;

        var svg = d3.select('body').append('svg').attr({
            width: width,
            height: height
        });

        var data = {
            nodes: [
                { name: 'aki' },
                { name: 'mii' },
                { name: 'akiton' }
            ],
            links: [
                { source: 0, target: 2 },
                { source: 1, target: 2 }
            ]
        };

        var force = d3.layout.force()
            .nodes(data.nodes)
            .links(data.links)
            .size([width, height])
            .gravity(0.1)
            .charge([-100])
            .friction(0.95)
            .linkDistance([100])
            .linkStrength(1);

        // レイアウト計算開始
        force.start();
        for (var i = 0; i < 10000; i++) {
            force.tick();
        }
        force.stop();

        // lineを生成
        var line = svg.selectAll('line')
            .data(data.links)
            .enter()
            .append('line')
            .attr({
                'stroke': 'black',
                'x1': function(d, i) { return d.source.x; },
                'y1': function(d, i) { return d.source.y; },
                'x2': function(d, i) { return d.target.x; },
                'y2': function(d, i) { return d.target.y; }
            })
            .style({
            });

        var circle = svg.selectAll('circle')
            .data(data.nodes)
            .enter()
            .append('circle')
            .attr({
                'r': 8,
                'fill': 'black',
                'cx': function(d, i) { return d.x; },
                'cy': function(d, i) { return d.y; }
            })
            .style({
            });
            // .call(force.drag);

        var moveTarget = null;
        circle
            .on('mousedown', function(d, i) {
                console.log(d.name + '(' + d.x + ',' + d.y + ')');
                moveTarget = d;
            })
            .on('mouseup', function(d, i) {
                moveTarget = null;
            });

        svg.on('mousemove', function(e) {
            if (moveTarget != null) {
                var mousePos = d3.mouse(this);
                console.log('moveTarget = ' + moveTarget.name + ' (' + mousePos[0] + ',' + mousePos[1] + ')');
                moveTarget.x = mousePos[0];
                moveTarget.y = mousePos[1];

                d3.selectAll('line')
                    .attr({
                        'x1': function(d) { return d.source.x; },
                        'y1': function(d) { return d.source.y; },
                        'x2': function(d) { return d.target.x; },
                        'y2': function(d) { return d.target.y; }
                    });
                d3.selectAll('circle')
                    .attr({
                        'cx': function(d) { return d.x; },
                        'cy': function(d) { return d.y; }
                    });
            }
        });

        svg.on('mousedown', function() {
            if (moveTarget != null) return;
            var newCircle = svg.append('circle');
            var mousePos = d3.mouse(this);
            var newData = {
                name: 'super',
                age: 10,
                x: mousePos[0],
                y: mousePos[1]
            };
            data.nodes.push(newData);
            console.log('add circle: ' + newData.x + ',' + newData.y);
            newCircle
                .datum(newData)
                .attr({
                    'cx': function(d, i) { console.log(d);return d.x; },
                    'cy': function(d, i) { return d.y; },
                    'r': 10,
                    'fill': 'red'
                })
                .on('mousedown', function(d) {
                    moveTarget = d;
                })
                .on('mouseup', function(d) {
                    moveTarget = null;
                });
        });

        function randomMove() {
            for (var i = 0; i < data.nodes.length; i++) {
                var d = data.nodes[i];
                d.x += Math.random() * 2 <= 1 ? Math.random()*10 : -Math.random()*10;
                d.y += Math.random() * 2 <= 1 ? Math.random()*10 : -Math.random()*10;

                d3.selectAll('line')
                    .attr({
                        'x1': function(d) { return d.source.x; },
                        'y1': function(d) { return d.source.y; },
                        'x2': function(d) { return d.target.x; },
                        'y2': function(d) { return d.target.y; }
                    });
                d3.selectAll('circle')
                    .attr({
                        'cx': function(d) { return d.x; },
                        'cy': function(d) { return d.y; }
                    });
            }
        }
    </script>
    <input type="button" value="randomMove" onClick="randomMove()"/>
</body>
</html>

参考

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11