Arcgis Time Animation

by SaschaBrunnerCH

data

Work with temporal data using TimeSlider, TimeExtent, and time-aware layers. Use for animating data over time, filtering by date ranges, and visualizing temporal patterns.

Skill Details

Repository Files

1 file in this skill directory


name: arcgis-time-animation description: Work with temporal data using TimeSlider, TimeExtent, and time-aware layers. Use for animating data over time, filtering by date ranges, and visualizing temporal patterns.

ArcGIS Time Animation

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

TimeExtent

Represents a time range with start and end dates.

import TimeExtent from "@arcgis/core/TimeExtent.js";

// Create time extent
const timeExtent = new TimeExtent({
  start: new Date("2024-01-01"),
  end: new Date("2024-12-31")
});

// Apply to view
view.timeExtent = timeExtent;

TimeExtent Properties

const timeExtent = new TimeExtent({
  start: new Date("2024-01-01T00:00:00Z"),
  end: new Date("2024-06-30T23:59:59Z")
});

console.log(timeExtent.start);  // Date object
console.log(timeExtent.end);    // Date object

// Check if instant (start === end)
if (timeExtent.start.getTime() === timeExtent.end.getTime()) {
  console.log("This is a time instant");
}

Null TimeExtent

// No time filter (show all data)
view.timeExtent = null;

// Instant in time
const instant = new TimeExtent({
  start: new Date("2024-06-15"),
  end: new Date("2024-06-15")
});

TimeInterval

Represents a duration of time.

import TimeInterval from "@arcgis/core/TimeInterval.js";

const interval = new TimeInterval({
  value: 1,
  unit: "months"  // milliseconds, seconds, minutes, hours, days, weeks, months, years
});

TimeInterval Units

  • milliseconds
  • seconds
  • minutes
  • hours
  • days
  • weeks
  • months
  • years
  • decades
  • centuries

TimeSlider

Interactive widget for controlling temporal display.

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

import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";

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

TimeSlider with Playback

const timeSlider = new TimeSlider({
  container: "timeSliderDiv",
  view: view,
  mode: "time-window",  // instant, time-window, cumulative-from-start, cumulative-from-end
  fullTimeExtent: {
    start: new Date("2020-01-01"),
    end: new Date("2024-12-31")
  },
  playRate: 1000,  // Milliseconds between steps
  loop: true,
  stops: {
    interval: {
      value: 1,
      unit: "months"
    }
  }
});

// Start/stop playback
timeSlider.play();
timeSlider.stop();

TimeSlider Modes

// Instant - single point in time
const instantSlider = new TimeSlider({
  mode: "instant",
  fullTimeExtent: { start, end }
});

// Time Window - range with start and end
const windowSlider = new TimeSlider({
  mode: "time-window",
  fullTimeExtent: { start, end }
});

// Cumulative from Start - everything from start to current
const cumulativeStart = new TimeSlider({
  mode: "cumulative-from-start",
  fullTimeExtent: { start, end }
});

// Cumulative from End - everything from current to end
const cumulativeEnd = new TimeSlider({
  mode: "cumulative-from-end",
  fullTimeExtent: { start, end }
});

Custom Stops

// Interval-based stops
const timeSlider = new TimeSlider({
  stops: {
    interval: {
      value: 1,
      unit: "weeks"
    }
  }
});

// Specific dates
const timeSlider = new TimeSlider({
  stops: {
    dates: [
      new Date("2024-01-01"),
      new Date("2024-04-01"),
      new Date("2024-07-01"),
      new Date("2024-10-01")
    ]
  }
});

// Number of stops (evenly distributed)
const timeSlider = new TimeSlider({
  stops: {
    count: 12  // 12 evenly spaced stops
  }
});

TimeSlider Events

// Watch for time extent changes
timeSlider.watch("timeExtent", (timeExtent) => {
  console.log("New time extent:", timeExtent.start, "to", timeExtent.end);
  updateCharts(timeExtent);
});

// Watch for playback state
timeSlider.watch("viewModel.state", (state) => {
  console.log("State:", state);  // ready, playing, disabled
});

TimeSlider Configuration

const timeSlider = new TimeSlider({
  container: "timeSliderDiv",
  view: view,
  fullTimeExtent: {
    start: new Date("2020-01-01"),
    end: new Date("2024-12-31")
  },

  // Display options
  layout: "auto",  // auto, compact, wide
  tickConfigs: [{
    mode: "position",
    values: [
      new Date("2021-01-01"),
      new Date("2022-01-01"),
      new Date("2023-01-01"),
      new Date("2024-01-01")
    ],
    labelsVisible: true,
    labelFormatFunction: (value) => value.getFullYear().toString()
  }],

  // Behavior
  playRate: 2000,
  loop: true,

  // Labels
  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",  // Field containing date
    endField: "end_date",      // Optional end date field
    interval: {
      value: 1,
      unit: "days"
    }
  }
});

