Custom Animation

This example uses OpenLayers v4.0.1. The latest is v.

#### Custom Animation

Demonstrates how to animate features.

This example shows how to use postcompose and vectorContext to animate features. Here we choose to do a flash animation each time a feature is added to the layer.

Related API documentation:

- ol.Feature
,
- ol.Map
,
- ol.Observable
,
- ol.View
,
- ol.control
,
- ol.easing
,
- ol.geom.Point
,
- ol.layer.Tile
,
- ol.layer.Vector
,
- ol.proj
,
- ol.source.OSM
,
- ol.source.Vector
,
- ol.style.Circle
,
- ol.style.Stroke
,
- ol.style.Style

Copy Edit
Custom Animation Demonstrates how to animate features. var map = new ol.Map({ layers: [ new ol.layer.Tile({ source: new ol.source.OSM({ wrapX: false }) }) ], controls: ol.control.defaults({ attributionOptions: /** @type {olx.control.AttributionOptions} */ ({ collapsible: false }) }), target: 'map', view: new ol.View({ center: [0, 0], zoom: 1 }) }); var source = new ol.source.Vector({ wrapX: false }); var vector = new ol.layer.Vector({ source: source }); map.addLayer(vector); function addRandomFeature() { var x = Math.random() * 360 - 180; var y = Math.random() * 180 - 90; var geom = new ol.geom.Point(ol.proj.transform([x, y], 'EPSG:4326', 'EPSG:3857')); var feature = new ol.Feature(geom); source.addFeature(feature); } var duration = 3000; function flash(feature) { var start = new Date().getTime(); var listenerKey; function animate(event) { var vectorContext = event.vectorContext; var frameState = event.frameState; var flashGeom = feature.getGeometry().clone(); var elapsed = frameState.time - start; var elapsedRatio = elapsed / duration; // radius will be 5 at start and 30 at end. var radius = ol.easing.easeOut(elapsedRatio) * 25 + 5; var opacity = ol.easing.easeOut(1 - elapsedRatio); var style = new ol.style.Style({ image: new ol.style.Circle({ radius: radius, snapToPixel: false, stroke: new ol.style.Stroke({ color: 'rgba(255, 0, 0, ' + opacity + ')', width: 0.25 + opacity }) }) }); vectorContext.setStyle(style); vectorContext.drawGeometry(flashGeom); if (elapsed > duration) { ol.Observable.unByKey(listenerKey); return; } // tell OpenLayers to continue postcompose animation map.render(); } listenerKey = map.on('postcompose', animate); } source.on('addfeature', function(e) { flash(e.feature); }); window.setInterval(addRandomFeature, 1000); <div id="map" class="map"></div>

    <!DOCTYPE html>
    <html>
      <head>
        <title>Custom Animation</title>
        <link rel="stylesheet" href="https://openlayers.org/en/v4.0.1/css/ol.css" type="text/css">
        <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
        <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
        <script src="https://openlayers.org/en/v4.0.1/build/ol.js"></script>
      </head>
      <body>
        <div id="map" class="map"></div>
        <script>
          var map = new ol.Map({
            layers: [
              new ol.layer.Tile({
                source: new ol.source.OSM({
                  wrapX: false
                })
              })
            ],
            controls: ol.control.defaults({
              attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
                collapsible: false
              })
            }),
            target: 'map',
            view: new ol.View({
              center: [0, 0],
              zoom: 1
            })
          });

          var source = new ol.source.Vector({
            wrapX: false
          });
          var vector = new ol.layer.Vector({
            source: source
          });
          map.addLayer(vector);

          function addRandomFeature() {
            var x = Math.random() * 360 - 180;
            var y = Math.random() * 180 - 90;
            var geom = new ol.geom.Point(ol.proj.transform([x, y],
                'EPSG:4326', 'EPSG:3857'));
            var feature = new ol.Feature(geom);
            source.addFeature(feature);
          }

          var duration = 3000;
          function flash(feature) {
            var start = new Date().getTime();
            var listenerKey;

            function animate(event) {
              var vectorContext = event.vectorContext;
              var frameState = event.frameState;
              var flashGeom = feature.getGeometry().clone();
              var elapsed = frameState.time - start;
              var elapsedRatio = elapsed / duration;
              // radius will be 5 at start and 30 at end.
              var radius = ol.easing.easeOut(elapsedRatio) * 25 + 5;
              var opacity = ol.easing.easeOut(1 - elapsedRatio);

              var style = new ol.style.Style({
                image: new ol.style.Circle({
                  radius: radius,
                  snapToPixel: false,
                  stroke: new ol.style.Stroke({
                    color: 'rgba(255, 0, 0, ' + opacity + ')',
                    width: 0.25 + opacity
                  })
                })
              });

              vectorContext.setStyle(style);
              vectorContext.drawGeometry(flashGeom);
              if (elapsed > duration) {
                ol.Observable.unByKey(listenerKey);
                return;
              }
              // tell OpenLayers to continue postcompose animation
              map.render();
            }
            listenerKey = map.on('postcompose', animate);
          }

          source.on('addfeature', function(e) {
            flash(e.feature);
          });

          window.setInterval(addRandomFeature, 1000);
        </script>
      </body>
    </html>