diff --git a/build.py b/build.py index a2f90bdcbc..7533eb1d38 100755 --- a/build.py +++ b/build.py @@ -309,6 +309,7 @@ def examples_star_json(name, match): '../externs/bingmaps.js', '../externs/bootstrap.js', '../externs/geojson.js', + '../externs/oli.js', '../externs/proj4js.js', '../externs/tilejson.js', ], diff --git a/buildcfg/base.json b/buildcfg/base.json index 10924bb5e8..557581927e 100644 --- a/buildcfg/base.json +++ b/buildcfg/base.json @@ -42,6 +42,7 @@ "//json.js", "../externs/bingmaps.js", "../externs/geojson.js", + "../externs/oli.js", "../externs/proj4js.js", "../externs/tilejson.js" ], diff --git a/buildcfg/ol-all.json b/buildcfg/ol-all.json index 8b4f9dfa31..340936188c 100644 --- a/buildcfg/ol-all.json +++ b/buildcfg/ol-all.json @@ -7,6 +7,7 @@ "../build/src/external/externs/types.js", "../externs/bingmaps.js", "../externs/geojson.js", + "../externs/oli.js", "../externs/proj4js.js", "../externs/tilejson.js" ], diff --git a/buildcfg/ol-simple.json b/buildcfg/ol-simple.json index 3f2b82544e..c21ae1528e 100644 --- a/buildcfg/ol-simple.json +++ b/buildcfg/ol-simple.json @@ -16,6 +16,7 @@ "//json.js", "../externs/bingmaps.js", "../externs/geojson.js", + "../externs/oli.js", "../externs/proj4js.js", "../externs/tilejson.js" ], diff --git a/buildcfg/ol-whitespace.json b/buildcfg/ol-whitespace.json index 94089465b6..fb99f44cc3 100644 --- a/buildcfg/ol-whitespace.json +++ b/buildcfg/ol-whitespace.json @@ -17,6 +17,7 @@ "//json.js", "../externs/bingmaps.js", "../externs/geojson.js", + "../externs/oli.js", "../externs/proj4js.js", "../externs/tilejson.js" ], diff --git a/buildcfg/ol.json b/buildcfg/ol.json index 28f8d9c4ec..cb689bbddc 100644 --- a/buildcfg/ol.json +++ b/buildcfg/ol.json @@ -17,6 +17,7 @@ "../build/src/external/externs/types.js", "../externs/bingmaps.js", "../externs/geojson.js", + "../externs/oli.js", "../externs/proj4js.js", "../externs/tilejson.js" ], diff --git a/examples/custom-controls.html b/examples/custom-controls.html new file mode 100644 index 0000000000..257a02e3d9 --- /dev/null +++ b/examples/custom-controls.html @@ -0,0 +1,94 @@ + + + + + + + + + + + ol3 custom controls example + + + + + +
+ +
+
+
+
+
+ +
+
+

Custom controls

+

This example shows how to create custom controls.

+
+

+ This example creates a "zoom to extent" button. + See the custom-controls.js + source to see how this is done. + Per default, the zoom extent control use the map projection extent. +

