CesiumのQuickStartからつまづいた人がQuickStartを完全に理解してnode.jsで動かすまで

いやほんとJavaScriptとか普段触ってないから無理です……

# 概要

Cesiumを使って3次元データを可視化したいと思い立ったのがここ数日。ま，とにかく触ってみるか，ということで公式のQuickStartを動かしてみる……動かしてみる……動かない……

ということでイライラしていたものの最終的に動いたので備忘録。

# 注意

新しい技術なので仕方がないことだが，Cesiumは，たびたび，破壊的に仕様が変わるらしい（未確認情報）。なので，この内容がこの先どれだけ使えるか不明。

そもそも，同様の情報が見つからないところを見ると，とんでもなく基礎的なところで私が躓いているか，私の環境特有の問題なのかもしれない。

# QuickStartで詰まるまで

公式はココ

https://cesium.com/learn/cesiumjs-learn/cesiumjs-quickstart/

アカウントを作って，tokenを取得する。
取得したtokenに合わせてQuickStartのコードが変わるという近未来な仕様にビビる。

さて，2つのコードがサンプルで掲載されている。きちんと動けばサンフランシスコの街の様子が表示されるらしい。

ひとつは素HTMLに`<script>`で，モリモリJavaScriptを食わせて動かすコード。これは簡単そうだけれども，HTMLにコードがまとまってしまうというのが嫌。

ひとつは，JavaScript。これは，Webpack, Parcel, Rollupなどのモジュールバンドラーを使う場合に良いよ，と書いてある。そんなものは知らない（かろうじてnode.jsくらいは知ってる）ので，パス。

仕方がないので，前者で試すことにする。コードをコピペして，htmlを開く。

と，……宇宙空間に浮かぶ建物の様な何かが表示される……。サンフランシスコどこ？

開発者ツールで見ると，ファイルを読みに行くときに，セキュリティではじかれているっぽい。薄々思ってたけど，これ，`index.html`を作ってブラウザで開くだけではダメなのでは？

ネットで見つかる情報も色々試してみたが，トークンの読み込みが全然うまくいかない。こりゃだめだ。

# QuickStartを解決するまで

実際にはあれでもないこれでもないと紆余曲折していたが，結果だけ示す。

## node.jsの導入

npmとnode.jsは，ずいぶん前に何かで導入していた。詳しくは忘れた。

これを使って，ローカルにcesiumを導入して，仮想サーバーで動かして，それをブラウザから見にいけばいいんじゃないか？という発想。

`npm i cesium`でcesiumは簡単にインストールできた。バージョンは`1.117`。

## 新しいファイル構成

- `node_modules/`：npmで勝手に入った
- `package.json`：npmで勝手に入った
- `package-lock.json`：npmで勝手に入った
- `server.js`：node.jsを使って，サーバーサイドで動くプログラム
- `index.html`：`server.js`から呼び出すhtmlファイル
- `cliant.js`：クライアントサイドのプログラム。`index.html`から呼び出し

## `server.js`

`index.html`と`client.js`を分離するために，`client.js`のリクエストがあった際の対応を記載しておく必要がある。

```javascript
import http from 'http'
import fs from 'fs'

const server = http.createServer((req, res) => {
  
  if (req.url === '/'){
    fs.readFile("./index.html", (err, data) => {
      if (err) {
        console.log(err);
      } else {
        res.statusCode = 200;
        res.setHeader("Content-Type", "text/html");
        res.end(data);
      }
    });
  } else if (req.url === '/client.js') {
    fs.readFile("./client.js", (err, data) => {
      if (err) {
        console.log(err);
      } else {
        res.statusCode = 200;
        res.setHeader("Content-Type", "text/javascript");
        res.end(data);
      }
    });
  }
})

server.listen(1337)
```

## `index.html`

単に`Cesium.js`や`client.js`を呼び出しているだけ。

```javascript
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <!-- Include the CesiumJS JavaScript and CSS files -->
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.117/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.117/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
  <div id="cesiumContainer"></div>
  <script src="client.js"></script>
 </div>
</body>
</html>
```

## `client.js`

元のQuickStartとほぼ同じ。`Cesium.Ion.defaultAccessToken`にはトークンが必要。

```javascript
async function initializeCesium() {
  // Your access token can be found at: https://ion.cesium.com/tokens.
  // This is the default access token from your ion account

  Cesium.Ion.defaultAccessToken = 'hogehoge';

  // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
  const viewer = new Cesium.Viewer('cesiumContainer', {
    terrain: Cesium.Terrain.fromWorldTerrain(),
  });    

  // Fly the camera to San Francisco at the given longitude, latitude, and height.
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400),
    orientation: {
      heading: Cesium.Math.toRadians(0.0),
      pitch: Cesium.Math.toRadians(-15.0),
    }
  });

  // Add Cesium OSM Buildings, a global 3D buildings layer.
  const buildingTileset = await Cesium.createOsmBuildingsAsync();
  viewer.scene.primitives.add(buildingTileset);   
}

initializeCesium();
```

## QuickStart（修正版）

- 上のファイル一式を用意する
- コンソールから`node server.js`を実行
- ブラウザで`localhost:1337`を開く

<b>WELCOME TO SAN FARANCISCO!!!!</b>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617623/2712928a-0480-2428-801d-ff291702a0a9.png)

あーよかった。
Cesium完全に理解した。