Temporal Data - hiro-nyon/cesium-heatbox GitHub Wiki
Temporal Data / 時系列データ
日本語 | English
日本語
概要
Heatbox v1.2.0 では temporal オプションを指定するだけで Cesium の viewer.clock と自動連携し、時間帯ごとに異なるヒートマップを再生できます。TimeController が clock.onTick を監視し、エントリーが変わったタイミングでだけ setData() を呼び出すため、毎フレームの再計算や手動スロットリングは不要です。
オプション一覧
temporal.enabled— true で時間依存モードを有効化(updateOptionsでも切替可能)temporal.data—{ start, stop, data }の配列。dataには通常のsetData()と同じエンティティ配列を渡しますclassificationScope—'global'は全期間共通、'per-time'は時点ごとに統計量を再計算updateInterval—'frame'またはミリ秒値。値を大きくすると更新頻度を抑制outOfRangeBehavior—'hold'(既定)か'clear'。Clock が範囲外にいるときの表示制御overlapResolution—'prefer-earlier'(既定)/'prefer-later'/'skip'。時間帯が重なるデータの扱い
データ準備の手順
- 時刻の正規化: 生データの timestamp を ISO8601 または JulianDate に揃える
- スライス分割:
[{ start, stop, data: Cesium.Entity[] }]形式で配列化 - 重複対策: 時間が重なる場合は
overlapResolutionの方針(早い方/遅い方/エラー)を決める - Clock設定:
viewer.clock.startTime/stopTime/currentTimeをデータ範囲に合わせ、clockRange = Cesium.ClockRange.LOOP_STOPなどで挙動を定義
使用例
const slices = buildSlices(); // 24エントリーなど
const heatbox = new Heatbox(viewer, {
voxelSize: 40,
temporal: {
enabled: true,
data: slices,
classificationScope: 'global',
updateInterval: 200,
outOfRangeBehavior: 'clear',
overlapResolution: 'prefer-later'
}
});
viewer.clock.startTime = Cesium.JulianDate.fromIso8601(slices[0].start);
viewer.clock.stopTime = Cesium.JulianDate.fromIso8601(slices.at(-1).stop);
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 600;
viewer.clock.shouldAnimate = true;
ベストプラクティス
- データサイズ: 1スライスあたり 1,000〜2,000 エンティティを目安に調整(必要に応じて
maxRenderVoxelsで抑制) - スロットリング: ランダムアクセスが多い UI(スクラバー等)では
updateInterval: 0相当の'frame'を指定し、通常再生では 100〜250ms が推奨 - 統計スコープ: 時刻間の絶対比較をしたい場合は
'global'、その瞬間のコントラストを最大化したい場合は'per-time' - 監視:
heatbox.getStatistics()は従来どおり取得可能。_externalStatsを渡している場合でもclassification.domainはグローバル値で固定されます
English
Overview
Heatbox 1.2.0 ships with a built-in TimeController that synchronizes with viewer.clock. Provide ordered slices via the temporal option and Heatbox will automatically call setData() only when the active slice changes, eliminating manual onTick handlers and ad-hoc throttling.
Options
temporal.enabled— enable/disable temporal mode (can be toggled throughupdateOptions)temporal.data— array of{ start, stop, data }slices using Cesium entitiesclassificationScope—'global'shares statistics across the entire timeline,'per-time'recomputes per sliceupdateInterval—'frame'or a millisecond interval for throttlingoutOfRangeBehavior—'hold'(keep last frame) or'clear'overlapResolution—'prefer-earlier','prefer-later', or'skip'to control overlapping intervals
Preparation Checklist
- Normalize timestamps to ISO8601/JulianDate
- Chunk your entities per time window and store them as slices
- Decide how to resolve overlaps via
overlapResolution - Configure
viewer.clock(start/stop/current time, multiplier, loop range) to match your dataset
Example
const slices = buildSlices();
const heatbox = new Heatbox(viewer, {
voxelSize: 40,
temporal: {
enabled: true,
data: slices,
classificationScope: 'per-time',
updateInterval: 150,
outOfRangeBehavior: 'hold',
overlapResolution: 'prefer-earlier'
}
});
viewer.clock.startTime = Cesium.JulianDate.fromIso8601(slices[0].start);
viewer.clock.stopTime = Cesium.JulianDate.fromIso8601(slices.at(-1).stop);
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 900;
viewer.clock.shouldAnimate = true;
Tips
- Target ~1k entities per slice; rely on
maxRenderVoxelsandrenderLimitStrategyif your slices are heavier - Use
'frame'updates for scrubber-heavy UX, otherwise throttle with 100–250 ms - Toggle scopes via
heatbox.updateOptions({ temporal: { classificationScope: 'global' } })to reuse the same Heatbox instance - When
outOfRangeBehavior: 'clear', ensure your Cesium clock range eventually leaves the dataset to avoid stale overlays