mcpField
C
cesiumjs-core-utilities

cesiumjs-core-utilities

github.com/cesiumgs開発193217 回インストール6 週間前に更新
リポジトリ

cesiumjs-core-utilities について

CesiumJSのコアユーティリティとネットワークAPIを扱う開発者向けガイドです。HTTPリソース、イベント、リクエストスケジューリング、エラー、ワーカー、ピンなどを説明します。

主な機能

  1. 01データ取得とHTTPリソース設定
  2. 02イベントとリクエスト数の管理
  3. 03エラー処理とバックグラウンドタスク
  4. 04ピン生成とユーティリティの利用

活用シーン

  1. 01ResourceによるJSON取得やデータ送信
  2. 02タイル読み込み時の同時リクエスト調整
  3. 03イベントリスナーとワーカータスクの管理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cesiumgs/cesiumjs-skills --skill cesiumjs-core-utilities

インストール後、Claude Code で/cesiumjs-core-utilitiesを入力して読み込まれたか確認します。

詳細

CesiumJS コアユーティリティとネットワーキング

バージョンの基準:CesiumJS v1.144 以降(ES モジュールのインポート、defaultValue は v1.134 で削除)

破壊的変更:defaultValue の削除(v1.134)

// WRONG (removed in v1.134)
const name = defaultValue(options.name, "default");
const opts = defaultValue(options, defaultValue.EMPTY_OBJECT);

// CORRECT (v1.134+)
import { Frozen } from "cesium";
const name = options.name ?? "default";
const opts = options ?? Frozen.EMPTY_OBJECT;

Frozen.EMPTY_OBJECT は Object.freeze({})、Frozen.EMPTY_ARRAY は Object.freeze([]) です。オプションオブジェクトや配列パラメーターの安全なデフォルト値として使用してください。

Resource:HTTP リクエストとデータ取得

Resource は、すべての HTTP 操作に使用する統合クラスです。URL の構築、クエリパラメーター、ヘッダー、プロキシ処理、再試行ロジックを扱います。

データの取得
import { Resource } from "cesium";

// Static shorthand: accepts a URL string or options object
const jsonData = await Resource.fetchJson({ url: "https://api.example.com/data.json" });

// data: URIs work with Resource.fetchJson -- useful for inline GeoJSON or test fixtures
const dataUrl = "data:application/json," + encodeURIComponent(JSON.stringify(geojson));
const parsed = await Resource.fetchJson({ url: dataUrl });

// Instance-based: construct once, reuse for multiple fetches
const resource = new Resource({
  url: "https://api.example.com/features",
  queryParameters: { format: "json", limit: "100" },
  headers: { "Authorization": "Bearer my-token" },
});
const features = await resource.fetchJson();
const text = await resource.fetchText();           // string
const buffer = await resource.fetchArrayBuffer();  // ArrayBuffer
const blob = await resource.fetchBlob();           // Blob
const image = await resource.fetchImage();         // HTMLImageElement or ImageBitmap
派生リソースとテンプレート値
import { Resource } from "cesium";

const api = new Resource({
  url: "https://tiles.example.com/{version}/tiles/{z}/{x}/{y}.png",
  templateValues: { version: "v2" },
  headers: { "X-Api-Key": "abc123" },
});

// getDerivedResource inherits headers, proxy, and retry settings
const tile = api.getDerivedResource({
  templateValues: { z: "10", x: "512", y: "384" },
});
const tileImage = await tile.fetchImage();

// Modify query parameters on an existing resource
resource.setQueryParameters({ access_token: "<access-token>" });
resource.appendQueryParameters({ extra: "param" });
再試行とプロキシ
import { Resource, DefaultProxy } from "cesium";

// Retry on specific HTTP status codes
const resource = new Resource({
  url: "https://api.example.com/unstable",
  retryAttempts: 3,
  retryCallback: (resource, error) => {
    if (error.statusCode === 429) {
      return new Promise((resolve) => setTimeout(() => resolve(true), 2000));
    }
    return false;
  },
});

// DefaultProxy appends the target URL as a query parameter
const proxied = new Resource({
  url: "https://external-server.com/data.json",
  proxy: new DefaultProxy("/proxy/"),
});
// Request goes to: /proxy/?https%3A%2F%2Fexternal-server.com%2Fdata.json
POST と PUT
import { Resource } from "cesium";

