Compare commits

...

223 Commits

Author SHA1 Message Date
Tim Schaub
929ce05f81 Merge pull request #3958 from openlayers/release-v3.8.0
Release v3.8.0.
2015-08-04 00:16:31 -06:00
Tim Schaub
81b7a77954 Update package version to 3.8.0 2015-08-04 00:03:33 -06:00
Tim Schaub
91045b0ad1 Changelog for v3.8.0 2015-08-04 00:03:24 -06:00
Tim Schaub
b11f6abb3c Merge pull request #3957 from tschaub/shared-delete
Properly handle vertex deletion with multiple features.
2015-08-03 23:38:43 -06:00
Tim Schaub
571f3f30a4 Regression test for shared vertex deletion 2015-08-03 23:07:19 -06:00
Tim Schaub
85ddded15c Only remove the vertex feature if it exists
When deleting a vertex shared by multiple features, we iterate through drag segments and only need to remove the vertex feature once.
2015-08-03 22:44:22 -06:00
Tim Schaub
d3c8880b22 Merge pull request #3954 from fredj/rm_bindMouseOutFocusOutBlur
Remove ol.control.Control.bindMouseOutFocusOutBlur function.
2015-08-03 21:51:09 -06:00
Tim Schaub
54d3bbd625 Merge pull request #3214 from tschaub/raster
Pixel manipulation with raster sources.
2015-08-03 21:49:19 -06:00
Tim Schaub
405a8db075 Merge pull request #3946 from Turbo87/modify
Fix vertex deletion for Modify interaction on mobile devices.
2015-08-03 21:47:41 -06:00
Tim Schaub
27e58be43d Merge pull request #3910 from ahocevar/ol-ext-no-amd
Do not provide an AMD environment to ol.ext modules.
2015-08-03 21:43:42 -06:00
Tim Schaub
cee34fa51b Table for controls 2015-08-03 21:33:46 -06:00
Tim Schaub
16aa548383 Only create a worker if an operation is provided 2015-08-03 21:32:16 -06:00
Tim Schaub
860fdabd76 Simplify raster sources by working with a single operation 2015-08-03 20:10:46 -06:00
Frederic Junod
761aa0ea5c Remove ol.control.Control.bindMouseOutFocusOutBlur function
It was a workaround added in #1761 to hide the button tooltip on
OSX / Chrome 32 and 33.

Because we're not using the tooltips anymore (see #2781) and this
version of chrome is deprecated this workaround can be removed.
2015-08-03 17:12:33 +02:00
Frédéric Junod
d493d0a820 Merge pull request #3934 from fredj/drawpoint_events
Fix `drawstart` and `drawend` events when drawing a point
2015-08-03 16:26:00 +02:00
Pierre GIRAUD
d6e35edac5 Merge pull request #3774 from pgiraud/measure_tooltips_touchdevice
Measure tooltips touchdevice
2015-08-03 15:57:57 +02:00
Frederic Junod
2143eebd30 Fix drawstart and drawend events when drawing a point
The previous behavior was to fire a `drawstart` on the first `mousemove`.
2015-08-03 13:40:56 +02:00
Frédéric Junod
64225776d4 Merge pull request #3949 from fredj/expect_called
Remove count argument from `called` function
2015-08-03 13:40:16 +02:00
Éric Lemoine
355c3c7b58 Merge pull request #3950 from elemoine/vbarray
Remove reference to vbarray.js
2015-08-03 11:19:29 +02:00
Éric Lemoine
e792a121f4 Remove reference to vbarray.js
This file was removed with https://github.com/openlayers/ol3/pull/3516.

Fixes #3702.
2015-08-03 11:06:43 +02:00
Frederic Junod
3364dbb46e Remove count argument from called function
This function takes no arguments, use the `callCount` property instead.
2015-08-03 10:02:21 +02:00
Tim Schaub
23610efe30 Merge pull request #3947 from alvinlindstam/clarify-ratio-docs
Clarify documentation of Image source ratio option.
2015-08-02 12:46:00 -06:00
Alvin Lindstam
75bf3e1ccf Clarify documentation of Image source ratio option. 2015-08-02 19:51:00 +02:00
Tim Schaub
f2f5cd2630 Make seed coordinate sticky 2015-08-01 17:06:40 -06:00
Ian Schneider
6f6698dd6a Add a region growing example 2015-08-01 17:06:33 -06:00
Tim Schaub
4320b07c5d Doc corrections 2015-08-01 16:33:43 -06:00
Tim Schaub
25603d7cf1 Merge pull request #3920 from probins/patch-1
Remove use_types_for_optimization from custom build tutorial.
2015-08-01 16:23:51 -06:00
Tim Schaub
935eb63876 Merge pull request #3922 from probins/expandurl
Document {?-?} pattern in expandUrl
2015-08-01 15:54:51 -06:00
Tim Schaub
6111b91cca Merge pull request #3921 from bjornharrtell/travis-cache
Cache node_modules on Travis.
2015-08-01 15:52:20 -06:00
Tobias Bieniek
7a34d22b37 interaction/modify: Add missing goog.require() to test 2015-08-01 22:09:32 +02:00
Tobias Bieniek
c3f51c676a interaction/modify: Fix identation issue 2015-08-01 22:05:44 +02:00
Tobias Bieniek
968c8aa34e interaction/modify: Replace lastNewVertexPixel with ignoreNextSingleClick
The previous approach did not work on mobile devices where no `pointermove`
event is sent except from dragging.

Logic now is: Upon vertex creation due to `pointerdown` we will ignore
the next `singleclick` event unless there is a `pointerdrag` event, which will
not lead to a `singleclick` event following the vertex creation.

Resolves #3935
2015-08-01 22:00:41 +02:00
Tobias Bieniek
b001a48567 interaction/modify: Simplify lastNewVertexPixel condition 2015-08-01 21:12:59 +02:00
Tobias Bieniek
bf9156cbeb interaction/modify: Adjust simulated events
This is exactly matching the event sent by Chrome now
2015-08-01 21:03:18 +02:00
Tobias Bieniek
bafd8548d1 interaction/modify: Add tests for deleteCondition option 2015-08-01 20:52:31 +02:00
Tobias Bieniek
e3ead5df06 events/condition: Add doubleClick condition 2015-08-01 20:46:21 +02:00
Tobias Bieniek
22ca08179d interaction/modify: Use expect().to.be() assertion
... instead of expect(a === b).to.be.ok()
2015-08-01 20:20:06 +02:00
Andreas Hocevar
c8df907ff2 Merge pull request #3942 from ahocevar/matrixset-by-projection
Fix WMTS TileMatrixSet lookup by SRS identifier
2015-07-31 11:45:06 +02:00
Andreas Hocevar
c0950dee11 Merge pull request #3945 from ahocevar/popup-on-icon
Simplify icon example and show popup at clicked position
2015-07-31 11:24:58 +02:00
Andreas Hocevar
da3d8952da Simplify icon example and show popup at clicked position
By using the event's coordinate instead of the feature's, we make sure
that the popup is shown where the user clicked when on a wrapped world.
2015-07-31 10:09:16 +02:00
Andreas Hocevar
95e43c852d Fix WMTS TileMatrixSet lookup by SRS identifier 2015-07-30 19:48:28 +02:00
Frédéric Junod
d4d3555a88 Merge pull request #3930 from fredj/goog.functions.identity
Use goog.functions.identity instead of goog.identityFunction
2015-07-29 08:53:53 +02:00
Andreas Hocevar
ef9a1a25b1 Merge pull request #3929 from probins/patch-2
Expand description for XYZ source
2015-07-28 22:15:16 +02:00
Peter Robins
44fdfaa630 Expand description for XYZ source 2015-07-28 12:54:01 +00:00
Andreas Hocevar
112473afee Merge pull request #3933 from ahocevar/snap-center-to-pixel
Snap center to pixel to avoid floating point issues
2015-07-28 14:20:43 +02:00
Andreas Hocevar
5e505f200a Snap center to pixel to avoid floating point issues 2015-07-28 14:02:09 +02:00
Frédéric Junod
5e4474ca8c Merge pull request #3932 from Turbo87/patch-1
SnapOptions: Fix typo in pixelTolerance JSDoc
2015-07-28 13:03:14 +02:00
Tobias Bieniek
d3f766c748 SnapOptions: Fix typo in pixelTolerance JSDoc
This was apparently copy-pasted from the `ModifyOptions` without adjustment
2015-07-28 12:26:54 +02:00
Frédéric Junod
2b1acc6216 Merge pull request #3931 from fredj/rm_htmlparser2
Remove unused htmlparser2 package
2015-07-28 11:07:48 +02:00
Frederic Junod
c008de1a88 Remove unused htmlparser2 package
No longer used since #3542
2015-07-28 10:31:58 +02:00
Frederic Junod
e6a38d8211 Use goog.functions.identity instead of goog.identityFunction
goog.identityFunction is deprecated
2015-07-28 09:44:51 +02:00
Peter Robins
e6f4054d3b Document {?-?} pattern in expandUrl 2015-07-25 13:41:36 +00:00
Björn Harrtell
fe636a0e98 Use Travis CI dependency cache 2015-07-25 15:12:59 +02:00
Peter Robins
76d36d4b20 Remove use_types_for_optimization from custom build tutorial 2015-07-23 15:11:55 +01:00
Frédéric Junod
abb5fef043 Merge pull request #3912 from fredj/zoomslider_event_type
Fix the event type fired by goog.fx.Dragger
2015-07-22 14:39:40 +02:00
Tim Schaub
0c486c522a Allow UI thread to be used
Where workers are not available, or if operations are trivial to run, the main UI thread can be used instead.  This also adds tests that run in real browsers.
2015-07-21 17:12:08 -06:00
Tim Schaub
af3c38052e Avoid examples that cannot be run in Phantom 2015-07-21 17:12:08 -06:00
Tim Schaub
f1ff39cc8b Avoid compiling the shaded relief example
The compiler doesn't support the use of the ImageData constructor.
2015-07-21 17:12:08 -06:00
Tim Schaub
643c2e6f21 Only update canvas if not dirty 2015-07-21 17:12:07 -06:00
Tim Schaub
d5aa0d9a8e Update example to work with the latest pixelworks 2015-07-21 17:12:07 -06:00
Tim Schaub
793b27e9f5 Allow operations to be updated 2015-07-21 17:12:07 -06:00
Tim Schaub
9d28549b2b Pass along potentially modified data 2015-07-21 17:12:07 -06:00
Tim Schaub
ef90f5a097 Run operations in a worker 2015-07-21 17:12:07 -06:00
Tim Schaub
c50d775330 Vertical exaggeration control 2015-07-21 17:12:07 -06:00
Tim Schaub
6da6cef760 Improved shaded relief example 2015-07-21 17:12:07 -06:00
Tim Schaub
1d94d71a5b Shaded relief example 2015-07-21 17:12:07 -06:00
Tim Schaub
65fee5b7ac Pass data object to operations 2015-07-21 17:12:07 -06:00
Tim Schaub
5267776627 Provide extent and resolution in raster events 2015-07-21 17:12:06 -06:00
Tim Schaub
a721ce03c9 Support for image or pixel operations 2015-07-21 17:12:06 -06:00
Tim Schaub
23e2fcefef Only render if sources are ready 2015-07-21 17:12:06 -06:00
Tim Schaub
d17d470d48 Fire change when updating operations 2015-07-21 17:12:06 -06:00
Tim Schaub
c6dedbc40b Use the first pixel for rendering, allow setting operations 2015-07-21 17:12:06 -06:00
Tim Schaub
de107c5502 Frame and canvas have equal size 2015-07-21 17:12:06 -06:00
Tim Schaub
6740ca9ee8 More interactive example 2015-07-21 17:12:06 -06:00
Tim Schaub
2c82ca86f0 Fire events before and after running ops 2015-07-21 17:12:06 -06:00
Tim Schaub
b7ad9160ef Nicer example 2015-07-21 17:12:06 -06:00
Tim Schaub
acc97a53eb Raster source for composing pixels from other sources 2015-07-21 17:12:05 -06:00
Frederic Junod
7634c0c2c4 Fix the event type fired by goog.fx.Dragger 2015-07-20 15:33:44 +02:00
Andreas Hocevar
49cc39c4dd Merge pull request #3871 from ahocevar/change-event
Document change events properly
2015-07-18 15:41:05 +02:00
Andreas Hocevar
3595c2cce7 Document change events properly
With this change, the generic 'change' event is properly documented, as
all other events. It is no longer necessary to annotate `@fires change` for
every ol.Observable subclass.
2015-07-18 15:27:16 +02:00
Andreas Hocevar
80c4809aee Do not provide an AMD environment to ol.ext modules
This fixes issues with ol.source.Vector being unable to use ol.ext.rbush,
but it also means that potential future external modules without node
module loader support will not work. If we ever depend on such a module,
we can replace "var define;" with a minimal AMD define shim.
2015-07-17 18:07:39 +02:00
Andreas Hocevar
10b4aa1bab Merge pull request #3906 from ahocevar/featurescollection-only
Clear features properly when there is no spatial index
2015-07-16 08:57:14 +02:00
Andreas Hocevar
8f7cbc5ed6 Clear features properly when there is no spatial index
Previously clear() only kept the features collection in sync whern there
was also a features RTree.
2015-07-15 15:15:41 +02:00
Andreas Hocevar
7094f65ef7 Merge pull request #3896 from ahocevar/webgl-precompose
Fire WebGL precompose event in same sequence as other renderers
2015-07-12 10:05:45 +02:00
Andreas Hocevar
ac8e62818f Fire WebGL precompose event in same sequence as other renderers
In other map renderers, the precompose event is fired before preparing and
composing layer frames. In WebGL, it is fired in between. This change makes
it so the sequence of events is the same for all renderers.

Because the WebGL renderer creates the list of layers to render before the
precompose event, unmanaged layers are never rendered. This is also fixed
by dispatching the precompose event earlier.
2015-07-11 14:58:31 +02:00
Tim Schaub
c89fb3ccfe Merge pull request #3359 from Kenny806/deep_clone
Enable deep clone of MultiPolygon.
2015-07-10 23:11:25 -06:00
Tim Schaub
223d5ab60d Merge pull request #3895 from planetlabs/greedy-multi-queue
Rework the tile queue for multiple queues.
2015-07-10 16:33:49 -06:00
Alessandro Isaacs
2142b538ac Greedify the queue loading strategy 2015-07-10 15:06:41 -07:00
Alessandro Isaacs
5149889bd2 Improve the test 2015-07-10 15:06:41 -07:00
Alessandro Isaacs
b57cdb730c Only load tiles that are not yet loaded 2015-07-10 15:06:35 -07:00
Tim Schaub
8600d46a0e Merge pull request #3894 from tschaub/no-sudo
Install Python dependencies without sudo.
2015-07-10 14:20:35 -06:00
Tim Schaub
7509425aa4 Install Python dependencies without sudo 2015-07-10 11:00:13 -06:00
Pierre GIRAUD
c9ab9bc711 Hide the help tooltip when cursor is out of the map 2015-07-10 09:32:32 +02:00
Tim Schaub
cd6ac857b9 Merge pull request #3824 from probins/select
Improve docs for interaction.Select.
2015-07-09 16:54:05 -06:00
Tim Schaub
7b35557cee Merge pull request #3884 from tschaub/debug-server
Provide a debug loader for the library.
2015-07-09 16:02:12 -06:00
Tim Schaub
4549d2f7a8 Try multiple ports 2015-07-09 10:49:24 -06:00
Tim Schaub
7780d77ade Update to closure-util@1.5.0 2015-07-09 10:16:15 -06:00
Tim Schaub
bfaac061c8 Provide a debug loader for the library 2015-07-09 10:16:15 -06:00
Andreas Hocevar
afce912f11 Merge pull request #3883 from ahocevar/foreachfeatureatpixel-unmanaged-always
Ignore layer filter for unmanaged layers
2015-07-09 00:03:25 +02:00
Tim Schaub
a705c6fe11 Test two queues sharing tiles 2015-07-08 15:12:31 -06:00
Andreas Hocevar
26e146b1d8 Ignore layer filter for unmanaged layers
To make unmanaged vector layers work like the removed ol.FeatureOverlay,
the layer filter for ol.Map#forEachFeatureAtPixel needs to ignore unmanaged
layers.
2015-07-07 22:24:57 +02:00
Bart van den Eijnden
a62bbd6650 Merge pull request #3859 from llambanna/patch-2
Add in crossOrigin option
2015-07-06 11:58:39 +02:00
Bart van den Eijnden
38fa805f03 Merge pull request #3873 from probins/patch-1
Correct minor typo in modifyinteraction
2015-07-06 09:36:07 +02:00
Anna Lambrechtsen
1d3f8b5d7d Add in crossOrigin option 2015-07-06 14:07:40 +12:00
Peter Robins
c53aa7e8d5 Correct minor typo in modifyinteraction 2015-07-05 10:57:59 +01:00
Andreas Hocevar
109cd6f3a6 Merge pull request #3872 from probins/patch-1
Correct event notations in ol.Feature
2015-07-04 14:20:25 +02:00
Peter Robins
4f703efd23 Correct event notations in ol.Feature 2015-07-04 11:43:06 +01:00
Bart van den Eijnden
a157fff318 Merge pull request #3869 from openlayers/release-v3.7.0
Release v3.7.0
2015-07-03 11:36:40 +02:00
Bart van den Eijnden
84ed12ec46 Update package version to 3.7.0 2015-07-03 11:34:19 +02:00
Bart van den Eijnden
5fb692a876 Changelog for v3.7.0 2015-07-03 11:33:48 +02:00
Andreas Hocevar
06908775e8 Merge pull request #3867 from ahocevar/no-proj-extent-required
Do not require projection extent for x-wrapping tile sources
2015-07-03 11:25:06 +02:00
Andreas Hocevar
da66a37182 Do not require projection extent for x-wrapping tile sources 2015-07-03 11:05:49 +02:00
Bart van den Eijnden
96eaf2de06 Merge pull request #3635 from bjornharrtell/modify-singleclick-vertex
Create vertex on boundary single click
2015-07-03 11:00:33 +02:00
Andreas Hocevar
86d9d691e4 Merge pull request #3806 from ahocevar/clip-wrapx
Do not clip canvas for vector layers when wrapping the world
2015-07-03 10:47:45 +02:00
Björn Harrtell
c69ba6a3dd Create vertex on boundary single click 2015-07-03 10:26:38 +02:00
Bart van den Eijnden
2adf3befb8 Merge pull request #3461 from bjornharrtell/modifyevent
High level Modify interaction events
2015-07-03 10:24:43 +02:00
Björn Harrtell
f81e36d8e0 Add mapBrowserPointerEvent property to ModifyEvent 2015-07-03 10:11:24 +02:00
Björn Harrtell
f7d62f054c High level Modify interaction events 2015-07-03 10:11:24 +02:00
Bart van den Eijnden
c0b6eefd8f Merge pull request #3865 from bartvde/fit
ol.View#fit()
2015-07-02 16:58:33 +02:00
Andreas Hocevar
a09fa923a5 Merge pull request #3864 from klokantech/xyz-canwrapx
Check projection.canWrapX() before wrapping tiles
2015-07-02 17:04:11 +03:00
Bart van den Eijnden
7c207d47bb Move upgrade notes to 3.7 and fix typos 2015-07-02 15:23:34 +02:00
Petr Sloup
eac5d652cf Check projection.canWrapX() before wrapping tiles
Even if wrapX is true on the source
2015-07-02 15:21:34 +02:00
vmalaret
4d3e903670 ol.View#fit -- fix docs and add assertions 2015-07-02 15:19:09 +02:00
vmalaret
e7cd691362 rotation support for ol.View#calculateExtent 2015-07-02 15:19:08 +02:00
vmalaret
74759142d9 Replace fitGeometry and fitExtent with fit
Fit accepts either a geometry or an extent.

This combines two previously distinct functions
into one more flexible call.

