D3でガントチャート作る


[TextGantt](http://hashrock.github.io/TextGantt/
)というテキスト→ガントチャート変換ツールを作ってます。


![スクリーンショット 2014-12-13 0.17.05.png](https://qiita-image-store.s3.amazonaws.com/0/32596/e9982a26-f01d-eca1-645c-44feb81b79f9.png "スクリーンショット 2014-12-13 0.17.05.png")

が、ガントチャート描画をjQuery pluginに依存しており、いろいろと自由になりません。
せっかくなので、SVGなどで自前で描くようにしたいところです。

そこで今回はD3の練習として簡易ガントチャートを描いてみました。今後は描画部はD3で書き直したいと思っています。

成果物
----

![スクリーンショット 2014-12-12 23.53.41.png](https://qiita-image-store.s3.amazonaws.com/0/32596/351299c9-c07f-007b-704e-8b3f44de083c.png)

すごくシンプル（ダサい）ですね・・・

[DEMO](http://hashrock.github.io/d3-gantt-example/)

参考になるかわかりませんが、コードは下記から取得できます。

[github](https://github.com/hashrock/d3-gantt-example)

ポイント
----

 * ホイール・タッチスクリーン対応ズーム
 * 一応日本語化
 * 地味な見た目（多分職場で使えるはず・・・）


コード一部解説
---

###曜日表示を日本語にする

```js
    //曜日表示を日本語に設定
    var ja_JP = d3.locale({
        "decimal": ".",
        "thousands": ",",
        "grouping": [3],
        "currency": ["", "円"],
        "dateTime": "%a %b %e %X %Y",
        "date": "%Y/%m/%d",
        "time": "%H:%M:%S",
        "periods": ["AM", "PM"],
        "days": ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"],
        "shortDays": ["日", "月", "火", "水", "木", "金", "土"],
        "months": ["01月", "02月", "03月", "04月", "05月", "06月", "07月", "08月", "09月", "10月", "11月", "12月"],
        "shortMonths": ["01月", "02月", "03月", "04月", "05月", "06月", "07月", "08月", "09月", "10月", "11月", "12月"]
    });

    //X軸表示設定
    var xAxis = d3.svg.axis()
            .scale(xScale)
            .orient("bottom")
            .ticks(d3.time.day, 1)
            .tickSize(-height)
            .tickFormat(ja_JP.timeFormat("%d%a"));
```


d3.localeを利用して、日付が日本語で表示されるようにしました。

ちなみに、localeは全てを定義しないと、グラフが表示されません。
使うものだけを差分定義したいところです。

###タスク名の右寄せ

```js
        //タスクのラベル表示
        text.text(function (item) {
            return item.name
        })
        .attr("text-anchor", "end")
        .attr("x", function (item) {
            return xScale(item.start) - 10
        })
        .attr("y", function (item, i) {
            return i * 40 + 28
        });

```

text-anchorを使うと、テキストの原点をどこに取るかを指定できます（SVGの機能）。ここにendを指定すると、右寄せになります。


###ズーム機能


```js
    var update = function () {
        //ズーム
        svg.select(".x.axis").call(xAxis);

        //タスク表示
        rect.attr("x", function (item) {
            return xScale(item.start);
        }).attr("y", function (item, i) {
            return i * 40 + 20
        }).attr("width", function (item) {
            return xScale(item.end) - xScale(item.start)
        }).attr("height", 10);

    };
```

このコードを、on("zoom")で実行しています。ズーム実行後、軸の再評価と、タスク表示の座標の再評価を行っています。

また、svg要素をappendした後に、このupdateを呼ぶことで、初期表示を行うことができます（呼ばないと真っ白）。


また、忘れがちなのが、ピンチイン・アウトの当たり判定として、背景にrectを敷いておくことです。これがないと、ピンチイン・アウトを拾えません。

```js
    //ズーム当たり判定
    svg.append("rect")
            .attr("width", width)
            .attr("height", height);
```


D3使ってみた感想
---

####D3のズーム最強

D3自体は使いこなせていないものの、D3のズーム機能はよく使っています。タッチスクロールからピンチイン・ピンチアウトによる拡大縮小、マウスホイール対応など、何も意識しなくても全てに対応できます。

特に、スマホサイトを構築するときに、ジェスチャによる擬似的なタッチ対応ではなく、ヌルヌルとタッチに反応して欲しい時に、d3のタッチ機能を使うことがあります。

####メソッドチェーンでどんなオブジェクトが戻ってきているのかが今ひとつわかっていない

未だによくわかりません。対策として、TypeScriptでd.tsの助けを借りながら組んでいたことがありました。
もう少し習熟しないとですね・・・。


##参考にしたサイト

http://tech.nitoyon.com/ja/blog/2013/10/24/d3js/