// Check if layer supports time
if (featureLayer.timeInfo) {
  console.log("Time field:", featureLayer.timeInfo.startField);
  console.log("Full extent:", featureLayer.timeInfo.fullTimeExtent);
}

TimeInfo Properties

const timeInfo = {
  startField: "start_time",           // Required: start date field
  endField: "end_time",               // Optional: end date field (for duration)
  fullTimeExtent: {                   // Data's full time range
    start: new Date("2020-01-01"),
    end: new Date("2024-12-31")
  },
  interval: {                         // Suggested animation interval
    value: 1,
    unit: "months"
  },
  useTime: true                       // Enable time filtering
};

ImageryLayer with Time

const imageryLayer = new ImageryLayer({
  url: "https://services.arcgis.com/.../ImageServer",
  timeInfo: {
    startField: "acquisition_date"
  }
});

// Multidimensional imagery
const multidimLayer = new ImageryLayer({
  url: "https://services.arcgis.com/.../ImageServer",
  multidimensionalDefinition: [{
    variableName: "temperature",
    dimensionName: "StdTime",
    values: [1609459200000]  // Epoch milliseconds
  }]
});

MapImageLayer with Time

const mapImageLayer = new MapImageLayer({
  url: "https://services.arcgis.com/.../MapServer",
  timeInfo: {
    startField: "date_field"
  }
});

StreamLayer with Time

const streamLayer = new StreamLayer({
  url: "wss://services.arcgis.com/.../StreamServer",
  timeInfo: {
    trackIdField: "vehicle_id",
    startField: "timestamp"
  },
  purgeOptions: {
    displayCount: 1000,
    age: 5  // Minutes to keep
  }
});

Initializing TimeSlider from Layer

// Auto-configure from time-aware layer
await featureLayer.load();

const timeSlider = new TimeSlider({
  container: "timeSliderDiv",
  view: view
});

// Initialize from layer's time info
TimeSlider.getPropertiesFromWebMap(webMap).then((properties) => {
  timeSlider.set(properties);
});

// Or manually from layer
if (featureLayer.timeInfo) {
  timeSlider.fullTimeExtent = featureLayer.timeInfo.fullTimeExtent;
  timeSlider.stops = {
    interval: featureLayer.timeInfo.interval
  };
}

TimeZoneLabel

Display time zone information.

TimeZoneLabel Component

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

TimeZoneLabel Widget (Core API) - Deprecated

DEPRECATED since 4.33: Use the arcgis-time-zone-label component shown above instead. For information on widget deprecation, see Esri's move to web components.

// DEPRECATED - Use arcgis-time-zone-label component instead
import TimeZoneLabel from "@arcgis/core/widgets/TimeZoneLabel.js";

const timeZoneLabel = new TimeZoneLabel({
  view: view
});

view.ui.add(timeZoneLabel, "bottom-left");

Filtering by Time

Client-Side Filter

// Apply time filter to view
view.timeExtent = new TimeExtent({
  start: new Date("2024-01-01"),
  end: new Date("2024-06-30")
});

// Filter specific layer
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

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

// Usage
animateOverTime(
  featureLayer,
  new Date("2024-01-01"),
  new Date("2024-12-31"),
  7  // Weekly intervals
);

TimeSlider with Statistics

// Update statistics panel as time changes
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;
});

Synchronized TimeSliders

// Sync multiple time sliders
const mainSlider = new TimeSlider({
  container: "mainSliderDiv",
  view: mainView
});

const compareSlider = new TimeSlider({
  container: "compareSliderDiv",
  view: compareView
});

// Sync them
mainSlider.watch("timeExtent", (timeExtent) => {
  compareSlider.timeExtent = timeExtent;
});

Historical Data Visualization

Track Lines

// Show movement paths with time
const featureLayer = new FeatureLayer({
  url: "https://.../tracks/FeatureServer/0",
  timeInfo: {
    startField: "timestamp",
    trackIdField: "vehicle_id"
  },
  renderer: {
    type: "simple",
    symbol: {
      type: "simple-line",
      color: "blue",
      width: 2
    }
  }
});

Age-Based Styling

// Style features based on age
const featureLayer = new FeatureLayer({
  url: "...",
  renderer: {
    type: "simple",
    symbol: { type: "simple-marker", size: 8 },
    visualVariables: [{
      type: "color",
      field: "timestamp",
      stops: [
        { value: Date.now() - 86400000, color: "red" },    // 1 day old
        { value: Date.now() - 604800000, color: "yellow" }, // 1 week old
        { value: Date.now() - 2592000000, color: "gray" }   // 30 days old
      ]
    }]
  }
});

