关于 arcgis-time-animation
arcgis-time-animation 是面向使用 ArcGIS 构建时序地图的开发者技能,介绍如何通过 ArcGIS API for JavaScript 配置时间范围、筛选图层、使用 TimeSlider 控件及制作动画。
主要功能
- 01配置时间范围和间隔
- 02使用 TimeSlider 模式与播放控制
- 03筛选时序图层和查询
- 04监听时间变化并更新显示
- 05为时序数据制作动画
适用场景
- 01为 ArcGIS 地图添加时间滑块
- 02按日期范围筛选地图图层
- 03动态呈现时序数据的变化
- 04查询选定时段内的图层要素
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ saschabrunnerch/ arcgis-maps-sdk-js-ai-context --skill arcgis-time-animation安装后在 Claude Code 中输入/arcgis-time-animation确认已加载。
详细介绍
ArcGIS 时间动画
将此技能用于时序数据、时间感知图层、时间筛选和动画控件。
导入模式
ESM(npm)
import TimeExtent from "@arcgis/core/TimeExtent.js";
import TimeInterval from "@arcgis/core/TimeInterval.js";
import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";
CDN(动态导入)
const TimeExtent = await $arcgis.import("@arcgis/core/TimeExtent.js");
const TimeInterval = await $arcgis.import("@arcgis/core/TimeInterval.js");
const TimeSlider = await $arcgis.import("@arcgis/core/widgets/TimeSlider.js");
TimeExtent
表示具有开始和结束日期的时间范围。
const timeExtent = new TimeExtent({
start: new Date("2024-01-01"),
end: new Date("2024-12-31"),
});
// Apply to view (filters all time-aware layers)
view.timeExtent = timeExtent;
// Instant in time (start === end)
const instant = new TimeExtent({
start: new Date("2024-06-15"),
end: new Date("2024-06-15"),
});
// No time filter (show all data)
view.timeExtent = null;
TimeInterval
表示一段时间。
const interval = new TimeInterval({
value: 1,
unit: "months",
});
支持的单位: milliseconds、seconds、minutes、hours、days、weeks、months、years、decades、centuries
TimeSlider 组件
arcgis-time-slider(地图组件)
<arcgis-map item-id="YOUR_WEBMAP_ID">
<arcgis-time-slider slot="bottom-left" mode="time-window" loop time-visible>
</arcgis-time-slider>
</arcgis-map>
<script type="module">
const map = document.querySelector("arcgis-map");
const timeSlider = document.querySelector("arcgis-time-slider");
await map.viewOnReady();
// Configure from layer
const layer = map.view.map.layers.find((l) => l.timeInfo);
if (layer) {
await layer.load();
timeSlider.fullTimeExtent = layer.timeInfo.fullTimeExtent;
timeSlider.stops = { interval: layer.timeInfo.interval };
}
</script>
TimeSlider 微件(核心 API)
const timeSlider = new TimeSlider({
container: "timeSliderDiv",
view: view,
fullTimeExtent: {
start: new Date("2020-01-01"),
end: new Date("2024-12-31"),
},
timeExtent: {
start: new Date("2024-01-01"),
end: new Date("2024-03-31"),
},
mode: "time-window",
playRate: 1000,
loop: true,
stops: {
interval: {
value: 1,
unit: "months",
},
},
});
TimeSlider 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fullTimeExtent | TimeExtent | — | 微件可显示的完整时间范围 |
timeExtent | TimeExtent | — | 当前选定的时间范围 |
mode | string | "instant" | 动画模式 |
stops | object | — | 滑块的吸附点 |
playRate | number | 1000 | 步骤之间的毫秒数 |
loop | boolean | false | 到达末尾时重新开始 |
layout | string | "auto" | "auto"、"compact"、"wide" |
disabled | boolean | false | 禁用交互 |
TimeSlider 模式
// Instant - single point in time
mode: "instant";
// Time Window - range with start and end
mode: "time-window";
// Cumulative from Start - everything from start to current
mode: "cumulative-from-start";
// Cumulative from End - everything from current to end
mode: "cumulative-from-end";
自定义停止点
// Interval-based stops
stops: {
interval: { value: 1, unit: "weeks" }
}
// Specific dates
stops: {
dates: [
new Date("2024-01-01"),
new Date("2024-04-01"),
new Date("2024-07-01"),
new Date("2024-10-01")
]
}
// Number of evenly distributed stops
stops: {
count: 12
}
播放控制
timeSlider.play();
timeSlider.stop();
侦听时间变化
timeSlider.watch("timeExtent", (timeExtent) => {
console.log("New time range:", timeExtent.start, "to", timeExtent.end);
});
timeSlider.watch("viewModel.state", (state) => {
console.log("State:", state); // "ready", "playing", "disabled"
});
自定义标签
const timeSlider = new TimeSlider({
container: "timeSliderDiv",
view: view,
fullTimeExtent: { start, end },
tickConfigs: [
{
mode: "position",
values: [
new Date("2021-01-01"),
new Date("2022-01-01"),
new Date("2023-01-01"),
],
labelsVisible: true,
labelFormatFunction: (value) => value.getFullYear().toString(),
},
],
labelFormatFunction: (value, type, element, layout) => {
const date = new Date(value);
if (type === "min" || type === "max") {
return date.toLocaleDateString();
}
return date.toLocaleDateString("en-US", {
month: "short",
year: "numeric",
});
},
});
时间感知图层
带时间的 FeatureLayer
const featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
timeInfo: {
startField: "event_date",
endField: "end_date",
interval: {
value: 1,
unit: "days",
},
},
});
// Check if layer supports time
await featureLayer.load();
if (featureLayer.timeInfo) {
console.log("Time field:", featureLayer.timeInfo.startField);
console.log("Full extent:", featureLayer.timeInfo.fullTimeExtent);
}
TimeInfo 属性
| 属性 | 类型 | 说明 |
|---|---|---|
startField | string | 开始日期字段名称(必需) |
endField | string | 结束日期字段名称(可选) |
fullTimeExtent | TimeExtent | 数据的完整时间范围 |
interval | TimeInterval | 建议的动画间隔 |
trackIdField | string | 轨迹标识符字段(用于 StreamLayer) |
其他时间感知图层
// ImageryLayer
const imageryLayer = new ImageryLayer({
url: "...",
timeInfo: { startField: "acquisition_date" },
});
// MapImageLayer
const mapImageLayer = new MapImageLayer({
url: "...",
timeInfo: { startField: "date_field" },
});
// StreamLayer
const streamLayer = new StreamLayer({
url: "wss://services.arcgis.com/.../StreamServer",
timeInfo: {
trackIdField: "vehicle_id",
startField: "timestamp",
},
purgeOptions: {
displayCount: 1000,
age: 5,
},
});
从图层初始化 TimeSlider
async function setupTimeSlider(view, layer) {
await layer.load();
if (!layer.timeInfo) {
console.warn("Layer is not time-aware");
return null;
}
const timeSlider = new TimeSlider({
container: "timeSliderDiv",
view: view,
fullTimeExtent: layer.timeInfo.fullTimeExtent,
mode: "time-window",
playRate: 1000,
loop: true,
stops: {
interval: layer.timeInfo.interval || { value: 1, unit: "months" },
},
});
timeSlider.watch("timeExtent", (extent) => {
document.getElementById("currentTime").textContent =
`${extent.start.toLocaleDateString()} - ${extent.end.toLocaleDateString()}`;
});
return timeSlider;
}
按时间筛选
客户端筛选
// Filter all time-aware layers via view
view.timeExtent = new TimeExtent({
start: new Date("2024-01-01"),
end: new Date("2024-06-30"),
});
// Filter specific layer via layerView
const layerView = await view.whenLayerView(featureLayer);
layerView.filter = {
timeExtent: new TimeExtent({
start: new Date("2024-03-01"),
end: new Date("2024-03-31"),
}),
};
带时间的查询
const query = featureLayer.createQuery();
query.timeExtent = new TimeExtent({
start: new Date("2024-01-01"),
end: new Date("2024-12-31"),
});
query.where = "status = 'active'";
query.returnGeometry = true;
const results = await featureLayer.queryFeatures(query);
动画模式
带统计信息的 TimeSlider
timeSlider.watch("timeExtent", async (timeExtent) => {
const query = featureLayer.createQuery();
query.timeExtent = timeExtent;
query.outStatistics = [
{
statisticType: "count",
onStatisticField: "OBJECTID",
outStatisticFieldName: "count",
},
{
statisticType: "sum",
onStatisticField: "value",
outStatisticFieldName: "total",
},
];
const result = await featureLayer.queryFeatures(query);
const stats = result.features[0].attributes;
document.getElementById("count").textContent = stats.count;
document.getElementById("total").textContent = stats.total;
});
基于时间的高亮显示
let highlightHandle;
timeSlider.watch("timeExtent", async (timeExtent) => {
if (highlightHandle) highlightHandle.remove();
const query = featureLayer.createQuery();
query.timeExtent = timeExtent;
const layerView = await view.whenLayerView(featureLayer);
const results = await featureLayer.queryFeatures(query);
highlightHandle = layerView.highlight(results.features);
});
手动动画循环
async function animateOverTime(layer, startDate, endDate, intervalDays) {
const current = new Date(startDate);
while (current <= endDate) {
const nextDate = new Date(current);
nextDate.setDate(nextDate.getDate() + intervalDays);
view.timeExtent = new TimeExtent({
start: current,
end: nextDate,
});
await new Promise((resolve) => setTimeout(resolve, 500));
current.setDate(current.getDate() + intervalDays);
}
}
TimeZoneLabel 组件
<arcgis-map>
<arcgis-time-zone-label slot="bottom-left"></arcgis-time-zone-label>
</arcgis-map>
根据时间控制图形可见性
// Set time visibility on individual graphics
graphic.visibilityTimeExtent = new TimeExtent({
start: new Date("2024-01-01"),
end: new Date("2024-06-30"),
});
常见问题
-
时区问题:日期会受 JavaScript 本地时区影响;请使用 UTC 日期以保持一致。
const date = new Date("2024-06-15T00:00:00Z"); -
图层必须已加载:只有在执行
await layer.load()后,timeInfo才可用。 -
TimeExtent 未生效:必须设置视图的
timeExtent,才能筛选所有时间感知图层。 -
设为 null 可移除筛选:使用
view.timeExtent = null显示所有数据(不进行时间筛选)。 -
性能:较大的时间范围可能会返回大量要素;请尽可能使用服务器端查询。
-
必须设置停止点:TimeSlider 需要配置
stops来定义滑块位置。
参考示例
timeslider— 基本 TimeSlider 微件timeslider-filter— 使用 TimeSlider 筛选数据timeslider-component-filter— 带筛选功能的 TimeSlider 组件time-layer— 使用时间感知图层widgets-timeslider— TimeSlider 微件示例widgets-timeslider-offset— 带时区偏移的 TimeSliderlayers-scenelayer-time— 时间感知 SceneLayerlayers-voxel-time— 时间感知 VoxelLayerlayers-graphics-visibilitytimeextent— 根据时间控制图形可见性
相关技能
arcgis-imagery— 带时间的多维影像arcgis-layers— 图层配置arcgis-widgets-ui— 微件放置和插槽
评论
支持 Markdown