Compare commits

...

138 Commits

Author SHA1 Message Date
Andreas Hocevar
4255e81b93 Merge pull request #6914 from openlayers/release-v4.2.0
Finish upgrade notes for v4.2.0
2017-06-12 16:36:29 +02:00
Andreas Hocevar
81e8cdc7ab Finish upgrade notes for v4.2.0 2017-06-12 16:34:29 +02:00
Andreas Hocevar
b1b5b54fd0 Merge pull request #6913 from openlayers/release-v4.2.0
Release v4.2.0
2017-06-12 16:30:36 +02:00
Andreas Hocevar
109362f147 Update package version to 4.2.0 2017-06-12 16:30:04 +02:00
Andreas Hocevar
b5038c18e2 Changelog for v4.2.0 2017-06-12 16:30:04 +02:00
Andreas Hocevar
87d889f96c Merge pull request #6912 from ahocevar/translate-cursor
Use class instead of style for Translate cursor
2017-06-12 14:26:41 +02:00
Andreas Hocevar
9b41ea4017 Use class instead of style for Translate cursor 2017-06-12 13:30:25 +02:00
Frédéric Junod
51658a0d7c Merge pull request #6858 from GaborFarkas/webgl_vector_improvements
Webgl vector improvements
2017-06-12 09:23:15 +02:00
Andreas Hocevar
2f45e14bea Merge pull request #6890 from ahocevar/movestart
Add a movestart event
2017-06-12 09:00:09 +02:00
Andreas Hocevar
aa56afdab7 Merge pull request #6910 from ahocevar/apidoc-no-duplicate-observables
Avoid duplicates in Observables list
2017-06-12 08:47:00 +02:00
Andreas Hocevar
9fda131d37 Add a movestart event 2017-06-12 08:39:12 +02:00
Andreas Hocevar
b3ddcd4ed9 Avoid duplicates in Observables list 2017-06-12 08:24:44 +02:00
Andreas Hocevar
107792635d Merge pull request #6902 from ahocevar/fix-kinetic
Require minimum duration for kinetic animation
2017-06-12 07:01:03 +02:00
GaborFarkas
7ea8cf5fb3 Don't introduce new self-intersections. Fixes #6823 2017-06-11 22:07:22 +02:00
Andreas Hocevar
1d6ce6db35 Merge pull request #6904 from openlayers/greenkeeper/sinon-2.3.4
chore(package): update sinon to version 2.3.4
2017-06-10 23:45:13 +02:00
greenkeeper[bot]
4e44a09072 chore(package): update sinon to version 2.3.4
Closes #6903
2017-06-10 10:38:14 +00:00
Andreas Hocevar
dc6d0c091a Require minimum duration for kinetic animation 2017-06-10 09:33:40 +02:00
Andreas Hocevar
af6aaf4bab Merge pull request #6901 from KlausBenndorf/regularShapePointsNotes
Added release note for changed methods of ol.style.regularShape
2017-06-10 09:16:12 +02:00
simonseyock
e822731f8c Added release note for changed methods of ol.style.regularShape
Regarding #6759
2017-06-09 22:57:41 +02:00
Frédéric Junod
a23246aca1 Merge pull request #6886 from gberaudo/extensible_cluster_source
Make ol.source.Cluster extensible
2017-06-09 15:12:44 +02:00
Andreas Hocevar
f31e45d7d2 Merge pull request #6887 from ahocevar/disable-rotation
Disable rotation for views with enableRotation: false
2017-06-09 14:07:58 +02:00
Andreas Hocevar
34e61da366 Merge pull request #6900 from openlayers/greenkeeper/clean-css-cli-4.1.4
Update clean-css-cli to the latest version 🚀
2017-06-09 14:02:13 +02:00
Frédéric Junod
451aef200f Merge pull request #6897 from probins/like
ProjectionLike in proj.getPointResolution
2017-06-09 13:57:05 +02:00
Guillaume Beraudo
bb8a1b061c Make ol.source.Cluster extensible
Change from private to protected to allow extension.
2017-06-09 13:43:07 +02:00
greenkeeper[bot]
d4367cdd7d chore(package): update clean-css-cli to version 4.1.4 2017-06-09 11:38:57 +00:00
Peter Robins
3b15bb80b9 ProjectionLike in proj.getPointResolution 2017-06-09 09:33:43 +00:00
Andreas Hocevar
399e11edf7 Merge pull request #6888 from probins/patch-1
Add note about custom functions to getPointResolution
2017-06-09 10:18:38 +02:00
Peter Robins
f97f370e5b Improve docs for getPointResolution functions 2017-06-09 08:07:35 +00:00
Andreas Hocevar
070f2e181c Merge pull request #6893 from tchandelle/decimals
Fix decimals options when writing features
2017-06-09 09:27:08 +02:00
Andreas Hocevar
9d9da4feb9 Merge pull request #6759 from KlausBenndorf/regularShapePoints
Regular shape points
2017-06-09 08:48:47 +02:00
Frédéric Junod
ce858a80ed Merge pull request #6892 from fredj/ProjectionLike
Accept a ol.ProjectionLike instead of ol.proj.Projection
2017-06-09 08:45:45 +02:00
Frederic Junod
4898c83590 Accept a ol.ProjectionLike in ol.control.MousePosition#setProjection 2017-06-09 08:29:14 +02:00
Frederic Junod
d8ed2eb1be Accept a ol.ProjectionLike in ol.Geolocation#setProjection 2017-06-09 08:28:29 +02:00
Andreas Hocevar
00c8a5845e Disable rotation for views with enableRotation: false 2017-06-08 17:29:47 +02:00
Thomas Chandelle
d8dba61b0a Rounds if decimals options = 0 2017-06-08 12:08:02 +02:00
Thomas Chandelle
b8117b3931 This method will never be used with an extent and write = true 2017-06-08 12:08:02 +02:00
Thomas Chandelle
aface2f43e Clone the geometry before applying the decimals transform
We may only do it if the geometry has not been previously transformed.
2017-06-08 12:08:02 +02:00
Frédéric Junod
9691130b83 Merge pull request #6883 from fredj/cleanup
Remove unused ol.pointer.EventSource#getMapping function
2017-06-08 11:12:09 +02:00
Frederic Junod
1fbf3caa50 Remove unused ol.pointer.EventSource#getMapping function 2017-06-08 10:42:10 +02:00
Andreas Hocevar
e3128c204e Merge pull request #6870 from kannes/patch-1
Center map on proper earth, not one to the left
2017-06-06 15:36:43 +02:00
Andreas Hocevar
1e6b27d42a Merge pull request #6872 from openlayers/greenkeeper/rollup-0.42.0
Update rollup to the latest version 🚀
2017-06-06 15:27:26 +02:00
Frédéric Junod
c24bd209e6 Merge pull request #6876 from fredj/filereader_tests
Only test ol.interaction.DragAndDrop if FileReader is supported
2017-06-06 13:45:42 +02:00
Frédéric Junod
df96cc6e56 Merge pull request #6874 from probins/patch-1
Remove unused var from ol.proj
2017-06-06 11:02:12 +02:00
Peter Robins
641549c9ed Remove unused var from ol.proj 2017-06-06 08:23:42 +00:00
Frederic Junod
66e0308028 Use 'in' operator instead of 'typeof'
In PhantomJS, `typeof XXX` returns `"object"`, not `"function"`
2017-06-06 09:48:02 +02:00
Frederic Junod
22939abb0d Only test ol.interaction.DragAndDrop if FileReader is supported 2017-06-06 09:43:59 +02:00
Frédéric Junod
dfc4bff579 Merge pull request #6875 from openlayers/greenkeeper/sinon-2.3.2
chore(package): update sinon to version 2.3.2
2017-06-06 08:58:40 +02:00
greenkeeper[bot]
588223915c fix(package): update rollup to version 0.42.0 2017-06-03 19:01:54 +00:00
Hannes
5702670bd3 removed bad [ 2017-06-02 14:20:52 +02:00
Hannes
d79760e9dd Center map on proper earth, not one to the left
The previous x coordinate was one earth to the left which led to confusing results with everything.
This change makes sure the map is centered in a proper location (pretty much the same as before) WITHIN proper bounds.
2017-06-02 14:10:37 +02:00
Frédéric Junod
21011d00ea Merge pull request #6867 from cs09g/cs09g-patch-1
add getArea to api
2017-06-01 08:20:30 +02:00
Chase(Seul-gi Choi)
23cb98272c add getArea to api
#6854
2017-06-01 11:44:44 +09:00
Andreas Hocevar
b8b2712f73 Merge pull request #6863 from cs09g/cs09g-patch-1
change size to optional
2017-05-31 13:37:52 +02:00
Frédéric Junod
8b6a29decf Merge pull request #6864 from openlayers/greenkeeper/closure-util-1.21.0
fix(package): update closure-util to version 1.21.0
2017-05-31 10:30:58 +02:00
Chase(Seul-gi Choi)
5475841ca0 fix parameter type string 2017-05-31 15:29:34 +09:00
cs09gi@gmail.com
e8a2ad1d1b change size to optional 2017-05-31 13:40:01 +09:00
Andreas Hocevar
54a62ea78d Merge pull request #6834 from notnotse/move-tolerance-option
Move tolerance option
2017-05-30 09:10:09 +02:00
GaborFarkas
bcda41b508 Do not bridge holes outside of outer ring 2017-05-29 15:55:16 +02:00
GaborFarkas
c0fac0f5ca Prepare replays for vector tiles 2017-05-29 15:53:53 +02:00
Andreas Hocevar
0faf0dd2a1 Merge pull request #6856 from oterral/fix_6848
Fix creation of new URL in readSharedStyle_ and readSharedStyleMap_
2017-05-29 14:32:32 +02:00
oterral
9a698ce1e8 Fix creation of new URL in readSharedStyle_ and readSharedStyleMap_ 2017-05-29 09:49:04 +02:00
greenkeeper[bot]
a7683c60c9 chore(package): update sinon to version 2.3.2 2017-05-26 17:27:50 +00:00
greenkeeper[bot]
9412b770bf fix(package): update closure-util to version 1.21.0 2017-05-26 13:38:43 +00:00
Andreas Hocevar
29a6473c3d Merge pull request #6852 from openlayers/greenkeeper/mocha-3.4.2
Update mocha to the latest version 🚀
2017-05-25 08:31:17 +02:00
greenkeeper[bot]
7ceed1f42d chore(package): update mocha to version 3.4.2 2017-05-24 17:33:13 +00:00
Andreas Hocevar
959367629e Merge pull request #6851 from ahocevar/draganddrop-active
Register/unregister listeners in setActive
2017-05-24 15:36:26 +02:00
Frédéric Junod
aeed1f79bb Merge pull request #6832 from oterral/fix_5269
Force state of error tiles when usInterimTilesOnError is false
2017-05-24 15:27:11 +02:00
Andreas Hocevar
278d3a0313 Register/unregister listeners in setActive 2017-05-24 14:51:39 +02:00
Andreas Hocevar
5af9f71d38 Merge pull request #6849 from oterral/fix_6848
Create URL object only when we can
2017-05-24 14:44:09 +02:00
Andreas Hocevar
b6f446e909 Merge pull request #6845 from tchandelle/snap-circle
Snap on circles
2017-05-24 14:34:07 +02:00
oterral
7804a2db86 Create URL object only when we can 2017-05-24 14:21:56 +02:00
Andreas Hocevar
0e4d2b50b4 Merge pull request #6842 from cs09g/cs09g-patch-1
add condition to check if active
2017-05-24 13:20:08 +02:00
Frédéric Junod
b594cf0d74 Merge pull request #6844 from openlayers/greenkeeper/sinon-2.3.1
Update sinon to the latest version 🚀
2017-05-24 08:28:27 +02:00
Thomas Chandelle
074fdeb212 Add snapping abilities on circles 2017-05-23 14:45:03 +02:00
Thomas Chandelle
a1355ee766 Changes snap example to allow Circle creations 2017-05-23 11:04:46 +02:00
greenkeeper[bot]
c3e1bb40f4 chore(package): update sinon to version 2.3.1 2017-05-23 09:04:09 +00:00
Chase(Seul-gi Choi)
661410a96e add condition to check if active
fixes #6840
"setMap" registers listeners to dropArea, but it doesn't check whether "active" is true or false. Simply add condition to check "active".
2017-05-23 10:48:12 +09:00
Andreas Hocevar
e272eced94 Merge pull request #6841 from openlayers/greenkeeper/sinon-2.3.0
Update sinon to the latest version 🚀
2017-05-22 13:07:06 +02:00
greenkeeper[bot]
4ab901ed43 chore(package): update sinon to version 2.3.0 2017-05-22 10:26:40 +00:00
oterral
c1abe4a550 Force state of error tiles when usInterimTilesOnError is false 2017-05-22 09:31:07 +02:00
Andreas Hocevar
3fc76f9c10 Merge pull request #6839 from openlayers/greenkeeper/async-2.4.1
Update async to the latest version 🚀
2017-05-22 07:37:55 +02:00
greenkeeper[bot]
1e304f56cb fix(package): update async to version 2.4.1 2017-05-22 04:23:48 +00:00
Andreas Hocevar
5929826c5f Merge pull request #6838 from openlayers/greenkeeper/handlebars-4.0.10
fix(package): update handlebars to version 4.0.10
2017-05-21 23:35:38 +02:00
greenkeeper[bot]
9dad36b117 fix(package): update handlebars to version 4.0.10
Closes #6837
2017-05-21 12:19:39 +00:00
Andreas Hocevar
8b9f994cea Merge pull request #6817 from ahocevar/topojson-layer
Multiple layers in TopoJSON vector tiles
2017-05-20 16:58:19 +02:00
Andreas Hocevar
7ecb2c0185 Add layerName and layers options to ol.source.TopoJSON 2017-05-20 16:48:42 +02:00
Andreas Hocevar
342c49f0bb Merge pull request #6833 from oterral/fix_6789
Fix geojson-vt example for line and point geometries
2017-05-20 09:31:25 +02:00
itjope
bb220b5c3b Add tests for isMoving 2017-05-20 09:08:03 +02:00
oterral
3455f00d23 Fix geojson-vt example for line and point geometries 2017-05-19 17:52:14 +02:00
Frédéric Junod
992ab7120c Merge pull request #6829 from openlayers/greenkeeper/clean-css-cli-4.1.3
Update clean-css-cli to the latest version 🚀
2017-05-19 12:34:11 +02:00
greenkeeper[bot]
5215722c78 chore(package): update clean-css-cli to version 4.1.3 2017-05-18 19:40:06 +00:00
itjope
56b3203fa9 Add moveTolerance option for ol.Map 2017-05-18 13:22:31 +02:00
Andreas Hocevar
3cc4a0c6e3 Merge pull request #6819 from ahocevar/vectortile-getfeatures
Adjust/fix API for working with vector tile features
2017-05-18 11:13:30 +02:00
Andreas Hocevar
556ede5960 Remove api annotation from ol.VectorImageTile#getImage 2017-05-17 10:15:45 +02:00
Andreas Hocevar
46c610f35e Merge pull request #6818 from ahocevar/tilejson
Add tileJSON option to ol.source.TileJSON
2017-05-17 08:45:57 +02:00
Frédéric Junod
18357be938 Merge pull request #6805 from fredj/better_box-selection_example
Display country name on click select
2017-05-17 08:20:58 +02:00
Andreas Hocevar
a9f369479f Dispose of vector tiles properly 2017-05-17 00:18:46 +02:00
Andreas Hocevar
8c00bbc91d Report ol.VectorTile instead of ol.VectorImageTile loads 2017-05-17 00:18:46 +02:00
Andreas Hocevar
9af01c515f Make ol.VectorTile#getFeatures and #getProjection exportable 2017-05-16 22:57:03 +02:00
Andreas Hocevar
567cc304ed Add tileJSON option to ol.source.TileJSON 2017-05-16 18:37:18 +02:00
Tim Schaub
98a1654b47 Merge pull request #6813 from tschaub/version-with-a-v
Prepend the version with a v
2017-05-16 09:02:08 -07:00
Andreas Hocevar
ddbe1986ad Merge pull request #6814 from ahocevar/renderfeature-getgeometry
Re-add ol.render.Feature#getGeometry()
2017-05-16 09:02:29 +02:00
Andreas Hocevar
ac19d4d19c Better documentation for ol.render.Feature#getGeometry 2017-05-16 08:43:08 +02:00
Andreas Hocevar
142f16afe4 Re-add the ol.render.Feature#getGeometry() method
This method does have value for users that want to switch between ol.Feature
and ol.render.Feature and still be able to use #getGeometry().getType() in a
style function to determine the feature geometry's type.
2017-05-16 08:41:55 +02:00
Tim Schaub
07810818cc Prepend the version with a v 2017-05-15 19:31:40 -07:00
Frédéric Junod
4664a19718 Merge pull request #6812 from openlayers/greenkeeper/mocha-3.4.1
Update mocha to the latest version 🚀
2017-05-15 08:42:33 +02:00
greenkeeper[bot]
46f59acdce chore(package): update mocha to version 3.4.1 2017-05-14 21:41:35 +00:00
Frédéric Junod
c61189121e Merge pull request #6786 from fredj/during_filter
Add ol.format.filter.during
2017-05-12 15:26:03 +02:00
Andreas Hocevar
8c14262efc Merge pull request #6806 from drnextgis/docs
Add note about features with the same id
2017-05-12 13:01:44 +02:00
drnextgis
fa398766d9 Add note about features with the same id 2017-05-12 17:49:37 +07:00
Frederic Junod
026fcc66c9 Display country name on click select
And not only when the box selection is used
2017-05-12 09:56:21 +02:00
Andreas Hocevar
7c5a3ae311 Merge pull request #6802 from ahocevar/vectorimage-nofeature
Remove unused setFeatures and getFormat methods
2017-05-12 08:50:47 +02:00
Andreas Hocevar
feacf7614e Remove unused getFormat() method and format_ member 2017-05-12 00:06:56 +02:00
Andreas Hocevar
8609e65fc2 Remove unused setFeatures method 2017-05-11 18:19:42 +02:00
Andreas Hocevar
3ff33699c8 Merge pull request #6801 from ahocevar/renderfeature-getid
Add getId method for ol.render.Feature
2017-05-11 17:07:53 +02:00
Andreas Hocevar
df72d7b20f Add getId() method for ol.render.Feature 2017-05-11 15:54:20 +02:00
Andreas Hocevar
1d7144564c Remove getGeometry() from the API 2017-05-11 15:53:55 +02:00
Frédéric Junod
aced2e4e94 Merge pull request #6778 from fredj/isMoving_tolerance
Add a small tolerance when testing pointer event positions
2017-05-11 09:43:24 +02:00
Andreas Hocevar
9b9ac03760 Merge pull request #6796 from ahocevar/rendered-resolution
Re-add accidently dropped condition
2017-05-11 08:55:03 +02:00
Frédéric Junod
c052de2bbc Merge pull request #6798 from openlayers/greenkeeper/clean-css-cli-4.1.2
chore(package): update clean-css-cli to version 4.1.2
2017-05-11 08:45:42 +02:00
Frederic Junod
85d0e9797c Add a small tolerance when testing pointer event positions 2017-05-11 08:36:11 +02:00
greenkeeper[bot]
f975319d02 chore(package): update clean-css-cli to version 4.1.2
Closes #6797
2017-05-11 08:32:24 +02:00
Frédéric Junod
b8164df349 Merge pull request #6795 from fredj/ol.DrawGeometryFunctionType_type
Fix ol.DrawGeometryFunctionType coordinates argument type
2017-05-11 08:26:58 +02:00
Andreas Hocevar
1458d77844 Merge pull request #6797 from openlayers/greenkeeper/clean-css-cli-4.1.1
Update clean-css-cli to the latest version 🚀
2017-05-11 00:40:28 +02:00
greenkeeper[bot]
052f2ac321 chore(package): update clean-css-cli to version 4.1.1 2017-05-10 17:53:06 +00:00
Andreas Hocevar
4a6945ac17 Merge pull request #6779 from ahocevar/vector-tile-grid
Decouple source and rendered tile grid of vector tile sources
2017-05-10 19:07:21 +02:00
Andreas Hocevar
c9ca9737a7 Re-add condition accidently dropped in 5061555 2017-05-10 19:04:55 +02:00
Frédéric Junod
2e1495fc07 Merge pull request #6785 from fredj/insertVertexCondition
Add insertVertexCondition to ol.interaction.Modify options
2017-05-10 13:37:59 +02:00
Frederic Junod
55de3020d3 Fix ol.DrawGeometryFunctionType coordinates argument type 2017-05-10 13:36:29 +02:00
Frederic Junod
ff91974345 Add insertVertexCondition to ol.interaction.Modify options 2017-05-09 15:34:43 +02:00
Andreas Hocevar
e7dc09cf9f Add more tests 2017-05-09 14:25:28 +02:00
Frederic Junod
fcf9649ef9 Add ol.format.filter.during 2017-05-09 14:07:33 +02:00
Andreas Hocevar
55e3746554 Avoid garbage creation on frame preparation/composition 2017-05-09 14:04:05 +02:00
Andreas Hocevar
a59a147dbd Handle tile state of ol.VectorImageTile properly 2017-05-09 14:04:05 +02:00
Andreas Hocevar
355ce9f679 Use same tile size in rendered and source tile grid 2017-05-09 14:04:04 +02:00
Andreas Hocevar
785e7135a7 Decouple source and rendered tile grid of vector tile sources 2017-05-09 14:04:04 +02:00
simonseyock
25aeb58c87 ol.style.RegularShape#getRadius2
returns undefined if no radius2 was provided in the constructor
2017-04-29 11:43:46 +02:00
simonseyock
dd73ac8892 ol.style.RegularShape#getPoints
returns now same amount of points as provided to the constructor
2017-04-29 11:43:27 +02:00
93 changed files with 2155 additions and 754 deletions

View File

@@ -2,6 +2,16 @@
### Next release
### v4.2.0
#### Return values of two `ol.style.RegularShape` getters have changed
To provide a more consistent behaviour the following getters now return the same value that was given to constructor:
`ol.style.RegularShape#getPoints` does not return the double amount of points anymore if a radius2 is set.
`ol.style.RegularShape#getRadius2` will return `undefined` if no radius2 is set.
### v4.1.0
#### Adding duplicate layers to a map throws

151
changelog/v4.2.0.md Normal file
View File

@@ -0,0 +1,151 @@
# 4.2.0
## Summary
The v4.2.0 release includes features and fixes from 87 pull requests.
#### New `movestart` event on `ol.Map`
The map now has a `movestart` event, as countarpart to the already existing `moveend` event.
#### New `moveTolerance` option in `ol.Map`
Some touch devices do not play well with OpenLayers's way of detecting clicks. To overcome this, a new `moveTolerance` option was introduced, so users can override the 1 pixel threshold above which a touch-release sequence won't be considered a click any more.
#### Support for multiple layers in `ol.format.TopoJSON`
With the new `layerName` and `layers` options, applications can extract the layer as additional attribute for vector features from `ol.format.TopoJSON`. This can especially be useful for styling vector tile layers.
#### New `tileJSON` option for `ol.source.TileJSON`
Like `ol.source.TileUTFGrid`, `ol.source.TileJSON` now also has a `tileJSON` option to configue it with inline TileJSON instead of a TileJSON URL.
#### New `ol.format.filter.during` filter
Although OpenLayers has no support for WFS v2.0, we added `ol.format.filter.during` for the `During` temporal operator.
#### Improved vector tile rendering at non-native resolutions
The vector tile renderer now uses an internal tile grid for all resolutions to cache pre-rendered tiles, even if the tile source does not have tiles for the viewed resolution. This improves rendering quality and performance.
#### New `insertVertexCondition` for `ol.interaction.Modify`
Applications can now control whether a vertex will be inserted into the modified geometry. This makes it easier to modify custom geometries.
#### New `callback` option for `ol.View#fit()`
To allow applications to perform custom actions when an animation associated with `ol.View#fit()` is completed, that method now has a new `callback` option.
#### New `ol.View#getInteracting()` getter
Like `ol.View#getAnimating()` returns `true` during a view animation, `ol.View#getInteracting()` returns `true` while users are interacting with the view.
#### New `hasZ` option for `ol.format.WFS#writeTransaction()`
When the new `hasZ` option is set to `true`, 3D coordinates will be preserved and encoded when writing a WFS transaction.
#### New `wrapX` option for `ol.source.Stamen`
Like other tile sources, `ol.source.Stamen` now also has a `wrapX` option, which allows applications to turn off wrapping the world in x direction.
#### Label support for `ol.Graticule`
The `ol.Graticule` component has several new options to add and control the output of labels. To turn on labelling, configure `ol.Graticule` with `showLabels: true`. The new options to control label formatting are `lonLabelFormatter`, `latLabelFormatter`, `lonLabelPosition` and `latLabelPosition`.
#### Return values of two `ol.style.RegularShape` getters have changed
To provide a more consistent behaviour the following getters now return the same value that was given to constructor:
`ol.style.RegularShape#getPoints` does not return the double amount of points anymore if a radius2 is set.
`ol.style.RegularShape#getRadius2` will return `undefined` if no radius2 is set.
## Detailed changes
* [#6912](https://github.com/openlayers/openlayers/pull/6912) - Use class instead of style for Translate cursor ([@ahocevar](https://github.com/ahocevar))
* [#6858](https://github.com/openlayers/openlayers/pull/6858) - Webgl vector improvements ([@GaborFarkas](https://github.com/GaborFarkas))
* [#6890](https://github.com/openlayers/openlayers/pull/6890) - Add a movestart event ([@ahocevar](https://github.com/ahocevar))
* [#6910](https://github.com/openlayers/openlayers/pull/6910) - Avoid duplicates in Observables list ([@ahocevar](https://github.com/ahocevar))
* [#6902](https://github.com/openlayers/openlayers/pull/6902) - Require minimum duration for kinetic animation ([@ahocevar](https://github.com/ahocevar))
* [#6904](https://github.com/openlayers/openlayers/pull/6904) - chore(package): update sinon to version 2.3.4 ([@openlayers](https://github.com/openlayers))
* [#6901](https://github.com/openlayers/openlayers/pull/6901) - Added release note for changed methods of ol.style.regularShape ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#6886](https://github.com/openlayers/openlayers/pull/6886) - Make ol.source.Cluster extensible ([@gberaudo](https://github.com/gberaudo))
* [#6887](https://github.com/openlayers/openlayers/pull/6887) - Disable rotation for views with enableRotation: false ([@ahocevar](https://github.com/ahocevar))
* [#6900](https://github.com/openlayers/openlayers/pull/6900) - Update clean-css-cli to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6897](https://github.com/openlayers/openlayers/pull/6897) - ProjectionLike in proj.getPointResolution ([@probins](https://github.com/probins))
* [#6888](https://github.com/openlayers/openlayers/pull/6888) - Add note about custom functions to getPointResolution ([@probins](https://github.com/probins))
* [#6893](https://github.com/openlayers/openlayers/pull/6893) - Fix decimals options when writing features ([@tchandelle](https://github.com/tchandelle))
* [#6759](https://github.com/openlayers/openlayers/pull/6759) - Regular shape points ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#6892](https://github.com/openlayers/openlayers/pull/6892) - Accept a ol.ProjectionLike instead of ol.proj.Projection ([@fredj](https://github.com/fredj))
* [#6883](https://github.com/openlayers/openlayers/pull/6883) - Remove unused ol.pointer.EventSource#getMapping function ([@fredj](https://github.com/fredj))
* [#6870](https://github.com/openlayers/openlayers/pull/6870) - Center map on proper earth, not one to the left ([@kannes](https://github.com/kannes))
* [#6872](https://github.com/openlayers/openlayers/pull/6872) - Update rollup to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6876](https://github.com/openlayers/openlayers/pull/6876) - Only test ol.interaction.DragAndDrop if FileReader is supported ([@fredj](https://github.com/fredj))
* [#6874](https://github.com/openlayers/openlayers/pull/6874) - Remove unused var from ol.proj ([@probins](https://github.com/probins))
* [#6875](https://github.com/openlayers/openlayers/pull/6875) - chore(package): update sinon to version 2.3.2 ([@openlayers](https://github.com/openlayers))
* [#6867](https://github.com/openlayers/openlayers/pull/6867) - add getArea to api ([@cs09g](https://github.com/cs09g))
* [#6863](https://github.com/openlayers/openlayers/pull/6863) - change size to optional ([@cs09g](https://github.com/cs09g))
* [#6864](https://github.com/openlayers/openlayers/pull/6864) - fix(package): update closure-util to version 1.21.0 ([@openlayers](https://github.com/openlayers))
* [#6834](https://github.com/openlayers/openlayers/pull/6834) - Move tolerance option ([@notnotse](https://github.com/notnotse))
* [#6856](https://github.com/openlayers/openlayers/pull/6856) - Fix creation of new URL in readSharedStyle_ and readSharedStyleMap_ ([@oterral](https://github.com/oterral))
* [#6852](https://github.com/openlayers/openlayers/pull/6852) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6851](https://github.com/openlayers/openlayers/pull/6851) - Register/unregister listeners in setActive ([@ahocevar](https://github.com/ahocevar))
* [#6832](https://github.com/openlayers/openlayers/pull/6832) - Force state of error tiles when usInterimTilesOnError is false ([@oterral](https://github.com/oterral))
* [#6849](https://github.com/openlayers/openlayers/pull/6849) - Create URL object only when we can ([@oterral](https://github.com/oterral))
* [#6845](https://github.com/openlayers/openlayers/pull/6845) - Snap on circles ([@tchandelle](https://github.com/tchandelle))
* [#6842](https://github.com/openlayers/openlayers/pull/6842) - add condition to check if active ([@cs09g](https://github.com/cs09g))
* [#6844](https://github.com/openlayers/openlayers/pull/6844) - Update sinon to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6841](https://github.com/openlayers/openlayers/pull/6841) - Update sinon to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6839](https://github.com/openlayers/openlayers/pull/6839) - Update async to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6838](https://github.com/openlayers/openlayers/pull/6838) - fix(package): update handlebars to version 4.0.10 ([@openlayers](https://github.com/openlayers))
* [#6817](https://github.com/openlayers/openlayers/pull/6817) - Multiple layers in TopoJSON vector tiles ([@ahocevar](https://github.com/ahocevar))
* [#6833](https://github.com/openlayers/openlayers/pull/6833) - Fix geojson-vt example for line and point geometries ([@oterral](https://github.com/oterral))
* [#6829](https://github.com/openlayers/openlayers/pull/6829) - Update clean-css-cli to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6819](https://github.com/openlayers/openlayers/pull/6819) - Adjust/fix API for working with vector tile features ([@ahocevar](https://github.com/ahocevar))
* [#6818](https://github.com/openlayers/openlayers/pull/6818) - Add tileJSON option to ol.source.TileJSON ([@ahocevar](https://github.com/ahocevar))
* [#6805](https://github.com/openlayers/openlayers/pull/6805) - Display country name on click select ([@fredj](https://github.com/fredj))
* [#6813](https://github.com/openlayers/openlayers/pull/6813) - Prepend the version with a v ([@tschaub](https://github.com/tschaub))
* [#6814](https://github.com/openlayers/openlayers/pull/6814) - Re-add ol.render.Feature#getGeometry() ([@ahocevar](https://github.com/ahocevar))
* [#6812](https://github.com/openlayers/openlayers/pull/6812) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6786](https://github.com/openlayers/openlayers/pull/6786) - Add ol.format.filter.during ([@fredj](https://github.com/fredj))
* [#6806](https://github.com/openlayers/openlayers/pull/6806) - Add note about features with the same id ([@drnextgis](https://github.com/drnextgis))
* [#6802](https://github.com/openlayers/openlayers/pull/6802) - Remove unused setFeatures and getFormat methods ([@ahocevar](https://github.com/ahocevar))
* [#6801](https://github.com/openlayers/openlayers/pull/6801) - Add getId method for ol.render.Feature ([@ahocevar](https://github.com/ahocevar))
* [#6778](https://github.com/openlayers/openlayers/pull/6778) - Add a small tolerance when testing pointer event positions ([@fredj](https://github.com/fredj))
* [#6796](https://github.com/openlayers/openlayers/pull/6796) - Re-add accidently dropped condition ([@ahocevar](https://github.com/ahocevar))
* [#6798](https://github.com/openlayers/openlayers/pull/6798) - chore(package): update clean-css-cli to version 4.1.2 ([@openlayers](https://github.com/openlayers))
* [#6795](https://github.com/openlayers/openlayers/pull/6795) - Fix ol.DrawGeometryFunctionType coordinates argument type ([@fredj](https://github.com/fredj))
* [#6797](https://github.com/openlayers/openlayers/pull/6797) - Update clean-css-cli to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6779](https://github.com/openlayers/openlayers/pull/6779) - Decouple source and rendered tile grid of vector tile sources ([@ahocevar](https://github.com/ahocevar))
* [#6785](https://github.com/openlayers/openlayers/pull/6785) - Add insertVertexCondition to ol.interaction.Modify options ([@fredj](https://github.com/fredj))
* [#6792](https://github.com/openlayers/openlayers/pull/6792) - Create intermediate canvas when resolutions have changed ([@ahocevar](https://github.com/ahocevar))
* [#6790](https://github.com/openlayers/openlayers/pull/6790) - Update resemblejs to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6784](https://github.com/openlayers/openlayers/pull/6784) - chore(package): update clean-css-cli to version 4.1.0 ([@openlayers](https://github.com/openlayers))
* [#6556](https://github.com/openlayers/openlayers/pull/6556) - Reading kml xunits/yunits insetPixels ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#6775](https://github.com/openlayers/openlayers/pull/6775) - Update closure-util to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6774](https://github.com/openlayers/openlayers/pull/6774) - Update fs-extra to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6770](https://github.com/openlayers/openlayers/pull/6770) - Enforce the "no missing requires" rule ([@tschaub](https://github.com/tschaub))
* [#6772](https://github.com/openlayers/openlayers/pull/6772) - Remove html tag from shortdesc ([@fredj](https://github.com/fredj))
* [#6769](https://github.com/openlayers/openlayers/pull/6769) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6757](https://github.com/openlayers/openlayers/pull/6757) - Fix crashing on creation of snap-interaction, if Circle is among the features to snap to. ([@hajjimurad](https://github.com/hajjimurad))
* [#6766](https://github.com/openlayers/openlayers/pull/6766) - Update sinon to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6765](https://github.com/openlayers/openlayers/pull/6765) - Add new callback function to view.FitOptions ([@fredj](https://github.com/fredj))
* [#6764](https://github.com/openlayers/openlayers/pull/6764) - Added View#getInteracting() to the api ([@mblinsitu](https://github.com/mblinsitu))
* [#6760](https://github.com/openlayers/openlayers/pull/6760) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6761](https://github.com/openlayers/openlayers/pull/6761) - Update async to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6755](https://github.com/openlayers/openlayers/pull/6755) - Add missing goog.require ([@fredj](https://github.com/fredj))
* [#6751](https://github.com/openlayers/openlayers/pull/6751) - Update coveralls to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6750](https://github.com/openlayers/openlayers/pull/6750) - Update fs-extra to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6741](https://github.com/openlayers/openlayers/pull/6741) - Allow user selection in overlay container ([@fredj](https://github.com/fredj))
* [#6744](https://github.com/openlayers/openlayers/pull/6744) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6737](https://github.com/openlayers/openlayers/pull/6737) - Graticule labels ([@ahocevar](https://github.com/ahocevar))
* [#6740](https://github.com/openlayers/openlayers/pull/6740) - Fix spelling ([@fredj](https://github.com/fredj))
* [#6730](https://github.com/openlayers/openlayers/pull/6730) - Update metalsmith-layouts to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#6732](https://github.com/openlayers/openlayers/pull/6732) - Use firefox < 53 in travis ([@fredj](https://github.com/fredj))
* [#6677](https://github.com/openlayers/openlayers/pull/6677) - Add an option to writeTransaction to support 3D geometries ([@Jenselme](https://github.com/Jenselme))
* [#6524](https://github.com/openlayers/openlayers/pull/6524) - Don't append feature prefix twice in WFS requests ([@Jenselme](https://github.com/Jenselme))
* [#6727](https://github.com/openlayers/openlayers/pull/6727) - Add default value in doc for the hitTolerance option ([@fredj](https://github.com/fredj))
* [#6724](https://github.com/openlayers/openlayers/pull/6724) - Add wrapX option to Stamen source ([@fredj](https://github.com/fredj))
* [#6728](https://github.com/openlayers/openlayers/pull/6728) - Fix tissot examples docs ([@fredj](https://github.com/fredj))
* [#6725](https://github.com/openlayers/openlayers/pull/6725) - Update dependencies to enable Greenkeeper 🌴 ([@openlayers](https://github.com/openlayers))
* [#6711](https://github.com/openlayers/openlayers/pull/6711) - Correct path to cleancss ([@tschaub](https://github.com/tschaub))

View File

@@ -41,7 +41,7 @@ exports.handlers = {
cls.observables = [];
}
observable = observables[doclet.observable];
if (cls.observables.indexOf(observable) == -1) {
if (observable.type && cls.observables.indexOf(observable) == -1) {
cls.observables.push(observable);
}
if (!cls.fires) {

View File

@@ -16,8 +16,10 @@
<tbody>
<?js
var self = this;
var propsByName = {};
props.forEach(function(prop) {
if (!prop) { return; }
if (!prop || propsByName[prop.name]) { return; }
propsByName[prop.name] = prop;
var setter = prop.readonly ? 'no' : 'yes';
?>

View File

@@ -49,6 +49,17 @@
-ms-user-select: auto;
user-select: auto;
}
.ol-grabbing {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
.ol-grab {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.ol-control {
position: absolute;
background-color: rgba(255,255,255,0.4);

View File

@@ -45,29 +45,29 @@ var dragBox = new ol.interaction.DragBox({
map.addInteraction(dragBox);
var infoBox = document.getElementById('info');
dragBox.on('boxend', function() {
// features that intersect the box are added to the collection of
// selected features, and their names are displayed in the "info"
// div
var info = [];
// selected features
var extent = dragBox.getGeometry().getExtent();
vectorSource.forEachFeatureIntersectingExtent(extent, function(feature) {
selectedFeatures.push(feature);
info.push(feature.get('name'));
});
if (info.length > 0) {
infoBox.innerHTML = info.join(', ');
}
});
// clear selection when drawing a new box and when clicking on the map
dragBox.on('boxstart', function() {
selectedFeatures.clear();
infoBox.innerHTML = '&nbsp;';
});
map.on('click', function() {
selectedFeatures.clear();
infoBox.innerHTML = '&nbsp;';
var infoBox = document.getElementById('info');
selectedFeatures.on(['add', 'remove'], function() {
var names = selectedFeatures.getArray().map(function(feature) {
return feature.get('name');
});
if (names.length > 0) {
infoBox.innerHTML = names.join(', ');
} else {
infoBox.innerHTML = 'No countries selected';
}
});

View File

@@ -17,18 +17,30 @@ var replacer = function(key, value) {
var geometry = value.geometry;
if (rawType === 1) {
type = geometry.length === 1 ? 'Point' : 'MultiPoint';
type = 'MultiPoint';
if (geometry.length == 1) {
type = 'Point';
geometry = geometry[0];
}
} else if (rawType === 2) {
type = geometry.length === 1 ? 'LineString' : 'MultiLineString';
type = 'MultiLineString';
if (geometry.length == 1) {
type = 'LineString';
geometry = geometry[0];
}
} else if (rawType === 3) {
type = geometry.length === 1 ? 'Polygon' : 'MultiPolygon';
type = 'Polygon';
if (geometry.length > 1) {
type = 'MultiPolygon';
geometry = [geometry];
}
}
return {
'type': 'Feature',
'geometry': {
'type': type,
'coordinates': geometry.length == 1 ? geometry : [geometry]
'coordinates': geometry
},
'properties': value.tags
};

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Advanced Mapbox Vector Tiles
shortdesc: Example of a Mapbox vector tiles map with custom tile grid.
docs: >
A vector tiles map which reuses the same tiles for subsequent zoom levels to save bandwidth on mobile devices. **Note**: No map will be visible when the access token has expired.
A vector tiles map which reuses the same source tiles for subsequent zoom levels to save bandwidth on mobile devices. **Note**: No map will be visible when the access token has expired.
tags: "mapbox, vector, tiles, mobile"
resources:
- resources/mapbox-streets-v6-style.js

View File

@@ -15,25 +15,16 @@ goog.require('ol.tilegrid.TileGrid');
var key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiRk1kMWZaSSJ9.E5BkluenyWQMsBLsuByrmg';
// For how many zoom levels do we want to use the same vector tiles?
// 1 means "use tiles from all zoom levels". 2 means "use the same tiles for 2
// subsequent zoom levels".
var reuseZoomLevels = 2;
// Offset of loaded tiles from web mercator zoom level 0.
// 0 means "At map zoom level 0, use tiles from zoom level 0". 1 means "At map
// zoom level 0, use tiles from zoom level 1".
var zoomOffset = 1;
// Calculation of tile urls
// Calculation of resolutions that match zoom levels 1, 3, 5, 7, 9, 11, 13, 15.
var resolutions = [];
for (var z = zoomOffset / reuseZoomLevels; z <= 22 / reuseZoomLevels; ++z) {
resolutions.push(156543.03392804097 / Math.pow(2, z * reuseZoomLevels));
for (var i = 0; i <= 7; ++i) {
resolutions.push(156543.03392804097 / Math.pow(2, i * 2));
}
// Calculation of tile urls for zoom levels 1, 3, 5, 7, 9, 11, 13, 15.
function tileUrlFunction(tileCoord) {
return ('https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' +
'{z}/{x}/{y}.vector.pbf?access_token=' + key)
.replace('{z}', String(tileCoord[0] * reuseZoomLevels + zoomOffset))
.replace('{z}', String(tileCoord[0] * 2 - 1))
.replace('{x}', String(tileCoord[1]))
.replace('{y}', String(-tileCoord[2] - 1))
.replace('{a-d}', 'abcd'.substr(
@@ -43,8 +34,6 @@ function tileUrlFunction(tileCoord) {
var map = new ol.Map({
layers: [
new ol.layer.VectorTile({
renderMode: 'vector',
preload: Infinity,
source: new ol.source.VectorTile({
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
'© <a href="https://www.openstreetmap.org/copyright">' +
@@ -52,9 +41,10 @@ var map = new ol.Map({
format: new ol.format.MVT(),
tileGrid: new ol.tilegrid.TileGrid({
extent: ol.proj.get('EPSG:3857').getExtent(),
resolutions: resolutions
resolutions: resolutions,
tileSize: 512
}),
tilePixelRatio: 16,
tilePixelRatio: 8,
tileUrlFunction: tileUrlFunction
}),
style: createMapboxStreetsV6Style()

View File

@@ -222,7 +222,13 @@ var select = new ol.interaction.Select({
var modify = new ol.interaction.Modify({
features: select.getFeatures(),
style: overlayStyle
style: overlayStyle,
insertVertexCondition: function() {
// prevent new vertices to be added to the polygons
return !this.features_.getArray().every(function(feature) {
return feature.getGeometry().getType().match(/Polygon/);
});
}
});
var map = new ol.Map({

View File

@@ -4,7 +4,6 @@ goog.require('ol.control');
goog.require('ol.control.MousePosition');
goog.require('ol.coordinate');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.OSM');
var mousePositionControl = new ol.control.MousePosition({
@@ -37,7 +36,7 @@ var map = new ol.Map({
var projectionSelect = document.getElementById('projection');
projectionSelect.addEventListener('change', function(event) {
mousePositionControl.setProjection(ol.proj.get(event.target.value));
mousePositionControl.setProjection(event.target.value);
});
var precisionInput = document.getElementById('precision');

View File

@@ -3,7 +3,7 @@ layout: example.html
title: OSM Vector Tiles
shortdesc: Using OpenStreetMap vector tiles.
docs: >
A simple vector tiles map with Mapzen vector tiles. **Note**: TopoJSON vector tiles are not optimized for rendering - they might clip geometries exactly at the tile boundary instead of adding a buffer, and use geographic coordinates instead of tile relative pixel coordinates in view projection.
A simple vector tiles map with Mapzen vector tiles. This example uses the TopoJSON format's `layerName` option to determine the layer ("water", "roads", "buildings") for styling. **Note**: [`ol.format.MVT`](../apidoc/ol.format.MVT.html) is an even more efficient format for vector tiles.
tags: "vector, tiles, osm, mapzen"
cloak:
vector-tiles-5eJz6JX: Your Mapzen API key from https://mapzen.com/developers

View File

@@ -1,4 +1,3 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.TopoJSON');
@@ -13,11 +12,6 @@ goog.require('ol.tilegrid');
var key = 'vector-tiles-5eJz6JX';
var attribution = [new ol.Attribution({
html: '&copy; OpenStreetMap contributors, Whos On First, Natural Earth, and openstreetmapdata.com'
})];
var format = new ol.format.TopoJSON();
var tileGrid = ol.tilegrid.createXYZ({maxZoom: 19});
var roadStyleCache = {};
var roadColor = {
'major_road': '#776',
@@ -34,30 +28,12 @@ var buildingStyle = new ol.style.Style({
width: 1
})
});
var map = new ol.Map({
layers: [
new ol.layer.VectorTile({
source: new ol.source.VectorTile({
attributions: attribution,
format: format,
tileGrid: tileGrid,
url: 'https://tile.mapzen.com/mapzen/vector/v1/water/{z}/{x}/{y}.topojson?api_key=' + key
}),
style: new ol.style.Style({
var waterStyle = new ol.style.Style({
fill: new ol.style.Fill({
color: '#9db9e8'
})
})
}),
new ol.layer.VectorTile({
source: new ol.source.VectorTile({
attributions: attribution,
format: format,
tileGrid: tileGrid,
url: 'https://tile.mapzen.com/mapzen/vector/v1/roads/{z}/{x}/{y}.topojson?api_key=' + key
}),
style: function(feature) {
});
var roadStyle = function(feature) {
var kind = feature.get('kind');
var railway = feature.get('railway');
var sort_key = feature.get('sort_key');
@@ -82,17 +58,28 @@ var map = new ol.Map({
roadStyleCache[styleKey] = style;
}
return style;
}
}),
};
var map = new ol.Map({
layers: [
new ol.layer.VectorTile({
source: new ol.source.VectorTile({
attributions: attribution,
format: format,
tileGrid: tileGrid,
url: 'https://tile.mapzen.com/mapzen/vector/v1/buildings/{z}/{x}/{y}.topojson?api_key=' + key
attributions: '&copy; OpenStreetMap contributors, Whos On First, ' +
'Natural Earth, and openstreetmapdata.com',
format: new ol.format.TopoJSON({
layerName: 'layer',
layers: ['water', 'roads', 'buildings']
}),
style: function(f, resolution) {
return (resolution < 10) ? buildingStyle : null;
tileGrid: ol.tilegrid.createXYZ({maxZoom: 19}),
url: 'https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.topojson?api_key=' + key
}),
style: function(feature, resolution) {
switch (feature.get('layer')) {
case 'water': return waterStyle;
case 'roads': return roadStyle(feature);
case 'buildings': return (resolution < 10) ? buildingStyle : null;
default: return null;
}
}
})
],

View File

@@ -18,7 +18,7 @@ var map = new ol.Map({
})
}),
view: new ol.View({
center: [-25860000, 4130000],
center: [14200000, 4130000],
rotation: Math.PI / 6,
zoom: 10
})

View File

@@ -29,6 +29,7 @@ tags: "draw, edit, modify, vector, snap"
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
<option value="Circle">Circle</option>
</select>
</div>
</form>

View File

@@ -81,6 +81,8 @@ var Draw = {
this.LineString.setActive(false);
map.addInteraction(this.Polygon);
this.Polygon.setActive(false);
map.addInteraction(this.Circle);
this.Circle.setActive(false);
},
Point: new ol.interaction.Draw({
source: vector.getSource(),
@@ -94,6 +96,10 @@ var Draw = {
source: vector.getSource(),
type: /** @type {ol.geom.GeometryType} */ ('Polygon')
}),
Circle: new ol.interaction.Draw({
source: vector.getSource(),
type: /** @type {ol.geom.GeometryType} */ ('Circle')
}),
getActive: function() {
return this.activeType ? this[this.activeType].getActive() : false;
},

View File

@@ -29,13 +29,14 @@ var style = new ol.style.Style({
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'data/topojson/world-110m.json',
format: new ol.format.TopoJSON(),
format: new ol.format.TopoJSON({
// don't want to render the full world polygon (stored as 'land' layer),
// which repeats all countries
layers: ['countries']
}),
overlaps: false
}),
style: function(feature) {
// don't want to render the full world polygon, which repeats all countries
return feature.getId() !== undefined ? style : null;
}
style: style
});
var map = new ol.Map({

View File

@@ -292,6 +292,7 @@ olx.interaction.InteractionOptions.prototype.handleEvent;
* loadTilesWhileAnimating: (boolean|undefined),
* loadTilesWhileInteracting: (boolean|undefined),
* logo: (boolean|string|olx.LogoOptions|Element|undefined),
* moveTolerance: (number|undefined),
* overlays: (ol.Collection.<ol.Overlay>|Array.<ol.Overlay>|undefined),
* renderer: (ol.renderer.Type|Array.<ol.renderer.Type>|undefined),
* target: (Element|string|undefined),
@@ -385,6 +386,17 @@ olx.MapOptions.prototype.loadTilesWhileInteracting;
olx.MapOptions.prototype.logo;
/**
* The minimum distance in pixels the cursor must move to be detected
* as a map move event instead of a click. Increasing this value can make it
* easier to click on the map.
* Default is `1`.
* @type {number|undefined}
* @api
*/
olx.MapOptions.prototype.moveTolerance;
/**
* Overlays initially added to the map. By default, no overlays are added.
* @type {ol.Collection.<ol.Overlay>|Array.<ol.Overlay>|undefined}
@@ -668,7 +680,8 @@ 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
* the `{number}` resolution at the passed coordinate.
* the `{number}` resolution at the passed coordinate. If this is `undefined`,
* the default {@link ol.proj#getPointResolution} function will be used.
* @type {(function(number, ol.Coordinate):number|undefined)}
* @api
*/
@@ -1983,7 +1996,7 @@ olx.format.MVTOptions;
* which is optimized for rendering and hit detection.
* @type {undefined|function((ol.geom.Geometry|Object.<string,*>)=)|
* function(ol.geom.GeometryType,Array.<number>,
* (Array.<number>|Array.<Array.<number>>),Object.<string, *>)}
* (Array.<number>|Array.<Array.<number>>),Object.<string,*>,number)}
* @api
*/
olx.format.MVTOptions.prototype.featureClass;
@@ -2040,7 +2053,11 @@ olx.format.PolylineOptions.prototype.geometryLayout;
/**
* @typedef {{defaultDataProjection: ol.ProjectionLike}}
* @typedef {{
* defaultDataProjection: ol.ProjectionLike,
* layerName: (string|undefined),
* layers: (Array.<string>|undefined)
* }}
*/
olx.format.TopoJSONOptions;
@@ -2053,6 +2070,38 @@ olx.format.TopoJSONOptions;
olx.format.TopoJSONOptions.prototype.defaultDataProjection;
/**
* Set the name of the TopoJSON topology `objects`'s children as feature
* property with the specified name. This means that when set to `'layer'`, a
* topology like
* ```
* {
* "type": "Topology",
* "objects": {
* "example": {
* "type": "GeometryCollection",
* "geometries": []
* }
* }
* }
* ```
* will result in features that have a property `'layer'` set to `'example'`.
* When not set, no property will be added to features.
* @type {string|undefined}
* @api
*/
olx.format.TopoJSONOptions.prototype.layerName;
/**
* Names of the TopoJSON topology's `objects`'s children to read features from.
* If not provided, features will be read from all children.
* @type {Array.<string>|undefined}
* @api
*/
olx.format.TopoJSONOptions.prototype.layers;
/**
* @typedef {{altitudeMode: (ol.format.IGCZ|undefined)}}
*/
@@ -3164,12 +3213,15 @@ olx.interaction.KeyboardZoomOptions.prototype.delta;
/**
* @typedef {{condition: (ol.EventsConditionType|undefined),
* @typedef {{
* condition: (ol.EventsConditionType|undefined),
* deleteCondition: (ol.EventsConditionType|undefined),
* insertVertexCondition: (ol.EventsConditionType|undefined),
* pixelTolerance: (number|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined),
* features: ol.Collection.<ol.Feature>,
* wrapX: (boolean|undefined)}}
* wrapX: (boolean|undefined)
* }}
*/
olx.interaction.ModifyOptions;
@@ -3196,6 +3248,16 @@ olx.interaction.ModifyOptions.prototype.condition;
olx.interaction.ModifyOptions.prototype.deleteCondition;
/**
* A function that takes an {@link ol.MapBrowserEvent} and returns a boolean
* to indicate whether a new vertex can be added to the sketch features.
* Default is {@link ol.events.condition.always}
* @type {ol.EventsConditionType|undefined}
* @api
*/
olx.interaction.ModifyOptions.prototype.insertVertexCondition;
/**
* Pixel tolerance for considering the pointer close enough to a segment or
* vertex for editing. Default is `10`.
@@ -4864,7 +4926,7 @@ olx.source.VectorTileOptions.prototype.state;
/**
* Class used to instantiate image tiles. Default is {@link ol.VectorTile}.
* Class used to instantiate vector tiles. Default is {@link ol.VectorTile}.
* @type {function(new: ol.VectorTile, ol.TileCoord,
* ol.TileState, string, ol.format.Feature,
* ol.TileLoadFunctionType)|undefined}
@@ -5991,8 +6053,9 @@ olx.source.TileArcGISRestOptions.prototype.urls;
* crossOrigin: (null|string|undefined),
* jsonp: (boolean|undefined),
* reprojectionErrorThreshold: (number|undefined),
* tileJSON: (TileJSON|undefined),
* tileLoadFunction: (ol.TileLoadFunctionType|undefined),
* url: string,
* url: (string|undefined),
* wrapX: (boolean|undefined)}}
*/
olx.source.TileJSONOptions;
@@ -6046,6 +6109,15 @@ olx.source.TileJSONOptions.prototype.jsonp;
olx.source.TileJSONOptions.prototype.reprojectionErrorThreshold;
/**
* TileJSON configuration for this source. If not provided, `url` must be
* configured.
* @type {TileJSON|undefined}
* @api
*/
olx.source.TileJSONOptions.prototype.tileJSON;
/**
* Optional function to load a tile given a URL. The default is
* ```js
@@ -6060,8 +6132,8 @@ olx.source.TileJSONOptions.prototype.tileLoadFunction;
/**
* URL to the TileJSON file.
* @type {string}
* URL to the TileJSON file. If not provided, `tileJSON` must be configured.
* @type {string|undefined}
* @api
*/
olx.source.TileJSONOptions.prototype.url;

View File

@@ -5,7 +5,6 @@
*/
/**
* @constructor
*/

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "4.1.1",
"version": "4.2.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",
@@ -31,12 +31,12 @@
"css/ol.css"
],
"dependencies": {
"async": "2.4.0",
"closure-util": "1.20.0",
"async": "2.4.1",
"closure-util": "1.21.0",
"derequire": "2.0.6",
"fs-extra": "3.0.1",
"glob": "7.1.1",
"handlebars": "4.0.8",
"handlebars": "4.0.10",
"jsdoc": "3.4.3",
"marked": "0.3.6",
"metalsmith": "2.3.0",
@@ -45,7 +45,7 @@
"pbf": "3.0.5",
"pixelworks": "1.1.0",
"rbush": "2.0.1",
"rollup": "^0.41.6",
"rollup": "^0.42.0",
"rollup-plugin-cleanup": "^1.0.0",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-node-resolve": "^3.0.0",
@@ -54,7 +54,7 @@
"walk": "2.3.9"
},
"devDependencies": {
"clean-css-cli": "4.1.0",
"clean-css-cli": "4.1.4",
"coveralls": "2.13.1",
"debounce": "^1.0.0",
"eslint": "3.19.0",
@@ -65,14 +65,14 @@
"istanbul": "0.4.5",
"jquery": "3.2.1",
"jscodeshift": "^0.3.30",
"mocha": "3.3.0",
"mocha": "3.4.2",
"mocha-phantomjs-core": "^2.1.0",
"mustache": "2.3.0",
"phantomjs-prebuilt": "2.1.14",
"proj4": "2.4.3",
"resemblejs": "2.2.4",
"serve-files": "1.0.1",
"sinon": "2.2.0",
"sinon": "2.3.4",
"slimerjs": "0.10.3"
},
"eslintConfig": {

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "4.1.1",
"version": "4.2.0",
"description": "OpenLayers as ES2015 modules",
"main": "index.js",
"module": "index.js",

View File

@@ -1,29 +0,0 @@
goog.provide('ol.Constraints');
/**
* @constructor
* @param {ol.CenterConstraintType} centerConstraint Center constraint.
* @param {ol.ResolutionConstraintType} resolutionConstraint
* Resolution constraint.
* @param {ol.RotationConstraintType} rotationConstraint
* Rotation constraint.
*/
ol.Constraints = function(centerConstraint, resolutionConstraint, rotationConstraint) {
/**
* @type {ol.CenterConstraintType}
*/
this.center = centerConstraint;
/**
* @type {ol.ResolutionConstraintType}
*/
this.resolution = resolutionConstraint;
/**
* @type {ol.RotationConstraintType}
*/
this.rotation = rotationConstraint;
};

View File

@@ -47,7 +47,7 @@ ol.control.MousePosition = function(opt_options) {
this.setCoordinateFormat(options.coordinateFormat);
}
if (options.projection) {
this.setProjection(ol.proj.get(options.projection));
this.setProjection(options.projection);
}
/**
@@ -192,13 +192,13 @@ ol.control.MousePosition.prototype.setCoordinateFormat = function(format) {
/**
* Set the projection that is used to report the mouse position.
* @param {ol.proj.Projection} projection The projection to report mouse
* @param {ol.ProjectionLike} projection The projection to report mouse
* position in.
* @observable
* @api
*/
ol.control.MousePosition.prototype.setProjection = function(projection) {
this.set(ol.control.MousePosition.Property_.PROJECTION, projection);
this.set(ol.control.MousePosition.Property_.PROJECTION, ol.proj.get(projection));
};

View File

@@ -26,6 +26,37 @@ ol.coordinate.add = function(coordinate, delta) {
};
/**
* Calculates the point closest to the passed coordinate on the passed circle.
*
* @param {ol.Coordinate} coordinate The coordinate.
* @param {ol.geom.Circle} circle The circle.
* @return {ol.Coordinate} Closest point on the circumference
*/
ol.coordinate.closestOnCircle = function(coordinate, circle) {
var r = circle.getRadius();
var center = circle.getCenter();
var x0 = center[0];
var y0 = center[1];
var x1 = coordinate[0];
var y1 = coordinate[1];
var dx = x1 - x0;
var dy = y1 - y0;
if (dx === 0 && dy === 0) {
dx = 1;
}
var d = Math.sqrt(dx * dx + dy * dy);
var x, y;
x = x0 + r * dx / d;
y = y0 + r * dy / d;
return [x, y];
};
/**
* Calculates the point closest to the passed coordinate on the passed segment.
* This is the foot of the perpendicular of the coordinate to the segment when

View File

@@ -426,8 +426,10 @@ ol.extent.forEachCorner = function(extent, callback, opt_this) {
/**
* Get the size of an extent.
* @param {ol.Extent} extent Extent.
* @return {number} Area.
* @api
*/
ol.extent.getArea = function(extent) {
var area = 0;

View File

@@ -183,14 +183,14 @@ ol.format.Feature.transformWithOptions = function(
// FIXME this is necessary because ol.format.GML treats extents
// as geometries
transformed = ol.proj.transformExtent(
write ? geometry.slice() : geometry,
write ? featureProjection : dataProjection,
write ? dataProjection : featureProjection);
geometry,
dataProjection,
featureProjection);
}
} else {
transformed = geometry;
}
if (write && opt_options && opt_options.decimals) {
if (write && opt_options && opt_options.decimals !== undefined) {
var power = Math.pow(10, opt_options.decimals);
// if decimals option on write, round each coordinate appropriately
/**
@@ -203,11 +203,10 @@ ol.format.Feature.transformWithOptions = function(
}
return coordinates;
};
if (Array.isArray(transformed)) {
transform(transformed);
} else {
transformed.applyTransform(transform);
if (transformed === geometry) {
transformed = transformed.clone();
}
transformed.applyTransform(transform);
}
return transformed;
};

View File

@@ -2,6 +2,7 @@ goog.provide('ol.format.filter');
goog.require('ol.format.filter.And');
goog.require('ol.format.filter.Bbox');
goog.require('ol.format.filter.During');
goog.require('ol.format.filter.EqualTo');
goog.require('ol.format.filter.GreaterThan');
goog.require('ol.format.filter.GreaterThanOrEqualTo');
@@ -230,3 +231,17 @@ ol.format.filter.like = function(propertyName, pattern,
return new ol.format.filter.IsLike(propertyName, pattern,
opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase);
};
/**
* Create a `<During>` temporal operator.
*
* @param {!string} propertyName Name of the context property to compare.
* @param {!string} begin The begin date in ISO-8601 format.
* @param {!string} end The end date in ISO-8601 format.
* @returns {!ol.format.filter.During} `<During>` operator.
* @api
*/
ol.format.filter.during = function(propertyName, begin, end) {
return new ol.format.filter.During(propertyName, begin, end);
};

View File

@@ -0,0 +1,33 @@
goog.provide('ol.format.filter.During');
goog.require('ol');
goog.require('ol.format.filter.Comparison');
/**
* @classdesc
* Represents a `<During>` comparison operator.
*
* @constructor
* @param {!string} propertyName Name of the context property to compare.
* @param {!string} begin The begin date in ISO-8601 format.
* @param {!string} end The end date in ISO-8601 format.
* @extends {ol.format.filter.Comparison}
* @api
*/
ol.format.filter.During = function(propertyName, begin, end) {
ol.format.filter.Comparison.call(this, 'During', propertyName);
/**
* @public
* @type {!string}
*/
this.begin = begin;
/**
* @public
* @type {!string}
*/
this.end = end;
};
ol.inherits(ol.format.filter.During, ol.format.filter.Comparison);

View File

@@ -329,7 +329,8 @@ ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
/**
* Read a feature from a GeoJSON Feature source. Only works for Feature or
* geometry types. Use {@link ol.format.GeoJSON#readFeatures} to read
* FeatureCollection source.
* FeatureCollection source. If feature at source has an id, it will be used
* as Feature id by calling {@link ol.Feature#setId} internally.
*
* @function
* @param {Document|Node|Object|string} source Source.

View File

@@ -488,7 +488,7 @@ ol.format.KML.readFlatCoordinates_ = function(node) {
*/
ol.format.KML.readURI_ = function(node) {
var s = ol.xml.getAllTextContent(node, false).trim();
if (node.baseURI) {
if (node.baseURI && node.baseURI !== 'about:blank') {
var url = new URL(s, node.baseURI);
return url.href;
} else {
@@ -1737,7 +1737,7 @@ ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) {
var style = ol.format.KML.readStyle_(node, objectStack);
if (style) {
var styleUri;
if (node.baseURI) {
if (node.baseURI && node.baseURI !== 'about:blank') {
var url = new URL('#' + id, node.baseURI);
styleUri = url.href;
} else {
@@ -1764,7 +1764,7 @@ ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) {
return;
}
var styleUri;
if (node.baseURI) {
if (node.baseURI && node.baseURI !== 'about:blank') {
var url = new URL('#' + id, node.baseURI);
styleUri = url.href;
} else {

View File

@@ -46,7 +46,7 @@ ol.format.MVT = function(opt_options) {
* @private
* @type {function((ol.geom.Geometry|Object.<string,*>)=)|
* function(ol.geom.GeometryType,Array.<number>,
* (Array.<number>|Array.<Array.<number>>),Object.<string, *>)}
* (Array.<number>|Array.<Array.<number>>),Object.<string,*>,number)}
*/
this.featureClass_ = options.featureClass ?
options.featureClass : ol.render.Feature;
@@ -137,8 +137,9 @@ ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) {
var values = rawFeature.properties;
values[this.layerName_] = layer;
var id = rawFeature.id;
return new this.featureClass_(geometryType, flatCoordinates, ends, values);
return new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
};

View File

@@ -10,7 +10,6 @@ goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.obj');
goog.require('ol.proj');
@@ -29,6 +28,18 @@ ol.format.TopoJSON = function(opt_options) {
ol.format.JSONFeature.call(this);
/**
* @private
* @type {string|undefined}
*/
this.layerName_ = options.layerName;
/**
* @private
* @type {Array.<string>}
*/
this.layers_ = options.layers ? options.layers : null;
/**
* @inheritDoc
*/
@@ -202,18 +213,21 @@ ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) {
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {string|undefined} property Property to set the `GeometryCollection`'s parent
* object to.
* @param {string} name Name of the `Topology`'s child object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(
collection, arcs, scale, translate, opt_options) {
collection, arcs, scale, translate, property, name, opt_options) {
var geometries = collection.geometries;
var features = [];
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
features[i] = ol.format.TopoJSON.readFeatureFromGeometry_(
geometries[i], arcs, scale, translate, opt_options);
geometries[i], arcs, scale, translate, property, name, opt_options);
}
return features;
};
@@ -226,12 +240,15 @@ ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {string|undefined} property Property to set the `GeometryCollection`'s parent
* object to.
* @param {string} name Name of the `Topology`'s child object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @private
*/
ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,
scale, translate, opt_options) {
scale, translate, property, name, opt_options) {
var geometry;
var type = object.type;
var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type];
@@ -246,8 +263,15 @@ ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,
if (object.id !== undefined) {
feature.setId(object.id);
}
if (object.properties) {
feature.setProperties(object.properties);
var properties = object.properties;
if (property) {
if (!properties) {
properties = {};
}
properties[property] = name;
}
if (properties) {
feature.setProperties(properties);
}
return feature;
};
@@ -283,21 +307,24 @@ ol.format.TopoJSON.prototype.readFeaturesFromObject = function(
}
/** @type {Array.<ol.Feature>} */
var features = [];
var topoJSONFeatures = ol.obj.getValues(topoJSONTopology.objects);
var i, ii;
var feature;
for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) {
if (topoJSONFeatures[i].type === 'GeometryCollection') {
var topoJSONFeatures = topoJSONTopology.objects;
var property = this.layerName_;
var objectName, feature;
for (objectName in topoJSONFeatures) {
if (this.layers_ && this.layers_.indexOf(objectName) == -1) {
continue;
}
if (topoJSONFeatures[objectName].type === 'GeometryCollection') {
feature = /** @type {TopoJSONGeometryCollection} */
(topoJSONFeatures[i]);
(topoJSONFeatures[objectName]);
features.push.apply(features,
ol.format.TopoJSON.readFeaturesFromGeometryCollection_(
feature, arcs, scale, translate, opt_options));
feature, arcs, scale, translate, property, objectName, opt_options));
} else {
feature = /** @type {TopoJSONGeometry} */
(topoJSONFeatures[i]);
(topoJSONFeatures[objectName]);
features.push(ol.format.TopoJSON.readFeatureFromGeometry_(
feature, arcs, scale, translate, opt_options));
feature, arcs, scale, translate, property, objectName, opt_options));
}
}
return features;

View File

@@ -90,6 +90,13 @@ ol.format.WFS.OGCNS = 'http://www.opengis.net/ogc';
ol.format.WFS.WFSNS = 'http://www.opengis.net/wfs';
/**
* @const
* @type {string}
*/
ol.format.WFS.FESNS = 'http://www.opengis.net/fes';
/**
* @const
* @type {Object.<string, string>}
@@ -646,6 +653,32 @@ ol.format.WFS.writeWithinFilter_ = function(node, filter, objectStack) {
};
/**
* @param {Node} node Node.
* @param {ol.format.filter.During} filter Filter.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeDuringFilter_ = function(node, filter, objectStack) {
var valueReference = ol.xml.createElementNS(ol.format.WFS.FESNS, 'ValueReference');
ol.format.XSD.writeStringTextNode(valueReference, filter.propertyName);
node.appendChild(valueReference);
var timePeriod = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'TimePeriod');
node.appendChild(timePeriod);
var begin = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'begin');
timePeriod.appendChild(begin);
ol.format.WFS.writeTimeInstant_(begin, filter.begin);
var end = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'end');
timePeriod.appendChild(end);
ol.format.WFS.writeTimeInstant_(end, filter.end);
};
/**
* @param {Node} node Node.
* @param {ol.format.filter.LogicalNary} filter Filter.
@@ -777,6 +810,21 @@ ol.format.WFS.writeOgcLiteral_ = function(node, value) {
};
/**
* @param {Node} node Node.
* @param {string} time PropertyName value.
* @private
*/
ol.format.WFS.writeTimeInstant_ = function(node, time) {
var timeInstant = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'TimeInstant');
node.appendChild(timeInstant);
var timePosition = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'timePosition');
timeInstant.appendChild(timePosition);
ol.format.XSD.writeStringTextNode(timePosition, time);
};
/**
* @type {Object.<string, Object.<string, ol.XmlSerializer>>}
* @private
@@ -786,6 +834,7 @@ ol.format.WFS.GETFEATURE_SERIALIZERS_ = {
'Query': ol.xml.makeChildAppender(ol.format.WFS.writeQuery_)
},
'http://www.opengis.net/ogc': {
'During': ol.xml.makeChildAppender(ol.format.WFS.writeDuringFilter_),
'And': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
'Or': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
'Not': ol.xml.makeChildAppender(ol.format.WFS.writeNotFilter_),

View File

@@ -73,7 +73,7 @@ ol.Geolocation = function(opt_options) {
this.handleTrackingChanged_, this);
if (options.projection !== undefined) {
this.setProjection(ol.proj.get(options.projection));
this.setProjection(options.projection);
}
if (options.trackingOptions !== undefined) {
this.setTrackingOptions(options.trackingOptions);
@@ -308,13 +308,13 @@ ol.Geolocation.prototype.getTrackingOptions = function() {
/**
* Set the projection to use for transforming the coordinates.
* @param {ol.proj.Projection} projection The projection the position is
* @param {ol.ProjectionLike} projection The projection the position is
* reported in.
* @observable
* @api
*/
ol.Geolocation.prototype.setProjection = function(projection) {
this.set(ol.GeolocationProperty.PROJECTION, projection);
this.set(ol.GeolocationProperty.PROJECTION, ol.proj.get(projection));
};

View File

@@ -70,8 +70,8 @@ ol.ImageTile.prototype.disposeInternal = function() {
/**
* Get the image element for this tile.
* @inheritDoc
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
* @api
*/
ol.ImageTile.prototype.getImage = function() {
@@ -94,6 +94,7 @@ ol.ImageTile.prototype.getKey = function() {
*/
ol.ImageTile.prototype.handleImageError_ = function() {
this.state = ol.TileState.ERROR;
this.image_ = ol.ImageTile.blankImage;
this.unlistenImage_();
this.changed();
};
@@ -143,3 +144,11 @@ ol.ImageTile.prototype.unlistenImage_ = function() {
this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
this.imageListenerKeys_ = null;
};
/**
* A blank image.
* @type {Image}
*/
ol.ImageTile.blankImage = new Image();
ol.ImageTile.blankImage.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

View File

@@ -141,14 +141,10 @@ ol.interaction.DragAndDrop.handleEvent = ol.functions.TRUE;
/**
* @inheritDoc
* @private
*/
ol.interaction.DragAndDrop.prototype.setMap = function(map) {
if (this.dropListenKeys_) {
this.dropListenKeys_.forEach(ol.events.unlistenByKey);
this.dropListenKeys_ = null;
}
ol.interaction.Interaction.prototype.setMap.call(this, map);
ol.interaction.DragAndDrop.prototype.registerListeners_ = function() {
var map = this.getMap();
if (map) {
var dropArea = this.target ? this.target : map.getViewport();
this.dropListenKeys_ = [
@@ -165,6 +161,31 @@ ol.interaction.DragAndDrop.prototype.setMap = function(map) {
};
/**
* @inheritDoc
*/
ol.interaction.DragAndDrop.prototype.setActive = function(active) {
ol.interaction.Interaction.prototype.setActive.call(this, active);
if (active) {
this.registerListeners_();
} else {
this.unregisterListeners_();
}
};
/**
* @inheritDoc
*/
ol.interaction.DragAndDrop.prototype.setMap = function(map) {
this.unregisterListeners_();
ol.interaction.Interaction.prototype.setMap.call(this, map);
if (this.getActive()) {
this.registerListeners_();
}
};
/**
* @param {ol.format.Feature} format Format.
* @param {string} text Text.
@@ -181,6 +202,17 @@ ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text, o
};
/**
* @private
*/
ol.interaction.DragAndDrop.prototype.unregisterListeners_ = function() {
if (this.dropListenKeys_) {
this.dropListenKeys_.forEach(ol.events.unlistenByKey);
this.dropListenKeys_ = null;
}
};
/**
* @enum {string}
* @private

View File

@@ -1,6 +1,7 @@
goog.provide('ol.interaction.DragRotate');
goog.require('ol');
goog.require('ol.RotationConstraint');
goog.require('ol.ViewHint');
goog.require('ol.events.condition');
goog.require('ol.functions');
@@ -64,13 +65,16 @@ ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) {
}
var map = mapBrowserEvent.map;
var view = map.getView();
if (view.getConstraints().rotation === ol.RotationConstraint.disable) {
return;
}
var size = map.getSize();
var offset = mapBrowserEvent.pixel;
var theta =
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
if (this.lastAngle_ !== undefined) {
var delta = theta - this.lastAngle_;
var view = map.getView();
var rotation = view.getRotation();
ol.interaction.Interaction.rotateWithoutConstraints(
view, rotation - delta);

View File

@@ -1,6 +1,7 @@
goog.provide('ol.interaction.DragRotateAndZoom');
goog.require('ol');
goog.require('ol.RotationConstraint');
goog.require('ol.ViewHint');
goog.require('ol.events.condition');
goog.require('ol.interaction.Interaction');
@@ -85,7 +86,7 @@ ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) {
var theta = Math.atan2(deltaY, deltaX);
var magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var view = map.getView();
if (this.lastAngle_ !== undefined) {
if (view.getConstraints().rotation !== ol.RotationConstraint.disable && this.lastAngle_ !== undefined) {
var angleDelta = theta - this.lastAngle_;
ol.interaction.Interaction.rotateWithoutConstraints(
view, view.getRotation() - angleDelta);

View File

@@ -127,7 +127,7 @@ ol.interaction.Draw = function(options) {
if (!geometryFunction) {
if (this.type_ === ol.geom.GeometryType.CIRCLE) {
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {!Array.<ol.Coordinate>} coordinates
* The coordinates.
* @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
* @return {ol.geom.SimpleGeometry} A geometry.
@@ -151,7 +151,7 @@ ol.interaction.Draw = function(options) {
Constructor = ol.geom.Polygon;
}
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {!Array.<ol.Coordinate>} coordinates
* The coordinates.
* @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
* @return {ol.geom.SimpleGeometry} A geometry.
@@ -529,9 +529,7 @@ ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
}
last[0] = coordinate[0];
last[1] = coordinate[1];
this.geometryFunction_(
/** @type {!ol.Coordinate|!Array.<ol.Coordinate>|!Array.<Array.<ol.Coordinate>>} */ (this.sketchCoords_),
geometry);
this.geometryFunction_(/** @type {!Array.<ol.Coordinate>} */ (this.sketchCoords_), geometry);
if (this.sketchPoint_) {
var sketchPointGeom = /** @type {ol.geom.Point} */ (this.sketchPoint_.getGeometry());
sketchPointGeom.setCoordinates(coordinate);
@@ -800,7 +798,7 @@ ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) {
ol.interaction.Draw.createBox = function() {
return (
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {Array.<ol.Coordinate>} coordinates
* @param {ol.geom.SimpleGeometry=} opt_geometry
* @return {ol.geom.SimpleGeometry}
*/

View File

@@ -67,6 +67,13 @@ ol.interaction.Modify = function(options) {
this.deleteCondition_ = options.deleteCondition ?
options.deleteCondition : this.defaultDeleteCondition_;
/**
* @type {ol.EventsConditionType}
* @private
*/
this.insertVertexCondition_ = options.insertVertexCondition ?
options.insertVertexCondition : ol.events.condition.always;
/**
* Editing vertex.
* @type {ol.Feature}
@@ -600,7 +607,7 @@ ol.interaction.Modify.handleDownEvent_ = function(evt) {
this.dragSegments_.push([segmentDataMatch, 1]);
componentSegments[uid][1] = segmentDataMatch;
} else if (ol.getUid(segment) in this.vertexSegments_ &&
} else if (this.insertVertexCondition_(evt) && ol.getUid(segment) in this.vertexSegments_ &&
(!componentSegments[uid][0] && !componentSegments[uid][1])) {
insertVertices.push([segmentDataMatch, vertex]);
}

View File

@@ -5,6 +5,7 @@ goog.require('ol.ViewHint');
goog.require('ol.functions');
goog.require('ol.interaction.Interaction');
goog.require('ol.interaction.Pointer');
goog.require('ol.RotationConstraint');
/**
@@ -95,6 +96,10 @@ ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
this.lastAngle_ = angle;
var map = mapBrowserEvent.map;
var view = map.getView();
if (view.getConstraints().rotation === ol.RotationConstraint.disable) {
return;
}
// rotate anchor point.
// FIXME: should be the intersection point between the lines:
@@ -107,7 +112,6 @@ ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
// rotate
if (this.rotating_) {
var view = map.getView();
var rotation = view.getRotation();
map.render();
ol.interaction.Interaction.rotateWithoutConstraints(view,

View File

@@ -8,6 +8,8 @@ goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.extent');
goog.require('ol.functions');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Pointer');
goog.require('ol.obj');
goog.require('ol.source.Vector');
@@ -142,7 +144,8 @@ ol.interaction.Snap = function(opt_options) {
'MultiPoint': this.writeMultiPointGeometry_,
'MultiLineString': this.writeMultiLineStringGeometry_,
'MultiPolygon': this.writeMultiPolygonGeometry_,
'GeometryCollection': this.writeGeometryCollectionGeometry_
'GeometryCollection': this.writeGeometryCollectionGeometry_,
'Circle': this.writeCircleGeometry_
};
};
ol.inherits(ol.interaction.Snap, ol.interaction.Pointer);
@@ -345,6 +348,15 @@ ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {
var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
var segments = this.rBush_.getInExtent(box);
// If snapping on vertices only, don't consider circles
if (this.vertex_ && !this.edge_) {
segments = segments.filter(function(segment) {
return segment.feature.getGeometry().getType() !==
ol.geom.GeometryType.CIRCLE;
});
}
var snappedToVertex = false;
var snapped = false;
var vertex = null;
@@ -354,6 +366,8 @@ ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {
this.pixelCoordinate_ = pixelCoordinate;
segments.sort(this.sortByDistance_);
var closestSegment = segments[0].segment;
var isCircle = segments[0].feature.getGeometry().getType() ===
ol.geom.GeometryType.CIRCLE;
if (this.vertex_ && !this.edge_) {
pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
@@ -368,12 +382,17 @@ ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {
vertexPixel = map.getPixelFromCoordinate(vertex);
}
} else if (this.edge_) {
if (isCircle) {
vertex = ol.coordinate.closestOnCircle(pixelCoordinate,
/** @type {ol.geom.Circle} */ (segments[0].feature.getGeometry()));
} else {
vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,
closestSegment));
}
vertexPixel = map.getPixelFromCoordinate(vertex);
if (ol.coordinate.distance(pixel, vertexPixel) <= this.pixelTolerance_) {
snapped = true;
if (this.vertex_) {
if (this.vertex_ && !isCircle) {
pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
@@ -410,6 +429,26 @@ ol.interaction.Snap.prototype.updateFeature_ = function(feature) {
};
/**
* @param {ol.Feature} feature Feature
* @param {ol.geom.Circle} geometry Geometry.
* @private
*/
ol.interaction.Snap.prototype.writeCircleGeometry_ = function(feature, geometry) {
var polygon = ol.geom.Polygon.fromCircle(geometry);
var coordinates = polygon.getCoordinates()[0];
var i, ii, segment, segmentData;
for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
segment = coordinates.slice(i, i + 2);
segmentData = /** @type {ol.SnapSegmentDataType} */ ({
feature: feature,
segment: segment
});
this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
}
};
/**
* @param {ol.Feature} feature Feature
* @param {ol.geom.GeometryCollection} geometry Geometry.

View File

@@ -32,13 +32,6 @@ ol.interaction.Translate = function(opt_options) {
var options = opt_options ? opt_options : {};
/**
* @type {string|undefined}
* @private
*/
this.previousCursor_ = undefined;
/**
* The last position we translated to.
* @type {ol.Coordinate}
@@ -175,23 +168,15 @@ ol.interaction.Translate.handleDragEvent_ = function(event) {
* @private
*/
ol.interaction.Translate.handleMoveEvent_ = function(event) {
var elem = event.map.getTargetElement();
var elem = event.map.getViewport();
// Change the cursor to grab/grabbing if hovering any of the features managed
// by the interaction
if (this.featuresAtPixel_(event.pixel, event.map)) {
this.previousCursor_ = this.previousCursor_ !== undefined ?
this.previousCursor_ : elem.style.cursor;
// WebKit browsers don't support the grab icons without a prefix
elem.style.cursor = this.lastCoordinate_ ?
'-webkit-grabbing' : '-webkit-grab';
// Thankfully, attempting to set the standard ones will silently fail,
// keeping the prefixed icons
elem.style.cursor = this.lastCoordinate_ ? 'grabbing' : 'grab';
} else if (this.previousCursor_ !== undefined) {
elem.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
elem.classList.remove(this.lastCoordinate_ ? 'ol-grab' : 'ol-grabbing');
elem.classList.add(this.lastCoordinate_ ? 'ol-grabbing' : 'ol-grab');
} else {
elem.classList.remove('ol-grab', 'ol-grabbing');
}
};
@@ -266,14 +251,13 @@ ol.interaction.Translate.prototype.handleActiveChanged_ = function() {
ol.interaction.Translate.prototype.updateState_ = function(oldMap) {
var map = this.getMap();
var active = this.getActive();
if ((!map || !active) && this.previousCursor_ !== undefined) {
if ((!map || !active)) {
if (!map) {
map = oldMap;
}
var elem = map.getTargetElement();
elem.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
var elem = map.getViewport();
elem.classList.remove('ol-grab', 'ol-grabbing');
}
};

View File

@@ -94,7 +94,15 @@ ol.Kinetic.prototype.end = function() {
while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
firstIndex -= 3;
}
var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
// we don't want a duration of 0 (divide by zero)
// we also make sure the user panned for a duration of at least one frame
// (1/60s) to compute sane displacement values
if (duration < 1000 / 60) {
return false;
}
var dx = this.points_[lastIndex] - this.points_[firstIndex];
var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
this.angle_ = Math.atan2(dy, dx);

View File

@@ -210,7 +210,7 @@ ol.Map = function(options) {
* @private
* @type {ol.Extent}
*/
this.previousExtent_ = ol.extent.createEmpty();
this.previousExtent_ = null;
/**
* @private
@@ -278,7 +278,7 @@ ol.Map = function(options) {
* @private
* @type {ol.MapBrowserEventHandler}
*/
this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this);
this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this, options.moveTolerance);
for (var key in ol.MapBrowserEventType) {
ol.events.listen(this.mapBrowserEventHandler_, ol.MapBrowserEventType[key],
this.handleMapBrowserEvent, this);
@@ -1200,6 +1200,7 @@ ol.Map.prototype.renderFrame_ = function(time) {
var size = this.getSize();
var view = this.getView();
var extent = ol.extent.createEmpty();
var previousFrameState = this.frameState_;
/** @type {?olx.FrameState} */
var frameState = null;
if (size !== undefined && ol.size.hasArea(size) && view && view.isDef()) {
@@ -1249,7 +1250,19 @@ ol.Map.prototype.renderFrame_ = function(time) {
Array.prototype.push.apply(
this.postRenderFunctions_, frameState.postRenderFunctions);
var idle = !frameState.viewHints[ol.ViewHint.ANIMATING] &&
if (previousFrameState) {
var moveStart = !this.previousExtent_ ||
(!ol.extent.isEmpty(this.previousExtent_) &&
!ol.extent.equals(frameState.extent, this.previousExtent_));
if (moveStart) {
this.dispatchEvent(
new ol.MapEvent(ol.MapEventType.MOVESTART, this, previousFrameState));
this.previousExtent_ = ol.extent.createOrUpdateEmpty(this.previousExtent_);
}
}
var idle = this.previousExtent_ &&
!frameState.viewHints[ol.ViewHint.ANIMATING] &&
!frameState.viewHints[ol.ViewHint.INTERACTING] &&
!ol.extent.equals(frameState.extent, this.previousExtent_);

View File

@@ -1,6 +1,7 @@
goog.provide('ol.MapBrowserEventHandler');
goog.require('ol');
goog.require('ol.has');
goog.require('ol.MapBrowserEventType');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.events');
@@ -11,10 +12,11 @@ goog.require('ol.pointer.PointerEventHandler');
/**
* @param {ol.Map} map The map with the viewport to listen to events on.
* @param {number|undefined} moveTolerance The minimal distance the pointer must travel to trigger a move.
* @constructor
* @extends {ol.events.EventTarget}
*/
ol.MapBrowserEventHandler = function(map) {
ol.MapBrowserEventHandler = function(map, moveTolerance) {
ol.events.EventTarget.call(this);
@@ -43,6 +45,13 @@ ol.MapBrowserEventHandler = function(map) {
*/
this.dragListenerKeys_ = [];
/**
* @type {number}
* @private
*/
this.moveTolerance_ = moveTolerance ?
moveTolerance * ol.has.DEVICE_PIXEL_RATIO : ol.has.DEVICE_PIXEL_RATIO;
/**
* The most recent "down" type event (or null if none have occurred).
* Set on pointerdown.
@@ -241,11 +250,9 @@ ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent)
* @private
*/
ol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {
// Fix IE10 on windows Surface : When you tap the tablet, it triggers
// multiple pointermove events between pointerdown and pointerup with
// the exact same coordinates of the pointerdown event. To avoid a
// 'false' touchmove event to be dispatched , we test if the pointer
// effectively moved.
// Between pointerdown and pointerup, pointermove events are triggered.
// To avoid a 'false' touchmove event to be dispatched, we test if the pointer
// moved a significant distance.
if (this.isMoving_(pointerEvent)) {
this.dragging_ = true;
var newEvent = new ol.MapBrowserPointerEvent(
@@ -281,8 +288,8 @@ ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {
* @private
*/
ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {
return pointerEvent.clientX != this.down_.clientX ||
pointerEvent.clientY != this.down_.clientY;
return Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ ||
Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;
};

View File

@@ -12,6 +12,13 @@ ol.MapEventType = {
*/
POSTRENDER: 'postrender',
/**
* Triggered when the map starts moving.
* @event ol.MapEvent#movestart
* @api
*/
MOVESTART: 'movestart',
/**
* Triggered after the map is moved.
* @event ol.MapEvent#moveend

View File

@@ -31,17 +31,6 @@ ol.pointer.EventSource.prototype.getEvents = function() {
};
/**
* Returns a mapping between the supported event types and
* the handlers that should handle an event.
* @return {Object.<string, function(Event)>}
* Event/Handler mapping
*/
ol.pointer.EventSource.prototype.getMapping = function() {
return this.mapping_;
};
/**
* Returns the handler that should handle a given event type.
* @param {string} eventType The event type.

View File

@@ -44,16 +44,22 @@ if (ol.ENABLE_PROJ4JS) {
* Get the resolution of the point in degrees or distance units.
* For projections with degrees as the unit this will simply return the
* provided resolution. For other projections the point resolution is
* estimated by transforming the 'point' pixel to EPSG:4326,
* by default estimated by transforming the 'point' pixel to EPSG:4326,
* measuring its width and height on the normal sphere,
* and taking the average of the width and height.
* @param {ol.proj.Projection} projection The projection.
* A custom function can be provided for a specific projection, either
* by setting the `getPointResolution` option in the
* {@link ol.proj.Projection} constructor or by using
* {@link ol.proj.Projection#setGetPointResolution} to change an existing
* projection object.
* @param {ol.ProjectionLike} projection The projection.
* @param {number} resolution Nominal resolution in projection units.
* @param {ol.Coordinate} point Point to find adjusted resolution at.
* @return {number} Point resolution at point in projection units.
* @api
*/
ol.proj.getPointResolution = function(projection, resolution, point) {
projection = ol.proj.get(projection);
var pointResolution;
var getter = projection.getPointResolutionFunc();
if (getter) {
@@ -148,10 +154,7 @@ ol.proj.addProjection = function(projection) {
* @param {Array.<ol.proj.Projection>} projections Projections.
*/
ol.proj.addProjections = function(projections) {
var addedProjections = [];
projections.forEach(function(projection) {
addedProjections.push(ol.proj.addProjection(projection));
});
projections.forEach(ol.proj.addProjection);
};

View File

@@ -254,7 +254,8 @@ ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) {
/**
* Set the getPointResolution function for this projection.
* Set the getPointResolution function (see {@link ol.proj#getPointResolution}
* for this projection.
* @param {function(number, ol.Coordinate):number} func Function
* @api
*/

View File

@@ -16,14 +16,21 @@ goog.require('ol.geom.GeometryType');
* to be right-handed for polygons.
* @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss.
* @param {Object.<string, *>} properties Properties.
* @param {number|string|undefined} id Feature id.
*/
ol.render.Feature = function(type, flatCoordinates, ends, properties) {
ol.render.Feature = function(type, flatCoordinates, ends, properties, id) {
/**
* @private
* @type {ol.Extent|undefined}
*/
this.extent_;
/**
* @private
* @type {number|string|undefined}
*/
this.id_ = id;
/**
* @private
* @type {ol.geom.GeometryType}
@@ -85,6 +92,16 @@ ol.render.Feature.prototype.getExtent = function() {
return this.extent_;
};
/**
* Get the feature identifier. This is a stable identifier for the feature and
* is set when reading data from a remote source.
* @return {number|string|undefined} Id.
* @api
*/
ol.render.Feature.prototype.getId = function() {
return this.id_;
};
/**
* @return {Array.<number>} Flat coordinates.
@@ -102,7 +119,8 @@ ol.render.Feature.prototype.getFlatCoordinates =
/**
* Get the feature for working with its geometry.
* For API compatibility with {@link ol.Feature}, this method is useful when
* determining the geometry type in style function (see {@link #getType}).
* @return {ol.render.Feature} Feature.
* @api
*/

View File

@@ -324,16 +324,19 @@ if (ol.ENABLE_WEBGL) {
*/
ol.render.webgl.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {
var indexCount = this.indices.length;
var lineStringGeometries = multiLineStringGeometry.getLineStrings();
var ends = multiLineStringGeometry.getEnds();
ends.unshift(0);
var flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
var stride = multiLineStringGeometry.getStride();
var i, ii;
for (i = 0, ii = lineStringGeometries.length; i < ii; ++i) {
var flatCoordinates = lineStringGeometries[i].getFlatCoordinates();
var stride = lineStringGeometries[i].getStride();
if (this.isValid_(flatCoordinates, 0, flatCoordinates.length, stride)) {
flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,
if (ends.length > 1) {
for (i = 1, ii = ends.length; i < ii; ++i) {
if (this.isValid_(flatCoordinates, ends[i - 1], ends[i], stride)) {
var lineString = ol.geom.flat.transform.translate(flatCoordinates, ends[i - 1], ends[i],
stride, -this.origin[0], -this.origin[1]);
this.drawCoordinates_(
flatCoordinates, 0, flatCoordinates.length, stride);
lineString, 0, lineString.length, stride);
}
}
}
if (this.indices.length > indexCount) {

View File

@@ -88,20 +88,39 @@ if (ol.ENABLE_WEBGL) {
for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) {
var holeList = {
list: new ol.structs.LinkedList(),
maxX: undefined
maxX: undefined,
rtree: new ol.structs.RBush()
};
holeLists.push(holeList);
holeList.maxX = this.processFlatCoordinates_(holeFlatCoordinates[i],
stride, holeList.list, rtree, false);
stride, holeList.list, holeList.rtree, false);
}
holeLists.sort(function(a, b) {
return b.maxX - a.maxX;
return b.maxX[0] === a.maxX[0] ? a.maxX[1] - b.maxX[1] : b.maxX[0] - a.maxX[0];
});
for (i = 0; i < holeLists.length; ++i) {
this.bridgeHole_(holeLists[i].list, holeLists[i].maxX, outerRing, maxX, rtree);
}
var currList = holeLists[i].list;
var start = currList.firstItem();
var currItem = start;
var intersection;
do {
if (this.getIntersections_(currItem, rtree).length) {
intersection = true;
break;
}
currItem = currList.nextItem();
} while (start !== currItem);
if (!intersection) {
this.classifyPoints_(currList, holeLists[i].rtree, true);
if (this.bridgeHole_(currList, holeLists[i].maxX[0], outerRing, maxX[0], rtree)) {
rtree.concat(holeLists[i].rtree);
this.classifyPoints_(outerRing, rtree, false);
}
}
}
} else {
this.classifyPoints_(outerRing, rtree, false);
}
this.triangulate_(outerRing, rtree);
};
@@ -114,13 +133,13 @@ if (ol.ENABLE_WEBGL) {
* @param {ol.structs.LinkedList} list Linked list.
* @param {ol.structs.RBush} rtree R-Tree of the polygon.
* @param {boolean} clockwise Coordinate order should be clockwise.
* @return {number} Maximum X value.
* @return {Array.<number>} X and Y coords of maximum X value.
*/
ol.render.webgl.PolygonReplay.prototype.processFlatCoordinates_ = function(
flatCoordinates, stride, list, rtree, clockwise) {
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(flatCoordinates,
0, flatCoordinates.length, stride);
var i, ii, maxX;
var i, ii, maxXX, maxXY;
var n = this.vertices.length / 2;
/** @type {ol.WebglPolygonVertex} */
var start;
@@ -133,13 +152,17 @@ if (ol.ENABLE_WEBGL) {
if (clockwise === isClockwise) {
start = this.createPoint_(flatCoordinates[0], flatCoordinates[1], n++);
p0 = start;
maxX = flatCoordinates[0];
maxXX = flatCoordinates[0];
maxXY = flatCoordinates[1];
for (i = stride, ii = flatCoordinates.length; i < ii; i += stride) {
p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);
segments.push(this.insertItem_(p0, p1, list));
extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
Math.max(p0.y, p1.y)]);
maxX = flatCoordinates[i] > maxX ? flatCoordinates[i] : maxX;
if (flatCoordinates[i] > maxXX) {
maxXX = flatCoordinates[i];
maxXY = flatCoordinates[i + 1];
}
p0 = p1;
}
segments.push(this.insertItem_(p1, start, list));
@@ -149,13 +172,17 @@ if (ol.ENABLE_WEBGL) {
var end = flatCoordinates.length - stride;
start = this.createPoint_(flatCoordinates[end], flatCoordinates[end + 1], n++);
p0 = start;
maxX = flatCoordinates[end];
maxXX = flatCoordinates[end];
maxXY = flatCoordinates[end + 1];
for (i = end - stride, ii = 0; i >= ii; i -= stride) {
p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);
segments.push(this.insertItem_(p0, p1, list));
extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
Math.max(p0.y, p1.y)]);
maxX = flatCoordinates[i] > maxX ? flatCoordinates[i] : maxX;
if (flatCoordinates[i] > maxXX) {
maxXX = flatCoordinates[i];
maxXY = flatCoordinates[i + 1];
}
p0 = p1;
}
segments.push(this.insertItem_(p1, start, list));
@@ -164,7 +191,7 @@ if (ol.ENABLE_WEBGL) {
}
rtree.load(extents, segments);
return maxX;
return [maxXX, maxXY];
};
@@ -212,10 +239,10 @@ if (ol.ENABLE_WEBGL) {
* @param {ol.structs.LinkedList} list Linked list of the polygon.
* @param {number} listMaxX Maximum X value of the polygon.
* @param {ol.structs.RBush} rtree R-Tree of the polygon.
* @return {boolean} Bridging was successful.
*/
ol.render.webgl.PolygonReplay.prototype.bridgeHole_ = function(hole, holeMaxX,
list, listMaxX, rtree) {
this.classifyPoints_(hole, rtree, true);
var seg = hole.firstItem();
while (seg.p1.x !== holeMaxX) {
seg = hole.nextItem();
@@ -232,19 +259,18 @@ if (ol.ENABLE_WEBGL) {
var intersectingSegments = this.getIntersections_({p0: p1, p1: p2}, rtree, true);
for (i = 0, ii = intersectingSegments.length; i < ii; ++i) {
var currSeg = intersectingSegments[i];
if (currSeg.p0.reflex === undefined) {
var intersection = this.calculateIntersection_(p1, p2, currSeg.p0,
currSeg.p1, true);
var dist = Math.abs(p1.x - intersection[0]);
if (dist < minDist) {
if (dist < minDist && ol.render.webgl.triangleIsCounterClockwise(p1.x, p1.y,
currSeg.p0.x, currSeg.p0.y, currSeg.p1.x, currSeg.p1.y) !== undefined) {
minDist = dist;
p5 = {x: intersection[0], y: intersection[1], i: -1};
seg = currSeg;
}
}
}
if (minDist === Infinity) {
return;
return false;
}
bestPoint = seg.p1;
@@ -264,7 +290,7 @@ if (ol.ENABLE_WEBGL) {
}
seg = list.firstItem();
while (seg.p1 !== bestPoint) {
while (seg.p1.x !== bestPoint.x || seg.p1.y !== bestPoint.y) {
seg = list.nextItem();
}
@@ -278,6 +304,8 @@ if (ol.ENABLE_WEBGL) {
seg.p1 = p1Bridge;
hole.setFirstItem();
list.concat(hole);
return true;
};
@@ -712,28 +740,33 @@ if (ol.ENABLE_WEBGL) {
* @inheritDoc
*/
ol.render.webgl.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
var polygons = multiPolygonGeometry.getPolygons();
var endss = multiPolygonGeometry.getEndss();
var stride = multiPolygonGeometry.getStride();
var currIndex = this.indices.length;
var currLineIndex = this.lineStringReplay.getCurrentIndex();
var flatCoordinates = multiPolygonGeometry.getFlatCoordinates();
var i, ii, j, jj;
for (i = 0, ii = polygons.length; i < ii; ++i) {
var linearRings = polygons[i].getLinearRings();
if (linearRings.length > 0) {
var flatCoordinates = linearRings[0].getFlatCoordinates();
flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,
var start = 0;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
if (ends.length > 0) {
var outerRing = ol.geom.flat.transform.translate(flatCoordinates, start, ends[0],
stride, -this.origin[0], -this.origin[1]);
if (outerRing.length) {
var holes = [];
var holeFlatCoords;
for (j = 1, jj = linearRings.length; j < jj; ++j) {
holeFlatCoords = linearRings[j].getFlatCoordinates();
holeFlatCoords = ol.geom.flat.transform.translate(holeFlatCoords, 0, holeFlatCoords.length,
stride, -this.origin[0], -this.origin[1]);
for (j = 1, jj = ends.length; j < jj; ++j) {
if (ends[j] !== ends[j - 1]) {
holeFlatCoords = ol.geom.flat.transform.translate(flatCoordinates, ends[j - 1],
ends[j], stride, -this.origin[0], -this.origin[1]);
holes.push(holeFlatCoords);
}
this.lineStringReplay.drawPolygonCoordinates(flatCoordinates, holes, stride);
this.drawCoordinates_(flatCoordinates, holes, stride);
}
this.lineStringReplay.drawPolygonCoordinates(outerRing, holes, stride);
this.drawCoordinates_(outerRing, holes, stride);
}
}
start = ends[ends.length - 1];
}
if (this.indices.length > currIndex) {
this.startIndices.push(currIndex);
@@ -753,9 +786,23 @@ if (ol.ENABLE_WEBGL) {
* @inheritDoc
*/
ol.render.webgl.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
var linearRings = polygonGeometry.getLinearRings();
var ends = polygonGeometry.getEnds();
var stride = polygonGeometry.getStride();
if (linearRings.length > 0) {
if (ends.length > 0) {
var flatCoordinates = polygonGeometry.getFlatCoordinates().map(Number);
var outerRing = ol.geom.flat.transform.translate(flatCoordinates, 0, ends[0],
stride, -this.origin[0], -this.origin[1]);
if (outerRing.length) {
var holes = [];
var i, ii, holeFlatCoords;
for (i = 1, ii = ends.length; i < ii; ++i) {
if (ends[i] !== ends[i - 1]) {
holeFlatCoords = ol.geom.flat.transform.translate(flatCoordinates, ends[i - 1],
ends[i], stride, -this.origin[0], -this.origin[1]);
holes.push(holeFlatCoords);
}
}
this.startIndices.push(this.indices.length);
this.startIndicesFeature.push(feature);
if (this.state_.changed) {
@@ -764,19 +811,9 @@ if (ol.ENABLE_WEBGL) {
}
this.lineStringReplay.setPolygonStyle(feature);
var flatCoordinates = linearRings[0].getFlatCoordinates();
flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,
stride, -this.origin[0], -this.origin[1]);
var holes = [];
var i, ii, holeFlatCoords;
for (i = 1, ii = linearRings.length; i < ii; ++i) {
holeFlatCoords = linearRings[i].getFlatCoordinates();
holeFlatCoords = ol.geom.flat.transform.translate(holeFlatCoords, 0, holeFlatCoords.length,
stride, -this.origin[0], -this.origin[1]);
holes.push(holeFlatCoords);
this.lineStringReplay.drawPolygonCoordinates(outerRing, holes, stride);
this.drawCoordinates_(outerRing, holes, stride);
}
this.lineStringReplay.drawPolygonCoordinates(flatCoordinates, holes, stride);
this.drawCoordinates_(flatCoordinates, holes, stride);
}
};

View File

@@ -144,6 +144,10 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tile = tileSource.getTile(z, x, y, pixelRatio, projection);
// When useInterimTilesOnError is false, we consider the error tile as loaded.
if (tile.getState() == ol.TileState.ERROR && !this.getLayer().getUseInterimTilesOnError()) {
tile.setState(ol.TileState.LOADED);
}
if (!this.isDrawableTile_(tile)) {
tile = tile.getInterimTile();
}
@@ -173,7 +177,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layer
var renderedResolution = tileResolution * pixelRatio / tilePixelRatio * oversampling;
var hints = frameState.viewHints;
var animatingOrInteracting = hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING];
if (!(Date.now() - frameState.time > 16 && animatingOrInteracting) && (
if (!(this.renderedResolution && Date.now() - frameState.time > 16 && animatingOrInteracting) && (
newTiles ||
!(this.renderedExtent_ && ol.extent.containsExtent(this.renderedExtent_, extent)) ||
this.renderedRevision != sourceRevision ||

View File

@@ -1,6 +1,7 @@
goog.provide('ol.renderer.canvas.VectorTileLayer');
goog.require('ol');
goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.proj');
@@ -12,7 +13,6 @@ goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.render.replay');
goog.require('ol.renderer.canvas.TileLayer');
goog.require('ol.renderer.vector');
goog.require('ol.size');
goog.require('ol.transform');
@@ -23,6 +23,9 @@ goog.require('ol.transform');
*/
ol.renderer.canvas.VectorTileLayer = function(layer) {
/**
* @type {CanvasRenderingContext2D}
*/
this.context = null;
ol.renderer.canvas.TileLayer.call(this, layer);
@@ -95,17 +98,18 @@ ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState,
/**
* @param {ol.VectorTile} tile Tile.
* @param {ol.VectorImageTile} tile Tile.
* @param {olx.FrameState} frameState Frame state.
* @private
*/
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
frameState) {
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
tile, frameState) {
var layer = this.getLayer();
var pixelRatio = frameState.pixelRatio;
var projection = frameState.viewState.projection;
var revision = layer.getRevision();
var renderOrder = layer.getRenderOrder() || null;
var renderOrder = /** @type {ol.RenderOrderFunction} */
(layer.getRenderOrder()) || null;
var replayState = tile.getReplayState();
if (!replayState.dirty && replayState.renderedRevision == revision &&
@@ -113,25 +117,37 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
return;
}
replayState.replayGroup = null;
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
var sourceTile = tile.getTile(tile.tileKeys[t]);
sourceTile.replayGroup = null;
replayState.dirty = false;
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
var tileGrid = source.getTileGrid();
var tileCoord = tile.tileCoord;
var tileProjection = tile.getProjection();
var resolution = tileGrid.getResolution(tileCoord[0]);
var sourceTileGrid = source.getTileGrid();
var sourceTileCoord = sourceTile.tileCoord;
var tileProjection = sourceTile.getProjection();
var tileGrid = source.getTileGridForProjection(projection);
var resolution = tileGrid.getResolution(tile.tileCoord[0]);
var sourceTileResolution = sourceTileGrid.getResolution(sourceTile.tileCoord[0]);
var tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
var sharedExtent = ol.extent.getIntersection(tileExtent, sourceTileExtent);
var extent, reproject, tileResolution;
if (tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS) {
var tilePixelRatio = tileResolution = source.getTilePixelRatio();
var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));
extent = [0, 0, tileSize[0] * tilePixelRatio, tileSize[1] * tilePixelRatio];
var transform = ol.transform.compose(this.tmpTransform_,
0, 0,
1 / sourceTileResolution * tilePixelRatio, -1 / sourceTileResolution * tilePixelRatio,
0,
-sourceTileExtent[0], -sourceTileExtent[3]);
extent = (ol.transform.apply(transform, [sharedExtent[0], sharedExtent[3]])
.concat(ol.transform.apply(transform, [sharedExtent[2], sharedExtent[1]])));
} else {
tileResolution = resolution;
extent = tileGrid.getTileCoordExtent(tileCoord);
extent = sharedExtent;
if (!ol.proj.equivalent(projection, tileProjection)) {
reproject = true;
tile.setProjection(projection);
sourceTile.setProjection(projection);
}
}
replayState.dirty = false;
@@ -144,7 +160,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @this {ol.renderer.canvas.VectorTileLayer}
*/
function renderFeature(feature) {
var renderFeature = function(feature) {
var styles;
var styleFunction = feature.getStyleFunction();
if (styleFunction) {
@@ -164,9 +180,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
this.dirty_ = this.dirty_ || dirty;
replayState.dirty = replayState.dirty || dirty;
}
}
};
var features = tile.getFeatures();
var features = sourceTile.getFeatures();
if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {
features.sort(renderOrder);
}
@@ -178,13 +194,11 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
}
renderFeature.call(this, feature);
}
replayGroup.finish();
sourceTile.setReplayGroup(tile.tileCoord.toString(), replayGroup);
}
replayState.renderedRevision = revision;
replayState.renderedRenderOrder = renderOrder;
replayState.replayGroup = replayGroup;
replayState.resolution = NaN;
};
@@ -193,10 +207,10 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
*/
ol.renderer.canvas.VectorTileLayer.prototype.drawTileImage = function(
tile, frameState, layerState, x, y, w, h, gutter) {
var vectorTile = /** @type {ol.VectorTile} */ (tile);
this.createReplayGroup_(vectorTile, frameState);
var vectorImageTile = /** @type {ol.VectorImageTile} */ (tile);
this.createReplayGroup_(vectorImageTile, frameState);
if (this.context) {
this.renderTileImage_(vectorTile, frameState, layerState);
this.renderTileImage_(vectorImageTile, frameState, layerState);
ol.renderer.canvas.TileLayer.prototype.drawTileImage.apply(this, arguments);
}
};
@@ -213,25 +227,31 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
/** @type {Object.<string, boolean>} */
var features = {};
/** @type {Array.<ol.VectorTile>} */
var replayables = this.renderedTiles;
/** @type {Array.<ol.VectorImageTile>} */
var renderedTiles = this.renderedTiles;
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
var tileGrid = source.getTileGrid();
var found, tileSpaceCoordinate;
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
var sourceTileGrid = source.getTileGrid();
var bufferedExtent, found, tileSpaceCoordinate;
var i, ii, origin, replayGroup;
var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution;
for (i = 0, ii = replayables.length; i < ii; ++i) {
tile = replayables[i];
for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
tile = renderedTiles[i];
tileCoord = tile.tileCoord;
tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, this.tmpExtent);
if (!ol.extent.containsCoordinate(ol.extent.buffer(tileExtent, hitTolerance * resolution), coordinate)) {
tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
bufferedExtent = ol.extent.buffer(tileExtent, hitTolerance * resolution, bufferedExtent);
if (!ol.extent.containsCoordinate(bufferedExtent, coordinate)) {
continue;
}
if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
origin = ol.extent.getTopLeft(tileExtent);
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
var sourceTile = tile.getTile(tile.tileKeys[t]);
if (sourceTile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
var sourceTileCoord = sourceTile.tileCoord;
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
origin = ol.extent.getTopLeft(sourceTileExtent);
tilePixelRatio = source.getTilePixelRatio();
tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio;
tileResolution = sourceTileGrid.getResolution(sourceTileCoord[0]) / tilePixelRatio;
tileSpaceCoordinate = [
(coordinate[0] - origin[0]) / tileResolution,
(origin[1] - coordinate[1]) / tileResolution
@@ -240,7 +260,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
} else {
tileSpaceCoordinate = coordinate;
}
replayGroup = tile.getReplayState().replayGroup;
replayGroup = sourceTile.getReplayGroup(tile.tileCoord);
found = found || replayGroup.forEachFeatureAtCoordinate(
tileSpaceCoordinate, resolution, rotation, hitTolerance, {},
/**
@@ -255,12 +275,13 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
}
});
}
}
return found;
};
/**
* @param {ol.Tile} tile Tile.
* @param {ol.VectorTile} tile Tile.
* @param {olx.FrameState} frameState Frame state.
* @return {ol.Transform} transform Transform.
* @private
@@ -308,7 +329,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(
* @inheritDoc
*/
ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {
var renderMode = this.getLayer().getRenderMode();
var layer = this.getLayer();
var source = layer.getSource();
var renderMode = layer.getRenderMode();
var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
if (replays) {
var pixelRatio = frameState.pixelRatio;
@@ -317,18 +340,32 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
var offsetX = Math.round(pixelRatio * size[0] / 2);
var offsetY = Math.round(pixelRatio * size[1] / 2);
var tiles = this.renderedTiles;
var tilePixelRatio = layer.getSource().getTilePixelRatio();
var sourceTileGrid = source.getTileGrid();
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
var clips = [];
var zs = [];
for (var i = tiles.length - 1; i >= 0; --i) {
var tile = /** @type {ol.VectorTile} */ (tiles[i]);
// Create a clip mask for regions in this low resolution tile that are
// already filled by a higher resolution tile
var transform = this.getReplayTransform_(tile, frameState);
var currentClip = tile.getReplayState().replayGroup.getClipCoords(transform);
var currentZ = tile.tileCoord[0];
var tile = /** @type {ol.VectorImageTile} */ (tiles[i]);
if (tile.getState() == ol.TileState.ABORT) {
continue;
}
var tileCoord = tile.tileCoord;
var worldOffset = tileGrid.getTileCoordExtent(tileCoord)[0] -
tileGrid.getTileCoordExtent(tile.wrappedTileCoord)[0];
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
var sourceTile = tile.getTile(tile.tileKeys[t]);
var currentZ = sourceTile.tileCoord[0];
var sourceResolution = sourceTileGrid.getResolution(currentZ);
var transform = this.getReplayTransform_(sourceTile, frameState);
ol.transform.translate(transform, worldOffset * tilePixelRatio / sourceResolution, 0);
var replayGroup = sourceTile.getReplayGroup(tileCoord.toString());
var currentClip = replayGroup.getClipCoords(transform);
context.save();
context.globalAlpha = layerState.opacity;
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
// Create a clip mask for regions in this low resolution tile that are
// already filled by a higher resolution tile
for (var j = 0, jj = clips.length; j < jj; ++j) {
var clip = clips[j];
if (currentZ < zs[j]) {
@@ -346,13 +383,13 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
context.clip();
}
}
var replayGroup = tile.getReplayState().replayGroup;
replayGroup.replay(context, pixelRatio, transform, rotation, {}, replays);
context.restore();
clips.push(currentClip);
zs.push(currentZ);
}
}
}
ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);
};
@@ -386,7 +423,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, s
/**
* @param {ol.VectorTile} tile Tile.
* @param {ol.VectorImageTile} tile Tile.
* @param {olx.FrameState} frameState Frame state.
* @param {ol.LayerState} layerState Layer state.
* @private
@@ -399,28 +436,38 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
var replays = ol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS[layer.getRenderMode()];
if (replays && replayState.renderedTileRevision !== revision) {
replayState.renderedTileRevision = revision;
var tileCoord = tile.tileCoord;
var z = tile.tileCoord[0];
var tileCoord = tile.wrappedTileCoord;
var z = tileCoord[0];
var pixelRatio = frameState.pixelRatio;
var source = layer.getSource();
var tileGrid = source.getTileGrid();
var tilePixelRatio = source.getTilePixelRatio();
var transform = ol.transform.reset(this.tmpTransform_);
if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
var renderPixelRatio = pixelRatio / tilePixelRatio;
ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);
} else {
var sourceTileGrid = source.getTileGrid();
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
var resolution = tileGrid.getResolution(z);
var pixelScale = pixelRatio / resolution;
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
ol.transform.scale(transform, pixelScale, -pixelScale);
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
}
var tilePixelRatio = source.getTilePixelRatio();
var context = tile.getContext();
var size = source.getTilePixelSize(z, pixelRatio, frameState.viewState.projection);
context.canvas.width = size[0];
context.canvas.height = size[1];
replayState.replayGroup.replay(context, pixelRatio, transform, 0, {}, replays);
var tileExtent = tileGrid.getTileCoordExtent(tileCoord);
for (var i = 0, ii = tile.tileKeys.length; i < ii; ++i) {
var sourceTile = tile.getTile(tile.tileKeys[i]);
var sourceTileCoord = sourceTile.tileCoord;
var pixelScale = pixelRatio / resolution;
var transform = ol.transform.reset(this.tmpTransform_);
if (sourceTile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
var sourceResolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
var renderPixelRatio = pixelRatio / tilePixelRatio * sourceResolution / resolution;
ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);
var offsetX = (sourceTileExtent[0] - tileExtent[0]) / sourceResolution * tilePixelRatio;
var offsetY = (tileExtent[3] - sourceTileExtent[3]) / sourceResolution * tilePixelRatio;
ol.transform.translate(transform, Math.round(offsetX), Math.round(offsetY));
} else {
ol.transform.scale(transform, pixelScale, -pixelScale);
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
}
var replayGroup = sourceTile.getReplayGroup(tile.tileCoord.toString());
replayGroup.replay(context, pixelRatio, transform, 0, {}, replays);
}
}
};

View File

@@ -202,7 +202,8 @@ ol.reproj.Tile.prototype.disposeInternal = function() {
/**
* @inheritDoc
* Get the HTML Canvas element for this tile.
* @return {HTMLCanvasElement} Canvas.
*/
ol.reproj.Tile.prototype.getImage = function() {
return this.canvas_;

View File

@@ -35,27 +35,28 @@ ol.source.Cluster = function(options) {
/**
* @type {number|undefined}
* @private
* @protected
*/
this.resolution_ = undefined;
this.resolution = undefined;
/**
* @type {number}
* @private
* @protected
*/
this.distance_ = options.distance !== undefined ? options.distance : 20;
this.distance = options.distance !== undefined ? options.distance : 20;
/**
* @type {Array.<ol.Feature>}
* @private
* @protected
*/
this.features_ = [];
this.features = [];
/**
* @param {ol.Feature} feature Feature.
* @return {ol.geom.Point} Cluster calculation point.
* @protected
*/
this.geometryFunction_ = options.geometryFunction || function(feature) {
this.geometryFunction = options.geometryFunction || function(feature) {
var geometry = /** @type {ol.geom.Point} */ (feature.getGeometry());
ol.asserts.assert(geometry instanceof ol.geom.Point,
10); // The default `geometryFunction` can only handle `ol.geom.Point` geometries
@@ -64,12 +65,12 @@ ol.source.Cluster = function(options) {
/**
* @type {ol.source.Vector}
* @private
* @protected
*/
this.source_ = options.source;
this.source = options.source;
this.source_.on(ol.events.EventType.CHANGE,
ol.source.Cluster.prototype.refresh_, this);
this.source.on(ol.events.EventType.CHANGE,
ol.source.Cluster.prototype.refresh, this);
};
ol.inherits(ol.source.Cluster, ol.source.Vector);
@@ -80,7 +81,7 @@ ol.inherits(ol.source.Cluster, ol.source.Vector);
* @api
*/
ol.source.Cluster.prototype.getDistance = function() {
return this.distance_;
return this.distance;
};
@@ -90,7 +91,7 @@ ol.source.Cluster.prototype.getDistance = function() {
* @api
*/
ol.source.Cluster.prototype.getSource = function() {
return this.source_;
return this.source;
};
@@ -99,12 +100,12 @@ ol.source.Cluster.prototype.getSource = function() {
*/
ol.source.Cluster.prototype.loadFeatures = function(extent, resolution,
projection) {
this.source_.loadFeatures(extent, resolution, projection);
if (resolution !== this.resolution_) {
this.source.loadFeatures(extent, resolution, projection);
if (resolution !== this.resolution) {
this.clear();
this.resolution_ = resolution;
this.cluster_();
this.addFeatures(this.features_);
this.resolution = resolution;
this.cluster();
this.addFeatures(this.features);
}
};
@@ -115,34 +116,34 @@ ol.source.Cluster.prototype.loadFeatures = function(extent, resolution,
* @api
*/
ol.source.Cluster.prototype.setDistance = function(distance) {
this.distance_ = distance;
this.refresh_();
this.distance = distance;
this.refresh();
};
/**
* handle the source changing
* @private
* @override
*/
ol.source.Cluster.prototype.refresh_ = function() {
ol.source.Cluster.prototype.refresh = function() {
this.clear();
this.cluster_();
this.addFeatures(this.features_);
this.changed();
this.cluster();
this.addFeatures(this.features);
ol.source.Vector.prototype.refresh.call(this);
};
/**
* @private
* @protected
*/
ol.source.Cluster.prototype.cluster_ = function() {
if (this.resolution_ === undefined) {
ol.source.Cluster.prototype.cluster = function() {
if (this.resolution === undefined) {
return;
}
this.features_.length = 0;
this.features.length = 0;
var extent = ol.extent.createEmpty();
var mapDistance = this.distance_ * this.resolution_;
var features = this.source_.getFeatures();
var mapDistance = this.distance * this.resolution;
var features = this.source.getFeatures();
/**
* @type {!Object.<string, boolean>}
@@ -152,13 +153,13 @@ ol.source.Cluster.prototype.cluster_ = function() {
for (var i = 0, ii = features.length; i < ii; i++) {
var feature = features[i];
if (!(ol.getUid(feature).toString() in clustered)) {
var geometry = this.geometryFunction_(feature);
var geometry = this.geometryFunction(feature);
if (geometry) {
var coordinates = geometry.getCoordinates();
ol.extent.createOrUpdateFromCoordinate(coordinates, extent);
ol.extent.buffer(extent, mapDistance, extent);
var neighbors = this.source_.getFeaturesInExtent(extent);
var neighbors = this.source.getFeaturesInExtent(extent);
neighbors = neighbors.filter(function(neighbor) {
var uid = ol.getUid(neighbor).toString();
if (!(uid in clustered)) {
@@ -168,7 +169,7 @@ ol.source.Cluster.prototype.cluster_ = function() {
return false;
}
});
this.features_.push(this.createCluster_(neighbors));
this.features.push(this.createCluster(neighbors));
}
}
}
@@ -178,12 +179,12 @@ ol.source.Cluster.prototype.cluster_ = function() {
/**
* @param {Array.<ol.Feature>} features Features
* @return {ol.Feature} The cluster feature.
* @private
* @protected
*/
ol.source.Cluster.prototype.createCluster_ = function(features) {
ol.source.Cluster.prototype.createCluster = function(features) {
var centroid = [0, 0];
for (var i = features.length - 1; i >= 0; --i) {
var geometry = this.geometryFunction_(features[i]);
var geometry = this.geometryFunction(features[i]);
if (geometry) {
ol.coordinate.add(centroid, geometry.getCoordinates());
} else {

View File

@@ -91,7 +91,6 @@ ol.inherits(ol.source.TileDebug.Tile_, ol.Tile);
/**
* Get the image element for this tile.
* @return {HTMLCanvasElement} Image.
* @override
*/
ol.source.TileDebug.Tile_.prototype.getImage = function() {
if (this.canvas_) {

View File

@@ -9,6 +9,7 @@ goog.provide('ol.source.TileJSON');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.TileUrlFunction');
goog.require('ol.asserts');
goog.require('ol.extent');
goog.require('ol.net');
goog.require('ol.proj');
@@ -45,6 +46,7 @@ ol.source.TileJSON = function(options) {
wrapX: options.wrapX !== undefined ? options.wrapX : true
});
if (options.url) {
if (options.jsonp) {
ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
this.handleTileJSONError.bind(this));
@@ -55,6 +57,11 @@ ol.source.TileJSON = function(options) {
client.open('GET', options.url);
client.send();
}
} else if (options.tileJSON) {
this.handleTileJSONResponse(options.tileJSON);
} else {
ol.asserts.assert(false, 51); // Either `url` or `tileJSON` options must be provided
}
};
ol.inherits(ol.source.TileJSON, ol.source.TileImage);

View File

@@ -320,7 +320,6 @@ ol.inherits(ol.source.TileUTFGrid.Tile_, ol.Tile);
/**
* Get the image element for this tile.
* @return {Image} Image.
* @override
*/
ol.source.TileUTFGrid.Tile_.prototype.getImage = function() {
return null;

View File

@@ -157,7 +157,9 @@ ol.inherits(ol.source.Vector, ol.source.Source);
/**
* Add a single feature to the source. If you want to add a batch of features
* at once, call {@link ol.source.Vector#addFeatures source.addFeatures()}
* instead.
* instead. A feature will not be added to the source if feature with
* the same id is already there. The reason for this behavior is to avoid
* feature duplication when using bbox or tile loading strategies.
* @param {ol.Feature} feature Feature to add.
* @api
*/

View File

@@ -2,10 +2,11 @@ goog.provide('ol.source.VectorTile');
goog.require('ol');
goog.require('ol.TileState');
goog.require('ol.VectorImageTile');
goog.require('ol.VectorTile');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.proj');
goog.require('ol.size');
goog.require('ol.tilegrid');
goog.require('ol.source.UrlTile');
@@ -37,7 +38,7 @@ ol.source.VectorTile = function(options) {
state: options.state,
tileGrid: options.tileGrid,
tileLoadFunction: options.tileLoadFunction ?
options.tileLoadFunction : ol.VectorTile.defaultLoadFunction,
options.tileLoadFunction : ol.VectorImageTile.defaultLoadFunction,
tileUrlFunction: options.tileUrlFunction,
tilePixelRatio: options.tilePixelRatio,
url: options.url,
@@ -51,6 +52,12 @@ ol.source.VectorTile = function(options) {
*/
this.format_ = options.format ? options.format : null;
/**
* @private
* @type {Object.<string,ol.VectorTile>}
*/
this.sourceTiles_ = {};
/**
* @private
* @type {boolean}
@@ -64,6 +71,16 @@ ol.source.VectorTile = function(options) {
*/
this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile;
/**
* @private
* @type {Object.<string,ol.tilegrid.TileGrid>}
*/
this.tileGrids_ = {};
if (!this.tileGrid) {
this.tileGrid = this.getTileGridForProjection(ol.proj.get(options.projection || 'EPSG:3857'));
}
};
ol.inherits(ol.source.VectorTile, ol.source.UrlTile);
@@ -89,13 +106,14 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
tileCoord, projection);
var tileUrl = urlTileCoord ?
this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
var tile = new this.tileClass(
var tile = new ol.VectorImageTile(
tileCoord,
tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
tileUrl !== undefined ? tileUrl : '',
this.format_, this.tileLoadFunction);
ol.events.listen(tile, ol.events.EventType.CHANGE,
this.handleTileChange, this);
this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction,
this.tileGrid, this.getTileGridForProjection(projection),
this.sourceTiles_, pixelRatio, projection, this.tileClass,
this.handleTileChange.bind(this));
this.tileCache.set(tileCoordKey, tile);
return tile;
@@ -103,6 +121,23 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
};
/**
* @inheritDoc
*/
ol.source.VectorTile.prototype.getTileGridForProjection = function(projection) {
var code = projection.getCode();
var tileGrid = this.tileGrids_[code];
if (!tileGrid) {
// A tile grid that matches the tile size of the source tile grid is more
// likely to have 1:1 relationships between source tiles and rendered tiles.
var sourceTileGrid = this.tileGrid;
tileGrid = this.tileGrids_[code] = ol.tilegrid.createForProjection(projection, undefined,
sourceTileGrid ? sourceTileGrid.getTileSize(sourceTileGrid.getMinZoom()) : undefined);
}
return tileGrid;
};
/**
* @inheritDoc
*/
@@ -117,6 +152,6 @@ ol.source.VectorTile.prototype.getTilePixelRatio = function(opt_pixelRatio) {
* @inheritDoc
*/
ol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
var tileSize = ol.size.toSize(this.getTileGridForProjection(projection).getTileSize(z));
return [Math.round(tileSize[0] * pixelRatio), Math.round(tileSize[1] * pixelRatio)];
};

View File

@@ -215,3 +215,14 @@ ol.structs.RBush.prototype.getExtent = function(opt_extent) {
var data = this.rbush_.data;
return ol.extent.createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, opt_extent);
};
/**
* @param {ol.structs.RBush} rbush R-Tree.
*/
ol.structs.RBush.prototype.concat = function(rbush) {
this.rbush_.load(rbush.rbush_.all());
for (var i in rbush.items_) {
this.items_[i | 0] = rbush.items_[i | 0];
}
};

View File

@@ -66,10 +66,9 @@ ol.style.RegularShape = function(options) {
/**
* @private
* @type {number}
* @type {number|undefined}
*/
this.radius2_ =
options.radius2 !== undefined ? options.radius2 : this.radius_;
this.radius2_ = options.radius2;
/**
* @private
@@ -146,7 +145,7 @@ ol.inherits(ol.style.RegularShape, ol.style.Image);
ol.style.RegularShape.prototype.clone = function() {
var style = new ol.style.RegularShape({
fill: this.getFill() ? this.getFill().clone() : undefined,
points: this.getRadius2() !== this.getRadius() ? this.getPoints() / 2 : this.getPoints(),
points: this.getPoints(),
radius: this.getRadius(),
radius2: this.getRadius2(),
angle: this.getAngle(),
@@ -263,7 +262,7 @@ ol.style.RegularShape.prototype.getRadius = function() {
/**
* Get the secondary radius for the shape.
* @return {number} Radius2.
* @return {number|undefined} Radius2.
* @api
*/
ol.style.RegularShape.prototype.getRadius2 = function() {
@@ -428,17 +427,20 @@ ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {
context.beginPath();
if (this.points_ === Infinity) {
var points = this.points_;
if (points === Infinity) {
context.arc(
renderOptions.size / 2, renderOptions.size / 2,
this.radius_, 0, 2 * Math.PI, true);
} else {
if (this.radius2_ !== this.radius_) {
this.points_ = 2 * this.points_;
var radius2 = (this.radius2_ !== undefined) ? this.radius2_
: this.radius_;
if (radius2 !== this.radius_) {
points = 2 * points;
}
for (i = 0; i <= this.points_; i++) {
angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
for (i = 0; i <= points; i++) {
angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : radius2;
context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
renderOptions.size / 2 + radiusC * Math.sin(angle0));
}
@@ -504,18 +506,21 @@ ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = function(renderOptions
context.beginPath();
if (this.points_ === Infinity) {
var points = this.points_;
if (points === Infinity) {
context.arc(
renderOptions.size / 2, renderOptions.size / 2,
this.radius_, 0, 2 * Math.PI, true);
} else {
if (this.radius2_ !== this.radius_) {
this.points_ = 2 * this.points_;
var radius2 = (this.radius2_ !== undefined) ? this.radius2_
: this.radius_;
if (radius2 !== this.radius_) {
points = 2 * points;
}
var i, radiusC, angle0;
for (i = 0; i <= this.points_; i++) {
angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
for (i = 0; i <= points; i++) {
angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : radius2;
context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
renderOptions.size / 2 + radiusC * Math.sin(angle0));
}

View File

@@ -59,14 +59,6 @@ ol.Tile.prototype.changed = function() {
};
/**
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
* @abstract
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
*/
ol.Tile.prototype.getImage = function() {};
/**
* @return {string} Key.
*/
@@ -153,6 +145,13 @@ ol.Tile.prototype.getState = function() {
return this.state;
};
/**
* @param {ol.TileState} state State.
*/
ol.Tile.prototype.setState = function(state) {
this.state = state;
this.changed();
};
/**
* Load the image or retry if loading previously failed.

View File

@@ -74,7 +74,7 @@ ol.tilegrid.createForExtent = function(extent, opt_maxZoom, opt_tileSize, opt_co
/**
* Creates a tile grid with a standard XYZ tiling scheme.
* @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.
* @return {ol.tilegrid.TileGrid} Tile grid instance.
* @return {!ol.tilegrid.TileGrid} Tile grid instance.
* @api
*/
ol.tilegrid.createXYZ = function(opt_options) {
@@ -126,7 +126,8 @@ ol.tilegrid.resolutionsFromExtent = function(extent, opt_maxZoom, opt_tileSize)
* @param {ol.ProjectionLike} projection Projection.
* @param {number=} opt_maxZoom Maximum zoom level (default is
* ol.DEFAULT_MAX_ZOOM).
* @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE).
* @param {number|ol.Size=} opt_tileSize Tile size (default uses
* ol.DEFAULT_TILE_SIZE).
* @param {ol.extent.Corner=} opt_corner Extent corner (default is
* ol.extent.Corner.BOTTOM_LEFT).
* @return {!ol.tilegrid.TileGrid} TileGrid instance.

View File

@@ -130,6 +130,16 @@ ol.Color;
ol.ColorLike;
/**
* @typedef {{
* center: ol.CenterConstraintType,
* resolution: ol.ResolutionConstraintType,
* rotation: ol.RotationConstraintType
* }}
*/
ol.Constraints;
/**
* An array of numbers representing an xy coordinate. Example: `[16, 48]`.
* @typedef {Array.<number>}
@@ -156,12 +166,11 @@ ol.DragBoxEndConditionType;
/**
* Function that takes coordinates and an optional existing geometry as
* Function that takes an array of coordinates and an optional existing geometry as
* arguments, and returns a geometry. The optional existing geometry is the
* geometry that is returned when the function is called without a second
* argument.
* @typedef {function(!(ol.Coordinate|Array.<ol.Coordinate>|
* Array.<Array.<ol.Coordinate>>), ol.geom.SimpleGeometry=):
* @typedef {function(!Array.<ol.Coordinate>, ol.geom.SimpleGeometry=):
* ol.geom.SimpleGeometry}
*/
ol.DrawGeometryFunctionType;
@@ -454,9 +463,11 @@ ol.RegularShapeRenderOptions;
/**
* A function to be used when sorting features before rendering.
* It takes two instances of {@link ol.Feature} and returns a `{number}`.
* It takes two instances of {@link ol.Feature} or {@link ol.render.Feature} and
* returns a `{number}`.
*
* @typedef {function(ol.Feature, ol.Feature):number}
* @typedef {function((ol.Feature|ol.render.Feature), (ol.Feature|ol.render.Feature)):
* number}
*/
ol.RenderOrderFunction;
@@ -652,8 +663,7 @@ ol.TilePriorityFunction;
* dirty: boolean,
* renderedRenderOrder: (null|ol.RenderOrderFunction),
* renderedTileRevision: number,
* renderedRevision: number,
* replayGroup: ol.render.ReplayGroup}}
* renderedRevision: number}}
*/
ol.TileReplayState;

266
src/ol/vectorimagetile.js Normal file
View File

@@ -0,0 +1,266 @@
goog.provide('ol.VectorImageTile');
goog.require('ol');
goog.require('ol.Tile');
goog.require('ol.TileState');
goog.require('ol.array');
goog.require('ol.dom');
goog.require('ol.events');
goog.require('ol.extent');
goog.require('ol.events.EventType');
goog.require('ol.featureloader');
/**
* @constructor
* @extends {ol.Tile}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.TileState} state State.
* @param {string} src Data source url.
* @param {ol.format.Feature} format Feature format.
* @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
* @param {ol.TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
* @param {ol.TileUrlFunctionType} tileUrlFunction Tile url function.
* @param {ol.tilegrid.TileGrid} sourceTileGrid Tile grid of the source.
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid of the renderer.
* @param {Object.<string,ol.VectorTile>} sourceTiles Source tiles.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.proj.Projection} projection Projection.
* @param {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string,
* ol.format.Feature, ol.TileLoadFunctionType)} tileClass Class to
* instantiate for source tiles.
* @param {function(this: ol.source.VectorTile, ol.events.Event)} handleTileChange
* Function to call when a source tile's state changes.
*/
ol.VectorImageTile = function(tileCoord, state, src, format, tileLoadFunction,
urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles,
pixelRatio, projection, tileClass, handleTileChange) {
ol.Tile.call(this, tileCoord, state);
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.context_ = null;
/**
* @private
* @type {ol.FeatureLoader}
*/
this.loader_;
/**
* @private
* @type {ol.TileReplayState}
*/
this.replayState_ = {
dirty: false,
renderedRenderOrder: null,
renderedRevision: -1,
renderedTileRevision: -1
};
/**
* @private
* @type {Object.<string,ol.VectorTile>}
*/
this.sourceTiles_ = sourceTiles;
/**
* Keys of source tiles used by this tile. Use with {@link #getTile}.
* @type {Array.<string>}
*/
this.tileKeys = [];
/**
* @type {string}
*/
this.src_ = src;
/**
* @type {ol.TileCoord}
*/
this.wrappedTileCoord = urlTileCoord;
/**
* @type {Array.<ol.EventsKey>}
*/
this.loadListenerKeys_ = [];
/**
* @type {Array.<ol.EventsKey>}
*/
this.sourceTileListenerKeys_ = [];
if (urlTileCoord) {
var extent = tileGrid.getTileCoordExtent(urlTileCoord);
var resolution = tileGrid.getResolution(tileCoord[0]);
var sourceZ = sourceTileGrid.getZForResolution(resolution);
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
var sharedExtent = ol.extent.getIntersection(extent,
sourceTileGrid.getTileCoordExtent(sourceTileCoord));
if (ol.extent.getWidth(sharedExtent) / resolution >= 0.5 &&
ol.extent.getHeight(sharedExtent) / resolution >= 0.5) {
// only include source tile if overlap is at least 1 pixel
var sourceTileKey = sourceTileCoord.toString();
var sourceTile = sourceTiles[sourceTileKey];
if (!sourceTile) {
var tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
tileUrl == undefined ? ol.TileState.EMPTY : ol.TileState.IDLE,
tileUrl == undefined ? '' : tileUrl,
format, tileLoadFunction);
this.sourceTileListenerKeys_.push(
ol.events.listen(sourceTile, ol.events.EventType.CHANGE, handleTileChange));
}
sourceTile.consumers++;
this.tileKeys.push(sourceTileKey);
}
}.bind(this));
}
};
ol.inherits(ol.VectorImageTile, ol.Tile);
/**
* @inheritDoc
*/
ol.VectorImageTile.prototype.disposeInternal = function() {
for (var i = 0, ii = this.tileKeys.length; i < ii; ++i) {
var sourceTileKey = this.tileKeys[i];
var sourceTile = this.getTile(sourceTileKey);
sourceTile.consumers--;
if (sourceTile.consumers == 0) {
delete this.sourceTiles_[sourceTileKey];
sourceTile.dispose();
}
}
this.tileKeys.length = 0;
this.sourceTiles_ = null;
if (this.state == ol.TileState.LOADING) {
this.loadListenerKeys_.forEach(ol.events.unlistenByKey);
this.loadListenerKeys_.length = 0;
}
if (this.interimTile) {
this.interimTile.dispose();
}
this.state = ol.TileState.ABORT;
this.changed();
this.sourceTileListenerKeys_.forEach(ol.events.unlistenByKey);
this.sourceTileListenerKeys_.length = 0;
ol.Tile.prototype.disposeInternal.call(this);
};
/**
* @return {CanvasRenderingContext2D} The rendering context.
*/
ol.VectorImageTile.prototype.getContext = function() {
if (!this.context_) {
this.context_ = ol.dom.createCanvasContext2D();
}
return this.context_;
};
/**
* Get the Canvas for this tile.
* @return {HTMLCanvasElement} Canvas.
*/
ol.VectorImageTile.prototype.getImage = function() {
return this.replayState_.renderedTileRevision == -1 ?
null : this.context_.canvas;
};
/**
* @return {ol.TileReplayState} The replay state.
*/
ol.VectorImageTile.prototype.getReplayState = function() {
return this.replayState_;
};
/**
* @inheritDoc
*/
ol.VectorImageTile.prototype.getKey = function() {
return this.tileKeys.join('/') + '/' + this.src_;
};
/**
* @param {string} tileKey Key (tileCoord) of the source tile.
* @return {ol.VectorTile} Source tile.
*/
ol.VectorImageTile.prototype.getTile = function(tileKey) {
return this.sourceTiles_[tileKey];
};
/**
* @inheritDoc
*/
ol.VectorImageTile.prototype.load = function() {
var leftToLoad = 0;
var errors = false;
if (this.state == ol.TileState.IDLE) {
this.setState(ol.TileState.LOADING);
}
if (this.state == ol.TileState.LOADING) {
this.tileKeys.forEach(function(sourceTileKey) {
var sourceTile = this.getTile(sourceTileKey);
if (sourceTile.state == ol.TileState.IDLE) {
sourceTile.setLoader(this.loader_);
sourceTile.load();
} else if (sourceTile.state == ol.TileState.ERROR) {
errors = true;
} else if (sourceTile.state == ol.TileState.EMPTY) {
ol.array.remove(this.tileKeys, sourceTileKey);
}
if (sourceTile.state == ol.TileState.LOADING) {
var key = ol.events.listen(sourceTile, ol.events.EventType.CHANGE, function(e) {
var state = sourceTile.getState();
if (state == ol.TileState.LOADED ||
state == ol.TileState.ERROR) {
--leftToLoad;
ol.events.unlistenByKey(key);
ol.array.remove(this.loadListenerKeys_, key);
if (state == ol.TileState.ERROR) {
ol.array.remove(this.tileKeys, sourceTileKey);
errors = true;
}
if (leftToLoad == 0) {
this.setState(this.tileKeys.length > 0 ?
ol.TileState.LOADED : ol.TileState.ERROR);
}
}
}.bind(this));
this.loadListenerKeys_.push(key);
++leftToLoad;
}
}.bind(this));
}
if (leftToLoad == 0) {
setTimeout(function() {
this.setState(this.tileKeys.length > 0 ?
ol.TileState.LOADED :
(errors ? ol.TileState.ERROR : ol.TileState.EMPTY));
}.bind(this), 0);
}
};
/**
* Sets the loader for a tile.
* @param {ol.VectorTile} tile Vector tile.
* @param {string} url URL.
*/
ol.VectorImageTile.defaultLoadFunction = function(tile, url) {
var loader = ol.featureloader.loadFeaturesXhr(
url, tile.getFormat(), tile.onLoad_.bind(tile), tile.onError_.bind(tile));
tile.setLoader(loader);
};

View File

@@ -3,8 +3,6 @@ goog.provide('ol.VectorTile');
goog.require('ol');
goog.require('ol.Tile');
goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.featureloader');
/**
@@ -21,10 +19,9 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
ol.Tile.call(this, tileCoord, state);
/**
* @private
* @type {CanvasRenderingContext2D}
* @type {number}
*/
this.context_ = null;
this.consumers = 0;
/**
* @private
@@ -51,17 +48,7 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
*/
this.projection_;
/**
* @private
* @type {ol.TileReplayState}
*/
this.replayState_ = {
dirty: false,
renderedRenderOrder: null,
renderedRevision: -1,
renderedTileRevision: -1,
replayGroup: null
};
this.replayGroups_ = {};
/**
* @private
@@ -80,22 +67,14 @@ ol.inherits(ol.VectorTile, ol.Tile);
/**
* @return {CanvasRenderingContext2D} The rendering context.
* @inheritDoc
*/
ol.VectorTile.prototype.getContext = function() {
if (!this.context_) {
this.context_ = ol.dom.createCanvasContext2D();
}
return this.context_;
};
/**
* @override
*/
ol.VectorTile.prototype.getImage = function() {
return this.replayState_.renderedTileRevision == -1 ?
null : this.context_.canvas;
ol.VectorTile.prototype.disposeInternal = function() {
this.features_ = null;
this.replayGroups_ = {};
this.state = ol.TileState.ABORT;
this.changed();
ol.Tile.prototype.disposeInternal.call(this);
};
@@ -110,21 +89,16 @@ ol.VectorTile.prototype.getFormat = function() {
/**
* @return {Array.<ol.Feature>} Features.
* Get the features for this tile. Geometries will be in the projection returned
* by {@link #getProjection}.
* @return {Array.<ol.Feature|ol.render.Feature>} Features.
* @api
*/
ol.VectorTile.prototype.getFeatures = function() {
return this.features_;
};
/**
* @return {ol.TileReplayState} The replay state.
*/
ol.VectorTile.prototype.getReplayState = function() {
return this.replayState_;
};
/**
* @inheritDoc
*/
@@ -134,13 +108,20 @@ ol.VectorTile.prototype.getKey = function() {
/**
* Get the feature projection of features returned by {@link #getFeatures}.
* @return {ol.proj.Projection} Feature projection.
* @api
*/
ol.VectorTile.prototype.getProjection = function() {
return this.projection_;
};
ol.VectorTile.prototype.getReplayGroup = function(key) {
return this.replayGroups_[key];
};
/**
* @inheritDoc
*/
@@ -192,12 +173,8 @@ ol.VectorTile.prototype.setProjection = function(projection) {
};
/**
* @param {ol.TileState} tileState Tile state.
*/
ol.VectorTile.prototype.setState = function(tileState) {
this.state = tileState;
this.changed();
ol.VectorTile.prototype.setReplayGroup = function(key, replayGroup) {
this.replayGroups_[key] = replayGroup;
};
@@ -209,16 +186,3 @@ ol.VectorTile.prototype.setState = function(tileState) {
ol.VectorTile.prototype.setLoader = function(loader) {
this.loader_ = loader;
};
/**
* Sets the loader for a tile.
* @param {ol.VectorTile} tile Vector tile.
* @param {string} url URL.
*/
ol.VectorTile.defaultLoadFunction = function(tile, url) {
var loader = ol.featureloader.loadFeaturesXhr(
url, tile.getFormat(), tile.onLoad_.bind(tile), tile.onError_.bind(tile));
tile.setLoader(loader);
};

View File

@@ -2,7 +2,6 @@ goog.provide('ol.View');
goog.require('ol');
goog.require('ol.CenterConstraint');
goog.require('ol.Constraints');
goog.require('ol.Object');
goog.require('ol.ResolutionConstraint');
goog.require('ol.RotationConstraint');
@@ -169,8 +168,11 @@ ol.View.prototype.applyOptions_ = function(options) {
* @private
* @type {ol.Constraints}
*/
this.constraints_ = new ol.Constraints(
centerConstraint, resolutionConstraint, rotationConstraint);
this.constraints_ = {
center: centerConstraint,
resolution: resolutionConstraint,
rotation: rotationConstraint
};
if (options.resolution !== undefined) {
properties[ol.ViewProperty.RESOLUTION] = options.resolution;
@@ -528,6 +530,14 @@ ol.View.prototype.getCenter = function() {
};
/**
* @return {ol.Constraints} Constraints.
*/
ol.View.prototype.getConstraints = function() {
return this.constraints_;
};
/**
* @param {Array.<number>=} opt_hints Destination array.
* @return {Array.<number>} Hint.
@@ -662,11 +672,13 @@ ol.View.prototype.getResolutions = function() {
/**
* Get the resolution for a provided extent (in map units) and size (in pixels).
* @param {ol.Extent} extent Extent.
* @param {ol.Size} size Box pixel size.
* @param {ol.Size=} opt_size Box pixel size.
* @return {number} The resolution at which the provided extent will render at
* the given size.
* @api
*/
ol.View.prototype.getResolutionForExtent = function(extent, size) {
ol.View.prototype.getResolutionForExtent = function(extent, opt_size) {
var size = opt_size || this.getSizeFromViewport_();
var xResolution = ol.extent.getWidth(extent) / size[0];
var yResolution = ol.extent.getHeight(extent) / size[1];
return Math.max(xResolution, yResolution);

View File

@@ -1,6 +1,7 @@
goog.provide('ol.test.coordinate');
goog.require('ol.coordinate');
goog.require('ol.geom.Circle');
describe('ol.coordinate', function() {
@@ -89,6 +90,19 @@ describe('ol.coordinate', function() {
});
});
describe('#closestOnCircle', function() {
var center = [5, 10];
var circle = new ol.geom.Circle(center, 10);
it('can find the closest point on circle', function() {
expect(ol.coordinate.closestOnCircle([-20, 10], circle))
.to.eql([-5, 10]);
});
it('can handle coordinate equal circle center', function() {
expect(ol.coordinate.closestOnCircle(center, circle))
.to.eql([15, 10]);
});
});
describe('#closestOnSegment', function() {
it('can handle points where the foot of the perpendicular is closest',
function() {

View File

@@ -826,6 +826,20 @@ describe('ol.format.GeoJSON', function() {
});
expect(format.readGeometry(geojson).getCoordinates()).to.eql(
[[42.123457, 38.987654], [43, 39]]);
expect(linestring.getCoordinates()).to.eql(
[[42.123456789, 38.987654321], [43, 39]]);
});
it('rounds a linestring with decimals option = 0', function() {
var linestring = new ol.geom.LineString([[42.123456789, 38.987654321],
[43, 39]]);
var geojson = format.writeGeometry(linestring, {
decimals: 0
});
expect(format.readGeometry(geojson).getCoordinates()).to.eql(
[[42, 39], [43, 39]]);
expect(linestring.getCoordinates()).to.eql(
[[42.123456789, 38.987654321], [43, 39]]);
});
});

View File

@@ -73,12 +73,19 @@ where('ArrayBuffer.isView').describe('ol.format.MVT', function() {
});
it('parses id property', function() {
// ol.Feature
var format = new ol.format.MVT({
featureClass: ol.Feature,
layers: ['building']
});
var features = format.readFeatures(data);
expect(features[0].getId()).to.be(2);
// ol.render.Feature
format = new ol.format.MVT({
layers: ['building']
});
features = format.readFeatures(data);
expect(features[0].getId()).to.be(2);
});
});

View File

@@ -176,6 +176,29 @@ describe('ol.format.TopoJSON', function() {
});
});
it('sets the topology\'s child names as feature property', function(done) {
afterLoadText('spec/ol/format/topojson/world-110m.json', function(text) {
var format = new ol.format.TopoJSON({
layerName: 'layer'
});
var features = format.readFeatures(text);
expect(features[0].get('layer')).to.be('land');
expect(features[177].get('layer')).to.be('countries');
done();
});
});
it('only parses features from specified topology\'s children', function(done) {
afterLoadText('spec/ol/format/topojson/world-110m.json', function(text) {
var format = new ol.format.TopoJSON({
layers: ['land']
});
var features = format.readFeatures(text);
expect(features.length).to.be(1);
done();
});
});
});
});

View File

@@ -587,6 +587,37 @@ describe('ol.format.WFS', function() {
expect(serialized.firstElementChild).to.xmleql(ol.xml.parse(text));
});
it('creates During property filter', function() {
var text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs" ' +
' typeName="states" srsName="EPSG:4326">' +
' <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">' +
' <ogc:During>' +
' <fes:ValueReference xmlns:fes="http://www.opengis.net/fes">date_prop</fes:ValueReference>' +
' <gml:TimePeriod xmlns:gml="http://www.opengis.net/gml">' +
' <gml:begin>' +
' <gml:TimeInstant>' +
' <gml:timePosition>2010-01-20T00:00:00Z</gml:timePosition>' +
' </gml:TimeInstant>' +
' </gml:begin>' +
' <gml:end>' +
' <gml:TimeInstant>' +
' <gml:timePosition>2012-12-31T00:00:00Z</gml:timePosition>' +
' </gml:TimeInstant>' +
' </gml:end>' +
' </gml:TimePeriod>' +
' </ogc:During>' +
' </ogc:Filter>' +
'</wfs:Query>';
var serialized = new ol.format.WFS().writeGetFeature({
srsName: 'EPSG:4326',
featureTypes: ['states'],
filter: ol.format.filter.during('date_prop', '2010-01-20T00:00:00Z', '2012-12-31T00:00:00Z')
});
expect(serialized.firstElementChild).to.xmleql(ol.xml.parse(text));
});
});
describe('when writing out a Transaction request', function() {

View File

@@ -61,6 +61,25 @@ describe('ol.ImageTile', function() {
tile.load();
});
it('loads an empty image on error ', function(done) {
var tileCoord = [0, 0, 0];
var state = ol.TileState.IDLE;
var src = 'spec/ol/data/osm-0-0-99.png';
var tileLoadFunction = ol.source.Image.defaultImageLoadFunction;
var tile = new ol.ImageTile(tileCoord, state, src, null, tileLoadFunction);
ol.events.listen(tile, ol.events.EventType.CHANGE, function(event) {
var state = tile.getState();
if (state == ol.TileState.ERROR) {
expect(state).to.be(ol.TileState.ERROR);
expect(tile.image_).to.be(ol.ImageTile.blankImage);
done();
}
});
tile.load();
});
});
});

View File

@@ -8,7 +8,7 @@ goog.require('ol.format.GeoJSON');
goog.require('ol.interaction.DragAndDrop');
describe('ol.interaction.DragAndDrop', function() {
where('FileReader').describe('ol.interaction.DragAndDrop', function() {
var viewport, map, interaction;
beforeEach(function() {
@@ -37,7 +37,20 @@ describe('ol.interaction.DragAndDrop', function() {
expect(interaction.formatConstructors_).to.have.length(1);
});
});
describe('#setActive()', function() {
it('registers and unregisters listeners', function() {
interaction.setMap(map);
interaction.setActive(true);
expect(viewport.hasListener('dragenter')).to.be(true);
expect(viewport.hasListener('dragover')).to.be(true);
expect(viewport.hasListener('drop')).to.be(true);
interaction.setActive(false);
expect(viewport.hasListener('dragenter')).to.be(false);
expect(viewport.hasListener('dragover')).to.be(false);
expect(viewport.hasListener('drop')).to.be(false);
});
});
describe('#setMap()', function() {
@@ -70,9 +83,11 @@ describe('ol.interaction.DragAndDrop', function() {
});
describe('#handleDrop_', function() {
var OrigFileReader = FileReader;
var OrigFileReader;
beforeEach(function() {
OrigFileReader = FileReader;
FileReader = function() {
ol.events.EventTarget.apply(this, arguments);
this.readAsText = function(file) {

View File

@@ -1,6 +1,12 @@
goog.provide('ol.test.interaction.DragRotateAndZoom');
goog.require('ol.Map');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.View');
goog.require('ol.interaction.DragRotateAndZoom');
goog.require('ol.layer.Vector');
goog.require('ol.pointer.PointerEvent');
goog.require('ol.source.Vector');
describe('ol.interaction.DragRotateAndZoom', function() {
@@ -13,4 +19,67 @@ describe('ol.interaction.DragRotateAndZoom', function() {
});
describe('#handleDragEvent_()', function() {
var target, map, interaction;
var width = 360;
var height = 180;
beforeEach(function(done) {
target = document.createElement('div');
var style = target.style;
style.position = 'absolute';
style.left = '-1000px';
style.top = '-1000px';
style.width = width + 'px';
style.height = height + 'px';
document.body.appendChild(target);
var source = new ol.source.Vector();
var layer = new ol.layer.Vector({source: source});
interaction = new ol.interaction.DragRotateAndZoom();
map = new ol.Map({
target: target,
layers: [layer],
interactions: [interaction],
view: new ol.View({
projection: 'EPSG:4326',
center: [0, 0],
resolution: 1
})
});
map.once('postrender', function() {
done();
});
});
afterEach(function() {
map.dispose();
document.body.removeChild(target);
});
it('does not rotate when rotation is disabled on the view', function() {
var event = new ol.MapBrowserPointerEvent('pointermove', map,
new ol.pointer.PointerEvent('pointermove', {clientX: 20, clientY: 10}, {pointerType: 'mouse'}),
true);
interaction.lastAngle_ = Math.PI;
var spy = sinon.spy(ol.interaction.Interaction, 'rotateWithoutConstraints');
interaction.handleDragEvent_(event);
expect(spy.callCount).to.be(1);
expect(interaction.lastAngle_).to.be(-0.8308214428190254);
map.setView(new ol.View({
projection: 'EPSG:4326',
center: [0, 0],
resolution: 1,
enableRotation: false
}));
event = new ol.MapBrowserPointerEvent('pointermove', map,
new ol.pointer.PointerEvent('pointermove', {clientX: 24, clientY: 16}, {pointerType: 'mouse'}),
true);
interaction.handleDragEvent_(event);
expect(spy.callCount).to.be(1);
ol.interaction.Interaction.rotateWithoutConstraints.restore();
});
});
});

View File

@@ -559,6 +559,40 @@ describe('ol.interaction.Modify', function() {
});
});
describe('insertVertexCondition', function() {
it('calls the callback function', function() {
var listenerSpy = sinon.spy(function(event) {
return false;
});
var modify = new ol.interaction.Modify({
features: new ol.Collection(features),
insertVertexCondition: listenerSpy
});
map.addInteraction(modify);
var feature = features[0];
// move first vertex
simulateEvent('pointermove', 0, 0, false, 0);
simulateEvent('pointerdown', 0, 0, false, 0);
simulateEvent('pointermove', -10, -10, false, 0);
simulateEvent('pointerdrag', -10, -10, false, 0);
simulateEvent('pointerup', -10, -10, false, 0);
expect(listenerSpy.callCount).to.be(0);
expect(feature.getGeometry().getCoordinates()[0]).to.have.length(5);
// try to add vertex
simulateEvent('pointerdown', 40, -20, false, 0);
simulateEvent('pointerup', 40, -20, false, 0);
simulateEvent('click', 40, -20, false, 0);
simulateEvent('singleclick', 40, -20, false, 0);
expect(listenerSpy.callCount).to.be(1);
expect(feature.getGeometry().getCoordinates()[0]).to.have.length(5);
});
});
describe('handle feature change', function() {
var getListeners;

View File

@@ -4,6 +4,7 @@ goog.require('ol.Collection');
goog.require('ol.Feature');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.geom.Circle');
goog.require('ol.geom.Point');
goog.require('ol.geom.LineString');
goog.require('ol.interaction.Snap');
@@ -109,6 +110,27 @@ describe('ol.interaction.Snap', function() {
expect(event.coordinate).to.eql([10, 0]);
});
it('snaps to circle', function() {
var circle = new ol.Feature(new ol.geom.Circle([0, 0], 10));
var snapInteraction = new ol.interaction.Snap({
features: new ol.Collection([circle]),
pixelTolerance: 5
});
snapInteraction.setMap(map);
var event = {
pixel: [5 + width / 2, height / 2 - 5],
coordinate: [5, 5],
map: map
};
ol.interaction.Snap.handleEvent_.call(snapInteraction, event);
expect(event.coordinate).to.eql([
Math.sin(Math.PI / 4) * 10,
Math.sin(Math.PI / 4) * 10
]);
});
it('handle feature without geometry', function() {
var feature = new ol.Feature();
var snapInteraction = new ol.interaction.Snap({

View File

@@ -210,83 +210,66 @@ describe('ol.interaction.Translate', function() {
beforeEach(function() {
translate = new ol.interaction.Translate();
map.addInteraction(translate);
element = map.getTargetElement();
element = map.getViewport();
});
it('changes css cursor', function() {
expect(element.style.cursor).to.eql('');
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(false);
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(true);
simulateEvent('pointerdown', 10, 20);
expect(element.style.cursor).to.match(/grabbing$/);
expect(element.classList.contains('ol-grabbing')).to.be(true);
expect(element.classList.contains('ol-grab')).to.be(false);
simulateEvent('pointerup', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(true);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('');
});
it('respects existing cursor value', function() {
element.style.cursor = 'pointer';
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
simulateEvent('pointerdown', 10, 20);
expect(element.style.cursor).to.match(/grabbing$/);
simulateEvent('pointerup', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('pointer');
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(false);
});
it('resets css cursor when interaction is deactivated while pointer is on feature', function() {
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(true);
translate.setActive(false);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('');
});
it('resets css cursor to existing cursor when interaction is deactivated while pointer is on feature', function() {
element.style.cursor = 'pointer';
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
translate.setActive(false);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('pointer');
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(false);
});
it('resets css cursor interaction is removed while pointer is on feature', function() {
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(true);
map.removeInteraction(translate);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('');
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(false);
});
it('resets css cursor to existing cursor interaction is removed while pointer is on feature', function() {
element.style.cursor = 'pointer';
simulateEvent('pointermove', 10, 20);
expect(element.style.cursor).to.match(/grab$/);
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(true);
map.removeInteraction(translate);
simulateEvent('pointermove', 0, 0);
expect(element.style.cursor).to.eql('pointer');
expect(element.classList.contains('ol-grabbing')).to.be(false);
expect(element.classList.contains('ol-grab')).to.be(false);
});
});

View File

@@ -99,7 +99,7 @@ describe('ol.Map', function() {
});
});
describe('moveend event', function() {
describe('movestart/moveend event', function() {
var target, view, map;
@@ -135,13 +135,18 @@ describe('ol.Map', function() {
document.body.removeChild(target);
});
it('is fired only once after view changes', function(done) {
it('are fired only once after view changes', function(done) {
var center = [10, 20];
var zoom = 3;
var calls = 0;
var startCalls = 0;
var endCalls = 0;
map.on('movestart', function() {
++startCalls;
expect(startCalls).to.be(1);
});
map.on('moveend', function() {
++calls;
expect(calls).to.be(1);
++endCalls;
expect(endCalls).to.be(1);
expect(view.getCenter()).to.eql(center);
expect(view.getZoom()).to.be(zoom);
window.setTimeout(done, 1000);
@@ -151,6 +156,31 @@ describe('ol.Map', function() {
view.setZoom(zoom);
});
it('are fired in sequence', function(done) {
view.setCenter([0, 0]);
view.setResolution(0.703125);
map.renderSync();
var center = [10, 20];
var zoom = 3;
var calls = [];
map.on('movestart', function(e) {
calls.push('start');
expect(calls).to.eql(['start']);
expect(e.frameState.viewState.center).to.eql([0, 0]);
expect(e.frameState.viewState.resolution).to.be(0.703125);
});
map.on('moveend', function() {
calls.push('end');
expect(calls).to.eql(['start', 'end']);
expect(view.getCenter()).to.eql(center);
expect(view.getZoom()).to.be(zoom);
done();
});
view.setCenter(center);
view.setZoom(zoom);
});
});
describe('#forEachLayerAtPixel()', function() {

View File

@@ -115,4 +115,60 @@ describe('ol.MapBrowserEventHandler', function() {
});
});
describe('#isMoving_', function() {
var defaultHandler;
var moveToleranceHandler;
var pointerdownAt0;
beforeEach(function() {
defaultHandler = new ol.MapBrowserEventHandler(new ol.Map({}));
moveToleranceHandler = new ol.MapBrowserEventHandler(new ol.Map({}), 8);
pointerdownAt0 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: 0,
clientY: 0
});
defaultHandler.handlePointerDown_(pointerdownAt0);
moveToleranceHandler.handlePointerDown_(pointerdownAt0);
});
it('is not moving if distance is 0', function() {
var pointerdownAt0 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: 0,
clientY: 0
});
expect(defaultHandler.isMoving_(pointerdownAt0)).to.be(false);
});
it('is moving if distance is 2', function() {
var pointerdownAt2 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: ol.has.DEVICE_PIXEL_RATIO + 1,
clientY: ol.has.DEVICE_PIXEL_RATIO + 1
});
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
});
it('is moving with negative distance', function() {
var pointerdownAt2 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: -(ol.has.DEVICE_PIXEL_RATIO + 1),
clientY: -(ol.has.DEVICE_PIXEL_RATIO + 1)
});
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
});
it('is not moving if distance is less than move tolerance', function() {
var pointerdownAt2 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: ol.has.DEVICE_PIXEL_RATIO + 1,
clientY: ol.has.DEVICE_PIXEL_RATIO + 1
});
expect(moveToleranceHandler.isMoving_(pointerdownAt2)).to.be(false);
});
it('is moving if distance is greater than move tolerance', function() {
var pointerdownAt9 = new ol.pointer.PointerEvent('pointerdown', {}, {
clientX: (ol.has.DEVICE_PIXEL_RATIO * 8) + 1,
clientY: (ol.has.DEVICE_PIXEL_RATIO * 8) + 1
});
expect(moveToleranceHandler.isMoving_(pointerdownAt9)).to.be(true);
});
});
});

View File

@@ -14,7 +14,7 @@ describe('ol.render.Feature', function() {
describe('Constructor', function() {
it('creates an instance', function() {
renderFeature =
new ol.render.Feature(type, flatCoordinates, ends, properties);
new ol.render.Feature(type, flatCoordinates, ends, properties, 'foo');
expect(renderFeature).to.be.a(ol.render.Feature);
});
});
@@ -57,6 +57,12 @@ describe('ol.render.Feature', function() {
});
});
describe('#getId()', function() {
it('returns the feature id', function() {
expect(renderFeature.getId()).to.be('foo');
});
});
describe('#getProperties()', function() {
it('returns the properties it was created with', function() {
expect(renderFeature.getProperties()).to.equal(properties);

View File

@@ -62,6 +62,11 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
tileClass: TileClass,
tileGrid: ol.tilegrid.createXYZ()
});
source.getTile = function() {
var tile = ol.source.VectorTile.prototype.getTile.apply(source, arguments);
tile.setState(ol.TileState.LOADED);
return tile;
};
layer = new ol.layer.VectorTile({
source: source,
style: layerStyle
@@ -156,12 +161,18 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
tileGrid: ol.tilegrid.createXYZ()
})
});
var tile = new ol.VectorTile([0, 0, 0], 2);
tile.projection_ = ol.proj.get('EPSG:3857');
tile.features_ = [];
tile.getImage = function() {
var sourceTile = new ol.VectorTile([0, 0, 0], 2);
sourceTile.setProjection(ol.proj.get('EPSG:3857'));
sourceTile.features_ = [];
sourceTile.getImage = function() {
return document.createElement('canvas');
};
var tile = new ol.VectorImageTile([0, 0, 0]);
tile.wrappedTileCoord = [0, 0, 0];
tile.setState(ol.TileState.LOADED);
tile.getSourceTile = function() {
return sourceTile;
};
layer.getSource().getTile = function() {
return tile;
};
@@ -195,12 +206,19 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
describe('#forEachFeatureAtCoordinate', function() {
var layer, renderer, replayGroup;
var TileClass = function() {
ol.VectorTile.apply(this, arguments);
ol.VectorImageTile.apply(this, arguments);
this.setState('loaded');
this.setProjection(ol.proj.get('EPSG:3857'));
this.replayState_.replayGroup = replayGroup;
var sourceTile = new ol.VectorTile([0, 0, 0]);
sourceTile.setProjection(ol.proj.get('EPSG:3857'));
sourceTile.getReplayGroup = function() {
return replayGroup;
};
ol.inherits(TileClass, ol.VectorTile);
var key = sourceTile.tileCoord.toString();
this.tileKeys = [key];
this.sourceTiles_ = {};
this.sourceTiles_[key] = sourceTile;
};
ol.inherits(TileClass, ol.VectorImageTile);
beforeEach(function() {
replayGroup = {};
@@ -226,6 +244,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
layerStates: {},
skippedFeatureUids: {},
viewState: {
projection: ol.proj.get('EPSG:3857'),
resolution: 1,
rotation: 0
}

View File

@@ -32,6 +32,45 @@ describe('ol.source.TileJSON', function() {
}
});
});
it ('parses inline TileJSON', function() {
var tileJSON = {
bounds: [
-180,
-85.05112877980659,
180,
85.05112877980659
],
center: [
0,
0,
4
],
created: 1322764050886,
description: 'One of the example maps that comes with TileMill - a bright & colorful world map that blends retro and high-tech with its folded paper texture and interactive flag tooltips. ',
download: 'https://a.tiles.mapbox.com/v3/mapbox.geography-class.mbtiles',
embed: 'https://a.tiles.mapbox.com/v3/mapbox.geography-class.html',
id: 'mapbox.geography-class',
mapbox_logo: true,
maxzoom: 8,
minzoom: 0,
name: 'Geography Class',
private: false,
scheme: 'xyz',
tilejson: '2.2.0',
tiles: [
'https://a.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png',
'https://b.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png'
],
version: '1.0.0',
webpage: 'https://a.tiles.mapbox.com/v3/mapbox.geography-class/page.html'
};
var source = new ol.source.TileJSON({
tileJSON: tileJSON
});
expect(source.getState()).to.be('ready');
expect(source.getTileUrlFunction()([0, 0, -1])).to.be('https://b.tiles.mapbox.com/v3/mapbox.geography-class/0/0/0.png');
});
});
describe('#getState', function() {

View File

@@ -1,6 +1,6 @@
goog.provide('ol.test.source.VectorTile');
goog.require('ol.VectorTile');
goog.require('ol.VectorImageTile');
goog.require('ol.format.MVT');
goog.require('ol.proj');
goog.require('ol.source.VectorTile');
@@ -12,8 +12,9 @@ describe('ol.source.VectorTile', function() {
var format = new ol.format.MVT();
var source = new ol.source.VectorTile({
format: format,
tileGrid: ol.tilegrid.createXYZ(),
url: '{z}/{x}/{y}.pbf'
tileGrid: ol.tilegrid.createXYZ({tileSize: 512}),
tilePixelRatio: 8,
url: 'spec/ol/data/{z}-{x}-{y}.vector.pbf'
});
var tile;
@@ -29,7 +30,7 @@ describe('ol.source.VectorTile', function() {
describe('#getTile()', function() {
it('creates a tile with the correct tile class', function() {
tile = source.getTile(0, 0, 0, 1, ol.proj.get('EPSG:3857'));
expect(tile).to.be.a(ol.VectorTile);
expect(tile).to.be.a(ol.VectorImageTile);
});
it('sets the correct tileCoord on the created tile', function() {
expect(tile.getTileCoord()).to.eql([0, 0, 0]);
@@ -40,4 +41,28 @@ describe('ol.source.VectorTile', function() {
});
});
describe('#getTileGridForProjection', function() {
it('creates a tile grid with the source tile grid\'s tile size', function() {
var tileGrid = source.getTileGridForProjection(ol.proj.get('EPSG:3857'));
expect(tileGrid.getTileSize(0)).to.be(512);
});
});
describe('Tile load events', function() {
it('triggers tileloadstart and tileloadend with ol.VectorTile', function(done) {
tile = source.getTile(14, 8938, -5681, 1, ol.proj.get('EPSG:3857'));
var started = false;
source.on('tileloadstart', function() {
started = true;
});
source.on('tileloadend', function(e) {
expect(started).to.be(true);
expect(e.tile).to.be.a(ol.VectorTile);
expect(e.tile.getFeatures().length).to.be(1327);
done();
});
tile.load();
});
});
});

View File

@@ -313,4 +313,29 @@ describe('ol.structs.RBush', function() {
});
describe('#concat', function() {
it('concatenates two RBush objects', function() {
var obj1 = {};
var obj2 = {};
var rBush2 = new ol.structs.RBush();
rBush.insert([0, 0, 1, 1], obj1);
rBush2.insert([0, 0, 2, 2], obj2);
rBush.concat(rBush2);
expect(rBush.getExtent()).to.eql([0, 0, 2, 2]);
expect(rBush.getAll().length).to.be(2);
});
it('preserves the concatenated object\'s references', function() {
var obj1 = {};
var obj2 = {};
var rBush2 = new ol.structs.RBush();
rBush.insert([0, 0, 1, 1], obj1);
rBush2.insert([0, 0, 2, 2], obj2);
rBush.concat(rBush2);
rBush.update([0, 0, 3, 3], obj2);
expect(rBush.getExtent()).to.eql([0, 0, 3, 3]);
});
});
});

View File

@@ -36,22 +36,6 @@ describe('ol.style.RegularShape', function() {
expect(style.getRadius2()).to.eql(10);
});
it('will use radius for radius2 if radius2 not defined', function() {
var style = new ol.style.RegularShape({
radius: 5
});
expect(style.getRadius()).to.eql(5);
expect(style.getRadius2()).to.eql(5);
});
it('will use radius1 for radius2 if radius2 not defined', function() {
var style = new ol.style.RegularShape({
radius1: 5
});
expect(style.getRadius()).to.eql(5);
expect(style.getRadius2()).to.eql(5);
});
it('creates a canvas if no atlas is used (no fill-style)', function() {
var style = new ol.style.RegularShape({radius: 10});
expect(style.getImage()).to.be.an(HTMLCanvasElement);

View File

@@ -0,0 +1,107 @@
goog.provide('ol.test.VectorImageTile');
goog.require('ol.events');
goog.require('ol.VectorImageTile');
goog.require('ol.VectorTile');
goog.require('ol.format.GeoJSON');
goog.require('ol.proj');
describe('ol.VectorImageTile', function() {
it('configures loader that sets features on the source tile', function(done) {
var format = new ol.format.GeoJSON();
var url = 'spec/ol/data/point.json';
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {
return url;
}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ(), {},
1, ol.proj.get('EPSG:3857'), ol.VectorTile, function() {});
tile.load();
var sourceTile = tile.getTile(tile.tileKeys[0]);
var loader = sourceTile.loader_;
expect(typeof loader).to.be('function');
ol.events.listen(sourceTile, 'change', function(e) {
expect(sourceTile.getFeatures().length).to.be.greaterThan(0);
done();
});
});
it('sets ERROR state when source tiles fail to load', function(done) {
var format = new ol.format.GeoJSON();
var url = 'spec/ol/data/unavailable.json';
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {
return url;
}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ(), {},
1, ol.proj.get('EPSG:3857'), ol.VectorTile, function() {});
tile.load();
ol.events.listen(tile, 'change', function(e) {
expect(tile.getState()).to.be(ol.TileState.ERROR);
done();
});
});
it('sets EMPTY state when tile has only empty source tiles', function(done) {
var format = new ol.format.GeoJSON();
var url = '';
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {},
ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ(), {},
1, ol.proj.get('EPSG:3857'), ol.VectorTile, function() {});
tile.load();
ol.events.listen(tile, 'change', function() {
expect(tile.getState()).to.be(ol.TileState.EMPTY);
done();
});
});
it('#dispose() while loading', function() {
var format = new ol.format.GeoJSON();
var url = 'spec/ol/data/point.json';
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {
return url;
}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ({tileSize: 512}), {},
1, ol.proj.get('EPSG:3857'), ol.VectorTile, function() {});
tile.load();
expect(tile.loadListenerKeys_.length).to.be(4);
expect(tile.tileKeys.length).to.be(4);
expect(tile.getState()).to.be(ol.TileState.LOADING);
tile.dispose();
expect(tile.loadListenerKeys_.length).to.be(0);
expect(tile.tileKeys.length).to.be(0);
expect(tile.sourceTiles_).to.be(null);
expect(tile.getState()).to.be(ol.TileState.ABORT);
});
it('#dispose() when loaded', function(done) {
var format = new ol.format.GeoJSON();
var url = 'spec/ol/data/point.json';
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {
return url;
}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ({tileSize: 512}), {},
1, ol.proj.get('EPSG:3857'), ol.VectorTile, function() {});
tile.load();
ol.events.listenOnce(tile, 'change', function() {
expect(tile.getState()).to.be(ol.TileState.LOADED);
expect(tile.loadListenerKeys_.length).to.be(0);
expect(tile.tileKeys.length).to.be(4);
tile.dispose();
expect(tile.tileKeys.length).to.be(0);
expect(tile.sourceTiles_).to.be(null);
expect(tile.getState()).to.be(ol.TileState.ABORT);
done();
});
});
});

View File

@@ -1,39 +1,14 @@
goog.provide('ol.test.VectorTile');
goog.require('ol.events');
goog.require('ol.VectorImageTile');
goog.require('ol.VectorTile');
goog.require('ol.Feature');
goog.require('ol.format.GeoJSON');
goog.require('ol.format.TextFeature');
goog.require('ol.proj');
describe('ol.VectorTile.defaultLoadFunction()', function() {
it('sets the loader function on the tile', function() {
var format = new ol.format.GeoJSON();
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
var url = 'https://example.com/';
ol.VectorTile.defaultLoadFunction(tile, url);
var loader = tile.loader_;
expect(typeof loader).to.be('function');
});
it('loader sets features on the tile', function(done) {
var format = new ol.format.GeoJSON();
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
var url = 'spec/ol/data/point.json';
ol.VectorTile.defaultLoadFunction(tile, url);
var loader = tile.loader_;
ol.events.listen(tile, 'change', function(e) {
expect(tile.getFeatures().length).to.be.greaterThan(0);
done();
});
loader.call(tile, [], 1, ol.proj.get('EPSG:3857'));
});
describe('ol.VectorTile', function() {
it('loader sets features on the tile and updates proj units', function(done) {
// mock format that return a tile-pixels feature
@@ -51,7 +26,7 @@ describe('ol.VectorTile.defaultLoadFunction()', function() {
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
var url = 'spec/ol/data/point.json';
ol.VectorTile.defaultLoadFunction(tile, url);
ol.VectorImageTile.defaultLoadFunction(tile, url);
var loader = tile.loader_;
ol.events.listen(tile, 'change', function(e) {
expect(tile.getFeatures().length).to.be.greaterThan(0);

View File

@@ -462,8 +462,9 @@
};
var features = {
ArrayBuffer: typeof ArrayBuffer === 'function',
'ArrayBuffer.isView': typeof ArrayBuffer === 'function' && ArrayBuffer.isView,
ArrayBuffer: 'ArrayBuffer' in global,
'ArrayBuffer.isView': 'ArrayBuffer' in global && !!ArrayBuffer.isView,
FileReader: 'FileReader' in global,
Uint8ClampedArray: ('Uint8ClampedArray' in global)
};

View File

@@ -132,7 +132,7 @@ module.exports = function(info, api) {
// replace `ol.VERSION = ''` with correct version
root.find(j.ExpressionStatement, getMemberExpressionAssignment('ol.VERSION'))
.forEach(path => {
path.value.expression.right = j.literal(thisPackage.version);
path.value.expression.right = j.literal('v' + thisPackage.version);
});
const replacements = {};