Common Patterns

Full TimeSlider Setup

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

  // Update UI on time change
  timeSlider.watch("timeExtent", (extent) => {
    document.getElementById("currentTime").textContent =
      `${extent.start.toLocaleDateString()} - ${extent.end.toLocaleDateString()}`;
  });

  return timeSlider;
}

Time-Aware Query

async function queryByTimeRange(layer, startDate, endDate) {
  const query = layer.createQuery();
  query.timeExtent = new TimeExtent({
    start: startDate,
    end: endDate
  });
  query.outFields = ["*"];
  query.returnGeometry = true;

  return await layer.queryFeatures(query);
}

// Usage
const marchData = await queryByTimeRange(
  featureLayer,
  new Date("2024-03-01"),
  new Date("2024-03-31")
);

Time-Based Highlighting

// Highlight features from current time period
timeSlider.watch("timeExtent", async (timeExtent) => {
  // Clear previous highlights
  if (highlightHandle) {
    highlightHandle.remove();
  }

  // Query features in current time extent
  const query = featureLayer.createQuery();
  query.timeExtent = timeExtent;

  const layerView = await view.whenLayerView(featureLayer);
  const results = await featureLayer.queryFeatures(query);

  highlightHandle = layerView.highlight(results.features);
});

TypeScript Usage

Time configurations use autocasting. For TypeScript safety, use as const:

// Use 'as const' for time slider configuration
const timeSlider = new TimeSlider({
  view: view,
  mode: "time-window",
  stops: {
    interval: {
      value: 1,
      unit: "hours"
    }
  } as const
});

// For layer time settings
layer.timeInfo = {
  startField: "start_date",
  endField: "end_date",
  interval: {
    value: 1,
    unit: "days"
  }
} as const;

Tip: See arcgis-core-maps skill for detailed guidance on autocasting vs explicit classes.

Common Pitfalls

  1. Time Zone Issues: Dates are affected by time zones

    // Use UTC dates for consistency
    const date = new Date("2024-06-15T00:00:00Z");
    
    // Or specify timezone
    const localDate = new Date("2024-06-15T00:00:00-05:00");
    
  2. Layer Must Be Loaded: TimeInfo is only available after loading

    await layer.load();
    if (layer.timeInfo) {
      // Now timeInfo is available
    }
    
  3. TimeExtent Not Applied: View's timeExtent must be set

    // Set on view to filter all time-aware layers
    view.timeExtent = timeExtent;
    
    // Or on specific layerView for per-layer filtering
    layerView.filter = { timeExtent };
    
  4. Null vs Undefined: Use null to show all data

    // Show all data (no time filter)
    view.timeExtent = null;
    
  5. Performance: Large time ranges can be slow

    // Consider using time-based queries instead of filtering
    const query = layer.createQuery();
    query.timeExtent = smallerTimeRange;
    

Related Skills

Xlsx

Comprehensive spreadsheet creation, editing, and analysis with support for formulas, formatting, data analysis, and visualization. When Claude needs to work with spreadsheets (.xlsx, .xlsm, .csv, .tsv, etc) for: (1) Creating new spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modify existing spreadsheets while preserving formulas, (4) Data analysis and visualization in spreadsheets, or (5) Recalculating formulas

data

Clickhouse Io

ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.

datacli

Clickhouse Io

ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.

datacli

Analyzing Financial Statements

This skill calculates key financial ratios and metrics from financial statement data for investment analysis

data

Data Storytelling

Transform data into compelling narratives using visualization, context, and persuasive structure. Use when presenting analytics to stakeholders, creating data reports, or building executive presentations.

data

Kpi Dashboard Design

Design effective KPI dashboards with metrics selection, visualization best practices, and real-time monitoring patterns. Use when building business dashboards, selecting metrics, or designing data visualization layouts.

designdata

Dbt Transformation Patterns

Master dbt (data build tool) for analytics engineering with model organization, testing, documentation, and incremental strategies. Use when building data transformations, creating data models, or implementing analytics engineering best practices.

testingdocumenttool

Sql Optimization Patterns

Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.

designdata

Anndata

This skill should be used when working with annotated data matrices in Python, particularly for single-cell genomics analysis, managing experimental measurements with metadata, or handling large-scale biological datasets. Use when tasks involve AnnData objects, h5ad files, single-cell RNA-seq data, or integration with scanpy/scverse tools.

arttooldata

Xlsx

Spreadsheet toolkit (.xlsx/.csv). Create/edit with formulas/formatting, analyze data, visualization, recalculate formulas, for spreadsheet processing and analysis.

tooldata

Skill Information

Category:Data
Last Updated:1/5/2026