0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

D3でリアルタイムチャートを描く

Last updated at Posted at 2025-02-09

ezgif-4b93dad6625514.gif

<!doctype html>
<html>
  <meta charset="utf-8" />
  <title>D3 chart</title>
  <style>
    body {
      margin: 1em auto 4em auto;
      position: relative;
      width: 960px;
    }

    svg {
      font: 10px sans-serif;
    }

    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }

    .x.axis line {
      shape-rendering: auto;
    }

    .line {
      fill: none;
      stroke: #000;
      stroke-width: 0.8px;
    }

    .bar {
      fill: steelblue;
      opacity: 0.8;
    }

    .area {
      fill: steelblue;
      opacity: 0.8;
    }

    .grid-line {
      stroke: lightgray;
      stroke-width: 0.5;
    }

    #container {
      display: flex;
      gap: 10px;
      padding: 10px;
    }

    #container > div {
      border: 1px solid #ccc;
      padding: 10px;
      box-sizing: border-box;
    }

    #container > div:first-child {
      flex: 1;
      min-width: 200px;
    }

    #container > div:last-child {
      flex: 3;
    }

    #chart-container {
      display: flex;
      flex-direction: column;
    }

    div > p {
      border: 1px solid #ccc;
      padding: 10px;
      box-sizing: border-box;
    }

    div > pre {
      border: 1px solid #ccc;
      padding: 10px;
      box-sizing: border-box;
    }
  </style>
  <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
  <script>
    const n = 60
    const duration = 750
    const random = d3.random.normal(0, 0.2)

    const margin = { top: 6, right: 6, bottom: 20, left: 25 }
    const width = 720 - margin.right
    const height = 120 - margin.top - margin.bottom

    const $ = (id) => document.getElementById(id)

    // --- Create SVG --------------------------
    function createSvg(data, id, xDomain) {
      var x = d3.scale.linear().domain(xDomain).range([0, width])
      var now = new Date(Date.now() - duration)
      var lastIndex = xDomain[1]

      var timeseries = d3.time
        .scale()
        .domain([now - lastIndex * duration, now - duration])
        .range([0, width])

      var y = d3.scale
        .linear()
        .domain([d3.min(data), d3.max(data)])
        .range([height, 0])

      var baseSvg = d3
        .select(id)
        .append('p')
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

      baseSvg //
        .append('defs')
        .append('clipPath')
        .attr('id', 'clip')
        .append('rect')
        .attr('width', width)
        .attr('height', height)

      var axisY = baseSvg
        .append('g')
        .attr('class', 'y axis')
        .call(
          (y.axis = d3.svg //
            .axis()
            .scale(y)
            .ticks(5)
            .orient('left')),
        )

      var axisX = baseSvg
        .append('g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0,' + height + ')')
        .call(
          (timeseries.axis = d3.svg //
            .axis()
            .scale(timeseries)
            .orient('bottom')),
        )

      return { lastIndex, x, timeseries, axisX, y, axisY, baseSvg }
    }

    // --- Update Axis --------------------------
    function updateAxis(data, svg) {
      const { timeseries, lastIndex, axisX, y, axisY } = svg

      const now = new Date()
      timeseries.domain([now - lastIndex * duration, now - duration])
      axisX.call(timeseries.axis)

      y.domain([d3.min(data), d3.max(data)])
      axisY.call(y.axis)

      const ticks = axisY.selectAll('g.tick')
      ticks.each(function () {
        const tick = d3.select(this)
        tick.selectAll('.grid-line').remove()
        tick //
          .append('line')
          .attr('class', 'grid-line')
          .attr('x1', 0)
          .attr('x2', width)
          .attr('stroke-dasharray', '3,6')
      })
    }

    // --- Line Chart --------------------------
    function lineChart(id, xDomain, interpolation, tick) {
      var data = d3.range(n).map(() => 0)
      var svg = createSvg(data, id, xDomain)

      var line = d3.svg
        .line()
        .interpolate(interpolation)
        .x((d, i) => svg.x(i))
        .y((d) => svg.y(d))

      var path = svg.baseSvg //
        .append('g')
        .attr('clip-path', 'url(#clip)')
        .append('path')
        .datum(data)
        .attr('class', 'line')
        .attr('d', line)

      tick(path, line, data, svg)
    }

    // --- Bar Chart --------------------------
    function barChart(id, xDomain, tick) {
      var data = d3.range(n).map(() => 0)
      var svg = createSvg(data, id, xDomain)

      var bars = svg.baseSvg //
        .append('g')
        .attr('class', 'bars')
        .attr('clip-path', 'url(#clip)')
        .selectAll('.bar')
        .data(data)
        .enter()
        .append('rect')
        .attr('class', 'bar')
        .attr('x', (d, i) => svg.x(i))
        .attr('y', (d) => svg.y(d))
        .attr('width', width / n - 1)
        .attr('height', (d) => height - svg.y(d))

      tick(bars, data, svg)
    }

    // --- Area Chart --------------------------
    function areaChart(id, xDomain, interpolation, tick) {
      var data = d3.range(n).map(() => 0)
      var svg = createSvg(data, id, xDomain)

      var area = d3.svg
        .area()
        .interpolate(interpolation)
        .x((d, i) => svg.x(i))
        .y0(svg.y(0))
        .y1((d) => svg.y(d))

      var path = svg.baseSvg //
        .append('g')
        .attr('clip-path', 'url(#clip)')
        .append('path')
        .datum(data)
        .attr('class', 'area')
        .attr('d', area)

      tick(path, area, data, svg)
    }

    // --- Chart1 --------------------------
    function Chart1() {
      var transition = d3.select({}).transition().duration(duration).ease('linear')

      function tick(path, line, data, svg) {
        function each() {
          data.push(random())
          showData('chart1-data', data)
          updateAxis(data, svg)

          path
            .attr('d', line)
            .attr('transform', null)
            .transition()
            .attr('transform', 'translate(' + svg.x(-1) + ')')

          data.shift()
        }

        transition = transition
          .each(each)
          .transition()
          .each('start', () => tick(path, line, data, svg))
      }

      lineChart('#chart1', [0, n - 1], 'linear', tick)
    }

    // --- Chart2 --------------------------
    function Chart2() {
      var transition = d3.select({}).transition().duration(duration).ease('linear')

      function tick(path, line, data, svg) {
        function each() {
          data.push(random())
          showData('chart2-data', data)
          updateAxis(data, svg)

          path
            .attr('d', line)
            .attr('transform', null)
            .transition()
            .attr('transform', 'translate(' + svg.x(0) + ')')

          data.shift()
        }

        transition = transition
          .each(each)
          .transition()
          .each('start', () => tick(path, line, data, svg))
      }

      lineChart('#chart2', [1, n - 2], 'basis', tick)
    }

    // --- Chart3 --------------------------
    function Chart3() {
      var transition = d3.select({}).transition().duration(duration).ease('linear')

      function tick(bars, data, svg) {
        function each() {
          data.push(random())
          showData('chart3-data', data)
          updateAxis(data, svg)

          svg.x.domain([svg.x.domain()[0] + 1, svg.x.domain()[1] + 1])

          bars = bars.data(data)
          bars
            .enter()
            .append('rect')
            .attr('class', 'bar')
            .attr('x', (d, i) => svg.x(i))
            .attr('y', (d) => svg.y(d))
            .attr('width', width / n - 1)
            .attr('height', (d) => height - svg.y(d))
            .attr('fill', 'steelblue')
          bars
            .transition()
            .duration(duration)
            .attr('x', (d, i) => svg.x(i))
        }

        transition = transition
          .each(each)
          .transition()
          .each('start', () => tick(bars, data, svg))
      }

      barChart('#chart3', [0, n - 1], tick)
    }

    // --- Chart4 --------------------------
    function Chart4() {
      var transition = d3.select({}).transition().duration(duration).ease('linear')

      function tick(path, area, data, svg) {
        function each() {
          data.push(random())
          showData('chart4-data', data)
          updateAxis(data, svg)

          path
            .attr('d', area)
            .attr('transform', null)
            .transition()
            .attr('transform', 'translate(' + svg.x(-1) + ')')

          data.shift()
        }

        transition = transition
          .each(each)
          .transition()
          .each('start', () => tick(path, area, data, svg))
      }

      areaChart('#chart4', [0, n - 1], 'linear', tick)
    }

    // --- Chart5 --------------------------
    function Chart5() {
      var transition = d3.select({}).transition().duration(duration).ease('linear')

      function tick(path, area, data, svg) {
        function each() {
          data.push(random())
          showData('chart5-data', data)
          updateAxis(data, svg)

          path
            .attr('d', area)
            .attr('transform', null)
            .transition()
            .attr('transform', 'translate(' + svg.x(-1) + ')')

          data.shift()
        }

        transition = transition
          .each(each)
          .transition()
          .each('start', () => tick(path, area, data, svg))
      }

      areaChart('#chart5', [0, n - 1], 'basis', tick)
    }

    function showData(id, data) {
      $(id).innerText = JSON.stringify(data.slice(-8), null, 2)
    }
  </script>
  <h1>D3 Real-time Chart</h1>
  <div id="container">
    <div>
      Chart1 Data
      <pre id="chart1-data"></pre>
      Chart2 Data
      <pre id="chart2-data"></pre>
      Chart3 Data
      <pre id="chart3-data"></pre>
      Chart4 Data
      <pre id="chart4-data"></pre>
      Chart5 Data
      <pre id="chart5-data"></pre>
    </div>
    <div id="chart-container">
      <div id="chart1">
        Chart1 Line linear
        <script>
          Chart1()
        </script>
      </div>
      <div id="chart2">
        Chart2 Line basis
        <script>
          Chart2()
        </script>
      </div>
      <div id="chart3">
        Chart3 Bar
        <script>
          Chart3()
        </script>
      </div>
      <div id="chart4">
        Chart4 Area linear
        <script>
          Chart4()
        </script>
      </div>
      <div id="chart5">
        Chart5 Area basis
        <script>
          Chart5()
        </script>
      </div>
    </div>
  </div>
</html>
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?