block by shimizu 089aaa943225b5838e4c415f2998a8f6

D3 v4 - Responsive Chart Example

Full Screen

D3 ver.4でレスポンシブなチャートを描画するサンプル。

Open」のリンクをクリックしてwindowサイズを変更して試してみてください。

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>D3 v4 - Responsive Chart Example</title>
<style>
html,body,#graph {
    width: 100%;
    height: 100%;
}

.valueLine{
    fill:none;
    stroke:blue;
}

.tick line {
    stroke-dasharray: 2 2 ;
    stroke: #ccc;
}

</style>
</head>

<body>
<div id="graph"></div>    
    
    
    
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script>    
<script>
!(function(){
    "use strict"
    
    var width,height
    var chartWidth, chartHeight
    var margin
    var svg = d3.select("#graph").append("svg")
    var axisLayer = svg.append("g").classed("axisLayer", true)
    var chartLayer = svg.append("g").classed("chartLayer", true)
    
    var xScale = d3.scaleTime()
    var yScale = d3.scaleLinear()
    
    
    d3.csv("data.csv", cast,  main)
    
    
    //データの方変換
    function cast(d) {
        d.date = new Date(d.date) //dateオブジェクトに変換
        d.value = +d.value
        return d 
    }
    
    //初期処理
    function main(data) {
        update(data)
        setReSizeEvent(data)
    }
    
    
    //チャートを再描画する
    function update(data) {
        setSize(data)
        drawAxis()
        drawChart(data)        
    }

    //リサイズ時のレスポンシブ処理
    function setReSizeEvent(data) {
        var resizeTimer;
        var interval = Math.floor(1000 / 60 * 10);
         
        window.addEventListener('resize', function (event) {
            
            //リサイズ中に何回もupdate関数が呼ばれてしまうのを防ぐために
            //タイマーの設置・削除を繰り返して、リサイズが終わるまで、update関数が実行されないようにしている。
            if (resizeTimer !== false) {
                clearTimeout(resizeTimer);
            }
            resizeTimer = setTimeout(function () {
                update(data)
            }, interval);
        });
    }
    
    
    //各種サイズを取得し、チャートのサイズを決定する
    function setSize(data) {
        //親要素のサイズを取得
        width = document.querySelector("#graph").clientWidth
        height = document.querySelector("#graph").clientHeight
    
        //チャート描画レイヤーのマージン
        margin = {top:40, left:60, bottom:40, right:60 }
        
        //axisエリアを除いたチャート(line)を描画する範囲を設定する
        chartWidth = width - (margin.left+margin.right)
        chartHeight = height - (margin.top+margin.bottom)
        
        //svgにおや要素のサイズを適用
        svg.attr("width", width).attr("height", height)
        //axis用のレイヤーはsvgと同等に設定している
        axisLayer.attr("width", width).attr("height", height)
        
        //チャート描画エリアのサイズを適用
        chartLayer
            .attr("width", chartWidth)
            .attr("height", chartHeight)
            .attr("transform", "translate("+[margin.left, margin.top]+")")
            
        //スケールのレンジをチャートサイズに合うように設定
        xScale.domain([new Date("2016/1/1"), new Date("2016/4/1")]).range([0, chartWidth])
        yScale.domain([500, d3.max(data, function(d){ return d.value})]).range([chartHeight, 0])
            
    }
    
    //チャートを描画
    function drawChart(data) {
        var t = d3.transition()
            .duration(1000)
            .ease(d3.easeLinear)
            .on("start", function(d){ console.log("transiton start") })
            .on("end", function(d){ console.log("transiton end") })
        
        
        var lineGen = d3.line()
            .x(function(d) { return xScale(d.date) })
            .y(function(d) { return yScale(d.value) })
            .curve(d3.curveStep)
           
        var selectedLineElm = chartLayer.selectAll(".valueLine")
            .data([data])
        
        var newLineElm = selectedLineElm.enter().append("path")
            .attr("class", "valueLine")

        selectedLineElm.merge(newLineElm)
            .attr("d", lineGen)
        
    }
    
    function drawAxis(){
        /* axisエレメントにダミーのデータを束縛することで、
         * エレメントが無い場合(初回)はエレメントを追加し、アトリビュートを更新する
         * すでにsvg上にaxisのエレメントが存在する場合はアトリビュートの更新のみが行われる
         */

        var yAxis = d3.axisLeft(yScale)
            .tickSizeInner(-chartWidth)
        
        var selectedYAxisElm = axisLayer.selectAll(".y")
            .data(["dummy"])
            
        var newYAxisElm = selectedYAxisElm.enter().append("g")
            .attr("class", "axis y")
            
        selectedYAxisElm.merge(newYAxisElm)
            .attr("transform", "translate("+[margin.left, margin.top]+")")
            .call(yAxis);
            
        var xAxis = d3.axisBottom(xScale)
    
        var selectedXAxisElm = axisLayer.selectAll(".x")
            .data(["dummy"])
            
        var newXAxisElm = selectedXAxisElm.enter().append("g")
            .attr("class", "axis x")
    
        selectedXAxisElm.merge(newXAxisElm)
            .attr("transform", "translate("+[margin.left, chartHeight+margin.top]+")")
            .call(xAxis);
        
    }
}());
</script>    
</body>
</html>

data.csv

date,value
2016/1/1, 1000
2016/1/15, 1300
2016/1/31, 1700
2016/2/1, 2000
2016/2/2, 1800
2016/2/3, 2100
2016/3/1, 1900
2016/3/10, 1600
2016/3/20, 2100
2016/3/30, 2000