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. 01通过 Resource 获取 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] 范围内的浮点数。包含 140 多个命名常量,作为冻结的静态属性,涵盖标准 CSS 颜色名称,采用 PascalCase 命名(例如,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(...) 或合适的高度构图,确保所有图钉都能轻松显示在视口内。如果有一个图钉位于边缘,请缩小或重新居中;即使所有实体都存在,三枚图钉中只看到两枚也属于视觉评估失败。

创建颜色
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 各处使用的发布-订阅机制。类会公开 Event 属性,例如 Viewer.selectedEntityChanged 和 Cesium3DTileset.tileLoad。

基本用法
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 的输出 —— 在多帧中生成许多相同图钉时,保存 canvas 引用。

另请参阅

  • cesiumjs-viewer-setup —— Viewer 初始化、Ion 令牌、场景配置
  • cesiumjs-imagery —— 使用 Resource 获取瓦片的影像提供程序
  • cesiumjs-entities —— 使用 Color、DistanceDisplayCondition 和 PinBuilder 的 Entity API

评论

支持 Markdown