agentleFS
GeoDaoyuGeoDaoyu/arcgis-maps-sdk-js-ai-context/skills/arcgis-time-animation/SKILL.md

arcgis-time-animation

Skill0 starsChanged 7 months agoMITView on GitHub

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.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill for temporal data, time-aware layers, time filtering, and animation controls.

    line 8
  2. Very specific:

    Null removes filter: Use view.timeExtent = null to show all data (no time filter).

    line 449

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ArcGIS Time Animation

Use this skill for temporal data, time-aware layers, time filtering, and animation controls.

Import Patterns

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 (dynamic import)

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

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;

TimeInterval

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

TimeSlider Component

arcgis-time-slider (Map Component)

<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 Widget (Core 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 Properties

PropertyTypeDefaultDescription
fullTimeExtentTimeExtent—Complete time range the widget can display
timeExtentTimeExtent—Currently selected time range
modestring"instant"Animation mode
stopsobject—Snap points for slider
playRatenumber1000Milliseconds between steps
loopbooleanfalseRestart at end
layoutstring"auto""auto", "compact", "wide"
disabledbooleanfalseDisable interaction

TimeSlider Modes

// 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";

Custom Stops

// 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
}

Playback Control

timeSlider.play();
timeSlider.stop();

Watch Time Changes

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"
});

Custom Labels

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",
    });
  },
});

Time-Aware Layers

FeatureLayer with Time

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 Properties

PropertyTypeDescription
startFieldstringStart date field name (required)
endFieldstringEnd date field name (optional)
fullTimeExtentTimeExtentComplete time range of data
intervalTimeIntervalSuggested animation interval
trackIdFieldstringTrack identifier field (for StreamLayer)

Other Time-Aware Layers

// 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,
  },
});

Initializing TimeSlider from Layer

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;
}

Filtering by Time

Client-Side Filter

// 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"),
  }),
};

Query with Time

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);

Animation Patterns

TimeSlider with Statistics

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;
});

Time-Based Highlighting

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);
});

Manual Animation Loop

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 Component

<arcgis-map>
  <arcgis-time-zone-label slot="bottom-left"></arcgis-time-zone-label>
</arcgis-map>

Graphics Visibility with Time

// Set time visibility on individual graphics
graphic.visibilityTimeExtent = new TimeExtent({
  start: new Date("2024-01-01"),
  end: new Date("2024-06-30"),
});

Common Pitfalls

  1. 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");
  2. Layer must be loaded: timeInfo is only available after await layer.load().
  3. TimeExtent not applied: The view's timeExtent must be set to filter all time-aware layers.
  4. Null removes filter: Use view.timeExtent = null to show all data (no time filter).
  5. Performance: Large time ranges can return many features — use server-side queries when possible.
  6. Stops required: TimeSlider needs stops configured to define slider positions.

Reference Samples

  • timeslider — Basic TimeSlider widget
  • timeslider-filter — Filtering data with TimeSlider
  • timeslider-component-filter — TimeSlider component with filtering
  • time-layer — Working with time-aware layers
  • widgets-timeslider — TimeSlider widget examples
  • widgets-timeslider-offset — TimeSlider with timezone offset
  • layers-scenelayer-time — Time-aware SceneLayer
  • layers-voxel-time — Time-aware VoxelLayer
  • layers-graphics-visibilitytimeextent — Graphics visibility with time

Related Skills

  • arcgis-imagery — Multidimensional imagery with time
  • arcgis-layers — Layer configuration
  • arcgis-widgets-ui — Widget placement and slots

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.