Slack API × D3

MeteorにD3を導入

発端

サークルで、Slackを使っているので、そのトークを分析したいと思い、D3 × Slackを試してみることに

導入

今回は、nvd3を使用した。実は、最初はD3で一から組んでいたが、学習コストが高く諦めることに。。。
以下のコンソールで、D3を勉強するページは非常にわかりやすかった!
【D3.js】超基本! コンソールでselect,data,enterメソッドを理解する。
Meteorへの導入は、以下のコマンドを叩くだけ

$ meteor npm install nvd3 --save
$ meteor add nvd3:nvd3

実際のコード

ほぼ、以下のページのコードのコピペ。
Horizontal Multi-Bar Chart

import { config } from '../../config'
import * as d3 from 'd3';
import * as nv from 'nvd3';

import '../../client/main.html';

// type declare
interface elementType {
  id: string
  name: string;
}

interface channelDataType {
  reaction: number;
  message: number;
}

interface d3DataType extends channelDataType {
  name: string;
}

interface d3BarDataType {
  key: string;
  color: string;
  values: { label: string; value:number; } [];
}

// get necessary data
function getData (data):channelDataType[] { 
  const channelData = [];

  let reactionCount: number = 0;
  const messageCount: number = data.length;

  data.forEach(element => {
    if (element.reactions !== undefined) {
      element.reactions.forEach(value => {
        reactionCount += value.count;
      });
    }
  });

  channelData['reaction'] = reactionCount;
  channelData['message'] = messageCount;
  return channelData;
}

// get each channel data
async function getChannelInfo(element:elementType) {
  let getPostUrl:string = 'https://slack.com/api/channels.history?token=' + config.token 
    + '&channel=' + element.id + '&count=500';
  const response = await fetch(getPostUrl); 
  const json = await response.json();
  const channelData = getData(json.messages);
  return channelData;
}

// get all channel data
async function getAllChannelInfo() {
  const getChannelsUrl:string  = 'https://slack.com/api/channels.list?token=' + config.token
        + '&exclude_archived=true';
  try {
    const allChannelData = [];
    const response = await fetch(getChannelsUrl);
    const json = await response.json();
    json.channels.forEach(element => {
      const channelData = getChannelInfo(element).then(val => 
        { val['name'] = element.name; return val; });
      allChannelData.push(channelData);
    });
    return allChannelData;
  } catch (error) {
    console.log(error);
  }
};

// formatting data
function formatData(data) {
  const filterData = data.filter(function(element){
    return (element.message > 15);
  }).sort(function(x, y){
    return y.message - x.message || y.reaction - x.reaction;
  });

  const formatDataForBar: d3BarDataType[] = [
    { key:"Message", color:"#d67777", values:[] },
    { key:"Reaction", color:"#4f99b4", values:[] },
  ];

  filterData.forEach(val=> {
    /* For Bar chart */
    formatDataForBar[0].values.push({ label: val.name, value: val.message });
    formatDataForBar[1].values.push({ label: val.name, value: val.reaction });
  })

  return formatDataForBar;
}

// draw d3 bar graph  
function d3BarDraw (d3Data) {
  nv.addGraph(function() {
    const chart = nv.models.multiBarHorizontalChart()
        .x(function(d) { return d.label })
        .y(function(d) { return d.value })
        .margin({top: 30, right: 20, bottom: 50, left: 175});

    chart.yAxis
        .tickFormat(d3.format("01d"));

    d3.select('#bar-graph svg')
        .datum(d3Data)
        .call(chart);

    nv.utils.windowResize(chart.update);

    return chart;
  });
}

// draw d3 graph
function drawBarGraph () {
  const alldata = getAllChannelInfo();

  alldata.then(e => {
    Promise.all(e).then((d3Data:d3DataType[]) => {
      // arrrange data
      return formatData(d3Data);
    }).then((d3FilterData):void => {
      // draw graph
      d3BarDraw(d3FilterData);
  });
};

// Draw Bar Graph
drawBarGraph();

結論

D3は、やっぱり学習コスト高め。凝った、アニメーションが必要でなければChart.jsで十分対応できる! ちなみに、以下のGifの下の折れ線グラフは、Chart.jsで作成してますー

[DEMO]