skills/arcgis-time-animation/SKILL.md
Work with temporal data using TimeSlider, TimeExtent, TimeInterval, and time-aware layers. Use for animating data over time, filtering by date ranges, and visualizing temporal patterns.
npx skillsauth add SaschaBrunnerCH/arcgis-maps-sdk-js-ai-context arcgis-time-animationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill for temporal data, time-aware layers, time filtering, and animation controls.
import TimeExtent from "@arcgis/core/TimeExtent.js";
import TimeInterval from "@arcgis/core/TimeInterval.js";
import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";
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");
Represents a time range with start and end dates.
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;
Represents a duration of time.
const interval = new TimeInterval({
value: 1,
unit: "months",
});
Supported units: milliseconds, seconds, minutes, hours, days, weeks, months, years, decades, centuries
<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>
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",
},
},
});
| Property | Type | Default | Description |
| ---------------- | ---------- | ----------- | ------------------------------------------ |
| fullTimeExtent | TimeExtent | — | Complete time range the widget can display |
| timeExtent | TimeExtent | — | Currently selected time range |
| mode | string | "instant" | Animation mode |
| stops | object | — | Snap points for slider |
| playRate | number | 1000 | Milliseconds between steps |
| loop | boolean | false | Restart at end |
| layout | string | "auto" | "auto", "compact", "wide" |
| disabled | boolean | false | Disable interaction |
// 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",
});
},
});
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);
}
| Property | Type | Description |
| ---------------- | ------------ | ---------------------------------------- |
| startField | string | Start date field name (required) |
| endField | string | End date field name (optional) |
| fullTimeExtent | TimeExtent | Complete time range of data |
| interval | TimeInterval | Suggested animation interval |
| trackIdField | string | Track identifier field (for 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,
},
});
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.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);
}
}
<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"),
});
Time zone issues: Dates are affected by JavaScript's local timezone — use UTC dates for consistency.
const date = new Date("2024-06-15T00:00:00Z");
Layer must be loaded: timeInfo is only available after await layer.load().
TimeExtent not applied: The view's timeExtent must be set to filter all time-aware layers.
Null removes filter: Use view.timeExtent = null to show all data (no time filter).
Performance: Large time ranges can return many features — use server-side queries when possible.
Stops required: TimeSlider needs stops configured to define slider positions.
timeslider — Basic TimeSlider widgettimeslider-filter — Filtering data with TimeSlidertimeslider-component-filter — TimeSlider component with filteringtime-layer — Working with time-aware layerswidgets-timeslider — TimeSlider widget exampleswidgets-timeslider-offset — TimeSlider with timezone offsetlayers-scenelayer-time — Time-aware SceneLayerlayers-voxel-time — Time-aware VoxelLayerlayers-graphics-visibilitytimeextent — Graphics visibility with timearcgis-imagery — Multidimensional imagery with timearcgis-layers — Layer configurationarcgis-widgets-ui — Widget placement and slotsdevelopment
Build map user interfaces with ArcGIS widgets, Map Components, and Calcite Design System. Use for adding legends, layer lists, search, tables, time sliders, and custom UI layouts.
development
Add specialized widgets including BuildingExplorer, FloorFilter, Track, Locate, HistogramRangeSlider, ScaleBar, Compass, NavigationToggle, and media viewers. Use for building exploration, indoor mapping, GPS tracking, and data histograms.
data-ai
Style and render geographic data with renderers, symbols, and visual variables. Use for creating thematic maps, heatmaps, class breaks, unique values, labels, and 3D visualization.
tools
Work with ArcGIS Utility Networks for modeling and analyzing connected infrastructure including network tracing, associations visualization, and topology validation. Use for electric, gas, water, and telecom network analysis.