const resource = new Resource({ url: "https://api.example.com/upload" });
const result = await resource.post(JSON.stringify({ name: "test" }), {
  headers: { "Content-Type": "application/json" },
});
// resource.put() works the same way

Color

RGBA の各成分は浮動小数点数 [0.0, 1.0] です。PascalCase で記述された標準 CSS カラー名を網羅する、140 を超える名前付き定数が、凍結された静的プロパティとして用意されています(例:Color.RED、Color.ORANGE、Color.YELLOW、Color.GREEN、Color.BLUE、Color.CORNFLOWERBLUE、Color.ROYALBLUE、Color.FORESTGREEN、Color.CRIMSON、Color.TRANSPARENT)。

ピンのビジュアル評価用フレーミング

PinBuilder をビジュアル評価に使う場合、スクリーンショット内でピンが明確に見えるようにする必要があります。都市規模のレビューでは 56~72 px のピンを使用し、VerticalOrigin.BOTTOM を設定して、Rectangle.fromDegrees(...) またはすべてのピンがビューポート内に余裕をもって収まる高度でフレーミングしてください。1 つのピンが端にある場合は、ズームアウトするか、中心位置を調整してください。エンティティがすべて存在していても、3 つのうち 2 つしか見えない場合はビジュアル評価に失敗します。

色の作成
import { Color } from "cesium";

const red = Color.RED;                                        // frozen constant
const orange = Color.ORANGE;                                  // frozen constant
const royalBlue = Color.ROYALBLUE;                           // frozen constant
const forestGreen = Color.FORESTGREEN;                       // frozen constant
const crimson = Color.CRIMSON;                               // frozen constant
const custom = new Color(0.2, 0.6, 0.8, 1.0);               // float constructor
const blue = Color.fromCssColorString("#3498db");             // hex string
const semiRed = Color.fromCssColorString("rgba(255,0,0,0.5)"); // CSS rgba()
const coral = Color.fromBytes(255, 127, 80, 255);            // 0-255 bytes
const hsl = Color.fromHsl(0.58, 0.8, 0.5, 1.0);             // hue/sat/light
const bright = Color.fromRandom({                             // constrained random
  minimumRed: 0.75, minimumGreen: 0.75, minimumBlue: 0.75, alpha: 1.0,
});
操作と変換
import { Color } from "cesium";

const base = Color.fromCssColorString("#3498db");
const translucent = base.withAlpha(0.5);                // new Color with alpha
const lighter = base.brighten(0.3, new Color());        // requires result param
const darker = base.darken(0.3, new Color());
const css = base.toCssColorString();                    // "rgb(52,152,219)"
const hex = base.toCssHexString();                      // "#3498db"
const bytes = base.toBytes();                           // [52, 152, 219, 255]
const equal = Color.RED.equals(new Color(1.0, 0.0, 0.0, 1.0)); // true

イベントシステム

Event は CesiumJS 全体で使用されるパブリッシュ/サブスクライブの仕組みです。クラスは、Viewer.selectedEntityChanged や Cesium3DTileset.tileLoad のような Event プロパティを公開します。

基本的な使い方
import { Event } from "cesium";

const onDataReceived = new Event();

// addEventListener returns a removal function
const removeListener = onDataReceived.addEventListener((data) => {
  console.log("Received:", data);
});

onDataReceived.raiseEvent({ id: 1, value: "test" }); // invoke all listeners
removeListener(); // unsubscribe
一括クリーンアップ用の EventHelper
import { EventHelper } from "cesium";

const helper = new EventHelper();
helper.add(viewer.selectedEntityChanged, (entity) => {
  console.log("Selected:", entity?.name);
});

// clock.onTick fires every animation frame; enable the clock with shouldAnimate
viewer.clock.shouldAnimate = true;
helper.add(viewer.clock.onTick, (clock) => { /* per-frame logic */ });

helper.add(viewer.scene.globe.tileLoadProgressEvent, (queueLength) => {
  console.log("Tiles loading:", queueLength);
});

// Remove all listeners at once (e.g., in a destroy method)
helper.removeAll();

クロックのティックで更新されるラベル:

import { EventHelper, Color, Cartesian3 } from "cesium";

let tickCount = 0;
const label = viewer.entities.add({
  position: Cartesian3.fromDegrees(-30.0, 30.0),
  label: {
    text: "Ticks: 0",
    showBackground: true,
    backgroundColor: Color.BLACK.withAlpha(0.7),
    fillColor: Color.WHITE,
    font: "24px monospace",
  },
});

