block by shimizu 9af05d01ce753f9098f0b93ff961a3d6

D3 Axis Tips#1 - Responsive

Full Screen

Axis Tips #1

軸(Axis)をレスポンシブ対応にする。

青枠はドラッグしてサイズを変更することができます。

index.html

<!DOCTYPE html>
<html lang="jp">
<head>
<style>
html, body {
    margin: 0px;
    padding: 0px;
    width:100%;
    height:100%;
}
    
#chart {
    width: 80%;
    height: 80%;
    border: 8px dashed gray;
  	border-left: none;
    border-top:none;
    cursor:all-scroll;
}
#chart svg{
    width: 99%;
    height: 99%;
    cursor: default;
}

.grid .tick line {
    stroke-dasharray:1;
}
    
</style>

<script src="//unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script>    
</head>
<body>
<div id="chart">
    <svg></svg>
</div>



<script type="text/babel">
const data = d3.range(30).map(d => { return {date:new Date(~~(Math.random()*17 + 2000), 12, 1), value:~~(Math.random()*100) } }) ;
const svg = d3.select("#chart").select("svg");
const grid = svg.append("g").classed("grid", true)
const plot = svg.append("g").classed("plot", true)
const axis = svg.append("g").classed("axis", true);
const yScale = d3.scaleLinear().domain([100, 0]);
const xScale = d3.scaleTime().domain([new Date(2000,1,1), new Date(2017,12,1)])


render();

function render(){
    const w = svg.node().clientWidth || svg.node().parentNode.clientWidth;
    const h = svg.node().clientHeight || svg.node().parentNode.clientHeight;
    
    const breakpoint = 480; //表示内容を変える閾値
    
    const m = (w < breakpoint) ? //横幅がブレークポイント以下の時は、マージンを小さくする
        {top:10, left:30, right:15, bottom:20}:
        {top:40, left:40, right:40, bottom:40};
        
    const r = (w < breakpoint) ? 4: 6; //ブレークポイント以下の場合はドットの半径を変更する

    //ブレークポイント以下の場合はticksの数を調整する
    const yTicks = (w < breakpoint) ? 5 : 11; 
    const xTicks = (w < breakpoint) ? 3 : 9; 
    
    const pw = w - (m.left + m.right);
    const ph = h - (m.top + m.bottom);


    
    yScale.range([0, ph]);
    xScale.range([0, pw]);
        
    //axis layer
    axis.attr("transform", `translate(${m.left}, ${m.top})`);
    
    //y axis    
    const yAxisUpdate = axis.selectAll(".yAxis").data([null]);
    const yAxisEnter = yAxisUpdate.enter().append("g").classed("yAxis", true);
    
    yAxisUpdate.merge(yAxisEnter).call( d3.axisLeft().scale(yScale).ticks(yTicks) );
    
    //x axis
    const xAxisUpdate = axis.selectAll(".xAxis").data([null]);
    const xAxisEnter = xAxisUpdate.enter().append("g").classed("xAxis", true);
    
    xAxisUpdate.merge(xAxisEnter).call( d3.axisBottom().scale(xScale).ticks(xTicks) )
        .attr("transform", `translate(0, ${ph})`);
        
        
    //grid layer   
    grid.attr("transform", `translate(${m.left}, ${m.top})`);
    
    //y grid
    const yGridUpdate = grid.selectAll(".yGrid").data([null]);
    const yGridEnter = yGridUpdate.enter().append("g").classed("yGrid", true);
    
    yGridUpdate.merge(yGridEnter).call( d3.axisLeft().scale(yScale).tickSizeInner(-pw).tickFormat( ()=> null) )
    
    
    //x grid    
    const xGridUpdate = grid.selectAll(".xGrid").data([null]);
    const xGridEnter = xGridUpdate.enter().append("g").classed("xGrid", true);
    
    xGridUpdate.merge(xGridEnter).call( d3.axisBottom().scale(xScale).tickSizeInner(-ph).tickFormat( ()=> null) )
        .attr("transform", `translate(0, ${ph})`);
        

    //plot layer 
    plot.attr("transform", `translate(${m.left}, ${m.top})`);
    
    //dot
    const dotsUpdate = plot.selectAll(".dot").data(data);
    const dotsEnter = dotsUpdate.enter().append("circle").classed("dot", true);
    
    const dots = dotsUpdate.merge(dotsEnter)
        .attr("r", r)
        .attr("cx", d => xScale(d.date) )
        .attr("cy", d => yScale(d.value) )
        
    
}



//divエレメントをドラッグでリサイズできるようにする。
const dispatch = d3.dispatch("resize");    
dispatch.on("resize", render);
setResizeControler();


function setResizeControler(){
    const drag = d3.drag()
        .on("drag", resized)
    
    d3.select("#chart")    
        .call(drag);
    
    function resized(e){
        const s = d3.event.sourceEvent;
        const w = (s.pageX < 300) ? 300 : s.pageX;
        const h = (s.pageY < 200) ? 200 : s.pageY;
        
        d3.select(this)
            .style("width", `${w}px`)
            .style("height", `${h}px`)
            .attr("data-test", "test")
        
        dispatch.call("resize");
        
    }
    
}
    
    
    
</script>


</body>
</html>