Also brings the rotations support and options
previously available to fitGeometry to extents
2015-07-02 15:19:08 +02:00
Bart van den Eijnden
3021d3a6a7 Merge pull request #3863 from nhambletCCRI/cdataInGML
Handle CDATA in attribute parsing for GML format
2015-07-02 14:57:21 +02:00
Nick Hamblet
cfafe90235 Handle CDATA in attribute parsing for GML format
Following [3827](https://github.com/openlayers/ol3/issues/3827),
handle CDATA XML nodes in attribute parsing of GML data. Currently
such data will be expected to be a geometry, and will fail to parse.

Treating the CDATA node as text is the easiest way to handle such
an attribute.
2015-07-01 16:32:17 -04:00
Tim Schaub
ccaca9fc52 Merge pull request #3860 from tschaub/update-bootstrap
Update example layout.
2015-07-01 08:01:32 -06:00
Pierre GIRAUD
3f918f4e8d Merge pull request #3861 from openlayers/pgiraud-patch-1
Don't force 'dom' renderer
2015-07-01 12:59:01 +02:00
Pierre GIRAUD
5871d64c9d Don't force 'dom' renderer 2015-07-01 12:31:40 +02:00
Tim Schaub
d1f19b8e0d Use the latest Bootstrap 2015-06-30 22:30:28 -06:00
Pierre GIRAUD
3f214f6ac4 Merge pull request #3855 from pgiraud/wmts_ign
Adding an example with WMTS tiles from IGN Geoportail
2015-06-30 07:28:29 +02:00
Andreas Hocevar
0159d20d6d Merge pull request #3856 from plepe/bug-3851
ol.source.TileVector(): bind success function of tileLoadFunction to source
2015-06-29 22:35:15 +03:00
Stephan Bösch-Plepelits
ce20380078 ol.source.TileVector(): bind success function of tileLoadFunction to source
- fixes #3851
2015-06-29 21:01:08 +02:00
Pierre GIRAUD
f9e5c9c596 Adding an example with WMTS tiles from IGN Geoportail 2015-06-29 11:42:38 +02:00
Tim Schaub
7d04ef3e2d Merge pull request #3848 from tschaub/webpack
Check for exports before define.
2015-06-25 11:55:32 -06:00
Frédéric Junod
ced3633d80 Merge pull request #3845 from fredj/collection_null_array
Prevent null array to be passed to an ol.Collection
2015-06-25 09:25:37 +02:00
Pierre GIRAUD
e62b2e4479 Merge pull request #3849 from pgiraud/dms_notation_leading_zeros
Pad min. and sec. with leading zeros in DMS notation
2015-06-25 09:23:37 +02:00
Frederic Junod
8cf57941ac Prevent null array to be passed to ol.Collection 2015-06-25 09:11:38 +02:00
Frederic Junod
dd132c9fad Add non-nullable notation to features array 2015-06-25 09:11:38 +02:00
Pierre GIRAUD
1cdfc709ae Pad min. and sec. with leading zeros in DMS notation
FIxes 3776
2015-06-25 08:40:43 +02:00
Tim Schaub
1b01efc08b Check for exports before define 2015-06-24 21:53:52 -06:00
Pierre GIRAUD
28450cbb5a Merge pull request #3842 from pgiraud/feature_animation
Adding a feature-animation example
2015-06-24 16:09:50 +02:00
Pierre GIRAUD
1c341e288c Adding a feature-animation example 2015-06-24 15:31:43 +02:00
Andreas Hocevar
3f23deb09a Merge pull request #3833 from bjornharrtell/customtilexhr
Enable use of custom XHR loader for TileVector sources
2015-06-23 14:31:26 +02:00
Björn Harrtell
ceafa88dc8 Enable use of custom XHR loader for TileVector sources 2015-06-23 14:07:19 +02:00
Bart van den Eijnden
54186d7893 Merge pull request #3834 from bartvde/arcgisrest-dpi
ArcGIS tiled example broken in Chrome
2015-06-22 12:43:35 +02:00
Bart van den Eijnden
9a0c0e2f2b Make sure we don't generate any floating point DPI values for ol.source.TileArcGISRest 2015-06-22 12:01:14 +02:00
Éric Lemoine
c6d1778202 Merge pull request #3829 from kzr-pzr/master
incorrect assert message
2015-06-20 12:24:35 +02:00
peterko
e532727713 incorrect assert message 2015-06-20 11:09:36 +02:00
Andreas Hocevar
edc16b9739 Merge pull request #3828 from ahocevar/fix-doc-typo
Fix typo in upgrade notes
2015-06-20 10:35:36 +02:00
Andreas Hocevar
59871274ca Fix typo in upgrade notes 2015-06-20 10:34:28 +02:00
Andreas Hocevar
039b54de48 Merge pull request #3826 from klokantech/xyzsource-tilegrid
Allow custom tileGrid in ol.source.XYZ
2015-06-20 10:25:28 +02:00
Petr Sloup
5993b45c63 Allow custom tileGrid in ol.source.XYZ 2015-06-19 19:58:06 +02:00
Andreas Hocevar
5c5364bbb7 Merge pull request #3815 from ahocevar/tilegrid-no-surprises
Simplify tilegrid API and internals
2015-06-19 19:05:19 +02:00
Andreas Hocevar
6411c9267b More clarity about origin and direction of tile coordinates 2015-06-19 18:49:49 +02:00
Andreas Hocevar
f85fcf30a2 Additional tests 2015-06-19 18:34:26 +02:00
Andreas Hocevar
b5e0ae6f8c Explain changes in upgrade notes 2015-06-19 18:34:20 +02:00
Andreas Hocevar
e6f5c2a008 Cleanup and example updates 2015-06-19 18:34:19 +02:00
Andreas Hocevar
31cfa0d952 Make tile range calculation work with arbitrary origins 2015-06-19 18:34:19 +02:00
Andreas Hocevar
a753d282cc Use top-left corner of extent for all generated tile grids 2015-06-19 18:34:18 +02:00
Andreas Hocevar
e3a8dc89de Fix calculation of tile coord from coordinate
Tile coord calculation was wrong in the case of reverseIntersectionPolicy
for y coords, and for extents with +/- Infinity.
2015-06-19 18:34:18 +02:00
Andreas Hocevar
18aa9b5091 Remove unused createFromQuadKey function 2015-06-19 18:34:18 +02:00
Andreas Hocevar
84e051d19b Fix TileDebugSource to display '' for out-of-range tiles 2015-06-19 18:34:18 +02:00
Andreas Hocevar
af319c259b Do not transform tile coordinates for tileUrlFunction 2015-06-19 18:34:09 +02:00
Andreas Hocevar
0af5642569 Merge pull request #3820 from ahocevar/vectorlayer-like-featureoverlay
Make unmanaged vector layers behave more like ol.FeatureOverlay
2015-06-19 18:18:07 +02:00
Peter Robins
d6118f31e4 Improve docs for interaction.Select 2015-06-19 13:11:27 +00:00
Andreas Hocevar
7463a58066 Do not clip canvas for vector layers when wrapping the world 2015-06-19 14:55:20 +02:00
Andreas Hocevar
f645a9e1e4 Make unmanaged vector layers behave more like ol.FeatureOverlay
* Skipped features need to be hit-detected on unmanaged layers.
* updateWhileAnimating and updateWhileInteracting are recommended to
  achieve the same instant visual feedback that ol.FeatureOverlay had.
2015-06-19 13:06:29 +02:00
Andreas Hocevar
a9591f8b99 Merge pull request #3822 from probins/update
Correct docs for updateWhileInteracting
2015-06-19 12:59:30 +02:00
Peter Robins
43d9ebe51d Correct docs for updateWhileInteracting 2015-06-19 07:24:12 +00:00
Tim Schaub
aa90c97ba3 Merge pull request #3818 from probins/transform
Make geometry.transform api stable again.
2015-06-18 10:42:08 -06:00
Peter Robins
874c4aef21 Make Geometry.transform api stable again 2015-06-18 16:01:25 +00:00
Andreas Hocevar
2249c82ac2 Merge pull request #3801 from ahocevar/tilevector-extent
Respect the tile grid's extent in ol.source.TileVector
2015-06-18 10:46:48 +02:00
Andreas Hocevar
a2c9a0796c Merge pull request #3810 from ahocevar/tilegrid-example-docs
Improve TileGrid documentation and examples
2015-06-16 23:53:49 +02:00
Andreas Hocevar
d6bb13b54b Add note about extent 2015-06-16 18:47:50 +02:00
Andreas Hocevar
d628f6b098 Use the tileSize variable 2015-06-16 17:16:28 +02:00
Andreas Hocevar
e2da56afa1 Tile grid documentation improvements
Using the term 'bottom-left' for origin and origins is misleading, because
many developers use -y-1 for the tile url's y in their tile url functions,
and the origin really only determines where tile coordinates start to
increase from left to right and from bottom to top.
2015-06-16 17:16:19 +02:00
Frédéric Junod
f74e4c95ff Merge pull request #3808 from probins/patch-1
Correct typo in OverlayOptions
2015-06-16 10:37:53 +02:00
Éric Lemoine
b8cb1fe795 Merge pull request #3766 from elemoine/draw-click-tolerance
Add a clickTolerance option to the Draw interaction
2015-06-16 10:06:01 +02:00
Peter Robins
1e8968d97a Correct typo in OverlayOptions 2015-06-16 09:04:12 +01:00
Andreas Hocevar
9c480d77f5 Merge pull request #3804 from ahocevar/fix-tilegrid-docs
Remove sentence that was only meant for WMTS tile grids
2015-06-15 16:44:54 +02:00
Andreas Hocevar
0e943f5832 Remove sentence that was only meant for WMTS tile grids 2015-06-15 16:08:29 +02:00
Éric Lemoine
e99f43af8d Add a clickTolerance option to the Draw interaction 2015-06-15 15:32:34 +02:00
Andreas Hocevar
2bcb10c973 Respect the tile grid's extent
By adding a getTileCoordForTileUrlFuction method like for ol.source.Tile,
we can now properly handle extent and resolution restrictions, and reuse
tiles on wrapped worlds. Also adds the missing wrapX option to
ol.source.TileVector.
2015-06-15 11:15:25 +02:00
Andreas Hocevar
9301fff6cb Merge pull request #3800 from probins/editstyle
Remove further references to FeatureOverlay
2015-06-13 19:08:50 +02:00
Peter Robins
83c33a03c6 Remove further references to FeatureOverlay 2015-06-13 14:01:45 +00:00
Andreas Hocevar
e848acd806 Merge pull request #3780 from ahocevar/call-tileurlfunction-with-transformed-tilecoord
Only expose transformed tile coordinates to the API
2015-06-12 11:18:16 +02:00
Andreas Hocevar
72cc824502 Explain changes in upgrade notes 2015-06-12 09:47:43 +02:00
Andreas Hocevar
4b3aac32c3 Return transformed tile coordinates from ol.TileGrid's API methods 2015-06-12 09:47:32 +02:00
Andreas Hocevar
acab0ebd57 Display transformed tile coordinates in ol.source.TileDebug 2015-06-12 09:46:17 +02:00
Andreas Hocevar
6a4d1c9b89 Pass transformed tile coordinates to the tileUrlFunction 2015-06-12 09:45:03 +02:00
Andreas Hocevar
698b62af98 Merge pull request #3793 from ahocevar/unmanaged-to-managed
Use 'managed' instead of 'unmanaged' in LayerState
2015-06-11 18:56:31 +02:00
Andreas Hocevar
817370a65b Use 'managed' instead of 'unmanaged' in LayerState 2015-06-11 18:34:20 +02:00
Marc Jansen
07d5211e30 Merge pull request #3792 from marcjansen/group-docs
Link to correct layer base class
2015-06-11 17:57:57 +02:00
Marc Jansen
3fcecc98e6 Merge pull request #3791 from marcjansen/overlay-remains
Remove docs referring to removed feature overlay
2015-06-11 17:55:50 +02:00
Marc Jansen
6ed677a3f0 Link to correct layer base class 2015-06-11 17:50:40 +02:00
Marc Jansen
dd16bb984c Remove docs referring to removed feature overlay 2015-06-11 17:47:16 +02:00
Frédéric Junod
f672c1792b Merge pull request #3790 from fredj/geojson_quotes
Remove unnecessary quotes around object keys
2015-06-11 13:32:58 +02:00
Frederic Junod
0286564e8a Remove unnecessary quotes around object keys 2015-06-11 11:58:11 +02:00
Andreas Hocevar
96e75ab17f Merge pull request #3787 from ahocevar/unmanaged-layerstate
Add 'unmanaged' to ol.layer.LayerState
2015-06-11 10:53:38 +02:00
Frédéric Junod
a6dddfa282 Merge pull request #3784 from fredj/geojson_geometry
Always write the GeoJSONFeature geometry property
2015-06-11 10:20:02 +02:00
Andreas Hocevar
5a2a7d30e6 Add 'unmanaged' to ol.layer.LayerState 2015-06-11 10:17:11 +02:00
Frederic Junod
d5ea855108 Add missing GeoJSONGeometryCollection type to GeoJSONFeature#geometry 2015-06-11 09:53:06 +02:00
Frederic Junod
d8a495b639 Always write the GeoJSONFeature geometry property 2015-06-11 09:53:06 +02:00
Andreas Hocevar
4aa3ef59d5 Merge pull request #3783 from ahocevar/wmts-hidpi-from-capabilities
Fix broken wmts-hidpi example
2015-06-10 20:03:53 +02:00
Andreas Hocevar
7451e176ef Use capabilities to create layer source options 2015-06-10 18:32:21 +02:00
Andreas Hocevar
872d869ded Merge pull request #3782 from gberaudo/typo
Fix assert documentation typo
2015-06-10 15:47:35 +02:00
Guillaume Beraudo
d48e818390 Fix assert documentation typo 2015-06-10 15:36:43 +02:00
Andreas Hocevar
fad3cf9672 Merge pull request #3758 from ahocevar/remove-featureoverlay
Removal of ol.FeatureOverlay
2015-06-10 14:33:28 +02:00
Andreas Hocevar
9acd65270a Make clear how to remove an unmanaged layer from a map 2015-06-09 15:44:39 +02:00
Andreas Hocevar
57e1dda5f1 Make sure that #clear() keeps the collection in sync 2015-06-09 15:44:39 +02:00
Andreas Hocevar
53d5d8c1d9 Get rid of ol.FeatureOverlay
This also introduces a wrapX option to the Draw, Modify and Select
interaction.
2015-06-09 15:44:31 +02:00
Andreas Hocevar
54da473991 Allow layers that are not managed by the map
When a layer is configured with a map, it will be added on top of other
layers, and not be managed in the map's features collection. The layerState
will have an 'unmanaged' flag for such layers. For vector layers, this flag
is used to not skip any features.
2015-06-09 15:44:29 +02:00
Andreas Hocevar
f186ed3deb Alternatively manage features in an ol.Collection
ol.layer.Vector can now manage both an RTree and a Collection of features.
The new useSpatialIndex option allows to opt out of RTree management, and
the new ol.Collection type of the features option allows to opt in for
Collection management.
2015-06-09 15:44:18 +02:00
Pierre GIRAUD
973cc6fd89 Merge pull request #3775 from pgiraud/touch-classname
Add ol-touch but keep ol-viewport className.
2015-06-09 12:20:55 +02:00
Pierre GIRAUD
36b521a00e Add ol-touch but keep ol-viewport className. 2015-06-09 11:34:19 +02:00
Pierre GIRAUD
7065722fa6 Show measurement tooltip on geometry change instead of relying on pointermove 2015-06-08 16:19:28 +02:00
Bart van den Eijnden
10b54a9f3f Merge pull request #3713 from bartvde/issue-3713
Add missing propertyNames member for olx.format.WFSWriteGetFeatureOptions
2015-06-08 16:15:17 +02:00
Bart van den Eijnden
e3bc0bca3e Add missing propertyNames member for olx.format.WFSWriteGetFeatureOptions extern 2015-06-08 15:56:42 +02:00
Andreas Hocevar
b903cee7dd Merge pull request #3763 from probins/drawmod
Standardise draw/modify descriptions
2015-06-07 17:34:47 +02:00
Peter Robins
282fdafad7 Standardise draw/modify descriptions 2015-06-05 07:54:22 +00:00
Jiri Matyas
ab9100450b enable deep clone of multipolygon endss 2015-03-17 11:09:03 +01:00
149 changed files with 5394 additions and 1848 deletions

View File

@@ -1,8 +1,13 @@
language: python
sudo: false
cache:
directories:
- node_modules
env:
- DISPLAY=:99.0
before_install:
- "sudo pip install -r requirements.txt"
- "pip install -r requirements.txt"
- "npm install -g npm && npm install"
before_script:

View File

@@ -19,7 +19,8 @@ BUILD_HOSTED := build/hosted/$(BRANCH)
BUILD_HOSTED_EXAMPLES := $(addprefix $(BUILD_HOSTED)/,$(EXAMPLES))
BUILD_HOSTED_EXAMPLES_JS := $(addprefix $(BUILD_HOSTED)/,$(EXAMPLES_JS))
CHECK_EXAMPLE_TIMESTAMPS = $(patsubst examples/%.html,build/timestamps/check-%-timestamp,$(EXAMPLES_HTML))
UNPHANTOMABLE_EXAMPLES = examples/shaded-relief.html examples/raster.html examples/region-growing.html
CHECK_EXAMPLE_TIMESTAMPS = $(patsubst examples/%.html,build/timestamps/check-%-timestamp,$(filter-out $(UNPHANTOMABLE_EXAMPLES),$(EXAMPLES_HTML)))
TASKS_JS := $(shell find tasks -name '*.js')

View File

@@ -1,5 +1,110 @@
## Upgrade notes
### v3.8.0
There should be nothing special required when upgrading from v3.7.0 to v3.8.0.
### v3.7.0
#### Removal of `ol.FeatureOverlay`
Instead of an `ol.FeatureOverlay`, we now use an `ol.layer.Vector` with an
`ol.source.Vector`. If you previously had:
```js
var featureOverlay = new ol.FeatureOverlay({
map: map,
style: overlayStyle
});
featureOverlay.addFeature(feature);
featureOverlay.removeFeature(feature);
var collection = featureOverlay.getFeatures();
```
you will have to change this to:
```js
var collection = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: collection,
useSpatialIndex: false // optional, might improve performance
}),
style: overlayStyle,
updateWhileAnimating: true, // optional, for instant visual feedback
updateWhileInteracting: true // optional, for instant visual feedback
});
featureOverlay.getSource().addFeature(feature);
featureOverlay.getSource().removeFeature(feature);
```
With the removal of `ol.FeatureOverlay`, `zIndex` symbolizer properties of overlays are no longer stacked per map, but per layer/overlay. If you previously had multiple feature overlays where you controlled the rendering order of features by using `zIndex` symbolizer properties, you can now achieve the same rendering order only if all overlay features are on the same layer.
Note that `ol.FeatureOverlay#getFeatures()` returned an `{ol.Collection.<ol.Feature>}`, whereas `ol.source.Vector#getFeatures()` returns an `{Array.<ol.Feature>}`.
#### `ol.TileCoord` changes
Until now, the API exposed two different types of `ol.TileCoord` tile coordinates: internal ones that increase left to right and upward, and transformed ones that may increase downward, as defined by a transform function on the tile grid. With this change, the API now only exposes tile coordinates that increase left to right and upward.
Previously, tile grids created by OpenLayers either had their origin at the top-left or at the bottom-left corner of the extent. To make it easier for application developers to transform tile coordinates to the common XYZ tiling scheme, all tile grids that OpenLayers creates internally have their origin now at the top-left corner of the extent.
This change affects applications that configure a custom `tileUrlFunction` for an `ol.source.Tile`. Previously, the `tileUrlFunction` was called with rather unpredictable tile coordinates, depending on whether a tile coordinate transform took place before calling the `tileUrlFunction`. Now it is always called with OpenLayers tile coordinates. To transform these into the common XYZ tiling scheme, a custom `tileUrlFunction` has to change the `y` value (tile row) of the `ol.TileCoord`:
```js
function tileUrlFunction = function(tileCoord, pixelRatio, projection) {
var urlTemplate = '{z}/{x}/{y}';
return urlTemplate
.replace('{z}', tileCoord[0].toString())
.replace('{x}', tileCoord[1].toString())
.replace('{y}', (-tileCoord[2] - 1).toString());
}
```
The `ol.tilegrid.TileGrid#createTileCoordTransform()` function which could be used to get the tile grid's tile coordinate transform function has been removed. This function was confusing and should no longer be needed now that application developers get tile coordinates in a known layout.
The code snippets below show how your application code needs to be changed:
Old application code (with `ol.tilegrid.TileGrid#createTileCoordTransform()`):
```js
var transform = source.getTileGrid().createTileCoordTransform();
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
tileCoord = transform(tileCoord, projection);
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' + tileCoord[2] + '.png';
};
```
Old application code (with custom `y` transform):
```js
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
var z = tileCoord[0];
var yFromBottom = tileCoord[2];
var resolution = tileGrid.getResolution(z);
var tileHeight = ol.size.toSize(tileSize)[1];
var matrixHeight =
Math.floor(ol.extent.getHeight(extent) / tileHeight / resolution);
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' +
(matrixHeight - yFromBottom - 1) + '.png';
};
```
New application code (simple -y - 1 transform):
```js
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' + (-tileCoord[2] - 1) + '.png';
};
```
#### Removal of `ol.tilegrid.Zoomify`
The replacement of `ol.tilegrid.Zoomify` is a plain `ol.tilegrid.TileGrid`, configured with `extent`, `origin` and `resolutions`. If the `size` passed to the `ol.source.Zoomify` source is `[width, height]`, then the extent for the tile grid will be `[0, -height, width, 0]`, and the origin will be `[0, 0]`.
#### Replace `ol.View.fitExtent()` and `ol.View.fitGeometry()` with `ol.View.fit()`
* This combines two previously distinct functions into one more flexible call which takes either a geometry or an extent.
* Rename all calls to `fitExtent` and `fitGeometry` to `fit`.
#### Change to `ol.interaction.Modify`
When single clicking a line or boundary within the `pixelTolerance`, a vertex is now created.
### v3.6.0
#### `ol.interaction.Draw` changes

152
changelog/v3.7.0.md Normal file
View File

@@ -0,0 +1,152 @@
# v3.7.0
## Summary
The v3.7.0 release includes features and fixes from 43 pull requests since v3.6.0. To simplify the code base, there were some changes to "experimental" features. Please follow the upgrade notes to make your applications work with the latest release.
## Upgrade notes
#### Removal of `ol.FeatureOverlay`
Instead of an `ol.FeatureOverlay`, we now use an `ol.layer.Vector` with an
`ol.source.Vector`. If you previously had:
```js
var featureOverlay = new ol.FeatureOverlay({
map: map,
style: overlayStyle
});
featureOverlay.addFeature(feature);
featureOverlay.removeFeature(feature);
var collection = featureOverlay.getFeatures();
```
you will have to change this to:
```js
var collection = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: collection,
useSpatialIndex: false // optional, might improve performance
}),
style: overlayStyle,
updateWhileAnimating: true, // optional, for instant visual feedback
updateWhileInteracting: true // optional, for instant visual feedback
});
featureOverlay.getSource().addFeature(feature);
featureOverlay.getSource().removeFeature(feature);
```
With the removal of `ol.FeatureOverlay`, `zIndex` symbolizer properties of overlays are no longer stacked per map, but per layer/overlay. If you previously had multiple feature overlays where you controlled the rendering order of features by using `zIndex` symbolizer properties, you can now achieve the same rendering order only if all overlay features are on the same layer.
Note that `ol.FeatureOverlay#getFeatures()` returned an `{ol.Collection.<ol.Feature>}`, whereas `ol.source.Vector#getFeatures()` returns an `{Array.<ol.Feature>}`.
#### `ol.TileCoord` changes
Until now, the API exposed two different types of `ol.TileCoord` tile coordinates: internal ones that increase left to right and upward, and transformed ones that may increase downward, as defined by a transform function on the tile grid. With this change, the API now only exposes tile coordinates that increase left to right and upward.
Previously, tile grids created by OpenLayers either had their origin at the top-left or at the bottom-left corner of the extent. To make it easier for application developers to transform tile coordinates to the common XYZ tiling scheme, all tile grids that OpenLayers creates internally have their origin now at the top-left corner of the extent.
This change affects applications that configure a custom `tileUrlFunction` for an `ol.source.Tile`. Previously, the `tileUrlFunction` was called with rather unpredictable tile coordinates, depending on whether a tile coordinate transform took place before calling the `tileUrlFunction`. Now it is always called with OpenLayers tile coordinates. To transform these into the common XYZ tiling scheme, a custom `tileUrlFunction` has to change the `y` value (tile row) of the `ol.TileCoord`:
```js
function tileUrlFunction = function(tileCoord, pixelRatio, projection) {
var urlTemplate = '{z}/{x}/{y}';
return urlTemplate
.replace('{z}', tileCoord[0].toString())
.replace('{x}', tileCoord[1].toString())
.replace('{y}', (-tileCoord[2] - 1).toString());
}
```
The `ol.tilegrid.TileGrid#createTileCoordTransform()` function which could be used to get the tile grid's tile coordinate transform function has been removed. This function was confusing and should no longer be needed now that application developers get tile coordinates in a known layout.
The code snippets below show how your application code needs to be changed:
Old application code (with `ol.tilegrid.TileGrid#createTileCoordTransform()`):
```js
var transform = source.getTileGrid().createTileCoordTransform();
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
tileCoord = transform(tileCoord, projection);
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' + tileCoord[2] + '.png';
};
```
Old application code (with custom `y` transform):
```js
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
var z = tileCoord[0];
var yFromBottom = tileCoord[2];
var resolution = tileGrid.getResolution(z);
var tileHeight = ol.size.toSize(tileSize)[1];
var matrixHeight =
Math.floor(ol.extent.getHeight(extent) / tileHeight / resolution);
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' +
(matrixHeight - yFromBottom - 1) + '.png';
};
```
New application code (simple -y - 1 transform):
```js
var tileUrlFunction = function(tileCoord, pixelRatio, projection) {
return 'http://mytiles.com/' +
tileCoord[0] + '/' + tileCoord[1] + '/' + (-tileCoord[2] - 1) + '.png';
};
```
#### Removal of `ol.tilegrid.Zoomify`
The replacement of `ol.tilegrid.Zoomify` is a plain `ol.tilegrid.TileGrid`, configured with `extent`, `origin` and `resolutions`. If the `size` passed to the `ol.source.Zoomify` source is `[width, height]`, then the extent for the tile grid will be `[0, -height, width, 0]`, and the origin will be `[0, 0]`.
#### Replace `ol.View.fitExtent()` and `ol.View.fitGeometry()` with `ol.View.fit()`
* This combines two previously distinct functions into one more flexible call which takes either a geometry or an extent.
* Rename all calls to `fitExtent` and `fitGeometry` to `fit`.
#### Change to `ol.interaction.Modify`
When single clicking a line or boundary within the `pixelTolerance`, a vertex is now created.
## New features and fixes
* [#3867](https://github.com/openlayers/ol3/pull/3867) - Do not require projection extent for x-wrapping tile sources ([@ahocevar](https://github.com/ahocevar))
* [#3635](https://github.com/openlayers/ol3/pull/3635) - Create vertex on boundary single click ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3806](https://github.com/openlayers/ol3/pull/3806) - Do not clip canvas for vector layers when wrapping the world ([@ahocevar](https://github.com/ahocevar))
* [#3461](https://github.com/openlayers/ol3/pull/3461) - High level Modify interaction events ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3865](https://github.com/openlayers/ol3/pull/3865) - ol.View#fit() ([@bartvde](https://github.com/bartvde))
* [#3864](https://github.com/openlayers/ol3/pull/3864) - Check projection.canWrapX() before wrapping tiles ([@klokantech](https://github.com/klokantech))
* [#3863](https://github.com/openlayers/ol3/pull/3863) - Handle CDATA in attribute parsing for GML format ([@nhambletCCRI](https://github.com/nhambletCCRI))
* [#3860](https://github.com/openlayers/ol3/pull/3860) - Update example layout. ([@tschaub](https://github.com/tschaub))
* [#3861](https://github.com/openlayers/ol3/pull/3861) - Don't force 'dom' renderer ([@openlayers](https://github.com/openlayers))
* [#3855](https://github.com/openlayers/ol3/pull/3855) - Adding an example with WMTS tiles from IGN Geoportail ([@pgiraud](https://github.com/pgiraud))
* [#3856](https://github.com/openlayers/ol3/pull/3856) - ol.source.TileVector(): bind success function of tileLoadFunction to source ([@plepe](https://github.com/plepe))
* [#3848](https://github.com/openlayers/ol3/pull/3848) - Check for exports before define. ([@tschaub](https://github.com/tschaub))
* [#3845](https://github.com/openlayers/ol3/pull/3845) - Prevent null array to be passed to an ol.Collection ([@fredj](https://github.com/fredj))
* [#3849](https://github.com/openlayers/ol3/pull/3849) - Pad min. and sec. with leading zeros in DMS notation ([@pgiraud](https://github.com/pgiraud))
* [#3842](https://github.com/openlayers/ol3/pull/3842) - Adding a feature-animation example ([@pgiraud](https://github.com/pgiraud))
* [#3833](https://github.com/openlayers/ol3/pull/3833) - Enable use of custom XHR loader for TileVector sources ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3834](https://github.com/openlayers/ol3/pull/3834) - ArcGIS tiled example broken in Chrome ([@bartvde](https://github.com/bartvde))
* [#3829](https://github.com/openlayers/ol3/pull/3829) - incorrect assert message ([@kzr-pzr](https://github.com/kzr-pzr))
* [#3828](https://github.com/openlayers/ol3/pull/3828) - Fix typo in upgrade notes ([@ahocevar](https://github.com/ahocevar))
* [#3826](https://github.com/openlayers/ol3/pull/3826) - Allow custom tileGrid in ol.source.XYZ ([@klokantech](https://github.com/klokantech))
* [#3815](https://github.com/openlayers/ol3/pull/3815) - Simplify tilegrid API and internals ([@ahocevar](https://github.com/ahocevar))
* [#3820](https://github.com/openlayers/ol3/pull/3820) - Make unmanaged vector layers behave more like ol.FeatureOverlay ([@ahocevar](https://github.com/ahocevar))
* [#3822](https://github.com/openlayers/ol3/pull/3822) - Correct docs for updateWhileInteracting ([@probins](https://github.com/probins))
* [#3818](https://github.com/openlayers/ol3/pull/3818) - Make geometry.transform api stable again. ([@probins](https://github.com/probins))
* [#3801](https://github.com/openlayers/ol3/pull/3801) - Respect the tile grid's extent in ol.source.TileVector ([@ahocevar](https://github.com/ahocevar))
* [#3810](https://github.com/openlayers/ol3/pull/3810) - Improve TileGrid documentation and examples ([@ahocevar](https://github.com/ahocevar))
* [#3808](https://github.com/openlayers/ol3/pull/3808) - Correct typo in OverlayOptions ([@probins](https://github.com/probins))
* [#3766](https://github.com/openlayers/ol3/pull/3766) - Add a clickTolerance option to the Draw interaction ([@elemoine](https://github.com/elemoine))
* [#3804](https://github.com/openlayers/ol3/pull/3804) - Remove sentence that was only meant for WMTS tile grids ([@ahocevar](https://github.com/ahocevar))
* [#3800](https://github.com/openlayers/ol3/pull/3800) - Remove further references to FeatureOverlay ([@probins](https://github.com/probins))
* [#3780](https://github.com/openlayers/ol3/pull/3780) - Only expose transformed tile coordinates to the API ([@ahocevar](https://github.com/ahocevar))
* [#3793](https://github.com/openlayers/ol3/pull/3793) - Use 'managed' instead of 'unmanaged' in LayerState ([@ahocevar](https://github.com/ahocevar))
* [#3792](https://github.com/openlayers/ol3/pull/3792) - Link to correct layer base class ([@marcjansen](https://github.com/marcjansen))
* [#3791](https://github.com/openlayers/ol3/pull/3791) - Remove docs referring to removed feature overlay ([@marcjansen](https://github.com/marcjansen))
* [#3790](https://github.com/openlayers/ol3/pull/3790) - Remove unnecessary quotes around object keys ([@fredj](https://github.com/fredj))
* [#3787](https://github.com/openlayers/ol3/pull/3787) - Add 'unmanaged' to ol.layer.LayerState ([@ahocevar](https://github.com/ahocevar))
* [#3784](https://github.com/openlayers/ol3/pull/3784) - Always write the GeoJSONFeature geometry property ([@fredj](https://github.com/fredj))
* [#3783](https://github.com/openlayers/ol3/pull/3783) - Fix broken wmts-hidpi example ([@ahocevar](https://github.com/ahocevar))
* [#3782](https://github.com/openlayers/ol3/pull/3782) - Fix assert documentation typo ([@gberaudo](https://github.com/gberaudo))
* [#3758](https://github.com/openlayers/ol3/pull/3758) - Removal of ol.FeatureOverlay ([@ahocevar](https://github.com/ahocevar))
* [#3775](https://github.com/openlayers/ol3/pull/3775) - Add ol-touch but keep ol-viewport className. ([@pgiraud](https://github.com/pgiraud))
* [#3713](https://github.com/openlayers/ol3/pull/3713) - Add missing propertyNames member for olx.format.WFSWriteGetFeatureOptions ([@bartvde](https://github.com/bartvde))
* [#3763](https://github.com/openlayers/ol3/pull/3763) - Standardise draw/modify descriptions ([@probins](https://github.com/probins))

41
changelog/v3.8.0.md Normal file
View File

@@ -0,0 +1,41 @@
# v3.8.0
## Summary
The v3.8.0 release includes features and fixes from 33 pull requests since v3.7.0. While summer vacations have slowed the pace of development a bit this month, there are some nice improvements in this release. See the complete list below for details.
## New features and fixes
* [#3957](https://github.com/openlayers/ol3/pull/3957) - Properly handle vertex deletion with multiple features. ([@tschaub](https://github.com/tschaub))
* [#3954](https://github.com/openlayers/ol3/pull/3954) - Remove ol.control.Control.bindMouseOutFocusOutBlur function. ([@fredj](https://github.com/fredj))
* [#3214](https://github.com/openlayers/ol3/pull/3214) - Pixel manipulation with raster sources. ([@tschaub](https://github.com/tschaub))
* [#3946](https://github.com/openlayers/ol3/pull/3946) - Fix vertex deletion for Modify interaction on mobile devices. ([@Turbo87](https://github.com/Turbo87))
* [#3910](https://github.com/openlayers/ol3/pull/3910) - Do not provide an AMD environment to ol.ext modules. ([@ahocevar](https://github.com/ahocevar))
* [#3934](https://github.com/openlayers/ol3/pull/3934) - Fix `drawstart` and `drawend` events when drawing a point ([@fredj](https://github.com/fredj))
* [#3774](https://github.com/openlayers/ol3/pull/3774) - Measure tooltips touchdevice ([@pgiraud](https://github.com/pgiraud))
* [#3949](https://github.com/openlayers/ol3/pull/3949) - Remove count argument from `called` function ([@fredj](https://github.com/fredj))
* [#3950](https://github.com/openlayers/ol3/pull/3950) - Remove reference to vbarray.js ([@elemoine](https://github.com/elemoine))
* [#3947](https://github.com/openlayers/ol3/pull/3947) - Clarify documentation of Image source ratio option. ([@alvinlindstam](https://github.com/alvinlindstam))
* [#3920](https://github.com/openlayers/ol3/pull/3920) - Remove use_types_for_optimization from custom build tutorial. ([@probins](https://github.com/probins))
* [#3922](https://github.com/openlayers/ol3/pull/3922) - Document {?-?} pattern in expandUrl ([@probins](https://github.com/probins))
* [#3921](https://github.com/openlayers/ol3/pull/3921) - Cache node_modules on Travis. ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3942](https://github.com/openlayers/ol3/pull/3942) - Fix WMTS TileMatrixSet lookup by SRS identifier ([@ahocevar](https://github.com/ahocevar))
* [#3945](https://github.com/openlayers/ol3/pull/3945) - Simplify icon example and show popup at clicked position ([@ahocevar](https://github.com/ahocevar))
* [#3930](https://github.com/openlayers/ol3/pull/3930) - Use goog.functions.identity instead of goog.identityFunction ([@fredj](https://github.com/fredj))
* [#3929](https://github.com/openlayers/ol3/pull/3929) - Expand description for XYZ source ([@probins](https://github.com/probins))
* [#3933](https://github.com/openlayers/ol3/pull/3933) - Snap center to pixel to avoid floating point issues ([@ahocevar](https://github.com/ahocevar))
* [#3932](https://github.com/openlayers/ol3/pull/3932) - SnapOptions: Fix typo in pixelTolerance JSDoc ([@Turbo87](https://github.com/Turbo87))
* [#3931](https://github.com/openlayers/ol3/pull/3931) - Remove unused htmlparser2 package ([@fredj](https://github.com/fredj))
* [#3912](https://github.com/openlayers/ol3/pull/3912) - Fix the event type fired by goog.fx.Dragger ([@fredj](https://github.com/fredj))
* [#3871](https://github.com/openlayers/ol3/pull/3871) - Document change events properly ([@ahocevar](https://github.com/ahocevar))
* [#3906](https://github.com/openlayers/ol3/pull/3906) - Clear features properly when there is no spatial index ([@ahocevar](https://github.com/ahocevar))
* [#3896](https://github.com/openlayers/ol3/pull/3896) - Fire WebGL precompose event in same sequence as other renderers ([@ahocevar](https://github.com/ahocevar))
* [#3359](https://github.com/openlayers/ol3/pull/3359) - Enable deep clone of MultiPolygon. ([@Kenny806](https://github.com/Kenny806))
* [#3895](https://github.com/openlayers/ol3/pull/3895) - Rework the tile queue for multiple queues. ([@aisaacs](https://github.com/aisaacs))
* [#3894](https://github.com/openlayers/ol3/pull/3894) - Install Python dependencies without sudo. ([@tschaub](https://github.com/tschaub))
* [#3824](https://github.com/openlayers/ol3/pull/3824) - Improve docs for interaction.Select. ([@probins](https://github.com/probins))
* [#3884](https://github.com/openlayers/ol3/pull/3884) - Provide a debug loader for the library. ([@tschaub](https://github.com/tschaub))
* [#3883](https://github.com/openlayers/ol3/pull/3883) - Ignore layer filter for unmanaged layers ([@ahocevar](https://github.com/ahocevar))
* [#3859](https://github.com/openlayers/ol3/pull/3859) - Add in crossOrigin option ([@llambanna](https://github.com/llambanna))
* [#3873](https://github.com/openlayers/ol3/pull/3873) - Correct minor typo in modifyinteraction ([@probins](https://github.com/probins))
* [#3872](https://github.com/openlayers/ol3/pull/3872) - Correct event notations in ol.Feature ([@probins](https://github.com/probins))

View File

@@ -20,8 +20,7 @@
"externs/jquery-1.9.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js",
"externs/vbarray.js"
"externs/topojson.js"
],
"define": [
"goog.array.ASSUME_NATIVE_FUNCTIONS=true",

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
{{{ extraHead }}}
@@ -15,13 +15,11 @@
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container" id="navbar-inner-container">
<a class="brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers 3 Examples</a>
</div>
<header class="navbar" role="navigation">
<div class="container" id="navbar-inner-container">
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers 3 Examples</a>
</div>
</div>
</header>
<div class="container-fluid">
@@ -52,8 +50,8 @@
&lt;head&gt;
&lt;title&gt;{{ title }}&lt;/title&gt;
&lt;script src="https://code.jquery.com/jquery-1.11.2.min.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"&gt;
&lt;script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"&gt;
&lt;script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/{{ olVersion }}/ol.css" type="text/css"&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/{{ olVersion }}/ol.js"&gt;&lt;/script&gt;
{{ extraHead }}
@@ -77,8 +75,8 @@
</div>
</div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="./resources/common.js"></script>
<script src="./resources/prism/prism.min.js"></script>
{{{ js.tag }}}

View File

@@ -24,7 +24,7 @@ var self = this;
<?js } ?>
</dt>
<dd class="<?js= (data.stability && data.stability !== 'stable') ? 'unstable' : '' ?>">
<?js if (data.description) { ?>
<div class="description">
<?js= data.description ?>
@@ -39,20 +39,20 @@ var self = this;
</li>
</ul>
<?js } ?>
<?js if (data['this']) { ?>
<h5>This:</h5>
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
<?js } ?>
<?js if (data.stability || kind !== 'class') { ?>
<?js if (data.params && params.length) { ?>
<?js= this.partial('params.tmpl', params) ?>
<?js } ?>
<?js } ?>
<?js= this.partial('details.tmpl', data) ?>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) {
@@ -68,7 +68,7 @@ var self = this;
}
?>
<li class="<?js= (eventDoclet || data).stability !== 'stable' ? 'unstable' : '' ?>">
<code><?js= self.linkto(f, type) ?></code>
<code><?js= eventClassName ? self.linkto(f, type) : type ?></code>
<?js if (eventClassName) {
var eventClass = self.find({longname: eventClassName})[0];
if (eventClass) { ?>
@@ -96,7 +96,7 @@ var self = this;
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.exceptions && exceptions.length) { ?>
<h5>Throws:</h5>
<?js if (exceptions.length > 1) { ?><ul><?js
@@ -108,12 +108,12 @@ var self = this;
<?js= self.partial('exceptions.tmpl', r) ?>
<?js });
} } ?>
<?js if (data.returns && returns.length) { ?>
<?js if (returns.length > 1) { ?><h5>Returns:</h5><?js } ?>
<?js= self.partial('returns.tmpl', data.returns) ?>
<?js } ?>
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>

View File

@@ -72,7 +72,6 @@ Creating a custom build requires writing a build configuration file. The format
"api", "observable"
],
"compilation_level": "ADVANCED_OPTIMIZATIONS",
"use_types_for_optimization": true,
"manage_closure_dependencies": true
}
}
@@ -180,7 +179,7 @@ The Closure documentation explains that "externs" are for external names used in
### Other compiler options
There are a couple of other compiler options in the config file above. `manage_closure_dependencies` should always be used. `use_types_for_optimization` should be used for better compression rates.
There are a couple of other compiler options in the config file above. `manage_closure_dependencies` should always be used.
You can specify any of the other compiler options here as needed, such as the renaming reports, output manifest, or source maps. There is a full list of available options in [closure-util](https://github.com/openlayers/closure-util/blob/master/compiler-options.txt).
@@ -219,7 +218,6 @@ Now let's try a more complicated example: [`heatmaps-earthquakes`](http://openla
"goog.DEBUG=false"
],
"compilation_level": "ADVANCED_OPTIMIZATIONS",
"use_types_for_optimization": true,
"manage_closure_dependencies": true
}
}

View File

@@ -3,8 +3,11 @@ template: example.html
title: Canvas tiles example
shortdesc: Renders tiles with coordinates for debugging.
docs: >
<p>The black grid tiles are generated on the client with an HTML5 canvas. Note that the tile coordinates are ol3 normalized tile coordinates (origin bottom left), not
OSM tile coordinates (origin top left).</p>
The black grid tiles are generated on the client with an HTML5 canvas. The
displayed tile coordinates are OpenLayers tile coordinates. These increase
from bottom to top, but standard XYZ tiling scheme coordinates increase from
top to bottom. To calculate the `y` for a standard XYZ tile coordinate, use
`-y - 1`.
tags: "layers, openstreetmap, canvas"
---
<div class="row-fluid">

View File

@@ -7,15 +7,16 @@ goog.require('ol.source.OSM');
goog.require('ol.source.TileDebug');
var osmSource = new ol.source.OSM();
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
source: osmSource
}),
new ol.layer.Tile({
source: new ol.source.TileDebug({
projection: 'EPSG:3857',
tileGrid: ol.tilegrid.createXYZ({maxZoom: 22})
tileGrid: osmSource.getTileGrid()
})
})
],

View File

@@ -6,7 +6,7 @@ docs: >
This example demonstrates how a map's view can be
adjusted so a geometry or coordinate is positioned at a specific
pixel location. The map above has top, right, bottom, and left
padding applied inside the viewport. The view's <code>fitGeometry</code> method
padding applied inside the viewport. The view's <code>fit</code> method
is used to fit a geometry in the view with the same padding. The
view's <code>centerOn</code> method is used to position a coordinate (Lausanne)
at a specific pixel location (the center of the black box).

View File

@@ -65,7 +65,7 @@ zoomtoswitzerlandbest.addEventListener('click', function() {
var feature = source.getFeatures()[0];
var polygon = /** @type {ol.geom.SimpleGeometry} */ (feature.getGeometry());
var size = /** @type {ol.Size} */ (map.getSize());
view.fitGeometry(
view.fit(
polygon,
size,
{
@@ -81,7 +81,7 @@ zoomtoswitzerlandconstrained.addEventListener('click', function() {
var feature = source.getFeatures()[0];
var polygon = /** @type {ol.geom.SimpleGeometry} */ (feature.getGeometry());
var size = /** @type {ol.Size} */ (map.getSize());
view.fitGeometry(
view.fit(
polygon,
size,
{
@@ -96,7 +96,7 @@ zoomtoswitzerlandnearest.addEventListener('click', function() {
var feature = source.getFeatures()[0];
var polygon = /** @type {ol.geom.SimpleGeometry} */ (feature.getGeometry());
var size = /** @type {ol.Size} */ (map.getSize());
view.fitGeometry(
view.fit(
polygon,
size,
{
@@ -111,7 +111,7 @@ zoomtolausanne.addEventListener('click', function() {
var feature = source.getFeatures()[1];
var point = /** @type {ol.geom.SimpleGeometry} */ (feature.getGeometry());
var size = /** @type {ol.Size} */ (map.getSize());
view.fitGeometry(
view.fit(
point,
size,
{

View File

@@ -122,7 +122,7 @@ dragAndDropInteraction.on('addfeatures', function(event) {
style: styleFunction
})
}));
map.getView().fitExtent(
map.getView().fit(
vectorSource.getExtent(), /** @type {ol.Size} */ (map.getSize()));
});

View File

@@ -118,7 +118,7 @@ dragAndDropInteraction.on('addfeatures', function(event) {
source: vectorSource,
style: styleFunction
}));
map.getView().fitExtent(
map.getView().fit(
vectorSource.getExtent(), /** @type {ol.Size} */ (map.getSize()));
});

View File

@@ -1,11 +1,13 @@
goog.require('ol.FeatureOverlay');
goog.require('ol.Collection');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.events.condition');
goog.require('ol.interaction.Draw');
goog.require('ol.interaction.Modify');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.source.MapQuest');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
@@ -24,11 +26,9 @@ var map = new ol.Map({
})
});
// The features are not added to a regular vector layer/source,
// but to a feature overlay which holds a collection of features.
// This collection is passed to the modify and also the draw
// interaction, so that both can add or modify features.
var featureOverlay = new ol.FeatureOverlay({
var features = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({features: features}),
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
@@ -48,7 +48,7 @@ var featureOverlay = new ol.FeatureOverlay({
featureOverlay.setMap(map);
var modify = new ol.interaction.Modify({
features: featureOverlay.getFeatures(),
features: features,
// the SHIFT key must be pressed to delete vertices, so
// that new vertices can be drawn at the same position
// of existing vertices
@@ -62,7 +62,7 @@ map.addInteraction(modify);
var draw; // global so we can remove it later
function addInteraction() {
draw = new ol.interaction.Draw({
features: featureOverlay.getFeatures(),
features: features,
type: /** @type {ol.geom.GeometryType} */ (typeSelect.value)
});
map.addInteraction(draw);

View File

@@ -0,0 +1,15 @@
---
template: example.html
title: Feature animation example
shortdesc: Demonstrates how to animate features.
docs: >
This example shows how to use <b>postcompose</b> and <b>vectorContext</b> to
animate features. Here we choose to do a flash animation each time a feature
is added to the layer.
tags: "animation, vector, feature, flash"
---
<div class="row">
<div class="span8">
<div id="map" class="map"></div>
</div>
</div>

View File

@@ -0,0 +1,96 @@
goog.require('ol.Feature');
goog.require('ol.Map');
goog.require('ol.Observable');
goog.require('ol.View');
goog.require('ol.control');
goog.require('ol.easing');
goog.require('ol.geom.Point');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.proj');
goog.require('ol.source.OSM');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
goog.require('ol.style.Stroke');
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM({
wrapX: false
})
})
],
controls: ol.control.defaults({
attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
renderer: common.getRendererFromQueryString(),
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 1
})
});
var source = new ol.source.Vector({
wrapX: false
});
var vector = new ol.layer.Vector({
source: source
});
map.addLayer(vector);
function addRandomFeature() {
var x = Math.random() * 360 - 180;
var y = Math.random() * 180 - 90;
var geom = new ol.geom.Point(ol.proj.transform([x, y],
'EPSG:4326', 'EPSG:3857'));
var feature = new ol.Feature(geom);
source.addFeature(feature);
}
var duration = 3000;
function flash(feature) {
var start = new Date().getTime();
var listenerKey;
function animate(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
var flashGeom = feature.getGeometry().clone();
var elapsed = frameState.time - start;
var elapsedRatio = elapsed / duration;
// radius will be 5 at start and 30 at end.
var radius = ol.easing.easeOut(elapsedRatio) * 25 + 5;
var opacity = ol.easing.easeOut(1 - elapsedRatio);
var flashStyle = new ol.style.Circle({
radius: radius,
snapToPixel: false,
stroke: new ol.style.Stroke({
color: 'rgba(255, 0, 0, ' + opacity + ')',
width: 1,
opacity: opacity
})
});
vectorContext.setImageStyle(flashStyle);
vectorContext.drawPointGeometry(flashGeom, null);
if (elapsed > duration) {
ol.Observable.unByKey(listenerKey);
return;
}
// tell OL3 to continue postcompose animation
frameState.animate = true;
}
listenerKey = map.on('postcompose', animate);
}
source.on('addfeature', function(e) {
flash(e.feature);
});
window.setInterval(addRandomFeature, 1000);

View File

@@ -10,7 +10,7 @@ tags: "fullscreen, geolocation, orientation, mobile"
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
<title>Mobile Geolocation Tracking with Orientation</title>

View File

@@ -1,12 +1,13 @@
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.Geolocation');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control');
goog.require('ol.geom.Point');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.source.OSM');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
@@ -85,7 +86,9 @@ geolocation.on('change:position', function() {
new ol.geom.Point(coordinates) : null);
});
var featuresOverlay = new ol.FeatureOverlay({
var featuresOverlay = new ol.layer.Vector({
map: map,
features: [accuracyFeature, positionFeature]
source: new ol.source.Vector({
features: [accuracyFeature, positionFeature]
})
});

View File

@@ -1,5 +1,4 @@
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.geom.Point');
@@ -102,12 +101,14 @@ for (i = 0; i < featureCount; i += 30) {
overlayFeatures.push(clone);
}
var featureOverlay = new ol.FeatureOverlay({
var featureOverlay = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: overlayFeatures
}),
style: new ol.style.Style({
image: icons[iconCount - 1]
}),
features: overlayFeatures
})
});
map.on('click', function(evt) {

View File

@@ -1,6 +1,3 @@
#map {
position: relative;
}
#popup {
padding-bottom: 45px;
}

View File

@@ -71,9 +71,7 @@ map.on('click', function(evt) {
return feature;
});
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
popup.setPosition(coord);
popup.setPosition(evt.coordinate);
$(element).popover({
'placement': 'top',
'html': true,

View File

@@ -1,6 +1,5 @@
goog.require('ol.Attribution');
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control');
@@ -180,7 +179,8 @@ map.on('postcompose', function(evt) {
}
});
var featureOverlay = new ol.FeatureOverlay({
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector(),
map: map,
style: new ol.style.Style({
image: new ol.style.Circle({
@@ -203,7 +203,7 @@ document.getElementById('time').addEventListener('input', function() {
if (highlight === undefined) {
highlight = new ol.Feature(new ol.geom.Point(coordinate));
feature.set('highlight', highlight);
featureOverlay.addFeature(highlight);
featureOverlay.getSource().addFeature(highlight);
} else {
highlight.getGeometry().setCoordinates(coordinate);
}

View File

@@ -1,9 +1,9 @@
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.GeoJSON');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.source.ImageVector');
goog.require('ol.source.MapQuest');
goog.require('ol.source.Vector');
@@ -42,7 +42,8 @@ var map = new ol.Map({
})
});
var featureOverlay = new ol.FeatureOverlay({
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector(),
map: map,
style: new ol.style.Style({
stroke: new ol.style.Stroke({
@@ -71,10 +72,10 @@ var displayFeatureInfo = function(pixel) {
if (feature !== highlight) {
if (highlight) {
featureOverlay.removeFeature(highlight);
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.addFeature(feature);
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}

View File

@@ -4,24 +4,33 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
<style>
body {
padding-top: 70px;
}
.navbar-form {
margin-top: 12px;
}
input.search-query {
color: #333;
}
.example {
padding: 10px;
background-color: #F5F5F5;
height: 140px;
padding: 3px;
background-color: #eee;
border-radius: 3px;
margin-bottom: 10px;
margin: 10px 0;
overflow: auto;
}
.example p.description {
font-size: smaller;
margin: 5px 0;
}
.example:hover {
background-color: #ddd;
}
.navbar-search.pull-left {
padding: 5px;
}
::-webkit-scrollbar {
width: 8px;
@@ -174,35 +183,31 @@
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers 3 Examples</a>
<form class="navbar-search pull-left">
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search">
<span id="count"></span>
</form>
</div>
<header class="navbar navbar-fixed-top" role="navigation">
<div class="container">
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers 3 Examples</a>
<form class="navbar-form navbar-left" role="search">
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search">
<span id="count"></span>
</form>
</div>
</div>
</header>
<div class="container-fluid">
<div id="examples"></div>
<div style="display: none;">
<div id="template">
<div class="span4 example" jugl:repeat="example examples">
<a jugl:attributes="href example.link" class="mainlink">
<strong><span jugl:replace="example.title">title</span></strong><br>
<small jugl:content="'(' + example.example + ')'"></small>
</a>
<p><div jugl:content="example.shortdesc"></div></p>
<p><small jugl:content="'tags: ' + example.tags"></small></p>
<div id="template" class="row">
<div class="col-md-4 col-sm-4" jugl:repeat="example examples">
<div class="example">
<a jugl:attributes="href example.link" class="mainlink">
<strong><span jugl:replace="example.title">title</span></strong><br>
<small jugl:content="'(' + example.example + ')'"></small>
</a>
<p class="description" jugl:content="example.shortdesc"></p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,4 +1,5 @@
goog.require('ol.Map');
goog.require('ol.Observable');
goog.require('ol.Overlay');
goog.require('ol.Sphere');
goog.require('ol.View');
@@ -103,27 +104,20 @@ var pointerMoveHandler = function(evt) {
}
/** @type {string} */
var helpMsg = 'Click to start drawing';
/** @type {ol.Coordinate|undefined} */
var tooltipCoord = evt.coordinate;
if (sketch) {
var output;
var geom = (sketch.getGeometry());
if (geom instanceof ol.geom.Polygon) {
output = formatArea(/** @type {ol.geom.Polygon} */ (geom));
helpMsg = continuePolygonMsg;
tooltipCoord = geom.getInteriorPoint().getCoordinates();
} else if (geom instanceof ol.geom.LineString) {
output = formatLength( /** @type {ol.geom.LineString} */ (geom));
helpMsg = continueLineMsg;
tooltipCoord = geom.getLastCoordinate();
}
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(tooltipCoord);
}
helpTooltipElement.innerHTML = helpMsg;
helpTooltip.setPosition(evt.coordinate);
$(helpTooltipElement).removeClass('hidden');
};
@@ -138,6 +132,10 @@ var map = new ol.Map({
map.on('pointermove', pointerMoveHandler);
$(map.getViewport()).on('mouseout', function() {
$(helpTooltipElement).addClass('hidden');
});
var typeSelect = document.getElementById('type');
var geodesicCheckbox = document.getElementById('geodesic');
@@ -172,10 +170,28 @@ function addInteraction() {
createMeasureTooltip();
createHelpTooltip();
var listener;
draw.on('drawstart',
function(evt) {
// set sketch
sketch = evt.feature;
/** @type {ol.Coordinate|undefined} */
var tooltipCoord = evt.coordinate;
listener = sketch.getGeometry().on('change', function(evt) {
var geom = evt.target;
var output;
if (geom instanceof ol.geom.Polygon) {
output = formatArea(/** @type {ol.geom.Polygon} */ (geom));
tooltipCoord = geom.getInteriorPoint().getCoordinates();
} else if (geom instanceof ol.geom.LineString) {
output = formatLength( /** @type {ol.geom.LineString} */ (geom));
tooltipCoord = geom.getLastCoordinate();
}
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(tooltipCoord);
});
}, this);
draw.on('drawend',
@@ -187,6 +203,7 @@ function addInteraction() {
// unset tooltip so that a new one can be created
measureTooltipElement = null;
createMeasureTooltip();
ol.Observable.unByKey(listener);
}, this);
}
@@ -199,7 +216,7 @@ function createHelpTooltip() {
helpTooltipElement.parentNode.removeChild(helpTooltipElement);
}
helpTooltipElement = document.createElement('div');
helpTooltipElement.className = 'tooltip';
helpTooltipElement.className = 'tooltip hidden';
helpTooltip = new ol.Overlay({
element: helpTooltipElement,
offset: [15, 0],

View File

@@ -24,7 +24,9 @@ var vector = new ol.layer.Vector({
})
});
var select = new ol.interaction.Select();
var select = new ol.interaction.Select({
wrapX: false
});
var modify = new ol.interaction.Modify({
features: select.getFeatures()

31
examples/raster.css Normal file
View File

@@ -0,0 +1,31 @@
.rel {
position: relative
}
#plot {
pointer-events: none;
position: absolute;
bottom: 10px;
left: 10px;
}
.bar {
pointer-events: auto;
fill: #AFAFB9;
}
.bar.selected {
fill: green;
}
.tip {
position: absolute;
background: black;
color: white;
padding: 6px;
font-size: 12px;
border-radius: 4px;
margin-bottom: 10px;
display: none;
opacity: 0;
}

31
examples/raster.html Normal file
View File

@@ -0,0 +1,31 @@
---
template: example.html
title: Raster Source
shortdesc: Demonstrates pixelwise operations with a raster source.
docs: >
<p>
This example uses a <code>ol.source.Raster</code> to generate data
based on another source. The raster source accepts any number of
input sources (tile or image based) and runs a pipeline of
operations on the input pixels. The return from the final
operation is used as the data for the output source.
</p>
<p>
In this case, a single tiled source of imagery is used as input.
For each pixel, the Vegetaion Greenness Index
(<a href="http://www.tandfonline.com/doi/abs/10.1080/10106040108542184#.Vb90ITBViko">VGI</a>)
is calculated from the input pixels. A second operation colors
those pixels based on a threshold value (values above the
threshold are green and those below are transparent).
</p>
tags: "raster, pixel"
resources:
- http://d3js.org/d3.v3.min.js
- raster.css
---
<div class="row-fluid">
<div class="span12 rel">
<div id="map" class="map"></div>
<div id="plot"></div>
</div>
</div>

200
examples/raster.js Normal file
View File

@@ -0,0 +1,200 @@
// NOCOMPILE
// this example uses d3 for which we don't have an externs file.
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.source.BingMaps');
goog.require('ol.source.Raster');
var minVgi = 0;
var maxVgi = 0.25;
var bins = 10;
/**
* Calculate the Vegetation Greenness Index (VGI) from an input pixel. This
* is a rough estimate assuming that pixel values correspond to reflectance.
* @param {ol.raster.Pixel} pixel An array of [R, G, B, A] values.
* @return {number} The VGI value for the given pixel.
*/
function vgi(pixel) {
var r = pixel[0] / 255;
var g = pixel[1] / 255;
var b = pixel[2] / 255;
return (2 * g - r - b) / (2 * g + r + b);
}
/**
* Summarize values for a histogram.
* @param {numver} value A VGI value.
* @param {Object} counts An object for keeping track of VGI counts.
*/
function summarize(value, counts) {
var min = counts.min;
var max = counts.max;
var num = counts.values.length;
if (value < min) {
// do nothing
} else if (value >= max) {
counts.values[num - 1] += 1;
} else {
var index = Math.floor((value - min) / counts.delta);
counts.values[index] += 1;
}
}
/**
* Use aerial imagery as the input data for the raster source.
*/
var bing = new ol.source.BingMaps({
key: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3',
imagerySet: 'Aerial'
});
/**
* Create a raster source where pixels with VGI values above a threshold will
* be colored green.
*/
var raster = new ol.source.Raster({
sources: [bing],
operation: function(pixels, data) {
var pixel = pixels[0];
var value = vgi(pixel);
summarize(value, data.counts);
if (value >= data.threshold) {
pixel[0] = 0;
pixel[1] = 255;
pixel[2] = 0;
pixel[3] = 128;
} else {
pixel[3] = 0;
}
return pixel;
},
lib: {
vgi: vgi,
summarize: summarize
}
});
raster.set('threshold', 0.1);
function createCounts(min, max, num) {
var values = new Array(num);
for (var i = 0; i < num; ++i) {
values[i] = 0;
}
return {
min: min,
max: max,
values: values,
delta: (max - min) / num
};
}
raster.on('beforeoperations', function(event) {
event.data.counts = createCounts(minVgi, maxVgi, bins);
event.data.threshold = raster.get('threshold');
});
raster.on('afteroperations', function(event) {
schedulePlot(event.resolution, event.data.counts, event.data.threshold);
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: bing
}),
new ol.layer.Image({
source: raster
})
],
target: 'map',
view: new ol.View({
center: [-9651695, 4937351],
zoom: 13,
minZoom: 12,
maxZoom: 19
})
});
var timer = null;
function schedulePlot(resolution, counts, threshold) {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(plot.bind(null, resolution, counts, threshold), 1000 / 60);
}
var barWidth = 15;
var plotHeight = 150;
var chart = d3.select('#plot').append('svg')
.attr('width', barWidth * bins)
.attr('height', plotHeight);
var chartRect = chart[0][0].getBoundingClientRect();
var tip = d3.select(document.body).append('div')
.attr('class', 'tip');
function plot(resolution, counts, threshold) {
var yScale = d3.scale.linear()
.domain([0, d3.max(counts.values)])
.range([0, plotHeight]);
var bar = chart.selectAll('rect').data(counts.values);
bar.enter().append('rect');
bar.attr('class', function(count, index) {
var value = counts.min + (index * counts.delta);
return 'bar' + (value >= threshold ? ' selected' : '');
})
.attr('width', barWidth - 2);
bar.transition().attr('transform', function(value, index) {
return 'translate(' + (index * barWidth) + ', ' +
(plotHeight - yScale(value)) + ')';
})
.attr('height', yScale);
bar.on('mousemove', function(count, index) {
var threshold = counts.min + (index * counts.delta);
if (raster.get('threshold') !== threshold) {
raster.set('threshold', threshold);
raster.changed();
}
});
bar.on('mouseover', function(count, index) {
var area = 0;
for (var i = counts.values.length - 1; i >= index; --i) {
area += resolution * resolution * counts.values[i];
}
tip.html(message(counts.min + (index * counts.delta), area));
tip.style('display', 'block');
tip.transition().style({
left: (chartRect.left + (index * barWidth) + (barWidth / 2)) + 'px',
top: (d3.event.y - 60) + 'px',
opacity: 1
});
});
bar.on('mouseout', function() {
tip.transition().style('opacity', 0).each('end', function() {
tip.style('display', 'none');
});
});
}
function message(value, area) {
var acres = (area / 4046.86).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return acres + ' acres at<br>' + value.toFixed(2) + ' VGI or above';
}

View File

@@ -0,0 +1,4 @@
table.controls td {
min-width: 110px;
padding: 2px 5px;
}

View File

@@ -0,0 +1,38 @@
---
template: example.html
title: Region Growing
shortdesc: Grow a region from a seed pixel
docs: >
<p>Click a region on the map. The computed region will be red.</p>
<p>
This example uses a <code>ol.source.Raster</code> to generate data
based on another source. The raster source accepts any number of
input sources (tile or image based) and runs a pipeline of
operations on the input data. The return from the final
operation is used as the data for the output source.
</p>
<p>
In this case, a single tiled source of imagery data is used as input.
The region is calculated in a single "image" operation using the "seed"
pixel provided by the user clicking on the map. The "threshold" value
determines whether a given contiguous pixel belongs to the "region" - the
difference between a candidate pixel's RGB values and the seed values must
be below the threshold.
</p>
<p>
This example also shows how an additional function can be made available
to the operation.
</p>
tags: "raster, region growing"
---
<div class="row-fluid">
<div class="span12">
<div id="map" class="map" style="cursor: pointer"></div>
<table class="controls">
<tr>
<td>Threshold: <span id="threshold-value"></span></td>
<td><input id="threshold" type="range" min="1" max="50" value="20"></td>
</tr>
</table>
</div>
</div>

132
examples/region-growing.js Normal file
View File

@@ -0,0 +1,132 @@
// NOCOMPILE
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.BingMaps');
goog.require('ol.source.Raster');
function growRegion(inputs, data) {
var image = inputs[0];
var seed = data.pixel;
var delta = parseInt(data.delta);
if (!seed) {
return image;
}
seed = seed.map(Math.round);
var width = image.width;
var height = image.height;
var inputData = image.data;
var outputData = new Uint8ClampedArray(inputData);
var seedIdx = (seed[1] * width + seed[0]) * 4;
var seedR = inputData[seedIdx];
var seedG = inputData[seedIdx + 1];
var seedB = inputData[seedIdx + 2];
var edge = [seed];
while (edge.length) {
var newedge = [];
for (var i = 0, ii = edge.length; i < ii; i++) {
// As noted in the Raster source constructor, this function is provided
// using the `lib` option. Other functions will NOT be visible unless
// provided using the `lib` option.
var next = nextEdges(edge[i]);
for (var j = 0, jj = next.length; j < jj; j++) {
var s = next[j][0], t = next[j][1];
if (s >= 0 && s < width && t >= 0 && t < height) {
var ci = (t * width + s) * 4;
var cr = inputData[ci];
var cg = inputData[ci + 1];
var cb = inputData[ci + 2];
var ca = inputData[ci + 3];
// if alpha is zero, carry on
if (ca === 0) {
continue;
}
if (Math.abs(seedR - cr) < delta && Math.abs(seedG - cg) < delta &&
Math.abs(seedB - cb) < delta) {
outputData[ci] = 255;
outputData[ci + 1] = 0;
outputData[ci + 2] = 0;
outputData[ci + 3] = 255;
newedge.push([s, t]);
}
// mark as visited
inputData[ci + 3] = 0;
}
}
}
edge = newedge;
}
return new ImageData(outputData, width, height);
}
function next4Edges(edge) {
var x = edge[0], y = edge[1];
return [
[x + 1, y],
[x - 1, y],
[x, y + 1],
[x, y - 1]
];
}
var key = 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3';
var imagery = new ol.layer.Tile({
source: new ol.source.BingMaps({key: key, imagerySet: 'Aerial'})
});
var raster = new ol.source.Raster({
sources: [imagery.getSource()],
operationType: 'image',
operation: growRegion,
// Functions in the `lib` object will be available to the operation run in
// the web worker.
lib: {
nextEdges: next4Edges
}
});
var rasterImage = new ol.layer.Image({
opacity: 0.7,
source: raster
});
var map = new ol.Map({
layers: [imagery, rasterImage],
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([-119.07, 47.65]),
zoom: 11
})
});
var coordinate;
map.on('click', function(event) {
coordinate = event.coordinate;
raster.changed();
});
raster.on('beforeoperations', function(event) {
// the event.data object will be passed to operations
var data = event.data;
data.delta = thresholdControl.value;
if (coordinate) {
data.pixel = map.getPixelFromCoordinate(coordinate);
}
});
var thresholdControl = document.getElementById('threshold');
function updateControlValue() {
document.getElementById('threshold-value').innerText = thresholdControl.value;
}
updateControlValue();
thresholdControl.addEventListener('input', function() {
updateControlValue();
raster.changed();
});

View File

@@ -1,15 +1,59 @@
@import url(http://fonts.googleapis.com/css?family=Quattrocento+Sans:400,400italic,700);
body {
padding-top: 60px;
font-family: 'Quattrocento Sans', sans-serif;
font-size: 16px;
}
.navbar {
background-color: #1F6B75;
color: white;
border: 0;
border-radius: 0;
}
.navbar-brand {
color: white;
font-weight: bold;
font-size: 160%;
padding: 8px 0;
}
.navbar-brand:hover,
.navbar-brand:focus {
color: #aae1e9;
}
.navbar-brand img {
height: 35px;
vertical-align: middle;
margin-right: 5px;
display: inline-block;
}
ul.inline,
ol.inline {
margin-left: 0;
padding-left: 0;
list-style: none;
}
ul.inline>li,
ol.inline>li {
display: inline-block;
padding-left: 5px;
padding-right: 5px;
}
.map {
height: 400px;
width: 100%;
background: url(map-background.jpg) repeat;
margin-bottom: 10px;
}
.ol-attribution {
.ol-attribution.ol-logo-only,
.ol-attribution.ol-uncollapsible {
max-width: calc(100% - 3em);
height: 1.5em;
}
.ol-attribution ul {
font-size: 1rem;
}
.ol-control button, .ol-attribution, .ol-scale-line-inner {
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
@@ -21,18 +65,3 @@ body {
#api-links ul {
display: inline;
}
body, h1, h2, h3, h4, p, li, td, th {
font-family: Quattrocento Sans;
}
.navbar-inverse .navbar-inner {
background: #1F6B75;
}
.navbar-inverse .brand {
color: white;
padding: 5px;
}
.brand img {
width: 35px;
height: 35px;
}

View File

@@ -0,0 +1,4 @@
table.controls td {
text-align: center;
padding: 2px 5px;
}

View File

@@ -0,0 +1,46 @@
---
template: example.html
title: Shaded Relief
shortdesc: Calculate shaded relief from elevation data
docs: >
<p>
This example uses a <code>ol.source.Raster</code> to generate data
based on another source. The raster source accepts any number of
input sources (tile or image based) and runs a pipeline of
operations on the input data. The return from the final
operation is used as the data for the output source.
</p>
<p>
In this case, a single tiled source of elevation data is used as input.
The shaded relief is calculated in a single "image" operation. By setting
<code>operationType: 'image'</code> on the raster source, operations are
called with an <code>ImageData</code> object for each of the input sources.
Operations are also called with a general purpose <code>data</code> object.
In this example, the sun elevation and azimuth data from the inputs above
are assigned to this <code>data</code> object and accessed in the shading
operation. The shading operation returns an array of <code>ImageData</code>
objects. When the raster source is used by an image layer, the first
<code>ImageData</code> object returned by the last operation in the pipeline
is used for rendering.
</p>
tags: "raster, shaded relief"
---
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
<table class="controls">
<tr>
<td>vertical exaggeration: <span id="vertOut"></span>x</td>
<td><input id="vert" type="range" min="1" max="5" value="1"/></td>
</tr>
<tr>
<td>sun elevation: <span id="sunElOut"></span>°</td>
<td><input id="sunEl" type="range" min="0" max="90" value="45"/></td>
</tr>
<tr>
<td>sun azimuth: <span id="sunAzOut"></span>°</td>
<td><input id="sunAz" type="range" min="0" max="360" value="45"/></td>
</tr>
</table>
</div>
</div>

158
examples/shaded-relief.js Normal file
View File

@@ -0,0 +1,158 @@
// NOCOMPILE
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.source.Raster');
goog.require('ol.source.TileJSON');
goog.require('ol.source.XYZ');
/**
* Generates a shaded relief image given elevation data. Uses a 3x3
* neighborhood for determining slope and aspect.
* @param {Array.<ImageData>} inputs Array of input images.
* @param {Object} data Data added in the "beforeoperations" event.
* @return {Array.<ImageData>} Output images (only the first is rendered).
*/
function shade(inputs, data) {
var elevationImage = inputs[0];
var width = elevationImage.width;
var height = elevationImage.height;
var elevationData = elevationImage.data;
var shadeData = new Uint8ClampedArray(elevationData.length);
var dp = data.resolution * 2;
var maxX = width - 1;
var maxY = height - 1;
var pixel = [0, 0, 0, 0];
var twoPi = 2 * Math.PI;
var halfPi = Math.PI / 2;
var sunEl = Math.PI * data.sunEl / 180;
var sunAz = Math.PI * data.sunAz / 180;
var cosSunEl = Math.cos(sunEl);
var sinSunEl = Math.sin(sunEl);
var pixelX, pixelY, x0, x1, y0, y1, offset,
z0, z1, dzdx, dzdy, slope, aspect, cosIncidence, scaled;
for (pixelY = 0; pixelY <= maxY; ++pixelY) {
y0 = pixelY === 0 ? 0 : pixelY - 1;
y1 = pixelY === maxY ? maxY : pixelY + 1;
for (pixelX = 0; pixelX <= maxX; ++pixelX) {
x0 = pixelX === 0 ? 0 : pixelX - 1;
x1 = pixelX === maxX ? maxX : pixelX + 1;
// determine elevation for (x0, pixelY)
offset = (pixelY * width + x0) * 4;
pixel[0] = elevationData[offset];
pixel[1] = elevationData[offset + 1];
pixel[2] = elevationData[offset + 2];
pixel[3] = elevationData[offset + 3];
z0 = data.vert * (pixel[0] + pixel[1] * 2 + pixel[2] * 3);
// determine elevation for (x1, pixelY)
offset = (pixelY * width + x1) * 4;
pixel[0] = elevationData[offset];
pixel[1] = elevationData[offset + 1];
pixel[2] = elevationData[offset + 2];
pixel[3] = elevationData[offset + 3];
z1 = data.vert * (pixel[0] + pixel[1] * 2 + pixel[2] * 3);
dzdx = (z1 - z0) / dp;
// determine elevation for (pixelX, y0)
offset = (y0 * width + pixelX) * 4;
pixel[0] = elevationData[offset];
pixel[1] = elevationData[offset + 1];
pixel[2] = elevationData[offset + 2];
pixel[3] = elevationData[offset + 3];
z0 = data.vert * (pixel[0] + pixel[1] * 2 + pixel[2] * 3);
// determine elevation for (pixelX, y1)
offset = (y1 * width + pixelX) * 4;
pixel[0] = elevationData[offset];
pixel[1] = elevationData[offset + 1];
pixel[2] = elevationData[offset + 2];
pixel[3] = elevationData[offset + 3];
z1 = data.vert * (pixel[0] + pixel[1] * 2 + pixel[2] * 3);
dzdy = (z1 - z0) / dp;
slope = Math.atan(Math.sqrt(dzdx * dzdx + dzdy * dzdy));
aspect = Math.atan2(dzdy, -dzdx);
if (aspect < 0) {
aspect = halfPi - aspect;
} else if (aspect > halfPi) {
aspect = twoPi - aspect + halfPi;
} else {
aspect = halfPi - aspect;
}
cosIncidence = sinSunEl * Math.cos(slope) +
cosSunEl * Math.sin(slope) * Math.cos(sunAz - aspect);
offset = (pixelY * width + pixelX) * 4;
scaled = 255 * cosIncidence;
shadeData[offset] = scaled;
shadeData[offset + 1] = scaled;
shadeData[offset + 2] = scaled;
shadeData[offset + 3] = elevationData[offset + 3];
}
}
return new ImageData(shadeData, width, height);
}
var elevation = new ol.source.XYZ({
url: 'https://{a-d}.tiles.mapbox.com/v3/aj.sf-dem/{z}/{x}/{y}.png',
crossOrigin: 'anonymous'
});
var raster = new ol.source.Raster({
sources: [elevation],
operationType: 'image',
operation: shade
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.TileJSON({
url: 'http://api.tiles.mapbox.com/v3/tschaub.miapgppd.jsonp'
})
}),
new ol.layer.Image({
opacity: 0.3,
source: raster
})
],
view: new ol.View({
extent: [-13675026, 4439648, -13580856, 4580292],
center: [-13615645, 4497969],
minZoom: 10,
maxZoom: 16,
zoom: 13
})
});
var controlIds = ['vert', 'sunEl', 'sunAz'];
var controls = {};
controlIds.forEach(function(id) {
var control = document.getElementById(id);
var output = document.getElementById(id + 'Out');
control.addEventListener('input', function() {
output.innerText = control.value;
raster.changed();
});
output.innerText = control.value;
controls[id] = control;
});
raster.on('beforeoperations', function(event) {
// the event.data object will be passed to operations
var data = event.data;
data.resolution = event.resolution;
for (var id in controls) {
data[id] = Number(controls[id].value);
}
});

View File

@@ -1,4 +1,3 @@
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.GeoJSON');
@@ -60,7 +59,8 @@ var map = new ol.Map({
var highlightStyleCache = {};
var featureOverlay = new ol.FeatureOverlay({
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector(),
map: map,
style: function(feature, resolution) {
var text = resolution < 5000 ? feature.get('name') : '';
@@ -106,10 +106,10 @@ var displayFeatureInfo = function(pixel) {
if (feature !== highlight) {
if (highlight) {
featureOverlay.removeFeature(highlight);
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.addFeature(feature);
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}

View File

@@ -1,75 +1,38 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.WMTSCapabilities');
goog.require('ol.has');
goog.require('ol.layer.Tile');
goog.require('ol.source.WMTS');
goog.require('ol.tilegrid.WMTS');
var template =
'{Layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpeg';
var urls = [
'http://maps1.wien.gv.at/basemap/' + template,
'http://maps2.wien.gv.at/basemap/' + template,
'http://maps3.wien.gv.at/basemap/' + template,
'http://maps4.wien.gv.at/basemap/' + template,
'http://maps.wien.gv.at/basemap/' + template
];
var capabilitiesUrl = 'http://www.basemap.at/wmts/1.0.0/WMTSCapabilities.xml';
// HiDPI support:
// * Use 'bmaphidpi' layer (pixel ratio 2) for device pixel ratio > 1
// * Use 'geolandbasemap' layer (pixel ratio 1) for device pixel ratio == 1
var hiDPI = ol.has.DEVICE_PIXEL_RATIO > 1;
var source = new ol.source.WMTS({
projection: 'EPSG:3857',
layer: hiDPI ? 'bmaphidpi' : 'geolandbasemap',
tilePixelRatio: hiDPI ? 2 : 1,
style: 'normal',
matrixSet: 'google3857',
urls: urls,
requestEncoding: 'REST',
tileGrid: new ol.tilegrid.WMTS({
origin: [-20037508.3428, 20037508.3428],
resolutions: [
559082264.029 * 0.28E-3,
279541132.015 * 0.28E-3,
139770566.007 * 0.28E-3,
69885283.0036 * 0.28E-3,
34942641.5018 * 0.28E-3,
17471320.7509 * 0.28E-3,
8735660.37545 * 0.28E-3,
4367830.18773 * 0.28E-3,
2183915.09386 * 0.28E-3,
1091957.54693 * 0.28E-3,
545978.773466 * 0.28E-3,
272989.386733 * 0.28E-3,
136494.693366 * 0.28E-3,
68247.3466832 * 0.28E-3,
34123.6733416 * 0.28E-3,
17061.8366708 * 0.28E-3,
8530.91833540 * 0.28E-3,
4265.45916770 * 0.28E-3,
2132.72958385 * 0.28E-3,
1066.36479193 * 0.28E-3
],
matrixIds: [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
]
})
});
var layer = hiDPI ? 'bmaphidpi' : 'geolandbasemap';
var tilePixelRatio = hiDPI ? 2 : 1;
var map = new ol.Map({
layers: [
new ol.layer.Tile({
extent: [977844.377599999, 5837774.6617, 1915609.8654, 6295560.8122],
source: source
})
],
target: 'map',
view: new ol.View({
center: [1823849, 6143760],
zoom: 11
})
});
$.ajax(capabilitiesUrl).then(function(response) {
var result = new ol.format.WMTSCapabilities().read(response);
var options = ol.source.WMTS.optionsFromCapabilities(result, {
layer: layer,
matrixSet: 'google3857',
requestEncoding: 'REST',
style: 'normal'
});
options.tilePixelRatio = tilePixelRatio;
map.addLayer(new ol.layer.Tile({
source: new ol.source.WMTS(options)
}));
});

18
examples/wmts-ign.html Normal file
View File

@@ -0,0 +1,18 @@
---
template: example.html
title: IGN WMTS example
shortdesc: Demonstrates displaying IGN (France) WMTS layers.
docs: >
In this example an IGN WMTS layer is displayed.
For more information on IGN's WMTS service see the
<a href="http://professionnels.ign.fr/api-sig">IGN Géoportail API web page
</a> and
<a href="http://www.geoportail.gouv.fr/depot/api/cgu/DT_APIGeoportail.pdf">
Descriptif technique des web services du Géoportail</a> (french).
tags: "french, ign, geoportail, wmts"
---
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
</div>
</div>

64
examples/wmts-ign.js Normal file
View File

@@ -0,0 +1,64 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control');
goog.require('ol.extent');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.WMTS');
goog.require('ol.tilegrid.WMTS');
var map = new ol.Map({
target: 'map',
controls: ol.control.defaults({
attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
view: new ol.View({
zoom: 5,
center: ol.proj.transform([5, 45], 'EPSG:4326', 'EPSG:3857')
})
});
var resolutions = [];
var matrixIds = [];
var proj3857 = ol.proj.get('EPSG:3857');
var maxResolution = ol.extent.getWidth(proj3857.getExtent()) / 256;
for (var i = 0; i < 18; i++) {
matrixIds[i] = i.toString();
resolutions[i] = maxResolution / Math.pow(2, i);
}
var tileGrid = new ol.tilegrid.WMTS({
origin: [-20037508, 20037508],
resolutions: resolutions,
matrixIds: matrixIds
});
// API key valid for 'openlayers.org' and 'localhost'.
// Expiration date is 06/29/2018.
var key = '2mqbg0z6cx7ube8gsou10nrt';
var ign_source = new ol.source.WMTS({
url: 'http://wxs.ign.fr/' + key + '/wmts',
layer: 'GEOGRAPHICALGRIDSYSTEMS.MAPS',
matrixSet: 'PM',
format: 'image/jpeg',
projection: 'EPSG:3857',
tileGrid: tileGrid,
style: 'normal',
attributions: [new ol.Attribution({
html: '<a href="http://www.geoportail.fr/" target="_blank">' +
'<img src="http://api.ign.fr/geoportail/api/js/latest/' +
'theme/geoportal/img/logo_gp.gif"></a>'
})]
});
var ign = new ol.layer.Tile({
source: ign_source
});
map.addLayer(ign);

View File

@@ -3,7 +3,7 @@ template: example.html
title: XYZ Esri EPSG:4326 tileSize 512 example
shortdesc: Example of a XYZ source in EPSG:4326 using Esri 512x512 tiles.
docs: >
ArcGIS REST tile services with custom tile sizes (here: 512x512 pixels) and projection (here: EPSG:4326) are supported by `ol.source.XYZ`. A custom tile grid and tile url function are required.
ArcGIS REST tile services with custom tile sizes (here: 512x512 pixels) and projection (here: EPSG:4326) are supported by `ol.source.XYZ`. A custom tile url function is used to handle zoom level offsets.
tags: "xyz, esri, tilesize, custom projection"
---
<div class="row-fluid">

View File

@@ -1,33 +1,19 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.extent');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.TileImage');
goog.require('ol.tilegrid.TileGrid');
goog.require('ol.source.XYZ');
var attribution = new ol.Attribution({
html: 'Copyright:&copy; 2013 ESRI, i-cubed, GeoEye'
});
var projection = ol.proj.get('EPSG:4326');
var projectionExtent = projection.getExtent();
// The tile size supported by the ArcGIS tile service.
var tileSize = 512;
// Calculate the resolutions supported by the ArcGIS tile service.
// There are 16 resolutions, with a factor of 2 between successive
// resolutions. The max resolution is such that the world (360°)
// fits into two (512x512 px) tiles.
var maxResolution = ol.extent.getWidth(projectionExtent) / (tileSize * 2);
var resolutions = new Array(16);
var z;
for (z = 0; z < 16; ++z) {
resolutions[z] = maxResolution / Math.pow(2, z);
}
var urlTemplate = 'http://services.arcgisonline.com/arcgis/rest/services/' +
'ESRI_Imagery_World_2D/MapServer/tile/{z}/{y}/{x}';
@@ -35,31 +21,17 @@ var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
/* ol.source.XYZ and ol.tilegrid.TileGrid have no resolutions config */
source: new ol.source.TileImage({
source: new ol.source.XYZ({
attributions: [attribution],
tileUrlFunction: function(tileCoord, pixelRatio, projection) {
var z = tileCoord[0];
var x = tileCoord[1];
var y = -tileCoord[2] - 1;
// wrap the world on the X axis
var n = Math.pow(2, z + 1); // 2 tiles at z=0
x = x % n;
if (x * n < 0) {
// x and n differ in sign so add n to wrap the result
// to the correct sign
x = x + n;
}
return urlTemplate.replace('{z}', z.toString())
.replace('{y}', y.toString())
.replace('{x}', x.toString());
},
maxZoom: 16,
projection: projection,
tileGrid: new ol.tilegrid.TileGrid({
origin: ol.extent.getTopLeft(projectionExtent),
resolutions: resolutions,
tileSize: 512
})
tileSize: tileSize,
tileUrlFunction: function(tileCoord) {
return urlTemplate.replace('{z}', (tileCoord[0] - 1).toString())
.replace('{x}', tileCoord[1].toString())
.replace('{y}', (-tileCoord[2] - 1).toString());
},
wrapX: true
})
})
],

View File

@@ -123,7 +123,7 @@ var GeoJSONFeature = function() {};
/**
* @type {GeoJSONGeometry}
* @type {GeoJSONGeometry|GeoJSONGeometryCollection}
*/
GeoJSONFeature.prototype.geometry;

View File

@@ -49,6 +49,25 @@ oli.DrawEvent.prototype.feature;
/**
* @interface
*/
oli.ModifyEvent = function() {};
/**
* @type {ol.Collection.<ol.Feature>}
*/
oli.ModifyEvent.prototype.features;
/**
* @type {ol.MapBrowserPointerEvent}
*/
oli.ModifyEvent.prototype.mapBrowserPointerEvent;
/**
* @interface
*/
@@ -247,6 +266,30 @@ oli.source.ImageEvent = function() {};
oli.source.ImageEvent.prototype.image;
/**
* @interface
*/
oli.source.RasterEvent = function() {};
/**
* @type {ol.Extent}
*/
oli.source.RasterEvent.prototype.extent;
/**
* @type {number}
*/
oli.source.RasterEvent.prototype.resolution;
/**
* @type {Object}
*/
oli.source.RasterEvent.prototype.data;
/**
* @interface
*/

View File

@@ -1,3 +1,4 @@
/**
* @type {Object}
*/
@@ -331,7 +332,7 @@ olx.OverlayOptions.prototype.element;
/**
* Offsets in pixels used when positioning the overlay. The fist element in the
* Offsets in pixels used when positioning the overlay. The first element in the
* array is the horizontal offset. A positive value shifts the overlay right.
* The second element in the array is the vertical offset. A positive value
* shifts the overlay down. Default is `[0, 0]`.
@@ -472,6 +473,7 @@ olx.ProjectionOptions.prototype.global;
*/
olx.ProjectionOptions.prototype.worldExtent;
/**
* Function to determine resolution at a point. The function is called with a
* `{number}` view resolution and an `{ol.Coordinate}` as arguments, and returns
@@ -911,6 +913,7 @@ olx.control.AttributionOptions.prototype.tipLabel;
*/
olx.control.AttributionOptions.prototype.label;
/**
* Text label to use for the expanded attributions button. Default is `»`.
* Instead of text, also a Node (e.g. a `span` element) can be used.
@@ -1910,6 +1913,7 @@ olx.format.WFSOptions.prototype.schemaLocation;
* outputFormat: (string|undefined),
* maxFeatures: (number|undefined),
* geometryName: (string|undefined),
* propertyNames: (Array.<string>|undefined),
* bbox: (ol.Extent|undefined)}}
* @api
*/
@@ -1981,6 +1985,14 @@ olx.format.WFSWriteGetFeatureOptions.prototype.maxFeatures;
olx.format.WFSWriteGetFeatureOptions.prototype.geometryName;
/**
* Optional list of property names to serialize.
* @type {Array.<string>|undefined}
* @api
*/
olx.format.WFSWriteGetFeatureOptions.prototype.propertyNames;
/**
* Extent to use for the BBOX filter.
* @type {ol.Extent|undefined}
@@ -2356,7 +2368,8 @@ olx.interaction.DragZoomOptions.prototype.style;
/**
* @typedef {{features: (ol.Collection.<ol.Feature>|undefined),
* @typedef {{clickTolerance: (number|undefined),
* features: (ol.Collection.<ol.Feature>|undefined),
* source: (ol.source.Vector|undefined),
* snapTolerance: (number|undefined),
* type: ol.geom.GeometryType,
@@ -2366,12 +2379,25 @@ olx.interaction.DragZoomOptions.prototype.style;
* geometryFunction: (ol.interaction.DrawGeometryFunctionType|undefined),
* geometryName: (string|undefined),
* condition: (ol.events.ConditionType|undefined),
* freehandCondition: (ol.events.ConditionType|undefined)}}
* freehandCondition: (ol.events.ConditionType|undefined),
* wrapX: (boolean|undefined)}}
* @api
*/
olx.interaction.DrawOptions;
/**
* The maximum distance in pixels between "down" and "up" for a "up" event
* to be considered a "click" event and actually add a point/vertex to the
* geometry being drawn. Default is 6 pixels. That value was chosen for
* the draw interaction to behave correctly on mouse as well as on touch
* devices.
* @type {number|undefined}
* @api
*/
olx.interaction.DrawOptions.prototype.clickTolerance;
/**
* Destination collection for the drawn features.
* @type {ol.Collection.<ol.Feature>|undefined}
@@ -2470,6 +2496,14 @@ olx.interaction.DrawOptions.prototype.condition;
olx.interaction.DrawOptions.prototype.freehandCondition;
/**
* Wrap the world horizontally on the sketch overlay. Default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.interaction.DrawOptions.prototype.wrapX;
/**
* @typedef {{condition: (ol.events.ConditionType|undefined),
* duration: (number|undefined),
@@ -2545,7 +2579,8 @@ olx.interaction.KeyboardZoomOptions.prototype.delta;
* @typedef {{deleteCondition: (ol.events.ConditionType|undefined),
* pixelTolerance: (number|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined),
* features: ol.Collection.<ol.Feature>}}
* features: ol.Collection.<ol.Feature>,
* wrapX: (boolean|undefined)}}
* @api
*/
olx.interaction.ModifyOptions;
@@ -2572,7 +2607,8 @@ olx.interaction.ModifyOptions.prototype.pixelTolerance;
/**
* FeatureOverlay style.
* Style used for the features being modified. By default the default edit
* style is used (see {@link ol.style}).
* @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined}
* @api
*/
@@ -2587,6 +2623,14 @@ olx.interaction.ModifyOptions.prototype.style;
olx.interaction.ModifyOptions.prototype.features;
/**
* Wrap the world horizontally on the sketch overlay. Default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.interaction.ModifyOptions.prototype.wrapX;
/**
* @typedef {{duration: (number|undefined)}}
* @api
@@ -2708,7 +2752,8 @@ olx.interaction.PointerOptions.prototype.handleUpEvent;
* removeCondition: (ol.events.ConditionType|undefined),
* toggleCondition: (ol.events.ConditionType|undefined),
* multi: (boolean|undefined),
* filter: (ol.interaction.SelectFilterFunction|undefined)}}
* filter: (ol.interaction.SelectFilterFunction|undefined),
* wrapX: (boolean|undefined)}}
* @api
*/
olx.interaction.SelectOptions;
@@ -2753,7 +2798,8 @@ olx.interaction.SelectOptions.prototype.layers;
/**
* Style for the selected features (those in the FeatureOverlay).
* Style for the selected features. By default the default edit style is used
* (see {@link ol.style}).
* @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined}
* @api
*/
@@ -2785,6 +2831,7 @@ olx.interaction.SelectOptions.prototype.removeCondition;
*/
olx.interaction.SelectOptions.prototype.toggleCondition;
/**
* A boolean that determines if the default behaviour should select only
* single features or all (overlapping) features at the clicked map
@@ -2794,6 +2841,7 @@ olx.interaction.SelectOptions.prototype.toggleCondition;
*/
olx.interaction.SelectOptions.prototype.multi;
/**
* A function that takes an {@link ol.Feature} and an {@link ol.layer.Layer} and
* returns `true` if the feature may be selected or `false` otherwise.
@@ -2803,6 +2851,14 @@ olx.interaction.SelectOptions.prototype.multi;
olx.interaction.SelectOptions.prototype.filter;
/**
* Wrap the world horizontally on the selection overlay. Default is `true`.
* @type {boolean|undefined}
* @api
*/
olx.interaction.SelectOptions.prototype.wrapX;
/**
* Options for snap
* @typedef {{
@@ -2825,7 +2881,7 @@ olx.interaction.SnapOptions.prototype.features;
/**
* Pixel tolerance for considering the pointer close enough to a segment or
* vertex for editing. Default is `10` pixels.
* vertex for snapping. Default is `10` pixels.
* @type {number|undefined}
* @api
*/
@@ -3282,6 +3338,7 @@ olx.layer.HeatmapOptions.prototype.visible;
* hue: (number|undefined),
* opacity: (number|undefined),
* saturation: (number|undefined),
* map: (ol.Map|undefined),
* source: (ol.source.Image|undefined),
* visible: (boolean|undefined),
* extent: (ol.Extent|undefined),
@@ -3340,6 +3397,17 @@ olx.layer.ImageOptions.prototype.saturation;
olx.layer.ImageOptions.prototype.source;
/**
* Sets the layer as overlay on a map. The map will not manage this layer in its
* layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it
* managed by the map is to use {@link ol.Map#addLayer}.
* @type {ol.Map|undefined}
* @api
*/
olx.layer.ImageOptions.prototype.map;
/**
* Visibility. Default is `true` (visible).
* @type {boolean|undefined}
@@ -3381,6 +3449,7 @@ olx.layer.ImageOptions.prototype.maxResolution;
* preload: (number|undefined),
* saturation: (number|undefined),
* source: (ol.source.Tile|undefined),
* map: (ol.Map|undefined),
* visible: (boolean|undefined),
* extent: (ol.Extent|undefined),
* minResolution: (number|undefined),
@@ -3448,6 +3517,17 @@ olx.layer.TileOptions.prototype.saturation;
olx.layer.TileOptions.prototype.source;
/**
* Sets the layer as overlay on a map. The map will not manage this layer in its
* layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it
* managed by the map is to use {@link ol.Map#addLayer}.
* @type {ol.Map|undefined}
* @api
*/
olx.layer.TileOptions.prototype.map;
/**
* Visibility. Default is `true` (visible).
* @type {boolean|undefined}
@@ -3500,6 +3580,7 @@ olx.layer.TileOptions.prototype.useInterimTilesOnError;
* renderBuffer: (number|undefined),
* saturation: (number|undefined),
* source: (ol.source.Vector|undefined),
* map: (ol.Map|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined),
* updateWhileAnimating: (boolean|undefined),
* updateWhileInteracting: (boolean|undefined),
@@ -3543,6 +3624,17 @@ olx.layer.VectorOptions.prototype.renderOrder;
olx.layer.VectorOptions.prototype.hue;
/**
* Sets the layer as overlay on a map. The map will not manage this layer in its
* layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it
* managed by the map is to use {@link ol.Map#addLayer}.
* @type {ol.Map|undefined}
* @api
*/
olx.layer.VectorOptions.prototype.map;
/**
* The bounding extent for layer rendering. The layer will not be rendered
* outside of this extent.
@@ -3625,7 +3717,7 @@ olx.layer.VectorOptions.prototype.updateWhileAnimating;
/**
* When set to `true`, feature batches will be recreated during interactions.
* See also `updateWhileInteracting`. Default is `false`.
* See also `updateWhileAnimating`. Default is `false`.
* @type {boolean|undefined}
* @api
*/
@@ -3640,39 +3732,6 @@ olx.layer.VectorOptions.prototype.updateWhileInteracting;
olx.layer.VectorOptions.prototype.visible;
/**
* @typedef {{features: (Array.<ol.Feature>|ol.Collection.<ol.Feature>|undefined),
* map: (ol.Map|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined)}}
* @api
*/
olx.FeatureOverlayOptions;
/**
* Features.
* @type {Array.<ol.Feature>|ol.Collection.<ol.Feature>|undefined}
* @api
*/
olx.FeatureOverlayOptions.prototype.features;
/**
* Map.
* @type {ol.Map|undefined}
* @api
*/
olx.FeatureOverlayOptions.prototype.map;
/**
* Feature style.
* @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined}
* @api
*/
olx.FeatureOverlayOptions.prototype.style;
/**
* Namespace.
* @type {Object}
@@ -3968,12 +4027,14 @@ olx.source.TileImageOptions.prototype.wrapX;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* format: ol.format.Feature,
* format: (ol.format.Feature|undefined),
* logo: (string|olx.LogoOptions|undefined),
* tileGrid: ol.tilegrid.TileGrid,
* tileUrlFunction: (ol.TileUrlFunctionType|undefined),
* tileLoadFunction: (ol.TileVectorLoadFunctionType|undefined),
* url: (string|undefined),
* urls: (Array.<string>|undefined)}}
* urls: (Array.<string>|undefined),
* wrapX: (boolean|undefined)}}
* @api
*/
olx.source.TileVectorOptions;
@@ -3988,8 +4049,8 @@ olx.source.TileVectorOptions.prototype.attributions;
/**
* Format.
* @type {ol.format.Feature}
* Format. Required unless tileLoadFunction is used.
* @type {ol.format.Feature|undefined}
* @api
*/
olx.source.TileVectorOptions.prototype.format;
@@ -4020,6 +4081,16 @@ olx.source.TileVectorOptions.prototype.tileGrid;
olx.source.TileVectorOptions.prototype.tileUrlFunction;
/**
* Optional function to override the default loading and format parsing behaviour.
* If this option is used format is ignored and the provided function will be
* responsible for data retrieval and transformation into features.
* @type {ol.TileVectorLoadFunctionType|undefined}
* @api
*/
olx.source.TileVectorOptions.prototype.tileLoadFunction;
/**
* URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
* @type {string|undefined}
@@ -4036,6 +4107,16 @@ olx.source.TileVectorOptions.prototype.url;
olx.source.TileVectorOptions.prototype.urls;
/**
* Wrap the world horizontally. Default is `true`. For vector editing across the
* -180° and 180° meridians to work properly, this should be set to `false`. The
* resulting geometry coordinates will then exceed the world bounds.
* @type {boolean|undefined}
* @api
*/
olx.source.TileVectorOptions.prototype.wrapX;
/**
* @typedef {{url: (string|undefined),
* displayDpi: (number|undefined),
@@ -4103,7 +4184,8 @@ olx.source.ImageMapGuideOptions.prototype.projection;
/**
* Ratio. `1` means image requests are the size of the map viewport, `2` means
* twice the size of the map viewport, and so on. Default is `1`.
* twice the width and height of the map viewport, and so on. Must be `1` or
* higher. Default is `1`.
* @type {number|undefined}
* @api stable
*/
@@ -4118,7 +4200,6 @@ olx.source.ImageMapGuideOptions.prototype.ratio;
olx.source.ImageMapGuideOptions.prototype.resolutions;
/**
* Optional function to load an image given a URL.
* @type {ol.TileLoadFunctionType|undefined}
@@ -4170,7 +4251,8 @@ olx.source.MapQuestOptions.prototype.url;
/**
* @typedef {{projection: ol.proj.ProjectionLike,
* tileGrid: (ol.tilegrid.TileGrid|undefined)}}
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* wrapX: (boolean|undefined)}}
* @api
*/
olx.source.TileDebugOptions;
@@ -4192,6 +4274,14 @@ olx.source.TileDebugOptions.prototype.projection;
olx.source.TileDebugOptions.prototype.tileGrid;
/**
* Whether to wrap the world horizontally. Default is `true`.
* @type {boolean|undefined}
* @api
*/
olx.source.TileDebugOptions.prototype.wrapX;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
@@ -4313,7 +4403,8 @@ olx.source.ImageCanvasOptions.prototype.projection;
/**
* Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
* size of the map viewport, and so on. Default is `1.5`.
* width and height of the map viewport, and so on. Must be `1` or higher.
* Default is `1.5`.
* @type {number|undefined}
* @api
*/
@@ -4376,7 +4467,8 @@ olx.source.ImageVectorOptions.prototype.projection;
/**
* Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
* size of the map viewport, and so on. Default is `1.5`.
* width and height of the map viewport, and so on. Must be `1` or higher.
* Default is `1.5`.
* @type {number|undefined}
* @api
*/
@@ -4409,6 +4501,65 @@ olx.source.ImageVectorOptions.prototype.source;
olx.source.ImageVectorOptions.prototype.style;
/**
* @typedef {{sources: Array.<ol.source.Source>,
* operation: (ol.raster.Operation|undefined),
* lib: (Object|undefined),
* threads: (number|undefined),
* operationType: (ol.raster.OperationType|undefined)}}
* @api
*/
olx.source.RasterOptions;
/**
* Input sources.
* @type {Array.<ol.source.Source>}
* @api
*/
olx.source.RasterOptions.prototype.sources;
/**
* Raster operation. The operation will be called with data from input sources
* and the output will be assigned to the raster source.
* @type {ol.raster.Operation|undefined}
* @api
*/
olx.source.RasterOptions.prototype.operation;
/**
* Functions that will be made available to operations run in a worker.
* @type {Object|undefined}
* @api
*/
olx.source.RasterOptions.prototype.lib;
/**
* By default, operations will be run in a single worker thread. To avoid using
* workers altogether, set `threads: 0`. For pixel operations, operations can
* be run in multiple worker threads. Note that there is additional overhead in
* transferring data to multiple workers, and that depending on the user's
* system, it may not be possible to parallelize the work.
* @type {number|undefined}
* @api
*/
olx.source.RasterOptions.prototype.threads;
/**
* Operation type. Supported values are `'pixel'` and `'image'`. By default,
* `'pixel'` operations are assumed, and operations will be called with an
* array of pixels from input sources. If set to `'image'`, operations will
* be called with an array of ImageData objects from input sources.
* @type {ol.raster.OperationType|undefined}
* @api
*/
olx.source.RasterOptions.prototype.operationType;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
@@ -4500,7 +4651,8 @@ olx.source.ImageWMSOptions.prototype.projection;
/**
* Ratio. `1` means image requests are the size of the map viewport, `2` means
* twice the size of the map viewport, and so on. Default is `1.5`.
* twice the width and height of the map viewport, and so on. Must be `1` or
* higher. Default is `1.5`.
* @type {number|undefined}
* @api stable
*/
@@ -4668,6 +4820,7 @@ olx.source.ImageStaticOptions.prototype.url;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
* params: (Object.<string, *>|undefined),
* logo: (string|olx.LogoOptions|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
@@ -4680,6 +4833,7 @@ olx.source.ImageStaticOptions.prototype.url;
*/
olx.source.TileArcGISRestOptions;
/**
* Attributions.
* @type {Array.<ol.Attribution>|undefined}
@@ -4688,6 +4842,18 @@ olx.source.TileArcGISRestOptions;
olx.source.TileArcGISRestOptions.prototype.attributions;
/**
* The `crossOrigin` attribute for loaded images. Note that you must provide a
* `crossOrigin` value if you are using the WebGL renderer or if you want to
* access pixel data with the Canvas renderer. See
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image}
* for more detail.
* @type {null|string|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.crossOrigin;
/**
* ArcGIS Rest parameters. This field is optional. Service defaults will be
* used for any fields not specified. `FORMAT` is `PNG32` by default. `F` is `IMAGE` by
@@ -4721,6 +4887,7 @@ olx.source.TileArcGISRestOptions.prototype.logo;
*/
olx.source.TileArcGISRestOptions.prototype.tileGrid;
/**
* Projection.
* @type {ol.proj.ProjectionLike}
@@ -4977,12 +5144,13 @@ olx.source.TileWMSOptions.prototype.wrapX;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* features: (Array.<ol.Feature>|undefined),
* features: (Array.<ol.Feature>|ol.Collection.<ol.Feature>|undefined),
* format: (ol.format.Feature|undefined),
* loader: (ol.FeatureLoader|undefined),
* logo: (string|olx.LogoOptions|undefined),
* strategy: (ol.LoadingStrategy|undefined),
* url: (string|undefined),
* useSpatialIndex: (boolean|undefined),
* wrapX: (boolean|undefined)}}
* @api
*/
@@ -4998,8 +5166,9 @@ olx.source.VectorOptions.prototype.attributions;
/**
* Features.
* @type {Array.<ol.Feature>|undefined}
* Features. If provided as {@link ol.Collection}, the features in the source
* and the collection will stay in sync.
* @type {Array.<ol.Feature>|ol.Collection.<ol.Feature>|undefined}
* @api stable
*/
olx.source.VectorOptions.prototype.features;
@@ -5052,6 +5221,29 @@ olx.source.VectorOptions.prototype.strategy;
olx.source.VectorOptions.prototype.url;
/**
* By default, an RTree is used as spatial index. When features are removed and
* added frequently, and the total number of features is low, setting this to
* `false` may improve performance.
*
* Note that
* {@link ol.source.Vector#getFeaturesInExtent},
* {@link ol.source.Vector#getClosestFeatureToCoordinate} and
* {@link ol.source.Vector#getExtent} cannot be used when `useSpatialIndex` is
* set to `false`, and {@link ol.source.Vector#forEachFeatureInExtent} will loop
* through all features.
*
* When set to `false`, the features will be maintained in an
* {@link ol.Collection}, which can be retrieved through
* {@link ol.source.Vector#getFeaturesCollection}.
*
* The default is `true`.
* @type {boolean|undefined}
* @api
*/
olx.source.VectorOptions.prototype.useSpatialIndex;
/**
* Wrap the world horizontally. Default is `true`. For vector editing across the
* -180° and 180° meridians to work properly, this should be set to `false`. The
@@ -5213,7 +5405,9 @@ olx.source.WMTSOptions.prototype.dimensions;
/**
* A URL for the service. For the RESTful request encoding, this is a URL
* template. For KVP encoding, it is normal URL.
* template. For KVP encoding, it is normal URL. A `{?-?}` template pattern,
* for example `subdomain{a-f}.domain.com`, may be used instead of defining
* each one separately in the `urls` option.
* @type {string|undefined}
* @api stable
*/
@@ -5259,6 +5453,7 @@ olx.source.WMTSOptions.prototype.wrapX;
* projection: ol.proj.ProjectionLike,
* maxZoom: (number|undefined),
* minZoom: (number|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* tileLoadFunction: (ol.TileLoadFunctionType|undefined),
* tilePixelRatio: (number|undefined),
* tileSize: (number|ol.Size|undefined),
@@ -5323,6 +5518,14 @@ olx.source.XYZOptions.prototype.maxZoom;
olx.source.XYZOptions.prototype.minZoom;
/**
* Tile grid.
* @type {ol.tilegrid.TileGrid}
* @api
*/
olx.source.XYZOptions.prototype.tileGrid;
/**
* Optional function to load a tile given a URL.
* @type {ol.TileLoadFunctionType|undefined}
@@ -5361,6 +5564,8 @@ olx.source.XYZOptions.prototype.tileUrlFunction;
/**
* URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
* used instead of defining each one separately in the `urls` option.
* @type {string|undefined}
* @api stable
*/
@@ -6036,8 +6241,7 @@ olx.tilegrid;
/**
* @typedef {{createTileCoordTransform: (undefined|function({extent: (ol.Extent|undefined)}):function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):ol.TileCoord),
* extent: (ol.Extent|undefined),
* @typedef {{extent: (ol.Extent|undefined),
* minZoom: (number|undefined),
* origin: (ol.Coordinate|undefined),
* origins: (Array.<ol.Coordinate>|undefined),
@@ -6053,8 +6257,7 @@ olx.tilegrid.TileGridOptions;
/**
* Extent for the tile grid. No tiles outside this extent will be requested by
* {@link ol.source.Tile} sources. When no `origin` or `origins` are
* configured, the `origin` will be set to the bottom-left corner of the extent.
* When no `sizes` are configured, they will be calculated from the extent.
* configured, the `origin` will be set to the top-left corner of the extent.
* @type {ol.Extent|undefined}
* @api
*/
@@ -6070,7 +6273,9 @@ olx.tilegrid.TileGridOptions.prototype.minZoom;
/**
* Origin, i.e. the bottom-left corner of the grid. Default is null.
* The tile grid origin, i.e. where the `x` and `y` axes meet (`[z, 0, 0]`).
* Tile coordinates increase left to right and upwards. If not specified,
* `extent` or `origins` must be provided.
* @type {ol.Coordinate|undefined}
* @api stable
*/
@@ -6078,9 +6283,11 @@ olx.tilegrid.TileGridOptions.prototype.origin;
/**
* Origins, i.e. the bottom-left corners of the grid for each zoom level. If
* given, the array length should match the length of the `resolutions` array,
* i.e. each resolution can have a different origin.
* Tile grid origins, i.e. where the `x` and `y` axes meet (`[z, 0, 0]`), for
* each zoom level. If given, the array length should match the length of the
* `resolutions` array, i.e. each resolution can have a different origin. Tile
* coordinates increase left to right and upwards. If not specified, `extent`
* or `origin` must be provided.
* @type {Array.<ol.Coordinate>|undefined}
* @api stable
*/
@@ -6097,17 +6304,6 @@ olx.tilegrid.TileGridOptions.prototype.origins;
olx.tilegrid.TileGridOptions.prototype.resolutions;
/**
* Number of tile rows and columns of the grid for each zoom level. This setting
* is only needed for tile coordinate transforms that need to work with origins
* other than the bottom-left corner of the grid. No tiles outside this range
* will be requested by sources. If an `extent` is also configured, it takes
* precedence.
* @type {Array.<ol.Size>|undefined}
*/
olx.tilegrid.TileGridOptions.prototype.sizes;
/**
* Tile size. Default is `[256, 256]`.
* @type {number|ol.Size|undefined}
@@ -6141,9 +6337,8 @@ olx.tilegrid.WMTSOptions;
/**
* Extent for the tile grid. No tiles outside this extent will be requested by
* {@link ol.source.WMTS} sources. When no `origin` or `origins` are
* configured, the `origin` will be calculated from the extent.
* When no `sizes` are configured, they will be calculated from the extent.
* {@link ol.source.Tile} sources. When no `origin` or `origins` are
* configured, the `origin` will be set to the top-left corner of the extent.
* @type {ol.Extent|undefined}
* @api
*/
@@ -6151,19 +6346,23 @@ olx.tilegrid.WMTSOptions.prototype.extent;
/**
* Origin, i.e. the top-left corner of the grid.
* The tile grid origin, i.e. where the `x` and `y` axes meet (`[z, 0, 0]`).
* Tile coordinates increase left to right and upwards. If not specified,
* `extent` or `origins` must be provided.
* @type {ol.Coordinate|undefined}
* @api
* @api stable
*/
olx.tilegrid.WMTSOptions.prototype.origin;
/**
* Origins, i.e. the top-left corners of the grid for each zoom level. The
* length of this array needs to match the length of the
* `resolutions` array.
* Tile grid origins, i.e. where the `x` and `y` axes meet (`[z, 0, 0]`), for
* each zoom level. If given, the array length should match the length of the
* `resolutions` array, i.e. each resolution can have a different origin. Tile
* coordinates increase left to right and upwards. If not specified, `extent` or
* `origin` must be provided.
* @type {Array.<ol.Coordinate>|undefined}
* @api
* @api stable
*/
olx.tilegrid.WMTSOptions.prototype.origins;
@@ -6192,7 +6391,10 @@ olx.tilegrid.WMTSOptions.prototype.matrixIds;
* here are the `TileMatrixWidth` and `TileMatrixHeight` advertised in the
* GetCapabilities response of the WMTS, and define the grid's extent together
* with the `origin`. An `extent` can be configured in addition, and will
* further limit the extent for which tile requests are made by sources.
* further limit the extent for which tile requests are made by sources. Note
* that when the top-left corner of the `extent` is used as `origin` or
* `origins`, then the `y` value must be negative because OpenLayers tile
* coordinates increase upwards.
* @type {Array.<ol.Size>|undefined}
* @api
*/
@@ -6275,21 +6477,6 @@ olx.tilegrid.XYZOptions.prototype.minZoom;
olx.tilegrid.XYZOptions.prototype.tileSize;
/**
* @typedef {{resolutions: !Array.<number>}}
* @api
*/
olx.tilegrid.ZoomifyOptions;
/**
* Resolutions.
* @type {!Array.<number>}
* @api
*/
olx.tilegrid.ZoomifyOptions.prototype.resolutions;
/**
* Namespace.
* @type {Object}
@@ -6305,7 +6492,7 @@ olx.view;
* minResolution: (number|undefined)}}
* @api
*/
olx.view.FitGeometryOptions;
olx.view.FitOptions;
/**
@@ -6314,7 +6501,7 @@ olx.view.FitGeometryOptions;
* @type {!Array.<number>}
* @api
*/
olx.view.FitGeometryOptions.prototype.padding;
olx.view.FitOptions.prototype.padding;
/**
@@ -6322,7 +6509,7 @@ olx.view.FitGeometryOptions.prototype.padding;
* @type {boolean|undefined}
* @api
*/
olx.view.FitGeometryOptions.prototype.constrainResolution;
olx.view.FitOptions.prototype.constrainResolution;
/**
@@ -6330,7 +6517,7 @@ olx.view.FitGeometryOptions.prototype.constrainResolution;
* @type {boolean|undefined}
* @api
*/
olx.view.FitGeometryOptions.prototype.nearest;
olx.view.FitOptions.prototype.nearest;
/**
@@ -6338,7 +6525,7 @@ olx.view.FitGeometryOptions.prototype.nearest;
* @type {number|undefined}
* @api
*/
olx.view.FitGeometryOptions.prototype.minResolution;
olx.view.FitOptions.prototype.minResolution;
/**
@@ -6347,7 +6534,7 @@ olx.view.FitGeometryOptions.prototype.minResolution;
* @type {number|undefined}
* @api
*/
olx.view.FitGeometryOptions.prototype.maxZoom;
olx.view.FitOptions.prototype.maxZoom;
/* typedefs for object literals exposed by the library */

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "3.6.0",
"version": "3.8.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",
@@ -12,7 +12,8 @@
"install": "node tasks/install.js",
"postinstall": "closure-util update",
"start": "node tasks/serve.js",
"test": "node tasks/test.js"
"test": "node tasks/test.js",
"debug-server": "node tasks/serve-lib.js"
},
"main": "dist/ol.js",
"repository": {
@@ -25,22 +26,22 @@
},
"dependencies": {
"async": "0.9.0",
"closure-util": "1.4.0",
"browserify": "9.0.3",
"closure-util": "1.5.0",
"fs-extra": "0.12.0",
"glob": "5.0.3",
"graceful-fs": "3.0.2",
"handlebars": "3.0.1",
"htmlparser2": "3.7.3",
"jsdoc": "3.3.0-alpha9",
"marked": "0.3.3",
"metalsmith": "1.6.0",
"metalsmith-templates": "0.7.0",
"nomnom": "1.8.0",
"pixelworks": "1.0.0",
"rbush": "1.3.5",
"temp": "0.8.1",
"walk": "2.3.4",
"wrench": "1.5.8",
"browserify": "9.0.3"
"wrench": "1.5.8"
},
"devDependencies": {
"clean-css": "2.2.16",
@@ -60,6 +61,7 @@
"slimerjs-edge": "0.10.0-pre-2"
},
"ext": [
"rbush"
"rbush",
{"module": "pixelworks", "browserify": true}
]
}

View File

@@ -79,7 +79,7 @@ ol.CollectionProperty = {
* @constructor
* @extends {ol.Object}
* @fires ol.CollectionEvent
* @param {Array.<T>=} opt_array Array.
* @param {!Array.<T>=} opt_array Array.
* @template T
* @api stable
*/
@@ -89,7 +89,7 @@ ol.Collection = function(opt_array) {
/**
* @private
* @type {Array.<T>}
* @type {!Array.<T>}
*/
this.array_ = goog.isDef(opt_array) ? opt_array : [];
@@ -113,7 +113,7 @@ ol.Collection.prototype.clear = function() {
/**
* Add elements to the collection. This pushes each item in the provided array
* to the end of the collection.
* @param {Array.<T>} arr Array.
* @param {!Array.<T>} arr Array.
* @return {ol.Collection.<T>} This collection.
* @api stable
*/
@@ -145,7 +145,7 @@ ol.Collection.prototype.forEach = function(f, opt_this) {
* is mutated, no events will be dispatched by the collection, and the
* collection's "length" property won't be in sync with the actual length
* of the array.
* @return {Array.<T>} Array.
* @return {!Array.<T>} Array.
* @api stable
*/
ol.Collection.prototype.getArray = function() {

View File

@@ -3,7 +3,6 @@ goog.provide('ol.control.Control');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.MapEventType');
goog.require('ol.Object');
@@ -79,24 +78,6 @@ ol.control.Control = function(options) {
goog.inherits(ol.control.Control, ol.Object);
/**
* Bind a listener that blurs the passed element on any mouseout- or
* focusout-event.
*
* @param {!Element} button The button which shall blur on mouseout- or
* focusout-event.
* @protected
*/
ol.control.Control.bindMouseOutFocusOutBlur = function(button) {
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], /** @this {Element} */ function() {
this.blur();
}, false);
};
/**
* @inheritDoc
*/

View File

@@ -67,8 +67,6 @@ ol.control.FullScreen = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
ol.control.Control.bindMouseOutFocusOutBlur(button);
goog.events.listen(goog.global.document,
goog.dom.fullscreen.EventType.CHANGE,
this.handleFullScreenChange_, false, this);

View File

@@ -90,8 +90,6 @@ ol.control.OverviewMap = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var ovmapDiv = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-overviewmap-map');
/**
@@ -338,7 +336,7 @@ ol.control.OverviewMap.prototype.resetExtent_ = function() {
ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2;
var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO);
ol.extent.scaleFromCenter(extent, ratio);
ovview.fitExtent(extent, ovmapSize);
ovview.fit(extent, ovmapSize);
};

View File

@@ -60,8 +60,6 @@ ol.control.Rotate = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
ol.control.Rotate.prototype.handleClick_, false, this);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, button);

View File

@@ -50,8 +50,6 @@ ol.control.Zoom = function(opt_options) {
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, delta), false, this);
ol.control.Control.bindMouseOutFocusOutBlur(inElement);
var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-out',
'type' : 'button',

View File

@@ -8,7 +8,7 @@ goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.fx.DragDropEvent');
goog.require('goog.fx.DragEvent');
goog.require('goog.fx.Dragger');
goog.require('goog.fx.Dragger.EventType');
goog.require('goog.math');
@@ -222,7 +222,7 @@ ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) {
/**
* Handle dragger start events.
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @param {goog.fx.DragEvent} event The drag event.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
@@ -233,7 +233,7 @@ ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
/**
* Handle dragger drag events.
*
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @param {goog.fx.DragEvent} event The drag event.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
@@ -245,7 +245,7 @@ ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
/**
* Handle dragger end events.
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @param {goog.fx.DragEvent} event The drag event.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {

View File

@@ -43,8 +43,6 @@ ol.control.ZoomToExtent = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, button);
@@ -77,5 +75,5 @@ ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() {
view.getProjection().getExtent() : this.extent_;
var size = map.getSize();
goog.asserts.assert(goog.isDef(size), 'size should be defined');
view.fitExtent(extent, size);
view.fit(extent, size);
};

View File

@@ -3,6 +3,7 @@ goog.provide('ol.CoordinateFormatType');
goog.provide('ol.coordinate');
goog.require('goog.math');
goog.require('goog.string');
/**
@@ -129,8 +130,8 @@ ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) {
var normalizedDegrees = goog.math.modulo(degrees + 180, 360) - 180;
var x = Math.abs(Math.round(3600 * normalizedDegrees));
return Math.floor(x / 3600) + '\u00b0 ' +
Math.floor((x / 60) % 60) + '\u2032 ' +
Math.floor(x % 60) + '\u2033 ' +
goog.string.padNumber(Math.floor((x / 60) % 60), 2) + '\u2032 ' +
goog.string.padNumber(Math.floor(x % 60), 2) + '\u2033 ' +
hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);
};

View File

@@ -67,9 +67,11 @@ ol.DeviceOrientationProperty = {
*
* @see http://www.w3.org/TR/orientation-event/
*
* To get notified of device orientation changes, register a listener for the
* generic `change` event on your `ol.DeviceOrientation` instance.
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the device orientation changes.
* @param {olx.DeviceOrientationOptions=} opt_options Options.
* @api
*/

View File

@@ -111,6 +111,18 @@ ol.events.condition.singleClick = function(mapBrowserEvent) {
};
/**
* Return `true` if the event is a map `dblclick` event, `false` otherwise.
*
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event is a map `dblclick` event.
* @api stable
*/
ol.events.condition.doubleClick = function(mapBrowserEvent) {
return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK;
};
/**
* Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is
* pressed.

View File

@@ -18,7 +18,7 @@ goog.require('ol.style.Style');
* GeoJSON.
*
* Features can be styled individually with `setStyle`; otherwise they use the
* style of their vector layer or feature overlay.
* style of their vector layer.
*
* Note that attribute properties are set as {@link ol.Object} properties on
* the feature object, so they are observable, and have get/set accessors.
@@ -50,8 +50,6 @@ goog.require('ol.style.Style');
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the id, the geometry or the style of the
* feature changes.
* @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties
* You may pass a Geometry object directly, or an object literal
* containing properties. If you pass an object literal, you may
@@ -153,6 +151,7 @@ ol.Feature.prototype.getGeometry = function() {
/**
* @return {number|string|undefined} Id.
* @api stable
* @observable
*/
ol.Feature.prototype.getId = function() {
return this.id_;
@@ -177,6 +176,7 @@ ol.Feature.prototype.getGeometryName = function() {
* @return {ol.style.Style|Array.<ol.style.Style>|
* ol.FeatureStyleFunction} The feature style.
* @api stable
* @observable
*/
ol.Feature.prototype.getStyle = function() {
return this.style_;
@@ -238,6 +238,7 @@ ol.Feature.prototype.setGeometry = function(geometry) {
* @param {ol.style.Style|Array.<ol.style.Style>|
* ol.FeatureStyleFunction} style Style for this feature.
* @api stable
* @observable
*/
ol.Feature.prototype.setStyle = function(style) {
this.style_ = style;
@@ -254,6 +255,7 @@ ol.Feature.prototype.setStyle = function(style) {
* method.
* @param {number|string|undefined} id The feature id.
* @api stable
* @observable
*/
ol.Feature.prototype.setId = function(id) {
this.id_ = id;

View File

@@ -1,326 +0,0 @@
goog.provide('ol.FeatureOverlay');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.render.EventType');
goog.require('ol.renderer.vector');
goog.require('ol.style.Style');
/**
* @classdesc
* A mechanism for changing the style of a small number of features on a
* temporary basis, for example highlighting. This is necessary with the Canvas
* renderer, where, unlike in SVG, features cannot be individually referenced.
* See examples/vector-layers for an example: create a FeatureOverlay with a
* different style, copy the feature(s) you want rendered in this different
* style into it, and then remove them again when you're finished.
*
* @constructor
* @param {olx.FeatureOverlayOptions=} opt_options Options.
* @api
*/
ol.FeatureOverlay = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {ol.Collection.<ol.Feature>}
*/
this.features_ = null;
/**
* @private
* @type {Array.<goog.events.Key>}
*/
this.featuresListenerKeys_ = null;
/**
* @private
* @type {Object.<string, goog.events.Key>}
*/
this.featureChangeListenerKeys_ = null;
/**
* @private
* @type {ol.Map}
*/
this.map_ = null;
/**
* @private
* @type {goog.events.Key}
*/
this.postComposeListenerKey_ = null;
/**
* @private
* @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction}
*/
this.style_ = null;
/**
* @private
* @type {ol.style.StyleFunction|undefined}
*/
this.styleFunction_ = undefined;
this.setStyle(goog.isDef(options.style) ?
options.style : ol.style.defaultStyleFunction);
if (goog.isDef(options.features)) {
if (goog.isArray(options.features)) {
this.setFeatures(new ol.Collection(options.features.slice()));
} else {
goog.asserts.assertInstanceof(options.features, ol.Collection,
'options.features should be an ol.Collection');
this.setFeatures(options.features);
}
} else {
this.setFeatures(new ol.Collection());
}
if (goog.isDef(options.map)) {
this.setMap(options.map);
}
};
/**
* Add a feature to the overlay.
* @param {ol.Feature} feature Feature.
* @api
*/
ol.FeatureOverlay.prototype.addFeature = function(feature) {
this.features_.push(feature);
};
/**
* Get the features on the overlay.
* @return {ol.Collection.<ol.Feature>} Features collection.
* @api
*/
ol.FeatureOverlay.prototype.getFeatures = function() {
return this.features_;
};
/**
* Get the map associated with the overlay.
* @return {?ol.Map} The map with which this feature overlay is associated.
* @api
*/
ol.FeatureOverlay.prototype.getMap = function() {
return this.map_;
};
/**
* @private
*/
ol.FeatureOverlay.prototype.handleFeatureChange_ = function() {
this.render_();
};
/**
* @private
* @param {ol.CollectionEvent} collectionEvent Collection event.
*/
ol.FeatureOverlay.prototype.handleFeaturesAdd_ = function(collectionEvent) {
goog.asserts.assert(!goog.isNull(this.featureChangeListenerKeys_),
'this.featureChangeListenerKeys_ should not be null');
var feature = /** @type {ol.Feature} */ (collectionEvent.element);
this.featureChangeListenerKeys_[goog.getUid(feature).toString()] =
goog.events.listen(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
this.render_();
};
/**
* @private
* @param {ol.CollectionEvent} collectionEvent Collection event.
*/
ol.FeatureOverlay.prototype.handleFeaturesRemove_ = function(collectionEvent) {
goog.asserts.assert(!goog.isNull(this.featureChangeListenerKeys_),
'this.featureChangeListenerKeys_ should not be null');
var feature = /** @type {ol.Feature} */ (collectionEvent.element);
var key = goog.getUid(feature).toString();
goog.events.unlistenByKey(this.featureChangeListenerKeys_[key]);
delete this.featureChangeListenerKeys_[key];
this.render_();
};
/**
* Handle changes in image style state.
* @param {goog.events.Event} event Image style change event.
* @private
*/
ol.FeatureOverlay.prototype.handleImageChange_ = function(event) {
this.render_();
};
/**
* @param {ol.render.Event} event Event.
* @private
*/
ol.FeatureOverlay.prototype.handleMapPostCompose_ = function(event) {
if (goog.isNull(this.features_)) {
return;
}
var styleFunction = this.styleFunction_;
if (!goog.isDef(styleFunction)) {
styleFunction = ol.style.defaultStyleFunction;
}
var replayGroup = /** @type {ol.render.IReplayGroup} */
(event.replayGroup);
goog.asserts.assert(goog.isDef(replayGroup),
'replayGroup should be defined');
var frameState = event.frameState;
var pixelRatio = frameState.pixelRatio;
var resolution = frameState.viewState.resolution;
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(resolution,
pixelRatio);
var i, ii, styles, featureStyleFunction;
this.features_.forEach(function(feature) {
featureStyleFunction = feature.getStyleFunction();
styles = goog.isDef(featureStyleFunction) ?
featureStyleFunction.call(feature, resolution) :
styleFunction(feature, resolution);
if (!goog.isDefAndNotNull(styles)) {
return;
}
ii = styles.length;
for (i = 0; i < ii; ++i) {
ol.renderer.vector.renderFeature(replayGroup, feature, styles[i],
squaredTolerance, this.handleImageChange_, this);
}
}, this);
};
/**
* Remove a feature from the overlay.
* @param {ol.Feature} feature The feature to be removed.
* @api
*/
ol.FeatureOverlay.prototype.removeFeature = function(feature) {
this.features_.remove(feature);
};
/**
* @private
*/
ol.FeatureOverlay.prototype.render_ = function() {
if (!goog.isNull(this.map_)) {
this.map_.render();
}
};
/**
* Set the features for the overlay.
* @param {ol.Collection.<ol.Feature>} features Features collection.
* @api
*/
ol.FeatureOverlay.prototype.setFeatures = function(features) {
if (!goog.isNull(this.featuresListenerKeys_)) {
goog.array.forEach(this.featuresListenerKeys_, goog.events.unlistenByKey);
this.featuresListenerKeys_ = null;
}
if (!goog.isNull(this.featureChangeListenerKeys_)) {
goog.array.forEach(
goog.object.getValues(this.featureChangeListenerKeys_),
goog.events.unlistenByKey);
this.featureChangeListenerKeys_ = null;
}
this.features_ = features;
if (!goog.isNull(features)) {
this.featuresListenerKeys_ = [
goog.events.listen(features, ol.CollectionEventType.ADD,
this.handleFeaturesAdd_, false, this),
goog.events.listen(features, ol.CollectionEventType.REMOVE,
this.handleFeaturesRemove_, false, this)
];
this.featureChangeListenerKeys_ = {};
features.forEach(function(feature) {
this.featureChangeListenerKeys_[goog.getUid(feature).toString()] =
goog.events.listen(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
}, this);
}
this.render_();
};
/**
* Set the map for the overlay.
* @param {ol.Map} map Map.
* @api
*/
ol.FeatureOverlay.prototype.setMap = function(map) {
if (!goog.isNull(this.postComposeListenerKey_)) {
goog.events.unlistenByKey(this.postComposeListenerKey_);
this.postComposeListenerKey_ = null;
}
this.render_();
this.map_ = map;
if (!goog.isNull(map)) {
this.postComposeListenerKey_ = goog.events.listen(
map, ol.render.EventType.POSTCOMPOSE, this.handleMapPostCompose_, false,
this);
map.render();
}
};
/**
* Set the style for features. This can be a single style object, an array
* of styles, or a function that takes a feature and resolution and returns
* an array of styles.
* @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} style
* Overlay style.
* @api
*/
ol.FeatureOverlay.prototype.setStyle = function(style) {
this.style_ = style;
this.styleFunction_ = ol.style.createStyleFunction(style);
this.render_();
};
/**
* Get the style for features. This returns whatever was passed to the `style`
* option at construction or to the `setStyle` method.
* @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction}
* Overlay style.
* @api
*/
ol.FeatureOverlay.prototype.getStyle = function() {
return this.style_;
};
/**
* Get the style function.
* @return {ol.style.StyleFunction|undefined} Style function.
* @api
*/
ol.FeatureOverlay.prototype.getStyleFunction = function() {
return this.styleFunction_;
};

View File

@@ -198,8 +198,8 @@ ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
*/
ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) {
return /** @type {GeoJSONGeometryCollection} */ ({
'type': 'GeometryCollection',
'geometries': []
type: 'GeometryCollection',
geometries: []
});
};
@@ -219,8 +219,8 @@ ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(
return ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
});
return /** @type {GeoJSONGeometryCollection} */ ({
'type': 'GeometryCollection',
'geometries': geometries
type: 'GeometryCollection',
geometries: geometries
});
};
@@ -235,8 +235,8 @@ ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
return /** @type {GeoJSONGeometry} */ ({
'type': 'LineString',
'coordinates': geometry.getCoordinates()
type: 'LineString',
coordinates: geometry.getCoordinates()
});
};
@@ -252,8 +252,8 @@ ol.format.GeoJSON.writeMultiLineStringGeometry_ =
goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString,
'geometry should be an ol.geom.MultiLineString');
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiLineString',
'coordinates': geometry.getCoordinates()
type: 'MultiLineString',
coordinates: geometry.getCoordinates()
});
};
@@ -268,8 +268,8 @@ ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint,
'geometry should be an ol.geom.MultiPoint');
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPoint',
'coordinates': geometry.getCoordinates()
type: 'MultiPoint',
coordinates: geometry.getCoordinates()
});
};
@@ -288,8 +288,8 @@ ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) {
right = opt_options.rightHanded;
}
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPolygon',
'coordinates': geometry.getCoordinates(right)
type: 'MultiPolygon',
coordinates: geometry.getCoordinates(right)
});
};
@@ -304,8 +304,8 @@ ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) {
goog.asserts.assertInstanceof(geometry, ol.geom.Point,
'geometry should be an ol.geom.Point');
return /** @type {GeoJSONGeometry} */ ({
'type': 'Point',
'coordinates': geometry.getCoordinates()
type: 'Point',
coordinates: geometry.getCoordinates()
});
};
@@ -324,8 +324,8 @@ ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) {
right = opt_options.rightHanded;
}
return /** @type {GeoJSONGeometry} */ ({
'type': 'Polygon',
'coordinates': geometry.getCoordinates(right)
type: 'Polygon',
coordinates: geometry.getCoordinates(right)
});
};
@@ -541,6 +541,8 @@ ol.format.GeoJSON.prototype.writeFeatureObject = function(
if (goog.isDefAndNotNull(geometry)) {
object['geometry'] =
ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
} else {
object['geometry'] = null;
}
var properties = feature.getProperties();
goog.object.remove(properties, feature.getGeometryName());
@@ -582,8 +584,8 @@ ol.format.GeoJSON.prototype.writeFeaturesObject =
objects.push(this.writeFeatureObject(features[i], opt_options));
}
return /** @type {GeoJSONFeatureCollection} */ ({
'type': 'FeatureCollection',
'features': objects
type: 'FeatureCollection',
features: objects
});
};

View File

@@ -203,10 +203,11 @@ ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) {
n = n.nextElementSibling) {
var localName = ol.xml.getLocalName(n);
// Assume attribute elements have one child node and that the child
// is a text node. Otherwise assume it is a geometry node.
// is a text or CDATA node (to be treated as text).
// Otherwise assume it is a geometry node.
if (n.childNodes.length === 0 ||
(n.childNodes.length === 1 &&
n.firstChild.nodeType === 3)) {
(n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
var value = ol.xml.getAllTextContent(n, false);
if (goog.string.isEmpty(value)) {
value = undefined;

View File

@@ -39,6 +39,9 @@ ol.GeolocationProperty = {
* The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
* is used to locate a user's position.
*
* To get notified of position changes, register a listener for the generic
* `change` event on your instance of `ol.Geolocation`.
*
* Example:
*
* var geolocation = new ol.Geolocation({
@@ -52,7 +55,6 @@ ol.GeolocationProperty = {
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the position changes.
* @param {olx.GeolocationOptions=} opt_options Options.
* @api stable
*/

View File

@@ -50,9 +50,11 @@ ol.geom.GeometryLayout = {
* instantiated in apps.
* Base class for vector geometries.
*
* To get notified of changes to the geometry, register a listener for the
* generic `change` event on your geometry instance.
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the geometry changes.
* @api stable
*/
ol.geom.Geometry = function() {
@@ -229,6 +231,7 @@ ol.geom.Geometry.prototype.translate = goog.abstractMethod;
* string identifier or a {@link ol.proj.Projection} object.
* @return {ol.geom.Geometry} This geometry. Note that original geometry is
* modified in place.
* @api stable
*/
ol.geom.Geometry.prototype.transform = function(source, destination) {
this.applyTransform(ol.proj.getTransform(source, destination));

View File

@@ -2,6 +2,7 @@ goog.provide('ol.geom.MultiPolygon');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.extent');
goog.require('ol.geom.GeometryLayout');
goog.require('ol.geom.GeometryType');
@@ -119,8 +120,10 @@ ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) {
*/
ol.geom.MultiPolygon.prototype.clone = function() {
var multiPolygon = new ol.geom.MultiPolygon(null);
var newEndss = /** @type {Array.<Array.<number>>} */
(goog.object.unsafeClone(this.endss_));
multiPolygon.setFlatCoordinates(
this.layout, this.flatCoordinates.slice(), this.endss_.slice());
this.layout, this.flatCoordinates.slice(), newEndss);
return multiPolygon;
};

View File

@@ -1,5 +1,6 @@
goog.provide('ol.ImageCanvas');
goog.require('goog.asserts');
goog.require('ol.ImageBase');
goog.require('ol.ImageState');
@@ -13,12 +14,23 @@ goog.require('ol.ImageState');
* @param {number} pixelRatio Pixel ratio.
* @param {Array.<ol.Attribution>} attributions Attributions.
* @param {HTMLCanvasElement} canvas Canvas.
* @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to
* support asynchronous canvas drawing.
*/
ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
canvas) {
canvas, opt_loader) {
goog.base(this, extent, resolution, pixelRatio, ol.ImageState.LOADED,
attributions);
/**
* Optional canvas loader function.
* @type {?ol.ImageCanvasLoader}
* @private
*/
this.loader_ = goog.isDef(opt_loader) ? opt_loader : null;
var state = goog.isDef(opt_loader) ?
ol.ImageState.IDLE : ol.ImageState.LOADED;
goog.base(this, extent, resolution, pixelRatio, state, attributions);
/**
* @private
@@ -26,13 +38,68 @@ ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
*/
this.canvas_ = canvas;
/**
* @private
* @type {Error}
*/
this.error_ = null;
};
goog.inherits(ol.ImageCanvas, ol.ImageBase);
/**
* Get any error associated with asynchronous rendering.
* @return {Error} Any error that occurred during rendering.
*/
ol.ImageCanvas.prototype.getError = function() {
return this.error_;
};
/**
* Handle async drawing complete.
* @param {Error} err Any error during drawing.
* @private
*/
ol.ImageCanvas.prototype.handleLoad_ = function(err) {
if (err) {
this.error_ = err;
this.state = ol.ImageState.ERROR;
} else {
this.state = ol.ImageState.LOADED;
}
this.changed();
};
/**
* Trigger drawing on canvas.
*/
ol.ImageCanvas.prototype.load = function() {
if (this.state == ol.ImageState.IDLE) {
goog.asserts.assert(!goog.isNull(this.loader_));
this.state = ol.ImageState.LOADING;
this.changed();
this.loader_(goog.bind(this.handleLoad_, this));
}
};
/**
* @inheritDoc
*/
ol.ImageCanvas.prototype.getImage = function(opt_context) {
return this.canvas_;
};
/**
* A function that is called to trigger asynchronous canvas drawing. It is
* called with a "done" callback that should be called when drawing is done.
* If any error occurs during drawing, the "done" callback should be called with
* that error.
*
* @typedef {function(function(Error))}
*/
ol.ImageCanvasLoader;

View File

@@ -10,7 +10,6 @@ goog.require('goog.events.Event');
goog.require('ol.Collection');
goog.require('ol.Coordinate');
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.MapBrowserEvent');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.Object');
@@ -27,6 +26,7 @@ goog.require('ol.geom.Polygon');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.interaction.InteractionProperty');
goog.require('ol.interaction.Pointer');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Style');
@@ -80,7 +80,7 @@ goog.inherits(ol.interaction.DrawEvent, goog.events.Event);
/**
* @classdesc
* Interaction that allows drawing geometries.
* Interaction for drawing feature geometries.
*
* @constructor
* @extends {ol.interaction.Pointer}
@@ -265,14 +265,19 @@ ol.interaction.Draw = function(options) {
* @type {number}
* @private
*/
this.squaredClickTolerance_ = 4;
this.squaredClickTolerance_ = goog.isDef(options.clickTolerance) ?
options.clickTolerance * options.clickTolerance : 36;
/**
* Draw overlay where our sketch features are drawn.
* @type {ol.FeatureOverlay}
* @type {ol.layer.Vector}
* @private
*/
this.overlay_ = new ol.FeatureOverlay({
this.overlay_ = new ol.layer.Vector({
source: new ol.source.Vector({
useSpatialIndex: false,
wrapX: goog.isDef(options.wrapX) ? options.wrapX : false
}),
style: goog.isDef(options.style) ?
options.style : ol.interaction.Draw.getDefaultStyleFunction()
});
@@ -393,10 +398,12 @@ ol.interaction.Draw.handleUpEvent_ = function(event) {
this.handlePointerMove_(event);
if (goog.isNull(this.finishCoordinate_)) {
this.startDrawing_(event);
} else if ((this.mode_ === ol.interaction.DrawMode.POINT ||
this.mode_ === ol.interaction.DrawMode.CIRCLE) &&
!goog.isNull(this.finishCoordinate_) ||
this.atFinish_(event)) {
if (this.mode_ === ol.interaction.DrawMode.POINT) {
this.finishDrawing();
}
} else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
this.finishDrawing();
} else if (this.atFinish_(event)) {
this.finishDrawing();
} else {
this.addToDrawing_(event);
@@ -414,10 +421,7 @@ ol.interaction.Draw.handleUpEvent_ = function(event) {
* @private
*/
ol.interaction.Draw.prototype.handlePointerMove_ = function(event) {
if (this.mode_ === ol.interaction.DrawMode.POINT &&
goog.isNull(this.finishCoordinate_)) {
this.startDrawing_(event);
} else if (!goog.isNull(this.finishCoordinate_)) {
if (!goog.isNull(this.finishCoordinate_)) {
this.modifyDrawing_(event);
} else {
this.createOrUpdateSketchPoint_(event);
@@ -674,7 +678,7 @@ ol.interaction.Draw.prototype.abortDrawing_ = function() {
this.sketchFeature_ = null;
this.sketchPoint_ = null;
this.sketchLine_ = null;
this.overlay_.getFeatures().clear();
this.overlay_.getSource().clear(true);
}
return sketchFeature;
};
@@ -701,7 +705,9 @@ ol.interaction.Draw.prototype.updateSketchFeatures_ = function() {
if (!goog.isNull(this.sketchPoint_)) {
sketchFeatures.push(this.sketchPoint_);
}
this.overlay_.setFeatures(new ol.Collection(sketchFeatures));
var overlaySource = this.overlay_.getSource();
overlaySource.clear(true);
overlaySource.addFeatures(sketchFeatures);
};

View File

@@ -3,11 +3,11 @@ goog.provide('ol.interaction.Modify');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.functions');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.ViewHint');
goog.require('ol.coordinate');
@@ -21,10 +21,66 @@ goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Pointer');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.structs.RBush');
goog.require('ol.style.Style');
/**
* @enum {string}
*/
ol.ModifyEventType = {
/**
* Triggered upon feature modification start
* @event ol.ModifyEvent#modifystart
* @api
*/
MODIFYSTART: 'modifystart',
/**
* Triggered upon feature modification end
* @event ol.ModifyEvent#modifyend
* @api
*/
MODIFYEND: 'modifyend'
};
/**
* @classdesc
* Events emitted by {@link ol.interaction.Modify} instances are instances of
* this type.
*
* @constructor
* @extends {goog.events.Event}
* @implements {oli.ModifyEvent}
* @param {ol.ModifyEventType} type Type.
* @param {ol.Collection.<ol.Feature>} features The features modified.
* @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated
* {@link ol.MapBrowserPointerEvent}.
*/
ol.ModifyEvent = function(type, features, mapBrowserPointerEvent) {
goog.base(this, type);
/**
* The features being modified.
* @type {ol.Collection.<ol.Feature>}
* @api
*/
this.features = features;
/**
* Associated {@link ol.MapBrowserPointerEvent}.
* @type {ol.MapBrowserPointerEvent}
* @api
*/
this.mapBrowserPointerEvent = mapBrowserPointerEvent;
};
goog.inherits(ol.ModifyEvent, goog.events.Event);
/**
* @typedef {{depth: (Array.<number>|undefined),
* feature: ol.Feature,
@@ -38,12 +94,13 @@ ol.interaction.SegmentDataType;
/**
* @classdesc
* Interaction for modifying vector data.
* Interaction for modifying feature geometries.
*
* @constructor
* @extends {ol.interaction.Pointer}
* @param {olx.interaction.ModifyOptions} options Options.
* @api stable
* @fires ol.ModifyEvent
* @api
*/
ol.interaction.Modify = function(options) {
@@ -84,6 +141,14 @@ ol.interaction.Modify = function(options) {
*/
this.lastPixel_ = [0, 0];
/**
* Tracks if the next `singleclick` event should be ignored to prevent
* accidental deletion right after vertex creation.
* @type {boolean}
* @private
*/
this.ignoreNextSingleClick_ = false;
/**
* Segment RTree for each layer
* @type {Object.<*, ol.structs.RBush>}
@@ -111,13 +176,19 @@ ol.interaction.Modify = function(options) {
this.dragSegments_ = null;
/**
* Draw overlay where are sketch features are drawn.
* @type {ol.FeatureOverlay}
* Draw overlay where sketch features are drawn.
* @type {ol.layer.Vector}
* @private
*/
this.overlay_ = new ol.FeatureOverlay({
this.overlay_ = new ol.layer.Vector({
source: new ol.source.Vector({
useSpatialIndex: false,
wrapX: goog.isDef(options.wrapX) ? options.wrapX : false
}),
style: goog.isDef(options.style) ? options.style :
ol.interaction.Modify.getDefaultStyleFunction()
ol.interaction.Modify.getDefaultStyleFunction(),
updateWhileAnimating: true,
updateWhileInteracting: true
});
/**
@@ -208,7 +279,7 @@ ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) {
// There remains only vertexFeature…
if (!goog.isNull(this.vertexFeature_) &&
this.features_.getLength() === 0) {
this.overlay_.removeFeature(this.vertexFeature_);
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
};
@@ -383,7 +454,7 @@ ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ =
if (goog.isNull(vertexFeature)) {
vertexFeature = new ol.Feature(new ol.geom.Point(coordinates));
this.vertexFeature_ = vertexFeature;
this.overlay_.addFeature(vertexFeature);
this.overlay_.getSource().addFeature(vertexFeature);
} else {
var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
geometry.setCoordinates(coordinates);
@@ -459,6 +530,8 @@ ol.interaction.Modify.handleDownEvent_ = function(evt) {
for (i = insertVertices.length - 1; i >= 0; --i) {
this.insertVertex_.apply(this, insertVertices[i]);
}
this.dispatchEvent(new ol.ModifyEvent(ol.ModifyEventType.MODIFYSTART,
this.features_, evt));
}
return !goog.isNull(this.vertexFeature_);
};
@@ -470,6 +543,8 @@ ol.interaction.Modify.handleDownEvent_ = function(evt) {
* @private
*/
ol.interaction.Modify.handleDragEvent_ = function(evt) {
this.ignoreNextSingleClick_ = false;
var vertex = evt.coordinate;
for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
var dragSegment = this.dragSegments_[i];
@@ -530,6 +605,8 @@ ol.interaction.Modify.handleUpEvent_ = function(evt) {
this.rBush_.update(ol.extent.boundingExtent(segmentData.segment),
segmentData);
}
this.dispatchEvent(new ol.ModifyEvent(ol.ModifyEventType.MODIFYEND,
this.features_, evt));
return false;
};
@@ -551,11 +628,21 @@ ol.interaction.Modify.handleEvent = function(mapBrowserEvent) {
}
if (!goog.isNull(this.vertexFeature_) &&
this.deleteCondition_(mapBrowserEvent)) {
var geometry = this.vertexFeature_.getGeometry();
goog.asserts.assertInstanceof(geometry, ol.geom.Point,
'geometry should be an ol.geom.Point');
handled = this.removeVertex_();
if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK ||
!this.ignoreNextSingleClick_) {
var geometry = this.vertexFeature_.getGeometry();
goog.asserts.assertInstanceof(geometry, ol.geom.Point,
'geometry should be an ol.geom.Point');
handled = this.removeVertex_();
} else {
handled = true;
}
}
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) {
this.ignoreNextSingleClick_ = false;
}
return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) &&
!handled;
};
@@ -630,7 +717,7 @@ ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) {
}
}
if (!goog.isNull(this.vertexFeature_)) {
this.overlay_.removeFeature(this.vertexFeature_);
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
};
@@ -709,6 +796,7 @@ ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) {
rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment),
newSegmentData2);
this.dragSegments_.push([newSegmentData2, 0]);
this.ignoreNextSingleClick_ = true;
};
@@ -800,8 +888,10 @@ ol.interaction.Modify.prototype.removeVertex_ = function() {
newSegmentData);
this.updateSegmentIndices_(geometry, index, segmentData.depth, -1);
this.overlay_.removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
if (!goog.isNull(this.vertexFeature_)) {
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
}
}
}

View File

@@ -8,10 +8,11 @@ goog.require('goog.events.Event');
goog.require('goog.functions');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.FeatureOverlay');
goog.require('ol.events.condition');
goog.require('ol.geom.GeometryType');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Style');
@@ -82,10 +83,13 @@ goog.inherits(ol.SelectEvent, goog.events.Event);
/**
* @classdesc
* Handles selection of vector data. A {@link ol.FeatureOverlay} is maintained
* internally to store the selected feature(s). Which features are selected is
* determined by the `condition` option, and optionally the `toggle` or
* `add`/`remove` options.
* Interaction for selecting vector features. By default, selected features are
* styled differently, so this interaction can be used for visual highlighting,
* as well as selecting features for other actions, such as modification or
* output. There are three ways of controlling which features are selected:
* using the browser event as defined by the `condition` and optionally the
* `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a
* further feature filter using the `filter` option.
*
* @constructor
* @extends {ol.interaction.Interaction}
@@ -169,14 +173,20 @@ ol.interaction.Select = function(opt_options) {
/**
* @private
* @type {ol.FeatureOverlay}
* @type {ol.layer.Vector}
*/
this.featureOverlay_ = new ol.FeatureOverlay({
this.featureOverlay_ = new ol.layer.Vector({
source: new ol.source.Vector({
useSpatialIndex: false,
wrapX: options.wrapX
}),
style: goog.isDef(options.style) ? options.style :
ol.interaction.Select.getDefaultStyleFunction()
ol.interaction.Select.getDefaultStyleFunction(),
updateWhileAnimating: true,
updateWhileInteracting: true
});
var features = this.featureOverlay_.getFeatures();
var features = this.featureOverlay_.getSource().getFeaturesCollection();
goog.events.listen(features, ol.CollectionEventType.ADD,
this.addFeature_, false, this);
goog.events.listen(features, ol.CollectionEventType.REMOVE,
@@ -192,7 +202,7 @@ goog.inherits(ol.interaction.Select, ol.interaction.Interaction);
* @api stable
*/
ol.interaction.Select.prototype.getFeatures = function() {
return this.featureOverlay_.getFeatures();
return this.featureOverlay_.getSource().getFeaturesCollection();
};
@@ -213,9 +223,9 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
var toggle = this.toggleCondition_(mapBrowserEvent);
var set = !add && !remove && !toggle;
var map = mapBrowserEvent.map;
var features = this.featureOverlay_.getFeatures();
var /** @type {Array.<ol.Feature>} */ deselected = [];
var /** @type {Array.<ol.Feature>} */ selected = [];
var features = this.featureOverlay_.getSource().getFeaturesCollection();
var /** @type {!Array.<ol.Feature>} */ deselected = [];
var /** @type {!Array.<ol.Feature>} */ selected = [];
var change = false;
if (set) {
// Replace the currently selected feature(s) with the feature(s) at the
@@ -290,7 +300,8 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
*/
ol.interaction.Select.prototype.setMap = function(map) {
var currentMap = this.getMap();
var selectedFeatures = this.featureOverlay_.getFeatures();
var selectedFeatures =
this.featureOverlay_.getSource().getFeaturesCollection();
if (!goog.isNull(currentMap)) {
selectedFeatures.forEach(currentMap.unskipFeature, currentMap);
}

View File

@@ -6,6 +6,7 @@ goog.require('goog.object');
goog.require('ol.Object');
goog.require('ol.layer.Base');
goog.require('ol.layer.LayerProperty');
goog.require('ol.render.EventType');
goog.require('ol.source.State');
@@ -18,10 +19,11 @@ goog.require('ol.source.State');
* Layers group together those properties that pertain to how the data is to be
* displayed, irrespective of the source of that data.
*
* A generic `change` event is fired when the state of the source changes.
*
* @constructor
* @extends {ol.layer.Base}
* @fires ol.render.Event
* @fires change Triggered when the state of the source changes.
* @param {olx.layer.LayerOptions} options Layer options.
* @api stable
*/
@@ -32,12 +34,28 @@ ol.layer.Layer = function(options) {
goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
/**
* @private
* @type {goog.events.Key}
*/
this.mapPrecomposeKey_ = null;
/**
* @private
* @type {goog.events.Key}
*/
this.mapRenderKey_ = null;
/**
* @private
* @type {goog.events.Key}
*/
this.sourceChangeKey_ = null;
if (goog.isDef(options.map)) {
this.setMap(options.map);
}
goog.events.listen(this,
ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE),
this.handleSourcePropertyChange_, false, this);
@@ -129,6 +147,36 @@ ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() {
};
/**
* Sets the layer to be rendered on a map. The map will not manage this layer in
* its layers collection, layer filters in {@link ol.Map#forEachLayerAtPixel}
* will not filter the layer, and it will be rendered on top. This is useful for
* temporary layers. To remove an unmanaged layer from the map, use
* `#setMap(null)`.
*
* To add the layer to a map and have it managed by the map, use
* {@link ol.Map#addLayer} instead.
* @param {ol.Map} map Map.
* @api
*/
ol.layer.Layer.prototype.setMap = function(map) {
goog.events.unlistenByKey(this.mapPrecomposeKey_);
this.changed();
goog.events.unlistenByKey(this.mapRenderKey_);
if (!goog.isNull(map)) {
this.mapPrecomposeKey_ = goog.events.listen(
map, ol.render.EventType.PRECOMPOSE, function(evt) {
var layerState = this.getLayerState();
layerState.managed = false;
evt.frameState.layerStatesArray.push(layerState);
evt.frameState.layerStates[goog.getUid(this)] = layerState;
}, false, this);
this.mapRenderKey_ = goog.events.listen(
this, goog.events.EventType.CHANGE, map.render, false, map);
}
};
/**
* Set the layer source.
* @param {ol.source.Source} source The layer source.

View File

@@ -35,6 +35,7 @@ ol.layer.LayerProperty = {
* saturation: number,
* sourceState: ol.source.State,
* visible: boolean,
* managed: boolean,
* extent: (ol.Extent|undefined),
* maxResolution: number,
* minResolution: number}}
@@ -142,6 +143,7 @@ ol.layer.Base.prototype.getLayerState = function() {
saturation: Math.max(saturation, 0),
sourceState: sourceState,
visible: visible,
managed: true,
extent: extent,
maxResolution: maxResolution,
minResolution: Math.max(minResolution, 0)

View File

@@ -29,9 +29,10 @@ ol.layer.GroupProperty = {
* @classdesc
* A {@link ol.Collection} of layers that are handled together.
*
* A generic `change` event is triggered when the group/Collection changes.
*
* @constructor
* @extends {ol.layer.Base}
* @fires change Triggered when the group/Collection changes.
* @param {olx.layer.GroupOptions=} opt_options Layer options.
* @api stable
*/
@@ -163,7 +164,7 @@ ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {
* Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
* in this group.
* @return {!ol.Collection.<ol.layer.Base>} Collection of
* {@link ol.layer.Layer layers} that are part of this group.
* {@link ol.layer.Base layers} that are part of this group.
* @observable
* @api stable
*/
@@ -177,7 +178,7 @@ ol.layer.Group.prototype.getLayers = function() {
* Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
* in this group.
* @param {!ol.Collection.<ol.layer.Base>} layers Collection of
* {@link ol.layer.Layer layers} that are part of this group.
* {@link ol.layer.Base layers} that are part of this group.
* @observable
* @api stable
*/

View File

@@ -13,6 +13,7 @@ goog.require('goog.debug.Console');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.ViewportSizeMonitor');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.Event');
@@ -266,7 +267,7 @@ ol.Map = function(options) {
// prevent page zoom on IE >= 10 browsers
this.viewport_.style.msTouchAction = 'none';
if (ol.has.TOUCH) {
this.viewport_.className = 'ol-touch';
goog.dom.classlist.add(this.viewport_, 'ol-touch');
}
/**
@@ -571,23 +572,20 @@ ol.Map.prototype.disposeInternal = function() {
/**
* Detect features that intersect a pixel on the viewport, and execute a
* callback with each intersecting feature. Layers included in the detection can
* be configured through `opt_layerFilter`. Feature overlays will always be
* included in the detection.
* be configured through `opt_layerFilter`.
* @param {ol.Pixel} pixel Pixel.
* @param {function(this: S, ol.Feature, ol.layer.Layer): T} callback Feature
* callback. The callback will be called with two arguments. The first
* argument is one {@link ol.Feature feature} at the pixel, the second is
* the {@link ol.layer.Layer layer} of the feature. If the detected feature
* is not on a layer, but on a {@link ol.FeatureOverlay}, then the second
* argument to this function will be `null`. To stop detection, callback
* functions can return a truthy value.
* the {@link ol.layer.Layer layer} of the feature. To stop detection,
* callback functions can return a truthy value.
* @param {S=} opt_this Value to use as `this` when executing `callback`.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* be tested.
* @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
* @return {T|undefined} Callback result, i.e. the return value of last
* callback execution, or the first truthy callback return value.
@@ -613,22 +611,19 @@ ol.Map.prototype.forEachFeatureAtPixel =
/**
* Detect layers that have a color value at a pixel on the viewport, and
* execute a callback with each matching layer. Layers included in the
* detection can be configured through `opt_layerFilter`. Feature overlays will
* always be included in the detection.
* detection can be configured through `opt_layerFilter`.
* @param {ol.Pixel} pixel Pixel.
* @param {function(this: S, ol.layer.Layer): T} callback Layer
* callback. Will receive one argument, the {@link ol.layer.Layer layer}
* that contains the color pixel. If the detected color value is not from a
* layer, but from a {@link ol.FeatureOverlay}, then the argument to this
* function will be `null`. To stop detection, callback functions can return
* a truthy value.
* that contains the color pixel. To stop detection, callback functions can
* return a truthy value.
* @param {S=} opt_this Value to use as `this` when executing `callback`.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* be tested.
* @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
* @return {T|undefined} Callback result, i.e. the return value of last
* callback execution, or the first truthy callback return value.
@@ -652,15 +647,14 @@ ol.Map.prototype.forEachLayerAtPixel =
/**
* Detect if features intersect a pixel on the viewport. Layers included in the
* detection can be configured through `opt_layerFilter`. Feature overlays will
* always be included in the detection.
* detection can be configured through `opt_layerFilter`.
* @param {ol.Pixel} pixel Pixel.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* be tested.
* @param {U=} opt_this Value to use as `this` when executing `layerFilter`.
* @return {boolean} Is there a feature at the given pixel?
* @template U

View File

@@ -16,6 +16,7 @@ goog.require('goog.events.EventType');
*
* @constructor
* @extends {goog.events.EventTarget}
* @fires change
* @suppress {checkStructDictInheritance}
* @struct
* @api stable
@@ -46,7 +47,6 @@ ol.Observable.unByKey = function(key) {
/**
* Increases the revision counter and dispatches a 'change' event.
* @fires change
* @api
*/
ol.Observable.prototype.changed = function() {
@@ -55,6 +55,13 @@ ol.Observable.prototype.changed = function() {
};
/**
* Triggered when the revision counter is increased.
* @event change
* @api
*/
/**
* @return {number} Revision.
* @api

View File

@@ -0,0 +1,32 @@
goog.provide('ol.raster.Operation');
goog.provide('ol.raster.OperationType');
/**
* Raster operation type. Supported values are `'pixel'` and `'image'`.
* @enum {string}
* @api
*/
ol.raster.OperationType = {
PIXEL: 'pixel',
IMAGE: 'image'
};
/**
* A function that takes an array of input data, performs some operation, and
* returns an array of ouput data. For `'pixel'` type operations, functions
* will be called with an array of {@link ol.raster.Pixel} data and should
* return an array of the same. For `'image'` type operations, functions will
* be called with an array of {@link ImageData
* https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return
* an array of the same. The operations are called with a second "data"
* argument, which can be used for storage. The data object is accessible
* from raster events, where it can be initialized in "beforeoperations" and
* accessed again in "afteroperations".
*
* @typedef {function((Array.<ol.raster.Pixel>|Array.<ImageData>), Object):
* (Array.<ol.raster.Pixel>|Array.<ImageData>)}
* @api
*/
ol.raster.Operation;

9
src/ol/raster/pixel.js Normal file
View File

@@ -0,0 +1,9 @@
goog.provide('ol.raster.Pixel');
/**
* An array of numbers representing pixel values.
* @typedef {Array.<number>} ol.raster.Pixel
* @api
*/
ol.raster.Pixel;

View File

@@ -471,8 +471,8 @@ ol.render.canvas.Immediate.prototype.drawCircleGeometry =
* Render a feature into the canvas. In order to respect the zIndex of the
* style this method draws asynchronously and thus *after* calls to
* drawXxxxGeometry have been finished, effectively drawing the feature
* *on top* of everything else. You probably should be using
* {@link ol.FeatureOverlay} instead of calling this method directly.
* *on top* of everything else. You probably should be using an
* {@link ol.layer.Vector} instead of calling this method directly.
*
* @param {ol.Feature} feature Feature.
* @param {ol.style.Style} style Style.

View File

@@ -353,7 +353,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
'3rd instruction should be a number');
dd = /** @type {number} */ (instruction[2]);
goog.asserts.assert(goog.isString(instruction[3]),
'4th instruction should be a number');
'4th instruction should be a string');
text = /** @type {string} */ (instruction[3]);
goog.asserts.assert(goog.isNumber(instruction[4]),
'5th instruction should be a number');

View File

@@ -35,14 +35,13 @@ ol.render.EventType = {
* @param {ol.render.EventType} type Type.
* @param {Object=} opt_target Target.
* @param {ol.render.VectorContext=} opt_vectorContext Vector context.
* @param {ol.render.IReplayGroup=} opt_replayGroup Replay group.
* @param {olx.FrameState=} opt_frameState Frame state.
* @param {?CanvasRenderingContext2D=} opt_context Context.
* @param {?ol.webgl.Context=} opt_glContext WebGL Context.
*/
ol.render.Event = function(
type, opt_target, opt_vectorContext, opt_replayGroup, opt_frameState,
opt_context, opt_glContext) {
type, opt_target, opt_vectorContext, opt_frameState, opt_context,
opt_glContext) {
goog.base(this, type, opt_target);
@@ -53,11 +52,6 @@ ol.render.Event = function(
*/
this.vectorContext = opt_vectorContext;
/**
* @type {ol.render.IReplayGroup|undefined}
*/
this.replayGroup = opt_replayGroup;
/**
* @type {olx.FrameState|undefined}
* @api

View File

@@ -131,8 +131,8 @@ ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ =
var render = new ol.render.canvas.Immediate(
context, frameState.pixelRatio, frameState.extent, transform,
frameState.viewState.rotation);
var composeEvent = new ol.render.Event(type, layer, render, null,
frameState, context, null);
var composeEvent = new ol.render.Event(type, layer, render, frameState,
context, null);
layer.dispatchEvent(composeEvent);
render.flush();
}

View File

@@ -10,7 +10,6 @@ goog.require('ol');
goog.require('ol.RendererType');
goog.require('ol.css');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.layer.Layer');
goog.require('ol.layer.Tile');
@@ -18,13 +17,11 @@ goog.require('ol.layer.Vector');
goog.require('ol.render.Event');
goog.require('ol.render.EventType');
goog.require('ol.render.canvas.Immediate');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.ImageLayer');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.canvas.TileLayer');
goog.require('ol.renderer.canvas.VectorLayer');
goog.require('ol.renderer.vector');
goog.require('ol.source.State');
goog.require('ol.vec.Mat4');
@@ -103,55 +100,27 @@ ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ =
var extent = frameState.extent;
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var projection = viewState.projection;
var resolution = viewState.resolution;
var rotation = viewState.rotation;
var offsetX = 0;
if (projection.canWrapX()) {
var projectionExtent = projection.getExtent();
var worldWidth = ol.extent.getWidth(projectionExtent);
var x = frameState.focus[0];
if (x < projectionExtent[0] || x > projectionExtent[2]) {
var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
offsetX = worldWidth * worldsAway;
extent = [
extent[0] + offsetX, extent[1],
extent[2] + offsetX, extent[3]
];
}
}
var transform = this.getTransform(frameState, offsetX);
var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
var replayGroup = new ol.render.canvas.ReplayGroup(
tolerance, extent, resolution);
var transform = this.getTransform(frameState);
var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
extent, transform, rotation);
var composeEvent = new ol.render.Event(type, map, vectorContext,
replayGroup, frameState, context, null);
frameState, context, null);
map.dispatchEvent(composeEvent);
replayGroup.finish();
if (!replayGroup.isEmpty()) {
replayGroup.replay(context, pixelRatio, transform, rotation, {});
}
vectorContext.flush();
this.replayGroup = replayGroup;
}
};
/**
* @param {olx.FrameState} frameState Frame state.
* @param {number} offsetX Offset on the x-axis in view coordinates.
* @protected
* @return {!goog.vec.Mat4.Number} Transform.
*/
ol.renderer.canvas.Map.prototype.getTransform = function(frameState, offsetX) {
ol.renderer.canvas.Map.prototype.getTransform = function(frameState) {
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var resolution = viewState.resolution;
@@ -159,8 +128,7 @@ ol.renderer.canvas.Map.prototype.getTransform = function(frameState, offsetX) {
this.canvas_.width / 2, this.canvas_.height / 2,
pixelRatio / resolution, -pixelRatio / resolution,
-viewState.rotation,
-viewState.center[0] - offsetX,
-viewState.center[1]);
-viewState.center[0], -viewState.center[1]);
};

View File

@@ -77,9 +77,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame =
function(frameState, layerState, context) {
var extent = frameState.extent;
var focus = frameState.focus;
var pixelRatio = frameState.pixelRatio;
var skippedFeatureUids = frameState.skippedFeatureUids;
var skippedFeatureUids = layerState.managed ?
frameState.skippedFeatureUids : {};
var viewState = frameState.viewState;
var projection = viewState.projection;
var rotation = viewState.rotation;
@@ -108,20 +108,11 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame =
// see http://jsperf.com/context-save-restore-versus-variable
var alpha = replayContext.globalAlpha;
replayContext.globalAlpha = layerState.opacity;
var noSkip = {};
var focusX = focus[0];
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
skippedFeatureUids);
if (vectorSource.getWrapX() && projection.canWrapX() &&
!ol.extent.containsExtent(projectionExtent, extent)) {
var projLeft = projectionExtent[0];
var projRight = projectionExtent[2];
// A feature from skippedFeatureUids will only be skipped in the world
// that has the frameState's focus, because this is where a feature
// overlay for highlighting or selection would render the skipped
// feature.
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft <= focusX && focusX <= projRight ?
skippedFeatureUids : noSkip);
var startX = extent[0];
var worldWidth = ol.extent.getWidth(projectionExtent);
var world = 0;
@@ -131,8 +122,7 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame =
offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft + offsetX <= focusX && focusX <= projRight + offsetX ?
skippedFeatureUids : noSkip);
skippedFeatureUids);
startX += worldWidth;
}
world = 0;
@@ -142,13 +132,11 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame =
offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft + offsetX <= focusX && focusX <= projRight + offsetX ?
skippedFeatureUids : noSkip);
skippedFeatureUids);
startX -= worldWidth;
}
} else {
replayGroup.replay(
replayContext, pixelRatio, transform, rotation, skippedFeatureUids);
// restore original transform for render and compose events
transform = this.getTransform(frameState, 0);
}
if (replayContext != context) {
@@ -174,10 +162,11 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate =
var resolution = frameState.viewState.resolution;
var rotation = frameState.viewState.rotation;
var layer = this.getLayer();
var layerState = frameState.layerStates[goog.getUid(layer)];
/** @type {Object.<string, boolean>} */
var features = {};
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate,
resolution, rotation, frameState.skippedFeatureUids,
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
rotation, layerState.managed ? frameState.skippedFeatureUids : {},
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
@@ -249,9 +238,15 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
if (vectorSource.getWrapX() && viewState.projection.canWrapX() &&
!ol.extent.containsExtent(projectionExtent, frameState.extent)) {
// do not clip when the view crosses the -180° or 180° meridians
extent[0] = projectionExtent[0];
extent[2] = projectionExtent[2];
// For the replay group, we need an extent that intersects the real world
// (-180° to +180°). To support geometries in a coordinate range from -540°
// to +540°, we add at least 1 world width on each side of the projection
// extent. If the viewport is wider than the world, we need to add half of
// the viewport width to make sure we cover the whole viewport.
var worldWidth = ol.extent.getWidth(projectionExtent);
var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth);
extent[0] = projectionExtent[0] - buffer;
extent[2] = projectionExtent[2] + buffer;
}
if (!this.dirty_ &&

View File

@@ -20,13 +20,11 @@ goog.require('ol.layer.Vector');
goog.require('ol.render.Event');
goog.require('ol.render.EventType');
goog.require('ol.render.canvas.Immediate');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.dom.ImageLayer');
goog.require('ol.renderer.dom.Layer');
goog.require('ol.renderer.dom.TileLayer');
goog.require('ol.renderer.dom.VectorLayer');
goog.require('ol.renderer.vector');
goog.require('ol.source.State');
goog.require('ol.vec.Mat4');
@@ -139,7 +137,6 @@ ol.renderer.dom.Map.prototype.dispatchComposeEvent_ =
var extent = frameState.extent;
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var resolution = viewState.resolution;
var rotation = viewState.rotation;
var context = this.context_;
var canvas = context.canvas;
@@ -153,18 +150,10 @@ ol.renderer.dom.Map.prototype.dispatchComposeEvent_ =
-viewState.center[0], -viewState.center[1]);
var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
extent, this.transform_, rotation);
var replayGroup = new ol.render.canvas.ReplayGroup(
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
resolution);
var composeEvent = new ol.render.Event(type, map, vectorContext,
replayGroup, frameState, context, null);
frameState, context, null);
map.dispatchEvent(composeEvent);
replayGroup.finish();
if (!replayGroup.isEmpty()) {
replayGroup.replay(context, pixelRatio, this.transform_, rotation, {});
}
vectorContext.flush();
this.replayGroup = replayGroup;
}
};

View File

@@ -142,7 +142,7 @@ ol.renderer.dom.VectorLayer.prototype.composeFrame =
context.globalAlpha = layerState.opacity;
replayGroup.replay(context, pixelRatio, transform, viewRotation,
frameState.skippedFeatureUids);
layerState.managed ? frameState.skippedFeatureUids : {});
this.dispatchEvent_(ol.render.EventType.RENDER, frameState, transform);
}
@@ -165,8 +165,8 @@ ol.renderer.dom.VectorLayer.prototype.dispatchEvent_ =
var render = new ol.render.canvas.Immediate(
context, frameState.pixelRatio, frameState.extent, transform,
frameState.viewState.rotation);
var event = new ol.render.Event(type, layer, render, null,
frameState, context, null);
var event = new ol.render.Event(type, layer, render, frameState,
context, null);
layer.dispatchEvent(event);
render.flush();
}
@@ -184,10 +184,11 @@ ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate =
var resolution = frameState.viewState.resolution;
var rotation = frameState.viewState.rotation;
var layer = this.getLayer();
var layerState = frameState.layerStates[goog.getUid(layer)];
/** @type {Object.<string, boolean>} */
var features = {};
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate,
resolution, rotation, frameState.skippedFeatureUids,
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
rotation, layerState.managed ? frameState.skippedFeatureUids : {},
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.

View File

@@ -113,7 +113,6 @@ ol.renderer.Layer.prototype.createLoadedTileFinder = function(source, tiles) {
/**
* @protected
* @return {ol.layer.Layer} Layer.
*/
ol.renderer.Layer.prototype.getLayer = function() {

View File

@@ -48,12 +48,6 @@ ol.renderer.Map = function(container, map) {
*/
this.map_ = map;
/**
* @protected
* @type {ol.render.IReplayGroup}
*/
this.replayGroup = null;
/**
* @private
* @type {Object.<string, ol.renderer.Layer>}
@@ -137,7 +131,6 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate =
var result;
var viewState = frameState.viewState;
var viewResolution = viewState.resolution;
var viewRotation = viewState.rotation;
/** @type {Object.<string, boolean>} */
var features = {};
@@ -168,21 +161,15 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate =
}
}
if (!goog.isNull(this.replayGroup)) {
result = this.replayGroup.forEachFeatureAtCoordinate(translatedCoordinate,
viewResolution, viewRotation, {}, forEachFeatureAtCoordinate);
if (result) {
return result;
}
}
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;
for (i = numLayers - 1; i >= 0; --i) {
var layerState = layerStates[i];
var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
layerFilter.call(thisArg2, layer)) {
if (!layerState.managed ||
(ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
layerFilter.call(thisArg2, layer))) {
var layerRenderer = this.getLayerRenderer(layer);
result = layerRenderer.forEachFeatureAtCoordinate(
layer.getSource().getWrapX() ? translatedCoordinate : coordinate,
@@ -216,20 +203,7 @@ ol.renderer.Map.prototype.forEachLayerAtPixel =
var result;
var viewState = frameState.viewState;
var viewResolution = viewState.resolution;
var viewRotation = viewState.rotation;
if (!goog.isNull(this.replayGroup)) {
var coordinate = this.getMap().getCoordinateFromPixel(pixel);
var hasFeature = this.replayGroup.forEachFeatureAtCoordinate(coordinate,
viewResolution, viewRotation, {}, goog.functions.TRUE);
if (hasFeature) {
result = callback.call(thisArg, null);
if (result) {
return result;
}
}
}
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;

View File

@@ -247,7 +247,7 @@ ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ =
var render = new ol.render.webgl.Immediate(
context, center, resolution, rotation, size, extent, pixelRatio);
var composeEvent = new ol.render.Event(
type, layer, render, null, frameState, null, context);
type, layer, render, frameState, null, context);
layer.dispatchEvent(composeEvent);
}
};

View File

@@ -24,9 +24,7 @@ goog.require('ol.layer.Vector');
goog.require('ol.render.Event');
goog.require('ol.render.EventType');
goog.require('ol.render.webgl.Immediate');
goog.require('ol.render.webgl.ReplayGroup');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.vector');
goog.require('ol.renderer.webgl.ImageLayer');
goog.require('ol.renderer.webgl.Layer');
goog.require('ol.renderer.webgl.TileLayer');
@@ -287,27 +285,14 @@ ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ =
var resolution = viewState.resolution;
var center = viewState.center;
var rotation = viewState.rotation;
var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
var vectorContext = new ol.render.webgl.Immediate(context,
center, resolution, rotation, size, extent, pixelRatio);
var replayGroup = new ol.render.webgl.ReplayGroup(tolerance, extent);
var composeEvent = new ol.render.Event(type, map, vectorContext,
replayGroup, frameState, null, context);
frameState, null, context);
map.dispatchEvent(composeEvent);
replayGroup.finish(context);
if (!replayGroup.isEmpty()) {
// use default color values
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
replayGroup.replay(context, center, resolution, rotation, size,
pixelRatio, d.opacity, d.brightness, d.contrast,
d.hue, d.saturation, {});
}
replayGroup.getDeleteResourcesFunction(context)();
vectorContext.flush();
this.replayGroup = replayGroup;
}
};
@@ -482,6 +467,8 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
this.textureCache_.set((-frameState.index).toString(), null);
++this.textureCacheFrameMarkerCount_;
this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
/** @type {Array.<ol.layer.LayerState>} */
var layerStatesToDraw = [];
var layerStatesArray = frameState.layerStatesArray;
@@ -514,8 +501,6 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
gl.enable(goog.webgl.BLEND);
gl.viewport(0, 0, this.canvas_.width, this.canvas_.height);
this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) {
layerState = layerStatesToDraw[i];
layerRenderer = this.getLayerRenderer(layerState.layer);
@@ -561,37 +546,8 @@ ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate =
return false;
}
var context = this.getContext();
var viewState = frameState.viewState;
// do the hit-detection for the overlays first
if (!goog.isNull(this.replayGroup)) {
/** @type {Object.<string, boolean>} */
var features = {};
// use default color values
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
result = this.replayGroup.forEachFeatureAtCoordinate(coordinate,
context, viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
d.opacity, d.brightness, d.contrast, d.hue, d.saturation, {},
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
*/
function(feature) {
goog.asserts.assert(goog.isDef(feature), 'received a feature');
var key = goog.getUid(feature).toString();
if (!(key in features)) {
features[key] = true;
return callback.call(thisArg, feature, null);
}
});
if (result) {
return result;
}
}
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;
@@ -623,22 +579,8 @@ ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate =
return false;
}
var context = this.getContext();
var viewState = frameState.viewState;
// do the hit-detection for the overlays first
if (!goog.isNull(this.replayGroup)) {
// use default color values
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
hasFeature = this.replayGroup.hasFeatureAtCoordinate(coordinate,
context, viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
d.opacity, d.brightness, d.contrast, d.hue, d.saturation, {});
if (hasFeature) {
return true;
}
}
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;
@@ -669,27 +611,9 @@ ol.renderer.webgl.Map.prototype.forEachLayerAtPixel =
return false;
}
var context = this.getContext();
var viewState = frameState.viewState;
var result;
// do the hit-detection for the overlays first
if (!goog.isNull(this.replayGroup)) {
// use default color values
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
var coordinate = this.getMap().getCoordinateFromPixel(pixel);
var hasFeature = this.replayGroup.hasFeatureAtCoordinate(coordinate,
context, viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
d.opacity, d.brightness, d.contrast, d.hue, d.saturation, {});
if (hasFeature) {
result = callback.call(thisArg, null);
if (result) {
return result;
}
}
}
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;

View File

@@ -83,7 +83,8 @@ ol.renderer.webgl.VectorLayer.prototype.composeFrame =
viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio, layerState.opacity,
layerState.brightness, layerState.contrast, layerState.hue,
layerState.saturation, frameState.skippedFeatureUids);
layerState.saturation,
layerState.managed ? frameState.skippedFeatureUids : {});
}
};
@@ -121,7 +122,8 @@ ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate =
context, viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
layerState.opacity, layerState.brightness, layerState.contrast,
layerState.hue, layerState.saturation, frameState.skippedFeatureUids,
layerState.hue, layerState.saturation,
layerState.managed ? frameState.skippedFeatureUids : {},
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.

View File

@@ -114,34 +114,35 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse =
this.tileGrid = tileGrid;
var culture = this.culture_;
this.tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform(
tileGrid.createTileCoordTransform(),
ol.TileUrlFunction.createFromTileUrlFunctions(
goog.array.map(
resource.imageUrlSubdomains,
function(subdomain) {
var imageUrl = resource.imageUrl
.replace('{subdomain}', subdomain)
.replace('{culture}', culture);
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.proj.Projection} projection Projection.
* @return {string|undefined} Tile URL.
*/
function(tileCoord, pixelRatio, projection) {
goog.asserts.assert(ol.proj.equivalent(
projection, sourceProjection),
'projections are equivalent');
if (goog.isNull(tileCoord)) {
return undefined;
} else {
return imageUrl.replace(
'{quadkey}', ol.tilecoord.quadKey(tileCoord));
}
});
})));
this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
goog.array.map(
resource.imageUrlSubdomains,
function(subdomain) {
var quadKeyTileCoord = [0, 0, 0];
var imageUrl = resource.imageUrl
.replace('{subdomain}', subdomain)
.replace('{culture}', culture);
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.proj.Projection} projection Projection.
* @return {string|undefined} Tile URL.
*/
function(tileCoord, pixelRatio, projection) {
goog.asserts.assert(ol.proj.equivalent(
projection, sourceProjection),
'projections are equivalent');
if (goog.isNull(tileCoord)) {
return undefined;
} else {
ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1],
-tileCoord[2] - 1, quadKeyTileCoord);
return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey(
quadKeyTileCoord));
}
});
}));
if (resource.imageryProviders) {
var transform = ol.proj.getTransformFromProjections(

View File

@@ -0,0 +1,535 @@
goog.provide('ol.source.Raster');
goog.provide('ol.source.RasterEvent');
goog.provide('ol.source.RasterEventType');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('goog.vec.Mat4');
goog.require('ol.ImageCanvas');
goog.require('ol.TileQueue');
goog.require('ol.dom');
goog.require('ol.ext.pixelworks');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.raster.OperationType');
goog.require('ol.renderer.canvas.ImageLayer');
goog.require('ol.renderer.canvas.TileLayer');
goog.require('ol.source.Image');
goog.require('ol.source.State');
goog.require('ol.source.Tile');
/**
* @classdesc
* A source that transforms data from any number of input sources using an array
* of {@link ol.raster.Operation} functions to transform input pixel values into
* output pixel values.
*
* @constructor
* @extends {ol.source.Image}
* @param {olx.source.RasterOptions} options Options.
* @api
*/
ol.source.Raster = function(options) {
/**
* @private
* @type {*}
*/
this.worker_ = null;
/**
* @private
* @type {ol.raster.OperationType}
*/
this.operationType_ = goog.isDef(options.operationType) ?
options.operationType : ol.raster.OperationType.PIXEL;
/**
* @private
* @type {number}
*/
this.threads_ = goog.isDef(options.threads) ? options.threads : 1;
/**
* @private
* @type {Array.<ol.renderer.canvas.Layer>}
*/
this.renderers_ = ol.source.Raster.createRenderers_(options.sources);
for (var r = 0, rr = this.renderers_.length; r < rr; ++r) {
goog.events.listen(this.renderers_[r], goog.events.EventType.CHANGE,
this.changed, false, this);
}
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.canvasContext_ = ol.dom.createCanvasContext2D();
/**
* @private
* @type {ol.TileQueue}
*/
this.tileQueue_ = new ol.TileQueue(
goog.functions.constant(1),
goog.bind(this.changed, this));
var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_);
var layerStates = {};
for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {
layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
}
/**
* The most recently rendered state.
* @type {?ol.source.Raster.RenderedState}
* @private
*/
this.renderedState_ = null;
/**
* The most recently rendered image canvas.
* @type {ol.ImageCanvas}
* @private
*/
this.renderedImageCanvas_ = null;
/**
* @private
* @type {olx.FrameState}
*/
this.frameState_ = {
animate: false,
attributions: {},
coordinateToPixelMatrix: goog.vec.Mat4.createNumber(),
extent: null,
focus: null,
index: 0,
layerStates: layerStates,
layerStatesArray: layerStatesArray,
logos: {},
pixelRatio: 1,
pixelToCoordinateMatrix: goog.vec.Mat4.createNumber(),
postRenderFunctions: [],
size: [0, 0],
skippedFeatureUids: {},
tileQueue: this.tileQueue_,
time: Date.now(),
usedTiles: {},
viewState: /** @type {olx.ViewState} */ ({
rotation: 0
}),
viewHints: [],
wantedTiles: {}
};
goog.base(this, {});
if (goog.isDef(options.operation)) {
this.setOperation(options.operation, options.lib);
}
};
goog.inherits(ol.source.Raster, ol.source.Image);
/**
* Set the operation.
* @param {ol.raster.Operation} operation New operation.
* @param {Object=} opt_lib Functions that will be available to operations run
* in a worker.
* @api
*/
ol.source.Raster.prototype.setOperation = function(operation, opt_lib) {
this.worker_ = new ol.ext.pixelworks.Processor({
operation: operation,
imageOps: this.operationType_ === ol.raster.OperationType.IMAGE,
queue: 1,
lib: opt_lib,
threads: this.threads_
});
this.changed();
};
/**
* Update the stored frame state.
* @param {ol.Extent} extent The view extent (in map units).
* @param {number} resolution The view resolution.
* @param {ol.proj.Projection} projection The view projection.
* @return {olx.FrameState} The updated frame state.
* @private
*/
ol.source.Raster.prototype.updateFrameState_ =
function(extent, resolution, projection) {
var frameState = /** @type {olx.FrameState} */ (
goog.object.clone(this.frameState_));
frameState.viewState = /** @type {olx.ViewState} */ (
goog.object.clone(frameState.viewState));
var center = ol.extent.getCenter(extent);
var width = Math.round(ol.extent.getWidth(extent) / resolution);
var height = Math.round(ol.extent.getHeight(extent) / resolution);
frameState.extent = extent;
frameState.focus = ol.extent.getCenter(extent);
frameState.size[0] = width;
frameState.size[1] = height;
var viewState = frameState.viewState;
viewState.center = center;
viewState.projection = projection;
viewState.resolution = resolution;
return frameState;
};
/**
* Determine if the most recently rendered image canvas is dirty.
* @param {ol.Extent} extent The requested extent.
* @param {number} resolution The requested resolution.
* @return {boolean} The image is dirty.
* @private
*/
ol.source.Raster.prototype.isDirty_ = function(extent, resolution) {
var state = this.renderedState_;
return !state ||
this.getRevision() !== state.revision ||
resolution !== state.resolution ||
!ol.extent.equals(extent, state.extent);
};
/**
* @inheritDoc
*/
ol.source.Raster.prototype.getImage =
function(extent, resolution, pixelRatio, projection) {
if (!this.allSourcesReady_()) {
return null;
}
if (!this.isDirty_(extent, resolution)) {
return this.renderedImageCanvas_;
}
var context = this.canvasContext_;
var canvas = context.canvas;
var width = Math.round(ol.extent.getWidth(extent) / resolution);
var height = Math.round(ol.extent.getHeight(extent) / resolution);
if (width !== canvas.width ||
height !== canvas.height) {
canvas.width = width;
canvas.height = height;
}
var frameState = this.updateFrameState_(extent, resolution, projection);
var imageCanvas = new ol.ImageCanvas(
extent, resolution, 1, this.getAttributions(), canvas,
this.composeFrame_.bind(this, frameState));
this.renderedImageCanvas_ = imageCanvas;
this.renderedState_ = {
extent: extent,
resolution: resolution,
revision: this.getRevision()
};
return imageCanvas;
};
/**
* Determine if all sources are ready.
* @return {boolean} All sources are ready.
* @private
*/
ol.source.Raster.prototype.allSourcesReady_ = function() {
var ready = true;
var source;
for (var i = 0, ii = this.renderers_.length; i < ii; ++i) {
source = this.renderers_[i].getLayer().getSource();
if (source.getState() !== ol.source.State.READY) {
ready = false;
break;
}
}
return ready;
};
/**
* Compose the frame. This renders data from all sources, runs pixel-wise
* operations, and renders the result to the stored canvas context.
* @param {olx.FrameState} frameState The frame state.
* @param {function(Error)} callback Called when composition is complete.
* @private
*/
ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) {
var len = this.renderers_.length;
var imageDatas = new Array(len);
for (var i = 0; i < len; ++i) {
var imageData = ol.source.Raster.getImageData_(
this.renderers_[i], frameState, frameState.layerStatesArray[i]);
if (imageData) {
imageDatas[i] = imageData;
} else {
// image not yet ready
return;
}
}
var data = {};
this.dispatchEvent(new ol.source.RasterEvent(
ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data));
this.worker_.process(imageDatas, data,
this.onWorkerComplete_.bind(this, frameState, callback));
frameState.tileQueue.loadMoreTiles(16, 16);
};
/**
* Called when pixel processing is complete.
* @param {olx.FrameState} frameState The frame state.
* @param {function(Error)} callback Called when rendering is complete.
* @param {Error} err Any error during processing.
* @param {ImageData} output The output image data.
* @param {Object} data The user data.
* @private
*/
ol.source.Raster.prototype.onWorkerComplete_ =
function(frameState, callback, err, output, data) {
if (err) {
callback(err);
return;
}
if (goog.isNull(output)) {
// job aborted
return;
}
this.dispatchEvent(new ol.source.RasterEvent(
ol.source.RasterEventType.AFTEROPERATIONS, frameState, data));
var resolution = frameState.viewState.resolution / frameState.pixelRatio;
if (!this.isDirty_(frameState.extent, resolution)) {
this.canvasContext_.putImageData(output, 0, 0);
}
callback(null);
};
/**
* Get image data from a renderer.
* @param {ol.renderer.canvas.Layer} renderer Layer renderer.
* @param {olx.FrameState} frameState The frame state.
* @param {ol.layer.LayerState} layerState The layer state.
* @return {ImageData} The image data.
* @private
*/
ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) {
renderer.prepareFrame(frameState, layerState);
// We should be able to call renderer.composeFrame(), but this is inefficient
// for tiled sources (we've already rendered to an intermediate canvas in the
// prepareFrame call and we don't need to render again to the output canvas).
// TODO: make all canvas renderers render to a single canvas
var image = renderer.getImage();
if (!image) {
return null;
}
var imageTransform = renderer.getImageTransform();
var dx = Math.round(goog.vec.Mat4.getElement(imageTransform, 0, 3));
var dy = Math.round(goog.vec.Mat4.getElement(imageTransform, 1, 3));
var width = frameState.size[0];
var height = frameState.size[1];
if (image instanceof Image) {
if (!ol.source.Raster.context_) {
ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
} else {
var canvas = ol.source.Raster.context_.canvas;
if (canvas.width !== width || canvas.height !== height) {
ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
} else {
ol.source.Raster.context_.clearRect(0, 0, width, height);
}
}
var dw = Math.round(
image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0));
var dh = Math.round(
image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1));
ol.source.Raster.context_.drawImage(image, dx, dy, dw, dh);
return ol.source.Raster.context_.getImageData(0, 0, width, height);
} else {
return image.getContext('2d').getImageData(-dx, -dy, width, height);
}
};
/**
* A reusable canvas context.
* @type {CanvasRenderingContext2D}
* @private
*/
ol.source.Raster.context_ = null;
/**
* Get a list of layer states from a list of renderers.
* @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers.
* @return {Array.<ol.layer.LayerState>} The layer states.
* @private
*/
ol.source.Raster.getLayerStatesArray_ = function(renderers) {
return renderers.map(function(renderer) {
return renderer.getLayer().getLayerState();
});
};
/**
* Create renderers for all sources.
* @param {Array.<ol.source.Source>} sources The sources.
* @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers.
* @private
*/
ol.source.Raster.createRenderers_ = function(sources) {
var len = sources.length;
var renderers = new Array(len);
for (var i = 0; i < len; ++i) {
renderers[i] = ol.source.Raster.createRenderer_(sources[i]);
}
return renderers;
};
/**
* Create a renderer for the provided source.
* @param {ol.source.Source} source The source.
* @return {ol.renderer.canvas.Layer} The renderer.
* @private
*/
ol.source.Raster.createRenderer_ = function(source) {
var renderer = null;
if (source instanceof ol.source.Tile) {
renderer = ol.source.Raster.createTileRenderer_(
/** @type {ol.source.Tile} */ (source));
} else if (source instanceof ol.source.Image) {
renderer = ol.source.Raster.createImageRenderer_(
/** @type {ol.source.Image} */ (source));
} else {
goog.asserts.fail('Unsupported source type: ' + source);
}
return renderer;
};
/**
* Create an image renderer for the provided source.
* @param {ol.source.Image} source The source.
* @return {ol.renderer.canvas.Layer} The renderer.
* @private
*/
ol.source.Raster.createImageRenderer_ = function(source) {
var layer = new ol.layer.Image({source: source});
return new ol.renderer.canvas.ImageLayer(layer);
};
/**
* Create a tile renderer for the provided source.
* @param {ol.source.Tile} source The source.
* @return {ol.renderer.canvas.Layer} The renderer.
* @private
*/
ol.source.Raster.createTileRenderer_ = function(source) {
var layer = new ol.layer.Tile({source: source});
return new ol.renderer.canvas.TileLayer(layer);
};
/**
* @typedef {{revision: number,
* resolution: number,
* extent: ol.Extent}}
*/
ol.source.Raster.RenderedState;
/**
* @classdesc
* Events emitted by {@link ol.source.Raster} instances are instances of this
* type.
*
* @constructor
* @extends {goog.events.Event}
* @implements {oli.source.RasterEvent}
* @param {string} type Type.
* @param {olx.FrameState} frameState The frame state.
* @param {Object} data An object made available to operations.
*/
ol.source.RasterEvent = function(type, frameState, data) {
goog.base(this, type);
/**
* The raster extent.
* @type {ol.Extent}
* @api
*/
this.extent = frameState.extent;
/**
* The pixel resolution (map units per pixel).
* @type {number}
* @api
*/
this.resolution = frameState.viewState.resolution / frameState.pixelRatio;
/**
* An object made available to all operations. This can be used by operations
* as a storage object (e.g. for calculating statistics).
* @type {Object}
* @api
*/
this.data = data;
};
goog.inherits(ol.source.RasterEvent, goog.events.Event);
/**
* @enum {string}
*/
ol.source.RasterEventType = {
/**
* Triggered before operations are run.
* @event ol.source.RasterEvent#beforeoperations
* @api
*/
BEFOREOPERATIONS: 'beforeoperations',
/**
* Triggered after operations are run.
* @event ol.source.RasterEvent#afteroperations
* @api
*/
AFTEROPERATIONS: 'afteroperations'
};

View File

@@ -37,9 +37,10 @@ ol.source.SourceOptions;
* instantiated in apps.
* Base class for {@link ol.layer.Layer} sources.
*
* A generic `change` event is triggered when the state of the source changes.
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the state of the source changes.
* @param {ol.source.SourceOptions} options Source options.
* @api stable
*/

View File

@@ -39,6 +39,7 @@ ol.source.TileArcGISRest = function(opt_options) {
goog.base(this, {
attributions: options.attributions,
crossOrigin: options.crossOrigin,
logo: options.logo,
projection: options.projection,
tileGrid: options.tileGrid,
@@ -111,7 +112,7 @@ ol.source.TileArcGISRest.prototype.getRequestUrl_ =
params['BBOX'] = tileExtent.join(',');
params['BBOXSR'] = srid;
params['IMAGESR'] = srid;
params['DPI'] = 90 * pixelRatio;
params['DPI'] = Math.round(90 * pixelRatio);
var url;
if (urls.length == 1) {

View File

@@ -7,7 +7,6 @@ goog.require('ol.dom');
goog.require('ol.size');
goog.require('ol.source.Tile');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');
@@ -15,10 +14,11 @@ goog.require('ol.tilegrid.TileGrid');
* @constructor
* @extends {ol.Tile}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @param {ol.Size} tileSize Tile size.
* @param {string} text Text.
* @private
*/
ol.DebugTile_ = function(tileCoord, tileGrid) {
ol.DebugTile_ = function(tileCoord, tileSize, text) {
goog.base(this, tileCoord, ol.TileState.LOADED);
@@ -26,8 +26,13 @@ ol.DebugTile_ = function(tileCoord, tileGrid) {
* @private
* @type {ol.Size}
*/
this.tileSize_ = ol.size.toSize(
tileGrid.getTileSize(tileCoord[0]));
this.tileSize_ = tileSize;
/**
* @private
* @type {string}
*/
this.text_ = text;
/**
* @private
@@ -58,8 +63,7 @@ ol.DebugTile_.prototype.getImage = function(opt_context) {
context.textAlign = 'center';
context.textBaseline = 'middle';
context.font = '24px sans-serif';
context.fillText(ol.tilecoord.toString(this.tileCoord),
tileSize[0] / 2, tileSize[1] / 2);
context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2);
this.canvasByContext_[key] = context.canvas;
return context.canvas;
@@ -87,7 +91,8 @@ ol.source.TileDebug = function(options) {
goog.base(this, {
opaque: false,
projection: options.projection,
tileGrid: options.tileGrid
tileGrid: options.tileGrid,
wrapX: goog.isDef(options.wrapX) ? options.wrapX : true
});
};
@@ -102,7 +107,12 @@ ol.source.TileDebug.prototype.getTile = function(z, x, y) {
if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey));
} else {
var tile = new ol.DebugTile_([z, x, y], this.tileGrid);
var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
var tileCoord = [z, x, y];
var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord);
var text = goog.isNull(textTileCoord) ? '' : ol.tilecoord.toString(
this.getTileCoordForTileUrlFunction(textTileCoord));
var tile = new ol.DebugTile_(tileCoord, tileSize, text);
this.tileCache.set(tileCoordKey, tile);
return tile;
}

View File

@@ -75,9 +75,7 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
});
this.tileGrid = tileGrid;
this.tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform(
tileGrid.createTileCoordTransform(),
ol.TileUrlFunction.createFromTemplates(tileJSON.tiles));
this.tileUrlFunction = ol.TileUrlFunction.createFromTemplates(tileJSON.tiles);
if (goog.isDef(tileJSON.attribution) &&
goog.isNull(this.getAttributions())) {

View File

@@ -217,8 +217,9 @@ ol.source.Tile.prototype.getTilePixelSize =
/**
* Handles x-axis wrapping and returns a tile coordinate when it is within
* the resolution and extent range.
* Returns a tile coordinate wrapped around the x-axis. When the tile coordinate
* is outside the resolution and extent range of the tile grid, `null` will be
* returned.
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection=} opt_projection Projection.
* @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or
@@ -230,10 +231,10 @@ ol.source.Tile.prototype.getTileCoordForTileUrlFunction =
opt_projection : this.getProjection();
var tileGrid = this.getTileGridForProjection(projection);
goog.asserts.assert(!goog.isNull(tileGrid), 'tile grid needed');
if (this.getWrapX()) {
if (this.getWrapX() && projection.isGlobal()) {
tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection);
}
return ol.tilecoord.restrictByExtentAndZ(tileCoord, tileGrid);
return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
};

View File

@@ -136,9 +136,7 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
return;
}
this.tileUrlFunction_ = ol.TileUrlFunction.withTileCoordTransform(
tileGrid.createTileCoordTransform(),
ol.TileUrlFunction.createFromTemplates(grids));
this.tileUrlFunction_ = ol.TileUrlFunction.createFromTemplates(grids);
if (goog.isDef(tileJSON.attribution)) {
var attributionExtent = goog.isDef(extent) ?
@@ -175,7 +173,9 @@ ol.source.TileUTFGrid.prototype.getTile =
} else {
goog.asserts.assert(projection, 'argument projection is truthy');
var tileCoord = [z, x, y];
var tileUrl = this.tileUrlFunction_(tileCoord, pixelRatio, projection);
var urlTileCoord =
this.getTileCoordForTileUrlFunction(tileCoord, projection);
var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection);
var tile = new ol.source.TileUTFGridTile_(
tileCoord,
goog.isDef(tileUrl) ? ol.TileState.IDLE : ol.TileState.EMPTY,

View File

@@ -3,11 +3,11 @@ goog.provide('ol.source.TileVector');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.featureloader');
goog.require('ol.source.State');
goog.require('ol.source.Vector');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');
@@ -28,17 +28,15 @@ ol.source.TileVector = function(options) {
attributions: options.attributions,
logo: options.logo,
projection: undefined,
state: ol.source.State.READY
state: ol.source.State.READY,
wrapX: options.wrapX
});
/**
* @private
* @type {ol.format.Feature}
* @type {ol.format.Feature|undefined}
*/
this.format_ = options.format;
goog.asserts.assert(goog.isDefAndNotNull(this.format_),
'ol.source.TileVector requires a format');
this.format_ = goog.isDef(options.format) ? options.format : null;
/**
* @private
@@ -54,9 +52,14 @@ ol.source.TileVector = function(options) {
/**
* @private
* @type {ol.TileCoordTransformType}
* @type {?ol.TileVectorLoadFunctionType}
*/
this.tileCoordTransform_ = this.tileGrid_.createTileCoordTransform();
this.tileLoadFunction_ = goog.isDef(options.tileLoadFunction) ?
options.tileLoadFunction : null;
goog.asserts.assert(!goog.isNull(this.format_) ||
!goog.isNull(this.tileLoadFunction_),
'Either format or tileLoadFunction are required');
/**
* @private
@@ -237,6 +240,28 @@ ol.source.TileVector.prototype.getFeaturesAtCoordinateAndResolution =
ol.source.TileVector.prototype.getFeaturesInExtent = goog.abstractMethod;
/**
* Handles x-axis wrapping and returns a tile coordinate transformed from the
* internal tile scheme to the tile grid's tile scheme. When the tile coordinate
* is outside the resolution and extent range of the tile grid, `null` will be
* returned.
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or
* null if no tile URL should be created for the passed `tileCoord`.
*/
ol.source.TileVector.prototype.getTileCoordForTileUrlFunction =
function(tileCoord, projection) {
var tileGrid = this.tileGrid_;
goog.asserts.assert(!goog.isNull(tileGrid), 'tile grid needed');
if (this.getWrapX() && projection.isGlobal()) {
tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection);
}
return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ?
tileCoord : null;
};
/**
* @param {number} z Z.
* @param {number} x X.
@@ -254,7 +279,6 @@ ol.source.TileVector.prototype.getTileKeyZXY_ = function(z, x, y) {
*/
ol.source.TileVector.prototype.loadFeatures =
function(extent, resolution, projection) {
var tileCoordTransform = this.tileCoordTransform_;
var tileGrid = this.tileGrid_;
var tileUrlFunction = this.tileUrlFunction_;
var tiles = this.tiles_;
@@ -275,16 +299,22 @@ ol.source.TileVector.prototype.loadFeatures =
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
var tileKey = this.getTileKeyZXY_(z, x, y);
if (!(tileKey in tiles)) {
tileCoord[0] = z;
tileCoord[1] = x;
tileCoord[2] = y;
tileCoordTransform(tileCoord, projection, tileCoord);
var url = tileUrlFunction(tileCoord, 1, projection);
var urlTileCoord = this.getTileCoordForTileUrlFunction(
tileCoord, projection);
var url = goog.isNull(urlTileCoord) ? undefined :
tileUrlFunction(urlTileCoord, 1, projection);
if (goog.isDef(url)) {
tiles[tileKey] = [];
var loader = ol.featureloader.loadFeaturesXhr(url, this.format_,
goog.partial(success, tileKey));
loader.call(this, extent, resolution, projection);
var tileSuccess = goog.partial(success, tileKey);
if (!goog.isNull(this.tileLoadFunction_)) {
this.tileLoadFunction_(url, goog.bind(tileSuccess, this));
} else {
var loader = ol.featureloader.loadFeaturesXhr(url,
/** @type {ol.format.Feature} */ (this.format_), tileSuccess);
loader.call(this, extent, resolution, projection);
}
}
}
}

View File

@@ -1,5 +1,4 @@
// FIXME bulk feature upload - suppress events
// FIXME put features in an ol.Collection
// FIXME make change-detection more refined (notably, geometry hint)
goog.provide('ol.source.Vector');
@@ -12,7 +11,10 @@ goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Extent');
goog.require('ol.Feature');
goog.require('ol.FeatureLoader');
goog.require('ol.LoadingStrategy');
goog.require('ol.ObjectEventType');
@@ -105,11 +107,14 @@ ol.source.Vector = function(opt_options) {
this.strategy_ = goog.isDef(options.strategy) ? options.strategy :
ol.loadingstrategy.all;
var useSpatialIndex =
goog.isDef(options.useSpatialIndex) ? options.useSpatialIndex : true;
/**
* @private
* @type {ol.structs.RBush.<ol.Feature>}
*/
this.featuresRtree_ = new ol.structs.RBush();
this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null;
/**
* @private
@@ -143,8 +148,27 @@ ol.source.Vector = function(opt_options) {
*/
this.featureChangeKeys_ = {};
if (goog.isDef(options.features)) {
this.addFeaturesInternal(options.features);
/**
* @private
* @type {ol.Collection.<ol.Feature>}
*/
this.featuresCollection_ = null;
var collection, features;
if (options.features instanceof ol.Collection) {
collection = options.features;
features = collection.getArray();
} else if (goog.isArray(options.features)) {
features = options.features;
}
if (!useSpatialIndex && !goog.isDef(collection)) {
collection = new ol.Collection(features);
}
if (goog.isDef(features)) {
this.addFeaturesInternal(features);
}
if (goog.isDef(collection)) {
this.bindFeaturesCollection_(collection);
}
};
@@ -181,7 +205,9 @@ ol.source.Vector.prototype.addFeatureInternal = function(feature) {
var geometry = feature.getGeometry();
if (goog.isDefAndNotNull(geometry)) {
var extent = geometry.getExtent();
this.featuresRtree_.insert(extent, feature);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.insert(extent, feature);
}
} else {
this.nullGeometryFeatures_[featureKey] = feature;
}
@@ -198,7 +224,7 @@ ol.source.Vector.prototype.addFeatureInternal = function(feature) {
*/
ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) {
goog.asserts.assert(!(featureKey in this.featureChangeKeys_),
'key (%s) not yet registered in featurChangeKey', featureKey);
'key (%s) not yet registered in featureChangeKey', featureKey);
this.featureChangeKeys_[featureKey] = [
goog.events.listen(feature,
goog.events.EventType.CHANGE,
@@ -280,7 +306,9 @@ ol.source.Vector.prototype.addFeaturesInternal = function(features) {
this.nullGeometryFeatures_[featureKey] = feature;
}
}
this.featuresRtree_.load(extents, geometryFeatures);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.load(extents, geometryFeatures);
}
for (i = 0, length = newFeatures.length; i < length; i++) {
this.dispatchEvent(new ol.source.VectorEvent(
@@ -289,6 +317,54 @@ ol.source.Vector.prototype.addFeaturesInternal = function(features) {
};
/**
* @param {!ol.Collection.<ol.Feature>} collection Collection.
* @private
*/
ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) {
goog.asserts.assert(goog.isNull(this.featuresCollection_),
'bindFeaturesCollection can only be called once');
var modifyingCollection = false;
goog.events.listen(this, ol.source.VectorEventType.ADDFEATURE,
function(evt) {
if (!modifyingCollection) {
modifyingCollection = true;
collection.push(evt.feature);
modifyingCollection = false;
}
});
goog.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE,
function(evt) {
if (!modifyingCollection) {
modifyingCollection = true;
collection.remove(evt.feature);
modifyingCollection = false;
}
});
goog.events.listen(collection, ol.CollectionEventType.ADD,
function(evt) {
if (!modifyingCollection) {
var feature = evt.element;
goog.asserts.assertInstanceof(feature, ol.Feature);
modifyingCollection = true;
this.addFeature(feature);
modifyingCollection = false;
}
}, false, this);
goog.events.listen(collection, ol.CollectionEventType.REMOVE,
function(evt) {
if (!modifyingCollection) {
var feature = evt.element;
goog.asserts.assertInstanceof(feature, ol.Feature);
modifyingCollection = true;
this.removeFeature(feature);
modifyingCollection = false;
}
}, false, this);
this.featuresCollection_ = collection;
};
/**
* Remove all features from the source.
* @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events.
@@ -300,22 +376,31 @@ ol.source.Vector.prototype.clear = function(opt_fast) {
var keys = this.featureChangeKeys_[featureId];
goog.array.forEach(keys, goog.events.unlistenByKey);
}
this.featureChangeKeys_ = {};
this.idIndex_ = {};
this.undefIdIndex_ = {};
if (goog.isNull(this.featuresCollection_)) {
this.featureChangeKeys_ = {};
this.idIndex_ = {};
this.undefIdIndex_ = {};
}
} else {
var rmFeatureInternal = this.removeFeatureInternal;
this.featuresRtree_.forEach(rmFeatureInternal, this);
goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this);
goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_),
'featureChangeKeys is an empty object now');
goog.asserts.assert(goog.object.isEmpty(this.idIndex_),
'idIndex is an empty object now');
goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_),
'undefIdIndex is an empty object now');
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.forEach(rmFeatureInternal, this);
goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this);
}
}
if (!goog.isNull(this.featuresCollection_)) {
this.featuresCollection_.clear();
}
goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_),
'featureChangeKeys is an empty object now');
goog.asserts.assert(goog.object.isEmpty(this.idIndex_),
'idIndex is an empty object now');
goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_),
'undefIdIndex is an empty object now');
this.featuresRtree_.clear();
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.clear();
}
this.loadedExtentsRtree_.clear();
this.nullGeometryFeatures_ = {};
@@ -338,7 +423,11 @@ ol.source.Vector.prototype.clear = function(opt_fast) {
* @api stable
*/
ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) {
return this.featuresRtree_.forEach(callback, opt_this);
if (!goog.isNull(this.featuresRtree_)) {
return this.featuresRtree_.forEach(callback, opt_this);
} else if (!goog.isNull(this.featuresCollection_)) {
return this.featuresCollection_.forEach(callback, opt_this);
}
};
@@ -381,6 +470,9 @@ ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect =
* the {@link ol.source.Vector#forEachFeatureIntersectingExtent
* source.forEachFeatureIntersectingExtent()} method instead.
*
* When `useSpatialIndex` is set to false, this method will loop through all
* features, equivalent to {@link ol.source.Vector#forEachFeature}.
*
* @param {ol.Extent} extent Extent.
* @param {function(this: T, ol.Feature): S} callback Called with each feature
* whose bounding box intersects the provided extent.
@@ -391,7 +483,11 @@ ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect =
*/
ol.source.Vector.prototype.forEachFeatureInExtent =
function(extent, callback, opt_this) {
return this.featuresRtree_.forEachInExtent(extent, callback, opt_this);
if (!goog.isNull(this.featuresRtree_)) {
return this.featuresRtree_.forEachInExtent(extent, callback, opt_this);
} else if (!goog.isNull(this.featuresCollection_)) {
return this.featuresCollection_.forEach(callback, opt_this);
}
};
@@ -448,17 +544,36 @@ ol.source.Vector.prototype.forEachFeatureIntersectingExtent =
};
/**
* Get the features collection associated with this source. Will be `null`
* unless the source was configured with `useSpatialIndex` set to `false`, or
* with an {@link ol.Collection} as `features`.
* @return {ol.Collection.<ol.Feature>}
* @api
*/
ol.source.Vector.prototype.getFeaturesCollection = function() {
return this.featuresCollection_;
};
/**
* Get all features on the source.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.source.Vector.prototype.getFeatures = function() {
var features = this.featuresRtree_.getAll();
if (!goog.object.isEmpty(this.nullGeometryFeatures_)) {
goog.array.extend(
features, goog.object.getValues(this.nullGeometryFeatures_));
var features;
if (!goog.isNull(this.featuresCollection_)) {
features = this.featuresCollection_.getArray();
} else if (!goog.isNull(this.featuresRtree_)) {
features = this.featuresRtree_.getAll();
if (!goog.object.isEmpty(this.nullGeometryFeatures_)) {
goog.array.extend(
features, goog.object.getValues(this.nullGeometryFeatures_));
}
}
goog.asserts.assert(goog.isDef(features),
'Neither featuresRtree_ nor featuresCollection_ are available');
return features;
};
@@ -482,17 +597,25 @@ ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) {
* Get all features in the provided extent. Note that this returns all features
* whose bounding boxes intersect the given extent (so it may include features
* whose geometries do not intersect the extent).
*
* This method is not available when the source is configured with
* `useSpatialIndex` set to `false`.
* @param {ol.Extent} extent Extent.
* @return {Array.<ol.Feature>} Features.
* @api
*/
ol.source.Vector.prototype.getFeaturesInExtent = function(extent) {
goog.asserts.assert(!goog.isNull(this.featuresRtree_),
'getFeaturesInExtent does not work when useSpatialIndex is set to false');
return this.featuresRtree_.getInExtent(extent);
};
/**
* Get the closest feature to the provided coordinate.
*
* This method is not available when the source is configured with
* `useSpatialIndex` set to `false`.
* @param {ol.Coordinate} coordinate Coordinate.
* @return {ol.Feature} Closest feature.
* @api stable
@@ -512,6 +635,9 @@ ol.source.Vector.prototype.getClosestFeatureToCoordinate =
var closestPoint = [NaN, NaN];
var minSquaredDistance = Infinity;
var extent = [-Infinity, -Infinity, Infinity, Infinity];
goog.asserts.assert(!goog.isNull(this.featuresRtree_),
'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' +
'to false');
this.featuresRtree_.forEachInExtent(extent,
/**
* @param {ol.Feature} feature Feature.
@@ -542,10 +668,15 @@ ol.source.Vector.prototype.getClosestFeatureToCoordinate =
/**
* Get the extent of the features currently in the source.
*
* This method is not available when the source is configured with
* `useSpatialIndex` set to `false`.
* @return {ol.Extent} Extent.
* @api stable
*/
ol.source.Vector.prototype.getExtent = function() {
goog.asserts.assert(!goog.isNull(this.featuresRtree_),
'getExtent does not work when useSpatialIndex is set to false');
return this.featuresRtree_.getExtent();
};
@@ -575,16 +706,22 @@ ol.source.Vector.prototype.handleFeatureChange_ = function(event) {
var geometry = feature.getGeometry();
if (!goog.isDefAndNotNull(geometry)) {
if (!(featureKey in this.nullGeometryFeatures_)) {
this.featuresRtree_.remove(feature);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.remove(feature);
}
this.nullGeometryFeatures_[featureKey] = feature;
}
} else {
var extent = geometry.getExtent();
if (featureKey in this.nullGeometryFeatures_) {
delete this.nullGeometryFeatures_[featureKey];
this.featuresRtree_.insert(extent, feature);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.insert(extent, feature);
}
} else {
this.featuresRtree_.update(extent, feature);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.update(extent, feature);
}
}
}
var id = feature.getId();
@@ -668,7 +805,9 @@ ol.source.Vector.prototype.removeFeature = function(feature) {
if (featureKey in this.nullGeometryFeatures_) {
delete this.nullGeometryFeatures_[featureKey];
} else {
this.featuresRtree_.remove(feature);
if (!goog.isNull(this.featuresRtree_)) {
this.featuresRtree_.remove(feature);
}
}
this.removeFeatureInternal(feature);
this.changed();

Some files were not shown because too many files have changed in this diff Show More