const helper = new EventHelper();
viewer.clock.shouldAnimate = true;
helper.add(viewer.clock.onTick, () => {
  tickCount++;
  label.label.text = "Ticks: " + tickCount;
});

RequestScheduler の設定

RequestScheduler は、同時リクエスト数の上限を管理するシングルトンです。Request オブジェクトは、優先度とスロットリング機能を持つ個々の HTTP リクエストを表します(主に内部で使用)。

import { RequestScheduler } from "cesium";

RequestScheduler.maximumRequests = 64;            // global max (default: 50)
RequestScheduler.maximumRequestsPerServer = 12;   // per-server max (default: 18)

// Override for known HTTP/2 servers
RequestScheduler.requestsByServer = {
  "api.cesium.com:443": 32,
  "assets.cesium.com:443": 32,
};

エラー処理

  • DeveloperError -- 呼び出し側のコードのバグ(引数が無効)。デバッグビルドでのみスローされます。コードを修正し、捕捉しないでください。
  • RuntimeError -- 実行時の失敗(ネットワーク、シェーダーのコンパイル)。本番環境では捕捉してください。
import { RuntimeError, formatError, Cesium3DTileset } from "cesium";

try {
  const tileset = await Cesium3DTileset.fromUrl("https://example.com/tileset.json");
  viewer.scene.primitives.add(tileset);
} catch (error) {
  if (error instanceof RuntimeError) {
    console.error("Failed to load tileset:", error.message);
  } else {
    console.error(formatError(error)); // extracts name, message, stack
  }
}

ヘルパー関数

defined、clone、combine
import { defined, clone, combine } from "cesium";

// defined: returns true if value is neither null nor undefined
if (defined(entity.billboard)) {
  entity.billboard.scale = 2.0;
}

// clone: shallow by default, pass true for deep
const obj = clone({ a: 1, nested: { b: 2 } }, true);

// combine: merge objects, first arg's keys take precedence
const merged = combine({ size: 20 }, { size: 10, color: "red" });
// { size: 20, color: "red" }
createGuid、buildModuleUrl
import { createGuid, buildModuleUrl } from "cesium";

const id = createGuid(); // "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"

// Resolve paths relative to Cesium installation
const iconUrl = buildModuleUrl("Assets/Textures/maki/marker.png");
URL ユーティリティ
import { objectToQuery, queryToObject, getExtensionFromUri, getBaseUri } from "cesium";

const qs = objectToQuery({ key1: "value 1", key2: ["x", "y"] });
// "key1=value%201&key2=x&key2=y"

const parsed = queryToObject("key1=value%201&key2=x&key2=y");
// { key1: "value 1", key2: ["x", "y"] }

getExtensionFromUri("https://example.com/model.glb?v=2"); // "glb"
getBaseUri("https://example.com/data/model.glb");          // "https://example.com/data/"
destroyObject

オブジェクトのすべてのメソッドを DeveloperError をスローする関数に置き換え、isDestroyed() が true を返すようにします。ネイティブリソースを保持するオブジェクトの標準的なクリーンアップパターンです。

import { destroyObject } from "cesium";

class MyWidget {
  constructor(viewer) {
    this._handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
  }
  isDestroyed() { return false; }
  destroy() {
    this._handler.destroy();
    return destroyObject(this);
  }
}

AssociativeArray

O(1) でキーを検索でき、レンダリングループ内でのアロケーションなしの反復処理に使える、常に最新の values 配列を備えています。

import { AssociativeArray } from "cesium";

const items = new AssociativeArray();
items.set("building-1", { height: 50 });
items.set("building-2", { height: 80 });

items.get("building-1");       // { height: 50 }
items.contains("building-1");  // true

// Iterate without per-frame allocations
const values = items.values;
for (let i = 0; i < values.length; i++) { /* process values[i] */ }

items.remove("building-1");
items.removeAll();

PinBuilder

色、テキスト、maki アイコン、カスタム画像を使ったマップピンのキャンバス要素を生成します。

import { PinBuilder, Color, Cartesian3, VerticalOrigin } from "cesium";

const pin = new PinBuilder();
const redPin = pin.fromColor(Color.RED, 48);                         // solid color
const textPin = pin.fromText("A", Color.BLUE, 48);                   // text label
const iconPin = await pin.fromMakiIconId("hospital", Color.GREEN, 48); // maki icon
const urlPin = await pin.fromUrl("/icons/custom.png", Color.YELLOW, 48);

