diff --git a/demos/full-screen/full-screen.js b/demos/full-screen/full-screen.js index e133624915..c0384a8be2 100644 --- a/demos/full-screen/full-screen.js +++ b/demos/full-screen/full-screen.js @@ -23,4 +23,7 @@ var map = new ol.Map(document.getElementById('map'), { layers: new ol.Collection([layer]), zoom: 2 }); -var zoom = new ol.control.Zoom(map, 4); +var zoom = new ol.control.Zoom({ + delta: 4, + map: map +}); diff --git a/demos/side-by-side/side-by-side.js b/demos/side-by-side/side-by-side.js index 9b953f41d2..6406ed9952 100644 --- a/demos/side-by-side/side-by-side.js +++ b/demos/side-by-side/side-by-side.js @@ -38,21 +38,26 @@ if (!goog.isNull(webglMap)) { webglMap.bindTo('rotation', domMap); } -var attributionControl = new ol.control.Attribution(domMap); -document.getElementById('attribution').appendChild( - attributionControl.getElement()); +var attributionControl = new ol.control.Attribution({ + map: domMap, + target: document.getElementById('attribution') +}); -var domMousePositionControl = new ol.control.MousePosition(domMap, - ol.Projection.getFromCode('EPSG:4326'), ol.CoordinateFormat.hdms, - ' '); -document.getElementById('domMousePosition').appendChild( - domMousePositionControl.getElement()); +var domMousePositionControl = new ol.control.MousePosition({ + coordinateFormat: ol.CoordinateFormat.hdms, + map: domMap, + projection: ol.Projection.getFromCode('EPSG:4326'), + target: document.getElementById('domMousePosition'), + undefinedHtml: ' ' +}); -var webglMousePositionControl = new ol.control.MousePosition(webglMap, - ol.Projection.getFromCode('EPSG:4326'), ol.CoordinateFormat.hdms, - ' '); -document.getElementById('webglMousePosition').appendChild( - webglMousePositionControl.getElement()); +var webglMousePositionControl = new ol.control.MousePosition({ + coordinateFormat: ol.CoordinateFormat.hdms, + map: webglMap, + projection: ol.Projection.getFromCode('EPSG:4326'), + target: document.getElementById('webglMousePosition'), + undefinedHtml: ' ' +}); var keyboardInteraction = new ol.interaction.Keyboard(); keyboardInteraction.addCallback('0', function() { diff --git a/demos/two-layers/two-layers.js b/demos/two-layers/two-layers.js index 2a17231f5f..54a0a662a4 100644 --- a/demos/two-layers/two-layers.js +++ b/demos/two-layers/two-layers.js @@ -39,6 +39,7 @@ domMap.bindTo('layers', webglMap); domMap.bindTo('resolution', webglMap); domMap.bindTo('rotation', webglMap); -var attributionControl = new ol.control.Attribution(webglMap); -document.getElementById('attribution').appendChild( - attributionControl.getElement()); +var attributionControl = new ol.control.Attribution({ + map: webglMap, + target: document.getElementById('attribution') +}); diff --git a/src/ol/control/attribution.js b/src/ol/control/attribution.js index 3df1dfff94..db8bac9370 100644 --- a/src/ol/control/attribution.js +++ b/src/ol/control/attribution.js @@ -4,6 +4,7 @@ // FIXME check clean-up code goog.provide('ol.control.Attribution'); +goog.provide('ol.control.AttributionOptions'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); @@ -19,21 +20,25 @@ goog.require('ol.control.Control'); goog.require('ol.layer.Layer'); +/** + * @typedef {{map: (ol.Map|undefined), + * target: (Element|undefined)}} + */ +ol.control.AttributionOptions; + + /** * @constructor * @extends {ol.control.Control} - * @param {ol.Map} map Map. + * @param {ol.control.AttributionOptions} attributionOptions Attribution + * options. */ -ol.control.Attribution = function(map) { +ol.control.Attribution = function(attributionOptions) { - goog.base(this, map); - - /** - * @private - * @type {Element} - */ - this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL); + var element = goog.dom.createDom(goog.dom.TagName.UL, { + 'class': 'ol-attribution' + }); /** * @private @@ -59,22 +64,17 @@ ol.control.Attribution = function(map) { */ this.coverageAreass_ = {}; - goog.events.listen( - map, ol.Object.getChangedEventType(ol.MapProperty.CENTER), - this.handleMapChanged, false, this); + /** + * @private + * @type {Array.} + */ + this.mapListenerKeys_ = null; - goog.events.listen( - map, ol.Object.getChangedEventType(ol.MapProperty.LAYERS), - this.handleMapLayersChanged, false, this); - - goog.events.listen(map, - ol.Object.getChangedEventType(ol.MapProperty.RESOLUTION), - this.handleMapChanged, false, this); - - goog.events.listen(map, ol.Object.getChangedEventType(ol.MapProperty.SIZE), - this.handleMapChanged, false, this); - - this.handleMapLayersChanged(); + goog.base(this, { + element: element, + map: attributionOptions.map, + target: attributionOptions.target + }); }; goog.inherits(ol.control.Attribution, ol.control.Control); @@ -145,7 +145,7 @@ ol.control.Attribution.prototype.createAttributionElementsForLayer_ = goog.style.showElement(attributionElement, false); } - goog.dom.appendChild(this.ulElement_, attributionElement); + goog.dom.appendChild(this.element, attributionElement); this.attributionElements_[attributionKey] = attributionElement; @@ -154,14 +154,6 @@ ol.control.Attribution.prototype.createAttributionElementsForLayer_ = }; -/** - * @inheritDoc - */ -ol.control.Attribution.prototype.getElement = function() { - return this.ulElement_; -}; - - /** * @param {ol.layer.Layer} layer Layer. * @param {ol.Extent} mapExtent Map extent. @@ -361,6 +353,35 @@ ol.control.Attribution.prototype.removeLayer = function(layer) { }; +/** + * @inheritDoc + */ +ol.control.Attribution.prototype.setMap = function(map) { + if (!goog.isNull(this.mapListenerKeys_)) { + goog.array.forEach(this.mapListenerKeys_, goog.events.unlistenByKey); + } + this.mapListenerKeys_ = null; + goog.base(this, 'setMap', map); + if (!goog.isNull(map)) { + this.mapListenerKeys_ = [ + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.CENTER), + this.handleMapChanged, false, this), + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.LAYERS), + this.handleMapLayersChanged, false, this), + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.RESOLUTION), + this.handleMapChanged, false, this), + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.SIZE), + this.handleMapChanged, false, this) + ]; + this.handleMapLayersChanged(); + } +}; + + /** * @param {ol.layer.Layer} layer Layer. * @param {boolean} mapIsDef Map is defined. diff --git a/src/ol/control/control.js b/src/ol/control/control.js index 83ca63706d..b974259b5d 100644 --- a/src/ol/control/control.js +++ b/src/ol/control/control.js @@ -1,38 +1,73 @@ goog.provide('ol.control.Control'); +goog.provide('ol.control.ControlOptions'); goog.require('goog.Disposable'); goog.require('ol.Map'); +/** + * @typedef {{element: (Element|undefined), + * map: (ol.Map|undefined), + * target: (Element|undefined)}} + */ +ol.control.ControlOptions; + + /** * @constructor * @extends {goog.Disposable} - * @param {ol.Map} map Map. + * @param {ol.control.ControlOptions} controlOptions Control options. */ -ol.control.Control = function(map) { +ol.control.Control = function(controlOptions) { goog.base(this); + /** + * @protected + * @type {Element} + */ + this.element = goog.isDef(controlOptions.element) ? + controlOptions.element : null; + + /** + * @private + * @type {Element|undefined} + */ + this.target_ = controlOptions.target; + /** * @private * @type {ol.Map} */ - this.map_ = map; + this.map_ = null; + + if (goog.isDef(controlOptions.map)) { + this.setMap(controlOptions.map); + } }; goog.inherits(ol.control.Control, goog.Disposable); -/** - * @return {Element} Element. - */ -ol.control.Control.prototype.getElement = goog.abstractMethod; - - /** * @return {ol.Map} Map. */ ol.control.Control.prototype.getMap = function() { return this.map_; }; + + +/** + * @param {ol.Map} map Map. + */ +ol.control.Control.prototype.setMap = function(map) { + if (!goog.isNull(this.map_)) { + goog.dom.removeNode(this.element); + } + this.map_ = map; + if (!goog.isNull(this.map_)) { + var target = goog.isDef(this.target_) ? this.target_ : map.getViewport(); + goog.dom.appendChild(target, this.element); + } +}; diff --git a/src/ol/control/mouseposition.js b/src/ol/control/mouseposition.js index fc8a570695..a60a9d9e16 100644 --- a/src/ol/control/mouseposition.js +++ b/src/ol/control/mouseposition.js @@ -1,53 +1,66 @@ // FIXME should listen on appropriate pane, once it is defined goog.provide('ol.control.MousePosition'); +goog.provide('ol.control.MousePositionOptions'); goog.require('goog.events'); goog.require('goog.events.EventType'); +goog.require('goog.style'); goog.require('ol.MapProperty'); goog.require('ol.Object'); +goog.require('ol.Pixel'); goog.require('ol.Projection'); goog.require('ol.TransformFunction'); goog.require('ol.control.Control'); +/** + * @typedef {{coordinateFormat: (ol.CoordinateFormatType|undefined), + * map: (ol.Map|undefined), + * projection: (ol.Projection|undefined), + * target: (Element|undefined), + * undefinedHtml: (string|undefined)}} + */ +ol.control.MousePositionOptions; + + /** * @constructor * @extends {ol.control.Control} - * @param {ol.Map} map Map. - * @param {ol.Projection=} opt_projection Projection. - * @param {ol.CoordinateFormatType=} opt_coordinateFormat Coordinate format. - * @param {string=} opt_undefinedHTML Undefined HTML. + * @param {ol.control.MousePositionOptions} mousePositionOptions Mouse position + * options. */ -ol.control.MousePosition = - function(map, opt_projection, opt_coordinateFormat, opt_undefinedHTML) { +ol.control.MousePosition = function(mousePositionOptions) { - goog.base(this, map); + var element = goog.dom.createDom(goog.dom.TagName.DIV, { + 'class': 'ol-mouse-position' + }); + + goog.base(this, { + element: element, + map: mousePositionOptions.map, + target: mousePositionOptions.target + }); /** * @private - * @type {Element} + * @type {ol.Projection|undefined} */ - this.divElement_ = goog.dom.createElement(goog.dom.TagName.DIV); - - /** - * @private - * @type {ol.Projection} - */ - this.projection_ = opt_projection || null; + this.projection_ = mousePositionOptions.projection; /** * @private * @type {ol.CoordinateFormatType|undefined} */ - this.coordinateFormat_ = opt_coordinateFormat; + this.coordinateFormat_ = mousePositionOptions.coordinateFormat; /** * @private * @type {string} */ - this.undefinedHTML_ = opt_undefinedHTML || ''; + this.undefinedHtml_ = goog.isDef(mousePositionOptions.undefinedHtml) ? + mousePositionOptions.undefinedHtml : ''; /** * @private @@ -55,15 +68,11 @@ ol.control.MousePosition = */ this.transform_ = ol.Projection.identityTransform; - goog.events.listen(map, - ol.Object.getChangedEventType(ol.MapProperty.PROJECTION), - this.handleMapProjectionChanged, false, this); - - goog.events.listen(map.getViewport(), goog.events.EventType.MOUSEMOVE, - this.handleMouseMove, false, this); - - goog.events.listen(map.getViewport(), goog.events.EventType.MOUSEOUT, - this.handleMouseOut, false, this); + /** + * @private + * @type {Array.} + */ + this.listenerKeys_ = []; this.handleMapProjectionChanged(); @@ -71,28 +80,20 @@ ol.control.MousePosition = goog.inherits(ol.control.MousePosition, ol.control.Control); -/** - * @inheritDoc - */ -ol.control.MousePosition.prototype.getElement = function() { - return this.divElement_; -}; - - /** * @protected */ ol.control.MousePosition.prototype.handleMapProjectionChanged = function() { var map = this.getMap(); var mapProjection = map.getProjection(); - if (!goog.isDef(mapProjection) || goog.isNull(this.projection_)) { + if (!goog.isDef(mapProjection) || !goog.isDef(this.projection_)) { this.transform_ = ol.Projection.identityTransform; } else { this.transform_ = ol.Projection.getTransform(mapProjection, this.projection_); } // FIXME should we instead re-calculate using the last known mouse position? - this.divElement_.innerHTML = this.undefinedHTML_; + this.element.innerHTML = this.undefinedHtml_; }; @@ -102,7 +103,9 @@ ol.control.MousePosition.prototype.handleMapProjectionChanged = function() { */ ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { var map = this.getMap(); - var pixel = new ol.Pixel(browserEvent.offsetX, browserEvent.offsetY); + var eventPosition = goog.style.getRelativePosition( + browserEvent, map.getViewport()); + var pixel = new ol.Pixel(eventPosition.x, eventPosition.y); var coordinate = map.getCoordinateFromPixel(pixel); var html; if (goog.isDef(coordinate)) { @@ -113,9 +116,9 @@ ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { html = coordinate.toString(); } } else { - html = this.undefinedHTML_; + html = this.undefinedHtml_; } - this.divElement_.innerHTML = html; + this.element.innerHTML = html; }; @@ -124,5 +127,29 @@ ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { * @protected */ ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) { - this.divElement_.innerHTML = this.undefinedHTML_; + this.element.innerHTML = this.undefinedHtml_; +}; + + +/** + * @inheritDoc + */ +ol.control.MousePosition.prototype.setMap = function(map) { + if (goog.isNull(this.listenerKeys_)) { + goog.array.forEach(this.listenerKeys_, goog.events.unlistenByKey); + } + this.listenerKeys_ = null; + goog.base(this, 'setMap', map); + if (!goog.isNull(map)) { + var viewport = map.getViewport(); + this.listenerKeys = [ + goog.events.listen(map, + ol.Object.getChangedEventType(ol.MapProperty.PROJECTION), + this.handleMapProjectionChanged, false, this), + goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE, + this.handleMouseMove, false, this), + goog.events.listen(viewport, goog.events.EventType.MOUSEOUT, + this.handleMouseOut, false, this) + ]; + } }; diff --git a/src/ol/control/zoom.js b/src/ol/control/zoom.js index 5c504d9668..5e9126093d 100644 --- a/src/ol/control/zoom.js +++ b/src/ol/control/zoom.js @@ -1,4 +1,5 @@ goog.provide('ol.control.Zoom'); +goog.provide('ol.control.ZoomOptions'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); @@ -8,67 +9,55 @@ goog.require('ol.Projection'); goog.require('ol.control.Control'); +/** + * @typedef {{delta: (number|undefined), + * map: (ol.Map|undefined), + * target: (Element|undefined)}} + */ +ol.control.ZoomOptions; + + /** * @constructor * @extends {ol.control.Control} - * @param {ol.Map} map Map. - * @param {number=} opt_zoomDelta Optional zoom delta. + * @param {ol.control.ZoomOptions} zoomOptions Zoom options. */ -ol.control.Zoom = function(map, opt_zoomDelta) { +ol.control.Zoom = function(zoomOptions) { - goog.base(this, map); + var inElement = goog.dom.createDom(goog.dom.TagName.A, { + 'href': '#zoomIn', + 'class': 'ol-zoom-in' + }, '+'); + goog.events.listen( + inElement, goog.events.EventType.CLICK, this.handleIn_, false, this); + + var outElement = goog.dom.createDom(goog.dom.TagName.A, { + 'href': '#zoomOut', + 'class': 'ol-zoom-out' + }, '\u2212'); + goog.events.listen( + outElement, goog.events.EventType.CLICK, this.handleOut_, false, this); + + var element = goog.dom.createDom( + goog.dom.TagName.DIV, 'ol-zoom', inElement, outElement); + + goog.base(this, { + element: element, + map: zoomOptions.map, + target: zoomOptions.target + }); /** * @type {number} * @private */ - this.zoomDelta_ = goog.isDef(opt_zoomDelta) ? opt_zoomDelta : 1; - - /** - * @type {Element} - * @private - */ - this.divElement_ = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-zoom'); - - /** - * @type {Element} - * @private - */ - this.inButton_ = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-zoom-in', - goog.dom.createDom(goog.dom.TagName.A, {'href': '#zoomIn'})); - - /** - * @type {Element} - * @private - */ - this.outButton_ = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-zoom-out', - goog.dom.createDom(goog.dom.TagName.A, {'href': '#zoomOut'})); - - goog.dom.setTextContent( - /** @type {Element} */ (this.inButton_.firstChild), '+'); - goog.dom.setTextContent( - /** @type {Element} */ (this.outButton_.firstChild), '\u2212'); - goog.dom.append(this.divElement_, this.inButton_, this.outButton_); - goog.dom.append(/** @type {!Node} */ (map.getViewport()), this.divElement_); - - goog.events.listen(this.inButton_, goog.events.EventType.CLICK, - this.handleIn_, false, this); - goog.events.listen(this.outButton_, goog.events.EventType.CLICK, - this.handleOut_, false, this); + this.delta_ = goog.isDef(zoomOptions.delta) ? zoomOptions.delta : 1; }; goog.inherits(ol.control.Zoom, ol.control.Control); -/** - * @inheritDoc - */ -ol.control.Zoom.prototype.getElement = function() { - return this.divElement_; -}; - - /** * @param {goog.events.BrowserEvent} browserEvent The browser event to handle. * @private @@ -76,7 +65,7 @@ ol.control.Zoom.prototype.getElement = function() { ol.control.Zoom.prototype.handleIn_ = function(browserEvent) { browserEvent.stopPropagation(); browserEvent.preventDefault(); - this.getMap().zoom(this.zoomDelta_); + this.getMap().zoom(this.delta_); }; @@ -87,17 +76,5 @@ ol.control.Zoom.prototype.handleIn_ = function(browserEvent) { ol.control.Zoom.prototype.handleOut_ = function(browserEvent) { browserEvent.stopPropagation(); browserEvent.preventDefault(); - this.getMap().zoom(-this.zoomDelta_); -}; - - -/** - * @inheritDoc - */ -ol.control.Zoom.prototype.disposeInternal = function() { - goog.dom.removeNode(this.divElement_); - delete this.inButton_; - delete this.outButton_; - delete this.divElement_; - goog.base(this, 'disposeInternal'); + this.getMap().zoom(-this.delta_); };