diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index 7eecf846d0..9f2c71999c 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -4,6 +4,26 @@ As last step in the removal of the dependency on Google Closure Library, the `goog.DEBUG` compiler define was renamed to `ol.DEBUG`. Please change accordingly in your custom build configuration json files. +#### Changes only relevant to those who compile their applications together with the Closure Compiler + +A number of internal types have been renamed. This will not affect those who use the API provided by the library, but if you are compiling your application together with OpenLayers and using type names, you'll need to do the following: + + * rename `ol.CollectionProperty` to `ol.Collection.Property` + * rename `ol.DeviceOrientationProperty` to `ol.DeviceOrientation.Property` + * rename `ol.GeolocationProperty` to `ol.Geolocation.Property` + * rename `ol.OverlayPositioning` to `ol.Overlay.Positioning` + * rename `ol.OverlayProperty` to `ol.Overlay.Property` + * rename `ol.control.MousePositionProperty` to `ol.control.MousePosition.Property` + * rename `ol.format.IGCZ` to `ol.format.IGC.Z` + * rename `ol.layer.GroupProperty` to `ol.layer.Group.Property` + * rename `ol.layer.HeatmapLayerProperty` to `ol.layer.Heatmap.Property` + * rename `ol.layer.VectorTileRenderType` to `ol.layer.VectorTile.RenderType` + * rename `ol.source.TileEvent` to `ol.source.Tile.Event` + * rename `ol.source.TileEventType` to `ol.source.Tile.EventType` + * rename `ol.source.WMTSRequestEncoding` to `ol.source.WMTS.RequestEncoding` + * rename `ol.style.IconAnchorUnits` to `ol.style.Icon.AnchorUnits` + * rename `ol.style.IconOrigin` to `ol.style.Icon.Origin` + ### v3.18.0 #### Changes in the way assertions are handled diff --git a/examples/osm-vector-tiles.js b/examples/osm-vector-tiles.js index 729b56b956..c3d80c195c 100644 --- a/examples/osm-vector-tiles.js +++ b/examples/osm-vector-tiles.js @@ -1,3 +1,4 @@ +goog.require('ol.Attribution'); goog.require('ol.Map'); goog.require('ol.View'); goog.require('ol.format.TopoJSON'); diff --git a/externs/oli.js b/externs/oli.js index 305b8fe033..0cc9e747b8 100644 --- a/externs/oli.js +++ b/externs/oli.js @@ -347,13 +347,13 @@ oli.source.RasterEvent.prototype.data; /** * @interface */ -oli.source.TileEvent = function() {}; +oli.source.Tile.Event = function() {}; /** * @type {ol.Tile} */ -oli.source.TileEvent.prototype.tile; +oli.source.Tile.Event.prototype.tile; /** diff --git a/externs/olx.js b/externs/olx.js index d79dccccfb..62d4e6f2d7 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -308,7 +308,7 @@ olx.MapOptions.prototype.view; * element: (Element|undefined), * offset: (Array.|undefined), * position: (ol.Coordinate|undefined), - * positioning: (ol.OverlayPositioning|string|undefined), + * positioning: (ol.Overlay.Positioning|string|undefined), * stopEvent: (boolean|undefined), * insertFirst: (boolean|undefined), * autoPan: (boolean|undefined), @@ -359,7 +359,7 @@ olx.OverlayOptions.prototype.position; * property. Possible values are `'bottom-left'`, `'bottom-center'`, * `'bottom-right'`, `'center-left'`, `'center-center'`, `'center-right'`, * `'top-left'`, `'top-center'`, and `'top-right'`. Default is `'top-left'`. - * @type {ol.OverlayPositioning|string|undefined} + * @type {ol.Overlay.Positioning|string|undefined} * @api stable */ olx.OverlayOptions.prototype.positioning; @@ -1791,7 +1791,7 @@ olx.format.TopoJSONOptions.prototype.defaultDataProjection; /** - * @typedef {{altitudeMode: (ol.format.IGCZ|undefined)}} + * @typedef {{altitudeMode: (ol.format.IGC.Z|undefined)}} */ olx.format.IGCOptions; @@ -1799,7 +1799,7 @@ olx.format.IGCOptions; /** * Altitude mode. Possible values are `barometric`, `gps`, and `none`. Default * is `none`. - * @type {ol.format.IGCZ|undefined} + * @type {ol.format.IGC.Z|undefined} * @api */ olx.format.IGCOptions.prototype.altitudeMode; @@ -2722,7 +2722,7 @@ olx.interaction.ExtentOptions; olx.interaction.ExtentOptions.prototype.extent; /** - * Style for the drawn extent box. + * Style for the drawn extent box. * Defaults to ol.style.Style.createDefaultEditing()[ol.geom.GeometryType.POLYGON] * @type {ol.style.Style|Array.|ol.StyleFunction|undefined} * @api @@ -2730,7 +2730,7 @@ olx.interaction.ExtentOptions.prototype.extent; olx.interaction.ExtentOptions.prototype.boxStyle; /** - * Style for the cursor used to draw the extent. + * Style for the cursor used to draw the extent. * Defaults to ol.style.Style.createDefaultEditing()[ol.geom.GeometryType.POINT] * @type {ol.style.Style|Array.|ol.StyleFunction|undefined} * @api @@ -2738,7 +2738,7 @@ olx.interaction.ExtentOptions.prototype.boxStyle; olx.interaction.ExtentOptions.prototype.pointerStyle; /** - * Wrap the drawn extent across multiple maps in the X direction? + * Wrap the drawn extent across multiple maps in the X direction? * Only affects visuals, not functionality. Defaults to false. * @type {boolean|undefined} * @api @@ -3823,7 +3823,7 @@ olx.layer.VectorOptions.prototype.visible; * maxResolution: (number|undefined), * opacity: (number|undefined), * renderBuffer: (number|undefined), - * renderMode: (ol.layer.VectorTileRenderType|string|undefined), + * renderMode: (ol.layer.VectorTile.RenderType|string|undefined), * renderOrder: (function(ol.Feature, ol.Feature):number|undefined), * source: (ol.source.VectorTile|undefined), * style: (ol.style.Style|Array.|ol.StyleFunction|undefined), @@ -3858,7 +3858,7 @@ olx.layer.VectorTileOptions.prototype.renderBuffer; * * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering * even during animations, but slower performance than the other options. * The default is `'hybrid'`. - * @type {ol.layer.VectorTileRenderType|string|undefined} + * @type {ol.layer.VectorTile.RenderType|string|undefined} * @api */ olx.layer.VectorTileOptions.prototype.renderMode; @@ -5985,7 +5985,7 @@ olx.source.VectorOptions.prototype.wrapX; * tileGrid: ol.tilegrid.WMTS, * projection: ol.ProjectionLike, * reprojectionErrorThreshold: (number|undefined), - * requestEncoding: (ol.source.WMTSRequestEncoding|string|undefined), + * requestEncoding: (ol.source.WMTS.RequestEncoding|string|undefined), * layer: string, * style: string, * tilePixelRatio: (number|undefined), @@ -6067,7 +6067,7 @@ olx.source.WMTSOptions.prototype.reprojectionErrorThreshold; /** * Request encoding. Default is `KVP`. - * @type {ol.source.WMTSRequestEncoding|string|undefined} + * @type {ol.source.WMTS.RequestEncoding|string|undefined} * @api stable */ olx.source.WMTSOptions.prototype.requestEncoding; @@ -6636,14 +6636,14 @@ olx.style.FillOptions.prototype.color; /** * @typedef {{anchor: (Array.|undefined), - * anchorOrigin: (ol.style.IconOrigin|undefined), - * anchorXUnits: (ol.style.IconAnchorUnits|undefined), - * anchorYUnits: (ol.style.IconAnchorUnits|undefined), + * anchorOrigin: (ol.style.Icon.Origin|undefined), + * anchorXUnits: (ol.style.Icon.AnchorUnits|undefined), + * anchorYUnits: (ol.style.Icon.AnchorUnits|undefined), * color: (ol.Color|string|undefined), * crossOrigin: (null|string|undefined), * img: (Image|HTMLCanvasElement|undefined), * offset: (Array.|undefined), - * offsetOrigin: (ol.style.IconOrigin|undefined), + * offsetOrigin: (ol.style.Icon.Origin|undefined), * opacity: (number|undefined), * scale: (number|undefined), * snapToPixel: (boolean|undefined), @@ -6667,7 +6667,7 @@ olx.style.IconOptions.prototype.anchor; /** * Origin of the anchor: `bottom-left`, `bottom-right`, `top-left` or * `top-right`. Default is `top-left`. - * @type {ol.style.IconOrigin|undefined} + * @type {ol.style.Icon.Origin|undefined} * @api */ olx.style.IconOptions.prototype.anchorOrigin; @@ -6677,7 +6677,7 @@ olx.style.IconOptions.prototype.anchorOrigin; * Units in which the anchor x value is specified. A value of `'fraction'` * indicates the x value is a fraction of the icon. A value of `'pixels'` * indicates the x value in pixels. Default is `'fraction'`. - * @type {ol.style.IconAnchorUnits|undefined} + * @type {ol.style.Icon.AnchorUnits|undefined} * @api */ olx.style.IconOptions.prototype.anchorXUnits; @@ -6687,7 +6687,7 @@ olx.style.IconOptions.prototype.anchorXUnits; * Units in which the anchor y value is specified. A value of `'fraction'` * indicates the y value is a fraction of the icon. A value of `'pixels'` * indicates the y value in pixels. Default is `'fraction'`. - * @type {ol.style.IconAnchorUnits|undefined} + * @type {ol.style.Icon.AnchorUnits|undefined} * @api */ olx.style.IconOptions.prototype.anchorYUnits; @@ -6736,7 +6736,7 @@ olx.style.IconOptions.prototype.offset; /** * Origin of the offset: `bottom-left`, `bottom-right`, `top-left` or * `top-right`. Default is `top-left`. - * @type {ol.style.IconOrigin|undefined} + * @type {ol.style.Icon.Origin|undefined} * @api */ olx.style.IconOptions.prototype.offsetOrigin; diff --git a/package.json b/package.json index 233cacf588..7a3d16a485 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "debounce": "^1.0.0", "eslint": "3.4.0", "eslint-config-openlayers": "5.0.0", - "eslint-plugin-openlayers-internal": "2.1.0", + "eslint-plugin-openlayers-internal": "2.2.0", "expect.js": "0.3.1", "gaze": "^1.0.0", "istanbul": "0.4.5", diff --git a/rules/no-missing-requires.js b/rules/no-missing-requires.js index e0ef07dda4..651529126f 100644 --- a/rules/no-missing-requires.js +++ b/rules/no-missing-requires.js @@ -9,8 +9,9 @@ const util = require('./util'); * if so, require the "namespace" (ol.foo) * 2. check if a name looks like a class (ol.foo.Bar or ol.foo.XYZ) * if so, require the class (ol.foo.Bar) - * 3. otherwise, lop off the last part of a name and require the rest - * (e.g. ol.foo.bar would require ol.foo) + * 3. otherwise, unless it's an external dependency (ol.ext.*), lop off the last + * part of a name and require the rest (e.g. ol.foo.bar would require ol.foo, + * but ol.ext.foo would require ol.ext.foo) */ const CONST_RE = /^(ol(\.[a-z]\w*)*)\.[A-Z]+_([_A-Z])+$/; @@ -76,7 +77,10 @@ exports.rule = { } // otherwise, assume the object should be required const parts = name.split('.'); - parts.pop(); + if (parts[1] !== 'ext') { + // unless it's an ol.ext.* + parts.pop(); + } const objectName = parts.join('.'); if (!defined[objectName]) { context.report(expression, `Missing goog.require('${objectName}')`); diff --git a/rules/package.json b/rules/package.json index bdd4291e0e..83d07489d8 100644 --- a/rules/package.json +++ b/rules/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-openlayers-internal", - "version": "2.1.0", + "version": "2.2.0", "description": "Custom ESLint rules for the OpenLayers project", "main": "index.js", "repository": { diff --git a/src/ol/collection.js b/src/ol/collection.js index 27de4deb00..6132df8ab8 100644 --- a/src/ol/collection.js +++ b/src/ol/collection.js @@ -10,14 +10,6 @@ goog.require('ol.events.Event'); goog.require('ol.Object'); -/** - * @enum {string} - */ -ol.CollectionProperty = { - LENGTH: 'length' -}; - - /** * @classdesc * An expanded version of standard JS Array, adding convenience methods for @@ -121,7 +113,7 @@ ol.Collection.prototype.item = function(index) { * @api stable */ ol.Collection.prototype.getLength = function() { - return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH)); + return /** @type {number} */ (this.get(ol.Collection.Property.LENGTH)); }; @@ -227,7 +219,15 @@ ol.Collection.prototype.setAt = function(index, elem) { * @private */ ol.Collection.prototype.updateLength_ = function() { - this.set(ol.CollectionProperty.LENGTH, this.array_.length); + this.set(ol.Collection.Property.LENGTH, this.array_.length); +}; + + +/** + * @enum {string} + */ +ol.Collection.Property = { + LENGTH: 'length' }; diff --git a/src/ol/color.js b/src/ol/color.js index 2808b0156c..9381d7e150 100644 --- a/src/ol/color.js +++ b/src/ol/color.js @@ -11,7 +11,7 @@ goog.require('ol.math'); * @type {RegExp} * @private */ -ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; +ol.color.HEX_COLOR_RE_ = /^#(?:[0-9a-f]{3}){1,2}$/i; /** @@ -20,7 +20,7 @@ ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; * @type {RegExp} * @private */ -ol.color.rgbColorRe_ = +ol.color.RGB_COLOR_RE_ = /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; @@ -30,7 +30,7 @@ ol.color.rgbColorRe_ = * @type {RegExp} * @private */ -ol.color.rgbaColorRe_ = +ol.color.RGBA_COLOR_RE_ = /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i; @@ -40,7 +40,7 @@ ol.color.rgbaColorRe_ = * @type {RegExp} * @private */ -ol.color.namedColorRe_ = +ol.color.NAMED_COLOR_RE_ = /^([a-z]*)$/i; @@ -154,11 +154,11 @@ ol.color.fromString = ( ol.color.fromStringInternal_ = function(s) { var r, g, b, a, color, match; - if (ol.color.namedColorRe_.exec(s)) { + if (ol.color.NAMED_COLOR_RE_.exec(s)) { s = ol.color.fromNamed(s); } - if (ol.color.hexColorRe_.exec(s)) { // hex + if (ol.color.HEX_COLOR_RE_.exec(s)) { // hex var n = s.length - 1; // number of hex digits ol.asserts.assert(n == 3 || n == 6, 54); // Hex color should have 3 or 6 digits var d = n == 3 ? 1 : 2; // number of digits per channel @@ -172,13 +172,13 @@ ol.color.fromStringInternal_ = function(s) { } a = 1; color = [r, g, b, a]; - } else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba() + } else if ((match = ol.color.RGBA_COLOR_RE_.exec(s))) { // rgba() r = Number(match[1]); g = Number(match[2]); b = Number(match[3]); a = Number(match[4]); color = ol.color.normalize([r, g, b, a]); - } else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb() + } else if ((match = ol.color.RGB_COLOR_RE_.exec(s))) { // rgb() r = Number(match[1]); g = Number(match[2]); b = Number(match[3]); diff --git a/src/ol/control/fullscreen.js b/src/ol/control/fullscreen.js index dfb3053778..f48eedf4ab 100644 --- a/src/ol/control/fullscreen.js +++ b/src/ol/control/fullscreen.js @@ -1,11 +1,11 @@ goog.provide('ol.control.FullScreen'); -goog.require('ol.events'); -goog.require('ol.events.EventType'); goog.require('ol'); goog.require('ol.control.Control'); -goog.require('ol.dom'); goog.require('ol.css'); +goog.require('ol.dom'); +goog.require('ol.events'); +goog.require('ol.events.EventType'); /** @@ -158,9 +158,10 @@ ol.control.FullScreen.prototype.handleFullScreenChange_ = function() { * @api stable */ ol.control.FullScreen.prototype.setMap = function(map) { + var global = ol.global; ol.control.Control.prototype.setMap.call(this, map); if (map) { - this.listenerKeys.push(ol.events.listen(ol.global.document, + this.listenerKeys.push(ol.events.listen(global.document, ol.control.FullScreen.getChangeType_(), this.handleFullScreenChange_, this) ); diff --git a/src/ol/control/mouseposition.js b/src/ol/control/mouseposition.js index 143db4b553..1e7658e20b 100644 --- a/src/ol/control/mouseposition.js +++ b/src/ol/control/mouseposition.js @@ -10,15 +10,6 @@ goog.require('ol.control.Control'); goog.require('ol.proj'); -/** - * @enum {string} - */ -ol.control.MousePositionProperty = { - PROJECTION: 'projection', - COORDINATE_FORMAT: 'coordinateFormat' -}; - - /** * @classdesc * A control to show the 2D coordinates of the mouse cursor. By default, these @@ -49,7 +40,7 @@ ol.control.MousePosition = function(opt_options) { }); ol.events.listen(this, - ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION), + ol.Object.getChangeEventType(ol.control.MousePosition.Property.PROJECTION), this.handleProjectionChanged_, this); if (options.coordinateFormat) { @@ -131,7 +122,7 @@ ol.control.MousePosition.prototype.handleProjectionChanged_ = function() { */ ol.control.MousePosition.prototype.getCoordinateFormat = function() { return /** @type {ol.CoordinateFormatType|undefined} */ ( - this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT)); + this.get(ol.control.MousePosition.Property.COORDINATE_FORMAT)); }; @@ -144,7 +135,7 @@ ol.control.MousePosition.prototype.getCoordinateFormat = function() { */ ol.control.MousePosition.prototype.getProjection = function() { return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.control.MousePositionProperty.PROJECTION)); + this.get(ol.control.MousePosition.Property.PROJECTION)); }; @@ -195,7 +186,7 @@ ol.control.MousePosition.prototype.setMap = function(map) { * @api stable */ ol.control.MousePosition.prototype.setCoordinateFormat = function(format) { - this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format); + this.set(ol.control.MousePosition.Property.COORDINATE_FORMAT, format); }; @@ -207,7 +198,7 @@ ol.control.MousePosition.prototype.setCoordinateFormat = function(format) { * @api stable */ ol.control.MousePosition.prototype.setProjection = function(projection) { - this.set(ol.control.MousePositionProperty.PROJECTION, projection); + this.set(ol.control.MousePosition.Property.PROJECTION, projection); }; @@ -244,3 +235,12 @@ ol.control.MousePosition.prototype.updateHTML_ = function(pixel) { this.renderedHTML_ = html; } }; + + +/** + * @enum {string} + */ +ol.control.MousePosition.Property = { + PROJECTION: 'projection', + COORDINATE_FORMAT: 'coordinateFormat' +}; diff --git a/src/ol/control/overviewmap.js b/src/ol/control/overviewmap.js index 3e16a5e616..731d773c94 100644 --- a/src/ol/control/overviewmap.js +++ b/src/ol/control/overviewmap.js @@ -4,10 +4,10 @@ goog.require('ol'); goog.require('ol.Collection'); goog.require('ol.Map'); goog.require('ol.MapEventType'); +goog.require('ol.MapProperty'); goog.require('ol.Object'); goog.require('ol.ObjectEventType'); goog.require('ol.Overlay'); -goog.require('ol.OverlayPositioning'); goog.require('ol.View'); goog.require('ol.control.Control'); goog.require('ol.coordinate'); @@ -123,7 +123,7 @@ ol.control.OverviewMap = function(opt_options) { */ this.boxOverlay_ = new ol.Overlay({ position: [0, 0], - positioning: ol.OverlayPositioning.BOTTOM_LEFT, + positioning: ol.Overlay.Positioning.BOTTOM_LEFT, element: box }); this.ovmap_.addOverlay(this.boxOverlay_); diff --git a/src/ol/control/zoomslider.js b/src/ol/control/zoomslider.js index d5d449764e..22fd464bcb 100644 --- a/src/ol/control/zoomslider.js +++ b/src/ol/control/zoomslider.js @@ -12,6 +12,7 @@ goog.require('ol.events'); goog.require('ol.events.Event'); goog.require('ol.events.EventType'); goog.require('ol.math'); +goog.require('ol.pointer.EventType'); goog.require('ol.pointer.PointerEventHandler'); @@ -180,13 +181,14 @@ ol.control.ZoomSlider.prototype.setMap = function(map) { * @private */ ol.control.ZoomSlider.prototype.initSlider_ = function() { + var global = ol.global; var container = this.element; var containerSize = { width: container.offsetWidth, height: container.offsetHeight }; var thumb = container.firstElementChild; - var computedStyle = ol.global.getComputedStyle(thumb); + var computedStyle = global.getComputedStyle(thumb); var thumbWidth = thumb.offsetWidth + parseFloat(computedStyle['marginRight']) + parseFloat(computedStyle['marginLeft']); diff --git a/src/ol/deviceorientation.js b/src/ol/deviceorientation.js index be0caf002a..173381da0b 100644 --- a/src/ol/deviceorientation.js +++ b/src/ol/deviceorientation.js @@ -7,18 +7,6 @@ goog.require('ol.has'); goog.require('ol.math'); -/** - * @enum {string} - */ -ol.DeviceOrientationProperty = { - ALPHA: 'alpha', - BETA: 'beta', - GAMMA: 'gamma', - HEADING: 'heading', - TRACKING: 'tracking' -}; - - /** * @classdesc * The ol.DeviceOrientation class provides access to information from @@ -87,7 +75,7 @@ ol.DeviceOrientation = function(opt_options) { this.listenerKey_ = null; ol.events.listen(this, - ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING), + ol.Object.getChangeEventType(ol.DeviceOrientation.Property.TRACKING), this.handleTrackingChanged_, this); this.setTracking(options.tracking !== undefined ? options.tracking : false); @@ -113,22 +101,22 @@ ol.DeviceOrientation.prototype.orientationChange_ = function(originalEvent) { var event = /** @type {DeviceOrientationEvent} */ (originalEvent); if (event.alpha !== null) { var alpha = ol.math.toRadians(event.alpha); - this.set(ol.DeviceOrientationProperty.ALPHA, alpha); + this.set(ol.DeviceOrientation.Property.ALPHA, alpha); // event.absolute is undefined in iOS. if (typeof event.absolute === 'boolean' && event.absolute) { - this.set(ol.DeviceOrientationProperty.HEADING, alpha); + this.set(ol.DeviceOrientation.Property.HEADING, alpha); } else if (typeof event.webkitCompassHeading === 'number' && event.webkitCompassAccuracy != -1) { var heading = ol.math.toRadians(event.webkitCompassHeading); - this.set(ol.DeviceOrientationProperty.HEADING, heading); + this.set(ol.DeviceOrientation.Property.HEADING, heading); } } if (event.beta !== null) { - this.set(ol.DeviceOrientationProperty.BETA, + this.set(ol.DeviceOrientation.Property.BETA, ol.math.toRadians(event.beta)); } if (event.gamma !== null) { - this.set(ol.DeviceOrientationProperty.GAMMA, + this.set(ol.DeviceOrientation.Property.GAMMA, ol.math.toRadians(event.gamma)); } this.changed(); @@ -144,7 +132,7 @@ ol.DeviceOrientation.prototype.orientationChange_ = function(originalEvent) { */ ol.DeviceOrientation.prototype.getAlpha = function() { return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.ALPHA)); + this.get(ol.DeviceOrientation.Property.ALPHA)); }; @@ -157,7 +145,7 @@ ol.DeviceOrientation.prototype.getAlpha = function() { */ ol.DeviceOrientation.prototype.getBeta = function() { return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.BETA)); + this.get(ol.DeviceOrientation.Property.BETA)); }; @@ -170,7 +158,7 @@ ol.DeviceOrientation.prototype.getBeta = function() { */ ol.DeviceOrientation.prototype.getGamma = function() { return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.GAMMA)); + this.get(ol.DeviceOrientation.Property.GAMMA)); }; @@ -183,7 +171,7 @@ ol.DeviceOrientation.prototype.getGamma = function() { */ ol.DeviceOrientation.prototype.getHeading = function() { return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.HEADING)); + this.get(ol.DeviceOrientation.Property.HEADING)); }; @@ -195,7 +183,7 @@ ol.DeviceOrientation.prototype.getHeading = function() { */ ol.DeviceOrientation.prototype.getTracking = function() { return /** @type {boolean} */ ( - this.get(ol.DeviceOrientationProperty.TRACKING)); + this.get(ol.DeviceOrientation.Property.TRACKING)); }; @@ -224,5 +212,17 @@ ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() { * @api */ ol.DeviceOrientation.prototype.setTracking = function(tracking) { - this.set(ol.DeviceOrientationProperty.TRACKING, tracking); + this.set(ol.DeviceOrientation.Property.TRACKING, tracking); +}; + + +/** + * @enum {string} + */ +ol.DeviceOrientation.Property = { + ALPHA: 'alpha', + BETA: 'beta', + GAMMA: 'gamma', + HEADING: 'heading', + TRACKING: 'tracking' }; diff --git a/src/ol/dom.js b/src/ol/dom.js index 2ae64be09b..f55e9655c8 100644 --- a/src/ol/dom.js +++ b/src/ol/dom.js @@ -37,6 +37,7 @@ ol.dom.createCanvasContext2D = function(opt_width, opt_height) { * @return {boolean} */ ol.dom.canUseCssTransform = (function() { + var global = ol.global; var canUseCssTransform; return function() { if (canUseCssTransform === undefined) { @@ -53,7 +54,7 @@ ol.dom.canUseCssTransform = (function() { for (var t in transforms) { if (t in el.style) { el.style[t] = 'translate(1px,1px)'; - has2d = ol.global.getComputedStyle(el).getPropertyValue( + has2d = global.getComputedStyle(el).getPropertyValue( transforms[t]); } } @@ -73,6 +74,7 @@ ol.dom.canUseCssTransform = (function() { * @return {boolean} */ ol.dom.canUseCssTransform3D = (function() { + var global = ol.global; var canUseCssTransform3D; return function() { if (canUseCssTransform3D === undefined) { @@ -89,7 +91,7 @@ ol.dom.canUseCssTransform3D = (function() { for (var t in transforms) { if (t in el.style) { el.style[t] = 'translate3d(1px,1px,1px)'; - has3d = ol.global.getComputedStyle(el).getPropertyValue( + has3d = global.getComputedStyle(el).getPropertyValue( transforms[t]); } } @@ -177,8 +179,9 @@ ol.dom.transformElement2D = function(element, transform, opt_precision) { * @return {number} The width. */ ol.dom.outerWidth = function(element) { + var global = ol.global; var width = element.offsetWidth; - var style = element.currentStyle || ol.global.getComputedStyle(element); + var style = element.currentStyle || global.getComputedStyle(element); width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); return width; @@ -193,8 +196,9 @@ ol.dom.outerWidth = function(element) { * @return {number} The height. */ ol.dom.outerHeight = function(element) { + var global = ol.global; var height = element.offsetHeight; - var style = element.currentStyle || ol.global.getComputedStyle(element); + var style = element.currentStyle || global.getComputedStyle(element); height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); return height; diff --git a/src/ol/events/condition.js b/src/ol/events/condition.js index 7b448d1bc6..1cc33cddb8 100644 --- a/src/ol/events/condition.js +++ b/src/ol/events/condition.js @@ -1,9 +1,9 @@ goog.provide('ol.events.condition'); -goog.require('ol.asserts'); -goog.require('ol.has'); -goog.require('ol.functions'); goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.asserts'); +goog.require('ol.functions'); +goog.require('ol.has'); /** diff --git a/src/ol/featureloader.js b/src/ol/featureloader.js index 1e1cf46bd5..060e372171 100644 --- a/src/ol/featureloader.js +++ b/src/ol/featureloader.js @@ -1,5 +1,6 @@ goog.provide('ol.featureloader'); +goog.require('ol'); goog.require('ol.Tile'); goog.require('ol.format.FormatType'); goog.require('ol.xml'); diff --git a/src/ol/format/igc.js b/src/ol/format/igc.js index be9fb6a3c1..ccfae500ba 100644 --- a/src/ol/format/igc.js +++ b/src/ol/format/igc.js @@ -1,5 +1,4 @@ goog.provide('ol.format.IGC'); -goog.provide('ol.format.IGCZ'); goog.require('ol'); goog.require('ol.Feature'); @@ -10,17 +9,6 @@ goog.require('ol.geom.LineString'); goog.require('ol.proj'); -/** - * IGC altitude/z. One of 'barometric', 'gps', 'none'. - * @enum {string} - */ -ol.format.IGCZ = { - BAROMETRIC: 'barometric', - GPS: 'gps', - NONE: 'none' -}; - - /** * @classdesc * Feature format for `*.igc` flight recording files. @@ -43,10 +31,10 @@ ol.format.IGC = function(opt_options) { /** * @private - * @type {ol.format.IGCZ} + * @type {ol.format.IGC.Z} */ this.altitudeMode_ = options.altitudeMode ? - options.altitudeMode : ol.format.IGCZ.NONE; + options.altitudeMode : ol.format.IGC.Z.NONE; }; ol.inherits(ol.format.IGC, ol.format.TextFeature); @@ -147,11 +135,11 @@ ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) { x = -x; } flatCoordinates.push(x, y); - if (altitudeMode != ol.format.IGCZ.NONE) { + if (altitudeMode != ol.format.IGC.Z.NONE) { var z; - if (altitudeMode == ol.format.IGCZ.GPS) { + if (altitudeMode == ol.format.IGC.Z.GPS) { z = parseInt(m[11], 10); - } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) { + } else if (altitudeMode == ol.format.IGC.Z.BAROMETRIC) { z = parseInt(m[12], 10); } else { ol.DEBUG && console.assert(false, 'Unknown altitude mode.'); @@ -185,7 +173,7 @@ ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) { return null; } var lineString = new ol.geom.LineString(null); - var layout = altitudeMode == ol.format.IGCZ.NONE ? + var layout = altitudeMode == ol.format.IGC.Z.NONE ? ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM; lineString.setFlatCoordinates(layout, flatCoordinates); var feature = new ol.Feature(ol.format.Feature.transformWithOptions( @@ -230,3 +218,14 @@ ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) { * @api */ ol.format.IGC.prototype.readProjection; + + +/** + * IGC altitude/z. One of 'barometric', 'gps', 'none'. + * @enum {string} + */ +ol.format.IGC.Z = { + BAROMETRIC: 'barometric', + GPS: 'gps', + NONE: 'none' +}; diff --git a/src/ol/format/kml.js b/src/ol/format/kml.js index c9ea0d32ce..a7a410e538 100644 --- a/src/ol/format/kml.js +++ b/src/ol/format/kml.js @@ -27,8 +27,6 @@ goog.require('ol.math'); goog.require('ol.proj'); goog.require('ol.style.Fill'); goog.require('ol.style.Icon'); -goog.require('ol.style.IconAnchorUnits'); -goog.require('ol.style.IconOrigin'); goog.require('ol.style.Stroke'); goog.require('ol.style.Style'); goog.require('ol.style.Text'); @@ -168,19 +166,19 @@ ol.format.KML.createStyleDefaults_ = function() { /** * @const - * @type {ol.style.IconAnchorUnits} + * @type {ol.style.Icon.AnchorUnits} * @private */ ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; + ol.style.Icon.AnchorUnits.PIXELS; /** * @const - * @type {ol.style.IconAnchorUnits} + * @type {ol.style.Icon.AnchorUnits} * @private */ ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; + ol.style.Icon.AnchorUnits.PIXELS; /** * @const @@ -211,7 +209,7 @@ ol.format.KML.createStyleDefaults_ = function() { */ ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({ anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + anchorOrigin: ol.style.Icon.Origin.BOTTOM_LEFT, anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_, anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_, crossOrigin: 'anonymous', @@ -286,12 +284,12 @@ ol.format.KML.createStyleDefaults_ = function() { /** * @const - * @type {Object.} + * @type {Object.} * @private */ ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = { - 'fraction': ol.style.IconAnchorUnits.FRACTION, - 'pixels': ol.style.IconAnchorUnits.PIXELS + 'fraction': ol.style.Icon.AnchorUnits.FRACTION, + 'pixels': ol.style.Icon.AnchorUnits.PIXELS }; @@ -598,8 +596,8 @@ ol.format.KML.IconStyleParser_ = function(node, objectStack) { anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_; } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) { anchor = [0.5, 0]; - anchorXUnits = ol.style.IconAnchorUnits.FRACTION; - anchorYUnits = ol.style.IconAnchorUnits.FRACTION; + anchorXUnits = ol.style.Icon.AnchorUnits.FRACTION; + anchorYUnits = ol.style.Icon.AnchorUnits.FRACTION; } var offset; @@ -645,12 +643,12 @@ ol.format.KML.IconStyleParser_ = function(node, objectStack) { var imageStyle = new ol.style.Icon({ anchor: anchor, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + anchorOrigin: ol.style.Icon.Origin.BOTTOM_LEFT, anchorXUnits: anchorXUnits, anchorYUnits: anchorYUnits, crossOrigin: 'anonymous', // FIXME should this be configurable? offset: offset, - offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + offsetOrigin: ol.style.Icon.Origin.BOTTOM_LEFT, rotation: rotation, scale: scale, size: size, @@ -2190,9 +2188,9 @@ ol.format.KML.writeIconStyle_ = function(node, style, objectStack) { if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) { var /** @type {ol.KMLVec2_} */ hotSpot = { x: anchor[0], - xunits: ol.style.IconAnchorUnits.PIXELS, + xunits: ol.style.Icon.AnchorUnits.PIXELS, y: size[1] - anchor[1], - yunits: ol.style.IconAnchorUnits.PIXELS + yunits: ol.style.Icon.AnchorUnits.PIXELS }; properties['hotSpot'] = hotSpot; } diff --git a/src/ol/geolocation.js b/src/ol/geolocation.js index d00b2905ee..37f6b9f41c 100644 --- a/src/ol/geolocation.js +++ b/src/ol/geolocation.js @@ -3,9 +3,9 @@ goog.provide('ol.Geolocation'); goog.require('ol'); +goog.require('ol.Object'); goog.require('ol.events'); goog.require('ol.events.EventType'); -goog.require('ol.Object'); goog.require('ol.geom.Polygon'); goog.require('ol.has'); goog.require('ol.math'); @@ -13,23 +13,6 @@ goog.require('ol.proj'); goog.require('ol.sphere.WGS84'); -/** - * @enum {string} - */ -ol.GeolocationProperty = { - ACCURACY: 'accuracy', - ACCURACY_GEOMETRY: 'accuracyGeometry', - ALTITUDE: 'altitude', - ALTITUDE_ACCURACY: 'altitudeAccuracy', - HEADING: 'heading', - POSITION: 'position', - PROJECTION: 'projection', - SPEED: 'speed', - TRACKING: 'tracking', - TRACKING_OPTIONS: 'trackingOptions' -}; - - /** * @classdesc * Helper class for providing HTML5 Geolocation capabilities. @@ -82,10 +65,10 @@ ol.Geolocation = function(opt_options) { this.watchId_ = undefined; ol.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION), + this, ol.Object.getChangeEventType(ol.Geolocation.Property.PROJECTION), this.handleProjectionChanged_, this); ol.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING), + this, ol.Object.getChangeEventType(ol.Geolocation.Property.TRACKING), this.handleTrackingChanged_, this); if (options.projection !== undefined) { @@ -120,7 +103,7 @@ ol.Geolocation.prototype.handleProjectionChanged_ = function() { ol.proj.get('EPSG:4326'), projection); if (this.position_) { this.set( - ol.GeolocationProperty.POSITION, this.transform_(this.position_)); + ol.Geolocation.Property.POSITION, this.transform_(this.position_)); } } }; @@ -130,15 +113,17 @@ ol.Geolocation.prototype.handleProjectionChanged_ = function() { * @private */ ol.Geolocation.prototype.handleTrackingChanged_ = function() { + var global = ol.global; if (ol.has.GEOLOCATION) { + var navigator = global.navigator; var tracking = this.getTracking(); if (tracking && this.watchId_ === undefined) { - this.watchId_ = ol.global.navigator.geolocation.watchPosition( + this.watchId_ = navigator.geolocation.watchPosition( this.positionChange_.bind(this), this.positionError_.bind(this), this.getTrackingOptions()); } else if (!tracking && this.watchId_ !== undefined) { - ol.global.navigator.geolocation.clearWatch(this.watchId_); + navigator.geolocation.clearWatch(this.watchId_); this.watchId_ = undefined; } } @@ -151,13 +136,13 @@ ol.Geolocation.prototype.handleTrackingChanged_ = function() { */ ol.Geolocation.prototype.positionChange_ = function(position) { var coords = position.coords; - this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy); - this.set(ol.GeolocationProperty.ALTITUDE, + this.set(ol.Geolocation.Property.ACCURACY, coords.accuracy); + this.set(ol.Geolocation.Property.ALTITUDE, coords.altitude === null ? undefined : coords.altitude); - this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY, + this.set(ol.Geolocation.Property.ALTITUDE_ACCURACY, coords.altitudeAccuracy === null ? undefined : coords.altitudeAccuracy); - this.set(ol.GeolocationProperty.HEADING, coords.heading === null ? + this.set(ol.Geolocation.Property.HEADING, coords.heading === null ? undefined : ol.math.toRadians(coords.heading)); if (!this.position_) { this.position_ = [coords.longitude, coords.latitude]; @@ -166,13 +151,13 @@ ol.Geolocation.prototype.positionChange_ = function(position) { this.position_[1] = coords.latitude; } var projectedPosition = this.transform_(this.position_); - this.set(ol.GeolocationProperty.POSITION, projectedPosition); - this.set(ol.GeolocationProperty.SPEED, + this.set(ol.Geolocation.Property.POSITION, projectedPosition); + this.set(ol.Geolocation.Property.SPEED, coords.speed === null ? undefined : coords.speed); var geometry = ol.geom.Polygon.circular( ol.sphere.WGS84, this.position_, coords.accuracy); geometry.applyTransform(this.transform_); - this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry); + this.set(ol.Geolocation.Property.ACCURACY_GEOMETRY, geometry); this.changed(); }; @@ -202,7 +187,7 @@ ol.Geolocation.prototype.positionError_ = function(error) { */ ol.Geolocation.prototype.getAccuracy = function() { return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ACCURACY)); + this.get(ol.Geolocation.Property.ACCURACY)); }; @@ -214,7 +199,7 @@ ol.Geolocation.prototype.getAccuracy = function() { */ ol.Geolocation.prototype.getAccuracyGeometry = function() { return /** @type {?ol.geom.Geometry} */ ( - this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null); + this.get(ol.Geolocation.Property.ACCURACY_GEOMETRY) || null); }; @@ -227,7 +212,7 @@ ol.Geolocation.prototype.getAccuracyGeometry = function() { */ ol.Geolocation.prototype.getAltitude = function() { return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE)); + this.get(ol.Geolocation.Property.ALTITUDE)); }; @@ -240,7 +225,7 @@ ol.Geolocation.prototype.getAltitude = function() { */ ol.Geolocation.prototype.getAltitudeAccuracy = function() { return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY)); + this.get(ol.Geolocation.Property.ALTITUDE_ACCURACY)); }; @@ -252,7 +237,7 @@ ol.Geolocation.prototype.getAltitudeAccuracy = function() { */ ol.Geolocation.prototype.getHeading = function() { return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.HEADING)); + this.get(ol.Geolocation.Property.HEADING)); }; @@ -265,7 +250,7 @@ ol.Geolocation.prototype.getHeading = function() { */ ol.Geolocation.prototype.getPosition = function() { return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.GeolocationProperty.POSITION)); + this.get(ol.Geolocation.Property.POSITION)); }; @@ -278,7 +263,7 @@ ol.Geolocation.prototype.getPosition = function() { */ ol.Geolocation.prototype.getProjection = function() { return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.GeolocationProperty.PROJECTION)); + this.get(ol.Geolocation.Property.PROJECTION)); }; @@ -291,7 +276,7 @@ ol.Geolocation.prototype.getProjection = function() { */ ol.Geolocation.prototype.getSpeed = function() { return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.SPEED)); + this.get(ol.Geolocation.Property.SPEED)); }; @@ -303,7 +288,7 @@ ol.Geolocation.prototype.getSpeed = function() { */ ol.Geolocation.prototype.getTracking = function() { return /** @type {boolean} */ ( - this.get(ol.GeolocationProperty.TRACKING)); + this.get(ol.Geolocation.Property.TRACKING)); }; @@ -318,7 +303,7 @@ ol.Geolocation.prototype.getTracking = function() { */ ol.Geolocation.prototype.getTrackingOptions = function() { return /** @type {GeolocationPositionOptions|undefined} */ ( - this.get(ol.GeolocationProperty.TRACKING_OPTIONS)); + this.get(ol.Geolocation.Property.TRACKING_OPTIONS)); }; @@ -330,7 +315,7 @@ ol.Geolocation.prototype.getTrackingOptions = function() { * @api stable */ ol.Geolocation.prototype.setProjection = function(projection) { - this.set(ol.GeolocationProperty.PROJECTION, projection); + this.set(ol.Geolocation.Property.PROJECTION, projection); }; @@ -341,7 +326,7 @@ ol.Geolocation.prototype.setProjection = function(projection) { * @api stable */ ol.Geolocation.prototype.setTracking = function(tracking) { - this.set(ol.GeolocationProperty.TRACKING, tracking); + this.set(ol.Geolocation.Property.TRACKING, tracking); }; @@ -355,5 +340,22 @@ ol.Geolocation.prototype.setTracking = function(tracking) { * @api stable */ ol.Geolocation.prototype.setTrackingOptions = function(options) { - this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options); + this.set(ol.Geolocation.Property.TRACKING_OPTIONS, options); +}; + + +/** + * @enum {string} + */ +ol.Geolocation.Property = { + ACCURACY: 'accuracy', + ACCURACY_GEOMETRY: 'accuracyGeometry', + ALTITUDE: 'altitude', + ALTITUDE_ACCURACY: 'altitudeAccuracy', + HEADING: 'heading', + POSITION: 'position', + PROJECTION: 'projection', + SPEED: 'speed', + TRACKING: 'tracking', + TRACKING_OPTIONS: 'trackingOptions' }; diff --git a/src/ol/has.js b/src/ol/has.js index 3d56c9d792..3f7d8124b1 100644 --- a/src/ol/has.js +++ b/src/ol/has.js @@ -3,7 +3,7 @@ goog.provide('ol.has'); goog.require('ol'); goog.require('ol.webgl'); - +var olGlobal = ol.global; var ua = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase() : ''; @@ -48,7 +48,7 @@ ol.has.MAC = ua.indexOf('macintosh') !== -1; * @type {number} * @api stable */ -ol.has.DEVICE_PIXEL_RATIO = ol.global.devicePixelRatio || 1; +ol.has.DEVICE_PIXEL_RATIO = olGlobal.devicePixelRatio || 1; /** @@ -70,7 +70,7 @@ ol.has.CANVAS = ol.ENABLE_CANVAS && ( * @return {boolean} Canvas supported. */ function() { - if (!('HTMLCanvasElement' in ol.global)) { + if (!('HTMLCanvasElement' in olGlobal)) { return false; } try { @@ -95,7 +95,7 @@ ol.has.CANVAS = ol.ENABLE_CANVAS && ( * @type {boolean} * @api stable */ -ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in ol.global; +ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in olGlobal; /** @@ -112,7 +112,7 @@ ol.has.DOM = ol.ENABLE_DOM; * @type {boolean} * @api stable */ -ol.has.GEOLOCATION = 'geolocation' in ol.global.navigator; +ol.has.GEOLOCATION = 'geolocation' in olGlobal.navigator; /** @@ -121,7 +121,7 @@ ol.has.GEOLOCATION = 'geolocation' in ol.global.navigator; * @type {boolean} * @api stable */ -ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in ol.global; +ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in olGlobal; /** @@ -129,7 +129,7 @@ ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in ol.global; * @const * @type {boolean} */ -ol.has.POINTER = 'PointerEvent' in ol.global; +ol.has.POINTER = 'PointerEvent' in olGlobal; /** @@ -137,7 +137,7 @@ ol.has.POINTER = 'PointerEvent' in ol.global; * @const * @type {boolean} */ -ol.has.MSPOINTER = !!(ol.global.navigator.msPointerEnabled); +ol.has.MSPOINTER = !!(olGlobal.navigator.msPointerEnabled); /** @@ -156,7 +156,7 @@ ol.has.WEBGL; var textureSize; var /** @type {Array.} */ extensions = []; - if ('WebGLRenderingContext' in ol.global) { + if ('WebGLRenderingContext' in olGlobal) { try { var canvas = /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS')); diff --git a/src/ol/interaction/mousewheelzoom.js b/src/ol/interaction/mousewheelzoom.js index 3457e7b528..91a1eb74c2 100644 --- a/src/ol/interaction/mousewheelzoom.js +++ b/src/ol/interaction/mousewheelzoom.js @@ -2,6 +2,7 @@ goog.provide('ol.interaction.MouseWheelZoom'); goog.require('ol'); goog.require('ol.events.EventType'); +goog.require('ol.has'); goog.require('ol.interaction.Interaction'); goog.require('ol.math'); @@ -86,13 +87,15 @@ ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { // https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js //TODO There's more good stuff in there for inspiration to improve this interaction. var delta; + var global = ol.global; + var WheelEvent = global.WheelEvent; if (mapBrowserEvent.type == ol.events.EventType.WHEEL) { delta = wheelEvent.deltaY; if (ol.has.FIREFOX && - wheelEvent.deltaMode === ol.global.WheelEvent.DOM_DELTA_PIXEL) { + wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) { delta /= ol.has.DEVICE_PIXEL_RATIO; } - if (wheelEvent.deltaMode === ol.global.WheelEvent.DOM_DELTA_LINE) { + if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) { delta *= 40; } } else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) { @@ -111,8 +114,8 @@ ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION; var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0); - ol.global.clearTimeout(this.timeoutId_); - this.timeoutId_ = ol.global.setTimeout( + global.clearTimeout(this.timeoutId_); + this.timeoutId_ = global.setTimeout( this.doZoom_.bind(this, map), timeLeft); mapBrowserEvent.preventDefault(); diff --git a/src/ol/interaction/pointer.js b/src/ol/interaction/pointer.js index c133c10161..cf7bb1ee03 100644 --- a/src/ol/interaction/pointer.js +++ b/src/ol/interaction/pointer.js @@ -1,6 +1,7 @@ goog.provide('ol.interaction.Pointer'); goog.require('ol'); +goog.require('ol.functions'); goog.require('ol.MapBrowserEvent.EventType'); goog.require('ol.MapBrowserPointerEvent'); goog.require('ol.interaction.Interaction'); diff --git a/src/ol/interaction/snap.js b/src/ol/interaction/snap.js index 5c1927375c..ac8001914b 100644 --- a/src/ol/interaction/snap.js +++ b/src/ol/interaction/snap.js @@ -1,5 +1,4 @@ goog.provide('ol.interaction.Snap'); -goog.provide('ol.interaction.SnapProperty'); goog.require('ol'); goog.require('ol.Collection'); diff --git a/src/ol/interaction/translate.js b/src/ol/interaction/translate.js index 06c6cf7ece..c26c8cdc7e 100644 --- a/src/ol/interaction/translate.js +++ b/src/ol/interaction/translate.js @@ -3,6 +3,7 @@ goog.provide('ol.interaction.TranslateEvent'); goog.require('ol'); goog.require('ol.events.Event'); +goog.require('ol.functions'); goog.require('ol.array'); goog.require('ol.interaction.Pointer'); diff --git a/src/ol/layer/group.js b/src/ol/layer/group.js index 260ebc2a8b..cd1f892aa8 100644 --- a/src/ol/layer/group.js +++ b/src/ol/layer/group.js @@ -13,14 +13,6 @@ goog.require('ol.obj'); goog.require('ol.source.State'); -/** - * @enum {string} - */ -ol.layer.GroupProperty = { - LAYERS: 'layers' -}; - - /** * @classdesc * A {@link ol.Collection} of layers that are handled together. @@ -56,7 +48,7 @@ ol.layer.Group = function(opt_options) { this.listenerKeys_ = {}; ol.events.listen(this, - ol.Object.getChangeEventType(ol.layer.GroupProperty.LAYERS), + ol.Object.getChangeEventType(ol.layer.Group.Property.LAYERS), this.handleLayersChanged_, this); if (layers) { @@ -166,7 +158,7 @@ ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) { */ ol.layer.Group.prototype.getLayers = function() { return /** @type {!ol.Collection.} */ (this.get( - ol.layer.GroupProperty.LAYERS)); + ol.layer.Group.Property.LAYERS)); }; @@ -179,7 +171,7 @@ ol.layer.Group.prototype.getLayers = function() { * @api stable */ ol.layer.Group.prototype.setLayers = function(layers) { - this.set(ol.layer.GroupProperty.LAYERS, layers); + this.set(ol.layer.Group.Property.LAYERS, layers); }; @@ -237,3 +229,10 @@ ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) { ol.layer.Group.prototype.getSourceState = function() { return ol.source.State.READY; }; + +/** + * @enum {string} + */ +ol.layer.Group.Property = { + LAYERS: 'layers' +}; diff --git a/src/ol/layer/heatmap.js b/src/ol/layer/heatmap.js index a15ac8e166..072f8107f8 100644 --- a/src/ol/layer/heatmap.js +++ b/src/ol/layer/heatmap.js @@ -12,16 +12,6 @@ goog.require('ol.style.Icon'); goog.require('ol.style.Style'); -/** - * @enum {string} - */ -ol.layer.HeatmapLayerProperty = { - BLUR: 'blur', - GRADIENT: 'gradient', - RADIUS: 'radius' -}; - - /** * @classdesc * Layer for rendering vector data as a heatmap. @@ -72,7 +62,7 @@ ol.layer.Heatmap = function(opt_options) { this.styleCache_ = null; ol.events.listen(this, - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), + ol.Object.getChangeEventType(ol.layer.Heatmap.Property.GRADIENT), this.handleGradientChanged_, this); this.setGradient(options.gradient ? @@ -83,10 +73,10 @@ ol.layer.Heatmap = function(opt_options) { this.setRadius(options.radius !== undefined ? options.radius : 8); ol.events.listen(this, - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.BLUR), + ol.Object.getChangeEventType(ol.layer.Heatmap.Property.BLUR), this.handleStyleChanged_, this); ol.events.listen(this, - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS), + ol.Object.getChangeEventType(ol.layer.Heatmap.Property.RADIUS), this.handleStyleChanged_, this); this.handleStyleChanged_(); @@ -196,7 +186,7 @@ ol.layer.Heatmap.prototype.createCircle_ = function() { * @observable */ ol.layer.Heatmap.prototype.getBlur = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.BLUR)); + return /** @type {number} */ (this.get(ol.layer.Heatmap.Property.BLUR)); }; @@ -208,7 +198,7 @@ ol.layer.Heatmap.prototype.getBlur = function() { */ ol.layer.Heatmap.prototype.getGradient = function() { return /** @type {Array.} */ ( - this.get(ol.layer.HeatmapLayerProperty.GRADIENT)); + this.get(ol.layer.Heatmap.Property.GRADIENT)); }; @@ -219,7 +209,7 @@ ol.layer.Heatmap.prototype.getGradient = function() { * @observable */ ol.layer.Heatmap.prototype.getRadius = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS)); + return /** @type {number} */ (this.get(ol.layer.Heatmap.Property.RADIUS)); }; @@ -273,7 +263,7 @@ ol.layer.Heatmap.prototype.handleRender_ = function(event) { * @observable */ ol.layer.Heatmap.prototype.setBlur = function(blur) { - this.set(ol.layer.HeatmapLayerProperty.BLUR, blur); + this.set(ol.layer.Heatmap.Property.BLUR, blur); }; @@ -284,7 +274,7 @@ ol.layer.Heatmap.prototype.setBlur = function(blur) { * @observable */ ol.layer.Heatmap.prototype.setGradient = function(colors) { - this.set(ol.layer.HeatmapLayerProperty.GRADIENT, colors); + this.set(ol.layer.Heatmap.Property.GRADIENT, colors); }; @@ -295,5 +285,15 @@ ol.layer.Heatmap.prototype.setGradient = function(colors) { * @observable */ ol.layer.Heatmap.prototype.setRadius = function(radius) { - this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius); + this.set(ol.layer.Heatmap.Property.RADIUS, radius); +}; + + +/** + * @enum {string} + */ +ol.layer.Heatmap.Property = { + BLUR: 'blur', + GRADIENT: 'gradient', + RADIUS: 'radius' }; diff --git a/src/ol/layer/vectortile.js b/src/ol/layer/vectortile.js index 1cdda6d8b4..dc6cb383ab 100644 --- a/src/ol/layer/vectortile.js +++ b/src/ol/layer/vectortile.js @@ -15,26 +15,6 @@ ol.layer.VectorTileProperty = { }; -/** - * @enum {string} - * Render mode for vector tiles: - * * `'image'`: Vector tiles are rendered as images. Great performance, but - * point symbols and texts are always rotated with the view and pixels are - * scaled during zoom animations. - * * `'hybrid'`: Polygon and line elements are rendered as images, so pixels - * are scaled during zoom animations. Point symbols and texts are accurately - * rendered as vectors and can stay upright on rotated views. - * * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering - * even during animations, but slower performance than the other options. - * @api - */ -ol.layer.VectorTileRenderType = { - IMAGE: 'image', - HYBRID: 'hybrid', - VECTOR: 'vector' -}; - - /** * @classdesc * Layer for vector tile data that is rendered client-side. @@ -61,16 +41,16 @@ ol.layer.VectorTile = function(opt_options) { options.useInterimTilesOnError : true); ol.asserts.assert(options.renderMode == undefined || - options.renderMode == ol.layer.VectorTileRenderType.IMAGE || - options.renderMode == ol.layer.VectorTileRenderType.HYBRID || - options.renderMode == ol.layer.VectorTileRenderType.VECTOR, + options.renderMode == ol.layer.VectorTile.RenderType.IMAGE || + options.renderMode == ol.layer.VectorTile.RenderType.HYBRID || + options.renderMode == ol.layer.VectorTile.RenderType.VECTOR, 28); // `renderMode` must be `'image'`, `'hybrid'` or `'vector'` /** * @private - * @type {ol.layer.VectorTileRenderType|string} + * @type {ol.layer.VectorTile.RenderType|string} */ - this.renderMode_ = options.renderMode || ol.layer.VectorTileRenderType.HYBRID; + this.renderMode_ = options.renderMode || ol.layer.VectorTile.RenderType.HYBRID; }; ol.inherits(ol.layer.VectorTile, ol.layer.Vector); @@ -88,7 +68,7 @@ ol.layer.VectorTile.prototype.getPreload = function() { /** - * @return {ol.layer.VectorTileRenderType|string} The render mode. + * @return {ol.layer.VectorTile.RenderType|string} The render mode. */ ol.layer.VectorTile.prototype.getRenderMode = function() { return this.renderMode_; @@ -128,3 +108,23 @@ ol.layer.VectorTile.prototype.setUseInterimTilesOnError = function(useInterimTil this.set( ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); }; + + +/** + * @enum {string} + * Render mode for vector tiles: + * * `'image'`: Vector tiles are rendered as images. Great performance, but + * point symbols and texts are always rotated with the view and pixels are + * scaled during zoom animations. + * * `'hybrid'`: Polygon and line elements are rendered as images, so pixels + * are scaled during zoom animations. Point symbols and texts are accurately + * rendered as vectors and can stay upright on rotated views. + * * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering + * even during animations, but slower performance than the other options. + * @api + */ +ol.layer.VectorTile.RenderType = { + IMAGE: 'image', + HYBRID: 'hybrid', + VECTOR: 'vector' +}; diff --git a/src/ol/map.js b/src/ol/map.js index e86229edc4..48e17709b2 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -553,6 +553,7 @@ ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) { * @inheritDoc */ ol.Map.prototype.disposeInternal = function() { + var global = ol.global; this.mapBrowserEventHandler_.dispose(); this.renderer_.dispose(); ol.events.unlisten(this.viewport_, ol.events.EventType.WHEEL, @@ -560,12 +561,12 @@ ol.Map.prototype.disposeInternal = function() { ol.events.unlisten(this.viewport_, ol.events.EventType.MOUSEWHEEL, this.handleBrowserEvent, this); if (this.handleResize_ !== undefined) { - ol.global.removeEventListener(ol.events.EventType.RESIZE, + global.removeEventListener(ol.events.EventType.RESIZE, this.handleResize_, false); this.handleResize_ = undefined; } if (this.animationDelayKey_) { - ol.global.cancelAnimationFrame(this.animationDelayKey_); + global.cancelAnimationFrame(this.animationDelayKey_); this.animationDelayKey_ = undefined; } this.setTarget(null); @@ -1039,6 +1040,7 @@ ol.Map.prototype.handleSizeChanged_ = function() { * @private */ ol.Map.prototype.handleTargetChanged_ = function() { + var global = ol.global; // target may be undefined, null, a string or an Element. // If it's a string we convert it to an Element before proceeding. // If it's not now an Element we remove the viewport from the DOM. @@ -1061,7 +1063,7 @@ ol.Map.prototype.handleTargetChanged_ = function() { if (!targetElement) { ol.dom.removeNode(this.viewport_); if (this.handleResize_ !== undefined) { - ol.global.removeEventListener(ol.events.EventType.RESIZE, + global.removeEventListener(ol.events.EventType.RESIZE, this.handleResize_, false); this.handleResize_ = undefined; } @@ -1079,7 +1081,7 @@ ol.Map.prototype.handleTargetChanged_ = function() { if (!this.handleResize_) { this.handleResize_ = this.updateSize.bind(this); - ol.global.addEventListener(ol.events.EventType.RESIZE, + global.addEventListener(ol.events.EventType.RESIZE, this.handleResize_, false); } } @@ -1160,8 +1162,9 @@ ol.Map.prototype.isRendered = function() { * @api stable */ ol.Map.prototype.renderSync = function() { + var global = ol.global; if (this.animationDelayKey_) { - ol.global.cancelAnimationFrame(this.animationDelayKey_); + global.cancelAnimationFrame(this.animationDelayKey_); } this.animationDelay_(); }; @@ -1172,8 +1175,9 @@ ol.Map.prototype.renderSync = function() { * @api stable */ ol.Map.prototype.render = function() { + var global = ol.global; if (this.animationDelayKey_ === undefined) { - this.animationDelayKey_ = ol.global.requestAnimationFrame( + this.animationDelayKey_ = global.requestAnimationFrame( this.animationDelay_); } }; @@ -1380,12 +1384,13 @@ ol.Map.prototype.skipFeature = function(feature) { * @api stable */ ol.Map.prototype.updateSize = function() { + var global = ol.global; var targetElement = this.getTargetElement(); if (!targetElement) { this.setSize(undefined); } else { - var computedStyle = ol.global.getComputedStyle(targetElement); + var computedStyle = global.getComputedStyle(targetElement); this.setSize([ targetElement.offsetWidth - parseFloat(computedStyle['borderLeftWidth']) - diff --git a/src/ol/mapbrowserevent.js b/src/ol/mapbrowserevent.js index c29813b6e5..90aa80f00c 100644 --- a/src/ol/mapbrowserevent.js +++ b/src/ol/mapbrowserevent.js @@ -8,6 +8,7 @@ goog.require('ol.MapEvent'); goog.require('ol.events'); goog.require('ol.events.EventTarget'); goog.require('ol.events.EventType'); +goog.require('ol.pointer.EventType'); goog.require('ol.pointer.PointerEventHandler'); @@ -213,20 +214,22 @@ ol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget); * @private */ ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { - var newEvent; - newEvent = new ol.MapBrowserPointerEvent( + var global = ol.global; + var clearTimeout = global.clearTimeout; + var setTimeout = global.setTimeout; + var newEvent = new ol.MapBrowserPointerEvent( ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); this.dispatchEvent(newEvent); if (this.clickTimeoutId_ !== 0) { // double-click - ol.global.clearTimeout(this.clickTimeoutId_); + clearTimeout(this.clickTimeoutId_); this.clickTimeoutId_ = 0; newEvent = new ol.MapBrowserPointerEvent( ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); this.dispatchEvent(newEvent); } else { // click - this.clickTimeoutId_ = ol.global.setTimeout(function() { + this.clickTimeoutId_ = setTimeout(function() { this.clickTimeoutId_ = 0; var newEvent = new ol.MapBrowserPointerEvent( ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); diff --git a/src/ol/net.js b/src/ol/net.js index 3b9684f762..0775bf2bd1 100644 --- a/src/ol/net.js +++ b/src/ol/net.js @@ -15,25 +15,26 @@ goog.require('ol'); * callback. Default is 'callback'. */ ol.net.jsonp = function(url, callback, opt_errback, opt_callbackParam) { - var script = ol.global.document.createElement('script'); + var global = ol.global; + var script = global.document.createElement('script'); var key = 'olc_' + ol.getUid(callback); function cleanup() { - delete ol.global[key]; + delete global[key]; script.parentNode.removeChild(script); } script.async = true; script.src = url + (url.indexOf('?') == -1 ? '?' : '&') + (opt_callbackParam || 'callback') + '=' + key; - var timer = ol.global.setTimeout(function() { + var timer = global.setTimeout(function() { cleanup(); if (opt_errback) { opt_errback(); } }, 10000); - ol.global[key] = function(data) { - ol.global.clearTimeout(timer); + global[key] = function(data) { + global.clearTimeout(timer); cleanup(); callback(data); }; - ol.global.document.getElementsByTagName('head')[0].appendChild(script); + document.getElementsByTagName('head')[0].appendChild(script); }; diff --git a/src/ol/overlay.js b/src/ol/overlay.js index 3214338282..947f84afe8 100644 --- a/src/ol/overlay.js +++ b/src/ol/overlay.js @@ -1,46 +1,14 @@ goog.provide('ol.Overlay'); -goog.provide('ol.OverlayPositioning'); goog.require('ol'); -goog.require('ol.events'); goog.require('ol.MapEventType'); goog.require('ol.Object'); goog.require('ol.animation'); goog.require('ol.dom'); +goog.require('ol.events'); goog.require('ol.extent'); -/** - * @enum {string} - */ -ol.OverlayProperty = { - ELEMENT: 'element', - MAP: 'map', - OFFSET: 'offset', - POSITION: 'position', - POSITIONING: 'positioning' -}; - - -/** - * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, - * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, - * `'top-center'`, `'top-right'` - * @enum {string} - */ -ol.OverlayPositioning = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_CENTER: 'bottom-center', - BOTTOM_RIGHT: 'bottom-right', - CENTER_LEFT: 'center-left', - CENTER_CENTER: 'center-center', - CENTER_RIGHT: 'center-right', - TOP_LEFT: 'top-left', - TOP_CENTER: 'top-center', - TOP_RIGHT: 'top-right' -}; - - /** * @classdesc * An element to be displayed over the map and attached to a single map @@ -136,23 +104,23 @@ ol.Overlay = function(options) { this.mapPostrenderListenerKey_ = null; ol.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT), + this, ol.Object.getChangeEventType(ol.Overlay.Property.ELEMENT), this.handleElementChanged, this); ol.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP), + this, ol.Object.getChangeEventType(ol.Overlay.Property.MAP), this.handleMapChanged, this); ol.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET), + this, ol.Object.getChangeEventType(ol.Overlay.Property.OFFSET), this.handleOffsetChanged, this); ol.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION), + this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITION), this.handlePositionChanged, this); ol.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING), + this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITIONING), this.handlePositioningChanged, this); if (options.element !== undefined) { @@ -162,8 +130,8 @@ ol.Overlay = function(options) { this.setOffset(options.offset !== undefined ? options.offset : [0, 0]); this.setPositioning(options.positioning !== undefined ? - /** @type {ol.OverlayPositioning} */ (options.positioning) : - ol.OverlayPositioning.TOP_LEFT); + /** @type {ol.Overlay.Positioning} */ (options.positioning) : + ol.Overlay.Positioning.TOP_LEFT); if (options.position !== undefined) { this.setPosition(options.position); @@ -181,7 +149,7 @@ ol.inherits(ol.Overlay, ol.Object); */ ol.Overlay.prototype.getElement = function() { return /** @type {Element|undefined} */ ( - this.get(ol.OverlayProperty.ELEMENT)); + this.get(ol.Overlay.Property.ELEMENT)); }; @@ -203,7 +171,7 @@ ol.Overlay.prototype.getId = function() { */ ol.Overlay.prototype.getMap = function() { return /** @type {ol.Map|undefined} */ ( - this.get(ol.OverlayProperty.MAP)); + this.get(ol.Overlay.Property.MAP)); }; @@ -215,7 +183,7 @@ ol.Overlay.prototype.getMap = function() { */ ol.Overlay.prototype.getOffset = function() { return /** @type {Array.} */ ( - this.get(ol.OverlayProperty.OFFSET)); + this.get(ol.Overlay.Property.OFFSET)); }; @@ -228,20 +196,20 @@ ol.Overlay.prototype.getOffset = function() { */ ol.Overlay.prototype.getPosition = function() { return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.OverlayProperty.POSITION)); + this.get(ol.Overlay.Property.POSITION)); }; /** * Get the current positioning of this overlay. - * @return {ol.OverlayPositioning} How the overlay is positioned + * @return {ol.Overlay.Positioning} How the overlay is positioned * relative to its point on the map. * @observable * @api stable */ ol.Overlay.prototype.getPositioning = function() { - return /** @type {ol.OverlayPositioning} */ ( - this.get(ol.OverlayProperty.POSITIONING)); + return /** @type {ol.Overlay.Positioning} */ ( + this.get(ol.Overlay.Property.POSITIONING)); }; @@ -303,7 +271,7 @@ ol.Overlay.prototype.handleOffsetChanged = function() { */ ol.Overlay.prototype.handlePositionChanged = function() { this.updatePixelPosition(); - if (this.get(ol.OverlayProperty.POSITION) !== undefined && this.autoPan) { + if (this.get(ol.Overlay.Property.POSITION) !== undefined && this.autoPan) { this.panIntoView_(); } }; @@ -324,7 +292,7 @@ ol.Overlay.prototype.handlePositioningChanged = function() { * @api stable */ ol.Overlay.prototype.setElement = function(element) { - this.set(ol.OverlayProperty.ELEMENT, element); + this.set(ol.Overlay.Property.ELEMENT, element); }; @@ -335,7 +303,7 @@ ol.Overlay.prototype.setElement = function(element) { * @api stable */ ol.Overlay.prototype.setMap = function(map) { - this.set(ol.OverlayProperty.MAP, map); + this.set(ol.Overlay.Property.MAP, map); }; @@ -346,7 +314,7 @@ ol.Overlay.prototype.setMap = function(map) { * @api stable */ ol.Overlay.prototype.setOffset = function(offset) { - this.set(ol.OverlayProperty.OFFSET, offset); + this.set(ol.Overlay.Property.OFFSET, offset); }; @@ -359,7 +327,7 @@ ol.Overlay.prototype.setOffset = function(offset) { * @api stable */ ol.Overlay.prototype.setPosition = function(position) { - this.set(ol.OverlayProperty.POSITION, position); + this.set(ol.Overlay.Property.POSITION, position); }; @@ -430,9 +398,10 @@ ol.Overlay.prototype.panIntoView_ = function() { * @private */ ol.Overlay.prototype.getRect_ = function(element, size) { + var global = ol.global; var box = element.getBoundingClientRect(); - var offsetX = box.left + ol.global.pageXOffset; - var offsetY = box.top + ol.global.pageYOffset; + var offsetX = box.left + global.pageXOffset; + var offsetY = box.top + global.pageYOffset; return [ offsetX, offsetY, @@ -444,13 +413,13 @@ ol.Overlay.prototype.getRect_ = function(element, size) { /** * Set the positioning for this overlay. - * @param {ol.OverlayPositioning} positioning how the overlay is + * @param {ol.Overlay.Positioning} positioning how the overlay is * positioned relative to its point on the map. * @observable * @api stable */ ol.Overlay.prototype.setPositioning = function(positioning) { - this.set(ol.OverlayProperty.POSITIONING, positioning); + this.set(ol.Overlay.Property.POSITIONING, positioning); }; @@ -500,9 +469,9 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { var offsetX = offset[0]; var offsetY = offset[1]; - if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT || - positioning == ol.OverlayPositioning.CENTER_RIGHT || - positioning == ol.OverlayPositioning.TOP_RIGHT) { + if (positioning == ol.Overlay.Positioning.BOTTOM_RIGHT || + positioning == ol.Overlay.Positioning.CENTER_RIGHT || + positioning == ol.Overlay.Positioning.TOP_RIGHT) { if (this.rendered_.left_ !== '') { this.rendered_.left_ = style.left = ''; } @@ -514,9 +483,9 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { if (this.rendered_.right_ !== '') { this.rendered_.right_ = style.right = ''; } - if (positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.TOP_CENTER) { + if (positioning == ol.Overlay.Positioning.BOTTOM_CENTER || + positioning == ol.Overlay.Positioning.CENTER_CENTER || + positioning == ol.Overlay.Positioning.TOP_CENTER) { offsetX -= this.element_.offsetWidth / 2; } var left = Math.round(pixel[0] + offsetX) + 'px'; @@ -524,9 +493,9 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { this.rendered_.left_ = style.left = left; } } - if (positioning == ol.OverlayPositioning.BOTTOM_LEFT || - positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.BOTTOM_RIGHT) { + if (positioning == ol.Overlay.Positioning.BOTTOM_LEFT || + positioning == ol.Overlay.Positioning.BOTTOM_CENTER || + positioning == ol.Overlay.Positioning.BOTTOM_RIGHT) { if (this.rendered_.top_ !== '') { this.rendered_.top_ = style.top = ''; } @@ -538,9 +507,9 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { if (this.rendered_.bottom_ !== '') { this.rendered_.bottom_ = style.bottom = ''; } - if (positioning == ol.OverlayPositioning.CENTER_LEFT || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.CENTER_RIGHT) { + if (positioning == ol.Overlay.Positioning.CENTER_LEFT || + positioning == ol.Overlay.Positioning.CENTER_CENTER || + positioning == ol.Overlay.Positioning.CENTER_RIGHT) { offsetY -= this.element_.offsetHeight / 2; } var top = Math.round(pixel[1] + offsetY) + 'px'; @@ -551,3 +520,34 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { this.setVisible(true); }; + + +/** + * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, + * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, + * `'top-center'`, `'top-right'` + * @enum {string} + */ +ol.Overlay.Positioning = { + BOTTOM_LEFT: 'bottom-left', + BOTTOM_CENTER: 'bottom-center', + BOTTOM_RIGHT: 'bottom-right', + CENTER_LEFT: 'center-left', + CENTER_CENTER: 'center-center', + CENTER_RIGHT: 'center-right', + TOP_LEFT: 'top-left', + TOP_CENTER: 'top-center', + TOP_RIGHT: 'top-right' +}; + + +/** + * @enum {string} + */ +ol.Overlay.Property = { + ELEMENT: 'element', + MAP: 'map', + OFFSET: 'offset', + POSITION: 'position', + POSITIONING: 'positioning' +}; diff --git a/src/ol/pointer/eventtype.js b/src/ol/pointer/eventtype.js new file mode 100644 index 0000000000..1c25d1d27b --- /dev/null +++ b/src/ol/pointer/eventtype.js @@ -0,0 +1,17 @@ +goog.provide('ol.pointer.EventType'); + + +/** + * Constants for event names. + * @enum {string} + */ +ol.pointer.EventType = { + POINTERMOVE: 'pointermove', + POINTERDOWN: 'pointerdown', + POINTERUP: 'pointerup', + POINTEROVER: 'pointerover', + POINTEROUT: 'pointerout', + POINTERENTER: 'pointerenter', + POINTERLEAVE: 'pointerleave', + POINTERCANCEL: 'pointercancel' +}; diff --git a/src/ol/pointer/pointereventhandler.js b/src/ol/pointer/pointereventhandler.js index c3f0199207..8a6d6b5031 100644 --- a/src/ol/pointer/pointereventhandler.js +++ b/src/ol/pointer/pointereventhandler.js @@ -35,6 +35,7 @@ goog.require('ol.events'); goog.require('ol.events.EventTarget'); goog.require('ol.has'); +goog.require('ol.pointer.EventType'); goog.require('ol.pointer.MouseSource'); goog.require('ol.pointer.MsSource'); goog.require('ol.pointer.NativeSource'); @@ -402,22 +403,6 @@ ol.pointer.PointerEventHandler.prototype.disposeInternal = function() { }; -/** - * Constants for event names. - * @enum {string} - */ -ol.pointer.EventType = { - POINTERMOVE: 'pointermove', - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - POINTERCANCEL: 'pointercancel' -}; - - /** * Properties to copy when cloning an event, with default values. * @type {Array.} diff --git a/src/ol/render/canvas/imagereplay.js b/src/ol/render/canvas/imagereplay.js new file mode 100644 index 0000000000..86ef562ce2 --- /dev/null +++ b/src/ol/render/canvas/imagereplay.js @@ -0,0 +1,271 @@ +goog.provide('ol.render.canvas.ImageReplay'); + +goog.require('ol'); +goog.require('ol.render.canvas.Instruction'); +goog.require('ol.render.canvas.Replay'); + + +/** + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @param {boolean} overlaps The replay can have overlapping geometries. + * @struct + */ +ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, overlaps) { + ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); + + /** + * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} + */ + this.hitDetectionImage_ = null; + + /** + * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} + */ + this.image_ = null; + + /** + * @private + * @type {number|undefined} + */ + this.anchorX_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.anchorY_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.height_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.opacity_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.originX_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.originY_ = undefined; + + /** + * @private + * @type {boolean|undefined} + */ + this.rotateWithView_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.rotation_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.scale_ = undefined; + + /** + * @private + * @type {boolean|undefined} + */ + this.snapToPixel_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.width_ = undefined; + +}; +ol.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @private + * @return {number} My end. + */ +ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { + return this.appendFlatCoordinates( + flatCoordinates, offset, end, stride, false); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) { + if (!this.image_) { + return; + } + ol.DEBUG && console.assert(this.anchorX_ !== undefined, + 'this.anchorX_ should be defined'); + ol.DEBUG && console.assert(this.anchorY_ !== undefined, + 'this.anchorY_ should be defined'); + ol.DEBUG && console.assert(this.height_ !== undefined, + 'this.height_ should be defined'); + ol.DEBUG && console.assert(this.opacity_ !== undefined, + 'this.opacity_ should be defined'); + ol.DEBUG && console.assert(this.originX_ !== undefined, + 'this.originX_ should be defined'); + ol.DEBUG && console.assert(this.originY_ !== undefined, + 'this.originY_ should be defined'); + ol.DEBUG && console.assert(this.rotateWithView_ !== undefined, + 'this.rotateWithView_ should be defined'); + ol.DEBUG && console.assert(this.rotation_ !== undefined, + 'this.rotation_ should be defined'); + ol.DEBUG && console.assert(this.scale_ !== undefined, + 'this.scale_ should be defined'); + ol.DEBUG && console.assert(this.width_ !== undefined, + 'this.width_ should be defined'); + this.beginGeometry(pointGeometry, feature); + var flatCoordinates = pointGeometry.getFlatCoordinates(); + var stride = pointGeometry.getStride(); + var myBegin = this.coordinates.length; + var myEnd = this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.instructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.hitDetectionInstructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, + this.hitDetectionImage_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.endGeometry(pointGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) { + if (!this.image_) { + return; + } + ol.DEBUG && console.assert(this.anchorX_ !== undefined, + 'this.anchorX_ should be defined'); + ol.DEBUG && console.assert(this.anchorY_ !== undefined, + 'this.anchorY_ should be defined'); + ol.DEBUG && console.assert(this.height_ !== undefined, + 'this.height_ should be defined'); + ol.DEBUG && console.assert(this.opacity_ !== undefined, + 'this.opacity_ should be defined'); + ol.DEBUG && console.assert(this.originX_ !== undefined, + 'this.originX_ should be defined'); + ol.DEBUG && console.assert(this.originY_ !== undefined, + 'this.originY_ should be defined'); + ol.DEBUG && console.assert(this.rotateWithView_ !== undefined, + 'this.rotateWithView_ should be defined'); + ol.DEBUG && console.assert(this.rotation_ !== undefined, + 'this.rotation_ should be defined'); + ol.DEBUG && console.assert(this.scale_ !== undefined, + 'this.scale_ should be defined'); + ol.DEBUG && console.assert(this.width_ !== undefined, + 'this.width_ should be defined'); + this.beginGeometry(multiPointGeometry, feature); + var flatCoordinates = multiPointGeometry.getFlatCoordinates(); + var stride = multiPointGeometry.getStride(); + var myBegin = this.coordinates.length; + var myEnd = this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.instructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.hitDetectionInstructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, + this.hitDetectionImage_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.endGeometry(multiPointGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ImageReplay.prototype.finish = function() { + this.reverseHitDetectionInstructions(); + // FIXME this doesn't really protect us against further calls to draw*Geometry + this.anchorX_ = undefined; + this.anchorY_ = undefined; + this.hitDetectionImage_ = null; + this.image_ = null; + this.height_ = undefined; + this.scale_ = undefined; + this.opacity_ = undefined; + this.originX_ = undefined; + this.originY_ = undefined; + this.rotateWithView_ = undefined; + this.rotation_ = undefined; + this.snapToPixel_ = undefined; + this.width_ = undefined; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) { + ol.DEBUG && console.assert(imageStyle, 'imageStyle should not be null'); + var anchor = imageStyle.getAnchor(); + ol.DEBUG && console.assert(anchor, 'anchor should not be null'); + var size = imageStyle.getSize(); + ol.DEBUG && console.assert(size, 'size should not be null'); + var hitDetectionImage = imageStyle.getHitDetectionImage(1); + ol.DEBUG && console.assert(hitDetectionImage, + 'hitDetectionImage should not be null'); + var image = imageStyle.getImage(1); + ol.DEBUG && console.assert(image, 'image should not be null'); + var origin = imageStyle.getOrigin(); + ol.DEBUG && console.assert(origin, 'origin should not be null'); + this.anchorX_ = anchor[0]; + this.anchorY_ = anchor[1]; + this.hitDetectionImage_ = hitDetectionImage; + this.image_ = image; + this.height_ = size[1]; + this.opacity_ = imageStyle.getOpacity(); + this.originX_ = origin[0]; + this.originY_ = origin[1]; + this.rotateWithView_ = imageStyle.getRotateWithView(); + this.rotation_ = imageStyle.getRotation(); + this.scale_ = imageStyle.getScale(); + this.snapToPixel_ = imageStyle.getSnapToPixel(); + this.width_ = size[0]; +}; diff --git a/src/ol/render/canvas/instruction.js b/src/ol/render/canvas/instruction.js new file mode 100644 index 0000000000..8985e59b97 --- /dev/null +++ b/src/ol/render/canvas/instruction.js @@ -0,0 +1,20 @@ +goog.provide('ol.render.canvas.Instruction'); + +/** + * @enum {number} + */ +ol.render.canvas.Instruction = { + BEGIN_GEOMETRY: 0, + BEGIN_PATH: 1, + CIRCLE: 2, + CLOSE_PATH: 3, + DRAW_IMAGE: 4, + DRAW_TEXT: 5, + END_GEOMETRY: 6, + FILL: 7, + MOVE_TO_LINE_TO: 8, + SET_FILL_STYLE: 9, + SET_STROKE_STYLE: 10, + SET_TEXT_STYLE: 11, + STROKE: 12 +}; diff --git a/src/ol/render/canvas/linestringreplay.js b/src/ol/render/canvas/linestringreplay.js new file mode 100644 index 0000000000..b0aa86c0fa --- /dev/null +++ b/src/ol/render/canvas/linestringreplay.js @@ -0,0 +1,249 @@ +goog.provide('ol.render.canvas.LineStringReplay'); + +goog.require('ol'); +goog.require('ol.array'); +goog.require('ol.color'); +goog.require('ol.extent'); +goog.require('ol.render.canvas'); +goog.require('ol.render.canvas.Instruction'); +goog.require('ol.render.canvas.Replay'); + + +/** + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @param {boolean} overlaps The replay can have overlapping geometries. + * @struct + */ +ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, overlaps) { + + ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); + + /** + * @private + * @type {ol.Extent} + */ + this.bufferedMaxExtent_ = null; + + /** + * @private + * @type {{currentStrokeStyle: (string|undefined), + * currentLineCap: (string|undefined), + * currentLineDash: Array., + * currentLineJoin: (string|undefined), + * currentLineWidth: (number|undefined), + * currentMiterLimit: (number|undefined), + * lastStroke: number, + * strokeStyle: (string|undefined), + * lineCap: (string|undefined), + * lineDash: Array., + * lineJoin: (string|undefined), + * lineWidth: (number|undefined), + * miterLimit: (number|undefined)}|null} + */ + this.state_ = { + currentStrokeStyle: undefined, + currentLineCap: undefined, + currentLineDash: null, + currentLineJoin: undefined, + currentLineWidth: undefined, + currentMiterLimit: undefined, + lastStroke: 0, + strokeStyle: undefined, + lineCap: undefined, + lineDash: null, + lineJoin: undefined, + lineWidth: undefined, + miterLimit: undefined + }; + +}; +ol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @private + * @return {number} end. + */ +ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) { + var myBegin = this.coordinates.length; + var myEnd = this.appendFlatCoordinates( + flatCoordinates, offset, end, stride, false); + var moveToLineToInstruction = + [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; + this.instructions.push(moveToLineToInstruction); + this.hitDetectionInstructions.push(moveToLineToInstruction); + return end; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() { + if (!this.bufferedMaxExtent_) { + this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); + if (this.maxLineWidth > 0) { + var width = this.resolution * (this.maxLineWidth + 1) / 2; + ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); + } + } + return this.bufferedMaxExtent_; +}; + + +/** + * @private + */ +ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { + var state = this.state_; + var strokeStyle = state.strokeStyle; + var lineCap = state.lineCap; + var lineDash = state.lineDash; + var lineJoin = state.lineJoin; + var lineWidth = state.lineWidth; + var miterLimit = state.miterLimit; + ol.DEBUG && console.assert(strokeStyle !== undefined, + 'strokeStyle should be defined'); + ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined'); + ol.DEBUG && console.assert(lineDash, 'lineDash should not be null'); + ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined'); + ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined'); + ol.DEBUG && console.assert(miterLimit !== undefined, 'miterLimit should be defined'); + if (state.currentStrokeStyle != strokeStyle || + state.currentLineCap != lineCap || + !ol.array.equals(state.currentLineDash, lineDash) || + state.currentLineJoin != lineJoin || + state.currentLineWidth != lineWidth || + state.currentMiterLimit != miterLimit) { + if (state.lastStroke != this.coordinates.length) { + this.instructions.push( + [ol.render.canvas.Instruction.STROKE]); + state.lastStroke = this.coordinates.length; + } + this.instructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + state.currentStrokeStyle = strokeStyle; + state.currentLineCap = lineCap; + state.currentLineDash = lineDash; + state.currentLineJoin = lineJoin; + state.currentLineWidth = lineWidth; + state.currentMiterLimit = miterLimit; + } +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + var strokeStyle = state.strokeStyle; + var lineWidth = state.lineWidth; + if (strokeStyle === undefined || lineWidth === undefined) { + return; + } + this.setStrokeStyle_(); + this.beginGeometry(lineStringGeometry, feature); + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + var flatCoordinates = lineStringGeometry.getFlatCoordinates(); + var stride = lineStringGeometry.getStride(); + this.drawFlatCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); + this.endGeometry(lineStringGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + var strokeStyle = state.strokeStyle; + var lineWidth = state.lineWidth; + if (strokeStyle === undefined || lineWidth === undefined) { + return; + } + this.setStrokeStyle_(); + this.beginGeometry(multiLineStringGeometry, feature); + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + var ends = multiLineStringGeometry.getEnds(); + var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); + var stride = multiLineStringGeometry.getStride(); + var offset = 0; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + offset = this.drawFlatCoordinates_( + flatCoordinates, offset, ends[i], stride); + } + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); + this.endGeometry(multiLineStringGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.LineStringReplay.prototype.finish = function() { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + if (state.lastStroke != this.coordinates.length) { + this.instructions.push([ol.render.canvas.Instruction.STROKE]); + } + this.reverseHitDetectionInstructions(); + this.state_ = null; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) { + ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); + ol.DEBUG && console.assert(!fillStyle, 'fillStyle should be null'); + ol.DEBUG && console.assert(strokeStyle, 'strokeStyle should not be null'); + var strokeStyleColor = strokeStyle.getColor(); + this.state_.strokeStyle = ol.color.asString(strokeStyleColor ? + strokeStyleColor : ol.render.canvas.defaultStrokeStyle); + var strokeStyleLineCap = strokeStyle.getLineCap(); + this.state_.lineCap = strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.canvas.defaultLineCap; + var strokeStyleLineDash = strokeStyle.getLineDash(); + this.state_.lineDash = strokeStyleLineDash ? + strokeStyleLineDash : ol.render.canvas.defaultLineDash; + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + this.state_.lineJoin = strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var strokeStyleWidth = strokeStyle.getWidth(); + this.state_.lineWidth = strokeStyleWidth !== undefined ? + strokeStyleWidth : ol.render.canvas.defaultLineWidth; + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; + + if (this.state_.lineWidth > this.maxLineWidth) { + this.maxLineWidth = this.state_.lineWidth; + // invalidate the buffered max extent cache + this.bufferedMaxExtent_ = null; + } +}; diff --git a/src/ol/render/canvas/polygonreplay.js b/src/ol/render/canvas/polygonreplay.js new file mode 100644 index 0000000000..53739428d1 --- /dev/null +++ b/src/ol/render/canvas/polygonreplay.js @@ -0,0 +1,381 @@ +goog.provide('ol.render.canvas.PolygonReplay'); + +goog.require('ol'); +goog.require('ol.color'); +goog.require('ol.colorlike'); +goog.require('ol.extent'); +goog.require('ol.geom.flat.simplify'); +goog.require('ol.render.canvas'); +goog.require('ol.render.canvas.Instruction'); +goog.require('ol.render.canvas.Replay'); + + +/** + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @param {boolean} overlaps The replay can have overlapping geometries. + * @struct + */ +ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) { + + ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); + + /** + * @private + * @type {ol.Extent} + */ + this.bufferedMaxExtent_ = null; + + /** + * @private + * @type {{currentFillStyle: (ol.ColorLike|undefined), + * currentStrokeStyle: (string|undefined), + * currentLineCap: (string|undefined), + * currentLineDash: Array., + * currentLineJoin: (string|undefined), + * currentLineWidth: (number|undefined), + * currentMiterLimit: (number|undefined), + * fillStyle: (ol.ColorLike|undefined), + * strokeStyle: (string|undefined), + * lineCap: (string|undefined), + * lineDash: Array., + * lineJoin: (string|undefined), + * lineWidth: (number|undefined), + * miterLimit: (number|undefined)}|null} + */ + this.state_ = { + currentFillStyle: undefined, + currentStrokeStyle: undefined, + currentLineCap: undefined, + currentLineDash: null, + currentLineJoin: undefined, + currentLineWidth: undefined, + currentMiterLimit: undefined, + fillStyle: undefined, + strokeStyle: undefined, + lineCap: undefined, + lineDash: null, + lineJoin: undefined, + lineWidth: undefined, + miterLimit: undefined + }; + +}; +ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.} ends Ends. + * @param {number} stride Stride. + * @private + * @return {number} End. + */ +ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) { + var state = this.state_; + var fill = state.fillStyle !== undefined; + var stroke = state.strokeStyle != undefined; + var numEnds = ends.length; + if (!fill && !stroke) { + return ends[numEnds - 1]; + } + var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; + this.instructions.push(beginPathInstruction); + this.hitDetectionInstructions.push(beginPathInstruction); + for (var i = 0; i < numEnds; ++i) { + var end = ends[i]; + var myBegin = this.coordinates.length; + var myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride, + // Performance optimization: only close the ring when we do not have a + // stroke. Otherwise closePath() will take care of that. + !stroke); + var moveToLineToInstruction = + [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; + this.instructions.push(moveToLineToInstruction); + this.hitDetectionInstructions.push(moveToLineToInstruction); + if (stroke) { + // Performance optimization: only call closePath() when we have a stroke. + // Otherwise the ring is closed already (see appendFlatCoordinates above). + var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; + this.instructions.push(closePathInstruction); + this.hitDetectionInstructions.push(closePathInstruction); + } + offset = end; + } + var fillInstruction = [ol.render.canvas.Instruction.FILL]; + this.hitDetectionInstructions.push(fillInstruction); + if (fill) { + this.instructions.push(fillInstruction); + } + if (stroke) { + ol.DEBUG && console.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; + this.instructions.push(strokeInstruction); + this.hitDetectionInstructions.push(strokeInstruction); + } + return offset; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; + } + if (strokeStyle !== undefined) { + ol.DEBUG && console.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(circleGeometry, feature); + // always fill the circle for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var flatCoordinates = circleGeometry.getFlatCoordinates(); + var stride = circleGeometry.getStride(); + var myBegin = this.coordinates.length; + this.appendFlatCoordinates( + flatCoordinates, 0, flatCoordinates.length, stride, false); + var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; + var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; + this.instructions.push(beginPathInstruction, circleInstruction); + this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); + var fillInstruction = [ol.render.canvas.Instruction.FILL]; + this.hitDetectionInstructions.push(fillInstruction); + if (state.fillStyle !== undefined) { + this.instructions.push(fillInstruction); + } + if (state.strokeStyle !== undefined) { + ol.DEBUG && console.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; + this.instructions.push(strokeInstruction); + this.hitDetectionInstructions.push(strokeInstruction); + } + this.endGeometry(circleGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; + } + if (strokeStyle !== undefined) { + ol.DEBUG && console.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(polygonGeometry, feature); + // always fill the polygon for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var ends = polygonGeometry.getEnds(); + var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); + var stride = polygonGeometry.getStride(); + this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride); + this.endGeometry(polygonGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) { + var state = this.state_; + ol.DEBUG && console.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; + } + if (strokeStyle !== undefined) { + ol.DEBUG && console.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(multiPolygonGeometry, feature); + // always fill the multi-polygon for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var endss = multiPolygonGeometry.getEndss(); + var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); + var stride = multiPolygonGeometry.getStride(); + var offset = 0; + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + offset = this.drawFlatCoordinatess_( + flatCoordinates, offset, endss[i], stride); + } + this.endGeometry(multiPolygonGeometry, feature); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.finish = function() { + ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); + this.reverseHitDetectionInstructions(); + this.state_ = null; + // We want to preserve topology when drawing polygons. Polygons are + // simplified using quantization and point elimination. However, we might + // have received a mix of quantized and non-quantized geometries, so ensure + // that all are quantized by quantizing all coordinates in the batch. + var tolerance = this.tolerance; + if (tolerance !== 0) { + var coordinates = this.coordinates; + var i, ii; + for (i = 0, ii = coordinates.length; i < ii; ++i) { + coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); + } + } +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() { + if (!this.bufferedMaxExtent_) { + this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); + if (this.maxLineWidth > 0) { + var width = this.resolution * (this.maxLineWidth + 1) / 2; + ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); + } + } + return this.bufferedMaxExtent_; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) { + ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); + ol.DEBUG && console.assert(fillStyle || strokeStyle, + 'fillStyle or strokeStyle should not be null'); + var state = this.state_; + if (fillStyle) { + var fillStyleColor = fillStyle.getColor(); + state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ? + fillStyleColor : ol.render.canvas.defaultFillStyle); + } else { + state.fillStyle = undefined; + } + if (strokeStyle) { + var strokeStyleColor = strokeStyle.getColor(); + state.strokeStyle = ol.color.asString(strokeStyleColor ? + strokeStyleColor : ol.render.canvas.defaultStrokeStyle); + var strokeStyleLineCap = strokeStyle.getLineCap(); + state.lineCap = strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.canvas.defaultLineCap; + var strokeStyleLineDash = strokeStyle.getLineDash(); + state.lineDash = strokeStyleLineDash ? + strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + state.lineJoin = strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var strokeStyleWidth = strokeStyle.getWidth(); + state.lineWidth = strokeStyleWidth !== undefined ? + strokeStyleWidth : ol.render.canvas.defaultLineWidth; + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + state.miterLimit = strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; + + if (state.lineWidth > this.maxLineWidth) { + this.maxLineWidth = state.lineWidth; + // invalidate the buffered max extent cache + this.bufferedMaxExtent_ = null; + } + } else { + state.strokeStyle = undefined; + state.lineCap = undefined; + state.lineDash = null; + state.lineJoin = undefined; + state.lineWidth = undefined; + state.miterLimit = undefined; + } +}; + + +/** + * @private + */ +ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { + var state = this.state_; + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + var lineCap = state.lineCap; + var lineDash = state.lineDash; + var lineJoin = state.lineJoin; + var lineWidth = state.lineWidth; + var miterLimit = state.miterLimit; + if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { + this.instructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); + state.currentFillStyle = state.fillStyle; + } + if (strokeStyle !== undefined) { + ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined'); + ol.DEBUG && console.assert(lineDash, 'lineDash should not be null'); + ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined'); + ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined'); + ol.DEBUG && console.assert(miterLimit !== undefined, + 'miterLimit should be defined'); + if (state.currentStrokeStyle != strokeStyle || + state.currentLineCap != lineCap || + state.currentLineDash != lineDash || + state.currentLineJoin != lineJoin || + state.currentLineWidth != lineWidth || + state.currentMiterLimit != miterLimit) { + this.instructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); + state.currentStrokeStyle = strokeStyle; + state.currentLineCap = lineCap; + state.currentLineDash = lineDash; + state.currentLineJoin = lineJoin; + state.currentLineWidth = lineWidth; + state.currentMiterLimit = miterLimit; + } + } +}; diff --git a/src/ol/render/canvas/replay.js b/src/ol/render/canvas/replay.js index 4b3c5b8f8a..8302579e8c 100644 --- a/src/ol/render/canvas/replay.js +++ b/src/ol/render/canvas/replay.js @@ -1,51 +1,19 @@ -// FIXME add option to apply snapToPixel to all coordinates? -// FIXME can eliminate empty set styles and strokes (when all geoms skipped) - goog.provide('ol.render.canvas.Replay'); -goog.provide('ol.render.canvas.ImageReplay'); -goog.provide('ol.render.canvas.LineStringReplay'); -goog.provide('ol.render.canvas.PolygonReplay'); -goog.provide('ol.render.canvas.ReplayGroup'); -goog.provide('ol.render.canvas.TextReplay'); goog.require('ol'); goog.require('ol.array'); -goog.require('ol.color'); goog.require('ol.colorlike'); -goog.require('ol.dom'); goog.require('ol.extent'); goog.require('ol.extent.Relationship'); -goog.require('ol.geom.flat.simplify'); goog.require('ol.geom.flat.transform'); goog.require('ol.has'); goog.require('ol.obj'); -goog.require('ol.render.ReplayGroup'); goog.require('ol.render.VectorContext'); goog.require('ol.render.canvas'); -goog.require('ol.render.replay'); +goog.require('ol.render.canvas.Instruction'); goog.require('ol.transform'); -/** - * @enum {number} - */ -ol.render.canvas.Instruction = { - BEGIN_GEOMETRY: 0, - BEGIN_PATH: 1, - CIRCLE: 2, - CLOSE_PATH: 3, - DRAW_IMAGE: 4, - DRAW_TEXT: 5, - END_GEOMETRY: 6, - FILL: 7, - MOVE_TO_LINE_TO: 8, - SET_FILL_STYLE: 9, - SET_STROKE_STYLE: 10, - SET_TEXT_STYLE: 11, - STROKE: 12 -}; - - /** * @constructor * @extends {ol.render.VectorContext} @@ -53,7 +21,6 @@ ol.render.canvas.Instruction = { * @param {ol.Extent} maxExtent Maximum extent. * @param {number} resolution Resolution. * @param {boolean} overlaps The replay can have overlapping geometries. - * @protected * @struct */ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) { @@ -78,12 +45,6 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) { */ this.overlaps = overlaps; - /** - * @private - * @type {ol.Extent} - */ - this.bufferedMaxExtent_ = null; - /** * @protected * @type {number} @@ -625,9 +586,9 @@ ol.render.canvas.Replay.prototype.replayHitDetection = function( /** - * @private + * Reverse the hit detection instructions. */ -ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = function() { +ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions = function() { var hitDetectionInstructions = this.hitDetectionInstructions; // step 1 - reverse array hitDetectionInstructions.reverse(); @@ -690,1463 +651,3 @@ ol.render.canvas.Replay.prototype.finish = ol.nullFunction; ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() { return this.maxExtent; }; - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @param {boolean} overlaps The replay can have overlapping geometries. - * @protected - * @struct - */ -ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, overlaps) { - ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); - - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.hitDetectionImage_ = null; - - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.image_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.anchorX_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.anchorY_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.height_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.opacity_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.originX_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.originY_ = undefined; - - /** - * @private - * @type {boolean|undefined} - */ - this.rotateWithView_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.rotation_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.scale_ = undefined; - - /** - * @private - * @type {boolean|undefined} - */ - this.snapToPixel_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.width_ = undefined; - -}; -ol.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} My end. - */ -ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { - return this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) { - if (!this.image_) { - return; - } - ol.DEBUG && console.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - ol.DEBUG && console.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - ol.DEBUG && console.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - ol.DEBUG && console.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - ol.DEBUG && console.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - ol.DEBUG && console.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - ol.DEBUG && console.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - ol.DEBUG && console.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - ol.DEBUG && console.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - ol.DEBUG && console.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(pointGeometry, feature); - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(pointGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) { - if (!this.image_) { - return; - } - ol.DEBUG && console.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - ol.DEBUG && console.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - ol.DEBUG && console.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - ol.DEBUG && console.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - ol.DEBUG && console.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - ol.DEBUG && console.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - ol.DEBUG && console.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - ol.DEBUG && console.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - ol.DEBUG && console.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - ol.DEBUG && console.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(multiPointGeometry, feature); - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(multiPointGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.finish = function() { - this.reverseHitDetectionInstructions_(); - // FIXME this doesn't really protect us against further calls to draw*Geometry - this.anchorX_ = undefined; - this.anchorY_ = undefined; - this.hitDetectionImage_ = null; - this.image_ = null; - this.height_ = undefined; - this.scale_ = undefined; - this.opacity_ = undefined; - this.originX_ = undefined; - this.originY_ = undefined; - this.rotateWithView_ = undefined; - this.rotation_ = undefined; - this.snapToPixel_ = undefined; - this.width_ = undefined; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) { - ol.DEBUG && console.assert(imageStyle, 'imageStyle should not be null'); - var anchor = imageStyle.getAnchor(); - ol.DEBUG && console.assert(anchor, 'anchor should not be null'); - var size = imageStyle.getSize(); - ol.DEBUG && console.assert(size, 'size should not be null'); - var hitDetectionImage = imageStyle.getHitDetectionImage(1); - ol.DEBUG && console.assert(hitDetectionImage, - 'hitDetectionImage should not be null'); - var image = imageStyle.getImage(1); - ol.DEBUG && console.assert(image, 'image should not be null'); - var origin = imageStyle.getOrigin(); - ol.DEBUG && console.assert(origin, 'origin should not be null'); - this.anchorX_ = anchor[0]; - this.anchorY_ = anchor[1]; - this.hitDetectionImage_ = hitDetectionImage; - this.image_ = image; - this.height_ = size[1]; - this.opacity_ = imageStyle.getOpacity(); - this.originX_ = origin[0]; - this.originY_ = origin[1]; - this.rotateWithView_ = imageStyle.getRotateWithView(); - this.rotation_ = imageStyle.getRotation(); - this.scale_ = imageStyle.getScale(); - this.snapToPixel_ = imageStyle.getSnapToPixel(); - this.width_ = size[0]; -}; - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @param {boolean} overlaps The replay can have overlapping geometries. - * @protected - * @struct - */ -ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, overlaps) { - - ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); - - /** - * @private - * @type {{currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array., - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * lastStroke: number, - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array., - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} - */ - this.state_ = { - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - lastStroke: 0, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; - -}; -ol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} end. - */ -ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) { - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - this.instructions.push(moveToLineToInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction); - return end; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); - } - } - return this.bufferedMaxExtent_; -}; - - -/** - * @private - */ -ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { - var state = this.state_; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - ol.DEBUG && console.assert(strokeStyle !== undefined, - 'strokeStyle should be defined'); - ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined'); - ol.DEBUG && console.assert(lineDash, 'lineDash should not be null'); - ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined'); - ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined'); - ol.DEBUG && console.assert(miterLimit !== undefined, 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - !ol.array.equals(state.currentLineDash, lineDash) || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - if (state.lastStroke != this.coordinates.length) { - this.instructions.push( - [ol.render.canvas.Instruction.STROKE]); - state.lastStroke = this.coordinates.length; - } - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(lineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var flatCoordinates = lineStringGeometry.getFlatCoordinates(); - var stride = lineStringGeometry.getStride(); - this.drawFlatCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(lineStringGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(multiLineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var ends = multiLineStringGeometry.getEnds(); - var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); - var stride = multiLineStringGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.drawFlatCoordinates_( - flatCoordinates, offset, ends[i], stride); - } - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(multiLineStringGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.finish = function() { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - if (state.lastStroke != this.coordinates.length) { - this.instructions.push([ol.render.canvas.Instruction.STROKE]); - } - this.reverseHitDetectionInstructions_(); - this.state_ = null; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) { - ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); - ol.DEBUG && console.assert(!fillStyle, 'fillStyle should be null'); - ol.DEBUG && console.assert(strokeStyle, 'strokeStyle should not be null'); - var strokeStyleColor = strokeStyle.getColor(); - this.state_.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - this.state_.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - this.state_.lineDash = strokeStyleLineDash ? - strokeStyleLineDash : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - this.state_.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - this.state_.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - - if (this.state_.lineWidth > this.maxLineWidth) { - this.maxLineWidth = this.state_.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; - } -}; - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @param {boolean} overlaps The replay can have overlapping geometries. - * @protected - * @struct - */ -ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) { - - ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); - - /** - * @private - * @type {{currentFillStyle: (ol.ColorLike|undefined), - * currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array., - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * fillStyle: (ol.ColorLike|undefined), - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array., - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} - */ - this.state_ = { - currentFillStyle: undefined, - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - fillStyle: undefined, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; - -}; -ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.} ends Ends. - * @param {number} stride Stride. - * @private - * @return {number} End. - */ -ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) { - var state = this.state_; - var fill = state.fillStyle !== undefined; - var stroke = state.strokeStyle != undefined; - var numEnds = ends.length; - if (!fill && !stroke) { - return ends[numEnds - 1]; - } - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - this.instructions.push(beginPathInstruction); - this.hitDetectionInstructions.push(beginPathInstruction); - for (var i = 0; i < numEnds; ++i) { - var end = ends[i]; - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride, - // Performance optimization: only close the ring when we do not have a - // stroke. Otherwise closePath() will take care of that. - !stroke); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - this.instructions.push(moveToLineToInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction); - if (stroke) { - // Performance optimization: only call closePath() when we have a stroke. - // Otherwise the ring is closed already (see appendFlatCoordinates above). - var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; - this.instructions.push(closePathInstruction); - this.hitDetectionInstructions.push(closePathInstruction); - } - offset = end; - } - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (fill) { - this.instructions.push(fillInstruction); - } - if (stroke) { - ol.DEBUG && console.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); - } - return offset; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - ol.DEBUG && console.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(circleGeometry, feature); - // always fill the circle for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var flatCoordinates = circleGeometry.getFlatCoordinates(); - var stride = circleGeometry.getStride(); - var myBegin = this.coordinates.length; - this.appendFlatCoordinates( - flatCoordinates, 0, flatCoordinates.length, stride, false); - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; - this.instructions.push(beginPathInstruction, circleInstruction); - this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); - } - if (state.strokeStyle !== undefined) { - ol.DEBUG && console.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); - } - this.endGeometry(circleGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - ol.DEBUG && console.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(polygonGeometry, feature); - // always fill the polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var ends = polygonGeometry.getEnds(); - var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); - var stride = polygonGeometry.getStride(); - this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride); - this.endGeometry(polygonGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) { - var state = this.state_; - ol.DEBUG && console.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - ol.DEBUG && console.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(multiPolygonGeometry, feature); - // always fill the multi-polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var endss = multiPolygonGeometry.getEndss(); - var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); - var stride = multiPolygonGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - offset = this.drawFlatCoordinatess_( - flatCoordinates, offset, endss[i], stride); - } - this.endGeometry(multiPolygonGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.finish = function() { - ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); - this.reverseHitDetectionInstructions_(); - this.state_ = null; - // We want to preserve topology when drawing polygons. Polygons are - // simplified using quantization and point elimination. However, we might - // have received a mix of quantized and non-quantized geometries, so ensure - // that all are quantized by quantizing all coordinates in the batch. - var tolerance = this.tolerance; - if (tolerance !== 0) { - var coordinates = this.coordinates; - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); - } - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); - } - } - return this.bufferedMaxExtent_; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) { - ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null'); - ol.DEBUG && console.assert(fillStyle || strokeStyle, - 'fillStyle or strokeStyle should not be null'); - var state = this.state_; - if (fillStyle) { - var fillStyleColor = fillStyle.getColor(); - state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ? - fillStyleColor : ol.render.canvas.defaultFillStyle); - } else { - state.fillStyle = undefined; - } - if (strokeStyle) { - var strokeStyleColor = strokeStyle.getColor(); - state.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - state.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - state.lineDash = strokeStyleLineDash ? - strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - state.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - state.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - state.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - - if (state.lineWidth > this.maxLineWidth) { - this.maxLineWidth = state.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; - } - } else { - state.strokeStyle = undefined; - state.lineCap = undefined; - state.lineDash = null; - state.lineJoin = undefined; - state.lineWidth = undefined; - state.miterLimit = undefined; - } -}; - - -/** - * @private - */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { - var state = this.state_; - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); - state.currentFillStyle = state.fillStyle; - } - if (strokeStyle !== undefined) { - ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined'); - ol.DEBUG && console.assert(lineDash, 'lineDash should not be null'); - ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined'); - ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined'); - ol.DEBUG && console.assert(miterLimit !== undefined, - 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - state.currentLineDash != lineDash || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } - } -}; - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @param {boolean} overlaps The replay can have overlapping geometries. - * @protected - * @struct - */ -ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, overlaps) { - - ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); - - /** - * @private - * @type {?ol.CanvasFillState} - */ - this.replayFillState_ = null; - - /** - * @private - * @type {?ol.CanvasStrokeState} - */ - this.replayStrokeState_ = null; - - /** - * @private - * @type {?ol.CanvasTextState} - */ - this.replayTextState_ = null; - - /** - * @private - * @type {string} - */ - this.text_ = ''; - - /** - * @private - * @type {number} - */ - this.textOffsetX_ = 0; - - /** - * @private - * @type {number} - */ - this.textOffsetY_ = 0; - - /** - * @private - * @type {boolean|undefined} - */ - this.textRotateWithView_ = undefined; - - /** - * @private - * @type {number} - */ - this.textRotation_ = 0; - - /** - * @private - * @type {number} - */ - this.textScale_ = 0; - - /** - * @private - * @type {?ol.CanvasFillState} - */ - this.textFillState_ = null; - - /** - * @private - * @type {?ol.CanvasStrokeState} - */ - this.textStrokeState_ = null; - - /** - * @private - * @type {?ol.CanvasTextState} - */ - this.textState_ = null; - -}; -ol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay); - - -/** - * @inheritDoc - */ -ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) { - if (this.text_ === '' || !this.textState_ || - (!this.textFillState_ && !this.textStrokeState_)) { - return; - } - if (this.textFillState_) { - this.setReplayFillState_(this.textFillState_); - } - if (this.textStrokeState_) { - this.setReplayStrokeState_(this.textStrokeState_); - } - this.setReplayTextState_(this.textState_); - this.beginGeometry(geometry, feature); - var myBegin = this.coordinates.length; - var myEnd = - this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); - var fill = !!this.textFillState_; - var stroke = !!this.textStrokeState_; - var drawTextInstruction = [ - ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, - this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, - fill, stroke, this.textRotateWithView_]; - this.instructions.push(drawTextInstruction); - this.hitDetectionInstructions.push(drawTextInstruction); - this.endGeometry(geometry, feature); -}; - - -/** - * @param {ol.CanvasFillState} fillState Fill state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayFillState_ = function(fillState) { - var replayFillState = this.replayFillState_; - if (replayFillState && - replayFillState.fillStyle == fillState.fillStyle) { - return; - } - var setFillStyleInstruction = - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle]; - this.instructions.push(setFillStyleInstruction); - this.hitDetectionInstructions.push(setFillStyleInstruction); - if (!replayFillState) { - this.replayFillState_ = { - fillStyle: fillState.fillStyle - }; - } else { - replayFillState.fillStyle = fillState.fillStyle; - } -}; - - -/** - * @param {ol.CanvasStrokeState} strokeState Stroke state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = function(strokeState) { - var replayStrokeState = this.replayStrokeState_; - if (replayStrokeState && - replayStrokeState.lineCap == strokeState.lineCap && - replayStrokeState.lineDash == strokeState.lineDash && - replayStrokeState.lineJoin == strokeState.lineJoin && - replayStrokeState.lineWidth == strokeState.lineWidth && - replayStrokeState.miterLimit == strokeState.miterLimit && - replayStrokeState.strokeStyle == strokeState.strokeStyle) { - return; - } - var setStrokeStyleInstruction = [ - ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle, - strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin, - strokeState.miterLimit, strokeState.lineDash, false - ]; - this.instructions.push(setStrokeStyleInstruction); - this.hitDetectionInstructions.push(setStrokeStyleInstruction); - if (!replayStrokeState) { - this.replayStrokeState_ = { - lineCap: strokeState.lineCap, - lineDash: strokeState.lineDash, - lineJoin: strokeState.lineJoin, - lineWidth: strokeState.lineWidth, - miterLimit: strokeState.miterLimit, - strokeStyle: strokeState.strokeStyle - }; - } else { - replayStrokeState.lineCap = strokeState.lineCap; - replayStrokeState.lineDash = strokeState.lineDash; - replayStrokeState.lineJoin = strokeState.lineJoin; - replayStrokeState.lineWidth = strokeState.lineWidth; - replayStrokeState.miterLimit = strokeState.miterLimit; - replayStrokeState.strokeStyle = strokeState.strokeStyle; - } -}; - - -/** - * @param {ol.CanvasTextState} textState Text state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayTextState_ = function(textState) { - var replayTextState = this.replayTextState_; - if (replayTextState && - replayTextState.font == textState.font && - replayTextState.textAlign == textState.textAlign && - replayTextState.textBaseline == textState.textBaseline) { - return; - } - var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE, - textState.font, textState.textAlign, textState.textBaseline]; - this.instructions.push(setTextStyleInstruction); - this.hitDetectionInstructions.push(setTextStyleInstruction); - if (!replayTextState) { - this.replayTextState_ = { - font: textState.font, - textAlign: textState.textAlign, - textBaseline: textState.textBaseline - }; - } else { - replayTextState.font = textState.font; - replayTextState.textAlign = textState.textAlign; - replayTextState.textBaseline = textState.textBaseline; - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { - if (!textStyle) { - this.text_ = ''; - } else { - var textFillStyle = textStyle.getFill(); - if (!textFillStyle) { - this.textFillState_ = null; - } else { - var textFillStyleColor = textFillStyle.getColor(); - var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ? - textFillStyleColor : ol.render.canvas.defaultFillStyle); - if (!this.textFillState_) { - this.textFillState_ = { - fillStyle: fillStyle - }; - } else { - var textFillState = this.textFillState_; - textFillState.fillStyle = fillStyle; - } - } - var textStrokeStyle = textStyle.getStroke(); - if (!textStrokeStyle) { - this.textStrokeState_ = null; - } else { - var textStrokeStyleColor = textStrokeStyle.getColor(); - var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); - var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); - var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); - var textStrokeStyleWidth = textStrokeStyle.getWidth(); - var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); - var lineCap = textStrokeStyleLineCap !== undefined ? - textStrokeStyleLineCap : ol.render.canvas.defaultLineCap; - var lineDash = textStrokeStyleLineDash ? - textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var lineJoin = textStrokeStyleLineJoin !== undefined ? - textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var lineWidth = textStrokeStyleWidth !== undefined ? - textStrokeStyleWidth : ol.render.canvas.defaultLineWidth; - var miterLimit = textStrokeStyleMiterLimit !== undefined ? - textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - var strokeStyle = ol.color.asString(textStrokeStyleColor ? - textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle); - if (!this.textStrokeState_) { - this.textStrokeState_ = { - lineCap: lineCap, - lineDash: lineDash, - lineJoin: lineJoin, - lineWidth: lineWidth, - miterLimit: miterLimit, - strokeStyle: strokeStyle - }; - } else { - var textStrokeState = this.textStrokeState_; - textStrokeState.lineCap = lineCap; - textStrokeState.lineDash = lineDash; - textStrokeState.lineJoin = lineJoin; - textStrokeState.lineWidth = lineWidth; - textStrokeState.miterLimit = miterLimit; - textStrokeState.strokeStyle = strokeStyle; - } - } - var textFont = textStyle.getFont(); - var textOffsetX = textStyle.getOffsetX(); - var textOffsetY = textStyle.getOffsetY(); - var textRotateWithView = textStyle.getRotateWithView(); - var textRotation = textStyle.getRotation(); - var textScale = textStyle.getScale(); - var textText = textStyle.getText(); - var textTextAlign = textStyle.getTextAlign(); - var textTextBaseline = textStyle.getTextBaseline(); - var font = textFont !== undefined ? - textFont : ol.render.canvas.defaultFont; - var textAlign = textTextAlign !== undefined ? - textTextAlign : ol.render.canvas.defaultTextAlign; - var textBaseline = textTextBaseline !== undefined ? - textTextBaseline : ol.render.canvas.defaultTextBaseline; - if (!this.textState_) { - this.textState_ = { - font: font, - textAlign: textAlign, - textBaseline: textBaseline - }; - } else { - var textState = this.textState_; - textState.font = font; - textState.textAlign = textAlign; - textState.textBaseline = textBaseline; - } - this.text_ = textText !== undefined ? textText : ''; - this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; - this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; - this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false; - this.textRotation_ = textRotation !== undefined ? textRotation : 0; - this.textScale_ = textScale !== undefined ? textScale : 1; - } -}; - - -/** - * @constructor - * @extends {ol.render.ReplayGroup} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @param {number} resolution Resolution. - * @param {boolean} overlaps The replay group can have overlapping geometries. - * @param {number=} opt_renderBuffer Optional rendering buffer. - * @struct - */ -ol.render.canvas.ReplayGroup = function( - tolerance, maxExtent, resolution, overlaps, opt_renderBuffer) { - ol.render.ReplayGroup.call(this); - - /** - * @private - * @type {number} - */ - this.tolerance_ = tolerance; - - /** - * @private - * @type {ol.Extent} - */ - this.maxExtent_ = maxExtent; - - /** - * @private - * @type {boolean} - */ - this.overlaps_ = overlaps; - - /** - * @private - * @type {number} - */ - this.resolution_ = resolution; - - /** - * @private - * @type {number|undefined} - */ - this.renderBuffer_ = opt_renderBuffer; - - /** - * @private - * @type {!Object.>} - */ - this.replaysByZIndex_ = {}; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1); - - /** - * @private - * @type {ol.Transform} - */ - this.hitDetectionTransform_ = ol.transform.create(); - -}; -ol.inherits(ol.render.canvas.ReplayGroup, ol.render.ReplayGroup); - - -/** - * FIXME empty description for jsdoc - */ -ol.render.canvas.ReplayGroup.prototype.finish = function() { - var zKey; - for (zKey in this.replaysByZIndex_) { - var replays = this.replaysByZIndex_[zKey]; - var replayKey; - for (replayKey in replays) { - replays[replayKey].finish(); - } - } -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {Object.} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature - * callback. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( - coordinate, resolution, rotation, skippedFeaturesHash, callback) { - - var transform = ol.transform.compose(this.hitDetectionTransform_, - 0.5, 0.5, - 1 / resolution, -1 / resolution, - -rotation, - -coordinate[0], -coordinate[1]); - - var context = this.hitDetectionContext_; - context.clearRect(0, 0, 1, 1); - - /** - * @type {ol.Extent} - */ - var hitExtent; - if (this.renderBuffer_ !== undefined) { - hitExtent = ol.extent.createEmpty(); - ol.extent.extendCoordinate(hitExtent, coordinate); - ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent); - } - - return this.replayHitDetection_(context, transform, rotation, - skippedFeaturesHash, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - var imageData = context.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - var result = callback(feature); - if (result) { - return result; - } - context.clearRect(0, 0, 1, 1); - } - }, hitExtent); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) { - var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; - var replays = this.replaysByZIndex_[zIndexKey]; - if (replays === undefined) { - replays = {}; - this.replaysByZIndex_[zIndexKey] = replays; - } - var replay = replays[replayType]; - if (replay === undefined) { - var Constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType]; - ol.DEBUG && console.assert(Constructor !== undefined, - replayType + - ' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_'); - replay = new Constructor(this.tolerance_, this.maxExtent_, - this.resolution_, this.overlaps_); - replays[replayType] = replay; - } - return replay; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { - return ol.obj.isEmpty(this.replaysByZIndex_); -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Transform} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.=} opt_replayTypes Ordered replay types - * to replay. Default is {@link ol.render.replay.ORDER} - */ -ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio, - transform, viewRotation, skippedFeaturesHash, opt_replayTypes) { - - /** @type {Array.} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - zs.sort(ol.array.numberSafeCompareFunction); - - // setup clipping so that the parts of over-simplified geometries are not - // visible outside the current extent when panning - var maxExtent = this.maxExtent_; - var minX = maxExtent[0]; - var minY = maxExtent[1]; - var maxX = maxExtent[2]; - var maxY = maxExtent[3]; - var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; - ol.geom.flat.transform.transform2D( - flatClipCoords, 0, 8, 2, transform, flatClipCoords); - context.save(); - context.beginPath(); - context.moveTo(flatClipCoords[0], flatClipCoords[1]); - context.lineTo(flatClipCoords[2], flatClipCoords[3]); - context.lineTo(flatClipCoords[4], flatClipCoords[5]); - context.lineTo(flatClipCoords[6], flatClipCoords[7]); - context.clip(); - - var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER; - var i, ii, j, jj, replays, replay; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = 0, jj = replayTypes.length; j < jj; ++j) { - replay = replays[replayTypes[j]]; - if (replay !== undefined) { - replay.replay(context, pixelRatio, transform, viewRotation, - skippedFeaturesHash); - } - } - } - - context.restore(); -}; - - -/** - * @private - * @param {CanvasRenderingContext2D} context Context. - * @param {ol.Transform} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback - * Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( - context, transform, viewRotation, skippedFeaturesHash, - featureCallback, opt_hitExtent) { - /** @type {Array.} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - zs.sort(function(a, b) { - return b - a; - }); - - var i, ii, j, replays, replay, result; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) { - replay = replays[ol.render.replay.ORDER[j]]; - if (replay !== undefined) { - result = replay.replayHitDetection(context, transform, viewRotation, - skippedFeaturesHash, featureCallback, opt_hitExtent); - if (result) { - return result; - } - } - } - } - return undefined; -}; - - -/** - * @const - * @private - * @type {Object.} - */ -ol.render.canvas.BATCH_CONSTRUCTORS_ = { - 'Image': ol.render.canvas.ImageReplay, - 'LineString': ol.render.canvas.LineStringReplay, - 'Polygon': ol.render.canvas.PolygonReplay, - 'Text': ol.render.canvas.TextReplay -}; diff --git a/src/ol/render/canvas/replaygroup.js b/src/ol/render/canvas/replaygroup.js new file mode 100644 index 0000000000..51a9646099 --- /dev/null +++ b/src/ol/render/canvas/replaygroup.js @@ -0,0 +1,289 @@ +goog.provide('ol.render.canvas.ReplayGroup'); + +goog.require('ol'); +goog.require('ol.array'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.geom.flat.transform'); +goog.require('ol.obj'); +goog.require('ol.render.ReplayGroup'); +goog.require('ol.render.canvas.ImageReplay'); +goog.require('ol.render.canvas.LineStringReplay'); +goog.require('ol.render.canvas.PolygonReplay'); +goog.require('ol.render.canvas.TextReplay'); +goog.require('ol.render.replay'); +goog.require('ol.transform'); + + +/** + * @constructor + * @extends {ol.render.ReplayGroup} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Max extent. + * @param {number} resolution Resolution. + * @param {boolean} overlaps The replay group can have overlapping geometries. + * @param {number=} opt_renderBuffer Optional rendering buffer. + * @struct + */ +ol.render.canvas.ReplayGroup = function( + tolerance, maxExtent, resolution, overlaps, opt_renderBuffer) { + ol.render.ReplayGroup.call(this); + + /** + * @private + * @type {number} + */ + this.tolerance_ = tolerance; + + /** + * @private + * @type {ol.Extent} + */ + this.maxExtent_ = maxExtent; + + /** + * @private + * @type {boolean} + */ + this.overlaps_ = overlaps; + + /** + * @private + * @type {number} + */ + this.resolution_ = resolution; + + /** + * @private + * @type {number|undefined} + */ + this.renderBuffer_ = opt_renderBuffer; + + /** + * @private + * @type {!Object.>} + */ + this.replaysByZIndex_ = {}; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1); + + /** + * @private + * @type {ol.Transform} + */ + this.hitDetectionTransform_ = ol.transform.create(); + +}; +ol.inherits(ol.render.canvas.ReplayGroup, ol.render.ReplayGroup); + + +/** + * FIXME empty description for jsdoc + */ +ol.render.canvas.ReplayGroup.prototype.finish = function() { + var zKey; + for (zKey in this.replaysByZIndex_) { + var replays = this.replaysByZIndex_[zKey]; + var replayKey; + for (replayKey in replays) { + replays[replayKey].finish(); + } + } +}; + + +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {Object.} skippedFeaturesHash Ids of features + * to skip. + * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature + * callback. + * @return {T|undefined} Callback result. + * @template T + */ +ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( + coordinate, resolution, rotation, skippedFeaturesHash, callback) { + + var transform = ol.transform.compose(this.hitDetectionTransform_, + 0.5, 0.5, + 1 / resolution, -1 / resolution, + -rotation, + -coordinate[0], -coordinate[1]); + + var context = this.hitDetectionContext_; + context.clearRect(0, 0, 1, 1); + + /** + * @type {ol.Extent} + */ + var hitExtent; + if (this.renderBuffer_ !== undefined) { + hitExtent = ol.extent.createEmpty(); + ol.extent.extendCoordinate(hitExtent, coordinate); + ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent); + } + + return this.replayHitDetection_(context, transform, rotation, + skippedFeaturesHash, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + var imageData = context.getImageData(0, 0, 1, 1).data; + if (imageData[3] > 0) { + var result = callback(feature); + if (result) { + return result; + } + context.clearRect(0, 0, 1, 1); + } + }, hitExtent); +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) { + var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; + var replays = this.replaysByZIndex_[zIndexKey]; + if (replays === undefined) { + replays = {}; + this.replaysByZIndex_[zIndexKey] = replays; + } + var replay = replays[replayType]; + if (replay === undefined) { + var Constructor = ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_[replayType]; + ol.DEBUG && console.assert(Constructor !== undefined, + replayType + + ' constructor missing from ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_'); + replay = new Constructor(this.tolerance_, this.maxExtent_, + this.resolution_, this.overlaps_); + replays[replayType] = replay; + } + return replay; +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { + return ol.obj.isEmpty(this.replaysByZIndex_); +}; + + +/** + * @param {CanvasRenderingContext2D} context Context. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.Transform} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.} skippedFeaturesHash Ids of features + * to skip. + * @param {Array.=} opt_replayTypes Ordered replay types + * to replay. Default is {@link ol.render.replay.ORDER} + */ +ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio, + transform, viewRotation, skippedFeaturesHash, opt_replayTypes) { + + /** @type {Array.} */ + var zs = Object.keys(this.replaysByZIndex_).map(Number); + zs.sort(ol.array.numberSafeCompareFunction); + + // setup clipping so that the parts of over-simplified geometries are not + // visible outside the current extent when panning + var maxExtent = this.maxExtent_; + var minX = maxExtent[0]; + var minY = maxExtent[1]; + var maxX = maxExtent[2]; + var maxY = maxExtent[3]; + var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; + ol.geom.flat.transform.transform2D( + flatClipCoords, 0, 8, 2, transform, flatClipCoords); + context.save(); + context.beginPath(); + context.moveTo(flatClipCoords[0], flatClipCoords[1]); + context.lineTo(flatClipCoords[2], flatClipCoords[3]); + context.lineTo(flatClipCoords[4], flatClipCoords[5]); + context.lineTo(flatClipCoords[6], flatClipCoords[7]); + context.clip(); + + var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER; + var i, ii, j, jj, replays, replay; + for (i = 0, ii = zs.length; i < ii; ++i) { + replays = this.replaysByZIndex_[zs[i].toString()]; + for (j = 0, jj = replayTypes.length; j < jj; ++j) { + replay = replays[replayTypes[j]]; + if (replay !== undefined) { + replay.replay(context, pixelRatio, transform, viewRotation, + skippedFeaturesHash); + } + } + } + + context.restore(); +}; + + +/** + * @private + * @param {CanvasRenderingContext2D} context Context. + * @param {ol.Transform} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.} skippedFeaturesHash Ids of features + * to skip. + * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback + * Feature callback. + * @param {ol.Extent=} opt_hitExtent Only check features that intersect this + * extent. + * @return {T|undefined} Callback result. + * @template T + */ +ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( + context, transform, viewRotation, skippedFeaturesHash, + featureCallback, opt_hitExtent) { + /** @type {Array.} */ + var zs = Object.keys(this.replaysByZIndex_).map(Number); + zs.sort(function(a, b) { + return b - a; + }); + + var i, ii, j, replays, replay, result; + for (i = 0, ii = zs.length; i < ii; ++i) { + replays = this.replaysByZIndex_[zs[i].toString()]; + for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) { + replay = replays[ol.render.replay.ORDER[j]]; + if (replay !== undefined) { + result = replay.replayHitDetection(context, transform, viewRotation, + skippedFeaturesHash, featureCallback, opt_hitExtent); + if (result) { + return result; + } + } + } + } + return undefined; +}; + + +/** + * @const + * @private + * @type {Object.} + */ +ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = { + 'Image': ol.render.canvas.ImageReplay, + 'LineString': ol.render.canvas.LineStringReplay, + 'Polygon': ol.render.canvas.PolygonReplay, + 'Text': ol.render.canvas.TextReplay +}; diff --git a/src/ol/render/canvas/textreplay.js b/src/ol/render/canvas/textreplay.js new file mode 100644 index 0000000000..7453382063 --- /dev/null +++ b/src/ol/render/canvas/textreplay.js @@ -0,0 +1,325 @@ +goog.provide('ol.render.canvas.TextReplay'); + +goog.require('ol'); +goog.require('ol.color'); +goog.require('ol.colorlike'); +goog.require('ol.render.canvas'); +goog.require('ol.render.canvas.Instruction'); +goog.require('ol.render.canvas.Replay'); + + +/** + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @param {boolean} overlaps The replay can have overlapping geometries. + * @struct + */ +ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, overlaps) { + + ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps); + + /** + * @private + * @type {?ol.CanvasFillState} + */ + this.replayFillState_ = null; + + /** + * @private + * @type {?ol.CanvasStrokeState} + */ + this.replayStrokeState_ = null; + + /** + * @private + * @type {?ol.CanvasTextState} + */ + this.replayTextState_ = null; + + /** + * @private + * @type {string} + */ + this.text_ = ''; + + /** + * @private + * @type {number} + */ + this.textOffsetX_ = 0; + + /** + * @private + * @type {number} + */ + this.textOffsetY_ = 0; + + /** + * @private + * @type {boolean|undefined} + */ + this.textRotateWithView_ = undefined; + + /** + * @private + * @type {number} + */ + this.textRotation_ = 0; + + /** + * @private + * @type {number} + */ + this.textScale_ = 0; + + /** + * @private + * @type {?ol.CanvasFillState} + */ + this.textFillState_ = null; + + /** + * @private + * @type {?ol.CanvasStrokeState} + */ + this.textStrokeState_ = null; + + /** + * @private + * @type {?ol.CanvasTextState} + */ + this.textState_ = null; + +}; +ol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay); + + +/** + * @inheritDoc + */ +ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) { + if (this.text_ === '' || !this.textState_ || + (!this.textFillState_ && !this.textStrokeState_)) { + return; + } + if (this.textFillState_) { + this.setReplayFillState_(this.textFillState_); + } + if (this.textStrokeState_) { + this.setReplayStrokeState_(this.textStrokeState_); + } + this.setReplayTextState_(this.textState_); + this.beginGeometry(geometry, feature); + var myBegin = this.coordinates.length; + var myEnd = + this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); + var fill = !!this.textFillState_; + var stroke = !!this.textStrokeState_; + var drawTextInstruction = [ + ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, + this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, + fill, stroke, this.textRotateWithView_]; + this.instructions.push(drawTextInstruction); + this.hitDetectionInstructions.push(drawTextInstruction); + this.endGeometry(geometry, feature); +}; + + +/** + * @param {ol.CanvasFillState} fillState Fill state. + * @private + */ +ol.render.canvas.TextReplay.prototype.setReplayFillState_ = function(fillState) { + var replayFillState = this.replayFillState_; + if (replayFillState && + replayFillState.fillStyle == fillState.fillStyle) { + return; + } + var setFillStyleInstruction = + [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle]; + this.instructions.push(setFillStyleInstruction); + this.hitDetectionInstructions.push(setFillStyleInstruction); + if (!replayFillState) { + this.replayFillState_ = { + fillStyle: fillState.fillStyle + }; + } else { + replayFillState.fillStyle = fillState.fillStyle; + } +}; + + +/** + * @param {ol.CanvasStrokeState} strokeState Stroke state. + * @private + */ +ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = function(strokeState) { + var replayStrokeState = this.replayStrokeState_; + if (replayStrokeState && + replayStrokeState.lineCap == strokeState.lineCap && + replayStrokeState.lineDash == strokeState.lineDash && + replayStrokeState.lineJoin == strokeState.lineJoin && + replayStrokeState.lineWidth == strokeState.lineWidth && + replayStrokeState.miterLimit == strokeState.miterLimit && + replayStrokeState.strokeStyle == strokeState.strokeStyle) { + return; + } + var setStrokeStyleInstruction = [ + ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle, + strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin, + strokeState.miterLimit, strokeState.lineDash, false + ]; + this.instructions.push(setStrokeStyleInstruction); + this.hitDetectionInstructions.push(setStrokeStyleInstruction); + if (!replayStrokeState) { + this.replayStrokeState_ = { + lineCap: strokeState.lineCap, + lineDash: strokeState.lineDash, + lineJoin: strokeState.lineJoin, + lineWidth: strokeState.lineWidth, + miterLimit: strokeState.miterLimit, + strokeStyle: strokeState.strokeStyle + }; + } else { + replayStrokeState.lineCap = strokeState.lineCap; + replayStrokeState.lineDash = strokeState.lineDash; + replayStrokeState.lineJoin = strokeState.lineJoin; + replayStrokeState.lineWidth = strokeState.lineWidth; + replayStrokeState.miterLimit = strokeState.miterLimit; + replayStrokeState.strokeStyle = strokeState.strokeStyle; + } +}; + + +/** + * @param {ol.CanvasTextState} textState Text state. + * @private + */ +ol.render.canvas.TextReplay.prototype.setReplayTextState_ = function(textState) { + var replayTextState = this.replayTextState_; + if (replayTextState && + replayTextState.font == textState.font && + replayTextState.textAlign == textState.textAlign && + replayTextState.textBaseline == textState.textBaseline) { + return; + } + var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE, + textState.font, textState.textAlign, textState.textBaseline]; + this.instructions.push(setTextStyleInstruction); + this.hitDetectionInstructions.push(setTextStyleInstruction); + if (!replayTextState) { + this.replayTextState_ = { + font: textState.font, + textAlign: textState.textAlign, + textBaseline: textState.textBaseline + }; + } else { + replayTextState.font = textState.font; + replayTextState.textAlign = textState.textAlign; + replayTextState.textBaseline = textState.textBaseline; + } +}; + + +/** + * @inheritDoc + */ +ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { + if (!textStyle) { + this.text_ = ''; + } else { + var textFillStyle = textStyle.getFill(); + if (!textFillStyle) { + this.textFillState_ = null; + } else { + var textFillStyleColor = textFillStyle.getColor(); + var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ? + textFillStyleColor : ol.render.canvas.defaultFillStyle); + if (!this.textFillState_) { + this.textFillState_ = { + fillStyle: fillStyle + }; + } else { + var textFillState = this.textFillState_; + textFillState.fillStyle = fillStyle; + } + } + var textStrokeStyle = textStyle.getStroke(); + if (!textStrokeStyle) { + this.textStrokeState_ = null; + } else { + var textStrokeStyleColor = textStrokeStyle.getColor(); + var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); + var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); + var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); + var textStrokeStyleWidth = textStrokeStyle.getWidth(); + var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); + var lineCap = textStrokeStyleLineCap !== undefined ? + textStrokeStyleLineCap : ol.render.canvas.defaultLineCap; + var lineDash = textStrokeStyleLineDash ? + textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; + var lineJoin = textStrokeStyleLineJoin !== undefined ? + textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var lineWidth = textStrokeStyleWidth !== undefined ? + textStrokeStyleWidth : ol.render.canvas.defaultLineWidth; + var miterLimit = textStrokeStyleMiterLimit !== undefined ? + textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; + var strokeStyle = ol.color.asString(textStrokeStyleColor ? + textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle); + if (!this.textStrokeState_) { + this.textStrokeState_ = { + lineCap: lineCap, + lineDash: lineDash, + lineJoin: lineJoin, + lineWidth: lineWidth, + miterLimit: miterLimit, + strokeStyle: strokeStyle + }; + } else { + var textStrokeState = this.textStrokeState_; + textStrokeState.lineCap = lineCap; + textStrokeState.lineDash = lineDash; + textStrokeState.lineJoin = lineJoin; + textStrokeState.lineWidth = lineWidth; + textStrokeState.miterLimit = miterLimit; + textStrokeState.strokeStyle = strokeStyle; + } + } + var textFont = textStyle.getFont(); + var textOffsetX = textStyle.getOffsetX(); + var textOffsetY = textStyle.getOffsetY(); + var textRotateWithView = textStyle.getRotateWithView(); + var textRotation = textStyle.getRotation(); + var textScale = textStyle.getScale(); + var textText = textStyle.getText(); + var textTextAlign = textStyle.getTextAlign(); + var textTextBaseline = textStyle.getTextBaseline(); + var font = textFont !== undefined ? + textFont : ol.render.canvas.defaultFont; + var textAlign = textTextAlign !== undefined ? + textTextAlign : ol.render.canvas.defaultTextAlign; + var textBaseline = textTextBaseline !== undefined ? + textTextBaseline : ol.render.canvas.defaultTextBaseline; + if (!this.textState_) { + this.textState_ = { + font: font, + textAlign: textAlign, + textBaseline: textBaseline + }; + } else { + var textState = this.textState_; + textState.font = font; + textState.textAlign = textAlign; + textState.textBaseline = textBaseline; + } + this.text_ = textText !== undefined ? textText : ''; + this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; + this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; + this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false; + this.textRotation_ = textRotation !== undefined ? textRotation : 0; + this.textScale_ = textScale !== undefined ? textScale : 1; + } +}; diff --git a/src/ol/renderer/canvas/vectortilelayer.js b/src/ol/renderer/canvas/vectortilelayer.js index 780a0603b0..f22f19a72d 100644 --- a/src/ol/renderer/canvas/vectortilelayer.js +++ b/src/ol/renderer/canvas/vectortilelayer.js @@ -5,6 +5,7 @@ goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.proj'); goog.require('ol.proj.Units'); +goog.require('ol.layer.VectorTile'); goog.require('ol.render.EventType'); goog.require('ol.render.ReplayType'); goog.require('ol.render.canvas'); @@ -59,7 +60,7 @@ ol.renderer.canvas.VectorTileLayer = function(layer) { // Use lower resolution for pure vector rendering. Closest resolution otherwise. this.zDirection = - layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0; + layer.getRenderMode() == ol.layer.VectorTile.RenderType.VECTOR ? 1 : 0; }; ol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer); @@ -81,10 +82,10 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function( } var renderMode = this.getLayer().getRenderMode(); - if (renderMode !== ol.layer.VectorTileRenderType.VECTOR) { + if (renderMode !== ol.layer.VectorTile.RenderType.VECTOR) { this.renderTileImages(context, frameState, layerState); } - if (renderMode !== ol.layer.VectorTileRenderType.IMAGE) { + if (renderMode !== ol.layer.VectorTile.RenderType.IMAGE) { this.renderTileReplays_(context, frameState, layerState); } diff --git a/src/ol/source/source.js b/src/ol/source/source.js index acfd9b21fa..6fd4cdf57f 100644 --- a/src/ol/source/source.js +++ b/src/ol/source/source.js @@ -1,22 +1,10 @@ goog.provide('ol.source.Source'); -goog.provide('ol.source.State'); goog.require('ol'); goog.require('ol.Attribution'); goog.require('ol.Object'); goog.require('ol.proj'); - - -/** - * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. - * @enum {string} - */ -ol.source.State = { - UNDEFINED: 'undefined', - LOADING: 'loading', - READY: 'ready', - ERROR: 'error' -}; +goog.require('ol.source.State'); /** diff --git a/src/ol/source/state.js b/src/ol/source/state.js new file mode 100644 index 0000000000..e53aa054d2 --- /dev/null +++ b/src/ol/source/state.js @@ -0,0 +1,14 @@ +goog.provide('ol.source.State'); + + +/** + * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. + * @enum {string} + */ +ol.source.State = { + UNDEFINED: 'undefined', + LOADING: 'loading', + READY: 'ready', + ERROR: 'error' +}; + diff --git a/src/ol/source/tile.js b/src/ol/source/tile.js index 1772e3a6c5..8211d28cfd 100644 --- a/src/ol/source/tile.js +++ b/src/ol/source/tile.js @@ -1,5 +1,4 @@ goog.provide('ol.source.Tile'); -goog.provide('ol.source.TileEvent'); goog.require('ol'); goog.require('ol.Tile'); @@ -318,11 +317,11 @@ ol.source.Tile.prototype.useTile = ol.nullFunction; * * @constructor * @extends {ol.events.Event} - * @implements {oli.source.TileEvent} + * @implements {oli.source.Tile.Event} * @param {string} type Type. * @param {ol.Tile} tile The tile. */ -ol.source.TileEvent = function(type, tile) { +ol.source.Tile.Event = function(type, tile) { ol.events.Event.call(this, type); @@ -334,31 +333,31 @@ ol.source.TileEvent = function(type, tile) { this.tile = tile; }; -ol.inherits(ol.source.TileEvent, ol.events.Event); +ol.inherits(ol.source.Tile.Event, ol.events.Event); /** * @enum {string} */ -ol.source.TileEventType = { +ol.source.Tile.EventType = { /** * Triggered when a tile starts loading. - * @event ol.source.TileEvent#tileloadstart + * @event ol.source.Tile.Event#tileloadstart * @api stable */ TILELOADSTART: 'tileloadstart', /** * Triggered when a tile finishes loading. - * @event ol.source.TileEvent#tileloadend + * @event ol.source.Tile.Event#tileloadend * @api stable */ TILELOADEND: 'tileloadend', /** * Triggered if tile loading results in an error. - * @event ol.source.TileEvent#tileloaderror + * @event ol.source.Tile.Event#tileloaderror * @api stable */ TILELOADERROR: 'tileloaderror' diff --git a/src/ol/source/tiledebug.js b/src/ol/source/tiledebug.js index 4d40bb02ff..0ef9e0439c 100644 --- a/src/ol/source/tiledebug.js +++ b/src/ol/source/tiledebug.js @@ -7,71 +7,6 @@ goog.require('ol.size'); goog.require('ol.source.Tile'); -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {string} text Text. - * @private - */ -ol.DebugTile_ = function(tileCoord, tileSize, text) { - - ol.Tile.call(this, tileCoord, ol.Tile.State.LOADED); - - /** - * @private - * @type {ol.Size} - */ - this.tileSize_ = tileSize; - - /** - * @private - * @type {string} - */ - this.text_ = text; - - /** - * @private - * @type {Object.} - */ - this.canvasByContext_ = {}; - -}; -ol.inherits(ol.DebugTile_, ol.Tile); - - -/** - * Get the image element for this tile. - * @param {Object=} opt_context Optional context. Only used by the DOM - * renderer. - * @return {HTMLCanvasElement} Image. - */ -ol.DebugTile_.prototype.getImage = function(opt_context) { - var key = opt_context !== undefined ? ol.getUid(opt_context) : -1; - if (key in this.canvasByContext_) { - return this.canvasByContext_[key]; - } else { - - var tileSize = this.tileSize_; - var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]); - - context.strokeStyle = 'black'; - context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); - - context.fillStyle = 'black'; - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.font = '24px sans-serif'; - context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2); - - this.canvasByContext_[key] = context.canvas; - return context.canvas; - - } -}; - - /** * @classdesc * A pseudo tile source, which does not fetch tiles from a server, but renders @@ -104,15 +39,80 @@ ol.inherits(ol.source.TileDebug, ol.source.Tile); ol.source.TileDebug.prototype.getTile = function(z, x, y) { var tileCoordKey = this.getKeyZXY(z, x, y); if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey)); + return /** @type {!ol.source.TileDebug.Tile_} */ (this.tileCache.get(tileCoordKey)); } else { var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z)); var tileCoord = [z, x, y]; var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord); var text = !textTileCoord ? '' : this.getTileCoordForTileUrlFunction(textTileCoord).toString(); - var tile = new ol.DebugTile_(tileCoord, tileSize, text); + var tile = new ol.source.TileDebug.Tile_(tileCoord, tileSize, text); this.tileCache.set(tileCoordKey, tile); return tile; } }; + + +/** + * @constructor + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.Size} tileSize Tile size. + * @param {string} text Text. + * @private + */ +ol.source.TileDebug.Tile_ = function(tileCoord, tileSize, text) { + + ol.Tile.call(this, tileCoord, ol.Tile.State.LOADED); + + /** + * @private + * @type {ol.Size} + */ + this.tileSize_ = tileSize; + + /** + * @private + * @type {string} + */ + this.text_ = text; + + /** + * @private + * @type {Object.} + */ + this.canvasByContext_ = {}; + +}; +ol.inherits(ol.source.TileDebug.Tile_, ol.Tile); + + +/** + * Get the image element for this tile. + * @param {Object=} opt_context Optional context. Only used by the DOM + * renderer. + * @return {HTMLCanvasElement} Image. + */ +ol.source.TileDebug.Tile_.prototype.getImage = function(opt_context) { + var key = opt_context !== undefined ? ol.getUid(opt_context) : -1; + if (key in this.canvasByContext_) { + return this.canvasByContext_[key]; + } else { + + var tileSize = this.tileSize_; + var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]); + + context.strokeStyle = 'black'; + context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); + + context.fillStyle = 'black'; + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.font = '24px sans-serif'; + context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2); + + this.canvasByContext_[key] = context.canvas; + return context.canvas; + + } +}; diff --git a/src/ol/source/tileimage.js b/src/ol/source/tileimage.js index 132055da5a..dba039aa93 100644 --- a/src/ol/source/tileimage.js +++ b/src/ol/source/tileimage.js @@ -17,7 +17,7 @@ goog.require('ol.tilegrid'); * Base class for sources providing images divided into a tile grid. * * @constructor - * @fires ol.source.TileEvent + * @fires ol.source.Tile.Event * @extends {ol.source.UrlTile} * @param {olx.source.TileImageOptions} options Image tile options. * @api diff --git a/src/ol/source/tilejson.js b/src/ol/source/tilejson.js index 5b9ff62c57..2c1e8677fb 100644 --- a/src/ol/source/tilejson.js +++ b/src/ol/source/tilejson.js @@ -5,7 +5,6 @@ */ goog.provide('ol.source.TileJSON'); -goog.provide('ol.tilejson'); goog.require('ol'); goog.require('ol.Attribution'); diff --git a/src/ol/source/tileutfgrid.js b/src/ol/source/tileutfgrid.js index 13a1e8aef8..5bef4b55db 100644 --- a/src/ol/source/tileutfgrid.js +++ b/src/ol/source/tileutfgrid.js @@ -134,7 +134,7 @@ ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function( if (this.tileGrid) { var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution( coordinate, resolution); - var tile = /** @type {!ol.source.TileUTFGridTile_} */(this.getTile( + var tile = /** @type {!ol.source.TileUTFGrid.Tile_} */(this.getTile( tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection())); tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request); } else { @@ -234,7 +234,7 @@ ol.source.TileUTFGrid.prototype.getTile = function(z, x, y, pixelRatio, projecti var urlTileCoord = this.getTileCoordForTileUrlFunction(tileCoord, projection); var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection); - var tile = new ol.source.TileUTFGridTile_( + var tile = new ol.source.TileUTFGrid.Tile_( tileCoord, tileUrl !== undefined ? ol.Tile.State.IDLE : ol.Tile.State.EMPTY, tileUrl !== undefined ? tileUrl : '', @@ -269,7 +269,7 @@ ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { * @param {boolean} jsonp Load the tile as a script. * @private */ -ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive, jsonp) { +ol.source.TileUTFGrid.Tile_ = function(tileCoord, state, src, extent, preemptive, jsonp) { ol.Tile.call(this, tileCoord, state); @@ -317,7 +317,7 @@ ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive, this.jsonp_ = jsonp; }; -ol.inherits(ol.source.TileUTFGridTile_, ol.Tile); +ol.inherits(ol.source.TileUTFGrid.Tile_, ol.Tile); /** @@ -326,7 +326,7 @@ ol.inherits(ol.source.TileUTFGridTile_, ol.Tile); * renderer. * @return {Image} Image. */ -ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) { +ol.source.TileUTFGrid.Tile_.prototype.getImage = function(opt_context) { return null; }; @@ -336,7 +336,7 @@ ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) { * @param {ol.Coordinate} coordinate Coordinate. * @return {*} The data. */ -ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) { +ol.source.TileUTFGrid.Tile_.prototype.getData = function(coordinate) { if (!this.grid_ || !this.keys_) { return null; } @@ -383,7 +383,7 @@ ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) { * The tile data is requested if not yet loaded. * @template T */ -ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = function(coordinate, callback, opt_this, opt_request) { +ol.source.TileUTFGrid.Tile_.prototype.forDataAtCoordinate = function(coordinate, callback, opt_this, opt_request) { if (this.state == ol.Tile.State.IDLE && opt_request === true) { ol.events.listenOnce(this, ol.events.EventType.CHANGE, function(e) { callback.call(opt_this, this.getData(coordinate)); @@ -404,7 +404,7 @@ ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = function(coordinate, /** * @inheritDoc */ -ol.source.TileUTFGridTile_.prototype.getKey = function() { +ol.source.TileUTFGrid.Tile_.prototype.getKey = function() { return this.src_; }; @@ -412,7 +412,7 @@ ol.source.TileUTFGridTile_.prototype.getKey = function() { /** * @private */ -ol.source.TileUTFGridTile_.prototype.handleError_ = function() { +ol.source.TileUTFGrid.Tile_.prototype.handleError_ = function() { this.state = ol.Tile.State.ERROR; this.changed(); }; @@ -422,7 +422,7 @@ ol.source.TileUTFGridTile_.prototype.handleError_ = function() { * @param {!UTFGridJSON} json UTFGrid data. * @private */ -ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { +ol.source.TileUTFGrid.Tile_.prototype.handleLoad_ = function(json) { this.grid_ = json.grid; this.keys_ = json.keys; this.data_ = json.data; @@ -435,7 +435,7 @@ ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { /** * @private */ -ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { +ol.source.TileUTFGrid.Tile_.prototype.loadInternal_ = function() { if (this.state == ol.Tile.State.IDLE) { this.state = ol.Tile.State.LOADING; if (this.jsonp_) { @@ -456,7 +456,7 @@ ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { * @private * @param {Event} event The load event. */ -ol.source.TileUTFGridTile_.prototype.onXHRLoad_ = function(event) { +ol.source.TileUTFGrid.Tile_.prototype.onXHRLoad_ = function(event) { var client = /** @type {XMLHttpRequest} */ (event.target); // status will be 0 for file:// urls if (!client.status || client.status >= 200 && client.status < 300) { @@ -478,7 +478,7 @@ ol.source.TileUTFGridTile_.prototype.onXHRLoad_ = function(event) { * @private * @param {Event} event The error event. */ -ol.source.TileUTFGridTile_.prototype.onXHRError_ = function(event) { +ol.source.TileUTFGrid.Tile_.prototype.onXHRError_ = function(event) { this.handleError_(); }; @@ -486,7 +486,7 @@ ol.source.TileUTFGridTile_.prototype.onXHRError_ = function(event) { /** * Load not yet loaded URI. */ -ol.source.TileUTFGridTile_.prototype.load = function() { +ol.source.TileUTFGrid.Tile_.prototype.load = function() { if (this.preemptive_) { this.loadInternal_(); } diff --git a/src/ol/source/urltile.js b/src/ol/source/urltile.js index 1cbc28bc19..11c66bed3b 100644 --- a/src/ol/source/urltile.js +++ b/src/ol/source/urltile.js @@ -4,7 +4,6 @@ goog.require('ol'); goog.require('ol.Tile'); goog.require('ol.TileUrlFunction'); goog.require('ol.source.Tile'); -goog.require('ol.source.TileEvent'); /** @@ -12,7 +11,7 @@ goog.require('ol.source.TileEvent'); * Base class for sources providing tiles divided into a tile grid over http. * * @constructor - * @fires ol.source.TileEvent + * @fires ol.source.Tile.Event * @extends {ol.source.Tile} * @param {ol.SourceUrlTileOptions} options Image tile options. */ @@ -112,15 +111,15 @@ ol.source.UrlTile.prototype.handleTileChange = function(event) { switch (tile.getState()) { case ol.Tile.State.LOADING: this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADSTART, tile)); + new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADSTART, tile)); break; case ol.Tile.State.LOADED: this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADEND, tile)); + new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADEND, tile)); break; case ol.Tile.State.ERROR: this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADERROR, tile)); + new ol.source.Tile.Event(ol.source.Tile.EventType.TILELOADERROR, tile)); break; default: // pass diff --git a/src/ol/source/vectortile.js b/src/ol/source/vectortile.js index cf972b0c39..b6482bde47 100644 --- a/src/ol/source/vectortile.js +++ b/src/ol/source/vectortile.js @@ -21,7 +21,7 @@ goog.require('ol.source.UrlTile'); * editing. * * @constructor - * @fires ol.source.TileEvent + * @fires ol.source.Tile.Event * @extends {ol.source.UrlTile} * @param {olx.source.VectorTileOptions} options Vector tile options. * @api diff --git a/src/ol/source/wmts.js b/src/ol/source/wmts.js index 454404c05f..147d6e4688 100644 --- a/src/ol/source/wmts.js +++ b/src/ol/source/wmts.js @@ -1,5 +1,4 @@ goog.provide('ol.source.WMTS'); -goog.provide('ol.source.WMTSRequestEncoding'); goog.require('ol'); goog.require('ol.TileUrlFunction'); @@ -12,16 +11,6 @@ goog.require('ol.tilegrid.WMTS'); goog.require('ol.uri'); -/** - * Request encoding. One of 'KVP', 'REST'. - * @enum {string} - */ -ol.source.WMTSRequestEncoding = { - KVP: 'KVP', // see spec §8 - REST: 'REST' // see spec §10 -}; - - /** * @classdesc * Layer source for tile data from WMTS servers. @@ -81,11 +70,11 @@ ol.source.WMTS = function(options) { /** * @private - * @type {ol.source.WMTSRequestEncoding} + * @type {ol.source.WMTS.RequestEncoding} */ this.requestEncoding_ = options.requestEncoding !== undefined ? - /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) : - ol.source.WMTSRequestEncoding.KVP; + /** @type {ol.source.WMTS.RequestEncoding} */ (options.requestEncoding) : + ol.source.WMTS.RequestEncoding.KVP; var requestEncoding = this.requestEncoding_; @@ -101,7 +90,7 @@ ol.source.WMTS = function(options) { 'tilematrixset': this.matrixSet_ }; - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + if (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) { ol.obj.assign(context, { 'Service': 'WMTS', 'Request': 'GetTile', @@ -122,7 +111,7 @@ ol.source.WMTS = function(options) { // order conforms to wmts spec guidance, and so that we can avoid to escape // special template params - template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? + template = (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) ? ol.uri.appendParams(template, context) : template.replace(/\{(\w+?)\}/g, function(m, p) { return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m; @@ -146,7 +135,7 @@ ol.source.WMTS = function(options) { }; ol.obj.assign(localContext, dimensions); var url = template; - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + if (requestEncoding == ol.source.WMTS.RequestEncoding.KVP) { url = ol.uri.appendParams(url, localContext); } else { url = url.replace(/\{(\w+?)\}/g, function(m, p) { @@ -229,7 +218,7 @@ ol.source.WMTS.prototype.getMatrixSet = function() { /** * Return the request encoding, either "KVP" or "REST". - * @return {ol.source.WMTSRequestEncoding} Request encoding. + * @return {ol.source.WMTS.RequestEncoding} Request encoding. * @api */ ol.source.WMTS.prototype.getRequestEncoding = function() { @@ -442,8 +431,8 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { // requestEncoding not provided, use the first encoding from the list requestEncoding = encodings[0]; } - if (requestEncoding === ol.source.WMTSRequestEncoding.KVP) { - if (ol.array.includes(encodings, ol.source.WMTSRequestEncoding.KVP)) { + if (requestEncoding === ol.source.WMTS.RequestEncoding.KVP) { + if (ol.array.includes(encodings, ol.source.WMTS.RequestEncoding.KVP)) { urls.push(/** @type {string} */ (gets[i]['href'])); } } else { @@ -452,7 +441,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { } } if (urls.length === 0) { - requestEncoding = ol.source.WMTSRequestEncoding.REST; + requestEncoding = ol.source.WMTS.RequestEncoding.REST; l['ResourceURL'].forEach(function(element) { if (element['resourceType'] === 'tile') { format = element['format']; @@ -476,3 +465,13 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { }; }; + + +/** + * Request encoding. One of 'KVP', 'REST'. + * @enum {string} + */ +ol.source.WMTS.RequestEncoding = { + KVP: 'KVP', // see spec §8 + REST: 'REST' // see spec §10 +}; diff --git a/src/ol/source/zoomify.js b/src/ol/source/zoomify.js index 173647a9f4..932ffc9a61 100644 --- a/src/ol/source/zoomify.js +++ b/src/ol/source/zoomify.js @@ -10,15 +10,6 @@ goog.require('ol.source.TileImage'); goog.require('ol.tilegrid.TileGrid'); -/** - * @enum {string} - */ -ol.source.ZoomifyTierSizeCalculation = { - DEFAULT: 'default', - TRUNCATED: 'truncated' -}; - - /** * @classdesc * Layer source for tile data in Zoomify format. @@ -35,7 +26,7 @@ ol.source.Zoomify = function(opt_options) { var size = options.size; var tierSizeCalculation = options.tierSizeCalculation !== undefined ? options.tierSizeCalculation : - ol.source.ZoomifyTierSizeCalculation.DEFAULT; + ol.source.Zoomify.TierSizeCalculation.DEFAULT; var imageWidth = size[0]; var imageHeight = size[1]; @@ -43,7 +34,7 @@ ol.source.Zoomify = function(opt_options) { var tileSize = ol.DEFAULT_TILE_SIZE; switch (tierSizeCalculation) { - case ol.source.ZoomifyTierSizeCalculation.DEFAULT: + case ol.source.Zoomify.TierSizeCalculation.DEFAULT: while (imageWidth > tileSize || imageHeight > tileSize) { tierSizeInTiles.push([ Math.ceil(imageWidth / tileSize), @@ -52,7 +43,7 @@ ol.source.Zoomify = function(opt_options) { tileSize += tileSize; } break; - case ol.source.ZoomifyTierSizeCalculation.TRUNCATED: + case ol.source.Zoomify.TierSizeCalculation.TRUNCATED: var width = imageWidth; var height = imageHeight; while (width > tileSize || height > tileSize) { @@ -123,7 +114,7 @@ ol.source.Zoomify = function(opt_options) { crossOrigin: options.crossOrigin, logo: options.logo, reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileClass: ol.source.ZoomifyTile_, + tileClass: ol.source.Zoomify.Tile_, tileGrid: tileGrid, tileUrlFunction: tileUrlFunction }); @@ -142,7 +133,7 @@ ol.inherits(ol.source.Zoomify, ol.source.TileImage); * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. * @private */ -ol.source.ZoomifyTile_ = function( +ol.source.Zoomify.Tile_ = function( tileCoord, state, src, crossOrigin, tileLoadFunction) { ol.ImageTile.call(this, tileCoord, state, src, crossOrigin, tileLoadFunction); @@ -155,13 +146,13 @@ ol.source.ZoomifyTile_ = function( this.zoomifyImageByContext_ = {}; }; -ol.inherits(ol.source.ZoomifyTile_, ol.ImageTile); +ol.inherits(ol.source.Zoomify.Tile_, ol.ImageTile); /** * @inheritDoc */ -ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) { +ol.source.Zoomify.Tile_.prototype.getImage = function(opt_context) { var tileSize = ol.DEFAULT_TILE_SIZE; var key = opt_context !== undefined ? ol.getUid(opt_context).toString() : ''; @@ -184,3 +175,12 @@ ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) { } } }; + + +/** + * @enum {string} + */ +ol.source.Zoomify.TierSizeCalculation = { + DEFAULT: 'default', + TRUNCATED: 'truncated' +}; diff --git a/src/ol/style/atlas.js b/src/ol/style/atlas.js new file mode 100644 index 0000000000..7a394eabee --- /dev/null +++ b/src/ol/style/atlas.js @@ -0,0 +1,181 @@ +goog.provide('ol.style.Atlas'); + +goog.require('ol'); +goog.require('ol.dom'); + + +/** + * This class facilitates the creation of image atlases. + * + * Images added to an atlas will be rendered onto a single + * atlas canvas. The distribution of images on the canvas is + * managed with the bin packing algorithm described in: + * http://www.blackpawn.com/texts/lightmaps/ + * + * @constructor + * @struct + * @param {number} size The size in pixels of the sprite image. + * @param {number} space The space in pixels between images. + * Because texture coordinates are float values, the edges of + * images might not be completely correct (in a way that the + * edges overlap when being rendered). To avoid this we add a + * padding around each image. + */ +ol.style.Atlas = function(size, space) { + + /** + * @private + * @type {number} + */ + this.space_ = space; + + /** + * @private + * @type {Array.} + */ + this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}]; + + /** + * @private + * @type {Object.} + */ + this.entries_ = {}; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = ol.dom.createCanvasContext2D(size, size); + + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = this.context_.canvas; +}; + + +/** + * @param {string} id The identifier of the entry to check. + * @return {?ol.AtlasInfo} The atlas info. + */ +ol.style.Atlas.prototype.get = function(id) { + return this.entries_[id] || null; +}; + + +/** + * @param {string} id The identifier of the entry to add. + * @param {number} width The width. + * @param {number} height The height. + * @param {function(CanvasRenderingContext2D, number, number)} renderCallback + * Called to render the new image onto an atlas image. + * @param {Object=} opt_this Value to use as `this` when executing + * `renderCallback`. + * @return {?ol.AtlasInfo} The position and atlas image for the entry. + */ +ol.style.Atlas.prototype.add = function(id, width, height, renderCallback, opt_this) { + var block, i, ii; + for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) { + block = this.emptyBlocks_[i]; + if (block.width >= width + this.space_ && + block.height >= height + this.space_) { + // we found a block that is big enough for our entry + var entry = { + offsetX: block.x + this.space_, + offsetY: block.y + this.space_, + image: this.canvas_ + }; + this.entries_[id] = entry; + + // render the image on the atlas image + renderCallback.call(opt_this, this.context_, + block.x + this.space_, block.y + this.space_); + + // split the block after the insertion, either horizontally or vertically + this.split_(i, block, width + this.space_, height + this.space_); + + return entry; + } + } + + // there is no space for the new entry in this atlas + return null; +}; + + +/** + * @private + * @param {number} index The index of the block. + * @param {ol.AtlasBlock} block The block to split. + * @param {number} width The width of the entry to insert. + * @param {number} height The height of the entry to insert. + */ +ol.style.Atlas.prototype.split_ = function(index, block, width, height) { + var deltaWidth = block.width - width; + var deltaHeight = block.height - height; + + /** @type {ol.AtlasBlock} */ + var newBlock1; + /** @type {ol.AtlasBlock} */ + var newBlock2; + + if (deltaWidth > deltaHeight) { + // split vertically + // block right of the inserted entry + newBlock1 = { + x: block.x + width, + y: block.y, + width: block.width - width, + height: block.height + }; + + // block below the inserted entry + newBlock2 = { + x: block.x, + y: block.y + height, + width: width, + height: block.height - height + }; + this.updateBlocks_(index, newBlock1, newBlock2); + } else { + // split horizontally + // block right of the inserted entry + newBlock1 = { + x: block.x + width, + y: block.y, + width: block.width - width, + height: height + }; + + // block below the inserted entry + newBlock2 = { + x: block.x, + y: block.y + height, + width: block.width, + height: block.height - height + }; + this.updateBlocks_(index, newBlock1, newBlock2); + } +}; + + +/** + * Remove the old block and insert new blocks at the same array position. + * The new blocks are inserted at the same position, so that splitted + * blocks (that are potentially smaller) are filled first. + * @private + * @param {number} index The index of the block to remove. + * @param {ol.AtlasBlock} newBlock1 The 1st block to add. + * @param {ol.AtlasBlock} newBlock2 The 2nd block to add. + */ +ol.style.Atlas.prototype.updateBlocks_ = function(index, newBlock1, newBlock2) { + var args = [index, 1]; + if (newBlock1.width > 0 && newBlock1.height > 0) { + args.push(newBlock1); + } + if (newBlock2.width > 0 && newBlock2.height > 0) { + args.push(newBlock2); + } + this.emptyBlocks_.splice.apply(this.emptyBlocks_, args); +}; diff --git a/src/ol/style/atlasmanager.js b/src/ol/style/atlasmanager.js index aa4fdfebdb..40480bc679 100644 --- a/src/ol/style/atlasmanager.js +++ b/src/ol/style/atlasmanager.js @@ -1,8 +1,7 @@ goog.provide('ol.style.AtlasManager'); -goog.provide('ol.style.Atlas'); goog.require('ol'); -goog.require('ol.dom'); +goog.require('ol.style.Atlas'); /** @@ -223,180 +222,3 @@ ol.style.AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height, ol.DEBUG && console.assert(false, 'Failed to add to atlasmanager'); return null; }; - - -/** - * This class facilitates the creation of image atlases. - * - * Images added to an atlas will be rendered onto a single - * atlas canvas. The distribution of images on the canvas is - * managed with the bin packing algorithm described in: - * http://www.blackpawn.com/texts/lightmaps/ - * - * @constructor - * @struct - * @param {number} size The size in pixels of the sprite image. - * @param {number} space The space in pixels between images. - * Because texture coordinates are float values, the edges of - * images might not be completely correct (in a way that the - * edges overlap when being rendered). To avoid this we add a - * padding around each image. - */ -ol.style.Atlas = function(size, space) { - - /** - * @private - * @type {number} - */ - this.space_ = space; - - /** - * @private - * @type {Array.} - */ - this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}]; - - /** - * @private - * @type {Object.} - */ - this.entries_ = {}; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(size, size); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = this.context_.canvas; -}; - - -/** - * @param {string} id The identifier of the entry to check. - * @return {?ol.AtlasInfo} The atlas info. - */ -ol.style.Atlas.prototype.get = function(id) { - return this.entries_[id] || null; -}; - - -/** - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback`. - * @return {?ol.AtlasInfo} The position and atlas image for the entry. - */ -ol.style.Atlas.prototype.add = function(id, width, height, renderCallback, opt_this) { - var block, i, ii; - for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) { - block = this.emptyBlocks_[i]; - if (block.width >= width + this.space_ && - block.height >= height + this.space_) { - // we found a block that is big enough for our entry - var entry = { - offsetX: block.x + this.space_, - offsetY: block.y + this.space_, - image: this.canvas_ - }; - this.entries_[id] = entry; - - // render the image on the atlas image - renderCallback.call(opt_this, this.context_, - block.x + this.space_, block.y + this.space_); - - // split the block after the insertion, either horizontally or vertically - this.split_(i, block, width + this.space_, height + this.space_); - - return entry; - } - } - - // there is no space for the new entry in this atlas - return null; -}; - - -/** - * @private - * @param {number} index The index of the block. - * @param {ol.AtlasBlock} block The block to split. - * @param {number} width The width of the entry to insert. - * @param {number} height The height of the entry to insert. - */ -ol.style.Atlas.prototype.split_ = function(index, block, width, height) { - var deltaWidth = block.width - width; - var deltaHeight = block.height - height; - - /** @type {ol.AtlasBlock} */ - var newBlock1; - /** @type {ol.AtlasBlock} */ - var newBlock2; - - if (deltaWidth > deltaHeight) { - // split vertically - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: block.height - }; - - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } else { - // split horizontally - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: height - }; - - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: block.width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } -}; - - -/** - * Remove the old block and insert new blocks at the same array position. - * The new blocks are inserted at the same position, so that splitted - * blocks (that are potentially smaller) are filled first. - * @private - * @param {number} index The index of the block to remove. - * @param {ol.AtlasBlock} newBlock1 The 1st block to add. - * @param {ol.AtlasBlock} newBlock2 The 2nd block to add. - */ -ol.style.Atlas.prototype.updateBlocks_ = function(index, newBlock1, newBlock2) { - var args = [index, 1]; - if (newBlock1.width > 0 && newBlock1.height > 0) { - args.push(newBlock1); - } - if (newBlock2.width > 0 && newBlock2.height > 0) { - args.push(newBlock2); - } - this.emptyBlocks_.splice.apply(this.emptyBlocks_, args); -}; diff --git a/src/ol/style/icon.js b/src/ol/style/icon.js index 4a381fb364..156a470eea 100644 --- a/src/ol/style/icon.js +++ b/src/ol/style/icon.js @@ -1,6 +1,4 @@ goog.provide('ol.style.Icon'); -goog.provide('ol.style.IconAnchorUnits'); -goog.provide('ol.style.IconOrigin'); goog.require('ol'); goog.require('ol.asserts'); @@ -12,28 +10,6 @@ goog.require('ol.style.IconImage'); goog.require('ol.style.Image'); -/** - * Icon anchor units. One of 'fraction', 'pixels'. - * @enum {string} - */ -ol.style.IconAnchorUnits = { - FRACTION: 'fraction', - PIXELS: 'pixels' -}; - - -/** - * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. - * @enum {string} - */ -ol.style.IconOrigin = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right' -}; - - /** * @classdesc * Set icon style for vector features. @@ -61,24 +37,24 @@ ol.style.Icon = function(opt_options) { /** * @private - * @type {ol.style.IconOrigin} + * @type {ol.style.Icon.Origin} */ this.anchorOrigin_ = options.anchorOrigin !== undefined ? - options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT; + options.anchorOrigin : ol.style.Icon.Origin.TOP_LEFT; /** * @private - * @type {ol.style.IconAnchorUnits} + * @type {ol.style.Icon.AnchorUnits} */ this.anchorXUnits_ = options.anchorXUnits !== undefined ? - options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION; + options.anchorXUnits : ol.style.Icon.AnchorUnits.FRACTION; /** * @private - * @type {ol.style.IconAnchorUnits} + * @type {ol.style.Icon.AnchorUnits} */ this.anchorYUnits_ = options.anchorYUnits !== undefined ? - options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION; + options.anchorYUnits : ol.style.Icon.AnchorUnits.FRACTION; /** * @type {?string} @@ -139,10 +115,10 @@ ol.style.Icon = function(opt_options) { /** * @private - * @type {ol.style.IconOrigin} + * @type {ol.style.Icon.Origin} */ this.offsetOrigin_ = options.offsetOrigin !== undefined ? - options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT; + options.offsetOrigin : ol.style.Icon.Origin.TOP_LEFT; /** * @private @@ -205,33 +181,33 @@ ol.style.Icon.prototype.getAnchor = function() { } var anchor = this.anchor_; var size = this.getSize(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION || - this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { + if (this.anchorXUnits_ == ol.style.Icon.AnchorUnits.FRACTION || + this.anchorYUnits_ == ol.style.Icon.AnchorUnits.FRACTION) { if (!size) { return null; } anchor = this.anchor_.slice(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) { + if (this.anchorXUnits_ == ol.style.Icon.AnchorUnits.FRACTION) { anchor[0] *= size[0]; } - if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { + if (this.anchorYUnits_ == ol.style.Icon.AnchorUnits.FRACTION) { anchor[1] *= size[1]; } } - if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) { + if (this.anchorOrigin_ != ol.style.Icon.Origin.TOP_LEFT) { if (!size) { return null; } if (anchor === this.anchor_) { anchor = this.anchor_.slice(); } - if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + if (this.anchorOrigin_ == ol.style.Icon.Origin.TOP_RIGHT || + this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) { anchor[0] = -anchor[0] + size[0]; } - if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + if (this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_LEFT || + this.anchorOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) { anchor[1] = -anchor[1] + size[1]; } } @@ -294,19 +270,19 @@ ol.style.Icon.prototype.getOrigin = function() { } var offset = this.offset_; - if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) { + if (this.offsetOrigin_ != ol.style.Icon.Origin.TOP_LEFT) { var size = this.getSize(); var iconImageSize = this.iconImage_.getSize(); if (!size || !iconImageSize) { return null; } offset = offset.slice(); - if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + if (this.offsetOrigin_ == ol.style.Icon.Origin.TOP_RIGHT || + this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) { offset[0] = iconImageSize[0] - size[0] - offset[0]; } - if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + if (this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_LEFT || + this.offsetOrigin_ == ol.style.Icon.Origin.BOTTOM_RIGHT) { offset[1] = iconImageSize[1] - size[1] - offset[1]; } } @@ -362,3 +338,25 @@ ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) { ol.events.unlisten(this.iconImage_, ol.events.EventType.CHANGE, listener, thisArg); }; + + +/** + * Icon anchor units. One of 'fraction', 'pixels'. + * @enum {string} + */ +ol.style.Icon.AnchorUnits = { + FRACTION: 'fraction', + PIXELS: 'pixels' +}; + + +/** + * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. + * @enum {string} + */ +ol.style.Icon.Origin = { + BOTTOM_LEFT: 'bottom-left', + BOTTOM_RIGHT: 'bottom-right', + TOP_LEFT: 'top-left', + TOP_RIGHT: 'top-right' +}; diff --git a/src/ol/tilecoord.js b/src/ol/tilecoord.js index 3b646d7167..521ab2dfd3 100644 --- a/src/ol/tilecoord.js +++ b/src/ol/tilecoord.js @@ -1,17 +1,6 @@ goog.provide('ol.tilecoord'); -/** - * @enum {number} - */ -ol.QuadKeyCharCode = { - ZERO: '0'.charCodeAt(0), - ONE: '1'.charCodeAt(0), - TWO: '2'.charCodeAt(0), - THREE: '3'.charCodeAt(0) -}; - - /** * @param {string} str String that follows pattern “z/x/y” where x, y and z are * numbers. @@ -76,7 +65,8 @@ ol.tilecoord.quadKey = function(tileCoord) { var mask = 1 << (z - 1); var i, charCode; for (i = 0; i < z; ++i) { - charCode = ol.QuadKeyCharCode.ZERO; + // 48 is charCode for 0 - '0'.charCodeAt(0) + charCode = 48; if (tileCoord[1] & mask) { charCode += 1; } diff --git a/src/ol/typedefs.js b/src/ol/typedefs.js index 5482829f31..a4b4ac8b24 100644 --- a/src/ol/typedefs.js +++ b/src/ol/typedefs.js @@ -274,8 +274,8 @@ ol.ImageLoadFunctionType; /** - * @typedef {{x: number, xunits: (ol.style.IconAnchorUnits|undefined), - * y: number, yunits: (ol.style.IconAnchorUnits|undefined)}} + * @typedef {{x: number, xunits: (ol.style.Icon.AnchorUnits|undefined), + * y: number, yunits: (ol.style.Icon.AnchorUnits|undefined)}} */ ol.KMLVec2_; diff --git a/test/spec/ol/source/tileutfgrid.test.js b/test/spec/ol/source/tileutfgrid.test.js index 239da558ec..c585b0e207 100644 --- a/test/spec/ol/source/tileutfgrid.test.js +++ b/test/spec/ol/source/tileutfgrid.test.js @@ -236,7 +236,7 @@ describe('ol.source.TileUTFGrid', function() { var urlTileCoord = this.getTileCoordForTileUrlFunction(tileCoord, projection); var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection); - var tile = new ol.source.TileUTFGridTile_( + var tile = new ol.source.TileUTFGrid.Tile_( tileCoord, tileUrl !== undefined ? 0 : 4, // IDLE : EMPTY tileUrl !== undefined ? tileUrl : '', diff --git a/test/spec/ol/source/zoomify.test.js b/test/spec/ol/source/zoomify.test.js index 0eabc60b2c..44b4b36e71 100644 --- a/test/spec/ol/source/zoomify.test.js +++ b/test/spec/ol/source/zoomify.test.js @@ -189,15 +189,15 @@ describe('ol.source.Zoomify', function() { describe('uses a custom tileClass', function() { - it('uses "ol.source.ZoomifyTile_" as tileClass', function() { + it('uses "ol.source.Zoomify.Tile_" as tileClass', function() { var source = getZoomifySource(); - expect(source.tileClass).to.be(ol.source.ZoomifyTile_); + expect(source.tileClass).to.be(ol.source.Zoomify.Tile_); }); it('returns expected tileClass instances via "getTile"', function() { var source = getZoomifySource(); var tile = source.getTile(0, 0, -1, 1, proj); - expect(tile).to.be.an(ol.source.ZoomifyTile_); + expect(tile).to.be.an(ol.source.Zoomify.Tile_); }); it('"tile.getImage" returns and caches an unloaded image', function() {