// Named color constants work directly -- any PascalCase CSS color name is valid
viewer.entities.add({
  position: Cartesian3.fromDegrees(-75.17, 39.95),
  billboard: {
    image: pin.fromText("1", Color.ROYALBLUE, 48),
    verticalOrigin: VerticalOrigin.BOTTOM,
  },
});
viewer.entities.add({
  position: Cartesian3.fromDegrees(-73.78, 40.64),
  billboard: {
    image: pin.fromText("2", Color.FORESTGREEN, 48),
    verticalOrigin: VerticalOrigin.BOTTOM,
  },
});
viewer.entities.add({
  position: Cartesian3.fromDegrees(-118.41, 33.94),
  billboard: {
    image: pin.fromText("3", Color.CRIMSON, 48),
    verticalOrigin: VerticalOrigin.BOTTOM,
  },
});

DistanceDisplayCondition

カメラからの距離に基づいて、エンティティ/ビルボード/ラベルの表示を制御します。

import { DistanceDisplayCondition, Cartesian3, Color } from "cesium";

viewer.entities.add({
  position: Cartesian3.fromDegrees(-75.17, 39.95),
  billboard: {
    image: "/icons/marker.png",
    distanceDisplayCondition: new DistanceDisplayCondition(100.0, 50000.0),
  },
});

機能検出とフルスクリーン

import { FeatureDetection, Fullscreen } from "cesium";

if (FeatureDetection.supportsWebAssembly()) { /* WASM workers OK */ }
if (FeatureDetection.supportsTypedArrays()) { /* TypedArrays OK */ }

if (Fullscreen.supportsFullscreen()) {
  Fullscreen.requestFullscreen(viewer.container);
}

TaskProcessor

バックグラウンド処理用の Web Worker をラップします。Worker は、最初の scheduleTask 呼び出し時に遅延生成されます。

import { TaskProcessor, defined } from "cesium";

const processor = new TaskProcessor("myWorkerModule");
const promise = processor.scheduleTask({ data: largeArray, op: "simplify" });

if (!defined(promise)) {
  // Too many active tasks; retry next frame
} else {
  const result = await promise;
}
processor.destroy(); // release worker when done

TrustedServers

認証情報(Cookie、認証ヘッダー)は、登録済みサーバーにのみ送信されます。

import { TrustedServers } from "cesium";

TrustedServers.add("secure-tiles.example.com", 443);
TrustedServers.contains("https://secure-tiles.example.com/tileset.json"); // true
TrustedServers.remove("secure-tiles.example.com", 443);

パフォーマンスのヒント

  1. Resource インスタンスを再利用する -- getDerivedResource は、URL を再解析せずにプロキシ、ヘッダー、リトライ設定を継承します。
  2. HTTP/2 向けに RequestScheduler を調整する -- requestsByServer を使って maximumRequests とサーバーごとの上限を増やすと、タイルの読み込みが速くなります。
  3. デフォルト値には Frozen.EMPTY_OBJECT を使う -- 負荷の高い処理で、呼び出しのたびに新しい {} を割り当てずに済みます。
  4. 真偽値の判定には defined() を使う -- 0、""、false を null/undefined と正しく区別できます。
  5. レンダリングループでは AssociativeArray を使う -- values 配列を使うことで、フレームごとの Object.keys() の割り当てを回避できます。
  6. retryAttempts は控えめに設定する -- retryCallback で特定のステータスコード(401、429、503)に対してのみリトライするようにします。
  7. 使い終わったら TaskProcessors を破棄する -- アイドル状態のワーカーもメモリを消費します。
  8. 凍結された Color 定数を変更しない -- 先に .clone() または .withAlpha() を呼び出します。
  9. catch ブロックでは formatError を使う -- どのようなエラー型からも名前、メッセージ、スタックを抽出できます。
  10. PinBuilder の出力をキャッシュする -- 多数の同一のピンを複数フレームにわたって生成する場合は、キャンバスへの参照を保存します。

関連項目

  • cesiumjs-viewer-setup -- Viewer の初期化、Ion トークン、シーン構成
  • cesiumjs-imagery -- タイル取得に Resource を使用する画像プロバイダー
  • cesiumjs-entities -- Color、DistanceDisplayCondition、PinBuilder を使用する Entity API

コメント