Hide Table of Contents
View Geolocation with a temporal renderer sample in sandbox
Geolocation with a temporal renderer

Description

This sample uses the Geolocation API to find the users current position and update the location as it changes. The route the user travels is displayed on the map using a temporal renderer. The temporal renderer, new version 2.0 of the ArcGIS JavaScript API allows you to display data from a feature layer using time information.Since we need a feature layer to use the temporal renderer, we'll build one using the FeatureCollection option in the feature layer's constructor and add it to the map.

var featureCollection = {layerDefinition:layerDefinition,featureSet:null};
featureLayer = new FeatureLayer(featureCollection, {  mode: FeatureLayer.MODE_SNAPSHOT});
map.addLayer(featureLayer);

The temporal renderer allows you to define a set of renderers to display time-based data in interesting ways. The temporal renderer constructor takes an observation renderer, latestObservationRenderer, trackRenderer and ager. The observation renderer defines the symbology for the each observation.

var sms = new SimpleMarkerSymbol().setColor(new Color([255,0,0])).setSize(8);
var observationRenderer = new SimpleRenderer(sms);

The latest observation renderer defines the symbology for the latest observations, in this case the current location.

var latestObservationRenderer = new SimpleRenderer(featureLayer.defaultSymbol);

The track renderer is used to define the symbology for the line that connects the observations.

var trackRenderer = new SimpleRenderer(new SimpleLineSymbol());

The ager is used to determine how the symbology changes as it ages, in this snippet the fill color changes from red, to orange to yellow to null as the observation ages

var infos = [
  {
    minAge: 0,
    maxAge: 1,
    color: new Color([255, 0, 0])
  },
  {
    minAge: 1,
    maxAge: 5,
    color: new Color([255, 153, 0])
  },
  {
    minAge: 5,
    maxAge: 10,
    color: new Color([255, 204, 0])
  },
  {
    minAge: 10,
    maxAge: Infinity,
    color: new Color([0, 0, 0, 0])
  }
];
var ager = new TimeClassBreaksAger(infos, TimeClassBreaksAger.UNIT_MINUTES);

Code

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>Geolocate</title>

<link rel="stylesheet" href="https://js.arcgis.com/3.20/esri/css/esri.css">
<style>
  html, body {
    height: 100%;
    margin: 0px;
    padding: 0px;
    width: 100%;
  }

  #map {
    height: 100%;
    width: 100%;
  }
</style>

