世界最大の配車アプリを開発・運営するUber社がオープンソースとして公開しているデータビジュアライゼーションフレームワーク。 同じくUber社が公開している可視化スイート「Vis.gl」のツールの一つ。
Deck.glを含むUber社が公開しているデータビジュアライゼーションスイート可視化ツール群。スイート(ひとそろいの、一式の)と名がつく通り、それぞれのライブラリやフレームワークは組み合わせて使えるようにコンポーネント化されている。Uber社の全部盛りデータ可視化ツールスイート「Vis.gl」一覧 – GUNMA GIS GEEK
deck.glは、大規模なデータセットの視覚化をWebGlを用いて簡単に作成できるように設計されています。 ポイントやライン、ポリゴンなどのデータを地図上に可視化するための様々なレイヤーコンポーネントが提供されており、複数のレイヤーを組み合わせることにより、少ない労力で労力で印象的なデータビジュアライゼーションを作成することができます。
ReactはFacebook社によって開発された、ユーザーインターフェイスを構築するためのJavaScriptフレームワークです。
ReactはJavaScriptのコードをコンポーネントという単位で分割し、再利用可能な部品として使うことを想定してシステムが設計されています。
Uber社のvis.glスイートもReactコンポーネントとして作成されており、各ツールを簡単に組み合わせて使えるように設計されています。
//MyComponent
import React from 'react';
export default (props) => {
const { text } = props; //引数を受け取る
return <h1>{text}</h1>; //引数を適用したjsxを返す
};
Reactのコンポーネントは基本、単なる関数。値を受け取って(ない場合もある)、値を返すだけのものでしかない。
以前はクラスが主流だったが、フックという新機能の登場でステートレスなファンクションが基本となりつつある。
//App.js
import React from 'react';
//コンポーネントの読み込み
import MyComponent from './MyComponent.js';
export default () => {
return (
<div className="App">
<!--コンポーネントを使う-->
<MyComponent text="ここの値がコンポーネントに渡されます"></MyComponent>
</div>
);
};
//App.js
import React from "react";
import DeckGL from "deck.gl";
export default () => {
return (
<DeckGL
layers={renderLayers({ data: data })}
controller={true}
initialViewState={viewport}]
>
</DeckGL>
);
};
node.jsとnpmをインストール
$ apt install nodejs
$ apt install npm
npmを使ってcreate-react-appコマンドをインストトール
$ npm install create-react-app -g
パーミッションエラーが出る場合はsudoをつけて実行してください。
プロジェクトの作成
$ create-react-app myproject
$ cd myproject
$ npm install deck.gl --save #deck.glを追加する
開発サーバーの起動
$ npm start
ビルド
$ npm run build
buildディレクトリが生成され、コードが出力されます。
とりあえずこれだけわかっておけば、ビルドツールの細かい設定等がわからなくても開発はできます。
「レイヤー」はDeck.glの中核をなす機能で、データムのコレクションを取得し、各データを位置、色、3Dポリゴンなどに関連付けてマップ上にレンダリングする可視化コレクションです。
複数のレイヤーを重ね合わせたり、ホバーやクリックなどのインタラクションを管理する機能があります。
//RennderLayer.js
//散布図レイヤークラスをインポート
import { ScatterplotLayer } from "deck.gl";
export default props => {
const { data } = props;
//インスタンス化
const scatter = new ScatterplotLayer({
id: "scatter-layer",
data: data,
getFillColor: d => d.color,
getPosition: d => [d.lng, d.lat]
})
//レイヤーを配列にまとめる
const layes = [scatter];
return layes;
};
Deck.glライブラリから必要なレイヤークラスをインポートし、プロパティを設定してインスタンス化します。
//App.js
import React from "react";
import DeckGL from "deck.gl";
import renderLayers from "./RenderLayers.js";
export default () => {
const data = {
{ name: 'Colma', lng:-122.466233, lat:37.684638 },
{ name: 'Civic Center', lng:-122.413756, lat:37.779528 },
...
};
return (
<DeckGL
layers={renderLayers({ //レイヤーをDeckコンポーネントに設置
data: data
})}
controller={true}
initialViewState={ViewState}
/>
);
};
Deckコンポーネントのlayerプロパティにレイヤーオブジェクトを渡す。
$ //deck.gl
import { GeoJsonLayer } from 'deck.gl';
const data = loadJson("example.geojson");
const layer = new GeoJsonLayer({
id: 'geojson-layer',
data:data,
getFillColor: d => d.properties.color,
getRadius: d => d.properties.population,
});
return [layer];
//d3.js
d3.json("example.geojson").then(data =>{
svg.selectALL("circle")
.data(data)
.enter()
.append("circle")
.attr("fill", d => d.properties.color)
.attr("r", d => d.properties.population)
});
指定したコールバックがデータストリームをトラバースする仕組みはD3を使ったことがある人には理解しやすい
「view」はdeck.glが可視化したレイヤーを映し出すカメラとカメラコントロールロジックをパッケージ化したクラスです。
データセットの座標(地理空間座標、2次元座標など)および、カメラの視点(トップダウン、一人称など)に基づいて、1つまたは複数のviewクラスを選択できます。
「viewState」は、viewの状態を保存するオブジェクトです。
//App.js
const viewState = {
width: window.innerWidth,
height: window.innerHeight,
longitude: -3.2943888952729092,
latitude: 53.63605986631115,
zoom: 6,
maxZoom: 16,
pitch: 65
};
export default () => {
return (
<DeckGL
controller={true}
initialViewState={viewState}
/>
);
};
Deckコンポーネントに渡されたviewStateオブジェクトは、ユーザーの操作を検出したコントローラーによって更新されます。
viewStateオブジェクトの受け渡しには、viewStateプロパティかinitialViewStateプロパティを使います。
//initialViewState
const viewState = { … };
export default () => {
return (
<DeckGL
controller={true}
initialViewState={viewState}
/>
);
};
//viewState
const viewState = { … };
export default () => {
return (
<DeckGL
controller={true}
viewState={viewState}
onViewStateChange={v => setViewState(v.state) }
/>
);
};
他コンポーネントとviewStateを共有する場合には、onViewStateChangeを使って明示的にviewStateの更新を行う必要がある。
//App.js
export default () => {
const [viewState, setViewState] = useState({ … });
return (
<div>
<MapGL
{...viewState}
mapStyle={"mapbox://styles/mapbox/light-v9"}
mapboxApiAccessToken={MAPBOX_TOKEN}
onViewportChange={v => setViewState(v)}
>
<DeckGL
layers={renderLayers({
data: data
})}
controller={true}
viewState={viewState}
onViewStateChange={v => setViewState(v.viewState)}
/>
</MapGL>
</div>
);
};
onViewportChangeとonViewStateChangeでコールバックの引数として渡される値にも微妙に違いがあって悩ましい
//App.js
//ビュークラスを読み込む
import DeckGL, { OrbitView } from "deck.gl";
//ビュークラスをインスタンス化
const view = new OrbitView({ fov: 50 });
const viewState = { … };
export default () => {
return (
<DeckGL
views={view} //ビューを指定する
controller={true}
initialViewState={viewState}
/>
);
};
クラス | 座標系 | 詳細 |
---|---|---|
View |
生のveiwクラス。通常使用することはないが、投影行列を指定することで独自の座標系を利用できる。 | |
MapView
(デフォルト) |
地理空間 | Web Meractor Projectionを用いてデータをレンダリングする。mapbox-glやGoogle Mapsなどの外部ベースマップライブラリの座標と一致するように設計されている。 |
FirstPersonView
|
地理空間 | カメラは指定されたジオロケーションに配置され、一人称視点でデータをレンダリングする |
ThirdPersonView
|
地理空間 | カメラは指定されたジオロケーションに配置され、三人称視点でデータをレンダリングする |
OrthographicView
|
info-vis(2D) | カメラは2Dの座標に対して垂直(見下ろし)に設置されターゲットポイントを映します。回転(チルト)は変更されません。 |
OrbitView |
info-vis(3D) | カメラは指定された方向から2D座標をターゲットポイントを映します。指定されたポイントを中心に回転します。 |
PerspectiveView
|
info-vis(3D) | カメラは指定された方向から2D座標をターゲットポイントを映します。またカメラの位置を中心に回転します。 |