Compare commits

..

363 Commits

Author SHA1 Message Date
Andreas Hocevar
af9f26b9d3 Update package version for 6.3.1 2020-04-06 09:15:48 +02:00
Andreas Hocevar
6704cf3ace Changelog for v6.3.1 2020-04-06 09:11:58 +02:00
Andreas Hocevar
afa96df55d Merge pull request #10877 from ahocevar/no-dts
Remove .d.ts files from the package
2020-04-06 09:02:46 +02:00
Andreas Hocevar
a21470f6b4 Merge pull request #10872 from ahocevar/fix-type-generation
Use TypeScript 3.9 for type generation for better enums
2020-04-06 09:00:46 +02:00
Andreas Hocevar
b71e8ebb73 Develop on 6.3.1-dev 2020-04-02 22:24:08 +02:00
Andreas Hocevar
bdf969cc95 Update package version to 6.3.0 2020-04-02 22:04:52 +02:00
Andreas Hocevar
5357b4fced Changelog for v6.3.0 2020-04-02 22:03:53 +02:00
Andreas Hocevar
e683c0a0c5 Merge pull request #10490 from bepremeg/CK-240_RemoveSelectEventHandler
Select style multiple select interactions removed
2020-04-02 20:26:52 +02:00
Geert Premereur
ad77143417 Experiment with test impact further (3) 2020-04-02 20:05:15 +02:00
Geert Premereur
cf1191505e Experiment with test impact further (2) 2020-04-02 20:05:15 +02:00
Geert Premereur
3909938a70 Experiment with test impact further 2020-04-02 20:05:15 +02:00
Geert Premereur
e9e75cd8af temporarily disable test to observe impact 2020-04-02 20:05:14 +02:00
Geert Premereur
2d7e55e26a Small code cleanup
drop superfluous if.
2020-04-02 20:05:14 +02:00
Geert Premereur
dc957ec104 CK-240: fix lint errors 2020-04-02 20:05:14 +02:00
Geert Premereur
a30a92a963 CK-240: fix multiple select interactions on map
event handlers have to be (de)activated when the interaction is added or removed to the map, not when constructed

added unit test
2020-04-02 20:05:14 +02:00
Geert Premereur
10c7f08fa4 Select style multiple select interactions removed
This fixes issue 10486 by removing the event listeners when an
interaction is removed from a map.
2020-04-02 20:00:37 +02:00
Tim Schaub
c196f2f7b0 Merge pull request #10531 from pjsg/fix_image_reproj
Dynamically chose the number of subdivisions based on the size of the Image to reproject
2020-04-02 11:50:30 -06:00
Tim Schaub
0034d6f206 Merge pull request #10618 from MoonE/apidoc-debug-task
Add apidoc-debug task to debug the apidoc generation process
2020-04-02 11:27:38 -06:00
Tim Schaub
b4e51ed841 Merge pull request #10343 from mike-000/patch-10
Correct interactions with circle geometries when using user coordinates
2020-04-02 11:06:48 -06:00
philip
72907566bb Add comment to explain calculation. 2020-04-02 14:14:13 +00:00
Andreas Hocevar
612910bcd2 Merge pull request #10864 from ahocevar/dependency-updates
Update dependencies
2020-04-02 14:12:55 +02:00
Andreas Hocevar
8e6b5ce0bf Update dependencies 2020-04-02 13:50:12 +02:00
Tim Schaub
a073c5ab1e Merge pull request #10859 from SDaron/clipping-layer
Add an example of clipping layer based on a vector source
2020-04-01 03:59:58 -06:00
Andreas Hocevar
5e8102bbd1 Merge pull request #10850 from ahocevar/enum-docs
API docs for enums
2020-04-01 11:47:55 +02:00
Simon Daron
23c2e1062c Add an example of clipping layer based on a vector source 2020-04-01 10:08:37 +02:00
Andreas Hocevar
7dd42ef19f Key update 2020-04-01 09:07:07 +02:00
Andreas Hocevar
061ccb987b Key update 2020-04-01 08:43:52 +02:00
Andreas Hocevar
001128c98e Merge pull request #10857 from mike-000/patch-9
Make OSM XML example work at dateline and replace Bing with MapTiler
2020-04-01 08:33:34 +02:00
Andreas Hocevar
27169c2942 Merge pull request #10858 from ejn/overlay-autopan-on-set-map-10843
Perform auto-pan when adding an Overlay to a Map
2020-04-01 08:13:56 +02:00
Edward Nash
2b863793d0 Perform auto-pan when adding an Overlay to a Map
* Auto-pan settings currently only activate when the position of the
   Overlay is set and the Overlay is already on a Map.

 * The consequence of this is that creating an Overlay with position
   set and then adding to a Map results in no auto-pan being performed -
   it is necessary to first create the Overlay, then add to a Map and
   finally set the position in order for the Map to auto-pan.

 * This commit changes this behaviour so that the auto-pan settings are
   also considered when the map property of the Overlay is set and not
   only when the position property is set, leading to a more intuitive
   behaviour.

 * Fixes Issue #10843