<script src="https://js.arcgis.com/3.20compact/"></script>
<script>
  require([
    "esri/Color",
    "esri/geometry/Point",
    "esri/geometry/webMercatorUtils",
    "esri/graphic",
    "esri/layers/FeatureLayer",
    "esri/map",
    "esri/renderers/SimpleRenderer",
    "esri/renderers/TemporalRenderer",
    "esri/renderers/TimeClassBreaksAger",
    "esri/symbols/SimpleLineSymbol",
    "esri/symbols/SimpleMarkerSymbol",
    "esri/TimeExtent",
    "dojo/domReady!"
  ], function (Color, Point, webMercatorUtils, Graphic, FeatureLayer, Map, SimpleRenderer, TemporalRenderer,
    TimeClassBreaksAger, SimpleLineSymbol, SimpleMarkerSymbol, TimeExtent){

    var map, featureLayer;
    var OBJECTID_COUNTER = 1000;
    var TRACKID_COUNTER = 1;
    //onorientationchange doesn't always fire in a timely manner in Android so check for both orientationchange and resize
    var supportsOrientationChange = "onorientationchange" in window, orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

    window.addEventListener(orientationEvent, function (){
      orientationChanged();
    }, false);

    map = new Map("map", {
      basemap: "streets"
    });
    map.on("load", mapLoadedHandler);

    function mapLoadedHandler(maploadEvent){
      console.log("map loaded", maploadEvent);

      //create a layer definition for the gps points
      var layerDefinition = {
        "objectIdField": "OBJECTID",
        "trackIdField": "TrackID",
        "geometryType": "esriGeometryPoint",
        "timeInfo": {
          "startTimeField": "DATETIME",
          "endTimeField": null,
          "timeExtent": [1277412330365],
          "timeInterval": 1,
          "timeIntervalUnits": "esriTimeUnitsMinutes"
        },
        "fields": [
          {
            "name": "OBJECTID",
            "type": "esriFieldTypeOID",
            "alias": "OBJECTID",
            "sqlType": "sqlTypeOther"
          },
          {
            "name": "TrackID",
            "type": "esriFieldTypeInteger",
            "alias": "TrackID"
          },
          {
            "name": "DATETIME",
            "type": "esriFieldTypeDate",
            "alias": "DATETIME"
          }
        ]
      };

      var featureCollection = {
        layerDefinition: layerDefinition,
        featureSet: null
      };
      featureLayer = new FeatureLayer(featureCollection);

      //setup a temporal renderer
      var sms = new SimpleMarkerSymbol().setColor(new Color([255, 0, 0])).setSize(8);
      var observationRenderer = new SimpleRenderer(sms);
      var latestObservationRenderer = new SimpleRenderer(new SimpleMarkerSymbol());
      var infos = [
        {
          minAge: 0,
          maxAge: 1,
          color: new Color([255, 0, 0])
        }, {
          minAge: 1,
          maxAge: 5,
          color: new Color([255, 153, 0])
        }, {
          minAge: 5,
          maxAge: 10,
          color: new Color([255, 204, 0])
        }, {
          minAge: 10,
          maxAge: Infinity,
          color: new Color([0, 0, 0, 0])
        }
      ];
      var ager = new TimeClassBreaksAger(infos, TimeClassBreaksAger.UNIT_MINUTES);
      var sls = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
        new Color([255, 0, 0]), 3);
      var trackRenderer = new SimpleRenderer(sls);
      var renderer = new TemporalRenderer(observationRenderer, latestObservationRenderer,
        trackRenderer, ager);
      featureLayer.setRenderer(renderer);
      map.addLayer(featureLayer);

      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(zoomToLocation, locationError);
        navigator.geolocation.watchPosition(showLocation, locationError);
      }
    }

    function locationError(error){
      switch (error.code) {
        case error.PERMISSION_DENIED:
          alert("Location not provided");
          break;

        case error.POSITION_UNAVAILABLE:
          alert("Current location not available");
          break;

        case error.TIMEOUT:
          alert("Timeout");
          break;

        default:
          alert("unknown error");
          break;
      }
    }

    function zoomToLocation(location){
      var pt = webMercatorUtils.geographicToWebMercator(new Point(location.coords.longitude,
        location.coords.latitude));
      map.centerAndZoom(pt, 16);
    }

    function showLocation(location){
      if (location.coords.accuracy <= 500) {
        var now = new Date();
        var attributes = {};
        attributes.OBJECTID = OBJECTID_COUNTER;
        attributes.DATETIME = now.getTime();
        attributes.TrackID = TRACKID_COUNTER;

        OBJECTID_COUNTER++;
        TRACKID_COUNTER++;

        var pt = webMercatorUtils.geographicToWebMercator(new Point(location.coords.longitude,
          location.coords.latitude));
        var graphic = new Graphic(new Point(pt, map.spatialReference), null, attributes);

        featureLayer.applyEdits([graphic], null, null, function (adds){
          map.setTimeExtent(new TimeExtent(null, new Date()));
          map.centerAt(graphic.geometry);
        });
      }
      else {
        console.warn("Point not added due to low accuracy: " + location.coords.accuracy);
      }
    }

    function orientationChanged(){
      if (map) {
        map.reposition();
        map.resize();
      }
    }

  });
</script>
</head>

<body>
  <div id="map"></div>
</body>
</html>