«

오픈API를 이용해서 D3로 날씨차트 구현하기

서론

D3는 웹브라우저상에서 정보들을 동적이고 시각적으로 전달하기 위한 자바스크립트 라이브러리 입니다. 데이터를 시각화 한다고 생각하시면 됩니다.

설명

완성이미지

오픈날씨 API를 이용해서 데이터를 Ajax로 받아서 D3를 이용해 차트를 만드는 것 까지 진행하겠습니다. 진행하기 전에 Node.js, Webpack을 설치해주세요 폴더구조는 아래처럼 해주세요

+ src
    - ajax.js
    - app.js
    - xcharts.min.css
    - xcharts.min.js
    
- index.html
- package.json
- webpack.config.js

package.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server -d --hot --host 127.0.0.1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel": "^6.23.0",
    "babel-core": "^6.23.1",
    "babel-loader": "^6.3.2",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-es2016": "^6.22.0",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.3.0"
  }
}

webpack.config.js

const webpack = require('webpack');

module.exports = {
    entry: __dirname+'/src/app.js',
    output: {
        filename: 'bundle.js'
    },
    module:{
        loaders:[{
            test:/\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/,
            query:{
                presets:['es2015', 'es2016']
            }
        }]
    },
    plugins:[
        new webpack.optimize.UglifyJsPlugin({
            compressor:{
                warnings: false
            }
        })
    ],
    devServer:{
        inline: true,
        port: 7777,
        contentBase: __dirname,
        historyApiFallback: true
    }
};

여기까지 진행이 됬다면 터미널에서 npm i로 babel, jquery, webpack을 설치해주세요

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>d3로 날씨차트 만들기</title>
    <link rel="stylesheet" href="./src/xcharts.min.css">
    <style>
        #myChart{
            width: 600px;
            height: 300px;
        }
        .xchart{
            overflow: visible;
        }
    </style>
</head>
<body>
    <div id="myChart"></div>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="./src/xcharts.min.js"></script>
    <script src="bundle.js"></script>
</body>
</html>

저희가 만든 차트를 구현하려면 xcharts를 다운받으셔야 합니다. xcharts다운받기 다운받으셨다면 이번엔 ajax파일을 수정하겠습니다.

ajax.js

export default (url, callback) => {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {
        if(xhr.readyState === 4 && xhr.status === 200){
            callback(JSON.parse(xhr.responseText));
        }
    };

    xhr.open('get', url, true);
    xhr.send();
};

이제 app.js만 작성하면 끝이 납니다.

app.js

var tt = document.createElement('div'),
  leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),
  topOffset = -32;
tt.className = 'ex-tooltip';
document.body.appendChild(tt);

var data = {
  "xScale": "time",
  "yScale": "linear",
  "main": [
    {
      "className": ".pizza",
      "data": [
        {
          "x": "2012-11-05",
          "y": 6
        },
        {
          "x": "2012-11-06",
          "y": 6
        },
        {
          "x": "2012-11-07",
          "y": 8
        },
        {
          "x": "2012-11-08",
          "y": 3
        },
        {
          "x": "2012-11-09",
          "y": 4
        },
        {
          "x": "2012-11-10",
          "y": 9
        },
        {
          "x": "2012-11-11",
          "y": 6
        }
      ]
    }
  ]
};
var opts = {
  "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
  "tickFormatX": function (x) { return d3.time.format('%A')(x); },
  "mouseover": function (d, i) {
    var pos = $(this).offset();
    $(tt).text(d3.time.format('%A')(d.x) + ': ' + d.y)
      .css({top: topOffset + pos.top, left: pos.left + leftOffset})
      .show();
  },
  "mouseout": function (x) {
    $(tt).hide();
  }
};
var myChart = new xChart('line-dotted', data, '#example4', opts);