2020-04-01 06:50:01 +02:00
mike-000
82dd764d13 Replace Bing layer with MapTiler 2020-03-31 22:37:51 +01:00
mike-000
7b55fe381e Replace Bing layer with MapTiler 2020-03-31 22:36:07 +01:00
mike-000
3c0ff15414 Cap Longitudes and replace Bing with MapTiler 2020-03-31 22:32:02 +01:00
Andreas Hocevar
2401e0af00 Merge pull request #10646 from mike-000/patch-1
Write fill and outline in KML PolyStyle
2020-03-31 23:22:15 +02:00
Andreas Hocevar
f66b44068c Merge pull request #10800 from ejn/overlay-pan-into-view-10741
Make Overlay.panIntoView an API method
2020-03-31 23:19:38 +02:00
Andreas Hocevar
25fcc6b604 Merge pull request #10855 from openlayers/dependabot/npm_and_yarn/rollup-2.3.0
Bump rollup from 2.1.0 to 2.3.0
2020-03-31 23:00:56 +02:00
Andreas Hocevar
820984d0eb Merge pull request #10854 from openlayers/dependabot/npm_and_yarn/ol-mapbox-style-6.1.1
Bump ol-mapbox-style from 6.1.0 to 6.1.1
2020-03-31 22:59:34 +02:00
Andreas Hocevar
ea12f7945f Merge pull request #10853 from openlayers/dependabot/npm_and_yarn/buble-0.20.0
Bump buble from 0.19.8 to 0.20.0
2020-03-31 22:46:58 +02:00
Andreas Hocevar
7334951056 Merge pull request #10852 from openlayers/dependabot/npm_and_yarn/webpack-4.42.1
Bump webpack from 4.42.0 to 4.42.1
2020-03-31 22:44:46 +02:00
Andreas Hocevar
78202c78b9 Merge pull request #10807 from mike-000/patch-2
Handle Graticule wrapX without calculating excess meridians
2020-03-31 21:02:16 +02:00
mike-000
bfca3cf713 change loader check back to equal extents 2020-03-31 17:00:12 +01:00
mike-000
929b9f4068 change loader check back to equal extents 2020-03-31 16:55:23 +01:00
mike-000
149ca7efad return previous extent if extents are approx equal 2020-03-31 16:26:30 +01:00
Andreas Hocevar
9af1e223af More tests and docs for extent and coordinate wrapX 2020-03-31 16:11:06 +02:00
Andreas Hocevar
cdafc4fa05 Add approximatelyEquals function for comparing extents 2020-03-31 16:11:06 +02:00
mike-000
2c7f58dbed remove unused import 2020-03-31 16:03:14 +02:00
mike-000
6013763480 replace containsExtent with equals in strategy 2020-03-31 16:03:14 +02:00
mike-000
99a1641afe remove duplication 2020-03-31 16:03:13 +02:00
mike-000
e3ad05f805 Include center at right edge in calculations 2020-03-31 16:03:13 +02:00
mike-000
660845f5b8 Include center at right edge in calculations 2020-03-31 16:03:13 +02:00
Andreas Hocevar
098885a006 New wrapX functions for coordinate and extent 2020-03-31 16:03:12 +02:00
mike-000
48b79cf7d1 only use one extent if two are passed 2020-03-31 16:03:12 +02:00
Andreas Hocevar
a35794ae97 Load two extents for views that cross the date line 2020-03-31 16:03:12 +02:00
mike-000
3d8495742b Simplify following renderer changes 2020-03-31 16:03:11 +02:00
Andreas Hocevar
190cd202a1 Always use load extent with real world center 2020-03-31 16:03:11 +02:00
mike-000
0c9324f398 Test extents passed to loader 2020-03-31 16:03:10 +02:00
mike-000
67c37c2163 Test extents passed to loader 2020-03-31 16:03:10 +02:00
mike-000
3b760dc308 Use getLoadWrapX() to determine extent to load 2020-03-31 16:03:10 +02:00
mike-000
b560dab513 Set loadWrapX: false in source 2020-03-31 16:03:09 +02:00
mike-000
f6bbf414a8 Add loadWrapX option and getter 2020-03-31 16:03:09 +02:00
mike-000
f6ede1a9c0 handle wrapX without calculating excess meridians
override extent validation only if the extent includes parts of two worlds
2020-03-31 16:03:08 +02:00
mike-000
516a75ae22 Always load frameState extent for graticule layers
reorder and comment
2020-03-31 16:03:08 +02:00
mike-000
bad0ff38ca handle wrapX without calculating excess meridians
avoid calculating more meridians or longer parallels than necessary when viewport extent includes a wrapped world
2020-03-31 16:03:08 +02:00
mike-000
772741cd0e Always load frameState extent for graticule layers
do not call graticule loader with wrapped projection extent
2020-03-31 16:03:06 +02:00
dependabot-preview[bot]
c92f72ac3f Bump rollup from 2.1.0 to 2.3.0
Bumps [rollup](https://github.com/rollup/rollup) from 2.1.0 to 2.3.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.1.0...v2.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-30 08:59:06 +00:00
dependabot-preview[bot]
e583e0775d Bump ol-mapbox-style from 6.1.0 to 6.1.1
Bumps [ol-mapbox-style](https://github.com/openlayers/ol-mapbox-style) from 6.1.0 to 6.1.1.
- [Release notes](https://github.com/openlayers/ol-mapbox-style/releases)
- [Changelog](https://github.com/openlayers/ol-mapbox-style/blob/master/CHANGELOG.md)
- [Commits](https://github.com/openlayers/ol-mapbox-style/compare/v6.1.0...v6.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-30 08:57:39 +00:00
dependabot-preview[bot]
6ca6c70aac Bump buble from 0.19.8 to 0.20.0
Bumps [buble](https://github.com/bublejs/buble) from 0.19.8 to 0.20.0.
- [Release notes](https://github.com/bublejs/buble/releases)
- [Changelog](https://github.com/bublejs/buble/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bublejs/buble/compare/v0.19.8...v0.20.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-30 08:56:40 +00:00
dependabot-preview[bot]
8222118fb1 Bump webpack from 4.42.0 to 4.42.1
Bumps [webpack](https://github.com/webpack/webpack) from 4.42.0 to 4.42.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.42.0...v4.42.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-30 08:55:08 +00:00
Edward Nash
2537da690a Add check that Position is set in panIntoView()
* If panIntoView is an API method, it may now be called when the
   position of the overlay has not yet been set.

 * Adds a check for a set position to the panIntoView() method,
   and removes the now unneccessary check in handlePositionChanged()
2020-03-30 07:15:03 +02:00
Edward Nash
b1b01cf943 Allow pan options supplied as autoPan
* Follow the suggestion from @ahocevar to use the existing
   autoPan constructor option instead of creating a new autoPanOptions
   option

 * Internally also store the autoPanOptions in autoPan
2020-03-30 07:12:52 +02:00
Andreas Hocevar
0a7f7db817 Merge pull request #10795 from mike-000/patch-6
Show graticule labels in wrapped worlds
2020-03-28 14:46:54 +01:00
Andreas Hocevar
b39e12406a Merge pull request #10824 from MoonE/icon-color-ie11
Fix drawing svg icon with color option in ie11
2020-03-28 14:26:10 +01:00
Andreas Hocevar
dd44ecf185 Only document enums when they have API properties 2020-03-28 14:17:56 +01:00
Andreas Hocevar
a6a5b72c57 Only mark items as api, not enums 2020-03-27 12:33:54 +01:00
Maximilian Krög
1020c384bb Fix two missing apidoc links
Add IconAnchorUnits and IconOrigin to the api.
2020-03-27 12:33:54 +01:00
Andreas Hocevar
f89b32de66 Merge pull request #10802 from MoonE/apidoc-add-default-export-enums
Apidoc add default-exported enums
2020-03-27 12:07:12 +01:00
Andreas Hocevar
f24ecf7b2c Merge pull request #10805 from regileeso/master
make ImageSourceEventType available for consumers
2020-03-27 11:35:30 +01:00
Andreas Hocevar
0366bca7c1 Merge pull request #10822 from lysek/master
parsing color from IconStyle in KML files
2020-03-27 11:31:49 +01:00
Andreas Hocevar
597e3a6bca Merge pull request #10848 from horsenit/master
Speed up Overlay element positioning using CSS translate()
2020-03-27 10:08:21 +01:00
horsenit
03ea8911f6 Fix type checking for IE9 style.msTransform 2020-03-27 03:03:21 -04:00
horsenit
83a5cd63c6 Speed up Overlay element positioning using CSS translate() 2020-03-27 02:26:01 -04:00
Andreas Hocevar
2d8782b1da Merge pull request #9590 from mloskot/ml/wmts-augment-tms-extent
Calculate tile grid extent from extent of bottom-level tile matrix
2020-03-26 23:23:54 +01:00
Andreas Hocevar
f50ae44150 Merge pull request #10845 from gedaiu/master
Fix createHitDetectionImageData error for features with no size
2020-03-26 23:20:43 +01:00
Szabo Bogdan
6aa398cbec Fix hit detection for images with missing size 2020-03-26 21:23:23 +01:00
Szabo Bogdan
fbe7b0bd78 Fix test typo 2020-03-26 21:22:08 +01:00
Mateusz Łoskot
98e8bec370 Calculate tile grid extent from extent of bottom-level tile matrix
Prefers extent derived from the tile matrix set in the capabilities
over default projection extent.
2020-03-26 19:17:32 +01:00
Andreas Hocevar
8f46bb563b Merge pull request #10842 from mike-000/patch-8
Fix custom symbol example short description
2020-03-25 14:36:01 +01:00
mike-000
c3d9ac6265 Fix description 2020-03-25 12:55:57 +00:00
Andreas Hocevar
60dd85fa08 Merge pull request #10828 from ahocevar/offscreen-canvas
Offscreen canvas example
2020-03-24 21:45:06 +01:00
Andreas Hocevar
d70b3aa3d5 Move catch-up logic to main thread
This avoids requestAnimationFrame in the worker.
2020-03-24 12:14:31 +01:00
Andreas Hocevar
576f50331b Add attribution 2020-03-23 20:30:58 +01:00
Andreas Hocevar
5113d70701 Rename example 2020-03-23 19:37:13 +01:00
Andreas Hocevar
0e1af6836f Example cleanup 2020-03-23 12:47:27 +01:00
Andreas Hocevar
828becf68e Position rotate control in the bottom left 2020-03-23 12:47:26 +01:00
Andreas Hocevar
941df3b270 Fix issues with TypeScript's built-in webworker lib 2020-03-23 12:47:26 +01:00
Andreas Hocevar
28f390828d Use same data as in mapbox-style example 2020-03-23 12:47:26 +01:00
Andreas Hocevar
ade9ac8857 Make mapbox-style example fullscreen on demand 2020-03-23 12:47:25 +01:00
Andreas Hocevar
bc1be50cbc Add worker support to examples 2020-03-23 12:47:25 +01:00
Andreas Hocevar
30ac91c4ae Simpler feature check 2020-03-23 12:47:25 +01:00
Andreas Hocevar
b9bfe45d86 Update ol-mapbox-style 2020-03-23 12:47:25 +01:00
Andreas Hocevar
3f7f999db0 Avoid try/catch, DOM and workers 2020-03-23 12:46:24 +01:00
Andreas Hocevar
6dcc54bfb8 'action' instead of 'type' as message identifier 2020-03-23 12:46:24 +01:00
Andreas Hocevar
f80c175263 Do not transform rotated views 2020-03-23 12:46:23 +01:00
Andreas Hocevar
3217bf1316 Add style handling 2020-03-23 12:46:23 +01:00
Andreas Hocevar
10c3330580 Use correct transorms at the right time 2020-03-23 12:46:23 +01:00
Andreas Hocevar
06f6ba13c8 Make font loading work in workers 2020-03-23 12:46:22 +01:00
Andreas Hocevar
bb1ca76bcc Make Executor work in workers 2020-03-23 12:46:22 +01:00
Andreas Hocevar
a93edb338b Instant UI feedback 2020-03-23 12:46:21 +01:00
Andreas Hocevar
56edbb2d73 Make createTransformToString a standalone function 2020-03-23 12:46:21 +01:00
Andreas Hocevar
3f5022630b Create a basic example for OffscreenCanvas rendering 2020-03-23 12:46:20 +01:00
Andreas Hocevar
8b76f52652 Make createTransformString work in non-window context 2020-03-23 12:46:20 +01:00
Andreas Hocevar
717b8ad0cf Make createCanvasContext2D work in non-window context 2020-03-23 12:46:19 +01:00
Andreas Hocevar
f896d9fb03 Move tile priority function to the TileQueue module 2020-03-23 12:46:18 +01:00
Andreas Hocevar
3944a5a038 Make DEVICE_PIXEL_RATIO work in non-window context 2020-03-23 12:46:18 +01:00
Andreas Hocevar
c7f2399e7f Merge pull request #10837 from openlayers/dependabot/npm_and_yarn/ol-mapbox-style-6.1.0
Bump ol-mapbox-style from 6.0.1 to 6.1.0
2020-03-23 11:48:01 +01:00
Andreas Hocevar
306a773e61 Merge pull request #10836 from openlayers/dependabot/npm_and_yarn/coveralls-3.0.11
Bump coveralls from 3.0.9 to 3.0.11
2020-03-23 11:24:05 +01:00
Andreas Hocevar
6e4351f119 Merge pull request #10835 from openlayers/dependabot/npm_and_yarn/babel/preset-env-7.9.0
Bump @babel/preset-env from 7.8.7 to 7.9.0
2020-03-23 11:04:38 +01:00
Andreas Hocevar
7c23c501c3 Merge pull request #10834 from openlayers/dependabot/npm_and_yarn/rollup-2.1.0
Bump rollup from 1.32.1 to 2.1.0
2020-03-23 11:03:41 +01:00
Andreas Hocevar
98ddf7a147 Merge pull request #10833 from openlayers/dependabot/npm_and_yarn/fs-extra-9.0.0
Bump fs-extra from 8.1.0 to 9.0.0
2020-03-23 11:00:21 +01:00
Andreas Hocevar
6969ee6275 Merge pull request #10832 from openlayers/dependabot/npm_and_yarn/babel/core-7.9.0
Bump @babel/core from 7.8.7 to 7.9.0
2020-03-23 10:58:32 +01:00
Andreas Hocevar
1331131e04 Merge pull request #10831 from openlayers/dependabot/npm_and_yarn/babel-loader-8.1.0
Bump babel-loader from 8.0.6 to 8.1.0
2020-03-23 10:44:09 +01:00
dependabot-preview[bot]
b70c9a70f8 Bump ol-mapbox-style from 6.0.1 to 6.1.0
Bumps [ol-mapbox-style](https://github.com/openlayers/ol-mapbox-style) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/openlayers/ol-mapbox-style/releases)
- [Changelog](https://github.com/openlayers/ol-mapbox-style/blob/master/CHANGELOG.md)
- [Commits](https://github.com/openlayers/ol-mapbox-style/compare/v6.0.1...v6.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 09:44:03 +00:00
Andreas Hocevar
0fdfed439c Merge pull request #10830 from openlayers/dependabot/npm_and_yarn/mocha-7.1.1
Bump mocha from 7.1.0 to 7.1.1
2020-03-23 10:41:41 +01:00
dependabot-preview[bot]
3512638900 Bump mocha from 7.1.0 to 7.1.1
Bumps [mocha](https://github.com/mochajs/mocha) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v7.1.0...v7.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 09:18:35 +00:00
Andreas Hocevar
124d00daf2 Merge pull request #10829 from openlayers/dependabot/npm_and_yarn/marked-0.8.2
Bump marked from 0.8.0 to 0.8.2
2020-03-23 10:16:07 +01:00
Jiri Lysek
2b6e767840 encoding color into KML 2020-03-23 10:10:12 +01:00
dependabot-preview[bot]
d61da37191 Bump coveralls from 3.0.9 to 3.0.11
Bumps [coveralls](https://github.com/nickmerwin/node-coveralls) from 3.0.9 to 3.0.11.
- [Release notes](https://github.com/nickmerwin/node-coveralls/releases)
- [Commits](https://github.com/nickmerwin/node-coveralls/compare/3.0.9...3.0.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 09:01:54 +00:00
dependabot-preview[bot]
7dd6bb7c1b Bump @babel/preset-env from 7.8.7 to 7.9.0
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.8.7 to 7.9.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.7...v7.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 09:01:12 +00:00
dependabot-preview[bot]
274135db2e Bump rollup from 1.32.1 to 2.1.0
Bumps [rollup](https://github.com/rollup/rollup) from 1.32.1 to 2.1.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v1.32.1...v2.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 09:00:00 +00:00
dependabot-preview[bot]
5ab7f5dacf Bump fs-extra from 8.1.0 to 9.0.0
Bumps [fs-extra](https://github.com/jprichardson/node-fs-extra) from 8.1.0 to 9.0.0.
- [Release notes](https://github.com/jprichardson/node-fs-extra/releases)
- [Changelog](https://github.com/jprichardson/node-fs-extra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jprichardson/node-fs-extra/compare/8.1.0...9.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 08:59:43 +00:00
dependabot-preview[bot]
d8b2e452d5 Bump @babel/core from 7.8.7 to 7.9.0
Bumps [@babel/core](https://github.com/babel/babel) from 7.8.7 to 7.9.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.7...v7.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 08:58:20 +00:00
dependabot-preview[bot]
bbc8870832 Bump babel-loader from 8.0.6 to 8.1.0
Bumps [babel-loader](https://github.com/babel/babel-loader) from 8.0.6 to 8.1.0.
- [Release notes](https://github.com/babel/babel-loader/releases)
- [Changelog](https://github.com/babel/babel-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel-loader/compare/v8.0.6...v8.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 08:57:18 +00:00
dependabot-preview[bot]
52d840b35d Bump marked from 0.8.0 to 0.8.2
Bumps [marked](https://github.com/markedjs/marked) from 0.8.0 to 0.8.2.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Commits](https://github.com/markedjs/marked/compare/v0.8.0...v0.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 08:55:33 +00:00
Maximilian Krög
24f9e1c6ac Update comment for the IconImage replaceColor_ method 2020-03-22 13:29:29 +01:00
Maximilian Krög
fbb0364ea5 Make Icon's color attribute work in ie11 2020-03-21 00:33:41 +01:00
Maximilian Krög
f942c482d8 Svg icon needs imgSize to display in ie11 2020-03-21 00:15:49 +01:00
Jiri Lysek
7bf44078e1 fixed type comment 2020-03-19 13:32:02 +01:00
Jiri Lysek
d5b3d27e62 parsing color from IconStyle in KML files 2020-03-19 13:02:53 +01:00
Marc Jansen
3674ec5481 Merge pull request #10816 from marcjansen/npm-funding-field
Add 'funding' field to `package.json`
2020-03-18 10:51:45 +01:00
Marc Jansen
0af85f7396 Add 'funding' field to package.json
This was introduced to `npm` recently and allows users of the ol
package to e.g. type `npm fund ol` and our opencollective page
opens in a browser. Just typing `npm fund` in a npm package will list
the funding options of the dependencies of the current project.
2020-03-18 10:15:31 +01:00
Tim Schaub
9fe84e4dba Merge pull request #10813 from tschaub/sponsor
Add sponsors section to the readme
2020-03-17 05:18:03 -06:00
Tim Schaub
dca694ccc9 Add sponsors section to the readme 2020-03-16 17:10:49 -06:00
Andreas Hocevar
ca6288a800 Merge pull request #10811 from openlayers/dependabot/npm_and_yarn/sinon-9.0.1
Bump sinon from 9.0.0 to 9.0.1
2020-03-16 18:47:32 +01:00
Andreas Hocevar
d85b5065f5 Merge pull request #10810 from openlayers/dependabot/npm_and_yarn/rollup-plugin-terser-5.3.0
Bump rollup-plugin-terser from 5.2.0 to 5.3.0
2020-03-16 18:47:03 +01:00
Andreas Hocevar
bb0c6635a2 Merge pull request #10809 from openlayers/dependabot/npm_and_yarn/yargs-15.3.1
Bump yargs from 15.3.0 to 15.3.1
2020-03-16 18:46:29 +01:00
dependabot-preview[bot]
21b2d8aa48 Bump sinon from 9.0.0 to 9.0.1
Bumps [sinon](https://github.com/sinonjs/sinon) from 9.0.0 to 9.0.1.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v9.0.0...v9.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-16 08:21:07 +00:00
dependabot-preview[bot]
7bc7affccc Bump rollup-plugin-terser from 5.2.0 to 5.3.0
Bumps [rollup-plugin-terser](https://github.com/TrySound/rollup-plugin-terser) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/TrySound/rollup-plugin-terser/releases)
- [Commits](https://github.com/TrySound/rollup-plugin-terser/compare/v5.2.0...v5.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-16 08:20:12 +00:00
dependabot-preview[bot]
47ce1490f8 Bump yargs from 15.3.0 to 15.3.1
Bumps [yargs](https://github.com/yargs/yargs) from 15.3.0 to 15.3.1.
- [Release notes](https://github.com/yargs/yargs/releases)
- [Changelog](https://github.com/yargs/yargs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/yargs/compare/v15.3.0...v15.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-16 08:19:01 +00:00
Frédéric Junod
e5131f811f Merge pull request #10806 from openlayers/dependabot/npm_and_yarn/acorn-6.4.1
[Security] Bump acorn from 6.1.1 to 6.4.1
2020-03-14 07:28:36 +01:00
dependabot-preview[bot]
3c1ad1fc1d [Security] Bump acorn from 6.1.1 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.1.1 to 6.4.1. **This update includes a security fix.**
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.1.1...6.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-13 21:23:16 +00:00
regileeso
406c38403b make ImageSourceEventType available for consumers 2020-03-13 11:36:20 +00:00
Edward Nash
859bf338a2 Use Object for options to Overlay panIntoView
* animation and margin encapsulated in a single object to allow
   easier extension in future

 * Constructor options extended to allow single object for
   autoPan; separate options still allowed but deprecated

 * Protected fields for animation and margin replaced with single
   field
2020-03-13 10:12:14 +01:00
Maximilian Krög
873cccc4f3 Add default exported enums to apidoc 2020-03-12 22:29:46 +01:00
Maximilian Krög
f2477622c3 Remove redundant check if doclet kind is typedef 2020-03-12 22:29:34 +01:00
Maximilian Krög
058ca59233 Also correctly detect default exports without an identifier 2020-03-12 21:36:19 +01:00
Edward Nash
022caae848 Document default margin in Overlay.panIntoView 2020-03-12 09:37:40 +01:00
Edward Nash
092a199757 Make Overlay.panIntoView an API method
* Add parameters for custom animation parameters and margin

 * Add protected wrapper method for previous autoPan functionality

See #10741
2020-03-12 08:57:32 +01:00
Andreas Hocevar
0b7b979c89 Merge pull request #10474 from mike-000/patch-2
Fix for undefined source in Image layer
2020-03-11 18:05:29 +01:00
mike-000
4ca966bd92 show labels in wrapped worlds
test labels in wrapped world
2020-03-11 16:06:31 +00:00
Andreas Hocevar
f448d7179a Merge pull request #10785 from ahocevar/zoomify-retina
Detect Zoomify server-side retina tiles
2020-03-11 11:05:57 +01:00
Tim Schaub
7299c0dd04 Merge pull request #10787 from mike-000/patch-7
Improved projection extent in the "Reprojection with EPSG.io Search" example
2020-03-10 16:56:08 -06:00
Andreas Hocevar
2f35a3be75 Merge pull request #10792 from flexjoly/native-javascript-eventListener.handleEvent
Add support for EventListener Object
2020-03-10 19:17:22 +01:00
Andreas Hocevar
5f283496ed Merge pull request #10777 from ahocevar/geolocation-example
Keep the render loop running during simulation
2020-03-10 16:11:14 +01:00
Andreas Hocevar
e59aa02a15 Remove duplicated for loop 2020-03-10 14:20:20 +01:00
Andreas Hocevar
4fa454f2b3 Fix types 2020-03-10 14:20:12 +01:00
Andreas Hocevar
ed10ac168b Merge pull request #10791 from sosmo/fix-ios-pointermove-2
iOS 12 touchmove: Prevent touchmove event default when no preceding pointer event
2020-03-10 13:40:59 +01:00
Andreas Hocevar
5e51e397bb Merge pull request #10786 from ahocevar/resolve-contraints-on-updatesize
Resolve constraints when updating size
2020-03-10 13:05:29 +01:00
Lydia de Jongh
e099257461 Add support for EventListener Object
See: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

Support for native javascript eventListener.handleEvent()

Typedef not correct yet.
2020-03-10 12:51:05 +01:00
Sampo Osmonen
dd480feda1 Prevent touchmove event default when no preceding pointer event
Prevents zooming the page instead of the map on the first interaction
2020-03-10 12:56:15 +02:00
Andreas Hocevar
9f76ec197a Merge pull request #10788 from sosmo/fix-ios-pointermove
Add safeguard to handleTouchMove
2020-03-10 09:49:42 +01:00
Andreas Hocevar
a1386e3a1f Update comment 2020-03-10 09:36:10 +01:00
Olivier Guyot
7b4e522e8f Merge pull request #10722 from jellyedwards/master
fix: handle layer clear event in case clear(true) called
2020-03-10 09:27:15 +01:00
John Leonard
e6a2d4b235 fix: handle layer clear event in case clear(true) called
and individual delete feature events aren't generated
2020-03-09 18:36:12 +00:00
Sampo Osmonen
85d84a0c40 Add safeguard to handleTouchMove 2020-03-09 19:37:21 +02:00
mike-000
7c22b5a238 Improve the calculation of projection extent
fix quotes
2020-03-09 16:09:07 +00:00
mike-000
230c6b011e Improve the calculation of projection extent
Add show graticule option
2020-03-09 15:24:01 +00:00
Andreas Hocevar
c5fd013e31 Resolve constraints when updating size 2020-03-09 16:20:21 +01:00
mike-000
6019a61cca Add show graticule option 2020-03-09 14:54:24 +00:00
dependabot-preview[bot]
831c5f8c69 Merge pull request #10783 from openlayers/dependabot/npm_and_yarn/babel/preset-env-7.8.7 2020-03-09 14:53:23 +00:00
dependabot-preview[bot]
ed748bf173 Merge pull request #10780 from openlayers/dependabot/npm_and_yarn/babel/core-7.8.7 2020-03-09 14:33:09 +00:00
dependabot-preview[bot]
51b4ee3137 Merge pull request #10784 from openlayers/dependabot/npm_and_yarn/rollup-plugin-babel-4.4.0 2020-03-09 14:32:29 +00:00
Andreas Hocevar
686b4dbdc8 Merge pull request #10723 from mike-000/patch-6
Improve the extent transforms used by Graticule and handle extents crossing the dateline
2020-03-09 15:26:52 +01:00
dependabot-preview[bot]
c1f40b4d98 Merge pull request #10782 from openlayers/dependabot/npm_and_yarn/webpack-4.42.0 2020-03-09 14:26:26 +00:00
Andreas Hocevar
5424e3eae2 Keep the render loop running during simulation 2020-03-09 15:25:49 +01:00
Andreas Hocevar
ad476f6086 Detect Zoomify server-side retina tiles 2020-03-09 15:22:43 +01:00
dependabot-preview[bot]
9ef220d5de Merge pull request #10781 from openlayers/dependabot/npm_and_yarn/yargs-15.3.0 2020-03-09 14:04:09 +00:00
dependabot-preview[bot]
d4b76299e7 Merge pull request #10779 from openlayers/dependabot/npm_and_yarn/rollup-1.32.1 2020-03-09 14:02:32 +00:00
dependabot-preview[bot]
2123d19926 Bump rollup-plugin-babel from 4.3.3 to 4.4.0
Bumps [rollup-plugin-babel](https://github.com/rollup/rollup-plugin-babel) from 4.3.3 to 4.4.0.
- [Release notes](https://github.com/rollup/rollup-plugin-babel/releases)
- [Changelog](https://github.com/rollup/rollup-plugin-babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup-plugin-babel/compare/v4.3.3...v4.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:38:41 +00:00
dependabot-preview[bot]
0613444f12 Bump @babel/preset-env from 7.8.6 to 7.8.7
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.8.6 to 7.8.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.6...v7.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:37:51 +00:00
dependabot-preview[bot]
80c36b298d Bump webpack from 4.41.6 to 4.42.0
Bumps [webpack](https://github.com/webpack/webpack) from 4.41.6 to 4.42.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.41.6...v4.42.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:37:17 +00:00
dependabot-preview[bot]
365e14148a Bump yargs from 15.1.0 to 15.3.0
Bumps [yargs](https://github.com/yargs/yargs) from 15.1.0 to 15.3.0.
- [Release notes](https://github.com/yargs/yargs/releases)
- [Changelog](https://github.com/yargs/yargs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/yargs/compare/v15.1.0...v15.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:36:16 +00:00
dependabot-preview[bot]
a8dcadbd99 Bump @babel/core from 7.8.6 to 7.8.7
Bumps [@babel/core](https://github.com/babel/babel) from 7.8.6 to 7.8.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.6...v7.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:35:54 +00:00
dependabot-preview[bot]
601023acf4 Bump rollup from 1.32.0 to 1.32.1
Bumps [rollup](https://github.com/rollup/rollup) from 1.32.0 to 1.32.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v1.32.0...v1.32.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 08:34:28 +00:00
Andreas Hocevar
1d4744b730 Merge pull request #10744 from mike-000/patch-7
Ensure the Modify Features Test example opens at correct zoom
2020-03-08 23:44:43 +01:00
Andreas Hocevar
2d57e795e7 Merge pull request #10767 from mike-000/patch-8
Replace Bing layer with MapTiler in examples
2020-03-08 14:24:20 +01:00
Andreas Hocevar
8c3da1167c Merge pull request #10751 from MoonE/apidoc-sort-events
Sort events / observables in all cases
2020-03-07 23:25:22 +01:00
mike-000
9d0b139432 Ensure example opens at correct zoom
wrapX: false not needed for consistency with OL5
2020-03-05 17:41:33 +00:00
mike-000
408eac2524 Replace Bing layer with MapTiler 2020-03-05 15:27:18 +00:00
mike-000
737c30fedc Replace Bing layer with MapTiler 2020-03-05 15:25:48 +00:00
mike-000
c4d864ed45 Replace Bing layer with MapTiler 2020-03-05 15:21:11 +00:00
mike-000
315db526c9 Replace Bing layer with MapTiler 2020-03-05 15:17:34 +00:00
Tim Schaub
a34b22f1d9 Merge pull request #10763 from jumpinjackie/bug/fix-types
TypeScript: Fix inconsistent optionality in various APIs
2020-03-04 07:41:00 -07:00
Jackie Ng
6d16fe8405 Make arg2 of GeometryFunction also optional as it comes after an optional arg1 2020-03-05 01:01:03 +11:00
Jackie Ng
21fcb4621b Ensure consistent optionality for options.projection for all ImageSource-derived constructor options 2020-03-04 23:38:54 +11:00
Olivier Guyot
29387a2cbb Merge pull request #10758 from jahow/webgl-rotation-fix-attribute
Allow using feature attributes for symbol rotation in WebGL layers
2020-03-03 12:55:25 +01:00
Olivier Guyot
40d44db85e Shader Builder / use vertex context to parse the symbol rotation expression
Previously the expression was parsed in the fragment shader context, which
meant in case the expression used an attributes the resulting GLSL code
would be wrong.

Fragment shader context:
`float angle = v_heading; // we're using the varying: not OK`

Vertex shader context:
`float angle = a_heading; // we're using the attribute: OK`
2020-03-03 10:09:39 +01:00
Frédéric Junod
7a37231a87 Merge pull request #10755 from openlayers/dependabot/npm_and_yarn/rollup-1.32.0
Bump rollup from 1.31.1 to 1.32.0
2020-03-02 14:00:35 +01:00
Frédéric Junod
d2b26e198b Merge pull request #10754 from openlayers/dependabot/npm_and_yarn/babel/preset-env-7.8.6
Bump @babel/preset-env from 7.8.4 to 7.8.6
2020-03-02 14:00:04 +01:00
Frédéric Junod
24b252bb1d Merge pull request #10753 from openlayers/dependabot/npm_and_yarn/mocha-7.1.0
Bump mocha from 7.0.1 to 7.1.0
2020-03-02 13:59:39 +01:00
Frédéric Junod
6384b83cc1 Merge pull request #10752 from openlayers/dependabot/npm_and_yarn/babel/core-7.8.6
Bump @babel/core from 7.8.4 to 7.8.6
2020-03-02 13:59:00 +01:00
dependabot-preview[bot]
88f958286b Bump rollup from 1.31.1 to 1.32.0
Bumps [rollup](https://github.com/rollup/rollup) from 1.31.1 to 1.32.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v1.31.1...v1.32.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-02 08:45:52 +00:00
dependabot-preview[bot]
f59f4e2d56 Bump @babel/preset-env from 7.8.4 to 7.8.6
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.8.4 to 7.8.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.4...v7.8.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-02 08:44:52 +00:00
dependabot-preview[bot]
9f6b021000 Bump mocha from 7.0.1 to 7.1.0
Bumps [mocha](https://github.com/mochajs/mocha) from 7.0.1 to 7.1.0.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v7.0.1...v7.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-02 08:44:00 +00:00
dependabot-preview[bot]
3014df1677 Bump @babel/core from 7.8.4 to 7.8.6
Bumps [@babel/core](https://github.com/babel/babel) from 7.8.4 to 7.8.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.4...v7.8.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-02 08:42:59 +00:00
Maximilian Krög
1d7d7a7eef Sort events / observables in all cases
Right now this only changes the order of events of the UrlTile class.
2020-03-01 00:25:11 +01:00
Tim Schaub
457e7216b4 Merge pull request #10748 from mike-000/patch-8
Fix "Cannot read property 'anchor' of undefined" in ol/View
2020-02-29 07:18:03 -07:00
mike-000
ce6d7bd55c Fix "Cannot read property 'anchor' of undefined"
replace unnecessary filter with for loop and break
2020-02-29 10:12:48 +00:00
Andreas Hocevar
730a0dbe09 Merge pull request #10746 from MoonE/apidoc-fix-windows-build
Fix building apidoc on windows
2020-02-28 22:47:48 +01:00
mike-000
5ba978311e Fix "Cannot read property 'anchor' of undefined" 2020-02-28 21:47:22 +00:00
Maximilian Krög
d28be3c160 Fix building apidoc on windows 2020-02-28 21:44:06 +01:00
Andreas Hocevar
6370175b28 Merge pull request #10720 from MoonE/apidoc-better-search
Apidoc better search
2020-02-28 14:27:20 +01:00
Maximilian Krög
e484eca1a1 Some more cleanup
No need to sort beforehand and therefore sorting can be done at last too.
Also forEach is just fine, no need for underscore.

This changes the navigation default order for modules to be after classes
when the name is the same.
2020-02-27 23:47:22 +01:00
Maximilian Krög
bc8499472c Current item may be undefined
Worked fine before, but better safe than sorry.
2020-02-27 22:58:07 +01:00
Maximilian Krög
47ed2963c4 Default exported classes have same prettyname as modules 2020-02-27 22:57:55 +01:00
mike-000
203f557883 Ensure example opens at correct zoom
Set multiWorld: true so view opens at zoom 2 on wide displays
Set wrapX false on source
2020-02-27 20:53:58 +00:00
mike-000
b8e34ef5bf rename some variables and add comments 2020-02-27 19:12:40 +00:00
Andreas Hocevar
0fd336daa5 Merge pull request #10743 from ahocevar/ignore-cache-size-when-too-small
Ignore user provided tile cache size when too small
2020-02-27 14:52:33 +01:00
Andreas Hocevar
e235ad0708 Merge pull request #10736 from M393/clustersource-setsource
Allow cluster source to unlisten from its source
2020-02-27 14:00:38 +01:00
Andreas Hocevar
a072e3acea Ignore user provided tile cache size when too small 2020-02-27 13:41:21 +01:00
mike-000
ac2b58c554 test using extra stops for extent transform
correct coordinate order
2020-02-27 12:19:31 +00:00
mike-000
633396e7df test using extra stops for extent transform 2020-02-27 12:12:57 +00:00
Maximilian Kroeg
ba84cfad61 Do requeseted changes 3/3 2020-02-27 10:28:26 +01:00
Maximilian Kroeg
f18b78d2da Do requested changes 2/3 to cluster source 2020-02-27 10:01:20 +01:00
Andreas Hocevar
df1d0ac4a0 Merge pull request #10739 from ahocevar/timeout-typo
Fix typo in trackpad timeout
2020-02-27 07:49:09 +01:00
Tim Schaub
a651667f24 Merge pull request #10740 from matthias-ccri/tabindex
Document tabindex behavior for MouseWheelZoom and DragPan
2020-02-26 22:45:00 -07:00
Matthias
b695320dcf Update DragPan.js 2020-02-26 20:37:51 -05:00
Matthias
10a624db3c Update MouseWheelZoom.js 2020-02-26 20:36:07 -05:00
mike-000
591e5ce01b More validation. Handle voids in some projections.
Handle NaN latitude transform results at void centers of some projections (e.g. Pole LAEA).
Clamp latitudes to not go beyond the poles when calculating intervals.
Further improve polar projections by checking if extent contains max and min intersection coordinates when calculating max and min.
2020-02-26 22:17:49 +00:00
Andreas Hocevar
e9227a9bc1 Fix typo in trackpad timeout 2020-02-26 19:27:20 +01:00
Andreas Hocevar
59f14eaa2e Merge pull request #10738 from ahocevar/textbackground-declutter
Fix text background decluttering
2020-02-26 14:47:25 +01:00
Andreas Hocevar
a03cfa35ed Store copies of background points for decluttering 2020-02-26 13:30:00 +01:00
mike-000
adcf57ef20 Better validation to handle polar projections
For some projections (e.g. polar) the maximum or minimum values may be at the center.
To improve the display for polar projections take validated center values into account when calculating max and min.
2020-02-25 13:47:02 +00:00
Maximilian Kroeg
b25fc6741e Add tests for ol/source/Cluster~Cluster#setSource 2020-02-25 11:15:56 +01:00
Maximilian Kroeg
01b3f9a97b Allow cluster source to unlisten from its source
This adds a setSource method to change or remove the cluster source's source.
2020-02-25 10:33:02 +01:00
mike-000
9039e2629b fix trailing space 2020-02-24 21:57:22 +00:00
mike-000
737f3a5066 Handle view projections crossing dateline
Use custom toLonLat transform to return wrapped longitudes for extents if view projection crosses the dateline.
Enhance the validation for center and extents to avoid proj4 errors.
2020-02-24 21:53:53 +00:00
Andreas Hocevar
e02ede8f76 Merge pull request #10725 from openlayers/dependabot/npm_and_yarn/elm-pep-1.0.6
Bump elm-pep from 1.0.4 to 1.0.6
2020-02-24 11:45:51 +01:00
Frédéric Junod
58ef1ab166 Merge pull request #10726 from openlayers/dependabot/npm_and_yarn/sinon-9.0.0
Bump sinon from 8.1.1 to 9.0.0
2020-02-24 09:17:30 +01:00
dependabot-preview[bot]
89b5adc601 Bump sinon from 8.1.1 to 9.0.0
Bumps [sinon](https://github.com/sinonjs/sinon) from 8.1.1 to 9.0.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v8.1.1...v9.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-24 08:07:24 +00:00
dependabot-preview[bot]
c987b1f1b0 Bump elm-pep from 1.0.4 to 1.0.6
Bumps [elm-pep](https://github.com/ahocevar/elm-pep) from 1.0.4 to 1.0.6.
- [Release notes](https://github.com/ahocevar/elm-pep/releases)
- [Commits](https://github.com/ahocevar/elm-pep/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-24 08:06:23 +00:00
mike-000
6ae6d0b835 Optional extra stops to refine extent transforms
Add optional extra stops to refine some non-parallel transforms

Refine extent transforms use by Gratucule by using 32 points (8 per side) instead of the standard corners only transform
Update Graticule class description with current limitations

Correct projection extent in Mollweide example and revise opening zoom level correspondingly
2020-02-23 19:13:06 +00:00
Maximilian Krög
c2505f938e Remove measuring code 2020-02-22 14:30:44 +01:00
Maximilian Krög
6b9a35b7b9 Always sort top level matches before member matches 2020-02-22 14:30:25 +01:00
Maximilian Krög
df8c0f3e6f Avoid deprecated jquery :eq selector 2020-02-22 01:07:43 +01:00
Maximilian Krög
bf2a7bd21a Allow toggel on whole title, add toggle transition 2020-02-22 01:07:41 +01:00
Maximilian Krög
ee8ec6f03a Shorter css paths in navigation 2020-02-21 22:58:05 +01:00
Maximilian Krög
b46b250d75 On toggle when searching show unfiltered instead of hiding all 2020-02-21 22:58:05 +01:00
Maximilian Krög
2dec296aae Use css to show / hide items; track matched items
... to improve search speed.

Instead of marking all items as hidden, and then marking the matched
ones again, this keeps track of all matched items and only
removes those that no longer match and adds those that previously did
not match.
2020-02-21 22:57:53 +01:00
Maximilian Krög
646ecfd405 Weight function prefer classes over modules 2020-02-21 22:56:54 +01:00
Maximilian Krög
99d9a9ff86 Use strict mode 2020-02-21 22:56:54 +01:00
Maximilian Krög
15beb1f2c6 Put more weight on the base name 2020-02-21 22:56:53 +01:00
Maximilian Krög
b613e8e77f Fix regex dot escape 2020-02-21 22:56:53 +01:00
Maximilian Krög
ccafb4b91d Improved weight function.
++++ Full match from start to end
+++  Full match between word boundaries
++   Begin matches at word boundary, multiple matches are better
+    Matches somewhere

Classes with (multiple) members matching at the beginning are
weighted higher.
2020-02-21 22:56:51 +01:00
Maximilian Krög
1b4ed08bc5 Indent line-wrapped class names 2020-02-21 22:55:32 +01:00
Maximilian Krög
cc561dab8e Allow word wrap before '.' and '~' in class names 2020-02-21 22:55:32 +01:00
Maximilian Krög
8b857eed26 Change prettyname of classes
Now also includes the class name if it is different than its module name.
`ol/source/Vector` -> `ol/source/Vector~VectorSource`.
2020-02-21 22:55:32 +01:00
Maximilian Krög
7640bcd163 Only match the displayed name of items when searching
Currently the search term is matched against the longname of members.
Because of this most members are matched when searching for a
class / module and also searching for 'mod' matches everything as
all longnames start with 'module:'
2020-02-21 22:55:32 +01:00
Maximilian Krög
d3b9b25429 Search if the search input is not empty after page loads
Firefox remembers input on the same page if a normal reload is performed.
In this case the results for the search term should be shown automatically.
2020-02-21 22:55:32 +01:00
Maximilian Krög
f7871d6103 Store search data in lowercase and compare in lowercase
This way we can do the search case-sensitive after only converting
the search term to lowercase.
2020-02-21 22:55:32 +01:00
Maximilian Krög
b9455bfad9 Remove unnecessary / duplicate code. 2020-02-21 22:55:31 +01:00
Maximilian Krög
2b8582fcad Catch errors when search term is an invalid regular expression
On error search escape special characters, with only '.' matching
any characters.
2020-02-21 22:50:57 +01:00
Maximilian Krög
d56513b722 Add code to measure search function speed 2020-02-21 22:50:57 +01:00
Maximilian Krög
99ecce2a87 Provide the searchTerm as argument to doSearch function 2020-02-21 22:50:57 +01:00
Maximilian Krög
b919074aa3 Skip searches when typing fast / slow cpu. 2020-02-21 22:50:57 +01:00
Maximilian Krög
6187118166 Hide member-lists, show current item when clearing input 2020-02-21 22:50:57 +01:00
Maximilian Krög
f5a996a64e Highlight current anchor with css instead of js.
The `:target` selector is supported by all browsers.
2020-02-21 22:50:57 +01:00
Andreas Hocevar
05d3386995 Merge pull request #10715 from mike-000/patch-8
Fix disappearing graticule labels when rotation returns to 0
2020-02-20 21:21:17 +01:00
mike-000
e731574e06 Fix disappearing labels when rotation returns to 0 2020-02-20 17:49:05 +00:00
Andreas Hocevar
c20e5bf58a Merge pull request #10713 from mike-000/patch-7
Draw graticule labels in a postrender function
2020-02-20 17:10:08 +01:00
mike-000
59142f800c Draw labels in a postrender function 2020-02-20 15:50:10 +00:00
mike-000
bc2c49165e Draw labels in a postrender function 2020-02-20 15:39:08 +00:00
mike-000
00275f1a67 Draw labels in a postrender function 2020-02-20 15:25:32 +00:00
mike-000
3558dbe235 Draw labels in a postrender function 2020-02-20 14:43:48 +00:00
mike-000
a74d33dafb Draw labels in a postrender function 2020-02-20 14:12:37 +00:00
mike-000
c28793ae04 Draw labels in a postrender function
Position labels relative to the viewport when view is rotated
2020-02-20 13:31:41 +00:00
Andreas Hocevar
4a11bcccbb Merge pull request #10711 from ahocevar/optional-args
Make sure that optional args are typed accordingly
2020-02-20 12:50:48 +01:00
Andreas Hocevar
608d515f1f Make sure that optional args are typed accordingly 2020-02-20 12:39:31 +01:00
Andreas Hocevar
ef63644211 Merge pull request #10710 from ahocevar/fix-stylefunction-type
Fix stylefunction return type
2020-02-20 12:35:52 +01:00
Andreas Hocevar
6b9791eeed Fix stylefunction return type 2020-02-20 11:47:42 +01:00
Andreas Hocevar
d6eb66f083 Merge pull request #10709 from ahocevar/stylefunction-type
Fix type and documentation of style function
2020-02-20 11:25:43 +01:00
Andreas Hocevar
13713bab51 Fix type and documentation of style function 2020-02-20 11:09:12 +01:00
Andreas Hocevar
74d26f04fa Merge pull request #10708 from ahocevar/falsey-select-style
Handle Select interactions with falsey select style
2020-02-20 08:46:44 +01:00
Tim Schaub
f154a854c3 Merge pull request #10707 from AugustusKling/circle-ci-test
Get default projection for overview map from main map.
2020-02-19 19:38:25 -07:00
Andreas Hocevar
c73034fe7d Handle Select interactions with falsey select style 2020-02-20 00:36:33 +01:00
Augustus Kling
da7f51c085 Get default projection for overview map from main map.
Changes OverviewMap such that it will use whatever projection the
hosting map is using unless a view was specified explicitly.

Fixes #2998 #5188 #10670
2020-02-19 23:10:15 +01:00
Andreas Hocevar
3a92a8091a Merge pull request #10699 from ahocevar/select
Make Select interaction work when there are multiple instances
2020-02-19 15:33:00 +01:00
Tim Schaub
d7aa47eedc Merge pull request #10694 from M393/image-opacity
Draw image with configured opacity
2020-02-19 06:59:33 -07:00
Andreas Hocevar
cac903c837 Merge pull request #10703 from ahocevar/tests
CI and test fixes
2020-02-19 14:55:31 +01:00
Andreas Hocevar
bdeab6ab49 Update coverage reporter 2020-02-19 14:23:29 +01:00
Andreas Hocevar
2c213f805c Try a different cicleci image 2020-02-19 14:23:06 +01:00
Andreas Hocevar
502bb8a169 Merge pull request #10698 from ahocevar/shadow-root
Shadow root
2020-02-19 13:45:45 +01:00
Andreas Hocevar
f98f66c529 Make Select interaction work when there are multiple instances 2020-02-19 11:52:12 +01:00
Andreas Hocevar
575ef48b3a Merge pull request #10688 from ahocevar/generate-d-ts
Publish type definition files
2020-02-19 10:57:31 +01:00
Andreas Hocevar
7fa4b2cb24 Publish type definition files 2020-02-19 10:42:54 +01:00
Tim Schaub
341e482f30 Add rendering test for image style opacity 2020-02-18 18:31:57 -07:00
Andreas Hocevar
7fee85734a Add custom element example 2020-02-18 21:32:31 +01:00
Andreas Hocevar
b6abe036ce Make events work in shadow dom 2020-02-18 21:32:09 +01:00
Maximilian Krög
6f18350eda Add regression test for image opacity 2020-02-18 16:30:38 +01:00
Maximilian Krög
ab9d7cdc70 Draw image with configured opacity 2020-02-18 14:09:36 +01:00
Andreas Hocevar
5ea0b52ba8 Merge pull request #10691 from ahocevar/hitdetect-color-range
Do not exceed color range
2020-02-18 10:04:00 +01:00
Frédéric Junod
1481ec7d85 Merge pull request #10683 from fredj/fs_events
Dispatch enterfullscreen and leavefullscreen from the FullScreen control
2020-02-18 08:26:44 +01:00
Tim Schaub
7c394c6a1b Merge pull request #10676 from mike-000/patch-6
Document that overviewmap view must use same projection as main map
2020-02-17 20:17:22 -07:00
Andreas Hocevar
07b02fe947 Do not exceed color range 2020-02-17 21:58:45 +01:00
Andreas Hocevar
8f9552e78c Merge pull request #10678 from mike-000/patch-7
Add maxResolution option to ol/tilegrid.createXYZ() and ol/source/XYZ
2020-02-17 19:54:55 +01:00
mike-000
1416e30127 Add maxResolution option to createXYZ()
include maxResolution in options test
2020-02-17 18:20:50 +00:00
Andreas Hocevar
d5f249f0ef Merge pull request #10690 from mike-000/patch-8
Document minZoom and maxZoom options for all layers
2020-02-17 18:29:21 +01:00
Andreas Hocevar
eebb2cb9ae Merge pull request #10672 from ahocevar/mousewheel
Nicer mousewheel and trackpad zooming
2020-02-17 18:27:03 +01:00
mike-000
fa4fcf3886 add minZoom and maxZoom options 2020-02-17 16:59:40 +00:00
mike-000
4cf093ab75 add minZoom and maxZoom options 2020-02-17 16:58:46 +00:00
mike-000
c5885cc649 add minZoom and maxZoom options 2020-02-17 16:57:00 +00:00
mike-000
d0e439ee80 add minZoom and maxZoom options 2020-02-17 16:55:15 +00:00
mike-000
edb94af314 add minZoom and maxZoom options 2020-02-17 16:53:57 +00:00
mike-000
501546bc44 add minZoom and maxZoom options 2020-02-17 16:52:59 +00:00
mike-000
d102f561f9 add minZoom and maxZoom options 2020-02-17 16:52:12 +00:00
mike-000
265eb5421d add minZoom and maxZoom options 2020-02-17 16:51:08 +00:00
mike-000
fbaa4da153 add minZoom and maxZoom options 2020-02-17 16:49:47 +00:00
mike-000
3dc4e546bf add minZoom and maxZoom options 2020-02-17 16:47:55 +00:00
Frédéric Junod
3df7c4a1da Merge pull request #10687 from fredj/win_failing_img_test
Increase timeout in listenImage test
2020-02-17 15:42:03 +01:00
Frederic Junod
09689e547c Increase timeout in listenImage test
Fixes failing test with Chrome 80 on Windows 10
2020-02-17 13:27:23 +01:00
Olivier Guyot
bf38796ec7 Merge pull request #10684 from jellyedwards/master
perf: only do expensive reload when texture changes
2020-02-17 13:26:46 +01:00
Frédéric Junod
e81721cada Merge pull request #10680 from openlayers/dependabot/npm_and_yarn/terser-webpack-plugin-2.3.5
Bump terser-webpack-plugin from 2.3.4 to 2.3.5
2020-02-17 13:08:49 +01:00
Frédéric Junod
c4231a25e3 Merge pull request #10682 from openlayers/dependabot/npm_and_yarn/webpack-4.41.6
Bump webpack from 4.41.5 to 4.41.6
2020-02-17 11:31:37 +01:00
dependabot-preview[bot]
058d1c2e51 Bump webpack from 4.41.5 to 4.41.6
Bumps [webpack](https://github.com/webpack/webpack) from 4.41.5 to 4.41.6.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.41.5...v4.41.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-17 09:54:23 +00:00
Frédéric Junod
4b508185b3 Merge pull request #10681 from openlayers/dependabot/npm_and_yarn/webpack-cli-3.3.11
Bump webpack-cli from 3.3.10 to 3.3.11
2020-02-17 10:52:17 +01:00
Frédéric Junod
14e22e6bc9 Merge pull request #10679 from openlayers/dependabot/npm_and_yarn/rollup-1.31.1
Bump rollup from 1.31.0 to 1.31.1
2020-02-17 10:51:53 +01:00
Frederic Junod
9a03ca8417 Dispatch enterfullscreen and leavefullscreen from the FullScreen control 2020-02-17 10:48:29 +01:00
dependabot-preview[bot]
5b7d2d15e9 Bump webpack-cli from 3.3.10 to 3.3.11
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.3.10 to 3.3.11.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/next/CHANGELOG_v3.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/v3.3.10...v3.3.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-17 08:05:05 +00:00
dependabot-preview[bot]
88fbdff322 Bump terser-webpack-plugin from 2.3.4 to 2.3.5
Bumps [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) from 2.3.4 to 2.3.5.
- [Release notes](https://github.com/webpack-contrib/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v2.3.4...v2.3.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-17 08:03:59 +00:00
dependabot-preview[bot]
533b38a3c1 Bump rollup from 1.31.0 to 1.31.1
Bumps [rollup](https://github.com/rollup/rollup) from 1.31.0 to 1.31.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v1.31.0...v1.31.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-17 08:03:25 +00:00
mike-000
2e1e0dba54 document that views must use same projection 2020-02-16 11:11:37 +00:00
Andreas Hocevar
d93073f8d0 No trackpad mode for constrained resolutions 2020-02-16 10:05:32 +01:00
Andreas Hocevar
5150378983 Improve trackpad rebound behavior 2020-02-16 09:08:27 +01:00
Andreas Hocevar
a6c195e528 Merge pull request #10675 from jipexu/patch-1
typo
2020-02-16 07:51:59 +01:00
jipexu
bed2b6e222 typo 2020-02-15 22:10:41 +01:00
Andreas Hocevar
f3ce8e23b4 Fractional zoom changes in WHEEL mode 2020-02-15 13:53:14 +01:00
Andreas Hocevar
804c307fa9 Merge pull request #10669 from mike-000/patch-6
More browser compatible Export Map example
2020-02-14 22:41:08 +01:00
mike-000
f48a1a5f26 remove overlay and html-to-image 2020-02-14 19:49:17 +00:00
Andreas Hocevar
2c7c639f4b Merge pull request #10667 from ahocevar/label-linedash
Do not render label with the current linedash
2020-02-14 14:31:43 +01:00
Andreas Hocevar
0471b6e650 Do not render label with the current linedash 2020-02-14 13:50:03 +01:00
Andreas Hocevar
003e415382 Merge pull request #10666 from mike-000/patch-6
Load polyfill before example specific scripts in examples template
2020-02-14 13:34:15 +01:00
mike-000
16e46ea2c0 load polyfill before example specific scripts 2020-02-14 12:15:52 +00:00
John Leonard
8fe71bbbff perf: only do expensive reload when texture changes 2020-02-14 11:39:54 +00:00
Andreas Hocevar
ea5c91e19e Revert "Merge pull request #9565 from dbrnz/v6.0.0-beta.7-branch"
This reverts commit 35569a8427, reversing
changes made to 29a434314b.
2020-02-14 11:46:57 +01:00
Frédéric Junod
cc86719388 Merge pull request #6526 from tchandelle/draw-abort
Draw interaction: add abortDrawing method and drawabort event
2020-02-14 09:05:22 +01:00
Andreas Hocevar
0e9b43ed93 Merge pull request #10657 from openlayers/release-v6.2.1
Changelog for v6.2.1
2020-02-13 21:11:49 +01:00
Andreas Hocevar
9c21bda88e Develop on 6.2.2 2020-02-13 21:04:45 +01:00
Thomas Chandelle
33a8466913 Add API method abortDrawing and dispatch a DRAWABORT event 2020-02-13 17:22:39 +01:00
mike-000
7a77793d69 Write fill and outline in PolyStyle
Write styles based on style objects appropriate for geometry.
Write fill and outline in PolyStyle if false (i.e. non-default)
Handle MultiLineString, MultiPoint and MultiPolygon within heterogenous MultiGeometry when writing features

Add getGeometriesArrayRecursive method to ol/geom/GeometryCollection to allow for nested MultiGeometry

Enhanced write GeometryCollection geometries test

A more rigorous write GeometryCollection geometries test including nested collections (the output is simplified to a single MultiGeomtry)

Add writeFeatures to outline and fill tests, setting geometry for geometry specific tests

Add <fill>0</fill> and <outline>0</outline> to some existing tests
2020-02-12 21:18:57 +00:00
Maximilian Krög
0057144b52 Add apidoc-debug task to debug the apidoc generation process 2020-02-07 00:25:04 +01:00
philip
ccf3532eb2 Fix the parameter name to have the opt_ prefix. 2020-01-14 13:48:23 +00:00
philip
d2b0599177 Dynamically chose the number of subdivisions based on the size of the Image. 2020-01-14 13:39:52 +00:00
mike-000
5b1df4438d Fix for undefined source in Image layer
Prevent error if layer does not have a source.  Also clear any existing image if source is set to null or undefined by setSource.
2020-01-01 22:04:10 +00:00
mike-000
9d8609dd08 Modify and snap to circle in user coordinates
Correct modify interaction at center and at drawn circle circumference
Correct snap interaction at drawn circle circumference

Test circle geometry in a user projection
2019-12-13 16:40:39 +00:00
164 changed files with 4828 additions and 2832 deletions

View File

@@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- image: circleci/node:latest-browsers
- image: circleci/node:current-browsers
working_directory: ~/repo

View File

@@ -41,14 +41,26 @@ See the following examples for more detail on bundling OpenLayers with your appl
* Using [Parcel](https://github.com/openlayers/ol-parcel)
* Using [Browserify](https://github.com/openlayers/ol-browserify)
## Sponsors
OpenLayers appreciates contributions of all kinds. We especially want to thank our fiscal sponsors who contribute to ongoing project maintenance.
![Pozi logo](./sponsor-logos/pozi.png)
> Pozi helps connect communities through spatial thinking.
> We love Openlayers and it forms a core part of our platform.
> https://pozi.com/ https://app.pozi.com/
See our [Open Collective](https://opencollective.com/openlayers/contribute/sponsors-214/checkout) page if you too are interested in becoming a regular sponsor.
## IntelliSense support and type checking for VS Code
The `ol` package contains a `src/` folder with JSDoc annotated sources. TypeScript can get type definitions from these sources with a `jsconfig.json` config file in the project root:
```js
The ol package contains a src/ folder with JSDoc annotated sources. TypeScript can get type definitions from these sources with a `jsconfig.json` config file in the project root:
```json
{
"compilerOptions": {
"checkJs": true,
// Point to the JSDoc typed sources when using modules from the ol package
"baseUrl": "./",
"paths": {
"ol": ["node_modules/ol/src"],
@@ -61,9 +73,10 @@ The `ol` package contains a `src/` folder with JSDoc annotated sources. TypeScri
]
}
```
Project template with this configuration: https://gist.github.com/9a7253cb4712e8bf38d75d8ac898e36c.
Note that the above only works when authoring in plain JavaScript. For similar configurations with a `tsconfig.json` in TypeScript projects, your mileage may vary.
Note that the above only works when authoring in plain JavaScript. For similar configurations with a `tsconfig.json` in TypeScript projects, your mileage may vary. You may want to use a [third-party types package](https://github.com/hanreev/types-ol) in this case.
## Supported Browsers

View File

@@ -1,8 +1,10 @@
## Upgrade notes
### v6.2.0
### v6.3.0
### v6.1.0
#### Vector source loading when extent crosses +/-180
Previously, when an extent crossed the date line, vector source loaders were called with an extent with 540 degrees of longitude. Now, two loader calls with the visible extent on both sides of the projection extent are issued. This should not require any application code changes, but may affect custom loaders.
### v6.0.0

123
changelog/v6.3.0.md Normal file
View File

@@ -0,0 +1,123 @@
# 6.3.0
With more than 70 pull requests, this release not only brings significant improvements to the API documentation. It also fixes some old bugs and brings frequently requested improvments. And good news for TypeScript users: OpenLayers now ships with type definitions in `.d.ts` files.
## New features and improvements
* Several improvements to the Graticule layer, like consistent labeling, no more missing graticule lines, and it now works for views that cross the date line.
* Better support for KML icon colors, as well as fills and outlines in PolyStyle
* Better `ol/Overlay` performance and support for panning off-screen overlays into view
* Most of the rendering code can now be run in web workers, e.g. to render to an OffscreenCanvas
* OpenLayers now works fine in web components with shadow root
* WebGL point layers now support rotation based on feature attributes
## List of all changes
* [#10490](https://github.com/openlayers/openlayers/pull/10490) - Select style multiple select interactions removed ([@bepremeg](https://github.com/bepremeg))
* [#10531](https://github.com/openlayers/openlayers/pull/10531) - Dynamically chose the number of subdivisions based on the size of the Image to reproject ([@pjsg](https://github.com/pjsg))
* [#10618](https://github.com/openlayers/openlayers/pull/10618) - Add apidoc-debug task to debug the apidoc generation process ([@MoonE](https://github.com/MoonE))
* [#10343](https://github.com/openlayers/openlayers/pull/10343) - Correct interactions with circle geometries when using user coordinates ([@mike-000](https://github.com/mike-000))
* [#10864](https://github.com/openlayers/openlayers/pull/10864) - Update dependencies ([@ahocevar](https://github.com/ahocevar))
* [#10859](https://github.com/openlayers/openlayers/pull/10859) - Add an example of clipping layer based on a vector source ([@SDaron](https://github.com/SDaron))
* [#10850](https://github.com/openlayers/openlayers/pull/10850) - API docs for enums ([@ahocevar](https://github.com/ahocevar))
* [#10857](https://github.com/openlayers/openlayers/pull/10857) - Make OSM XML example work at dateline and replace Bing with MapTiler ([@mike-000](https://github.com/mike-000))
* [#10858](https://github.com/openlayers/openlayers/pull/10858) - Perform auto-pan when adding an Overlay to a Map ([@ejn](https://github.com/ejn))
* [#10646](https://github.com/openlayers/openlayers/pull/10646) - Write fill and outline in KML PolyStyle ([@mike-000](https://github.com/mike-000))
* [#10800](https://github.com/openlayers/openlayers/pull/10800) - Make Overlay.panIntoView an API method ([@ejn](https://github.com/ejn))
* [#10807](https://github.com/openlayers/openlayers/pull/10807) - Handle Graticule wrapX without calculating excess meridians ([@mike-000](https://github.com/mike-000))
* [#10795](https://github.com/openlayers/openlayers/pull/10795) - Show graticule labels in wrapped worlds ([@mike-000](https://github.com/mike-000))
* [#10824](https://github.com/openlayers/openlayers/pull/10824) - Fix drawing svg icon with color option in ie11 ([@MoonE](https://github.com/MoonE))
* [#10802](https://github.com/openlayers/openlayers/pull/10802) - Apidoc add default-exported enums ([@MoonE](https://github.com/MoonE))
* [#10805](https://github.com/openlayers/openlayers/pull/10805) - make ImageSourceEventType available for consumers ([@regileeso](https://github.com/regileeso))
* [#10822](https://github.com/openlayers/openlayers/pull/10822) - parsing color from IconStyle in KML files ([@lysek](https://github.com/lysek))
* [#10848](https://github.com/openlayers/openlayers/pull/10848) - Speed up Overlay element positioning using CSS translate() ([@horsenit](https://github.com/horsenit))
* [#9590](https://github.com/openlayers/openlayers/pull/9590) - Calculate tile grid extent from extent of bottom-level tile matrix ([@mloskot](https://github.com/mloskot))
* [#10845](https://github.com/openlayers/openlayers/pull/10845) - Fix createHitDetectionImageData error for features with no size ([@gedaiu](https://github.com/gedaiu))
* [#10842](https://github.com/openlayers/openlayers/pull/10842) - Fix custom symbol example short description ([@mike-000](https://github.com/mike-000))
* [#10828](https://github.com/openlayers/openlayers/pull/10828) - Offscreen canvas example ([@ahocevar](https://github.com/ahocevar))
* [#10816](https://github.com/openlayers/openlayers/pull/10816) - Add 'funding' field to `package.json` ([@marcjansen](https://github.com/marcjansen))
* [#10813](https://github.com/openlayers/openlayers/pull/10813) - Add sponsors section to the readme ([@tschaub](https://github.com/tschaub))
* [#10474](https://github.com/openlayers/openlayers/pull/10474) - Fix for undefined source in Image layer ([@mike-000](https://github.com/mike-000))
* [#10785](https://github.com/openlayers/openlayers/pull/10785) - Detect Zoomify server-side retina tiles ([@ahocevar](https://github.com/ahocevar))
* [#10787](https://github.com/openlayers/openlayers/pull/10787) - Improved projection extent in the "Reprojection with EPSG.io Search" example ([@mike-000](https://github.com/mike-000))
* [#10792](https://github.com/openlayers/openlayers/pull/10792) - Add support for EventListener Object ([@flexjoly](https://github.com/flexjoly))
* [#10777](https://github.com/openlayers/openlayers/pull/10777) - Keep the render loop running during simulation ([@ahocevar](https://github.com/ahocevar))
* [#10791](https://github.com/openlayers/openlayers/pull/10791) - iOS 12 touchmove: Prevent touchmove event default when no preceding pointer event ([@sosmo](https://github.com/sosmo))
* [#10786](https://github.com/openlayers/openlayers/pull/10786) - Resolve constraints when updating size ([@ahocevar](https://github.com/ahocevar))
* [#10788](https://github.com/openlayers/openlayers/pull/10788) - Add safeguard to handleTouchMove ([@sosmo](https://github.com/sosmo))
* [#10722](https://github.com/openlayers/openlayers/pull/10722) - fix: handle layer clear event in case clear(true) called ([@jellyedwards](https://github.com/jellyedwards))
* [#10723](https://github.com/openlayers/openlayers/pull/10723) - Improve the extent transforms used by Graticule and handle extents crossing the dateline ([@mike-000](https://github.com/mike-000))
* [#10744](https://github.com/openlayers/openlayers/pull/10744) - Ensure the Modify Features Test example opens at correct zoom ([@mike-000](https://github.com/mike-000))
* [#10767](https://github.com/openlayers/openlayers/pull/10767) - Replace Bing layer with MapTiler in examples ([@mike-000](https://github.com/mike-000))
* [#10751](https://github.com/openlayers/openlayers/pull/10751) - Sort events / observables in all cases ([@MoonE](https://github.com/MoonE))
* [#10763](https://github.com/openlayers/openlayers/pull/10763) - TypeScript: Fix inconsistent optionality in various APIs ([@jumpinjackie](https://github.com/jumpinjackie))
* [#10758](https://github.com/openlayers/openlayers/pull/10758) - Allow using feature attributes for symbol rotation in WebGL layers ([@jahow](https://github.com/jahow))
* [#10748](https://github.com/openlayers/openlayers/pull/10748) - Fix "Cannot read property 'anchor' of undefined" in ol/View ([@mike-000](https://github.com/mike-000))
* [#10746](https://github.com/openlayers/openlayers/pull/10746) - Fix building apidoc on windows ([@MoonE](https://github.com/MoonE))
* [#10720](https://github.com/openlayers/openlayers/pull/10720) - Apidoc better search ([@MoonE](https://github.com/MoonE))
* [#10743](https://github.com/openlayers/openlayers/pull/10743) - Ignore user provided tile cache size when too small ([@ahocevar](https://github.com/ahocevar))
* [#10736](https://github.com/openlayers/openlayers/pull/10736) - Allow cluster source to unlisten from its source ([@M393](https://github.com/M393))
* [#10739](https://github.com/openlayers/openlayers/pull/10739) - Fix typo in trackpad timeout ([@ahocevar](https://github.com/ahocevar))
* [#10740](https://github.com/openlayers/openlayers/pull/10740) - Document tabindex behavior for MouseWheelZoom and DragPan ([@matthias-ccri](https://github.com/matthias-ccri))
* [#10738](https://github.com/openlayers/openlayers/pull/10738) - Fix text background decluttering ([@ahocevar](https://github.com/ahocevar))
* [#10715](https://github.com/openlayers/openlayers/pull/10715) - Fix disappearing graticule labels when rotation returns to 0 ([@mike-000](https://github.com/mike-000))
* [#10713](https://github.com/openlayers/openlayers/pull/10713) - Draw graticule labels in a postrender function ([@mike-000](https://github.com/mike-000))
* [#10711](https://github.com/openlayers/openlayers/pull/10711) - Make sure that optional args are typed accordingly ([@ahocevar](https://github.com/ahocevar))
* [#10710](https://github.com/openlayers/openlayers/pull/10710) - Fix stylefunction return type ([@ahocevar](https://github.com/ahocevar))
* [#10709](https://github.com/openlayers/openlayers/pull/10709) - Fix type and documentation of style function ([@ahocevar](https://github.com/ahocevar))
* [#10708](https://github.com/openlayers/openlayers/pull/10708) - Handle Select interactions with falsey select style ([@ahocevar](https://github.com/ahocevar))
* [#10707](https://github.com/openlayers/openlayers/pull/10707) - Get default projection for overview map from main map. ([@AugustusKling](https://github.com/AugustusKling))
* [#10699](https://github.com/openlayers/openlayers/pull/10699) - Make Select interaction work when there are multiple instances ([@ahocevar](https://github.com/ahocevar))
* [#10694](https://github.com/openlayers/openlayers/pull/10694) - Draw image with configured opacity ([@M393](https://github.com/M393))
* [#10703](https://github.com/openlayers/openlayers/pull/10703) - CI and test fixes ([@ahocevar](https://github.com/ahocevar))
* [#10698](https://github.com/openlayers/openlayers/pull/10698) - Shadow root ([@ahocevar](https://github.com/ahocevar))
* [#10688](https://github.com/openlayers/openlayers/pull/10688) - Publish type definition files ([@ahocevar](https://github.com/ahocevar))
* [#10691](https://github.com/openlayers/openlayers/pull/10691) - Do not exceed color range ([@ahocevar](https://github.com/ahocevar))
* [#10683](https://github.com/openlayers/openlayers/pull/10683) - Dispatch enterfullscreen and leavefullscreen from the FullScreen control ([@fredj](https://github.com/fredj))
* [#10676](https://github.com/openlayers/openlayers/pull/10676) - Document that overviewmap view must use same projection as main map ([@mike-000](https://github.com/mike-000))
* [#10678](https://github.com/openlayers/openlayers/pull/10678) - Add maxResolution option to ol/tilegrid.createXYZ() and ol/source/XYZ ([@mike-000](https://github.com/mike-000))
* [#10690](https://github.com/openlayers/openlayers/pull/10690) - Document minZoom and maxZoom options for all layers ([@mike-000](https://github.com/mike-000))
* [#10672](https://github.com/openlayers/openlayers/pull/10672) - Nicer mousewheel and trackpad zooming ([@ahocevar](https://github.com/ahocevar))
* [#10687](https://github.com/openlayers/openlayers/pull/10687) - Increase timeout in listenImage test ([@fredj](https://github.com/fredj))
* [#10684](https://github.com/openlayers/openlayers/pull/10684) - perf: only do expensive reload when texture changes ([@jellyedwards](https://github.com/jellyedwards))
* [#10675](https://github.com/openlayers/openlayers/pull/10675) - typo ([@jipexu](https://github.com/jipexu))
* [#10669](https://github.com/openlayers/openlayers/pull/10669) - More browser compatible Export Map example ([@mike-000](https://github.com/mike-000))
* [#10667](https://github.com/openlayers/openlayers/pull/10667) - Do not render label with the current linedash ([@ahocevar](https://github.com/ahocevar))
* [#10666](https://github.com/openlayers/openlayers/pull/10666) - Load polyfill before example specific scripts in examples template ([@mike-000](https://github.com/mike-000))
* [#6526](https://github.com/openlayers/openlayers/pull/6526) - Draw interaction: add abortDrawing method and drawabort event ([@tchandelle](https://github.com/tchandelle))
* [#10657](https://github.com/openlayers/openlayers/pull/10657) - Changelog for v6.2.1 ([@openlayers](https://github.com/openlayers))
<details>
<summary>Dependency Updates</summary>
* [#10855](https://github.com/openlayers/openlayers/pull/10855) - Bump rollup from 2.1.0 to 2.3.0 ([@openlayers](https://github.com/openlayers))
* [#10854](https://github.com/openlayers/openlayers/pull/10854) - Bump ol-mapbox-style from 6.1.0 to 6.1.1 ([@openlayers](https://github.com/openlayers))
* [#10853](https://github.com/openlayers/openlayers/pull/10853) - Bump buble from 0.19.8 to 0.20.0 ([@openlayers](https://github.com/openlayers))
* [#10852](https://github.com/openlayers/openlayers/pull/10852) - Bump webpack from 4.42.0 to 4.42.1 ([@openlayers](https://github.com/openlayers))
* [#10837](https://github.com/openlayers/openlayers/pull/10837) - Bump ol-mapbox-style from 6.0.1 to 6.1.0 ([@openlayers](https://github.com/openlayers))
* [#10836](https://github.com/openlayers/openlayers/pull/10836) - Bump coveralls from 3.0.9 to 3.0.11 ([@openlayers](https://github.com/openlayers))
* [#10835](https://github.com/openlayers/openlayers/pull/10835) - Bump @babel/preset-env from 7.8.7 to 7.9.0 ([@openlayers](https://github.com/openlayers))
* [#10834](https://github.com/openlayers/openlayers/pull/10834) - Bump rollup from 1.32.1 to 2.1.0 ([@openlayers](https://github.com/openlayers))
* [#10833](https://github.com/openlayers/openlayers/pull/10833) - Bump fs-extra from 8.1.0 to 9.0.0 ([@openlayers](https://github.com/openlayers))
* [#10832](https://github.com/openlayers/openlayers/pull/10832) - Bump @babel/core from 7.8.7 to 7.9.0 ([@openlayers](https://github.com/openlayers))
* [#10831](https://github.com/openlayers/openlayers/pull/10831) - Bump babel-loader from 8.0.6 to 8.1.0 ([@openlayers](https://github.com/openlayers))
* [#10830](https://github.com/openlayers/openlayers/pull/10830) - Bump mocha from 7.1.0 to 7.1.1 ([@openlayers](https://github.com/openlayers))
* [#10829](https://github.com/openlayers/openlayers/pull/10829) - Bump marked from 0.8.0 to 0.8.2 ([@openlayers](https://github.com/openlayers))
* [#10811](https://github.com/openlayers/openlayers/pull/10811) - Bump sinon from 9.0.0 to 9.0.1 ([@openlayers](https://github.com/openlayers))
* [#10810](https://github.com/openlayers/openlayers/pull/10810) - Bump rollup-plugin-terser from 5.2.0 to 5.3.0 ([@openlayers](https://github.com/openlayers))
* [#10809](https://github.com/openlayers/openlayers/pull/10809) - Bump yargs from 15.3.0 to 15.3.1 ([@openlayers](https://github.com/openlayers))
* [#10806](https://github.com/openlayers/openlayers/pull/10806) - [Security] Bump acorn from 6.1.1 to 6.4.1 ([@openlayers](https://github.com/openlayers))
* [#10755](https://github.com/openlayers/openlayers/pull/10755) - Bump rollup from 1.31.1 to 1.32.0 ([@openlayers](https://github.com/openlayers))
* [#10754](https://github.com/openlayers/openlayers/pull/10754) - Bump @babel/preset-env from 7.8.4 to 7.8.6 ([@openlayers](https://github.com/openlayers))
* [#10753](https://github.com/openlayers/openlayers/pull/10753) - Bump mocha from 7.0.1 to 7.1.0 ([@openlayers](https://github.com/openlayers))
* [#10752](https://github.com/openlayers/openlayers/pull/10752) - Bump @babel/core from 7.8.4 to 7.8.6 ([@openlayers](https://github.com/openlayers))
* [#10725](https://github.com/openlayers/openlayers/pull/10725) - Bump elm-pep from 1.0.4 to 1.0.6 ([@openlayers](https://github.com/openlayers))
* [#10726](https://github.com/openlayers/openlayers/pull/10726) - Bump sinon from 8.1.1 to 9.0.0 ([@openlayers](https://github.com/openlayers))
* [#10680](https://github.com/openlayers/openlayers/pull/10680) - Bump terser-webpack-plugin from 2.3.4 to 2.3.5 ([@openlayers](https://github.com/openlayers))
* [#10682](https://github.com/openlayers/openlayers/pull/10682) - Bump webpack from 4.41.5 to 4.41.6 ([@openlayers](https://github.com/openlayers))
* [#10681](https://github.com/openlayers/openlayers/pull/10681) - Bump webpack-cli from 3.3.10 to 3.3.11 ([@openlayers](https://github.com/openlayers))
* [#10679](https://github.com/openlayers/openlayers/pull/10679) - Bump rollup from 1.31.0 to 1.31.1 ([@openlayers](https://github.com/openlayers))
</details>

9
changelog/v6.3.1.md Normal file
View File

@@ -0,0 +1,9 @@
# 6.3.1
This is a bugfix release which removes the auto-generated `.d.ts` TypeScript type files from the published package.
## List of all changes
* [#10877](https://github.com/openlayers/openlayers/pull/10877) - Remove .d.ts files from the package ([@ahocevar](https://github.com/ahocevar))
* [#10872](https://github.com/openlayers/openlayers/pull/10872) - Use TypeScript 3.9 for type generation for better enums ([@ahocevar](https://github.com/ahocevar))

View File

@@ -73,9 +73,6 @@ function includeAugments(doclet) {
});
}
cls._hideConstructor = true;
if (!cls.undocumented) {
cls._documented = true;
}
}
}
}
@@ -106,6 +103,34 @@ function includeTypes(doclet) {
}
}
const defaultExports = {};
const path = require('path');
const moduleRoot = path.join(process.cwd(), 'src');
// Tag default exported Identifiers because their name should be the same as the module name.
exports.astNodeVisitor = {
visitNode: function(node, e, parser, currentSourceName) {
if (node.parent && node.parent.type === 'ExportDefaultDeclaration') {
const modulePath = path.relative(moduleRoot, currentSourceName).replace(/\.js$/, '');
const exportName = 'module:' + modulePath.replace(/\\/g, '/') + (node.name ? '~' + node.name : '');
defaultExports[exportName] = true;
}
}
};
function sortOtherMembers(doclet) {
if (doclet.fires) {
doclet.fires.sort(function(a, b) {
return a.split(/#?event:/)[1] < b.split(/#?event:/)[1] ? -1 : 1;
});
}
if (doclet.observables) {
doclet.observables.sort(function(a, b) {
return a.name < b.name ? -1 : 1;
});
}
}
exports.handlers = {
newDoclet: function(e) {
@@ -129,22 +154,14 @@ exports.handlers = {
parseComplete: function(e) {
const doclets = e.doclets;
const byLongname = doclets.index.longname;
for (let i = doclets.length - 1; i >= 0; --i) {
const doclet = doclets[i];
if (doclet.stability) {
if (doclet.kind == 'class') {
includeAugments(doclet);
}
if (doclet.fires) {
doclet.fires.sort(function(a, b) {
return a.split(/#?event:/)[1] < b.split(/#?event:/)[1] ? -1 : 1;
});
}
if (doclet.observables) {
doclet.observables.sort(function(a, b) {
return a.name < b.name ? -1 : 1;
});
}
sortOtherMembers(doclet);
// Always document namespaces and items with stability annotation
continue;
}
@@ -161,14 +178,26 @@ exports.handlers = {
// constructor from the docs.
doclet._hideConstructor = true;
includeAugments(doclet);
} else if (!doclet._hideConstructor && !(doclet.kind == 'typedef' && doclet.longname in types)) {
sortOtherMembers(doclet);
} else if (!doclet._hideConstructor) {
// Remove all other undocumented symbols
doclet.undocumented = true;
}
if (doclet._documented) {
delete doclet.undocumented;
if (doclet.memberof && byLongname[doclet.memberof] &&
byLongname[doclet.memberof][0].isEnum &&
!byLongname[doclet.memberof][0].properties.some(p => p.stability)) {
byLongname[doclet.memberof][0].undocumented = true;
}
}
},
processingComplete(e) {
const byLongname = e.doclets.index.longname;
for (const name in defaultExports) {
byLongname[name].forEach(function(doclet) {
doclet.isDefaultExport = true;
});
}
}
};

View File

@@ -14,7 +14,6 @@ const path = require('jsdoc/lib/jsdoc/path');
const taffy = require('taffydb').taffy;
const handle = require('jsdoc/lib/jsdoc/util/error').handle;
const helper = require('jsdoc/lib/jsdoc/util/templateHelper');
const _ = require('underscore');
const htmlsafe = helper.htmlsafe;
const linkto = helper.linkto;
const resolveAuthorLinks = helper.resolveAuthorLinks;
@@ -188,10 +187,12 @@ function attachModuleSymbols(doclets, modules) {
});
}
function getPrettyName(longname) {
return longname
.split('~')[0]
.replace('module:', '');
function getPrettyName(doclet) {
const fullname = doclet.longname.replace('module:', '');
if (doclet.isDefaultExport) {
return fullname.split('~')[0];
}
return fullname;
}
/**
@@ -209,27 +210,13 @@ function getPrettyName(longname) {
*/
function buildNav(members) {
const nav = [];
// merge namespaces and classes, then sort
const merged = members.modules.concat(members.classes);
merged.sort(function(a, b) {
const prettyNameA = getPrettyName(a.longname).toLowerCase();
const prettyNameB = getPrettyName(b.longname).toLowerCase();
if (prettyNameA > prettyNameB) {
return 1;
}
if (prettyNameA < prettyNameB) {
return -1;
}
return 0;
});
_.each(merged, function(v) {
members.classes.forEach(function(v) {
// exclude interfaces from sidebar
if (v.interface !== true && v.kind === 'class') {
if (v.interface !== true) {
nav.push({
type: 'class',
longname: v.longname,
prettyname: getPrettyName(v.longname),
prettyname: getPrettyName(v),
name: v.name,
module: find({
kind: 'module',
@@ -253,44 +240,57 @@ function buildNav(members) {
memberof: v.longname
})
});
} else if (v.kind == 'module') {
const classes = find({
kind: 'class',
memberof: v.longname
});
const members = find({
kind: 'member',
memberof: v.longname
});
const methods = find({
kind: 'function',
memberof: v.longname
});
const typedefs = find({
kind: 'typedef',
memberof: v.longname
});
const events = find({
kind: 'event',
memberof: v.longname
});
// Only add modules that contain more than just classes with their
// associated Options typedef
if (typedefs.length > classes.length || members.length + methods.length > 0) {
nav.push({
type: 'module',
longname: v.longname,
prettyname: getPrettyName(v.longname),
name: v.name,
members: members,
methods: methods,
typedefs: typedefs,
fires: v.fires,
events: events
});
}
}
});
members.modules.forEach(function(v) {
const classes = find({
kind: 'class',
memberof: v.longname
});
const members = find({
kind: 'member',
memberof: v.longname
});
const methods = find({
kind: 'function',
memberof: v.longname
});
const typedefs = find({
kind: 'typedef',
memberof: v.longname
});
const events = find({
kind: 'event',
memberof: v.longname
});
// Only add modules that contain more than just classes with their
// associated Options typedef
if (typedefs.length > classes.length || members.length + methods.length > 0) {
nav.push({
type: 'module',
longname: v.longname,
prettyname: getPrettyName(v),
name: v.name,
members: members,
methods: methods,
typedefs: typedefs,
fires: v.fires,
events: events
});
}
});
nav.sort(function(a, b) {
const prettyNameA = a.prettyname.toLowerCase();
const prettyNameB = b.prettyname.toLowerCase();
if (prettyNameA > prettyNameB) {
return 1;
}
if (prettyNameA < prettyNameB) {
return -1;
}
return 0;
});
return nav;
}

View File

@@ -1,99 +1,258 @@
$(function () {
// Search Items
$('#include_modules').change(function (e) {
console.log('change');
if ($(this).is(':checked')) {
'use strict';
// Allow user configuration?
const allowRegex = true;
const minInputForSearch = 1;
const minInputForFullText = 2;
const expandAllOnInputWithoutSearch = true;
function constructRegex(searchTerm, makeRe, allowRegex) {
try {
if (allowRegex) {
return makeRe(searchTerm);
}
} catch (e) {
}
// In case of invalid regexp fall back to non-regexp, but still allow . to match /
return makeRe(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\./g, '[./]'));
}
function getWeightFunction(searchTerm, allowRegex) {
function makeRe(searchTerm) {
return {
begin: new RegExp('\\b' + searchTerm), // Begin matches word boundary
baseName: new RegExp('\\b' + searchTerm + '[^/]*$'), // Begin matches word boundary of class / module name
fullName: new RegExp('\\b' + searchTerm + '(?:[~.]|$)'), // Complete word(s) of class / module matches
completeName: new RegExp('^' + searchTerm + '$') // Match from start to finish
}
}
const re = constructRegex(searchTerm, makeRe, allowRegex);
return function (matchedItem, beginOnly) {
// We could get smarter on the weight here
const name = matchedItem.dataset.name;
if (beginOnly) {
return re.baseName.test(name) ? 100 : 1;
}
// If everything else is equal, prefer shorter names, and prefer classes over modules
let weight = 10000 + matchedItem.dataset.longname.length - name.length * 100;
if (name.match(re.begin)) {
weight += 10000;
if (re.baseName.test(name)) {
weight += 10000;
if (re.fullName.test(name)) {
weight += 10000;
if (re.completeName.test(name)) {
weight += 10000;
}
}
}
}
return weight;
}
}
const search = (function () {
const $navList = $('.navigation-list');
const navListNode = $navList.get(0);
let $classItems;
let $members;
let stateClass = (function () {
$navList.removeClass('search-started searching');
$navList.addClass('search-empty');
return 'search-empty';
})();
let manualToggles = {};
// Show an item related a current documentation automatically
const longname = $('.page-title').data('filename')
.replace(/\.[a-z]+$/, '')
.replace('module-', 'module:')
.replace(/_/g, '/')
.replace(/-/g, '~');
const currentItem = navListNode.querySelector('.item[data-longname="' + longname + '"]');
if (currentItem) {
$navList.prepend(currentItem);
}
return {
$navList: $navList,
$currentItem: currentItem ? $(currentItem) : undefined,
lastSearchTerm: undefined,
lastState: {},
getClassList: function () {
return $classItems || ($classItems = $navList.find('li.item'));
},
getMembers: function () {
return $members || ($members = $navList.find('.item li'));
},
changeStateClass: function (newClass) {
if (newClass !== stateClass) {
navListNode.classList.remove(stateClass);
navListNode.classList.add(newClass);
stateClass = newClass;
}
},
manualToggle: function ($node, show) {
$node.addClass('toggle-manual');
$node.toggleClass('toggle-manual-hide', !show);
$node.toggleClass('toggle-manual-show', show);
manualToggles[$node.data('longname')] = $node;
},
clearManualToggles: function() {
for (let clsName in manualToggles) {
manualToggles[clsName].removeClass('toggle-manual toggle-manual-show toggle-manual-hide');
}
manualToggles = {};
},
};
})();
const dummy = {subItems: {}};
function clearOldMatches(lastState, searchState) {
for (let itemName in lastState) {
const lastItem = lastState[itemName];
const item = searchState[itemName];
if (!item) {
lastItem.item.classList.remove('match');
}
if (lastItem.subItems) {
clearOldMatches(lastItem.subItems, (item || dummy).subItems);
}
}
}
function doSearch(searchTerm) {
searchTerm = searchTerm.toLowerCase();
const lastSearchTerm = search.lastSearchTerm;
if (searchTerm === lastSearchTerm) {
return;
}
// Avoid layout reflow by scrolling to top first.
search.$navList.scrollTop(0);
search.lastSearchTerm = searchTerm;
search.clearManualToggles();
if (searchTerm.length < minInputForSearch) {
const state = searchTerm.length && expandAllOnInputWithoutSearch ? 'search-started' : 'search-empty';
search.changeStateClass(state);
if (lastSearchTerm !== undefined && lastSearchTerm.length >= minInputForSearch) {
// Restore the original, sorted order
search.$navList.append(search.getClassList());
}
if (state === 'search-empty' && search.$currentItem) {
search.manualToggle(search.$currentItem, true);
}
} else {
}
});
var getSearchWeight = function (searchTerm, $matchedItem) {
let weight = 0;
// We could get smarter on the weight here
if ($matchedItem.data('shortname')
&& $matchedItem.data('shortname').toLowerCase() === searchTerm.toLowerCase()) {
weight++;
}
return weight;
};
// sort function callback
var weightSorter = function (a, b) {
var aW = $(a).data('weight') || 0;
var bW = $(b).data('weight') || 0;
return bW - aW;
};
// Search Items
$('#search').on('keyup', function (e) {
var value = $(this).val();
var $el = $('.navigation');
if (value && value.length > 1) {
var regexp = new RegExp(value, 'i');
$el.find('li, .member-list').hide();
$el.find('li').each(function (i, v) {
const $item = $(v);
const name = $item.data('name');
if (name && regexp.test(name)) {
const $classEntry = $item.closest('.item');
const $members = $item.closest('.member-list');
// Do the weight thing
$classEntry.removeData('weight');
$classEntry.show();
const weight = getSearchWeight(value, $classEntry);
$classEntry.data('weight', weight);
$members.show();
$classEntry.show();
$item.show();
search.changeStateClass('searching');
searchTerm = searchTerm.toLowerCase();
const beginOnly = searchTerm.length < minInputForFullText;
const getSearchWeight = getWeightFunction(searchTerm, allowRegex);
const re = constructRegex(searchTerm, function (searchTerm) {
return new RegExp((beginOnly ? '\\b' : '') + searchTerm);
}, allowRegex);
const navList = search.$navList.get(0);
const classes = [];
const searchState = {};
search.getClassList().each(function (i, classEntry) {
const className = classEntry.dataset.longname;
if (!(className in searchState) && re.test(classEntry.dataset.name)) {
const cls = searchState[className] = {
item: classEntry,
// Do the weight thing
weight: getSearchWeight(classEntry, beginOnly) * 100000,
subItems: {}
};
classes.push(cls);
classEntry.classList.add('match');
}
});
search.getMembers().each(function (i, li) {
const name = li.dataset.name;
if (re.test(name)) {
const itemMember = li.parentElement.parentElement;
const classEntry = itemMember.parentElement;
const className = classEntry.dataset.longname;
let cls = searchState[className];
if (!cls) {
cls = searchState[className] = {
item: classEntry,
weight: 0,
subItems: {}
};
classes.push(cls);
classEntry.classList.add('match');
}
cls.weight += getSearchWeight(li, true);
const memberType = itemMember.dataset.type;
let members = cls.subItems[memberType];
if (!members) {
members = cls.subItems[memberType] = {
item: itemMember,
subItems: {}
};
itemMember.classList.add('match');
}
members.subItems[name] = { item: li };
li.classList.add('match');
}
});
clearOldMatches(search.lastState, searchState);
search.lastState = searchState;
$(".navigation ul.list li.item:visible")
.sort(weightSorter) // sort elements
.appendTo(".navigation ul.list"); // append again to the list
} else {
$el.find('.item, .member-list').show();
classes.sort(function (a, b) {
return a.weight - b.weight;
});
for (let i = classes.length - 1; i >= 0; --i) {
navList.appendChild(classes[i].item);
}
}
}
$el.find('.list').scrollTop(0);
});
const searchInput = $('#search').get(0);
// Skip searches when typing fast.
let key;
function queueSearch() {
if (!key) {
key = setTimeout(function () {
key = undefined;
const searchTerm = searchInput.value;
doSearch(searchTerm);
}, 0);
}
}
// Search Items
searchInput.addEventListener('input', queueSearch);
doSearch(searchInput.value);
// Toggle when click an item element
$('.navigation').on('click', '.toggle', function (e) {
$(this).parent().parent().find('.member-list').toggle();
search.$navList.on('click', '.toggle', function (e) {
if (event.target.tagName.toLowerCase() === 'a') {
return;
}
const clsItem = $(this).closest('.item');
let show;
if (clsItem.hasClass('toggle-manual-show')) {
show = false;
} else if (clsItem.hasClass('toggle-manual-hide')) {
show = true;
} else {
clsItem.find('.member-list li').each(function (i, v) {
show = $(v).is(':hidden');
return !show;
});
}
search.manualToggle(clsItem, !!show);
});
// Show an item related a current documentation automatically
var filename = $('.page-title').data('filename')
.replace(/\.[a-z]+$/, '')
.replace('module-', 'module:')
.replace(/_/g, '/')
.replace(/-/g, '~');
var $currentItem = $('.navigation .item[data-name*="' + filename + '"]:eq(0)');
if ($currentItem.length) {
$currentItem
.remove()
.prependTo('.navigation .list')
.show()
.find('.member-list')
.show();
}
// Auto resizing on navigation
var _onResize = function () {
var height = $(window).height();
var $el = $('.navigation');
$el.height(height).find('.list').height(height - 133);
$el.height(height).find('.navigation-list').height(height - 133);
};
$(window).on('resize', _onResize);
@@ -137,22 +296,4 @@ $(function () {
'<a href="' + link + textParts[1].replace('line ', '#L') + '">' +
textParts[1] + '</a>';
});
// Highlighting current anchor
var anchors = $('.anchor');
var _onHashChange = function () {
var activeHash = window.document.location.hash
.replace(/\./g, '\\.') // Escape dot in element id
.replace(/\~/g, '\\~'); // Escape tilde in element id
anchors.removeClass('highlighted');
if (activeHash.length > 0) {
anchors.filter(activeHash).addClass('highlighted');
}
};
$(window).on('hashchange', _onHashChange);
_onHashChange();
});

View File

@@ -51,7 +51,8 @@ body {
width: 0px;
height: 0px;
}
.nameContainer .anchor.highlighted + h4 {
/* Highlighting current anchor */
.nameContainer .anchor:target + h4 {
background-color: #faebcc;
}
a {
@@ -123,7 +124,7 @@ li {
color: #fff;
border-color: #555;
}
.navigation .list {
.navigation .navigation-list {
padding: 10px 15px 0 15px;
position: relative;
overflow: auto;
@@ -135,6 +136,24 @@ li {
border-bottom: 1px solid #333;
}
.navigation .glyphicon {
margin-right: 3px;
flex-shrink: 0;
}
.navigation .item .glyphicon:before {
display: inline-block;
}
.navigation .item.toggle-manual .glyphicon:before {
transition: transform .1s;
}
.navigation .item-class.toggle-manual-show .glyphicon:before {
/* With 90deg the icon slightly slides left at transition end */
transform: rotate(89.9deg);
}
.navigation .item-module.toggle-manual-show .glyphicon:before {
transform: rotate(45deg);
}
.navigation li.perfect-match {
border: 5px solid orange;
}
@@ -147,8 +166,8 @@ li {
}
.navigation li.item .title {
cursor: pointer;
position: relative;
display: block;
display: -ms-flexbox;
display: flex;
font-size: 0.85em;
}
.navigation li.item .title a {
@@ -184,9 +203,41 @@ li {
margin-top: 2px;
}
.navigation li.item .member-list {
display: none;
padding-left: 8px;
}
/* search state */
/* show all classes when search is empty */
.navigation-list.search-empty .item {
display: block;
}
/* hide all members by default when search is empty */
.navigation-list.search-empty .item .member-list {
display: none;
}
/* expand all members when input in search field available but too short to search */
.navigation-list.search-started li,
.navigation-list.search-started .member-list {
display: block;
}
/* when searching hide everything that is not a match */
.navigation-list.searching li,
.navigation-list.searching .member-list {
display: none;
}
.navigation-list.searching .match {
display: block;
}
/* allow user to hide / show members */
.navigation-list .item.toggle-manual-show li,
.navigation-list .item.toggle-manual-show .member-list {
display: block!important;
}
.navigation-list:not(.searching) .item.toggle-manual-hide li,
.navigation-list:not(.searching) .item.toggle-manual-hide .member-list {
display: none!important;
}
.main {
padding: 20px 20px;
margin-left: 250px;

View File

@@ -64,7 +64,7 @@ var self = this;
<ul><?js fires.forEach(function(f) {
var parts = f.split(/#?event:/);
var type = parts.pop();
var eventClassName = parts[0];
var eventClass = self.find({longname: parts[0]})[0];
parts = type.split(' ');
type = parts.shift();
var description = parts.length ? parts.join(' ') : '';
@@ -74,12 +74,9 @@ var self = this;
}
?>
<li class="<?js= (eventDoclet || data).stability !== 'stable' ? 'unstable' : '' ?>">
<code><?js= eventClassName ? self.linkto(f, type) : type ?></code>
<?js if (eventClassName) {
var eventClass = self.find({longname: eventClassName})[0];
if (eventClass) { ?>
(<?js= self.linkto(eventClass.longname) ?>)
<?js } ?>
<code><?js= eventClass ? self.linkto(f, type) : type ?></code>
<?js if (eventClass) { ?>
(<?js= self.linkto(eventClass.longname) ?>)
<?js } ?>
<?js= self.partial('stability.tmpl', eventDoclet || (data.stability ? data : {})) ?>
<?js if (description) { ?> -

View File

@@ -15,17 +15,17 @@ function getItemCssClass(type) {
}
const printList = v => { ?>
<li data-name="<?js= v.longname ?>"><?js
<li data-name="<?js= toShortName(v.name).toLowerCase() ?>"><?js
}
const printListWithStability = v => {
const cls = v.stability && v.stability !== 'stable' ? ' class="unstable"' : ''; ?>
<li data-name="<?js= v.longname ?>"<?js= cls ?>><?js
<li data-name="<?js= toShortName(v.name).toLowerCase() ?>"<?js= cls ?>><?js
}
function listContent(item, title, listItemPrinter) {
const type = title.toLowerCase();
if (item[type] && item[type].length) { ?>
<div class="member-list">
<div class="member-list" data-type="<?js= type ?>">
<span class="subtitle"><?js= title ?></span>
<ul><?js
item[type].forEach(function (v) {
@@ -40,12 +40,12 @@ function listContent(item, title, listItemPrinter) {
<div class="search">
<input id="search" type="text" class="form-control input-sm" placeholder="Search Documentation">
</div>
<ul class="list"><?js
<ul class="navigation-list search-empty"><?js
this.nav.forEach(function (item) { ?>
<li class="item" data-name="<?js= item.longname ?>" data-shortname="<?js= item.name.toLowerCase() ?>">
<span class="title">
<span class="glyphicon <?js= getItemCssClass(item.type) ?> toggle"></span>
<?js= self.linkto(item.longname, item.prettyname) ?>
<li class="item item-<?js= item.type ?>" data-longname="<?js= item.longname ?>" data-name="<?js= item.prettyname.toLowerCase() ?>">
<span class="title toggle">
<span class="glyphicon <?js= getItemCssClass(item.type) ?>"></span>
<span><?js= self.linkto(item.longname, item.prettyname.replace(/[.~]/g, '\u200b$&')) ?></span>
</span><?js
listContent(item, 'Members', printList);
listContent(item, 'Typedefs', printListWithStability);

View File

@@ -6,7 +6,7 @@ docs: >
<p>When the Bing Maps tile service doesn't have tiles for a given resolution and region it returns "placeholder" tiles indicating that. Zoom the map beyond level 19 to see the "placeholder" tiles. If you want OpenLayers to display stretched tiles in place of "placeholder" tiles beyond zoom level 19 then set <code>maxZoom</code> to <code>19</code> in the options passed to <code>ol/source/BingMaps</code>.</p>
tags: "bing, bing-maps"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
---
<div id="map" class="map"></div>

View File

@@ -18,7 +18,7 @@ for (i = 0, ii = styles.length; i < ii; ++i) {
visible: false,
preload: Infinity,
source: new BingMaps({
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ',
imagerySet: styles[i]
// use maxZoom 19 to see stretched tiles instead of the BingMaps
// "no photos at this zoom level" tiles

View File

@@ -2,6 +2,6 @@
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg">
<g>
<rect width="20" height="20" style="fill:#fff" />
<rect width="20" height="20" style="fill:#fff; stroke-width:4px; stroke:#000" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 225 B

View File

@@ -1,7 +1,7 @@
---
layout: example.html
title: Earthquakes with custom symbols
shortdesc: Demonstrates the use of `toCanvas` to create custom icon symbols.
shortdesc: Demonstrates the use of `toContext` to create custom icon symbols.
docs: >
This example parses a KML file and renders the features as a vector layer. The layer is given a <code>style</code> that renders earthquake locations with a custom lightning symbol and a size relative to their magnitude.
tags: "KML, vector, style, canvas, symbol"

View File

@@ -0,0 +1,9 @@
---
layout: example.html
title: Custom map element
shortdesc: Example of a custom element with a map.
docs: >
The example creates and registers a custom element, `ol-map`, which contains a simple map. **Note:** Only works in browsers that supports `ShadowRoot`.
tags: "es2015, web-component, custom-element, shadow-dom"
---
<ol-map id="map" class="map"></ol-map>

View File

@@ -0,0 +1,43 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js';
class OLComponent extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode: 'open'});
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'css/ol.css');
this.shadow.appendChild(link);
const style = document.createElement('style');
style.innerText = `
:host {
display: block;
}
`;
this.shadow.appendChild(style);
const div = document.createElement('div');
div.style.width = '100%';
div.style.height = '100%';
this.shadow.appendChild(div);
this.map = new Map({
target: div,
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [0, 0],
zoom: 2
})
});
}
}
customElements.define('ol-map', OLComponent);

View File

@@ -1,6 +0,0 @@
.overlay {
background-color: yellow;
border-radius: 6px;
padding: 4px;
white-space: nowrap;
}

View File

@@ -3,13 +3,9 @@ layout: example.html
title: Map Export
shortdesc: Example of exporting a map as a PNG image.
docs: >
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/html-to-image">html-to-image</a>
library.
Example of exporting a map as a PNG image.
tags: "export, png, openstreetmap"
---
<div id="map" class="map"></div>
<div style="display: none;">
<div class="overlay" id="null">Null Island</div>
</div>
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
<a id="image-download" download="map.png"></a>

View File

@@ -1,12 +1,9 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Overlay from '../src/ol/Overlay.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {toPng} from 'html-to-image';
const map = new Map({
layers: [
new TileLayer({
@@ -16,7 +13,8 @@ const map = new Map({
source: new VectorSource({
url: 'data/geojson/countries.geojson',
format: new GeoJSON()
})
}),
opacity: 0.5
})
],
target: 'map',
@@ -26,28 +24,33 @@ const map = new Map({
})
});
map.addOverlay(new Overlay({
position: [0, 0],
element: document.getElementById('null')
}));
// export options for html-to-image.
// See: https://github.com/bubkoo/html-to-image#options
const exportOptions = {
filter: function(element) {
return element.className ? element.className.indexOf('ol-control') === -1 : true;
}
};
document.getElementById('export-png').addEventListener('click', function() {
map.once('rendercomplete', function() {
toPng(map.getTargetElement(), exportOptions)
.then(function(dataURL) {
const link = document.getElementById('image-download');
link.href = dataURL;
link.click();
});
const mapCanvas = document.createElement('canvas');
const size = map.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
const mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(document.querySelectorAll('.ol-layer canvas'), function(canvas) {
if (canvas.width > 0) {
const opacity = canvas.parentNode.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
const transform = canvas.style.transform;
// Get the transform parameters from the style's transform matrix
const matrix = transform.match(/^matrix\(([^\(]*)\)$/)[1].split(',').map(Number);
// Apply the transform to the export map context
CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix);
mapContext.drawImage(canvas, 0, 0);
}
});
if (navigator.msSaveBlob) {
// link download attribuute does not work on MS browsers
navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
} else {
const link = document.getElementById('image-download');
link.href = mapCanvas.toDataURL();
link.click();
}
});
map.renderSync();
});

View File

@@ -147,6 +147,7 @@ function updateView() {
view.setCenter(getCenterWithHeading(c, -c[2], view.getResolution()));
view.setRotation(-c[2]);
marker.setPosition(c);
map.render();
}
}

View File

@@ -25,6 +25,7 @@ rome.setStyle(new Style({
image: new Icon({
color: '#8959A8',
crossOrigin: 'anonymous',
imgSize: [20, 20],
src: 'data/square.svg'
})
}));

View File

@@ -0,0 +1,3 @@
#map {
background: transparent;
}

View File

@@ -0,0 +1,9 @@
---
layout: example.html
title: Vector Clipping Layer
shortdesc: Vector Clipping Layer example
docs: >
Example of a clipping layer based on a vector source
tags: "clipping, openstreetmap, vector"
---
<div id="map" class="map"></div>

View File

@@ -0,0 +1,46 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import VectorSource from '../src/ol/source/Vector.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import OSM from '../src/ol/source/OSM.js';
import {Fill, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
import {fromLonLat} from '../src/ol/proj.js';
const base = new TileLayer({
source: new OSM()
});
const clipLayer = new VectorLayer({
style: null,
source: new VectorSource({
url:
'./data/geojson/switzerland.geojson',
format: new GeoJSON()
})
});
const style = new Style({
fill: new Fill({
color: 'black'
})
});
base.on('postrender', function(e) {
e.context.globalCompositeOperation = 'destination-in';
const vectorContext = getVectorContext(e);
clipLayer.getSource().forEachFeature(function(feature) {
vectorContext.drawFeature(feature, style);
});
e.context.globalCompositeOperation = 'source-over';
});
const map = new Map({
layers: [base, clipLayer],
target: 'map',
view: new View({
center: fromLonLat([8.23, 46.86]),
zoom: 7
})
});

View File

@@ -0,0 +1,6 @@
.ol-rotate {
left: .5em;
bottom: .5em;
top: unset;
right: unset;
}

View File

@@ -1,5 +1,5 @@
---
layout: example-verbatim.html
layout: example.html
title: Vector tiles created from a Mapbox Style object
shortdesc: Example of using ol-mapbox-style with tiles from maptiler.com.
docs: >
@@ -10,27 +10,4 @@ cloak:
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>Mapbox Style objects with ol-mapbox-style</title>
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,String.prototype.startsWith,Object.assign"></script>
<style type="text/css">
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script src="common.js"></script>
<script src="mapbox-style.js"></script>
</body>
</html>
<div id="map" class="map"></div>

View File

@@ -1,3 +1,6 @@
import apply from 'ol-mapbox-style';
import FullScreen from '../src/ol/control/FullScreen.js';
apply('map', 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB');
apply('map', 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB').then(function(map) {
map.addControl(new FullScreen());
});

View File

@@ -4,7 +4,7 @@ title: Full-Screen Mobile
shortdesc: Example of a full screen map.
tags: "fullscreen, geolocation, mobile"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
---
<!doctype html>

View File

@@ -14,7 +14,7 @@ const map = new Map({
layers: [
new TileLayer({
source: new BingMaps({
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ',
imagerySet: 'RoadOnDemand'
})
})

View File

@@ -232,6 +232,7 @@ const map = new Map({
target: 'map',
view: new View({
center: [0, 1000000],
zoom: 2
zoom: 2,
multiWorld: true
})
});

View File

@@ -0,0 +1,9 @@
.map {
background: rgba(232, 230, 223, 1);
}
.ol-rotate {
left: .5em;
bottom: .5em;
top: unset;
right: unset;
}

View File

@@ -0,0 +1,10 @@
---
layout: example.html
title: Vector tiles rendered in an offscreen canvas
shortdesc: Example of a map that delegates rendering to a worker.
docs: >
The map in this example is rendered in a web worker, using `OffscreenCanvas`. **Note:** This is currently only supported in Chrome and Edge.
tags: "worker, offscreencanvas, vector-tiles"
experimental: true
---
<div id="map" class="map"></div>

View File

@@ -0,0 +1,125 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Layer from '../src/ol/layer/Layer.js';
import Worker from 'worker-loader!./offscreen-canvas.worker.js'; //eslint-disable-line
import {compose, create} from '../src/ol/transform.js';
import {createTransformString} from '../src/ol/render/canvas.js';
import {createXYZ} from '../src/ol/tilegrid.js';
import {FullScreen} from '../src/ol/control.js';
import stringify from 'json-stringify-safe';
import Source from '../src/ol/source/Source.js';
const worker = new Worker();
let container, transformContainer, canvas, rendering, workerFrameState, mainThreadFrameState;
// Transform the container to account for the differnece between the (newer)
// main thread frameState and the (older) worker frameState
function updateContainerTransform() {
if (workerFrameState) {
const viewState = mainThreadFrameState.viewState;
const renderedViewState = workerFrameState.viewState;
const center = viewState.center;
const resolution = viewState.resolution;
const rotation = viewState.rotation;
const renderedCenter = renderedViewState.center;
const renderedResolution = renderedViewState.resolution;
const renderedRotation = renderedViewState.rotation;
const transform = create();
// Skip the extra transform for rotated views, because it will not work
// correctly in that case
if (!rotation) {
compose(transform,
(renderedCenter[0] - center[0]) / resolution,
(center[1] - renderedCenter[1]) / resolution,
renderedResolution / resolution, renderedResolution / resolution,
rotation - renderedRotation,
0, 0);
}
transformContainer.style.transform = createTransformString(transform);
}
}
const map = new Map({
layers: [
new Layer({
render: function(frameState) {
if (!container) {
container = document.createElement('div');
container.style.position = 'absolute';
container.style.width = '100%';
container.style.height = '100%';
transformContainer = document.createElement('div');
transformContainer.style.position = 'absolute';
transformContainer.style.width = '100%';
transformContainer.style.height = '100%';
container.appendChild(transformContainer);
canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.left = '0';
canvas.style.transformOrigin = 'top left';
transformContainer.appendChild(canvas);
}
mainThreadFrameState = frameState;
updateContainerTransform();
if (!rendering) {
rendering = true;
worker.postMessage({
action: 'render',
frameState: JSON.parse(stringify(frameState))
});
} else {
frameState.animate = true;
}
return container;
},
source: new Source({
attributions: [
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a>',
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>'
]
})
})
],
target: 'map',
view: new View({
resolutions: createXYZ({tileSize: 512}).getResolutions89,
center: [0, 0],
zoom: 2
})
});
map.addControl(new FullScreen());
// Worker messaging and actions
worker.addEventListener('message', message => {
if (message.data.action === 'loadImage') {
// Image loader for ol-mapbox-style
const image = new Image();
image.crossOrigin = 'anonymous';
image.addEventListener('load', function() {
createImageBitmap(image, 0, 0, image.width, image.height).then(imageBitmap => {
worker.postMessage({
action: 'imageLoaded',
image: imageBitmap,
src: message.data.src
}, [imageBitmap]);
});
});
image.src = event.data.src;
} else if (message.data.action === 'requestRender') {
// Worker requested a new render frame
map.render();
} else if (canvas && message.data.action === 'rendered') {
// Worker provies a new render frame
requestAnimationFrame(function() {
const imageData = message.data.imageData;
canvas.width = imageData.width;
canvas.height = imageData.height;
canvas.getContext('2d').drawImage(imageData, 0, 0);
canvas.style.transform = message.data.transform;
workerFrameState = message.data.frameState;
updateContainerTransform();
});
rendering = false;
}
});

View File

@@ -0,0 +1,136 @@
import VectorTileLayer from '../src/ol/layer/VectorTile.js';
import VectorTileSource from '../src/ol/source/VectorTile.js';
import MVT from '../src/ol/format/MVT.js';
import {Projection} from '../src/ol/proj.js';
import TileQueue from '../src/ol/TileQueue.js';
import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js';
import {renderDeclutterItems} from '../src/ol/render.js';
import styleFunction from 'ol-mapbox-style/dist/stylefunction.js';
import {inView} from '../src/ol/layer/Layer.js';
import stringify from 'json-stringify-safe';
/** @type {any} */
const worker = self;
let frameState, pixelRatio, rendererTransform;
const canvas = new OffscreenCanvas(1, 1);
// OffscreenCanvas does not have a style, so we mock it
canvas.style = {};
const context = canvas.getContext('2d');
const sources = {
landcover: new VectorTileSource({
maxZoom: 9,
format: new MVT(),
url: 'https://api.maptiler.com/tiles/landcover/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB'
}),
contours: new VectorTileSource({
minZoom: 9,
maxZoom: 14,
format: new MVT(),
url: 'https://api.maptiler.com/tiles/contours/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB'
}),
openmaptiles: new VectorTileSource({
format: new MVT(),
maxZoom: 14,
url: 'https://api.maptiler.com/tiles/v3/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB'
})
};
const layers = [];
// Font replacement so we do not need to load web fonts in the worker
function getFont(font) {
return font[0]
.replace('Noto Sans', 'serif')
.replace('Roboto', 'sans-serif');
}
function loadStyles() {
const styleUrl = 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB';
fetch(styleUrl).then(data => data.json()).then(styleJson => {
const buckets = [];
let currentSource;
styleJson.layers.forEach(layer => {
if (!layer.source) {
return;
}
if (currentSource !== layer.source) {
currentSource = layer.source;
buckets.push({
source: layer.source,
layers: []
});
}
buckets[buckets.length - 1].layers.push(layer.id);
});
const spriteUrl = styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.json';
const spriteImageUrl = styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.png';
fetch(spriteUrl).then(data => data.json()).then(spriteJson => {
buckets.forEach(bucket => {
const source = sources[bucket.source];
if (!source) {
return;
}
const layer = new VectorTileLayer({
declutter: true,
source,
minZoom: source.getTileGrid().getMinZoom()
});
layer.getRenderer().useContainer = function(target, transform) {
this.containerReused = this.getLayer() !== layers[0];
this.canvas = canvas;
this.context = context;
this.container = {
firstElementChild: canvas
};
rendererTransform = transform;
};
styleFunction(layer, styleJson, bucket.layers, undefined, spriteJson, spriteImageUrl, getFont);
layers.push(layer);
});
worker.postMessage({action: 'requestRender'});
});
});
}
// Minimal map-like functionality for rendering
const tileQueue = new TileQueue(
(tile, tileSourceKey, tileCenter, tileResolution) => tilePriorityFunction(frameState, tile, tileSourceKey, tileCenter, tileResolution),
() => worker.postMessage({action: 'requestRender'}));
const maxTotalLoading = 8;
const maxNewLoads = 2;
worker.addEventListener('message', event => {
if (event.data.action !== 'render') {
return;
}
frameState = event.data.frameState;
if (!pixelRatio) {
pixelRatio = frameState.pixelRatio;
loadStyles();
}
frameState.tileQueue = tileQueue;
frameState.viewState.projection.__proto__ = Projection.prototype;
layers.forEach(layer => {
if (inView(layer.getLayerState(), frameState.viewState)) {
const renderer = layer.getRenderer();
renderer.renderFrame(frameState, canvas);
}
});
renderDeclutterItems(frameState, null);
if (tileQueue.getTilesLoading() < maxTotalLoading) {
tileQueue.reprioritize();
tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);
}
const imageData = canvas.transferToImageBitmap();
worker.postMessage({
action: 'rendered',
imageData: imageData,
transform: rendererTransform,
frameState: JSON.parse(stringify(frameState))
}, [imageData]);
});

View File

@@ -6,7 +6,7 @@ docs: >
<p>The map on the top preloads low resolution tiles. The map on the bottom does not use any preloading. Try zooming out and panning to see the difference.</p>
tags: "preload, bing"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
---
<div id="map1" class="map"></div>

View File

@@ -14,7 +14,7 @@ const map1 = new Map({
new TileLayer({
preload: Infinity,
source: new BingMaps({
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ',
imagerySet: 'Aerial'
})
})
@@ -28,7 +28,7 @@ const map2 = new Map({
new TileLayer({
preload: 0, // default value
source: new BingMaps({
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ',
imagerySet: 'AerialWithLabelsOnDemand'
})
})

View File

@@ -6,12 +6,12 @@ docs: >
This example shows client-side raster reprojection capabilities from
OSM (EPSG:3857) to arbitrary projection by searching
in <a href="https://epsg.io/">EPSG.io</a> database.
tags: "reprojection, projection, proj4js, epsg.io"
tags: "reprojection, projection, proj4js, epsg.io, graticule"
---
<div id="map" class="map"></div>
<form class="form-inline">
<label for="epsg-query">Search projection:</label>
<input type="text" id="epsg-query" placeholder="4326, 27700, US National Atlas, Swiss, France, ..." class="form-control" size="50" />
<input type="text" id="epsg-query" placeholder="4326, 27700, 3031, US National Atlas, Swiss, France, ..." class="form-control" size="50" />
<button id="epsg-search" class="btn">Search</button>
<span id="epsg-result"></span>
<div>
@@ -19,5 +19,9 @@ tags: "reprojection, projection, proj4js, epsg.io"
Render reprojection edges
<input type="checkbox" id="render-edges">
</label>
<label for="show-graticule">
&nbsp;&nbsp;&nbsp;Show graticule
<input type="checkbox" id="show-graticule" />
</label>
</div>
</form>

View File

@@ -1,19 +1,34 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {applyTransform} from '../src/ol/extent.js';
import Graticule from '../src/ol/layer/Graticule.js';
import TileLayer from '../src/ol/layer/Tile.js';
import {get as getProjection, getTransform} from '../src/ol/proj.js';
import {register} from '../src/ol/proj/proj4.js';
import OSM from '../src/ol/source/OSM.js';
import TileImage from '../src/ol/source/TileImage.js';
import Stroke from '../src/ol/style/Stroke.js';
import proj4 from 'proj4';
const graticule = new Graticule({
// the style to use for the lines, optional.
strokeStyle: new Stroke({
color: 'rgba(255,120,0,0.9)',
width: 2,
lineDash: [0.5, 4]
}),
showLabels: true,
visible: false,
wrapX: false
});
const map = new Map({
layers: [
new TileLayer({
source: new OSM()
})
}),
graticule
],
target: 'map',
view: new View({
@@ -28,6 +43,7 @@ const queryInput = document.getElementById('epsg-query');
const searchButton = document.getElementById('epsg-search');
const resultSpan = document.getElementById('epsg-result');
const renderEdgesCheckbox = document.getElementById('render-edges');
const showGraticuleCheckbox = document.getElementById('show-graticule');
function setProjection(code, name, proj4def, bbox) {
if (code === null || name === null || proj4def === null || bbox === null) {
@@ -48,9 +64,15 @@ function setProjection(code, name, proj4def, bbox) {
const newProj = getProjection(newProjCode);
const fromLonLat = getTransform('EPSG:4326', newProj);
// very approximate calculation of projection extent
const extent = applyTransform(
[bbox[1], bbox[2], bbox[3], bbox[0]], fromLonLat);
let worldExtent = [bbox[1], bbox[2], bbox[3], bbox[0]];
newProj.setWorldExtent(worldExtent);
// approximate calculation of projection extent,
// checking if the world extent crosses the dateline
if (bbox[1] > bbox[3]) {
worldExtent = [bbox[1], bbox[2], bbox[3] + 360, bbox[0]];
}
const extent = applyTransform(worldExtent, fromLonLat, undefined, 8);
newProj.setExtent(extent);
const newView = new View({
projection: newProj
@@ -98,7 +120,7 @@ searchButton.onclick = function(event) {
/**
* Handle change event.
* Handle checkbox change event.
*/
renderEdgesCheckbox.onchange = function() {
map.getLayers().forEach(function(layer) {
@@ -110,3 +132,10 @@ renderEdgesCheckbox.onchange = function() {
}
});
};
/**
* Handle checkbox change event.
*/
showGraticuleCheckbox.onchange = function() {
graticule.setVisible(showGraticuleCheckbox.checked);
};

View File

@@ -57,6 +57,8 @@
event.preventDefault();
const html = document.getElementById('example-html-source').innerText;
const js = document.getElementById('example-js-source').innerText;
const workerContainer = document.getElementById('example-worker-source');
const worker = workerContainer ? workerContainer.innerText : undefined;
const pkgJson = document.getElementById('example-pkg-source').innerText;
const form = document.getElementById('codepen-form');
@@ -68,22 +70,28 @@
Promise.all(promises)
.then(results => {
const data = {
files: {
'index.html': {
content: html
},
'index.js': {
content: js
},
"package.json": {
content: pkgJson
},
'sandbox.config.json': {
content: '{"template": "parcel"}'
}
const files = {
'index.html': {
content: html
},
'index.js': {
content: js
},
"package.json": {
content: pkgJson
},
'sandbox.config.json': {
content: '{"template": "parcel"}'
}
};
if (worker) {
files['worker.js'] = {
content: worker
}
}
const data = {
files: files
};
for (let i = 0; i < localResources.length; i++) {
data.files[localResources[i]] = results[i];

View File

@@ -10,7 +10,7 @@ docs: >
tags: "draw, edit, modify, vector, snap"
---
<div id="map" class="map"></div>
<form id="options-form" automplete="off">
<form id="options-form" autocomplete="off">
<div class="radio">
<label>
<input type="radio" name="interaction" value="draw" id="draw" checked>

View File

@@ -17,8 +17,8 @@ register(proj4);
// and a world extent. These are required for the Graticule.
const sphereMollweideProjection = new Projection({
code: 'ESRI:53009',
extent: [-9009954.605703328, -9009954.605703328,
9009954.605703328, 9009954.605703328],
extent: [-18019909.21177587, -9009954.605703328,
18019909.21177587, 9009954.605703328],
worldExtent: [-179, -89.99, 179, 89.99]
});
@@ -37,6 +37,6 @@ const map = new Map({
view: new View({
center: [0, 0],
projection: sphereMollweideProjection,
zoom: 0
zoom: 1
})
});

View File

@@ -67,9 +67,9 @@
<link rel="stylesheet" href="./resources/prism/prism.css" type="text/css">
<link rel="stylesheet" href="./css/ol.css" type="text/css">
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
{{{ extraHead.local }}}
{{{ css.tag }}}
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
<title>{{ title }}</title>
</head>
@@ -160,6 +160,14 @@
<pre><legend>index.js</legend><code id="example-js-source" class="language-js">import 'ol/ol.css';
{{ js.source }}</code></pre>
</div>
{{#if worker.source}}
<div class="row-fluid">
<div class="source-controls">
<a class="copy-button" id="copy-worker-button" data-clipboard-target="#example-worker-source"><i class="fa fa-clipboard"></i> Copy</a>
</div>
<pre><legend>worker.js</legend><code id="example-worker-source" class="language-js">{{ worker.source }}</code></pre>
</div>
{{/if}}
<div class="row-fluid">
<div class="source-controls">
<a class="copy-button" id="copy-pkg-button" data-clipboard-target="#example-pkg-source"><i class="fa fa-clipboard"></i> Copy</a>
@@ -167,7 +175,6 @@
<pre><legend>package.json</legend><code id="example-pkg-source" class="language-js">{{ pkgJson }}</code></pre>
</div>
</div>
<script src="./resources/common.js"></script>
<script src="./resources/prism/prism.min.js"></script>
{{{ js.tag }}}

View File

@@ -1,19 +1,5 @@
This folder contains example templates. These templates are used to build the examples in the `examples/` folder. The resulting examples are written to the `build/examples` folder.
Although the main purpose of these examples is to demonstrate how to use the API, they also serve other purposes in the development cycle, and so are not exactly as they would be in normal application code:
* every time the library changes, they are compiled together with the library as a basic check that they remain in sync with the library
* they use a special loader script to enable defining at run time which build mode (raw/debug/advanced) to use
To enable this, examples have the following, not needed in application code:
* each html file loads `loader.js`; application code would not need this, but would instead load the appropriate library build file, either a hosted version or a custom build
* each js file starts with `goog.require` functions, used by the compiler; application code would only have these if the code is to be compiled together with the library and/or Closure library
* some js files use type definitions (comments with @type tags); these are also used by the compiler, and are only needed if the code is to be compiled together with the library
* html files load `resources/common.js` and some scripts use `common.getRendererFromQueryString()` to set the map renderer; application code would not need these
The examples are transpiled to es5. If the name of an example starts with `es2015-`, transpilation will be bypassed. This allows for showing es2015+ features in examples.
At the bottom of each example generated in the `build/examples` folder, a modified version of its source code is shown. That modified version can be run standalone and is usually used as starting point for users to extend examples into their own application.

View File

@@ -4,9 +4,9 @@ title: OSM XML
shortdesc: Example of using the OSM XML source.
docs: >
OSM XML vector data is loaded dynamically from a the [Overpass API](http://overpass-api.de) using a bbox strategy. Note that panning and zooming will eventually lead to "Too many requests" errors from the Overpass API.
tags: "vector, osmxml, loading, server, strategy, bbox"
tags: "vector, osmxml, loading, server, strategy, bbox, maptiler"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<div id="map" class="map"></div>

View File

@@ -4,7 +4,7 @@ import OSMXML from '../src/ol/format/OSMXML.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {bbox as bboxStrategy} from '../src/ol/loadingstrategy.js';
import {transformExtent} from '../src/ol/proj.js';
import BingMaps from '../src/ol/source/BingMaps.js';
import XYZ from '../src/ol/source/XYZ.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
@@ -85,8 +85,8 @@ const vectorSource = new VectorSource({
vectorSource.addFeatures(features);
});
const query = '(node(' +
epsg4326Extent[1] + ',' + epsg4326Extent[0] + ',' +
epsg4326Extent[3] + ',' + epsg4326Extent[2] +
epsg4326Extent[1] + ',' + Math.max(epsg4326Extent[0], -180) + ',' +
epsg4326Extent[3] + ',' + Math.min(epsg4326Extent[2], 180) +
');rel(bn)->.foo;way(bn);node(w)->.foo;rel(bw););out meta;';
client.send(query);
},
@@ -110,10 +110,15 @@ const vector = new VectorLayer({
}
});
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>';
const raster = new TileLayer({
source: new BingMaps({
imagerySet: 'Aerial',
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
source: new XYZ({
attributions: attributions,
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
maxZoom: 20
})
});

View File

@@ -6,9 +6,9 @@ docs: >
This example generates a `GetFeature` request which uses a `PropertyIsEqualTo`
and a `PropertyIsLike` filter, and then posts the request to load the features
that match the query.
tags: "vector, WFS, GetFeature, filter"
tags: "vector, WFS, GetFeature, filter, maptiler"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<div id="map" class="map"></div>

View File

@@ -7,7 +7,7 @@ import {
} from '../src/ol/format/filter.js';
import {WFS, GeoJSON} from '../src/ol/format.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import BingMaps from '../src/ol/source/BingMaps.js';
import XYZ from '../src/ol/source/XYZ.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Stroke, Style} from '../src/ol/style.js';
@@ -23,10 +23,15 @@ const vector = new VectorLayer({
})
});
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>';
const raster = new TileLayer({
source: new BingMaps({
imagerySet: 'Aerial',
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
source: new XYZ({
attributions: attributions,
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
maxZoom: 20
})
});

View File

@@ -4,9 +4,9 @@ title: WFS
shortdesc: Example of using WFS with a BBOX strategy.
docs: >
This example loads new features from GeoServer WFS when the view extent changes.
tags: "vector, WFS, bbox, loading, server"
tags: "vector, WFS, bbox, loading, server, maptiler"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<div id="map" class="map"></div>

View File

@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {bbox as bboxStrategy} from '../src/ol/loadingstrategy.js';
import BingMaps from '../src/ol/source/BingMaps.js';
import XYZ from '../src/ol/source/XYZ.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Stroke, Style} from '../src/ol/style.js';
@@ -30,10 +30,15 @@ const vector = new VectorLayer({
})
});
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>';
const raster = new TileLayer({
source: new BingMaps({
imagerySet: 'Aerial',
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
source: new XYZ({
attributions: attributions,
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
maxZoom: 20
})
});

View File

@@ -22,7 +22,7 @@ module.exports = {
stats: 'minimal',
module: {
rules: [{
test: /\.js$/,
test: /^((?!es2015-)[\s\S])*\.js$/,
use: {
loader: 'buble-loader'
},

View File

@@ -208,6 +208,10 @@ ExampleBuilder.prototype.render = async function(dir, chunk) {
jsSource = jsSource.replace(new RegExp(entry.key, 'g'), entry.value);
}
}
// Remove worker loader import and modify `new Worker()` to add source
jsSource = jsSource.replace(/import Worker from 'worker-loader![^\n]*\n/g, '');
jsSource = jsSource.replace('new Worker()', 'new Worker(\'./worker.js\')');
data.js = {
tag: `<script src="${this.common}.js"></script><script src="${jsName}"></script>`,
source: jsSource
@@ -218,9 +222,33 @@ ExampleBuilder.prototype.render = async function(dir, chunk) {
data.js.tag = prelude + data.js.tag;
}
// check for worker js
const workerName = `${name}.worker.js`;
const workerPath = path.join(dir, workerName);
let workerSource;
try {
workerSource = await readFile(workerPath, readOptions);
} catch (err) {
// pass
}
if (workerSource) {
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
workerSource = workerSource.replace(/'\.\.\/src\//g, '\'');
workerSource = workerSource.replace(/\.js';/g, '\';');
if (data.cloak) {
for (const entry of data.cloak) {
workerSource = workerSource.replace(new RegExp(entry.key, 'g'), entry.value);
}
}
data.worker = {
source: workerSource
};
assets[workerName] = workerSource;
}
data.pkgJson = JSON.stringify({
name: name,
dependencies: getDependencies(jsSource),
dependencies: getDependencies(jsSource + workerSource ? `\n${workerSource}` : ''),
devDependencies: {
parcel: '1.11.0'
},

View File

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

View File

@@ -3,26 +3,18 @@ import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import XYZ from '../src/ol/source/XYZ.js';
// The tile size supported by the ArcGIS tile service.
const tileSize = 512;
const urlTemplate = 'https://services.arcgisonline.com/arcgis/rest/services/' +
'ESRI_Imagery_World_2D/MapServer/tile/{z}/{y}/{x}';
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new XYZ({
attributions: 'Copyright:© 2013 ESRI, i-cubed, GeoEye',
maxZoom: 16,
url: 'https://services.arcgisonline.com/arcgis/rest/services/' +
'ESRI_Imagery_World_2D/MapServer/tile/{z}/{y}/{x}',
maxZoom: 15,
projection: 'EPSG:4326',
tileSize: tileSize,
tileUrlFunction: function(tileCoord) {
return urlTemplate.replace('{z}', (tileCoord[0] - 1).toString())
.replace('{x}', tileCoord[1].toString())
.replace('{y}', tileCoord[2].toString());
},
tileSize: 512, // the tile size supported by the ArcGIS tile service
maxResolution: 180 / 512, // Esri's tile grid fits 180 degrees on one 512 px tile
wrapX: true
})
})

2875
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.2.1",
"version": "6.3.1",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -24,6 +24,7 @@
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json",
"typecheck": "tsc --pretty",
"apidoc-debug": "shx rm -rf build/apidoc && node --inspect-brk=9229 ./node_modules/jsdoc/jsdoc.js -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc",
"apidoc": "shx rm -rf build/apidoc && jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
},
"main": "index.js",
@@ -35,6 +36,10 @@
"bugs": {
"url": "https://github.com/openlayers/openlayers/issues"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/openlayers"
},
"dependencies": {
"elm-pep": "^1.0.4",
"pbf": "3.2.1",
@@ -50,58 +55,58 @@
"@types/pbf": "^3.0.2",
"@types/topojson-specification": "^1.0.1",
"babel-loader": "^8.0.5",
"buble": "^0.19.7",
"buble": "^0.20.0",
"buble-loader": "^0.5.1",
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.4",
"coveralls": "3.0.9",
"coveralls": "3.0.11",
"eslint": "^6.0.0",
"eslint-config-openlayers": "^13.0.0",
"expect.js": "0.3.1",
"front-matter": "^3.0.2",
"fs-extra": "^8.0.0",
"fs-extra": "^9.0.0",
"glob": "^7.1.5",
"globby": "^11.0.0",
"handlebars": "4.7.3",
"html-to-image": "^0.1.0",
"handlebars": "4.7.4",
"istanbul": "0.4.5",
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "3.4.1",
"jsdoc": "3.6.3",
"jsdoc-plugin-typescript": "^2.0.5",
"json-stringify-safe": "^5.0.1",
"karma": "^4.4.1",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "^2.0.1",
"karma-coverage-istanbul-reporter": "^2.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "1.3.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-rc.2",
"loglevelnext": "^3.0.1",
"marked": "0.8.0",
"mocha": "7.0.1",
"ol-mapbox-style": "^6.0.0",
"marked": "0.8.2",
"mocha": "7.1.1",
"ol-mapbox-style": "^6.1.1",
"pixelmatch": "^5.1.0",
"pngjs": "^3.4.0",
"proj4": "2.6.0",
"proj4": "2.6.1",
"puppeteer": "~2.1.0",
"rollup": "^1.25.1",
"rollup": "^2.1.0",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^5.0.0",
"serve-static": "^1.14.0",
"shx": "^0.3.2",
"sinon": "^8.0.0",
"sinon": "^9.0.0",
"terser-webpack-plugin": "^2.0.1",
"typescript": "3.5.3",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.41.5",
"webpack": "4.42.1",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"worker-loader": "^2.0.0",
"yargs": "^15.0.2"
},
"eslintConfig": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,47 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js';
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
import Point from '../../../src/ol/geom/Point.js';
import Feature from '../../../src/ol/Feature.js';
import {fromLonLat} from '../../../src/ol/proj.js';
import {Style, Icon} from '../../../src/ol/style.js';
const center = fromLonLat([8.6, 50.1]);
new Map({
layers: [
new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
})
}),
new VectorLayer({
style: function() {
return new Style({
image: new Icon({
opacity: 0.5,
src: '/data/icon.png',
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels'
})
});
},
source: new VectorSource({
features: [
new Feature(
new Point(center)
)
]
})
})
],
target: 'map',
view: new View({
center: center,
zoom: 3
})
});
render();

BIN
sponsor-logos/pozi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -26,7 +26,7 @@ export class CollectionEvent extends Event {
/**
* @param {CollectionEventType} type Type.
* @param {*=} opt_element Element.
* @param {number} opt_index The index of the added or removed element.
* @param {number=} opt_index The index of the added or removed element.
*/
constructor(type, opt_element, opt_index) {
super(type);

View File

@@ -275,7 +275,9 @@ class MapBrowserEventHandler extends EventTarget {
* @private
*/
handleTouchMove_(event) {
if (this.originalPointerMoveEvent_.defaultPrevented) {
// Due to https://github.com/mpizenberg/elm-pep/issues/2, `this.originalPointerMoveEvent_`
// may not be initialized yet when we get here on a platform without native pointer events.
if (!this.originalPointerMoveEvent_ || this.originalPointerMoveEvent_.defaultPrevented) {
event.preventDefault();
}
}

View File

@@ -51,7 +51,7 @@ class Observable extends EventTarget {
/**
* Listen for a certain type of event.
* @param {string|Array<string>} type The event type or array of event types.
* @param {function(?): ?} listener The listener function.
* @param {import("./events.js").ListenerFunction} listener The listener function.
* @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If
* called with an array of event types as the first argument, the return
* will be an array of keys.

View File

@@ -37,15 +37,21 @@ import {containsExtent} from './extent.js';
* container as that of the controls (see the `stopEvent` option) you will
* probably set `insertFirst` to `true` so the overlay is displayed below the
* controls.
* @property {boolean} [autoPan=false] If set to `true` the map is panned when
* calling `setPosition`, so that the overlay is entirely visible in the current
* viewport.
* @property {PanOptions} [autoPanAnimation] The
* animation options used to pan the overlay into view. This animation is only
* used when `autoPan` is enabled. A `duration` and `easing` may be provided to
* customize the animation.
* @property {PanIntoViewOptions|boolean} [autoPan=false] Pan the map when calling
* `setPosition`, so that the overlay is entirely visible in the current viewport?
* If `true` (deprecated), then `autoPanAnimation` and `autoPanMargin` will be
* used to determine the panning parameters; if an object is supplied then other
* parameters are ignored.
* @property {PanOptions} [autoPanAnimation] The animation options used to pan
* the overlay into view. This animation is only used when `autoPan` is enabled.
* A `duration` and `easing` may be provided to customize the animation.
* Deprecated and ignored if `autoPan` is supplied as an object.
* @property {number} [autoPanMargin=20] The margin (in pixels) between the
* overlay and the borders of the map when autopanning.
* overlay and the borders of the map when autopanning. Deprecated and ignored
* if `autoPan` is supplied as an object.
* @property {PanIntoViewOptions} [autoPanOptions] The options to use for the
* autoPan. This is only used when `autoPan` is enabled and has preference over
* the individual `autoPanMargin` and `autoPanOptions`.
* @property {string} [className='ol-overlay-container ol-selectable'] CSS class
* name.
*/
@@ -60,6 +66,12 @@ import {containsExtent} from './extent.js';
* Default is {@link module:ol/easing~inAndOut}.
*/
/**
* @typedef {Object} PanIntoViewOptions
* @property {PanOptions} [animation={}] The animation parameters for the pan
* @property {number} [margin=20] The margin (in pixels) between the
* overlay and the borders of the map when panning into view.
*/
/**
* @enum {string}
@@ -137,38 +149,26 @@ class Overlay extends BaseObject {
options.className : 'ol-overlay-container ' + CLASS_SELECTABLE;
this.element.style.position = 'absolute';
let autoPan = options.autoPan;
if (autoPan && ('object' !== typeof autoPan)) {
autoPan = {
animation: options.autoPanAnimation,
margin: options.autoPanMargin
};
}
/**
* @protected
* @type {boolean}
* @type {PanIntoViewOptions|false}
*/
this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
this.autoPan = /** @type {PanIntoViewOptions} */(autoPan) || false;
/**
* @protected
* @type {PanOptions}
*/
this.autoPanAnimation = options.autoPanAnimation || /** @type {PanOptions} */ ({});
/**
* @protected
* @type {number}
*/
this.autoPanMargin = options.autoPanMargin !== undefined ?
options.autoPanMargin : 20;
/**
* @protected
* @type {{bottom_: string,
* left_: string,
* right_: string,
* top_: string,
* @type {{transform_: string,
* visible: boolean}}
*/
this.rendered = {
bottom_: '',
left_: '',
right_: '',
top_: '',
transform_: '',
visible: true
};
@@ -300,6 +300,7 @@ class Overlay extends BaseObject {
} else {
container.appendChild(this.element);
}
this.performAutoPan();
}
}
@@ -322,9 +323,7 @@ class Overlay extends BaseObject {
*/
handlePositionChanged() {
this.updatePixelPosition();
if (this.get(Property.POSITION) && this.autoPan) {
this.panIntoView();
}
this.performAutoPan();
}
/**
@@ -378,14 +377,26 @@ class Overlay extends BaseObject {
}
/**
* Pan the map so that the overlay is entirely visible in the current viewport
* (if necessary).
* Pan the map so that the overlay is entirely visisble in the current viewport
* (if necessary) using the configured autoPan parameters
* @protected
*/
panIntoView() {
performAutoPan() {
if (this.autoPan) {
this.panIntoView(this.autoPan);
}
}
/**
* Pan the map so that the overlay is entirely visible in the current viewport
* (if necessary).
* @param {PanIntoViewOptions|undefined} panIntoViewOptions Options for the pan action
* @api
*/
panIntoView(panIntoViewOptions) {
const map = this.getMap();
if (!map || !map.getTargetElement()) {
if (!map || !map.getTargetElement() || !this.get(Property.POSITION)) {
return;
}
@@ -393,7 +404,7 @@ class Overlay extends BaseObject {
const element = this.getElement();
const overlayRect = this.getRect(element, [outerWidth(element), outerHeight(element)]);
const margin = this.autoPanMargin;
const myMargin = (panIntoViewOptions.margin === undefined) ? 20 : panIntoViewOptions.margin;
if (!containsExtent(mapRect, overlayRect)) {
// the overlay is not completely inside the viewport, so pan the map
const offsetLeft = overlayRect[0] - mapRect[0];
@@ -404,17 +415,17 @@ class Overlay extends BaseObject {
const delta = [0, 0];
if (offsetLeft < 0) {
// move map to the left
delta[0] = offsetLeft - margin;
delta[0] = offsetLeft - myMargin;
} else if (offsetRight < 0) {
// move map to the right
delta[0] = Math.abs(offsetRight) + margin;
delta[0] = Math.abs(offsetRight) + myMargin;
}
if (offsetTop < 0) {
// move map up
delta[1] = offsetTop - margin;
delta[1] = offsetTop - myMargin;
} else if (offsetBottom < 0) {
// move map down
delta[1] = Math.abs(offsetBottom) + margin;
delta[1] = Math.abs(offsetBottom) + myMargin;
}
if (delta[0] !== 0 || delta[1] !== 0) {
@@ -425,10 +436,11 @@ class Overlay extends BaseObject {
centerPx[1] + delta[1]
];
const panOptions = panIntoViewOptions.animation || {};
map.getView().animateInternal({
center: map.getCoordinateFromPixelInternal(newCenterPx),
duration: this.autoPanAnimation.duration,
easing: this.autoPanAnimation.easing
duration: panOptions.duration,
easing: panOptions.easing
});
}
}
@@ -506,63 +518,34 @@ class Overlay extends BaseObject {
this.setVisible(true);
let offsetX = offset[0];
let offsetY = offset[1];
const x = Math.round(pixel[0] + offset[0]) + 'px';
const y = Math.round(pixel[1] + offset[1]) + 'px';
let posX = '0%';
let posY = '0%';
if (positioning == OverlayPositioning.BOTTOM_RIGHT ||
positioning == OverlayPositioning.CENTER_RIGHT ||
positioning == OverlayPositioning.TOP_RIGHT) {
if (this.rendered.left_ !== '') {
this.rendered.left_ = '';
style.left = '';
}
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
if (this.rendered.right_ != right) {
this.rendered.right_ = right;
style.right = right;
}
} else {
if (this.rendered.right_ !== '') {
this.rendered.right_ = '';
style.right = '';
}
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
positioning == OverlayPositioning.CENTER_CENTER ||
positioning == OverlayPositioning.TOP_CENTER) {
offsetX -= this.element.offsetWidth / 2;
}
const left = Math.round(pixel[0] + offsetX) + 'px';
if (this.rendered.left_ != left) {
this.rendered.left_ = left;
style.left = left;
}
posX = '-100%';
} else if (positioning == OverlayPositioning.BOTTOM_CENTER ||
positioning == OverlayPositioning.CENTER_CENTER ||
positioning == OverlayPositioning.TOP_CENTER) {
posX = '-50%';
}
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
positioning == OverlayPositioning.BOTTOM_CENTER ||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
if (this.rendered.top_ !== '') {
this.rendered.top_ = '';
style.top = '';
}
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
if (this.rendered.bottom_ != bottom) {
this.rendered.bottom_ = bottom;
style.bottom = bottom;
}
} else {
if (this.rendered.bottom_ !== '') {
this.rendered.bottom_ = '';
style.bottom = '';
}
if (positioning == OverlayPositioning.CENTER_LEFT ||
positioning == OverlayPositioning.CENTER_CENTER ||
positioning == OverlayPositioning.CENTER_RIGHT) {
offsetY -= this.element.offsetHeight / 2;
}
const top = Math.round(pixel[1] + offsetY) + 'px';
if (this.rendered.top_ != top) {
this.rendered.top_ = 'top';
style.top = top;
}
posY = '-100%';
} else if (positioning == OverlayPositioning.CENTER_LEFT ||
positioning == OverlayPositioning.CENTER_CENTER ||
positioning == OverlayPositioning.CENTER_RIGHT) {
posY = '-50%';
}
const transform = `translate(${posX}, ${posY}) translate(${x}, ${y})`;
if (this.rendered.transform_ != transform) {
this.rendered.transform_ = transform;
style.transform = transform;
// @ts-ignore IE9
style.msTransform = transform;
}
}

View File

@@ -12,7 +12,7 @@ import MapProperty from './MapProperty.js';
import RenderEventType from './render/EventType.js';
import BaseObject, {getChangeEventType} from './Object.js';
import ObjectEventType from './ObjectEventType.js';
import TileQueue from './TileQueue.js';
import TileQueue, {getTilePriority} from './TileQueue.js';
import View from './View.js';
import ViewHint from './ViewHint.js';
import {assert} from './asserts.js';
@@ -24,7 +24,6 @@ import {TRUE} from './functions.js';
import {DEVICE_PIXEL_RATIO, IMAGE_DECODE, PASSIVE_EVENT_LISTENERS} from './has.js';
import LayerGroup from './layer/Group.js';
import {hasArea} from './size.js';
import {DROP} from './structs/PriorityQueue.js';
import {create as createTransform, apply as applyTransform} from './transform.js';
import {toUserCoordinate, fromUserCoordinate} from './proj.js';
@@ -891,26 +890,7 @@ class PluggableMap extends BaseObject {
* @return {number} Tile priority.
*/
getTilePriority(tile, tileSourceKey, tileCenter, tileResolution) {
// Filter out tiles at higher zoom levels than the current zoom level, or that
// are outside the visible extent.
const frameState = this.frameState_;
if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {
return DROP;
}
if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {
return DROP;
}
// Prioritize the highest zoom level tiles closest to the focus.
// Tiles at higher zoom levels are prioritized using Math.log(tileResolution).
// Within a zoom level, tiles are prioritized by the distance in pixels between
// the center of the tile and the center of the viewport. The factor of 65536
// means that the prioritization should behave as desired for tiles up to
// 65536 * Math.log(2) = 45426 pixels from the focus.
const center = frameState.viewState.center;
const deltaX = tileCenter[0] - center[0];
const deltaY = tileCenter[1] - center[1];
return 65536 * Math.log(tileResolution) +
Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
return getTilePriority(this.frameState_, tile, tileSourceKey, tileCenter, tileResolution);
}
/**
@@ -934,7 +914,7 @@ class PluggableMap extends BaseObject {
}
const target = /** @type {Node} */ (mapBrowserEvent.originalEvent.target);
if (!mapBrowserEvent.dragging) {
if (this.overlayContainerStopEvent_.contains(target) || !document.body.contains(target)) {
if (this.overlayContainerStopEvent_.contains(target) || !(document.body.contains(target) || this.viewport_.getRootNode && this.viewport_.getRootNode().contains(target))) {
// Abort if the event target is a child of the container that doesn't allow
// event propagation or is no longer in the page. It's possible for the target to no longer
// be in the page if it has been removed in an event listener, this might happen in a Control

View File

@@ -7,7 +7,7 @@ import {fromKey, getKey} from './tilecoord.js';
class TileCache extends LRUCache {
/**
* @param {!Object<string, import("./TileRange.js").default>} usedTiles Used tiles.
* @param {!Object<string, boolean>} usedTiles Used tiles.
*/
expireCache(usedTiles) {
while (this.canExpireCache()) {

View File

@@ -3,7 +3,7 @@
*/
import TileState from './TileState.js';
import EventType from './events/EventType.js';
import PriorityQueue from './structs/PriorityQueue.js';
import PriorityQueue, {DROP} from './structs/PriorityQueue.js';
/**
@@ -119,3 +119,34 @@ class TileQueue extends PriorityQueue {
export default TileQueue;
/**
* @param {import('./PluggableMap.js').FrameState} frameState Frame state.
* @param {import("./Tile.js").default} tile Tile.
* @param {string} tileSourceKey Tile source key.
* @param {import("./coordinate.js").Coordinate} tileCenter Tile center.
* @param {number} tileResolution Tile resolution.
* @return {number} Tile priority.
*/
export function getTilePriority(frameState, tile, tileSourceKey, tileCenter, tileResolution) {
// Filter out tiles at higher zoom levels than the current zoom level, or that
// are outside the visible extent.
if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {
return DROP;
}
if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {
return DROP;
}
// Prioritize the highest zoom level tiles closest to the focus.
// Tiles at higher zoom levels are prioritized using Math.log(tileResolution).
// Within a zoom level, tiles are prioritized by the distance in pixels between
// the center of the tile and the center of the viewport. The factor of 65536
// means that the prioritization should behave as desired for tiles up to
// 65536 * Math.log(2) = 45426 pixels from the focus.
const center = frameState.viewState.center;
const deltaX = tileCenter[0] - center[0];
const deltaY = tileCenter[1] - center[1];
return 65536 * Math.log(tileResolution) +
Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
}

View File

@@ -405,7 +405,6 @@ class View extends BaseObject {
} else if (options.zoom !== undefined) {
this.setZoom(options.zoom);
}
this.resolveConstraints(0);
this.setProperties(properties);
@@ -609,10 +608,15 @@ class View extends BaseObject {
if (series[0].callback) {
animationCallback(series[0].callback, false);
}
anchor = anchor ||
series.filter(function(animation) {
return !animation.complete;
})[0].anchor;
if (!anchor) {
for (let j = 0, jj = series.length; j < jj; ++j) {
const animation = series[j];
if (!animation.complete) {
anchor = animation.anchor;
break;
}
}
}
}
this.animations_.length = 0;
this.cancelAnchor_ = anchor;
@@ -762,6 +766,7 @@ class View extends BaseObject {
*/
setViewportSize(opt_size) {
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
this.resolveConstraints(0);
}
/**
@@ -793,6 +798,13 @@ class View extends BaseObject {
return this.constraints_;
}
/**
* @return {boolean} Resolution constraint is set
*/
getConstrainResolution() {
return this.options_.constrainResolution;
}
/**
* @param {Array<number>=} opt_hints Destination array.
* @return {Array<number>} Hint.

View File

@@ -9,6 +9,29 @@ import EventType from '../events/EventType.js';
const events = ['fullscreenchange', 'webkitfullscreenchange', 'MSFullscreenChange'];
/**
* @enum {string}
*/
const FullScreenEventType = {
/**
* Triggered after the map entered fullscreen.
* @event FullScreenEventType#enterfullscreen
* @api
*/
ENTERFULLSCREEN: 'enterfullscreen',
/**
* Triggered after the map leave fullscreen.
* @event FullScreenEventType#leavefullscreen
* @api
*/
LEAVEFULLSCREEN: 'leavefullscreen'
};
/**
* @typedef {Object} Options
* @property {string} [className='ol-full-screen'] CSS class name.
@@ -38,6 +61,8 @@ const events = ['fullscreenchange', 'webkitfullscreenchange', 'MSFullscreenChang
* The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
* toggle the map in full screen mode.
*
* @fires FullScreenEventType#enterfullscreen
* @fires FullScreenEventType#leavefullscreen
* @api
*/
class FullScreen extends Control {
@@ -162,9 +187,11 @@ class FullScreen extends Control {
if (isFullScreen()) {
this.setClassName_(this.button_, true);
replaceNode(this.labelActiveNode_, this.labelNode_);
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
} else {
this.setClassName_(this.button_, false);
replaceNode(this.labelNode_, this.labelActiveNode_);
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
}
if (map) {
map.updateSize();

View File

@@ -17,6 +17,7 @@ import {replaceNode} from '../dom.js';
import {listen, listenOnce} from '../events.js';
import EventType from '../events/EventType.js';
import {containsExtent, equals as equalsExtent, getBottomRight, getTopLeft, scaleFromCenter} from '../extent.js';
import View from '../View.js';
/**
@@ -59,8 +60,8 @@ class ControlledMap extends PluggableMap {
* @property {HTMLElement|string} [target] Specify a target if you want the control
* to be rendered outside of the map's viewport.
* @property {string} [tipLabel='Overview map'] Text label to use for the button tip.
* @property {import("../View.js").default} [view] Custom view for the overview map. If not provided,
* a default view with an EPSG:3857 projection will be used.
* @property {View} [view] Custom view for the overview map (should use same projection as main map). If not provided,
* a default view with the same projection as the main map will be used.
*/
@@ -167,6 +168,13 @@ class OverviewMap extends Control {
this.ovmapDiv_ = document.createElement('div');
this.ovmapDiv_.className = 'ol-overviewmap-map';
/**
* Explicitly given view to be used instead of a view derived from the main map.
* @type {View}
* @private
*/
this.view_ = options.view;
/**
* @type {ControlledMap}
* @private
@@ -303,6 +311,14 @@ class OverviewMap extends Control {
* @private
*/
bindView_(view) {
if (!this.view_) {
// Unless an explicit view definition was given, derive default from whatever main map uses.
const newView = new View({
projection: view.getProjection()
});
this.ovmap_.setView(newView);
}
view.addEventListener(getChangeEventType(ViewProperty.ROTATION), this.boundHandleRotationChanged_);
// Sync once with the new view
this.handleRotationChanged_();

View File

@@ -3,6 +3,7 @@
*/
import {modulo} from './math.js';
import {padNumber} from './string.js';
import {getWidth} from './extent.js';
/**
@@ -402,3 +403,23 @@ export function toStringHDMS(coordinate, opt_fractionDigits) {
export function toStringXY(coordinate, opt_fractionDigits) {
return format(coordinate, '{x}, {y}', opt_fractionDigits);
}
/**
* Modifies the provided coordinate in-place to be within the real world
* extent. The lower projection extent boundary is inclusive, the upper one
* exclusive.
*
* @param {Coordinate} coordinate Coordinate.
* @param {import("./proj/Projection.js").default} projection Projection
* @return {Coordinate} The coordinate within the real world extent.
*/
export function wrapX(coordinate, projection) {
const projectionExtent = projection.getExtent();
if (projection.canWrapX() && (coordinate[0] < projectionExtent[0] || coordinate[0] >= projectionExtent[2])) {
const worldWidth = getWidth(projectionExtent);
const worldsAway = Math.floor((coordinate[0] - projectionExtent[0]) / worldWidth);
coordinate[0] -= (worldsAway * worldWidth);
}
return coordinate;
}

View File

@@ -4,9 +4,13 @@
/**
* @typedef {Object} FontParameters
* @property {Array<string>} families
* @property {string} style
* @property {string} variant
* @property {string} weight
* @property {string} size
* @property {string} lineHeight
* @property {string} family
* @property {Array<string>} families
*/
@@ -64,42 +68,52 @@ export const CLASS_CONTROL = 'ol-control';
*/
export const CLASS_COLLAPSED = 'ol-collapsed';
/**
* From http://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font
* @type {RegExp}
*/
const fontRegEx = new RegExp([
'^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)',
'(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)',
'(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)',
'(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?',
'(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))',
'(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))',
'?\\s*([-,\\"\\\'\\sa-z]+?)\\s*$'
].join(''), 'i');
const fontRegExMatchIndex = [
'style',
'variant',
'weight',
'size',
'lineHeight',
'family'
];
/**
* 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 {FontParameters} The font families (or null if the input spec is invalid).
* @param {string} fontSpec The CSS font property.
* @return {FontParameters} The font parameters (or null if the input spec is invalid).
*/
export const getFontParameters = (function() {
/**
* @type {CSSStyleDeclaration}
*/
let style;
/**
* @type {Object<string, FontParameters>}
*/
const cache = {};
return function(font) {
if (!style) {
style = document.createElement('div').style;
export const getFontParameters = function(fontSpec) {
const match = fontSpec.match(fontRegEx);
if (!match) {
return null;
}
const style = /** @type {FontParameters} */ ({
lineHeight: 'normal',
size: '1.2em',
style: 'normal',
weight: 'normal',
variant: 'normal'
});
for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {
const value = match[i + 1];
if (value !== undefined) {
style[fontRegExMatchIndex[i]] = value;
}
if (!(font in cache)) {
style.font = font;
const family = style.fontFamily;
const fontWeight = style.fontWeight;
const fontStyle = style.fontStyle;
style.font = '';
if (!family) {
return null;
}
const families = family.split(/,\s?/);
cache[font] = {
families: families,
weight: fontWeight,
style: fontStyle
};
}
return cache[font];
};
})();
}
style.families = style.family.split(/,\s?/);
return style;
};

View File

@@ -1,8 +1,11 @@
import {WORKER_OFFSCREEN_CANVAS} from './has.js';
/**
* @module ol/dom
*/
//FIXME Move this function to the canvas module
/**
* Create an html canvas element and returns its 2d context.
* @param {number=} opt_width Canvas width.
@@ -12,14 +15,18 @@
*/
export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) {
const canvas = opt_canvasPool && opt_canvasPool.length ?
opt_canvasPool.shift() : document.createElement('canvas');
opt_canvasPool.shift() :
WORKER_OFFSCREEN_CANVAS ?
new OffscreenCanvas(opt_width || 300, opt_height || 300) :
document.createElement('canvas');
if (opt_width) {
canvas.width = opt_width;
}
if (opt_height) {
canvas.height = opt_height;
}
return canvas.getContext('2d');
//FIXME Allow OffscreenCanvasRenderingContext2D as return type
return /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d'));
}

View File

@@ -13,7 +13,6 @@ import {clear} from './obj.js';
* @api
*/
/**
* Listener function. This function is called with an event object as argument.
* When the function returns `false`, event propagation will stop.
@@ -22,6 +21,14 @@ import {clear} from './obj.js';
* @api
*/
/**
* @typedef {Object} ListenerObject
* @property {ListenerFunction} handleEvent
*/
/**
* @typedef {ListenerFunction|ListenerObject} Listener
*/
/**
* Registers an event listener on an event target. Inspired by

View File

@@ -56,7 +56,7 @@ class Target extends Disposable {
/**
* @private
* @type {!Object<string, Array<import("../events.js").ListenerFunction>>}
* @type {!Object<string, Array<import("../events.js").Listener>>}
*/
this.listeners_ = {};
@@ -64,7 +64,7 @@ class Target extends Disposable {
/**
* @param {string} type Type.
* @param {import("../events.js").ListenerFunction} listener Listener.
* @param {import("../events.js").Listener} listener Listener.
*/
addEventListener(type, listener) {
if (!type || !listener) {
@@ -85,15 +85,13 @@ class Target extends Disposable {
* of this type. The event parameter can either be a string or an
* Object with a `type` property.
*
* @param {{type: string,
* target: (EventTargetLike|undefined),
* propagationStopped: (boolean|undefined)}|
* import("./Event.js").default|string} event Event object.
* @param {import("./Event.js").default|string} event Event object.
* @return {boolean|undefined} `false` if anyone called preventDefault on the
* event object or if any of the listeners returned false.
* @api
*/
dispatchEvent(event) {
/** @type {import("./Event.js").default|Event} */
const evt = typeof event === 'string' ? new Event(event) : event;
const type = evt.type;
if (!evt.target) {
@@ -108,7 +106,12 @@ class Target extends Disposable {
}
++this.dispatching_[type];
for (let i = 0, ii = listeners.length; i < ii; ++i) {
if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
if ('handleEvent' in listeners[i]) {
propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[i]).handleEvent(evt);
} else {
propagate = /** @type {import("../events.js").ListenerFunction} */ (listeners[i]).call(this, evt);
}
if (propagate === false || evt.propagationStopped) {
propagate = false;
break;
}
@@ -138,7 +141,7 @@ class Target extends Disposable {
* order that they will be called in.
*
* @param {string} type Type.
* @return {Array<import("../events.js").ListenerFunction>} Listeners.
* @return {Array<import("../events.js").Listener>} Listeners.
*/
getListeners(type) {
return this.listeners_[type];
@@ -157,7 +160,7 @@ class Target extends Disposable {
/**
* @param {string} type Type.
* @param {import("../events.js").ListenerFunction} listener Listener.
* @param {import("../events.js").Listener} listener Listener.
*/
removeEventListener(type, listener) {
const listeners = this.listeners_[type];

View File

@@ -295,6 +295,18 @@ export function equals(extent1, extent2) {
extent1[1] == extent2[1] && extent1[3] == extent2[3];
}
/**
* Determine if two extents are approximately equivalent.
* @param {Extent} extent1 Extent 1.
* @param {Extent} extent2 Extent 2.
* @param {number} tolerance Tolerance in extent coordinate units.
* @return {boolean} The two extents differ by less than the tolerance.
*/
export function approximatelyEquals(extent1, extent2, tolerance) {
return Math.abs(extent1[0] - extent2[0]) < tolerance && Math.abs(extent1[2] - extent2[2]) < tolerance &&
Math.abs(extent1[1] - extent2[1]) < tolerance && Math.abs(extent1[3] - extent2[3]) < tolerance;
}
/**
* Modify an extent to include another extent.
@@ -778,18 +790,60 @@ export function intersectsSegment(extent, start, end) {
* @param {import("./proj.js").TransformFunction} transformFn Transform function.
* Called with `[minX, minY, maxX, maxY]` extent coordinates.
* @param {Extent=} opt_extent Destination extent.
* @param {number=} opt_stops Number of stops per side used for the transform.
* By default only the corners are used.
* @return {Extent} Extent.
* @api
*/
export function applyTransform(extent, transformFn, opt_extent) {
const coordinates = [
extent[0], extent[1],
extent[0], extent[3],
extent[2], extent[1],
extent[2], extent[3]
];
export function applyTransform(extent, transformFn, opt_extent, opt_stops) {
let coordinates = [];
if (opt_stops > 1) {
const width = extent[2] - extent[0];
const height = extent[3] - extent[1];
for (let i = 0; i < opt_stops; ++i) {
coordinates.push(
extent[0] + width * i / opt_stops, extent[1],
extent[2], extent[1] + height * i / opt_stops,
extent[2] - width * i / opt_stops, extent[3],
extent[0], extent[3] - height * i / opt_stops
);
}
} else {
coordinates = [
extent[0], extent[1],
extent[2], extent[1],
extent[2], extent[3],
extent[0], extent[3]
];
}
transformFn(coordinates, coordinates, 2);
const xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
const ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
const xs = [];
const ys = [];
for (let i = 0, l = coordinates.length; i < l; i += 2) {
xs.push(coordinates[i]);
ys.push(coordinates[i + 1]);
}
return _boundingExtentXYs(xs, ys, opt_extent);
}
/**
* Modifies the provided extent in-place to be within the real world
* extent.
*
* @param {Extent} extent Extent.
* @param {import("./proj/Projection.js").default} projection Projection
* @return {Extent} The extent within the real world extent.
*/
export function wrapX(extent, projection) {
const projectionExtent = projection.getExtent();
const center = getCenter(extent);
if (projection.canWrapX() && (center[0] < projectionExtent[0] || center[0] >= projectionExtent[2])) {
const worldWidth = getWidth(projectionExtent);
const worldsAway = Math.floor((center[0] - projectionExtent[0]) / worldWidth);
const offset = (worldsAway * worldWidth);
extent[0] -= offset;
extent[2] -= offset;
}
return extent;
}

View File

@@ -349,7 +349,7 @@ class IIIFInfo {
}
/**
* @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality.
* @param {PreferredOptions=} opt_preferredOptions Optional options for preferred format and quality.
* @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
* @api
*/

View File

@@ -918,11 +918,7 @@ function createNameStyleFunction(foundStyle, name) {
const nameStyle = new Style({
image: imageStyle,
text: textStyle,
// although nameStyle will be used only for Point geometries
// fill and stroke are included to assist writing of MultiGeometry styles
fill: foundStyle.getFill(),
stroke: foundStyle.getStroke()
text: textStyle
});
return nameStyle;
}
@@ -953,7 +949,7 @@ function createFeatureStyleFunction(style, styleUrl, defaultStyle, sharedStyles,
if (geometry) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
multiGeometryPoints = geometry.getGeometriesArray().filter(function(geometry) {
multiGeometryPoints = geometry.getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type === GeometryType.POINT || type === GeometryType.MULTI_POINT;
});
@@ -1171,6 +1167,7 @@ function readStyleMapValue(node, objectStack) {
const ICON_STYLE_PARSERS = makeStructureNS(
NAMESPACE_URIS, {
'Icon': makeObjectPropertySetter(readIcon),
'color': makeObjectPropertySetter(readColor),
'heading': makeObjectPropertySetter(readDecimal),
'hotSpot': makeObjectPropertySetter(readVec2),
'scale': makeObjectPropertySetter(readScale)
@@ -1252,6 +1249,9 @@ function iconStyleParser(node, objectStack) {
let scale = /** @type {number|undefined} */
(object['scale']);
const color = /** @type {Array<number>|undefined} */
(object['color']);
if (drawIcon) {
if (src == DEFAULT_IMAGE_STYLE_SRC) {
size = DEFAULT_IMAGE_STYLE_SIZE;
@@ -1271,7 +1271,8 @@ function iconStyleParser(node, objectStack) {
rotation: rotation,
scale: scale,
size: size,
src: src
src: src,
color: color
});
styleObject['imageStyle'] = imageStyle;
} else {
@@ -1806,7 +1807,7 @@ function readStyle(node, objectStack) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
return new GeometryCollection(
geometry.getGeometriesArray().filter(function(geometry) {
geometry.getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type !== GeometryType.POLYGON && type !== GeometryType.MULTI_POLYGON;
})
@@ -1827,7 +1828,7 @@ function readStyle(node, objectStack) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
return new GeometryCollection(
geometry.getGeometriesArray().filter(function(geometry) {
geometry.getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type === GeometryType.POLYGON || type === GeometryType.MULTI_POLYGON;
})
@@ -2447,7 +2448,7 @@ function writeIcon(node, icon, objectStack) {
// @ts-ignore
const ICON_STYLE_SEQUENCE = makeStructureNS(
NAMESPACE_URIS, [
'scale', 'heading', 'Icon', 'hotSpot'
'scale', 'heading', 'Icon', 'color', 'hotSpot'
]);
@@ -2459,6 +2460,7 @@ const ICON_STYLE_SEQUENCE = makeStructureNS(
const ICON_STYLE_SERIALIZERS = makeStructureNS(
NAMESPACE_URIS, {
'Icon': makeChildAppender(writeIcon),
'color': makeChildAppender(writeColorTextNode),
'heading': makeChildAppender(writeDecimalTextNode),
'hotSpot': makeChildAppender(writeVec2),
'scale': makeChildAppender(writeScaleTextNode)
@@ -2514,6 +2516,11 @@ function writeIconStyle(node, style, objectStack) {
properties['heading'] = rotation; // 0-360
}
const color = style.getColor();
if (color) {
properties['color'] = color;
}
const parentNode = objectStack[objectStack.length - 1].node;
const orderedKeys = ICON_STYLE_SEQUENCE[parentNode.namespaceURI];
const values = makeSequence(properties, orderedKeys);
@@ -2703,20 +2710,35 @@ function writeMultiGeometry(node, geometry, objectStack) {
const context = {node: node};
const type = geometry.getType();
/** @type {Array<import("../geom/Geometry.js").default>} */
let geometries;
let geometries = [];
/** @type {function(*, Array<*>, string=): (Node|undefined)} */
let factory;
if (type == GeometryType.GEOMETRY_COLLECTION) {
geometries = /** @type {GeometryCollection} */ (geometry).getGeometries();
if (type === GeometryType.GEOMETRY_COLLECTION) {
/** @type {GeometryCollection} */ (geometry).getGeometriesArrayRecursive().forEach(function(geometry) {
const type = geometry.getType();
if (type === GeometryType.MULTI_POINT) {
geometries = geometries.concat(/** @type {MultiPoint} */ (geometry).getPoints());
} else if (type === GeometryType.MULTI_LINE_STRING) {
geometries = geometries.concat(/** @type {MultiLineString} */ (geometry).getLineStrings());
} else if (type === GeometryType.MULTI_POLYGON) {
geometries = geometries.concat(/** @type {MultiPolygon} */ (geometry).getPolygons());
} else if (type === GeometryType.POINT
|| type === GeometryType.LINE_STRING
|| type === GeometryType.POLYGON) {
geometries.push(geometry);
} else {
assert(false, 39); // Unknown geometry type
}
});
factory = GEOMETRY_NODE_FACTORY;
} else if (type == GeometryType.MULTI_POINT) {
} else if (type === GeometryType.MULTI_POINT) {
geometries = /** @type {MultiPoint} */ (geometry).getPoints();
factory = POINT_NODE_FACTORY;
} else if (type == GeometryType.MULTI_LINE_STRING) {
} else if (type === GeometryType.MULTI_LINE_STRING) {
geometries =
(/** @type {MultiLineString} */ (geometry)).getLineStrings();
factory = LINE_STRING_NODE_FACTORY;
} else if (type == GeometryType.MULTI_POLYGON) {
} else if (type === GeometryType.MULTI_POLYGON) {
geometries =
(/** @type {MultiPolygon} */ (geometry)).getPolygons();
factory = POLYGON_NODE_FACTORY;
@@ -2831,13 +2853,61 @@ function writePlacemark(node, feature, objectStack) {
// resolution-independent here
const styles = styleFunction(feature, 0);
if (styles) {
const style = Array.isArray(styles) ? styles[0] : styles;
if (this.writeStyles_) {
properties['Style'] = style;
const styleArray = Array.isArray(styles) ? styles : [styles];
let pointStyles = styleArray;
if (feature.getGeometry()) {
pointStyles = styleArray.filter(function(style) {
const geometry = style.getGeometryFunction()(feature);
if (geometry) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
return /** @type {GeometryCollection} */ (geometry).getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type === GeometryType.POINT || type === GeometryType.MULTI_POINT;
}).length;
}
return type === GeometryType.POINT || type === GeometryType.MULTI_POINT;
}
});
}
const textStyle = style.getText();
if (textStyle) {
properties['name'] = textStyle.getText();
if (this.writeStyles_) {
let lineStyles = styleArray;
let polyStyles = styleArray;
if (feature.getGeometry()) {
lineStyles = styleArray.filter(function(style) {
const geometry = style.getGeometryFunction()(feature);
if (geometry) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
return /** @type {GeometryCollection} */ (geometry).getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type === GeometryType.LINE_STRING || type === GeometryType.MULTI_LINE_STRING;
}).length;
}
return type === GeometryType.LINE_STRING || type === GeometryType.MULTI_LINE_STRING;
}
});
polyStyles = styleArray.filter(function(style) {
const geometry = style.getGeometryFunction()(feature);
if (geometry) {
const type = geometry.getType();
if (type === GeometryType.GEOMETRY_COLLECTION) {
return /** @type {GeometryCollection} */ (geometry).getGeometriesArrayRecursive().filter(function(geometry) {
const type = geometry.getType();
return type === GeometryType.POLYGON || type === GeometryType.MULTI_POLYGON;
}).length;
}
return type === GeometryType.POLYGON || type === GeometryType.MULTI_POLYGON;
}
});
}
properties['Style'] = {pointStyles: pointStyles, lineStyles: lineStyles, polyStyles: polyStyles};
}
if (pointStyles.length && properties['name'] === undefined) {
const textStyle = pointStyles[0].getText();
if (textStyle) {
properties['name'] = textStyle.getText();
}
}
}
}
@@ -2913,6 +2983,17 @@ function writePrimitiveGeometry(node, geometry, objectStack) {
}
/**
* @const
* @type {Object<string, Array<string>>}
*/
// @ts-ignore
const POLY_STYLE_SEQUENCE = makeStructureNS(
NAMESPACE_URIS, [
'color', 'fill', 'outline'
]);
/**
* @const
* @type {Object<string, Object<string, import("../xml.js").Serializer>>}
@@ -2972,27 +3053,31 @@ function writePolygon(node, polygon, objectStack) {
// @ts-ignore
const POLY_STYLE_SERIALIZERS = makeStructureNS(
NAMESPACE_URIS, {
'color': makeChildAppender(writeColorTextNode)
'color': makeChildAppender(writeColorTextNode),
'fill': makeChildAppender(writeBooleanTextNode),
'outline': makeChildAppender(writeBooleanTextNode)
});
/**
* A factory for creating coordinates nodes.
* @const
* @type {function(*, Array<*>, string=): (Node|undefined)}
*/
const COLOR_NODE_FACTORY = makeSimpleNodeFactory('color');
/**
* @param {Node} node Node.
* @param {Fill} style Style.
* @param {Style} style Style.
* @param {Array<*>} objectStack Object stack.
*/
function writePolyStyle(node, style, objectStack) {
const /** @type {import("../xml.js").NodeStackItem} */ context = {node: node};
const fill = style.getFill();
const stroke = style.getStroke();
const properties = {
'color': fill ? fill.getColor() : undefined,
'fill': fill ? undefined : false,
'outline': stroke ? undefined : false
};
const parentNode = objectStack[objectStack.length - 1].node;
const orderedKeys = POLY_STYLE_SEQUENCE[parentNode.namespaceURI];
const values = makeSequence(properties, orderedKeys);
pushSerializeAndPop(context, POLY_STYLE_SERIALIZERS,
COLOR_NODE_FACTORY, [style.getColor()], objectStack);
OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
}
@@ -3034,27 +3119,34 @@ const STYLE_SERIALIZERS = makeStructureNS(
/**
* @param {Node} node Node.
* @param {Style} style Style.
* @param {Object<string, Array<Style>>} styles Styles.
* @param {Array<*>} objectStack Object stack.
*/
function writeStyle(node, style, objectStack) {
function writeStyle(node, styles, objectStack) {
const /** @type {import("../xml.js").NodeStackItem} */ context = {node: node};
const properties = {};
const fillStyle = style.getFill();
const strokeStyle = style.getStroke();
const imageStyle = style.getImage();
const textStyle = style.getText();
if (imageStyle && typeof /** @type {?} */ (imageStyle).getSrc === 'function') {
properties['IconStyle'] = imageStyle;
if (styles.pointStyles.length) {
const textStyle = styles.pointStyles[0].getText();
if (textStyle) {
properties['LabelStyle'] = textStyle;
}
const imageStyle = styles.pointStyles[0].getImage();
if (imageStyle && typeof /** @type {?} */ (imageStyle).getSrc === 'function') {
properties['IconStyle'] = imageStyle;
}
}
if (textStyle) {
properties['LabelStyle'] = textStyle;
if (styles.lineStyles.length) {
const strokeStyle = styles.lineStyles[0].getStroke();
if (strokeStyle) {
properties['LineStyle'] = strokeStyle;
}
}
if (strokeStyle) {
properties['LineStyle'] = strokeStyle;
}
if (fillStyle) {
properties['PolyStyle'] = fillStyle;
if (styles.polyStyles.length) {
const strokeStyle = styles.polyStyles[0].getStroke();
if (strokeStyle && !properties['LineStyle']) {
properties['LineStyle'] = strokeStyle;
}
properties['PolyStyle'] = styles.polyStyles[0];
}
const parentNode = objectStack[objectStack.length - 1].node;
const orderedKeys = STYLE_SEQUENCE[parentNode.namespaceURI];

View File

@@ -126,6 +126,23 @@ class GeometryCollection extends Geometry {
return this.geometries_;
}
/**
* @return {Array<Geometry>} Geometries.
*/
getGeometriesArrayRecursive() {
/** @type {Array<Geometry>} */
let geometriesArray = [];
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].getType() === this.getType()) {
geometriesArray = geometriesArray.concat(/** @type {GeometryCollection} */ (geometries[i]).getGeometriesArrayRecursive());
} else {
geometriesArray.push(geometries[i]);
}
}
return geometriesArray;
}
/**
* @inheritDoc
*/

View File

@@ -37,7 +37,15 @@ export const MAC = ua.indexOf('macintosh') !== -1;
* @type {number}
* @api
*/
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
export const DEVICE_PIXEL_RATIO = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;
/**
* The execution context is a worker with OffscreenCanvas available.
* @const
* @type {boolean}
*/
export const WORKER_OFFSCREEN_CANVAS = typeof WorkerGlobalScope !== 'undefined' && typeof OffscreenCanvas !== 'undefined' &&
self instanceof WorkerGlobalScope; //eslint-disable-line
/**
* Image.prototype.decode() is supported.

View File

@@ -13,6 +13,8 @@ import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js
* @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
* to indicate whether that event should be handled.
* Default is {@link module:ol/events/condition~noModifierKeys} and {@link module:ol/events/condition~primaryAction}.
* In addition, if there is a `tabindex` attribute on the map element,
* {@link module:ol/events/condition~focus} will also be applied.
* @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
*/

View File

@@ -110,7 +110,7 @@ import {fromUserCoordinate, getUserProjection} from '../proj.js';
* geometry is the geometry that is returned when the function is called without
* a second argument.
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=,
* import("../proj/Projection.js").default):
* import("../proj/Projection.js").default=):
* import("../geom/SimpleGeometry.js").default} GeometryFunction
*/
@@ -143,7 +143,13 @@ const DrawEventType = {
* @event DrawEvent#drawend
* @api
*/
DRAWEND: 'drawend'
DRAWEND: 'drawend',
/**
* Triggered upon feature draw abortion
* @event DrawEvent#drawabort
* @api
*/
DRAWABORT: 'drawabort'
};
@@ -584,8 +590,7 @@ class Draw extends PointerInteraction {
}
pass = false;
} else if (this.freehand_) {
this.finishCoordinate_ = null;
this.abortDrawing_();
this.abortDrawing();
}
if (!pass && this.stopClick_) {
event.stopPropagation();
@@ -834,7 +839,7 @@ class Draw extends PointerInteraction {
}
if (coordinates.length === 0) {
this.finishCoordinate_ = null;
this.abortDrawing();
}
this.updateSketchFeatures_();
@@ -901,6 +906,18 @@ class Draw extends PointerInteraction {
return sketchFeature;
}
/**
* Stop drawing without adding the sketch feature to the target layer.
* @api
*/
abortDrawing() {
const sketchFeature = this.abortDrawing_();
if (sketchFeature) {
this.dispatchEvent(new DrawEvent(DrawEventType.DRAWABORT, sketchFeature));
}
}
/**
* Append coordinates to the end of the geometry that is currently being drawn.
* This can be used when drawing LineStrings or Polygons. Coordinates will
@@ -982,7 +999,7 @@ class Draw extends PointerInteraction {
const map = this.getMap();
const active = this.getActive();
if (!map || !active) {
this.abortDrawing_();
this.abortDrawing();
}
this.overlay_.setMap(active ? map : null);
}

View File

@@ -14,13 +14,14 @@ import {always, primaryAction, altKeyOnly, singleClick} from '../events/conditio
import {boundingExtent, buffer as bufferExtent, createOrUpdateFromCoordinate as createExtent} from '../extent.js';
import GeometryType from '../geom/GeometryType.js';
import Point from '../geom/Point.js';
import {fromCircle} from '../geom/Polygon.js';
import PointerInteraction from './Pointer.js';
import VectorLayer from '../layer/Vector.js';
import VectorSource from '../source/Vector.js';
import VectorEventType from '../source/VectorEventType.js';
import RBush from '../structs/RBush.js';
import {createEditingStyle} from '../style/Style.js';
import {fromUserExtent, toUserExtent, fromUserCoordinate, toUserCoordinate} from '../proj.js';
import {getUserProjection, fromUserExtent, toUserExtent, fromUserCoordinate, toUserCoordinate} from '../proj.js';
/**
@@ -657,7 +658,14 @@ class Modify extends PointerInteraction {
centerSegmentData.featureSegments = featureSegments;
circumferenceSegmentData.featureSegments = featureSegments;
this.rBush_.insert(createExtent(coordinates), centerSegmentData);
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
let circleGeometry = /** @type {import("../geom/Geometry.js").default} */ (geometry);
const userProjection = getUserProjection();
if (userProjection && this.getMap()) {
const projection = this.getMap().getView().getProjection();
circleGeometry = circleGeometry.clone().transform(userProjection, projection);
circleGeometry = fromCircle(/** @type {import("../geom/Circle.js").default} */ (circleGeometry)).transform(projection, userProjection);
}
this.rBush_.insert(circleGeometry.getExtent(), circumferenceSegmentData);
}
/**
@@ -785,7 +793,16 @@ class Modify extends PointerInteraction {
this.changingFeature_ = false;
} else { // We're dragging the circle's circumference:
this.changingFeature_ = true;
geometry.setRadius(coordinateDistance(geometry.getCenter(), vertex));
const projection = evt.map.getView().getProjection();
let radius = coordinateDistance(fromUserCoordinate(geometry.getCenter(), projection),
fromUserCoordinate(vertex, projection));
const userProjection = getUserProjection();
if (userProjection) {
const circleGeometry = geometry.clone().transform(userProjection, projection);
circleGeometry.setRadius(radius);
radius = circleGeometry.transform(projection, userProjection).getRadius();
}
geometry.setRadius(radius);
this.changingFeature_ = false;
}
break;
@@ -898,7 +915,14 @@ class Modify extends PointerInteraction {
circumferenceSegmentData.segment[0] = coordinates;
circumferenceSegmentData.segment[1] = coordinates;
this.rBush_.update(createExtent(coordinates), centerSegmentData);
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
let circleGeometry = geometry;
const userProjection = getUserProjection();
if (userProjection) {
const projection = evt.map.getView().getProjection();
circleGeometry = circleGeometry.clone().transform(userProjection, projection);
circleGeometry = fromCircle(circleGeometry).transform(projection, userProjection);
}
this.rBush_.update(circleGeometry.getExtent(), circumferenceSegmentData);
} else {
this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
}
@@ -1249,11 +1273,15 @@ function projectedDistanceToSegmentDataSquared(pointCoordinates, segmentData, pr
const geometry = segmentData.geometry;
if (geometry.getType() === GeometryType.CIRCLE) {
const circleGeometry = /** @type {import("../geom/Circle.js").default} */ (geometry);
let circleGeometry = /** @type {import("../geom/Circle.js").default} */ (geometry);
if (segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
const userProjection = getUserProjection();
if (userProjection) {
circleGeometry = /** @type {import("../geom/Circle.js").default} */ (circleGeometry.clone().transform(userProjection, projection));
}
const distanceToCenterSquared =
squaredCoordinateDistance(circleGeometry.getCenter(), pointCoordinates);
squaredCoordinateDistance(circleGeometry.getCenter(), fromUserCoordinate(pointCoordinates, projection));
const distanceToCircumference =
Math.sqrt(distanceToCenterSquared) - circleGeometry.getRadius();
return distanceToCircumference * distanceToCircumference;
@@ -1280,7 +1308,12 @@ function closestOnSegmentData(pointCoordinates, segmentData, projection) {
const geometry = segmentData.geometry;
if (geometry.getType() === GeometryType.CIRCLE && segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
return geometry.getClosestPoint(pointCoordinates);
let circleGeometry = /** @type {import("../geom/Circle.js").default} */ (geometry);
const userProjection = getUserProjection();
if (userProjection) {
circleGeometry = /** @type {import("../geom/Circle.js").default} */ (circleGeometry.clone().transform(userProjection, projection));
}
return toUserCoordinate(circleGeometry.getClosestPoint(fromUserCoordinate(pointCoordinates, projection)), projection);
}
const coordinate = fromUserCoordinate(pointCoordinates, projection);
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);

View File

@@ -4,7 +4,17 @@
import {always, focus} from '../events/condition.js';
import EventType from '../events/EventType.js';
import {DEVICE_PIXEL_RATIO, FIREFOX} from '../has.js';
import Interaction from './Interaction.js';
import Interaction, {zoomByDelta} from './Interaction.js';
import {clamp} from '../math.js';
/**
* @enum {string}
*/
export const Mode = {
TRACKPAD: 'trackpad',
WHEEL: 'wheel'
};
/**
@@ -13,6 +23,8 @@ import Interaction from './Interaction.js';
* takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether that event should be handled. Default is
* {@link module:ol/events/condition~always}.
* In addition, if there is a `tabindex` attribute on the map element,
* {@link module:ol/events/condition~focus} will also be applied.
* @property {number} [maxDelta=1] Maximum mouse wheel delta.
* @property {number} [duration=250] Animation duration in milliseconds.
* @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds.
@@ -92,16 +104,28 @@ class MouseWheelZoom extends Interaction {
this.startTime_ = undefined;
/**
* Events separated by this delay will be considered separate
* @private
* @type {?}
*/
this.timeoutId_;
/**
* @private
* @type {Mode|undefined}
*/
this.mode_ = undefined;
/**
* Trackpad events separated by this delay will be considered separate
* interactions.
* @type {number}
*/
this.eventGap_ = 400;
this.trackpadEventGap_ = 400;
/**
* @type {?}
*/
this.timeoutId_;
this.trackpadTimeoutId_;
/**
* The number of delta values per zoom level
@@ -130,7 +154,7 @@ class MouseWheelZoom extends Interaction {
* @private
*/
endInteraction_() {
this.timeoutId_ = undefined;
this.trackpadTimeoutId_ = undefined;
const view = this.getMap().getView();
view.endInteraction(undefined, this.lastDelta_ ? (this.lastDelta_ > 0 ? 1 : -1) : 0, this.lastAnchor_);
}
@@ -184,18 +208,61 @@ class MouseWheelZoom extends Interaction {
this.startTime_ = now;
}
const view = map.getView();
if (this.timeoutId_) {
clearTimeout(this.timeoutId_);
} else {
view.beginInteraction();
if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {
this.mode_ = Math.abs(delta) < 4 ?
Mode.TRACKPAD :
Mode.WHEEL;
}
this.timeoutId_ = setTimeout(this.endInteraction_.bind(this), this.eventGap_);
view.adjustZoom(-delta / this.deltaPerZoom_, this.lastAnchor_);
this.startTime_ = now;
const view = map.getView();
if (this.mode_ === Mode.TRACKPAD && !view.getConstrainResolution()) {
if (this.trackpadTimeoutId_) {
clearTimeout(this.trackpadTimeoutId_);
} else {
if (view.getAnimating()) {
view.cancelAnimations();
}
view.beginInteraction();
}
this.trackpadTimeoutId_ = setTimeout(this.endInteraction_.bind(this), this.timeout_);
view.adjustZoom(-delta / this.deltaPerZoom_, this.lastAnchor_);
this.startTime_ = now;
return false;
}
this.totalDelta_ += delta;
const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
clearTimeout(this.timeoutId_);
this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);
return false;
}
/**
* @private
* @param {import("../PluggableMap.js").default} map Map.
*/
handleWheelZoom_(map) {
const view = map.getView();
if (view.getAnimating()) {
view.cancelAnimations();
}
let delta = -clamp(this.totalDelta_, -this.maxDelta_ * this.deltaPerZoom_, this.maxDelta_ * this.deltaPerZoom_) / this.deltaPerZoom_;
if (view.getConstrainResolution()) {
// view has a zoom constraint, zoom by 1
delta = delta ? delta > 0 ? 1 : -1 : 0;
}
zoomByDelta(view, delta, this.lastAnchor_, this.duration_);
this.mode_ = undefined;
this.totalDelta_ = 0;
this.lastAnchor_ = null;
this.startTime_ = undefined;
this.timeoutId_ = undefined;
}
/**
* Enable or disable using the mouse's location as an anchor when zooming
* @param {boolean} useAnchor true to zoom to the mouse's location, false

View File

@@ -61,7 +61,7 @@ const SelectEventType = {
* @property {import("../style/Style.js").StyleLike} [style]
* Style for the selected features. By default the default edit style is used
* (see {@link module:ol/style}).
* If set to `false` the selected feature's style will not change.
* If set to a falsey value, the selected feature's style will not change.
* @property {import("../events/condition.js").Condition} [removeCondition] A function
* that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether that event should be handled.
@@ -133,6 +133,12 @@ class SelectEvent extends Event {
}
/**
* Original feature styles to reset to when features are no longer selected.
* @type {Object.<number, import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction>}
*/
const originalFeatureStyles = {};
/**
* @classdesc
@@ -161,6 +167,16 @@ class Select extends Interaction {
const options = opt_options ? opt_options : {};
/**
* @private
*/
this.boundAddFeature_ = this.addFeature_.bind(this);
/**
* @private
*/
this.boundRemoveFeature_ = this.removeFeature_.bind(this);
/**
* @private
* @type {import("../events/condition.js").Condition}
@@ -209,14 +225,6 @@ class Select extends Interaction {
*/
this.style_ = options.style !== undefined ? options.style : getDefaultStyleFunction();
/**
* An association between selected feature (key)
* and original style (value)
* @private
* @type {Object.<number, import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction>}
*/
this.featureStyleAssociation_ = {};
/**
* @private
* @type {import("../Collection.js").default}
@@ -251,10 +259,6 @@ class Select extends Interaction {
* @type {Object<string, import("../layer/Layer.js").default>}
*/
this.featureLayerAssociation_ = {};
const features = this.getFeatures();
features.addEventListener(CollectionEventType.ADD, this.addFeature_.bind(this));
features.addEventListener(CollectionEventType.REMOVE, this.removeFeature_.bind(this));
}
/**
@@ -319,11 +323,19 @@ class Select extends Interaction {
setMap(map) {
const currentMap = this.getMap();
if (currentMap && this.style_) {
this.features_.forEach(this.removeSelectedStyle_.bind(this));
this.features_.forEach(this.restorePreviousStyle_.bind(this));
}
super.setMap(map);
if (map && this.style_) {
this.features_.forEach(this.giveSelectedStyle_.bind(this));
if (map) {
this.features_.addEventListener(CollectionEventType.ADD, this.boundAddFeature_);
this.features_.addEventListener(CollectionEventType.REMOVE, this.boundRemoveFeature_);
if (this.style_) {
this.features_.forEach(this.applySelectedStyle_.bind(this));
}
} else {
this.features_.removeEventListener(CollectionEventType.ADD, this.boundAddFeature_);
this.features_.removeEventListener(CollectionEventType.REMOVE, this.boundRemoveFeature_);
}
}
@@ -334,7 +346,7 @@ class Select extends Interaction {
addFeature_(evt) {
const feature = evt.element;
if (this.style_) {
this.giveSelectedStyle_(feature);
this.applySelectedStyle_(feature);
}
}
@@ -345,17 +357,26 @@ class Select extends Interaction {
removeFeature_(evt) {
const feature = evt.element;
if (this.style_) {
this.removeSelectedStyle_(feature);
this.restorePreviousStyle_(feature);
}
}
/**
* @return {import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction|null} Select style.
*/
getStyle() {
return this.style_;
}
/**
* @param {import("../Feature.js").default} feature Feature
* @private
*/
giveSelectedStyle_(feature) {
applySelectedStyle_(feature) {
const key = getUid(feature);
this.featureStyleAssociation_[key] = feature.getStyle();
if (!(key in originalFeatureStyles)) {
originalFeatureStyles[key] = feature.getStyle();
}
feature.setStyle(this.style_);
}
@@ -363,10 +384,17 @@ class Select extends Interaction {
* @param {import("../Feature.js").default} feature Feature
* @private
*/
removeSelectedStyle_(feature) {
restorePreviousStyle_(feature) {
const key = getUid(feature);
feature.setStyle(this.featureStyleAssociation_[key]);
delete this.featureStyleAssociation_[key];
const selectInteractions = /** @type {Array<Select>} */ (this.getMap().getInteractions().getArray().filter(function(interaction) {
return interaction instanceof Select && interaction.getStyle() && interaction.getFeatures().getArray().indexOf(feature) !== -1;
}));
if (selectInteractions.length > 0) {
feature.setStyle(selectInteractions[selectInteractions.length - 1].getStyle());
} else {
feature.setStyle(originalFeatureStyles[key]);
delete originalFeatureStyles[key];
}
}
/**

View File

@@ -14,7 +14,7 @@ import PointerInteraction from './Pointer.js';
import {getValues} from '../obj.js';
import VectorEventType from '../source/VectorEventType.js';
import RBush from '../structs/RBush.js';
import {fromUserCoordinate, toUserCoordinate} from '../proj.js';
import {getUserProjection, fromUserCoordinate, toUserCoordinate} from '../proj.js';
/**
@@ -431,8 +431,13 @@ class Snap extends PointerInteraction {
} else if (this.edge_) {
const isCircle = closestSegmentData.feature.getGeometry().getType() === GeometryType.CIRCLE;
if (isCircle) {
vertex = closestOnCircle(pixelCoordinate,
/** @type {import("../geom/Circle.js").default} */ (closestSegmentData.feature.getGeometry()));
let circleGeometry = closestSegmentData.feature.getGeometry();
const userProjection = getUserProjection();
if (userProjection) {
circleGeometry = circleGeometry.clone().transform(userProjection, projection);
}
vertex = toUserCoordinate(closestOnCircle(projectedCoordinate,
/** @type {import("../geom/Circle.js").default} */ (circleGeometry)), projection);
} else {
tempSegment[0] = fromUserCoordinate(closestSegment[0], projection);
tempSegment[1] = fromUserCoordinate(closestSegment[1], projection);
@@ -482,7 +487,16 @@ class Snap extends PointerInteraction {
* @private
*/
writeCircleGeometry_(feature, geometry) {
const polygon = fromCircle(geometry);
const projection = this.getMap().getView().getProjection();
let circleGeometry = geometry;
const userProjection = getUserProjection();
if (userProjection) {
circleGeometry = /** @type {import("../geom/Circle.js").default} */ (circleGeometry.clone().transform(userProjection, projection));
}
const polygon = fromCircle(circleGeometry);
if (userProjection) {
polygon.transform(projection, userProjection);
}
const coordinates = polygon.getCoordinates()[0];
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2);

View File

@@ -19,6 +19,10 @@ import Layer from './Layer.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../PluggableMap.js").default} [map] Sets the layer as overlay on a map. The map will not manage
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to

View File

@@ -21,6 +21,10 @@ import {assign} from '../obj.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {number} [preload=0] Preload. Load low-resolution tiles up to `preload` levels. `0`
* means no preloading.
* @property {import("../source/Tile.js").default} [source] Source for this layer.

View File

@@ -21,6 +21,10 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
* features before rendering. By default features are drawn in the order that they are created. Use
* `null` to avoid the sort, but get an undefined draw order.

View File

@@ -12,10 +12,22 @@ import VectorSource from '../source/Vector.js';
import {
equivalent as equivalentProjection,
get as getProjection,
getTransform,
transformExtent
getTransform
} from '../proj.js';
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent.js';
import {
applyTransform,
containsCoordinate,
containsExtent,
equals,
approximatelyEquals,
getCenter,
getHeight,
getIntersection,
getWidth,
intersects,
isEmpty,
wrapX as wrapExtentX
} from '../extent.js';
import {clamp} from '../math.js';
import Style from '../style/Style.js';
import Feature from '../Feature.js';
@@ -23,6 +35,8 @@ import {meridian, parallel} from '../geom/flat/geodesic.js';
import GeometryLayout from '../geom/GeometryLayout.js';
import Point from '../geom/Point.js';
import Collection from '../Collection.js';
import {getVectorContext} from '../render.js';
import EventType from '../render/EventType.js';
/**
@@ -64,6 +78,10 @@ const INTERVALS = [
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {number} [maxLines=100] The maximum number of meridians and
* parallels from the center of the map. The default value of 100 means that at
* most 200 meridians and 200 parallels will be displayed. The default value is
@@ -138,7 +156,8 @@ const INTERVALS = [
/**
* @classdesc
* Layer that renders a grid for a coordinate system.
* Layer that renders a grid for a coordinate system (currently only EPSG:4326 is supported).
* Note that the view projection must define both extent and worldExtent.
*
* @fires import("../render/Event.js").RenderEvent
* @api
@@ -202,25 +221,25 @@ class Graticule extends VectorLayer {
* @type {number}
* @private
*/
this.maxLatP_ = Infinity;
this.maxX_ = Infinity;
/**
* @type {number}
* @private
*/
this.maxLonP_ = Infinity;
this.maxY_ = Infinity;
/**
* @type {number}
* @private
*/
this.minLatP_ = -Infinity;
this.minX_ = -Infinity;
/**
* @type {number}
* @private
*/
this.minLonP_ = -Infinity;
this.minY_ = -Infinity;
/**
* @type {number}
@@ -270,6 +289,30 @@ class Graticule extends VectorLayer {
*/
this.projectionCenterLonLat_ = null;
/**
* @type {import("../coordinate.js").Coordinate}
* @private
*/
this.bottomLeft_ = null;
/**
* @type {import("../coordinate.js").Coordinate}
* @private
*/
this.bottomRight_ = null;
/**
* @type {import("../coordinate.js").Coordinate}
* @private
*/
this.topLeft_ = null;
/**
* @type {import("../coordinate.js").Coordinate}
* @private
*/
this.topRight_ = null;
/**
* @type {Array<GraticuleLabelDataType>}
* @private
@@ -378,6 +421,8 @@ class Graticule extends VectorLayer {
this.meridiansLabels_ = [];
this.parallelsLabels_ = [];
this.addEventListener(EventType.POSTRENDER, this.drawLabels_.bind(this));
}
/**
@@ -415,6 +460,7 @@ class Graticule extends VectorLayer {
/**
* @type {?import("../extent.js").Extent}
* @private
*/
this.loadedExtent_ = null;
@@ -435,11 +481,21 @@ class Graticule extends VectorLayer {
* @return {Array<import("../extent.js").Extent>} Extents.
*/
strategyFunction(extent, resolution) {
if (this.loadedExtent_ && !equals(this.loadedExtent_, extent)) {
// we should not keep track of loaded extents
this.getSource().removeLoadedExtent(this.loadedExtent_);
// extents may be passed in different worlds, to avoid endless loop we use only one
let realWorldExtent = extent.slice();
if (this.projection_ && this.getSource().getWrapX()) {
wrapExtentX(realWorldExtent, this.projection_);
}
return [extent];
if (this.loadedExtent_) {
if (approximatelyEquals(this.loadedExtent_, realWorldExtent, resolution)) {
// make sure result is exactly equal to previous extent
realWorldExtent = this.loadedExtent_.slice();
} else {
// we should not keep track of loaded extents
this.getSource().removeLoadedExtent(this.loadedExtent_);
}
}
return [realWorldExtent];
}
/**
@@ -482,10 +538,10 @@ class Graticule extends VectorLayer {
// first make sure we have enough features in the pool
let featureCount = this.meridians_.length + this.parallels_.length;
if (this.meridiansLabels_) {
featureCount += this.meridiansLabels_.length;
featureCount += this.meridians_.length;
}
if (this.parallelsLabels_) {
featureCount += this.parallelsLabels_.length;
featureCount += this.parallels_.length;
}
let feature;
@@ -512,27 +568,6 @@ class Graticule extends VectorLayer {
feature.setStyle(this.lineStyle_);
featuresColl.push(feature);
}
let labelData;
if (this.meridiansLabels_) {
for (i = 0, l = this.meridiansLabels_.length; i < l; ++i) {
labelData = this.meridiansLabels_[i];
feature = this.featurePool_[poolIndex++];
feature.setGeometry(labelData.geom);
feature.setStyle(this.lonLabelStyle_);
feature.set('graticule_label', labelData.text);
featuresColl.push(feature);
}
}
if (this.parallelsLabels_) {
for (i = 0, l = this.parallelsLabels_.length; i < l; ++i) {
labelData = this.parallelsLabels_[i];
feature = this.featurePool_[poolIndex++];
feature.setGeometry(labelData.geom);
feature.setStyle(this.latLabelStyle_);
feature.set('graticule_label', labelData.text);
featuresColl.push(feature);
}
}
}
/**
@@ -549,11 +584,15 @@ class Graticule extends VectorLayer {
const lineString = this.getMeridian_(lon, minLat, maxLat, squaredTolerance, index);
if (intersects(lineString.getExtent(), extent)) {
if (this.meridiansLabels_) {
const textPoint = this.getMeridianPoint_(lineString, extent, index);
this.meridiansLabels_[index] = {
geom: textPoint,
text: this.lonLabelFormatter_(lon)
};
const text = this.lonLabelFormatter_(lon);
if (index in this.meridiansLabels_) {
this.meridiansLabels_[index].text = text;
} else {
this.meridiansLabels_[index] = {
geom: new Point([]),
text: text
};
}
}
this.meridians_[index++] = lineString;
}
@@ -574,17 +613,101 @@ class Graticule extends VectorLayer {
const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);
if (intersects(lineString.getExtent(), extent)) {
if (this.parallelsLabels_) {
const textPoint = this.getParallelPoint_(lineString, extent, index);
this.parallelsLabels_[index] = {
geom: textPoint,
text: this.latLabelFormatter_(lat)
};
const text = this.latLabelFormatter_(lat);
if (index in this.parallelsLabels_) {
this.parallelsLabels_[index].text = text;
} else {
this.parallelsLabels_[index] = {
geom: new Point([]),
text: text
};
}
}
this.parallels_[index++] = lineString;
}
return index;
}
/**
* @param {import("../render/Event.js").default} event Render event.
* @private
*/
drawLabels_(event) {
const rotation = event.frameState.viewState.rotation;
const extent = event.frameState.extent;
const rotationCenter = getCenter(extent);
let rotationExtent = extent;
if (rotation) {
const width = getWidth(extent);
const height = getHeight(extent);
const cr = Math.abs(Math.cos(rotation));
const sr = Math.abs(Math.sin(rotation));
const unrotatedWidth = (sr * height - cr * width) / (sr * sr - cr * cr);
const unrotatedHeight = (sr * width - cr * height) / (sr * sr - cr * cr);
rotationExtent = [
rotationCenter[0] - unrotatedWidth / 2, rotationCenter[1] - unrotatedHeight / 2,
rotationCenter[0] + unrotatedWidth / 2, rotationCenter[1] + unrotatedHeight / 2
];
}
let startWorld = 0;
let endWorld = 0;
let labelsAtStart = this.latLabelPosition_ < 0.5;
const projectionExtent = this.projection_.getExtent();
const worldWidth = getWidth(projectionExtent);
if (this.getSource().getWrapX() && this.projection_.canWrapX() && !containsExtent(projectionExtent, extent)) {
startWorld = Math.floor((extent[0] - projectionExtent[0]) / worldWidth);
endWorld = Math.ceil((extent[2] - projectionExtent[2]) / worldWidth);
const inverted = Math.abs(rotation) > Math.PI / 2;
labelsAtStart = labelsAtStart !== inverted;
}
const vectorContext = getVectorContext(event);
for (let world = startWorld; world <= endWorld; ++world) {
let poolIndex = this.meridians_.length + this.parallels_.length;
let feature, index, l, textPoint;
if (this.meridiansLabels_) {
for (index = 0, l = this.meridiansLabels_.length; index < l; ++index) {
const lineString = this.meridians_[index];
if (!rotation && world === 0) {
textPoint = this.getMeridianPoint_(lineString, extent, index);
} else {
const clone = lineString.clone();
clone.translate(world * worldWidth, 0);
clone.rotate(-rotation, rotationCenter);
textPoint = this.getMeridianPoint_(clone, rotationExtent, index);
textPoint.rotate(rotation, rotationCenter);
}
feature = this.featurePool_[poolIndex++];
feature.setGeometry(textPoint);
feature.set('graticule_label', this.meridiansLabels_[index].text);
vectorContext.drawFeature(feature, this.lonLabelStyle_(feature));
}
}
if (this.parallelsLabels_) {
if (world === startWorld && labelsAtStart || world === endWorld && !labelsAtStart) {
for (index = 0, l = this.parallels_.length; index < l; ++index) {
const lineString = this.parallels_[index];
if (!rotation && world === 0) {
textPoint = this.getParallelPoint_(lineString, extent, index);
} else {
const clone = lineString.clone();
clone.translate(world * worldWidth, 0);
clone.rotate(-rotation, rotationCenter);
textPoint = this.getParallelPoint_(clone, rotationExtent, index);
textPoint.rotate(rotation, rotationCenter);
}
feature = this.featurePool_[poolIndex++];
feature.setGeometry(textPoint);
feature.set('graticule_label', this.parallelsLabels_[index].text);
vectorContext.drawFeature(feature, this.latLabelStyle_(feature));
}
}
}
}
}
/**
* @param {import("../extent.js").Extent} extent Extent.
* @param {import("../coordinate.js").Coordinate} center Center.
@@ -606,24 +729,91 @@ class Graticule extends VectorLayer {
return;
}
const centerLonLat = this.toLonLatTransform_(center);
let centerLon = centerLonLat[0];
let centerLat = centerLonLat[1];
let wrapX = false;
const projectionExtent = this.projection_.getExtent();
const worldWidth = getWidth(projectionExtent);
if (this.getSource().getWrapX() && this.projection_.canWrapX() && !containsExtent(projectionExtent, extent)) {
if (getWidth(extent) >= worldWidth) {
extent[0] = projectionExtent[0];
extent[2] = projectionExtent[2];
} else {
wrapX = true;
}
}
// Constrain the center to fit into the extent available to the graticule
const validCenterP = [
clamp(center[0], this.minX_, this.maxX_),
clamp(center[1], this.minY_, this.maxY_)
];
// Transform the center to lon lat
// Some projections may have a void area at the poles
// so replace any NaN latitudes with the min or max value closest to a pole
const centerLonLat = this.toLonLatTransform_(validCenterP);
if (isNaN(centerLonLat[1])) {
centerLonLat[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
this.maxLat_ : this.minLat_;
}
let centerLon = clamp(centerLonLat[0], this.minLon_, this.maxLon_);
let centerLat = clamp(centerLonLat[1], this.minLat_, this.maxLat_);
const maxLines = this.maxLines_;
let cnt, idx, lat, lon;
let validExtent = [
Math.max(extent[0], this.minLonP_),
Math.max(extent[1], this.minLatP_),
Math.min(extent[2], this.maxLonP_),
Math.min(extent[3], this.maxLatP_)
];
// Limit the extent to fit into the extent available to the graticule
validExtent = transformExtent(validExtent, this.projection_, 'EPSG:4326');
const maxLat = validExtent[3];
const maxLon = validExtent[2];
const minLat = validExtent[1];
const minLon = validExtent[0];
let validExtentP = extent;
if (!wrapX) {
validExtentP = [
clamp(extent[0], this.minX_, this.maxX_),
clamp(extent[1], this.minY_, this.maxY_),
clamp(extent[2], this.minX_, this.maxX_),
clamp(extent[3], this.minY_, this.maxY_)
];
}
// Transform the extent to get the lon lat ranges for the edges of the extent
const validExtent = applyTransform(validExtentP, this.toLonLatTransform_, undefined, 8);
let maxLat = validExtent[3];
let maxLon = validExtent[2];
let minLat = validExtent[1];
let minLon = validExtent[0];
if (!wrapX) {
// Check if extremities of the world extent lie inside the extent
// (for example the pole in a polar projection)
// and extend the extent as appropriate
if (containsCoordinate(validExtentP, this.bottomLeft_)) {
minLon = this.minLon_;
minLat = this.minLat_;
}
if (containsCoordinate(validExtentP, this.bottomRight_)) {
maxLon = this.maxLon_;
minLat = this.minLat_;
}
if (containsCoordinate(validExtentP, this.topLeft_)) {
minLon = this.minLon_;
maxLat = this.maxLat_;
}
if (containsCoordinate(validExtentP, this.topRight_)) {
maxLon = this.maxLon_;
maxLat = this.maxLat_;
}
// The transformed center may also extend the lon lat ranges used for rendering
maxLat = clamp(maxLat, centerLat, this.maxLat_);
maxLon = clamp(maxLon, centerLon, this.maxLon_);
minLat = clamp(minLat, this.minLat_, centerLat);
minLon = clamp(minLon, this.minLon_, centerLon);
}
// Create meridians
@@ -633,17 +823,29 @@ class Graticule extends VectorLayer {
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0);
cnt = 0;
while (lon != this.minLon_ && cnt++ < maxLines) {
lon = Math.max(lon - interval, this.minLon_);
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
if (wrapX) {
while ((lon -= interval) >= minLon && cnt++ < maxLines) {
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
}
} else {
while (lon != this.minLon_ && cnt++ < maxLines) {
lon = Math.max(lon - interval, this.minLon_);
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
}
}
lon = clamp(centerLon, this.minLon_, this.maxLon_);
cnt = 0;
while (lon != this.maxLon_ && cnt++ < maxLines) {
lon = Math.min(lon + interval, this.maxLon_);
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
if (wrapX) {
while ((lon += interval) <= maxLon && cnt++ < maxLines) {
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
}
} else {
while (lon != this.maxLon_ && cnt++ < maxLines) {
lon = Math.min(lon + interval, this.maxLon_);
idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
}
}
this.meridians_.length = idx;
@@ -694,11 +896,13 @@ class Graticule extends VectorLayer {
/** @type {Array<number>} **/
const p2 = [];
for (let i = 0, ii = this.intervals_.length; i < ii; ++i) {
const delta = this.intervals_[i] / 2;
const delta = clamp(this.intervals_[i] / 2, 0, 90);
// Don't attempt to transform latitudes beyond the poles!
const clampedLat = clamp(centerLat, -90 + delta, 90 - delta);
p1[0] = centerLon - delta;
p1[1] = centerLat - delta;
p1[1] = clampedLat - delta;
p2[0] = centerLon + delta;
p2[1] = centerLat + delta;
p2[1] = clampedLat + delta;
this.fromLonLatTransform_(p1, p1);
this.fromLonLatTransform_(p2, p2);
const dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
@@ -741,19 +945,23 @@ class Graticule extends VectorLayer {
*/
getMeridianPoint_(lineString, extent, index) {
const flatCoordinates = lineString.getFlatCoordinates();
const clampedBottom = Math.max(extent[1], flatCoordinates[1]);
const clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 1]);
let bottom = 1;
let top = flatCoordinates.length - 1;
if (flatCoordinates[bottom] > flatCoordinates[top]) {
bottom = top;
top = 1;
}
const clampedBottom = Math.max(extent[1], flatCoordinates[bottom]);
const clampedTop = Math.min(extent[3], flatCoordinates[top]);
const lat = clamp(
extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
clampedBottom, clampedTop);
const coordinate = [flatCoordinates[0], lat];
let point;
if (index in this.meridiansLabels_) {
point = this.meridiansLabels_[index].geom;
point.setCoordinates(coordinate);
} else {
point = new Point(coordinate);
}
const coordinate0 = flatCoordinates[bottom - 1] +
(flatCoordinates[top - 1] - flatCoordinates[bottom - 1]) * (lat - flatCoordinates[bottom]) /
(flatCoordinates[top] - flatCoordinates[bottom]);
const coordinate = [coordinate0, lat];
const point = this.meridiansLabels_[index].geom;
point.setCoordinates(coordinate);
return point;
}
@@ -797,19 +1005,23 @@ class Graticule extends VectorLayer {
*/
getParallelPoint_(lineString, extent, index) {
const flatCoordinates = lineString.getFlatCoordinates();
const clampedLeft = Math.max(extent[0], flatCoordinates[0]);
const clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);
let left = 0;
let right = flatCoordinates.length - 2;
if (flatCoordinates[left] > flatCoordinates[right]) {
left = right;
right = 0;
}
const clampedLeft = Math.max(extent[0], flatCoordinates[left]);
const clampedRight = Math.min(extent[2], flatCoordinates[right]);
const lon = clamp(
extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
clampedLeft, clampedRight);
const coordinate = [lon, flatCoordinates[1]];
let point;
if (index in this.parallelsLabels_) {
point = this.parallelsLabels_[index].geom;
point.setCoordinates(coordinate);
} else {
point = new Point(coordinate);
}
const coordinate1 = flatCoordinates[left + 1] +
(flatCoordinates[right + 1] - flatCoordinates[left + 1]) * (lon - flatCoordinates[left]) /
(flatCoordinates[right] - flatCoordinates[left]);
const coordinate = [lon, coordinate1];
const point = this.parallelsLabels_[index].geom;
point.setCoordinates(coordinate);
return point;
}
@@ -830,23 +1042,66 @@ class Graticule extends VectorLayer {
const epsg4326Projection = getProjection('EPSG:4326');
const worldExtent = projection.getWorldExtent();
const worldExtentP = transformExtent(worldExtent, epsg4326Projection, projection);
this.maxLat_ = worldExtent[3];
this.maxLon_ = worldExtent[2];
this.minLat_ = worldExtent[1];
this.minLon_ = worldExtent[0];
this.maxLatP_ = worldExtentP[3];
this.maxLonP_ = worldExtentP[2];
this.minLatP_ = worldExtentP[1];
this.minLonP_ = worldExtentP[0];
// If the world extent crosses the dateline define a custom transform to
// return longitudes which wrap the dateline
const toLonLatTransform = getTransform(projection, epsg4326Projection);
if (this.minLon_ < this.maxLon_) {
this.toLonLatTransform_ = toLonLatTransform;
} else {
const split = this.minLon_ + this.maxLon_ / 2;
this.maxLon_ += 360;
this.toLonLatTransform_ = function(coordinates, opt_output, opt_dimension) {
const dimension = opt_dimension || 2;
const lonLatCoordinates = toLonLatTransform(coordinates, opt_output, dimension);
for (let i = 0, l = lonLatCoordinates.length; i < l; i += dimension) {
if (lonLatCoordinates[i] < split) {
lonLatCoordinates[i] += 360;
}
}
return lonLatCoordinates;
};
}
// Transform the extent to get the limits of the view projection extent
// which should be available to the graticule
this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection);
const worldExtentP = applyTransform(
[this.minLon_, this.minLat_, this.maxLon_, this.maxLat_],
this.fromLonLatTransform_,
undefined,
8
);
this.toLonLatTransform_ = getTransform(projection, epsg4326Projection);
this.minX_ = worldExtentP[0];
this.maxX_ = worldExtentP[2];
this.minY_ = worldExtentP[1];
this.maxY_ = worldExtentP[3];
// Determine the view projection coordinates of the extremities of the world extent
// as these may lie inside a view extent (for example the pole in a polar projection)
this.bottomLeft_ = this.fromLonLatTransform_([this.minLon_, this.minLat_]);
this.bottomRight_ = this.fromLonLatTransform_([this.maxLon_, this.minLat_]);
this.topLeft_ = this.fromLonLatTransform_([this.minLon_, this.maxLat_]);
this.topRight_ = this.fromLonLatTransform_([this.maxLon_, this.maxLat_]);
// Transform the projection center to lon lat
// Some projections may have a void area at the poles
// so replace any NaN latitudes with the min or max value closest to a pole
this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent()));
if (isNaN(this.projectionCenterLonLat_[1])) {
this.projectionCenterLonLat_[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
this.maxLat_ : this.minLat_;
}
this.projection_ = projection;
}

View File

@@ -33,6 +33,10 @@ import SourceState from '../source/State.js';
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {Array<import("./Base.js").default>|import("../Collection.js").default<import("./Base.js").default>} [layers] Child layers.
*/

View File

@@ -24,6 +24,10 @@ import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {Array<string>} [gradient=['#00f', '#0ff', '#0f0', '#ff0', '#f00']] The color gradient
* of the heatmap, specified as an array of CSS color strings.
* @property {number} [radius=8] Radius size in pixels.

View File

@@ -31,6 +31,10 @@ import {assert} from '../asserts.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../source/Source.js").default} [source] Source for this layer. If not provided to the constructor,
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
* construction.

View File

@@ -20,6 +20,10 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
* features before rendering. By default features are drawn in the order that they are created. Use
* `null` to avoid the sort, but get an undefined draw order.

View File

@@ -24,6 +24,10 @@ import {assign} from '../obj.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
* features before rendering. By default features are drawn in the order that they are created. Use
* `null` to avoid the sort, but get an undefined draw order.

View File

@@ -23,6 +23,10 @@ import Layer from './Layer.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {import("../source/Vector.js").default} [source] Source.
* @property {boolean} [disableHitDetection=false] Setting this to true will provide a slight performance boost, but will
* prevent all hit detection on the layer.

View File

@@ -476,12 +476,14 @@ export function transform(coordinate, source, destination) {
* @param {import("./extent.js").Extent} extent The extent to transform.
* @param {ProjectionLike} source Source projection-like.
* @param {ProjectionLike} destination Destination projection-like.
* @param {number=} opt_stops Number of stops per side used for the transform.
* By default only the corners are used.
* @return {import("./extent.js").Extent} The transformed extent.
* @api
*/
export function transformExtent(extent, source, destination) {
export function transformExtent(extent, source, destination, opt_stops) {
const transformFunc = getTransform(source, destination);
return applyTransform(extent, transformFunc);
return applyTransform(extent, transformFunc, undefined, opt_stops);
}

View File

@@ -6,6 +6,8 @@ import {createCanvasContext2D} from '../dom.js';
import {clear} from '../obj.js';
import BaseObject from '../Object.js';
import EventTarget from '../events/Target.js';
import {WORKER_OFFSCREEN_CANVAS} from '../has.js';
import {toString} from '../transform.js';
/**
@@ -297,34 +299,40 @@ export const measureTextHeight = (function() {
*/
let div;
const heights = textHeights;
return function(font) {
let height = heights[font];
return function(fontSpec) {
let height = heights[fontSpec];
if (height == undefined) {
if (!div) {
div = document.createElement('div');
div.innerHTML = 'M';
div.style.margin = '0 !important';
div.style.padding = '0 !important';
div.style.position = 'absolute !important';
div.style.left = '-99999px !important';
if (WORKER_OFFSCREEN_CANVAS) {
const font = getFontParameters(fontSpec);
const metrics = measureText(fontSpec, 'Žg');
const lineHeight = isNaN(Number(font.lineHeight)) ? 1.2 : Number(font.lineHeight);
textHeights[fontSpec] = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
} else {
if (!div) {
div = document.createElement('div');
div.innerHTML = 'M';
div.style.margin = '0 !important';
div.style.padding = '0 !important';
div.style.position = 'absolute !important';
div.style.left = '-99999px !important';
}
div.style.font = fontSpec;
document.body.appendChild(div);
height = div.offsetHeight;
heights[fontSpec] = height;
document.body.removeChild(div);
}
div.style.font = font;
document.body.appendChild(div);
height = div.offsetHeight;
heights[font] = height;
document.body.removeChild(div);
}
return height;
};
})();
/**
* @param {string} font Font.
* @param {string} text Text.
* @return {number} Width.
* @return {TextMetrics} Text metrics.
*/
export function measureTextWidth(font, text) {
function measureText(font, text) {
if (!measureContext) {
measureContext = createCanvasContext2D(1, 1);
}
@@ -332,9 +340,17 @@ export function measureTextWidth(font, text) {
measureContext.font = font;
measureFont = measureContext.font;
}
return measureContext.measureText(text).width;
return measureContext.measureText(text);
}
/**
* @param {string} font Font.
* @param {string} text Text.
* @return {number} Width.
*/
export function measureTextWidth(font, text) {
return measureText(font, text).width;
}
/**
* Measure text width using a cache.
@@ -404,6 +420,9 @@ export function drawImageOrLabel(context,
transform, opacity, labelOrImage, originX, originY, w, h, x, y, scale) {
context.save();
if (opacity !== 1) {
context.globalAlpha *= opacity;
}
if (transform) {
context.setTransform.apply(context, transform);
}
@@ -429,9 +448,31 @@ function executeLabelInstructions(label, context) {
const contextInstructions = label.contextInstructions;
for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {
if (Array.isArray(contextInstructions[i + 1])) {
CanvasRenderingContext2D.prototype[contextInstructions[i]].apply(context, contextInstructions[i + 1]);
context[contextInstructions[i]].apply(context, contextInstructions[i + 1]);
} else {
context[contextInstructions[i]] = contextInstructions[i + 1];
}
}
}
/**
* @type {HTMLCanvasElement}
* @private
*/
let createTransformStringCanvas = null;
/**
* @param {import("../transform.js").Transform} transform Transform.
* @return {string} CSS transform.
*/
export function createTransformString(transform) {
if (WORKER_OFFSCREEN_CANVAS) {
return toString(transform);
} else {
if (!createTransformStringCanvas) {
createTransformStringCanvas = createCanvasContext2D(1, 1).canvas;
}
createTransformStringCanvas.style.transform = toString(transform);
return createTransformStringCanvas.style.transform;
}
}

View File

@@ -18,6 +18,7 @@ import {
} from '../../transform.js';
import {defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
import RBush from 'rbush/rbush.js';
import {WORKER_OFFSCREEN_CANVAS} from '../../has.js';
/**
@@ -204,7 +205,9 @@ class Executor {
contextInstructions.push('lineCap', strokeState.lineCap);
contextInstructions.push('lineJoin', strokeState.lineJoin);
contextInstructions.push('miterLimit', strokeState.miterLimit);
if (CanvasRenderingContext2D.prototype.setLineDash && strokeState.lineDash.length) {
// eslint-disable-next-line
const Context = WORKER_OFFSCREEN_CANVAS ? OffscreenCanvasRenderingContext2D : CanvasRenderingContext2D;
if (Context.prototype.setLineDash) {
contextInstructions.push('setLineDash', [strokeState.lineDash]);
contextInstructions.push('lineDashOffset', strokeState.lineDashOffset);
}
@@ -362,7 +365,7 @@ class Executor {
null;
if (declutterArgs) {
if (fillStroke) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
declutterArgs.push(fillInstruction, strokeInstruction, p1.slice(0), p2.slice(0), p3.slice(0), p4.slice(0));
}
declutterGroup.push(declutterArgs);
}

View File

@@ -33,7 +33,7 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
const renderer = new CanvasImmediateRenderer(context, 0.5, extent, null, rotation);
const featureCount = features.length;
// Stretch hit detection index to use the whole available color range
const indexFactor = Math.ceil((256 * 256 * 256 - 1) / featureCount);
const indexFactor = Math.floor((256 * 256 * 256 - 1) / featureCount);
const featuresByZIndex = {};
for (let i = 1; i <= featureCount; ++i) {
const feature = features[i - 1];
@@ -65,6 +65,10 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
const image = originalStyle.getImage();
if (image) {
const imgSize = image.getImageSize();
if (!imgSize) {
continue;
}
const canvas = document.createElement('canvas');
canvas.width = imgSize[0];
canvas.height = imgSize[1];
@@ -121,6 +125,7 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
}
}
}
document.body.appendChild(context.canvas);
return context.getImageData(0, 0, canvas.width, canvas.height);
}
@@ -141,7 +146,7 @@ export function hitDetect(pixel, features, imageData) {
const g = imageData.data[index + 1];
const b = imageData.data[index + 2];
const i = b + (256 * (g + (256 * r)));
const indexFactor = Math.ceil((256 * 256 * 256 - 1) / features.length);
const indexFactor = Math.floor((256 * 256 * 256 - 1) / features.length);
if (i && i % indexFactor === 0) {
resultFeatures.push(features[i / indexFactor - 1]);
}

View File

@@ -9,6 +9,7 @@ import {inView} from '../layer/Layer.js';
import {shared as iconImageCache} from '../style/IconImageCache.js';
import {compose as composeTransform, makeInverse} from '../transform.js';
import {renderDeclutterItems} from '../render.js';
import {wrapX} from '../coordinate.js';
/**
* @abstract
@@ -102,19 +103,12 @@ class MapRenderer extends Disposable {
const projection = viewState.projection;
let translatedCoordinate = coordinate;
const translatedCoordinate = wrapX(coordinate.slice(), projection);
const offsets = [[0, 0]];
if (projection.canWrapX()) {
if (projection.canWrapX() && checkWrapped) {
const projectionExtent = projection.getExtent();
const worldWidth = getWidth(projectionExtent);
const x = coordinate[0];
if (x < projectionExtent[0] || x > projectionExtent[2]) {
const worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
}
if (checkWrapped) {
offsets.push([-worldWidth, 0], [worldWidth, 0]);
}
offsets.push([-worldWidth, 0], [worldWidth, 0]);
}
const layerStates = frameState.layerStatesArray;

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