Move vector code out of the way

This commit is contained in:
Tom Payne
2013-11-06 16:40:26 +01:00
parent 81349d382b
commit 4e65fefc00
271 changed files with 881 additions and 0 deletions

View File

@@ -0,0 +1,881 @@
/**
* @typedef {Object} ol.AttributionOptions
* @property {string} html HTML markup for this attribution.
* @property {Object.<string, Array.<ol.TileRange>>|undefined} tileRanges
* Tile ranges (FOR INTERNAL USE ONLY).
* @todo stability experimental
*/
/**
* @typedef {Object} ol.DeviceOrientationOptions
* @property {boolean|undefined} tracking Start tracking. Default is `false`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.GeolocationOptions
* @property {boolean|undefined} tracking Start Tracking. Default is `false`.
* @property {GeolocationPositionOptions|undefined} trackingOptions Tracking options.
* @property {ol.proj.ProjectionLike} projection Projection.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.GetFeatureInfoOptions
* @property {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @property {Array.<ol.layer.Layer>|undefined} layers Layers to restrict the
* query to. All map layers will be queried if not provided.
* @property {function(Array.<Array.<string|undefined>>)} success Callback for
* successful queries. The passed argument is the resulting feature
* information for each layer, with array indices being the same as in the
* passed `layers` array or in the layer collection as returned from
* `ol.Map#getLayers()` if no `layers` were provided.
* @property {function()|undefined} error Callback for unsuccessful queries.
* Note that queries with no matching features trigger the success callback,
* not the error callback.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.GetFeaturesOptions
* @property {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @property {Array.<ol.layer.Layer>|undefined} layers Layers to restrict the
* query to. All layers will be queried if not provided.
* @property {function(Array.<Array.<ol.Feature|undefined>>)} success Callback
* for successful queries. The passed argument is the resulting features for
* each layer, with array indices being the same as in the passed `layers`
* array or in the layer collection as returned from `ol.Map#getLayers()` if
* no layers were provided.
* @property {function()|undefined} error Callback for unsuccessful queries.
* Note that queries with no matching features trigger the success callback,
* not the error callback.
* @todo stability experimental
*/
/**
* Object literal with config options for the map.
* @typedef {Object} ol.MapOptions
* @property {ol.Collection|Array.<ol.control.Control>|undefined} controls
* Controls initially added to the map.
* @property {ol.Collection|Array.<ol.interaction.Interaction>|undefined} interactions
* Interactions that are initially added to the map.
* @property {Array.<ol.layer.Base>|ol.Collection|undefined} layers Layers.
* @property {ol.Collection|Array.<ol.Overlay>|undefined} overlays
* Overlays initially added to the map.
* @property {ol.RendererHint|undefined} renderer Renderer.
* @property {Array.<ol.RendererHint>|undefined} renderers Renderers.
* @property {Element|string|undefined} target The container for the map.
* @property {ol.IView|undefined} view The map's view. Currently
* {@link ol.View2D} is available as view.
* @todo stability experimental
*/
/**
* Object literal with config options for the overlay.
* @typedef {Object} ol.OverlayOptions
* @property {Element|undefined} element The overlay element.
* @property {ol.Coordinate|undefined} position The overlay position in map
* projection.
* @property {ol.OverlayPositioning|undefined} positioning Positioning.
* @property {boolean|undefined} stopEvent Whether event propagation to the map
* viewport should be stopped. Default is `true`. If `true` the overlay is
* placed in the same container as that of the controls
* (`ol-overlaycontainer-stopevent`).
* @property {boolean|undefined} insertFirst Whether the overlay is inserted
* first in the overlay container, or appended. Default is `true`. If the
* overlay is placed in the same container as that of the controls (see
* the `stopEvent` option) you will probably set `insertFirst` to `true`
* so the overlay is displayed below the controls.
* @todo stability experimental
*/
/**
* Object literal with config options for the Proj4js projection.
* @typedef {Object} ol.Proj4jsProjectionOptions
* @property {string} code The SRS identifier code, e.g. `EPSG:31256`.
* @property {ol.Extent|undefined} extent The validity extent for the SRS.
* @property {boolean|undefined} global Whether the projection is valid for the
* whole globe. Default is `false`.
* @todo stability experimental
*/
/**
* Object literal with config options for the projection.
* @typedef {Object} ol.ProjectionOptions
* @property {string} code The SRS identifier code, e.g. `EPSG:4326`.
* @property {ol.proj.Units} units Units.
* @property {ol.Extent|undefined} extent The validity extent for the SRS.
* @property {string|undefined} axisOrientation The axis orientation as
* specified in Proj4. The default is `enu`.
* @property {boolean|undefined} global Whether the projection is valid for the
* whole globe. Default is `false`.
* @todo stability experimental
*/
/**
* Object literal with config options for the view.
* @typedef {Object} ol.View2DOptions
* @property {ol.Coordinate|undefined} center The initial center for the view.
* The coordinate system for the center is specified with the `projection`
* option. Default is `undefined`, and layer sources will not be fetched if
* this is not set.
* @property {ol.Extent|undefined} extent The extent that constrains the center,
* in other words, center cannot be set outside this extent.
* Default is `undefined`.
* @property {number|undefined} maxResolution The maximum resolution used to
* determine the resolution constraint. It is used together with `maxZoom`
* and `zoomFactor`. If unspecified it is calculated in such a way that the
* projection's validity extent fits in a 256x256 px tile. If the projection
* is Spherical Mercator (the default) then `maxResolution` defaults to
* `40075016.68557849 / 256 = 156543.03392804097`.
* @property {number|undefined} maxZoom The maximum zoom level used to determine
* the resolution constraint. It is used together with `maxResolution` and
* `zoomFactor`. Default is `28`.
* @property {ol.proj.ProjectionLike} projection The projection. Default is
* `EPSG:3857` (Spherical Mercator).
* @property {number|undefined} resolution The initial resolution for the view.
* The units are `projection` units per pixel (e.g. meters per pixel).
* An alternative to setting this is to set `zoom`. Default is `undefined`,
* and layer sources will not be fetched if neither this nor `zoom` are
* defined.
* @property {Array.<number>|undefined} resolutions Resolutions to determine the
* resolution constraint. If set the `maxResolution`, `maxZoom` and
* `zoomFactor` options are ignored.
* @property {number|undefined} rotation The initial rotation for the view
* in radians (positive rotation clockwise). Default is `0`.
* @property {number|undefined} zoom Only used if `resolution` is not defined.
* Zoom level used to calculate the initial resolution for the view.
* The initial resolution is determined using the
* `ol.View2D#constrainResolution` method.
* @property {number|undefined} zoomFactor The zoom factor used to determine the
* resolution constraint. Used together with `maxResolution` and `maxZoom`.
* Default is `2`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.animation.BounceOptions
* @property {number} resolution The resolution to start the bounce from, typically `map.getView().getResolution()`.
* @property {number|undefined} start The start time of the animation. Default is immediately.
* @property {number|undefined} duration The duration of the animation in milliseconds. Default is `1000`.
* @property {function(number):number|undefined} easing The easing function to use. Default is `ol.easing.upAndDown`
* @todo stability experimental
*/
/**
* @typedef {Object} ol.animation.PanOptions
* @property {ol.Coordinate} source The location to start panning from, typically `map.getView().getCenter()`.
* @property {number|undefined} start The start time of the animation. Default is immediately.
* @property {number|undefined} duration The duration of the animation in milliseconds. Default is `1000`.
* @property {function(number):number|undefined} easing The easing function to use. Default is `ol.easing.inAndOut`
* @todo stability experimental
*/
/**
* @typedef {Object} ol.animation.RotateOptions
* @property {number} rotation The rotation to apply, in radians.
* @property {number|undefined} start The start time of the animation. Default is immediately.
* @property {number|undefined} duration The duration of the animation in milliseconds. Default is `1000`.
* @property {function(number):number|undefined} easing The easing function to use. Default is `ol.easing.inAndOut`
* @todo stability experimental
*/
/**
* @typedef {Object} ol.animation.ZoomOptions
* @property {number} resolution number The resolution to begin zooming from, typically `map.getView().getResolution()`.
* @property {number|undefined} start The start time of the animation. Default is immediately.
* @property {number|undefined} duration The duration of the animation in milliseconds. Default is `1000`.
* @property {function(number):number|undefined} easing Easing function.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.AttributionOptions
* @property {string|undefined} className CSS class name. Default is `ol-attribution`.
* @property {Element|undefined} target Target.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.ControlOptions
* @property {Element|undefined} element Element.
* @property {Element|undefined} target Target.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.DefaultsOptions
* @property {boolean|undefined} attribution Attribution.
* @property {ol.control.AttributionOptions|undefined} attributionOptions
* Attribution options.
* @property {boolean|undefined} logo Logo.
* @property {ol.control.LogoOptions|undefined} logoOptions Logo options.
* @property {boolean|undefined} zoom Zoom.
* @property {ol.control.ZoomOptions|undefined} zoomOptions Zoom options.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.FullScreenOptions
* @property {string|undefined} className CSS class name. Default is `ol-full-screen`.
* @property {boolean|undefined} keys Full keyboard access.
* @property {Element|undefined} target Target.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.LogoOptions
* @property {string|undefined} className CSS class name. Default is `ol-logo`.
* @property {Element|undefined} target Target.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.MousePositionOptions
* @property {string|undefined} className CSS class name. Default is `ol-mouse-position`.
* @property {ol.CoordinateFormatType|undefined} coordinateFormat Coordinate
* format.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {Element|undefined} target Target.
* @property {string|undefined} undefinedHTML Markup for undefined coordinates.
* Default is `` (empty string).
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.ScaleLineOptions
* @property {string|undefined} className CSS Class name. Default is `ol-scale-line`.
* @property {number|undefined} minWidth Minimum width in pixels.
* @property {Element|undefined} target Target.
* @property {ol.control.ScaleLineUnits|undefined} units Units.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.ZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `250`.
* @property {string|undefined} className CSS class name. Default is `ol-zoom`.
* @property {number|undefined} delta The zoom delta applied on each click.
* @property {Element|undefined} target Target.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.ZoomSliderOptions
* @property {string|undefined} className CSS class name.
* @property {number|undefined} maxResolution Maximum resolution.
* @property {number|undefined} minResolution Minimum resolution.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.control.ZoomToExtentOptions
* @property {string|undefined} className Class name. Default is `ol-zoom-extent`.
* @property {Element|undefined} target Target.
* @property {ol.Extent|undefined} extent The extent to zoom to. If
* undefined the validity extent of the view projection is used.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.DoubleClickZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `250`.
* @property {number|undefined} delta The zoom delta applied on each double
* click, default is `1`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.DragPanOptions
* @property {ol.Kinetic|undefined} kinetic Kinetic inertia to apply to the pan.
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is no modifiers.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.DragRotateOptions
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is both shift and alt keys.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.DragRotateAndZoomOptions
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is shify key.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.DragZoomOptions
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is shift key.
* @todo stability experimental
*/
/**
* Interactions for the map. Default is `true` for all options.
* @typedef {Object} ol.interaction.DefaultsOptions
* @property {boolean|undefined} altShiftDragRotate Whether Alt-Shift-drag
* rotate is desired.
* @property {boolean|undefined} doubleClickZoom Whether double click zoom is
* desired.
* @property {boolean|undefined} dragPan Whether drag-pan is desired.
* @property {boolean|undefined} keyboard Whether keyboard interaction is
* desired.
* @property {boolean|undefined} mouseWheelZoom Whether mousewheel zoom is
* desired.
* @property {boolean|undefined} shiftDragZoom Whether Shift-drag zoom is
* desired.
* @property {boolean|undefined} touchPan Whether touch pan is
* desired.
* @property {boolean|undefined} touchRotate Whether touch rotate is desired.
* @property {boolean|undefined} touchZoom Whether touch zoom is desired.
* @property {number|undefined} zoomDelta Zoom delta.
* @property {number|undefined} zoomDuration Zoom duration.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.KeyboardPanOptions
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is no modifiers.
* @property {number|undefined} pixelDelta Pixel The amount to pan on each key
* press
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.KeyboardZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `100`.
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (i.e. Shift key) that determines if the interaction is active
* or not, default is no modifiers.
* @property {number|undefined} delta The amount to zoom on each key press.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.MouseWheelZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `250`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.SelectOptions
* @property {ol.events.ConditionType|undefined} addCondition A conditional
* modifier (e.g. shift key) that determines if the selection is added to
* the current selection. By default, a shift-click adds to the current
* selection.
* @property {ol.events.ConditionType|undefined} condition A conditional
* modifier (e.g. shift key) that determines if the interaction is active
* (i.e. selection occurs) or not. By default, a click with no modifier keys
* toggles the selection.
* @property {undefined|function(ol.layer.Layer):boolean} layerFilter Filter
* function to restrict selection to a subset of layers.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.TouchPanOptions
* @property {ol.Kinetic|undefined} kinetic Kinetic inertia to apply to the
* pan.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.TouchRotateOptions
* @property {number|undefined} threshold Minimal angle to start a rotation.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.interaction.TouchZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `400`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.layer.BaseOptions
* @property {number|undefined} brightness Brightness.
* @property {number|undefined} contrast Contrast.
* @property {number|undefined} hue Hue.
* @property {number|undefined} opacity Opacity.
* @property {number|undefined} saturation Saturation.
* @property {boolean|undefined} visible Visibility.
* @property {number|undefined} minResolution The minimum resolution
* (inclusive) at which this layer will be visible.
* @property {number|undefined} maxResolution The maximum resolution
* (exclusive) below which this layer will be visible.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.layer.LayerOptions
* @property {number|undefined} brightness Brightness.
* @property {number|undefined} contrast Contrast.
* @property {number|undefined} hue Hue.
* @property {number|undefined} opacity Opacity. 0-1. Default is `1`.
* @property {number|undefined} saturation Saturation.
* @property {ol.source.Source} source Source for this layer.
* @property {boolean|undefined} visible Visibility. Default is `true` (visible).
* @property {number|undefined} minResolution The minimum resolution
* (inclusive) at which this layer will be visible.
* @property {number|undefined} maxResolution The maximum resolution
* (exclusive) below which this layer will be visible.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.layer.GroupOptions
* @property {number|undefined} brightness Brightness.
* @property {number|undefined} contrast Contrast.
* @property {number|undefined} hue Hue.
* @property {number|undefined} opacity Opacity.
* @property {number|undefined} saturation Saturation.
* @property {boolean|undefined} visible Visibility.
* @property {number|undefined} minResolution The minimum resolution
* (inclusive) at which this layer will be visible.
* @property {number|undefined} maxResolution The maximum resolution
* (exclusive) below which this layer will be visible.
* @property {Array.<ol.layer.Base>|ol.Collection|undefined} layers Child layers.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.layer.TileOptions
* @property {number|undefined} brightness Brightness.
* @property {number|undefined} contrast Contrast.
* @property {number|undefined} hue Hue.
* @property {number|undefined} opacity Opacity. 0-1. Default is `1`.
* @property {number|undefined} preload Preload.
* @property {number|undefined} saturation Saturation.
* @property {ol.source.Source} source Source for this layer.
* @property {boolean|undefined} visible Visibility. Default is `true` (visible).
* @property {number|undefined} minResolution The minimum resolution
* (inclusive) at which this layer will be visible.
* @property {number|undefined} maxResolution The maximum resolution
* (exclusive) below which this layer will be visible.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.layer.VectorLayerOptions
* @property {function(Array.<ol.Feature>):string|undefined} transformFeatureInfo
* Function to render an array of
* features into feature info markup. If not provided, a comma separated
* list of the unique ids of the resulting features will be returned.
* @property {number|undefined} opacity Opacity. 0-1. Default is `1`.
* @property {ol.source.Source} source Source for this layer.
* @property {ol.style.Style|undefined} style Style.
* @property {boolean|undefined} visible Visibility. Default is `true` (visible).
* @property {number|undefined} minResolution The minimum resolution
* (inclusive) at which this layer will be visible.
* @property {number|undefined} maxResolution The maximum resolution
* (exclusive) below which this layer will be visible.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.KMLOptions
* @property {boolean|undefined} extractAttributes Should we extract attributes
* from the KML? Default is `true`.
* @property {boolean|undefined} extractStyles Should we extract styles from the
* KML? Default is `false`.
* @property {number|undefined} maxDepth Maximum depth to follow network links.
* Default is `0`, which means we don't follow network links at all.
* @property {Array.<string>|undefined} trackAttributes Track attributes to
* parse.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.GMLReadOptions
* @property {string|undefined} axisOrientation The axis orientation.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.GMLWriteOptions
* @property {ol.proj.ProjectionLike} srsName The srsName to use when writing.
* @property {string|undefined} axisOrientation The axis orientation.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.GMLOptions
* @property {boolean|undefined} curve Write gml:Curve instead of
* gml:LineString elements. This also affects the elements in multi-part
* geometries. Default is `false`. This only applies to GML version 3.
* @property {boolean|undefined} extractAttributes Should we extract attributes
* from the GML? Default is `true`.
* @property {string|undefined} featureNS The feature namespace. If not set it
* will be automatically configured from the GML.
* @property {Array.<string>|string|undefined} featureType The local
* (without prefix) feature typeName(s).
* @property {string|undefined} geometryName Name of geometry element.
* Defaults to `geometry`. If null, it will be set on <read> when the
* first geometry is parsed.
* @property {boolean|undefined} multiCurve Write gml:MultiCurve instead of
* gml:MultiLineString. Since the latter is deprecated in GML 3, the
* default is `true`. This only applies to GML version 3.
* @property {boolean|undefined} multiSurface Write gml:multiSurface instead
* of gml:MultiPolygon. Since the latter is deprecated in GML 3, the
* default is `true`. This only applies to GML version 3.
* @property {string|undefined} schemaLocation Optional schemaLocation to use
* when writing out the GML, this will override the default provided.
* @property {boolean|undefined} surface Write gml:Surface instead of
* gml:Polygon elements. This also affects the elements in multi-part
* geometries. Default is `false`. This only applies to GML version 3.
* @property {ol.parser.GMLReadOptions|undefined} readOptions readOptions to
* use for this instance.
* @property {ol.parser.GMLWriteOptions|undefined} writeOptions writeOptions
* to use for this instance.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.GPXOptions
* @property {string|undefined} creator The creator attribute to be added to
* the written GPX files. Defaults to `OpenLayers`.
* @property {string|undefined} defaultDesc Default description for the
* waypoints/tracks in the case where the feature has no `description`
* attribute. Default is `No description available`.
* @property {boolean|undefined} extractAttributes Should we extract attributes
* from the GPX? Default is `true`.
* @property {boolean|undefined} extractWaypoints Extract waypoints from GPX.
* Default is `true`.
* @property {boolean|undefined} extractTracks Extract tracks from GPX.
* Default is `true`.
* @property {boolean|undefined} extractRoutes Extract routes from GPX.
* Default is `true`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.parser.GPXWriteOptions
* @property {Array.<ol.Feature>|ol.Feature} features The features to write
* out.
* @property {Object|undefined} metadata Metadata key/value pair with keys:
* name, desc and author.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.BingMapsOptions
* @property {string|undefined} culture Culture.
* @property {string} key Bing Maps API key. Get yours at
* http://bingmapsportal.com/.
* @property {string} style Style.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.MapQuestOptions
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.TileDebugOptions
* @property {ol.Extent|undefined} extent Extent.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {ol.tilegrid.TileGrid|undefined} tileGrid Tile grid.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.OSMOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {number|undefined} maxZoom Max zoom.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {string|undefined} url URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.ImageWMSOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {null|string|undefined} crossOrigin crossOrigin setting for image
* requests.
* @property {ol.Extent|undefined} extent Extent.
* @property {ol.source.WMSGetFeatureInfoOptions|undefined}
* getFeatureInfoOptions Options for GetFeatureInfo.
* @property {Object.<string,*>} params WMS request parameters. At least a
* `LAYERS` param is required. `STYLES` is `` by default. `VERSION` is
* `1.3.0` by default. `WIDTH`, `HEIGHT`, `BBOX` and `CRS` (`SRS` for WMS
* version < 1.3.0) will be set dynamically.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {number|undefined} ratio Ratio. 1 means image requests are the size
* of the map viewport, 2 means twice the size of the map viewport, and so
* on.
* @property {Array.<number>|undefined} resolutions Resolutions. If specified,
* requests will be made for these resolutions only.
* @property {string|undefined} url WMS service URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.StamenOptions
* @property {string} layer Layer.
* @property {number|undefined} minZoom Minimum zoom.
* @property {number|undefined} maxZoom Maximum zoom.
* @property {boolean|undefined} opaque Whether the layer is opaque.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {string|undefined} url URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.ImageStaticOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {null|string|undefined} crossOrigin crossOrigin setting for image
* requests.
* @property {ol.Extent|undefined} extent Extent.
* @property {ol.Extent|undefined} imageExtent Extent of the image.
* @property {ol.Size|undefined} imageSize Size of the image.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {string|undefined} url URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.TileJSONOptions
* @property {null|string|undefined} crossOrigin crossOrigin setting for image
* requests.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {string} url URL.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.TileWMSOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {Object.<string,*>} params WMS request parameters. At least a
* `LAYERS` param is required. `STYLES` is `` by default. `VERSION` is
* `1.3.0` by default. `WIDTH`, `HEIGHT`, `BBOX` and `CRS` (`SRS` for WMS
* version < 1.3.0) will be set dynamically.
* @property {null|string|undefined} crossOrigin crossOrigin setting for image
* requests.
* @property {ol.Extent|undefined} extent Extent.
* @property {ol.source.WMSGetFeatureInfoOptions|undefined}
* getFeatureInfoOptions Options for GetFeatureInfo.
* @property {string|undefined} logo Logo.
* @property {ol.tilegrid.TileGrid|undefined} tileGrid Tile grid.
* @property {number|undefined} maxZoom Maximum zoom.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {string|undefined} url WMS service URL.
* @property {Array.<string>|undefined} urls WMS service urls. Use this instead
* of `url` when the WMS supports multiple urls for GetMap requests.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.VectorOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {Object|string|undefined} data Data to parse.
* @property {ol.Extent|undefined} extent Extent.
* @property {string|undefined} logo Logo.
* @property {ol.parser.Parser} parser Parser instance to parse data
* provided as `data` or fetched from `url`.
* @property {ol.proj.ProjectionLike|undefined} projection Projection. Usually the
* projection is provided by the parser, so this only needs to be set if
* the parser does not know the SRS (e.g. in some GML flavors), or if the
* projection determined by the parser needs to be overridden.
* @property {string|undefined} url Server url providing the vector data.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.Vector2Options
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {ol.Extent|undefined} extent Extent.
* @property {Array.<ol.geom2.LineStringCollection>|undefined}
* lineStringCollections Line string collections.
* @property {Array.<ol.geom2.PointCollection>|undefined} pointCollections
* Point collections.
* @property {ol.proj.ProjectionLike} projection Projection.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.WMSGetFeatureInfoOptions
* @property {ol.source.WMSGetFeatureInfoMethod} method Method for requesting
* GetFeatureInfo. Default is `ol.source.WMSGetFeatureInfoMethod.IFRAME`.
* @property {Object} params Params for the GetFeatureInfo request. Default is
* `{'INFO_FORMAT': 'text/html'}`.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.WMTSOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {string|null|undefined} crossOrigin crossOrigin setting for image
* requests.
* @property {ol.Extent|undefined} extent Extent.
* @property {string|undefined} logo Logo.
* @property {ol.tilegrid.WMTS} tileGrid Tile grid.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {ol.source.WMTSRequestEncoding|undefined} requestEncoding Request
* encoding.
* @property {string} layer Layer.
* @property {string} style Style.
* @property {string|undefined} version WMTS version. Default to `1.0.0`.
* @property {string|undefined} format Format.
* @property {string} matrixSet Matrix set.
* @property {Object|undefined} dimensions Dimensions.
* @property {string|undefined} url URL.
* @property {number|undefined} maxZoom Maximum zoom.
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {Array.<string>|undefined} urls Urls.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.source.XYZOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {null|string|undefined} crossOrigin Cross origin setting for image
* requests.
* @property {ol.Extent|undefined} extent Extent.
* @property {string|undefined} logo Logo.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {number|undefined} maxZoom Optional max zoom level. Default is `18`.
* @property {number|undefined} minZoom Unsupported (TODO: remove this).
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional
* function to load a tile given a URL.
* @property {ol.TileUrlFunctionType|undefined} tileUrlFunction Optional
* function to get tile URL given a tile coordinate and the projection.
* Required if url or urls are not provided.
* @property {string|undefined} url URL template. Must include `{x}`, `{y}`,
* and `{z}` placeholders.
* @property {Array.<string>|undefined} urls An array of URL templates.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.IconOptions
* @property {string|ol.expr.Expression} url Icon image URL.
* @property {number|ol.expr.Expression|undefined} width Width of the icon
* in pixels. Default is the width of the icon image.
* @property {number|ol.expr.Expression|undefined} height Height of the
* icon in pixels. Default is the height of the icon image.
* @property {number|ol.expr.Expression|undefined} opacity Icon opacity
* (0-1).
* @property {number|ol.expr.Expression|undefined} rotation Rotation in
* radians (positive rotation clockwise).
* @property {number|ol.expr.Expression|undefined} xOffset Pixel offset from the
* point to the center of the icon (positive values shift image left).
* @property {number|ol.expr.Expression|undefined} yOffset Pixel offset from the
* point to the center of the icon (positive values shift image down).
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.FillOptions
* @property {string|ol.expr.Expression|undefined} color Fill color as hex color
* code.
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.RuleOptions
* @property {ol.expr.Expression|string|undefined} filter Filter.
* @property {number|undefined} maxResolution Optional maximum resolution. If
* a value is provided, the rule will apply at resolutions less than
* this value.
* @property {number|undefined} minResolution Optional minimum resolution. If
* a value is provided, the rule will apply at resolutions greater than or
* equal to this value.
* @property {Array.<ol.style.Symbolizer>|undefined} symbolizers Symbolizers.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.ShapeOptions
* @property {ol.style.ShapeType|undefined} type Type.
* @property {number|ol.expr.Expression|undefined} size Size in pixels.
* @property {ol.style.Fill|undefined} fill Fill symbolizer for shape.
* @property {ol.style.Stroke|undefined} stroke Stroke symbolizer for shape.
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.StrokeOptions
* @property {string|ol.expr.Expression|undefined} color Stroke color as hex
* color code.
* @property {number|ol.expr.Expression|undefined} opacity Stroke opacity (0-1).
* @property {number|ol.expr.Expression|undefined} width Stroke width in pixels.
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.StyleOptions
* @property {Array.<ol.style.Rule>|undefined} rules Rules.
* @property {Array.<ol.style.Symbolizer>|undefined} symbolizers Symbolizers
* (that apply if no rules are provided or where none of the provided rules
* apply).
* @todo stability experimental
*/
/**
* @typedef {Object} ol.style.TextOptions
* @property {string|ol.expr.Expression|undefined} color Color.
* @property {string|ol.expr.Expression|undefined} fontFamily Font family.
* @property {number|ol.expr.Expression|undefined} fontSize Font size in pixels.
* @property {string|ol.expr.Expression|undefined} fontWeight Font weight.
* @property {string|ol.expr.Expression} text Text for the label.
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
* @property {ol.style.Stroke|undefined} stroke Stroke symbolizer for text.
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.tilegrid.TileGridOptions
* @property {number|undefined} minZoom Minimum zoom.
* @property {ol.Coordinate|undefined} origin Origin.
* @property {Array.<ol.Coordinate>|undefined} origins Origins.
* @property {!Array.<number>} resolutions Resolutions.
* @property {ol.Size|undefined} tileSize Tile size.
* @property {Array.<ol.Size>|undefined} tileSizes Tile sizes.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.tilegrid.WMTSOptions
* @property {ol.Coordinate|undefined} origin Origin.
* @property {Array.<ol.Coordinate>|undefined} origins Origins.
* @property {!Array.<number>} resolutions Resolutions.
* @property {!Array.<string>} matrixIds matrix IDs.
* @property {ol.Size|undefined} tileSize Tile size.
* @property {Array.<ol.Size>|undefined} tileSizes Tile sizes.
* @todo stability experimental
*/
/**
* @typedef {Object} ol.tilegrid.XYZOptions
* @property {number} maxZoom Maximum zoom.
* @todo stability experimental
*/

2
old/src/ol/expr.exports Normal file
View File

@@ -0,0 +1,2 @@
@exportSymbol ol.expr.parse
@exportSymbol ol.expr.register

3
old/src/ol/expr.jsdoc Normal file
View File

@@ -0,0 +1,3 @@
/**
* @namespace ol.expr
*/

View File

@@ -0,0 +1,309 @@
goog.provide('ol.expr');
goog.provide('ol.expr.functions');
goog.require('ol.Extent');
goog.require('ol.Feature');
goog.require('ol.expr.Call');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Parser');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
/**
* Evaluate an expression with a feature. The feature attributes will be used
* as the evaluation scope. The `ol.expr.lib` functions will be used as
* function scope. The feature itself will be used as the `this` argument.
*
* @param {ol.expr.Expression} expr The expression.
* @param {ol.Feature=} opt_feature The feature.
* @return {*} The result of the expression.
*/
ol.expr.evaluateFeature = function(expr, opt_feature) {
var scope;
if (goog.isDef(opt_feature)) {
scope = opt_feature.getAttributes();
}
return expr.evaluate(scope, ol.expr.lib, opt_feature);
};
/**
* Parse an expression.
* @param {string} source The expression source (e.g. `'foo + 2'`).
* @return {ol.expr.Expression} An expression instance that can be
* evaluated within some scope to provide a value.
* @todo stability experimental
*/
ol.expr.parse = function(source) {
var parser = new ol.expr.Parser();
return parser.parse(source);
};
/**
* Register a library function to be used in expressions.
* @param {string} name The function name (e.g. 'myFunc').
* @param {function(this:ol.Feature)} func The function to be called in an
* expression. This function will be called with a feature as the `this`
* argument when the expression is evaluated in the context of a features.
* @todo stability experimental
*/
ol.expr.register = function(name, func) {
ol.expr.lib[name] = func;
};
/**
* Determines whether an expression is a call expression that calls one of the
* `ol.expr.lib` functions.
*
* @param {ol.expr.Expression} expr The candidate expression.
* @return {string|undefined} If the candidate expression is a call to a lib
* function, the return will be the function name. If not, the return will be
* `undefined`.
*/
ol.expr.isLibCall = function(expr) {
var name;
if (expr instanceof ol.expr.Call) {
var callee = expr.getCallee();
if (callee instanceof ol.expr.Identifier) {
name = callee.getName();
if (!ol.expr.lib.hasOwnProperty(name)) {
name = undefined;
}
}
}
return name;
};
/**
* Library of well-known functions. These are available to expressions parsed
* with `ol.expr.parse`.
*
* @type {Object.<string, function(...)>}
*/
ol.expr.lib = {};
/**
* Enumeration of library function names.
*
* @enum {string}
*/
ol.expr.functions = {
CONCAT: 'concat',
COUNTER: 'counter',
EXTENT: 'extent',
FID: 'fid',
GEOMETRY_TYPE: 'geometryType',
RENDER_INTENT: 'renderIntent',
INTERSECTS: 'intersects',
CONTAINS: 'contains',
DWITHIN: 'dwithin',
WITHIN: 'within',
LIKE: 'like',
IEQ: 'ieq',
INEQ: 'ineq'
};
/**
* Concatenate strings. All provided arguments will be cast to string and
* concatenated.
* @param {...string} var_args Strings to concatenate.
* @return {string} All input arguments concatenated as strings.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.CONCAT] = function(var_args) {
var str = '';
for (var i = 0, ii = arguments.length; i < ii; ++i) {
str += String(arguments[i]);
}
return str;
};
/**
* Returns a counter which increases every time this function is called.
* @param {number=} opt_start Start. If not provided, the counter starts at 1.
* @return {number} Counter.
*/
ol.expr.lib[ol.expr.functions.COUNTER] = (function() {
var counter = 0;
return function(opt_start) {
var result = ++counter;
if (goog.isDef(opt_start)) {
result += opt_start;
}
return result;
};
})();
/**
* Determine if a feature's extent intersects the provided extent.
* @param {number} minX Minimum x-coordinate value.
* @param {number} minY Minimum y-coordinate value.
* @param {number} maxX Maximum x-coordinate value.
* @param {number} maxY Maximum y-coordinate value.
* @param {string=} opt_projection Projection of the extent.
* @param {string=} opt_attribute Name of the geometry attribute to use.
* @return {boolean} The provided extent intersects the feature's extent.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, minY, maxX, maxY,
opt_projection, opt_attribute) {
var intersects = false;
var geometry = goog.isDef(opt_attribute) ?
this.get(opt_attribute) : this.getGeometry();
if (geometry) {
intersects = ol.extent.intersects(geometry.getBounds(),
[minX, minY, maxX, maxY]);
}
return intersects;
};
/**
* Determine if the feature identifier matches any of the provided values.
* @param {...string} var_args Feature identifiers.
* @return {boolean} The feature's identifier matches one of the given values.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.FID] = function(var_args) {
var matches = false;
var id = this.getId();
if (goog.isDef(id)) {
for (var i = 0, ii = arguments.length; i < ii; ++i) {
if (arguments[i] === id) {
matches = true;
break;
}
}
}
return matches;
};
/**
* Determine if two strings are like one another, based on simple pattern
* matching.
* @param {string} value The string to test.
* @param {string} pattern The comparison pattern.
* @param {string} wildCard The wildcard character to use.
* @param {string} singleChar The single character to use.
* @param {string} escapeChar The escape character to use.
* @param {boolean} matchCase Should we match case or not?
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.LIKE] = function(value, pattern, wildCard,
singleChar, escapeChar, matchCase) {
if (wildCard == '.') {
throw new Error('"." is an unsupported wildCard character for ' +
'the "like" function');
}
// set UMN MapServer defaults for unspecified parameters
wildCard = goog.isDef(wildCard) ? wildCard : '*';
singleChar = goog.isDef(singleChar) ? singleChar : '.';
escapeChar = goog.isDef(escapeChar) ? escapeChar : '!';
pattern = pattern.replace(
new RegExp('\\' + escapeChar + '(.|$)', 'g'), '\\$1');
pattern = pattern.replace(
new RegExp('\\' + singleChar, 'g'), '.');
pattern = pattern.replace(
new RegExp('\\' + wildCard, 'g'), '.*');
pattern = pattern.replace(
new RegExp('\\\\.\\*', 'g'), '\\' + wildCard);
pattern = pattern.replace(
new RegExp('\\\\\\.', 'g'), '\\' + singleChar);
var modifiers = (matchCase === false) ? 'gi' : 'g';
return new RegExp(pattern, modifiers).test(value);
};
/**
* Case insensitive comparison for equality.
* @param {*} first First value.
* @param {*} second Second value.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.IEQ] = function(first, second) {
if (goog.isString(first) && goog.isString(second)) {
return first.toUpperCase() == second.toUpperCase();
} else {
return first == second;
}
};
/**
* Case insensitive comparison for non-equality.
* @param {*} first First value.
* @param {*} second Second value.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.INEQ] = function(first, second) {
if (goog.isString(first) && goog.isString(second)) {
return first.toUpperCase() != second.toUpperCase();
} else {
return first != second;
}
};
/**
* Determine if a feature's default geometry is of the given type.
* @param {ol.geom.GeometryType} type Geometry type.
* @return {boolean} The feature's default geometry is of the given type.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.GEOMETRY_TYPE] = function(type) {
var same = false;
var geometry = this.getGeometry();
if (geometry) {
same = geometry.getType() === type;
}
return same;
};
/**
* Determine if a feature's renderIntent matches the given one.
* @param {string} renderIntent Render intent.
* @return {boolean} The feature's renderIntent matches the given one.
* @this {ol.Feature}
*/
ol.expr.lib[ol.expr.functions.RENDER_INTENT] = function(renderIntent) {
return this.getRenderIntent() == renderIntent;
};
ol.expr.lib[ol.expr.functions.INTERSECTS] = function(geom, opt_projection,
opt_attribute) {
throw new Error('Spatial function not implemented: ' +
ol.expr.functions.INTERSECTS);
};
ol.expr.lib[ol.expr.functions.WITHIN] = function(geom, opt_projection,
opt_attribute) {
throw new Error('Spatial function not implemented: ' +
ol.expr.functions.WITHIN);
};
ol.expr.lib[ol.expr.functions.CONTAINS] = function(geom, opt_projeciton,
opt_attribute) {
throw new Error('Spatial function not implemented: ' +
ol.expr.functions.CONTAINS);
};
ol.expr.lib[ol.expr.functions.DWITHIN] = function(geom, distance, units,
opt_projection, opt_attribute) {
throw new Error('Spatial function not implemented: ' +
ol.expr.functions.DWITHIN);
};

View File

@@ -0,0 +1,626 @@
goog.provide('ol.expr.Call');
goog.provide('ol.expr.Comparison');
goog.provide('ol.expr.ComparisonOp');
goog.provide('ol.expr.Expression');
goog.provide('ol.expr.Identifier');
goog.provide('ol.expr.Literal');
goog.provide('ol.expr.Logical');
goog.provide('ol.expr.LogicalOp');
goog.provide('ol.expr.Math');
goog.provide('ol.expr.MathOp');
goog.provide('ol.expr.Member');
goog.provide('ol.expr.Not');
/**
* Base class for all expressions. Instances of ol.expr.Expression
* correspond to a limited set of ECMAScript 5.1 expressions.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11
*
* This base class should not be constructed directly. Instead, use one of
* the subclass constructors.
*
* @constructor
*/
ol.expr.Expression = function() {};
/**
* Evaluate the expression and return the result.
*
* @param {Object=} opt_scope Evaluation scope. All properties of this object
* will be available as variables when evaluating the expression. If not
* provided, `null` will be used.
* @param {Object=} opt_fns Optional scope for looking up functions. If not
* provided, functions will be looked in the evaluation scope.
* @param {Object=} opt_this Object to use as this when evaluating call
* expressions. If not provided, `this` will resolve to a new object.
* @return {*} Result of the expression.
*/
ol.expr.Expression.prototype.evaluate = goog.abstractMethod;
/**
* A call expression (e.g. `foo(bar)`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.Expression} callee An expression that resolves to a
* function.
* @param {Array.<ol.expr.Expression>} args Arguments.
*/
ol.expr.Call = function(callee, args) {
/**
* @type {ol.expr.Expression}
* @private
*/
this.callee_ = callee;
/**
* @type {Array.<ol.expr.Expression>}
* @private
*/
this.args_ = args;
};
goog.inherits(ol.expr.Call, ol.expr.Expression);
/**
* @inheritDoc
*/
ol.expr.Call.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
var fnScope = goog.isDefAndNotNull(opt_fns) ? opt_fns : opt_scope;
var fn = this.callee_.evaluate(fnScope);
if (!fn || !goog.isFunction(fn)) {
throw new Error('Expected function but found ' + fn);
}
var thisArg = goog.isDef(opt_this) ? opt_this : {};
var len = this.args_.length;
var values = new Array(len);
for (var i = 0; i < len; ++i) {
values[i] = this.args_[i].evaluate(opt_scope, opt_fns, opt_this);
}
return fn.apply(thisArg, values);
};
/**
* Get the argument list.
* @return {Array.<ol.expr.Expression>} The argument.
*/
ol.expr.Call.prototype.getArgs = function() {
return this.args_;
};
/**
* Get the callee expression.
* @return {ol.expr.Expression} The callee expression.
*/
ol.expr.Call.prototype.getCallee = function() {
return this.callee_;
};
/**
* @enum {string}
*/
ol.expr.ComparisonOp = {
EQ: '==',
NEQ: '!=',
STRICT_EQ: '===',
STRICT_NEQ: '!==',
GT: '>',
LT: '<',
GTE: '>=',
LTE: '<='
};
/**
* A comparison expression (e.g. `foo >= 42`, `bar != "chicken"`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.ComparisonOp} operator Comparison operator.
* @param {ol.expr.Expression} left Left expression.
* @param {ol.expr.Expression} right Right expression.
*/
ol.expr.Comparison = function(operator, left, right) {
/**
* @type {ol.expr.ComparisonOp}
* @private
*/
this.operator_ = operator;
/**
* @type {ol.expr.Expression}
* @private
*/
this.left_ = left;
/**
* @type {ol.expr.Expression}
* @private
*/
this.right_ = right;
};
goog.inherits(ol.expr.Comparison, ol.expr.Expression);
/**
* Determine if a given string is a valid comparison operator.
* @param {string} candidate Operator to test.
* @return {boolean} The operator is valid.
*/
ol.expr.Comparison.isValidOp = (function() {
var valid = {};
for (var key in ol.expr.ComparisonOp) {
valid[ol.expr.ComparisonOp[key]] = true;
}
return function isValidOp(candidate) {
return !!valid[candidate];
};
}());
/**
* @inheritDoc
*/
ol.expr.Comparison.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
var result;
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
var op = this.operator_;
if (op === ol.expr.ComparisonOp.EQ) {
result = leftVal == rightVal;
} else if (op === ol.expr.ComparisonOp.NEQ) {
result = leftVal != rightVal;
} else if (op === ol.expr.ComparisonOp.STRICT_EQ) {
result = leftVal === rightVal;
} else if (op === ol.expr.ComparisonOp.STRICT_NEQ) {
result = leftVal !== rightVal;
} else if (op === ol.expr.ComparisonOp.GT) {
result = leftVal > rightVal;
} else if (op === ol.expr.ComparisonOp.LT) {
result = leftVal < rightVal;
} else if (op === ol.expr.ComparisonOp.GTE) {
result = leftVal >= rightVal;
} else if (op === ol.expr.ComparisonOp.LTE) {
result = leftVal <= rightVal;
} else {
throw new Error('Unsupported comparison operator: ' + this.operator_);
}
return result;
};
/**
* Get the comparison operator.
* @return {string} The comparison operator.
*/
ol.expr.Comparison.prototype.getOperator = function() {
return this.operator_;
};
/**
* Get the left expression.
* @return {ol.expr.Expression} The left expression.
*/
ol.expr.Comparison.prototype.getLeft = function() {
return this.left_;
};
/**
* Get the right expression.
* @return {ol.expr.Expression} The right expression.
*/
ol.expr.Comparison.prototype.getRight = function() {
return this.right_;
};
/**
* An identifier expression (e.g. `foo`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {string} name An identifier name.
*/
ol.expr.Identifier = function(name) {
/**
* @type {string}
* @private
*/
this.name_ = name;
};
goog.inherits(ol.expr.Identifier, ol.expr.Expression);
/**
* @inheritDoc
*/
ol.expr.Identifier.prototype.evaluate = function(opt_scope) {
if (!goog.isDefAndNotNull(opt_scope)) {
throw new Error('Attempt to evaluate identifier with no scope');
}
return opt_scope[this.name_];
};
/**
* Get the identifier name.
* @return {string} The identifier name.
*/
ol.expr.Identifier.prototype.getName = function() {
return this.name_;
};
/**
* A literal expression (e.g. `"chicken"`, `42`, `true`, `null`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {string|number|boolean|Date|null} value A literal value.
*/
ol.expr.Literal = function(value) {
/**
* @type {string|number|boolean|Date|null}
* @private
*/
this.value_ = value;
};
goog.inherits(ol.expr.Literal, ol.expr.Expression);
/**
* @inheritDoc
*/
ol.expr.Literal.prototype.evaluate = function() {
return this.value_;
};
/**
* Get the literal value.
* @return {string|number|boolean|Date|null} The literal value.
*/
ol.expr.Literal.prototype.getValue = function() {
return this.value_;
};
/**
* @enum {string}
*/
ol.expr.LogicalOp = {
AND: '&&',
OR: '||'
};
/**
* A binary logical expression (e.g. `foo && bar`, `bar || "chicken"`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.LogicalOp} operator Logical operator.
* @param {ol.expr.Expression} left Left expression.
* @param {ol.expr.Expression} right Right expression.
*/
ol.expr.Logical = function(operator, left, right) {
/**
* @type {ol.expr.LogicalOp}
* @private
*/
this.operator_ = operator;
/**
* @type {ol.expr.Expression}
* @private
*/
this.left_ = left;
/**
* @type {ol.expr.Expression}
* @private
*/
this.right_ = right;
};
goog.inherits(ol.expr.Logical, ol.expr.Expression);
/**
* Determine if a given string is a valid logical operator.
* @param {string} candidate Operator to test.
* @return {boolean} The operator is valid.
*/
ol.expr.Logical.isValidOp = (function() {
var valid = {};
for (var key in ol.expr.LogicalOp) {
valid[ol.expr.LogicalOp[key]] = true;
}
return function isValidOp(candidate) {
return !!valid[candidate];
};
}());
/**
* @inheritDoc
*/
ol.expr.Logical.prototype.evaluate = function(opt_scope, opt_fns,
opt_this) {
var result;
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
if (this.operator_ === ol.expr.LogicalOp.AND) {
result = leftVal && rightVal;
} else if (this.operator_ === ol.expr.LogicalOp.OR) {
result = leftVal || rightVal;
} else {
throw new Error('Unsupported logical operator: ' + this.operator_);
}
return result;
};
/**
* Get the logical operator.
* @return {string} The logical operator.
*/
ol.expr.Logical.prototype.getOperator = function() {
return this.operator_;
};
/**
* Get the left expression.
* @return {ol.expr.Expression} The left expression.
*/
ol.expr.Logical.prototype.getLeft = function() {
return this.left_;
};
/**
* Get the right expression.
* @return {ol.expr.Expression} The right expression.
*/
ol.expr.Logical.prototype.getRight = function() {
return this.right_;
};
/**
* @enum {string}
*/
ol.expr.MathOp = {
ADD: '+',
SUBTRACT: '-',
MULTIPLY: '*',
DIVIDE: '/',
MOD: '%'
};
/**
* A math expression (e.g. `foo + 42`, `bar % 10`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.MathOp} operator Math operator.
* @param {ol.expr.Expression} left Left expression.
* @param {ol.expr.Expression} right Right expression.
*/
ol.expr.Math = function(operator, left, right) {
/**
* @type {ol.expr.MathOp}
* @private
*/
this.operator_ = operator;
/**
* @type {ol.expr.Expression}
* @private
*/
this.left_ = left;
/**
* @type {ol.expr.Expression}
* @private
*/
this.right_ = right;
};
goog.inherits(ol.expr.Math, ol.expr.Expression);
/**
* Determine if a given string is a valid math operator.
* @param {string} candidate Operator to test.
* @return {boolean} The operator is valid.
*/
ol.expr.Math.isValidOp = (function() {
var valid = {};
for (var key in ol.expr.MathOp) {
valid[ol.expr.MathOp[key]] = true;
}
return function isValidOp(candidate) {
return !!valid[candidate];
};
}());
/**
* @inheritDoc
*/
ol.expr.Math.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
var result;
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
var op = this.operator_;
if (op === ol.expr.MathOp.ADD) {
result = leftVal + rightVal;
} else if (op === ol.expr.MathOp.SUBTRACT) {
result = Number(leftVal) - Number(rightVal);
} else if (op === ol.expr.MathOp.MULTIPLY) {
result = Number(leftVal) * Number(rightVal);
} else if (op === ol.expr.MathOp.DIVIDE) {
result = Number(leftVal) / Number(rightVal);
} else if (op === ol.expr.MathOp.MOD) {
result = Number(leftVal) % Number(rightVal);
} else {
throw new Error('Unsupported math operator: ' + this.operator_);
}
return result;
};
/**
* Get the math operator.
* @return {string} The math operator.
*/
ol.expr.Math.prototype.getOperator = function() {
return this.operator_;
};
/**
* Get the left expression.
* @return {ol.expr.Expression} The left expression.
*/
ol.expr.Math.prototype.getLeft = function() {
return this.left_;
};
/**
* Get the right expression.
* @return {ol.expr.Expression} The right expression.
*/
ol.expr.Math.prototype.getRight = function() {
return this.right_;
};
/**
* A member expression (e.g. `foo.bar`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.Expression} object An expression that resolves to an
* object.
* @param {ol.expr.Identifier} property Identifier with name of property.
*/
ol.expr.Member = function(object, property) {
/**
* @type {ol.expr.Expression}
* @private
*/
this.object_ = object;
/**
* @type {ol.expr.Identifier}
* @private
*/
this.property_ = property;
};
goog.inherits(ol.expr.Member, ol.expr.Expression);
/**
* @inheritDoc
*/
ol.expr.Member.prototype.evaluate = function(opt_scope, opt_fns,
opt_this) {
var obj = this.object_.evaluate(opt_scope, opt_fns, opt_this);
if (!goog.isObject(obj)) {
throw new Error('Expected member expression to evaluate to an object ' +
'but got ' + obj);
}
return this.property_.evaluate(/** @type {Object} */ (obj));
};
/**
* Get the object expression.
* @return {ol.expr.Expression} The object.
*/
ol.expr.Member.prototype.getObject = function() {
return this.object_;
};
/**
* Get the property expression.
* @return {ol.expr.Identifier} The property.
*/
ol.expr.Member.prototype.getProperty = function() {
return this.property_;
};
/**
* A logical not expression (e.g. `!foo`).
*
* @constructor
* @extends {ol.expr.Expression}
* @param {ol.expr.Expression} argument Expression to negate.
*/
ol.expr.Not = function(argument) {
/**
* @type {ol.expr.Expression}
* @private
*/
this.argument_ = argument;
};
goog.inherits(ol.expr.Not, ol.expr.Expression);
/**
* @inheritDoc
*/
ol.expr.Not.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
return !this.argument_.evaluate(opt_scope, opt_fns, opt_this);
};
/**
* Get the argument (the negated expression).
* @return {ol.expr.Expression} The argument.
*/
ol.expr.Not.prototype.getArgument = function() {
return this.argument_;
};

900
old/src/ol/expr/lexer.js Normal file
View File

@@ -0,0 +1,900 @@
/**
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
* Esprima (http://esprima.org) includes the following copyright notices:
*
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
*/
goog.provide('ol.expr.Char'); // TODO: remove this - see #785
goog.provide('ol.expr.Lexer');
goog.provide('ol.expr.Token');
goog.provide('ol.expr.TokenType');
goog.provide('ol.expr.UnexpectedToken');
goog.require('goog.asserts');
goog.require('goog.debug.Error');
/**
* @enum {number}
*/
ol.expr.Char = {
AMPERSAND: 38,
BACKSLASH: 92,
BANG: 33, // !
CARRIAGE_RETURN: 13,
COMMA: 44,
DIGIT_0: 48,
DIGIT_7: 55,
DIGIT_9: 57,
DOLLAR: 36,
DOUBLE_QUOTE: 34,
DOT: 46,
EQUAL: 61,
FORM_FEED: 0xC,
GREATER: 62,
LEFT_PAREN: 40,
LESS: 60,
LINE_FEED: 10,
LINE_SEPARATOR: 0x2028,
LOWER_A: 97,
LOWER_E: 101,
LOWER_F: 102,
LOWER_X: 120,
LOWER_Z: 122,
MINUS: 45,
NONBREAKING_SPACE: 0xA0,
PARAGRAPH_SEPARATOR: 0x2029,
PERCENT: 37,
PIPE: 124,
PLUS: 43,
RIGHT_PAREN: 41,
SINGLE_QUOTE: 39,
SLASH: 47,
SPACE: 32,
STAR: 42,
TAB: 9,
TILDE: 126,
UNDERSCORE: 95,
UPPER_A: 65,
UPPER_E: 69,
UPPER_F: 70,
UPPER_X: 88,
UPPER_Z: 90,
VERTICAL_TAB: 0xB
};
/**
* @enum {string}
*/
ol.expr.TokenType = {
BOOLEAN_LITERAL: 'Boolean',
EOF: '<end>',
IDENTIFIER: 'Identifier',
KEYWORD: 'Keyword',
NULL_LITERAL: 'Null',
NUMERIC_LITERAL: 'Numeric',
PUNCTUATOR: 'Punctuator',
STRING_LITERAL: 'String',
UNKNOWN: 'Unknown'
};
/**
* @typedef {{type: (ol.expr.TokenType),
* value: (string|number|boolean|null),
* index: (number)}}
*/
ol.expr.Token;
/**
* Lexer constructor. Provides a tokenizer for a limited subset of ECMAScript
* 5.1 expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
*
* @constructor
* @param {string} source Source code.
*/
ol.expr.Lexer = function(source) {
/**
* Source code.
* @type {string}
* @private
*/
this.source_ = source;
/**
* Source length.
* @type {number}
* @private
*/
this.length_ = source.length;
/**
* Current character index.
* @type {number}
* @private
*/
this.index_ = 0;
/**
* Next character index (only set after `peek`ing).
* @type {number}
* @private
*/
this.nextIndex_ = 0;
};
/**
* Scan the next token and throw if it isn't a punctuator that matches input.
* @param {string} value Token value.
*/
ol.expr.Lexer.prototype.expect = function(value) {
var match = this.match(value);
if (!match) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: this.getCurrentChar_(),
index: this.index_
});
}
this.skip();
};
/**
* Increment the current character index.
*
* @param {number} delta Delta by which the index is advanced.
* @private
*/
ol.expr.Lexer.prototype.increment_ = function(delta) {
this.index_ += delta;
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is a decimal digit.
* @private
*/
ol.expr.Lexer.prototype.isDecimalDigit_ = function(code) {
return (
code >= ol.expr.Char.DIGIT_0 &&
code <= ol.expr.Char.DIGIT_9);
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.2
*
* @param {string} id A string identifier.
* @return {boolean} The identifier is a future reserved word.
* @private
*/
ol.expr.Lexer.prototype.isFutureReservedWord_ = function(id) {
return (
id === 'class' ||
id === 'enum' ||
id === 'export' ||
id === 'extends' ||
id === 'import' ||
id === 'super');
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is a hex digit.
* @private
*/
ol.expr.Lexer.prototype.isHexDigit_ = function(code) {
return this.isDecimalDigit_(code) ||
(code >= ol.expr.Char.LOWER_A &&
code <= ol.expr.Char.LOWER_F) ||
(code >= ol.expr.Char.UPPER_A &&
code <= ol.expr.Char.UPPER_F);
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
* Doesn't deal with non-ascii identifiers.
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is a valid identifier part.
* @private
*/
ol.expr.Lexer.prototype.isIdentifierPart_ = function(code) {
return this.isIdentifierStart_(code) ||
(code >= ol.expr.Char.DIGIT_0 &&
code <= ol.expr.Char.DIGIT_9);
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
* Doesn't yet deal with non-ascii identifiers.
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is a valid identifier start.
* @private
*/
ol.expr.Lexer.prototype.isIdentifierStart_ = function(code) {
return (code === ol.expr.Char.DOLLAR) ||
(code === ol.expr.Char.UNDERSCORE) ||
(code >= ol.expr.Char.UPPER_A &&
code <= ol.expr.Char.UPPER_Z) ||
(code >= ol.expr.Char.LOWER_A &&
code <= ol.expr.Char.LOWER_Z);
};
/**
* Determine if the given identifier is an ECMAScript keyword. These cannot
* be used as identifiers in programs. There is no real reason these could not
* be used in ol.exprs - but they are reserved for future use.
*
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.1
*
* @param {string} id Identifier.
* @return {boolean} The identifier is a keyword.
* @private
*/
ol.expr.Lexer.prototype.isKeyword_ = function(id) {
return (
id === 'break' ||
id === 'case' ||
id === 'catch' ||
id === 'continue' ||
id === 'debugger' ||
id === 'default' ||
id === 'delete' ||
id === 'do' ||
id === 'else' ||
id === 'finally' ||
id === 'for' ||
id === 'function' ||
id === 'if' ||
id === 'in' ||
id === 'instanceof' ||
id === 'new' ||
id === 'return' ||
id === 'switch' ||
id === 'this' ||
id === 'throw' ||
id === 'try' ||
id === 'typeof' ||
id === 'var' ||
id === 'void' ||
id === 'while' ||
id === 'with');
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.3
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is a line terminator.
* @private
*/
ol.expr.Lexer.prototype.isLineTerminator_ = function(code) {
return (code === ol.expr.Char.LINE_FEED) ||
(code === ol.expr.Char.CARRIAGE_RETURN) ||
(code === ol.expr.Char.LINE_SEPARATOR) ||
(code === ol.expr.Char.PARAGRAPH_SEPARATOR);
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is an octal digit.
* @private
*/
ol.expr.Lexer.prototype.isOctalDigit_ = function(code) {
return (
code >= ol.expr.Char.DIGIT_0 &&
code <= ol.expr.Char.DIGIT_7);
};
/**
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.2
*
* @param {number} code The unicode of a character.
* @return {boolean} The character is whitespace.
* @private
*/
ol.expr.Lexer.prototype.isWhitespace_ = function(code) {
return (code === ol.expr.Char.SPACE) ||
(code === ol.expr.Char.TAB) ||
(code === ol.expr.Char.VERTICAL_TAB) ||
(code === ol.expr.Char.FORM_FEED) ||
(code === ol.expr.Char.NONBREAKING_SPACE) ||
(code >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005' +
'\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'
.indexOf(String.fromCharCode(code)) > 0);
};
/**
* Get the unicode of the character at the given offset from the current index.
*
* @param {number} delta Offset from current index.
* @return {number} The character code.
* @private
*/
ol.expr.Lexer.prototype.getCharCode_ = function(delta) {
return this.source_.charCodeAt(this.index_ + delta);
};
/**
* Get the character at the current index.
*
* @return {string} The current character.
* @private
*/
ol.expr.Lexer.prototype.getCurrentChar_ = function() {
return this.source_[this.index_];
};
/**
* Get the unicode of the character at the current index.
*
* @return {number} The current character code.
* @private
*/
ol.expr.Lexer.prototype.getCurrentCharCode_ = function() {
return this.getCharCode_(0);
};
/**
* Determine whether the upcoming token matches the given punctuator.
* @param {string} value Punctuator value.
* @return {boolean} The token matches.
*/
ol.expr.Lexer.prototype.match = function(value) {
var token = this.peek();
return (
token.type === ol.expr.TokenType.PUNCTUATOR &&
token.value === value);
};
/**
* Scan the next token.
*
* @return {ol.expr.Token} Next token.
*/
ol.expr.Lexer.prototype.next = function() {
var code = this.skipWhitespace_();
if (this.index_ >= this.length_) {
return {
type: ol.expr.TokenType.EOF,
value: null,
index: this.index_
};
}
// check for common punctuation
if (code === ol.expr.Char.LEFT_PAREN ||
code === ol.expr.Char.RIGHT_PAREN) {
return this.scanPunctuator_(code);
}
// check for string literal
if (code === ol.expr.Char.SINGLE_QUOTE ||
code === ol.expr.Char.DOUBLE_QUOTE) {
return this.scanStringLiteral_(code);
}
// check for identifier
if (this.isIdentifierStart_(code)) {
return this.scanIdentifier_(code);
}
// check dot punctuation or decimal
if (code === ol.expr.Char.DOT) {
if (this.isDecimalDigit_(this.getCharCode_(1))) {
return this.scanNumericLiteral_(code);
}
return this.scanPunctuator_(code);
}
// check for numeric literal
if (this.isDecimalDigit_(code)) {
return this.scanNumericLiteral_(code);
}
// all the rest is punctuation
return this.scanPunctuator_(code);
};
/**
* Peek at the next token, but don't advance the index.
*
* @return {ol.expr.Token} The upcoming token.
*/
ol.expr.Lexer.prototype.peek = function() {
var currentIndex = this.index_;
var token = this.next();
this.nextIndex_ = this.index_;
this.index_ = currentIndex;
return token;
};
/**
* Scan hex literal as numeric token.
*
* @param {number} code The current character code.
* @return {ol.expr.Token} Numeric literal token.
* @private
*/
ol.expr.Lexer.prototype.scanHexLiteral_ = function(code) {
var str = '';
var start = this.index_ - 2;
while (this.index_ < this.length_) {
if (!this.isHexDigit_(code)) {
break;
}
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
}
if (str.length === 0 || this.isIdentifierStart_(code)) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(code),
index: this.index_
});
}
goog.asserts.assert(!isNaN(parseInt('0x' + str, 16)), 'Valid hex: ' + str);
return {
type: ol.expr.TokenType.NUMERIC_LITERAL,
value: parseInt('0x' + str, 16),
index: start
};
};
/**
* Scan identifier token.
*
* @param {number} code The current character code.
* @return {ol.expr.Token} Identifier token.
* @private
*/
ol.expr.Lexer.prototype.scanIdentifier_ = function(code) {
goog.asserts.assert(this.isIdentifierStart_(code),
'Must be called with a valid identifier');
var start = this.index_;
this.increment_(1);
while (this.index_ < this.length_) {
code = this.getCurrentCharCode_();
if (this.isIdentifierPart_(code)) {
this.increment_(1);
} else {
break;
}
}
var id = this.source_.slice(start, this.index_);
var type;
if (id.length === 1) {
type = ol.expr.TokenType.IDENTIFIER;
} else if (this.isKeyword_(id)) {
type = ol.expr.TokenType.KEYWORD;
} else if (id === 'null') {
type = ol.expr.TokenType.NULL_LITERAL;
} else if (id === 'true' || id === 'false') {
type = ol.expr.TokenType.BOOLEAN_LITERAL;
} else {
type = ol.expr.TokenType.IDENTIFIER;
}
return {
type: type,
value: id,
index: start
};
};
/**
* Scan numeric literal token.
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
*
* @param {number} code The current character code.
* @return {ol.expr.Token} Numeric literal token.
* @private
*/
ol.expr.Lexer.prototype.scanNumericLiteral_ = function(code) {
goog.asserts.assert(
code === ol.expr.Char.DOT || this.isDecimalDigit_(code),
'Valid start for numeric literal: ' + String.fromCharCode(code));
// start assembling numeric string
var str = '';
var start = this.index_;
if (code !== ol.expr.Char.DOT) {
if (code === ol.expr.Char.DIGIT_0) {
var nextCode = this.getCharCode_(1);
// hex literals start with 0X or 0x
if (nextCode === ol.expr.Char.UPPER_X ||
nextCode === ol.expr.Char.LOWER_X) {
this.increment_(2);
return this.scanHexLiteral_(this.getCurrentCharCode_());
}
// octals start with 0
if (this.isOctalDigit_(nextCode)) {
this.increment_(1);
return this.scanOctalLiteral_(nextCode);
}
// numbers like 09 not allowed
if (this.isDecimalDigit_(nextCode)) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(nextCode),
index: this.index_
});
}
}
// scan all decimal chars
while (this.isDecimalDigit_(code)) {
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
}
}
// scan fractional part
if (code === ol.expr.Char.DOT) {
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
// scan all decimal chars
while (this.isDecimalDigit_(code)) {
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
}
}
// scan exponent
if (code === ol.expr.Char.UPPER_E ||
code === ol.expr.Char.LOWER_E) {
str += 'E';
this.increment_(1);
code = this.getCurrentCharCode_();
if (code === ol.expr.Char.PLUS ||
code === ol.expr.Char.MINUS) {
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
}
if (!this.isDecimalDigit_(code)) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(code),
index: this.index_
});
}
// scan all decimal chars (TODO: unduplicate this)
while (this.isDecimalDigit_(code)) {
str += String.fromCharCode(code);
this.increment_(1);
code = this.getCurrentCharCode_();
}
}
if (this.isIdentifierStart_(code)) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(code),
index: this.index_
});
}
goog.asserts.assert(!isNaN(parseFloat(str)), 'Valid number: ' + str);
return {
type: ol.expr.TokenType.NUMERIC_LITERAL,
value: parseFloat(str),
index: start
};
};
/**
* Scan octal literal as numeric token.
*
* @param {number} code The current character code.
* @return {ol.expr.Token} Numeric literal token.
* @private
*/
ol.expr.Lexer.prototype.scanOctalLiteral_ = function(code) {
goog.asserts.assert(this.isOctalDigit_(code));
var str = '0' + String.fromCharCode(code);
var start = this.index_ - 1;
this.increment_(1);
while (this.index_ < this.length_) {
code = this.getCurrentCharCode_();
if (!this.isOctalDigit_(code)) {
break;
}
str += String.fromCharCode(code);
this.increment_(1);
}
code = this.getCurrentCharCode_();
if (this.isIdentifierStart_(code) ||
this.isDecimalDigit_(code)) {
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(code),
index: this.index_
});
}
goog.asserts.assert(!isNaN(parseInt(str, 8)), 'Valid octal: ' + str);
return {
type: ol.expr.TokenType.NUMERIC_LITERAL,
value: parseInt(str, 8),
index: start
};
};
/**
* Scan punctuator token (a subset of allowed tokens in 7.7).
*
* @param {number} code The current character code.
* @return {ol.expr.Token} Punctuator token.
* @private
*/
ol.expr.Lexer.prototype.scanPunctuator_ = function(code) {
var start = this.index_;
// single char punctuation that also doesn't start longer punctuation
// (we disallow assignment, so no += etc.)
if (code === ol.expr.Char.DOT ||
code === ol.expr.Char.LEFT_PAREN ||
code === ol.expr.Char.RIGHT_PAREN ||
code === ol.expr.Char.COMMA ||
code === ol.expr.Char.PLUS ||
code === ol.expr.Char.MINUS ||
code === ol.expr.Char.STAR ||
code === ol.expr.Char.SLASH ||
code === ol.expr.Char.PERCENT ||
code === ol.expr.Char.TILDE) {
this.increment_(1);
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: String.fromCharCode(code),
index: start
};
}
// check for 2-character punctuation
var nextCode = this.getCharCode_(1);
// assignment or comparison (and we don't allow assignment)
if (nextCode === ol.expr.Char.EQUAL) {
if (code === ol.expr.Char.BANG || code === ol.expr.Char.EQUAL) {
// we're looking at !=, ==, !==, or ===
this.increment_(2);
// check for triple
if (this.getCurrentCharCode_() === ol.expr.Char.EQUAL) {
this.increment_(1);
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: String.fromCharCode(code) + '==',
index: start
};
} else {
// != or ==
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: String.fromCharCode(code) + '=',
index: start
};
}
}
if (code === ol.expr.Char.GREATER ||
code === ol.expr.Char.LESS) {
this.increment_(2);
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: String.fromCharCode(code) + '=',
index: start
};
}
}
// remaining 2-charcter punctuators are || and &&
if (code === nextCode &&
(code === ol.expr.Char.PIPE ||
code === ol.expr.Char.AMPERSAND)) {
this.increment_(2);
var str = String.fromCharCode(code);
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: str + str,
index: start
};
}
// we don't allow 4-character punctuator (>>>=)
// and the allowed 3-character punctuators (!==, ===) are already consumed
// other single character punctuators
if (code === ol.expr.Char.GREATER ||
code === ol.expr.Char.LESS ||
code === ol.expr.Char.BANG ||
code === ol.expr.Char.AMPERSAND ||
code === ol.expr.Char.PIPE) {
this.increment_(1);
return {
type: ol.expr.TokenType.PUNCTUATOR,
value: String.fromCharCode(code),
index: start
};
}
throw new ol.expr.UnexpectedToken({
type: ol.expr.TokenType.UNKNOWN,
value: String.fromCharCode(code),
index: this.index_
});
};
/**
* Scan string literal token.
*
* @param {number} quote The current character code.
* @return {ol.expr.Token} String literal token.
* @private
*/
ol.expr.Lexer.prototype.scanStringLiteral_ = function(quote) {
goog.asserts.assert(quote === ol.expr.Char.SINGLE_QUOTE ||
quote === ol.expr.Char.DOUBLE_QUOTE,
'Strings must start with a quote: ' + String.fromCharCode(quote));
var start = this.index_;
this.increment_(1);
var str = '';
var code;
while (this.index_ < this.length_) {
code = this.getCurrentCharCode_();
this.increment_(1);
if (code === quote) {
quote = 0;
break;
}
// look for escaped quote or backslash
if (code === ol.expr.Char.BACKSLASH) {
str += this.getCurrentChar_();
this.increment_(1);
} else {
str += String.fromCharCode(code);
}
}
if (quote !== 0) {
// unterminated string literal
throw new ol.expr.UnexpectedToken(this.peek());
}
return {
type: ol.expr.TokenType.STRING_LITERAL,
value: str,
index: start
};
};
/**
* After peeking, skip may be called to advance the cursor without re-scanning.
*/
ol.expr.Lexer.prototype.skip = function() {
this.index_ = this.nextIndex_;
};
/**
* Skip all whitespace.
* @return {number} The character code of the first non-whitespace character.
* @private
*/
ol.expr.Lexer.prototype.skipWhitespace_ = function() {
var code = NaN;
while (this.index_ < this.length_) {
code = this.getCurrentCharCode_();
if (this.isWhitespace_(code)) {
this.increment_(1);
} else {
break;
}
}
return code;
};
/**
* Error object for unexpected tokens.
* @param {ol.expr.Token} token The unexpected token.
* @param {string=} opt_message Custom error message.
* @constructor
* @extends {goog.debug.Error}
*/
ol.expr.UnexpectedToken = function(token, opt_message) {
var message = goog.isDef(opt_message) ? opt_message :
'Unexpected token ' + token.value + ' at index ' + token.index;
goog.debug.Error.call(this, message);
/**
* @type {ol.expr.Token}
*/
this.token = token;
};
goog.inherits(ol.expr.UnexpectedToken, goog.debug.Error);
/** @override */
ol.expr.UnexpectedToken.prototype.name = 'UnexpectedToken';

478
old/src/ol/expr/parser.js Normal file
View File

@@ -0,0 +1,478 @@
/**
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
* Esprima (http://esprima.org) includes the following copyright notices:
*
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
*/
goog.provide('ol.expr.Parser');
goog.require('goog.asserts');
goog.require('ol.expr.Call');
goog.require('ol.expr.Comparison');
goog.require('ol.expr.ComparisonOp');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Lexer');
goog.require('ol.expr.Literal');
goog.require('ol.expr.Logical');
goog.require('ol.expr.LogicalOp');
goog.require('ol.expr.Math');
goog.require('ol.expr.MathOp');
goog.require('ol.expr.Member');
goog.require('ol.expr.Not');
goog.require('ol.expr.Token');
goog.require('ol.expr.TokenType');
goog.require('ol.expr.UnexpectedToken');
/**
* Instances of ol.expr.Parser parse a very limited set of ECMAScript
* expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
*
* - Primary Expression (11.1):
* - Identifier (e.g. `foo`)
* - Literal (e.g. `"some string"` or `42`)
* - Grouped (e.g. `(foo)`)
* - Left-Hand-Side Expression (11.2):
* - Property Accessors
* - Dot notation only
* - Function Calls
* - Identifier with arguments only (e.g. `foo(bar, 42)`)
* - Unary Operators (11.4)
* - Logical Not (e.g. `!foo`)
* - Multiplicitave Operators (11.5)
* - Additive Operators (11.6)
* - Relational Operators (11.8)
* - <, >, <=, and >= only
* - Equality Operators (11.9)
* - Binary Logical Operators (11.11)
*
* @constructor
*/
ol.expr.Parser = function() {
};
/**
* Determine the precedence for the given token.
*
* @param {ol.expr.Token} token A token.
* @return {number} The precedence for the given token. Higher gets more
* precedence.
* @private
*/
ol.expr.Parser.prototype.binaryPrecedence_ = function(token) {
var precedence = 0;
if (token.type !== ol.expr.TokenType.PUNCTUATOR) {
return precedence;
}
switch (token.value) {
case ol.expr.LogicalOp.OR:
precedence = 1;
break;
case ol.expr.LogicalOp.AND:
precedence = 2;
break;
case ol.expr.ComparisonOp.EQ:
case ol.expr.ComparisonOp.NEQ:
case ol.expr.ComparisonOp.STRICT_EQ:
case ol.expr.ComparisonOp.STRICT_NEQ:
precedence = 3;
break;
case ol.expr.ComparisonOp.GT:
case ol.expr.ComparisonOp.LT:
case ol.expr.ComparisonOp.GTE:
case ol.expr.ComparisonOp.LTE:
precedence = 4;
break;
case ol.expr.MathOp.ADD:
case ol.expr.MathOp.SUBTRACT:
precedence = 5;
break;
case ol.expr.MathOp.MULTIPLY:
case ol.expr.MathOp.DIVIDE:
case ol.expr.MathOp.MOD:
precedence = 6;
break;
default:
// punctuator is not a supported binary operator, that's fine
break;
}
return precedence;
};
/**
* Create a binary expression.
*
* @param {string} operator Operator.
* @param {ol.expr.Expression} left Left expression.
* @param {ol.expr.Expression} right Right expression.
* @return {ol.expr.Expression} The expression.
* @private
*/
ol.expr.Parser.prototype.createBinaryExpression_ = function(operator,
left, right) {
var expr;
if (ol.expr.Comparison.isValidOp(operator)) {
expr = new ol.expr.Comparison(
/** @type {ol.expr.ComparisonOp.<string>} */ (operator),
left, right);
} else if (ol.expr.Logical.isValidOp(operator)) {
expr = new ol.expr.Logical(
/** @type {ol.expr.LogicalOp.<string>} */ (operator),
left, right);
} else if (ol.expr.Math.isValidOp(operator)) {
expr = new ol.expr.Math(
/** @type {ol.expr.MathOp.<string>} */ (operator),
left, right);
} else {
throw new Error('Unsupported binary operator: ' + operator);
}
return expr;
};
/**
* Create a call expression.
*
* @param {ol.expr.Expression} callee Expression for function.
* @param {Array.<ol.expr.Expression>} args Arguments array.
* @return {ol.expr.Call} Call expression.
* @private
*/
ol.expr.Parser.prototype.createCallExpression_ = function(callee, args) {
return new ol.expr.Call(callee, args);
};
/**
* Create an identifier expression.
*
* @param {string} name Identifier name.
* @return {ol.expr.Identifier} Identifier expression.
* @private
*/
ol.expr.Parser.prototype.createIdentifier_ = function(name) {
return new ol.expr.Identifier(name);
};
/**
* Create a literal expression.
*
* @param {string|number|boolean|null} value Literal value.
* @return {ol.expr.Literal} The literal expression.
* @private
*/
ol.expr.Parser.prototype.createLiteral_ = function(value) {
return new ol.expr.Literal(value);
};
/**
* Create a member expression.
*
* // TODO: make exp {ol.expr.Member|ol.expr.Identifier}
* @param {ol.expr.Expression} object Expression.
* @param {ol.expr.Identifier} property Member name.
* @return {ol.expr.Member} The member expression.
* @private
*/
ol.expr.Parser.prototype.createMemberExpression_ = function(object,
property) {
return new ol.expr.Member(object, property);
};
/**
* Create a unary expression. The only true unary operator supported here is
* "!". For +/-, we apply the operator to literal expressions and return
* another literal.
*
* @param {ol.expr.Token} op Operator.
* @param {ol.expr.Expression} argument Expression.
* @return {ol.expr.Expression} The unary expression.
* @private
*/
ol.expr.Parser.prototype.createUnaryExpression_ = function(op, argument) {
goog.asserts.assert(op.value === '!' || op.value === '+' || op.value === '-');
var expr;
if (op.value === '!') {
expr = new ol.expr.Not(argument);
} else if (!(argument instanceof ol.expr.Literal)) {
throw new ol.expr.UnexpectedToken(op);
} else {
// we've got +/- literal
if (op.value === '+') {
expr = this.createLiteral_(
+ /** @type {number|string|boolean|null} */ (argument.evaluate()));
} else {
expr = this.createLiteral_(
- /** @type {number|string|boolean|null} */ (argument.evaluate()));
}
}
return expr;
};
/**
* Parse an expression.
*
* @param {string} source Expression source.
* @return {ol.expr.Expression} Expression.
*/
ol.expr.Parser.prototype.parse = function(source) {
var lexer = new ol.expr.Lexer(source);
var expr = this.parseExpression_(lexer);
var token = lexer.peek();
if (token.type !== ol.expr.TokenType.EOF) {
throw new ol.expr.UnexpectedToken(token);
}
return expr;
};
/**
* Parse call arguments
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {Array.<ol.expr.Expression>} Arguments.
* @private
*/
ol.expr.Parser.prototype.parseArguments_ = function(lexer) {
var args = [];
lexer.expect('(');
if (!lexer.match(')')) {
while (true) {
args.push(this.parseBinaryExpression_(lexer));
if (lexer.match(')')) {
break;
}
lexer.expect(',');
}
}
lexer.skip();
return args;
};
/**
* Parse a binary expression. Supported binary expressions:
*
* - Multiplicative Operators (`*`, `/`, `%`)
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.5
* - Additive Operators (`+`, `-`)
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.6
*
* - Relational Operators (`<`, `>`, `<=`, `>=`)
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.8
*
* - Equality Operators (`==`, `!=`, `===`, `!==`)
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.9
*
* - Binary Logical Operators (`&&`, `||`)
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.11
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parseBinaryExpression_ = function(lexer) {
var left = this.parseUnaryExpression_(lexer);
var operator = lexer.peek();
var precedence = this.binaryPrecedence_(operator);
if (precedence === 0) {
// not a supported binary operator
return left;
}
lexer.skip();
var right = this.parseUnaryExpression_(lexer);
var stack = [left, operator, right];
precedence = this.binaryPrecedence_(lexer.peek());
while (precedence > 0) {
// TODO: cache operator precedence in stack
while (stack.length > 2 &&
(precedence <= this.binaryPrecedence_(stack[stack.length - 2]))) {
right = stack.pop();
operator = stack.pop();
left = stack.pop();
stack.push(this.createBinaryExpression_(operator.value, left, right));
}
stack.push(lexer.next());
stack.push(this.parseUnaryExpression_(lexer));
precedence = this.binaryPrecedence_(lexer.peek());
}
var i = stack.length - 1;
var expr = stack[i];
while (i > 1) {
expr = this.createBinaryExpression_(stack[i - 1].value, stack[i - 2], expr);
i -= 2;
}
return expr;
};
/**
* Parse a group expression.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.6
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parseGroupExpression_ = function(lexer) {
lexer.expect('(');
var expr = this.parseExpression_(lexer);
lexer.expect(')');
return expr;
};
/**
* Parse left-hand-side expression. Limited to Member Expressions
* and Call Expressions.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parseLeftHandSideExpression_ = function(lexer) {
var expr = this.parsePrimaryExpression_(lexer);
var token = lexer.peek();
if (token.value === '(') {
// only allow calls on identifiers (e.g. `foo()` not `foo.bar()`)
if (!(expr instanceof ol.expr.Identifier)) {
// TODO: more helpful error messages for restricted syntax
throw new ol.expr.UnexpectedToken(token);
}
var args = this.parseArguments_(lexer);
expr = this.createCallExpression_(expr, args);
} else {
// TODO: throw if not Identifier
while (token.value === '.') {
var property = this.parseNonComputedMember_(lexer);
expr = this.createMemberExpression_(expr, property);
token = lexer.peek();
}
}
return expr;
};
/**
* Parse non-computed member.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Identifier} Expression.
* @private
*/
ol.expr.Parser.prototype.parseNonComputedMember_ = function(lexer) {
lexer.expect('.');
var token = lexer.next();
if (token.type !== ol.expr.TokenType.IDENTIFIER &&
token.type !== ol.expr.TokenType.KEYWORD &&
token.type !== ol.expr.TokenType.BOOLEAN_LITERAL &&
token.type !== ol.expr.TokenType.NULL_LITERAL) {
throw new ol.expr.UnexpectedToken(token);
}
return this.createIdentifier_(String(token.value));
};
/**
* Parse primary expression.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parsePrimaryExpression_ = function(lexer) {
var token = lexer.peek();
if (token.value === '(') {
return this.parseGroupExpression_(lexer);
}
lexer.skip();
var expr;
var type = token.type;
if (type === ol.expr.TokenType.IDENTIFIER) {
expr = this.createIdentifier_(/** @type {string} */ (token.value));
} else if (type === ol.expr.TokenType.STRING_LITERAL ||
type === ol.expr.TokenType.NUMERIC_LITERAL) {
// numeric and string literals are already the correct type
expr = this.createLiteral_(token.value);
} else if (type === ol.expr.TokenType.BOOLEAN_LITERAL) {
// because booleans are valid member properties, tokens are still string
expr = this.createLiteral_(token.value === 'true');
} else if (type === ol.expr.TokenType.NULL_LITERAL) {
expr = this.createLiteral_(null);
} else {
throw new ol.expr.UnexpectedToken(token);
}
return expr;
};
/**
* Parse expression with a unary operator. Limited to logical not operator.
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.4
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parseUnaryExpression_ = function(lexer) {
var expr;
var operator = lexer.peek();
if (operator.type !== ol.expr.TokenType.PUNCTUATOR) {
expr = this.parseLeftHandSideExpression_(lexer);
} else if (operator.value === '!' || operator.value === '-' ||
operator.value === '+') {
lexer.skip();
expr = this.parseUnaryExpression_(lexer);
expr = this.createUnaryExpression_(operator, expr);
} else {
expr = this.parseLeftHandSideExpression_(lexer);
}
return expr;
};
/**
* Parse an expression.
*
* @param {ol.expr.Lexer} lexer Lexer.
* @return {ol.expr.Expression} Expression.
* @private
*/
ol.expr.Parser.prototype.parseExpression_ = function(lexer) {
return this.parseBinaryExpression_(lexer);
};

View File

@@ -0,0 +1,6 @@
@exportSymbol ol.Feature
@exportProperty ol.Feature.prototype.getAttributes
@exportProperty ol.Feature.prototype.getId
@exportProperty ol.Feature.prototype.getGeometry
@exportProperty ol.Feature.prototype.set
@exportProperty ol.Feature.prototype.setGeometry

273
old/src/ol/feature.js Normal file
View File

@@ -0,0 +1,273 @@
goog.provide('ol.Feature');
goog.provide('ol.FeatureEvent');
goog.provide('ol.FeatureEventType');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.layer.VectorLayerRenderIntent');
/**
* Create a new feature. A feature is the base entity for vectors and has
* attributes, including normally a geometry attribute.
*
* Example:
*
* var feature = new ol.Feature({'foo': 'bar'});
* feature.setGeometry(new ol.geom.Point([100, 500]));
*
* @constructor
* @extends {ol.Object}
* @param {Object.<string, *>=} opt_values Attributes.
* @todo stability experimental
*/
ol.Feature = function(opt_values) {
goog.base(this, opt_values);
/**
* @type {string|undefined}
* @private
*/
this.featureId_;
/**
* @type {string|undefined}
* @private
*/
this.geometryName_;
/**
* Original of this feature when it was modified.
* @type {ol.Feature}
* @private
*/
this.original_ = null;
/**
* The render intent for this feature.
* @type {ol.layer.VectorLayerRenderIntent|string}
* @private
*/
this.renderIntent_ = ol.layer.VectorLayerRenderIntent.DEFAULT;
/**
* @type {Array.<ol.style.Symbolizer>}
* @private
*/
this.symbolizers_ = null;
};
goog.inherits(ol.Feature, ol.Object);
/**
* Gets a copy of the attributes of this feature.
* @param {boolean=} opt_nonGeometry Don't include any geometry attributes
* (by default geometry attributes are returned).
* @return {Object.<string, *>} Attributes object.
* @todo stability experimental
*/
ol.Feature.prototype.getAttributes = function(opt_nonGeometry) {
var keys = this.getKeys(),
includeGeometry = !opt_nonGeometry,
len = keys.length,
attributes = {},
i, value, key;
for (i = 0; i < len; ++ i) {
key = keys[i];
value = this.get(key);
if (includeGeometry || !(value instanceof ol.geom.Geometry)) {
attributes[key] = value;
}
}
return attributes;
};
/**
* Returns the feature's commonly used identifier. This identifier is usually
* the unique id in the source store.
*
* @return {string|undefined} The feature's identifier.
* @todo stability experimental
*/
ol.Feature.prototype.getId = function() {
return this.featureId_;
};
/**
* Get the geometry associated with this feature.
* @return {ol.geom.Geometry} The geometry (or null if none).
* @todo stability experimental
*/
ol.Feature.prototype.getGeometry = function() {
return goog.isDef(this.geometryName_) ?
/** @type {ol.geom.Geometry} */ (this.get(this.geometryName_)) :
null;
};
/**
* Get the original of this feature when it was modified.
* @return {ol.Feature} Original.
*/
ol.Feature.prototype.getOriginal = function() {
return this.original_;
};
/**
* Get any symbolizers set directly on the feature.
* @return {Array.<ol.style.Symbolizer>} Symbolizers (or null if none).
*/
ol.Feature.prototype.getSymbolizers = function() {
return this.symbolizers_;
};
/**
* Listener for geometry change events.
* @param {ol.geom.GeometryEvent} evt Geometry event.
* @private
*/
ol.Feature.prototype.handleGeometryChange_ = function(evt) {
this.dispatchEvent(new ol.FeatureEvent(
ol.FeatureEventType.CHANGE, this, evt.oldExtent));
};
/**
* @inheritDoc
* @param {string} key Key.
* @param {*} value Value.
* @todo stability experimental
*/
ol.Feature.prototype.set = function(key, value) {
var geometry = this.getGeometry();
var oldExtent = null;
if (goog.isDefAndNotNull(geometry)) {
oldExtent = geometry.getBounds();
if (key === this.geometryName_) {
goog.events.unlisten(geometry, goog.events.EventType.CHANGE,
this.handleGeometryChange_, false, this);
}
}
if (value instanceof ol.geom.Geometry) {
if (!goog.isDef(this.geometryName_)) {
this.geometryName_ = key;
}
if (key === this.geometryName_) {
goog.events.listen(value, goog.events.EventType.CHANGE,
this.handleGeometryChange_, false, this);
}
}
goog.base(this, 'set', key, value);
this.dispatchEvent(new ol.FeatureEvent(
ol.FeatureEventType.CHANGE, this, oldExtent));
};
/**
* Set the feature's commonly used identifier. This identifier is usually the
* unique id in the source store.
*
* @param {string|undefined} featureId The feature's identifier.
*/
ol.Feature.prototype.setId = function(featureId) {
this.featureId_ = featureId;
};
/**
* Set the geometry to be associated with this feature after its creation.
* @param {ol.geom.Geometry} geometry The geometry.
* @todo stability experimental
*/
ol.Feature.prototype.setGeometry = function(geometry) {
if (!goog.isDef(this.geometryName_)) {
this.geometryName_ = ol.Feature.DEFAULT_GEOMETRY;
}
this.set(this.geometryName_, geometry);
};
/**
* Set the original of this feature when it was modified.
* @param {ol.Feature} original Original.
*/
ol.Feature.prototype.setOriginal = function(original) {
this.original_ = original;
};
/**
* Gets the renderIntent for this feature.
* @return {string} Render intent.
*/
ol.Feature.prototype.getRenderIntent = function() {
return this.renderIntent_;
};
/**
* Changes the renderIntent for this feature.
* @param {string} renderIntent Render intent.
*/
ol.Feature.prototype.setRenderIntent = function(renderIntent) {
this.renderIntent_ = renderIntent;
var geometry = this.getGeometry();
if (!goog.isNull(geometry)) {
this.dispatchEvent(new ol.FeatureEvent(
ol.FeatureEventType.INTENTCHANGE, this, geometry.getBounds()));
}
};
/**
* Set the symbolizers to be used for this feature.
* @param {Array.<ol.style.Symbolizer>} symbolizers Symbolizers for this
* feature. If set, these take precedence over layer style.
*/
ol.Feature.prototype.setSymbolizers = function(symbolizers) {
this.symbolizers_ = symbolizers;
};
/**
* @const
* @type {string}
*/
ol.Feature.DEFAULT_GEOMETRY = 'geometry';
/**
* @enum {string}
*/
ol.FeatureEventType = {
CHANGE: 'featurechange',
INTENTCHANGE: 'featureintentchange'
};
/**
* Constructor for feature events.
* @constructor
* @extends {goog.events.Event}
* @param {string} type Event type.
* @param {ol.Feature} target The target feature.
* @param {ol.Extent} oldExtent The previous geometry extent.
*/
ol.FeatureEvent = function(type, target, oldExtent) {
goog.base(this, type, target);
this.oldExtent = oldExtent;
};
goog.inherits(ol.FeatureEvent, goog.events.Event);

29
old/src/ol/geom.exports Normal file
View File

@@ -0,0 +1,29 @@
@exportSymbol ol.geom.GeometryType
@exportProperty ol.geom.GeometryType.POINT
@exportProperty ol.geom.GeometryType.LINEARRING
@exportProperty ol.geom.GeometryType.LINESTRING
@exportProperty ol.geom.GeometryType.POLYGON
@exportProperty ol.geom.GeometryType.MULTIPOINT
@exportProperty ol.geom.GeometryType.MULTILINESTRING
@exportProperty ol.geom.GeometryType.MULTIPOLYGON
@exportProperty ol.geom.GeometryType.GEOMETRYCOLLECTION
@exportSymbol ol.geom.Geometry
@exportSymbol ol.geom.Point
@exportProperty ol.geom.Point.prototype.getCoordinates
@exportSymbol ol.geom.LineString
@exportProperty ol.geom.LineString.prototype.getCoordinates
@exportSymbol ol.geom.Polygon
@exportProperty ol.geom.Polygon.prototype.getCoordinates
@exportSymbol ol.geom.MultiPoint
@exportProperty ol.geom.MultiPoint.prototype.getCoordinates
@exportSymbol ol.geom.MultiLineString
@exportProperty ol.geom.MultiLineString.prototype.getCoordinates
@exportSymbol ol.geom.MultiPolygon
@exportProperty ol.geom.MultiPolygon.prototype.getCoordinates

3
old/src/ol/geom.jsdoc Normal file
View File

@@ -0,0 +1,3 @@
/**
* @namespace ol.geom
*/

View File

@@ -0,0 +1,107 @@
goog.provide('ol.geom.AbstractCollection');
goog.require('goog.events.EventType');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
/**
* A collection of geometries. This constructor is not to be used directly.
*
* @constructor
* @extends {ol.geom.Geometry}
*/
ol.geom.AbstractCollection = function() {
goog.base(this);
/**
* @type {Array.<ol.geom.Geometry>}
* @protected
*/
this.components = null;
/**
* @type {ol.Extent}
* @protected
*/
this.bounds = null;
};
goog.inherits(ol.geom.AbstractCollection, ol.geom.Geometry);
/**
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.getBounds = function() {
if (goog.isNull(this.bounds)) {
var bounds = ol.extent.createEmpty();
var components = this.components;
for (var i = 0, ii = components.length; i < ii; ++i) {
ol.extent.extend(bounds, components[i].getBounds());
}
this.bounds = bounds;
}
return this.bounds;
};
/**
* @return {Array.<ol.geom.Geometry>} Components.
*/
ol.geom.AbstractCollection.prototype.getComponents = function() {
return this.components;
};
/**
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.getCoordinates = function() {
var count = this.components.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = this.components[i].getCoordinates();
}
return coordinates;
};
/**
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.getType = goog.abstractMethod;
/**
* Listener for component change events.
* @param {ol.geom.GeometryEvent} evt Geometry event.
* @protected
*/
ol.geom.AbstractCollection.prototype.handleComponentChange = function(evt) {
this.bounds = null;
var oldExtent = ol.extent.createEmpty();
var components = this.components;
for (var i = components.length - 1; i >= 0; --i) {
var component = components[i];
ol.extent.extend(oldExtent,
component === evt.target && !goog.isNull(evt.oldExtent) ?
evt.oldExtent : component.getBounds());
}
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldExtent));
};
/**
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.transform = function(transform) {
var components = this.components;
for (var i = 0, ii = components.length; i < ii; ++i) {
components[i].transform(transform);
}
this.bounds = null;
};

View File

@@ -0,0 +1,92 @@
goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryEvent');
goog.provide('ol.geom.GeometryType');
goog.require('goog.events.Event');
goog.require('goog.events.EventTarget');
goog.require('goog.object');
goog.require('ol.Extent');
goog.require('ol.TransformFunction');
/**
* @constructor
* @extends {goog.events.EventTarget}
* @todo stability experimental
*/
ol.geom.Geometry = function() {
goog.base(this);
};
goog.inherits(ol.geom.Geometry, goog.events.EventTarget);
/**
* Create a clone of this geometry.
* @return {ol.geom.Geometry} The cloned geometry.
*/
ol.geom.Geometry.prototype.clone = function() {
return new this.constructor(goog.object.unsafeClone(this.getCoordinates()));
};
/**
* Get the rectangular 2D envelope for this geoemtry.
* @return {ol.Extent} The bounding rectangular envelope.
*/
ol.geom.Geometry.prototype.getBounds = goog.abstractMethod;
/**
* @return {Array} The GeoJSON style coordinates array for the geometry.
*/
ol.geom.Geometry.prototype.getCoordinates = goog.abstractMethod;
/**
* Get the geometry type.
* @return {ol.geom.GeometryType} The geometry type.
*/
ol.geom.Geometry.prototype.getType = goog.abstractMethod;
/**
* Transform a geometry in place.
* @param {ol.TransformFunction} transform Transform function.
*/
ol.geom.Geometry.prototype.transform = goog.abstractMethod;
/**
* Constructor for geometry events.
* @constructor
* @extends {goog.events.Event}
* @param {string} type Event type.
* @param {ol.geom.Geometry} target The target geometry.
* @param {ol.Extent} oldExtent The previous geometry extent.
*/
ol.geom.GeometryEvent = function(type, target, oldExtent) {
goog.base(this, type, target);
this.oldExtent = oldExtent;
};
goog.inherits(ol.geom.GeometryEvent, goog.events.Event);
/**
* Geometry types.
*
* @enum {string}
* @todo stability experimental
*/
ol.geom.GeometryType = {
POINT: 'point',
LINESTRING: 'linestring',
LINEARRING: 'linearring',
POLYGON: 'polygon',
MULTIPOINT: 'multipoint',
MULTILINESTRING: 'multilinestring',
MULTIPOLYGON: 'multipolygon',
GEOMETRYCOLLECTION: 'geometrycollection'
};

View File

@@ -0,0 +1,57 @@
goog.provide('ol.geom.GeometryCollection');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
/**
* A mixed collection of geometries. Used one of the fixed type multi-part
* constructors for collections of the same type.
*
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {Array.<ol.geom.Geometry>} geometries Array of geometries.
* @todo stability experimental
*/
ol.geom.GeometryCollection = function(geometries) {
goog.base(this);
for (var i = geometries.length - 1; i >= 0; --i) {
goog.events.listen(geometries[i], goog.events.EventType.CHANGE,
this.handleComponentChange, false, this);
}
/**
* @type {Array.<ol.geom.Geometry>}
* @protected
*/
this.components = geometries;
};
goog.inherits(ol.geom.GeometryCollection, ol.geom.AbstractCollection);
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.clone = function() {
var numComponents = this.components.length;
var components = new Array(numComponents);
for (var i = 0; i < numComponents; ++i) {
components[i] = this.components[i].clone();
}
return new ol.geom.GeometryCollection(components);
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.getType = function() {
return ol.geom.GeometryType.GEOMETRYCOLLECTION;
};

View File

@@ -0,0 +1,100 @@
goog.provide('ol.geom.LinearRing');
goog.require('ol.CoordinateArray');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
/**
* @constructor
* @extends {ol.geom.LineString}
* @param {ol.CoordinateArray} coordinates Vertex array (e.g.
* [[x0, y0], [x1, y1]]).
* @todo stability experimental
*/
ol.geom.LinearRing = function(coordinates) {
goog.base(this, coordinates);
/**
* We're intentionally not enforcing that rings be closed right now. This
* will allow proper rendering of data from tiled vector sources that leave
* open rings.
*/
};
goog.inherits(ol.geom.LinearRing, ol.geom.LineString);
/**
* Determine if a vertex array representing a linear ring is in clockwise
* order.
*
* This method comes from Green's Theorem and was mentioned in an answer to a
* a Stack Overflow question (http://tinyurl.com/clockwise-method).
*
* Note that calculating the cross product for each pair of edges could be
* avoided by first finding the lowest, rightmost vertex. See OGR's
* implementation for an example of this.
* https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
*
* @param {ol.CoordinateArray} coordinates Linear ring coordinates.
* @return {boolean} The coordinates are in clockwise order.
*/
ol.geom.LinearRing.isClockwise = function(coordinates) {
var length = coordinates.length;
var edge = 0;
var last = coordinates[length - 1];
var x1 = last[0];
var y1 = last[1];
var x2, y2, coord;
for (var i = 0; i < length; ++i) {
coord = coordinates[i];
x2 = coord[0];
y2 = coord[1];
edge += (x2 - x1) * (y2 + y1);
x1 = x2;
y1 = y2;
}
return edge > 0;
};
/**
* @inheritDoc
*/
ol.geom.LinearRing.prototype.getType = function() {
return ol.geom.GeometryType.LINEARRING;
};
/**
* Check whether a given coordinate is inside this ring. Note that this is a
* fast and simple check - points on an edge or vertex of the ring are either
* classified inside or outside.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Whether the coordinate is inside the ring.
*/
ol.geom.LinearRing.prototype.containsCoordinate = function(coordinate) {
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var x = coordinate[0], y = coordinate[1];
var vertices = this.getCoordinates();
var inside = false;
var xi, yi, xj, yj, intersect;
var numVertices = vertices.length;
for (var i = 0, j = numVertices - 1; i < numVertices; j = i++) {
xi = vertices[i][0];
yi = vertices[i][1];
xj = vertices[j][0];
yj = vertices[j][1];
intersect = ((yi > y) != (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) {
inside = !inside;
}
}
return inside;
};

View File

@@ -0,0 +1,138 @@
goog.provide('ol.geom.LineString');
goog.require('goog.asserts');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.coordinate');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
/**
* @constructor
* @extends {ol.geom.Geometry}
* @param {ol.CoordinateArray} coordinates Array of coordinates (e.g.
* [[x0, y0], [x1, y1]]).
* @todo stability experimental
*/
ol.geom.LineString = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0]));
/**
* Array of coordinates.
* @type {ol.CoordinateArray}
* @private
*/
this.coordinates_ = coordinates;
/**
* @type {ol.Extent}
* @private
*/
this.bounds_ = null;
};
goog.inherits(ol.geom.LineString, ol.geom.Geometry);
/**
* Get a vertex coordinate value for the given dimension.
* @param {number} index Vertex index.
* @param {number} dim Coordinate dimension.
* @return {number} The vertex coordinate value.
*/
ol.geom.LineString.prototype.get = function(index, dim) {
var coordinates = this.getCoordinates();
goog.asserts.assert(coordinates.length > index);
return coordinates[index][dim];
};
/**
* @inheritDoc
* @return {ol.CoordinateArray} Coordinates array.
*/
ol.geom.LineString.prototype.getCoordinates = function() {
return this.coordinates_;
};
/**
* Get the count of vertices in this linestring.
* @return {number} The vertex count.
*/
ol.geom.LineString.prototype.getCount = function() {
return this.getCoordinates().length;
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.getBounds = function() {
if (goog.isNull(this.bounds_)) {
var coordinates = this.getCoordinates();
var extent = ol.extent.createEmpty();
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
ol.extent.extendCoordinate(extent, coordinates[i]);
}
this.bounds_ = extent;
}
return this.bounds_;
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.getType = function() {
return ol.geom.GeometryType.LINESTRING;
};
/**
* Calculate the distance from a coordinate to this linestring.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {number} Distance from the coordinate to this linestring.
*/
ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) {
var coordinates = this.getCoordinates();
var dist2 = Infinity;
for (var i = 0, j = 1, len = coordinates.length; j < len; i = j++) {
dist2 = Math.min(dist2, ol.coordinate.squaredDistanceToSegment(coordinate,
[coordinates[i], coordinates[j]]));
}
return Math.sqrt(dist2);
};
/**
* Update the linestring coordinates.
* @param {ol.CoordinateArray} coordinates Coordinates array.
*/
ol.geom.LineString.prototype.setCoordinates = function(coordinates) {
var oldBounds = this.bounds_;
this.bounds_ = null;
this.coordinates_ = coordinates;
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldBounds));
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.transform = function(transform) {
var coordinates = this.getCoordinates();
var coord;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
coord = coordinates[i];
transform(coord, coord, coord.length);
}
this.setCoordinates(coordinates); // for change event
};

View File

@@ -0,0 +1,81 @@
goog.provide('ol.geom.MultiLineString');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {Array.<ol.CoordinateArray>} coordinates Coordinates array.
* @todo stability experimental
*/
ol.geom.MultiLineString = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0][0]));
var numParts = coordinates.length;
/**
* @type {Array.<ol.geom.LineString>}
* @protected
*/
this.components = new Array(numParts);
for (var i = 0; i < numParts; ++i) {
var component = new ol.geom.LineString(coordinates[i]);
this.components[i] = component;
goog.events.listen(component, goog.events.EventType.CHANGE,
this.handleComponentChange, false, this);
}
};
goog.inherits(ol.geom.MultiLineString, ol.geom.AbstractCollection);
/**
* @inheritDoc
*/
ol.geom.MultiLineString.prototype.getType = function() {
return ol.geom.GeometryType.MULTILINESTRING;
};
/**
* Calculate the distance from a coordinate to this multilinestring. This is
* the closest distance of the coordinate to one of this multilinestring's
* components.<
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {number} Distance from the coordinate to this multilinestring.
*/
ol.geom.MultiLineString.prototype.distanceFromCoordinate =
function(coordinate) {
var distance = Infinity;
for (var i = 0, ii = this.components.length; i < ii; ++i) {
distance = Math.min(distance,
this.components[i].distanceFromCoordinate(coordinate));
}
return distance;
};
/**
* Create a multi-linestring geometry from an array of linestring geometries.
*
* @param {Array.<ol.geom.LineString>} geometries Array of geometries.
* @return {ol.geom.MultiLineString} A new geometry.
*/
ol.geom.MultiLineString.fromParts = function(geometries) {
var count = geometries.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = geometries[i].getCoordinates();
}
return new ol.geom.MultiLineString(coordinates);
};

View File

@@ -0,0 +1,62 @@
goog.provide('ol.geom.MultiPoint');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Point');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {ol.CoordinateArray} coordinates Coordinates array.
* @todo stability experimental
*/
ol.geom.MultiPoint = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0]));
var numParts = coordinates.length;
/**
* @type {Array.<ol.geom.Point>}
* @protected
*/
this.components = new Array(numParts);
for (var i = 0; i < numParts; ++i) {
var component = new ol.geom.Point(coordinates[i]);
this.components[i] = component;
goog.events.listen(component, goog.events.EventType.CHANGE,
this.handleComponentChange, false, this);
}
};
goog.inherits(ol.geom.MultiPoint, ol.geom.AbstractCollection);
/**
* @inheritDoc
*/
ol.geom.MultiPoint.prototype.getType = function() {
return ol.geom.GeometryType.MULTIPOINT;
};
/**
* Create a multi-point geometry from an array of point geometries.
*
* @param {Array.<ol.geom.Point>} geometries Array of geometries.
* @return {ol.geom.MultiPoint} A new geometry.
*/
ol.geom.MultiPoint.fromParts = function(geometries) {
var count = geometries.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = geometries[i].getCoordinates();
}
return new ol.geom.MultiPoint(coordinates);
};

View File

@@ -0,0 +1,81 @@
goog.provide('ol.geom.MultiPolygon');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Polygon');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {Array.<Array.<ol.CoordinateArray>>} coordinates Coordinates
* array.
* @todo stability experimental
*/
ol.geom.MultiPolygon = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0][0][0]));
var numParts = coordinates.length;
/**
* @type {Array.<ol.geom.Polygon>}
* @protected
*/
this.components = new Array(numParts);
for (var i = 0; i < numParts; ++i) {
var component = new ol.geom.Polygon(coordinates[i]);
this.components[i] = component;
goog.events.listen(component, goog.events.EventType.CHANGE,
this.handleComponentChange, false, this);
}
};
goog.inherits(ol.geom.MultiPolygon, ol.geom.AbstractCollection);
/**
* @inheritDoc
*/
ol.geom.MultiPolygon.prototype.getType = function() {
return ol.geom.GeometryType.MULTIPOLYGON;
};
/**
* Check whether a given coordinate is inside this multipolygon.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Whether the coordinate is inside the multipolygon.
*/
ol.geom.MultiPolygon.prototype.containsCoordinate = function(coordinate) {
var containsCoordinate = false;
for (var i = 0, ii = this.components.length; i < ii; ++i) {
if (this.components[i].containsCoordinate(coordinate)) {
containsCoordinate = true;
break;
}
}
return containsCoordinate;
};
/**
* Create a multi-polygon geometry from an array of polygon geometries.
*
* @param {Array.<ol.geom.Polygon>} geometries Array of geometries.
* @return {ol.geom.MultiPolygon} A new geometry.
*/
ol.geom.MultiPolygon.fromParts = function(geometries) {
var count = geometries.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = geometries[i].getCoordinates();
}
return new ol.geom.MultiPolygon(coordinates);
};

97
old/src/ol/geom/point.js Normal file
View File

@@ -0,0 +1,97 @@
goog.provide('ol.geom.Point');
goog.require('goog.asserts');
goog.require('goog.events.EventType');
goog.require('ol.Coordinate');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
/**
* @constructor
* @extends {ol.geom.Geometry}
* @param {ol.Coordinate} coordinates Coordinate values (e.g. [x, y]).
* @todo stability experimental
*/
ol.geom.Point = function(coordinates) {
goog.base(this);
/**
* Point coordinate values.
* @type {ol.Coordinate}
* @private
*/
this.coordinates_ = coordinates;
/**
* @type {ol.Extent}
* @private
*/
this.bounds_ = null;
};
goog.inherits(ol.geom.Point, ol.geom.Geometry);
/**
* @param {number} dim Coordinate dimension.
* @return {number} The coordinate value.
*/
ol.geom.Point.prototype.get = function(dim) {
return this.getCoordinates()[dim];
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.getBounds = function() {
if (goog.isNull(this.bounds_)) {
var x = this.get(0),
y = this.get(1);
this.bounds_ = [x, y, x, y];
}
return this.bounds_;
};
/**
* @inheritDoc
* @return {ol.Coordinate} Coordinates array.
*/
ol.geom.Point.prototype.getCoordinates = function() {
return this.coordinates_;
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.getType = function() {
return ol.geom.GeometryType.POINT;
};
/**
* Update the point coordinates.
* @param {ol.Coordinate} coordinates Coordinates array.
*/
ol.geom.Point.prototype.setCoordinates = function(coordinates) {
var oldBounds = this.bounds_;
this.bounds_ = null;
this.coordinates_ = coordinates;
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldBounds));
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.transform = function(transform) {
var coordinates = this.getCoordinates();
transform(coordinates, coordinates, coordinates.length);
this.setCoordinates(coordinates); // for change event
};

207
old/src/ol/geom/polygon.js Normal file
View File

@@ -0,0 +1,207 @@
goog.provide('ol.geom.Polygon');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LinearRing');
/**
* Create a polygon from an array of vertex arrays. Coordinates for the
* exterior ring will be forced to clockwise order. Coordinates for any
* interior rings will be forced to counter-clockwise order. In cases where
* the opposite winding order occurs in the passed vertex arrays, they will
* be modified in place.
*
* @constructor
* @extends {ol.geom.Geometry}
* @param {Array.<ol.CoordinateArray>} coordinates Array of rings. First
* is outer, any remaining are inner.
* @todo stability experimental
*/
ol.geom.Polygon = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0][0]));
/**
* @private
* @type {ol.Coordinate}
*/
this.labelPoint_ = null;
var numRings = coordinates.length;
/**
* @type {Array.<ol.geom.LinearRing>}
* @private
*/
this.rings_ = new Array(numRings);
var ringCoords, ring;
for (var i = 0; i < numRings; ++i) {
ringCoords = coordinates[i];
if (i === 0) {
// force exterior ring to be clockwise
if (!ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
} else {
// force interior rings to be counter-clockwise
if (ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
}
ring = new ol.geom.LinearRing(ringCoords);
goog.events.listen(ring, goog.events.EventType.CHANGE,
this.handleRingChange_, false, this);
this.rings_[i] = ring;
}
};
goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getBounds = function() {
return this.rings_[0].getBounds();
};
/**
* @return {Array.<ol.CoordinateArray>} Coordinates array.
* @todo stability experimental
*/
ol.geom.Polygon.prototype.getCoordinates = function() {
var count = this.rings_.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = this.rings_[i].getCoordinates();
}
return coordinates;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getType = function() {
return ol.geom.GeometryType.POLYGON;
};
/**
* Get polygon rings.
* @return {Array.<ol.geom.LinearRing>} Array of rings. The first ring is the
* exterior and any additional rings are interior.
*/
ol.geom.Polygon.prototype.getRings = function() {
return this.rings_;
};
/**
* Listener for ring change events.
* @param {ol.geom.GeometryEvent} evt Geometry event.
* @private
*/
ol.geom.Polygon.prototype.handleRingChange_ = function(evt) {
var ring = evt.target;
var oldExtent = null;
if (ring === this.rings_[0]) {
oldExtent = evt.oldExtent;
} else {
oldExtent = this.getBounds();
}
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldExtent));
};
/**
* Check whether a given coordinate is inside this polygon. Note that this is a
* fast and simple check - points on an edge or vertex of the polygon or one of
* its inner rings are either classified inside or outside.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Whether the coordinate is inside the polygon.
*/
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
var rings = this.rings_;
/** @type {boolean} */
var containsCoordinate;
for (var i = 0, ii = rings.length; i < ii; ++i) {
containsCoordinate = rings[i].containsCoordinate(coordinate);
// if inner ring (i > 0) contains coordinate, polygon does not contain it
if (i > 0) {
containsCoordinate = !containsCoordinate;
}
if (!containsCoordinate) {
break;
}
}
return containsCoordinate;
};
/**
* Calculates a point that is guaranteed to lie in the interior of the polygon.
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
* @return {ol.Coordinate} A point which is in the interior of the polygon.
*/
ol.geom.Polygon.prototype.getInteriorPoint = function() {
if (goog.isNull(this.labelPoint_)) {
var center = ol.extent.getCenter(this.getBounds()),
resultY = center[1],
vertices = this.rings_[0].getCoordinates(),
intersections = [],
maxLength = 0,
i, vertex1, vertex2, x, segmentLength, resultX;
// Calculate intersections with the horizontal bounding box center line
for (i = vertices.length - 1; i >= 1; --i) {
vertex1 = vertices[i];
vertex2 = vertices[i - 1];
if ((vertex1[1] >= resultY && vertex2[1] <= resultY) ||
(vertex1[1] <= resultY && vertex2[1] >= resultY)) {
x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) *
(vertex2[0] - vertex1[0]) + vertex1[0];
intersections.push(x);
}
}
// Find the longest segment of the horizontal bounding box center line that
// has its center point inside the polygon
intersections.sort();
for (i = intersections.length - 1; i >= 1; --i) {
segmentLength = Math.abs(intersections[i] - intersections[i - 1]);
if (segmentLength > maxLength) {
x = (intersections[i] + intersections[i - 1]) / 2;
if (this.containsCoordinate([x, resultY])) {
maxLength = segmentLength;
resultX = x;
}
}
}
this.labelPoint_ = [resultX, resultY];
}
return this.labelPoint_;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.transform = function(transform) {
var rings = this.rings_;
for (var i = 0, ii = rings.length; i < ii; ++i) {
rings[i].transform(transform);
}
};

View File

@@ -0,0 +1 @@
@exportClass ol.interaction.Draw ol.interaction.DrawOptions

View File

@@ -0,0 +1,405 @@
goog.provide('ol.interaction.Draw');
goog.require('goog.asserts');
goog.require('ol.Coordinate');
goog.require('ol.Feature');
goog.require('ol.Map');
goog.require('ol.MapBrowserEvent');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.layer.VectorLayerRenderIntent');
goog.require('ol.source.Vector');
/**
* Interaction that allows drawing geometries.
* @param {ol.interaction.DrawOptions} options Options.
* @constructor
* @extends {ol.interaction.Interaction}
*/
ol.interaction.Draw = function(options) {
goog.base(this);
/**
* Target layer for drawn features.
* @type {ol.layer.Vector}
* @private
*/
this.layer_ = options.layer;
/**
* Temporary sketch layer.
* @type {ol.layer.Vector}
* @private
*/
this.sketchLayer_ = null;
/**
* Pixel distance for snapping.
* @type {number}
* @private
*/
this.snapTolerance_ = goog.isDef(options.snapTolerance) ?
options.snapTolerance : 12;
/**
* Geometry type.
* @type {ol.geom.GeometryType}
* @private
*/
this.type_ = options.type;
/**
* Drawing mode (derived from geometry type.
* @type {ol.interaction.DrawMode}
* @private
*/
this.mode_ = ol.interaction.Draw.getMode_(this.type_);
/**
* Finish coordinate for the feature (first point for polygons, last point for
* linestrings).
* @type {ol.Coordinate}
* @private
*/
this.finishCoordinate_ = null;
/**
* Sketch feature.
* @type {ol.Feature}
* @private
*/
this.sketchFeature_ = null;
/**
* Sketch point.
* @type {ol.Feature}
* @private
*/
this.sketchPoint_ = null;
/**
* Squared tolerance for handling click events. If the squared distance
* between a down and click event is greater than this tolerance, click events
* will not be handled.
* @type {number}
* @private
*/
this.squaredClickTolerance_ = 4;
};
goog.inherits(ol.interaction.Draw, ol.interaction.Interaction);
/**
* @inheritDoc
*/
ol.interaction.Draw.prototype.setMap = function(map) {
var oldMap = this.getMap();
if (!goog.isNull(oldMap)) {
oldMap.removeLayer(this.sketchLayer_);
}
if (!goog.isNull(map)) {
if (goog.isNull(this.sketchLayer_)) {
var layer = new ol.layer.Vector({
source: new ol.source.Vector({parser: null}),
style: this.layer_.getStyle()
});
layer.setTemporary(true);
this.sketchLayer_ = layer;
}
map.addLayer(this.sketchLayer_);
} else {
// removing from a map, clean up
this.abortDrawing_();
this.sketchLayer_ = null;
}
goog.base(this, 'setMap', map);
};
/**
* @inheritDoc
*/
ol.interaction.Draw.prototype.handleMapBrowserEvent = function(event) {
var map = event.map;
if (!map.isDef()) {
return true;
}
var pass = true;
if (event.type === ol.MapBrowserEvent.EventType.CLICK) {
pass = this.handleClick_(event);
} else if (event.type === ol.MapBrowserEvent.EventType.MOUSEMOVE) {
pass = this.handleMove_(event);
} else if (event.type === ol.MapBrowserEvent.EventType.DBLCLICK) {
pass = false;
}
return pass;
};
/**
* Handle click events.
* @param {ol.MapBrowserEvent} event A click event.
* @return {boolean} Pass the event to other interactions.
* @private
*/
ol.interaction.Draw.prototype.handleClick_ = function(event) {
var downPx = event.map.getEventPixel(event.target.getDown());
var clickPx = event.getPixel();
var dx = downPx[0] - clickPx[0];
var dy = downPx[1] - clickPx[1];
var squaredDistance = dx * dx + dy * dy;
var pass = true;
if (squaredDistance <= this.squaredClickTolerance_) {
if (goog.isNull(this.finishCoordinate_)) {
this.startDrawing_(event);
} else if (this.mode_ === ol.interaction.DrawMode.POINT ||
this.atFinish_(event)) {
this.finishDrawing_(event);
} else {
this.addToDrawing_(event);
}
pass = false;
}
return pass;
};
/**
* Handle mousemove events.
* @param {ol.MapBrowserEvent} event A mousemove event.
* @return {boolean} Pass the event to other interactions.
* @private
*/
ol.interaction.Draw.prototype.handleMove_ = function(event) {
if (this.mode_ === ol.interaction.DrawMode.POINT &&
goog.isNull(this.finishCoordinate_)) {
this.startDrawing_(event);
} else if (!goog.isNull(this.finishCoordinate_)) {
this.modifyDrawing_(event);
}
return true;
};
/**
* Determine if an event is within the snapping tolerance of the start coord.
* @param {ol.MapBrowserEvent} event Event.
* @return {boolean} The event is within the snapping tolerance of the start.
* @private
*/
ol.interaction.Draw.prototype.atFinish_ = function(event) {
var at = false;
if (this.sketchFeature_) {
var geometry = this.sketchFeature_.getGeometry();
var potentiallyDone = false;
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
potentiallyDone = geometry.getCoordinates().length > 2;
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
potentiallyDone = geometry.getRings()[0].getCoordinates().length > 3;
}
if (potentiallyDone) {
var map = event.map;
var finishPixel = map.getPixelFromCoordinate(this.finishCoordinate_);
var pixel = event.getPixel();
var dx = pixel[0] - finishPixel[0];
var dy = pixel[1] - finishPixel[1];
at = Math.sqrt(dx * dx + dy * dy) <= this.snapTolerance_;
}
}
return at;
};
/**
* Start the drawing.
* @param {ol.MapBrowserEvent} event Event.
* @private
*/
ol.interaction.Draw.prototype.startDrawing_ = function(event) {
var start = event.getCoordinate();
this.finishCoordinate_ = start;
var sketchFeature = new ol.Feature();
sketchFeature.setRenderIntent(ol.layer.VectorLayerRenderIntent.SELECTED);
var features = [sketchFeature];
var geometry;
if (this.mode_ === ol.interaction.DrawMode.POINT) {
geometry = new ol.geom.Point(start.slice());
} else {
var sketchPoint = new ol.Feature({
geom: new ol.geom.Point(start.slice())
});
sketchPoint.setRenderIntent(ol.layer.VectorLayerRenderIntent.TEMPORARY);
this.sketchPoint_ = sketchPoint;
features.push(sketchPoint);
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
geometry = new ol.geom.LineString([start.slice(), start.slice()]);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
geometry = new ol.geom.Polygon([[start.slice(), start.slice()]]);
}
}
goog.asserts.assert(goog.isDef(geometry));
sketchFeature.setGeometry(geometry);
this.sketchFeature_ = sketchFeature;
this.sketchLayer_.addFeatures(features);
};
/**
* Modify the drawing.
* @param {ol.MapBrowserEvent} event Event.
* @private
*/
ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
var coordinate = event.getCoordinate();
var geometry = this.sketchFeature_.getGeometry();
var coordinates, last;
if (this.mode_ === ol.interaction.DrawMode.POINT) {
last = geometry.getCoordinates();
last[0] = coordinate[0];
last[1] = coordinate[1];
geometry.setCoordinates(last);
} else {
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
coordinates = geometry.getCoordinates();
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
geometry = geometry.getRings()[0];
coordinates = geometry.getCoordinates();
}
if (this.atFinish_(event)) {
// snap to finish
coordinate = this.finishCoordinate_.slice();
}
this.sketchPoint_.getGeometry().setCoordinates(coordinate);
last = coordinates[coordinates.length - 1];
last[0] = coordinate[0];
last[1] = coordinate[1];
geometry.setCoordinates(coordinates);
}
};
/**
* Add a new coordinate to the drawing.
* @param {ol.MapBrowserEvent} event Event.
* @private
*/
ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
var coordinate = event.getCoordinate();
var geometry = this.sketchFeature_.getGeometry();
var coordinates, last;
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
this.finishCoordinate_ = coordinate.slice();
coordinates = geometry.getCoordinates();
coordinates.push(coordinate.slice());
geometry.setCoordinates(coordinates);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
var ring = geometry.getRings()[0];
coordinates = ring.getCoordinates();
coordinates.push(coordinate.slice());
ring.setCoordinates(coordinates);
}
};
/**
* Stop drawing and add the sketch feature to the target layer.
* @param {ol.MapBrowserEvent} event Event.
* @private
*/
ol.interaction.Draw.prototype.finishDrawing_ = function(event) {
var sketchFeature = this.abortDrawing_();
goog.asserts.assert(!goog.isNull(sketchFeature));
sketchFeature.setRenderIntent(ol.layer.VectorLayerRenderIntent.DEFAULT);
var geometry = sketchFeature.getGeometry();
var coordinates = geometry.getCoordinates();
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
// remove the redundant last point
coordinates.pop();
geometry.setCoordinates(coordinates);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
// force clockwise order for exterior ring
sketchFeature.setGeometry(new ol.geom.Polygon(coordinates));
}
// cast multi-part geometries
if (this.type_ === ol.geom.GeometryType.MULTIPOINT) {
sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates]));
} else if (this.type_ === ol.geom.GeometryType.MULTILINESTRING) {
sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates]));
} else if (this.type_ === ol.geom.GeometryType.MULTIPOLYGON) {
sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));
}
this.layer_.addFeatures([sketchFeature]);
};
/**
* Stop drawing without adding the sketch feature to the target layer.
* @return {ol.Feature} The sketch feature (or null if none).
* @private
*/
ol.interaction.Draw.prototype.abortDrawing_ = function() {
this.finishCoordinate_ = null;
var sketchFeature = this.sketchFeature_;
if (!goog.isNull(sketchFeature)) {
var features = [sketchFeature];
this.sketchFeature_ = null;
if (this.mode_ !== ol.interaction.DrawMode.POINT) {
features.push(this.sketchPoint_);
this.sketchPoint_ = null;
}
this.sketchLayer_.removeFeatures(features);
}
return sketchFeature;
};
/**
* Get the drawing mode. The mode for mult-part geometries is the same as for
* their single-part cousins.
* @param {ol.geom.GeometryType} type Geometry type.
* @return {ol.interaction.DrawMode} Drawing mode.
* @private
*/
ol.interaction.Draw.getMode_ = function(type) {
var mode;
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
mode = ol.interaction.DrawMode.POINT;
} else if (type === ol.geom.GeometryType.LINESTRING ||
type === ol.geom.GeometryType.MULTILINESTRING) {
mode = ol.interaction.DrawMode.LINESTRING;
} else if (type === ol.geom.GeometryType.POLYGON ||
type === ol.geom.GeometryType.MULTIPOLYGON) {
mode = ol.interaction.DrawMode.POLYGON;
}
goog.asserts.assert(goog.isDef(mode));
return mode;
};
/**
* Draw mode. This collapses multi-part geometry types with their single-part
* cousins.
* @enum {string}
*/
ol.interaction.DrawMode = {
POINT: 'point',
LINESTRING: 'linestring',
POLYGON: 'polygon'
};

View File

@@ -0,0 +1 @@
@exportClass ol.interaction.Modify ol.interaction.ModifyOptions

View File

@@ -0,0 +1,525 @@
goog.provide('ol.interaction.Modify');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.ViewHint');
goog.require('ol.coordinate');
goog.require('ol.extent');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.LineString');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Drag');
goog.require('ol.layer.Layer');
goog.require('ol.layer.Vector');
goog.require('ol.layer.VectorEventType');
goog.require('ol.layer.VectorLayerRenderIntent');
goog.require('ol.source.Vector');
goog.require('ol.structs.RTree');
/**
* @typedef {{feature: ol.Feature,
* geometry: ol.geom.Geometry,
* index: (number|undefined),
* style: ol.style.Style,
* segment: (Array.<ol.Extent>|undefined)}}
*/
ol.interaction.SegmentDataType;
/**
* @constructor
* @extends {ol.interaction.Drag}
* @param {ol.interaction.ModifyOptions=} opt_options Options.
*/
ol.interaction.Modify = function(opt_options) {
goog.base(this);
var options = goog.isDef(opt_options) ? opt_options : {};
var layerFilter = options.layers;
if (!goog.isDef(layerFilter)) {
layerFilter = goog.functions.TRUE;
} else if (goog.isArray(layerFilter)) {
layerFilter = function(layer) {return options.layers.indexOf(layer) > -1;};
}
goog.asserts.assertFunction(layerFilter);
/**
* @type {function(ol.layer.Layer):boolean}
* @private
*/
this.layerFilter_ = layerFilter;
/**
* Temporary sketch layer.
* @type {ol.layer.Vector}
* @private
*/
this.sketchLayer_ = null;
/**
* Editing vertex.
* @type {ol.Feature}
* @private
*/
this.vertexFeature_ = null;
/**
* @type {boolean}
* @private
*/
this.modifiable_ = false;
/**
* Segment RTree for each layer
* @type {Object.<*, ol.structs.RTree>}
* @private
*/
this.rTree_ = null;
/**
* @type {number}
* @private
*/
this.pixelTolerance_ = goog.isDef(options.pixelTolerance) ?
options.pixelTolerance : 20;
/**
* @type {Array}
* @private
*/
this.dragSegments_ = null;
};
goog.inherits(ol.interaction.Modify, ol.interaction.Drag);
/**
* @inheritDoc
*/
ol.interaction.Modify.prototype.setMap = function(map) {
var oldMap = this.getMap();
var layers;
if (!goog.isNull(oldMap)) {
oldMap.removeLayer(this.sketchLayer_);
layers = oldMap.getLayerGroup().getLayers();
goog.asserts.assert(goog.isDef(layers));
layers.forEach(goog.bind(this.removeLayer_, this));
layers.unlisten(ol.CollectionEventType.ADD, this.handleLayerAdded_, false,
this);
layers.unlisten(ol.CollectionEventType.REMOVE, this.handleLayerRemoved_,
false, this);
}
if (!goog.isNull(map)) {
if (goog.isNull(this.rTree_)) {
this.rTree_ = new ol.structs.RTree();
}
if (goog.isNull(this.sketchLayer_)) {
var sketchLayer = new ol.layer.Vector({
source: new ol.source.Vector({parser: null})
});
this.sketchLayer_ = sketchLayer;
sketchLayer.setTemporary(true);
map.addLayer(sketchLayer);
}
layers = map.getLayerGroup().getLayers();
goog.asserts.assert(goog.isDef(layers));
layers.forEach(goog.bind(this.addLayer_, this));
layers.listen(ol.CollectionEventType.ADD, this.handleLayerAdded_, false,
this);
layers.listen(ol.CollectionEventType.REMOVE, this.handleLayerRemoved_,
false, this);
} else {
// removing from a map, clean up
this.rTree_ = null;
this.sketchLayer_ = null;
}
goog.base(this, 'setMap', map);
};
/**
* @param {ol.CollectionEvent} evt Event.
* @private
*/
ol.interaction.Modify.prototype.handleLayerAdded_ = function(evt) {
var layer = evt.getElement();
goog.asserts.assertInstanceof(layer, ol.layer.Layer);
this.addLayer_(layer);
};
/**
* Add a layer for modification.
* @param {ol.layer.Layer} layer Layer.
* @private
*/
ol.interaction.Modify.prototype.addLayer_ = function(layer) {
if (this.layerFilter_(layer) && layer instanceof ol.layer.Vector &&
!layer.getTemporary()) {
this.addIndex_(layer.getFeatures(ol.layer.Vector.selectedFeaturesFilter),
layer);
goog.events.listen(layer, ol.layer.VectorEventType.INTENTCHANGE,
this.handleIntentChange_, false, this);
}
};
/**
* @param {ol.CollectionEvent} evt Event.
* @private
*/
ol.interaction.Modify.prototype.handleLayerRemoved_ = function(evt) {
var layer = evt.getElement();
goog.asserts.assertInstanceof(layer, ol.layer.Layer);
this.removeLayer_(layer);
};
/**
* Remove a layer for modification.
* @param {ol.layer.Layer} layer Layer.
* @private
*/
ol.interaction.Modify.prototype.removeLayer_ = function(layer) {
if (this.layerFilter_(layer) && layer instanceof ol.layer.Vector &&
!layer.getTemporary()) {
this.removeIndex_(
layer.getFeatures(ol.layer.Vector.selectedFeaturesFilter));
goog.events.unlisten(layer, ol.layer.VectorEventType.INTENTCHANGE,
this.handleIntentChange_, false, this);
}
};
/**
* @param {Array.<ol.Feature>} features Array of features.
* @param {ol.layer.Vector} layer Layer the features belong to.
* @private
*/
ol.interaction.Modify.prototype.addIndex_ = function(features, layer) {
for (var i = 0, ii = features.length; i < ii; ++i) {
var feature = features[i];
var geometry = feature.getGeometry();
if (geometry instanceof ol.geom.AbstractCollection) {
var components = geometry.getComponents();
for (var j = 0, jj = components.length; j < jj; ++j) {
this.addSegments_(feature, components[j], layer);
}
} else {
this.addSegments_(feature, geometry, layer);
}
}
};
/**
* @param {Array.<ol.Feature>} features Array of features.
* @private
*/
ol.interaction.Modify.prototype.removeIndex_ = function(features) {
var rTree = this.rTree_;
for (var i = 0, ii = features.length; i < ii; ++i) {
var feature = features[i];
var segmentDataMatches = rTree.search(feature.getGeometry().getBounds(),
goog.getUid(feature));
for (var j = segmentDataMatches.length - 1; j >= 0; --j) {
var segmentDataMatch = segmentDataMatches[j];
rTree.remove(ol.extent.boundingExtent(segmentDataMatch.segment),
segmentDataMatch);
}
}
};
/**
* Listen for feature additions.
* @param {ol.layer.VectorEvent} evt Event object.
* @private
*/
ol.interaction.Modify.prototype.handleIntentChange_ = function(evt) {
var layer = evt.target;
goog.asserts.assertInstanceof(layer, ol.layer.Vector);
var features = evt.features;
for (var i = 0, ii = features.length; i < ii; ++i) {
var feature = features[i];
var renderIntent = feature.getRenderIntent();
if (renderIntent == ol.layer.VectorLayerRenderIntent.SELECTED) {
this.addIndex_([feature], layer);
} else {
this.removeIndex_([feature]);
}
}
};
/**
* @param {ol.Feature} feature Feature to add segments for.
* @param {ol.geom.Geometry} geometry Geometry to add segments for.
* @param {ol.layer.Vector} layer Vector layer to add segments for.
* @private
*/
ol.interaction.Modify.prototype.addSegments_ =
function(feature, geometry, layer) {
var uid = goog.getUid(feature);
var rTree = this.rTree_;
var segment, segmentData, coordinates;
if (geometry instanceof ol.geom.Point) {
segmentData = /** @type {ol.interaction.SegmentDataType} */ ({
feature: feature,
geometry: geometry,
style: layer.getStyle()
});
rTree.insert(geometry.getBounds(), segmentData, uid);
} else if (geometry instanceof ol.geom.LineString ||
geometry instanceof ol.geom.LinearRing) {
coordinates = geometry.getCoordinates();
for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
segment = coordinates.slice(i, i + 2);
segmentData = /** @type {ol.interaction.SegmentDataType} */ ({
feature: feature,
geometry: geometry,
index: i,
style: layer.getStyle(),
segment: segment
});
rTree.insert(ol.extent.boundingExtent(segment), segmentData, uid);
}
} else if (geometry instanceof ol.geom.Polygon) {
var rings = geometry.getRings();
for (var j = 0, jj = rings.length; j < jj; ++j) {
this.addSegments_(feature, rings[j], layer);
}
}
};
/**
* @param {ol.style.Style} style Style of the layer that the feature being
* modified belongs to.
* @param {ol.Coordinate} coordinates Coordinates.
* @return {ol.Feature} Vertex feature.
* @private
*/
ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ =
function(style, coordinates) {
var vertexFeature = this.vertexFeature_;
if (goog.isNull(vertexFeature)) {
vertexFeature = new ol.Feature({g: new ol.geom.Point(coordinates)});
this.vertexFeature_ = vertexFeature;
this.sketchLayer_.addFeatures([vertexFeature]);
} else {
var geometry = vertexFeature.getGeometry();
geometry.setCoordinates(coordinates);
}
if (this.sketchLayer_.getStyle() !== style) {
this.sketchLayer_.setStyle(style);
}
return vertexFeature;
};
/**
* @inheritDoc
*/
ol.interaction.Modify.prototype.handleDragStart = function(evt) {
this.dragSegments_ = [];
var vertexFeature = this.vertexFeature_;
if (!goog.isNull(vertexFeature) && vertexFeature.getRenderIntent() !=
ol.layer.VectorLayerRenderIntent.HIDDEN) {
var renderIntent = vertexFeature.getRenderIntent();
var insertVertices = [];
var vertex = vertexFeature.getGeometry().getCoordinates();
var vertexExtent = ol.extent.boundingExtent([vertex]);
var segmentDataMatches = this.rTree_.search(vertexExtent);
var distinctFeatures = {};
for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
var segmentDataMatch = segmentDataMatches[i];
var segment = segmentDataMatch.segment;
if (!(goog.getUid(segmentDataMatch.feature) in distinctFeatures)) {
var feature = segmentDataMatch.feature;
distinctFeatures[goog.getUid(feature)] = true;
var original = new ol.Feature(feature.getAttributes());
original.setGeometry(feature.getGeometry().clone());
original.setId(feature.getId());
original.setOriginal(feature.getOriginal());
original.setSymbolizers(feature.getSymbolizers());
feature.setOriginal(original);
}
if (renderIntent == ol.layer.VectorLayerRenderIntent.TEMPORARY) {
if (ol.coordinate.equals(segment[0], vertex)) {
this.dragSegments_.push([segmentDataMatch, 0]);
} else if (ol.coordinate.equals(segment[1], vertex)) {
this.dragSegments_.push([segmentDataMatch, 1]);
}
} else if (
ol.coordinate.squaredDistanceToSegment(vertex, segment) === 0) {
insertVertices.push([segmentDataMatch, vertex]);
}
}
for (i = insertVertices.length - 1; i >= 0; --i) {
this.insertVertex_.apply(this, insertVertices[i]);
}
}
return this.modifiable_;
};
/**
* @inheritDoc
*/
ol.interaction.Modify.prototype.handleDrag = function(evt) {
var vertex = evt.getCoordinate();
for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
var dragSegment = this.dragSegments_[i];
var segmentData = dragSegment[0];
var feature = segmentData.feature;
var geometry = segmentData.geometry;
var coordinates = geometry.getCoordinates();
var oldBounds, newBounds;
if (geometry instanceof ol.geom.Point) {
oldBounds = geometry.getBounds();
geometry.setCoordinates(vertex);
newBounds = geometry.getBounds();
} else {
var index = dragSegment[1];
coordinates[segmentData.index + index] = vertex;
geometry.setCoordinates(coordinates);
var segment = segmentData.segment;
oldBounds = ol.extent.boundingExtent(segment);
segment[index] = vertex;
newBounds = ol.extent.boundingExtent(segment);
}
this.createOrUpdateVertexFeature_(segmentData.style, vertex);
this.rTree_.remove(oldBounds, segmentData);
this.rTree_.insert(newBounds, segmentData, goog.getUid(feature));
}
};
/**
* @inheritDoc
*/
ol.interaction.Modify.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] &&
!this.getDragging() &&
mapBrowserEvent.type == ol.MapBrowserEvent.EventType.MOUSEMOVE) {
this.handleMouseMove_(mapBrowserEvent);
}
goog.base(this, 'handleMapBrowserEvent', mapBrowserEvent);
return !this.modifiable_;
};
/**
* @param {ol.MapBrowserEvent} evt Event.
* @private
*/
ol.interaction.Modify.prototype.handleMouseMove_ = function(evt) {
var map = evt.map;
var pixel = evt.getPixel();
var pixelCoordinate = map.getCoordinateFromPixel(pixel);
var sortByDistance = function(a, b) {
return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) -
ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment);
};
var lowerLeft = map.getCoordinateFromPixel(
[pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
var upperRight = map.getCoordinateFromPixel(
[pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
this.modifiable_ = false;
var vertexFeature = this.vertexFeature_;
var rTree = this.rTree_;
var segmentDataMatches = rTree.search(box);
var renderIntent = ol.layer.VectorLayerRenderIntent.HIDDEN;
if (segmentDataMatches.length > 0) {
segmentDataMatches.sort(sortByDistance);
var segmentDataMatch = segmentDataMatches[0];
var segment = segmentDataMatch.segment; // the closest segment
var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, segment));
var vertexPixel = map.getPixelFromCoordinate(vertex);
if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=
this.pixelTolerance_) {
var pixel1 = map.getPixelFromCoordinate(segment[0]);
var pixel2 = map.getPixelFromCoordinate(segment[1]);
var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
renderIntent = ol.layer.VectorLayerRenderIntent.FUTURE;
if (dist <= 10) {
vertex = squaredDist1 > squaredDist2 ? segment[1] : segment[0];
renderIntent = ol.layer.VectorLayerRenderIntent.TEMPORARY;
}
vertexFeature = this.createOrUpdateVertexFeature_(segmentDataMatch.style,
vertex);
this.modifiable_ = true;
}
}
if (!goog.isNull(vertexFeature) &&
renderIntent != vertexFeature.getRenderIntent()) {
vertexFeature.setRenderIntent(renderIntent);
}
};
/**
* @param {ol.interaction.SegmentDataType} segmentData Segment data.
* @param {ol.Coordinate} vertex Vertex.
* @private
*/
ol.interaction.Modify.prototype.insertVertex_ =
function(segmentData, vertex) {
var segment = segmentData.segment;
var feature = segmentData.feature;
var geometry = segmentData.geometry;
var index = segmentData.index;
var coordinates = geometry.getCoordinates();
coordinates.splice(index + 1, 0, vertex);
geometry.setCoordinates(coordinates);
var rTree = this.rTree_;
goog.asserts.assert(goog.isDef(segment));
rTree.remove(ol.extent.boundingExtent(segment), segmentData);
var uid = goog.getUid(feature);
var segmentDataMatches = this.rTree_.search(geometry.getBounds(), uid);
for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
var segmentDataMatch = segmentDataMatches[i];
if (segmentDataMatch.geometry === geometry &&
segmentDataMatch.index > index) {
++segmentDataMatch.index;
}
}
var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({
style: segmentData.style,
segment: [segment[0], vertex],
feature: feature,
geometry: geometry,
index: index
});
rTree.insert(ol.extent.boundingExtent(newSegmentData.segment), newSegmentData,
uid);
this.dragSegments_.push([newSegmentData, 1]);
newSegmentData = goog.object.clone(newSegmentData);
newSegmentData.segment = [vertex, segment[1]];
newSegmentData.index += 1;
rTree.insert(ol.extent.boundingExtent(newSegmentData.segment), newSegmentData,
uid);
this.dragSegments_.push([newSegmentData, 0]);
};

View File

@@ -0,0 +1 @@
@exportClass ol.interaction.Select ol.interaction.SelectOptions

View File

@@ -0,0 +1,118 @@
goog.provide('ol.interaction.Select');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.events.ConditionType');
goog.require('ol.events.condition');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.layer.VectorLayerRenderIntent');
/**
* Allows the user to select features on the map.
* @constructor
* @extends {ol.interaction.Interaction}
* @param {ol.interaction.SelectOptions=} opt_options Options.
* @todo stability experimental
*/
ol.interaction.Select = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {ol.events.ConditionType}
*/
this.condition_ = goog.isDef(options.condition) ?
options.condition : ol.events.condition.singleClick;
/**
* @private
* @type {ol.events.ConditionType}
*/
this.addCondition_ = goog.isDef(options.addCondition) ?
options.addCondition : ol.events.condition.shiftKeyOnly;
var layerFilter = options.layers;
if (!goog.isDef(layerFilter)) {
layerFilter = goog.functions.TRUE;
} else if (goog.isArray(layerFilter)) {
layerFilter = function(layer) {return options.layers.indexOf(layer) > -1;};
}
goog.asserts.assertFunction(layerFilter);
/**
* @type {function(ol.layer.Layer):boolean}
* @private
*/
this.layerFilter_ = layerFilter;
goog.base(this);
};
goog.inherits(ol.interaction.Select, ol.interaction.Interaction);
/**
* @inheritDoc.
*/
ol.interaction.Select.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
if (this.condition_(mapBrowserEvent)) {
var map = mapBrowserEvent.map;
var layers = goog.array.filter(
map.getLayerGroup().getLayersArray(), this.layerFilter_);
var clear = !this.addCondition_(mapBrowserEvent);
var that = this;
var select = function(featuresByLayer) {
that.select(map, featuresByLayer, layers, clear);
};
map.getFeatures({
layers: layers,
pixel: mapBrowserEvent.getPixel(),
success: select
});
}
// TODO: Implement box selection
return true;
};
/**
* @param {ol.Map} map The map where the selction event originated.
* @param {Array.<Array.<ol.Feature>>} featuresByLayer Features by layer.
* @param {Array.<ol.layer.Layer>} layers The queried layers.
* @param {boolean} clear Whether the current layer content should be cleared.
*/
ol.interaction.Select.prototype.select =
function(map, featuresByLayer, layers, clear) {
for (var i = 0, ii = featuresByLayer.length; i < ii; ++i) {
var layer = layers[i];
if (!(layer instanceof ol.layer.Vector)) {
// TODO Support non-vector layers and remove this
continue;
}
var featuresToSelect = featuresByLayer[i];
var selectedFeatures = layer.getFeatures(
ol.layer.Vector.selectedFeaturesFilter);
if (clear) {
for (var j = selectedFeatures.length - 1; j >= 0; --j) {
selectedFeatures[j].setRenderIntent(
ol.layer.VectorLayerRenderIntent.DEFAULT);
}
}
for (var j = featuresToSelect.length - 1; j >= 0; --j) {
var feature = featuresToSelect[j];
// TODO: Make toggle configurable
feature.setRenderIntent(feature.getRenderIntent() ==
ol.layer.VectorLayerRenderIntent.SELECTED ?
ol.layer.VectorLayerRenderIntent.DEFAULT :
ol.layer.VectorLayerRenderIntent.SELECTED);
}
// TODO: Dispatch an event with selectedFeatures and unselectedFeatures
}
};

View File

@@ -0,0 +1 @@
@exportClass ol.layer.Vector ol.layer.VectorLayerOptions

View File

@@ -0,0 +1,539 @@
goog.provide('ol.layer.Vector');
goog.provide('ol.layer.VectorEventType');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.FeatureEventType');
goog.require('ol.extent');
goog.require('ol.layer.Layer');
goog.require('ol.layer.VectorLayerRenderIntent');
goog.require('ol.proj');
goog.require('ol.source.Vector');
goog.require('ol.structs.RTree');
goog.require('ol.style');
goog.require('ol.style.Style');
goog.require('ol.style.TextLiteral');
/**
* @constructor
*/
ol.layer.FeatureCache = function() {
/**
* @type {Object.<string, ol.Feature>}
* @private
*/
this.idLookup_;
/**
* @type {ol.structs.RTree}
* @private
*/
this.rTree_;
this.clear();
};
/**
* Clear the cache.
*/
ol.layer.FeatureCache.prototype.clear = function() {
this.idLookup_ = {};
this.rTree_ = new ol.structs.RTree();
};
/**
* Add a feature to the cache.
* @param {ol.Feature} feature Feature to be cached.
*/
ol.layer.FeatureCache.prototype.add = function(feature) {
var id = goog.getUid(feature).toString(),
geometry = feature.getGeometry();
this.idLookup_[id] = feature;
// index by bounding box
if (!goog.isNull(geometry)) {
this.rTree_.insert(geometry.getBounds(), feature);
}
};
/**
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
*/
ol.layer.FeatureCache.prototype.getFeaturesObject = function() {
return this.idLookup_;
};
/**
* Get all features whose bounding box intersects the provided extent.
*
* @param {ol.Extent} extent Bounding extent.
* @return {Object.<string, ol.Feature>} Features.
*/
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent) {
return this.rTree_.searchReturningObject(extent);
};
/**
* Get features by ids.
* @param {Array.<string>} ids Array of (internal) identifiers.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.layer.FeatureCache.prototype.getFeaturesByIds_ = function(ids) {
var len = ids.length,
features = new Array(len),
i;
for (i = 0; i < len; ++i) {
features[i] = this.idLookup_[ids[i]];
}
return features;
};
/**
* Remove a feature from the cache.
* @param {ol.Feature} feature Feature.
* @param {ol.Extent=} opt_extent Optional extent (used when the current feature
* extent is different than the one in the index).
*/
ol.layer.FeatureCache.prototype.remove = function(feature, opt_extent) {
var id = goog.getUid(feature).toString(),
geometry = feature.getGeometry();
delete this.idLookup_[id];
// index by bounding box
if (!goog.isNull(geometry)) {
var extent = goog.isDef(opt_extent) ? opt_extent : geometry.getBounds();
this.rTree_.remove(extent, feature);
}
};
/**
* @constructor
* @extends {ol.layer.Layer}
* @param {ol.layer.VectorLayerOptions} options Vector layer options.
* @todo stability experimental
*/
ol.layer.Vector = function(options) {
goog.base(this, /** @type {ol.layer.LayerOptions} */ (options));
/**
* @private
* @type {ol.style.Style}
*/
this.style_ = goog.isDef(options.style) ? options.style : null;
/**
* @type {ol.layer.FeatureCache}
* @private
*/
this.featureCache_ = new ol.layer.FeatureCache();
/**
* @type {function(Array.<ol.Feature>):string}
* @private
*/
this.transformFeatureInfo_ = goog.isDef(options.transformFeatureInfo) ?
options.transformFeatureInfo : ol.layer.Vector.uidTransformFeatureInfo;
/**
* True if this is a temporary layer.
* @type {boolean}
* @private
*/
this.temporary_ = false;
};
goog.inherits(ol.layer.Vector, ol.layer.Layer);
/**
* @param {Array.<ol.Feature>} features Array of features.
*/
ol.layer.Vector.prototype.addFeatures = function(features) {
var extent = ol.extent.createEmpty(),
feature, geometry;
for (var i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
this.featureCache_.add(feature);
geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
ol.extent.extend(extent, geometry.getBounds());
}
goog.events.listen(feature, ol.FeatureEventType.CHANGE,
this.handleFeatureChange_, false, this);
goog.events.listen(feature, ol.FeatureEventType.INTENTCHANGE,
this.handleIntentChange_, false, this);
}
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.ADD,
features, [extent]));
};
/**
* Listener for feature change events.
* @param {ol.FeatureEvent} evt The feature change event.
* @private
*/
ol.layer.Vector.prototype.handleFeatureChange_ = function(evt) {
goog.asserts.assertInstanceof(evt.target, ol.Feature);
var feature = /** @type {ol.Feature} */ (evt.target);
var extents = [];
if (!goog.isNull(evt.oldExtent)) {
extents.push(evt.oldExtent);
}
var geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
this.featureCache_.remove(feature, evt.oldExtent);
this.featureCache_.add(feature);
extents.push(geometry.getBounds());
}
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE,
[feature], extents));
};
/**
* Listener for render intent change events of features.
* @param {ol.FeatureEvent} evt The feature intent change event.
* @private
*/
ol.layer.Vector.prototype.handleIntentChange_ = function(evt) {
goog.asserts.assertInstanceof(evt.target, ol.Feature);
var feature = /** @type {ol.Feature} */ (evt.target);
var geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
this.dispatchEvent(new ol.layer.VectorEvent(
ol.layer.VectorEventType.INTENTCHANGE, [feature],
[geometry.getBounds()]));
}
};
/**
* Remove all features from the layer.
*/
ol.layer.Vector.prototype.clear = function() {
this.featureCache_.clear();
this.dispatchEvent(
new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE, [], []));
};
/**
* @return {boolean} Whether this layer is temporary.
*/
ol.layer.Vector.prototype.getTemporary = function() {
return this.temporary_;
};
/**
* @return {ol.source.Vector} Source.
*/
ol.layer.Vector.prototype.getVectorSource = function() {
return /** @type {ol.source.Vector} */ (this.getSource());
};
/**
* @return {ol.style.Style} This layer's style.
*/
ol.layer.Vector.prototype.getStyle = function() {
return this.style_;
};
/**
* Set a style for this layer.
* @param {ol.style.Style} style Style.
*/
ol.layer.Vector.prototype.setStyle = function(style) {
this.style_ = style;
this.dispatchEvent(
new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE, [], []));
};
/**
* Returns an array of features that match a filter. This will not fetch data,
* it only considers features that are loaded already.
* @param {(function(ol.Feature):boolean)=} opt_filter Filter function.
* @return {Array.<ol.Feature>} Features that match the filter, or all features
* if no filter was provided.
*/
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
var result;
var features = this.featureCache_.getFeaturesObject();
if (goog.isDef(opt_filter)) {
result = [];
for (var f in features) {
if (opt_filter(features[f]) === true) {
result.push(features[f]);
}
}
} else {
result = goog.object.getValues(features);
}
return result;
};
/**
* Get all features whose bounding box intersects the provided extent. This
* method is intended for being called by the renderer. When null is returned,
* the renderer should not waste time rendering, and `opt_callback` is
* usually a function that requests a renderFrame, which will be called as soon
* as the data for `extent` is available.
*
* @param {ol.Extent} extent Bounding extent.
* @param {ol.proj.Projection} projection Target projection.
* @param {Function=} opt_callback Callback to call when data is parsed.
* @return {Object.<string, ol.Feature>} Features or null if source is loading
* data for `extent`.
*/
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
projection, opt_callback) {
var source = this.getSource();
return source.prepareFeatures(this, extent, projection, opt_callback) ==
ol.source.VectorLoadState.LOADING ?
null :
this.featureCache_.getFeaturesObjectForExtent(extent);
};
/**
* @param {Object.<string, ol.Feature>} features Features.
* @param {number} resolution Map resolution.
* @return {Array.<Array>} symbolizers for features. Each array in this array
* contains 3 items: an array of features, the symbolizer literal, and
* an array with optional additional data for each feature.
*/
ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
function(features, resolution) {
var uniqueLiterals = {},
featuresBySymbolizer = [],
style = this.style_,
i, j, l, feature, symbolizers, literals, numLiterals, literal,
uniqueLiteral, key, item;
for (i in features) {
feature = features[i];
// feature level symbolizers take precedence
symbolizers = feature.getSymbolizers();
if (!goog.isNull(symbolizers)) {
literals = ol.style.Style.createLiterals(symbolizers, feature);
} else {
// layer style second
if (goog.isNull(style)) {
style = ol.style.getDefault();
}
literals = style.createLiterals(feature, resolution);
}
numLiterals = literals.length;
for (j = 0; j < numLiterals; ++j) {
literal = literals[j];
for (l in uniqueLiterals) {
uniqueLiteral = featuresBySymbolizer[uniqueLiterals[l]][1];
if (literal.equals(uniqueLiteral)) {
literal = uniqueLiteral;
break;
}
}
key = goog.getUid(literal);
if (!goog.object.containsKey(uniqueLiterals, key)) {
uniqueLiterals[key] = featuresBySymbolizer.length;
featuresBySymbolizer.push([
/** @type {Array.<ol.Feature>} */ ([]),
/** @type {ol.style.Literal} */ (literal),
/** @type {Array} */ ([])
]);
}
item = featuresBySymbolizer[uniqueLiterals[key]];
item[0].push(feature);
if (literal instanceof ol.style.TextLiteral) {
item[2].push(literals[j].text);
}
}
}
featuresBySymbolizer.sort(this.sortByZIndex_);
return featuresBySymbolizer;
};
/**
* @param {Object|Element|Document|string} data Feature data.
* @param {ol.parser.Parser} parser Feature parser.
* @param {ol.proj.Projection} projection This sucks. The layer should be a
* view in one projection.
*/
ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
var addFeatures = function(data) {
var features = data.features;
var sourceProjection = this.getSource().getProjection();
if (goog.isNull(sourceProjection)) {
sourceProjection = data.metadata.projection;
}
var transform = ol.proj.getTransform(sourceProjection, projection);
var geometry = null;
for (var i = 0, ii = features.length; i < ii; ++i) {
geometry = features[i].getGeometry();
if (!goog.isNull(geometry)) {
geometry.transform(transform);
}
}
this.addFeatures(features);
};
var result;
if (goog.isString(data)) {
if (goog.isFunction(parser.readFeaturesFromStringAsync)) {
parser.readFeaturesFromStringAsync(data, goog.bind(addFeatures, this));
} else {
goog.asserts.assert(
goog.isFunction(parser.readFeaturesFromString),
'Expected parser with a readFeaturesFromString method.');
result = parser.readFeaturesFromString(data);
addFeatures.call(this, result);
}
} else if (goog.isObject(data)) {
if (goog.isFunction(parser.readFeaturesFromObjectAsync)) {
parser.readFeaturesFromObjectAsync(data, goog.bind(addFeatures, this));
} else {
goog.asserts.assert(
goog.isFunction(parser.readFeaturesFromObject),
'Expected parser with a readFeaturesFromObject method.');
result = parser.readFeaturesFromObject(data);
addFeatures.call(this, result);
}
} else {
// TODO: parse more data types
throw new Error('Data type not supported: ' + data);
}
};
/**
* @return {function(Array.<ol.Feature>):string} Feature info function.
*/
ol.layer.Vector.prototype.getTransformFeatureInfo = function() {
return this.transformFeatureInfo_;
};
/**
* Remove features from the layer.
* @param {Array.<ol.Feature>} features Features to remove.
*/
ol.layer.Vector.prototype.removeFeatures = function(features) {
var extent = ol.extent.createEmpty(),
feature, geometry;
for (var i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
this.featureCache_.remove(feature);
geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
ol.extent.extend(extent, geometry.getBounds());
}
goog.events.unlisten(feature, ol.FeatureEventType.CHANGE,
this.handleFeatureChange_, false, this);
goog.events.unlisten(feature, ol.FeatureEventType.INTENTCHANGE,
this.handleIntentChange_, false, this);
}
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE,
features, [extent]));
};
/**
* @param {boolean} temporary Whether this layer is temporary.
*/
ol.layer.Vector.prototype.setTemporary = function(temporary) {
this.temporary_ = temporary;
};
/**
* Sort function for `groupFeaturesBySymbolizerLiteral`.
* @private
* @param {Array} a 1st item for the sort comparison.
* @param {Array} b 2nd item for the sort comparison.
* @return {number} Comparison result.
*/
ol.layer.Vector.prototype.sortByZIndex_ = function(a, b) {
return a[1].zIndex - b[1].zIndex;
};
/**
* @param {Array.<ol.Feature>} features Features.
* @return {string} Feature info.
*/
ol.layer.Vector.uidTransformFeatureInfo = function(features) {
var uids = goog.array.map(features,
function(feature) { return goog.getUid(feature); });
return uids.join(', ');
};
/**
* @param {ol.Feature} feature Feature.
* @return {boolean} Whether the feature is selected.
*/
ol.layer.Vector.selectedFeaturesFilter = function(feature) {
return feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.SELECTED;
};
/**
* @constructor
* @extends {goog.events.Event}
* @param {string} type Event type.
* @param {Array.<ol.Feature>} features Features associated with the event.
* @param {Array.<ol.Extent>} extents Any extents associated with the event.
*/
ol.layer.VectorEvent = function(type, features, extents) {
goog.base(this, type);
/**
* @type {Array.<ol.Feature>}
*/
this.features = features;
/**
* @type {Array.<ol.Extent>}
*/
this.extents = extents;
};
goog.inherits(ol.layer.VectorEvent, goog.events.Event);
/**
* @enum {string}
*/
ol.layer.VectorEventType = {
ADD: 'featureadd',
CHANGE: 'featurechange',
INTENTCHANGE: 'featureintentchange',
REMOVE: 'featureremove'
};

View File

@@ -0,0 +1,13 @@
goog.provide('ol.layer.VectorLayerRenderIntent');
/**
* @enum {string}
*/
ol.layer.VectorLayerRenderIntent = {
DEFAULT: 'default',
FUTURE: 'future',
HIDDEN: 'hidden',
SELECTED: 'selected',
TEMPORARY: 'temporary'
};

3
old/src/ol/parser.jsdoc Normal file
View File

@@ -0,0 +1,3 @@
/**
* @namespace ol.parser
*/

View File

@@ -0,0 +1,98 @@
goog.provide('ol.parser.AsyncObjectFeatureParser');
goog.provide('ol.parser.AsyncStringFeatureParser');
goog.provide('ol.parser.DomFeatureParser');
goog.provide('ol.parser.ObjectFeatureParser');
goog.provide('ol.parser.ReadFeaturesResult');
goog.provide('ol.parser.StringFeatureParser');
goog.require('ol.Feature');
/**
* @interface
*/
ol.parser.DomFeatureParser = function() {};
/**
* @param {Element|Document} node Document or element node.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.DomFeatureParser.prototype.readFeaturesFromNode =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.ObjectFeatureParser = function() {};
/**
* @param {Object} obj Object representing features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.ObjectFeatureParser.prototype.readFeaturesFromObject =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.StringFeatureParser = function() {};
/**
* @param {string} data String data.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.StringFeatureParser.prototype.readFeaturesFromString =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.AsyncStringFeatureParser = function() {};
/**
* @param {string} data String data.
* @param {function(ol.parser.ReadFeaturesResult)} callback Callback which is
* called after parsing.
*/
ol.parser.AsyncStringFeatureParser.prototype.readFeaturesFromStringAsync =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.AsyncObjectFeatureParser = function() {};
/**
* @param {Object} obj Object representing features.
* @param {function(ol.parser.ReadFeaturesResult)} callback Callback which is
* called after parsing.
*/
ol.parser.AsyncObjectFeatureParser.prototype.readFeaturesFromObjectAsync =
goog.abstractMethod;
/**
* @typedef {{projection: ol.proj.ProjectionLike}}
*/
ol.parser.ReadFeaturesMetadata;
/**
* @typedef {{features: Array.<ol.Feature>,
* metadata: ol.parser.ReadFeaturesMetadata}}
*/
ol.parser.ReadFeaturesResult;

View File

@@ -0,0 +1 @@
@exportSymbol ol.parser.GeoJSON

View File

@@ -0,0 +1,419 @@
goog.provide('ol.parser.GeoJSON');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.Parser');
goog.require('ol.parser.ReadFeaturesResult');
goog.require('ol.parser.StringFeatureParser');
/**
* Read and write [GeoJSON](http://geojson.org/)
*
* @constructor
* @implements {ol.parser.StringFeatureParser}
* @extends {ol.parser.Parser}
* @todo stability experimental
*/
ol.parser.GeoJSON = function() {};
goog.inherits(ol.parser.GeoJSON, ol.parser.Parser);
goog.addSingletonGetter(ol.parser.GeoJSON);
/**
* Parse a GeoJSON string.
* @param {string} str GeoJSON string.
* @return {ol.Feature|Array.<ol.Feature>|
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
* of geometries.
*/
ol.parser.GeoJSON.prototype.read = function(str) {
var json = /** @type {GeoJSONObject} */ (JSON.parse(str));
return this.parse_(json);
};
/**
* Parse a GeoJSON string.
* @param {string} str GeoJSON string.
* @return {ol.Feature|Array.<ol.Feature>|
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
* of geometries.
*/
ol.parser.GeoJSON.read = function(str) {
return ol.parser.GeoJSON.getInstance().read(str);
};
/**
* Parse a GeoJSON feature collection.
* @param {string} str GeoJSON feature collection.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromString = function(str) {
var json = /** @type {GeoJSONFeatureCollection} */ (JSON.parse(str));
return this.parseAsFeatureCollection_(json);
};
/**
* Parse a GeoJSON feature collection from decoded JSON.
* @param {GeoJSONFeatureCollection} object GeoJSON feature collection decoded
* from JSON.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromObject = function(object) {
return this.parseAsFeatureCollection_(object);
};
/**
* Parse any GeoJSON object.
*
* @param {GeoJSONObject} json GeoJSON object.
* @return {ol.Feature|Array.<ol.Feature>|
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
* of geometries.
* @private
*/
ol.parser.GeoJSON.prototype.parse_ = function(json) {
var result;
if (json.type === 'FeatureCollection') {
result = this.parseFeatureCollection_(
/** @type {GeoJSONFeatureCollection} */ (json));
} else if (json.type === 'Feature') {
result = this.parseFeature_(
/** @type {GeoJSONFeature} */ (json));
} else if (json.type === 'GeometryCollection') {
result = this.parseGeometryCollection_(
/** @type {GeoJSONGeometryCollection} */ (json));
} else {
// we've been called with a geometry or an unknown object
// create a feature to get shared vertices handling
var feature = this.parseFeature_(
/** @type {GeoJSONFeature} */ ({type: 'Feature', geometry: json}));
result = feature.getGeometry();
}
return result;
};
/**
* @param {GeoJSONObject} json GeoJSON object.
* @return {ol.parser.ReadFeaturesResult} Parsed object coerced into array of
* features.
* @private
*/
ol.parser.GeoJSON.prototype.parseAsFeatureCollection_ = function(json) {
var obj = this.parse_(json);
var features = [];
var feature;
if (obj instanceof ol.Feature) {
features = [obj];
} else if (obj instanceof ol.geom.Geometry) {
feature = new ol.Feature();
feature.setGeometry(obj);
features = [feature];
} else if (goog.isArray(obj)) {
var item, geomArray;
for (var i = 0, ii = obj.length; i < ii; ++i) {
item = obj[i];
geomArray = geomArray || (item instanceof ol.geom.Geometry);
if (!geomArray) {
goog.asserts.assert(item instanceof ol.Feature, 'expected feature');
features = obj;
break;
} else {
feature = new ol.Feature();
feature.setGeometry(item);
features[i] = feature;
}
}
}
var projection = 'EPSG:4326';
if (goog.isDefAndNotNull(json.crs)) {
var crs = json.crs;
if (crs.type === 'name') {
projection = (/** GeoJSONCRSName */ (crs.properties)).name;
}
}
return {features: features, metadata: {projection: projection}};
};
/**
* @param {GeoJSONFeature} json GeoJSON feature.
* @return {ol.Feature} Parsed feature.
* @private
*/
ol.parser.GeoJSON.prototype.parseFeature_ = function(json) {
var geomJson = json.geometry,
geometry = null;
var feature = new ol.Feature(json.properties);
if (goog.isDef(json.id)) {
feature.setId(json.id);
}
if (geomJson) {
var type = geomJson.type;
switch (type) {
case 'Point':
geometry = this.parsePoint_(geomJson);
break;
case 'LineString':
geometry = this.parseLineString_(geomJson);
break;
case 'Polygon':
geometry = this.parsePolygon_(geomJson);
break;
case 'MultiPoint':
geometry = this.parseMultiPoint_(geomJson);
break;
case 'MultiLineString':
geometry = this.parseMultiLineString_(geomJson);
break;
case 'MultiPolygon':
geometry = this.parseMultiPolygon_(geomJson);
break;
default:
throw new Error('Bad geometry type: ' + type);
}
feature.setGeometry(geometry);
}
return feature;
};
/**
* @param {GeoJSONFeatureCollection} json GeoJSON feature collection.
* @return {Array.<ol.Feature>} Parsed array of features.
* @private
*/
ol.parser.GeoJSON.prototype.parseFeatureCollection_ = function(json) {
var features = json.features,
len = features.length,
result = new Array(len),
i;
for (i = 0; i < len; ++i) {
result[i] = this.parseFeature_(/** @type {GeoJSONFeature} */ (features[i]));
}
return result;
};
/**
* @param {GeoJSONGeometryCollection} json GeoJSON geometry collection.
* @return {Array.<ol.geom.Geometry>} Parsed array of geometries.
* @private
*/
ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json) {
var geometries = json.geometries,
len = geometries.length,
result = new Array(len),
i;
for (i = 0; i < len; ++i) {
result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i]));
}
return result;
};
/**
* @param {GeoJSONGeometry} json GeoJSON linestring.
* @return {ol.geom.LineString} Parsed linestring.
* @private
*/
ol.parser.GeoJSON.prototype.parseLineString_ = function(json) {
return new ol.geom.LineString(json.coordinates);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-linestring.
* @return {ol.geom.MultiLineString} Parsed multi-linestring.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiLineString_ = function(json) {
return new ol.geom.MultiLineString(json.coordinates);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-point.
* @return {ol.geom.MultiPoint} Parsed multi-point.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiPoint_ = function(json) {
return new ol.geom.MultiPoint(json.coordinates);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-polygon.
* @return {ol.geom.MultiPolygon} Parsed multi-polygon.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiPolygon_ = function(json) {
return new ol.geom.MultiPolygon(json.coordinates);
};
/**
* @param {GeoJSONGeometry} json GeoJSON point.
* @return {ol.geom.Point} Parsed point.
* @private
*/
ol.parser.GeoJSON.prototype.parsePoint_ = function(json) {
return new ol.geom.Point(json.coordinates);
};
/**
* @param {GeoJSONGeometry} json GeoJSON polygon.
* @return {ol.geom.Polygon} Parsed polygon.
* @private
*/
ol.parser.GeoJSON.prototype.parsePolygon_ = function(json) {
return new ol.geom.Polygon(json.coordinates);
};
/**
* @param {ol.geom.Geometry} geometry Geometry to encode.
* @return {GeoJSONGeometry} GeoJSON geometry.
* @private
*/
ol.parser.GeoJSON.prototype.encodeGeometry_ = function(geometry) {
var type = geometry.getType();
return /** @type {GeoJSONGeometry} */({
type: goog.object.findKey(ol.parser.GeoJSON.GeometryType,
function(value, key) {
return value === type;
}
),
coordinates: geometry.getCoordinates()
});
};
/**
* @param {ol.geom.GeometryCollection} collection Geometry collection to
* encode.
* @return {GeoJSONGeometryCollection} GeoJSON geometry collection.
* @private
*/
ol.parser.GeoJSON.prototype.encodeGeometryCollection_ = function(collection) {
var geometries = [];
var components = collection.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
geometries.push(this.encodeGeometry_(components[i]));
}
return /** @type {GeoJSONGeometryCollection} */({
type: 'GeometryCollection',
geometries: geometries
});
};
/**
* @param {Array.<ol.Feature>} collection Feature collection to encode.
* @return {GeoJSONFeatureCollection} GeoJSON feature collection.
* @private
*/
ol.parser.GeoJSON.prototype.encodeFeatureCollection_ = function(collection) {
var features = [];
for (var i = 0, ii = collection.length; i < ii; ++i) {
features.push(this.encodeFeature_(collection[i]));
}
return /** @type {GeoJSONFeatureCollection} */({
type: 'FeatureCollection',
features: features
});
};
/**
* @param {ol.Feature} feature Feature to encode.
* @return {GeoJSONFeature} GeoJSON feature.
* @private
*/
ol.parser.GeoJSON.prototype.encodeFeature_ = function(feature) {
var geometry = feature.getGeometry(),
properties = feature.getAttributes(true);
return /** @type {GeoJSONFeature} */({
type: 'Feature',
properties: properties,
geometry: this.encodeGeometry_(geometry)
});
};
/**
* @param {ol.geom.GeometryCollection|ol.geom.Geometry|Array.<ol.Feature>|
* ol.Feature} obj The object to encode.
* @return {string} The GeoJSON as string.
* @private
*/
ol.parser.GeoJSON.prototype.encode_ = function(obj) {
var result;
if (obj instanceof ol.geom.GeometryCollection) {
result = this.encodeGeometryCollection_(obj);
} else if (obj instanceof ol.geom.Geometry) {
result = this.encodeGeometry_(obj);
} else if (obj instanceof ol.Feature) {
result = this.encodeFeature_(obj);
} else if (goog.isArray(obj)) {
result = this.encodeFeatureCollection_(obj);
}
return JSON.stringify(result);
};
/**
* Write out a geometry, geometry collection, feature or an array of features
* as a GeoJSON string.
* @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature|
* Array.<ol.Feature>} obj The object to encode.
* @return {string} GeoJSON for the geometry.
*/
ol.parser.GeoJSON.write = function(obj) {
return ol.parser.GeoJSON.getInstance().write(obj);
};
/**
* Write out a geometry, geometry collection, feature or an array of features
* as a GeoJSON string.
* @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature|
* Array.<ol.Feature>} obj The object to encode.
* @return {string} GeoJSON for the geometry.
*/
ol.parser.GeoJSON.prototype.write = function(obj) {
return this.encode_(obj);
};
/**
* @enum {ol.geom.GeometryType}
*/
ol.parser.GeoJSON.GeometryType = {
'Point': ol.geom.GeometryType.POINT,
'LineString': ol.geom.GeometryType.LINESTRING,
'Polygon': ol.geom.GeometryType.POLYGON,
'MultiPoint': ol.geom.GeometryType.MULTIPOINT,
'MultiLineString': ol.geom.GeometryType.MULTILINESTRING,
'MultiPolygon': ol.geom.GeometryType.MULTIPOLYGON,
'GeometryCollection': ol.geom.GeometryType.GEOMETRYCOLLECTION
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.parser.GPX

View File

@@ -0,0 +1,291 @@
goog.provide('ol.parser.GPX');
goog.require('goog.dom.xml');
goog.require('ol.Feature');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.DomFeatureParser');
goog.require('ol.parser.ObjectFeatureParser');
goog.require('ol.parser.StringFeatureParser');
goog.require('ol.parser.XML');
/**
* Read and write [GPX](http://www.topografix.com/gpx.asp) version 1.1
*
* @constructor
* @implements {ol.parser.DomFeatureParser}
* @implements {ol.parser.StringFeatureParser}
* @implements {ol.parser.ObjectFeatureParser}
* @param {ol.parser.GPXOptions=} opt_options Optional configuration object.
* @extends {ol.parser.XML}
* @todo stability experimental
*/
ol.parser.GPX = function(opt_options) {
var options = /** @type {ol.parser.GPXOptions} */
(goog.isDef(opt_options) ? opt_options : {});
this.extractAttributes = goog.isDef(options.extractAttributes) ?
options.extractAttributes : true;
this.extractWaypoints = goog.isDef(options.extractWaypoints) ?
options.extractWaypoints : true;
this.extractTracks = goog.isDef(options.extractTracks) ?
options.extractTracks : true;
this.extractRoutes = goog.isDef(options.extractRoutes) ?
options.extractRoutes : true;
this.creator = goog.isDef(options.creator) ?
options.creator : 'OpenLayers';
this.defaultDesc = goog.isDef(options.defaultDesc) ?
options.defaultDesc : 'No description available';
this.defaultNamespaceURI = 'http://www.topografix.com/GPX/1/1';
this.schemaLocation = 'http://www.topografix.com/GPX/1/1 ' +
'http://www.topografix.com/GPX/1/1/gpx.xsd';
this.readers = {
'http://www.topografix.com/GPX/1/1': {
'gpx': function(node, obj) {
if (!goog.isDef(obj.features)) {
obj.features = [];
}
this.readChildNodes(node, obj);
},
'wpt': function(node, obj) {
if (this.extractWaypoints) {
var properties = {};
var coordinates = [parseFloat(node.getAttribute('lon')),
parseFloat(node.getAttribute('lat'))];
this.readChildNodes(node, properties);
var feature = new ol.Feature(properties);
var geometry = new ol.geom.Point(coordinates);
feature.setGeometry(geometry);
obj.features.push(feature);
}
},
'rte': function(node, obj) {
if (this.extractRoutes || obj.force) {
var type = ol.geom.GeometryType.LINESTRING;
var container = {
properties: {},
geometry: {
type: type,
coordinates: []
}
};
this.readChildNodes(node, container);
var feature = new ol.Feature(container.properties);
var geometry = new ol.geom.LineString(container.geometry.coordinates);
feature.setGeometry(geometry);
obj.features.push(feature);
}
},
'rtept': function(node, container) {
var coordinate = [parseFloat(node.getAttribute('lon')),
parseFloat(node.getAttribute('lat'))];
container.geometry.coordinates.push(coordinate);
},
'trk': function(node, obj) {
if (this.extractTracks) {
var readers = this.readers[this.defaultNamespaceURI];
obj.force = true;
readers['rte'].apply(this, arguments);
}
},
'trkseg': function(node, container) {
this.readChildNodes(node, container);
},
'trkpt': function(node, container) {
var readers = this.readers[this.defaultNamespaceURI];
readers['rtept'].apply(this, arguments);
},
'*': function(node, obj) {
if (this.extractAttributes === true) {
var len = node.childNodes.length;
if ((len === 1 || len === 2) && (node.firstChild.nodeType === 3 ||
node.firstChild.nodeType === 4)) {
var readers = this.readers[this.defaultNamespaceURI];
readers['_attribute'].apply(this, arguments);
}
}
},
'_attribute': function(node, obj) {
var local = node.localName || node.nodeName.split(':').pop();
var value = this.getChildValue(node);
if (obj.properties) {
obj.properties[local] = value.replace(this.regExes.trimSpace, '');
} else {
obj[local] = value.replace(this.regExes.trimSpace, '');
}
}
}
};
// create an alias for GXP 1.0
this.readers['http://www.topografix.com/GPX/1/0'] =
this.readers[this.defaultNamespaceURI];
this.writers = {
'http://www.topografix.com/GPX/1/1': {
'_feature': function(feature) {
var geom = feature.getGeometry();
if (geom instanceof ol.geom.Point) {
return this.writeNode('wpt', feature);
} else if ((geom instanceof ol.geom.LineString) ||
(geom instanceof ol.geom.MultiLineString) ||
(geom instanceof ol.geom.Polygon)) {
return this.writeNode('trk', feature);
}
},
'wpt': function(feature) {
var node = this.createElementNS('wpt');
var geom = feature.getGeometry();
var coordinates = geom.getCoordinates();
node.setAttribute('lon', coordinates[0]);
node.setAttribute('lat', coordinates[1]);
var attributes = feature.getAttributes();
var name = attributes['name'] || goog.getUid(feature).toString();
this.writeNode('name', name, undefined, node);
var desc = attributes['description'] || this.defaultDesc;
this.writeNode('desc', desc, undefined, node);
return node;
},
'trk': function(feature) {
var attributes = feature.getAttributes();
var node = this.createElementNS('trk');
var name = attributes['name'] || goog.getUid(feature).toString();
this.writeNode('name', name, undefined, node);
var desc = attributes['description'] || this.defaultDesc;
this.writeNode('desc', desc, undefined, node);
var geom = feature.getGeometry();
var i, ii, rings;
if (geom instanceof ol.geom.LineString) {
this.writeNode('trkseg', feature.getGeometry(), undefined, node);
} else if (geom instanceof ol.geom.MultiLineString) {
var components = geom.getComponents();
for (i = 0, ii = components.length; i < ii; ++i) {
this.writeNode('trkseg', components[i], undefined, node);
}
} else if (geom instanceof ol.geom.Polygon) {
rings = geom.getRings();
for (i = 0, ii = rings.length; i < ii; ++i) {
this.writeNode('trkseg', rings[i], undefined, node);
}
}
return node;
},
'trkseg': function(geometry) {
var node = this.createElementNS('trkseg');
var coordinates = geometry.getCoordinates();
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
this.writeNode('trkpt', coordinates[i], undefined, node);
}
return node;
},
'trkpt': function(coord) {
var node = this.createElementNS('trkpt');
node.setAttribute('lon', coord[0]);
node.setAttribute('lat', coord[1]);
return node;
},
'metadata': function(metadata) {
var node = this.createElementNS('metadata');
if (goog.isDef(metadata['name'])) {
this.writeNode('name', metadata['name'], undefined, node);
}
if (goog.isDef(metadata['desc'])) {
this.writeNode('desc', metadata['desc'], undefined, node);
}
if (goog.isDef(metadata['author'])) {
this.writeNode('author', metadata['author'], undefined, node);
}
return node;
},
'name': function(name) {
var node = this.createElementNS('name');
node.appendChild(this.createTextNode(name));
return node;
},
'desc': function(desc) {
var node = this.createElementNS('desc');
node.appendChild(this.createTextNode(desc));
return node;
},
'author': function(author) {
var node = this.createElementNS('author');
node.appendChild(this.createTextNode(author));
return node;
}
}
};
goog.base(this);
};
goog.inherits(ol.parser.GPX, ol.parser.XML);
/**
* @param {string|Document|Element|Object} data Data to read.
* @return {ol.parser.ReadFeaturesResult} An object representing the document.
*/
ol.parser.GPX.prototype.read = function(data) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({metadata: {projection: 'EPSG:4326'}});
this.readNode(data, obj);
return obj;
};
/**
* Parse a GPX document provided as a string.
* @param {string} str GPX document.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromString = function(str) {
return this.read(str);
};
/**
* Parse a GPX document provided as a DOM structure.
* @param {Element|Document} node Document or element node.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromNode = function(node) {
return this.read(node);
};
/**
* @param {Object} obj Object representing features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromObject = function(obj) {
return this.read(obj);
};
/**
* @param {ol.parser.GPXWriteOptions} obj Object structure to write out
* as GPX.
* @return {string} An string representing the GPX document.
*/
ol.parser.GPX.prototype.write = function(obj) {
var features = goog.isArray(obj.features) ? obj.features : [obj.features];
var root = this.createElementNS('gpx');
root.setAttribute('version', '1.1');
root.setAttribute('creator', this.creator);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
if (goog.isDef(obj.metadata)) {
this.writeNode('metadata', obj.metadata, undefined, root);
}
for (var i = 0, ii = features.length; i < ii; i++) {
this.writeNode('_feature', features[i], undefined, root);
}
return this.serialize(root);
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.parser.KML

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
goog.provide('ol.parser.ogc.ExceptionReport');
goog.require('goog.dom.xml');
goog.require('ol.parser.XML');
/**
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.ExceptionReport = function() {
var exceptionReader = function(node, exceptionReport) {
var exception = {
code: node.getAttribute('exceptionCode'),
locator: node.getAttribute('locator'),
texts: []
};
exceptionReport.exceptions.push(exception);
this.readChildNodes(node, exception);
};
var exceptionTextReader = function(node, exception) {
var text = this.getChildValue(node);
exception.texts.push(text);
};
this.readers = {
'http://www.opengis.net/ogc': {
'ServiceExceptionReport': function(node, obj) {
obj['exceptionReport'] = {};
obj['exceptionReport']['exceptions'] = [];
this.readChildNodes(node, obj['exceptionReport']);
},
'ServiceException': function(node, exceptionReport) {
var exception = {};
exception['code'] = node.getAttribute('code');
exception['locator'] = node.getAttribute('locator');
exception['text'] = this.getChildValue(node);
exceptionReport['exceptions'].push(exception);
}
},
'http://www.opengis.net/ows': {
'ExceptionReport': function(node, obj) {
obj.success = false;
obj.exceptionReport = {
version: node.getAttribute('version'),
language: node.getAttribute('language'),
exceptions: []
};
this.readChildNodes(node, obj.exceptionReport);
},
'Exception': function(node, exceptionReport) {
exceptionReader.apply(this, arguments);
},
'ExceptionText': function(node, exception) {
exceptionTextReader.apply(this, arguments);
}
},
'http://www.opengis.net/ows/1.1': {
'ExceptionReport': function(node, obj) {
obj.exceptionReport = {
version: node.getAttribute('version'),
language: node.getAttribute('xml:lang'),
exceptions: []
};
this.readChildNodes(node, obj.exceptionReport);
},
'Exception': function(node, exceptionReport) {
exceptionReader.apply(this, arguments);
},
'ExceptionText': function(node, exception) {
exceptionTextReader.apply(this, arguments);
}
}
};
goog.base(this);
};
goog.inherits(ol.parser.ogc.ExceptionReport, ol.parser.XML);
/**
* Read OGC exception report data from a string, and return an object with
* information about the exceptions.
*
* @param {string|Document} data to read/parse.
* @return {Object} Information about the exceptions that occurred.
*/
ol.parser.ogc.ExceptionReport.prototype.read = function(data) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
var exceptionInfo = {};
exceptionInfo['exceptionReport'] = null;
if (data) {
this.readChildNodes(data, exceptionInfo);
}
return exceptionInfo;
};

View File

@@ -0,0 +1,37 @@
goog.provide('ol.parser.ogc.Filter');
goog.require('ol.parser.ogc.Filter_v1_0_0');
goog.require('ol.parser.ogc.Filter_v1_1_0');
goog.require('ol.parser.ogc.Versioned');
/**
* @define {boolean} Whether to enable OGC Filter version 1.0.0.
*/
ol.ENABLE_OGCFILTER_1_0_0 = true;
/**
* @define {boolean} Whether to enable OGC Filter version 1.1.0.
*/
ol.ENABLE_OGCFILTER_1_1_0 = true;
/**
* @constructor
* @param {Object=} opt_options Options which will be set on this object.
* @extends {ol.parser.ogc.Versioned}
*/
ol.parser.ogc.Filter = function(opt_options) {
opt_options = opt_options || {};
opt_options['defaultVersion'] = '1.0.0';
this.parsers = {};
if (ol.ENABLE_OGCFILTER_1_0_0) {
this.parsers['v1_0_0'] = ol.parser.ogc.Filter_v1_0_0;
}
if (ol.ENABLE_OGCFILTER_1_1_0) {
this.parsers['v1_1_0'] = ol.parser.ogc.Filter_v1_1_0;
}
goog.base(this, opt_options);
};
goog.inherits(ol.parser.ogc.Filter, ol.parser.ogc.Versioned);

View File

@@ -0,0 +1,601 @@
goog.provide('ol.parser.ogc.Filter_v1');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.xml');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.expr');
goog.require('ol.expr.Call');
goog.require('ol.expr.Comparison');
goog.require('ol.expr.ComparisonOp');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Literal');
goog.require('ol.expr.Logical');
goog.require('ol.expr.LogicalOp');
goog.require('ol.expr.Not');
goog.require('ol.expr.functions');
goog.require('ol.parser.XML');
/**
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.Filter_v1 = function() {
this.defaultNamespaceURI = 'http://www.opengis.net/ogc';
this.errorProperty = 'filter';
this.readers = {
'http://www.opengis.net/ogc': {
_expression: function(node) {
var expressions = [];
var obj, value, numValue, expr;
for (var child = node.firstChild; child; child = child.nextSibling) {
switch (child.nodeType) {
case 1:
obj = this.readNode(child);
if (obj.property) {
expressions.push(obj.property);
} else if (goog.isDef(obj.value)) {
expressions.push(obj.value);
}
break;
case 3: // text node
case 4: // cdata section
value = goog.string.trim(child.nodeValue);
// no need to concatenate empty strings
if (value) {
// check for numeric values
numValue = goog.string.toNumber(value);
if (!isNaN(numValue)) {
value = numValue;
}
expressions.push(new ol.expr.Literal(value));
}
break;
default:
break;
}
}
// if we have more than one property or literal, we concatenate them
var num = expressions.length;
if (num === 1) {
expr = expressions[0];
} else {
expr = new ol.expr.Call(
new ol.expr.Identifier(ol.expr.functions.CONCAT),
expressions);
}
return expr;
},
'Filter': function(node, obj) {
var container = {
filters: []
};
this.readChildNodes(node, container);
if (goog.isDef(container.fids)) {
obj.filter = new ol.expr.Call(
new ol.expr.Identifier(ol.expr.functions.FID),
goog.object.getValues(container.fids));
} else if (container.filters.length > 0) {
obj.filter = container.filters[0];
}
},
'FeatureId': function(node, obj) {
var fid = node.getAttribute('fid');
if (fid) {
if (!goog.isDef(obj.fids)) {
obj.fids = {};
}
if (!obj.fids.hasOwnProperty(fid)) {
obj.fids[fid] = new ol.expr.Literal(fid);
}
}
},
'And': function(node, obj) {
var container = {filters: []};
this.readChildNodes(node, container);
var filter = this.aggregateLogical_(container.filters,
ol.expr.LogicalOp.AND);
obj.filters.push(filter);
},
'Or': function(node, obj) {
var container = {filters: []};
this.readChildNodes(node, container);
var filter = this.aggregateLogical_(container.filters,
ol.expr.LogicalOp.OR);
obj.filters.push(filter);
},
'Not': function(node, obj) {
var container = {filters: []};
this.readChildNodes(node, container);
// Not is unary so can only contain 1 child filter
obj.filters.push(new ol.expr.Not(
container.filters[0]));
},
'PropertyIsNull': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.EQ,
container.property,
new ol.expr.Literal(null)));
},
'PropertyIsLessThan': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.LT,
container.property,
container.value));
},
'PropertyIsGreaterThan': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.GT,
container.property,
container.value));
},
'PropertyIsLessThanOrEqualTo': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.LTE,
container.property,
container.value));
},
'PropertyIsGreaterThanOrEqualTo': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.GTE,
container.property,
container.value));
},
'PropertyIsBetween': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Logical(ol.expr.LogicalOp.AND,
new ol.expr.Comparison(ol.expr.ComparisonOp.GTE,
container.property, container.lowerBoundary),
new ol.expr.Comparison(ol.expr.ComparisonOp.LTE,
container.property, container.upperBoundary)));
},
'Literal': function(node, obj) {
var nodeValue = this.getChildValue(node);
var value = goog.string.toNumber(nodeValue);
obj.value = new ol.expr.Literal(isNaN(value) ? nodeValue : value);
},
'PropertyName': function(node, obj) {
obj.property = new ol.expr.Identifier(this.getChildValue(node));
},
'LowerBoundary': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
obj.lowerBoundary = readers._expression.call(this, node);
},
'UpperBoundary': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
obj.upperBoundary = readers._expression.call(this, node);
},
_spatial: function(node, obj, identifier) {
var args = [], container = {};
this.readChildNodes(node, container);
if (goog.isDef(container.geometry)) {
args.push(new ol.expr.Literal(this.gml_.createGeometry(container)));
} else {
args = [new ol.expr.Literal(container.bounds[0]),
new ol.expr.Literal(container.bounds[1]),
new ol.expr.Literal(container.bounds[2]),
new ol.expr.Literal(container.bounds[3])];
}
if (goog.isDef(container.distance)) {
args.push(container.distance);
}
if (goog.isDef(container.distanceUnits)) {
args.push(container.distanceUnits);
}
args.push(new ol.expr.Literal(container.projection));
if (goog.isDef(container.property)) {
args.push(container.property);
}
obj.filters.push(new ol.expr.Call(new ol.expr.Identifier(
identifier), args));
},
'BBOX': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
readers._spatial.call(this, node, obj,
ol.expr.functions.EXTENT);
},
'Intersects': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
readers._spatial.call(this, node, obj,
ol.expr.functions.INTERSECTS);
},
'Within': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
readers._spatial.call(this, node, obj,
ol.expr.functions.WITHIN);
},
'Contains': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
readers._spatial.call(this, node, obj,
ol.expr.functions.CONTAINS);
},
'DWithin': function(node, obj) {
var readers = this.readers[this.defaultNamespaceURI];
readers._spatial.call(this, node, obj,
ol.expr.functions.DWITHIN);
},
'Distance': function(node, obj) {
var value = goog.string.toNumber(this.getChildValue(node));
obj.distance = new ol.expr.Literal(value);
obj.distanceUnits = new ol.expr.Literal(node.getAttribute('units'));
}
}
};
this.writers = {
'http://www.opengis.net/ogc': {
'Filter': function(filter) {
var node = this.createElementNS('ogc:Filter');
this.writeNode(this.getFilterType_(filter), filter, null, node);
return node;
},
'_featureIds': function(filter) {
var node = this.createDocumentFragment();
var args = filter.getArgs();
for (var i = 0, ii = args.length; i < ii; i++) {
goog.asserts.assert(args[i] instanceof ol.expr.Literal);
this.writeNode('FeatureId', args[i].getValue(), null, node);
}
return node;
},
'FeatureId': function(fid) {
var node = this.createElementNS('ogc:FeatureId');
node.setAttribute('fid', fid);
return node;
},
'And': function(filter) {
var node = this.createElementNS('ogc:And');
var subFilters = [];
this.getSubfiltersForLogical_(filter, subFilters);
for (var i = 0, ii = subFilters.length; i < ii; ++i) {
var subFilter = subFilters[i];
if (goog.isDefAndNotNull(subFilter)) {
this.writeNode(this.getFilterType_(subFilter), subFilter,
null, node);
}
}
return node;
},
'Or': function(filter) {
var node = this.createElementNS('ogc:Or');
var subFilters = [];
this.getSubfiltersForLogical_(filter, subFilters);
for (var i = 0, ii = subFilters.length; i < ii; ++i) {
var subFilter = subFilters[i];
if (goog.isDefAndNotNull(subFilter)) {
this.writeNode(this.getFilterType_(subFilter), subFilter,
null, node);
}
}
return node;
},
'Not': function(filter) {
var node = this.createElementNS('ogc:Not');
var childFilter = filter.getArgument();
this.writeNode(this.getFilterType_(childFilter), childFilter, null,
node);
return node;
},
'PropertyIsLessThan': function(filter) {
var node = this.createElementNS('ogc:PropertyIsLessThan');
this.writeNode('PropertyName', filter.getLeft(), null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsGreaterThan': function(filter) {
var node = this.createElementNS('ogc:PropertyIsGreaterThan');
this.writeNode('PropertyName', filter.getLeft(), null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsLessThanOrEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsLessThanOrEqualTo');
this.writeNode('PropertyName', filter.getLeft(), null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsGreaterThanOrEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsGreaterThanOrEqualTo');
this.writeNode('PropertyName', filter.getLeft(), null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsBetween': function(filter) {
var node = this.createElementNS('ogc:PropertyIsBetween');
var property = filter.getLeft().getLeft();
this.writeNode('PropertyName', property, null, node);
var lower, upper;
var filters = new Array(2);
filters[0] = filter.getLeft();
filters[1] = filter.getRight();
for (var i = 0; i < 2; ++i) {
var expr = filters[i].getRight();
if (filters[i].getOperator() === ol.expr.ComparisonOp.GTE) {
lower = expr;
} else if (filters[i].getOperator() === ol.expr.ComparisonOp.LTE) {
upper = expr;
}
}
this.writeNode('LowerBoundary', lower, null, node);
this.writeNode('UpperBoundary', upper, null, node);
return node;
},
'PropertyName': function(expr) {
goog.asserts.assert(expr instanceof ol.expr.Identifier);
var node = this.createElementNS('ogc:PropertyName');
node.appendChild(this.createTextNode(expr.getName()));
return node;
},
'Literal': function(expr) {
goog.asserts.assert(expr instanceof ol.expr.Literal);
var node = this.createElementNS('ogc:Literal');
node.appendChild(this.createTextNode(expr.getValue()));
return node;
},
'LowerBoundary': function(expr) {
var node = this.createElementNS('ogc:LowerBoundary');
this.writeOgcExpression(expr, node);
return node;
},
'UpperBoundary': function(expr) {
var node = this.createElementNS('ogc:UpperBoundary');
this.writeOgcExpression(expr, node);
return node;
},
'INTERSECTS': function(filter) {
return this.writeSpatial_(filter, 'Intersects');
},
'WITHIN': function(filter) {
return this.writeSpatial_(filter, 'Within');
},
'CONTAINS': function(filter) {
return this.writeSpatial_(filter, 'Contains');
},
'DWITHIN': function(filter) {
var node = this.writeSpatial_(filter, 'DWithin');
this.writeNode('Distance', filter, null, node);
return node;
},
'Distance': function(filter) {
var node = this.createElementNS('ogc:Distance');
var args = filter.getArgs();
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
node.setAttribute('units', args[2].getValue());
goog.asserts.assert(args[1] instanceof ol.expr.Literal);
node.appendChild(this.createTextNode(args[1].getValue()));
return node;
},
'Function': function(filter) {
var node = this.createElementNS('ogc:Function');
node.setAttribute('name', filter.getCallee().getName());
var params = filter.getArgs();
for (var i = 0, len = params.length; i < len; i++) {
this.writeOgcExpression(params[i], node);
}
return node;
},
'PropertyIsNull': function(filter) {
var node = this.createElementNS('ogc:PropertyIsNull');
this.writeNode('PropertyName', filter.getLeft(), null, node);
return node;
}
}
};
goog.base(this);
};
goog.inherits(ol.parser.ogc.Filter_v1, ol.parser.XML);
/**
* @private
*/
ol.parser.ogc.Filter_v1.filterMap_ = {
'&&': 'And',
'||': 'Or',
'!': 'Not',
'==': 'PropertyIsEqualTo',
'!=': 'PropertyIsNotEqualTo',
'<': 'PropertyIsLessThan',
'>': 'PropertyIsGreaterThan',
'<=': 'PropertyIsLessThanOrEqualTo',
'>=': 'PropertyIsGreaterThanOrEqualTo',
'..': 'PropertyIsBetween',
'like': 'PropertyIsLike',
'null': 'PropertyIsNull',
'extent': 'BBOX',
'dwithin': 'DWITHIN',
'within': 'WITHIN',
'contains': 'CONTAINS',
'intersects': 'INTERSECTS',
'fid': '_featureIds',
'ieq': 'PropertyIsEqualTo',
'ineq': 'PropertyIsNotEqualTo'
};
/**
* @param {ol.expr.Expression} filter The filter to determine the type of.
* @return {string} The type of filter.
* @private
*/
ol.parser.ogc.Filter_v1.prototype.getFilterType_ = function(filter) {
var type;
if (filter instanceof ol.expr.Logical ||
filter instanceof ol.expr.Comparison) {
type = filter.getOperator();
var left = filter.getLeft();
var right = filter.getRight();
var isNull = (type === ol.expr.ComparisonOp.EQ &&
right instanceof ol.expr.Literal && right.getValue() === null);
if (isNull) {
type = 'null';
}
var isBetween = (type === ol.expr.LogicalOp.AND &&
left instanceof ol.expr.Comparison &&
right instanceof ol.expr.Comparison &&
left.getLeft() instanceof ol.expr.Identifier &&
right.getLeft() instanceof ol.expr.Identifier &&
left.getLeft().getName() === right.getLeft().getName() &&
(left.getOperator() === ol.expr.ComparisonOp.LTE ||
left.getOperator() === ol.expr.ComparisonOp.GTE) &&
(right.getOperator() === ol.expr.ComparisonOp.LTE ||
right.getOperator() === ol.expr.ComparisonOp.GTE));
if (isBetween) {
type = '..';
}
} else if (filter instanceof ol.expr.Call) {
var callee = filter.getCallee();
goog.asserts.assert(callee instanceof ol.expr.Identifier);
type = callee.getName();
} else if (filter instanceof ol.expr.Not) {
type = '!';
}
var filterType = ol.parser.ogc.Filter_v1.filterMap_[type];
if (!filterType) {
throw new Error('Filter writing not supported for rule type: ' + type);
}
return filterType;
};
/**
* @param {string|Document|Element} data Data to read.
* @return {Object} An object representing the document.
*/
ol.parser.ogc.Filter_v1.prototype.read = function(data) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {};
this.readNode(data, obj);
return obj.filter;
};
/**
* @param {ol.expr.Expression} filter The filter to write out.
* @return {string} The serialized filter.
*/
ol.parser.ogc.Filter_v1.prototype.write = function(filter) {
var root = this.writeNode('Filter', filter);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
return this.serialize(root);
};
/**
* @param {ol.expr.Expression} expr The value write out.
* @param {Element} node The node to append to.
* @return {Element} The node to which was appended.
* @protected
*/
ol.parser.ogc.Filter_v1.prototype.writeOgcExpression = function(expr, node) {
if (expr instanceof ol.expr.Call) {
this.writeNode('Function', expr, null, node);
} else if (expr instanceof ol.expr.Literal) {
this.writeNode('Literal', expr, null, node);
} else if (expr instanceof ol.expr.Identifier) {
this.writeNode('PropertyName', expr, null, node);
}
return node;
};
/**
* @param {ol.expr.Logical} filter The filter to retrieve the sub filters from.
* @param {Array.<ol.expr.Expression>} subFilters The sub filters retrieved.
* @private
*/
ol.parser.ogc.Filter_v1.prototype.getSubfiltersForLogical_ = function(filter,
subFilters) {
var operator = filter.getOperator();
var filters = new Array(2);
filters[0] = filter.getLeft();
filters[1] = filter.getRight();
for (var i = 0; i < 2; ++i) {
if (filters[i] instanceof ol.expr.Logical && filters[i].getOperator() ===
operator) {
this.getSubfiltersForLogical_(filters[i], subFilters);
} else {
subFilters.push(filters[i]);
}
}
};
/**
* Since ol.expr.Logical can only have a left and a right, we need to nest
* sub filters coming from OGC Filter.
* @param {Array.<ol.expr.Expression>} filters The filters to aggregate.
* @param {ol.expr.LogicalOp} operator The logical operator to use.
* @return {ol.expr.Logical} The logical filter created.
* @private
*/
ol.parser.ogc.Filter_v1.prototype.aggregateLogical_ = function(filters,
operator) {
var subFilters = [];
var newFilters = [];
// we only need to do this if we have more than 2 items
if (filters.length > 2) {
while (filters.length) {
subFilters.push(filters.pop());
if (subFilters.length === 2) {
newFilters.push(new ol.expr.Logical(operator,
subFilters[0], subFilters[1]));
subFilters.length = 0;
}
}
// there could be a single item left now
if (subFilters.length === 1) {
newFilters.push(subFilters[0]);
}
return this.aggregateLogical_(newFilters, operator);
} else {
return new ol.expr.Logical(operator, filters[0], filters[1]);
}
};
/**
* @param {ol.parser.ogc.GML_v2|ol.parser.ogc.GML_v3} gml The GML parser to
* use.
* @protected
*/
ol.parser.ogc.Filter_v1.prototype.setGmlParser = function(gml) {
this.gml_ = gml;
for (var uri in this.gml_.readers) {
for (var key in this.gml_.readers[uri]) {
if (!goog.isDef(this.readers[uri])) {
this.readers[uri] = {};
}
this.readers[uri][key] = goog.bind(this.gml_.readers[uri][key],
this.gml_);
}
}
for (uri in this.gml_.writers) {
for (key in this.gml_.writers[uri]) {
if (!goog.isDef(this.writers[uri])) {
this.writers[uri] = {};
}
this.writers[uri][key] = goog.bind(this.gml_.writers[uri][key],
this.gml_);
}
}
};

View File

@@ -0,0 +1,184 @@
goog.provide('ol.parser.ogc.Filter_v1_0_0');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.expr');
goog.require('ol.expr.Call');
goog.require('ol.expr.Comparison');
goog.require('ol.expr.ComparisonOp');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Literal');
goog.require('ol.expr.functions');
goog.require('ol.geom.Geometry');
goog.require('ol.parser.ogc.Filter_v1');
goog.require('ol.parser.ogc.GML_v2');
/**
* @constructor
* @extends {ol.parser.ogc.Filter_v1}
*/
ol.parser.ogc.Filter_v1_0_0 = function() {
goog.base(this);
this.version = '1.0.0';
this.schemaLocation = 'http://www.opengis.net/ogc ' +
'http://schemas.opengis.net/filter/1.0.0/filter.xsd';
goog.object.extend(this.readers['http://www.opengis.net/ogc'], {
'PropertyIsEqualTo': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.EQ,
container.property,
container.value));
},
'PropertyIsNotEqualTo': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.filters.push(new ol.expr.Comparison(
ol.expr.ComparisonOp.NEQ,
container.property,
container.value));
},
'PropertyIsLike': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
var args = [];
args.push(container.property, container.value,
new ol.expr.Literal(node.getAttribute('wildCard')),
new ol.expr.Literal(node.getAttribute('singleChar')),
new ol.expr.Literal(node.getAttribute('escape')));
obj.filters.push(new ol.expr.Call(
new ol.expr.Identifier(ol.expr.functions.LIKE), args));
}
});
goog.object.extend(this.writers['http://www.opengis.net/ogc'], {
'PropertyIsEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsEqualTo');
var property = filter.getLeft();
this.writeNode('PropertyName', property, null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsNotEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsNotEqualTo');
var property = filter.getLeft();
this.writeNode('PropertyName', property, null, node);
this.writeOgcExpression(filter.getRight(), node);
return node;
},
'PropertyIsLike': function(filter) {
var node = this.createElementNS('ogc:PropertyIsLike');
var args = filter.getArgs();
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
node.setAttribute('wildCard', args[2].getValue());
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
node.setAttribute('singleChar', args[3].getValue());
goog.asserts.assert(args[4] instanceof ol.expr.Literal);
node.setAttribute('escape', args[4].getValue());
var property = args[0];
if (goog.isDef(property)) {
this.writeNode('PropertyName', property, null, node);
}
this.writeNode('Literal', args[1], null, node);
return node;
},
'BBOX': function(filter) {
var node = this.createElementNS('ogc:BBOX');
var args = filter.getArgs();
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
goog.asserts.assert(args[1] instanceof ol.expr.Literal);
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
goog.asserts.assert(args[4] instanceof ol.expr.Literal);
var bbox = [
args[0].getValue(), args[1].getValue(),
args[2].getValue(), args[3].getValue()
];
var projection = args[4].getValue();
var property = args[5];
// PropertyName is mandatory in 1.0.0, but e.g. GeoServer also
// accepts filters without it.
if (goog.isDefAndNotNull(property)) {
this.writeNode('PropertyName', property, null, node);
}
var box = this.writeNode('Box', bbox,
'http://www.opengis.net/gml');
if (goog.isDefAndNotNull(projection)) {
box.setAttribute('srsName', projection);
}
node.appendChild(box);
return node;
}
});
this.setGmlParser(new ol.parser.ogc.GML_v2({featureNS: 'http://foo'}));
};
goog.inherits(ol.parser.ogc.Filter_v1_0_0,
ol.parser.ogc.Filter_v1);
/**
* @param {ol.expr.Call} filter The filter to write out.
* @param {string} name The name of the spatial operator.
* @return {Element} The node created.
* @private
*/
ol.parser.ogc.Filter_v1_0_0.prototype.writeSpatial_ = function(filter, name) {
var node = this.createElementNS('ogc:' + name);
var args = filter.getArgs();
var property, geom = null, bbox, call, projection;
if (args[0] instanceof ol.expr.Literal && goog.isNumber(args[0].getValue())) {
goog.asserts.assert(args[1] instanceof ol.expr.Literal);
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
bbox = [
args[0].getValue(), args[1].getValue(),
args[2].getValue(), args[3].getValue()
];
projection = args[4];
property = args[5];
} else if (args[0] instanceof ol.expr.Literal &&
args[0].getValue() instanceof ol.geom.Geometry) {
geom = args[0].getValue();
if (name === 'DWithin') {
projection = args[3];
property = args[4];
} else {
projection = args[1];
property = args[2];
}
} else if (args[0] instanceof ol.expr.Call) {
call = args[0];
if (name === 'DWithin') {
projection = args[3];
property = args[4];
} else {
projection = args[1];
property = args[2];
}
}
if (goog.isDefAndNotNull(property)) {
this.writeNode('PropertyName', property, null, node);
}
if (goog.isDef(call)) {
this.writeNode('Function', call, null, node);
} else {
var child;
if (geom !== null) {
child = this.writeNode('_geometry', geom,
this.gml_.featureNS).firstChild;
} else if (bbox.length === 4) {
child = this.writeNode('Box', bbox,
'http://www.opengis.net/gml');
}
if (goog.isDef(child)) {
goog.asserts.assert(projection instanceof ol.expr.Literal);
if (goog.isDefAndNotNull(projection.getValue())) {
child.setAttribute('srsName', projection.getValue());
}
node.appendChild(child);
}
}
return node;
};

View File

@@ -0,0 +1,242 @@
goog.provide('ol.parser.ogc.Filter_v1_1_0');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.expr');
goog.require('ol.expr.Call');
goog.require('ol.expr.Comparison');
goog.require('ol.expr.ComparisonOp');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Literal');
goog.require('ol.expr.functions');
goog.require('ol.geom.Geometry');
goog.require('ol.parser.ogc.Filter_v1');
goog.require('ol.parser.ogc.GML_v3');
/**
* @constructor
* @extends {ol.parser.ogc.Filter_v1}
*/
ol.parser.ogc.Filter_v1_1_0 = function() {
goog.base(this);
this.version = '1.1.0';
this.schemaLocation = 'http://www.opengis.net/ogc ' +
'http://schemas.opengis.net/filter/1.1.0/filter.xsd';
goog.object.extend(this.readers['http://www.opengis.net/ogc'], {
'PropertyIsEqualTo': function(node, obj) {
var matchCase = node.getAttribute('matchCase');
var container = {}, filter;
this.readChildNodes(node, container);
if (matchCase === 'false' || matchCase === '0') {
filter = new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.IEQ),
[container.property, container.value]);
} else {
filter = new ol.expr.Comparison(
ol.expr.ComparisonOp.EQ,
container.property,
container.value);
}
obj.filters.push(filter);
},
'PropertyIsNotEqualTo': function(node, obj) {
var matchCase = node.getAttribute('matchCase');
var container = {}, filter;
this.readChildNodes(node, container);
if (matchCase === 'false' || matchCase === '0') {
filter = new ol.expr.Call(new ol.expr.Identifier(
ol.expr.functions.INEQ),
[container.property, container.value]);
} else {
filter = new ol.expr.Comparison(
ol.expr.ComparisonOp.NEQ,
container.property,
container.value);
}
obj.filters.push(filter);
},
'PropertyIsLike': function(node, obj) {
var container = {};
this.readChildNodes(node, container);
var args = [];
args.push(container.property, container.value,
new ol.expr.Literal(node.getAttribute('wildCard')),
new ol.expr.Literal(node.getAttribute('singleChar')),
new ol.expr.Literal(node.getAttribute('escapeChar')),
new ol.expr.Literal(node.getAttribute('matchCase')));
obj.filters.push(new ol.expr.Call(
new ol.expr.Identifier(ol.expr.functions.LIKE), args));
}
});
goog.object.extend(this.writers['http://www.opengis.net/ogc'], {
'PropertyIsEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsEqualTo');
var property, value;
if (filter instanceof ol.expr.Call) {
var args = filter.getArgs();
property = args[0];
value = args[1];
node.setAttribute('matchCase', false);
} else {
property = filter.getLeft();
value = filter.getRight();
}
this.writeNode('PropertyName', property, null, node);
this.writeOgcExpression(value, node);
return node;
},
'PropertyIsNotEqualTo': function(filter) {
var node = this.createElementNS('ogc:PropertyIsNotEqualTo');
var property, value;
if (filter instanceof ol.expr.Call) {
var args = filter.getArgs();
property = args[0];
value = args[1];
node.setAttribute('matchCase', false);
} else {
property = filter.getLeft();
value = filter.getRight();
}
this.writeNode('PropertyName', property, null, node);
this.writeOgcExpression(value, node);
return node;
},
'PropertyIsLike': function(filter) {
var node = this.createElementNS('ogc:PropertyIsLike');
var args = filter.getArgs();
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
goog.asserts.assert(args[4] instanceof ol.expr.Literal);
node.setAttribute('wildCard', args[2].getValue());
node.setAttribute('singleChar', args[3].getValue());
node.setAttribute('escapeChar', args[4].getValue());
if (goog.isDefAndNotNull(args[5])) {
goog.asserts.assert(args[5] instanceof ol.expr.Literal);
node.setAttribute('matchCase', args[5].getValue());
}
var property = args[0];
if (goog.isDef(property)) {
this.writeNode('PropertyName', property, null, node);
}
this.writeNode('Literal', args[1], null, node);
return node;
},
'BBOX': function(filter) {
var node = this.createElementNS('ogc:BBOX');
var args = filter.getArgs();
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
goog.asserts.assert(args[1] instanceof ol.expr.Literal);
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
goog.asserts.assert(args[4] instanceof ol.expr.Literal);
var bbox = [
args[0].getValue(), args[1].getValue(),
args[2].getValue(), args[3].getValue()
];
var projection = args[4].getValue();
var property = args[5];
// PropertyName is optional in 1.1.0
if (goog.isDefAndNotNull(property)) {
this.writeNode('PropertyName', property, null, node);
}
var box = this.writeNode('Envelope', bbox,
'http://www.opengis.net/gml');
if (goog.isDefAndNotNull(projection)) {
box.setAttribute('srsName', projection);
}
node.appendChild(box);
return node;
},
'SortBy': function(sortProperties) {
var node = this.createElementNS('ogc:SortBy');
for (var i = 0, l = sortProperties.length; i < l; i++) {
this.writeNode('SortProperty', sortProperties[i], null, node);
}
return node;
},
'SortProperty': function(sortProperty) {
var node = this.createElementNS('ogc:SortProperty');
this.writeNode('PropertyName', sortProperty['property'], null, node);
goog.asserts.assert(sortProperty['order'] instanceof ol.expr.Literal);
this.writeNode('SortOrder',
(sortProperty['order'].getValue() == 'DESC') ? 'DESC' : 'ASC', null,
node);
return node;
},
'SortOrder': function(value) {
var node = this.createElementNS('ogc:SortOrder');
node.appendChild(this.createTextNode(value));
return node;
}
});
this.setGmlParser(new ol.parser.ogc.GML_v3());
};
goog.inherits(ol.parser.ogc.Filter_v1_1_0,
ol.parser.ogc.Filter_v1);
/**
* @param {ol.expr.Call} filter The filter to write out.
* @param {string} name The name of the spatial operator.
* @return {Element} The node created.
* @private
*/
ol.parser.ogc.Filter_v1_1_0.prototype.writeSpatial_ = function(filter, name) {
var node = this.createElementNS('ogc:' + name);
var args = filter.getArgs();
var property, geom = null, bbox, call, projection;
if (args[0] instanceof ol.expr.Literal && goog.isNumber(args[0].getValue())) {
goog.asserts.assert(args[1] instanceof ol.expr.Literal);
goog.asserts.assert(args[2] instanceof ol.expr.Literal);
goog.asserts.assert(args[3] instanceof ol.expr.Literal);
bbox = [
args[0].getValue(), args[1].getValue(),
args[2].getValue(), args[3].getValue()
];
projection = args[4];
property = args[5];
} else if (args[0] instanceof ol.expr.Literal &&
args[0].getValue() instanceof ol.geom.Geometry) {
geom = args[0].getValue();
if (name === 'DWithin') {
projection = args[3];
property = args[4];
} else {
projection = args[1];
property = args[2];
}
} else if (args[0] instanceof ol.expr.Call) {
call = args[0];
if (name === 'DWithin') {
projection = args[3];
property = args[4];
} else {
projection = args[1];
property = args[2];
}
}
if (goog.isDefAndNotNull(property)) {
this.writeNode('PropertyName', property, null, node);
}
if (goog.isDef(call)) {
this.writeNode('Function', call, null, node);
} else {
var child;
if (geom !== null) {
child = this.writeNode('_geometry', geom,
this.gml_.featureNS).firstChild;
} else if (bbox.length === 4) {
child = this.writeNode('Envelope', bbox,
'http://www.opengis.net/gml');
}
if (goog.isDef(child)) {
goog.asserts.assert(projection instanceof ol.expr.Literal);
if (goog.isDefAndNotNull(projection.getValue())) {
child.setAttribute('srsName', projection.getValue());
}
node.appendChild(child);
}
}
return node;
};

View File

@@ -0,0 +1,6 @@
@exportSymbol ol.parser.ogc.GML_v2
@exportProperty ol.parser.ogc.GML_v2.prototype.read
@exportProperty ol.parser.ogc.GML_v2.prototype.write
@exportSymbol ol.parser.ogc.GML_v3
@exportProperty ol.parser.ogc.GML_v3.prototype.read
@exportProperty ol.parser.ogc.GML_v3.prototype.write

View File

@@ -0,0 +1,641 @@
goog.provide('ol.parser.ogc.GML');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.xml');
goog.require('ol.Feature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.StringFeatureParser');
goog.require('ol.parser.XML');
goog.require('ol.proj');
/**
* @constructor
* @implements {ol.parser.StringFeatureParser}
* @param {ol.parser.GMLOptions=} opt_options
* Optional configuration object.
* @extends {ol.parser.XML}
*/
ol.parser.ogc.GML = function(opt_options) {
var options = /** @type {ol.parser.GMLOptions} */
(goog.isDef(opt_options) ? opt_options : {});
this.extractAttributes = goog.isDef(options.extractAttributes) ?
options.extractAttributes : true;
this.surface = goog.isDef(options.surface) ?
options.surface : false;
this.curve = goog.isDef(options.curve) ?
options.curve : false;
this.multiCurve = goog.isDef(options.multiCurve) ?
options.multiCurve : true;
this.multiSurface = goog.isDef(options.multiSurface) ?
options.multiSurface : true;
this.readOptions = options.readOptions;
this.writeOptions = options.writeOptions;
/**
* @protected
* @type {string|undefined}
*/
this.srsName;
/**
* @protected
* @type {string|undefined}
*/
this.axisOrientation;
if (goog.isDef(options.schemaLocation)) {
this.schemaLocation = options.schemaLocation;
}
if (goog.isDef(options.featureNS)) {
this.featureNS = options.featureNS;
}
if (goog.isDef(options.featureType)) {
this.featureType = options.featureType;
}
this.singleFeatureType = !goog.isDef(opt_options) ||
goog.isString(opt_options.featureType);
this.defaultNamespaceURI = 'http://www.opengis.net/gml';
this.readers = {
'http://www.opengis.net/wfs': {
'FeatureCollection': function(node, obj) {
this.readChildNodes(node, obj);
}
},
'http://www.opengis.net/gml': {
'_inherit': function(node, obj, container) {
// Version specific parsers extend this with goog.functions.sequence
var srsName;
if (!goog.isDef(this.srsName)) {
srsName = this.srsName = node.getAttribute('srsName');
}
if (!goog.isDef(this.axisOrientation)) {
if (goog.isDefAndNotNull(srsName)) {
this.axisOrientation = ol.proj.get(srsName).getAxisOrientation();
} else {
this.axisOrientation = 'enu';
}
}
},
'name': function(node, obj) {
obj.name = this.getChildValue(node);
},
'featureMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'featureMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'GeometryCollection': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.GEOMETRYCOLLECTION,
parts: parts
};
},
'geometryMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'MultiPoint': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTIPOINT,
parts: parts
};
},
'pointMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'MultiLineString': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTILINESTRING,
parts: parts
};
},
'lineStringMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'MultiPolygon': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTIPOLYGON,
parts: parts
};
},
'polygonMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'Point': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
var point = {
type: ol.geom.GeometryType.POINT,
coordinates: coordinates[0][0]
};
// in the case of a multi geometry this is parts
if (goog.isArray(container)) {
container.push(point);
} else {
container.geometry = point;
}
},
'LineString': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
var linestring = {
type: ol.geom.GeometryType.LINESTRING,
coordinates: coordinates[0]
};
// in the case of a multi geometry this is parts
if (goog.isArray(container)) {
container.push(linestring);
} else {
container.geometry = linestring;
}
},
'Polygon': function(node, container) {
var obj = {outer: null, inner: []};
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, obj, container]);
this.readChildNodes(node, obj);
obj.inner.unshift(obj.outer);
var polygon = {
type: ol.geom.GeometryType.POLYGON,
coordinates: obj.inner
};
// in the case of a multi geometry this is parts
if (goog.isArray(container)) {
container.push(polygon);
} else {
container.geometry = polygon;
}
},
'LinearRing': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
if (goog.isArray(container)) {
container.push(coordinates);
} else {
container.geometry = {
type: ol.geom.GeometryType.LINEARRING,
coordinates: coordinates[0]
};
}
},
'coordinates': function(node, coordinates) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
str = str.replace(this.regExes.trimComma, ',');
var coords;
var cs = node.getAttribute('cs') || ',';
var ts = node.getAttribute('ts') || this.regExes.splitSpace;
var pointList = str.split(ts);
var numPoints = pointList.length;
var points = new Array(numPoints);
for (var i = 0; i < numPoints; ++i) {
coords = goog.array.map(pointList[i].split(cs), parseFloat);
if (this.axisOrientation.substr(0, 2) === 'en') {
points[i] = coords;
} else {
if (coords.length === 2) {
points[i] = coords.reverse();
} else if (coords.length === 3) {
points[i] = [coords[1], coords[0], coords[2]];
}
}
}
coordinates.push(points);
},
'coord': function(node, coordinates) {
var coord = {};
if (coordinates.length === 0) {
coordinates.push([]);
}
this.readChildNodes(node, coord);
if (goog.isDef(coord.z)) {
coordinates.push([coord.x, coord.y, coord.z]);
} else {
coordinates[0].push([coord.x, coord.y]);
}
},
'X': function(node, coord) {
coord.x = parseFloat(this.getChildValue(node));
},
'Y': function(node, coord) {
coord.y = parseFloat(this.getChildValue(node));
},
'Z': function(node, coord) {
coord.z = parseFloat(this.getChildValue(node));
}
}
};
this.featureNSReaders_ = {
'*': function(node, obj) {
// The node can either be named like the featureType, or it
// can be a child of the feature:featureType. Children can be
// geometry or attributes.
var name;
var local = node.localName || node.nodeName.split(':').pop();
// Since an attribute can have the same name as the feature type
// we only want to read the node as a feature if the parent
// node can have feature nodes as children. In this case, the
// obj.features property is set.
if (obj.features) {
if (!this.singleFeatureType &&
(goog.array.indexOf(this.featureType, local) !== -1)) {
name = '_typeName';
} else if (local === this.featureType) {
name = '_typeName';
}
} else {
// Assume attribute elements have one child node and that the child
// is a text node. Otherwise assume it is a geometry node.
if (node.childNodes.length === 0 ||
(node.childNodes.length === 1 &&
node.firstChild.nodeType === 3)) {
if (this.extractAttributes) {
name = '_attribute';
}
} else {
name = '_geometry';
}
}
if (name) {
this.readers[this.featureNS][name].apply(this, [node, obj]);
}
},
'_typeName': function(node, obj) {
var container = {properties: {}};
this.readChildNodes(node, container);
// look for common gml namespaced elements
if (container.name) {
container.properties.name = container.name;
}
var feature = new ol.Feature(container.properties);
var geom = container.geometry;
if (geom) {
var geometry = this.createGeometry({geometry: geom});
if (goog.isDef(geometry)) {
feature.setGeometry(geometry);
}
}
// TODO set feature.type and feature.namespace
var fid = node.getAttribute('fid') ||
this.getAttributeNS(node, this.defaultNamespaceURI, 'id');
if (!goog.isNull(fid)) {
feature.setId(fid);
}
obj.features.push(feature);
},
'_geometry': function(node, obj) {
if (!this.geometryName) {
this.geometryName = node.nodeName.split(':').pop();
}
this.readChildNodes(node, obj);
},
'_attribute': function(node, obj) {
var local = node.localName || node.nodeName.split(':').pop();
var value = this.getChildValue(node);
obj.properties[local] = value;
}
};
if (goog.isDef(this.featureNS)) {
this.readers[this.featureNS] = this.featureNSReaders_;
}
this.writers = {
'http://www.opengis.net/gml': {
'featureMember': function(obj) {
var node = this.createElementNS('gml:featureMember');
this.writeNode('_typeName', obj, this.featureNS, node);
return node;
},
'MultiPoint': function(geometry) {
var node = this.createElementNS('gml:MultiPoint');
var components = geometry.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
this.writeNode('pointMember', components[i], null, node);
}
return node;
},
'pointMember': function(geometry) {
var node = this.createElementNS('gml:pointMember');
this.writeNode('Point', geometry, null, node);
return node;
},
'MultiLineString': function(geometry) {
var node = this.createElementNS('gml:MultiLineString');
var components = geometry.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
this.writeNode('lineStringMember', components[i], null, node);
}
return node;
},
'lineStringMember': function(geometry) {
var node = this.createElementNS('gml:lineStringMember');
this.writeNode('LineString', geometry, null, node);
return node;
},
'MultiPolygon': function(geometry) {
var node = this.createElementNS('gml:MultiPolygon');
var components = geometry.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
this.writeNode('polygonMember', components[i], null, node);
}
return node;
},
'polygonMember': function(geometry) {
var node = this.createElementNS('gml:polygonMember');
this.writeNode('Polygon', geometry, null, node);
return node;
},
'GeometryCollection': function(geometry) {
var node = this.createElementNS('gml:GeometryCollection');
var components = geometry.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
this.writeNode('geometryMember', components[i], null, node);
}
return node;
},
'geometryMember': function(geometry) {
var node = this.createElementNS('gml:geometryMember');
var child = this.writeNode('_geometry', geometry, this.featureNS);
node.appendChild(child.firstChild);
return node;
}
},
'http://www.opengis.net/wfs': {
'FeatureCollection': function(features) {
/**
* This is only here because GML2 only describes abstract
* feature collections. Typically, you would not be using
* the GML format to write wfs elements. This just provides
* some way to write out lists of features. GML3 defines the
* featureMembers element, so that is used by default instead.
*/
var node = this.createElementNS('wfs:FeatureCollection',
'http://www.opengis.net/wfs');
for (var i = 0, ii = features.length; i < ii; ++i) {
this.writeNode('featureMember', features[i], null, node);
}
return node;
}
}
};
this.featureNSWiters_ = {
'_typeName': function(feature) {
var node = this.createElementNS('feature:' + this.featureType,
this.featureNS);
var fid = feature.getId();
if (goog.isDef(fid)) {
this.setAttributeNS(node, this.defaultNamespaceURI, 'fid', fid);
}
if (feature.getGeometry() !== null) {
this.writeNode('_geometry', feature.getGeometry(), this.featureNS,
node);
}
var attributes = feature.getAttributes(true);
for (var name in attributes) {
var value = attributes[name];
if (goog.isDefAndNotNull(value)) {
this.writeNode('_attribute', {name: name, value: value},
this.featureNS, node);
}
}
return node;
},
'_geometry': function(geometry) {
var node = this.createElementNS('feature:' + this.geometryName,
this.featureNS);
var type = geometry.getType(), child;
if (type === ol.geom.GeometryType.POINT) {
child = this.writeNode('Point', geometry, null, node);
} else if (type === ol.geom.GeometryType.MULTIPOINT) {
child = this.writeNode('MultiPoint', geometry, null, node);
} else if (type === ol.geom.GeometryType.LINEARRING) {
child = this.writeNode('LinearRing', geometry.getCoordinates(), null,
node);
} else if (type === ol.geom.GeometryType.LINESTRING) {
child = this.writeNode('LineString', geometry, null, node);
} else if (type === ol.geom.GeometryType.MULTILINESTRING) {
child = this.writeNode('MultiLineString', geometry, null, node);
} else if (type === ol.geom.GeometryType.POLYGON) {
child = this.writeNode('Polygon', geometry, null, node);
} else if (type === ol.geom.GeometryType.MULTIPOLYGON) {
child = this.writeNode('MultiPolygon', geometry, null, node);
} else if (type === ol.geom.GeometryType.GEOMETRYCOLLECTION) {
child = this.writeNode('GeometryCollection', geometry, null, node);
}
if (goog.isDefAndNotNull(this.srsName)) {
this.setAttributeNS(child, null, 'srsName', this.srsName);
}
return node;
},
'_attribute': function(obj) {
var node = this.createElementNS('feature:' + obj.name, this.featureNS);
node.appendChild(this.createTextNode(obj.value));
return node;
}
};
if (goog.isDef(this.featureNS)) {
this.writers[this.featureNS] = this.featureNSWiters_;
}
goog.base(this);
};
goog.inherits(ol.parser.ogc.GML, ol.parser.XML);
/**
* @param {string|Document|Element|Object} data Data to read.
* @param {ol.parser.GMLReadOptions=} opt_options Read options.
* @return {ol.parser.ReadFeaturesResult} An object representing the document.
*/
ol.parser.ogc.GML.prototype.read = function(data, opt_options) {
var srsName;
if (goog.isDef(opt_options) && goog.isDef(opt_options.srsName)) {
srsName = opt_options.srsName;
} else if (goog.isDef(this.readOptions) &&
goog.isDef(this.readOptions.srsName)) {
srsName = this.readOptions.srsName;
}
if (goog.isDef(srsName)) {
this.srsName = goog.isString(srsName) ? srsName : srsName.getCode();
}
if (goog.isDef(opt_options) && goog.isDef(opt_options.axisOrientation)) {
this.axisOrientation = opt_options.axisOrientation;
} else if (goog.isDef(this.readOptions) &&
goog.isDef(this.readOptions.axisOrientation)) {
this.axisOrientation = this.readOptions.axisOrientation;
}
if (typeof data == 'string') {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({features: [], metadata: {}});
this.readNode(data, obj, true);
obj.metadata.projection = this.srsName;
delete this.srsName;
delete this.axisOrientation;
return obj;
};
/**
* @param {Element|Document} node The node to be read.
* @param {Object} obj The object to be modified.
* @param {boolean=} opt_first Should be set to true for the first node read.
* This is usually the readNode call in the read method. Without this being
* set, auto-configured properties will stick on subsequent reads.
* @return {Object} The input object, modified (or a new one if none was
* provided).
*/
ol.parser.ogc.GML.prototype.readNode = function(node, obj, opt_first) {
// on subsequent calls of this.read(), we want to reset auto-
// configured properties and auto-configure again.
if (opt_first === true && this.autoConfig === true) {
this.featureType = null;
delete this.readers[this.featureNS];
delete this.writers[this.featureNS];
this.featureNS = null;
}
// featureType auto-configuration
if (!this.featureNS && (!(node.namespaceURI in this.readers) &&
node.parentNode.namespaceURI == this.defaultNamespaceURI &&
(/^(.*:)?featureMembers?$/).test(node.parentNode.nodeName))) {
this.featureType = node.nodeName.split(':').pop();
this.readers[node.namespaceURI] = this.featureNSReaders_;
this.writers[node.namespaceURI] = this.featureNSWiters_;
this.featureNS = node.namespaceURI;
this.autoConfig = true;
}
return ol.parser.XML.prototype.readNode.apply(this, [node, obj]);
};
/**
* @param {Object} container Geometry container.
* @return {ol.geom.Geometry} The geometry created.
*/
// TODO use a mixin since this is also used in the KML parser
ol.parser.ogc.GML.prototype.createGeometry = function(container) {
var geometry = null, coordinates, i, ii;
switch (container.geometry.type) {
case ol.geom.GeometryType.POINT:
geometry = new ol.geom.Point(container.geometry.coordinates);
break;
case ol.geom.GeometryType.LINEARRING:
geometry = new ol.geom.LinearRing(container.geometry.coordinates);
break;
case ol.geom.GeometryType.LINESTRING:
geometry = new ol.geom.LineString(container.geometry.coordinates);
break;
case ol.geom.GeometryType.POLYGON:
geometry = new ol.geom.Polygon(container.geometry.coordinates);
break;
case ol.geom.GeometryType.MULTIPOINT:
coordinates = [];
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
coordinates.push(container.geometry.parts[i].coordinates);
}
geometry = new ol.geom.MultiPoint(coordinates);
break;
case ol.geom.GeometryType.MULTILINESTRING:
coordinates = [];
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
coordinates.push(container.geometry.parts[i].coordinates);
}
geometry = new ol.geom.MultiLineString(coordinates);
break;
case ol.geom.GeometryType.MULTIPOLYGON:
coordinates = [];
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
coordinates.push(container.geometry.parts[i].coordinates);
}
geometry = new ol.geom.MultiPolygon(coordinates);
break;
case ol.geom.GeometryType.GEOMETRYCOLLECTION:
var geometries = [];
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
geometries.push(this.createGeometry({
geometry: container.geometry.parts[i]
}));
}
geometry = new ol.geom.GeometryCollection(geometries);
break;
default:
break;
}
return geometry;
};
/**
* Parse a GML document provided as a string.
* @param {string} str GML document.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.ogc.GML.prototype.readFeaturesFromString = function(str) {
return this.read(str);
};
/**
* Applies the writeOptions passed into the write function.
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* GML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
*/
ol.parser.ogc.GML.prototype.applyWriteOptions = function(obj, opt_options) {
// srsName handling: opt_options -> this.writeOptions -> obj.metadata
var srsName;
if (goog.isDef(opt_options) && goog.isDef(opt_options.srsName)) {
srsName = opt_options.srsName;
} else if (goog.isDef(this.writeOptions) &&
goog.isDef(this.writeOptions.srsName)) {
srsName = this.writeOptions.srsName;
} else if (goog.isDef(obj.metadata)) {
srsName = obj.metadata.projection;
}
goog.asserts.assert(goog.isDef(srsName), 'srsName required for writing GML');
this.srsName = goog.isString(srsName) ? srsName : srsName.getCode();
// axisOrientation handling: opt_options -> this.writeOptions
if (goog.isDef(opt_options) && goog.isDef(opt_options.axisOrientation)) {
this.axisOrientation = opt_options.axisOrientation;
} else if (goog.isDef(this.writeOptions) &&
goog.isDef(this.writeOptions.axisOrientation)) {
this.axisOrientation = this.writeOptions.axisOrientation;
} else {
this.axisOrientation = ol.proj.get(this.srsName).getAxisOrientation();
}
};

View File

@@ -0,0 +1,144 @@
goog.provide('ol.parser.ogc.GML_v2');
goog.require('goog.array');
goog.require('goog.object');
goog.require('ol.parser.ogc.GML');
/**
* Read and write [GML](http://www.opengeospatial.org/standards/gml)
* version 2.1.2
*
* @constructor
* @param {ol.parser.GMLOptions=} opt_options Optional configuration object.
* @extends {ol.parser.ogc.GML}
* @todo stability experimental
*/
ol.parser.ogc.GML_v2 = function(opt_options) {
this.schemaLocation = 'http://www.opengis.net/gml ' +
'http://schemas.opengis.net/gml/2.1.2/feature.xsd';
goog.base(this, opt_options);
goog.object.extend(this.readers['http://www.opengis.net/gml'], {
'outerBoundaryIs': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container['outer'] = coordinates[0][0];
},
'innerBoundaryIs': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.inner.push(coordinates[0][0]);
},
'Box': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
container.projection = node.getAttribute('srsName');
container.bounds = [
coordinates[0][0][0], coordinates[0][0][1],
coordinates[0][1][0], coordinates[0][1][1]
];
}
});
goog.object.extend(this.writers['http://www.opengis.net/gml'], {
'Point': function(geometry) {
var node = this.createElementNS('gml:Point');
this.writeNode('coordinates', [geometry.getCoordinates()], null, node);
return node;
},
'coordinates': function(coordinates) {
var numCoordinates = coordinates.length;
var parts = new Array(numCoordinates);
for (var i = 0; i < numCoordinates; ++i) {
var coord = coordinates[i];
var part = goog.array.concat(coord);
if (this.axisOrientation.substr(0, 2) !== 'en') {
part[0] = coord[1];
part[1] = coord[0];
}
parts[i] = part.join(',');
}
var value = parts.join(' ');
var node = this.createElementNS('gml:coordinates');
this.setAttributeNS(node, null, 'decimal', '.');
this.setAttributeNS(node, null, 'cs', ',');
this.setAttributeNS(node, null, 'ts', ' ');
node.appendChild(this.createTextNode(value));
return node;
},
'LineString': function(geometry) {
var node = this.createElementNS('gml:LineString');
this.writeNode('coordinates', geometry.getCoordinates(), null, node);
return node;
},
'Polygon': function(geometry) {
var node = this.createElementNS('gml:Polygon');
var coordinates = geometry.getCoordinates();
/**
* Though there continues to be ambiguity around this, GML references
* ISO 19107, which says polygons have counter-clockwise exterior rings
* and clockwise interior rings. The ambiguity comes because the
* the Simple Feature Access - SQL spec (ISO 19125-2) says that no
* winding order is enforced. Anyway, we write out counter-clockwise
* exterior and clockwise interior here but accept either when reading.
*/
this.writeNode('outerBoundaryIs', coordinates[0].reverse(), null, node);
for (var i = 1; i < coordinates.length; ++i) {
this.writeNode('innerBoundaryIs', coordinates[i].reverse(), null, node);
}
return node;
},
'outerBoundaryIs': function(ring) {
var node = this.createElementNS('gml:outerBoundaryIs');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'innerBoundaryIs': function(ring) {
var node = this.createElementNS('gml:innerBoundaryIs');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'LinearRing': function(ring) {
var node = this.createElementNS('gml:LinearRing');
this.writeNode('coordinates', ring, null, node);
return node;
},
'Box': function(extent) {
var node = this.createElementNS('gml:Box');
var coordinates = [
[extent[0], extent[1]],
[extent[2], extent[3]]
];
this.writeNode('coordinates', coordinates, null, node);
// srsName attribute is optional for gml:Box
if (goog.isDefAndNotNull(this.srsName)) {
node.setAttribute('srsName', this.srsName);
}
return node;
}
});
};
goog.inherits(ol.parser.ogc.GML_v2, ol.parser.ogc.GML);
/**
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* GML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
* @return {string} A string representing the GML document.
* @todo stability experimental
*/
ol.parser.ogc.GML_v2.prototype.write = function(obj, opt_options) {
this.applyWriteOptions(obj, opt_options);
var root = this.writeNode('FeatureCollection', obj.features,
'http://www.opengis.net/wfs');
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
var gml = this.serialize(root);
delete this.srsName;
delete this.axisOrientation;
return gml;
};

View File

@@ -0,0 +1,441 @@
goog.provide('ol.parser.ogc.GML_v3');
goog.require('goog.array');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('ol.geom.GeometryType');
goog.require('ol.parser.ogc.GML');
/**
* Read and write [GML](http://www.opengeospatial.org/standards/gml)
* version 3.1.1
*
* @constructor
* @param {ol.parser.GMLOptions=} opt_options Optional configuration object.
* @extends {ol.parser.ogc.GML}
* @todo stability experimental
*/
ol.parser.ogc.GML_v3 = function(opt_options) {
this.schemaLocation = 'http://www.opengis.net/gml ' +
'http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' +
'1.0.0/gmlsf.xsd';
goog.base(this, opt_options);
this.featureNSWiters_['_geometry'] = function(geometry) {
var node = this.createElementNS('feature:' + this.geometryName,
this.featureNS);
var type = geometry.getType(), child;
if (type === ol.geom.GeometryType.POINT) {
child = this.writeNode('Point', geometry, null, node);
} else if (type === ol.geom.GeometryType.MULTIPOINT) {
child = this.writeNode('MultiPoint', geometry, null, node);
} else if (type === ol.geom.GeometryType.LINESTRING) {
if (this.curve === true) {
child = this.writeNode('Curve', geometry, null, node);
} else {
child = this.writeNode('LineString', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.LINEARRING) {
child = this.writeNode('LinearRing', geometry.getCoordinates(), null,
node);
} else if (type === ol.geom.GeometryType.MULTILINESTRING) {
if (this.multiCurve === false) {
child = this.writeNode('MultiLineString', geometry, null, node);
} else {
child = this.writeNode('MultiCurve', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.POLYGON) {
if (this.surface === true) {
child = this.writeNode('Surface', geometry, null, node);
} else {
child = this.writeNode('Polygon', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.MULTIPOLYGON) {
if (this.multiSurface === false) {
child = this.writeNode('MultiPolygon', geometry, null, node);
} else {
child = this.writeNode('MultiSurface', geometry, null, node);
}
} else if (type === ol.geom.GeometryType.GEOMETRYCOLLECTION) {
child = this.writeNode('MultiGeometry', geometry, null, node);
}
if (goog.isDefAndNotNull(this.srsName)) {
this.setAttributeNS(child, null, 'srsName', this.srsName);
}
return node;
};
goog.object.extend(this.readers['http://www.opengis.net/gml'], {
'_inherit': goog.functions.sequence(
this.readers['http://www.opengis.net/gml']['_inherit'],
function(node, obj, container) {
// SRSReferenceGroup attributes
var dim = parseInt(node.getAttribute('srsDimension'), 10) ||
(container && container.srsDimension);
if (dim) {
obj.srsDimension = dim;
}
}),
'featureMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'Curve': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
var linestring = {
type: ol.geom.GeometryType.LINESTRING,
coordinates: coordinates[0]
};
// in the case of a multi geometry this is parts
if (goog.isArray(container)) {
container.push(linestring);
} else {
container.geometry = linestring;
}
},
'segments': function(node, obj) {
this.readChildNodes(node, obj);
},
'LineStringSegment': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.push(coordinates[0]);
},
'pos': function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
var coords = goog.array.map(str.split(this.regExes.splitSpace),
parseFloat);
if (this.axisOrientation.substr(0, 2) === 'en') {
obj.push([coords]);
} else {
if (coords.length === 2) {
obj.push([coords.reverse()]);
} else if (coords.length === 3) {
obj.push([[coords[1], coords[0], coords[2]]]);
}
}
},
'posList': function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
var coords = str.split(this.regExes.splitSpace);
// The "dimension" attribute is from the GML 3.0.1 spec.
var dim = obj.srsDimension ||
parseInt(node.getAttribute('srsDimension') ||
node.getAttribute('dimension'), 10) || 2;
var x, y, z;
var numPoints = coords.length / dim;
var points = new Array(numPoints);
for (var i = 0, ii = coords.length; i < ii; i += dim) {
x = parseFloat(coords[i]);
y = parseFloat(coords[i + 1]);
var xy = this.axisOrientation.substr(0, 2) === 'en';
if (dim === 3) {
if (xy) {
points[i / dim] = [x, y, parseFloat(coords[i + 2])];
} else {
points[i / dim] = [y, x, parseFloat(coords[i + 2])];
}
} else if (dim === 2) {
if (xy) {
points[i / dim] = [x, y];
} else {
points[i / dim] = [y, x];
}
}
}
obj.push(points);
},
'Surface': function(node, obj) {
this.readChildNodes(node, obj);
},
'patches': function(node, obj) {
this.readChildNodes(node, obj);
},
'PolygonPatch': function(node, obj) {
this.readers[this.defaultNamespaceURI]['Polygon'].apply(this,
[node, obj]);
},
'exterior': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.outer = coordinates[0][0];
},
'interior': function(node, container) {
var coordinates = [];
this.readChildNodes(node, coordinates);
container.inner.push(coordinates[0][0]);
},
'MultiCurve': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTILINESTRING,
parts: parts
};
},
'curveMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'MultiSurface': function(node, container) {
var parts = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, parts, container]);
this.readChildNodes(node, parts);
container.geometry = {
type: ol.geom.GeometryType.MULTIPOLYGON,
parts: parts
};
},
'surfaceMember': function(node, obj) {
this.readChildNodes(node, obj);
},
'surfaceMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'pointMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'lineStringMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'polygonMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'geometryMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
'Envelope': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
container.projection = node.getAttribute('srsName');
container.bounds = [
coordinates[0][0], coordinates[0][1],
coordinates[1][0], coordinates[1][1]
];
},
'lowerCorner': function(node, envelope) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['pos'].apply(this,
[node, coordinates]);
envelope.push(coordinates[0][0]);
},
'upperCorner': function(node, envelope) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['pos'].apply(this,
[node, coordinates]);
envelope.push(coordinates[0][0]);
}
});
goog.object.extend(this.writers['http://www.opengis.net/gml'], {
'featureMembers': function(features) {
var node = this.createElementNS('gml:featureMembers');
for (var i = 0, ii = features.length; i < ii; ++i) {
this.writeNode('_typeName', features[i], this.featureNS, node);
}
return node;
},
'Point': function(geometry) {
var node = this.createElementNS('gml:Point');
this.writeNode('pos', geometry.getCoordinates(), null, node);
return node;
},
'pos': function(point) {
// only 2d for simple features profile
var pos;
if (this.axisOrientation.substr(0, 2) === 'en') {
pos = (point[0] + ' ' + point[1]);
} else {
pos = (point[1] + ' ' + point[0]);
}
var node = this.createElementNS('gml:pos');
node.appendChild(this.createTextNode(pos));
return node;
},
'LineString': function(geometry) {
var node = this.createElementNS('gml:LineString');
this.writeNode('posList', geometry.getCoordinates(), null, node);
return node;
},
'Curve': function(geometry) {
var node = this.createElementNS('gml:Curve');
this.writeNode('segments', geometry, null, node);
return node;
},
'segments': function(geometry) {
var node = this.createElementNS('gml:segments');
this.writeNode('LineStringSegment', geometry, null, node);
return node;
},
'LineStringSegment': function(geometry) {
var node = this.createElementNS('gml:LineStringSegment');
this.writeNode('posList', geometry.getCoordinates(), null, node);
return node;
},
'posList': function(points) {
// only 2d for simple features profile
var len = points.length;
var parts = new Array(len);
var point;
for (var i = 0; i < len; ++i) {
point = points[i];
if (this.axisOrientation.substr(0, 2) === 'en') {
parts[i] = point[0] + ' ' + point[1];
} else {
parts[i] = point[1] + ' ' + point[0];
}
}
var node = this.createElementNS('gml:posList');
node.appendChild(this.createTextNode(parts.join(' ')));
return node;
},
'Surface': function(geometry) {
var node = this.createElementNS('gml:Surface');
this.writeNode('patches', geometry, null, node);
return node;
},
'patches': function(geometry) {
var node = this.createElementNS('gml:patches');
this.writeNode('PolygonPatch', geometry, null, node);
return node;
},
'PolygonPatch': function(geometry) {
var node = this.createElementNS('gml:PolygonPatch');
node.setAttribute('interpolation', 'planar');
var coordinates = geometry.getCoordinates();
this.writeNode('exterior', coordinates[0].reverse(), null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i].reverse(), null, node);
}
return node;
},
'Polygon': function(geometry) {
var node = this.createElementNS('gml:Polygon');
var coordinates = geometry.getCoordinates();
/**
* Though there continues to be ambiguity around this, GML references
* ISO 19107, which says polygons have counter-clockwise exterior rings
* and clockwise interior rings. The ambiguity comes because the
* the Simple Feature Access - SQL spec (ISO 19125-2) says that no
* winding order is enforced. Anyway, we write out counter-clockwise
* exterior and clockwise interior here but accept either when reading.
*/
this.writeNode('exterior', coordinates[0].reverse(), null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i].reverse(), null, node);
}
return node;
},
'exterior': function(ring) {
var node = this.createElementNS('gml:exterior');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'interior': function(ring) {
var node = this.createElementNS('gml:interior');
this.writeNode('LinearRing', ring, null, node);
return node;
},
'LinearRing': function(ring) {
var node = this.createElementNS('gml:LinearRing');
this.writeNode('posList', ring, null, node);
return node;
},
'MultiCurve': function(geometry) {
var node = this.createElementNS('gml:MultiCurve');
var components = geometry.getComponents();
for (var i = 0, len = components.length; i < len; ++i) {
this.writeNode('curveMember', components[i], null, node);
}
return node;
},
'curveMember': function(geometry) {
var node = this.createElementNS('gml:curveMember');
if (this.curve) {
this.writeNode('Curve', geometry, null, node);
} else {
this.writeNode('LineString', geometry, null, node);
}
return node;
},
'MultiSurface': function(geometry) {
var node = this.createElementNS('gml:MultiSurface');
var components = geometry.getComponents();
for (var i = 0, len = components.length; i < len; ++i) {
this.writeNode('surfaceMember', components[i], null, node);
}
return node;
},
'surfaceMember': function(polygon) {
var node = this.createElementNS('gml:surfaceMember');
if (this.surface) {
this.writeNode('Surface', polygon, null, node);
} else {
this.writeNode('Polygon', polygon, null, node);
}
return node;
},
'Envelope': function(bounds) {
var node = this.createElementNS('gml:Envelope');
this.writeNode('lowerCorner', bounds, null, node);
this.writeNode('upperCorner', bounds, null, node);
// srsName attribute is required for gml:Envelope
if (goog.isDef(this.srsName)) {
node.setAttribute('srsName', this.srsName);
}
return node;
},
'lowerCorner': function(bounds) {
// only 2d for simple features profile
var pos;
if (this.axisOrientation.substr(0, 2) === 'en') {
pos = (bounds[0] + ' ' + bounds[1]);
} else {
pos = (bounds[1] + ' ' + bounds[0]);
}
var node = this.createElementNS('gml:lowerCorner');
node.appendChild(this.createTextNode(pos));
return node;
},
'upperCorner': function(bounds) {
// only 2d for simple features profile
var pos;
if (this.axisOrientation.substr(0, 2) === 'en') {
pos = (bounds[2] + ' ' + bounds[3]);
} else {
pos = (bounds[3] + ' ' + bounds[2]);
}
var node = this.createElementNS('gml:upperCorner');
node.appendChild(this.createTextNode(pos));
return node;
}
});
};
goog.inherits(ol.parser.ogc.GML_v3, ol.parser.ogc.GML);
/**
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* XML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
* @return {string} An string representing the XML document.
* @todo stability experimental
*/
ol.parser.ogc.GML_v3.prototype.write = function(obj, opt_options) {
this.applyWriteOptions(obj, opt_options);
var root = this.writeNode('featureMembers', obj.features);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
var gml = this.serialize(root);
delete this.srsName;
delete this.axisOrientation;
return gml;
};

View File

@@ -0,0 +1,214 @@
goog.provide('ol.parser.ogc.OWSCommon_v1');
goog.require('ol.parser.XML');
/**
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.OWSCommon_v1 = function() {
this.readers = {
'http://www.opengis.net/ows': {
'ServiceIdentification': function(node, obj) {
obj['serviceIdentification'] = {};
this.readChildNodes(node, obj['serviceIdentification']);
},
'Title': function(node, obj) {
obj['title'] = this.getChildValue(node);
},
'Abstract': function(node, serviceIdentification) {
serviceIdentification['abstract'] = this.getChildValue(node);
},
'Keywords': function(node, serviceIdentification) {
serviceIdentification['keywords'] = {};
this.readChildNodes(node, serviceIdentification['keywords']);
},
'Keyword': function(node, keywords) {
keywords[this.getChildValue(node)] = true;
},
'ServiceType': function(node, serviceIdentification) {
serviceIdentification['serviceType'] = {
'codeSpace': node.getAttribute('codeSpace'),
'value': this.getChildValue(node)};
},
'ServiceTypeVersion': function(node, serviceIdentification) {
serviceIdentification['serviceTypeVersion'] = this.getChildValue(node);
},
'Fees': function(node, serviceIdentification) {
serviceIdentification['fees'] = this.getChildValue(node);
},
'AccessConstraints': function(node, serviceIdentification) {
serviceIdentification['accessConstraints'] =
this.getChildValue(node);
},
'ServiceProvider': function(node, obj) {
obj['serviceProvider'] = {};
this.readChildNodes(node, obj['serviceProvider']);
},
'ProviderName': function(node, serviceProvider) {
serviceProvider['providerName'] = this.getChildValue(node);
},
'ProviderSite': function(node, serviceProvider) {
serviceProvider['providerSite'] = this.getAttributeNS(node,
'http://www.w3.org/1999/xlink', 'href');
},
'ServiceContact': function(node, serviceProvider) {
serviceProvider['serviceContact'] = {};
this.readChildNodes(node, serviceProvider['serviceContact']);
},
'IndividualName': function(node, serviceContact) {
serviceContact['individualName'] = this.getChildValue(node);
},
'PositionName': function(node, serviceContact) {
serviceContact['positionName'] = this.getChildValue(node);
},
'ContactInfo': function(node, serviceContact) {
serviceContact['contactInfo'] = {};
this.readChildNodes(node, serviceContact['contactInfo']);
},
'Phone': function(node, contactInfo) {
contactInfo['phone'] = {};
this.readChildNodes(node, contactInfo['phone']);
},
'Voice': function(node, phone) {
phone['voice'] = this.getChildValue(node);
},
'Address': function(node, contactInfo) {
contactInfo['address'] = {};
this.readChildNodes(node, contactInfo['address']);
},
'DeliveryPoint': function(node, address) {
address['deliveryPoint'] = this.getChildValue(node);
},
'City': function(node, address) {
address['city'] = this.getChildValue(node);
},
'AdministrativeArea': function(node, address) {
address['administrativeArea'] = this.getChildValue(node);
},
'PostalCode': function(node, address) {
address['postalCode'] = this.getChildValue(node);
},
'Country': function(node, address) {
address['country'] = this.getChildValue(node);
},
'ElectronicMailAddress': function(node, address) {
address['electronicMailAddress'] = this.getChildValue(node);
},
'Role': function(node, serviceContact) {
serviceContact['role'] = this.getChildValue(node);
},
'OperationsMetadata': function(node, obj) {
obj['operationsMetadata'] = {};
this.readChildNodes(node, obj['operationsMetadata']);
},
'Operation': function(node, operationsMetadata) {
var name = node.getAttribute('name');
operationsMetadata[name] = {};
this.readChildNodes(node, operationsMetadata[name]);
},
'DCP': function(node, operation) {
operation['dcp'] = {};
this.readChildNodes(node, operation['dcp']);
},
'HTTP': function(node, dcp) {
dcp['http'] = {};
this.readChildNodes(node, dcp['http']);
},
'Get': function(node, http) {
if (!http['get']) {
http['get'] = [];
}
var obj = {
'url': this.getAttributeNS(node, 'http://www.w3.org/1999/xlink',
'href')
};
this.readChildNodes(node, obj);
http['get'].push(obj);
},
'Post': function(node, http) {
if (!http['post']) {
http['post'] = [];
}
var obj = {
'url': this.getAttributeNS(node, 'http://www.w3.org/1999/xlink',
'href')
};
this.readChildNodes(node, obj);
http['post'].push(obj);
},
'Parameter': function(node, operation) {
if (!operation['parameters']) {
operation['parameters'] = {};
}
var name = node.getAttribute('name');
operation['parameters'][name] = {};
this.readChildNodes(node, operation['parameters'][name]);
},
'Constraint': function(node, obj) {
if (!obj['constraints']) {
obj['constraints'] = {};
}
var name = node.getAttribute('name');
obj['constraints'][name] = {};
this.readChildNodes(node, obj['constraints'][name]);
},
'Value': function(node, allowedValues) {
allowedValues[this.getChildValue(node)] = true;
},
'OutputFormat': function(node, obj) {
obj['formats'].push({'value': this.getChildValue(node)});
this.readChildNodes(node, obj);
},
'WGS84BoundingBox': function(node, obj) {
var boundingBox = {};
boundingBox['crs'] = node.getAttribute('crs');
if (obj['BoundingBox']) {
obj['BoundingBox'].push(boundingBox);
} else {
obj['projection'] = boundingBox['crs'];
boundingBox = obj;
}
this.readChildNodes(node, boundingBox);
},
'BoundingBox': function(node, obj) {
// FIXME: We consider that BoundingBox is the same as WGS84BoundingBox
// LowerCorner = "min_x min_y"
// UpperCorner = "max_x max_y"
// It should normally depend on the projection
var readers = this.readers[node.namespaceURI];
readers['WGS84BoundingBox'].apply(this, [node, obj]);
},
'LowerCorner': function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
str = str.replace(this.regExes.trimComma, ',');
var pointList = str.split(this.regExes.splitSpace);
obj['left'] = pointList[0];
obj['bottom'] = pointList[1];
},
'UpperCorner': function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, '');
str = str.replace(this.regExes.trimComma, ',');
var pointList = str.split(this.regExes.splitSpace);
obj['right'] = pointList[0];
obj['top'] = pointList[1];
obj['bounds'] = [
parseFloat(obj['left']), parseFloat(obj['right']),
parseFloat(obj['bottom']), parseFloat(obj['top'])
];
delete obj['left'];
delete obj['bottom'];
delete obj['right'];
delete obj['top'];
},
'Language': function(node, obj) {
obj['language'] = this.getChildValue(node);
}
}
};
goog.base(this);
};
goog.inherits(ol.parser.ogc.OWSCommon_v1, ol.parser.XML);

View File

@@ -0,0 +1,45 @@
goog.provide('ol.parser.ogc.OWSCommon_v1_1_0');
goog.require('goog.object');
goog.require('ol.parser.ogc.OWSCommon_v1');
/**
* @constructor
* @extends {ol.parser.ogc.OWSCommon_v1}
*/
ol.parser.ogc.OWSCommon_v1_1_0 = function() {
goog.base(this);
this.readers['http://www.opengis.net/ows/1.1'] =
this.readers['http://www.opengis.net/ows'];
goog.object.extend(this.readers['http://www.opengis.net/ows/1.1'], {
'AllowedValues': function(node, parameter) {
parameter['allowedValues'] = {};
this.readChildNodes(node, parameter['allowedValues']);
},
'AnyValue': function(node, parameter) {
parameter['anyValue'] = true;
},
'DataType': function(node, parameter) {
parameter['dataType'] = this.getChildValue(node);
},
'Range': function(node, allowedValues) {
allowedValues['range'] = {};
this.readChildNodes(node, allowedValues['range']);
},
'MinimumValue': function(node, range) {
range['minValue'] = this.getChildValue(node);
},
'MaximumValue': function(node, range) {
range['maxValue'] = this.getChildValue(node);
},
'Identifier': function(node, obj) {
obj['identifier'] = this.getChildValue(node);
},
'SupportedCRS': function(node, obj) {
obj['supportedCRS'] = this.getChildValue(node);
}
});
};
goog.inherits(ol.parser.ogc.OWSCommon_v1_1_0,
ol.parser.ogc.OWSCommon_v1);

View File

@@ -0,0 +1,121 @@
goog.provide('ol.parser.ogc.Versioned');
goog.require('goog.dom.xml');
goog.require('ol.parser.ogc.ExceptionReport');
/**
* @constructor
* @param {Object=} opt_options Options which will be set on this object.
*/
ol.parser.ogc.Versioned = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
this.options = options;
this.defaultVersion = options.defaultVersion || null;
this.version = options.version;
this.profile = options.profile;
if (goog.isDef(options.allowFallback)) {
this.allowFallback = options.allowFallback;
} else {
this.allowFallback = false;
}
if (goog.isDef(options.stringifyOutput)) {
this.stringifyOutput = options.stringifyOutput;
} else {
this.stringifyOutput = false;
}
};
/**
* @param {Element} root root element.
* @param {Object=} opt_options optional configuration object.
* @return {string} the version to use.
*/
ol.parser.ogc.Versioned.prototype.getVersion = function(root, opt_options) {
var version;
// read
if (root) {
version = this.version;
if (!version) {
version = root.getAttribute('version');
if (!version) {
version = this.defaultVersion;
}
}
} else {
// write
version = (opt_options && opt_options.version) ||
this.version || this.defaultVersion;
}
return version;
};
/**
* @param {string} version the version to use.
* @return {Object} the parser to use.
*/
ol.parser.ogc.Versioned.prototype.getParser = function(version) {
version = version || this.defaultVersion;
var profile = this.profile ? '_' + this.profile : '';
if (!this.parser || this.parser.VERSION != version) {
var format = this.parsers['v' + version.replace(/\./g, '_') + profile];
if (!format) {
if (profile !== '' && this.allowFallback) {
// fallback to the non-profiled version of the parser
profile = '';
format = this.parsers['v' + version.replace(/\./g, '_') + profile];
}
if (!format) {
throw 'Can\'t find a parser for version ' +
version + profile;
}
}
this.parser = new format(this.options);
}
return this.parser;
};
/**
* Write a document.
*
* @param {Object} obj An object representing the document.
* @param {Object=} opt_options Optional configuration object.
* @return {Element|string} the XML created.
*/
ol.parser.ogc.Versioned.prototype.write = function(obj, opt_options) {
var version = this.getVersion(null, opt_options);
this.parser = this.getParser(version);
var root = this.parser.write(obj, opt_options);
if (this.stringifyOutput === false) {
return root;
} else {
return goog.dom.xml.serialize(root);
}
};
/**
* @param {string|Document} data Data to read.
* @param {Object=} opt_options Options for the reader.
* @return {Object} An object representing the document.
*/
ol.parser.ogc.Versioned.prototype.read = function(data, opt_options) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
var root = data.documentElement;
var version = this.getVersion(root);
this.parser = this.getParser(version);
var obj = this.parser.read(data, opt_options);
var errorProperty = this.parser.errorProperty || null;
if (errorProperty !== null && obj[errorProperty] === undefined) {
// an error must have happened, so parse it and report back
var format = new ol.parser.ogc.ExceptionReport();
obj.error = format.read(data);
}
obj.version = version;
return obj;
};

View File

@@ -0,0 +1,2 @@
@exportSymbol ol.parser.ogc.WMSCapabilities
@exportProperty ol.parser.ogc.WMSCapabilities.prototype.read

View File

@@ -0,0 +1,69 @@
goog.provide('ol.parser.ogc.WMSCapabilities');
goog.require('ol.parser.ogc.Versioned');
goog.require('ol.parser.ogc.WMSCapabilities_v1_0_0');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1_0');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1_1');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1_1_WMSC');
goog.require('ol.parser.ogc.WMSCapabilities_v1_3_0');
/**
* @define {boolean} Whether to enable WMS Capabilities version 1.0.0.
*/
ol.ENABLE_WMSCAPS_1_0_0 = false;
/**
* @define {boolean} Whether to enable WMS Capabilities version 1.1.0.
*/
ol.ENABLE_WMSCAPS_1_1_0 = true;
/**
* @define {boolean} Whether to enable WMS Capabilities version 1.1.1.
*/
ol.ENABLE_WMSCAPS_1_1_1 = true;
/**
* @define {boolean} Whether to enable WMS Capabilities version 1.3.0.
*/
ol.ENABLE_WMSCAPS_1_3_0 = true;
/**
* @define {boolean} Whether to enable WMS Capabilities version 1.1.1.
* WMSC profile.
*/
ol.ENABLE_WMSCAPS_1_1_1_WMSC = true;
/**
* @constructor
* @param {Object=} opt_options Options which will be set on this object.
* @extends {ol.parser.ogc.Versioned}
* @todo stability experimental
*/
ol.parser.ogc.WMSCapabilities = function(opt_options) {
opt_options = opt_options || {};
opt_options['defaultVersion'] = '1.1.1';
this.parsers = {};
if (ol.ENABLE_WMSCAPS_1_0_0) {
this.parsers['v1_0_0'] = ol.parser.ogc.WMSCapabilities_v1_0_0;
}
if (ol.ENABLE_WMSCAPS_1_1_0) {
this.parsers['v1_1_0'] = ol.parser.ogc.WMSCapabilities_v1_1_0;
}
if (ol.ENABLE_WMSCAPS_1_1_1) {
this.parsers['v1_1_1'] = ol.parser.ogc.WMSCapabilities_v1_1_1;
}
if (ol.ENABLE_WMSCAPS_1_1_1_WMSC) {
this.parsers['v1_1_1_WMSC'] = ol.parser.ogc.WMSCapabilities_v1_1_1_WMSC;
}
if (ol.ENABLE_WMSCAPS_1_3_0) {
this.parsers['v1_3_0'] = ol.parser.ogc.WMSCapabilities_v1_3_0;
}
goog.base(this, opt_options);
};
goog.inherits(ol.parser.ogc.WMSCapabilities, ol.parser.ogc.Versioned);

View File

@@ -0,0 +1,317 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1');
goog.require('goog.dom.xml');
goog.require('goog.object');
goog.require('ol.parser.XML');
/**
* Read [WMS](http://www.opengeospatial.org/standards/wms) capabilities
*
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.WMSCapabilities_v1 = function() {
this.defaultNamespaceURI = 'http://www.opengis.net/wms';
this.errorProperty = 'service';
this.readers = {
'http://www.opengis.net/wms': {
'Service': function(node, obj) {
obj['service'] = {};
this.readChildNodes(node, obj['service']);
},
'Name': function(node, obj) {
obj['name'] = this.getChildValue(node);
},
'Title': function(node, obj) {
obj['title'] = this.getChildValue(node);
},
'Abstract': function(node, obj) {
obj['abstract'] = this.getChildValue(node);
},
'BoundingBox': function(node, obj) {
var bbox = {};
bbox['bbox'] = [
parseFloat(node.getAttribute('minx')),
parseFloat(node.getAttribute('miny')),
parseFloat(node.getAttribute('maxx')),
parseFloat(node.getAttribute('maxy'))
];
var res = {
x: parseFloat(node.getAttribute('resx')),
y: parseFloat(node.getAttribute('resy'))
};
if (! (isNaN(res.x) && isNaN(res.y))) {
bbox['res'] = res;
}
// return the bbox so that descendant classes can set the
// CRS and SRS and add it to the obj
return bbox;
},
'OnlineResource': function(node, obj) {
obj['href'] = this.getAttributeNS(node, 'http://www.w3.org/1999/xlink',
'href');
},
'ContactInformation': function(node, obj) {
obj['contactInformation'] = {};
this.readChildNodes(node, obj['contactInformation']);
},
'ContactPersonPrimary': function(node, obj) {
obj['personPrimary'] = {};
this.readChildNodes(node, obj['personPrimary']);
},
'ContactPerson': function(node, obj) {
obj['person'] = this.getChildValue(node);
},
'ContactOrganization': function(node, obj) {
obj['organization'] = this.getChildValue(node);
},
'ContactPosition': function(node, obj) {
obj['position'] = this.getChildValue(node);
},
'ContactAddress': function(node, obj) {
obj['contactAddress'] = {};
this.readChildNodes(node, obj['contactAddress']);
},
'AddressType': function(node, obj) {
obj['type'] = this.getChildValue(node);
},
'Address': function(node, obj) {
obj['address'] = this.getChildValue(node);
},
'City': function(node, obj) {
obj['city'] = this.getChildValue(node);
},
'StateOrProvince': function(node, obj) {
obj['stateOrProvince'] = this.getChildValue(node);
},
'PostCode': function(node, obj) {
obj['postcode'] = this.getChildValue(node);
},
'Country': function(node, obj) {
obj['country'] = this.getChildValue(node);
},
'ContactVoiceTelephone': function(node, obj) {
obj['phone'] = this.getChildValue(node);
},
'ContactFacsimileTelephone': function(node, obj) {
obj['fax'] = this.getChildValue(node);
},
'ContactElectronicMailAddress': function(node, obj) {
obj['email'] = this.getChildValue(node);
},
'Fees': function(node, obj) {
var fees = this.getChildValue(node);
if (fees && fees.toLowerCase() != 'none') {
obj['fees'] = fees;
}
},
'AccessConstraints': function(node, obj) {
var constraints = this.getChildValue(node);
if (constraints && constraints.toLowerCase() != 'none') {
obj['accessConstraints'] = constraints;
}
},
'Capability': function(node, obj) {
obj['capability'] = {};
obj['capability']['nestedLayers'] = [];
obj['capability']['layers'] = [];
this.readChildNodes(node, obj['capability']);
},
'Request': function(node, obj) {
obj['request'] = {};
this.readChildNodes(node, obj['request']);
},
'GetCapabilities': function(node, obj) {
obj['getcapabilities'] = {};
obj['getcapabilities']['formats'] = [];
this.readChildNodes(node, obj['getcapabilities']);
},
'Format': function(node, obj) {
if (goog.isArray(obj['formats'])) {
obj['formats'].push(this.getChildValue(node));
} else {
obj['format'] = this.getChildValue(node);
}
},
'DCPType': function(node, obj) {
this.readChildNodes(node, obj);
},
'HTTP': function(node, obj) {
this.readChildNodes(node, obj);
},
'Get': function(node, obj) {
obj['get'] = {};
this.readChildNodes(node, obj['get']);
},
'Post': function(node, obj) {
obj['post'] = {};
this.readChildNodes(node, obj['post']);
},
'GetMap': function(node, obj) {
obj['getmap'] = {};
obj['getmap']['formats'] = [];
this.readChildNodes(node, obj['getmap']);
},
'GetFeatureInfo': function(node, obj) {
obj['getfeatureinfo'] = {};
obj['getfeatureinfo']['formats'] = [];
this.readChildNodes(node, obj['getfeatureinfo']);
},
'Exception': function(node, obj) {
obj['exception'] = {};
obj['exception']['formats'] = [];
this.readChildNodes(node, obj['exception']);
},
'Layer': function(node, obj) {
var parentLayer, capability;
if (obj['capability']) {
capability = obj['capability'];
parentLayer = obj;
} else {
capability = obj;
}
var attrNode = node.getAttributeNode('queryable');
var queryable = (attrNode && attrNode.specified) ?
node.getAttribute('queryable') : null;
attrNode = node.getAttributeNode('cascaded');
var cascaded = (attrNode && attrNode.specified) ?
node.getAttribute('cascaded') : null;
attrNode = node.getAttributeNode('opaque');
var opaque = (attrNode && attrNode.specified) ?
node.getAttribute('opaque') : null;
var noSubsets = node.getAttribute('noSubsets');
var fixedWidth = node.getAttribute('fixedWidth');
var fixedHeight = node.getAttribute('fixedHeight');
var parent = parentLayer || {};
var layer = {
'nestedLayers': [],
'styles': parentLayer ? [].concat(parentLayer['styles']) : [],
'srs': {},
'metadataURLs': [],
'bbox': {},
'llbbox': parent['llbbox'],
'dimensions': {},
'authorityURLs': {},
'identifiers': {},
'keywords': [],
'queryable': (queryable && queryable !== '') ?
(queryable === '1' || queryable === 'true') :
(parent['queryable'] || false),
'cascaded': (cascaded !== null) ? parseInt(cascaded, 10) :
(parent['cascaded'] || 0),
'opaque': opaque ?
(opaque === '1' || opaque === 'true') :
(parent['opaque'] || false),
'noSubsets': (noSubsets !== null) ?
(noSubsets === '1' || noSubsets === 'true') :
(parent['noSubsets'] || false),
'fixedWidth': (fixedWidth !== null) ?
parseInt(fixedWidth, 10) : (parent['fixedWidth'] || 0),
'fixedHeight': (fixedHeight !== null) ?
parseInt(fixedHeight, 10) : (parent['fixedHeight'] || 0),
'minScale': parent['minScale'],
'maxScale': parent['maxScale'],
'attribution': parent['attribution']
};
if (parentLayer) {
goog.object.extend(layer['srs'], parent['srs']);
goog.object.extend(layer['bbox'], parent['bbox']);
goog.object.extend(layer['dimensions'], parent['dimensions']);
goog.object.extend(layer['authorityURLs'], parent['authorityURLs']);
}
obj['nestedLayers'].push(layer);
layer['capability'] = capability;
this.readChildNodes(node, layer);
delete layer['capability'];
if (layer['name']) {
var parts = layer['name'].split(':'),
request = capability['request'],
gfi = request['getfeatureinfo'];
if (parts.length > 0) {
layer['prefix'] = parts[0];
}
capability['layers'].push(layer);
if (!goog.isDef(layer['formats'])) {
layer['formats'] = request['getmap']['formats'];
}
if (!goog.isDef(layer['infoFormats']) && gfi) {
layer['infoFormats'] = gfi['formats'];
}
}
},
'Attribution': function(node, obj) {
obj['attribution'] = {};
this.readChildNodes(node, obj['attribution']);
},
'LogoURL': function(node, obj) {
obj['logo'] = {
'width': node.getAttribute('width'),
'height': node.getAttribute('height')
};
this.readChildNodes(node, obj['logo']);
},
'Style': function(node, obj) {
var style = {};
obj['styles'].push(style);
this.readChildNodes(node, style);
},
'LegendURL': function(node, obj) {
var legend = {
'width': node.getAttribute('width'),
'height': node.getAttribute('height')
};
obj['legend'] = legend;
this.readChildNodes(node, legend);
},
'MetadataURL': function(node, obj) {
var metadataURL = {'type': node.getAttribute('type')};
obj['metadataURLs'].push(metadataURL);
this.readChildNodes(node, metadataURL);
},
'DataURL': function(node, obj) {
obj['dataURL'] = {};
this.readChildNodes(node, obj['dataURL']);
},
'FeatureListURL': function(node, obj) {
obj['featureListURL'] = {};
this.readChildNodes(node, obj['featureListURL']);
},
'AuthorityURL': function(node, obj) {
var name = node.getAttribute('name');
var authority = {};
this.readChildNodes(node, authority);
obj['authorityURLs'][name] = authority['href'];
},
'Identifier': function(node, obj) {
var authority = node.getAttribute('authority');
obj['identifiers'][authority] = this.getChildValue(node);
},
'KeywordList': function(node, obj) {
this.readChildNodes(node, obj);
},
'SRS': function(node, obj) {
obj['srs'][this.getChildValue(node)] = true;
}
}
};
goog.base(this);
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1, ol.parser.XML);
/**
* @param {string|Document|Element} data Data to read.
* @return {Object} An object representing the document.
*/
ol.parser.ogc.WMSCapabilities_v1.prototype.read = function(data) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {};
this.readNode(data, obj);
return obj;
};

View File

@@ -0,0 +1,66 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_0_0');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1_0');
/**
* Read [WMS](http://www.opengeospatial.org/standards/wms) capabilities
* version 1.0.0
*
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1_1_0}
*/
ol.parser.ogc.WMSCapabilities_v1_0_0 = function() {
goog.base(this);
this.version = '1.0.0';
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'Format': function(node, obj) {
for (var i = 0, ii = node.childNodes.length; i < ii; i++) {
var child = node.childNodes[i];
var local = child.localName || child.nodeName.split(':').pop();
if (goog.isArray(obj['formats'])) {
obj['formats'].push(local);
} else {
obj['format'] = local;
}
}
},
'Keywords': function(node, obj) {
if (!goog.isDef(obj['keywords'])) {
obj['keywords'] = [];
}
var keywords = this.getChildValue(node).split(/ +/);
for (var i = 0, ii = keywords.length; i < ii; ++i) {
if (!goog.string.isEmpty(keywords[i])) {
obj['keywords'].push({'value': keywords[i]});
}
}
},
'OnlineResource': function(node, obj) {
obj['href'] = this.getChildValue(node);
},
'Get': function(node, obj) {
obj['get'] = {'href': node.getAttribute('onlineResource')};
},
'Post': function(node, obj) {
obj['post'] = {'href': node.getAttribute('onlineResource')};
},
'Map': function(node, obj) {
var reader = this.readers[this.defaultNamespaceURI]['GetMap'];
reader.apply(this, arguments);
},
'Capabilities': function(node, obj) {
var reader = this.readers[this.defaultNamespaceURI]['GetCapabilities'];
reader.apply(this, arguments);
},
'FeatureInfo': function(node, obj) {
var reader = this.readers[this.defaultNamespaceURI]['GetFeatureInfo'];
reader.apply(this, arguments);
}
});
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_0_0,
ol.parser.ogc.WMSCapabilities_v1_1_0);

View File

@@ -0,0 +1,101 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_1');
goog.require('goog.object');
goog.require('ol.parser.ogc.WMSCapabilities_v1');
/**
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1}
*/
ol.parser.ogc.WMSCapabilities_v1_1 = function() {
goog.base(this);
var bboxreader = this.readers['http://www.opengis.net/wms']['BoundingBox'];
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'WMT_MS_Capabilities': function(node, obj) {
this.readChildNodes(node, obj);
},
'Keyword': function(node, obj) {
if (obj['keywords']) {
obj['keywords'].push({'value': this.getChildValue(node)});
}
},
'DescribeLayer': function(node, obj) {
obj['describelayer'] = {'formats': []};
this.readChildNodes(node, obj['describelayer']);
},
'GetLegendGraphic': function(node, obj) {
obj['getlegendgraphic'] = {'formats': []};
this.readChildNodes(node, obj['getlegendgraphic']);
},
'GetStyles': function(node, obj) {
obj['getstyles'] = {'formats': []};
this.readChildNodes(node, obj['getstyles']);
},
'PutStyles': function(node, obj) {
obj['putstyles'] = {'formats': []};
this.readChildNodes(node, obj['putstyles']);
},
'UserDefinedSymbolization': function(node, obj) {
var userSymbols = {
'supportSLD': parseInt(node.getAttribute('SupportSLD'), 10) == 1,
'userLayer': parseInt(node.getAttribute('UserLayer'), 10) == 1,
'userStyle': parseInt(node.getAttribute('UserStyle'), 10) == 1,
'remoteWFS': parseInt(node.getAttribute('RemoteWFS'), 10) == 1
};
obj['userSymbols'] = userSymbols;
},
'LatLonBoundingBox': function(node, obj) {
obj['llbbox'] = [
parseFloat(node.getAttribute('minx')),
parseFloat(node.getAttribute('miny')),
parseFloat(node.getAttribute('maxx')),
parseFloat(node.getAttribute('maxy'))
];
},
'BoundingBox': function(node, obj) {
var bbox = bboxreader.apply(this, arguments);
bbox['srs'] = node.getAttribute('SRS');
obj['bbox'][bbox['srs']] = bbox;
},
'ScaleHint': function(node, obj) {
var min = parseFloat(node.getAttribute('min'));
var max = parseFloat(node.getAttribute('max'));
var rad2 = Math.pow(2, 0.5);
var dpi = (25.4 / 0.28);
var ipm = 39.37;
if (min !== 0) {
obj['maxScale'] = parseFloat((min / rad2) * ipm * dpi);
}
if (max != Infinity) {
obj['minScale'] = parseFloat((max / rad2) * ipm * dpi);
}
},
'Dimension': function(node, obj) {
var name = node.getAttribute('name').toLowerCase();
var dim = {
'name': name,
'units': node.getAttribute('units'),
'unitsymbol': node.getAttribute('unitSymbol')
};
obj['dimensions'][dim.name] = dim;
},
'Extent': function(node, obj) {
var name = node.getAttribute('name').toLowerCase();
if (name in obj['dimensions']) {
var extent = obj['dimensions'][name];
extent['nearestVal'] =
node.getAttribute('nearestValue') === '1';
extent['multipleVal'] =
node.getAttribute('multipleValues') === '1';
extent['current'] = node.getAttribute('current') === '1';
extent['default'] = node.getAttribute('default') || '';
var values = this.getChildValue(node);
extent['values'] = values.split(',');
}
}
});
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_1,
ol.parser.ogc.WMSCapabilities_v1);

View File

@@ -0,0 +1,29 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_1_0');
goog.require('goog.object');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1');
/**
* Read [WMS](http://www.opengeospatial.org/standards/wms) capabilities
* version 1.1.0
*
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1_1}
*/
ol.parser.ogc.WMSCapabilities_v1_1_0 = function() {
goog.base(this);
this.version = '1.1.0';
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'SRS': function(node, obj) {
var srs = this.getChildValue(node);
var values = srs.split(/ +/);
for (var i = 0, ii = values.length; i < ii; i++) {
obj['srs'][values[i]] = true;
}
}
});
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_1_0,
ol.parser.ogc.WMSCapabilities_v1_1);

View File

@@ -0,0 +1,25 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_1_1');
goog.require('goog.object');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1');
/**
* Read [WMS](http://www.opengeospatial.org/standards/wms) capabilities
* version 1.1.1
*
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1_1}
*/
ol.parser.ogc.WMSCapabilities_v1_1_1 = function() {
goog.base(this);
this.version = '1.1.1';
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'SRS': function(node, obj) {
obj['srs'][this.getChildValue(node)] = true;
}
});
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_1_1,
ol.parser.ogc.WMSCapabilities_v1_1);

View File

@@ -0,0 +1,48 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_1_1_WMSC');
goog.require('goog.object');
goog.require('ol.parser.ogc.WMSCapabilities_v1_1_1');
/**
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1_1_1}
*/
ol.parser.ogc.WMSCapabilities_v1_1_1_WMSC = function() {
goog.base(this);
this.profile = 'WMSC';
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'VendorSpecificCapabilities': function(node, obj) {
obj['vendorSpecific'] = {'tileSets': []};
this.readChildNodes(node, obj['vendorSpecific']);
},
'TileSet': function(node, vendorSpecific) {
var tileset = {'srs': {}, 'bbox': {}, 'resolutions': []};
this.readChildNodes(node, tileset);
vendorSpecific.tileSets.push(tileset);
},
'Resolutions': function(node, tileset) {
var res = this.getChildValue(node).split(' ');
for (var i = 0, ii = res.length; i < ii; i++) {
if (res[i] !== '') {
tileset['resolutions'].push(parseFloat(res[i]));
}
}
},
'Width': function(node, tileset) {
tileset['width'] = parseInt(this.getChildValue(node), 10);
},
'Height': function(node, tileset) {
tileset['height'] = parseInt(this.getChildValue(node), 10);
},
'Layers': function(node, tileset) {
tileset['layers'] = this.getChildValue(node);
},
'Styles': function(node, tileset) {
tileset['styles'] = this.getChildValue(node);
}
});
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_1_1_WMSC,
ol.parser.ogc.WMSCapabilities_v1_1_1);

View File

@@ -0,0 +1,114 @@
goog.provide('ol.parser.ogc.WMSCapabilities_v1_3_0');
goog.require('goog.object');
goog.require('ol.parser.ogc.WMSCapabilities_v1');
/**
* Read [WMS](http://www.opengeospatial.org/standards/wms) capabilities
* version 1.3.0
*
* @constructor
* @extends {ol.parser.ogc.WMSCapabilities_v1}
*/
ol.parser.ogc.WMSCapabilities_v1_3_0 = function() {
goog.base(this);
var bboxreader = this.readers['http://www.opengis.net/wms']['BoundingBox'];
goog.object.extend(this.readers['http://www.opengis.net/wms'], {
'WMS_Capabilities': function(node, obj) {
this.readChildNodes(node, obj);
},
'LayerLimit': function(node, obj) {
obj['layerLimit'] = parseInt(this.getChildValue(node), 10);
},
'MaxWidth': function(node, obj) {
obj['maxWidth'] = parseInt(this.getChildValue(node), 10);
},
'MaxHeight': function(node, obj) {
obj['maxHeight'] = parseInt(this.getChildValue(node), 10);
},
'BoundingBox': function(node, obj) {
var bbox = bboxreader.apply(this, arguments);
bbox['srs'] = node.getAttribute('CRS');
obj['bbox'][bbox['srs']] = bbox;
},
'CRS': function(node, obj) {
// CRS is the synonym of SRS
this.readers['http://www.opengis.net/wms']['SRS'].apply(this, arguments);
},
'EX_GeographicBoundingBox': function(node, obj) {
// replacement of LatLonBoundingBox
obj['llbbox'] = [];
this.readChildNodes(node, obj['llbbox']);
},
'westBoundLongitude': function(node, obj) {
obj[0] = this.getChildValue(node);
},
'eastBoundLongitude': function(node, obj) {
obj[2] = this.getChildValue(node);
},
'southBoundLatitude': function(node, obj) {
obj[1] = this.getChildValue(node);
},
'northBoundLatitude': function(node, obj) {
obj[3] = this.getChildValue(node);
},
'MinScaleDenominator': function(node, obj) {
obj['maxScale'] = parseFloat(this.getChildValue(node)).toPrecision(16);
},
'MaxScaleDenominator': function(node, obj) {
obj['minScale'] = parseFloat(this.getChildValue(node)).toPrecision(16);
},
'Dimension': function(node, obj) {
// dimension has extra attributes: default, multipleValues,
// nearestValue, current which used to be part of Extent. It now
// also contains the values.
var name = node.getAttribute('name').toLowerCase();
var dim = {
'name': name,
'units': node.getAttribute('units'),
'unitsymbol': node.getAttribute('unitSymbol'),
'nearestVal': node.getAttribute('nearestValue') === '1',
'multipleVal': node.getAttribute('multipleValues') === '1',
'default': node.getAttribute('default') || '',
'current': node.getAttribute('current') === '1',
'values': this.getChildValue(node).split(',')
};
// Theoretically there can be more dimensions with the same
// name, but with a different unit. Until we meet such a case,
// let's just keep the same structure as the WMS 1.1
// GetCapabilities parser uses. We will store the last
// one encountered.
obj['dimensions'][dim['name']] = dim;
},
'Keyword': function(node, obj) {
var keyword = {'value': this.getChildValue(node),
'vocabulary': node.getAttribute('vocabulary')};
if (obj['keywords']) {
obj['keywords'].push(keyword);
}
}
});
this.readers['sld'] = {
'UserDefinedSymbolization': function(node, obj) {
var readers = this.readers['http://www.opengis.net/wms'];
readers.UserDefinedSymbolization.apply(this, arguments);
// add the two extra attributes
var value = node.getAttribute('InlineFeature');
obj['userSymbols']['inlineFeature'] = parseInt(value, 10) == 1;
value = node.getAttribute('RemoteWCS');
obj['userSymbols']['remoteWCS'] = parseInt(value, 10) == 1;
},
'DescribeLayer': function(node, obj) {
var readers = this.readers['http://www.opengis.net/wms'];
readers.DescribeLayer.apply(this, arguments);
},
'GetLegendGraphic': function(node, obj) {
var readers = this.readers['http://www.opengis.net/wms'];
readers.GetLegendGraphic.apply(this, arguments);
}
};
};
goog.inherits(ol.parser.ogc.WMSCapabilities_v1_3_0,
ol.parser.ogc.WMSCapabilities_v1);

View File

@@ -0,0 +1,2 @@
@exportSymbol ol.parser.ogc.WMTSCapabilities
@exportProperty ol.parser.ogc.WMTSCapabilities.prototype.read

View File

@@ -0,0 +1,22 @@
goog.provide('ol.parser.ogc.WMTSCapabilities');
goog.require('ol.parser.ogc.Versioned');
goog.require('ol.parser.ogc.WMTSCapabilities_v1_0_0');
/**
* Read [WMTS](http://www.opengeospatial.org/standards/wmts) capabilities
*
* @constructor
* @param {Object=} opt_options Options which will be set on this object.
* @extends {ol.parser.ogc.Versioned}
* @todo stability experimental
*/
ol.parser.ogc.WMTSCapabilities = function(opt_options) {
opt_options = opt_options || {};
opt_options['defaultVersion'] = '1.0.0';
this.parsers = {};
this.parsers['v1_0_0'] = ol.parser.ogc.WMTSCapabilities_v1_0_0;
goog.base(this, opt_options);
};
goog.inherits(ol.parser.ogc.WMTSCapabilities, ol.parser.ogc.Versioned);

View File

@@ -0,0 +1,169 @@
goog.provide('ol.parser.ogc.WMTSCapabilities_v1_0_0');
goog.require('goog.dom.xml');
goog.require('ol.coordinate');
goog.require('ol.parser.XML');
goog.require('ol.parser.ogc.OWSCommon_v1_1_0');
goog.require('ol.proj');
/**
* Read [WMTS](http://www.opengeospatial.org/standards/wmts) capabilities
* version 1.0
*
* @constructor
* @extends {ol.parser.XML}
*/
ol.parser.ogc.WMTSCapabilities_v1_0_0 = function() {
this.defaultNamespaceURI = 'http://www.opengis.net/wmts/1.0';
this.errorProperty = 'serviceIdentification';
this.readers = {
'http://www.opengis.net/wmts/1.0': {
'Capabilities': function(node, obj) {
this.readChildNodes(node, obj);
},
'Contents': function(node, obj) {
obj['contents'] = {};
obj['contents']['layers'] = [];
obj['contents']['tileMatrixSets'] = {};
this.readChildNodes(node, obj['contents']);
},
'Layer': function(node, obj) {
var layer = {
'styles': [],
'formats': [],
'dimensions': [],
'tileMatrixSetLinks': []
};
layer['layers'] = [];
this.readChildNodes(node, layer);
obj['layers'].push(layer);
},
'Style': function(node, obj) {
var style = {};
style['isDefault'] = (node.getAttribute('isDefault') === 'true');
this.readChildNodes(node, style);
obj['styles'].push(style);
},
'Format': function(node, obj) {
obj['formats'].push(this.getChildValue(node));
},
'TileMatrixSetLink': function(node, obj) {
var tileMatrixSetLink = {};
this.readChildNodes(node, tileMatrixSetLink);
obj['tileMatrixSetLinks'].push(tileMatrixSetLink);
},
'TileMatrixSet': function(node, obj) {
// node could be child of wmts:Contents or wmts:TileMatrixSetLink
// duck type wmts:Contents by looking for layers
if (obj['layers']) {
// TileMatrixSet as object type in schema
var tileMatrixSet = {
'matrixIds': []
};
this.readChildNodes(node, tileMatrixSet);
obj['tileMatrixSets'][tileMatrixSet['identifier']] = tileMatrixSet;
} else {
// TileMatrixSet as string type in schema
obj['tileMatrixSet'] = this.getChildValue(node);
}
},
'TileMatrix': function(node, obj) {
var tileMatrix = {
'supportedCRS': obj['supportedCRS']
};
this.readChildNodes(node, tileMatrix);
obj['matrixIds'].push(tileMatrix);
},
'ScaleDenominator': function(node, obj) {
obj['scaleDenominator'] = parseFloat(this.getChildValue(node));
},
'TopLeftCorner': function(node, obj) {
var topLeftCorner = this.getChildValue(node);
var coords = topLeftCorner.split(' ');
var axisOrientation =
ol.proj.get(obj['supportedCRS']).getAxisOrientation();
obj['topLeftCorner'] = ol.coordinate.fromProjectedArray(
[parseFloat(coords[0]), parseFloat(coords[1])], axisOrientation);
},
'TileWidth': function(node, obj) {
obj['tileWidth'] = parseInt(this.getChildValue(node), 10);
},
'TileHeight': function(node, obj) {
obj['tileHeight'] = parseInt(this.getChildValue(node), 10);
},
'MatrixWidth': function(node, obj) {
obj['matrixWidth'] = parseInt(this.getChildValue(node), 10);
},
'MatrixHeight': function(node, obj) {
obj['matrixHeight'] = parseInt(this.getChildValue(node), 10);
},
'ResourceURL': function(node, obj) {
var resourceType = node.getAttribute('resourceType');
var format = node.getAttribute('format');
var template = node.getAttribute('template');
if (!obj['resourceUrls']) {
obj['resourceUrls'] = {};
}
if (!obj['resourceUrls'][resourceType]) {
obj['resourceUrls'][resourceType] = {};
}
if (!obj['resourceUrls'][resourceType][format]) {
obj['resourceUrls'][resourceType][format] = [];
}
obj['resourceUrls'][resourceType][format].push(template);
},
'WSDL': function(node, obj) {
obj['wsdl'] = {};
obj['wsdl']['href'] = this.getAttributeNS(node,
'http://www.w3.org/1999/xlink', 'href');
// TODO: other attributes of <WSDL> element
},
'ServiceMetadataURL': function(node, obj) {
obj['serviceMetadataUrl'] = {};
obj['serviceMetadataUrl']['href'] =
this.getAttributeNS(node, 'http://www.w3.org/1999/xlink', 'href');
// TODO: other attributes of <ServiceMetadataURL> element
},
'LegendURL': function(node, obj) {
obj['legend'] = {};
obj['legend']['href'] = this.getAttributeNS(node,
'http://www.w3.org/1999/xlink', 'href');
obj['legend']['format'] = node.getAttribute('format');
},
'Dimension': function(node, obj) {
var dimension = {'values': []};
this.readChildNodes(node, dimension);
obj['dimensions'].push(dimension);
},
'Default': function(node, obj) {
obj['default'] = this.getChildValue(node);
},
'Value': function(node, obj) {
obj['values'].push(this.getChildValue(node));
}
}
};
var ows = new ol.parser.ogc.OWSCommon_v1_1_0();
this.readers['http://www.opengis.net/ows/1.1'] =
ows.readers['http://www.opengis.net/ows/1.1'];
goog.base(this);
};
goog.inherits(ol.parser.ogc.WMTSCapabilities_v1_0_0, ol.parser.XML);
/**
* @param {string|Document|Element} data Data to read.
* @return {Object} An object representing the document.
*/
ol.parser.ogc.WMTSCapabilities_v1_0_0.prototype.read = function(data) {
if (goog.isString(data)) {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {};
this.readNode(data, obj);
return obj;
};

View File

@@ -0,0 +1,9 @@
goog.provide('ol.parser.Parser');
/**
* @constructor
* @todo stability experimental
*/
ol.parser.Parser = function() {};

View File

@@ -0,0 +1,335 @@
goog.provide('ol.parser.polyline');
/**
* Encode a list of coordinates in a flat array and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} flatPoints A flat array of coordinates.
* @param {number=} opt_dimension The dimension of the coordinates in the array.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFlatCoordinates =
function(flatPoints, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.encodeDeltas(flatPoints, dimension);
};
/**
* Decode a list of coordinates from an encoded string into a flat array
*
* @param {string} encoded An encoded string.
* @param {number=} opt_dimension The dimension of the coordinates in the
* encoded string.
* @return {Array.<number>} A flat array of coordinates.
*/
ol.parser.polyline.decodeFlatCoordinates = function(encoded, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.decodeDeltas(encoded, dimension);
};
/**
* Encode a list of n-dimensional points and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of n-dimensional points.
* @param {number} dimension The dimension of the points in the list.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeDeltas = function(numbers, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
var num = numbers[i];
var delta = num - lastNumbers[d];
lastNumbers[d] = num;
numbers[i] = delta;
}
}
return ol.parser.polyline.encodeFloats(numbers, factor);
};
/**
* Decode a list of n-dimensional points from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number} dimension The dimension of the points in the encoded string.
* @param {number=} opt_factor The factor by which the resulting numbers will
* be divided.
* @return {Array.<number>} A list of n-dimensional points.
*/
ol.parser.polyline.decodeDeltas = function(encoded, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbers = ol.parser.polyline.decodeFloats(encoded, factor);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
lastNumbers[d] += numbers[i];
numbers[i] = lastNumbers[d];
}
}
return numbers;
};
/**
* Encode a list of floating point numbers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of floating point numbers.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFloats = function(numbers, opt_factor) {
var factor = opt_factor || 1e5;
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] = Math.round(numbers[i] * factor);
}
return ol.parser.polyline.encodeSignedIntegers(numbers);
};
/**
* Decode a list of floating point numbers from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {Array.<number>} A list of floating point numbers.
*/
ol.parser.polyline.decodeFloats = function(encoded, opt_factor) {
var factor = opt_factor || 1e5;
var numbers = ol.parser.polyline.decodeSignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] /= factor;
}
return numbers;
};
/**
* Encode a list of signed integers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of signed integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeSignedIntegers = function(numbers) {
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
numbers[i] = signedNum;
}
return ol.parser.polyline.encodeUnsignedIntegers(numbers);
};
/**
* Decode a list of signed integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of signed integers.
*/
ol.parser.polyline.decodeSignedIntegers = function(encoded) {
var numbers = ol.parser.polyline.decodeUnsignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}
return numbers;
};
/**
* Encode a list of unsigned integers and return an encoded string
*
* @param {Array.<number>} numbers A list of unsigned integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeUnsignedIntegers = function(numbers) {
var encoded = '';
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
encoded += ol.parser.polyline.encodeUnsignedInteger(numbers[i]);
}
return encoded;
};
/**
* Decode a list of unsigned integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of unsigned integers.
*/
ol.parser.polyline.decodeUnsignedIntegers = function(encoded) {
var numbers = [];
var current = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
current |= (b & 0x1f) << shift;
if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}
return numbers;
};
/**
* Encode one single floating point number and return an encoded string
*
* @param {number} num Floating point number that should be encoded.
* @param {number=} opt_factor The factor by which num will be multiplied.
* The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFloat = function(num, opt_factor) {
num = Math.round(num * (opt_factor || 1e5));
return ol.parser.polyline.encodeSignedInteger(num);
};
/**
* Decode one single floating point number from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {number} The decoded floating point number.
*/
ol.parser.polyline.decodeFloat = function(encoded, opt_factor) {
var result = ol.parser.polyline.decodeSignedInteger(encoded);
return result / (opt_factor || 1e5);
};
/**
* Encode one single signed integer and return an encoded string
*
* @param {number} num Signed integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeSignedInteger = function(num) {
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
return ol.parser.polyline.encodeUnsignedInteger(signedNum);
};
/**
* Decode one single signed integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded signed integer.
*/
ol.parser.polyline.decodeSignedInteger = function(encoded) {
var result = ol.parser.polyline.decodeUnsignedInteger(encoded);
return ((result & 1) ? ~(result >> 1) : (result >> 1));
};
/**
* Encode one single unsigned integer and return an encoded string
*
* @param {number} num Unsigned integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeUnsignedInteger = function(num) {
var value, encoded = '';
while (num >= 0x20) {
value = (0x20 | (num & 0x1f)) + 63;
encoded += (String.fromCharCode(value));
num >>= 5;
}
value = num + 63;
encoded += (String.fromCharCode(value));
return encoded;
};
/**
* Decode one single unsigned integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded unsigned integer.
*/
ol.parser.polyline.decodeUnsignedInteger = function(encoded) {
var result = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
result |= (b & 0x1f) << shift;
if (b < 0x20)
break;
shift += 5;
}
return result;
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.parser.TopoJSON

View File

@@ -0,0 +1,382 @@
goog.provide('ol.parser.TopoJSON');
goog.require('ol.Coordinate');
goog.require('ol.CoordinateArray');
goog.require('ol.Feature');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.Parser');
goog.require('ol.parser.StringFeatureParser');
/**
* Read [TopoJSON](https://github.com/mbostock/topojson)
*
* @constructor
* @implements {ol.parser.StringFeatureParser}
* @extends {ol.parser.Parser}
* @todo stability experimental
*/
ol.parser.TopoJSON = function() {};
goog.inherits(ol.parser.TopoJSON, ol.parser.Parser);
goog.addSingletonGetter(ol.parser.TopoJSON);
/**
* Concatenate arcs into a coordinate array.
* @param {Array.<number>} indices Indices of arcs to concatenate. Negative
* values indicate arcs need to be reversed.
* @param {Array.<ol.CoordinateArray>} arcs Arcs (already transformed).
* @return {ol.CoordinateArray} Coordinate array.
* @private
*/
ol.parser.TopoJSON.prototype.concatenateArcs_ = function(indices, arcs) {
var coordinates = [];
var index, arc;
for (var i = 0, ii = indices.length; i < ii; ++i) {
index = indices[i];
if (i > 0) {
// splicing together arcs, discard last point
coordinates.pop();
}
if (index >= 0) {
// forward arc
arc = arcs[index];
} else {
// reverse arc
arc = arcs[~index].slice().reverse();
}
coordinates.push.apply(coordinates, arc);
}
// provide fresh copies of coordinate arrays
for (var j = 0, jj = coordinates.length; j < jj; ++j) {
coordinates[j] = coordinates[j].slice();
}
return coordinates;
};
/**
* Parse a TopoJSON string.
* @param {string} str TopoJSON string.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.TopoJSON.prototype.read = function(str) {
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
return this.readFeaturesFromObject(topology).features;
};
/**
* Create features from a TopoJSON topology string.
*
* @param {string} str TopoJSON topology string.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.TopoJSON.prototype.readFeaturesFromString = function(str) {
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
if (topology.type !== 'Topology') {
throw new Error('Not a "Topology" type object');
}
return {
features: this.readFeaturesFromTopology_(topology),
metadata: {projection: 'EPSG:4326'}
};
};
/**
* Create features from a TopoJSON topology object.
*
* @param {TopoJSONTopology} topology TopoJSON topology object.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.TopoJSON.prototype.readFeaturesFromObject = function(topology) {
if (topology.type !== 'Topology') {
throw new Error('Not a "Topology" type object');
}
return {
features: this.readFeaturesFromTopology_(topology),
metadata: {projection: 'EPSG:4326'}
};
};
/**
* Create a feature from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON geometry object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {ol.Feature} Feature.
* @private
*/
ol.parser.TopoJSON.prototype.readFeatureFromGeometry_ = function(object, arcs,
scale, translate) {
var geometry;
var type = object.type;
if (type === 'Point') {
geometry = this.readPoint_(/** @type {TopoJSONPoint} */ (object), scale,
translate);
} else if (type === 'LineString') {
geometry = this.readLineString_(/** @type {TopoJSONLineString} */ (object),
arcs);
} else if (type === 'Polygon') {
geometry = this.readPolygon_(/** @type {TopoJSONPolygon} */ (object), arcs);
} else if (type === 'MultiPoint') {
geometry = this.readMultiPoint_(/** @type {TopoJSONMultiPoint} */ (object),
scale, translate);
} else if (type === 'MultiLineString') {
geometry = this.readMultiLineString_(
/** @type {TopoJSONMultiLineString} */(object), arcs);
} else if (type === 'MultiPolygon') {
geometry = this.readMultiPolygon_(
/** @type {TopoJSONMultiPolygon} */ (object), arcs);
} else {
throw new Error('Unsupported geometry type: ' + type);
}
var feature = new ol.Feature();
feature.setGeometry(geometry);
if (goog.isDef(object.id)) {
feature.setId(String(object.id));
}
return feature;
};
/**
* Create features from a TopoJSON GeometryCollection object.
*
* @param {TopoJSONGeometryCollection} collection TopoJSON GeometryCollection
* object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.parser.TopoJSON.prototype.readFeaturesFromGeometryCollection_ = function(
collection, arcs, scale, translate) {
var geometries = collection.geometries;
var num = geometries.length;
var features = new Array(num);
for (var i = 0; i < num; ++i) {
features[i] = this.readFeatureFromGeometry_(geometries[i], arcs, scale,
translate);
}
return features;
};
/**
* @param {TopoJSONTopology} topology TopoJSON object.
* @return {Array.<ol.Feature>} Parsed features.
* @private
*/
ol.parser.TopoJSON.prototype.readFeaturesFromTopology_ = function(topology) {
var transform = topology.transform;
var scale = transform.scale;
var translate = transform.translate;
var arcs = topology.arcs;
this.transformArcs_(arcs, scale, translate);
var objects = topology.objects;
var features = [];
for (var key in objects) {
if (objects[key].type === 'GeometryCollection') {
features.push.apply(features, this.readFeaturesFromGeometryCollection_(
/** @type {TopoJSONGeometryCollection} */ (objects[key]),
arcs, scale, translate));
} else {
features.push(this.readFeatureFromGeometry_(
/** @type {TopoJSONGeometry} */ (objects[key]),
arcs, scale, translate));
}
}
return features;
};
/**
* Create a linestring from a TopoJSON geometry object.
*
* @param {TopoJSONLineString} object TopoJSON object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @return {ol.geom.LineString} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readLineString_ = function(object, arcs) {
var coordinates = this.concatenateArcs_(object.arcs, arcs);
return new ol.geom.LineString(coordinates);
};
/**
* Create a multi-linestring from a TopoJSON geometry object.
*
* @param {TopoJSONMultiLineString} object TopoJSON object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @return {ol.geom.MultiLineString} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiLineString_ = function(object, arcs) {
var array = object.arcs; // I'm out of good names
var num = array.length;
var coordinates = new Array(num);
for (var i = 0; i < num; ++i) {
coordinates[i] = this.concatenateArcs_(array[i], arcs);
}
return new ol.geom.MultiLineString(coordinates);
};
/**
* Create a multi-point from a TopoJSON geometry object.
*
* @param {TopoJSONMultiPoint} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {ol.geom.MultiPoint} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiPoint_ = function(object, scale,
translate) {
var coordinates = object.coordinates;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
this.transformVertex_(coordinates[i], scale, translate);
}
return new ol.geom.MultiPoint(coordinates);
};
/**
* Create a multi-polygon from a TopoJSON geometry object.
*
* @param {TopoJSONMultiPolygon} object TopoJSON object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @return {ol.geom.MultiPolygon} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiPolygon_ = function(object, arcs) {
var array = object.arcs;
var numPolys = array.length;
var coordinates = new Array(numPolys);
var polyArray, numRings, ringCoords, j;
for (var i = 0; i < numPolys; ++i) {
// for each polygon
polyArray = array[i];
numRings = polyArray.length;
ringCoords = new Array(numRings);
for (j = 0; j < numRings; ++j) {
// for each ring
ringCoords[j] = this.concatenateArcs_(polyArray[j], arcs);
}
coordinates[i] = ringCoords;
}
return new ol.geom.MultiPolygon(coordinates);
};
/**
* Create a point from a TopoJSON geometry object.
*
* @param {TopoJSONPoint} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {ol.geom.Point} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readPoint_ = function(object, scale, translate) {
var coordinates = object.coordinates;
this.transformVertex_(coordinates, scale, translate);
return new ol.geom.Point(coordinates);
};
/**
* Create a polygon from a TopoJSON geometry object.
*
* @param {TopoJSONPolygon} object TopoJSON object.
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @return {ol.geom.Polygon} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readPolygon_ = function(object, arcs) {
var array = object.arcs; // I'm out of good names
var num = array.length;
var coordinates = new Array(num);
for (var i = 0; i < num; ++i) {
coordinates[i] = this.concatenateArcs_(array[i], arcs);
}
return new ol.geom.Polygon(coordinates);
};
/**
* Apply a linear transform to array of arcs. The provided array of arcs is
* modified in place.
*
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformArcs_ = function(arcs, scale, translate) {
for (var i = 0, ii = arcs.length; i < ii; ++i) {
this.transformArc_(arcs[i], scale, translate);
}
};
/**
* Apply a linear transform to an arc. The provided arc is modified in place.
*
* @param {ol.CoordinateArray} arc Arc.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformArc_ = function(arc, scale, translate) {
var x = 0;
var y = 0;
var vertex;
for (var i = 0, ii = arc.length; i < ii; ++i) {
vertex = arc[i];
x += vertex[0];
y += vertex[1];
vertex[0] = x;
vertex[1] = y;
this.transformVertex_(vertex, scale, translate);
}
};
/**
* Apply a linear transform to a vertex. The provided vertex is modified in
* place.
*
* @param {ol.Coordinate} vertex Vertex.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformVertex_ = function(vertex, scale,
translate) {
vertex[0] = vertex[0] * scale[0] + translate[0];
vertex[1] = vertex[1] * scale[1] + translate[1];
};
/**
* Parse a TopoJSON string.
* @param {string} str TopoJSON string.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.TopoJSON.read = function(str) {
return ol.parser.TopoJSON.getInstance().read(str);
};

View File

@@ -0,0 +1,5 @@
@exportSymbol ol.parser.WKT
@exportProperty ol.parser.WKT.prototype.read
@exportProperty ol.parser.WKT.prototype.write
@exportProperty ol.parser.WKT.read
@exportProperty ol.parser.WKT.write

View File

@@ -0,0 +1,392 @@
goog.provide('ol.parser.WKT');
goog.require('goog.array');
goog.require('goog.string');
goog.require('ol.Feature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.Parser');
goog.require('ol.parser.StringFeatureParser');
/**
* @constructor
* @extends {ol.parser.Parser}
* @implements {ol.parser.StringFeatureParser}
* @todo stability experimental
*/
ol.parser.WKT = function() {
};
goog.inherits(ol.parser.WKT, ol.parser.Parser);
goog.addSingletonGetter(ol.parser.WKT);
/**
* Constants for regExes.
* @enum {RegExp}
*/
ol.parser.WKT.regExes = {
typeStr: /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
spaces: /\s+/,
parenComma: /\)\s*,\s*\(/,
doubleParenComma: /\)\s*\)\s*,\s*\(\s*\(/,
trimParens: /^\s*\(?(.*?)\)?\s*$/,
geomCollection: /,\s*([A-Za-z])/g,
removeNewLine: /[\n\r]/g
};
/**
* @param {string} str WKT point.
* @return {ol.geom.Point} Parsed point.
* @private
*/
ol.parser.WKT.prototype.parsePoint_ = function(str) {
var coords = goog.string.trim(str).split(ol.parser.WKT.regExes.spaces);
return new ol.geom.Point(goog.array.map(coords, parseFloat));
};
/**
* @param {string} str WKT linestring.
* @return {ol.geom.LineString} Parsed linestring.
* @private
*/
ol.parser.WKT.prototype.parseLineString_ = function(str) {
var points = goog.string.trim(str).split(',');
var coordinates = [];
for (var i = 0, ii = points.length; i < ii; ++i) {
coordinates.push(this.parsePoint_.apply(this,
[points[i]]).getCoordinates());
}
return new ol.geom.LineString(coordinates);
};
/**
* @param {string} str WKT multipoint.
* @return {ol.geom.MultiPoint} Parsed multipoint.
* @private
*/
ol.parser.WKT.prototype.parseMultiPoint_ = function(str) {
var point;
var points = goog.string.trim(str).split(',');
var parts = [];
for (var i = 0, ii = points.length; i < ii; ++i) {
point = points[i].replace(ol.parser.WKT.regExes.trimParens, '$1');
parts.push(this.parsePoint_.apply(this, [point]));
}
return ol.geom.MultiPoint.fromParts(parts);
};
/**
* @param {string} str WKT multilinestring.
* @return {ol.geom.MultiLineString} Parsed multilinestring.
* @private
*/
ol.parser.WKT.prototype.parseMultiLineString_ = function(str) {
var line;
var lines = goog.string.trim(str).split(ol.parser.WKT.regExes.parenComma);
var parts = [];
for (var i = 0, ii = lines.length; i < ii; ++i) {
line = lines[i].replace(ol.parser.WKT.regExes.trimParens, '$1');
parts.push(this.parseLineString_.apply(this, [line]));
}
return ol.geom.MultiLineString.fromParts(parts);
};
/**
* @param {string} str WKT polygon.
* @return {ol.geom.Polygon} Parsed polygon.
* @private
*/
ol.parser.WKT.prototype.parsePolygon_ = function(str) {
var ring, linestring, linearring;
var rings = goog.string.trim(str).split(ol.parser.WKT.regExes.parenComma);
var coordinates = [];
for (var i = 0, ii = rings.length; i < ii; ++i) {
ring = rings[i].replace(ol.parser.WKT.regExes.trimParens, '$1');
linestring = this.parseLineString_.apply(this, [ring]).getCoordinates();
coordinates.push(linestring);
}
return new ol.geom.Polygon(coordinates);
};
/**
* @param {string} str WKT multipolygon.
* @return {ol.geom.MultiPolygon} Parsed multipolygon.
* @private
*/
ol.parser.WKT.prototype.parseMultiPolygon_ = function(str) {
var polygon;
var polygons = goog.string.trim(str).split(
ol.parser.WKT.regExes.doubleParenComma);
var parts = [];
for (var i = 0, ii = polygons.length; i < ii; ++i) {
polygon = polygons[i].replace(ol.parser.WKT.regExes.trimParens, '$1');
parts.push(this.parsePolygon_.apply(this, [polygon]));
}
return ol.geom.MultiPolygon.fromParts(parts);
};
/**
* @param {string} str WKT geometrycollection.
* @return {ol.geom.GeometryCollection} Parsed geometrycollection.
* @private
*/
ol.parser.WKT.prototype.parseGeometryCollection_ = function(str) {
// separate components of the collection with |
str = str.replace(ol.parser.WKT.regExes.geomCollection, '|$1');
var wktArray = goog.string.trim(str).split('|');
var components = [];
for (var i = 0, ii = wktArray.length; i < ii; ++i) {
components.push(this.parse_.apply(this, [wktArray[i]]));
}
return new ol.geom.GeometryCollection(components);
};
/**
* @param {ol.geom.Point} geom Point geometry.
* @return {string} Coordinates part of Point as WKT.
* @private
*/
ol.parser.WKT.prototype.encodePoint_ = function(geom) {
var coordinates = geom.getCoordinates();
return coordinates[0] + ' ' + coordinates[1];
};
/**
* @param {ol.geom.MultiPoint} geom MultiPoint geometry.
* @return {string} Coordinates part of MultiPoint as WKT.
* @private
*/
ol.parser.WKT.prototype.encodeMultiPoint_ = function(geom) {
var array = [];
var components = geom.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + this.encodePoint_.apply(this, [components[i]]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.GeometryCollection} geom GeometryCollection geometry.
* @return {string} Coordinates part of GeometryCollection as WKT.
* @private
*/
ol.parser.WKT.prototype.encodeGeometryCollection_ = function(geom) {
var array = [];
var components = geom.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push(this.encode_.apply(this, [components[i]]));
}
return array.join(',');
};
/**
* @param {ol.geom.LineString} geom LineString geometry.
* @return {string} Coordinates part of LineString as WKT.
* @private
*/
ol.parser.WKT.prototype.encodeLineString_ = function(geom) {
var coordinates = geom.getCoordinates();
var array = [];
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
array.push(coordinates[i][0] + ' ' + coordinates[i][1]);
}
return array.join(',');
};
/**
* @param {ol.geom.MultiLineString} geom MultiLineString geometry.
* @return {string} Coordinates part of MultiLineString as WKT.
* @private
*/
ol.parser.WKT.prototype.encodeMultiLineString_ = function(geom) {
var array = [];
var components = geom.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + this.encodeLineString_.apply(this,
[components[i]]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.Polygon} geom Polygon geometry.
* @return {string} Coordinates part of Polygon as WKT.
* @private
*/
ol.parser.WKT.prototype.encodePolygon_ = function(geom) {
var array = [];
var rings = geom.getRings();
for (var i = 0, ii = rings.length; i < ii; ++i) {
array.push('(' + this.encodeLineString_.apply(this,
[rings[i]]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.MultiPolygon} geom MultiPolygon geometry.
* @return {string} Coordinates part of MultiPolygon as WKT.
* @private
*/
ol.parser.WKT.prototype.encodeMultiPolygon_ = function(geom) {
var array = [];
var components = geom.getComponents();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + this.encodePolygon_.apply(this, [components[i]]) + ')');
}
return array.join(',');
};
/**
* Parse a WKT string.
* @param {string} wkt WKT string.
* @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined}
* The geometry created.
* @private
*/
ol.parser.WKT.prototype.parse_ = function(wkt) {
wkt = wkt.replace(ol.parser.WKT.regExes.removeNewLine, ' ');
var matches = ol.parser.WKT.regExes.typeStr.exec(wkt);
var geometry;
if (matches) {
var type = matches[1].toLowerCase();
var str = matches[2];
switch (type) {
case 'point':
geometry = this.parsePoint_(str);
break;
case 'multipoint':
geometry = this.parseMultiPoint_(str);
break;
case 'linestring':
geometry = this.parseLineString_(str);
break;
case 'multilinestring':
geometry = this.parseMultiLineString_(str);
break;
case 'polygon':
geometry = this.parsePolygon_(str);
break;
case 'multipolygon':
geometry = this.parseMultiPolygon_(str);
break;
case 'geometrycollection':
geometry = this.parseGeometryCollection_(str);
break;
default:
throw new Error('Bad geometry type: ' + type);
}
}
return geometry;
};
/**
* Encode a geometry as WKT.
* @param {ol.geom.Geometry} geom The geometry to encode.
* @return {string} WKT string for the geometry.
* @private
*/
ol.parser.WKT.prototype.encode_ = function(geom) {
var type = geom.getType();
var result = type.toUpperCase() + '(';
if (geom instanceof ol.geom.Point) {
result += this.encodePoint_(geom);
} else if (geom instanceof ol.geom.MultiPoint) {
result += this.encodeMultiPoint_(geom);
} else if (geom instanceof ol.geom.LineString) {
result += this.encodeLineString_(geom);
} else if (geom instanceof ol.geom.MultiLineString) {
result += this.encodeMultiLineString_(geom);
} else if (geom instanceof ol.geom.Polygon) {
result += this.encodePolygon_(geom);
} else if (geom instanceof ol.geom.MultiPolygon) {
result += this.encodeMultiPolygon_(geom);
} else if (geom instanceof ol.geom.GeometryCollection) {
result += this.encodeGeometryCollection_(geom);
} else {
throw new Error('Bad geometry type: ' + type);
}
return result + ')';
};
/**
* Parse a WKT string.
* @param {string} str WKT string.
* @return {ol.geom.Geometry|undefined} Parsed geometry.
*/
ol.parser.WKT.prototype.read = function(str) {
return this.parse_(str);
};
/**
* Parse a WKT document provided as a string.
* @param {string} str WKT document.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.WKT.prototype.readFeaturesFromString = function(str) {
var geom = this.read(str);
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({});
if (goog.isDef(geom)) {
var feature = new ol.Feature();
feature.setGeometry(geom);
obj.features = [feature];
}
return obj;
};
/**
* Write out a geometry as a WKT string.
* @param {ol.geom.Geometry} geom The geometry to encode.
* @return {string} WKT for the geometry.
*/
ol.parser.WKT.prototype.write = function(geom) {
return this.encode_(geom);
};
/**
* Parse a WKT string.
* @param {string} str WKT string.
* @return {ol.geom.Geometry|undefined} Parsed geometry.
*/
ol.parser.WKT.read = function(str) {
return ol.parser.WKT.getInstance().read(str);
};
/**
* Write out a geometry as a WKT string.
* @param {ol.geom.Geometry} geom The geometry to encode.
* @return {string} WKT for the geometry.
*/
ol.parser.WKT.write = function(geom) {
return ol.parser.WKT.getInstance().write(geom);
};

View File

@@ -0,0 +1,296 @@
goog.provide('ol.parser.XML');
goog.require('goog.dom.xml');
goog.require('ol.parser.Parser');
/**
* @constructor
* @extends {ol.parser.Parser}
* @todo stability experimental
*/
ol.parser.XML = function() {
if (goog.global.ActiveXObject) {
this.xmldom = new ActiveXObject('Microsoft.XMLDOM');
}
this.regExes = {
trimSpace: (/^\s*|\s*$/g),
removeSpace: (/\s*/g),
splitSpace: (/\s+/),
trimComma: (/\s*,\s*/g)
};
};
goog.inherits(ol.parser.XML, ol.parser.Parser);
/**
* Shorthand for applying one of the named readers given the node
* namespace and local name. Readers take two args (node, obj) and
* generally extend or modify the second.
*
* @param {Element|Document} node The node to be read (required).
* @param {Object} obj The object to be modified (optional).
* @return {Object} The input object, modified (or a new one if none was
* provided).
*/
ol.parser.XML.prototype.readNode = function(node, obj) {
if (!obj) {
obj = {};
}
var group = this.readers[node.namespaceURI] ||
this.readers[this.defaultNamespaceURI];
if (group) {
var local = node.localName || node.nodeName.split(':').pop();
var reader = group[local] || group['*'];
if (reader) {
reader.apply(this, [node, obj]);
}
}
return obj;
};
/**
* Shorthand for applying the named readers to all children of a node.
* For each child of type 1 (element), <readSelf> is called.
*
* @param {Element|Document} node The node to be read (required).
* @param {Object} obj The object to be modified (optional).
* @return {Object} The input object, modified.
*/
ol.parser.XML.prototype.readChildNodes = function(node, obj) {
if (!obj) {
obj = {};
}
var children = node.childNodes;
var child;
for (var i = 0, len = children.length; i < len; ++i) {
child = children[i];
if (child.nodeType == 1) {
this.readNode(child, obj);
}
}
return obj;
};
/**
* Get the textual value of the node if it exists, or return an
* optional default string. Returns an empty string if no first child
* exists and no default value is supplied.
*
* @param {Element} node The element used to look for a first child value.
* @param {string} def Optional string to return in the event that no
* first child value exists.
* @return {string} The value of the first child of the given node.
*/
ol.parser.XML.prototype.getChildValue = function(node, def) {
var value = def || '';
if (node) {
for (var child = node.firstChild; child; child = child.nextSibling) {
switch (child.nodeType) {
case 3: // text node
case 4: // cdata section
value += child.nodeValue;
break;
default:
break;
}
}
}
return value;
};
/**
* Get an attribute node given the namespace URI and local name.
*
* @param {Element} node Node on which to search for attribute nodes.
* @param {string} uri Namespace URI.
* @param {string} name Local name of the attribute (without the prefix).
* @return {?Element} An attribute node or null if none found.
*/
ol.parser.XML.prototype.getAttributeNodeNS = function(node, uri, name) {
var attributeNode = null;
if (node.getAttributeNodeNS) {
attributeNode = node.getAttributeNodeNS(uri, name);
} else {
var attributes = node.attributes;
var potentialNode, fullName;
for (var i = 0, len = attributes.length; i < len; ++i) {
potentialNode = attributes[i];
if (potentialNode.namespaceURI == uri) {
fullName = (potentialNode.prefix) ?
(potentialNode.prefix + ':' + name) : name;
if (fullName == potentialNode.nodeName) {
attributeNode = potentialNode;
break;
}
}
}
}
return attributeNode;
};
/**
* Get an attribute value given the namespace URI and local name.
*
* @param {Element} node Node on which to search for an attribute.
* @param {string} uri Namespace URI.
* @param {string} name Local name of the attribute (without the prefix).
* @return {string} An attribute value or and empty string if none found.
*/
ol.parser.XML.prototype.getAttributeNS = function(node, uri, name) {
var attributeValue = '';
if (node.getAttributeNS) {
attributeValue = node.getAttributeNS(uri, name) || '';
} else {
var attributeNode = this.getAttributeNodeNS(node, uri, name);
if (attributeNode) {
attributeValue = attributeNode.nodeValue;
}
}
return attributeValue;
};
/**
* Create a new element with namespace. This node can be appended to
* another node with the standard node.appendChild method. For
* cross-browser support, this method must be used instead of
* document.createElementNS.
*
* @param {string} name The qualified name of the element (prefix:localname).
* @param {string=} opt_uri Namespace URI for the element.
* @return {Element} A DOM element with namespace.
*/
ol.parser.XML.prototype.createElementNS = function(name, opt_uri) {
var uri = opt_uri ? opt_uri : this.defaultNamespaceURI;
var element;
if (this.xmldom) {
element = this.xmldom.createNode(1, name, uri);
} else {
element = document.createElementNS(uri, name);
}
return element;
};
/**
* Shorthand for applying one of the named writers and appending the
* results to a node.
*
* @param {string} name The name of a node to generate. Only use a local name.
* @param {Object|string|number} obj Structure containing data for the writer.
* @param {?string=} opt_uri The name space uri to which the node
* belongs.
* @param {Element=} opt_parent Result will be appended to this node. If no
* parent is supplied, the node will not be appended to anything.
* @return {?Element} The child node.
*/
ol.parser.XML.prototype.writeNode = function(name, obj, opt_uri, opt_parent) {
var child = null;
if (goog.isDef(this.writers)) {
var uri = opt_uri ? opt_uri : this.defaultNamespaceURI;
child = this.writers[uri][name].apply(this, [obj]);
if (opt_parent && child) {
opt_parent.appendChild(child);
}
}
return child;
};
/**
* Create a text node. This node can be appended to another node with
* the standard node.appendChild method. For cross-browser support,
* this method must be used instead of document.createTextNode.
*
* @param {string} text The text of the node.
* @return {Element} A DOM text node.
*/
ol.parser.XML.prototype.createTextNode = function(text) {
var node;
if (this.xmldom) {
node = this.xmldom.createTextNode(text);
} else {
node = document.createTextNode(text);
}
return node;
};
/**
* Adds a new attribute or changes the value of an attribute with the given
* namespace and name.
*
* @param {Element} node Element node on which to set the attribute.
* @param {string} uri Namespace URI for the attribute.
* @param {string} name Qualified name (prefix:localname) for the attribute.
* @param {string} value Attribute value.
*/
ol.parser.XML.prototype.setAttributeNS = function(node, uri, name, value) {
if (node.setAttributeNS) {
node.setAttributeNS(uri, name, value);
} else {
if (this.xmldom) {
if (uri) {
var attribute = node.ownerDocument.createNode(
2, name, uri);
attribute.nodeValue = value;
node.setAttributeNode(attribute);
} else {
node.setAttribute(name, value);
}
} else {
throw new Error('setAttributeNS not implemented');
}
}
};
/**
* Serializes a node.
*
* @param {Element} node Element node to serialize.
* @return {string} The serialized XML string.
*/
ol.parser.XML.prototype.serialize = function(node) {
if (this.xmldom) {
return node.xml;
} else if (node.nodeType == 1) {
// Add nodes to a document before serializing. Everything else
// is serialized as is. This is also needed to get all namespaces
// defined in some browsers such as Chrome (xmlns attributes).
var doc = document.implementation.createDocument('', '', null);
if (doc.importNode) {
doc.appendChild(doc.importNode(node, true));
} else {
doc.appendChild(node);
}
return goog.dom.xml.serialize(doc);
} else {
return goog.dom.xml.serialize(node);
}
};
/**
* Create a document fragment node that can be appended to another node
* created by createElementNS. This will call
* document.createDocumentFragment outside of IE. In IE, the ActiveX
* object's createDocumentFragment method is used.
*
* @return {Element} A document fragment.
*/
ol.parser.XML.prototype.createDocumentFragment = function() {
var element;
if (this.xmldom) {
element = this.xmldom.createDocumentFragment();
} else {
element = document.createDocumentFragment();
}
return element;
};

View File

@@ -0,0 +1,581 @@
goog.provide('ol.renderer.canvas.VectorLayer');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.object');
goog.require('goog.vec.Mat4');
goog.require('ol.Pixel');
goog.require('ol.TileCache');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.ViewHint');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.layer.Vector');
goog.require('ol.layer.VectorEventType');
goog.require('ol.layer.VectorLayerRenderIntent');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.canvas.Vector');
goog.require('ol.tilegrid.TileGrid');
/**
* Resolution at zoom level 21 in a web mercator default tiling scheme. This
* is a workaround for browser bugs that cause line segments to disappear when
* they get too long. TODO: Use line clipping as a better work around. See
* https://github.com/openlayers/ol3/issues/404.
*
* @define {number} The lowest supported resolution value.
*/
ol.renderer.canvas.MIN_RESOLUTION = 0.14929107086948487;
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} layer Vector layer.
*/
ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
goog.base(this, mapRenderer, layer);
/**
* Final canvas made available to the map renderer.
* @private
* @type {HTMLCanvasElement}
*/
this.canvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.context_ = /** @type {CanvasRenderingContext2D} */
(this.canvas_.getContext('2d'));
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.transform_ = goog.vec.Mat4.createNumber();
/**
* Interim canvas for drawing newly visible features.
* @private
* @type {HTMLCanvasElement}
*/
this.sketchCanvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.sketchTransform_ = goog.vec.Mat4.createNumber();
/**
* Tile cache entries are arrays. The first item in each array is the tile
* itself, the second are the symbol sizes, and the third is the maximum
* symbol size.
*
* @private
* @type {ol.TileCache}
*/
this.tileCache_ = new ol.TileCache(
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE);
goog.events.listen(layer, [
ol.layer.VectorEventType.ADD,
ol.layer.VectorEventType.CHANGE,
ol.layer.VectorEventType.REMOVE,
ol.layer.VectorEventType.INTENTCHANGE
],
this.handleLayerChange_, false, this);
/**
* @private
* @type {HTMLCanvasElement}
*/
this.tileArchetype_ = null;
/**
* The maximum symbol size ever rendered for this layer (in pixels).
* @private
* @type {number}
*/
this.maxSymbolPixelDim_ = 0;
/**
* @private
* @type {number}
*/
this.renderedResolution_;
/**
* @private
* @type {ol.Extent}
*/
this.renderedExtent_ = null;
/**
* Flag to be set internally when we know something has changed that suggests
* we need to re-render.
* TODO: discuss setting this for all layers when something changes before
* calling map.render().
* @private
* @type {boolean}
*/
this.dirty_ = false;
/**
* @private
* @type {boolean}
*/
this.pendingCachePrune_ = false;
/**
* Grid used for internal generation of canvas tiles. This is created
* lazily so we have access to the view projection.
*
* @private
* @type {ol.tilegrid.TileGrid}
*/
this.tileGrid_ = null;
/**
* Tile range before the current animation or interaction. This is updated
* whenever the view is idle.
*
* @private
* @type {ol.TileRange}
*/
this.tileRange_ = new ol.TileRange(NaN, NaN, NaN, NaN);
/**
* @private
* @type {function()}
*/
this.requestMapRenderFrame_ = goog.bind(function() {
this.dirty_ = true;
mapRenderer.getMap().requestRenderFrame();
}, this);
};
goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
/**
* Get rid cached tiles. If the optional extent is provided, only tiles that
* intersect that extent will be removed.
* @param {Array.<ol.Extent>} extents extent Expire tiles within the provided
* extents. If the array is empty, all tiles will be expired.
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(extents) {
// buffer by max symbolizer size at rendered resolution
var resolution = this.renderedResolution_;
goog.asserts.assertNumber(resolution);
var tileCache = this.tileCache_;
var length = extents.length;
var extent;
if (length > 0) {
for (var i = 0; i < length; ++i) {
extent = ol.extent.clone(extents[i]);
ol.extent.buffer(extent, this.maxSymbolPixelDim_ * resolution / 2);
tileCache.pruneTileRange(
this.tileGrid_.getTileRangeForExtentAndZ(extent, 0));
}
} else {
tileCache.clear();
}
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.getImage = function() {
return this.canvas_;
};
/**
* @return {ol.layer.Vector} Vector layer.
*/
ol.renderer.canvas.VectorLayer.prototype.getVectorLayer = function() {
return /** @type {ol.layer.Vector} */ (this.getLayer());
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.getTransform = function() {
return this.transform_;
};
/**
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @param {function(string, ol.layer.Layer)} success Callback for
* successful queries. The passed arguments are the resulting feature
* information and the layer.
*/
ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
function(pixel, success) {
var callback = function(features, layer) {
success(layer.getTransformFeatureInfo()(features), layer);
};
this.getFeaturesForPixel(pixel, callback);
};
/**
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @param {function(Array.<ol.Feature>, ol.layer.Layer)} success Callback for
* successful queries. The passed arguments are the resulting features
* and the layer.
* @param {function()=} opt_error Callback for unsuccessful queries.
*/
ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
function(pixel, success, opt_error) {
// TODO What do we want to pass to the error callback?
var map = this.getMap();
var result = [];
var layer = this.getLayer();
var location = map.getCoordinateFromPixel(pixel);
var tileCoord = this.tileGrid_.getTileCoordForCoordAndZ(location, 0);
var key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
var cachedTile = this.tileCache_.get(key);
var symbolSizes = cachedTile[1];
var maxSymbolSize = cachedTile[2];
var symbolOffsets = cachedTile[3];
var halfMaxWidth = maxSymbolSize[0] / 2;
var halfMaxHeight = maxSymbolSize[1] / 2;
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
var candidates = layer.getFeaturesObjectForExtent(locationBbox,
map.getView().getView2D().getProjection());
if (goog.isNull(candidates)) {
// data is not loaded
if (goog.isDef(opt_error)) {
goog.global.setTimeout(function() { opt_error(); }, 0);
}
return;
}
var candidate, geom, type, symbolBounds, symbolSize, symbolOffset,
halfWidth, halfHeight, uid, coordinates, j;
for (var id in candidates) {
candidate = candidates[id];
if (candidate.getRenderIntent() ==
ol.layer.VectorLayerRenderIntent.HIDDEN) {
continue;
}
geom = candidate.getGeometry();
type = geom.getType();
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
// For points, check if the pixel coordinate is inside the candidate's
// symbol
uid = goog.getUid(candidate);
symbolSize = symbolSizes[uid];
symbolOffset = symbolOffsets[uid];
halfWidth = symbolSize[0] / 2;
halfHeight = symbolSize[1] / 2;
symbolBounds = ol.extent.boundingExtent([
[location[0] - halfWidth - symbolOffset[0],
location[1] - halfHeight + symbolOffset[1]],
[location[0] + halfWidth - symbolOffset[0],
location[1] + halfHeight + symbolOffset[1]]
]);
coordinates = geom.getCoordinates();
if (!goog.isArray(coordinates[0])) {
coordinates = [coordinates];
}
for (j = coordinates.length - 1; j >= 0; --j) {
if (ol.extent.containsCoordinate(symbolBounds, coordinates[j])) {
result.push(candidate);
break;
}
}
} else if (goog.isFunction(geom.containsCoordinate)) {
// For polygons, check if the pixel location is inside the polygon
if (geom.containsCoordinate(location)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
// For lines, check if the distance to the pixel location is
// within the rendered line width
if (2 * geom.distanceFromCoordinate(location) <=
symbolSizes[goog.getUid(candidate)][0]) {
result.push(candidate);
}
}
}
}
goog.global.setTimeout(function() { success(result, layer); }, 0);
};
/**
* @param {ol.layer.VectorEvent} event Vector layer event.
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.handleLayerChange_ = function(event) {
if (goog.isDef(this.renderedResolution_)) {
this.expireTiles_(event.extents);
}
this.requestMapRenderFrame_();
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
function(frameState, layerState) {
// TODO: consider bailing out here if rendered center and resolution
// have not changed. Requires that other change listeners set a dirty flag.
var view2DState = frameState.view2DState,
resolution = view2DState.resolution,
projection = view2DState.projection,
extent = frameState.extent,
layer = this.getVectorLayer(),
tileGrid = this.tileGrid_,
tileSize = [512, 512],
idle = !frameState.viewHints[ol.ViewHint.ANIMATING] &&
!frameState.viewHints[ol.ViewHint.INTERACTING];
// lazy tile grid creation
if (idle) {
// avoid rendering issues for very high zoom levels
var minResolution = ol.renderer.canvas.MIN_RESOLUTION;
var metersPerUnit = projection.getMetersPerUnit();
if (metersPerUnit) {
minResolution = minResolution / metersPerUnit;
}
var gridResolution = Math.max(resolution, minResolution);
if (gridResolution !== this.renderedResolution_) {
tileGrid = new ol.tilegrid.TileGrid({
origin: [0, 0],
projection: projection,
resolutions: [gridResolution],
tileSize: tileSize
});
this.tileCache_.clear();
this.tileGrid_ = tileGrid;
}
}
if (goog.isNull(tileGrid)) {
// We should only get here when the first call to prepareFrame happens
// during an animation. Try again in the next prepareFrame call.
return;
}
// set up transform for the layer canvas to be drawn to the map canvas
var tileResolution = tileGrid.getResolution(0);
if (idle) {
tileGrid.getTileRangeForExtentAndResolution(
extent, tileResolution, this.tileRange_);
}
var transform = this.transform_,
tileRange = this.tileRange_,
tileRangeExtent = tileGrid.getTileRangeExtent(0, tileRange),
sketchOrigin = ol.extent.getTopLeft(tileRangeExtent);
goog.vec.Mat4.makeIdentity(transform);
goog.vec.Mat4.translate(transform,
frameState.size[0] / 2,
frameState.size[1] / 2,
0);
goog.vec.Mat4.scale(transform,
tileResolution / resolution, tileResolution / resolution, 1);
goog.vec.Mat4.rotateZ(transform, view2DState.rotation);
goog.vec.Mat4.translate(transform,
(sketchOrigin[0] - view2DState.center[0]) / tileResolution,
(view2DState.center[1] - sketchOrigin[1]) / tileResolution,
0);
/**
* Fastest path out of here. This method is called many many times while
* there is nothing to do (e.g. while waiting for tiles from every other
* layer to load.) Do not put anything above here that is more expensive than
* necessary. And look for ways to get here faster.
*/
if (!this.dirty_ && this.renderedResolution_ === tileResolution &&
ol.extent.equals(this.renderedExtent_, tileRangeExtent)) {
return;
}
if (goog.isNull(this.tileArchetype_)) {
this.tileArchetype_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
this.tileArchetype_.width = tileSize[0];
this.tileArchetype_.height = tileSize[1];
}
/**
* Prepare the sketch canvas. This covers the currently visible tile range
* and will have rendered all newly visible features.
*/
var sketchCanvas = this.sketchCanvas_;
var sketchWidth = tileSize[0] * tileRange.getWidth();
var sketchHeight = tileSize[1] * tileRange.getHeight();
// transform for map coords to sketch canvas pixel coords
var sketchTransform = this.sketchTransform_;
var halfWidth = sketchWidth / 2;
var halfHeight = sketchHeight / 2;
goog.vec.Mat4.makeIdentity(sketchTransform);
goog.vec.Mat4.translate(sketchTransform,
halfWidth,
halfHeight,
0);
goog.vec.Mat4.scale(sketchTransform,
1 / tileResolution,
-1 / tileResolution,
1);
goog.vec.Mat4.translate(sketchTransform,
-(sketchOrigin[0] + halfWidth * tileResolution),
-(sketchOrigin[1] - halfHeight * tileResolution),
0);
// clear/resize sketch canvas
sketchCanvas.width = sketchWidth;
sketchCanvas.height = sketchHeight;
var sketchContext = /** @type {CanvasRenderingContext2D} */
(sketchCanvas.getContext('2d'));
var sketchCanvasRenderer = new ol.renderer.canvas.Vector(
sketchContext, sketchTransform, this.requestMapRenderFrame_);
// clear/resize final canvas
var finalCanvas = this.canvas_;
finalCanvas.width = sketchWidth;
finalCanvas.height = sketchHeight;
var finalContext = this.context_;
var featuresToRender = {};
var tilesToRender = {};
var tilesOnSketchCanvas = {};
// TODO make gutter configurable?
var tileGutter = 15 * tileResolution;
var tile, tileCoord, key, x, y, i, type;
var deferred = false;
var dirty = false;
var tileExtent, groups, group, j, numGroups, featuresObject, tileHasFeatures;
fetchTileData:
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(0, x, y);
key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
tilesToRender[key] = tileCoord;
} else if (idle) {
tileExtent = tileGrid.getTileCoordExtent(tileCoord);
tileExtent[0] -= tileGutter;
tileExtent[2] += tileGutter;
tileExtent[1] -= tileGutter;
tileExtent[3] += tileGutter;
tileHasFeatures = false;
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
projection, this.requestMapRenderFrame_);
if (goog.isNull(featuresObject)) {
deferred = true;
break fetchTileData;
}
tileHasFeatures = tileHasFeatures ||
!goog.object.isEmpty(featuresObject);
goog.object.extend(featuresToRender, featuresObject);
if (tileHasFeatures) {
tilesOnSketchCanvas[key] = tileCoord;
}
} else {
dirty = true;
}
}
}
this.dirty_ = dirty;
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender,
tileResolution);
numGroups = groups.length;
for (j = 0; j < numGroups; ++j) {
group = groups[j];
deferred = sketchCanvasRenderer.renderFeatures(group[0], group[1],
group[2]);
if (deferred) {
break;
}
}
if (!deferred) {
goog.object.extend(tilesToRender, tilesOnSketchCanvas);
}
var symbolSizes = sketchCanvasRenderer.getSymbolSizes(),
maxSymbolSize = sketchCanvasRenderer.getMaxSymbolSize(),
symbolOffsets = sketchCanvasRenderer.getSymbolOffsets();
// keep track of maximum pixel size for symbols rendered on this layer
this.maxSymbolPixelDim_ = Math.max(maxSymbolSize[0] / tileResolution,
maxSymbolSize[1] / tileResolution);
for (key in tilesToRender) {
tileCoord = tilesToRender[key];
if (this.tileCache_.containsKey(key)) {
tile = /** @type {HTMLCanvasElement} */ (this.tileCache_.get(key)[0]);
} else {
tile = /** @type {HTMLCanvasElement} */
(this.tileArchetype_.cloneNode(false));
tile.getContext('2d').drawImage(sketchCanvas,
(tileRange.minX - tileCoord.x) * tileSize[0],
(tileCoord.y - tileRange.maxY) * tileSize[1]);
// TODO: Create an ol.VectorTile subclass of ol.Tile
this.tileCache_.set(key,
[tile, symbolSizes, maxSymbolSize, symbolOffsets]);
}
finalContext.drawImage(tile,
tileSize[0] * (tileCoord.x - tileRange.minX),
tileSize[1] * (tileRange.maxY - tileCoord.y));
}
this.renderedResolution_ = tileResolution;
this.renderedExtent_ = tileRangeExtent;
if (!this.pendingCachePrune_) {
this.pendingCachePrune_ = true;
frameState.postRenderFunctions.push(goog.bind(this.pruneTileCache_, this));
}
};
/**
* Get rid of tiles that exceed the cache capacity.
* TODO: add a method to the cache to handle this
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.pruneTileCache_ = function() {
while (this.tileCache_.canExpireCache()) {
this.tileCache_.pop();
}
this.pendingCachePrune_ = false;
};
/**
* @type {number}
*/
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE = 128;

View File

@@ -0,0 +1,116 @@
goog.provide('ol.renderer.canvas.VectorLayer2');
goog.require('goog.dom');
goog.require('goog.vec.Mat4');
goog.require('ol.layer.Vector');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.canvas.Vector');
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} layer Vector layer.
*/
ol.renderer.canvas.VectorLayer2 = function(mapRenderer, layer) {
goog.base(this, mapRenderer, layer);
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.transform_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {function()}
*/
this.requestMapRenderFrame_ = goog.bind(function() {
mapRenderer.getMap().requestRenderFrame();
}, this);
};
goog.inherits(ol.renderer.canvas.VectorLayer2, ol.renderer.canvas.Layer);
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer2.prototype.composeFrame =
function(frameState, layerState, context) {
var extent = frameState.extent;
var view2DState = frameState.view2DState;
var viewCenter = view2DState.center;
var viewProjection = view2DState.projection;
var viewResolution = view2DState.resolution;
var viewRotation = view2DState.rotation;
var vectorLayer = this.getVectorLayer();
var features = vectorLayer.getFeaturesObjectForExtent(extent,
viewProjection, this.requestMapRenderFrame_);
if (goog.isNull(features)) {
return;
}
var transform = this.transform_;
goog.vec.Mat4.makeIdentity(transform);
goog.vec.Mat4.translate(transform,
frameState.size[0] / 2,
frameState.size[1] / 2,
0);
goog.vec.Mat4.scale(transform,
1 / viewResolution,
-1 / viewResolution,
1);
goog.vec.Mat4.rotateZ(transform, -viewRotation);
goog.vec.Mat4.translate(transform,
-viewCenter[0],
-viewCenter[1],
0);
var renderer = new ol.renderer.canvas.Vector(context, transform,
this.requestMapRenderFrame_);
var groups = vectorLayer.groupFeaturesBySymbolizerLiteral(features,
viewResolution);
var i, ii, group, deferred;
ii = groups.length;
for (i = 0; i < ii; ++i) {
group = groups[i];
deferred = renderer.renderFeatures(group[0], group[1], group[2]);
if (deferred) {
break;
}
}
};
/**
* @return {ol.layer.Vector} Vector layer.
*/
ol.renderer.canvas.VectorLayer2.prototype.getVectorLayer = function() {
return /** @type {ol.layer.Vector} */ (this.getLayer());
};
/**
* @param {ol.layer.VectorEvent} event Vector layer event.
* @private
*/
ol.renderer.canvas.VectorLayer2.prototype.handleLayerChange_ = function(event) {
this.requestMapRenderFrame_();
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer2.prototype.prepareFrame = goog.nullFunction;

View File

@@ -0,0 +1,642 @@
goog.provide('ol.renderer.canvas.Vector');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.vec.Mat4');
goog.require('ol.Feature');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.layer.VectorLayerRenderIntent');
goog.require('ol.style.IconLiteral');
goog.require('ol.style.LineLiteral');
goog.require('ol.style.Literal');
goog.require('ol.style.PointLiteral');
goog.require('ol.style.PolygonLiteral');
goog.require('ol.style.ShapeLiteral');
goog.require('ol.style.ShapeType');
goog.require('ol.style.TextLiteral');
/**
* @constructor
* @param {CanvasRenderingContext2D} context Context.
* @param {goog.vec.Mat4.Number} transform Transform.
* @param {function()=} opt_iconLoadedCallback Callback for deferred rendering
* when images need to be loaded before rendering.
*/
ol.renderer.canvas.Vector =
function(context, transform, opt_iconLoadedCallback) {
/**
* @type {goog.vec.Mat4.Number}
* @private
*/
this.transform_ = transform;
var vec = [1, 0, 0];
goog.vec.Mat4.multVec3NoTranslate(transform, vec, vec);
/**
* @type {number}
* @private
*/
this.inverseScale_ = 1 / Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
/**
* @type {CanvasRenderingContext2D}
* @private
*/
this.context_ = context;
/**
* @type {function()|undefined}
* @private
*/
this.iconLoadedCallback_ = opt_iconLoadedCallback;
/**
* @type {Object.<number, Array.<number>>}
* @private
*/
this.symbolSizes_ = {};
/**
* @type {Object.<number, Array.<number>>}
* @private
*/
this.symbolOffsets_ = {};
/**
* @type {Array.<number>}
* @private
*/
this.maxSymbolSize_ = [0, 0];
};
/**
* @return {Object.<number, Array.<number>>} Symbolizer sizes.
*/
ol.renderer.canvas.Vector.prototype.getSymbolSizes = function() {
return this.symbolSizes_;
};
/**
* @return {Object.<number, Array.<number>>} Symbolizer offsets.
*/
ol.renderer.canvas.Vector.prototype.getSymbolOffsets = function() {
return this.symbolOffsets_;
};
/**
* @return {Array.<number>} Maximum symbolizer size.
*/
ol.renderer.canvas.Vector.prototype.getMaxSymbolSize = function() {
return this.maxSymbolSize_;
};
/**
* @param {Array.<ol.Feature>} features Array of features.
* @param {ol.style.Literal} symbolizer Symbolizer.
* @param {Array} data Additional data.
* @return {boolean} true if deferred, false if rendered.
*/
ol.renderer.canvas.Vector.prototype.renderFeatures =
function(features, symbolizer, data) {
var deferred = false;
if (symbolizer instanceof ol.style.PointLiteral) {
deferred = this.renderPointFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.LineLiteral) {
this.renderLineStringFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.PolygonLiteral) {
this.renderPolygonFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.TextLiteral) {
this.renderText_(features, symbolizer, data);
}
return deferred;
};
/**
* @param {Array.<ol.Feature>} features Array of line features.
* @param {ol.style.LineLiteral} symbolizer Line symbolizer.
* @private
*/
ol.renderer.canvas.Vector.prototype.renderLineStringFeatures_ =
function(features, symbolizer) {
var context = this.context_,
i, ii, feature, id, currentSize, geometry, components, j, jj,
coordinates, coordinate, k, kk, strokeSize;
var vec = [NaN, NaN, 0];
var pixel = [NaN, NaN];
var lastPixel = [NaN, NaN];
context.globalAlpha = symbolizer.opacity;
context.strokeStyle = symbolizer.color;
context.lineWidth = symbolizer.width;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
strokeSize = context.lineWidth * this.inverseScale_;
context.beginPath();
for (i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
continue;
}
id = goog.getUid(feature);
currentSize = goog.isDef(this.symbolSizes_[id]) ?
this.symbolSizes_[id] : [0];
currentSize[0] = Math.max(currentSize[0], strokeSize);
this.symbolSizes_[id] = currentSize;
this.maxSymbolSize_ = [Math.max(currentSize[0], this.maxSymbolSize_[0]),
Math.max(currentSize[0], this.maxSymbolSize_[1])];
geometry = feature.getGeometry();
if (geometry instanceof ol.geom.LineString) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiLineString,
'Expected MultiLineString');
components = geometry.getComponents();
}
for (j = 0, jj = components.length; j < jj; ++j) {
coordinates = components[j].getCoordinates();
for (k = 0, kk = coordinates.length; k < kk; ++k) {
coordinate = coordinates[k];
vec[0] = coordinate[0];
vec[1] = coordinate[1];
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
if (k === 0) {
lastPixel[0] = NaN;
lastPixel[1] = NaN;
context.moveTo(vec[0], vec[1]);
} else {
pixel[0] = Math.round(vec[0]);
pixel[1] = Math.round(vec[1]);
if (pixel[0] !== lastPixel[0] || pixel[1] !== lastPixel[1]) {
context.lineTo(vec[0], vec[1]);
lastPixel[0] = pixel[0];
lastPixel[1] = pixel[1];
}
}
}
}
}
context.stroke();
};
/**
* @param {Array.<ol.Feature>} features Array of point features.
* @param {ol.style.PointLiteral} symbolizer Point symbolizer.
* @return {boolean} true if deferred, false if rendered.
* @private
*/
ol.renderer.canvas.Vector.prototype.renderPointFeatures_ =
function(features, symbolizer) {
var context = this.context_,
content, alpha, i, ii, feature, id, size, geometry, components, j, jj,
point, vec;
var xOffset = 0;
var yOffset = 0;
if (symbolizer instanceof ol.style.ShapeLiteral) {
content = ol.renderer.canvas.Vector.renderShape(symbolizer);
alpha = 1;
} else if (symbolizer instanceof ol.style.IconLiteral) {
content = ol.renderer.canvas.Vector.renderIcon(
symbolizer, this.iconLoadedCallback_);
alpha = symbolizer.opacity;
xOffset = symbolizer.xOffset;
yOffset = symbolizer.yOffset;
} else {
throw new Error('Unsupported symbolizer: ' + symbolizer);
}
if (goog.isNull(content)) {
return true;
}
var midWidth = Math.floor(content.width / 2);
var midHeight = Math.floor(content.height / 2);
var contentWidth = content.width * this.inverseScale_;
var contentHeight = content.height * this.inverseScale_;
var contentXOffset = xOffset * this.inverseScale_;
var contentYOffset = yOffset * this.inverseScale_;
context.save();
context.setTransform(1, 0, 0, 1, -midWidth, -midHeight);
context.globalAlpha = alpha;
for (i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
continue;
}
id = goog.getUid(feature);
size = this.symbolSizes_[id];
this.symbolSizes_[id] = goog.isDef(size) ?
[Math.max(size[0], contentWidth), Math.max(size[1], contentHeight)] :
[contentWidth, contentHeight];
this.symbolOffsets_[id] =
[xOffset * this.inverseScale_, yOffset * this.inverseScale_];
this.maxSymbolSize_ =
[Math.max(this.maxSymbolSize_[0],
this.symbolSizes_[id][0] + 2 * Math.abs(contentXOffset)),
Math.max(this.maxSymbolSize_[1],
this.symbolSizes_[id][1] + 2 * Math.abs(contentYOffset))];
geometry = feature.getGeometry();
if (geometry instanceof ol.geom.Point) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiPoint,
'Expected MultiPoint');
components = geometry.getComponents();
}
for (j = 0, jj = components.length; j < jj; ++j) {
point = components[j];
vec = [point.get(0), point.get(1), 0];
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
context.drawImage(content, Math.round(vec[0] + xOffset),
Math.round(vec[1] + yOffset),
content.width, content.height);
}
}
context.restore();
return false;
};
/**
* @param {Array.<ol.Feature>} features Array of features.
* @param {ol.style.TextLiteral} text Text symbolizer.
* @param {Array} texts Label text for each feature.
* @private
*/
ol.renderer.canvas.Vector.prototype.renderText_ =
function(features, text, texts) {
var context = this.context_,
feature, vecs, vec;
if (context.fillStyle !== text.color) {
context.fillStyle = text.color;
}
// font shorthand values must be given in the correct order
// see http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
context.font = text.fontWeight + ' ' +
text.fontSize + 'px ' +
text.fontFamily;
context.globalAlpha = text.opacity;
// TODO: make alignments configurable
context.textAlign = 'center';
context.textBaseline = 'middle';
var stroke = false;
if (goog.isDef(text.strokeColor)) {
stroke = true;
goog.asserts.assertString(text.strokeColor);
context.strokeStyle = text.strokeColor;
goog.asserts.assertNumber(text.strokeWidth);
context.lineWidth = text.strokeWidth;
}
for (var i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
continue;
}
vecs = ol.renderer.canvas.Vector.getLabelVectors(
feature.getGeometry());
for (var j = 0, jj = vecs.length; j < jj; ++j) {
vec = vecs[j];
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
if (stroke) {
if (text.strokeOpacity !== text.opacity) {
goog.asserts.assertNumber(text.strokeOpacity);
context.globalAlpha = text.strokeOpacity;
}
context.strokeText(texts[i], vec[0], vec[1]);
if (text.strokeOpacity !== text.opacity) {
context.globalAlpha = text.opacity;
}
}
context.fillText(texts[i], vec[0], vec[1]);
}
}
};
/**
* @param {Array.<ol.Feature>} features Array of polygon features.
* @param {ol.style.PolygonLiteral} symbolizer Polygon symbolizer.
* @private
*/
ol.renderer.canvas.Vector.prototype.renderPolygonFeatures_ =
function(features, symbolizer) {
var context = this.context_,
strokeColor = symbolizer.strokeColor,
strokeWidth = symbolizer.strokeWidth,
strokeOpacity = symbolizer.strokeOpacity,
fillColor = symbolizer.fillColor,
fillOpacity = symbolizer.fillOpacity,
globalAlpha,
i, ii, geometry, components, j, jj, poly,
rings, numRings, coordinates, coordinate, k, kk, feature;
var vec = [NaN, NaN, 0];
var pixel = [NaN, NaN];
var lastPixel = [NaN, NaN];
if (strokeColor) {
context.strokeStyle = strokeColor;
if (strokeWidth) {
context.lineWidth = strokeWidth;
}
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
}
if (fillColor) {
context.fillStyle = fillColor;
}
/**
* Four scenarios covered here:
* 1) stroke only, no holes - only need to have a single path
* 2) fill only, no holes - only need to have a single path
* 3) fill and stroke, no holes
* 4) holes - render polygon to sketch canvas first
*/
context.beginPath();
for (i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
continue;
}
geometry = feature.getGeometry();
if (geometry instanceof ol.geom.Polygon) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiPolygon,
'Expected MultiPolygon');
components = geometry.getComponents();
}
for (j = 0, jj = components.length; j < jj; ++j) {
poly = components[j];
rings = poly.getRings();
numRings = rings.length;
if (numRings > 0) {
// TODO: scenario 4
coordinates = rings[0].getCoordinates();
for (k = 0, kk = coordinates.length; k < kk; ++k) {
coordinate = coordinates[k];
vec[0] = coordinate[0];
vec[1] = coordinate[1];
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
if (k === 0) {
lastPixel[0] = NaN;
lastPixel[1] = NaN;
context.moveTo(vec[0], vec[1]);
} else {
pixel[0] = Math.round(vec[0]);
pixel[1] = Math.round(vec[1]);
if (pixel[0] !== lastPixel[0] || pixel[1] !== lastPixel[1]) {
context.lineTo(vec[0], vec[1]);
lastPixel[0] = pixel[0];
lastPixel[1] = pixel[1];
}
}
}
if (fillColor && strokeColor) {
// scenario 3 - fill and stroke each time
if (fillOpacity !== globalAlpha) {
goog.asserts.assertNumber(fillOpacity);
context.globalAlpha = fillOpacity;
globalAlpha = fillOpacity;
}
context.fill();
if (strokeOpacity !== globalAlpha) {
goog.asserts.assertNumber(strokeOpacity);
context.globalAlpha = strokeOpacity;
globalAlpha = strokeOpacity;
}
context.stroke();
if (i < ii - 1 || j < jj - 1) {
context.beginPath();
}
}
}
}
}
if (!(fillColor && strokeColor)) {
if (fillColor) {
// scenario 2 - fill all at once
if (fillOpacity !== globalAlpha) {
goog.asserts.assertNumber(fillOpacity);
context.globalAlpha = fillOpacity;
globalAlpha = fillOpacity;
}
context.fill();
} else {
// scenario 1 - stroke all at once
if (strokeOpacity !== globalAlpha) {
goog.asserts.assertNumber(strokeOpacity);
context.globalAlpha = strokeOpacity;
globalAlpha = strokeOpacity;
}
context.stroke();
}
}
};
/**
* @param {ol.style.ShapeLiteral} circle Shape symbolizer.
* @return {!HTMLCanvasElement} Canvas element.
* @private
*/
ol.renderer.canvas.Vector.renderCircle_ = function(circle) {
var strokeWidth = circle.strokeWidth || 0,
size = circle.size + (2 * strokeWidth) + 1,
mid = size / 2,
canvas = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS)),
context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d')),
fillColor = circle.fillColor,
strokeColor = circle.strokeColor,
twoPi = Math.PI * 2;
canvas.height = size;
canvas.width = size;
if (fillColor) {
context.fillStyle = fillColor;
}
if (strokeColor) {
context.lineWidth = strokeWidth;
context.strokeStyle = strokeColor;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
}
context.beginPath();
context.arc(mid, mid, circle.size / 2, 0, twoPi, true);
if (fillColor) {
goog.asserts.assertNumber(circle.fillOpacity);
context.globalAlpha = circle.fillOpacity;
context.fill();
}
if (strokeColor) {
goog.asserts.assertNumber(circle.strokeOpacity);
context.globalAlpha = circle.strokeOpacity;
context.stroke();
}
return canvas;
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @return {Array.<goog.vec.Vec3.AnyType>} Renderable geometry vectors.
*/
ol.renderer.canvas.Vector.getLabelVectors = function(geometry) {
if (geometry instanceof ol.geom.AbstractCollection) {
var components = geometry.getComponents();
var numComponents = components.length;
var result = [];
for (var i = 0; i < numComponents; ++i) {
result.push.apply(result,
ol.renderer.canvas.Vector.getLabelVectors(components[i]));
}
return result;
}
var type = geometry.getType();
if (type == ol.geom.GeometryType.POINT) {
return [[geometry.get(0), geometry.get(1), 0]];
}
if (type == ol.geom.GeometryType.POLYGON) {
var coordinates = geometry.getInteriorPoint();
return [[coordinates[0], coordinates[1], 0]];
}
throw new Error('Label rendering not implemented for geometry type: ' +
type);
};
/**
* @param {ol.style.ShapeLiteral} shape Shape symbolizer.
* @return {!HTMLCanvasElement} Canvas element.
*/
ol.renderer.canvas.Vector.renderShape = function(shape) {
var canvas;
if (shape.type === ol.style.ShapeType.CIRCLE) {
canvas = ol.renderer.canvas.Vector.renderCircle_(shape);
} else {
throw new Error('Unsupported shape type: ' + shape);
}
return canvas;
};
/**
* @param {ol.style.IconLiteral} icon Icon literal.
* @param {function()=} opt_callback Callback which will be called when
* the icon is loaded and rendering will work without deferring.
* @return {HTMLImageElement} image element of null if deferred.
*/
ol.renderer.canvas.Vector.renderIcon = function(icon, opt_callback) {
var url = icon.url;
var image = ol.renderer.canvas.Vector.icons_[url];
var deferred = false;
if (!goog.isDef(image)) {
deferred = true;
image = /** @type {HTMLImageElement} */
(goog.dom.createElement(goog.dom.TagName.IMG));
goog.events.listenOnce(image, goog.events.EventType.ERROR,
goog.bind(ol.renderer.canvas.Vector.handleIconError_, null,
opt_callback),
false, ol.renderer.canvas.Vector.renderIcon);
goog.events.listenOnce(image, goog.events.EventType.LOAD,
goog.bind(ol.renderer.canvas.Vector.handleIconLoad_, null,
opt_callback),
false, ol.renderer.canvas.Vector.renderIcon);
image.setAttribute('src', url);
} else if (!goog.isNull(image)) {
var width = icon.width,
height = icon.height;
if (goog.isDef(width) && goog.isDef(height)) {
image.width = width;
image.height = height;
} else if (goog.isDef(width)) {
image.height = width / image.width * image.height;
image.width = width;
} else if (goog.isDef(height)) {
image.width = height / image.height * image.width;
image.height = height;
}
}
return deferred ? null : image;
};
/**
* @type {Object.<string, HTMLImageElement>}
* @private
*/
ol.renderer.canvas.Vector.icons_ = {};
/**
* @param {function()=} opt_callback Callback.
* @param {Event=} opt_event Event.
* @private
*/
ol.renderer.canvas.Vector.handleIconError_ =
function(opt_callback, opt_event) {
if (goog.isDef(opt_event)) {
var url = opt_event.target.getAttribute('src');
ol.renderer.canvas.Vector.icons_[url] = null;
ol.renderer.canvas.Vector.handleIconLoad_(opt_callback, opt_event);
}
};
/**
* @param {function()=} opt_callback Callback.
* @param {Event=} opt_event Event.
* @private
*/
ol.renderer.canvas.Vector.handleIconLoad_ =
function(opt_callback, opt_event) {
if (goog.isDef(opt_event)) {
var url = opt_event.target.getAttribute('src');
ol.renderer.canvas.Vector.icons_[url] =
/** @type {HTMLImageElement} */ (opt_event.target);
}
if (goog.isDef(opt_callback)) {
opt_callback();
}
};

View File

@@ -0,0 +1,19 @@
goog.provide('ol.source.FeatureInfoSource');
/**
* @interface
* @todo stability experimental
*/
ol.source.FeatureInfoSource = function() {};
/**
* @param {ol.Pixel} pixel Pixel.
* @param {ol.Map} map The map that the pixel belongs to.
* @param {function(string)} success Callback with feature info.
* @param {function()=} opt_error Optional error callback.
*/
ol.source.FeatureInfoSource.prototype.getFeatureInfoForPixel =
goog.abstractMethod;

View File

@@ -0,0 +1 @@
@exportClass ol.source.Vector ol.source.VectorOptions

View File

@@ -0,0 +1,96 @@
goog.provide('ol.source.Vector');
goog.require('goog.asserts');
goog.require('goog.net.XhrIo');
goog.require('ol.source.Source');
/**
* @enum {number}
*/
ol.source.VectorLoadState = {
IDLE: 0,
LOADING: 1,
LOADED: 2,
ERROR: 3
};
/**
* @constructor
* @extends {ol.source.Source}
* @param {ol.source.VectorOptions} options Vector source options.
* @todo stability experimental
*/
ol.source.Vector = function(options) {
/**
* @private
* @type {Object|string}
*/
this.data_ = goog.isDef(options.data) ? options.data : null;
/**
* @private
* @type {ol.source.VectorLoadState}
*/
this.loadState_ = ol.source.VectorLoadState.IDLE;
/**
* @private
* @type {ol.parser.Parser}
*/
this.parser_ = goog.isDef(options.parser) ? options.parser : null;
/**
* @private
* @type {string|undefined}
*/
this.url_ = options.url;
goog.base(this, {
attributions: options.attributions,
extent: options.extent,
logo: options.logo,
projection: options.projection
});
};
goog.inherits(ol.source.Vector, ol.source.Source);
/**
* @param {ol.layer.Vector} layer Layer that parses the data.
* @param {ol.Extent} extent Extent that needs to be fetched.
* @param {ol.proj.Projection} projection Projection of the view.
* @param {function()=} opt_callback Callback which is called when features are
* parsed after loading.
* @return {ol.source.VectorLoadState} The current load state.
*/
ol.source.Vector.prototype.prepareFeatures = function(layer, extent, projection,
opt_callback) {
// TODO: Implement strategies. BBOX aware strategies will need the extent.
if (goog.isDef(this.url_) &&
this.loadState_ == ol.source.VectorLoadState.IDLE) {
this.loadState_ = ol.source.VectorLoadState.LOADING;
goog.net.XhrIo.send(this.url_, goog.bind(function(event) {
var xhr = event.target;
if (xhr.isSuccess()) {
// TODO: Get source projection from data if supported by parser.
layer.parseFeatures(xhr.getResponseText(), this.parser_, projection);
this.loadState_ = ol.source.VectorLoadState.LOADED;
if (goog.isDef(opt_callback)) {
opt_callback();
}
} else {
// TODO: Error handling.
this.loadState_ = ol.source.VectorLoadState.ERROR;
}
}, this));
} else if (!goog.isNull(this.data_)) {
layer.parseFeatures(this.data_, this.parser_, projection);
this.data_ = null;
this.loadState_ = ol.source.VectorLoadState.LOADED;
}
return this.loadState_;
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.source.WMSGetFeatureInfoMethod

9
old/src/ol/style.exports Normal file
View File

@@ -0,0 +1,9 @@
@exportClass ol.style.Fill ol.style.FillOptions
@exportClass ol.style.Icon ol.style.IconOptions
@exportClass ol.style.Rule ol.style.RuleOptions
@exportClass ol.style.Shape ol.style.ShapeOptions
@exportClass ol.style.Stroke ol.style.StrokeOptions
@exportClass ol.style.Style ol.style.StyleOptions
@exportClass ol.style.Text ol.style.TextOptions
@exportSymbol ol.style.ShapeType
@exportProperty ol.style.ShapeType.CIRCLE

3
old/src/ol/style.jsdoc Normal file
View File

@@ -0,0 +1,3 @@
/**
* @namespace ol.style
*/

View File

@@ -0,0 +1,160 @@
goog.provide('ol.style.Fill');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Literal');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.PolygonLiteral');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @extends {ol.style.Symbolizer}
* @param {ol.style.FillOptions=} opt_options Polygon options.
* @todo stability experimental
*/
ol.style.Fill = function(opt_options) {
goog.base(this);
var options = opt_options || {};
/**
* @type {ol.expr.Expression}
* @private
*/
this.color_ = !goog.isDefAndNotNull(options.color) ?
new ol.expr.Literal(ol.style.FillDefaults.color) :
(options.color instanceof ol.expr.Expression) ?
options.color : new ol.expr.Literal(options.color);
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDefAndNotNull(options.opacity) ?
new ol.expr.Literal(ol.style.FillDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
/**
* @type {ol.expr.Expression}
* @private
*/
this.zIndex_ = !goog.isDefAndNotNull(options.zIndex) ?
new ol.expr.Literal(ol.style.FillDefaults.zIndex) :
(options.zIndex instanceof ol.expr.Expression) ?
options.zIndex : new ol.expr.Literal(options.zIndex);
};
goog.inherits(ol.style.Fill, ol.style.Symbolizer);
/**
* @inheritDoc
* @return {ol.style.PolygonLiteral} Literal shape symbolizer.
*/
ol.style.Fill.prototype.createLiteral = function(featureOrType) {
var feature, type;
if (featureOrType instanceof ol.Feature) {
feature = featureOrType;
var geometry = feature.getGeometry();
type = geometry ? geometry.getType() : null;
} else {
type = featureOrType;
}
var literal = null;
if (type === ol.geom.GeometryType.POLYGON ||
type === ol.geom.GeometryType.MULTIPOLYGON) {
var color = ol.expr.evaluateFeature(this.color_, feature);
goog.asserts.assertString(
color, 'color must be a string');
var opacity = Number(ol.expr.evaluateFeature(this.opacity_, feature));
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
literal = new ol.style.PolygonLiteral({
fillColor: color,
fillOpacity: opacity,
zIndex: zIndex
});
}
return literal;
};
/**
* Get the fill color.
* @return {ol.expr.Expression} Fill color.
*/
ol.style.Fill.prototype.getColor = function() {
return this.color_;
};
/**
* Get the fill opacity.
* @return {ol.expr.Expression} Fill opacity.
*/
ol.style.Fill.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the fill zIndex.
* @return {ol.expr.Expression} Fill zIndex.
*/
ol.style.Fill.prototype.getZIndex = function() {
return this.zIndex_;
};
/**
* Set the fill color.
* @param {ol.expr.Expression} color Fill color.
*/
ol.style.Fill.prototype.setColor = function(color) {
goog.asserts.assertInstanceof(color, ol.expr.Expression);
this.color_ = color;
};
/**
* Set the fill opacity.
* @param {ol.expr.Expression} opacity Fill opacity.
*/
ol.style.Fill.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the fill zIndex.
* @param {ol.expr.Expression} zIndex Fill zIndex.
*/
ol.style.Fill.prototype.setZIndex = function(zIndex) {
goog.asserts.assertInstanceof(zIndex, ol.expr.Expression);
this.zIndex_ = zIndex;
};
/**
* @typedef {{fillColor: string,
* fillOpacity: number,
* zIndex: number}}
*/
ol.style.FillDefaults = {
color: '#ffffff',
opacity: 0.4,
zIndex: 0
};

View File

@@ -0,0 +1,70 @@
goog.provide('ol.style.IconLiteral');
goog.require('goog.asserts');
goog.require('ol.style.PointLiteral');
/**
* @typedef {{url: string,
* width: (number|undefined),
* height: (number|undefined),
* opacity: number,
* rotation: number,
* xOffset: number,
* yOffset: number,
* zIndex: number}}
*/
ol.style.IconLiteralOptions;
/**
* @constructor
* @extends {ol.style.PointLiteral}
* @param {ol.style.IconLiteralOptions} options Icon literal options.
*/
ol.style.IconLiteral = function(options) {
/** @type {string} */
this.url = options.url;
/** @type {number|undefined} */
this.width = options.width;
/** @type {number|undefined} */
this.height = options.height;
/** @type {number} */
this.opacity = options.opacity;
/** @type {number} */
this.rotation = options.rotation;
/** @type {number} */
this.xOffset = options.xOffset;
/** @type {number} */
this.yOffset = options.yOffset;
goog.asserts.assertNumber(
options.zIndex, 'zIndex must be a number');
/** @type {number} */
this.zIndex = options.zIndex;
};
goog.inherits(ol.style.IconLiteral, ol.style.PointLiteral);
/**
* @inheritDoc
*/
ol.style.IconLiteral.prototype.equals = function(other) {
return this.url == other.url &&
this.width == other.width &&
this.height == other.height &&
this.opacity == other.opacity &&
this.rotation == other.rotation &&
this.xOffset == other.xOffset &&
this.yOffset == other.yOffset &&
this.zIndex == other.zIndex;
};

View File

@@ -0,0 +1,329 @@
goog.provide('ol.style.Icon');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Literal');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.IconLiteral');
goog.require('ol.style.Point');
/**
* @constructor
* @extends {ol.style.Point}
* @param {ol.style.IconOptions} options Icon options.
* @todo stability experimental
*/
ol.style.Icon = function(options) {
goog.base(this);
goog.asserts.assert(options.url, 'url must be set');
/**
* @type {ol.expr.Expression}
* @private
*/
this.url_ = (options.url instanceof ol.expr.Expression) ?
options.url : new ol.expr.Literal(options.url);
/**
* @type {ol.expr.Expression}
* @private
*/
this.width_ = !goog.isDef(options.width) ?
null :
(options.width instanceof ol.expr.Expression) ?
options.width : new ol.expr.Literal(options.width);
/**
* @type {ol.expr.Expression}
* @private
*/
this.height_ = !goog.isDef(options.height) ?
null :
(options.height instanceof ol.expr.Expression) ?
options.height : new ol.expr.Literal(options.height);
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.expr.Literal(ol.style.IconDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
/**
* @type {ol.expr.Expression}
* @private
*/
this.rotation_ = !goog.isDef(options.rotation) ?
new ol.expr.Literal(ol.style.IconDefaults.rotation) :
(options.rotation instanceof ol.expr.Expression) ?
options.rotation : new ol.expr.Literal(options.rotation);
/**
* @type {ol.expr.Expression}
* @private
*/
this.xOffset_ = !goog.isDef(options.xOffset) ?
new ol.expr.Literal(ol.style.IconDefaults.xOffset) :
(options.xOffset instanceof ol.expr.Expression) ?
options.xOffset : new ol.expr.Literal(options.xOffset);
/**
* @type {ol.expr.Expression}
* @private
*/
this.yOffset_ = !goog.isDef(options.yOffset) ?
new ol.expr.Literal(ol.style.IconDefaults.yOffset) :
(options.yOffset instanceof ol.expr.Expression) ?
options.yOffset : new ol.expr.Literal(options.yOffset);
/**
* @type {ol.expr.Expression}
* @private
*/
this.zIndex_ = !goog.isDefAndNotNull(options.zIndex) ?
new ol.expr.Literal(ol.style.IconDefaults.zIndex) :
(options.zIndex instanceof ol.expr.Expression) ?
options.zIndex : new ol.expr.Literal(options.zIndex);
};
goog.inherits(ol.style.Icon, ol.style.Point);
/**
* @inheritDoc
* @return {ol.style.IconLiteral} Literal shape symbolizer.
*/
ol.style.Icon.prototype.createLiteral = function(featureOrType) {
var feature, type;
if (featureOrType instanceof ol.Feature) {
feature = featureOrType;
var geometry = feature.getGeometry();
type = geometry ? geometry.getType() : null;
} else {
type = featureOrType;
}
var literal = null;
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
var url = ol.expr.evaluateFeature(this.url_, feature);
goog.asserts.assertString(url, 'url must be a string');
goog.asserts.assert(url != '#', 'url must not be "#"');
var width;
if (!goog.isNull(this.width_)) {
width = Number(ol.expr.evaluateFeature(this.width_, feature));
goog.asserts.assert(!isNaN(width), 'width must be a number');
}
var height;
if (!goog.isNull(this.height_)) {
height = Number(ol.expr.evaluateFeature(this.height_, feature));
goog.asserts.assertNumber(height, 'height must be a number');
}
var opacity = Number(ol.expr.evaluateFeature(this.opacity_, feature));
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
var rotation = Number(ol.expr.evaluateFeature(this.rotation_, feature));
goog.asserts.assert(!isNaN(rotation), 'rotation must be a number');
var xOffset = Number(ol.expr.evaluateFeature(this.xOffset_, feature));
goog.asserts.assert(!isNaN(xOffset), 'xOffset must be a number');
var yOffset = Number(ol.expr.evaluateFeature(this.yOffset_, feature));
goog.asserts.assert(!isNaN(yOffset), 'yOffset must be a number');
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
literal = new ol.style.IconLiteral({
url: url,
width: width,
height: height,
opacity: opacity,
rotation: rotation,
xOffset: xOffset,
yOffset: yOffset,
zIndex: zIndex
});
}
return literal;
};
/**
* Get the height.
* @return {ol.expr.Expression} Icon height.
*/
ol.style.Icon.prototype.getHeight = function() {
return this.height_;
};
/**
* Get the opacity.
* @return {ol.expr.Expression} Opacity.
*/
ol.style.Icon.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the rotation.
* @return {ol.expr.Expression} Icon rotation.
*/
ol.style.Icon.prototype.getRotation = function() {
return this.rotation_;
};
/**
* Get the URL.
* @return {ol.expr.Expression} Icon URL.
*/
ol.style.Icon.prototype.getUrl = function() {
return this.url_;
};
/**
* Get the width.
* @return {ol.expr.Expression} Icon width.
*/
ol.style.Icon.prototype.getWidth = function() {
return this.width_;
};
/**
* Get the xOffset.
* @return {ol.expr.Expression} Icon xOffset.
*/
ol.style.Icon.prototype.getXOffset = function() {
return this.xOffset_;
};
/**
* Get the yOffset.
* @return {ol.expr.Expression} Icon yOffset.
*/
ol.style.Icon.prototype.getYOffset = function() {
return this.yOffset_;
};
/**
* Get the zIndex.
* @return {ol.expr.Expression} Icon zIndex.
*/
ol.style.Icon.prototype.getZIndex = function() {
return this.zIndex_;
};
/**
* Set the height.
* @param {ol.expr.Expression} height Icon height.
*/
ol.style.Icon.prototype.setHeight = function(height) {
goog.asserts.assertInstanceof(height, ol.expr.Expression);
this.height_ = height;
};
/**
* Set the opacity.
* @param {ol.expr.Expression} opacity Opacity.
*/
ol.style.Icon.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the rotation.
* @param {ol.expr.Expression} rotation Icon rotation.
*/
ol.style.Icon.prototype.setRotation = function(rotation) {
goog.asserts.assertInstanceof(rotation, ol.expr.Expression);
this.rotation_ = rotation;
};
/**
* Set the URL.
* @param {ol.expr.Expression} url Icon URL.
*/
ol.style.Icon.prototype.setUrl = function(url) {
goog.asserts.assertInstanceof(url, ol.expr.Expression);
this.url_ = url;
};
/**
* Set the width.
* @param {ol.expr.Expression} width Icon width.
*/
ol.style.Icon.prototype.setWidth = function(width) {
goog.asserts.assertInstanceof(width, ol.expr.Expression);
this.width_ = width;
};
/**
* Set the xOffset.
* @param {ol.expr.Expression} xOffset Icon xOffset.
*/
ol.style.Icon.prototype.setXOffset = function(xOffset) {
goog.asserts.assertInstanceof(xOffset, ol.expr.Expression);
this.xOffset_ = xOffset;
};
/**
* Set the yOffset.
* @param {ol.expr.Expression} yOffset Icon yOffset.
*/
ol.style.Icon.prototype.setYOffset = function(yOffset) {
goog.asserts.assertInstanceof(yOffset, ol.expr.Expression);
this.yOffset_ = yOffset;
};
/**
* Set the zIndex.
* @param {ol.expr.Expression} zIndex Icon zIndex.
*/
ol.style.Icon.prototype.setZIndex = function(zIndex) {
goog.asserts.assertInstanceof(zIndex, ol.expr.Expression);
this.zIndex_ = zIndex;
};
/**
* @typedef {{opacity: number,
* rotation: number,
* xOffset: number,
* yOffset: number,
* zIndex: number}}
*/
ol.style.IconDefaults = {
opacity: 1,
rotation: 0,
xOffset: 0,
yOffset: 0,
zIndex: 0
};

View File

@@ -0,0 +1,57 @@
goog.provide('ol.style.LineLiteral');
goog.require('goog.asserts');
goog.require('ol.style.Literal');
/**
* @typedef {{color: string,
* opacity: number,
* width: number,
* zIndex: number}}
*/
ol.style.LineLiteralOptions;
/**
* @constructor
* @extends {ol.style.Literal}
* @param {ol.style.LineLiteralOptions} options Line literal options.
*/
ol.style.LineLiteral = function(options) {
goog.base(this);
goog.asserts.assertString(
options.color, 'color must be a string');
/** @type {string} */
this.color = options.color;
goog.asserts.assertNumber(
options.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = options.opacity;
goog.asserts.assertNumber(
options.width, 'width must be a number');
/** @type {number} */
this.width = options.width;
goog.asserts.assertNumber(
options.zIndex, 'zIndex must be a number');
/** @type {number} */
this.zIndex = options.zIndex;
};
goog.inherits(ol.style.LineLiteral, ol.style.Literal);
/**
* @inheritDoc
*/
ol.style.LineLiteral.prototype.equals = function(other) {
return this.color == other.color &&
this.opacity == other.opacity &&
this.width == other.width &&
this.zIndex == other.zIndex;
};

View File

@@ -0,0 +1,16 @@
goog.provide('ol.style.Literal');
/**
* @constructor
*/
ol.style.Literal = function() {};
/**
* @param {ol.style.Literal} symbolizerLiteral Symbolizer literal to
* compare to.
* @return {boolean} Is the passed symbolizer literal equal to this instance?
*/
ol.style.Literal.prototype.equals = goog.abstractMethod;

View File

@@ -0,0 +1,14 @@
goog.provide('ol.style.PointLiteral');
goog.require('ol.style.Literal');
/**
* @constructor
* @extends {ol.style.Literal}
*/
ol.style.PointLiteral = function() {
goog.base(this);
};
goog.inherits(ol.style.PointLiteral, ol.style.Literal);

View File

@@ -0,0 +1,20 @@
goog.provide('ol.style.Point');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @extends {ol.style.Symbolizer}
*/
ol.style.Point = function() {
goog.base(this);
};
goog.inherits(ol.style.Point, ol.style.Symbolizer);
/**
* @inheritDoc
*/
ol.style.Point.prototype.createLiteral = goog.abstractMethod;

View File

@@ -0,0 +1,89 @@
goog.provide('ol.style.PolygonLiteral');
goog.require('goog.asserts');
goog.require('ol.style.Literal');
/**
* @typedef {{fillColor: (string|undefined),
* fillOpacity: (number|undefined),
* strokeColor: (string|undefined),
* strokeOpacity: (number|undefined),
* strokeWidth: (number|undefined),
* zIndex: number}}
*/
ol.style.PolygonLiteralOptions;
/**
* @constructor
* @extends {ol.style.Literal}
* @param {ol.style.PolygonLiteralOptions} options Polygon literal options.
*/
ol.style.PolygonLiteral = function(options) {
goog.base(this);
/** @type {string|undefined} */
this.fillColor = options.fillColor;
if (goog.isDef(options.fillColor)) {
goog.asserts.assertString(options.fillColor, 'fillColor must be a string');
}
/** @type {number|undefined} */
this.fillOpacity = options.fillOpacity;
if (goog.isDef(options.fillOpacity)) {
goog.asserts.assertNumber(
options.fillOpacity, 'fillOpacity must be a number');
}
/** @type {string|undefined} */
this.strokeColor = options.strokeColor;
if (goog.isDef(this.strokeColor)) {
goog.asserts.assertString(
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeOpacity = options.strokeOpacity;
if (goog.isDef(this.strokeOpacity)) {
goog.asserts.assertNumber(
this.strokeOpacity, 'strokeOpacity must be a number');
}
/** @type {number|undefined} */
this.strokeWidth = options.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
goog.asserts.assertNumber(
this.strokeWidth, 'strokeWidth must be a number');
}
// fill and/or stroke properties must be defined
var fillDef = goog.isDef(this.fillColor) && goog.isDef(this.fillOpacity);
var strokeDef = goog.isDef(this.strokeColor) &&
goog.isDef(this.strokeOpacity) &&
goog.isDef(this.strokeWidth);
goog.asserts.assert(fillDef || strokeDef,
'Either fillColor and fillOpacity or ' +
'strokeColor and strokeOpacity and strokeWidth must be set');
goog.asserts.assertNumber(
options.zIndex, 'zIndex must be a number');
/** @type {number} */
this.zIndex = options.zIndex;
};
goog.inherits(ol.style.PolygonLiteral, ol.style.Literal);
/**
* @inheritDoc
*/
ol.style.PolygonLiteral.prototype.equals = function(other) {
return this.fillColor == other.fillColor &&
this.fillOpacity == other.fillOpacity &&
this.strokeColor == other.strokeColor &&
this.strokeOpacity == other.strokeOpacity &&
this.strokeWidth == other.strokeWidth &&
this.zIndex == other.zIndex;
};

80
old/src/ol/style/rule.js Normal file
View File

@@ -0,0 +1,80 @@
goog.provide('ol.style.Rule');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @param {ol.style.RuleOptions} options Rule options.
* @todo stability experimental
*/
ol.style.Rule = function(options) {
var filter = null;
if (goog.isDef(options.filter)) {
if (goog.isString(options.filter)) {
filter = ol.expr.parse(options.filter);
} else {
goog.asserts.assert(options.filter instanceof ol.expr.Expression);
filter = options.filter;
}
}
/**
* @type {ol.expr.Expression}
* @private
*/
this.filter_ = filter;
/**
* @type {Array.<ol.style.Symbolizer>}
* @private
*/
this.symbolizers_ = goog.isDef(options.symbolizers) ?
options.symbolizers : [];
/**
* @type {number}
* @private
*/
this.minResolution_ = goog.isDef(options.minResolution) ?
options.minResolution : 0;
/**
* @type {number}
* @private
*/
this.maxResolution_ = goog.isDef(options.maxResolution) ?
options.maxResolution : Infinity;
};
/**
* @param {ol.Feature} feature Feature.
* @param {number} resolution Map resolution.
* @return {boolean} Does the rule apply to the feature?
*/
ol.style.Rule.prototype.applies = function(feature, resolution) {
var applies = resolution >= this.minResolution_ &&
resolution < this.maxResolution_;
if (applies && !goog.isNull(this.filter_)) {
applies = !!ol.expr.evaluateFeature(this.filter_, feature);
}
return applies;
};
/**
* @return {Array.<ol.style.Symbolizer>} Symbolizers.
*/
ol.style.Rule.prototype.getSymbolizers = function() {
return this.symbolizers_;
};

View File

@@ -0,0 +1,110 @@
goog.provide('ol.style.ShapeLiteral');
goog.provide('ol.style.ShapeType');
goog.require('goog.asserts');
goog.require('ol.style.PointLiteral');
/**
* @enum {string}
* @todo stability experimental
*/
ol.style.ShapeType = {
CIRCLE: 'circle'
};
/**
* @typedef {{type: (ol.style.ShapeType),
* size: (number),
* fillColor: (string|undefined),
* fillOpacity: (number|undefined),
* strokeColor: (string|undefined),
* strokeOpacity: (number|undefined),
* strokeWidth: (number|undefined),
* zIndex: number}}
*/
ol.style.ShapeLiteralOptions;
/**
* @constructor
* @extends {ol.style.PointLiteral}
* @param {ol.style.ShapeLiteralOptions} options Shape literal options.
*/
ol.style.ShapeLiteral = function(options) {
goog.asserts.assertString(options.type, 'type must be a string');
/** @type {ol.style.ShapeType} */
this.type = options.type;
goog.asserts.assertNumber(options.size, 'size must be a number');
/** @type {number} */
this.size = options.size;
/** @type {string|undefined} */
this.fillColor = options.fillColor;
if (goog.isDef(options.fillColor)) {
goog.asserts.assertString(options.fillColor, 'fillColor must be a string');
}
/** @type {number|undefined} */
this.fillOpacity = options.fillOpacity;
if (goog.isDef(options.fillOpacity)) {
goog.asserts.assertNumber(
options.fillOpacity, 'fillOpacity must be a number');
}
/** @type {string|undefined} */
this.strokeColor = options.strokeColor;
if (goog.isDef(this.strokeColor)) {
goog.asserts.assertString(
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeOpacity = options.strokeOpacity;
if (goog.isDef(this.strokeOpacity)) {
goog.asserts.assertNumber(
this.strokeOpacity, 'strokeOpacity must be a number');
}
/** @type {number|undefined} */
this.strokeWidth = options.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
goog.asserts.assertNumber(
this.strokeWidth, 'strokeWidth must be a number');
}
// fill and/or stroke properties must be defined
var fillDef = goog.isDef(this.fillColor) && goog.isDef(this.fillOpacity);
var strokeDef = goog.isDef(this.strokeColor) &&
goog.isDef(this.strokeOpacity) &&
goog.isDef(this.strokeWidth);
goog.asserts.assert(fillDef || strokeDef,
'Either fillColor and fillOpacity or ' +
'strokeColor and strokeOpacity and strokeWidth must be set');
goog.asserts.assertNumber(
options.zIndex, 'zIndex must be a number');
/** @type {number} */
this.zIndex = options.zIndex;
};
goog.inherits(ol.style.ShapeLiteral, ol.style.PointLiteral);
/**
* @inheritDoc
*/
ol.style.ShapeLiteral.prototype.equals = function(other) {
return this.type == other.type &&
this.size == other.size &&
this.fillColor == other.fillColor &&
this.fillOpacity == other.fillOpacity &&
this.strokeColor == other.strokeColor &&
this.strokeOpacity == other.strokeOpacity &&
this.strokeWidth == other.strokeWidth &&
this.zIndex == other.zIndex;
};

View File

@@ -0,0 +1,241 @@
goog.provide('ol.style.Shape');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Literal');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.Fill');
goog.require('ol.style.Point');
goog.require('ol.style.ShapeLiteral');
goog.require('ol.style.ShapeType');
goog.require('ol.style.Stroke');
/**
* @constructor
* @extends {ol.style.Point}
* @param {ol.style.ShapeOptions} options Shape options.
* @todo stability experimental
*/
ol.style.Shape = function(options) {
goog.base(this);
/**
* @type {ol.style.ShapeType}
* @private
*/
this.type_ = /** @type {ol.style.ShapeType} */ (goog.isDef(options.type) ?
options.type : ol.style.ShapeDefaults.type);
/**
* @type {ol.expr.Expression}
* @private
*/
this.size_ = !goog.isDefAndNotNull(options.size) ?
new ol.expr.Literal(ol.style.ShapeDefaults.size) :
(options.size instanceof ol.expr.Expression) ?
options.size : new ol.expr.Literal(options.size);
/**
* @type {ol.style.Fill}
* @private
*/
this.fill_ = goog.isDefAndNotNull(options.fill) ? options.fill : null;
/**
* @type {ol.style.Stroke}
* @private
*/
this.stroke_ = goog.isDefAndNotNull(options.stroke) ? options.stroke : null;
// one of stroke or fill can be null, both null is user error
goog.asserts.assert(this.fill_ || this.stroke_,
'Stroke or fill must be provided');
/**
* @type {ol.expr.Expression}
* @private
*/
this.zIndex_ = !goog.isDefAndNotNull(options.zIndex) ?
new ol.expr.Literal(ol.style.ShapeDefaults.zIndex) :
(options.zIndex instanceof ol.expr.Expression) ?
options.zIndex : new ol.expr.Literal(options.zIndex);
};
goog.inherits(ol.style.Shape, ol.style.Point);
/**
* @inheritDoc
* @return {ol.style.ShapeLiteral} Literal shape symbolizer.
*/
ol.style.Shape.prototype.createLiteral = function(featureOrType) {
var feature, type;
if (featureOrType instanceof ol.Feature) {
feature = featureOrType;
var geometry = feature.getGeometry();
type = geometry ? geometry.getType() : null;
} else {
type = featureOrType;
}
var literal = null;
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
var size = Number(ol.expr.evaluateFeature(this.size_, feature));
goog.asserts.assert(!isNaN(size), 'size must be a number');
var fillColor, fillOpacity;
if (!goog.isNull(this.fill_)) {
fillColor = ol.expr.evaluateFeature(this.fill_.getColor(), feature);
goog.asserts.assertString(
fillColor, 'fillColor must be a string');
fillOpacity = Number(ol.expr.evaluateFeature(
this.fill_.getOpacity(), feature));
goog.asserts.assert(!isNaN(fillOpacity), 'fillOpacity must be a number');
}
var strokeColor, strokeOpacity, strokeWidth;
if (!goog.isNull(this.stroke_)) {
strokeColor = ol.expr.evaluateFeature(this.stroke_.getColor(), feature);
goog.asserts.assertString(
strokeColor, 'strokeColor must be a string');
strokeOpacity = Number(ol.expr.evaluateFeature(
this.stroke_.getOpacity(), feature));
goog.asserts.assert(!isNaN(strokeOpacity),
'strokeOpacity must be a number');
strokeWidth = Number(ol.expr.evaluateFeature(
this.stroke_.getWidth(), feature));
goog.asserts.assert(!isNaN(strokeWidth), 'strokeWidth must be a number');
}
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
literal = new ol.style.ShapeLiteral({
type: this.type_,
size: size,
fillColor: fillColor,
fillOpacity: fillOpacity,
strokeColor: strokeColor,
strokeOpacity: strokeOpacity,
strokeWidth: strokeWidth,
zIndex: zIndex
});
}
return literal;
};
/**
* Get the fill.
* @return {ol.style.Fill} Shape fill.
*/
ol.style.Shape.prototype.getFill = function() {
return this.fill_;
};
/**
* Get the shape size.
* @return {ol.expr.Expression} Shape size.
*/
ol.style.Shape.prototype.getSize = function() {
return this.size_;
};
/**
* Get the stroke.
* @return {ol.style.Stroke} Shape stroke.
*/
ol.style.Shape.prototype.getStroke = function() {
return this.stroke_;
};
/**
* Get the shape type.
* @return {ol.style.ShapeType} Shape type.
*/
ol.style.Shape.prototype.getType = function() {
return this.type_;
};
/**
* Get the shape zIndex.
* @return {ol.expr.Expression} Shape zIndex.
*/
ol.style.Shape.prototype.getZIndex = function() {
return this.zIndex_;
};
/**
* Set the fill.
* @param {ol.style.Fill} fill Shape fill.
*/
ol.style.Shape.prototype.setFill = function(fill) {
if (!goog.isNull(fill)) {
goog.asserts.assertInstanceof(fill, ol.style.Fill);
}
this.fill_ = fill;
};
/**
* Set the shape size.
* @param {ol.expr.Expression} size Shape size.
*/
ol.style.Shape.prototype.setSize = function(size) {
goog.asserts.assertInstanceof(size, ol.expr.Expression);
this.size_ = size;
};
/**
* Set the stroke.
* @param {ol.style.Stroke} stroke Shape stroke.
*/
ol.style.Shape.prototype.setStroke = function(stroke) {
if (!goog.isNull(stroke)) {
goog.asserts.assertInstanceof(stroke, ol.style.Stroke);
}
this.stroke_ = stroke;
};
/**
* Set the shape type.
* @param {ol.style.ShapeType} type Shape type.
*/
ol.style.Shape.prototype.setType = function(type) {
this.type_ = type;
};
/**
* Set the shape zIndex.
* @param {ol.expr.Expression} zIndex Shape zIndex.
*/
ol.style.Shape.prototype.setZIndex = function(zIndex) {
goog.asserts.assertInstanceof(zIndex, ol.expr.Expression);
this.zIndex_ = zIndex;
};
/**
* @typedef {{type: ol.style.ShapeType,
* size: number,
* zIndex: number}}
*/
ol.style.ShapeDefaults = {
type: ol.style.ShapeType.CIRCLE,
size: 5,
zIndex: 0
};

View File

@@ -0,0 +1,205 @@
goog.provide('ol.style.Stroke');
goog.provide('ol.style.StrokeDefaults');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Literal');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.LineLiteral');
goog.require('ol.style.PolygonLiteral');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @extends {ol.style.Symbolizer}
* @param {ol.style.StrokeOptions=} opt_options Stroke options.
* @todo stability experimental
*/
ol.style.Stroke = function(opt_options) {
goog.base(this);
var options = opt_options || {};
/**
* @type {ol.expr.Expression}
* @private
*/
this.color_ = !goog.isDefAndNotNull(options.color) ?
new ol.expr.Literal(ol.style.StrokeDefaults.color) :
(options.color instanceof ol.expr.Expression) ?
options.color : new ol.expr.Literal(options.color);
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDefAndNotNull(options.opacity) ?
new ol.expr.Literal(ol.style.StrokeDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
/**
* @type {ol.expr.Expression}
* @private
*/
this.width_ = !goog.isDefAndNotNull(options.width) ?
new ol.expr.Literal(ol.style.StrokeDefaults.width) :
(options.width instanceof ol.expr.Expression) ?
options.width : new ol.expr.Literal(options.width);
/**
* @type {ol.expr.Expression}
* @private
*/
this.zIndex_ = !goog.isDefAndNotNull(options.zIndex) ?
new ol.expr.Literal(ol.style.StrokeDefaults.zIndex) :
(options.zIndex instanceof ol.expr.Expression) ?
options.zIndex : new ol.expr.Literal(options.zIndex);
};
goog.inherits(ol.style.Stroke, ol.style.Symbolizer);
/**
* @inheritDoc
* @return {ol.style.LineLiteral|ol.style.PolygonLiteral} Symbolizer literal.
*/
ol.style.Stroke.prototype.createLiteral = function(featureOrType) {
var feature, type;
if (featureOrType instanceof ol.Feature) {
feature = featureOrType;
var geometry = feature.getGeometry();
type = geometry ? geometry.getType() : null;
} else {
type = featureOrType;
}
var color = ol.expr.evaluateFeature(
this.color_, feature);
goog.asserts.assertString(color, 'color must be a string');
var opacity = Number(ol.expr.evaluateFeature(
this.opacity_, feature));
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
var width = Number(ol.expr.evaluateFeature(
this.width_, feature));
goog.asserts.assert(!isNaN(width), 'width must be a number');
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
var literal = null;
if (type === ol.geom.GeometryType.LINESTRING ||
type === ol.geom.GeometryType.MULTILINESTRING) {
literal = new ol.style.LineLiteral({
color: color,
opacity: opacity,
width: width,
zIndex: zIndex
});
} else if (type === ol.geom.GeometryType.POLYGON ||
type === ol.geom.GeometryType.MULTIPOLYGON) {
literal = new ol.style.PolygonLiteral({
strokeColor: color,
strokeOpacity: opacity,
strokeWidth: width,
zIndex: zIndex
});
}
return literal;
};
/**
* Get the stroke color.
* @return {ol.expr.Expression} Stroke color.
*/
ol.style.Stroke.prototype.getColor = function() {
return this.color_;
};
/**
* Get the stroke opacity.
* @return {ol.expr.Expression} Stroke opacity.
*/
ol.style.Stroke.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the stroke width.
* @return {ol.expr.Expression} Stroke width.
*/
ol.style.Stroke.prototype.getWidth = function() {
return this.width_;
};
/**
* Get the stroke zIndex.
* @return {ol.expr.Expression} Stroke zIndex.
*/
ol.style.Stroke.prototype.getZIndex = function() {
return this.zIndex_;
};
/**
* Set the stroke color.
* @param {ol.expr.Expression} color Stroke color.
*/
ol.style.Stroke.prototype.setColor = function(color) {
goog.asserts.assertInstanceof(color, ol.expr.Expression);
this.color_ = color;
};
/**
* Set the stroke opacity.
* @param {ol.expr.Expression} opacity Stroke opacity.
*/
ol.style.Stroke.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the stroke width.
* @param {ol.expr.Expression} width Stroke width.
*/
ol.style.Stroke.prototype.setWidth = function(width) {
goog.asserts.assertInstanceof(width, ol.expr.Expression);
this.width_ = width;
};
/**
* Set the stroke zIndex.
* @param {ol.expr.Expression} zIndex Stroke zIndex.
*/
ol.style.Stroke.prototype.setZIndex = function(zIndex) {
goog.asserts.assertInstanceof(zIndex, ol.expr.Expression);
this.zIndex_ = zIndex;
};
/**
* @typedef {{strokeColor: string,
* strokeOpacity: number,
* strokeWidth: number,
* zIndex: number}}
*/
ol.style.StrokeDefaults = {
color: '#696969',
opacity: 0.75,
width: 1.5,
zIndex: 0
};

209
old/src/ol/style/style.js Normal file
View File

@@ -0,0 +1,209 @@
goog.provide('ol.style');
goog.provide('ol.style.Style');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.expr.Call');
goog.require('ol.expr.Identifier');
goog.require('ol.expr.Literal');
goog.require('ol.expr.functions');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.Fill');
goog.require('ol.style.Literal');
goog.require('ol.style.PolygonLiteral');
goog.require('ol.style.Rule');
goog.require('ol.style.Shape');
goog.require('ol.style.Stroke');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @param {ol.style.StyleOptions} options Style options.
* @todo stability experimental
*/
ol.style.Style = function(options) {
/**
* @type {Array.<ol.style.Rule>}
* @private
*/
this.rules_ = goog.isDef(options.rules) ? options.rules : [];
/**
* Symbolizers that apply if no rules are given or where none of the given
* rules apply (these are the "else" symbolizers).
* @type {Array.<ol.style.Symbolizer>}
* @private
*/
this.symbolizers_ = goog.isDef(options.symbolizers) ?
options.symbolizers : [];
};
/**
* Create an array of symbolizer literals for a feature.
* @param {ol.Feature} feature Feature.
* @param {number} resolution Map resolution.
* @return {Array.<ol.style.Literal>} Symbolizer literals for the
* feature.
*/
ol.style.Style.prototype.createLiterals = function(feature, resolution) {
var rules = this.rules_,
symbolizers = [],
applies = false,
rule;
for (var i = 0, ii = rules.length; i < ii; ++i) {
rule = rules[i];
if (rule.applies(feature, resolution)) {
applies = true;
symbolizers.push.apply(symbolizers, rule.getSymbolizers());
}
} if (!applies) {
// these are the "else" symbolizers
symbolizers = this.symbolizers_;
}
return ol.style.Style.createLiterals(symbolizers, feature);
};
/**
* The default style.
* @type {ol.style.Style}
* @private
*/
ol.style.default_ = null;
/**
* Get the default style.
* @return {ol.style.Style} The default style.
*/
ol.style.getDefault = function() {
if (goog.isNull(ol.style.default_)) {
ol.style.default_ = new ol.style.Style({
rules: [
new ol.style.Rule({
filter: new ol.expr.Call(
new ol.expr.Identifier(ol.expr.functions.RENDER_INTENT),
[new ol.expr.Literal('select')]),
symbolizers: [
new ol.style.Shape({
fill: new ol.style.Fill({
color: '#ffffff',
opacity: 0.7
}),
stroke: new ol.style.Stroke({
color: '#696969',
opacity: 0.9,
width: 2.0
})
}),
new ol.style.Fill({
color: '#ffffff',
opacity: 0.7
}),
new ol.style.Stroke({
color: '#696969',
opacity: 0.9,
width: 2.0
})
]
})
],
symbolizers: [
new ol.style.Shape({
fill: new ol.style.Fill(),
stroke: new ol.style.Stroke()
}),
new ol.style.Fill(),
new ol.style.Stroke()
]
});
}
return ol.style.default_;
};
/**
* Set the default style.
* @param {ol.style.Style} style The new default style.
* @return {ol.style.Style} The default style.
*/
ol.style.setDefault = function(style) {
ol.style.default_ = style;
return style;
};
/**
* Given an array of symbolizers, generate an array of literals.
* @param {Array.<ol.style.Symbolizer>} symbolizers List of symbolizers.
* @param {ol.Feature|ol.geom.GeometryType} featureOrType Feature or geometry
* type.
* @return {Array.<ol.style.Literal>} Array of literals.
*/
ol.style.Style.createLiterals = function(symbolizers, featureOrType) {
var length = symbolizers.length;
var literals = new Array(length);
for (var i = 0; i < length; ++i) {
literals[i] = symbolizers[i].createLiteral(featureOrType);
}
return ol.style.Style.reduceLiterals_(literals);
};
/**
* Collapse partial polygon symbolizers and remove null symbolizers.
* @param {Array.<ol.style.Literal>} literals Input literals.
* @return {Array.<ol.style.Literal>} Reduced literals.
* @private
*/
ol.style.Style.reduceLiterals_ = function(literals) {
var reduced = [];
var literal, stroke, fill, key, value;
for (var i = 0, ii = literals.length; i < ii; ++i) {
literal = literals[i];
if (literal instanceof ol.style.PolygonLiteral) {
if (goog.isDef(literal.strokeColor) &&
!goog.isDef(literal.fillColor)) {
// stroke only, check for previous fill only
if (fill) {
for (key in literal) {
value = literal[key];
if (goog.isDef(value)) {
fill[key] = value;
}
}
fill = null;
} else {
stroke = literal;
reduced.push(stroke);
}
} else if (goog.isDef(literal.fillColor) &&
!goog.isDef(literal.strokeColor)) {
// fill only, check for previous stroke only
if (stroke) {
for (key in literal) {
value = literal[key];
if (goog.isDef(value)) {
stroke[key] = value;
}
}
stroke = null;
} else {
fill = literal;
reduced.push(fill);
}
} else {
// both stroke and fill, proceed
reduced.push(literal);
}
} else if (literal) {
reduced.push(literal);
}
}
return reduced;
};

View File

@@ -0,0 +1,21 @@
goog.provide('ol.style.Symbolizer');
goog.require('ol.Feature');
goog.require('ol.style.Literal');
/**
* @constructor
*/
ol.style.Symbolizer = function() {};
/**
* Create a literal from the symbolizer given a complete feature or a geometry
* type.
* @param {ol.geom.GeometryType|ol.Feature} featureOrType Feature for evaluating
* expressions or a geometry type.
* @return {ol.style.Literal} Literal symbolizer.
*/
ol.style.Symbolizer.prototype.createLiteral = goog.abstractMethod;

View File

@@ -0,0 +1,106 @@
goog.provide('ol.style.TextLiteral');
goog.require('goog.asserts');
goog.require('ol.style.Literal');
/**
* @typedef {{color: string,
* fontFamily: string,
* fontSize: number,
* fontWeight: string,
* text: string,
* opacity: number,
* strokeColor: (string|undefined),
* strokeOpacity: (number|undefined),
* strokeWidth: (number|undefined),
* zIndex: number}}
*/
ol.style.TextLiteralOptions;
/**
* @constructor
* @extends {ol.style.Literal}
* @param {ol.style.TextLiteralOptions} options Text literal options.
*/
ol.style.TextLiteral = function(options) {
goog.asserts.assertString(options.color, 'color must be a string');
/** @type {string} */
this.color = options.color;
goog.asserts.assertString(options.fontFamily, 'fontFamily must be a string');
/** @type {string} */
this.fontFamily = options.fontFamily;
goog.asserts.assertNumber(options.fontSize, 'fontSize must be a number');
/** @type {number} */
this.fontSize = options.fontSize;
goog.asserts.assertString(options.fontWeight, 'fontWeight must be a string');
/** @type {string} */
this.fontWeight = options.fontWeight;
goog.asserts.assertString(options.text, 'text must be a string');
/** @type {string} */
this.text = options.text;
goog.asserts.assertNumber(options.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = options.opacity;
/** @type {string|undefined} */
this.strokeColor = options.strokeColor;
if (goog.isDef(this.strokeColor)) {
goog.asserts.assertString(
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeOpacity = options.strokeOpacity;
if (goog.isDef(this.strokeOpacity)) {
goog.asserts.assertNumber(
this.strokeOpacity, 'strokeOpacity must be a number');
}
/** @type {number|undefined} */
this.strokeWidth = options.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
goog.asserts.assertNumber(
this.strokeWidth, 'strokeWidth must be a number');
}
// if any stroke property is defined, all must be defined
var strokeDef = goog.isDef(this.strokeColor) &&
goog.isDef(this.strokeOpacity) &&
goog.isDef(this.strokeWidth);
var strokeUndef = !goog.isDef(this.strokeColor) &&
!goog.isDef(this.strokeOpacity) &&
!goog.isDef(this.strokeWidth);
goog.asserts.assert(strokeDef || strokeUndef,
'If any stroke property is defined, all must be defined');
goog.asserts.assertNumber(options.zIndex, 'zIndex must be a number');
/** @type {number} */
this.zIndex = options.zIndex;
};
goog.inherits(ol.style.TextLiteral, ol.style.Literal);
/**
* @inheritDoc
*/
ol.style.TextLiteral.prototype.equals = function(other) {
return this.color == other.color &&
this.fontFamily == other.fontFamily &&
this.fontSize == other.fontSize &&
this.fontWeight == other.fontWeight &&
this.opacity == other.opacity &&
this.strokeColor == other.strokeColor &&
this.strokeOpacity == other.strokeOpacity &&
this.strokeWidth == other.strokeWidth &&
this.zIndex == other.zIndex;
};

View File

@@ -0,0 +1,303 @@
goog.provide('ol.style.Text');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Expression');
goog.require('ol.expr.Literal');
goog.require('ol.style.Symbolizer');
goog.require('ol.style.TextLiteral');
/**
* @constructor
* @extends {ol.style.Symbolizer}
* @param {ol.style.TextOptions} options Text options.
*/
ol.style.Text = function(options) {
/**
* @type {ol.expr.Expression}
* @private
*/
this.color_ = !goog.isDef(options.color) ?
new ol.expr.Literal(ol.style.TextDefaults.color) :
(options.color instanceof ol.expr.Expression) ?
options.color : new ol.expr.Literal(options.color);
/**
* @type {ol.expr.Expression}
* @private
*/
this.fontFamily_ = !goog.isDef(options.fontFamily) ?
new ol.expr.Literal(ol.style.TextDefaults.fontFamily) :
(options.fontFamily instanceof ol.expr.Expression) ?
options.fontFamily : new ol.expr.Literal(options.fontFamily);
/**
* @type {ol.expr.Expression}
* @private
*/
this.fontSize_ = !goog.isDef(options.fontSize) ?
new ol.expr.Literal(ol.style.TextDefaults.fontSize) :
(options.fontSize instanceof ol.expr.Expression) ?
options.fontSize : new ol.expr.Literal(options.fontSize);
/**
* @type {ol.expr.Expression}
* @private
*/
this.fontWeight_ = !goog.isDef(options.fontWeight) ?
new ol.expr.Literal(ol.style.TextDefaults.fontWeight) :
(options.fontWeight instanceof ol.expr.Expression) ?
options.fontWeight : new ol.expr.Literal(options.fontWeight);
/**
* @type {ol.expr.Expression}
* @private
*/
this.text_ = (options.text instanceof ol.expr.Expression) ?
options.text : new ol.expr.Literal(options.text);
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.expr.Literal(ol.style.TextDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
/**
* @type {ol.style.Stroke}
* @private
*/
this.stroke_ = goog.isDefAndNotNull(options.stroke) ? options.stroke : null;
/**
* @type {ol.expr.Expression}
* @private
*/
this.zIndex_ = !goog.isDefAndNotNull(options.zIndex) ?
new ol.expr.Literal(ol.style.TextDefaults.zIndex) :
(options.zIndex instanceof ol.expr.Expression) ?
options.zIndex : new ol.expr.Literal(options.zIndex);
};
goog.inherits(ol.style.Text, ol.style.Symbolizer);
/**
* @inheritDoc
* @return {ol.style.TextLiteral} Literal text symbolizer.
*/
ol.style.Text.prototype.createLiteral = function(featureOrType) {
var feature, type;
if (featureOrType instanceof ol.Feature) {
feature = featureOrType;
var geometry = feature.getGeometry();
type = geometry ? geometry.getType() : null;
} else {
type = featureOrType;
}
var color = ol.expr.evaluateFeature(this.color_, feature);
goog.asserts.assertString(color, 'color must be a string');
var fontFamily = ol.expr.evaluateFeature(this.fontFamily_, feature);
goog.asserts.assertString(fontFamily, 'fontFamily must be a string');
var fontSize = Number(ol.expr.evaluateFeature(this.fontSize_, feature));
goog.asserts.assert(!isNaN(fontSize), 'fontSize must be a number');
var fontWeight = ol.expr.evaluateFeature(this.fontWeight_, feature);
goog.asserts.assertString(fontWeight, 'fontWeight must be a string');
var text = ol.expr.evaluateFeature(this.text_, feature);
goog.asserts.assertString(text, 'text must be a string');
var opacity = Number(ol.expr.evaluateFeature(this.opacity_, feature));
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
var strokeColor, strokeOpacity, strokeWidth;
if (!goog.isNull(this.stroke_)) {
strokeColor = ol.expr.evaluateFeature(this.stroke_.getColor(), feature);
goog.asserts.assertString(
strokeColor, 'strokeColor must be a string');
strokeOpacity = Number(ol.expr.evaluateFeature(
this.stroke_.getOpacity(), feature));
goog.asserts.assert(!isNaN(strokeOpacity),
'strokeOpacity must be a number');
strokeWidth = Number(ol.expr.evaluateFeature(
this.stroke_.getWidth(), feature));
goog.asserts.assert(!isNaN(strokeWidth), 'strokeWidth must be a number');
}
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
return new ol.style.TextLiteral({
color: color,
fontFamily: fontFamily,
fontSize: fontSize,
fontWeight: fontWeight,
text: text,
opacity: opacity,
strokeColor: strokeColor,
strokeOpacity: strokeOpacity,
strokeWidth: strokeWidth,
zIndex: zIndex
});
};
/**
* Get the font color.
* @return {ol.expr.Expression} Font color.
*/
ol.style.Text.prototype.getColor = function() {
return this.color_;
};
/**
* Get the font family.
* @return {ol.expr.Expression} Font family.
*/
ol.style.Text.prototype.getFontFamily = function() {
return this.fontFamily_;
};
/**
* Get the font size.
* @return {ol.expr.Expression} Font size.
*/
ol.style.Text.prototype.getFontSize = function() {
return this.fontSize_;
};
/**
* Get the font weight.
* @return {ol.expr.Expression} Font weight.
*/
ol.style.Text.prototype.getFontWeight = function() {
return this.fontWeight_;
};
/**
* Get the opacity.
* @return {ol.expr.Expression} Opacity.
*/
ol.style.Text.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the text.
* @return {ol.expr.Expression} Text.
*/
ol.style.Text.prototype.getText = function() {
return this.text_;
};
/**
* Get the zIndex.
* @return {ol.expr.Expression} Text.
*/
ol.style.Text.prototype.getZIndex = function() {
return this.zIndex_;
};
/**
* Set the font color.
* @param {ol.expr.Expression} color Font color.
*/
ol.style.Text.prototype.setColor = function(color) {
goog.asserts.assertInstanceof(color, ol.expr.Expression);
this.color_ = color;
};
/**
* Set the font family.
* @param {ol.expr.Expression} fontFamily Font family.
*/
ol.style.Text.prototype.setFontFamily = function(fontFamily) {
goog.asserts.assertInstanceof(fontFamily, ol.expr.Expression);
this.fontFamily_ = fontFamily;
};
/**
* Set the font size.
* @param {ol.expr.Expression} fontSize Font size.
*/
ol.style.Text.prototype.setFontSize = function(fontSize) {
goog.asserts.assertInstanceof(fontSize, ol.expr.Expression);
this.fontSize_ = fontSize;
};
/**
* Set the font weight.
* @param {ol.expr.Expression} fontWeight Font weight.
*/
ol.style.Text.prototype.setFontWeight = function(fontWeight) {
goog.asserts.assertInstanceof(fontWeight, ol.expr.Expression);
this.fontWeight_ = fontWeight;
};
/**
* Set the opacity.
* @param {ol.expr.Expression} opacity Opacity.
*/
ol.style.Text.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the text.
* @param {ol.expr.Expression} text Text.
*/
ol.style.Text.prototype.setText = function(text) {
goog.asserts.assertInstanceof(text, ol.expr.Expression);
this.text_ = text;
};
/**
* Set the zIndex.
* @param {ol.expr.Expression} zIndex Text.
*/
ol.style.Text.prototype.setZIndex = function(zIndex) {
goog.asserts.assertInstanceof(zIndex, ol.expr.Expression);
this.zIndex_ = zIndex;
};
/**
* @typedef {{color: string,
* fontFamily: string,
* fontSize: number,
* fontWeight: string,
* opacity: number,
* zIndex: number}}
*/
ol.style.TextDefaults = {
color: '#000',
fontFamily: 'sans-serif',
fontSize: 10,
fontWeight: 'normal',
opacity: 1,
zIndex: 0
};