Compare commits

..

186 Commits

Author SHA1 Message Date
Tim Schaub
a73170ca1d Merge pull request #7458 from tschaub/release-v4.5.0
Release v4.5.0
2017-11-12 17:19:14 -07:00
Tim Schaub
c811bd488e Collapsed list of dependency changes 2017-11-12 11:35:32 -07:00
Tim Schaub
ce051b78a9 Update package version to 4.5.0 2017-11-12 11:25:08 -07:00
Tim Schaub
1103779432 Changelog for v4.5.0 2017-11-12 11:24:26 -07:00
Tim Schaub
bbec759c5e Merge pull request #7456 from tschaub/connect-retries
Retry if sauce connect fails
2017-11-12 07:29:49 -07:00
Tim Schaub
a2c5ce6925 Retry if sauce connect fails 2017-11-11 10:54:13 -07:00
Tim Schaub
54c69ae1c6 Merge pull request #7455 from openlayers/greenkeeper/eslint-4.11.0
Update eslint to the latest version 🚀
2017-11-10 20:13:19 -07:00
greenkeeper[bot]
0bd989e917 chore(package): update eslint to version 4.11.0 2017-11-11 00:00:58 +00:00
Frédéric Junod
93abd6fe57 Merge pull request #7447 from openlayers/greenkeeper/rollup-plugin-commonjs-8.2.6
chore(package): update rollup-plugin-commonjs to version 8.2.6
2017-11-10 11:14:53 +01:00
Frédéric Junod
3d8f39804e Merge pull request #7448 from openlayers/greenkeeper/debounce-1.1.0
chore(package): update debounce to version 1.1.0
2017-11-10 10:57:58 +01:00
greenkeeper[bot]
b2ef54d4a7 chore(package): update debounce to version 1.1.0 2017-11-10 10:35:55 +01:00
greenkeeper[bot]
09a324bc6b chore(package): update rollup-plugin-commonjs to version 8.2.6 2017-11-10 10:34:29 +01:00
Frédéric Junod
07631e4d1f Merge pull request #7451 from openlayers/greenkeeper/karma-1.7.1
chore(package): update karma to version 1.7.1
2017-11-10 10:32:14 +01:00
greenkeeper[bot]
4aee919de2 chore(package): update karma to version 1.7.1 2017-11-10 10:18:42 +01:00
Andreas Hocevar
6cc3c47d95 Merge pull request #7440 from ahocevar/font-load
Attempt to make font loading tests more stable
2017-11-10 10:09:42 +01:00
Andreas Hocevar
55692c3da5 Merge pull request #7446 from openlayers/greenkeeper/rollup-0.51.3
fix(package): update rollup to version 0.51.3
2017-11-10 09:47:01 +01:00
Andreas Hocevar
dbfca19e09 Merge pull request #7444 from ahocevar/simpler-style-management
Simpler style management
2017-11-10 08:44:25 +01:00
Andreas Hocevar
4324d49813 Attempt to make font loading tests more stable
Also changes things to use setInterval() instead of setTimeout().
2017-11-10 08:34:30 +01:00
greenkeeper[bot]
2da2ae0154 fix(package): update rollup to version 0.51.3
Closes #7432
2017-11-10 07:14:09 +00:00
Andreas Hocevar
c6eca804f9 Refactor stroke style management to reuse code 2017-11-10 01:16:18 +01:00
Andreas Hocevar
47e6918072 Refactor setTextStyle() for better readability 2017-11-09 16:42:41 +01:00
Andreas Hocevar
c1181bdfe7 Merge pull request #7438 from ahocevar/source-projection
Call getProjection() only once
2017-11-09 14:44:20 +01:00
Tim Schaub
9a8afff0fa Merge pull request #7430 from tschaub/hexa
Add support for hex colors with alpha
2017-11-09 06:38:27 -07:00
Andreas Hocevar
0ec05f5795 Call getProjection() only once 2017-11-09 08:08:41 +01:00
Tim Schaub
6668d03122 Add support for hex colors with alpha 2017-11-08 09:53:22 -07:00
Tim Schaub
3a6fc7a1f2 Merge pull request #7431 from tschaub/defined-zoom
Avoid returning undefined zoom
2017-11-08 09:32:33 -07:00
Andreas Hocevar
be06224756 Merge pull request #7436 from pjeweb/patch-1
Always use source projection loading image tiles
2017-11-08 17:01:33 +01:00
Frédéric Junod
9fe032b49c Merge pull request #7433 from fredj/hints
Don't use getHints if it's not needed
2017-11-08 14:46:31 +01:00
pjeweb
b9313e76f4 Always use source projection loading image tiles
Use the defined source projection despite it being equivalent to the rendering projection to enable using the specified alias code name instead of the code provided by the renderer's projection object. For example: The server only knows the name "EPSG:900913", which is an alias for the equivalent "EPSG:3857", that the renderer uses (by default).
2017-11-08 14:36:46 +01:00
Frederic Junod
0d01a4ca0f Don't use getHints if it's not needed
memory optimization: `getHints` creates a copy of the hints array.
2017-11-08 11:47:29 +01:00
Frederic Junod
82da43af35 Use getAnimating and getInteracting from ol.View 2017-11-08 11:47:29 +01:00
Tim Schaub
967118e699 Avoid returning undefined zoom 2017-11-07 18:40:58 -07:00
Andreas Hocevar
0fceb2f3e3 Merge pull request #7428 from openlayers/greenkeeper/sinon-4.1.2
Update sinon to the latest version 🚀
2017-11-07 22:52:54 +01:00
Andreas Hocevar
ccab7be20a Merge pull request #7362 from Alexandre27/master
Added option to the ol.format.GeoJSON to allow the reading of the geometry_name from the geojson
2017-11-07 22:52:30 +01:00
greenkeeper[bot]
39e3e9f915 chore(package): update sinon to version 4.1.2 2017-11-07 17:41:49 +00:00
Alexandre Silva
cd5e5039e9 Changed option name to extractGeometryName 2017-11-07 10:24:10 +00:00
Andreas Hocevar
36fd49334c Merge pull request #7425 from openlayers/greenkeeper/async-2.6.0
Update async to the latest version 🚀
2017-11-07 08:18:54 +01:00
Andreas Hocevar
2e982deba6 Merge pull request #7426 from glen-nu/update-handleEvent-docs
Update InteractionOptions.prototype.handleEvent docs
2017-11-07 08:18:29 +01:00
glen-nu
2ebb1ce8fa update InteractionOptions.prototype.handleEvent docs
`InteractionOptions.prototype.handleEvent` stops propagation on falsy return, not explicit `false`
2017-11-07 14:16:01 +08:00
greenkeeper[bot]
d7bf98f49f fix(package): update async to version 2.6.0 2017-11-07 03:29:08 +00:00
Tim Schaub
2b09dc8b70 Merge pull request #7423 from tschaub/get-wrapped-features
Get rendered features by coordinate when wrapping
2017-11-06 17:14:52 -07:00
Tim Schaub
dbeef9f73e Use wrapped tile coord for getting feature at coordinate 2017-11-06 10:53:44 -07:00
Tim Schaub
8a6fe81f09 Example demonstrating how to get feature properties from vector tiles 2017-11-06 09:57:16 -07:00
Tim Schaub
4ea72c2483 Merge pull request #7421 from tschaub/one-world
Keep longitude between -180 and 180
2017-11-06 08:15:23 -07:00
Bart van den Eijnden
d15a85c402 Merge pull request #7420 from TDesjardins/master
Fix MapGuide example resolves #7325
2017-11-06 14:53:54 +01:00
Tim Schaub
42da3f18dd Keep longitude between -180 and 180 2017-11-06 06:39:17 -07:00
Alexandre Silva
260327341c Documented the default value. 2017-11-06 11:10:49 +00:00
Tino Desjardins
7cb8b526a9 Format source code 2017-11-04 14:53:21 +01:00
Tino Desjardins
02016cf244 Fix MapGuide example 2017-11-04 14:38:36 +01:00
Andreas Hocevar
4a6317dde3 Merge pull request #7340 from ahocevar/check-font-loaded
Clear label cache when fonts become available
2017-11-03 14:23:38 +01:00
Andreas Hocevar
129350d863 Fix return type 2017-11-03 13:54:41 +01:00
Andreas Hocevar
72eb8ab5e8 Define font as variable 2017-11-03 13:52:06 +01:00
Andreas Hocevar
5483fa3181 More efficient font checking loop 2017-11-03 13:52:06 +01:00
Andreas Hocevar
8c46f6d1f0 Workaround for a Safari issue 2017-11-03 13:04:06 +01:00
Andreas Hocevar
7f865b8520 Check if fonts are available and redraw when label cache was cleared 2017-11-03 13:04:06 +01:00
Tim Schaub
dea8a340a6 Add utility method for extracting font families from a font spec 2017-11-03 12:55:12 +01:00
Tim Schaub
06728ab0fa Quote font names with spaces 2017-11-03 12:55:12 +01:00
Andreas Hocevar
a80458f2c3 Show dynamic font loading in the ugly vector-labels example 2017-11-03 12:55:12 +01:00
Andreas Hocevar
2451c8f1d0 Merge pull request #7414 from ahocevar/preserve-ligatures
Only split text at line angle changes
2017-11-03 12:13:10 +01:00
Andreas Hocevar
431d570b91 Only split text at line angle changes 2017-11-03 11:26:38 +01:00
Frédéric Junod
ddba26b193 Merge pull request #7411 from fredj/getset_layers
Add getLayers and setLayers functions to ol.format.WMSGetFeatureInfo
2017-11-03 11:22:29 +01:00
Andreas Hocevar
f05511cff7 Merge pull request #7328 from ahocevar/declutter
Declutter text and images
2017-11-03 11:22:08 +01:00
Frédéric Junod
e55985818f Merge pull request #7418 from openlayers/greenkeeper/sinon-4.1.1
Update sinon to the latest version 🚀
2017-11-03 10:58:02 +01:00
Frederic Junod
8a9d6b417f Add getLayers and setLayers functions to ol.format.WMSGetFeatureInfo 2017-11-03 10:51:25 +01:00
Andreas Hocevar
306851d6ee Consistent naming of declutterTree 2017-11-03 10:36:28 +01:00
greenkeeper[bot]
70dc35cc6c chore(package): update sinon to version 4.1.1 2017-11-03 08:56:02 +00:00
Andreas Hocevar
bfebc50a48 Merge pull request #7406 from lasselaakkonen/7390-zoomify-custom-extent
Add option to Zoomify source for setting custom extent
2017-11-03 07:17:22 +01:00
Andreas Hocevar
50b50ae21f Merge pull request #7416 from openlayers/greenkeeper/sinon-4.1.0
Update sinon to the latest version 🚀
2017-11-03 07:13:34 +01:00
Andreas Hocevar
a5625955a8 Merge pull request #7417 from openlayers/greenkeeper/phantomjs-prebuilt-2.1.16
Update phantomjs-prebuilt to the latest version 🚀
2017-11-03 07:13:16 +01:00
greenkeeper[bot]
47a1aed750 chore(package): update phantomjs-prebuilt to version 2.1.16 2017-11-02 20:27:57 +00:00
greenkeeper[bot]
4afb5bfd40 chore(package): update sinon to version 4.1.0 2017-11-02 17:12:29 +00:00
Frédéric Junod
8ef9b8feea Merge pull request #7410 from fredj/getset_getFeatureType
Add getFeatureType and setFeatureType functions to ol.format.WFS
2017-11-01 15:32:25 +01:00
Frederic Junod
daea26ec50 Add getFeatureType and setFeatureType functions to ol.format.WFS 2017-11-01 14:07:54 +01:00
Lasse Laakkonen
1cf8631889 Add extent property definition to olx.source.ZoomifyOptions definition. 2017-11-01 00:30:20 +02:00
Lasse Laakkonen
eefb3f9207 Add option to Zoomify source for setting custom extent.
https://github.com/openlayers/openlayers/issues/7390
2017-11-01 00:20:43 +02:00
Andreas Hocevar
e6ae029d08 Improve text rendering performance 2017-10-31 11:33:48 +01:00
Andreas Hocevar
6ce201c429 Do not render text along oversimplified geometries 2017-10-31 11:33:48 +01:00
Andreas Hocevar
b29e74d1ab Measure height only once per font 2017-10-31 11:33:48 +01:00
Andreas Hocevar
4a73754b93 Entertain the compiler 2017-10-31 11:33:48 +01:00
Andreas Hocevar
dfa3cbf4e2 Use native decluttering in vector-label-decluttering example 2017-10-31 11:33:48 +01:00
Andreas Hocevar
29ebdde314 Test decluttering for vector tile layers 2017-10-31 11:33:48 +01:00
Andreas Hocevar
912e908032 Test decluttered hit detection 2017-10-31 11:33:48 +01:00
Andreas Hocevar
53a2cf55f1 Fix hit detection for decluttered layers 2017-10-31 11:33:48 +01:00
Andreas Hocevar
f4506d87eb Use existing sort function 2017-10-31 11:33:48 +01:00
Andreas Hocevar
22e4ba06a6 Add rendering tests 2017-10-31 11:33:48 +01:00
Andreas Hocevar
80e67bac7a Give lower z-index priority (painter's order) 2017-10-31 11:33:48 +01:00
Andreas Hocevar
b3f9e4e8ef Improve documentation 2017-10-31 11:33:48 +01:00
Andreas Hocevar
08af207724 Add decluttering for images and text 2017-10-31 11:33:48 +01:00
Andreas Hocevar
5ebc969599 Support line and polygon label points for ol.render.Feature 2017-10-31 11:33:48 +01:00
Andreas Hocevar
dbeb3d2795 Only render parts of source tile that are needed for the view tile 2017-10-31 11:33:48 +01:00
Andreas Hocevar
742a71cd4b Only render images when visible 2017-10-31 11:33:48 +01:00
Andreas Hocevar
1a1d45fdd1 Merge pull request #7379 from lasselaakkonen/6608-zoomify-custom-tile-size
Add support for custom tile size to Zoomify source
2017-10-31 10:50:37 +01:00
Andreas Hocevar
da2a23aacd Always use ol.Size tile size array 2017-10-31 10:36:20 +01:00
Lasse Laakkonen
3c8c7db8f3 Fix using multiple Zoomify sources at a time.. 2017-10-31 11:12:18 +02:00
Lasse Laakkonen
2836f9511f Remove unnecessary changes to Tile and ImageTile for changing Zoomify source tile size. 2017-10-31 09:31:38 +02:00
Lasse Laakkonen
e2581931a7 Add tileSize property definition to olx.source.ZoomifyOptions definition. 2017-10-30 21:53:52 +02:00
Frédéric Junod
435f93a197 Merge pull request #7376 from virtualcitySYSTEMS/feature-overlay-visibility
changed visibility of overlay properties to protected
2017-10-30 08:37:40 +01:00
Frédéric Junod
27eaa0d8c0 Merge pull request #7399 from openlayers/greenkeeper/eslint-4.10.0
Update eslint to the latest version 🚀
2017-10-30 08:29:35 +01:00
greenkeeper[bot]
00807ea98f chore(package): update eslint to version 4.10.0 2017-10-27 23:38:25 +00:00
Jannes Bolling
a802f5937b changed visibility of overlay properties to protected,
added new getOptions function to overlay, to get the original options

remove trailing underscore from protected properties and functions
2017-10-27 16:10:39 +02:00
Frédéric Junod
485680919e Merge pull request #7395 from openlayers/greenkeeper/closure-util-1.25.0
Update closure-util to the latest version 🚀
2017-10-27 10:12:12 +02:00
greenkeeper[bot]
cae6a07aa7 fix(package): update closure-util to version 1.25.0 2017-10-27 07:29:23 +00:00
Frédéric Junod
d33e41d322 Merge pull request #7392 from openlayers/greenkeeper/sinon-4.0.2
Update sinon to the latest version 🚀
2017-10-26 08:58:00 +02:00
greenkeeper[bot]
8d59b5d301 chore(package): update sinon to version 4.0.2 2017-10-25 17:20:30 +00:00
Frédéric Junod
5a6fafd85b Merge pull request #7377 from notnotse/overlay-classname
Add support to specify CSS class name when creating ol.Overlay
2017-10-25 15:32:24 +02:00
Andreas Hocevar
eeb20cf4ad Merge pull request #7383 from ahocevar/null-tilecoord
Handle null tile coordinates correctly
2017-10-22 21:59:35 +02:00
Frédéric Junod
35a357ee80 Merge pull request #7375 from fredj/ows_more_ServiceIdentification
Read 'Abstract', 'AccessConstraints' and 'Fees' in ol.format.OWS
2017-10-22 08:49:06 +02:00
Andreas Hocevar
6da92d5f71 Handle null tile coordinates correctly 2017-10-21 21:41:56 +02:00
Frédéric Junod
a625d1f1a8 Merge pull request #7378 from notnotse/fix-raster-source-docs
Fix incorrect docs about ol.source.Raster
2017-10-20 16:51:05 +02:00
Andreas Hocevar
10f59fc81c Merge pull request #7380 from openlayers/greenkeeper/rollup-plugin-cleanup-2.0.0
Update rollup-plugin-cleanup to the latest version 🚀
2017-10-20 10:55:14 +02:00
greenkeeper[bot]
0c9e2458e6 fix(package): update rollup-plugin-cleanup to version 2.0.0 2017-10-19 21:40:58 +00:00
Lasse Laakkonen
b8589acc6e Add test for initializing Zoomify source with custom tile size. 2017-10-19 17:54:46 +03:00
Bobo Häggström
7a800d4b39 Add support to specify CSS class name when creating ol.Overlay 2017-10-19 16:06:24 +02:00
itjope
f7b6682832 Fix incorrect docs about ol.source.Raster 2017-10-19 15:37:00 +02:00
Lasse Laakkonen
e41693816a Add support for custom tile size to Zoomify layer.
https://github.com/openlayers/openlayers/issues/6608
2017-10-19 15:39:47 +03:00
Andreas Hocevar
8d5a8665b2 Merge pull request #7371 from notnotse/vt-missing-api-annotation
Add @api annotation to ol.VectorTile.getExtent
2017-10-19 12:57:20 +02:00
Frederic Junod
e235c83231 Read 'Abstract', 'AccessConstraints' and 'Fees' in ol.format.OWS 2017-10-19 12:03:02 +02:00
Bobo Häggström
cdea7040ee Add @api annotation to ol.VectorTile.getExtent 2017-10-19 08:38:54 +02:00
Frédéric Junod
0e9bd75bc6 Merge pull request #7369 from fredj/bing_culture
Always request the Bing API with the 'culture' value
2017-10-19 08:25:31 +02:00
Frederic Junod
2e2e63a3e0 Always request the Bing API with the 'culture' value 2017-10-18 17:07:33 +02:00
Frédéric Junod
a121806715 Merge pull request #7366 from openlayers/greenkeeper/handlebars-4.0.11
Update handlebars to the latest version 🚀
2017-10-18 08:23:46 +02:00
greenkeeper[bot]
2268cbe90f chore(package): update handlebars to version 4.0.11 2017-10-17 21:05:07 +00:00
Frédéric Junod
82b7116f81 Merge pull request #7364 from fredj/rm_geojson_geoserver_workaround
Remove GeoJSON workaround for GeoServer
2017-10-17 16:52:59 +02:00
Tim Schaub
ab85a91efd Merge pull request #7355 from marcosox/master
Pass pixel tolerance as a parameter to constructor of ol.interaction.Extent
2017-10-17 08:44:42 -06:00
Frederic Junod
bcfad6ea8b Remove GeoJSON workaround for GeoServer
See #1569
See https://osgeo-org.atlassian.net/browse/GEOS-5996
2017-10-17 08:32:16 +02:00
Alexandre Silva
011285aefe Added option to the ol.format.GeoJSON to allow the reading of the geometry_name from the geojson. 2017-10-16 14:51:55 +01:00
marcosox
850aaf96f2 Add pixelTolerance to olx.interaction.ExtentOptions 2017-10-16 15:46:12 +02:00
marcosox
d40dd695cb Pass pixel tolerance as a parameter to constructor of ol.interaction.Extent
This adds the pixelTolerance option parameter to the constructor of ol.interaction.Extent.
In this way the user can override the current default value of 10.
2017-10-16 15:36:42 +02:00
Tim Schaub
382c6b9832 Merge pull request #7360 from openlayers/greenkeeper/eslint-4.9.0
Update eslint to the latest version 🚀
2017-10-14 16:58:32 -06:00
greenkeeper[bot]
660a661aa1 chore(package): update eslint to version 4.9.0 2017-10-14 21:19:32 +00:00
Tim Schaub
924780abf1 Merge pull request #7356 from EduardoNogueira/master
Fix documentation for target option in the controls
2017-10-14 12:13:37 -06:00
Tim Schaub
7d8a74ee5a Merge pull request #7359 from akkumar/rollup_options_fix
Rename entry to input - regarding options to rollup lib - Issue #7358
2017-10-14 12:09:34 -06:00
Karthik Kumar A
02b899869d rename entry to input - regarding options to rollup lib - Issue #7358 2017-10-14 14:18:20 +05:30
Tim Schaub
1f34f17436 Merge pull request #7357 from tschaub/release-v4.4.2
Release v4.4.2
2017-10-13 17:27:20 -06:00
Eduardo Nogueira
ad29aa742e Fix documentation for target option in the controls 2017-10-13 18:20:45 +01:00
Frédéric Junod
d2e6acd478 Merge pull request #7354 from openlayers/greenkeeper/closure-util-1.24.2
Update closure-util to the latest version 🚀
2017-10-13 16:10:28 +02:00
greenkeeper[bot]
80d5cc87c4 fix(package): update closure-util to version 1.24.2 2017-10-13 13:42:29 +00:00
Andreas Hocevar
fe1d01a3cb Merge pull request #7350 from ahocevar/text-box
Calculate correct text box size
2017-10-12 07:04:39 +02:00
Andreas Hocevar
c2926df045 Merge pull request #7349 from ahocevar/vectortile-url
Do not use tileUrlFunction for renderer tile coordinates
2017-10-12 07:04:00 +02:00
Andreas Hocevar
8dbaf29fca Calculate correct text box size 2017-10-12 00:35:22 +02:00
Andreas Hocevar
ffb7d72c90 Do not use tileUrlFunction for renderer tile coordinates 2017-10-11 19:44:08 +02:00
Andreas Hocevar
e6534894fd Merge pull request #7305 from oterral/teo_info
Fix #7304: Re-calculate the resolution when the WMS source is reprojected
2017-10-11 17:04:33 +02:00
Andreas Hocevar
d74bef9fd7 Merge pull request #7346 from ahocevar/text-scale
Pre-render text images for configured scale
2017-10-11 16:06:04 +02:00
Andreas Hocevar
380690a6a3 Pre-render text images for configured scale 2017-10-11 15:51:15 +02:00
Andreas Hocevar
dcf38c22e2 Merge pull request #7345 from ahocevar/line-width
Handle different lineWidth scaling in Safari
2017-10-11 08:56:34 +02:00
Andreas Hocevar
b81952f142 Merge pull request #7344 from ahocevar/measure-width
Make text height detection independent of css settings
2017-10-11 08:56:02 +02:00
Andreas Hocevar
d0092ecd18 Handle different lineWidth scaling in Safari 2017-10-11 00:40:14 +02:00
Andreas Hocevar
1fcb94a29c Make text height detection independent of css settings 2017-10-11 00:21:29 +02:00
Tim Schaub
80dbedf946 Merge pull request #7341 from tschaub/raster-fix
Proper rendering of raster sources when there is a tile transition
2017-10-10 03:31:00 -06:00
Andreas Hocevar
609bd23eff Merge pull request #7339 from ahocevar/text-stroke
Use correct text stroke on HiDPI devices
2017-10-10 07:40:29 +02:00
Tim Schaub
373179ad82 Avoid unnecessary transition on raster sources 2017-10-09 18:24:21 -06:00
Tim Schaub
88ca77b8c7 Set time and handle frame animation in raster source 2017-10-09 18:24:15 -06:00
Tim Schaub
55b5d0c719 Merge pull request #7327 from tschaub/tile-management
Prune the tile cache after updating a source's URL
2017-10-09 17:01:12 -06:00
Tim Schaub
5558994827 Merge pull request #7333 from waxenegger/pluggable_calling
Pluggable Map/Layers - function calls to handles and create
2017-10-09 16:59:59 -06:00
Andreas Hocevar
1aafd8320d Allow reference image creation without existing reference image 2017-10-09 18:51:57 +02:00
Andreas Hocevar
02e23e3cd0 Take pixel ratio into account for text stroke 2017-10-09 18:51:45 +02:00
Tim Schaub
9b8232f65b Merge pull request #7329 from tschaub/attribution
Reworked attribution handling
2017-10-09 08:26:30 -06:00
Andreas Hocevar
83cfb77407 Merge pull request #7337 from ahocevar/blank-image
Always create a new blank image to avoid CSP violations
2017-10-09 13:24:49 +02:00
Andreas Hocevar
590dd6f1cf Always create a new blank image to avoid CSP violations 2017-10-09 12:46:34 +02:00
Harald Waxenegger
01b17de36d access functions via bracked/string to avoid compilation mangling 2017-10-09 15:23:56 +10:00
Tim Schaub
b94b8cc40d Add deprecation notes for ol.Attribution 2017-10-08 20:29:12 -06:00
Tim Schaub
2dd8fdb5b7 Reworked attribution handling 2017-10-08 20:29:02 -06:00
Tim Schaub
a5a0f5b98b Merge pull request #7330 from tschaub/upgrade-notes
Add upgrade notes to 4.4.0 changelog
2017-10-08 15:21:36 -06:00
Tim Schaub
2eb8ed047a Add upgrade notes to 4.4.0 changelog 2017-10-08 15:11:19 -06:00
Tim Schaub
bedec9d596 Consistent use of ol.tilecoord.getKeyZXY() 2017-10-08 09:08:20 -06:00
Tim Schaub
dbaf24ec39 Get rid of unnecessary coord key prefix 2017-10-08 09:08:20 -06:00
Tim Schaub
c96c9cfc6d Prune all except for the most recent z on URL change 2017-10-08 09:08:14 -06:00
Tim Schaub
c692b98fa9 Maintain rendering order in the LRU cache 2017-10-08 08:51:09 -06:00
Tim Schaub
9fb7778156 Functions to get key from coord and coord from key 2017-10-08 08:50:19 -06:00
Tim Schaub
177156c293 Method for peeking at the newest cache entry key 2017-10-08 08:43:53 -06:00
Tim Schaub
10af59bfce Allow items to be removed from the cache 2017-10-08 08:42:10 -06:00
Tim Schaub
ad5f21fa5c Merge pull request #7321 from tschaub/release-v4.4.1
Release v4.4.1
2017-10-06 11:13:29 -06:00
Tim Schaub
c5a05f1abd Merge pull request #7323 from tschaub/flashless
Only clear the canvas when needed
2017-10-06 09:31:50 -06:00
Tim Schaub
ad4a258c87 Only clear the canvas when needed 2017-10-06 09:12:52 -06:00
Frédéric Junod
7d8e2a7372 Merge pull request #7319 from openlayers/greenkeeper/closure-util-1.24.1
Update closure-util to the latest version 🚀
2017-10-06 15:24:38 +02:00
greenkeeper[bot]
adbc64507f fix(package): update closure-util to version 1.24.1 2017-10-06 13:03:07 +00:00
Tim Schaub
be32b0f769 Merge pull request #7313 from tschaub/patch
Use lowercase module identifiers until ol@5
2017-10-06 02:31:15 -06:00
Tim Schaub
57a5ffa40b Merge pull request #7316 from mprins/patch-1
fix copy-paste error in 4.4.0 changelog
2017-10-06 02:30:41 -06:00
Mark Prins
9c6c14a55c fix copy-paste error in 4.4.0 changelog
Also IMHO it doesn't make much sense to have issues of previous patch releases eg. 4.3.4 in here as these have their own release notes already, but I'll leave that for your debate
2017-10-06 09:14:56 +02:00
Frédéric Junod
ae906c7aff Merge pull request #7315 from fredj/contains_filter
Add new ol.format.filter.Contains spatial operator
2017-10-06 09:02:33 +02:00
Frédéric Junod
a7729cc602 Merge pull request #7314 from openlayers/greenkeeper/mocha-4.0.1
Update mocha to the latest version 🚀
2017-10-06 08:46:26 +02:00
Frederic Junod
dfe9e9b59a Add new ol.format.filter.Contains spatial operator 2017-10-06 08:45:17 +02:00
greenkeeper[bot]
a6a6ce9879 chore(package): update mocha to version 4.0.1 2017-10-06 05:15:58 +00:00
Tim Schaub
0802f50bc6 Use lowercase module identifiers until ol@5 2017-10-05 16:42:45 -06:00
Tim Schaub
9a50f9ff75 Merge pull request #7311 from tschaub/release-v4.4.0
Release v4.4.0
2017-10-05 15:55:10 -06:00
Kogis IWI
232f56e229 Fix #7304: Re-calculate the resolution when the WMS source is reprojected 2017-10-03 17:25:44 +02:00
121 changed files with 3261 additions and 1462 deletions

View File

@@ -1,6 +1,42 @@
## Upgrade notes
### Next Release
### v4.5.0
#### Removed GeoJSON crs workaround for GeoServer
Previous version of GeoServer returned invalid crs in GeoJSON output. The workaround in `ol.format.GeoJSON` used to read this crs code is now removed.
#### Deprecation of `ol.Attribution`
`ol.Attribution` is deprecated and will be removed in the next major version. Instead, you can construct a source with a string attribution or an array of strings. For dynamic attributions, you can provide a function that gets called with the current frame state.
Before:
```js
var source = new ol.source.XYZ({
attributions: [
new ol.Attribution({html: 'some attribution'})
]
});
```
After:
```js
var source = new ol.source.XYZ({
attributions: 'some attribution'
});
```
In addition to passing a string or an array of strings for the `attributions` option, you can also pass a function that will get called with the current frame state.
```js
var source = new ol.source.XYZ({
attributions: function(frameState) {
// inspect the frame state and return attributions
return 'some attribution'; // or ['multiple', 'attributions'] or null
}
});
```
### v4.4.0
#### Behavior change for polygon labels

View File

@@ -1,8 +1,51 @@
# 4.3.0
# 4.4.0
## Summary
The 4.3.0 release includes features and fixes from 80 pull requests, including first time contributions from @EduardoNogueira, @ath0mas, @f7o, @trevorblades, @viethang, and @wb14123. There are some really nice rendering enhancements included in this release. It is now possible to render labels along lines (see [#7239](https://github.com/openlayers/openlayers/pull/7239) for more detail) and polygon labels are only rendered if they fit within the polygon ([#7292](https://github.com/openlayers/openlayers/pull/7292)). In addition, we now render tiles with an opacity transition, so tiled layers more gracefully fade in ([#7267](https://github.com/openlayers/openlayers/pull/7267)).
The 4.4.0 release includes features and fixes from 80 pull requests, including first time contributions from @EduardoNogueira, @ath0mas, @f7o, @trevorblades, @viethang, and @wb14123. There are some really nice rendering enhancements included in this release. It is now possible to render labels along lines (see [#7239](https://github.com/openlayers/openlayers/pull/7239) for more detail) and polygon labels are only rendered if they fit within the polygon ([#7292](https://github.com/openlayers/openlayers/pull/7292)). In addition, we now render tiles with an opacity transition, so tiled layers more gracefully fade in ([#7267](https://github.com/openlayers/openlayers/pull/7267)).
### Upgrade notes
#### Behavior change for polygon labels
Polygon labels are now only rendered when the label does not exceed the polygon at the label position. To get the old behavior, configure your `ol.style.Text` with `exceedLength: true`.
#### Minor change for custom `tileLoadFunction` with `ol.source.VectorTile`
It is no longer necessary to set the projection on the tile. Instead, the `readFeatures` method must be called with the tile's extent as `extent` option and the view's projection as `featureProjection`.
Before:
```js
tile.setLoader(function() {
var data = // ... fetch data
var format = tile.getFormat();
tile.setFeatures(format.readFeatures(data));
tile.setProjection(format.readProjection(data));
// uncomment the line below for ol.format.MVT only
//tile.setExtent(format.getLastExtent());
});
```
After:
```js
tile.setLoader(function() {
var data = // ... fetch data
var format = tile.getFormat();
tile.setFeatures(format.readFeatures(data, {
featureProjection: map.getView().getProjection(),
// uncomment the line below for ol.format.MVT only
//extent: tile.getExtent()
}));
);
```
#### Deprecation of `ol.DeviceOrientation`
`ol.DeviceOrientation` is deprecated and will be removed in the next major version.
The device-orientation example has been updated to use the (gyronorm.js)[https://github.com/dorukeker/gyronorm.js] library.
## Detailed changes
See below for the full list of changes.

127
changelog/v4.5.0.md Normal file
View File

@@ -0,0 +1,127 @@
# 4.5.0
### Summary
The 4.5 release includes enhancements and fixes from 50 or so pull requests. Headlining this release, vector layers got a new `declutter` option that can be used to avoid overlapping labels. See the [street labels example](http://openlayers.org/en/latest/examples/street-labels.html) for a demonstration of this feature.
Please note that if you are using `closure-util` to build your OpenLayers based application, it is time to migrate to using the [`ol` package](https://www.npmjs.com/package/ol) and a module bundler like webpack. OpenLayers has not had a dependency on the Closure Library since the [3.19 release](https://github.com/openlayers/openlayers/releases/tag/v3.19.0); and with the 5.0 release we will be moving completely away from `goog.require` and `goog.provide`, dropping support for `closure-util`, and going with ES modules for our sources.
We will be adding details to the wiki about upcoming changes in 5.0 and tips on how to upgrade. We'll likely have a few more 4.x releases before the 5.0 release. But if you're interested in continuing to get feature enhancements in future releases, migrating to the `ol` package now will make the transition easier.
### Upgrade notes
#### Removed GeoJSON crs workaround for GeoServer
Previous version of GeoServer returned invalid crs in GeoJSON output. The workaround in `ol.format.GeoJSON` used to read this crs code is now removed.
#### Deprecation of `ol.Attribution`
`ol.Attribution` is deprecated and will be removed in the next major version. Instead, you can construct a source with a string attribution or an array of strings. For dynamic attributions, you can provide a function that gets called with the current frame state.
Before:
```js
var source = new ol.source.XYZ({
attributions: [
new ol.Attribution({html: 'some attribution'})
]
});
```
After:
```js
var source = new ol.source.XYZ({
attributions: 'some attribution'
});
```
In addition to passing a string or an array of strings for the `attributions` option, you can also pass a function that will get called with the current frame state.
```js
var source = new ol.source.XYZ({
attributions: function(frameState) {
// inspect the frame state and return attributions
return 'some attribution'; // or ['multiple', 'attributions'] or null
}
});
```
## Detailed changes
See below for the full list of changes.
* [#7456](https://github.com/openlayers/openlayers/pull/7456) - Retry if sauce connect fails ([@tschaub](https://github.com/tschaub))
* [#7440](https://github.com/openlayers/openlayers/pull/7440) - Attempt to make font loading tests more stable ([@ahocevar](https://github.com/ahocevar))
* [#7444](https://github.com/openlayers/openlayers/pull/7444) - Simpler style management ([@ahocevar](https://github.com/ahocevar))
* [#7438](https://github.com/openlayers/openlayers/pull/7438) - Call getProjection() only once ([@ahocevar](https://github.com/ahocevar))
* [#7430](https://github.com/openlayers/openlayers/pull/7430) - Add support for hex colors with alpha ([@tschaub](https://github.com/tschaub))
* [#7431](https://github.com/openlayers/openlayers/pull/7431) - Avoid returning undefined zoom ([@tschaub](https://github.com/tschaub))
* [#7436](https://github.com/openlayers/openlayers/pull/7436) - Always use source projection loading image tiles ([@pjeweb](https://github.com/pjeweb))
* [#7433](https://github.com/openlayers/openlayers/pull/7433) - Don't use getHints if it's not needed ([@fredj](https://github.com/fredj))
* [#7362](https://github.com/openlayers/openlayers/pull/7362) - Added option to the ol.format.GeoJSON to allow the reading of the geometry_name from the geojson ([@Alexandre27](https://github.com/Alexandre27))
* [#7426](https://github.com/openlayers/openlayers/pull/7426) - Update InteractionOptions.prototype.handleEvent docs ([@glen-nu](https://github.com/glen-nu))
* [#7423](https://github.com/openlayers/openlayers/pull/7423) - Get rendered features by coordinate when wrapping ([@tschaub](https://github.com/tschaub))
* [#7421](https://github.com/openlayers/openlayers/pull/7421) - Keep longitude between -180 and 180 ([@tschaub](https://github.com/tschaub))
* [#7420](https://github.com/openlayers/openlayers/pull/7420) - Fix MapGuide example resolves #7325 ([@TDesjardins](https://github.com/TDesjardins))
* [#7340](https://github.com/openlayers/openlayers/pull/7340) - Clear label cache when fonts become available ([@ahocevar](https://github.com/ahocevar))
* [#7414](https://github.com/openlayers/openlayers/pull/7414) - Only split text at line angle changes ([@ahocevar](https://github.com/ahocevar))
* [#7411](https://github.com/openlayers/openlayers/pull/7411) - Add getLayers and setLayers functions to ol.format.WMSGetFeatureInfo ([@fredj](https://github.com/fredj))
* [#7328](https://github.com/openlayers/openlayers/pull/7328) - Declutter text and images ([@ahocevar](https://github.com/ahocevar))
* [#7406](https://github.com/openlayers/openlayers/pull/7406) - Add option to Zoomify source for setting custom extent ([@lasselaakkonen](https://github.com/lasselaakkonen))
* [#7410](https://github.com/openlayers/openlayers/pull/7410) - Add getFeatureType and setFeatureType functions to ol.format.WFS ([@fredj](https://github.com/fredj))
* [#7379](https://github.com/openlayers/openlayers/pull/7379) - Add support for custom tile size to Zoomify source ([@lasselaakkonen](https://github.com/lasselaakkonen))
* [#7376](https://github.com/openlayers/openlayers/pull/7376) - changed visibility of overlay properties to protected ([@virtualcitySYSTEMS](https://github.com/virtualcitySYSTEMS))
* [#7377](https://github.com/openlayers/openlayers/pull/7377) - Add support to specify CSS class name when creating ol.Overlay ([@notnotse](https://github.com/notnotse))
* [#7383](https://github.com/openlayers/openlayers/pull/7383) - Handle null tile coordinates correctly ([@ahocevar](https://github.com/ahocevar))
* [#7375](https://github.com/openlayers/openlayers/pull/7375) - Read 'Abstract', 'AccessConstraints' and 'Fees' in ol.format.OWS ([@fredj](https://github.com/fredj))
* [#7378](https://github.com/openlayers/openlayers/pull/7378) - Fix incorrect docs about ol.source.Raster ([@notnotse](https://github.com/notnotse))
* [#7371](https://github.com/openlayers/openlayers/pull/7371) - Add @api annotation to ol.VectorTile.getExtent ([@notnotse](https://github.com/notnotse))
* [#7369](https://github.com/openlayers/openlayers/pull/7369) - Always request the Bing API with the 'culture' value ([@fredj](https://github.com/fredj))
* [#7364](https://github.com/openlayers/openlayers/pull/7364) - Remove GeoJSON workaround for GeoServer ([@fredj](https://github.com/fredj))
* [#7355](https://github.com/openlayers/openlayers/pull/7355) - Pass pixel tolerance as a parameter to constructor of ol.interaction.Extent ([@marcosox](https://github.com/marcosox))
* [#7356](https://github.com/openlayers/openlayers/pull/7356) - Fix documentation for target option in the controls ([@EduardoNogueira](https://github.com/EduardoNogueira))
* [#7359](https://github.com/openlayers/openlayers/pull/7359) - Rename entry to input - regarding options to rollup lib - Issue #7358 ([@akkumar](https://github.com/akkumar))
* [#7357](https://github.com/openlayers/openlayers/pull/7357) - Release v4.4.2 ([@tschaub](https://github.com/tschaub))
* [#7350](https://github.com/openlayers/openlayers/pull/7350) - Calculate correct text box size ([@ahocevar](https://github.com/ahocevar))
* [#7349](https://github.com/openlayers/openlayers/pull/7349) - Do not use tileUrlFunction for renderer tile coordinates ([@ahocevar](https://github.com/ahocevar))
* [#7305](https://github.com/openlayers/openlayers/pull/7305) - Fix #7304: Re-calculate the resolution when the WMS source is reprojected ([@oterral](https://github.com/oterral))
* [#7346](https://github.com/openlayers/openlayers/pull/7346) - Pre-render text images for configured scale ([@ahocevar](https://github.com/ahocevar))
* [#7345](https://github.com/openlayers/openlayers/pull/7345) - Handle different lineWidth scaling in Safari ([@ahocevar](https://github.com/ahocevar))
* [#7344](https://github.com/openlayers/openlayers/pull/7344) - Make text height detection independent of css settings ([@ahocevar](https://github.com/ahocevar))
* [#7341](https://github.com/openlayers/openlayers/pull/7341) - Proper rendering of raster sources when there is a tile transition ([@tschaub](https://github.com/tschaub))
* [#7339](https://github.com/openlayers/openlayers/pull/7339) - Use correct text stroke on HiDPI devices ([@ahocevar](https://github.com/ahocevar))
* [#7327](https://github.com/openlayers/openlayers/pull/7327) - Prune the tile cache after updating a source's URL ([@tschaub](https://github.com/tschaub))
* [#7333](https://github.com/openlayers/openlayers/pull/7333) - Pluggable Map/Layers - function calls to handles and create ([@waxenegger](https://github.com/waxenegger))
* [#7329](https://github.com/openlayers/openlayers/pull/7329) - Reworked attribution handling ([@tschaub](https://github.com/tschaub))
* [#7337](https://github.com/openlayers/openlayers/pull/7337) - Always create a new blank image to avoid CSP violations ([@ahocevar](https://github.com/ahocevar))
* [#7330](https://github.com/openlayers/openlayers/pull/7330) - Add upgrade notes to 4.4.0 changelog ([@tschaub](https://github.com/tschaub))
* [#7321](https://github.com/openlayers/openlayers/pull/7321) - Release v4.4.1 ([@tschaub](https://github.com/tschaub))
* [#7323](https://github.com/openlayers/openlayers/pull/7323) - Only clear the canvas when needed ([@tschaub](https://github.com/tschaub))
* [#7313](https://github.com/openlayers/openlayers/pull/7313) - Use lowercase module identifiers until ol@5 ([@tschaub](https://github.com/tschaub))
* [#7316](https://github.com/openlayers/openlayers/pull/7316) - fix copy-paste error in 4.4.0 changelog ([@mprins](https://github.com/mprins))
* [#7315](https://github.com/openlayers/openlayers/pull/7315) - Add new ol.format.filter.Contains spatial operator ([@fredj](https://github.com/fredj))
* [#7311](https://github.com/openlayers/openlayers/pull/7311) - Release v4.4.0 ([@tschaub](https://github.com/tschaub))
Additionally a number of updates where made to our dependencies:
<details>
<summary>Click to expand</summary>
<ul>
<li><a href="https://github.com/openlayers/openlayers/pull/7455">#7455</a> - Update eslint to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7447">#7447</a> - chore(package): update rollup-plugin-commonjs to version 8.2.6 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7448">#7448</a> - chore(package): update debounce to version 1.1.0 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7451">#7451</a> - chore(package): update karma to version 1.7.1 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7446">#7446</a> - fix(package): update rollup to version 0.51.3 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7428">#7428</a> - Update sinon to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7425">#7425</a> - Update async to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7418">#7418</a> - Update sinon to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7416">#7416</a> - Update sinon to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7417">#7417</a> - Update phantomjs-prebuilt to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7399">#7399</a> - Update eslint to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7395">#7395</a> - Update closure-util to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7392">#7392</a> - Update sinon to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7380">#7380</a> - Update rollup-plugin-cleanup to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7366">#7366</a> - Update handlebars to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7360">#7360</a> - Update eslint to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7354">#7354</a> - Update closure-util to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7319">#7319</a> - Update closure-util to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
<li><a href="https://github.com/openlayers/openlayers/pull/7314">#7314</a> - Update mocha to the latest version 🚀 (<a href="https://github.com/openlayers">@openlayers</a>)</li>
</ul>
</details>

View File

@@ -15,6 +15,7 @@ var key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiRk1kMWZaSSJ9.E5BkluenyWQMsBLsuByrmg';
var map = new ol.Map({
layers: [
new ol.layer.VectorTile({
declutter: true,
source: new ol.source.VectorTile({
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
'© <a href="https://www.openstreetmap.org/copyright">' +

View File

@@ -3,9 +3,9 @@ goog.require('ol.View');
goog.require('ol.layer.Image');
goog.require('ol.source.ImageMapGuide');
var mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
var mdf = 'Library://Public/Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
var agentUrl =
'http://data.mapguide.com/mapguide/mapagent/mapagent.fcgi?USERNAME=Anonymous';
'http://www.buoyshark.com/mapguide/mapagent/mapagent.fcgi?';
var bounds = [
-87.865114442365922,
43.665065564837931,
@@ -23,7 +23,9 @@ var map = new ol.Map({
metersPerUnit: 111319.4908, //value returned from mapguide
params: {
MAPDEFINITION: mdf,
FORMAT: 'PNG'
FORMAT: 'PNG',
USERNAME: 'OpenLayers',
PASSWORD: 'OpenLayers'
},
ratio: 2
})

View File

@@ -28,6 +28,7 @@ var map = new ol.Map({
imagerySet: 'Aerial'
})
}), new ol.layer.Vector({
declutter: true,
source: new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: 'data/geojson/vienna-streets.geojson'

View File

@@ -4,10 +4,8 @@ title: Vector Label Decluttering
shortdesc: Label decluttering with a custom renderer.
resources:
- https://cdn.polyfill.io/v2/polyfill.min.js?features=Set"
- https://unpkg.com/rbush@2.0.1/rbush.min.js
- https://unpkg.com/labelgun@0.1.1/lib/labelgun.min.js
docs: >
A custom `renderer` function is used instead of an `ol.style.Text` to label the countries of the world. Only texts that are not wider than their country's bounding box are considered and handed over to [Labelgun](https://github.com/Geovation/labelgun) for decluttering.
tags: "vector, renderer, labelgun, label"
Decluttering is used to avoid overlapping labels with `exceedLength: true` set on the text style. For MultiPolygon geometries, only the widest polygon is selected in a custom `geometry` function.
tags: "vector, decluttering, labels"
---
<div id="map" class="map"></div>

View File

@@ -1,5 +1,3 @@
// NOCOMPILE
/* global labelgun */
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.extent');
@@ -9,26 +7,7 @@ goog.require('ol.source.Vector');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
// Style for labels
function setStyle(context) {
context.font = '12px Calibri,sans-serif';
context.fillStyle = '#000';
context.strokeStyle = '#fff';
context.lineWidth = 3;
context.textBaseline = 'hanging';
context.textAlign = 'start';
}
// A separate canvas context for measuring label width and height.
var textMeasureContext = document.createElement('CANVAS').getContext('2d');
setStyle(textMeasureContext);
// The label height is approximated by the width of the text 'WI'.
var height = textMeasureContext.measureText('WI').width;
// A cache for reusing label images once they have been created.
var textCache = {};
goog.require('ol.style.Text');
var map = new ol.Map({
target: 'map',
@@ -38,30 +17,35 @@ var map = new ol.Map({
})
});
var emptyFn = function() {};
var labelEngine = new labelgun['default'](emptyFn, emptyFn);
function createLabel(canvas, text, coord) {
var halfWidth = canvas.width / 2;
var halfHeight = canvas.height / 2;
var bounds = {
bottomLeft: [Math.round(coord[0] - halfWidth), Math.round(coord[1] - halfHeight)],
topRight: [Math.round(coord[0] + halfWidth), Math.round(coord[1] + halfHeight)]
};
labelEngine.ingestLabel(bounds, coord.toString(), 1, canvas, text, false);
}
// For multi-polygons, we only label the widest polygon. This is done by sorting
// by extent width in descending order, and take the first from the array.
function sortByWidth(a, b) {
return ol.extent.getWidth(b.getExtent()) - ol.extent.getWidth(a.getExtent());
}
var labelStyle = new ol.style.Style({
renderer: function(coords, state) {
var text = state.feature.get('name');
createLabel(textCache[text], text, coords);
}
geometry: function(feature) {
var geometry = feature.getGeometry();
if (geometry.getType() == 'MultiPolygon') {
// Only render label for the widest polygon of a multipolygon
var polygons = geometry.getPolygons();
var widest = 0;
for (var i = 0, ii = polygons.length; i < ii; ++i) {
var polygon = polygons[i];
var width = ol.extent.getWidth(polygon.getExtent());
if (width > widest) {
widest = width;
geometry = polygon;
}
}
}
return geometry;
},
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
exceedLength: true,
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 3
})
})
});
var countryStyle = new ol.style.Style({
fill: new ol.style.Fill({
@@ -72,54 +56,18 @@ var countryStyle = new ol.style.Style({
width: 1
})
});
var styleWithLabel = [countryStyle, labelStyle];
var styleWithoutLabel = [countryStyle];
var style = [countryStyle, labelStyle];
var pixelRatio; // This is set by the map's precompose listener
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'data/geojson/countries.geojson',
format: new ol.format.GeoJSON()
}),
style: function(feature, resolution) {
var text = feature.get('name');
var width = textMeasureContext.measureText(text).width;
var geometry = feature.getGeometry();
if (geometry.getType() == 'MultiPolygon') {
geometry = geometry.getPolygons().sort(sortByWidth)[0];
}
var extentWidth = ol.extent.getWidth(geometry.getExtent());
if (extentWidth / resolution > width) {
// Only consider label when it fits its geometry's extent
if (!(text in textCache)) {
// Draw the label to its own canvas and cache it.
var canvas = textCache[text] = document.createElement('CANVAS');
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
var context = canvas.getContext('2d');
context.scale(pixelRatio, pixelRatio);
setStyle(context);
context.strokeText(text, 0, 0);
context.fillText(text, 0, 0);
}
labelStyle.setGeometry(geometry.getInteriorPoint());
return styleWithLabel;
} else {
return styleWithoutLabel;
}
}
});
vectorLayer.on('precompose', function(e) {
pixelRatio = e.frameState.pixelRatio;
labelEngine.destroy();
});
vectorLayer.on('postcompose', function(e) {
var labels = labelEngine.getShown();
for (var i = 0, ii = labels.length; i < ii; ++i) {
var label = labels[i];
// Draw label to the map canvas
e.context.drawImage(label.labelObject, label.minX, label.minY);
}
style: function(feature) {
labelStyle.getText().setText(feature.get('name'));
return style;
},
declutter: true
});
map.addLayer(vectorLayer);

View File

@@ -6,7 +6,8 @@ docs: >
This example showcases a number of options that can be set on text styles.
When "Text/Wrap" is chosen (for example for the line features), the label is
wrapped by inserting the character `\n`, which will create a multi-line
label.
label. The "Open Sans" web font will be loaded on demand, to show dynamic font
loading.
tags: "geojson, vector, openstreetmap, label"
---
<div id="map" class="map"></div>
@@ -69,8 +70,8 @@ tags: "geojson, vector, openstreetmap, label"
<label>Font: </label>
<select id="points-font">
<option value="Arial" selected="selected">Arial</option>
<option value="Courier New">Courier New</option>
<option value="Quattrocento Sans">Quattrocento</option>
<option value="'Courier New'">Courier New</option>
<option value="'Open Sans'">Open Sans</option>
<option value="Verdana">Verdana</option>
</select>
<br />
@@ -178,8 +179,8 @@ tags: "geojson, vector, openstreetmap, label"
<label>Font: </label>
<select id="lines-font">
<option value="Arial">Arial</option>
<option value="Courier New" selected="selected">Courier New</option>
<option value="Quattrocento Sans">Quattrocento</option>
<option value="'Courier New'" selected="selected">Courier New</option>
<option value="'Open Sans'">Open Sans</option>
<option value="Verdana">Verdana</option>
</select>
<br />
@@ -287,8 +288,8 @@ tags: "geojson, vector, openstreetmap, label"
<label>Font: </label>
<select id="polygons-font">
<option value="Arial">Arial</option>
<option value="Courier New">Courier New</option>
<option value="Quattrocento Sans">Quattrocento</option>
<option value="'Courier New'">Courier New</option>
<option value="'Open Sans'">Open Sans</option>
<option value="Verdana" selected="selected">Verdana</option>
</select>
<br />

View File

@@ -11,6 +11,7 @@ goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
var openSansAdded = false;
var myDom = {
points: {
@@ -77,7 +78,7 @@ var getText = function(feature, resolution, dom) {
text = '';
} else if (type == 'shorten') {
text = text.trunc(12);
} else if (type == 'wrap') {
} else if (type == 'wrap' && dom.placement.value != 'line') {
text = stringDivider(text, 16, '\n');
}
@@ -96,6 +97,13 @@ var createTextStyle = function(feature, resolution, dom) {
var maxAngle = dom.maxangle ? parseFloat(dom.maxangle.value) : undefined;
var exceedLength = dom.exceedlength ? (dom.exceedlength.value == 'true') : undefined;
var rotation = parseFloat(dom.rotation.value);
if (dom.font.value == '\'Open Sans\'' && !openSansAdded) {
var openSans = document.createElement('link');
openSans.href = 'https://fonts.googleapis.com/css?family=Open+Sans';
openSans.rel = 'stylesheet';
document.getElementsByTagName('head')[0].appendChild(openSans);
openSansAdded = true;
}
var font = weight + ' ' + size + ' ' + dom.font.value;
var fillColor = dom.color.value;
var outlineColor = dom.outline.value;

View File

@@ -0,0 +1,16 @@
#map {
position: relative;
}
#info {
z-index: 1;
opacity: 0;
position: absolute;
bottom: 0;
left: 0;
margin: 0;
background: rgba(0,60,136,0.7);
color: white;
border: 0;
transition: opacity 100ms ease-in;
}

View File

@@ -0,0 +1,11 @@
---
layout: example.html
title: Vector Tile Info
shortdesc: Getting feature information from vector tiles.
docs: >
<p>Move your pointer over rendered features to display feature properties.</p>
tags: "vector tiles"
---
<div id="map" class="map">
<pre id="info"/>
</div>

View File

@@ -0,0 +1,34 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.MVT');
goog.require('ol.layer.VectorTile');
goog.require('ol.source.VectorTile');
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
}),
layers: [new ol.layer.VectorTile({
source: new ol.source.VectorTile({
format: new ol.format.MVT(),
url: 'https://basemaps.arcgis.com/v1/arcgis/rest/services/World_Basemap/VectorTileServer/tile/{z}/{y}/{x}.pbf'
})
})]
});
map.on('pointermove', showInfo);
var info = document.getElementById('info');
function showInfo(event) {
var features = map.getFeaturesAtPixel(event.pixel);
if (!features) {
info.innerText = '';
info.style.opacity = 0;
return;
}
var properties = features[0].getProperties();
info.innerText = JSON.stringify(properties, null, 2);
info.style.opacity = 1;
}

View File

@@ -1,4 +1,3 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control');
@@ -50,11 +49,9 @@ var ign_source = new ol.source.WMTS({
projection: 'EPSG:3857',
tileGrid: tileGrid,
style: 'normal',
attributions: [new ol.Attribution({
html: '<a href="http://www.geoportail.fr/" target="_blank">' +
attributions: '<a href="http://www.geoportail.fr/" target="_blank">' +
'<img src="https://api.ign.fr/geoportail/api/js/latest/' +
'theme/geoportal/img/logo_gp.gif"></a>'
})]
});
var ign = new ol.layer.Tile({

View File

@@ -1,14 +1,9 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.XYZ');
var attribution = new ol.Attribution({
html: 'Copyright:© 2013 ESRI, i-cubed, GeoEye'
});
var projection = ol.proj.get('EPSG:4326');
// The tile size supported by the ArcGIS tile service.
@@ -22,7 +17,7 @@ var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
attributions: [attribution],
attributions: 'Copyright:© 2013 ESRI, i-cubed, GeoEye',
maxZoom: 16,
projection: projection,
tileSize: tileSize,

View File

@@ -1,4 +1,3 @@
goog.require('ol.Attribution');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
@@ -6,17 +5,13 @@ goog.require('ol.proj');
goog.require('ol.source.XYZ');
var attribution = new ol.Attribution({
html: 'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
'rest/services/World_Topo_Map/MapServer">ArcGIS</a>'
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
attributions: [attribution],
attributions: 'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/' +
'World_Topo_Map/MapServer/tile/{z}/{y}/{x}'
})

View File

@@ -46,33 +46,11 @@ GeoJSONCRS.prototype.type;
/**
* TODO: remove GeoJSONCRSCode when http://jira.codehaus.org/browse/GEOS-5996
* is fixed and widely deployed.
* @type {!GeoJSONCRSCode|!GeoJSONCRSName|!GeoJSONLink}
* @type {!GeoJSONCRSName|!GeoJSONLink}
*/
GeoJSONCRS.prototype.properties;
/**
* `GeoJSONCRSCode` is not part of the GeoJSON specification, but is generated
* by GeoServer.
* TODO: remove GeoJSONCRSCode when http://jira.codehaus.org/browse/GEOS-5996
* is fixed and widely deployed.
* @constructor
*/
var GeoJSONCRSCode = function() {};
/**
* TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996 is fixed
* and widely deployed.
* @type {string}
*/
GeoJSONCRSCode.prototype.code;
/**
* @constructor
*/
@@ -140,6 +118,11 @@ GeoJSONFeature.prototype.id;
GeoJSONFeature.prototype.properties;
/**
* @type {string|undefined}
*/
GeoJSONFeature.prototype.geometry_name;
/**
* @constructor

View File

@@ -273,9 +273,10 @@ olx.interaction.InteractionOptions;
/**
* Method called by the map to notify the interaction that a browser event was
* dispatched to the map. The function may return `false` to prevent the
* dispatched to the map. If the function returns a falsy value,
* propagation of the event to other interactions in the map's interactions
* chain.
* chain will be prevented (this includes functions with no explicit return). See
* {@link https://developer.mozilla.org/en-US/docs/Glossary/Falsy}
* @type {function(ol.MapBrowserEvent):boolean}
* @api
*/
@@ -521,7 +522,8 @@ olx.AtPixelOptions.prototype.hitTolerance;
* insertFirst: (boolean|undefined),
* autoPan: (boolean|undefined),
* autoPanAnimation: (olx.OverlayPanOptions|undefined),
* autoPanMargin: (number|undefined)}}
* autoPanMargin: (number|undefined),
* className: (string|undefined)}}
*/
olx.OverlayOptions;
@@ -623,6 +625,12 @@ olx.OverlayOptions.prototype.autoPanAnimation;
*/
olx.OverlayOptions.prototype.autoPanMargin;
/**
* CSS class name. Default is `ol-overlay-container ol-selectable`.
* @type {string|undefined}
* @api
*/
olx.OverlayOptions.prototype.className;
/**
* @typedef {{
@@ -1174,7 +1182,7 @@ olx.control;
* label: (string|Node|undefined),
* collapseLabel: (string|Node|undefined),
* render: (function(ol.MapEvent)|undefined),
* target: (Element|undefined)}}
* target: (Element|string|undefined)}}
*/
olx.control.AttributionOptions;
@@ -1188,8 +1196,9 @@ olx.control.AttributionOptions.prototype.className;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.AttributionOptions.prototype.target;
@@ -1349,7 +1358,7 @@ olx.control.DefaultsOptions.prototype.zoomOptions;
* labelActive: (string|Node|undefined),
* tipLabel: (string|undefined),
* keys: (boolean|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* source: (Element|string|undefined)}}
*/
olx.control.FullScreenOptions;
@@ -1399,8 +1408,9 @@ olx.control.FullScreenOptions.prototype.keys;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.FullScreenOptions.prototype.target;
@@ -1417,7 +1427,7 @@ olx.control.FullScreenOptions.prototype.source;
* coordinateFormat: (ol.CoordinateFormatType|undefined),
* projection: ol.ProjectionLike,
* render: (function(ol.MapEvent)|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* undefinedHTML: (string|undefined)}}
*/
olx.control.MousePositionOptions;
@@ -1457,8 +1467,9 @@ olx.control.MousePositionOptions.prototype.render;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.MousePositionOptions.prototype.target;
@@ -1479,7 +1490,7 @@ olx.control.MousePositionOptions.prototype.undefinedHTML;
* label: (string|Node|undefined),
* layers: (Array.<ol.layer.Layer>|ol.Collection.<ol.layer.Layer>|undefined),
* render: (function(ol.MapEvent)|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* tipLabel: (string|undefined),
* view: (ol.View|undefined)}}
*/
@@ -1542,7 +1553,7 @@ olx.control.OverviewMapOptions.prototype.render;
/**
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|undefined}
* @type {Element|string|undefined}
* @api
*/
olx.control.OverviewMapOptions.prototype.target;
@@ -1569,7 +1580,7 @@ olx.control.OverviewMapOptions.prototype.view;
* @typedef {{className: (string|undefined),
* minWidth: (number|undefined),
* render: (function(ol.MapEvent)|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* units: (ol.control.ScaleLineUnits|string|undefined)}}
*/
olx.control.ScaleLineOptions;
@@ -1601,8 +1612,9 @@ olx.control.ScaleLineOptions.prototype.render;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.ScaleLineOptions.prototype.target;
@@ -1621,7 +1633,7 @@ olx.control.ScaleLineOptions.prototype.units;
* className: (string|undefined),
* label: (string|Element|undefined),
* tipLabel: (string|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* render: (function(ol.MapEvent)|undefined),
* resetNorth: (function()|undefined),
* autoHide: (boolean|undefined)}}
@@ -1689,8 +1701,9 @@ olx.control.RotateOptions.prototype.resetNorth;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.RotateOptions.prototype.target;
@@ -1704,7 +1717,7 @@ olx.control.RotateOptions.prototype.target;
* zoomInTipLabel: (string|undefined),
* zoomOutTipLabel: (string|undefined),
* delta: (number|undefined),
* target: (Element|undefined)}}
* target: (Element|string|undefined)}}
*/
olx.control.ZoomOptions;
@@ -1768,8 +1781,9 @@ olx.control.ZoomOptions.prototype.delta;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.ZoomOptions.prototype.target;
@@ -1828,7 +1842,7 @@ olx.control.ZoomSliderOptions.prototype.render;
/**
* @typedef {{className: (string|undefined),
* target: (Element|undefined),
* target: (Element|string|undefined),
* label: (string|Node|undefined),
* tipLabel: (string|undefined),
* extent: (ol.Extent|undefined)}}
@@ -1845,8 +1859,9 @@ olx.control.ZoomToExtentOptions.prototype.className;
/**
* Target.
* @type {Element|undefined}
* Specify a target if you want the control to be rendered outside of the map's
* viewport.
* @type {Element|string|undefined}
* @api
*/
olx.control.ZoomToExtentOptions.prototype.target;
@@ -1987,6 +2002,7 @@ olx.format.WriteOptions.prototype.decimals;
/**
* @typedef {{defaultDataProjection: ol.ProjectionLike,
* geometryName: (string|undefined),
* extractGeometryName: (boolean|undefined),
* featureProjection: ol.ProjectionLike}}
*/
olx.format.GeoJSONOptions;
@@ -2017,6 +2033,18 @@ olx.format.GeoJSONOptions.prototype.featureProjection;
olx.format.GeoJSONOptions.prototype.geometryName;
/**
* Certain GeoJSON providers include the geometry_name field in the feature
* geoJSON. If set to `true` the geoJSON reader will look for that field to
* set the geometry name. If both this field is set to `true` and a
* `geometryName` is provided, the `geometryName` will take precedence.
* Default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.format.GeoJSONOptions.prototype.extractGeometryName;
/**
* @typedef {{geometryName: (string|undefined)}}
*/
@@ -3131,6 +3159,7 @@ olx.interaction.DrawOptions.prototype.wrapX;
/**
* @typedef {{extent: (ol.Extent|undefined),
* boxStyle: (ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined),
* pixelTolerance: (number|undefined),
* pointerStyle: (ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined),
* wrapX: (boolean|undefined)}}
* @api
@@ -3152,6 +3181,14 @@ olx.interaction.ExtentOptions.prototype.extent;
*/
olx.interaction.ExtentOptions.prototype.boxStyle;
/**
* Pixel tolerance for considering the pointer close enough to a segment or
* vertex for editing. Default is `10`.
* @type {number|undefined}
* @api
*/
olx.interaction.ExtentOptions.prototype.pixelTolerance;
/**
* Style for the cursor used to draw the extent.
* Defaults to ol.style.Style.createDefaultEditing()[ol.geom.GeometryType.POINT]
@@ -4227,6 +4264,7 @@ olx.layer.TileOptions.prototype.zIndex;
* renderBuffer: (number|undefined),
* source: (ol.source.Vector|undefined),
* map: (ol.PluggableMap|undefined),
* declutter: (boolean|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined),
* updateWhileAnimating: (boolean|undefined),
* updateWhileInteracting: (boolean|undefined),
@@ -4309,6 +4347,16 @@ olx.layer.VectorOptions.prototype.renderBuffer;
olx.layer.VectorOptions.prototype.source;
/**
* Declutter images and text. Decluttering is applied to all image and text
* styles, and the priority is defined by the z-index of the style. Lower
* z-index means higher priority. Default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.layer.VectorOptions.prototype.declutter;
/**
* Layer style. See {@link ol.style} for default style which will be used if
* this is not defined.
@@ -4366,6 +4414,7 @@ olx.layer.VectorOptions.prototype.zIndex;
* renderMode: (ol.layer.VectorTileRenderType|string|undefined),
* renderOrder: (ol.RenderOrderFunction|undefined),
* source: (ol.source.VectorTile|undefined),
* declutter: (boolean|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined),
* updateWhileAnimating: (boolean|undefined),
* updateWhileInteracting: (boolean|undefined),
@@ -4399,7 +4448,8 @@ olx.layer.VectorTileOptions.prototype.renderBuffer;
* * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering
* even during animations, but slower performance than the other options.
*
* The default is `'hybrid'`.
* When `declutter` is set to `true`, `'hybrid'` will be used instead of
* `'image'`. The default is `'hybrid'`.
* @type {ol.layer.VectorTileRenderType|string|undefined}
* @api
*/
@@ -4475,6 +4525,17 @@ olx.layer.VectorTileOptions.prototype.preload;
olx.layer.VectorTileOptions.prototype.source;
/**
* Declutter images and text. Decluttering is applied to all image and text
* styles, and the priority is defined by the z-index of the style. Lower
* z-index means higher priority. When set to `true`, a `renderMode` of
* `'image'` will be overridden with `'hybrid'`. Default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.layer.VectorTileOptions.prototype.declutter;
/**
* Layer style. See {@link ol.style} for default style which will be used if
* this is not defined.
@@ -5487,7 +5548,7 @@ olx.source.OSMOptions.prototype.wrapX;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* @typedef {{attributions: (ol.AttributionLike|undefined),
* crossOrigin: (null|string|undefined),
* hidpi: (boolean|undefined),
* logo: (string|olx.LogoOptions|undefined),
@@ -5503,7 +5564,7 @@ olx.source.ImageArcGISRestOptions;
/**
* Attributions.
* @type {Array.<ol.Attribution>|undefined}
* @type {ol.AttributionLike|undefined}
* @api
*/
olx.source.ImageArcGISRestOptions.prototype.attributions;
@@ -7210,7 +7271,9 @@ olx.source.CartoDBOptions.prototype.account;
* url: !string,
* tierSizeCalculation: (string|undefined),
* size: ol.Size,
* transition: (number|undefined)}}
* extent: (ol.Extent|undefined),
* transition: (number|undefined),
* tileSize: (number|undefined)}}
*/
olx.source.ZoomifyOptions;
@@ -7301,6 +7364,17 @@ olx.source.ZoomifyOptions.prototype.tierSizeCalculation;
olx.source.ZoomifyOptions.prototype.size;
/**
* Extent for the TileGrid that is created. Default sets the TileGrid in the
* fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
* extent to the first quadrant (the default for OpenLayers 2) set the extent
* as `[0, 0, width, height]`.
* @type {ol.Extent|undefined}
* @api
*/
olx.source.ZoomifyOptions.prototype.extent;
/**
* Duration of the opacity transition for rendering. To disable the opacity
* transition, pass `transition: 0`.
@@ -7310,6 +7384,15 @@ olx.source.ZoomifyOptions.prototype.size;
olx.source.ZoomifyOptions.prototype.transition;
/**
* Tile size. Same tile size is used for all zoom levels. Default value is
* `OpenLayers.DEFAULT_TILE_SIZE`.
* @type {number|undefined}
* @api
*/
olx.source.ZoomifyOptions.prototype.tileSize;
/**
* Namespace.
* @type {Object}
@@ -8329,7 +8412,6 @@ olx.view.FitOptions.prototype.callback;
/**
* @typedef {{animate: boolean,
* attributions: Object.<string, ol.Attribution>,
* coordinateToPixelTransform: ol.Transform,
* extent: (null|ol.Extent),
* focus: ol.Coordinate,
@@ -8377,7 +8459,8 @@ olx.FrameState.prototype.viewState;
* @typedef {{center: ol.Coordinate,
* projection: ol.proj.Projection,
* resolution: number,
* rotation: number}}
* rotation: number,
* zoom: number}}
*/
olx.ViewState;
@@ -8410,6 +8493,14 @@ olx.ViewState.prototype.resolution;
olx.ViewState.prototype.rotation;
/**
* The current zoom level.
* @type {number}
* @api
*/
olx.ViewState.prototype.zoom;
/**
* @typedef {{initialSize: (number|undefined),
* maxSize: (number|undefined),

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "4.4.2",
"version": "4.5.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",
@@ -38,17 +38,17 @@
"css/ol.css"
],
"dependencies": {
"async": "2.5.0",
"closure-util": "1.24.0",
"async": "2.6.0",
"closure-util": "1.25.0",
"fs-extra": "4.0.2",
"jsdoc": "3.5.5",
"nomnom": "1.8.1",
"pbf": "3.1.0",
"pixelworks": "1.1.0",
"rbush": "2.0.1",
"rollup": "^0.50.0",
"rollup-plugin-cleanup": "^1.0.0",
"rollup-plugin-commonjs": "^8.0.2",
"rollup": "^0.51.3",
"rollup-plugin-cleanup": "^2.0.0",
"rollup-plugin-commonjs": "^8.2.6",
"rollup-plugin-node-resolve": "^3.0.0",
"temp": "0.8.3",
"walk": "2.3.9"
@@ -56,18 +56,18 @@
"devDependencies": {
"clean-css-cli": "4.1.10",
"coveralls": "3.0.0",
"debounce": "^1.0.0",
"eslint": "4.8.0",
"debounce": "^1.1.0",
"eslint": "4.11.0",
"eslint-config-openlayers": "7.0.0",
"eslint-plugin-openlayers-internal": "^3.1.0",
"expect.js": "0.3.1",
"gaze": "^1.0.0",
"glob": "7.1.1",
"handlebars": "4.0.10",
"handlebars": "4.0.11",
"istanbul": "0.4.5",
"jquery": "3.2.1",
"jscodeshift": "^0.3.30",
"karma": "^1.7.0",
"karma": "^1.7.1",
"karma-chrome-launcher": "^2.1.1",
"karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.0.1",
@@ -76,14 +76,14 @@
"marked": "0.3.6",
"metalsmith": "2.3.0",
"metalsmith-layouts": "1.8.1",
"mocha": "4.0.0",
"mocha": "4.0.1",
"mocha-phantomjs-core": "^2.1.0",
"mustache": "2.3.0",
"phantomjs-prebuilt": "2.1.15",
"phantomjs-prebuilt": "2.1.16",
"pixelmatch": "^4.0.2",
"proj4": "2.4.4",
"serve-files": "1.0.1",
"sinon": "4.0.1",
"sinon": "4.1.2",
"slimerjs": "0.10.3",
"url-polyfill": "^1.0.7"
},

View File

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

View File

@@ -22,6 +22,7 @@ goog.require('ol.tilegrid');
* ..
*
* @constructor
* @deprecated This class is deprecated and will removed in the next major release.
* @param {olx.AttributionOptions} options Attribution options.
* @struct
* @api

View File

@@ -5,12 +5,12 @@ goog.require('ol.math');
/**
* This RegExp matches # followed by 3 or 6 hex digits.
* This RegExp matches # followed by 3, 4, 6, or 8 hex digits.
* @const
* @type {RegExp}
* @private
*/
ol.color.HEX_COLOR_RE_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
ol.color.HEX_COLOR_RE_ = /^#(?:[0-9a-f]{3,4}){1,2}$/i;
/**
@@ -138,18 +138,30 @@ ol.color.fromStringInternal_ = function(s) {
if (ol.color.HEX_COLOR_RE_.exec(s)) { // hex
var n = s.length - 1; // number of hex digits
ol.asserts.assert(n == 3 || n == 6, 54); // Hex color should have 3 or 6 digits
var d = n == 3 ? 1 : 2; // number of digits per channel
var d; // number of digits per channel
if (n <= 4) {
d = 1;
} else {
d = 2;
}
var hasAlpha = n === 4 || n === 8;
r = parseInt(s.substr(1 + 0 * d, d), 16);
g = parseInt(s.substr(1 + 1 * d, d), 16);
b = parseInt(s.substr(1 + 2 * d, d), 16);
if (hasAlpha) {
a = parseInt(s.substr(1 + 3 * d, d), 16);
} else {
a = 255;
}
if (d == 1) {
r = (r << 4) + r;
g = (g << 4) + g;
b = (b << 4) + b;
if (hasAlpha) {
a = (a << 4) + a;
}
}
a = 1;
color = [r, g, b, a];
color = [r, g, b, a / 255];
} else if (s.indexOf('rgba(') == 0) { // rgba()
parts = s.slice(5, -1).split(',').map(Number);
color = ol.color.normalize(parts);

View File

@@ -3,11 +3,13 @@
goog.provide('ol.control.Attribution');
goog.require('ol');
goog.require('ol.dom');
goog.require('ol.array');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.layer.Layer');
goog.require('ol.obj');
@@ -116,24 +118,19 @@ ol.control.Attribution = function(opt_options) {
target: options.target
});
/**
* A list of currently rendered resolutions.
* @type {Array.<string>}
* @private
*/
this.renderedAttributions_ = [];
/**
* @private
* @type {boolean}
*/
this.renderedVisible_ = true;
/**
* @private
* @type {Object.<string, Element>}
*/
this.attributionElements_ = {};
/**
* @private
* @type {Object.<string, boolean>}
*/
this.attributionElementRenderedVisible_ = {};
/**
* @private
* @type {Object.<string, Element>}
@@ -145,59 +142,62 @@ ol.inherits(ol.control.Attribution, ol.control.Control);
/**
* @param {?olx.FrameState} frameState Frame state.
* @return {Array.<Object.<string, ol.Attribution>>} Attributions.
* Get a list of visible attributions.
* @param {olx.FrameState} frameState Frame state.
* @return {Array.<string>} Attributions.
* @private
*/
ol.control.Attribution.prototype.getSourceAttributions = function(frameState) {
var i, ii, j, jj, tileRanges, source, sourceAttribution,
sourceAttributionKey, sourceAttributions, sourceKey;
var intersectsTileRange;
ol.control.Attribution.prototype.getSourceAttributions_ = function(frameState) {
/**
* Used to determine if an attribution already exists.
* @type {Object.<string, boolean>}
*/
var lookup = {};
/**
* A list of visible attributions.
* @type {Array.<string>}
*/
var visibleAttributions = [];
var layerStatesArray = frameState.layerStatesArray;
/** @type {Object.<string, ol.Attribution>} */
var attributions = ol.obj.assign({}, frameState.attributions);
/** @type {Object.<string, ol.Attribution>} */
var hiddenAttributions = {};
var uniqueAttributions = {};
var projection = /** @type {!ol.proj.Projection} */ (frameState.viewState.projection);
for (i = 0, ii = layerStatesArray.length; i < ii; i++) {
source = layerStatesArray[i].layer.getSource();
var resolution = frameState.viewState.resolution;
for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {
var layerState = layerStatesArray[i];
if (!ol.layer.Layer.visibleAtResolution(layerState, resolution)) {
continue;
}
var source = layerState.layer.getSource();
if (!source) {
continue;
}
sourceKey = ol.getUid(source).toString();
sourceAttributions = source.getAttributions();
if (!sourceAttributions) {
var attributionGetter = source.getAttributions2();
if (!attributionGetter) {
continue;
}
for (j = 0, jj = sourceAttributions.length; j < jj; j++) {
sourceAttribution = sourceAttributions[j];
sourceAttributionKey = ol.getUid(sourceAttribution).toString();
if (sourceAttributionKey in attributions) {
continue;
}
tileRanges = frameState.usedTiles[sourceKey];
if (tileRanges) {
var tileGrid = /** @type {ol.source.Tile} */ (source).getTileGridForProjection(projection);
intersectsTileRange = sourceAttribution.intersectsAnyTileRange(
tileRanges, tileGrid, projection);
} else {
intersectsTileRange = false;
}
if (intersectsTileRange) {
if (sourceAttributionKey in hiddenAttributions) {
delete hiddenAttributions[sourceAttributionKey];
var attributions = attributionGetter(frameState);
if (!attributions) {
continue;
}
if (Array.isArray(attributions)) {
for (var j = 0, jj = attributions.length; j < jj; ++j) {
if (!(attributions[j] in lookup)) {
visibleAttributions.push(attributions[j]);
lookup[attributions[j]] = true;
}
var html = sourceAttribution.getHTML();
if (!(html in uniqueAttributions)) {
uniqueAttributions[html] = true;
attributions[sourceAttributionKey] = sourceAttribution;
}
} else {
hiddenAttributions[sourceAttributionKey] = sourceAttribution;
}
} else {
if (!(attributions in lookup)) {
visibleAttributions.push(attributions);
lookup[attributions] = true;
}
}
}
return [attributions, hiddenAttributions];
return visibleAttributions;
};
@@ -217,7 +217,6 @@ ol.control.Attribution.render = function(mapEvent) {
* @param {?olx.FrameState} frameState Frame state.
*/
ol.control.Attribution.prototype.updateElement_ = function(frameState) {
if (!frameState) {
if (this.renderedVisible_) {
this.element.style.display = 'none';
@@ -226,65 +225,38 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) {
return;
}
var attributions = this.getSourceAttributions(frameState);
/** @type {Object.<string, ol.Attribution>} */
var visibleAttributions = attributions[0];
/** @type {Object.<string, ol.Attribution>} */
var hiddenAttributions = attributions[1];
var attributionElement, attributionKey;
for (attributionKey in this.attributionElements_) {
if (attributionKey in visibleAttributions) {
if (!this.attributionElementRenderedVisible_[attributionKey]) {
this.attributionElements_[attributionKey].style.display = '';
this.attributionElementRenderedVisible_[attributionKey] = true;
}
delete visibleAttributions[attributionKey];
} else if (attributionKey in hiddenAttributions) {
if (this.attributionElementRenderedVisible_[attributionKey]) {
this.attributionElements_[attributionKey].style.display = 'none';
delete this.attributionElementRenderedVisible_[attributionKey];
}
delete hiddenAttributions[attributionKey];
} else {
ol.dom.removeNode(this.attributionElements_[attributionKey]);
delete this.attributionElements_[attributionKey];
delete this.attributionElementRenderedVisible_[attributionKey];
}
}
for (attributionKey in visibleAttributions) {
attributionElement = document.createElement('LI');
attributionElement.innerHTML =
visibleAttributions[attributionKey].getHTML();
this.ulElement_.appendChild(attributionElement);
this.attributionElements_[attributionKey] = attributionElement;
this.attributionElementRenderedVisible_[attributionKey] = true;
}
for (attributionKey in hiddenAttributions) {
attributionElement = document.createElement('LI');
attributionElement.innerHTML =
hiddenAttributions[attributionKey].getHTML();
attributionElement.style.display = 'none';
this.ulElement_.appendChild(attributionElement);
this.attributionElements_[attributionKey] = attributionElement;
var attributions = this.getSourceAttributions_(frameState);
if (ol.array.equals(attributions, this.renderedAttributions_)) {
return;
}
var renderVisible =
!ol.obj.isEmpty(this.attributionElementRenderedVisible_) ||
!ol.obj.isEmpty(frameState.logos);
if (this.renderedVisible_ != renderVisible) {
this.element.style.display = renderVisible ? '' : 'none';
this.renderedVisible_ = renderVisible;
// remove everything but the logo
while (this.ulElement_.lastChild !== this.logoLi_) {
this.ulElement_.removeChild(this.ulElement_.lastChild);
}
if (renderVisible &&
ol.obj.isEmpty(this.attributionElementRenderedVisible_)) {
// append the attributions
for (var i = 0, ii = attributions.length; i < ii; ++i) {
var element = document.createElement('LI');
element.innerHTML = attributions[i];
this.ulElement_.appendChild(element);
}
if (attributions.length === 0 && this.renderedAttributions_.length > 0) {
this.element.classList.add('ol-logo-only');
} else {
} else if (this.renderedAttributions_.length === 0 && attributions.length > 0) {
this.element.classList.remove('ol-logo-only');
}
this.insertLogos_(frameState);
var visible = attributions.length > 0 || !ol.obj.isEmpty(frameState.logos);
if (this.renderedVisible_ != visible) {
this.element.style.display = visible ? '' : 'none';
this.renderedVisible_ = visible;
}
this.renderedAttributions_ = attributions;
this.insertLogos_(frameState);
};

View File

@@ -43,3 +43,30 @@ ol.css.CLASS_UNSUPPORTED = 'ol-unsupported';
* @type {string}
*/
ol.css.CLASS_CONTROL = 'ol-control';
/**
* Get the list of font families from a font spec. Note that this doesn't work
* for font families that have commas in them.
* @param {string} The CSS font property.
* @return {Object.<string>} The font families (or null if the input spec is invalid).
*/
ol.css.getFontFamilies = (function() {
var style;
var cache = {};
return function(font) {
if (!style) {
style = document.createElement('div').style;
}
if (!(font in cache)) {
style.font = font;
var family = style.fontFamily;
style.font = '';
if (!family) {
return null;
}
cache[font] = family.split(/,\s?/);
}
return cache[font];
};
})();

View File

@@ -12,6 +12,7 @@ ol.events.EventType = {
*/
CHANGE: 'change',
CLEAR: 'clear',
CLICK: 'click',
DBLCLICK: 'dblclick',
DRAGENTER: 'dragenter',

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.Contains');
goog.require('ol.format.filter.During');
goog.require('ol.format.filter.EqualTo');
goog.require('ol.format.filter.GreaterThan');
@@ -71,6 +72,21 @@ ol.format.filter.bbox = function(geometryName, extent, opt_srsName) {
return new ol.format.filter.Bbox(geometryName, extent, opt_srsName);
};
/**
* Create a `<Contains>` operator to test whether a geometry-valued property
* contains a given geometry.
*
* @param {!string} geometryName Geometry name to use.
* @param {!ol.geom.Geometry} geometry Geometry.
* @param {string=} opt_srsName SRS name. No srsName attribute will be
* set on geometries when this is not provided.
* @returns {!ol.format.filter.Contains} `<Contains>` operator.
* @api
*/
ol.format.filter.contains = function(geometryName, geometry, opt_srsName) {
return new ol.format.filter.Contains(geometryName, geometry, opt_srsName);
};
/**
* Create a `<Intersects>` operator to test whether a geometry-valued property
* intersects a given geometry.

View File

@@ -0,0 +1,25 @@
goog.provide('ol.format.filter.Contains');
goog.require('ol');
goog.require('ol.format.filter.Spatial');
/**
* @classdesc
* Represents a `<Contains>` operator to test whether a geometry-valued property
* contains a given geometry.
*
* @constructor
* @param {!string} geometryName Geometry name to use.
* @param {!ol.geom.Geometry} geometry Geometry.
* @param {string=} opt_srsName SRS name. No srsName attribute will be
* set on geometries when this is not provided.
* @extends {ol.format.filter.Spatial}
* @api
*/
ol.format.filter.Contains = function(geometryName, geometry, opt_srsName) {
ol.format.filter.Spatial.call(this, 'Contains', geometryName, geometry, opt_srsName);
};
ol.inherits(ol.format.filter.Contains, ol.format.filter.Spatial);

View File

@@ -53,6 +53,13 @@ ol.format.GeoJSON = function(opt_options) {
*/
this.geometryName_ = options.geometryName;
/**
* Look for the geometry name in the feature GeoJSON
* @type {boolean|undefined}
* @private
*/
this.extractGeometryName_ = options.extractGeometryName;
};
ol.inherits(ol.format.GeoJSON, ol.format.JSONFeature);
@@ -377,6 +384,8 @@ ol.format.GeoJSON.prototype.readFeatureFromObject = function(
var feature = new ol.Feature();
if (this.geometryName_) {
feature.setGeometryName(this.geometryName_);
} else if (this.extractGeometryName_ && geoJSONFeature.geometry_name !== undefined) {
feature.setGeometryName(geoJSONFeature.geometry_name);
}
feature.setGeometry(geometry);
if (geoJSONFeature.id !== undefined) {
@@ -457,12 +466,6 @@ ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) {
if (crs) {
if (crs.type == 'name') {
projection = ol.proj.get(crs.properties.name);
} else if (crs.type == 'EPSG') {
// 'EPSG' is not part of the GeoJSON specification, but is generated by
// GeoServer.
// TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996
// is fixed and widely deployed.
projection = ol.proj.get('EPSG:' + crs.properties.code);
} else {
ol.asserts.assert(false, 36); // Unknown SRS type
}

View File

@@ -403,6 +403,9 @@ ol.format.OWS.SERVICE_CONTACT_PARSERS_ =
ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ =
ol.xml.makeStructureNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'AccessConstraints': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'ServiceTypeVersion': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),

View File

@@ -116,6 +116,22 @@ ol.format.WFS.SCHEMA_LOCATIONS = {
ol.format.WFS.DEFAULT_VERSION = '1.1.0';
/**
* @return {Array.<string>|string|undefined} featureType
*/
ol.format.WFS.prototype.getFeatureType = function() {
return this.featureType_;
};
/**
* @param {Array.<string>|string|undefined} featureType Feature type(s) to parse.
*/
ol.format.WFS.prototype.setFeatureType = function(featureType) {
this.featureType_ = featureType;
};
/**
* Read all features from a WFS FeatureCollection.
*
@@ -628,6 +644,21 @@ ol.format.WFS.writeBboxFilter_ = function(node, filter, objectStack) {
};
/**
* @param {Node} node Node.
* @param {ol.format.filter.Contains} filter Filter.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeContainsFilter_ = function(node, filter, objectStack) {
var context = objectStack[objectStack.length - 1];
context['srsName'] = filter.srsName;
ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);
ol.format.GML3.prototype.writeGeometryElement(node, filter.geometry, objectStack);
};
/**
* @param {Node} node Node.
* @param {ol.format.filter.Intersects} filter Filter.
@@ -846,6 +877,7 @@ ol.format.WFS.GETFEATURE_SERIALIZERS_ = {
'Or': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
'Not': ol.xml.makeChildAppender(ol.format.WFS.writeNotFilter_),
'BBOX': ol.xml.makeChildAppender(ol.format.WFS.writeBboxFilter_),
'Contains': ol.xml.makeChildAppender(ol.format.WFS.writeContainsFilter_),
'Intersects': ol.xml.makeChildAppender(ol.format.WFS.writeIntersectsFilter_),
'Within': ol.xml.makeChildAppender(ol.format.WFS.writeWithinFilter_),
'PropertyIsEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),

View File

@@ -63,6 +63,22 @@ ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature';
ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer';
/**
* @return {Array.<string>} layers
*/
ol.format.WMSGetFeatureInfo.prototype.getLayers = function() {
return this.layers_;
};
/**
* @param {Array.<string>} layers Layers to parse.
*/
ol.format.WMSGetFeatureInfo.prototype.setLayers = function(layers) {
this.layers_ = layers;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.

View File

@@ -13,16 +13,12 @@ goog.require('ol.math');
* width of the character passed as 1st argument.
* @param {number} startM m along the path where the text starts.
* @param {number} maxAngle Max angle between adjacent chars in radians.
* @param {Array.<Array.<number>>=} opt_result Array that will be populated with the
* result. Each entry consists of an array of x, y and z of the char to draw.
* If provided, this array will not be truncated to the number of characters of
* the `text`.
* @return {Array.<Array.<number>>} The result array of null if `maxAngle` was
* exceeded.
* @return {Array.<Array.<*>>} The result array of null if `maxAngle` was
* exceeded. Entries of the array are x, y, anchorX, angle, chunk.
*/
ol.geom.flat.textpath.lineString = function(
flatCoordinates, offset, end, stride, text, measure, startM, maxAngle, opt_result) {
var result = opt_result ? opt_result : [];
flatCoordinates, offset, end, stride, text, measure, startM, maxAngle) {
var result = [];
// Keep text upright
var reverse = flatCoordinates[offset] > flatCoordinates[end - stride];
@@ -37,11 +33,15 @@ ol.geom.flat.textpath.lineString = function(
var segmentM = 0;
var segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
var index, previousAngle;
var chunk = '';
var chunkLength = 0;
var data, index, previousAngle;
for (var i = 0; i < numChars; ++i) {
index = reverse ? numChars - i - 1 : i;
var char = text[index];
var charLength = measure(char);
var char = text.charAt(index);
chunk = reverse ? char + chunk : chunk + char;
var charLength = measure(chunk) - chunkLength;
chunkLength += charLength;
var charM = startM + charLength / 2;
while (offset < end - stride && segmentM + segmentLength < charM) {
x1 = x2;
@@ -64,11 +64,27 @@ ol.geom.flat.textpath.lineString = function(
return null;
}
}
previousAngle = angle;
var interpolate = segmentPos / segmentLength;
var x = ol.math.lerp(x1, x2, interpolate);
var y = ol.math.lerp(y1, y2, interpolate);
result[index] = [x, y, angle];
if (previousAngle == angle) {
if (reverse) {
data[0] = x;
data[1] = y;
data[2] = charLength / 2;
}
data[4] = chunk;
} else {
chunk = char;
chunkLength = charLength;
data = [x, y, charLength / 2, angle, chunk];
if (reverse) {
result.unshift(data);
} else {
result.push(data);
}
previousAngle = angle;
}
startM += charLength;
}
return result;

View File

@@ -14,16 +14,13 @@ goog.require('ol.extent');
* @param {ol.Extent} extent Extent.
* @param {number|undefined} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {Array.<ol.Attribution>} attributions Attributions.
* @param {string} src Image source URI.
* @param {?string} crossOrigin Cross origin.
* @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
*/
ol.Image = function(extent, resolution, pixelRatio, attributions, src,
crossOrigin, imageLoadFunction) {
ol.Image = function(extent, resolution, pixelRatio, src, crossOrigin, imageLoadFunction) {
ol.ImageBase.call(this, extent, resolution, pixelRatio, ol.ImageState.IDLE,
attributions);
ol.ImageBase.call(this, extent, resolution, pixelRatio, ol.ImageState.IDLE);
/**
* @private

View File

@@ -13,18 +13,11 @@ goog.require('ol.events.EventType');
* @param {number|undefined} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.ImageState} state State.
* @param {Array.<ol.Attribution>} attributions Attributions.
*/
ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) {
ol.ImageBase = function(extent, resolution, pixelRatio, state) {
ol.events.EventTarget.call(this);
/**
* @private
* @type {Array.<ol.Attribution>}
*/
this.attributions_ = attributions;
/**
* @protected
* @type {ol.Extent}
@@ -61,14 +54,6 @@ ol.ImageBase.prototype.changed = function() {
};
/**
* @return {Array.<ol.Attribution>} Attributions.
*/
ol.ImageBase.prototype.getAttributions = function() {
return this.attributions_;
};
/**
* @return {ol.Extent} Extent.
*/

View File

@@ -11,13 +11,11 @@ goog.require('ol.ImageState');
* @param {ol.Extent} extent Extent.
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {Array.<ol.Attribution>} attributions Attributions.
* @param {HTMLCanvasElement} canvas Canvas.
* @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to
* support asynchronous canvas drawing.
*/
ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
canvas, opt_loader) {
ol.ImageCanvas = function(extent, resolution, pixelRatio, canvas, opt_loader) {
/**
* Optional canvas loader function.
@@ -29,7 +27,7 @@ ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
var state = opt_loader !== undefined ?
ol.ImageState.IDLE : ol.ImageState.LOADED;
ol.ImageBase.call(this, extent, resolution, pixelRatio, state, attributions);
ol.ImageBase.call(this, extent, resolution, pixelRatio, state);
/**
* @private

View File

@@ -61,7 +61,7 @@ ol.inherits(ol.ImageTile, ol.Tile);
ol.ImageTile.prototype.disposeInternal = function() {
if (this.state == ol.TileState.LOADING) {
this.unlistenImage_();
this.image_.src = ol.ImageTile.blankImageUrl;
this.image_ = ol.ImageTile.getBlankImage();
}
if (this.interimTile) {
this.interimTile.dispose();
@@ -98,7 +98,7 @@ ol.ImageTile.prototype.getKey = function() {
ol.ImageTile.prototype.handleImageError_ = function() {
this.state = ol.TileState.ERROR;
this.unlistenImage_();
this.image_.src = ol.ImageTile.blankImageUrl;
this.image_ = ol.ImageTile.getBlankImage();
this.changed();
};
@@ -150,12 +150,12 @@ ol.ImageTile.prototype.unlistenImage_ = function() {
/**
* Data URI for a blank image.
* @type {string}
* Get a 1-pixel blank image.
* @return {HTMLCanvasElement} Blank image.
*/
ol.ImageTile.blankImageUrl = (function() {
ol.ImageTile.getBlankImage = function() {
var ctx = ol.dom.createCanvasContext2D(1, 1);
ctx.fillStyle = 'rgba(0,0,0,0)';
ctx.fillRect(0, 0, 1, 1);
return ctx.canvas.toDataURL('image/png');
})();
return ctx.canvas;
};

View File

@@ -151,7 +151,7 @@ ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {
view.setHint(ol.ViewHint.INTERACTING, 1);
}
// stop any current animation
if (view.getHints()[ol.ViewHint.ANIMATING]) {
if (view.getAnimating()) {
view.setCenter(mapBrowserEvent.frameState.viewState.center);
}
if (this.kinetic_) {

View File

@@ -31,6 +31,8 @@ goog.require('ol.style.Style');
*/
ol.interaction.Extent = function(opt_options) {
var options = opt_options || {};
/**
* Extent of the drawn box
* @type {ol.Extent}
@@ -50,7 +52,8 @@ ol.interaction.Extent = function(opt_options) {
* @type {number}
* @private
*/
this.pixelTolerance_ = 10;
this.pixelTolerance_ = options.pixelTolerance !== undefined ?
options.pixelTolerance : 10;
/**
* Is the pointer snapped to an extent vertex

View File

@@ -6,7 +6,6 @@ goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.MapBrowserEventType');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.ViewHint');
goog.require('ol.array');
goog.require('ol.coordinate');
goog.require('ol.events');
@@ -804,7 +803,7 @@ ol.interaction.Modify.handleEvent = function(mapBrowserEvent) {
this.lastPointerEvent_ = mapBrowserEvent;
var handled;
if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] &&
if (!mapBrowserEvent.map.getView().getInteracting() &&
mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE &&
!this.handlingDownUpSequence) {
this.handlePointerMove_(mapBrowserEvent);

View File

@@ -32,6 +32,12 @@ ol.layer.Vector = function(opt_options) {
delete baseOptions.updateWhileInteracting;
ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
/**
* @private
* @type {boolean}
*/
this.declutter_ = options.declutter !== undefined ? options.declutter : false;
/**
* @type {number}
* @private
@@ -80,6 +86,22 @@ ol.layer.Vector = function(opt_options) {
ol.inherits(ol.layer.Vector, ol.layer.Layer);
/**
* @return {boolean} Declutter.
*/
ol.layer.Vector.prototype.getDeclutter = function() {
return this.declutter_;
};
/**
* @param {boolean} declutter Declutter.
*/
ol.layer.Vector.prototype.setDeclutter = function(declutter) {
this.declutter_ = declutter;
};
/**
* @return {number|undefined} Render buffer.
*/

View File

@@ -34,17 +34,23 @@ ol.layer.VectorTile = function(opt_options) {
this.setUseInterimTilesOnError(options.useInterimTilesOnError ?
options.useInterimTilesOnError : true);
ol.asserts.assert(options.renderMode == undefined ||
options.renderMode == ol.layer.VectorTileRenderType.IMAGE ||
options.renderMode == ol.layer.VectorTileRenderType.HYBRID ||
options.renderMode == ol.layer.VectorTileRenderType.VECTOR,
var renderMode = options.renderMode;
ol.asserts.assert(renderMode == undefined ||
renderMode == ol.layer.VectorTileRenderType.IMAGE ||
renderMode == ol.layer.VectorTileRenderType.HYBRID ||
renderMode == ol.layer.VectorTileRenderType.VECTOR,
28); // `renderMode` must be `'image'`, `'hybrid'` or `'vector'`
if (options.declutter && renderMode == ol.layer.VectorTileRenderType.IMAGE) {
renderMode = ol.layer.VectorTileRenderType.HYBRID;
}
/**
* @private
* @type {ol.layer.VectorTileRenderType|string}
*/
this.renderMode_ = options.renderMode || ol.layer.VectorTileRenderType.HYBRID;
this.renderMode_ = renderMode || ol.layer.VectorTileRenderType.HYBRID;
/**
* The layer type.

View File

@@ -36,31 +36,38 @@ ol.Overlay = function(options) {
ol.Object.call(this);
/**
* @private
* @type {number|string|undefined}
* @protected
* @type {olx.OverlayOptions}
*/
this.id_ = options.id;
this.options = options;
/**
* @private
* @protected
* @type {number|string|undefined}
*/
this.id = options.id;
/**
* @protected
* @type {boolean}
*/
this.insertFirst_ = options.insertFirst !== undefined ?
this.insertFirst = options.insertFirst !== undefined ?
options.insertFirst : true;
/**
* @private
* @protected
* @type {boolean}
*/
this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true;
this.stopEvent = options.stopEvent !== undefined ? options.stopEvent : true;
/**
* @private
* @protected
* @type {Element}
*/
this.element_ = document.createElement('DIV');
this.element_.className = 'ol-overlay-container ' + ol.css.CLASS_SELECTABLE;
this.element_.style.position = 'absolute';
this.element = document.createElement('DIV');
this.element.className = options.className !== undefined ?
options.className : 'ol-overlay-container ' + ol.css.CLASS_SELECTABLE;
this.element.style.position = 'absolute';
/**
* @protected
@@ -69,28 +76,28 @@ ol.Overlay = function(options) {
this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
/**
* @private
* @protected
* @type {olx.OverlayPanOptions}
*/
this.autoPanAnimation_ = options.autoPanAnimation ||
this.autoPanAnimation = options.autoPanAnimation ||
/** @type {olx.OverlayPanOptions} */ ({});
/**
* @private
* @protected
* @type {number}
*/
this.autoPanMargin_ = options.autoPanMargin !== undefined ?
this.autoPanMargin = options.autoPanMargin !== undefined ?
options.autoPanMargin : 20;
/**
* @private
* @protected
* @type {{bottom_: string,
* left_: string,
* right_: string,
* top_: string,
* visible: boolean}}
*/
this.rendered_ = {
this.rendered = {
bottom_: '',
left_: '',
right_: '',
@@ -99,29 +106,29 @@ ol.Overlay = function(options) {
};
/**
* @private
* @protected
* @type {?ol.EventsKey}
*/
this.mapPostrenderListenerKey_ = null;
this.mapPostrenderListenerKey = null;
ol.events.listen(
this, ol.Object.getChangeEventType(ol.Overlay.Property_.ELEMENT),
this, ol.Object.getChangeEventType(ol.Overlay.Property.ELEMENT),
this.handleElementChanged, this);
ol.events.listen(
this, ol.Object.getChangeEventType(ol.Overlay.Property_.MAP),
this, ol.Object.getChangeEventType(ol.Overlay.Property.MAP),
this.handleMapChanged, this);
ol.events.listen(
this, ol.Object.getChangeEventType(ol.Overlay.Property_.OFFSET),
this, ol.Object.getChangeEventType(ol.Overlay.Property.OFFSET),
this.handleOffsetChanged, this);
ol.events.listen(
this, ol.Object.getChangeEventType(ol.Overlay.Property_.POSITION),
this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITION),
this.handlePositionChanged, this);
ol.events.listen(
this, ol.Object.getChangeEventType(ol.Overlay.Property_.POSITIONING),
this, ol.Object.getChangeEventType(ol.Overlay.Property.POSITIONING),
this.handlePositioningChanged, this);
if (options.element !== undefined) {
@@ -150,7 +157,7 @@ ol.inherits(ol.Overlay, ol.Object);
*/
ol.Overlay.prototype.getElement = function() {
return /** @type {Element|undefined} */ (
this.get(ol.Overlay.Property_.ELEMENT));
this.get(ol.Overlay.Property.ELEMENT));
};
@@ -160,7 +167,7 @@ ol.Overlay.prototype.getElement = function() {
* @api
*/
ol.Overlay.prototype.getId = function() {
return this.id_;
return this.id;
};
@@ -172,7 +179,7 @@ ol.Overlay.prototype.getId = function() {
*/
ol.Overlay.prototype.getMap = function() {
return /** @type {ol.PluggableMap|undefined} */ (
this.get(ol.Overlay.Property_.MAP));
this.get(ol.Overlay.Property.MAP));
};
@@ -184,7 +191,7 @@ ol.Overlay.prototype.getMap = function() {
*/
ol.Overlay.prototype.getOffset = function() {
return /** @type {Array.<number>} */ (
this.get(ol.Overlay.Property_.OFFSET));
this.get(ol.Overlay.Property.OFFSET));
};
@@ -197,7 +204,7 @@ ol.Overlay.prototype.getOffset = function() {
*/
ol.Overlay.prototype.getPosition = function() {
return /** @type {ol.Coordinate|undefined} */ (
this.get(ol.Overlay.Property_.POSITION));
this.get(ol.Overlay.Property.POSITION));
};
@@ -210,7 +217,7 @@ ol.Overlay.prototype.getPosition = function() {
*/
ol.Overlay.prototype.getPositioning = function() {
return /** @type {ol.OverlayPositioning} */ (
this.get(ol.Overlay.Property_.POSITIONING));
this.get(ol.Overlay.Property.POSITIONING));
};
@@ -218,10 +225,10 @@ ol.Overlay.prototype.getPositioning = function() {
* @protected
*/
ol.Overlay.prototype.handleElementChanged = function() {
ol.dom.removeChildren(this.element_);
ol.dom.removeChildren(this.element);
var element = this.getElement();
if (element) {
this.element_.appendChild(element);
this.element.appendChild(element);
}
};
@@ -230,22 +237,22 @@ ol.Overlay.prototype.handleElementChanged = function() {
* @protected
*/
ol.Overlay.prototype.handleMapChanged = function() {
if (this.mapPostrenderListenerKey_) {
ol.dom.removeNode(this.element_);
ol.events.unlistenByKey(this.mapPostrenderListenerKey_);
this.mapPostrenderListenerKey_ = null;
if (this.mapPostrenderListenerKey) {
ol.dom.removeNode(this.element);
ol.events.unlistenByKey(this.mapPostrenderListenerKey);
this.mapPostrenderListenerKey = null;
}
var map = this.getMap();
if (map) {
this.mapPostrenderListenerKey_ = ol.events.listen(map,
this.mapPostrenderListenerKey = ol.events.listen(map,
ol.MapEventType.POSTRENDER, this.render, this);
this.updatePixelPosition();
var container = this.stopEvent_ ?
var container = this.stopEvent ?
map.getOverlayContainerStopEvent() : map.getOverlayContainer();
if (this.insertFirst_) {
container.insertBefore(this.element_, container.childNodes[0] || null);
if (this.insertFirst) {
container.insertBefore(this.element, container.childNodes[0] || null);
} else {
container.appendChild(this.element_);
container.appendChild(this.element);
}
}
};
@@ -272,8 +279,8 @@ ol.Overlay.prototype.handleOffsetChanged = function() {
*/
ol.Overlay.prototype.handlePositionChanged = function() {
this.updatePixelPosition();
if (this.get(ol.Overlay.Property_.POSITION) && this.autoPan) {
this.panIntoView_();
if (this.get(ol.Overlay.Property.POSITION) && this.autoPan) {
this.panIntoView();
}
};
@@ -293,7 +300,7 @@ ol.Overlay.prototype.handlePositioningChanged = function() {
* @api
*/
ol.Overlay.prototype.setElement = function(element) {
this.set(ol.Overlay.Property_.ELEMENT, element);
this.set(ol.Overlay.Property.ELEMENT, element);
};
@@ -304,7 +311,7 @@ ol.Overlay.prototype.setElement = function(element) {
* @api
*/
ol.Overlay.prototype.setMap = function(map) {
this.set(ol.Overlay.Property_.MAP, map);
this.set(ol.Overlay.Property.MAP, map);
};
@@ -315,7 +322,7 @@ ol.Overlay.prototype.setMap = function(map) {
* @api
*/
ol.Overlay.prototype.setOffset = function(offset) {
this.set(ol.Overlay.Property_.OFFSET, offset);
this.set(ol.Overlay.Property.OFFSET, offset);
};
@@ -328,28 +335,28 @@ ol.Overlay.prototype.setOffset = function(offset) {
* @api
*/
ol.Overlay.prototype.setPosition = function(position) {
this.set(ol.Overlay.Property_.POSITION, position);
this.set(ol.Overlay.Property.POSITION, position);
};
/**
* Pan the map so that the overlay is entirely visible in the current viewport
* (if necessary).
* @private
* @protected
*/
ol.Overlay.prototype.panIntoView_ = function() {
ol.Overlay.prototype.panIntoView = function() {
var map = this.getMap();
if (!map || !map.getTargetElement()) {
return;
}
var mapRect = this.getRect_(map.getTargetElement(), map.getSize());
var mapRect = this.getRect(map.getTargetElement(), map.getSize());
var element = /** @type {!Element} */ (this.getElement());
var overlayRect = this.getRect_(element,
var overlayRect = this.getRect(element,
[ol.dom.outerWidth(element), ol.dom.outerHeight(element)]);
var margin = this.autoPanMargin_;
var margin = this.autoPanMargin;
if (!ol.extent.containsExtent(mapRect, overlayRect)) {
// the overlay is not completely inside the viewport, so pan the map
var offsetLeft = overlayRect[0] - mapRect[0];
@@ -383,8 +390,8 @@ ol.Overlay.prototype.panIntoView_ = function() {
map.getView().animate({
center: map.getCoordinateFromPixel(newCenterPx),
duration: this.autoPanAnimation_.duration,
easing: this.autoPanAnimation_.easing
duration: this.autoPanAnimation.duration,
easing: this.autoPanAnimation.easing
});
}
}
@@ -396,9 +403,9 @@ ol.Overlay.prototype.panIntoView_ = function() {
* @param {Element|undefined} element The element.
* @param {ol.Size|undefined} size The size of the element.
* @return {ol.Extent} The extent.
* @private
* @protected
*/
ol.Overlay.prototype.getRect_ = function(element, size) {
ol.Overlay.prototype.getRect = function(element, size) {
var box = element.getBoundingClientRect();
var offsetX = box.left + window.pageXOffset;
var offsetY = box.top + window.pageYOffset;
@@ -419,7 +426,7 @@ ol.Overlay.prototype.getRect_ = function(element, size) {
* @api
*/
ol.Overlay.prototype.setPositioning = function(positioning) {
this.set(ol.Overlay.Property_.POSITIONING, positioning);
this.set(ol.Overlay.Property.POSITIONING, positioning);
};
@@ -429,9 +436,9 @@ ol.Overlay.prototype.setPositioning = function(positioning) {
* @protected
*/
ol.Overlay.prototype.setVisible = function(visible) {
if (this.rendered_.visible !== visible) {
this.element_.style.display = visible ? '' : 'none';
this.rendered_.visible = visible;
if (this.rendered.visible !== visible) {
this.element.style.display = visible ? '' : 'none';
this.rendered.visible = visible;
}
};
@@ -460,7 +467,7 @@ ol.Overlay.prototype.updatePixelPosition = function() {
* @protected
*/
ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {
var style = this.element_.style;
var style = this.element.style;
var offset = this.getOffset();
var positioning = this.getPositioning();
@@ -472,59 +479,69 @@ ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {
if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT ||
positioning == ol.OverlayPositioning.CENTER_RIGHT ||
positioning == ol.OverlayPositioning.TOP_RIGHT) {
if (this.rendered_.left_ !== '') {
this.rendered_.left_ = style.left = '';
if (this.rendered.left_ !== '') {
this.rendered.left_ = style.left = '';
}
var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
if (this.rendered_.right_ != right) {
this.rendered_.right_ = style.right = right;
if (this.rendered.right_ != right) {
this.rendered.right_ = style.right = right;
}
} else {
if (this.rendered_.right_ !== '') {
this.rendered_.right_ = style.right = '';
if (this.rendered.right_ !== '') {
this.rendered.right_ = style.right = '';
}
if (positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
positioning == ol.OverlayPositioning.CENTER_CENTER ||
positioning == ol.OverlayPositioning.TOP_CENTER) {
offsetX -= this.element_.offsetWidth / 2;
offsetX -= this.element.offsetWidth / 2;
}
var left = Math.round(pixel[0] + offsetX) + 'px';
if (this.rendered_.left_ != left) {
this.rendered_.left_ = style.left = left;
if (this.rendered.left_ != left) {
this.rendered.left_ = style.left = left;
}
}
if (positioning == ol.OverlayPositioning.BOTTOM_LEFT ||
positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
positioning == ol.OverlayPositioning.BOTTOM_RIGHT) {
if (this.rendered_.top_ !== '') {
this.rendered_.top_ = style.top = '';
if (this.rendered.top_ !== '') {
this.rendered.top_ = style.top = '';
}
var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
if (this.rendered_.bottom_ != bottom) {
this.rendered_.bottom_ = style.bottom = bottom;
if (this.rendered.bottom_ != bottom) {
this.rendered.bottom_ = style.bottom = bottom;
}
} else {
if (this.rendered_.bottom_ !== '') {
this.rendered_.bottom_ = style.bottom = '';
if (this.rendered.bottom_ !== '') {
this.rendered.bottom_ = style.bottom = '';
}
if (positioning == ol.OverlayPositioning.CENTER_LEFT ||
positioning == ol.OverlayPositioning.CENTER_CENTER ||
positioning == ol.OverlayPositioning.CENTER_RIGHT) {
offsetY -= this.element_.offsetHeight / 2;
offsetY -= this.element.offsetHeight / 2;
}
var top = Math.round(pixel[1] + offsetY) + 'px';
if (this.rendered_.top_ != top) {
this.rendered_.top_ = style.top = top;
if (this.rendered.top_ != top) {
this.rendered.top_ = style.top = top;
}
}
};
/**
* @enum {string}
* @private
* returns the options this Overlay has been created with
* @public
* @return {olx.OverlayOptions} overlay options
*/
ol.Overlay.Property_ = {
ol.Overlay.prototype.getOptions = function() {
return this.options;
};
/**
* @enum {string}
* @protected
*/
ol.Overlay.Property = {
ELEMENT: 'element',
MAP: 'map',
OFFSET: 'offset',

View File

@@ -239,7 +239,7 @@ ol.PluggableMap = function(options) {
* @type {ol.renderer.Map}
* @private
*/
this.renderer_ = optionsInternal.mapRendererPlugin.create(this.viewport_, this);
this.renderer_ = optionsInternal.mapRendererPlugin['create'](this.viewport_, this);
/**
* @type {function(Event)|undefined}
@@ -1418,7 +1418,7 @@ ol.PluggableMap.createOptionsInternal = function(options) {
var rendererType = rendererTypes[i];
for (var j = 0, jj = mapRendererPlugins.length; j < jj; ++j) {
var candidate = mapRendererPlugins[j];
if (candidate.handles(rendererType)) {
if (candidate['handles'](rendererType)) {
mapRendererPlugin = candidate;
break outer;
}

View File

@@ -3,6 +3,7 @@ goog.provide('ol.proj');
goog.require('ol');
goog.require('ol.Sphere');
goog.require('ol.extent');
goog.require('ol.math');
goog.require('ol.proj.EPSG3857');
goog.require('ol.proj.EPSG4326');
goog.require('ol.proj.Projection');
@@ -282,8 +283,13 @@ ol.proj.fromLonLat = function(coordinate, opt_projection) {
* @api
*/
ol.proj.toLonLat = function(coordinate, opt_projection) {
return ol.proj.transform(coordinate,
var lonLat = ol.proj.transform(coordinate,
opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');
var lon = lonLat[0];
if (lon < -180 || lon > 180) {
lonLat[0] = ol.math.modulo(lon + 180, 360) - 180;
}
return lonLat;
};

View File

@@ -1,6 +1,12 @@
goog.provide('ol.render.canvas');
goog.require('ol.css');
goog.require('ol.dom');
goog.require('ol.structs.LRUCache');
goog.require('ol.transform');
/**
* @const
* @type {string}
@@ -78,6 +84,91 @@ ol.render.canvas.defaultTextBaseline = 'middle';
ol.render.canvas.defaultLineWidth = 1;
/**
* @type {ol.structs.LRUCache.<HTMLCanvasElement>}
*/
ol.render.canvas.labelCache = new ol.structs.LRUCache();
/**
* @type {!Object.<string, (number)>}
*/
ol.render.canvas.checkedFonts_ = {};
/**
* Clears the label cache when a font becomes available.
* @param {string} fontSpec CSS font spec.
*/
ol.render.canvas.checkFont = (function() {
var checked = ol.render.canvas.checkedFonts_;
var labelCache = ol.render.canvas.labelCache;
var font = '32px monospace';
var text = 'wmytzilWMYTZIL@#/&?$%10';
var context, interval, referenceWidth;
function isAvailable(fontFamily) {
if (!context) {
context = ol.dom.createCanvasContext2D(1, 1);
context.font = font;
referenceWidth = context.measureText(text).width;
}
var available = true;
if (fontFamily != 'monospace') {
context.font = '32px ' + fontFamily + ',monospace';
var width = context.measureText(text).width;
// If width and referenceWidth are the same, then the 'monospace'
// fallback was used instead of the font we wanted, so the font is not
// available.
available = width != referenceWidth;
// Setting the font back to a different one works around an issue in
// Safari where subsequent `context.font` assignments with the same font
// will not re-attempt to use a font that is currently loading.
context.font = font;
}
return available;
}
function check() {
var done = true;
for (var font in checked) {
if (checked[font] < 60) {
if (isAvailable(font)) {
checked[font] = 60;
labelCache.clear();
} else {
++checked[font];
done = false;
}
}
}
if (done) {
window.clearInterval(interval);
interval = undefined;
}
}
return function(fontSpec) {
var fontFamilies = ol.css.getFontFamilies(fontSpec);
if (!fontFamilies) {
return;
}
for (var i = 0, ii = fontFamilies.length; i < ii; ++i) {
var fontFamily = fontFamilies[i];
if (!(fontFamily in checked)) {
checked[fontFamily] = 60;
if (!isAvailable(fontFamily)) {
checked[fontFamily] = 0;
if (interval === undefined) {
interval = window.setInterval(check, 32);
}
}
}
}
};
})();
/**
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
@@ -91,3 +182,41 @@ ol.render.canvas.rotateAtOffset = function(context, rotation, offsetX, offsetY)
context.translate(-offsetX, -offsetY);
}
};
ol.render.canvas.resetTransform_ = ol.transform.create();
/**
* @param {CanvasRenderingContext2D} context Context.
* @param {ol.Transform|null} transform Transform.
* @param {number} opacity Opacity.
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.
* @param {number} originX Origin X.
* @param {number} originY Origin Y.
* @param {number} w Width.
* @param {number} h Height.
* @param {number} x X.
* @param {number} y Y.
* @param {number} scale Scale.
*/
ol.render.canvas.drawImage = function(context,
transform, opacity, image, originX, originY, w, h, x, y, scale) {
var alpha;
if (opacity != 1) {
alpha = context.globalAlpha;
context.globalAlpha = alpha * opacity;
}
if (transform) {
context.setTransform.apply(context, transform);
}
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
if (alpha) {
context.globalAlpha = alpha;
}
if (transform) {
context.setTransform.apply(context, ol.render.canvas.resetTransform_);
}
};

View File

@@ -13,10 +13,19 @@ goog.require('ol.render.canvas.Replay');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @struct
*/
ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps) {
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
ol.render.canvas.ImageReplay = function(
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree) {
ol.render.canvas.Replay.call(this,
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree);
/**
* @private
* @type {ol.DeclutterGroup}
*/
this.declutterGroup_ = null;
/**
* @private
@@ -130,7 +139,7 @@ ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, featu
this.instructions.push([
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_ * this.pixelRatio, this.snapToPixel_, this.width_
]);
@@ -138,7 +147,7 @@ ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, featu
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.snapToPixel_, this.width_
]);
@@ -162,7 +171,7 @@ ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeome
this.instructions.push([
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_ * this.pixelRatio, this.snapToPixel_, this.width_
]);
@@ -170,7 +179,7 @@ ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeome
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.snapToPixel_, this.width_
]);
@@ -203,7 +212,7 @@ ol.render.canvas.ImageReplay.prototype.finish = function() {
/**
* @inheritDoc
*/
ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle, declutterGroup) {
var anchor = imageStyle.getAnchor();
var size = imageStyle.getSize();
var hitDetectionImage = imageStyle.getHitDetectionImage(1);
@@ -211,6 +220,7 @@ ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
var origin = imageStyle.getOrigin();
this.anchorX_ = anchor[0];
this.anchorY_ = anchor[1];
this.declutterGroup_ = /** @type {ol.DeclutterGroup} */ (declutterGroup);
this.hitDetectionImage_ = hitDetectionImage;
this.image_ = image;
this.height_ = size[1];

View File

@@ -1,10 +1,6 @@
goog.provide('ol.render.canvas.LineStringReplay');
goog.require('ol');
goog.require('ol.array');
goog.require('ol.colorlike');
goog.require('ol.extent');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Instruction');
goog.require('ol.render.canvas.Replay');
@@ -17,54 +13,13 @@ goog.require('ol.render.canvas.Replay');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @struct
*/
ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps) {
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
/**
* @private
* @type {ol.Extent}
*/
this.bufferedMaxExtent_ = null;
/**
* @private
* @type {{currentStrokeStyle: (ol.ColorLike|undefined),
* currentLineCap: (string|undefined),
* currentLineDash: Array.<number>,
* currentLineDashOffset: (number|undefined),
* currentLineJoin: (string|undefined),
* currentLineWidth: (number|undefined),
* currentMiterLimit: (number|undefined),
* lastStroke: (number|undefined),
* strokeStyle: (ol.ColorLike|undefined),
* lineCap: (string|undefined),
* lineDash: Array.<number>,
* lineDashOffset: (number|undefined),
* lineJoin: (string|undefined),
* lineWidth: (number|undefined),
* miterLimit: (number|undefined)}|null}
*/
this.state_ = {
currentStrokeStyle: undefined,
currentLineCap: undefined,
currentLineDash: null,
currentLineDashOffset: undefined,
currentLineJoin: undefined,
currentLineWidth: undefined,
currentMiterLimit: undefined,
lastStroke: undefined,
strokeStyle: undefined,
lineCap: undefined,
lineDash: null,
lineDashOffset: undefined,
lineJoin: undefined,
lineWidth: undefined,
miterLimit: undefined
};
ol.render.canvas.LineStringReplay = function(
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree) {
ol.render.canvas.Replay.call(this,
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree);
};
ol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay);
@@ -89,74 +44,17 @@ ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flat
};
/**
* @inheritDoc
*/
ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() {
if (!this.bufferedMaxExtent_) {
this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
if (this.maxLineWidth > 0) {
var width = this.resolution * (this.maxLineWidth + 1) / 2;
ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
}
}
return this.bufferedMaxExtent_;
};
/**
* @private
*/
ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() {
var state = this.state_;
var strokeStyle = state.strokeStyle;
var lineCap = state.lineCap;
var lineDash = state.lineDash;
var lineDashOffset = state.lineDashOffset;
var lineJoin = state.lineJoin;
var lineWidth = state.lineWidth;
var miterLimit = state.miterLimit;
if (state.currentStrokeStyle != strokeStyle ||
state.currentLineCap != lineCap ||
!ol.array.equals(state.currentLineDash, lineDash) ||
state.currentLineDashOffset != lineDashOffset ||
state.currentLineJoin != lineJoin ||
state.currentLineWidth != lineWidth ||
state.currentMiterLimit != miterLimit) {
if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
this.instructions.push([ol.render.canvas.Instruction.STROKE]);
state.lastStroke = this.coordinates.length;
}
state.lastStroke = 0;
this.instructions.push([
ol.render.canvas.Instruction.SET_STROKE_STYLE,
strokeStyle, lineWidth * this.pixelRatio, lineCap, lineJoin, miterLimit,
this.applyPixelRatio(lineDash), lineDashOffset * this.pixelRatio
], [
ol.render.canvas.Instruction.BEGIN_PATH
]);
state.currentStrokeStyle = strokeStyle;
state.currentLineCap = lineCap;
state.currentLineDash = lineDash;
state.currentLineDashOffset = lineDashOffset;
state.currentLineJoin = lineJoin;
state.currentLineWidth = lineWidth;
state.currentMiterLimit = miterLimit;
}
};
/**
* @inheritDoc
*/
ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {
var state = this.state_;
var state = this.state;
var strokeStyle = state.strokeStyle;
var lineWidth = state.lineWidth;
if (strokeStyle === undefined || lineWidth === undefined) {
return;
}
this.setStrokeStyle_();
this.updateStrokeStyle(state, true);
this.beginGeometry(lineStringGeometry, feature);
this.hitDetectionInstructions.push([
ol.render.canvas.Instruction.SET_STROKE_STYLE,
@@ -177,13 +75,13 @@ ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineString
* @inheritDoc
*/
ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {
var state = this.state_;
var state = this.state;
var strokeStyle = state.strokeStyle;
var lineWidth = state.lineWidth;
if (strokeStyle === undefined || lineWidth === undefined) {
return;
}
this.setStrokeStyle_();
this.updateStrokeStyle(state, true);
this.beginGeometry(multiLineStringGeometry, feature);
this.hitDetectionInstructions.push([
ol.render.canvas.Instruction.SET_STROKE_STYLE,
@@ -210,44 +108,10 @@ ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multi
* @inheritDoc
*/
ol.render.canvas.LineStringReplay.prototype.finish = function() {
var state = this.state_;
var state = this.state;
if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
this.instructions.push([ol.render.canvas.Instruction.STROKE]);
}
this.reverseHitDetectionInstructions();
this.state_ = null;
};
/**
* @inheritDoc
*/
ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
var strokeStyleColor = strokeStyle.getColor();
this.state_.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
var strokeStyleLineCap = strokeStyle.getLineCap();
this.state_.lineCap = strokeStyleLineCap !== undefined ?
strokeStyleLineCap : ol.render.canvas.defaultLineCap;
var strokeStyleLineDash = strokeStyle.getLineDash();
this.state_.lineDash = strokeStyleLineDash ?
strokeStyleLineDash : ol.render.canvas.defaultLineDash;
var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
this.state_.lineDashOffset = strokeStyleLineDashOffset ?
strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
var strokeStyleLineJoin = strokeStyle.getLineJoin();
this.state_.lineJoin = strokeStyleLineJoin !== undefined ?
strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
var strokeStyleWidth = strokeStyle.getWidth();
this.state_.lineWidth = strokeStyleWidth !== undefined ?
strokeStyleWidth : ol.render.canvas.defaultLineWidth;
var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
this.state_.miterLimit = strokeStyleMiterLimit !== undefined ?
strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
if (this.state_.lineWidth > this.maxLineWidth) {
this.maxLineWidth = this.state_.lineWidth;
// invalidate the buffered max extent cache
this.bufferedMaxExtent_ = null;
}
this.state = null;
};

View File

@@ -1,10 +1,7 @@
goog.provide('ol.render.canvas.PolygonReplay');
goog.require('ol');
goog.require('ol.array');
goog.require('ol.color');
goog.require('ol.colorlike');
goog.require('ol.extent');
goog.require('ol.geom.flat.simplify');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Instruction');
@@ -19,56 +16,13 @@ goog.require('ol.render.canvas.Replay');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @struct
*/
ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps) {
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
/**
* @private
* @type {ol.Extent}
*/
this.bufferedMaxExtent_ = null;
/**
* @private
* @type {{currentFillStyle: (ol.ColorLike|undefined),
* currentStrokeStyle: (ol.ColorLike|undefined),
* currentLineCap: (string|undefined),
* currentLineDash: Array.<number>,
* currentLineDashOffset: (number|undefined),
* currentLineJoin: (string|undefined),
* currentLineWidth: (number|undefined),
* currentMiterLimit: (number|undefined),
* fillStyle: (ol.ColorLike|undefined),
* strokeStyle: (ol.ColorLike|undefined),
* lineCap: (string|undefined),
* lineDash: Array.<number>,
* lineDashOffset: (number|undefined),
* lineJoin: (string|undefined),
* lineWidth: (number|undefined),
* miterLimit: (number|undefined)}|null}
*/
this.state_ = {
currentFillStyle: undefined,
currentStrokeStyle: undefined,
currentLineCap: undefined,
currentLineDash: null,
currentLineDashOffset: undefined,
currentLineJoin: undefined,
currentLineWidth: undefined,
currentMiterLimit: undefined,
fillStyle: undefined,
strokeStyle: undefined,
lineCap: undefined,
lineDash: null,
lineDashOffset: undefined,
lineJoin: undefined,
lineWidth: undefined,
miterLimit: undefined
};
ol.render.canvas.PolygonReplay = function(
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree) {
ol.render.canvas.Replay.call(this,
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree);
};
ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);
@@ -82,7 +36,7 @@ ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);
* @return {number} End.
*/
ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) {
var state = this.state_;
var state = this.state;
var fill = state.fillStyle !== undefined;
var stroke = state.strokeStyle != undefined;
var numEnds = ends.length;
@@ -125,7 +79,7 @@ ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCo
* @inheritDoc
*/
ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) {
var state = this.state_;
var state = this.state;
var fillStyle = state.fillStyle;
var strokeStyle = state.strokeStyle;
if (fillStyle === undefined && strokeStyle === undefined) {
@@ -172,7 +126,7 @@ ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, f
* @inheritDoc
*/
ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
var state = this.state_;
var state = this.state;
this.setFillStrokeStyles_(polygonGeometry);
this.beginGeometry(polygonGeometry, feature);
// always fill the polygon for hit detection
@@ -199,7 +153,7 @@ ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry,
* @inheritDoc
*/
ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
var state = this.state_;
var state = this.state;
var fillStyle = state.fillStyle;
var strokeStyle = state.strokeStyle;
if (fillStyle === undefined && strokeStyle === undefined) {
@@ -237,7 +191,7 @@ ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygo
*/
ol.render.canvas.PolygonReplay.prototype.finish = function() {
this.reverseHitDetectionInstructions();
this.state_ = null;
this.state = null;
// We want to preserve topology when drawing polygons. Polygons are
// simplified using quantization and point elimination. However, we might
// have received a mix of quantized and non-quantized geometries, so ensure
@@ -253,87 +207,13 @@ ol.render.canvas.PolygonReplay.prototype.finish = function() {
};
/**
* @inheritDoc
*/
ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() {
if (!this.bufferedMaxExtent_) {
this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
if (this.maxLineWidth > 0) {
var width = this.resolution * (this.maxLineWidth + 1) / 2;
ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
}
}
return this.bufferedMaxExtent_;
};
/**
* @inheritDoc
*/
ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
var state = this.state_;
if (fillStyle) {
var fillStyleColor = fillStyle.getColor();
state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
fillStyleColor : ol.render.canvas.defaultFillStyle);
} else {
state.fillStyle = undefined;
}
if (strokeStyle) {
var strokeStyleColor = strokeStyle.getColor();
state.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
var strokeStyleLineCap = strokeStyle.getLineCap();
state.lineCap = strokeStyleLineCap !== undefined ?
strokeStyleLineCap : ol.render.canvas.defaultLineCap;
var strokeStyleLineDash = strokeStyle.getLineDash();
state.lineDash = strokeStyleLineDash ?
strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
state.lineDashOffset = strokeStyleLineDashOffset ?
strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
var strokeStyleLineJoin = strokeStyle.getLineJoin();
state.lineJoin = strokeStyleLineJoin !== undefined ?
strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
var strokeStyleWidth = strokeStyle.getWidth();
state.lineWidth = strokeStyleWidth !== undefined ?
strokeStyleWidth : ol.render.canvas.defaultLineWidth;
var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
state.miterLimit = strokeStyleMiterLimit !== undefined ?
strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
if (state.lineWidth > this.maxLineWidth) {
this.maxLineWidth = state.lineWidth;
// invalidate the buffered max extent cache
this.bufferedMaxExtent_ = null;
}
} else {
state.strokeStyle = undefined;
state.lineCap = undefined;
state.lineDash = null;
state.lineDashOffset = undefined;
state.lineJoin = undefined;
state.lineWidth = undefined;
state.miterLimit = undefined;
}
};
/**
* @private
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
*/
ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometry) {
var state = this.state_;
var state = this.state;
var fillStyle = state.fillStyle;
var strokeStyle = state.strokeStyle;
var lineCap = state.lineCap;
var lineDash = state.lineDash;
var lineDashOffset = state.lineDashOffset;
var lineJoin = state.lineJoin;
var lineWidth = state.lineWidth;
var miterLimit = state.miterLimit;
if (fillStyle !== undefined && (typeof fillStyle !== 'string' || state.currentFillStyle != fillStyle)) {
var fillInstruction = [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle];
if (typeof fillStyle !== 'string') {
@@ -343,26 +223,7 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometr
this.instructions.push(fillInstruction);
state.currentFillStyle = state.fillStyle;
}
if (strokeStyle !== undefined) {
if (state.currentStrokeStyle != strokeStyle ||
state.currentLineCap != lineCap ||
!ol.array.equals(state.currentLineDash, lineDash) ||
state.currentLineDashOffset != lineDashOffset ||
state.currentLineJoin != lineJoin ||
state.currentLineWidth != lineWidth ||
state.currentMiterLimit != miterLimit) {
this.instructions.push([
ol.render.canvas.Instruction.SET_STROKE_STYLE,
strokeStyle, lineWidth * this.pixelRatio, lineCap, lineJoin, miterLimit,
this.applyPixelRatio(lineDash), lineDashOffset * this.pixelRatio
]);
state.currentStrokeStyle = strokeStyle;
state.currentLineCap = lineCap;
state.currentLineDash = lineDash;
state.currentLineDashOffset = lineDashOffset;
state.currentLineJoin = lineJoin;
state.currentLineWidth = lineWidth;
state.currentMiterLimit = miterLimit;
}
if (state.strokeStyle !== undefined) {
this.updateStrokeStyle(state, false);
}
};

View File

@@ -2,6 +2,7 @@ goog.provide('ol.render.canvas.Replay');
goog.require('ol');
goog.require('ol.array');
goog.require('ol.colorlike');
goog.require('ol.extent');
goog.require('ol.extent.Relationship');
goog.require('ol.geom.GeometryType');
@@ -12,6 +13,7 @@ goog.require('ol.geom.flat.transform');
goog.require('ol.has');
goog.require('ol.obj');
goog.require('ol.render.VectorContext');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Instruction');
goog.require('ol.transform');
@@ -24,11 +26,23 @@ goog.require('ol.transform');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @struct
*/
ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps) {
ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree) {
ol.render.VectorContext.call(this);
/**
* @type {?}
*/
this.declutterTree = declutterTree;
/**
* @private
* @type {ol.Extent}
*/
this.tmpExtent_ = ol.extent.createEmpty();
/**
* @protected
* @type {number}
@@ -85,6 +99,12 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio,
*/
this.beginGeometryInstruction2_ = null;
/**
* @private
* @type {ol.Extent}
*/
this.bufferedMaxExtent_ = null;
/**
* @protected
* @type {Array.<*>}
@@ -121,6 +141,12 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio,
*/
this.pixelCoordinates_ = null;
/**
* @protected
* @type {ol.CanvasFillStrokeState}
*/
this.state = /** @type {ol.CanvasFillStrokeState} */ ({});
/**
* @private
* @type {!ol.Transform}
@@ -132,12 +158,6 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio,
* @type {!ol.Transform}
*/
this.resetTransform_ = ol.transform.create();
/**
* @private
* @type {Array.<Array.<number>>}
*/
this.chars_ = [];
};
ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
@@ -149,6 +169,7 @@ ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.
* @param {number} anchorX Anchor X.
* @param {number} anchorY Anchor Y.
* @param {ol.DeclutterGroup} declutterGroup Declutter group.
* @param {number} height Height.
* @param {number} opacity Opacity.
* @param {number} originX Origin X.
@@ -159,7 +180,7 @@ ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
* @param {number} width Width.
*/
ol.render.canvas.Replay.prototype.replayImage_ = function(context, x, y, image, anchorX, anchorY,
height, opacity, originX, originY, rotation, scale, snapToPixel, width) {
declutterGroup, height, opacity, originX, originY, rotation, scale, snapToPixel, width) {
var localTransform = this.tmpLocalTransform_;
anchorX *= scale;
anchorY *= scale;
@@ -169,28 +190,37 @@ ol.render.canvas.Replay.prototype.replayImage_ = function(context, x, y, image,
x = Math.round(x);
y = Math.round(y);
}
if (rotation !== 0) {
var centerX = x + anchorX;
var centerY = y + anchorY;
ol.transform.compose(localTransform,
centerX, centerY, 1, 1, rotation, -centerX, -centerY);
context.setTransform.apply(context, localTransform);
}
var alpha = context.globalAlpha;
if (opacity != 1) {
context.globalAlpha = alpha * opacity;
}
var w = (width + originX > image.width) ? image.width - originX : width;
var h = (height + originY > image.height) ? image.height - originY : height;
var box = this.tmpExtent_;
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
if (opacity != 1) {
context.globalAlpha = alpha;
}
var transform = null;
if (rotation !== 0) {
context.setTransform.apply(context, this.resetTransform_);
var centerX = x + anchorX;
var centerY = y + anchorY;
transform = ol.transform.compose(localTransform,
centerX, centerY, 1, 1, rotation, -centerX, -centerY);
ol.extent.createOrUpdateEmpty(box);
ol.extent.extendCoordinate(box, ol.transform.apply(localTransform, [x, y]));
ol.extent.extendCoordinate(box, ol.transform.apply(localTransform, [x + w, y]));
ol.extent.extendCoordinate(box, ol.transform.apply(localTransform, [x + w, y + h]));
ol.extent.extendCoordinate(box, ol.transform.apply(localTransform, [x, y + w]));
} else {
ol.extent.createOrUpdate(x, y, x + w * scale, y + h * scale, box);
}
var canvas = context.canvas;
var intersects = box[0] <= canvas.width && box[2] >= 0 && box[1] <= canvas.height && box[3] >= 0;
if (declutterGroup) {
if (!intersects && declutterGroup[4] == 1) {
return;
}
ol.extent.extend(declutterGroup, box);
declutterGroup.push(intersects ?
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
null);
} else if (intersects) {
ol.render.canvas.drawImage(context, transform, opacity, image, originX, originY, w, h, x, y, scale);
}
};
@@ -360,7 +390,37 @@ ol.render.canvas.Replay.prototype.fill_ = function(context, rotation) {
}
context.fill();
if (this.fillOrigin_) {
context.setTransform.apply(context, this.resetTransform_);
context.setTransform.apply(context, ol.render.canvas.resetTransform_);
}
};
/**
* @param {ol.DeclutterGroup} declutterGroup Declutter group.
*/
ol.render.canvas.Replay.prototype.renderDeclutter_ = function(declutterGroup) {
if (declutterGroup && declutterGroup.length > 5) {
var groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
/** @type {ol.RBushEntry} */
var box = {
minX: /** @type {number} */ (declutterGroup[0]),
minY: /** @type {number} */ (declutterGroup[1]),
maxX: /** @type {number} */ (declutterGroup[2]),
maxY: /** @type {number} */ (declutterGroup[3])
};
if (!this.declutterTree.collides(box)) {
this.declutterTree.insert(box);
var drawImage = ol.render.canvas.drawImage;
for (var j = 5, jj = declutterGroup.length; j < jj; ++j) {
if (declutterGroup[j]) {
drawImage.apply(undefined, /** @type {Array} */ (declutterGroup[j]));
}
}
}
declutterGroup.length = 5;
ol.extent.createOrUpdateEmpty(declutterGroup);
}
}
};
@@ -401,7 +461,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
var ii = instructions.length; // end of instructions
var d = 0; // data index
var dd; // end of per-instruction data
var anchorX, anchorY, prevX, prevY, roundX, roundY;
var anchorX, anchorY, prevX, prevY, roundX, roundY, declutterGroup;
var pendingFill = 0;
var pendingStroke = 0;
var coordinateCache = this.coordinateCache_;
@@ -497,60 +557,81 @@ ol.render.canvas.Replay.prototype.replay_ = function(
// Remaining arguments in DRAW_IMAGE are in alphabetical order
anchorX = /** @type {number} */ (instruction[4]);
anchorY = /** @type {number} */ (instruction[5]);
var height = /** @type {number} */ (instruction[6]);
var opacity = /** @type {number} */ (instruction[7]);
var originX = /** @type {number} */ (instruction[8]);
var originY = /** @type {number} */ (instruction[9]);
var rotateWithView = /** @type {boolean} */ (instruction[10]);
var rotation = /** @type {number} */ (instruction[11]);
var scale = /** @type {number} */ (instruction[12]);
var snapToPixel = /** @type {boolean} */ (instruction[13]);
var width = /** @type {number} */ (instruction[14]);
declutterGroup = /** @type {ol.DeclutterGroup} */ (instruction[6]);
var height = /** @type {number} */ (instruction[7]);
var opacity = /** @type {number} */ (instruction[8]);
var originX = /** @type {number} */ (instruction[9]);
var originY = /** @type {number} */ (instruction[10]);
var rotateWithView = /** @type {boolean} */ (instruction[11]);
var rotation = /** @type {number} */ (instruction[12]);
var scale = /** @type {number} */ (instruction[13]);
var snapToPixel = /** @type {boolean} */ (instruction[14]);
var width = /** @type {number} */ (instruction[15]);
if (rotateWithView) {
rotation += viewRotation;
}
for (; d < dd; d += 2) {
this.replayImage_(context, pixelCoordinates[d], pixelCoordinates[d + 1],
image, anchorX, anchorY, height, opacity, originX, originY,
rotation, scale, snapToPixel, width);
this.replayImage_(context,
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
declutterGroup, height, opacity, originX, originY, rotation, scale, snapToPixel, width);
}
this.renderDeclutter_(declutterGroup);
++i;
break;
case ol.render.canvas.Instruction.DRAW_CHARS:
var begin = /** @type {number} */ (instruction[1]);
var end = /** @type {number} */ (instruction[2]);
var images = /** @type {Array.<HTMLCanvasElement>} */ (instruction[3]);
// Remaining arguments in DRAW_CHARS are in alphabetical order
var baseline = /** @type {number} */ (instruction[4]);
var baseline = /** @type {number} */ (instruction[3]);
declutterGroup = /** @type {ol.DeclutterGroup} */ (instruction[4]);
var exceedLength = /** @type {number} */ (instruction[5]);
var maxAngle = /** @type {number} */ (instruction[6]);
var measure = /** @type {function(string):number} */ (instruction[7]);
var offsetY = /** @type {number} */ (instruction[8]);
var text = /** @type {string} */ (instruction[9]);
var align = /** @type {number} */ (instruction[10]);
var textScale = /** @type {number} */ (instruction[11]);
var fill = /** @type {boolean} */ (instruction[6]);
var maxAngle = /** @type {number} */ (instruction[7]);
var measure = /** @type {function(string):number} */ (instruction[8]);
var offsetY = /** @type {number} */ (instruction[9]);
var stroke = /** @type {boolean} */ (instruction[10]);
var strokeWidth = /** @type {number} */ (instruction[11]);
var text = /** @type {string} */ (instruction[12]);
var textAlign = /** @type {number} */ (instruction[13]);
var textScale = /** @type {number} */ (instruction[14]);
var pathLength = ol.geom.flat.length.lineString(pixelCoordinates, begin, end, 2);
var textLength = measure(text);
if (exceedLength || textLength <= pathLength) {
var startM = (pathLength - textLength) * align;
var chars = ol.geom.flat.textpath.lineString(
pixelCoordinates, begin, end, 2, text, measure, startM, maxAngle, this.chars_);
var numChars = text.length;
if (chars) {
var fillHeight = images[images.length - 1].height;
for (var c = 0, cc = images.length; c < cc; ++c) {
var char = chars[c % numChars]; // x, y, rotation
var label = images[c];
anchorX = label.width / 2;
anchorY = baseline * label.height + (0.5 - baseline) * (label.height - fillHeight) - offsetY;
this.replayImage_(context, char[0], char[1], label, anchorX, anchorY,
label.height, 1, 0, 0, char[2], textScale, false, label.width);
var startM = (pathLength - textLength) * textAlign;
var parts = ol.geom.flat.textpath.lineString(
pixelCoordinates, begin, end, 2, text, measure, startM, maxAngle);
if (parts) {
var c, cc, chars, label, part;
if (stroke) {
for (c = 0, cc = parts.length; c < cc; ++c) {
part = parts[c]; // x, y, anchorX, rotation, chunk
chars = /** @type {string} */ (part[4]);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, false, true);
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
anchorY = baseline * label.height + (0.5 - baseline) * 2 * strokeWidth - offsetY;
this.replayImage_(context,
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
/** @type {number} */ (part[3]), textScale, false, label.width);
}
}
if (fill) {
for (c = 0, cc = parts.length; c < cc; ++c) {
part = parts[c]; // x, y, anchorX, rotation, chunk
chars = /** @type {string} */ (part[4]);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, true, false);
anchorX = /** @type {number} */ (part[2]);
anchorY = baseline * label.height - offsetY;
this.replayImage_(context,
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
/** @type {number} */ (part[3]), textScale, false, label.width);
}
}
}
}
this.renderDeclutter_(declutterGroup);
++i;
break;
case ol.render.canvas.Instruction.END_GEOMETRY:
@@ -714,6 +795,103 @@ ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions = function() {
};
/**
* @inheritDoc
*/
ol.render.canvas.Replay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
var state = this.state;
if (fillStyle) {
var fillStyleColor = fillStyle.getColor();
state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
fillStyleColor : ol.render.canvas.defaultFillStyle);
} else {
state.fillStyle = undefined;
}
if (strokeStyle) {
var strokeStyleColor = strokeStyle.getColor();
state.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
var strokeStyleLineCap = strokeStyle.getLineCap();
state.lineCap = strokeStyleLineCap !== undefined ?
strokeStyleLineCap : ol.render.canvas.defaultLineCap;
var strokeStyleLineDash = strokeStyle.getLineDash();
state.lineDash = strokeStyleLineDash ?
strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
state.lineDashOffset = strokeStyleLineDashOffset ?
strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
var strokeStyleLineJoin = strokeStyle.getLineJoin();
state.lineJoin = strokeStyleLineJoin !== undefined ?
strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
var strokeStyleWidth = strokeStyle.getWidth();
state.lineWidth = strokeStyleWidth !== undefined ?
strokeStyleWidth : ol.render.canvas.defaultLineWidth;
var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
state.miterLimit = strokeStyleMiterLimit !== undefined ?
strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
if (state.lineWidth > this.maxLineWidth) {
this.maxLineWidth = state.lineWidth;
// invalidate the buffered max extent cache
this.bufferedMaxExtent_ = null;
}
} else {
state.strokeStyle = undefined;
state.lineCap = undefined;
state.lineDash = null;
state.lineDashOffset = undefined;
state.lineJoin = undefined;
state.lineWidth = undefined;
state.miterLimit = undefined;
}
};
/**
* @param {ol.CanvasFillStrokeState} state State.
* @param {boolean} managePath Manage stoke() - beginPath() for linestrings.
*/
ol.render.canvas.Replay.prototype.updateStrokeStyle = function(state, managePath) {
var strokeStyle = state.strokeStyle;
var lineCap = state.lineCap;
var lineDash = state.lineDash;
var lineDashOffset = state.lineDashOffset;
var lineJoin = state.lineJoin;
var lineWidth = state.lineWidth;
var miterLimit = state.miterLimit;
if (state.currentStrokeStyle != strokeStyle ||
state.currentLineCap != lineCap ||
!ol.array.equals(state.currentLineDash, lineDash) ||
state.currentLineDashOffset != lineDashOffset ||
state.currentLineJoin != lineJoin ||
state.currentLineWidth != lineWidth ||
state.currentMiterLimit != miterLimit) {
if (managePath) {
if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
this.instructions.push([ol.render.canvas.Instruction.STROKE]);
state.lastStroke = this.coordinates.length;
}
state.lastStroke = 0;
}
this.instructions.push([
ol.render.canvas.Instruction.SET_STROKE_STYLE,
strokeStyle, lineWidth * this.pixelRatio, lineCap, lineJoin, miterLimit,
this.applyPixelRatio(lineDash), lineDashOffset * this.pixelRatio
]);
if (managePath) {
this.instructions.push([ol.render.canvas.Instruction.BEGIN_PATH]);
}
state.currentStrokeStyle = strokeStyle;
state.currentLineCap = lineCap;
state.currentLineDash = lineDash;
state.currentLineDashOffset = lineDashOffset;
state.currentLineJoin = lineJoin;
state.currentLineWidth = lineWidth;
state.currentMiterLimit = miterLimit;
}
};
/**
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
* @param {ol.Feature|ol.render.Feature} feature Feature.
@@ -744,5 +922,12 @@ ol.render.canvas.Replay.prototype.finish = ol.nullFunction;
* @protected
*/
ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() {
return this.maxExtent;
if (!this.bufferedMaxExtent_) {
this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
if (this.maxLineWidth > 0) {
var width = this.resolution * (this.maxLineWidth + 1) / 2;
ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
}
}
return this.bufferedMaxExtent_;
};

View File

@@ -7,6 +7,7 @@ goog.require('ol.extent');
goog.require('ol.geom.flat.transform');
goog.require('ol.obj');
goog.require('ol.render.ReplayGroup');
goog.require('ol.render.ReplayType');
goog.require('ol.render.canvas.Replay');
goog.require('ol.render.canvas.ImageReplay');
goog.require('ol.render.canvas.LineStringReplay');
@@ -24,13 +25,27 @@ goog.require('ol.transform');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay group can have overlapping geometries.
* @param {?} declutterTree Declutter tree
* for declutter processing in postrender.
* @param {number=} opt_renderBuffer Optional rendering buffer.
* @struct
*/
ol.render.canvas.ReplayGroup = function(
tolerance, maxExtent, resolution, pixelRatio, overlaps, opt_renderBuffer) {
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree, opt_renderBuffer) {
ol.render.ReplayGroup.call(this);
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = declutterTree;
/**
* @type {ol.DeclutterGroup}
* @private
*/
this.declutterGroup_ = null;
/**
* @private
* @type {number}
@@ -170,6 +185,71 @@ ol.render.canvas.ReplayGroup.getCircleArray_ = function(radius) {
};
ol.render.canvas.ReplayGroup.replayDeclutter = function(declutterReplays, context, rotation) {
var zs = Object.keys(declutterReplays).map(Number).sort(ol.array.numberSafeCompareFunction);
for (var z = 0, zz = zs.length; z < zz; ++z) {
var replayData = declutterReplays[zs[z].toString()];
for (var i = 0, ii = replayData.length; i < ii;) {
var replay = replayData[i++];
var transform = replayData[i++];
replay.replay(context, transform, rotation, {});
}
}
};
ol.render.canvas.ReplayGroup.replayDeclutterHitDetection = function(
declutterReplays, context, rotation, featureCallback, hitExtent) {
var zs = Object.keys(declutterReplays).map(Number).sort(ol.array.numberSafeCompareFunction);
for (var z = 0, zz = zs.length; z < zz; ++z) {
var replayData = declutterReplays[zs[z].toString()];
for (var i = replayData.length - 1; i >= 0;) {
var transform = replayData[i--];
var replay = replayData[i--];
var result = replay.replayHitDetection(context, transform, rotation, {},
featureCallback, hitExtent);
if (result) {
return result;
}
}
}
};
/**
* @param {boolean} group Group with previous replay.
* @return {ol.DeclutterGroup} Declutter instruction group.
*/
ol.render.canvas.ReplayGroup.prototype.addDeclutter = function(group) {
var declutter = null;
if (this.declutterTree_) {
if (group) {
declutter = this.declutterGroup_;
/** @type {number} */ (declutter[4])++;
} else {
declutter = this.declutterGroup_ = ol.extent.createEmpty();
declutter.push(1);
}
}
return declutter;
};
/**
* @param {CanvasRenderingContext2D} context Context.
* @param {ol.Transform} transform Transform.
*/
ol.render.canvas.ReplayGroup.prototype.clip = function(context, transform) {
var flatClipCoords = this.getClipCoords(transform);
context.beginPath();
context.moveTo(flatClipCoords[0], flatClipCoords[1]);
context.lineTo(flatClipCoords[2], flatClipCoords[3]);
context.lineTo(flatClipCoords[4], flatClipCoords[5]);
context.lineTo(flatClipCoords[6], flatClipCoords[7]);
context.clip();
};
/**
* @param {Array.<ol.render.ReplayType>} replays Replays.
* @return {boolean} Has replays of the provided types.
@@ -211,11 +291,13 @@ ol.render.canvas.ReplayGroup.prototype.finish = function() {
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T} callback Feature
* callback.
* @param {Object.<string, ol.DeclutterGroup>} declutterReplays Declutter
* replays.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
coordinate, resolution, rotation, hitTolerance, skippedFeaturesHash, callback) {
coordinate, resolution, rotation, hitTolerance, skippedFeaturesHash, callback, declutterReplays) {
hitTolerance = Math.round(hitTolerance);
var contextSize = hitTolerance * 2 + 1;
@@ -245,30 +327,36 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
var mask = ol.render.canvas.ReplayGroup.getCircleArray_(hitTolerance);
return this.replayHitDetection_(context, transform, rotation,
skippedFeaturesHash,
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {?} Callback result.
*/
function(feature) {
var imageData = context.getImageData(0, 0, contextSize, contextSize).data;
for (var i = 0; i < contextSize; i++) {
for (var j = 0; j < contextSize; j++) {
if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
var result = callback(feature);
if (result) {
return result;
} else {
context.clearRect(0, 0, contextSize, contextSize);
return undefined;
}
}
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {?} Callback result.
*/
function hitDetectionCallback(feature) {
var imageData = context.getImageData(0, 0, contextSize, contextSize).data;
for (var i = 0; i < contextSize; i++) {
for (var j = 0; j < contextSize; j++) {
if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
var result = callback(feature);
if (result) {
return result;
} else {
context.clearRect(0, 0, contextSize, contextSize);
return undefined;
}
}
}
}, hitExtent);
}
}
}
var result = this.replayHitDetection_(context, transform, rotation,
skippedFeaturesHash, hitDetectionCallback, hitExtent, declutterReplays);
if (!result && declutterReplays) {
result = ol.render.canvas.ReplayGroup.replayDeclutterHitDetection(
declutterReplays, context, rotation, hitDetectionCallback, hitExtent);
}
return result;
};
@@ -303,13 +391,21 @@ ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType)
if (replay === undefined) {
var Constructor = ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
replay = new Constructor(this.tolerance_, this.maxExtent_,
this.resolution_, this.pixelRatio_, this.overlaps_);
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_);
replays[replayType] = replay;
}
return replay;
};
/**
* @return {Object.<string, Object.<ol.render.ReplayType, ol.render.canvas.Replay>>} Replays.
*/
ol.render.canvas.ReplayGroup.prototype.getReplays = function() {
return this.replaysByZIndex_;
};
/**
* @inheritDoc
*/
@@ -326,9 +422,11 @@ ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
* to skip.
* @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types
* to replay. Default is {@link ol.render.replay.ORDER}
* @param {Object.<string, ol.DeclutterGroup>=} opt_declutterReplays Declutter
* replays.
*/
ol.render.canvas.ReplayGroup.prototype.replay = function(context,
transform, viewRotation, skippedFeaturesHash, opt_replayTypes) {
transform, viewRotation, skippedFeaturesHash, opt_replayTypes, opt_declutterReplays) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
@@ -336,23 +434,29 @@ ol.render.canvas.ReplayGroup.prototype.replay = function(context,
// setup clipping so that the parts of over-simplified geometries are not
// visible outside the current extent when panning
var flatClipCoords = this.getClipCoords(transform);
context.save();
context.beginPath();
context.moveTo(flatClipCoords[0], flatClipCoords[1]);
context.lineTo(flatClipCoords[2], flatClipCoords[3]);
context.lineTo(flatClipCoords[4], flatClipCoords[5]);
context.lineTo(flatClipCoords[6], flatClipCoords[7]);
context.clip();
this.clip(context, transform);
var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER;
var i, ii, j, jj, replays, replay;
for (i = 0, ii = zs.length; i < ii; ++i) {
replays = this.replaysByZIndex_[zs[i].toString()];
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = 0, jj = replayTypes.length; j < jj; ++j) {
replay = replays[replayTypes[j]];
var replayType = replayTypes[j];
replay = replays[replayType];
if (replay !== undefined) {
replay.replay(context, transform, viewRotation, skippedFeaturesHash);
if (opt_declutterReplays &&
(replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) {
var declutter = opt_declutterReplays[zIndexKey];
if (!declutter) {
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
replay.replay(context, transform, viewRotation, skippedFeaturesHash);
}
}
}
}
@@ -372,28 +476,40 @@ ol.render.canvas.ReplayGroup.prototype.replay = function(context,
* Feature callback.
* @param {ol.Extent=} opt_hitExtent Only check features that intersect this
* extent.
* @param {Object.<string, ol.DeclutterGroup>=} opt_declutterReplays Declutter
* replays.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
context, transform, viewRotation, skippedFeaturesHash,
featureCallback, opt_hitExtent) {
featureCallback, opt_hitExtent, opt_declutterReplays) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(function(a, b) {
return b - a;
});
zs.sort(ol.array.numberSafeCompareFunction);
var i, ii, j, replays, replay, result;
for (i = 0, ii = zs.length; i < ii; ++i) {
replays = this.replaysByZIndex_[zs[i].toString()];
var i, j, replays, replay, result;
for (i = zs.length - 1; i >= 0; --i) {
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
replay = replays[ol.render.replay.ORDER[j]];
var replayType = ol.render.replay.ORDER[j];
replay = replays[replayType];
if (replay !== undefined) {
result = replay.replayHitDetection(context, transform, viewRotation,
skippedFeaturesHash, featureCallback, opt_hitExtent);
if (result) {
return result;
if (opt_declutterReplays &&
(replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) {
var declutter = opt_declutterReplays[zIndexKey];
if (!declutter) {
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
result = replay.replayHitDetection(context, transform, viewRotation,
skippedFeaturesHash, featureCallback, opt_hitExtent);
if (result) {
return result;
}
}
}
}
@@ -407,7 +523,7 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
* @private
* @type {Object.<ol.render.ReplayType,
* function(new: ol.render.canvas.Replay, number, ol.Extent,
* number, number, boolean)>}
* number, number, boolean, Array.<ol.DeclutterGroup>)>}
*/
ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = {
'Circle': ol.render.canvas.PolygonReplay,

View File

@@ -3,6 +3,7 @@ goog.provide('ol.render.canvas.TextReplay');
goog.require('ol');
goog.require('ol.colorlike');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.geom.flat.straightchunk');
goog.require('ol.geom.GeometryType');
goog.require('ol.has');
@@ -10,7 +11,6 @@ goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Instruction');
goog.require('ol.render.canvas.Replay');
goog.require('ol.render.replay');
goog.require('ol.structs.LRUCache');
goog.require('ol.style.TextPlacement');
@@ -22,11 +22,19 @@ goog.require('ol.style.TextPlacement');
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @struct
*/
ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRatio, overlaps) {
ol.render.canvas.TextReplay = function(
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree) {
ol.render.canvas.Replay.call(this,
tolerance, maxExtent, resolution, pixelRatio, overlaps, declutterTree);
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
/**
* @private
* @type {ol.DeclutterGroup}
*/
this.declutterGroup_;
/**
* @private
@@ -64,12 +72,6 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRa
*/
this.textRotation_ = 0;
/**
* @private
* @type {number}
*/
this.textScale_ = 0;
/**
* @private
* @type {?ol.CanvasFillState}
@@ -84,9 +86,9 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRa
/**
* @private
* @type {?ol.CanvasTextState}
* @type {ol.CanvasTextState}
*/
this.textState_ = null;
this.textState_ = /** @type {ol.CanvasTextState} */ ({});
/**
* @private
@@ -106,57 +108,61 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRa
*/
this.strokeKey_ = '';
while (ol.render.canvas.TextReplay.labelCache_.canExpireCache()) {
ol.render.canvas.TextReplay.labelCache_.pop();
}
/**
* @private
* @type {Object.<string, number>}
*/
this.widths_ = {};
};
ol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay);
/**
* @private
* @type {ol.structs.LRUCache.<HTMLCanvasElement>}
*/
ol.render.canvas.TextReplay.labelCache_ = new ol.structs.LRUCache();
/**
* @param {string} font Font to use for measuring.
* @return {ol.Size} Measurement.
*/
ol.render.canvas.TextReplay.measureTextHeight = (function() {
var textContainer;
return function(font, lines, widths) {
if (!textContainer) {
textContainer = document.createElement('span');
textContainer.textContent = 'M';
textContainer.style.visibility = 'hidden';
textContainer.style.whiteSpace = 'nowrap';
var span;
var heights = {};
return function(font) {
var height = heights[font];
if (height == undefined) {
if (!span) {
span = document.createElement('span');
span.textContent = 'M';
span.style.margin = span.style.padding = '0 !important';
span.style.position = 'absolute !important';
span.style.left = '-99999px !important';
}
span.style.font = font;
document.body.appendChild(span);
height = heights[font] = span.offsetHeight;
document.body.removeChild(span);
}
textContainer.style.font = font;
document.body.appendChild(textContainer);
var height = textContainer.offsetHeight;
document.body.removeChild(textContainer);
return height;
};
})();
/**
* @this {Object}
* @param {CanvasRenderingContext2D} context Context.
* @param {number} pixelRatio Pixel ratio.
* @param {string} font Font.
* @param {string} text Text.
* @return {number} Width.
*/
ol.render.canvas.TextReplay.getTextWidth = function(context, pixelRatio, text) {
var width = this[text];
if (!width) {
this[text] = width = context.measureText(text).width;
}
return width * pixelRatio;
};
ol.render.canvas.TextReplay.measureTextWidth = (function() {
var measureContext;
var currentFont;
return function(font, text) {
if (!measureContext) {
measureContext = ol.dom.createCanvasContext2D(1, 1);
}
if (font != currentFont) {
currentFont = measureContext.font = font;
}
return measureContext.measureText(text).width;
};
})();
/**
@@ -166,24 +172,17 @@ ol.render.canvas.TextReplay.getTextWidth = function(context, pixelRatio, text) {
* each line.
* @return {number} Width of the whole text.
*/
ol.render.canvas.TextReplay.measureTextWidths = (function() {
var context;
return function(font, lines, widths) {
if (!context) {
context = ol.dom.createCanvasContext2D(1, 1);
}
context.font = font;
var numLines = lines.length;
var width = 0;
var currentWidth, i;
for (i = 0; i < numLines; ++i) {
currentWidth = context.measureText(lines[i]).width;
width = Math.max(width, currentWidth);
widths.push(currentWidth);
}
return width;
};
})();
ol.render.canvas.TextReplay.measureTextWidths = function(font, lines, widths) {
var numLines = lines.length;
var width = 0;
var currentWidth, i;
for (i = 0; i < numLines; ++i) {
currentWidth = ol.render.canvas.TextReplay.measureTextWidth(font, lines[i]);
width = Math.max(width, currentWidth);
widths.push(currentWidth);
}
return width;
};
/**
@@ -205,7 +204,10 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
var stride = 2;
var i, ii;
if (this.textState_.placement === ol.style.TextPlacement.LINE) {
if (textState.placement === ol.style.TextPlacement.LINE) {
if (!ol.extent.intersects(this.getBufferedMaxExtent(), geometry.getExtent())) {
return;
}
var ends;
flatCoordinates = geometry.getFlatCoordinates();
stride = geometry.getStride();
@@ -235,15 +237,18 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
} else {
flatEnd = ends[o];
}
end = this.appendFlatCoordinates(flatCoordinates, flatOffset, flatEnd, stride, false, false);
for (i = flatOffset; i < flatEnd; i += stride) {
this.coordinates.push(flatCoordinates[i], flatCoordinates[i + 1]);
}
end = this.coordinates.length;
flatOffset = ends[o];
this.drawChars_(begin, end);
this.drawChars_(begin, end, this.declutterGroup_);
begin = end;
}
this.endGeometry(geometry, feature);
} else {
var label = this.getImage_(this.text_, !!this.textFillState_, !!this.textStrokeState_);
var label = this.getImage(this.text_, !!this.textFillState_, !!this.textStrokeState_);
var width = label.width / this.pixelRatio;
switch (geometryType) {
case ol.geom.GeometryType.POINT:
@@ -292,27 +297,27 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
/**
* @private
* @param {string} text Text.
* @param {boolean} fill Fill.
* @param {boolean} stroke Stroke.
* @return {HTMLCanvasElement} Image.
*/
ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) {
ol.render.canvas.TextReplay.prototype.getImage = function(text, fill, stroke) {
var label;
var key = (stroke ? this.strokeKey_ : '') + this.textKey_ + text + (fill ? this.fillKey_ : '');
var lines = text.split('\n');
var numLines = lines.length;
if (!ol.render.canvas.TextReplay.labelCache_.containsKey(key)) {
var labelCache = ol.render.canvas.labelCache;
if (!labelCache.containsKey(key)) {
var strokeState = this.textStrokeState_;
var fillState = this.textFillState_;
var textState = this.textState_;
var pixelRatio = this.pixelRatio;
var scale = this.textScale_ * pixelRatio;
var scale = textState.scale * pixelRatio;
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
var strokeWidth = stroke && strokeState.lineWidth ? strokeState.lineWidth : 0;
var lines = text.split('\n');
var numLines = lines.length;
var widths = [];
var width = ol.render.canvas.TextReplay.measureTextWidths(textState.font, lines, widths);
var lineHeight = ol.render.canvas.TextReplay.measureTextHeight(textState.font);
@@ -322,8 +327,10 @@ ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) {
Math.ceil(renderWidth * scale),
Math.ceil((height + strokeWidth) * scale));
label = context.canvas;
ol.render.canvas.TextReplay.labelCache_.set(key, label);
context.scale(scale, scale);
labelCache.pruneAndSet(key, label);
if (scale != 1) {
context.scale(scale, scale);
}
context.font = textState.font;
if (stroke) {
context.strokeStyle = strokeState.strokeStyle;
@@ -331,7 +338,7 @@ ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) {
context.lineCap = strokeState.lineCap;
context.lineJoin = strokeState.lineJoin;
context.miterLimit = strokeState.miterLimit;
if (ol.has.CANVAS_LINE_DASH) {
if (ol.has.CANVAS_LINE_DASH && strokeState.lineDash.length) {
context.setLineDash(strokeState.lineDash);
context.lineDashOffset = strokeState.lineDashOffset;
}
@@ -355,7 +362,7 @@ ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) {
}
}
}
return ol.render.canvas.TextReplay.labelCache_.get(key);
return labelCache.get(key);
};
@@ -377,12 +384,12 @@ ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(label, begin, en
var anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
this.instructions.push([ol.render.canvas.Instruction.DRAW_IMAGE, begin, end,
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
1, true, label.width
]);
this.hitDetectionInstructions.push([ol.render.canvas.Instruction.DRAW_IMAGE, begin, end,
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
1 / pixelRatio, true, label.width
]);
};
@@ -392,8 +399,9 @@ ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(label, begin, en
* @private
* @param {number} begin Begin.
* @param {number} end End.
* @param {ol.DeclutterGroup} declutterGroup Declutter group.
*/
ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end) {
ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end, declutterGroup) {
var pixelRatio = this.pixelRatio;
var strokeState = this.textStrokeState_;
var fill = !!this.textFillState_;
@@ -401,37 +409,36 @@ ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end) {
var textState = this.textState_;
var baseline = ol.render.replay.TEXT_ALIGN[textState.textBaseline];
var labels = [];
var text = this.text_;
var numChars = this.text_.length;
var i;
if (stroke) {
for (i = 0; i < numChars; ++i) {
labels.push(this.getImage_(text.charAt(i), false, stroke));
}
}
if (fill) {
for (i = 0; i < numChars; ++i) {
labels.push(this.getImage_(text.charAt(i), fill, false));
}
}
var context = labels[0].getContext('2d');
var offsetY = this.textOffsetY_ * pixelRatio;
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
var widths = {};
var textAlign = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
var text = this.text_;
var font = textState.font;
var textScale = textState.scale;
var strokeWidth = strokeState ? strokeState.lineWidth * textScale / 2 : 0;
var widths = this.widths_;
this.instructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
begin, end, labels, baseline,
textState.exceedLength, textState.maxAngle,
ol.render.canvas.TextReplay.getTextWidth.bind(widths, context, pixelRatio * this.textScale_),
offsetY, this.text_, align, 1
begin, end, baseline, declutterGroup,
textState.exceedLength, fill, textState.maxAngle,
function(text) {
var width = widths[text];
if (!width) {
width = widths[text] = ol.render.canvas.TextReplay.measureTextWidth(font, text);
}
return width * textScale * pixelRatio;
},
offsetY, stroke, strokeWidth * pixelRatio, text, textAlign, 1
]);
this.hitDetectionInstructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
begin, end, labels, baseline,
textState.exceedLength, textState.maxAngle,
ol.render.canvas.TextReplay.getTextWidth.bind(widths, context, this.textScale_),
offsetY, this.text_, align, 1 / pixelRatio
begin, end, baseline, declutterGroup,
textState.exceedLength, fill, textState.maxAngle,
function(text) {
var width = widths[text];
if (!width) {
width = widths[text] = ol.render.canvas.TextReplay.measureTextWidth(font, text);
}
return width * textScale;
},
offsetY, stroke, strokeWidth, text, textAlign, 1 / pixelRatio
]);
};
@@ -439,99 +446,78 @@ ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end) {
/**
* @inheritDoc
*/
ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle, declutterGroup) {
var textState, fillState, strokeState;
if (!textStyle) {
this.text_ = '';
} else {
this.declutterGroup_ = /** @type {ol.DeclutterGroup} */ (declutterGroup);
var textFillStyle = textStyle.getFill();
if (!textFillStyle) {
fillState = this.textFillState_ = null;
} else {
var textFillStyleColor = textFillStyle.getColor();
var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?
textFillStyleColor : ol.render.canvas.defaultFillStyle);
fillState = this.textFillState_;
if (!fillState) {
fillState = this.textFillState_ = /** @type {ol.CanvasFillState} */ ({});
}
fillState.fillStyle = fillStyle;
fillState.fillStyle = ol.colorlike.asColorLike(
textFillStyle.getColor() || ol.render.canvas.defaultFillStyle);
}
var textStrokeStyle = textStyle.getStroke();
if (!textStrokeStyle) {
strokeState = this.textStrokeState_ = null;
} else {
var textStrokeStyleColor = textStrokeStyle.getColor();
var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
var textStrokeStyleLineDash = textStrokeStyle.getLineDash();
var textStrokeStyleLineDashOffset = textStrokeStyle.getLineDashOffset();
var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
var textStrokeStyleWidth = textStrokeStyle.getWidth();
var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
var lineCap = textStrokeStyleLineCap !== undefined ?
textStrokeStyleLineCap : ol.render.canvas.defaultLineCap;
var lineDash = textStrokeStyleLineDash ?
textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
var lineDashOffset = textStrokeStyleLineDashOffset !== undefined ?
textStrokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
var lineJoin = textStrokeStyleLineJoin !== undefined ?
textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
var lineWidth = textStrokeStyleWidth !== undefined ?
textStrokeStyleWidth : ol.render.canvas.defaultLineWidth;
var miterLimit = textStrokeStyleMiterLimit !== undefined ?
textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
var strokeStyle = ol.colorlike.asColorLike(textStrokeStyleColor ?
textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);
strokeState = this.textStrokeState_;
if (!strokeState) {
strokeState = this.textStrokeState_ = /** @type {ol.CanvasStrokeState} */ ({});
}
strokeState.lineCap = lineCap;
strokeState.lineDash = lineDash;
strokeState.lineDashOffset = lineDashOffset;
strokeState.lineJoin = lineJoin;
strokeState.lineWidth = lineWidth;
strokeState.miterLimit = miterLimit;
strokeState.strokeStyle = strokeStyle;
var lineDash = textStrokeStyle.getLineDash();
var lineDashOffset = textStrokeStyle.getLineDashOffset();
var lineWidth = textStrokeStyle.getWidth();
var miterLimit = textStrokeStyle.getMiterLimit();
strokeState.lineCap = textStrokeStyle.getLineCap() || ol.render.canvas.defaultLineCap;
strokeState.lineDash = lineDash ? lineDash.slice() : ol.render.canvas.defaultLineDash;
strokeState.lineDashOffset =
lineDashOffset === undefined ? ol.render.canvas.defaultLineDashOffset : lineDashOffset;
strokeState.lineJoin = textStrokeStyle.getLineJoin() || ol.render.canvas.defaultLineJoin;
strokeState.lineWidth =
lineWidth === undefined ? ol.render.canvas.defaultLineWidth : lineWidth;
strokeState.miterLimit =
miterLimit === undefined ? ol.render.canvas.defaultMiterLimit : miterLimit;
strokeState.strokeStyle = ol.colorlike.asColorLike(
textStrokeStyle.getColor() || ol.render.canvas.defaultStrokeStyle);
}
var textFont = textStyle.getFont();
var textOffsetX = textStyle.getOffsetX();
var textOffsetY = textStyle.getOffsetY();
var textRotateWithView = textStyle.getRotateWithView();
var textRotation = textStyle.getRotation();
var textScale = textStyle.getScale();
var textText = textStyle.getText();
var textTextAlign = textStyle.getTextAlign();
var textTextBaseline = textStyle.getTextBaseline();
var font = textFont !== undefined ?
textFont : ol.render.canvas.defaultFont;
var textAlign = textTextAlign;
var textBaseline = textTextBaseline !== undefined ?
textTextBaseline : ol.render.canvas.defaultTextBaseline;
textState = this.textState_;
if (!textState) {
textState = this.textState_ = /** @type {ol.CanvasTextState} */ ({});
}
var font = textStyle.getFont() || ol.render.canvas.defaultFont;
ol.render.canvas.checkFont(font);
var textScale = textStyle.getScale();
textState.exceedLength = textStyle.getExceedLength();
textState.font = font;
textState.maxAngle = textStyle.getMaxAngle();
textState.placement = textStyle.getPlacement();
textState.textAlign = textAlign;
textState.textBaseline = textBaseline;
textState.textAlign = textStyle.getTextAlign();
textState.textBaseline = textStyle.getTextBaseline() || ol.render.canvas.defaultTextBaseline;
textState.scale = textScale === undefined ? 1 : textScale;
this.text_ = textText !== undefined ? textText : '';
this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;
this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;
this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
this.textScale_ = textScale !== undefined ? textScale : 1;
var textOffsetX = textStyle.getOffsetX();
var textOffsetY = textStyle.getOffsetY();
var textRotateWithView = textStyle.getRotateWithView();
var textRotation = textStyle.getRotation();
this.text_ = textStyle.getText() || '';
this.textOffsetX_ = textOffsetX === undefined ? 0 : textOffsetX;
this.textOffsetY_ = textOffsetY === undefined ? 0 : textOffsetY;
this.textRotateWithView_ = textRotateWithView === undefined ? false : textRotateWithView;
this.textRotation_ = textRotation === undefined ? 0 : textRotation;
this.strokeKey_ = strokeState ?
(typeof strokeState.strokeStyle == 'string' ? strokeState.strokeStyle : ol.getUid(strokeState.strokeStyle)) +
strokeState.lineCap + strokeState.lineDashOffset + '|' + strokeState.lineWidth +
strokeState.lineJoin + strokeState.miterLimit + '[' + strokeState.lineDash.join() + ']' :
'';
this.textKey_ = textState.font + (textState.textAlign || '?') + this.textScale_;
this.textKey_ = textState.font + (textState.textAlign || '?') + textState.scale;
this.fillKey_ = fillState ?
(typeof fillState.fillStyle == 'string' ? fillState.fillStyle : ('|' + ol.getUid(fillState.fillStyle))) :
'';

View File

@@ -1,8 +1,12 @@
goog.provide('ol.render.Feature');
goog.require('ol');
goog.require('ol.array');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.flat.center');
goog.require('ol.geom.flat.interiorpoint');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.transform');
goog.require('ol.transform');
@@ -45,6 +49,18 @@ ol.render.Feature = function(type, flatCoordinates, ends, properties, id) {
*/
this.flatCoordinates_ = flatCoordinates;
/**
* @private
* @type {Array.<number>}
*/
this.flatInteriorPoints_ = null;
/**
* @private
* @type {Array.<number>}
*/
this.flatMidpoints_ = null;
/**
* @private
* @type {Array.<number>|Array.<Array.<number>>}
@@ -102,6 +118,66 @@ ol.render.Feature.prototype.getExtent = function() {
return this.extent_;
};
/**
* @return {Array.<number>} Flat interior points.
*/
ol.render.Feature.prototype.getFlatInteriorPoint = function() {
if (!this.flatInteriorPoints_) {
var flatCenter = ol.extent.getCenter(this.getExtent());
this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRings(
this.flatCoordinates_, 0, this.ends_, 2, flatCenter, 0);
}
return this.flatInteriorPoints_;
};
/**
* @return {Array.<number>} Flat interior points.
*/
ol.render.Feature.prototype.getFlatInteriorPoints = function() {
if (!this.flatInteriorPoints_) {
var flatCenters = ol.geom.flat.center.linearRingss(
this.flatCoordinates_, 0, this.ends_, 2);
this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss(
this.flatCoordinates_, 0, this.ends_, 2, flatCenters);
}
return this.flatInteriorPoints_;
};
/**
* @return {Array.<number>} Flat midpoint.
*/
ol.render.Feature.prototype.getFlatMidpoint = function() {
if (!this.flatMidpoints_) {
this.flatMidpoints_ = ol.geom.flat.interpolate.lineString(
this.flatCoordinates_, 0, this.flatCoordinates_.length, 2, 0.5);
}
return this.flatMidpoints_;
};
/**
* @return {Array.<number>} Flat midpoints.
*/
ol.render.Feature.prototype.getFlatMidpoints = function() {
if (!this.flatMidpoints_) {
this.flatMidpoints_ = [];
var flatCoordinates = this.flatCoordinates_;
var offset = 0;
var ends = this.ends_;
for (var i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var midpoint = ol.geom.flat.interpolate.lineString(
flatCoordinates, offset, end, 2, 0.5);
ol.array.extend(this.flatMidpoints_, midpoint);
offset = end;
}
}
return this.flatMidpoints_;
};
/**
* Get the feature identifier. This is a stable identifier for the feature and
* is set when reading data from a remote source.

View File

@@ -123,11 +123,13 @@ ol.render.VectorContext.prototype.setFillStrokeStyle = function(fillStyle, strok
/**
* @param {ol.style.Image} imageStyle Image style.
* @param {ol.DeclutterGroup=} opt_declutterGroup Declutter.
*/
ol.render.VectorContext.prototype.setImageStyle = function(imageStyle) {};
ol.render.VectorContext.prototype.setImageStyle = function(imageStyle, opt_declutterGroup) {};
/**
* @param {ol.style.Text} textStyle Text style.
* @param {ol.DeclutterGroup=} opt_declutterGroup Declutter.
*/
ol.render.VectorContext.prototype.setTextStyle = function(textStyle) {};
ol.render.VectorContext.prototype.setTextStyle = function(textStyle, opt_declutterGroup) {};

View File

@@ -53,6 +53,13 @@ ol.render.webgl.ReplayGroup = function(tolerance, maxExtent, opt_renderBuffer) {
ol.inherits(ol.render.webgl.ReplayGroup, ol.render.ReplayGroup);
/**
* @param {ol.style.Style} style Style.
* @param {boolean} group Group with previous replay.
*/
ol.render.webgl.ReplayGroup.prototype.addDeclutter = function(style, group) {};
/**
* @param {ol.webgl.Context} context WebGL context.
* @return {function()} Delete resources function.

View File

@@ -134,7 +134,6 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
0,
-viewCenter[0], -viewCenter[1]);
this.updateAttributions(frameState.attributions, image.getAttributions());
this.updateLogos(frameState, imageSource);
this.renderedResolution = imageResolution * pixelRatio / imagePixelRatio;
}

View File

@@ -4,6 +4,9 @@ goog.require('ol');
goog.require('ol.LayerType');
goog.require('ol.ViewHint');
goog.require('ol.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.ext.rbush');
goog.require('ol.extent');
goog.require('ol.render.EventType');
goog.require('ol.render.canvas');
@@ -23,6 +26,13 @@ ol.renderer.canvas.VectorLayer = function(vectorLayer) {
ol.renderer.canvas.Layer.call(this, vectorLayer);
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = vectorLayer.getDeclutter() ?
ol.ext.rbush(9) : null;
/**
* @private
* @type {boolean}
@@ -65,6 +75,8 @@ ol.renderer.canvas.VectorLayer = function(vectorLayer) {
*/
this.context_ = ol.dom.createCanvasContext2D();
ol.events.listen(ol.render.canvas.labelCache, ol.events.EventType.CLEAR, this.handleFontsChanged_, this);
};
ol.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
@@ -91,6 +103,15 @@ ol.renderer.canvas.VectorLayer['create'] = function(mapRenderer, layer) {
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.disposeInternal = function() {
ol.events.unlisten(ol.render.canvas.labelCache, ol.events.EventType.CLEAR, this.handleFontsChanged_, this);
ol.renderer.canvas.Layer.prototype.disposeInternal.call(this);
};
/**
* @inheritDoc
*/
@@ -209,6 +230,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
if (clipped) {
context.restore();
}
if (this.declutterTree_) {
this.declutterTree_.clear();
}
this.postCompose(context, frameState, layerState, transform);
};
@@ -223,10 +247,11 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
} else {
var resolution = frameState.viewState.resolution;
var rotation = frameState.viewState.rotation;
var layer = this.getLayer();
var layer = /** @type {ol.layer.Vector} */ (this.getLayer());
/** @type {Object.<string, boolean>} */
var features = {};
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
var declutterReplays = layer.getDeclutter() ? {} : null;
var result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
rotation, hitTolerance, {},
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
@@ -238,7 +263,22 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
features[key] = true;
return callback.call(thisArg, feature, layer);
}
});
}, declutterReplays);
if (this.declutterTree_) {
this.declutterTree_.clear();
}
return result;
}
};
/**
* @param {ol.events.Event} event Event.
*/
ol.renderer.canvas.VectorLayer.prototype.handleFontsChanged_ = function(event) {
var layer = this.getLayer();
if (layer.getVisible() && this.replayGroup_) {
layer.changed();
}
};
@@ -261,8 +301,6 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
var vectorSource = vectorLayer.getSource();
this.updateAttributions(
frameState.attributions, vectorSource.getAttributions());
this.updateLogos(frameState, vectorSource);
var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
@@ -319,7 +357,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
var replayGroup = new ol.render.canvas.ReplayGroup(
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, resolution,
pixelRatio, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());
pixelRatio, vectorSource.getOverlaps(), this.declutterTree_, vectorLayer.getRenderBuffer());
vectorSource.loadFeatures(extent, resolution, projection);
/**
* @param {ol.Feature} feature Feature.
@@ -396,7 +434,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFeature = function(feature, resol
loading = ol.renderer.vector.renderFeature(
replayGroup, feature, styles,
ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
this.handleStyleImageChange_, this) || loading;
this.handleStyleImageChange_, this);
}
return loading;
};

View File

@@ -4,6 +4,9 @@ goog.require('ol');
goog.require('ol.LayerType');
goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.ext.rbush');
goog.require('ol.extent');
goog.require('ol.layer.VectorTileRenderType');
goog.require('ol.proj');
@@ -33,6 +36,12 @@ ol.renderer.canvas.VectorTileLayer = function(layer) {
ol.renderer.canvas.TileLayer.call(this, layer);
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = layer.getDeclutter() ? ol.ext.rbush(9) : null;
/**
* @private
* @type {boolean}
@@ -55,6 +64,8 @@ ol.renderer.canvas.VectorTileLayer = function(layer) {
this.zDirection =
layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0;
ol.events.listen(ol.render.canvas.labelCache, ol.events.EventType.CLEAR, this.handleFontsChanged_, this);
};
ol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);
@@ -103,6 +114,15 @@ ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS = {
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorTileLayer.prototype.disposeInternal = function() {
ol.events.unlisten(ol.render.canvas.labelCache, ol.events.EventType.CLEAR, this.handleFontsChanged_, this);
ol.renderer.canvas.TileLayer.prototype.disposeInternal.call(this);
};
/**
* @inheritDoc
*/
@@ -150,6 +170,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
var resolution = tileGrid.getResolution(tile.tileCoord[0]);
var tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
var zIndexKeys = {};
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
var sourceTile = tile.getTile(tile.tileKeys[t]);
if (sourceTile.getState() == ol.TileState.ERROR) {
@@ -159,6 +180,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
var sourceTileCoord = sourceTile.tileCoord;
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
var sharedExtent = ol.extent.getIntersection(tileExtent, sourceTileExtent);
var bufferedExtent = ol.extent.equals(sourceTileExtent, sharedExtent) ? null :
ol.extent.buffer(sharedExtent, layer.getRenderBuffer() * resolution);
var tileProjection = sourceTile.getProjection();
var reproject = false;
if (!ol.proj.equivalent(projection, tileProjection)) {
@@ -166,8 +189,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
sourceTile.setProjection(projection);
}
replayState.dirty = false;
var replayGroup = new ol.render.canvas.ReplayGroup(0, sharedExtent,
resolution, pixelRatio, source.getOverlaps(), layer.getRenderBuffer());
var replayGroup = new ol.render.canvas.ReplayGroup(0, sharedExtent, resolution,
pixelRatio, source.getOverlaps(), this.declutterTree_, layer.getRenderBuffer());
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
resolution, pixelRatio);
@@ -210,9 +233,14 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
}
feature.getGeometry().transform(tileProjection, projection);
}
renderFeature.call(this, feature);
if (!bufferedExtent || ol.extent.intersects(bufferedExtent, feature.getExtent())) {
renderFeature.call(this, feature);
}
}
replayGroup.finish();
for (var r in replayGroup.getReplays()) {
zIndexKeys[r] = true;
}
sourceTile.setReplayGroup(layer, tile.tileCoord.toString(), replayGroup);
}
replayState.renderedRevision = revision;
@@ -242,6 +270,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
var rotation = frameState.viewState.rotation;
hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;
var layer = this.getLayer();
var declutterReplays = layer.getDeclutter() ? {} : null;
/** @type {Object.<string, boolean>} */
var features = {};
@@ -255,7 +284,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
var tile, tileCoord, tileExtent;
for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
tile = renderedTiles[i];
tileCoord = tile.tileCoord;
tileCoord = tile.wrappedTileCoord;
tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
bufferedExtent = ol.extent.buffer(tileExtent, hitTolerance * resolution, bufferedExtent);
if (!ol.extent.containsCoordinate(bufferedExtent, coordinate)) {
@@ -279,9 +308,12 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
features[key] = true;
return callback.call(thisArg, feature, layer);
}
});
}, declutterReplays);
}
}
if (this.declutterTree_) {
this.declutterTree_.clear();
}
return found;
};
@@ -316,6 +348,17 @@ ol.renderer.canvas.VectorTileLayer.prototype.getReplayTransform_ = function(tile
};
/**
* @param {ol.events.Event} event Event.
*/
ol.renderer.canvas.VectorTileLayer.prototype.handleFontsChanged_ = function(event) {
var layer = this.getLayer();
if (layer.getVisible() && this.renderedLayerRevision_ !== undefined) {
layer.changed();
}
};
/**
* Handle changes in image style state.
* @param {ol.events.Event} event Image style change event.
@@ -331,14 +374,16 @@ ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(
*/
ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {
var layer = this.getLayer();
var declutterReplays = layer.getDeclutter() ? {} : null;
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
var renderMode = layer.getRenderMode();
var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
var replayTypes = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
var pixelRatio = frameState.pixelRatio;
var rotation = frameState.viewState.rotation;
var size = frameState.size;
var offsetX = Math.round(pixelRatio * size[0] / 2);
var offsetY = Math.round(pixelRatio * size[1] / 2);
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
var tiles = this.renderedTiles;
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
var clips = [];
@@ -351,21 +396,23 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
var tileCoord = tile.tileCoord;
var worldOffset = tileGrid.getTileCoordExtent(tileCoord)[0] -
tileGrid.getTileCoordExtent(tile.wrappedTileCoord)[0];
var transform = undefined;
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
var sourceTile = tile.getTile(tile.tileKeys[t]);
if (sourceTile.getState() == ol.TileState.ERROR) {
continue;
}
var replayGroup = sourceTile.getReplayGroup(layer, tileCoord.toString());
if (renderMode != ol.layer.VectorTileRenderType.VECTOR && !replayGroup.hasReplays(replays)) {
if (renderMode != ol.layer.VectorTileRenderType.VECTOR && !replayGroup.hasReplays(replayTypes)) {
continue;
}
if (!transform) {
transform = this.getTransform(frameState, worldOffset);
}
var currentZ = sourceTile.tileCoord[0];
var transform = this.getTransform(frameState, worldOffset);
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) {
@@ -385,12 +432,16 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
context.clip();
}
}
replayGroup.replay(context, transform, rotation, {}, replays);
replayGroup.replay(context, transform, rotation, {}, replayTypes, declutterReplays);
context.restore();
clips.push(currentClip);
zs.push(currentZ);
}
}
if (declutterReplays) {
ol.render.canvas.ReplayGroup.replayDeclutter(declutterReplays, context, rotation);
this.declutterTree_.clear();
}
ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);
};
@@ -417,7 +468,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, s
} else {
loading = ol.renderer.vector.renderFeature(
replayGroup, feature, styles, squaredTolerance,
this.handleStyleImageChange_, this) || loading;
this.handleStyleImageChange_, this);
}
return loading;
};
@@ -458,7 +509,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
ol.transform.scale(transform, pixelScale, -pixelScale);
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
var replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString());
replayGroup.replay(context, transform, 0, {}, replays, true);
replayGroup.replay(context, transform, 0, {}, replays);
}
}
};

View File

@@ -165,23 +165,6 @@ ol.renderer.Layer.prototype.scheduleExpireCache = function(frameState, tileSourc
};
/**
* @param {Object.<string, ol.Attribution>} attributionsSet Attributions
* set (target).
* @param {Array.<ol.Attribution>} attributions Attributions (source).
* @protected
*/
ol.renderer.Layer.prototype.updateAttributions = function(attributionsSet, attributions) {
if (attributions) {
var attribution, i, ii;
for (i = 0, ii = attributions.length; i < ii; ++i) {
attribution = attributions[i];
attributionsSet[ol.getUid(attribution).toString()] = attribution;
}
}
};
/**
* @param {olx.FrameState} frameState Frame state.
* @param {ol.source.Source} source Source.

View File

@@ -212,8 +212,8 @@ ol.renderer.Map.prototype.getLayerRenderer = function(layer) {
var type = this.getType();
for (var i = 0, ii = layerRendererPlugins.length; i < ii; ++i) {
var plugin = layerRendererPlugins[i];
if (plugin.handles(type, layer)) {
renderer = plugin.create(this, layer);
if (plugin['handles'](type, layer)) {
renderer = plugin['create'](this, layer);
break;
}
}

View File

@@ -57,7 +57,7 @@ ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
textReplay.drawText(geometry, feature);
}
};
@@ -94,6 +94,7 @@ ol.renderer.vector.renderFeature = function(
}
ol.renderer.vector.renderFeature_(replayGroup, feature, style,
squaredTolerance);
return loading;
};
@@ -180,7 +181,7 @@ ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, s
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
textReplay.drawText(geometry, feature);
}
};
@@ -205,7 +206,7 @@ ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geomet
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
textReplay.drawText(geometry, feature);
}
};
@@ -231,7 +232,7 @@ ol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry,
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
textReplay.drawText(geometry, feature);
}
};
@@ -252,14 +253,14 @@ ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style,
}
var imageReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.IMAGE);
imageReplay.setImageStyle(imageStyle);
imageReplay.setImageStyle(imageStyle, replayGroup.addDeclutter(false));
imageReplay.drawPoint(geometry, feature);
}
var textStyle = style.getText();
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(!!imageStyle));
textReplay.drawText(geometry, feature);
}
};
@@ -280,14 +281,14 @@ ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, s
}
var imageReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.IMAGE);
imageReplay.setImageStyle(imageStyle);
imageReplay.setImageStyle(imageStyle, replayGroup.addDeclutter(false));
imageReplay.drawMultiPoint(geometry, feature);
}
var textStyle = style.getText();
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(!!imageStyle));
textReplay.drawText(geometry, feature);
}
};
@@ -313,7 +314,7 @@ ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, styl
if (textStyle) {
var textReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.TEXT);
textReplay.setTextStyle(textStyle);
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
textReplay.drawText(geometry, feature);
}
};

View File

@@ -190,7 +190,6 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame = function(frameState, layer
this.image_ = image;
this.texture = texture;
this.updateAttributions(frameState.attributions, image.getAttributions());
this.updateLogos(frameState, imageSource);
}

View File

@@ -215,8 +215,6 @@ ol.renderer.webgl.VectorLayer.prototype.prepareFrame = function(frameState, laye
var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
var vectorSource = vectorLayer.getSource();
this.updateAttributions(
frameState.attributions, vectorSource.getAttributions());
this.updateLogos(frameState, vectorSource);
var animating = frameState.viewHints[ol.ViewHint.ANIMATING];

View File

@@ -100,15 +100,12 @@ ol.reproj.Image = function(sourceProj, targetProj,
var state = ol.ImageState.LOADED;
var attributions = [];
if (this.sourceImage_) {
state = ol.ImageState.IDLE;
attributions = this.sourceImage_.getAttributions();
}
ol.ImageBase.call(this, targetExtent, targetResolution, this.sourcePixelRatio_,
state, attributions);
ol.ImageBase.call(this, targetExtent, targetResolution, this.sourcePixelRatio_, state);
};
ol.inherits(ol.reproj.Image, ol.ImageBase);

View File

@@ -1,7 +1,6 @@
goog.provide('ol.source.BingMaps');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.TileUrlFunction');
goog.require('ol.extent');
goog.require('ol.net');
@@ -68,7 +67,8 @@ ol.source.BingMaps = function(options) {
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' +
this.imagerySet_ +
'?uriScheme=https&include=ImageryProviders&key=' + this.apiKey_;
'?uriScheme=https&include=ImageryProviders&key=' + this.apiKey_ +
'&c=' + this.culture_;
ol.net.jsonp(url, this.handleImageryMetadataResponse.bind(this), undefined,
'jsonp');
@@ -81,14 +81,12 @@ ol.inherits(ol.source.BingMaps, ol.source.TileImage);
* The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs
* Terms Of Use.
* @const
* @type {ol.Attribution}
* @type {string}
* @api
*/
ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({
html: '<a class="ol-attribution-bing-tos" ' +
ol.source.BingMaps.TOS_ATTRIBUTION = '<a class="ol-attribution-bing-tos" ' +
'href="https://www.microsoft.com/maps/product/terms.html">' +
'Terms of Use</a>'
});
'Terms of Use</a>';
/**
@@ -181,31 +179,32 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse = function(response)
var transform = ol.proj.getTransformFromProjections(
ol.proj.get('EPSG:4326'), this.getProjection());
var attributions = resource.imageryProviders.map(function(imageryProvider) {
var html = imageryProvider.attribution;
/** @type {Object.<string, Array.<ol.TileRange>>} */
var tileRanges = {};
imageryProvider.coverageAreas.forEach(function(coverageArea) {
var minZ = coverageArea.zoomMin;
var maxZ = Math.min(coverageArea.zoomMax, maxZoom);
var bbox = coverageArea.bbox;
var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
var extent = ol.extent.applyTransform(epsg4326Extent, transform);
var tileRange, z, zKey;
for (z = minZ; z <= maxZ; ++z) {
zKey = z.toString();
tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
if (zKey in tileRanges) {
tileRanges[zKey].push(tileRange);
} else {
tileRanges[zKey] = [tileRange];
this.setAttributions(function(frameState) {
var attributions = [];
var zoom = frameState.viewState.zoom;
resource.imageryProviders.map(function(imageryProvider) {
var intersects = false;
var coverageAreas = imageryProvider.coverageAreas;
for (var i = 0, ii = coverageAreas.length; i < ii; ++i) {
var coverageArea = coverageAreas[i];
if (zoom >= coverageArea.zoomMin && zoom <= coverageArea.zoomMax) {
var bbox = coverageArea.bbox;
var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
var extent = ol.extent.applyTransform(epsg4326Extent, transform);
if (ol.extent.intersects(extent, frameState.extent)) {
intersects = true;
break;
}
}
}
if (intersects) {
attributions.push(imageryProvider.attribution);
}
});
return new ol.Attribution({html: html, tileRanges: tileRanges});
attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION);
return attributions;
});
attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION);
this.setAttributions(attributions);
}
this.setLogo(brandLogoUri);

View File

@@ -169,7 +169,7 @@ ol.source.ImageArcGISRest.prototype.getImageInternal = function(extent, resoluti
projection, params);
this.image_ = new ol.Image(extent, resolution, pixelRatio,
this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
url, this.crossOrigin_, this.imageLoadFunction_);
this.renderedRevision_ = this.getRevision();

View File

@@ -78,8 +78,7 @@ ol.source.ImageCanvas.prototype.getImageInternal = function(extent, resolution,
var canvasElement = this.canvasFunction_(
extent, resolution, pixelRatio, size, projection);
if (canvasElement) {
canvas = new ol.ImageCanvas(extent, resolution, pixelRatio,
this.getAttributions(), canvasElement);
canvas = new ol.ImageCanvas(extent, resolution, pixelRatio, canvasElement);
}
this.canvas_ = canvas;
this.renderedRevision_ = this.getRevision();

View File

@@ -141,7 +141,7 @@ ol.source.ImageMapGuide.prototype.getImageInternal = function(extent, resolution
var imageUrl = this.getUrl(this.url_, this.params_, extent, size,
projection);
image = new ol.Image(extent, resolution, pixelRatio,
this.getAttributions(), imageUrl, this.crossOrigin_,
imageUrl, this.crossOrigin_,
this.imageLoadFunction_);
ol.events.listen(image, ol.events.EventType.CHANGE,
this.handleImageChange, this);

View File

@@ -40,8 +40,7 @@ ol.source.ImageStatic = function(options) {
* @private
* @type {ol.Image}
*/
this.image_ = new ol.Image(imageExtent, undefined, 1, this.getAttributions(),
options.url, crossOrigin, imageLoadFunction);
this.image_ = new ol.Image(imageExtent, undefined, 1, options.url, crossOrigin, imageLoadFunction);
/**
* @private

View File

@@ -4,6 +4,7 @@ goog.require('ol');
goog.require('ol.dom');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.ext.rbush');
goog.require('ol.extent');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.vector');
@@ -55,6 +56,12 @@ ol.source.ImageVector = function(options) {
*/
this.canvasSize_ = [0, 0];
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = ol.ext.rbush(9);
/**
* @private
* @type {number}
@@ -113,7 +120,7 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resol
var replayGroup = new ol.render.canvas.ReplayGroup(
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
resolution, pixelRatio, this.source_.getOverlaps(), this.renderBuffer_);
resolution, pixelRatio, this.source_.getOverlaps(), this.declutterTree_, this.renderBuffer_);
this.source_.loadFeatures(extent, resolution, projection);
@@ -146,6 +153,7 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resol
replayGroup.replay(this.canvasContext_, transform, 0, {});
this.replayGroup_ = replayGroup;
this.declutterTree_.clear();
return this.canvasContext_.canvas;
};
@@ -161,7 +169,7 @@ ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
} else {
/** @type {Object.<string, boolean>} */
var features = {};
return this.replayGroup_.forEachFeatureAtCoordinate(
var result = this.replayGroup_.forEachFeatureAtCoordinate(
coordinate, resolution, 0, hitTolerance, skippedFeatureUids,
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
@@ -173,7 +181,9 @@ ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
features[key] = true;
return callback(feature);
}
});
}, null);
this.declutterTree_.clear();
return result;
}
};

View File

@@ -10,6 +10,7 @@ goog.require('ol.events.EventType');
goog.require('ol.extent');
goog.require('ol.obj');
goog.require('ol.proj');
goog.require('ol.reproj');
goog.require('ol.source.Image');
goog.require('ol.source.WMSServerType');
goog.require('ol.string');
@@ -136,6 +137,13 @@ ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolut
if (this.url_ === undefined) {
return undefined;
}
var projectionObj = ol.proj.get(projection);
var sourceProjectionObj = this.getProjection();
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
resolution = ol.reproj.calculateSourceResolution(sourceProjectionObj, projectionObj, coordinate, resolution);
coordinate = ol.proj.transform(coordinate, projectionObj, sourceProjectionObj);
}
var extent = ol.extent.getForViewAndSize(
coordinate, resolution, 0,
@@ -158,7 +166,7 @@ ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolut
return this.getRequestUrl_(
extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_,
1, ol.proj.get(projection), baseParams);
1, sourceProjectionObj || projectionObj, baseParams);
};
@@ -225,7 +233,7 @@ ol.source.ImageWMS.prototype.getImageInternal = function(extent, resolution, pix
projection, params);
this.image_ = new ol.Image(requestExtent, resolution, pixelRatio,
this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
url, this.crossOrigin_, this.imageLoadFunction_);
this.renderedRevision_ = this.getRevision();

View File

@@ -1,7 +1,6 @@
goog.provide('ol.source.OSM');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.source.XYZ');
@@ -51,11 +50,9 @@ ol.inherits(ol.source.OSM, ol.source.XYZ);
* The attribution containing a link to the OpenStreetMap Copyright and License
* page.
* @const
* @type {ol.Attribution}
* @type {string}
* @api
*/
ol.source.OSM.ATTRIBUTION = new ol.Attribution({
html: '&copy; ' +
ol.source.OSM.ATTRIBUTION = '&copy; ' +
'<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> ' +
'contributors.'
});
'contributors.';

View File

@@ -23,8 +23,8 @@ goog.require('ol.transform');
/**
* @classdesc
* A source that transforms data from any number of input sources using an array
* of {@link ol.RasterOperation} functions to transform input pixel values into
* A source that transforms data from any number of input sources using an
* {@link ol.RasterOperation} function to transform input pixel values into
* output pixel values.
*
* @constructor
@@ -299,8 +299,7 @@ ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, err, output,
var width = Math.round(ol.extent.getWidth(extent) / resolution);
var height = Math.round(ol.extent.getHeight(extent) / resolution);
context = ol.dom.createCanvasContext2D(width, height);
this.renderedImageCanvas_ = new ol.ImageCanvas(
extent, resolution, 1, this.getAttributions(), context.canvas);
this.renderedImageCanvas_ = new ol.ImageCanvas(extent, resolution, 1, context.canvas);
}
context.putImageData(output, 0, 0);

View File

@@ -35,7 +35,13 @@ ol.source.Source = function(options) {
* @private
* @type {Array.<ol.Attribution>}
*/
this.attributions_ = ol.source.Source.toAttributionsArray_(options.attributions);
this.attributions_ = null;
/**
* @private
* @type {?ol.Attribution2}
*/
this.attributions2_ = this.adaptAttributions_(options.attributions);
/**
* @private
@@ -60,36 +66,61 @@ ol.source.Source = function(options) {
ol.inherits(ol.source.Source, ol.Object);
/**
* Turns various ways of defining an attribution to an array of `ol.Attributions`.
*
* @param {ol.AttributionLike|undefined}
* attributionLike The attributions as string, array of strings,
* `ol.Attribution`, array of `ol.Attribution` or undefined.
* @return {Array.<ol.Attribution>} The array of `ol.Attribution` or null if
* `undefined` was given.
* Turns the attributions option into an attributions function.
* @suppress {deprecated}
* @param {ol.AttributionLike|undefined} attributionLike The attribution option.
* @return {?ol.Attribution2} An attribution function (or null).
*/
ol.source.Source.toAttributionsArray_ = function(attributionLike) {
if (typeof attributionLike === 'string') {
return [new ol.Attribution({html: attributionLike})];
} else if (attributionLike instanceof ol.Attribution) {
return [attributionLike];
} else if (Array.isArray(attributionLike)) {
var len = attributionLike.length;
var attributions = new Array(len);
for (var i = 0; i < len; i++) {
var item = attributionLike[i];
if (typeof item === 'string') {
attributions[i] = new ol.Attribution({html: item});
} else {
attributions[i] = item;
}
}
return attributions;
} else {
ol.source.Source.prototype.adaptAttributions_ = function(attributionLike) {
if (!attributionLike) {
return null;
}
};
if (attributionLike instanceof ol.Attribution) {
// TODO: remove attributions_ in next major release
this.attributions_ = [attributionLike];
return function(frameState) {
return [attributionLike.getHTML()];
};
}
if (Array.isArray(attributionLike)) {
if (attributionLike[0] instanceof ol.Attribution) {
// TODO: remove attributions_ in next major release
this.attributions_ = attributionLike;
var attributions = attributionLike.map(function(attribution) {
return attribution.getHTML();
});
return function(frameState) {
return attributions;
};
}
// TODO: remove attributions_ in next major release
this.attributions_ = attributionLike.map(function(attribution) {
return new ol.Attribution({html: attribution});
});
return function(frameState) {
return attributionLike;
};
}
if (typeof attributionLike === 'function') {
return attributionLike;
}
// TODO: remove attributions_ in next major release
this.attributions_ = [
new ol.Attribution({html: attributionLike})
];
return function(frameState) {
return [attributionLike];
};
};
/**
* @param {ol.Coordinate} coordinate Coordinate.
@@ -115,6 +146,15 @@ ol.source.Source.prototype.getAttributions = function() {
};
/**
* Get the attribution function for the source.
* @return {?ol.Attribution2} Attribution function.
*/
ol.source.Source.prototype.getAttributions2 = function() {
return this.attributions2_;
};
/**
* Get the logo of the source.
* @return {string|olx.LogoOptions|undefined} Logo.
@@ -172,12 +212,12 @@ ol.source.Source.prototype.refresh = function() {
/**
* Set the attributions of the source.
* @param {ol.AttributionLike|undefined} attributions Attributions.
* Can be passed as `string`, `Array<string>`, `{@link ol.Attribution}`,
* `Array<{@link ol.Attribution}>` or `undefined`.
* Can be passed as `string`, `Array<string>`, `{@link ol.Attribution2}`,
* or `undefined`.
* @api
*/
ol.source.Source.prototype.setAttributions = function(attributions) {
this.attributions_ = ol.source.Source.toAttributionsArray_(attributions);
this.attributions2_ = this.adaptAttributions_(attributions);
this.changed();
};

View File

@@ -1,7 +1,6 @@
goog.provide('ol.source.Stamen');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.source.OSM');
goog.require('ol.source.XYZ');
@@ -44,14 +43,12 @@ ol.inherits(ol.source.Stamen, ol.source.XYZ);
/**
* @const
* @type {Array.<ol.Attribution>}
* @type {Array.<string>}
*/
ol.source.Stamen.ATTRIBUTIONS = [
new ol.Attribution({
html: 'Map tiles by <a href="https://stamen.com/">Stamen Design</a>, ' +
'Map tiles by <a href="https://stamen.com/">Stamen Design</a>, ' +
'under <a href="https://creativecommons.org/licenses/by/3.0/">CC BY' +
' 3.0</a>.'
}),
' 3.0</a>.',
ol.source.OSM.ATTRIBUTION
];

View File

@@ -237,11 +237,11 @@ ol.source.TileImage.prototype.createTile_ = function(z, x, y, pixelRatio, projec
* @inheritDoc
*/
ol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection) {
var sourceProjection = /** @type {!ol.proj.Projection} */ (this.getProjection());
if (!ol.ENABLE_RASTER_REPROJECTION ||
!this.getProjection() ||
!projection ||
ol.proj.equivalent(this.getProjection(), projection)) {
return this.getTileInternal(z, x, y, pixelRatio, /** @type {!ol.proj.Projection} */ (projection));
!sourceProjection || !projection ||
ol.proj.equivalent(sourceProjection, projection)) {
return this.getTileInternal(z, x, y, pixelRatio, sourceProjection || projection);
} else {
var cache = this.getTileCacheForProjection(projection);
var tileCoord = [z, x, y];
@@ -254,7 +254,6 @@ ol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection
if (tile && tile.key == key) {
return tile;
} else {
var sourceProjection = /** @type {!ol.proj.Projection} */ (this.getProjection());
var sourceTileGrid = this.getTileGridForProjection(sourceProjection);
var targetTileGrid = this.getTileGridForProjection(projection);
var wrappedTileCoord =

View File

@@ -7,7 +7,6 @@
goog.provide('ol.source.TileJSON');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.TileUrlFunction');
goog.require('ol.asserts');
goog.require('ol.extent');
@@ -136,23 +135,17 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
this.tileUrlFunction =
ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid);
if (tileJSON.attribution !== undefined && !this.getAttributions()) {
if (tileJSON.attribution !== undefined && !this.getAttributions2()) {
var attributionExtent = extent !== undefined ?
extent : epsg4326Projection.getExtent();
/** @type {Object.<string, Array.<ol.TileRange>>} */
var tileRanges = {};
var z, zKey;
for (z = minZoom; z <= maxZoom; ++z) {
zKey = z.toString();
tileRanges[zKey] =
[tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
}
this.setAttributions([
new ol.Attribution({
html: tileJSON.attribution,
tileRanges: tileRanges
})
]);
this.setAttributions(function(frameState) {
if (ol.extent.intersects(attributionExtent, frameState.extent)) {
return [tileJSON.attribution];
}
return null;
});
}
this.tileJSON_ = tileJSON;
this.setState(ol.source.State.READY);

View File

@@ -1,7 +1,6 @@
goog.provide('ol.source.TileUTFGrid');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.Tile');
goog.require('ol.TileState');
goog.require('ol.TileUrlFunction');
@@ -199,20 +198,13 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
if (tileJSON.attribution !== undefined) {
var attributionExtent = extent !== undefined ?
extent : epsg4326Projection.getExtent();
/** @type {Object.<string, Array.<ol.TileRange>>} */
var tileRanges = {};
var z, zKey;
for (z = minZoom; z <= maxZoom; ++z) {
zKey = z.toString();
tileRanges[zKey] =
[tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
}
this.setAttributions([
new ol.Attribution({
html: tileJSON.attribution,
tileRanges: tileRanges
})
]);
this.setAttributions(function(frameState) {
if (ol.extent.intersects(attributionExtent, frameState.extent)) {
return [tileJSON.attribution];
}
return null;
});
}
this.setState(ol.source.State.READY);

View File

@@ -10,6 +10,7 @@ goog.require('ol.extent');
goog.require('ol.obj');
goog.require('ol.math');
goog.require('ol.proj');
goog.require('ol.reproj');
goog.require('ol.size');
goog.require('ol.source.TileImage');
goog.require('ol.source.WMSServerType');
@@ -110,14 +111,14 @@ ol.inherits(ol.source.TileWMS, ol.source.TileImage);
*/
ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
var projectionObj = ol.proj.get(projection);
var sourceProjectionObj = this.getProjection();
var tileGrid = this.getTileGrid();
if (!tileGrid) {
tileGrid = this.getTileGridForProjection(projectionObj);
}
var tileCoord = tileGrid.getTileCoordForCoordAndResolution(
coordinate, resolution);
var tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return undefined;
@@ -125,14 +126,19 @@ ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resoluti
var tileResolution = tileGrid.getResolution(tileCoord[0]);
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
var tileSize = ol.size.toSize(
tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
var gutter = this.gutter_;
if (gutter !== 0) {
tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
tileExtent = ol.extent.buffer(tileExtent,
tileResolution * gutter, tileExtent);
tileExtent = ol.extent.buffer(tileExtent, tileResolution * gutter, tileExtent);
}
if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
tileResolution = ol.reproj.calculateSourceResolution(sourceProjectionObj, projectionObj, coordinate, tileResolution);
tileExtent = ol.proj.transformExtent(tileExtent, projectionObj, sourceProjectionObj);
coordinate = ol.proj.transform(coordinate, projectionObj, sourceProjectionObj);
}
var baseParams = {
@@ -152,7 +158,7 @@ ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resoluti
baseParams[this.v13_ ? 'J' : 'Y'] = y;
return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
1, projectionObj, baseParams);
1, sourceProjectionObj || projectionObj, baseParams);
};

View File

@@ -118,12 +118,10 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
var tileCoord = [z, x, y];
var urlTileCoord = this.getTileCoordForTileUrlFunction(
tileCoord, projection);
var tileUrl = urlTileCoord ?
this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
var tile = new ol.VectorImageTile(
tileCoord,
tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
tileUrl !== undefined ? tileUrl : '',
urlTileCoord !== null ? ol.TileState.IDLE : ol.TileState.EMPTY,
this.getRevision(),
this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction,
this.tileGrid, this.getTileGridForProjection(projection),
this.sourceTiles_, pixelRatio, projection, this.tileClass,

View File

@@ -7,6 +7,7 @@ goog.require('ol.TileUrlFunction');
goog.require('ol.asserts');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.size');
goog.require('ol.source.TileImage');
goog.require('ol.tilegrid.TileGrid');
@@ -32,26 +33,28 @@ ol.source.Zoomify = function(opt_options) {
var imageWidth = size[0];
var imageHeight = size[1];
var extent = options.extent || [0, -size[1], size[0], 0];
var tierSizeInTiles = [];
var tileSize = ol.DEFAULT_TILE_SIZE;
var tileSize = options.tileSize || ol.DEFAULT_TILE_SIZE;
var tileSizeForTierSizeCalculation = tileSize;
switch (tierSizeCalculation) {
case ol.source.Zoomify.TierSizeCalculation_.DEFAULT:
while (imageWidth > tileSize || imageHeight > tileSize) {
while (imageWidth > tileSizeForTierSizeCalculation || imageHeight > tileSizeForTierSizeCalculation) {
tierSizeInTiles.push([
Math.ceil(imageWidth / tileSize),
Math.ceil(imageHeight / tileSize)
Math.ceil(imageWidth / tileSizeForTierSizeCalculation),
Math.ceil(imageHeight / tileSizeForTierSizeCalculation)
]);
tileSize += tileSize;
tileSizeForTierSizeCalculation += tileSizeForTierSizeCalculation;
}
break;
case ol.source.Zoomify.TierSizeCalculation_.TRUNCATED:
var width = imageWidth;
var height = imageHeight;
while (width > tileSize || height > tileSize) {
while (width > tileSizeForTierSizeCalculation || height > tileSizeForTierSizeCalculation) {
tierSizeInTiles.push([
Math.ceil(width / tileSize),
Math.ceil(height / tileSize)
Math.ceil(width / tileSizeForTierSizeCalculation),
Math.ceil(height / tileSizeForTierSizeCalculation)
]);
width >>= 1;
height >>= 1;
@@ -77,8 +80,8 @@ ol.source.Zoomify = function(opt_options) {
}
resolutions.reverse();
var extent = [0, -size[1], size[0], 0];
var tileGrid = new ol.tilegrid.TileGrid({
tileSize: tileSize,
extent: extent,
origin: ol.extent.getTopLeft(extent),
resolutions: resolutions
@@ -113,7 +116,8 @@ ol.source.Zoomify = function(opt_options) {
var tileIndex =
tileCoordX +
tileCoordY * tierSizeInTiles[tileCoordZ][0];
var tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / ol.DEFAULT_TILE_SIZE) | 0;
var tileSize = tileGrid.getTileSize(tileCoordZ);
var tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / tileSize) | 0;
var localContext = {
'z': tileCoordZ,
'x': tileCoordX,
@@ -130,6 +134,8 @@ ol.source.Zoomify = function(opt_options) {
var tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(urls.map(createFromTemplate));
var ZoomifyTileClass = ol.source.Zoomify.Tile_.bind(null, tileGrid);
ol.source.TileImage.call(this, {
attributions: options.attributions,
cacheSize: options.cacheSize,
@@ -137,7 +143,7 @@ ol.source.Zoomify = function(opt_options) {
logo: options.logo,
projection: options.projection,
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
tileClass: ol.source.Zoomify.Tile_,
tileClass: ZoomifyTileClass,
tileGrid: tileGrid,
tileUrlFunction: tileUrlFunction,
transition: options.transition
@@ -146,10 +152,10 @@ ol.source.Zoomify = function(opt_options) {
};
ol.inherits(ol.source.Zoomify, ol.source.TileImage);
/**
* @constructor
* @extends {ol.ImageTile}
* @param {ol.tilegrid.TileGrid} tileGrid TileGrid that the tile belongs to.
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.TileState} state State.
* @param {string} src Image source URI.
@@ -159,7 +165,7 @@ ol.inherits(ol.source.Zoomify, ol.source.TileImage);
* @private
*/
ol.source.Zoomify.Tile_ = function(
tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
ol.ImageTile.call(this, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);
@@ -169,6 +175,11 @@ ol.source.Zoomify.Tile_ = function(
*/
this.zoomifyImage_ = null;
/**
* @private
* @type {ol.Size}
*/
this.tileSize_ = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));
};
ol.inherits(ol.source.Zoomify.Tile_, ol.ImageTile);
@@ -180,14 +191,14 @@ ol.source.Zoomify.Tile_.prototype.getImage = function() {
if (this.zoomifyImage_) {
return this.zoomifyImage_;
}
var tileSize = ol.DEFAULT_TILE_SIZE;
var image = ol.ImageTile.prototype.getImage.call(this);
if (this.state == ol.TileState.LOADED) {
if (image.width == tileSize && image.height == tileSize) {
var tileSize = this.tileSize_;
if (image.width == tileSize[0] && image.height == tileSize[1]) {
this.zoomifyImage_ = image;
return image;
} else {
var context = ol.dom.createCanvasContext2D(tileSize, tileSize);
var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]);
context.drawImage(image, 0, 0);
this.zoomifyImage_ = context.canvas;
return context.canvas;
@@ -197,7 +208,6 @@ ol.source.Zoomify.Tile_.prototype.getImage = function() {
}
};
/**
* @enum {string}
* @private

View File

@@ -1,6 +1,9 @@
goog.provide('ol.structs.LRUCache');
goog.require('ol');
goog.require('ol.asserts');
goog.require('ol.events.EventTarget');
goog.require('ol.events.EventType');
/**
@@ -8,12 +11,16 @@ goog.require('ol.asserts');
* Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring
* items from the cache is the responsibility of the user.
* @constructor
* @extends {ol.events.EventTarget}
* @fires ol.events.Event
* @struct
* @template T
* @param {number=} opt_highWaterMark High water mark.
*/
ol.structs.LRUCache = function(opt_highWaterMark) {
ol.events.EventTarget.call(this);
/**
* @type {number}
*/
@@ -45,6 +52,8 @@ ol.structs.LRUCache = function(opt_highWaterMark) {
};
ol.inherits(ol.structs.LRUCache, ol.events.EventTarget);
/**
* @return {boolean} Can expire cache.
@@ -62,6 +71,7 @@ ol.structs.LRUCache.prototype.clear = function() {
this.entries_ = {};
this.oldest_ = null;
this.newest_ = null;
this.dispatchEvent(ol.events.EventType.CLEAR);
};
@@ -255,3 +265,15 @@ ol.structs.LRUCache.prototype.set = function(key, value) {
this.entries_[key] = entry;
++this.count_;
};
/**
* @param {string} key Key.
* @param {T} value Value.
*/
ol.structs.LRUCache.prototype.pruneAndSet = function(key, value) {
while (this.canExpireCache()) {
this.pop();
}
this.set(key, value);
};

View File

@@ -46,15 +46,25 @@ ol.AtlasManagerInfo;
* A type that can be used to provide attribution information for data sources.
*
* It represents either
* * a simple string (e.g. `'© Acme Inc.'`),
* * an array of simple strings (e.g. `['© Acme Inc.', '© Bacme Inc.']`),
* * an instance of `{@link ol.Attribution}`,
* * or an array with multiple `{@link ol.Attribution}` instances.
* @typedef {string|Array.<string>|ol.Attribution|Array.<ol.Attribution>}
* * a simple string (e.g. `'© Acme Inc.'`)
* * an array of simple strings (e.g. `['© Acme Inc.', '© Bacme Inc.']`)
* * a function that returns a string or array of strings (`{@link ol.Attribution2}`)
*
* Note that the `{@link ol.Attribution}` constructor is deprecated.
* @typedef {string|Array.<string>|ol.Attribution2|ol.Attribution|Array.<ol.Attribution>}
*/
ol.AttributionLike;
/**
* A function that returns a string or an array of strings representing source
* attributions.
*
* @typedef {function(olx.FrameState): (string|Array.<string>)}
*/
ol.Attribution2;
/**
* @typedef {{fillStyle: ol.ColorLike}}
*/
@@ -76,6 +86,28 @@ ol.CanvasFillState;
ol.CanvasFunctionType;
/**
* @typedef {{currentFillStyle: (ol.ColorLike|undefined),
* currentStrokeStyle: (ol.ColorLike|undefined),
* currentLineCap: (string|undefined),
* currentLineDash: Array.<number>,
* currentLineDashOffset: (number|undefined),
* currentLineJoin: (string|undefined),
* currentLineWidth: (number|undefined),
* currentMiterLimit: (number|undefined),
* lastStroke: (number|undefined),
* fillStyle: (ol.ColorLike|undefined),
* strokeStyle: (ol.ColorLike|undefined),
* lineCap: (string|undefined),
* lineDash: Array.<number>,
* lineDashOffset: (number|undefined),
* lineJoin: (string|undefined),
* lineWidth: (number|undefined),
* miterLimit: (number|undefined)}|null}
*/
ol.CanvasFillStrokeState;
/**
* @typedef {{lineCap: string,
* lineDash: Array.<number>,
@@ -157,6 +189,20 @@ ol.Coordinate;
ol.CoordinateFormatType;
/**
* Container for decluttered replay instructions that need to be rendered or
* omitted together, i.e. when styles render both an image and text, or for the
* characters that form text along lines. The basic elements of this array are
* `[minX, minY, maxX, maxY, count]`, where the first four entries are the
* rendered extent of the group in pixel space. `count` is the number of styles
* in the group, i.e. 2 when an image and a text are grouped, or 1 otherwise.
* In addition to these four elements, declutter instruction arrays (i.e. the
* arguments to @{link ol.render.canvas.drawImage} are appended to the array.
* @typedef {Array.<*>}
*/
ol.DeclutterGroup;
/**
* A function that takes a {@link ol.MapBrowserEvent} and two
* {@link ol.Pixel}s and returns a `{boolean}`. If the condition is met,

View File

@@ -15,7 +15,7 @@ goog.require('ol.featureloader');
* @extends {ol.Tile}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.TileState} state State.
* @param {string} src Data source url.
* @param {number} sourceRevision Source revision.
* @param {ol.format.Feature} format Feature format.
* @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
* @param {ol.TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
@@ -32,9 +32,9 @@ goog.require('ol.featureloader');
* Function to call when a source tile's state changes.
* @param {olx.TileOptions=} opt_options Tile options.
*/
ol.VectorImageTile = function(tileCoord, state, src, format, tileLoadFunction,
urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles,
pixelRatio, projection, tileClass, handleTileChange, opt_options) {
ol.VectorImageTile = function(tileCoord, state, sourceRevision, format,
tileLoadFunction, urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid,
sourceTiles, pixelRatio, projection, tileClass, handleTileChange, opt_options) {
ol.Tile.call(this, tileCoord, state, opt_options);
@@ -69,9 +69,9 @@ ol.VectorImageTile = function(tileCoord, state, src, format, tileLoadFunction,
this.tileKeys = [];
/**
* @type {string}
* @type {number}
*/
this.src_ = src;
this.sourceRevision_ = sourceRevision;
/**
* @type {ol.TileCoord}
@@ -197,7 +197,7 @@ ol.VectorImageTile.prototype.getReplayState = function(layer) {
* @inheritDoc
*/
ol.VectorImageTile.prototype.getKey = function() {
return this.tileKeys.join('/') + '/' + this.src_;
return this.tileKeys.join('/') + '-' + this.sourceRevision_;
};

View File

@@ -92,6 +92,7 @@ ol.VectorTile.prototype.disposeInternal = function() {
/**
* Gets the extent of the vector tile.
* @return {ol.Extent} The extent.
* @api
*/
ol.VectorTile.prototype.getExtent = function() {
return this.extent_ || ol.VectorTile.DEFAULT_EXTENT;

View File

@@ -341,7 +341,7 @@ ol.View.prototype.animate = function(var_args) {
* @api
*/
ol.View.prototype.getAnimating = function() {
return this.getHints()[ol.ViewHint.ANIMATING] > 0;
return this.hints_[ol.ViewHint.ANIMATING] > 0;
};
@@ -351,7 +351,7 @@ ol.View.prototype.getAnimating = function() {
* @api
*/
ol.View.prototype.getInteracting = function() {
return this.getHints()[ol.ViewHint.INTERACTING] > 0;
return this.hints_[ol.ViewHint.INTERACTING] > 0;
};
@@ -360,7 +360,7 @@ ol.View.prototype.getInteracting = function() {
* @api
*/
ol.View.prototype.cancelAnimations = function() {
this.setHint(ol.ViewHint.ANIMATING, -this.getHints()[ol.ViewHint.ANIMATING]);
this.setHint(ol.ViewHint.ANIMATING, -this.hints_[ol.ViewHint.ANIMATING]);
for (var i = 0, ii = this.animations_.length; i < ii; ++i) {
var series = this.animations_[i];
if (series[0].callback) {
@@ -781,14 +781,16 @@ ol.View.prototype.getState = function() {
center: center.slice(),
projection: projection !== undefined ? projection : null,
resolution: resolution,
rotation: rotation
rotation: rotation,
zoom: this.getZoom()
});
};
/**
* Get the current zoom level. Return undefined if the current
* resolution is undefined or not within the "resolution constraints".
* Get the current zoom level. If you configured your view with a resolutions
* array (this is rare), this method may return non-integer zoom levels (so
* the zoom level is not safe to use as an index into a resolutions array).
* @return {number|undefined} Zoom.
* @api
*/
@@ -809,25 +811,22 @@ ol.View.prototype.getZoom = function() {
* @api
*/
ol.View.prototype.getZoomForResolution = function(resolution) {
var zoom;
if (resolution >= this.minResolution_ && resolution <= this.maxResolution_) {
var offset = this.minZoom_ || 0;
var max, zoomFactor;
if (this.resolutions_) {
var nearest = ol.array.linearFindNearest(this.resolutions_, resolution, 1);
offset += nearest;
if (nearest == this.resolutions_.length - 1) {
return offset;
}
max = this.resolutions_[nearest];
zoomFactor = max / this.resolutions_[nearest + 1];
var offset = this.minZoom_ || 0;
var max, zoomFactor;
if (this.resolutions_) {
var nearest = ol.array.linearFindNearest(this.resolutions_, resolution, 1);
offset += nearest;
max = this.resolutions_[nearest];
if (nearest == this.resolutions_.length - 1) {
zoomFactor = 2;
} else {
max = this.maxResolution_;
zoomFactor = this.zoomFactor_;
zoomFactor = max / this.resolutions_[nearest + 1];
}
zoom = offset + Math.log(max / resolution) / Math.log(zoomFactor);
} else {
max = this.maxResolution_;
zoomFactor = this.zoomFactor_;
}
return zoom;
return offset + Math.log(max / resolution) / Math.log(zoomFactor);
};

View File

@@ -48,7 +48,7 @@ function main() {
const moduleName = ext.name || ext.module;
const options = {
extend: true,
entry: require.resolve(ext.module),
input: require.resolve(ext.module),
format: 'iife',
exports: 'named',
plugins: [

View File

@@ -108,7 +108,8 @@ module.exports = function(karma) {
username: 'openlayers',
accessKey: process.env.SAUCE_ACCESS_KEY,
connectOptions: {
noSslBumpDomains: 'all'
noSslBumpDomains: 'all',
connectRetries: 5
}
},
hostname: 'travis.dev',

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -6,12 +6,15 @@ goog.require('ol.View');
goog.require('ol.format.GeoJSON');
goog.require('ol.geom.Circle');
goog.require('ol.geom.LineString');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
describe('ol.rendering.layer.Vector', function() {
@@ -461,4 +464,304 @@ describe('ol.rendering.layer.Vector', function() {
});
describe('decluttering', function() {
beforeEach(function() {
source = new ol.source.Vector();
});
it('declutters text', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
var centerFeature = new ol.Feature({
geometry: new ol.geom.Point(center),
text: 'center'
});
source.addFeature(centerFeature);
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] - 550, center[1]]),
text: 'west'
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] + 550, center[1]]),
text: 'east'
}));
layer.setDeclutter(true);
layer.setStyle(function(feature) {
return new ol.style.Style({
text: new ol.style.Text({
text: feature.get('text'),
font: '12px sans-serif'
})
});
});
map.once('postrender', function() {
var hitDetected = map.getFeaturesAtPixel([42, 42]);
expect(hitDetected).to.have.length(1);
expect(hitDetected[0]).to.equal(centerFeature);
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter.png',
2.2, done);
});
});
it('declutters text and respects z-index', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point(center),
text: 'center',
zIndex: 2
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] - 550, center[1]]),
text: 'west',
zIndex: 3
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] + 550, center[1]]),
text: 'east',
zIndex: 1
}));
layer.setDeclutter(true);
layer.setStyle(function(feature) {
return new ol.style.Style({
zIndex: feature.get('zIndex'),
text: new ol.style.Text({
text: feature.get('text'),
font: '12px sans-serif'
})
});
});
map.once('postrender', function() {
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-zindex.png',
3.9, done);
});
});
it('declutters images', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
var centerFeature = new ol.Feature({
geometry: new ol.geom.Point(center)
});
source.addFeature(centerFeature);
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] - 550, center[1]])
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] + 550, center[1]])
}));
layer.setDeclutter(true);
layer.setStyle(function(feature) {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 15,
stroke: new ol.style.Stroke({
color: 'blue'
})
})
});
});
map.once('postrender', function() {
var hitDetected = map.getFeaturesAtPixel([40, 40]);
expect(hitDetected).to.have.length(1);
expect(hitDetected[0]).to.equal(centerFeature);
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-image.png',
IMAGE_TOLERANCE, done);
});
});
it('declutters images and respects z-index', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point(center),
zIndex: 2
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] - 550, center[1]]),
zIndex: 3
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] + 550, center[1]]),
zIndex: 1
}));
layer.setDeclutter(true);
layer.setStyle(function(feature) {
return new ol.style.Style({
zIndex: feature.get('zIndex'),
image: new ol.style.Circle({
radius: 15,
stroke: new ol.style.Stroke({
color: 'blue'
})
})
});
});
map.once('postrender', function() {
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-image-zindex.png',
IMAGE_TOLERANCE, done);
});
});
it('declutters image & text groups', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point(center),
text: 'center'
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] - 550, center[1]]),
text: 'west'
}));
source.addFeature(new ol.Feature({
geometry: new ol.geom.Point([center[0] + 550, center[1]]),
text: 'east'
}));
layer.setDeclutter(true);
layer.setStyle(function(feature) {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'blue'
})
}),
text: new ol.style.Text({
text: feature.get('text'),
font: '12px sans-serif',
textBaseline: 'bottom',
offsetY: -5
})
});
});
map.once('postrender', function() {
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-group.png',
2.2, done);
});
});
it('declutters text along lines and images', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
var point = new ol.Feature(new ol.geom.Point(center));
point.setStyle(new ol.style.Style({
image: new ol.style.Circle({
radius: 8,
stroke: new ol.style.Stroke({
color: 'blue'
})
})
}));
var line = new ol.Feature(new ol.geom.LineString([
[center[0] - 650, center[1] - 200],
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#CCC',
width: 12
}),
text: new ol.style.Text({
placement: 'line',
text: 'east-west',
font: '12px sans-serif'
})
}));
source.addFeature(point);
source.addFeature(line);
layer.setDeclutter(true);
map.once('postrender', function() {
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-line.png',
IMAGE_TOLERANCE, done);
});
});
it('declutters text along lines and images with z-index', function(done) {
createMap('canvas');
var layer = new ol.layer.Vector({
source: source
});
map.addLayer(layer);
var point = new ol.Feature(new ol.geom.Point(center));
point.setStyle(new ol.style.Style({
zIndex: 2,
image: new ol.style.Circle({
radius: 8,
stroke: new ol.style.Stroke({
color: 'blue'
})
})
}));
var line = new ol.Feature(new ol.geom.LineString([
[center[0] - 650, center[1] - 200],
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new ol.style.Style({
zIndex: 1,
stroke: new ol.style.Stroke({
color: '#CCC',
width: 12
}),
text: new ol.style.Text({
placement: 'line',
text: 'east-west',
font: '12px sans-serif'
})
}));
source.addFeature(point);
source.addFeature(line);
layer.setDeclutter(true);
map.once('postrender', function() {
var hitDetected = map.getFeaturesAtPixel([35, 46]);
expect(hitDetected).to.have.length(1);
expect(hitDetected[0]).to.equal(line);
expectResemble(map, 'rendering/ol/layer/expected/vector-canvas-declutter-line-zindex.png',
4.1, done);
});
});
});
});

View File

@@ -6,6 +6,10 @@ goog.require('ol.format.MVT');
goog.require('ol.layer.VectorTile');
goog.require('ol.obj');
goog.require('ol.source.VectorTile');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
goog.require('ol.tilegrid');
@@ -13,10 +17,11 @@ describe('ol.rendering.layer.VectorTile', function() {
var map;
function createMap(renderer, opt_pixelRatio) {
function createMap(renderer, opt_pixelRatio, opt_size) {
var size = opt_size || 50;
map = new ol.Map({
pixelRatio: opt_pixelRatio || 1,
target: createMapDiv(50, 50),
target: createMapDiv(size, size),
renderer: renderer,
view: new ol.View({
center: [1825927.7316762917, 6143091.089223046],
@@ -104,6 +109,34 @@ describe('ol.rendering.layer.VectorTile', function() {
});
});
it('declutters text and images', function(done) {
createMap('canvas', 1, 100);
map.getView().setZoom(13.8);
var style = function(feature, resolution) {
var geom = feature.getGeometry();
if (geom.getType() == 'Point') {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: 'red'
})
}),
text: new ol.style.Text({
text: feature.get('name_en'),
font: '12px sans-serif',
textBaseline: 'bottom',
offsetY: -7
})
});
}
};
waitForTiles(source, {declutter: true, style: style}, function() {
expectResemble(map, 'rendering/ol/layer/expected/vectortile-canvas-declutter.png',
8.5, done);
});
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -358,7 +358,7 @@ describe('ol.rendering.style.Text', function() {
}));
vectorSource.addFeature(feature);
map.getView().fit(vectorSource.getExtent());
expectResemble(map, 'rendering/ol/style/expected/text-multilinestring.png', 6.9, done);
expectResemble(map, 'rendering/ol/style/expected/text-multilinestring.png', 7, done);
});
it('renders text along a Polygon', function(done) {

View File

@@ -1,12 +1,10 @@
goog.require('ol.color');
goog.require('ol');
describe('ol.color', function() {
describe('ol.color.asArray()', function() {
describe('asArray()', function() {
it('returns the same for an array', function() {
var color = [1, 2, 3, 0.4];
@@ -29,9 +27,14 @@ describe('ol.color', function() {
expect(color).to.eql([0, 204, 255, 1]);
});
it('returns an array given a hex string with alpha', function() {
var color = ol.color.asArray('#00ccffb0');
expect(color).to.eql([0, 204, 255, 176 / 255]);
});
});
describe('ol.color.asString()', function() {
describe('asString()', function() {
it('returns the same for a string', function() {
var color = 'rgba(0,1,2,0.3)';
@@ -51,7 +54,7 @@ describe('ol.color', function() {
});
describe('ol.color.fromString', function() {
describe('fromString()', function() {
before(function() {
sinon.spy(ol.color, 'fromStringInternal_');
@@ -72,10 +75,18 @@ describe('ol.color', function() {
expect(ol.color.fromString('#087')).to.eql([0, 136, 119, 1]);
});
it('can parse 4-digit hex colors', function() {
expect(ol.color.fromString('#0876')).to.eql([0, 136, 119, 102 / 255]);
});
it('can parse 6-digit hex colors', function() {
expect(ol.color.fromString('#56789a')).to.eql([86, 120, 154, 1]);
});
it('can parse 8-digit hex colors', function() {
expect(ol.color.fromString('#56789acc')).to.eql([86, 120, 154, 204 / 255]);
});
it('can parse rgb colors', function() {
expect(ol.color.fromString('rgb(0, 0, 255)')).to.eql([0, 0, 255, 1]);
});
@@ -130,7 +141,7 @@ describe('ol.color', function() {
});
it('throws an error on invalid colors', function() {
var invalidColors = ['tuesday', '#1234567', 'rgb(255.0,0,0)'];
var invalidColors = ['tuesday', '#12345', '#1234567', 'rgb(255.0,0,0)'];
var i, ii;
for (i = 0, ii < invalidColors.length; i < ii; ++i) {
expect(function() {
@@ -141,7 +152,7 @@ describe('ol.color', function() {
});
describe('ol.color.normalize', function() {
describe('normalize()', function() {
it('clamps out-of-range channels', function() {
expect(ol.color.normalize([-1, 256, 0, 2])).to.eql([0, 255, 0, 1]);
@@ -153,7 +164,7 @@ describe('ol.color', function() {
});
describe('ol.color.toString', function() {
describe('toString()', function() {
it('converts valid colors', function() {
expect(ol.color.toString([1, 2, 3, 0.4])).to.be('rgba(1,2,3,0.4)');

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