위의 코드는 xcharts에 가져온 기본코드 입니다. 이제 이부분을 수정해야 하는데요. 안에 내용을 보시면 2012-11-05 처럼 날짜가 하드코딩이 되어 있네요 날짜가 오늘날짜부터 일주일 날짜를 자동으로 변환 되도록 수정을 하고 y값에 해당 날짜에 해당하는 온도데이터를 뿌려주면 됩니다. 그럼 해야 할 작업을 정리해보면

1.날짜데이터 자동변환
2.날짜에 해당하는 온도 삽입

var data = {
  "xScale": "time",
  "yScale": "linear",
  "main": [
    {
      "className": ".pizza",
      "data": [
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        },
        {
          "x": ,
          "y": 
        }
      ]
    }
  ]
};
var opts = {
  "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
  "tickFormatX": function (x) { return d3.time.format('%A')(x); }
};
var myChart = new xChart('line-dotted', data, '#myChart', opts);
import ajax from './ajax';
const weatherURL = 'http://api.openweathermap.org/data/2.5/forecast/daily?q=seoul&mode=json&units=metric&cnt=7&apikey=8d554a626fc5d01d77812b612a6de257';

ajax(weatherURL, ajaxData => {
    let newDateYMD = i=> {
        let newDate = i=> {
            return new Date(ajaxData.list[i].dt * 1000);
        };
        return `${newDate(i).getFullYear()}-${newDate(i).getMonth()+1}-${newDate(i).getDate()}`
    };
    
    const data = {
      "xScale": "time",
      "yScale": "linear",
      "main": [
        {
          "className": ".pizza",
          "data": [
            {
              "x": newDateYMD(0),
              "y": 
            },
            {
              "x": newDateYMD(1),
              "y": 
            },
            {
              "x": newDateYMD(2),
              "y": 
            },
            {
              "x": newDateYMD(3),
              "y": 
            },
            {
              "x": newDateYMD(4),
              "y": 
            },
            {
              "x": newDateYMD(5),
              "y": 
            },
            {
              "x": newDateYMD(6),
              "y": 
            }
          ]
        }
      ]
    };
    const opts = {
      "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
      "tickFormatX": function (x) { return d3.time.format('%A')(x); }
    };
    const myChart = new xChart('line-dotted', data, '#myChart', opts);
});

날짜데이터는 끝났습니다. 이제 온도만 남았네요

import ajax from './ajax';
const weatherURL = 'http://api.openweathermap.org/data/2.5/forecast/daily?q=seoul&mode=json&units=metric&cnt=7&apikey=8d554a626fc5d01d77812b612a6de257';

ajax(weatherURL, ajaxData => {
        let newDateYMD = i=> {
            let newDate = i=> {
                return new Date(ajaxData.list[i].dt * 1000);
            };
            return `${newDate(i).getFullYear()}-${newDate(i).getMonth()+1}-${newDate(i).getDate()}`
        };
        let temp = i=> {
            return Math.round(ajaxData.list[i].temp.day);
        };

        const data = {
            "xScale": "time",
            "yScale": "linear",
            "main": [
                {
                    "className": ".pizza",
                    "data": [
                        {
                            "x": newDateYMD(0),
                            "y": temp(0)
                        },
                        {
                            "x": newDateYMD(1),
                            "y": temp(1)
                        },
                        {
                            "x": newDateYMD(2),
                            "y": temp(2)
                        },
                        {
                            "x": newDateYMD(3),
                            "y": temp(3)
                        },
                        {
                            "x": newDateYMD(4),
                            "y": temp(4)
                        },
                        {
                            "x": newDateYMD(5),
                            "y": temp(5)
                        },
                        {
                            "x": newDateYMD(6),
                            "y": temp(6)
                        }
                    ]
                }
            ]
        };

    const opts = {
        "dataFormatX": function (x) { return d3.time.format('%Y-%m-%d').parse(x); },
        "tickFormatX": function (x) { return d3.time.format('%a')(x); }
    };
    const myChart = new xChart('line-dotted', data, '#myChart', opts);
});

온도데이터도 삽입이 끝났습니다. 확인은 터미널에서 npm start를 입력 후 브라우저에서 localhost:7777을 입력하셔서 확인하시면 됩니다.