Custom Interactions

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

#### Custom Interactions

Example of a custom interaction.

This example demonstrates creating a custom interaction by subclassing `ol.interaction.Pointer`. Note that the built in interaction `ol.interaction.Translate` might be a better option for moving features.

Related API documentation:

- ol.Feature
,
- ol.Map
,
- ol.View
,
- ol.geom.LineString
,
- ol.geom.Point
,
- ol.geom.Polygon
,
- ol.interaction
,
- ol.interaction.Pointer
,
- ol.layer.Tile
,
- ol.layer.Vector
,
- ol.source.TileJSON
,
- ol.source.Vector
,
- ol.style.Fill
,
- ol.style.Icon
,
- ol.style.Stroke
,
- ol.style.Style

Copy Edit
Custom Interactions Example of a custom interaction. /** * Define a namespace for the application. */ var app = {}; /** * @constructor * @extends {ol.interaction.Pointer} */ app.Drag = function() { ol.interaction.Pointer.call(this, { handleDownEvent: app.Drag.prototype.handleDownEvent, handleDragEvent: app.Drag.prototype.handleDragEvent, handleMoveEvent: app.Drag.prototype.handleMoveEvent, handleUpEvent: app.Drag.prototype.handleUpEvent }); /** * @type {ol.Pixel} * @private */ this.coordinate_ = null; /** * @type {string|undefined} * @private */ this.cursor_ = 'pointer'; /** * @type {ol.Feature} * @private */ this.feature_ = null; /** * @type {string|undefined} * @private */ this.previousCursor_ = undefined; }; ol.inherits(app.Drag, ol.interaction.Pointer); /** * @param {ol.MapBrowserEvent} evt Map browser event. * @return {boolean} `true` to start the drag sequence. */ app.Drag.prototype.handleDownEvent = function(evt) { var map = evt.map; var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { return feature; }); if (feature) { this.coordinate_ = evt.coordinate; this.feature_ = feature; } return !!feature; }; /** * @param {ol.MapBrowserEvent} evt Map browser event. */ app.Drag.prototype.handleDragEvent = function(evt) { var deltaX = evt.coordinate[0] - this.coordinate_[0]; var deltaY = evt.coordinate[1] - this.coordinate_[1]; var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.feature_.getGeometry()); geometry.translate(deltaX, deltaY); this.coordinate_[0] = evt.coordinate[0]; this.coordinate_[1] = evt.coordinate[1]; }; /** * @param {ol.MapBrowserEvent} evt Event. */ app.Drag.prototype.handleMoveEvent = function(evt) { if (this.cursor_) { var map = evt.map; var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { return feature; }); var element = evt.map.getTargetElement(); if (feature) { if (element.style.cursor != this.cursor_) { this.previousCursor_ = element.style.cursor; element.style.cursor = this.cursor_; } } else if (this.previousCursor_ !== undefined) { element.style.cursor = this.previousCursor_; this.previousCursor_ = undefined; } } }; /** * @return {boolean} `false` to stop the drag sequence. */ app.Drag.prototype.handleUpEvent = function() { this.coordinate_ = null; this.feature_ = null; return false; }; var pointFeature = new ol.Feature(new ol.geom.Point([0, 0])); var lineFeature = new ol.Feature( new ol.geom.LineString([[-1e7, 1e6], [-1e6, 3e6]])); var polygonFeature = new ol.Feature( new ol.geom.Polygon([[[-3e6, -1e6], [-3e6, 1e6], [-1e6, 1e6], [-1e6, -1e6], [-3e6, -1e6]]])); var map = new ol.Map({ interactions: ol.interaction.defaults().extend([new app.Drag()]), layers: [ new ol.layer.Tile({ source: new ol.source.TileJSON({ url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure' }) }), new ol.layer.Vector({ source: new ol.source.Vector({ features: [pointFeature, lineFeature, polygonFeature] }), style: new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', opacity: 0.95, src: 'https://openlayers.org/en/v4.0.1/examples/data/icon.png' })), stroke: new ol.style.Stroke({ width: 3, color: [255, 0, 0, 1] }), fill: new ol.style.Fill({ color: [0, 0, 255, 0.6] }) }) }) ], target: 'map', view: new ol.View({ center: [0, 0], zoom: 2 }) }); <div id="map" class="map"></div>

    <!DOCTYPE html>
    <html>
      <head>
        <title>Custom Interactions</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>
          /**
           * Define a namespace for the application.
           */
          var app = {};

          /**
           * @constructor
           * @extends {ol.interaction.Pointer}
           */
          app.Drag = function() {

            ol.interaction.Pointer.call(this, {
              handleDownEvent: app.Drag.prototype.handleDownEvent,
              handleDragEvent: app.Drag.prototype.handleDragEvent,
              handleMoveEvent: app.Drag.prototype.handleMoveEvent,
              handleUpEvent: app.Drag.prototype.handleUpEvent
            });

            /**
             * @type {ol.Pixel}
             * @private
             */
            this.coordinate_ = null;

            /**
             * @type {string|undefined}
             * @private
             */
            this.cursor_ = 'pointer';

            /**
             * @type {ol.Feature}
             * @private
             */
            this.feature_ = null;

            /**
             * @type {string|undefined}
             * @private
             */
            this.previousCursor_ = undefined;

          };
          ol.inherits(app.Drag, ol.interaction.Pointer);

          /**
           * @param {ol.MapBrowserEvent} evt Map browser event.
           * @return {boolean} `true` to start the drag sequence.
           */
          app.Drag.prototype.handleDownEvent = function(evt) {
            var map = evt.map;

            var feature = map.forEachFeatureAtPixel(evt.pixel,
                function(feature) {
                  return feature;
                });

            if (feature) {
              this.coordinate_ = evt.coordinate;
              this.feature_ = feature;
            }

            return !!feature;
          };

          /**
           * @param {ol.MapBrowserEvent} evt Map browser event.
           */
          app.Drag.prototype.handleDragEvent = function(evt) {
            var deltaX = evt.coordinate[0] - this.coordinate_[0];
            var deltaY = evt.coordinate[1] - this.coordinate_[1];

            var geometry = /** @type {ol.geom.SimpleGeometry} */
                (this.feature_.getGeometry());
            geometry.translate(deltaX, deltaY);

            this.coordinate_[0] = evt.coordinate[0];
            this.coordinate_[1] = evt.coordinate[1];
          };

          /**
           * @param {ol.MapBrowserEvent} evt Event.
           */
          app.Drag.prototype.handleMoveEvent = function(evt) {
            if (this.cursor_) {
              var map = evt.map;
              var feature = map.forEachFeatureAtPixel(evt.pixel,
                  function(feature) {
                    return feature;
                  });
              var element = evt.map.getTargetElement();
              if (feature) {
                if (element.style.cursor != this.cursor_) {
                  this.previousCursor_ = element.style.cursor;
                  element.style.cursor = this.cursor_;
                }
              } else if (this.previousCursor_ !== undefined) {
                element.style.cursor = this.previousCursor_;
                this.previousCursor_ = undefined;
              }
            }
          };

          /**
           * @return {boolean} `false` to stop the drag sequence.
           */
          app.Drag.prototype.handleUpEvent = function() {
            this.coordinate_ = null;
            this.feature_ = null;
            return false;
          };

          var pointFeature = new ol.Feature(new ol.geom.Point([0, 0]));

          var lineFeature = new ol.Feature(
              new ol.geom.LineString([[-1e7, 1e6], [-1e6, 3e6]]));

          var polygonFeature = new ol.Feature(
              new ol.geom.Polygon([[[-3e6, -1e6], [-3e6, 1e6],
                  [-1e6, 1e6], [-1e6, -1e6], [-3e6, -1e6]]]));

          var map = new ol.Map({
            interactions: ol.interaction.defaults().extend([new app.Drag()]),
            layers: [
              new ol.layer.Tile({
                source: new ol.source.TileJSON({
                  url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure'
                })
              }),
              new ol.layer.Vector({
                source: new ol.source.Vector({
                  features: [pointFeature, lineFeature, polygonFeature]
                }),
                style: new ol.style.Style({
                  image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({
                    anchor: [0.5, 46],
                    anchorXUnits: 'fraction',
                    anchorYUnits: 'pixels',
                    opacity: 0.95,
                    src: 'https://openlayers.org/en/v4.0.1/examples/data/icon.png'
                  })),
                  stroke: new ol.style.Stroke({
                    width: 3,
                    color: [255, 0, 0, 1]
                  }),
                  fill: new ol.style.Fill({
                    color: [0, 0, 255, 0.6]
                  })
                })
              })
            ],
            target: 'map',
            view: new ol.View({
              center: [0, 0],
              zoom: 2
            })
          });
        </script>
      </body>
    </html>