+
+
+ custom, control +
+
+
+
+ + + + + + + diff --git a/examples/custom-controls.js b/examples/custom-controls.js new file mode 100644 index 0000000000..9ddadcc92d --- /dev/null +++ b/examples/custom-controls.js @@ -0,0 +1,109 @@ +goog.require('ol'); +goog.require('ol.Map'); +goog.require('ol.RendererHints'); +goog.require('ol.View2D'); +goog.require('ol.control.Control'); +goog.require('ol.control.defaults'); +goog.require('ol.layer.TileLayer'); +goog.require('ol.source.OSM'); + + +/** + * Define a namespace for the application. + */ +window.app = {}; +var app = window.app; + + +// +// Define zoom extent control. +// + + + +/** + * @constructor + * @extends {ol.control.Control} + * @param {Object=} opt_options Control options. + */ +app.ZoomExtentControl = function(opt_options) { + + var options = opt_options || {}; + this.extent_ = options.extent; + + var anchor = document.createElement('a'); + anchor.href = '#zoom-to'; + anchor.className = 'zoom-to'; + + var this_ = this; + var handleZoomTo = function(e) { + this_.handleZoomTo(e); + }; + + anchor.addEventListener('click', handleZoomTo, false); + anchor.addEventListener('touchstart', handleZoomTo, false); + + var element = document.createElement('div'); + element.className = 'zoom-extent ol-unselectable'; + element.appendChild(anchor); + + ol.control.Control.call(this, { + element: element, + map: options.map, + target: options.target + }); + +}; +ol.inherits(app.ZoomExtentControl, ol.control.Control); + + +/** + * @param {Event} e Browser event. + */ +app.ZoomExtentControl.prototype.handleZoomTo = function(e) { + // prevent #zoomTo anchor from getting appended to the url + e.preventDefault(); + + var map = this.getMap(); + var view = map.getView(); + view.fitExtent(this.extent_, map.getSize()); +}; + + +/** + * Overload setMap to use the view projection's validity extent + * if no extent was passed to the constructor. + * @param {ol.Map} map Map. + */ +app.ZoomExtentControl.prototype.setMap = function(map) { + ol.control.Control.prototype.setMap.call(this, map); + if (map && !this.extent_) { + this.extent_ = map.getView().getProjection().getExtent(); + } +}; + + +// +// Create map, giving it a zoom extent control. +// + + +var map = new ol.Map({ + controls: ol.control.defaults({}, [ + new app.ZoomExtentControl({ + extent: [813079.7791264898, 848966.9639063801, + 5929220.284081122, 5936863.986909639] + }) + ]), + layers: [ + new ol.layer.TileLayer({ + source: new ol.source.OSM() + }) + ], + renderers: ol.RendererHints.createFromQueryData(), + target: 'map', + view: new ol.View2D({ + center: [0, 0], + zoom: 2 + }) +}); diff --git a/externs/oli.js b/externs/oli.js new file mode 100644 index 0000000000..f6feed46c6 --- /dev/null +++ b/externs/oli.js @@ -0,0 +1,28 @@ +/** + * @externs + */ + + +/** + * @type {Object} + */ +var oli; + + +/** + * @interface + */ +oli.control.Control = function() {}; + + +/** + * @param {ol.MapEvent} mapEvent Map event. + */ +oli.control.Control.prototype.handleMapPostrender = function(mapEvent) {}; + + +/** + * @param {ol.Map} map Map. + * @return {undefined} Undefined. + */ +oli.control.Control.prototype.setMap = function(map) {}; diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index acf8dd4fb1..578a7f8b3c 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -123,6 +123,13 @@ * @property {Element|undefined} target Target. */ + /** + * @typedef {Object} ol.control.ControlOptions + * @property {Element|undefined} element Element. + * @property {ol.Map|undefined} map Map. + * @property {Element|undefined} target Target. + */ + /** * @typedef {Object} ol.control.DefaultsOptions * @property {boolean|undefined} attribution Attribution. diff --git a/src/ol/control/control.exports b/src/ol/control/control.exports new file mode 100644 index 0000000000..d44b62ce15 --- /dev/null +++ b/src/ol/control/control.exports @@ -0,0 +1,4 @@ +@exportClass ol.control.Control ol.control.ControlOptions +@exportProperty ol.control.Control.prototype.handleMapPostrender +@exportProperty ol.control.Control.prototype.getMap +@exportProperty ol.control.Control.prototype.setMap diff --git a/src/ol/control/control.js b/src/ol/control/control.js index 6ae418f8b7..e63ba7671a 100644 --- a/src/ol/control/control.js +++ b/src/ol/control/control.js @@ -1,5 +1,4 @@ goog.provide('ol.control.Control'); -goog.provide('ol.control.ControlOptions'); goog.require('goog.Disposable'); goog.require('goog.array'); @@ -8,14 +7,6 @@ goog.require('goog.events'); goog.require('ol.MapEventType'); -/** - * @typedef {{element: (Element|undefined), - * map: (ol.Map|undefined), - * target: (Element|undefined)}} - */ -ol.control.ControlOptions; - - /** * A thing which is painted over the map to provide a means for interaction @@ -23,6 +14,7 @@ ol.control.ControlOptions; * * @constructor * @extends {goog.Disposable} + * @implements {oli.control.Control} * @param {ol.control.ControlOptions} options Control options. */ ol.control.Control = function(options) { @@ -79,16 +71,18 @@ ol.control.Control.prototype.getMap = function() { /** + * Function called on each map render. Executes in a requestAnimationFrame + * callback. Can be implemented in sub-classes to re-render the control's + * UI. * @param {ol.MapEvent} mapEvent Map event. */ -ol.control.Control.prototype.handleMapPostrender = goog.nullFunction; +ol.control.Control.prototype.handleMapPostrender = function(mapEvent) {}; /** - * Removes the control from its current map and attaches it to the new map. - * Subtypes might also wish set up event handlers to get notified about changes - * to the map here. - * + * Remove the control from its current map and attach it to the new map. + * Subclasses may set up event handlers to get notified about changes to + * the map here. * @param {ol.Map} map Map. */ ol.control.Control.prototype.setMap = function(map) { @@ -104,7 +98,8 @@ ol.control.Control.prototype.setMap = function(map) { var target = goog.isDef(this.target_) ? this.target_ : map.getOverlayContainer(); goog.dom.appendChild(target, this.element); - if (this.handleMapPostrender !== goog.nullFunction) { + if (this.handleMapPostrender !== + ol.control.Control.prototype.handleMapPostrender) { this.listenerKeys.push(goog.events.listen(map, ol.MapEventType.POSTRENDER, this.handleMapPostrender, false, this)); } diff --git a/src/ol/ol.exports b/src/ol/ol.exports new file mode 100644 index 0000000000..e6371ba44b --- /dev/null +++ b/src/ol/ol.exports @@ -0,0 +1 @@ +@exportSymbol ol.inherits diff --git a/src/ol/ol.js b/src/ol/ol.js new file mode 100644 index 0000000000..d118ba330f --- /dev/null +++ b/src/ol/ol.js @@ -0,0 +1,14 @@ +goog.provide('ol'); + + +/** + * ol.inherits is an alias to the goog.inherits function. It is exported + * for use in non-compiled application code. See ol.exports. + * + * FIXME: We use a new line to fake the linter. Without the new line the + * linter complains with: + * + * "Missing newline between constructor and goog.inherits" + */ +ol.inherits = + goog.inherits;