Compare commits

..

242 Commits

Author SHA1 Message Date
Olivier Guyot
2ad39cf69e Added missing Type component 2019-09-24 10:50:52 +02:00
Olivier Guyot
6929cb3001 Store typedef on the helper and use it to show a parameter list 2019-09-24 10:47:06 +02:00
Tim Schaub
5ee3063d01 Gatsby setup for API docs 2019-05-20 10:30:44 -06:00
Frédéric Junod
2322131b01 Merge pull request #9576 from fredj/has-geolocation
Remove geolocation detection from ol/has
2019-05-18 09:40:21 +02:00
Frederic Junod
39bb6a8ffe Remove geolocation detection from ol/has 2019-05-18 08:50:33 +02:00
Tim Schaub
0631a121c3 Merge pull request #9575 from tschaub/untwisted-exports
Rework exports for getUid and control defaults
2019-05-17 13:03:14 -06:00
Tim Schaub
c860f15f91 Break the circular dependency by extending a pluggable map 2019-05-17 12:38:32 -06:00
Tim Schaub
c10fd7aaab Avoid overwriting longname for getUid 2019-05-17 12:00:10 -06:00
Andreas Hocevar
7ced251d19 Merge pull request #9574 from jumpinjackie/update-mapguide-demo-server
Update OL MapGuide example to point to my demo MapGuide Server.
2019-05-17 19:49:39 +02:00
Frédéric Junod
637c823fa6 Merge pull request #9571 from fredj/misc_examples
Small examples improvements
2019-05-17 17:00:58 +02:00
Frederic Junod
2d655143c3 Add an Overlay in the export-map example 2019-05-17 16:45:29 +02:00
Jackie Ng
fba95ea3f0 Update OL MapGuide example to point to my demo MapGuide Server.
Fixes #9573
2019-05-18 00:21:53 +10:00
Frédéric Junod
40393cd9a4 Merge pull request #9572 from fredj/upgrade-notes_css
Add a note about CSS removal in upgrade-notes.md
2019-05-17 15:44:31 +02:00
Frederic Junod
10527bd221 Remove margin in full screen
In only affects Safari, in Chrome `margin: 0;` is in the default browser's style sheet.
2019-05-17 15:41:03 +02:00
Frederic Junod
4c2b11f6d7 Add a note about CSS removal in upgrade-notes.md 2019-05-17 15:21:51 +02:00
Frédéric Junod
512a39bafd Merge pull request #9570 from fredj/rm_media_print
Remove CSS print rules in ol.css
2019-05-17 14:58:55 +02:00
Frederic Junod
78c09a0ff6 Add svg icon example 2019-05-17 14:48:03 +02:00
Frederic Junod
6dc00b75e0 Update d3 version in d3 example 2019-05-17 14:27:20 +02:00
Frederic Junod
6b50f1555b Add webgl tag to heatmap layer example 2019-05-17 14:25:34 +02:00
Frederic Junod
a6f098f78b Remove CSS print rules in ol.css
Fixes #7909
2019-05-17 14:21:19 +02:00
Tim Schaub
6d06f81ca7 Merge pull request #9563 from tschaub/fragile-docs
Fix @abstract and @module annotations
2019-05-16 16:27:09 -06:00
Tim Schaub
908ecb39e3 Description below @abstract trips up JSDoc 2019-05-16 16:10:30 -06:00
Tim Schaub
6cad19e9d5 Description below @module trips up JSDoc 2019-05-16 16:09:30 -06:00
Andreas Hocevar
17d26acb2f Merge pull request #9560 from ahocevar/simplify-loading
Simplify loading detection loop
2019-05-16 22:27:59 +02:00
Andreas Hocevar
579fadd797 Merge pull request #9561 from ahocevar/map-memory-leak
Remove memory leak caused by label cache listeners
2019-05-16 22:26:56 +02:00
Tim Schaub
9693336d99 Merge pull request #9559 from tschaub/minify-worker
Minify worker
2019-05-16 14:20:11 -06:00
ahocevar
335648d613 Remove memory leak caused by label cache listeners 2019-05-16 21:04:55 +02:00
ahocevar
dc906f79e1 Simplify loading detection loop 2019-05-16 20:19:32 +02:00
Tim Schaub
34a8a484c4 Merge pull request #9558 from tschaub/unlisten
Stop listening for image decoding
2019-05-16 11:46:15 -06:00
Tim Schaub
0d489f2ea9 Minify worker in examples for a production build 2019-05-16 10:41:33 -06:00
Tim Schaub
d49e166506 Minify worker source 2019-05-16 10:35:18 -06:00
Frederic Junod
a0e6af425e Add tests for listenImage function, fix private variables initialization 2019-05-16 16:42:37 +02:00
Tim Schaub
ee9a0bcd05 Stop listening for image decoding 2019-05-16 08:06:12 -06:00
Tim Schaub
442fbb13d2 Merge pull request #9550 from tschaub/worker
Setup for building workers
2019-05-16 07:02:34 -06:00
Frédéric Junod
fddc5bcc5b Merge pull request #9555 from fredj/rm_unused
Remove unused roundUpToPowerOfTwo function
2019-05-16 13:57:19 +02:00
Frederic Junod
c2058af13a Remove unused roundUpToPowerOfTwo function 2019-05-16 12:11:58 +02:00
Frederic Junod
bb022050ed Add 'webworker' lib into the TypeScript's compilerOptions 2019-05-16 09:49:29 +02:00
Frédéric Junod
a8e5cb1e12 Merge pull request #9553 from openlayers/greenkeeper/ol-mapbox-style-5.0.0-beta.2
chore(package): update ol-mapbox-style to version 5.0.0-beta.2
2019-05-16 09:43:56 +02:00
Frédéric Junod
1628ce8729 Merge pull request #9551 from fredj/img_decode
Use HTMLImageElement.decode if available
2019-05-16 09:30:55 +02:00
greenkeeper[bot]
37f96ddcfa chore(package): update ol-mapbox-style to version 5.0.0-beta.2 2019-05-16 07:21:23 +00:00
Andreas Hocevar
1fc75fdc68 Merge pull request #9500 from edellucien/kml_extended_data
KML string validation with extendedData
2019-05-16 09:20:03 +02:00
lucien
10c4ec0b37 Only use 'pushSerializeAndPop' later in code to write extendedData after 2019-05-16 09:10:40 +02:00
Frederic Junod
2e34dd0faf Use HTMLImageElement.decode if available 2019-05-16 08:53:29 +02:00
Tim Schaub
b7b37f9548 Add worker loader to the tests 2019-05-15 16:49:54 -06:00
Tim Schaub
05f13bb363 Add worker loader to the examples 2019-05-15 16:49:38 -06:00
Tim Schaub
e307410301 A task to inline workers 2019-05-15 16:38:06 -06:00
Tim Schaub
5a4541dadb Merge pull request #9534 from tschaub/simpler-mapbox-layer-example
Remove unnecessary parts from the Mapbox layer example
2019-05-15 14:00:46 -06:00
Andreas Hocevar
56ec6b093e Merge pull request #9548 from ahocevar/italic-labels
Avoid cut off labels for italic fonts
2019-05-15 16:58:17 +02:00
Frédéric Junod
61d753c803 Merge pull request #9549 from fredj/rm_unused
Remove unused getReplayTransform_ function in VectorTileLayer
2019-05-15 16:31:09 +02:00
Tim Schaub
f312706269 Remove unnecessary parts from the Mapbox layer example 2019-05-15 08:26:43 -06:00
Frederic Junod
f33ad5e025 Remove unused getReplayTransform_ function in VectorTileLayer 2019-05-15 15:10:54 +02:00
ahocevar
2e31f716ed Avoid cut off labels for italic text 2019-05-15 15:01:12 +02:00
Tim Schaub
eafb657264 Merge pull request #9545 from tschaub/default-view-extent
Avoid panning off the edge of the world
2019-05-15 04:58:29 -06:00
Tim Schaub
0cee259d0b Merge pull request #9539 from tschaub/event-error
Document existing error event type
2019-05-15 04:53:57 -06:00
Tim Schaub
be8797f355 Merge pull request #9541 from tschaub/rbush-three
Upgrade to rbush@3
2019-05-15 04:53:15 -06:00
Tim Schaub
d652bfc4a7 Merge pull request #9543 from tschaub/upgrade-jsdoc-plugin
Update jsdoc-plugin-typescript to version 2.0.1
2019-05-15 04:52:26 -06:00
Andreas Hocevar
11607caa81 Merge pull request #9536 from ahocevar/font-cache-hits
More font cache hits
2019-05-15 12:13:40 +02:00
ahocevar
41e958ea1f Split text into single chars or don't split at all 2019-05-15 11:55:29 +02:00
Olivier Guyot
39de2451bc Merge pull request #9537 from jahow/webgl-geojson-refactoring
WebGL / Points renderer refactoring
2019-05-15 11:44:40 +02:00
Olivier Guyot
e11e3c5f6e Webgl / minor function renaming 2019-05-15 11:30:24 +02:00
Olivier Guyot
c705775d75 Linting 2019-05-15 10:20:31 +02:00
Olivier Guyot
9ca75e9d43 Webgl points / rebuild buffers when source change 2019-05-15 10:18:53 +02:00
Olivier Guyot
5d2b7fe4bb Webgl points / use the helper ton compute the projection transform
The `WebGLHelper` class now provides a `makeProjectionTransform` method
that updates a transform to match the projection for a given frame state.

This also means that the WebGLHelper does not set the projection matrix
uniform anymore, this is the responsibility of the renderer as
the rendered coordinates will not be in world space from now on.
2019-05-15 10:18:47 +02:00
Olivier Guyot
fb455891ce Webgl points / make coordinates in view space to avoid precision glitches
Fixes #9479
2019-05-15 10:18:47 +02:00
Olivier Guyot
3e2e45ce6d Webgl helper / add the possibility to use transforms as custom uniforms
These will be translated into 4x4 matrices in GLSL.
2019-05-15 10:18:47 +02:00
Olivier Guyot
75eb62363a WebGL points / rebuild buffers only when extent changed 2019-05-15 10:18:47 +02:00
Olivier Guyot
523097903a WebGL points / rebuild buffers on every non animation frame 2019-05-15 10:18:22 +02:00
Olivier Guyot
c6d214b585 Webgl / implement support for custom attributes in webgl buffers
Only numerical attributes can be pushed in webgl buffers.
2019-05-15 10:15:55 +02:00
Frédéric Junod
c9604dbd69 Merge pull request #9546 from fredj/canvas_optim
Lazily create the hit detection context
2019-05-15 10:15:02 +02:00
Frédéric Junod
df37519858 Initialize hitDetectionContext to null
Co-Authored-By: Andreas Hocevar <andreas.hocevar@gmail.com>
2019-05-15 10:03:43 +02:00
Frederic Junod
10c6009ffa Lazily create the hit detection context 2019-05-15 09:52:57 +02:00
Olivier Guyot
27e520add4 WebGL points / use pushFeatureInBuffer util
Feature objects are converted to geoJSON with the properties
set for rendering.
2019-05-15 09:47:00 +02:00
Olivier Guyot
3a429d3f6c Webgl / add utils for pushing geojson geometries in webgl buffers
For now only point geometries are handled.
2019-05-15 09:44:41 +02:00
Olivier Guyot
5e36468245 Webgl / add a simple Layer renderer for common logic
This will eventually provides utilities for manipulating & rendering data
2019-05-15 09:43:29 +02:00
Olivier Guyot
a2d83f5358 WebGL points / add minimal tests 2019-05-15 09:42:15 +02:00
ahocevar
53b9718381 Bump version (beta) 2019-05-15 09:32:20 +02:00
Frédéric Junod
2de282ae49 Merge pull request #9533 from fredj/canvas_optim
Canvas optimizations
2019-05-15 08:24:57 +02:00
Tim Schaub
217c6ba764 Avoid panning off the edge of the world 2019-05-14 20:15:51 -06:00
greenkeeper[bot]
039f21274b chore(package): update jsdoc-plugin-typescript to version 2.0.1 2019-05-14 18:59:50 -06:00
Tim Schaub
09fdd30876 Upgrade to rbush@3 2019-05-14 18:43:08 -06:00
Tim Schaub
72551ab506 Merge pull request #9538 from tschaub/module-name
Correct the module annotation for the vector image layer renderer
2019-05-14 18:10:13 -06:00
Tim Schaub
811e5f60eb Document existing error event type 2019-05-14 14:28:00 -06:00
Tim Schaub
b1ea0fec50 Name the module like the module 2019-05-14 13:58:04 -06:00
Frederic Junod
98ee52c61c Move the transform matrix computation out of the for loop 2019-05-14 15:39:06 +02:00
Frederic Junod
f76b9bdd07 Only apply canvas transform if the tiles are scales 2019-05-14 15:33:44 +02:00
Frédéric Junod
3a1d927c41 Merge pull request #9532 from fredj/rm_prop_mapbox_example
Remove unused 'container' property in mapbox-layer example
2019-05-14 14:23:58 +02:00
Frederic Junod
9224bfab7d Remove unused 'container' property in mapbox-layer example 2019-05-14 13:48:26 +02:00
Frédéric Junod
b5535f3ba5 Merge pull request #9530 from fredj/spelling
Fix spelling
2019-05-14 09:26:53 +02:00
Frederic Junod
bfe6d29601 Fix spelling 2019-05-14 09:17:34 +02:00
Tim Schaub
807525b1db Merge pull request #9528 from openlayers/greenkeeper/puppeteer-1.16.0
Update puppeteer to the latest version 🚀
2019-05-13 21:01:49 -06:00
Tim Schaub
8504a49e17 Merge pull request #9489 from crubier/master
Fix Zoomify to display retina tiles
2019-05-13 19:05:31 -06:00
greenkeeper[bot]
83d317d16d chore(package): update puppeteer to version 1.16.0 2019-05-14 00:10:27 +00:00
Frédéric Junod
55b27c70b5 Merge pull request #9525 from jahow/custom-render-fn
Support a custom render function for the Layer class
2019-05-13 16:45:34 +02:00
Olivier Guyot
1c13893dd1 Mapbox Example / remove es6 shorthand
thanks @fredj

Co-Authored-By: Frédéric Junod <frederic.junod@camptocamp.com>
2019-05-13 16:38:10 +02:00
Olivier Guyot
4a1cda715d Layer / update doc to reflect custom render function support 2019-05-13 16:22:27 +02:00
Olivier Guyot
c9d1725f5c Composite renderer / trigger a render even when the source is undefined 2019-05-13 16:16:53 +02:00
Olivier Guyot
4bf314f9e6 Mapbox Example / simplify to use a custom render function 2019-05-13 16:16:53 +02:00
Olivier Guyot
14f580fe30 Layer / accepts a custom render function 2019-05-13 16:16:53 +02:00
Frédéric Junod
a2e6d4b324 Merge pull request #9522 from fredj/https
Use https urls for mapbox.com
2019-05-13 14:50:37 +02:00
Tim Schaub
dadc240038 Merge pull request #9520 from lutzhelm/iiif-doc
[WIP] Improve IIIF tile source and parser documentation
2019-05-13 06:47:09 -06:00
Andreas Hocevar
dd265623e4 Merge pull request #9523 from jahow/mapbox-simpler-example
Make the code simpler in the Mapbox example
2019-05-13 14:37:14 +02:00
Frederic Junod
23137cdab3 Use https urls for mapbox.com 2019-05-13 14:16:18 +02:00
Lutz Helm
1d08eb5752 Give a hint on how to parse IIIF info.json 2019-05-13 12:27:14 +02:00
Olivier Guyot
78cee60d91 Mapbox example / remove more unused code 2019-05-13 12:15:46 +02:00
Olivier Guyot
1deabaa1c0 Mapbox example / add mapbox css to avoid warning in console
Also remove manipulation of the mapbox canvas (not necessary anymore).
2019-05-13 11:42:28 +02:00
Olivier Guyot
88b6b18cc0 Mapbox example / remove overload of undocumented method
This was out of sync with mabox v54 and is not required anymore.
2019-05-13 11:38:45 +02:00
Andreas Hocevar
355fb41748 Merge pull request #9519 from jahow/mapbox-sync-render
Use synchronous render in Mapbox example
2019-05-13 11:37:26 +02:00
Olivier Guyot
7d2249f652 Mapbox example / trigger a synchronous redraw
This uses an undocumented method to trigger a synchronous redraw
instead of using the standard schedule from Mapbox. The CSS previously used
to make the OL and MB views match is not necessary anymore.

Reference: https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
2019-05-13 11:16:36 +02:00
Lutz Helm
5e288ebedf Improve IIIF tile source doc 2019-05-13 11:15:20 +02:00
Lutz Helm
80eb8b62ce Display union types in IIIFInfo constructor doc 2019-05-13 11:14:43 +02:00
Lutz Helm
cdb36a3bf2 Expose IIIFInfo methods for doc 2019-05-13 11:04:28 +02:00
Lutz Helm
04a28854c9 Make IIIFInfo#Versions appear in doc
For whatever reasons, the possible values of `Versions` did not appear
in the built docs.
2019-05-13 10:49:38 +02:00
Andreas Hocevar
51cf9ee3a1 Merge pull request #9518 from ahocevar/hitdetect-no-declutter
Fix hit detection for multiple layers when decluttering is off
2019-05-13 09:23:43 +02:00
Andreas Hocevar
fbc8580539 Merge pull request #9517 from openlayers/greenkeeper/jsdoc-3.6.2
Update jsdoc to the latest version 🚀
2019-05-13 07:47:07 +02:00
ahocevar
eeec56fa94 Fix hit detection for multiple layers when decluttering is off 2019-05-12 23:32:44 +02:00
Andreas Hocevar
17d83b9c20 Merge pull request #9516 from ahocevar/ol-mapbox-style-5
Upgrade ol-mapbox-style to v5
2019-05-12 21:33:21 +02:00
greenkeeper[bot]
2c9f6b496f chore(package): update jsdoc to version 3.6.2 2019-05-12 16:51:14 +00:00
ahocevar
5006bbe13f Upgrade ol-mapbox-style to v5 2019-05-12 17:34:39 +02:00
ahocevar
a1026a50bd Bump beta version 2019-05-12 16:13:50 +02:00
Andreas Hocevar
c117ec79f7 Merge pull request #9515 from openlayers/greenkeeper/fs-extra-8.0.0
Update fs-extra to the latest version 🚀
2019-05-12 15:48:25 +02:00
greenkeeper[bot]
b37eb29444 chore(package): update fs-extra to version 8.0.0 2019-05-11 14:48:40 +00:00
Andreas Hocevar
4df545dfb0 Merge pull request #9505 from ahocevar/vectortile-pixelratio
Avoid blurry vector tiles
2019-05-10 14:56:10 +02:00
Tim Schaub
70f5822217 Merge pull request #9430 from lutzhelm/iiif
Adds IIIF Image API tile source
2019-05-10 06:32:28 -06:00
Frédéric Junod
d49a41def0 Merge pull request #9512 from fredj/mapbox-layer-example
Mapbox layer example improvement
2019-05-10 14:18:00 +02:00
Frédéric Junod
e4941f60db Merge pull request #9511 from fredj/update_dev_deps
Update devDependencies
2019-05-10 14:17:29 +02:00
Frederic Junod
d1fe22a872 Simplify mapboxgl control container removal 2019-05-10 12:39:39 +02:00
Frederic Junod
5756003c88 Don't create temporary arrays in mapbox-layer example 2019-05-10 10:59:15 +02:00
Frederic Junod
e5e2129a88 Use toLonLat function in mapbox-layer example 2019-05-10 10:48:45 +02:00
Frederic Junod
c5e6728d6d Update mapbox-gl to version 0.54.0 2019-05-10 10:48:21 +02:00
Frederic Junod
d9b3986c95 Update typescript to version 3.4.5 2019-05-10 10:15:30 +02:00
greenkeeper[bot]
a67f8e3f38 chore(package): update serve-static to version 1.14.0 2019-05-10 10:14:40 +02:00
greenkeeper[bot]
7989991da9 chore(package): update glob to version 7.1.4 2019-05-10 10:14:30 +02:00
greenkeeper[bot]
afa70e5a1e chore(package): update webpack-cli to version 3.3.2 2019-05-10 10:14:09 +02:00
greenkeeper[bot]
ce9ea5cc93 chore(package): update loglevelnext to version 3.0.1 2019-05-10 10:13:22 +02:00
greenkeeper[bot]
5f5cdc9645 chore(package): update copy-webpack-plugin to version 5.0.3 2019-05-10 10:13:10 +02:00
greenkeeper[bot]
6370426d52 chore(package): update webpack-cli to version 3.3.1 2019-05-10 10:12:52 +02:00
greenkeeper[bot]
fb7bd2158d chore(package): update sinon to version 7.3.2 2019-05-10 10:11:57 +02:00
greenkeeper[bot]
387b4188f2 chore(package): update front-matter to version 3.0.2 2019-05-10 10:11:44 +02:00
greenkeeper[bot]
c922d4eb8f chore(package): update karma to version 4.1.0 2019-05-10 10:11:27 +02:00
Frédéric Junod
9d4eda2318 Merge pull request #9508 from openlayers/greenkeeper/webpack-4.31.0
Update webpack to the latest version 🚀
2019-05-10 10:09:04 +02:00
Lutz Helm
bd235b7b49 Fix JSDoc error in IIIFInfo 2019-05-09 18:00:18 +02:00
Lutz Helm
7daba05548 Use quoted strings for accessing IIIF_PROFILE_VALUES 2019-05-09 18:00:18 +02:00
Lutz Helm
64e67ae351 Correct IIIF tile source doc 2019-05-09 18:00:18 +02:00
Lutz Helm
40ea2a8b7e Remove extent definition from IIIF example
See
https://github.com/openlayers/openlayers/pull/9430#pullrequestreview-232616993
2019-05-09 18:00:18 +02:00
Lutz Helm
4629fe5028 Add @api annotation for TileGrid#getExtent 2019-05-09 18:00:18 +02:00
Lutz Helm
ba2c558b72 Add typedefs for IIIF info.json responses 2019-05-09 18:00:18 +02:00
Lutz Helm
84f1e0c66e Avoid minification/compilation errors in IIIFInfo
Unquoted properties might be renamed, resulting in errors while
accessing these properties via intented string values.
See also:
https://github.com/openlayers/openlayers/pull/9430#pullrequestreview-232622522
https://github.com/openlayers/openlayers/pull/9430#pullrequestreview-232622575
2019-05-09 18:00:18 +02:00
Lutz Helm
72e41d3703 Remove attribution generation from IIIFInfo
Generating attributions by injecting 3rd party HTML content introduces
XSS vulnerabilities, so with regard to upcoming Image API changes this
functionality is removed.
See also
https://github.com/openlayers/openlayers/pull/9430#issuecomment-482610729
2019-05-09 18:00:18 +02:00
Lutz Helm
6775723840 Fix error in IIIFInfo IIIF Image API v3 handling 2019-05-09 18:00:18 +02:00
Lutz Helm
d332b6a0f4 Prepare IIIFInfo for JSON-LD context extensions
IIIF Image API 3 allows context extensions that should be added to the
info.json's @context property. Therefore, '@context' might be an array
instead of a string.
2019-05-09 18:00:18 +02:00
Lutz Helm
f68b8d8df9 Make IIIF_PROFILE_VALUES consistent with it's doc 2019-05-09 18:00:18 +02:00
Lutz Helm
c2cbae95c6 Fix codestyle in IIIFInfo tests 2019-05-09 18:00:18 +02:00
Lutz Helm
b36ad87cb5 Extend IIIFInfo tests 2019-05-09 18:00:18 +02:00
Lutz Helm
b7c004f95c Remove version specific IIIFInfo methods from class 2019-05-09 18:00:18 +02:00
Lutz Helm
7bfaa3b6ad Refactor IIIFInfo and add tests 2019-05-09 18:00:18 +02:00
Lutz Helm
0cffee6f83 Rename IIIFInfo format methods for more clarity 2019-05-09 18:00:18 +02:00
Lutz Helm
3895a59c5e Fix typo 2019-05-09 18:00:18 +02:00
Lutz Helm
a2b39c9c53 Clean up and document IIIFInfo parser
Optional preferred options are now reduced to the two options that
depend on the image service's supported features: format and quality.
2019-05-09 18:00:18 +02:00
Lutz Helm
12154d98b4 Improve IIIF tile source documentation 2019-05-09 18:00:18 +02:00
Lutz Helm
c25dba415f Add more IIIF tile source tests 2019-05-09 18:00:18 +02:00
Lutz Helm
27d943dcc3 Add tests for IIIF tile source and fix source
The tests are still incomplete.
This commit also corrects the IIIF source where tests have failed.
2019-05-09 18:00:18 +02:00
Lutz Helm
66b5b5d7e1 Cleanup IIIF example code 2019-05-09 18:00:18 +02:00
Lutz Helm
3cf9b5aa28 Add zDirection option to IIIF tile source 2019-05-09 18:00:18 +02:00
Lutz Helm
b77177ed74 Fix errors in IIIF code
- missing import in IIIFInfo
- syntax errors in IIIF
2019-05-09 18:00:18 +02:00
Lutz Helm
f61562a51a Remove unsupported options, document options 2019-05-09 18:00:18 +02:00
Lutz Helm
e4a531de8c Declare IIIF versions as enum 2019-05-09 18:00:18 +02:00
Lutz Helm
063bc51c59 Rename IIIF features to supports
Avoid terminology confusion between OpenLayers map features and IIIF
region/size calculation capability features.
2019-05-09 18:00:18 +02:00
Lutz Helm
3f3fbe7e4b Remove IIIF source rounding workarounds
Always try to use canonical URI form. If the server serves wrong tile
heights for given w, shaped size request URI parameters, so be it.
2019-05-09 18:00:18 +02:00
Lutz Helm
01a6381756 Change the IIIF image example image 2019-05-09 18:00:18 +02:00
Lutz Helm
0ab7ad741f Add error codes for IIIF errors
60: "Missing or invalid `size`."
Without at least a size, no IIIF can be displayed.

61: "Cannot determine IIIF Image API version from provided image
information JSON."
Without finding out the version information, one could only guess how to
use the image info JSON.
2019-05-09 18:00:18 +02:00
Lutz Helm
58efe1f850 Limit IIIF tile source percentages to 10 decimals max
IIIF Image API versions 1 and 2 recommend limiting the number of
decimals digits to 10 at most.
2019-05-09 18:00:18 +02:00
Lutz Helm
66b41a53b8 Fix error in IIIF v3 level0 size paramter
Size request parameter in w,h form for level 0 services that only support
listed sizes had been using erroneous w,w instead of w,h.
2019-05-09 18:00:18 +02:00
Lutz Helm
c00400c500 Add IIIF Image API tilesource with example
src/ol/source/IIIF.js contains a tile source for IIIF Image API services.
It supports Image API version 1 and 2 on compliance levels 0, 1 and 2.

To get working constructor options for IIIF from an IIIF image info.json,
use src/ol/format/IIIFInfo.js.

An example is available in examples/iiif.html respectivly examples/iiif.js.
2019-05-09 18:00:18 +02:00
greenkeeper[bot]
944af1fe80 chore(package): update webpack to version 4.31.0 2019-05-09 08:26:44 +00:00
Vincent Lecrubier
ea55f39298 Support tilePixelRatio in Zoomify to support retina 2019-05-08 22:52:14 +02:00
ahocevar
84db84bc23 Avoid blurry vector tiles 2019-05-08 10:31:29 +02:00
Frédéric Junod
f366eaea52 Merge pull request #9504 from fredj/examples_tsc
Minor examples fixes
2019-05-07 16:38:20 +02:00
Frederic Junod
f5ae41f03e Compare Date with Date instead of number 2019-05-07 14:54:46 +02:00
Frederic Junod
6b1bce2b9d Add missing className property to BaseTile layer options 2019-05-07 14:54:46 +02:00
Frederic Junod
bd57128ca4 Remove unsupported condition property
There's no `condition` property for the Extent interaction
2019-05-07 14:54:46 +02:00
Frederic Junod
5012e4987c Don't use View#constrainCenter function 2019-05-07 14:54:46 +02:00
Andreas Hocevar
6e3d3d4877 Merge pull request #9466 from ahocevar/declutter-global
Declutter in correct order and for all layers
2019-05-07 14:33:24 +02:00
Frederic Junod
d30f6175ce Add function JSDoc tag 2019-05-07 13:52:48 +02:00
Frederic Junod
0e08d9e0fd Add empty declutterItems in RasterSource frameState
To please the type checker.
2019-05-07 13:52:25 +02:00
lucien
81f99f1579 Write placemark's ExtendedData tag after Style tag 2019-05-07 09:02:28 +02:00
Andreas Hocevar
4973281f3c Merge pull request #9497 from simonseyock/patch-2
Fix earth radius in documentation
2019-05-06 17:20:22 +02:00
Simon Seyock
8f3820be22 Fix earth radius in documentation 2019-05-06 16:26:49 +02:00
Andreas Hocevar
033a18bc1c Merge pull request #9493 from ahocevar/jsdoc-3-6
Upgrade jsdoc to v3.6.1
2019-05-06 09:51:39 +02:00
ahocevar
99fb0bf57e Revert "Try downgrading Node for JSDoc"
This reverts commit 284c1dff83.
2019-05-06 09:42:00 +02:00
ahocevar
49a9f21388 Upgrade jsdoc to v3.6.1 2019-05-05 21:29:19 +02:00
Andreas Hocevar
e4d25400ee Merge pull request #9490 from jahow/improve-webgl-doc
Misc. API doc improvements
2019-05-05 19:30:12 +02:00
Andreas Hocevar
1e350677fb Merge pull request #9492 from ahocevar/unmanaged-zindex
Fix zIndex handling for unmanaged layers
2019-05-05 19:14:21 +02:00
ahocevar
86f304ae02 Fix typos 2019-05-05 15:11:22 +02:00
ahocevar
00c09eb281 Make rendering tests more cross-platform proof 2019-05-05 15:05:02 +02:00
ahocevar
6c8c8a6477 Fix decluttering on VectorImage layers 2019-05-05 14:54:23 +02:00
ahocevar
1142caf5e8 Modify render tests to catch regressions 2019-05-05 14:54:23 +02:00
ahocevar
ba6ac43a28 Fix zIndex handling for unmanaged layers 2019-05-05 13:24:46 +02:00
ahocevar
12289b8ef9 Declutter in correct order and for all layers 2019-05-05 12:20:38 +02:00
Olivier Guyot
f69c37566e Improve documentation on webgl and View 2019-05-04 17:26:05 +02:00
Tim Schaub
6cfd0b70ed Merge pull request #9388 from jahow/restore-coverage
Restore code coverage report
2019-05-03 08:33:45 -06:00
Tim Schaub
d95bcc8594 Merge pull request #9487 from tschaub/examples-layout
Avoid header expanding over examples
2019-05-03 08:28:27 -06:00
Olivier Guyot
d3e6f4c3b2 Restore code coverage in Karma config
The transpiling step is done by babel instead of bublé now.
Bublé caused the istanbul instrumenter step to crash because of an
unexpected SourceMap object format.
2019-05-03 15:15:14 +02:00
Frédéric Junod
eb21369d86 Merge pull request #9488 from openlayers/codesandbox_lang_attr
Set the 'lang' attribute to the html tag in examples
2019-05-03 14:31:31 +02:00
Frederic Junod
68a29f1ac6 Set the 'lang' attribute to the html tag in examples 2019-05-03 11:32:33 +02:00
Tim Schaub
6413badada Avoid header expanding over examples 2019-05-02 18:31:56 -06:00
Frédéric Junod
d6485b1e94 Merge pull request #9486 from openlayers/greenkeeper/jquery-3.4.1
Update jquery to the latest version 🚀
2019-05-02 08:45:13 +02:00
greenkeeper[bot]
98a5f552b2 chore(package): update jquery to version 3.4.1 2019-05-01 21:22:51 +00:00
Tim Schaub
067260170b Merge pull request #9484 from tschaub/ci-docs
Build API docs in CI job
2019-05-01 12:44:33 -06:00
Tim Schaub
9850c0134e Merge pull request #9476 from tschaub/event-longnames
Document events fired by interactions
2019-05-01 10:04:58 -06:00
Tim Schaub
284c1dff83 Try downgrading Node for JSDoc 2019-05-01 10:03:17 -06:00
Tim Schaub
d166c79242 Build API docs in CI job 2019-05-01 09:06:40 -06:00
Tim Schaub
e4f377fb46 Merge pull request #9475 from tschaub/single-color-callback
Call the color callback once per feature
2019-04-29 09:14:40 -06:00
Tim Schaub
e22af6dbd6 Merge pull request #9477 from tschaub/unused
Tidy up the JSDoc events plugin
2019-04-29 06:18:22 -06:00
Tim Schaub
0f998b4522 Link to the extent event instead of the extent event type 2019-04-28 16:36:33 -06:00
Tim Schaub
2cdfcf8b21 Latest jsdoc plugin for event longnames 2019-04-28 16:26:14 -06:00
Tim Schaub
b3e770226f Smaller scope 2019-04-28 16:03:54 -06:00
Tim Schaub
981328576f Remove unused classes lookup 2019-04-28 16:00:43 -06:00
Tim Schaub
3b1a415d6b Call the color callback once per feature 2019-04-28 14:09:31 -06:00
Andreas Hocevar
fde36b237e Merge pull request #9469 from ahocevar/vectortile-zdirection
Use nearest lower resolution of vector tiles
2019-04-26 15:12:41 +02:00
ahocevar
dde9c59021 Use nearest lower resolution of vector tiles 2019-04-26 14:29:09 +02:00
Frédéric Junod
a12b323907 Merge pull request #9468 from openlayers/greenkeeper/puppeteer-1.15.0
Update puppeteer to the latest version 🚀
2019-04-26 08:42:08 +02:00
greenkeeper[bot]
1687f9bb84 chore(package): update puppeteer to version 1.15.0 2019-04-26 02:33:10 +00:00
Tim Schaub
9a12a668a2 Merge pull request #9452 from tschaub/color-callback
Fewer calls to the WebGL color callback
2019-04-24 09:46:41 -06:00
Tim Schaub
b98268ffee Merge pull request #9453 from tschaub/for-key-in-uniforms
Remove unnecessary closure and fix uniform type
2019-04-23 17:20:26 -06:00
Frédéric Junod
4d1ae3d483 Merge pull request #9459 from fredj/html-to-image
Use html-to-image instead of dom-to-image-more
2019-04-23 11:53:57 +02:00
Frederic Junod
2f6f110fa3 Remove constrainResolution property in fit options 2019-04-23 10:19:21 +02:00
Frederic Junod
93c25d4f82 Export the map viewport instead of the layers
And filter out the controls elements
2019-04-23 10:17:16 +02:00
Frederic Junod
2ac1095c52 Use html-to-image instead of dom-to-image-more
dom-to-image-more do not support safari
2019-04-23 09:58:31 +02:00
Tim Schaub
d5b868f4a6 Version without v 2019-04-22 09:22:20 -06:00
Tim Schaub
17081fac46 Bump to v6.0.0-beta.6
The version must point to an existing tag for published examples to work.
2019-04-22 09:15:27 -06:00
Andreas Hocevar
4a18b57021 Merge pull request #9450 from ahocevar/later-interacting-flag
Set the interacting flag on pointerdrag instead of pointerdown
2019-04-19 17:51:33 -07:00
Tim Schaub
58c4c9ebb8 Remove unnecessary closure and fix uniform type 2019-04-19 14:33:43 -07:00
Tim Schaub
a16234faaa Allow color callback without third arg 2019-04-19 13:57:40 -07:00
Tim Schaub
154265a2d9 Fewer calls to the color callback 2019-04-19 13:49:53 -07:00
Andreas Hocevar
440ae897a5 Merge pull request #9444 from openlayers/greenkeeper/mocha-6.1.4
Update mocha to the latest version 🚀
2019-04-19 10:11:46 -07:00
ahocevar
86fac0937b Set the interacting flag on pointerdrag instead of pointerdown 2019-04-19 09:42:12 -07:00
greenkeeper[bot]
682102d4d6 chore(package): update mocha to version 6.1.4 2019-04-18 18:59:28 +00:00
Tim Schaub
22774b4821 Bump to 6.0.0-beta 2019-04-18 10:09:58 -07:00
Andreas Hocevar
046e73e785 Merge pull request #9439 from ahocevar/vectortile-attributions
Add attributionsCollapsible option to source/VectorTile
2019-04-18 07:36:50 -07:00
Tim Schaub
a71a823676 Merge pull request #9440 from tschaub/csv-parsing
Skip the header and bad data in CSV parsing
2019-04-17 23:25:02 -07:00
Tim Schaub
fc0ed7b96f Skip the header and bad data 2019-04-17 16:26:40 -07:00
ahocevar
756f63e212 Add attributionsCollapsible option to source/VectorTile 2019-04-17 09:06:37 -07:00
141 changed files with 25173 additions and 1154 deletions

View File

@@ -27,6 +27,10 @@ jobs:
name: Run Tests
command: npm test
- store_artifacts:
path: coverage/
destination: coverage
- store_artifacts:
path: rendering/cases/
destination: rendering
@@ -38,3 +42,19 @@ jobs:
- store_artifacts:
path: build/examples
destination: examples
- run:
name: Build API Docs
command: npm run apidoc
- store_artifacts:
path: build/apidoc
destination: apidoc
- run:
name: Build Website
command: npm run build-site
- store_artifacts:
path: public
destination: website

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@
/coverage/
/dist/
node_modules/
/.cache/
/public/

View File

@@ -4,6 +4,28 @@
#### Backwards incompatible changes
#### Removal of `GEOLOCATION` constant from `ol/has`
If you were previously using this constant, you can check if `'geolocation'` is define in `navigator` instead.
```js
if ('geolocation' in navigator) {
// ...
}
```
#### Removal of CSS print rules
The CSS media print rules were removed from the `ol.css` file. To get the previous behavior, use the following CSS:
```css
@media print {
.ol-control {
display: none;
}
}
```
#### Removal of optional this arguments
The optional this (i.e. opt_this) arguments were removed from the following methods.
@@ -32,9 +54,9 @@ Previously, this options only constrained the view *center*. This behaviour can
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
##### Zoom is constrained so only one world is visible
##### The view is constrained so only one world is visible
Previously, maps showed multiple worlds at low zoom levels. Now, the view is restricted to show only one world. To get the previous behavior, configure the `ol/View` with `multiWorld: true`.
Previously, maps showed multiple worlds at low zoom levels. In addition, it used to be possible to pan off the north or south edge of the world. Now, the view is restricted to show only one world, and you cannot pan off the edge. To get the previous behavior, configure the `ol/View` with `multiWorld: true`.
##### Removal of deprecated methods
@@ -98,6 +120,14 @@ If you were previously using `VectorTile` layers with `renderMode: 'vector'`, yo
If you were previously using `Vector` layers with `renderMode: 'image'`, you have to remove this configuration option. Instead, use the new `ol/layer/VectorImage` layer with your `ol/source/Vector`.
##### New declutter behavior
If a map has more than one layer with `declutter` set to true, decluttering now considers all `Vector` and `VectorTile` layers, instead of decluttering each layer separately. Only `VectorImage` layers continue to be decluttered separately. The higher the z-index of a layer, the higher the priority of its decluttered items.
Within a layer, the declutter order has changed. Previously, styles with a lower `zIndex` were prioritized over those with a higher `zIndex`. Now the opposite order is used.
On vector layers, even if decluttered images or texts have a lower z-Index than polygons or lines, they will now be rendered on top of the polygons or lines. For vector tile layers, this was the case already in previous releases.
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.

View File

@@ -0,0 +1,23 @@
{
"opts": {
"recurse": true,
"template": "node_modules/jsdoc-json"
},
"tags": {
"allowUnknownTags": true
},
"source": {
"includePattern": "\\.js$",
"include": [
"src/ol"
]
},
"plugins": [
"jsdoc-plugin-typescript",
"config/jsdoc/api-info/plugins/api",
"config/jsdoc/api-info/plugins/module"
],
"typescript": {
"moduleRoot": "src"
}
}

View File

@@ -0,0 +1,15 @@
/**
* Handle the api annotation.
* @param {Object} dictionary The tag dictionary.
*/
exports.defineTags = dictionary => {
dictionary.defineTag('api', {
onTagged: (doclet, tag) => {
doclet.api = true;
}
});
};

View File

@@ -0,0 +1,170 @@
/**
* This plugin adds an `exportMap` property to @module doclets. Each export map
* is an object with properties named like the local identifier and values named
* like the exported identifier.
*
* For example, the code below
*
* export {foo as bar};
*
* would be a map like `{foo: 'bar'}`.
*
* In the case of an export declaration with a source, the export identifier is
* prefixed by the source. For example, this code
*
* export {foo as bar} from 'ol/bam';
*
* would be a map like `{'ol/bam foo': 'bar'}`.
*
* If a default export is a literal or object expression, the local name will be
* an empty string. For example
*
* export default {foo: 'bar'};
*
* would be a map like `{'': 'default'}`.
*/
const assert = require('assert');
const path = require('path');
/**
* A lookup of export maps per source filepath.
*/
const exportMapLookup = {};
function loc(filepath, node) {
return `${filepath}:${node.loc.start.line}`;
}
function nameFromChildIdentifier(filepath, node) {
assert.ok(node.id, `expected identifer in ${loc(filepath, node)}`);
assert.strictEqual(node.id.type, 'Identifier', `expected identifer in ${loc(filepath, node)}`);
return node.id.name;
}
function handleExportNamedDeclaration(filepath, node) {
if (!(filepath in exportMapLookup)) {
exportMapLookup[filepath] = {};
}
const exportMap = exportMapLookup[filepath];
const declaration = node.declaration;
if (declaration) {
// `export class Foo{}` or `export function foo() {}`
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
const name = nameFromChildIdentifier(filepath, declaration);
exportMap[name] = name;
return;
}
// `export const foo = 'bar', bam = 42`
if (declaration.type === 'VariableDeclaration') {
const declarations = declaration.declarations;
assert.ok(declarations.length > 0, `expected variable declarations in ${loc(filepath, declaration)}`);
for (const declarator of declarations) {
assert.strictEqual(declarator.type, 'VariableDeclarator', `unexpected "${declarator.type}" in ${loc(filepath, declarator)}`);
const name = nameFromChildIdentifier(filepath, declarator);
exportMap[name] = name;
}
return;
}
throw new Error(`Unexpected named export "${declaration.type}" in ${loc(filepath, declaration)}`);
}
let prefix = '';
const source = node.source;
if (source) {
// `export foo from 'bar'`
assert.strictEqual(source.type, 'Literal', `unexpected export source "${source.type}" in ${loc(filepath, source)}`);
prefix = `${source.value} `;
}
const specifiers = node.specifiers;
assert.ok(specifiers.length > 0, `expected export specifiers in ${loc(filepath, node)}`);
// `export {foo, bar}` or `export {default as Foo} from 'bar'`
for (const specifier of specifiers) {
assert.strictEqual(specifier.type, 'ExportSpecifier', `unexpected export specifier in ${loc(filepath, specifier)}`);
const local = specifier.local;
assert.strictEqual(local.type, 'Identifier', `unexpected local specifier "${local.type} in ${loc(filepath, local)}`);
const exported = specifier.exported;
assert.strictEqual(local.type, 'Identifier', `unexpected exported specifier "${exported.type} in ${loc(filepath, exported)}`);
exportMap[prefix + local.name] = exported.name;
}
}
function handleDefaultDeclaration(filepath, node) {
if (!(filepath in exportMapLookup)) {
exportMapLookup[filepath] = {};
}
const exportMap = exportMapLookup[filepath];
const declaration = node.declaration;
if (declaration) {
// `export default class Foo{}` or `export default function foo () {}`
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
const name = nameFromChildIdentifier(filepath, declaration);
exportMap[name] = 'default';
return;
}
// `export default foo`
if (declaration.type === 'Identifier') {
exportMap[declaration.name] = 'default';
return;
}
// `export default {foo: 'bar'}` or `export default 42`
if (declaration.type === 'ObjectExpression' || declaration.type === 'Literal') {
exportMap[''] = 'default';
return;
}
}
throw new Error(`Unexpected default export "${declaration.type}" in ${loc(filepath, declaration)}`);
}
exports.astNodeVisitor = {
visitNode: (node, event, parser, filepath) => {
if (node.type === 'ExportNamedDeclaration') {
return handleExportNamedDeclaration(filepath, node);
}
if (node.type === 'ExportDefaultDeclaration') {
return handleDefaultDeclaration(filepath, node);
}
}
};
const moduleLookup = {};
exports.handlers = {
// create a lookup of @module doclets
newDoclet: event => {
const doclet = event.doclet;
if (doclet.kind === 'module') {
const filepath = path.join(doclet.meta.path, doclet.meta.filename);
assert.ok(!(filepath in moduleLookup), `duplicate @module doc in ${filepath}`);
moduleLookup[filepath] = doclet;
}
},
// assign the `exportMap` property to @module doclets
parseComplete: event => {
for (const filepath in moduleLookup) {
assert.ok(filepath in exportMapLookup, `missing ${filepath} in export map lookup`);
moduleLookup[filepath].exportMap = exportMapLookup[filepath];
}
// make sure there was a @module doclet for each export map
for (const filepath in exportMapLookup) {
assert.ok(filepath in moduleLookup, `missing @module doclet in ${filepath}`);
}
}
};

View File

@@ -1,43 +1,43 @@
<table><tr>
<th width="33.3%">Map</th><th width="33.3%">View</th><th width="33.3%">Layers</th>
</tr><tr>
<td><p>A [map](module-ol_Map-Map.html) is made of [layers](module-ol_layer_Base-BaseLayer.html), a [view](module-ol_View-View.html) to visualize them, [interactions](module-ol_interaction_Interaction-Interaction.html) to modify map content and [controls](module-ol_control_Control-Control.html) with UI components.</p>
[Overview](module-ol_Map-Map.html)<br>
[Creation](module-ol_Map-Map.html#Map)<br>
[Events](module-ol_MapBrowserEvent-MapBrowserEvent.html)</td>
<td><p>A <a href="module-ol_Map-Map.html">map</a> is made of <a href="module-ol_layer_Base-BaseLayer.html">layers</a>, a <a href="module-ol_View-View.html">view</a> to visualize them, <a href="module-ol_interaction_Interaction-Interaction.html">interactions</a> to modify map content and <a href="module-ol_control_Control-Control.html">controls</a> with UI components.</p>
<a href="module-ol_Map-Map.html">Overview</a><br>
<a href="module-ol_Map-Map.html#Map">Creation</a><br>
<a href="module-ol_MapBrowserEvent-MapBrowserEvent.html">Events</a></td>
<td><p>The view manages the visual parameters of the map view, like resolution or rotation.</p>
[View](module-ol_View-View.html) with center, projection, resolution and rotation</td>
<td><p>Layers are lightweight containers that get their data from [sources](module-ol_source_Source-Source.html).</p>
[ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)<br>
[ol/layer/Image](module-ol_layer_Image-ImageLayer.html)<br>
[ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)<br>
[ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)</td>
<a href="module-ol_View-View.html">View</a> with center, projection, resolution and rotation</td>
<td><p>Layers are lightweight containers that get their data from <a href="module-ol_source_Source-Source.html">sources</a>.</p>
<a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a><br>
<a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a><br>
<a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a><br>
<a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a></td>
</tr><tr>
<th>Controls</th><th>Interactions</th><th>Sources and formats</th>
</tr><tr>
<td>[Map default controls](module-ol_control_util.html#.defaults)<br>
[All controls](module-ol_control_Control-Control.html)
<td><a href="module-ol_control_util.html#.defaults">Map default controls</a><br>
<a href="module-ol_control_Control-Control.html">All controls</a>
</td>
<td>
[Map default interactions](module-ol_interaction.html#~defaults)<br>
Interactions for [vector features](module-ol_Feature-Feature.html)
<ul><li>[ol/interaction/Select](module-ol_interaction_Select-Select.html)</li>
<li>[ol/interaction/Draw](module-ol_interaction_Draw-Draw.html)</li>
<li>[ol/interaction/Modify](module-ol_interaction_Modify-Modify.html)</li></ul>
[All interactions](module-ol_interaction_Interaction-Interaction.html)</td>
<td>[Tile sources](module-ol_source_Tile-TileSource.html) for [ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)
<br>[Image sources](module-ol_source_Image-ImageSource.html) for [ol/layer/Image](module-ol_layer_Image-ImageLayer.html)
<br>[Vector sources](module-ol_source_Vector-VectorSource.html) for [ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)
<br>[Vector tile sources](module-ol_source_VectorTile-VectorTile.html) for [ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)
<br>[Formats](module-ol_format_Feature-FeatureFormat.html) for reading/writing vector data
<br>[ol/format/WMSCapabilities](module-ol_format_WMSCapabilities-WMSCapabilities.html)</td></tr>
<a href="module-ol_interaction.html#~defaults">Map default interactions</a><br>
Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
<ul><li><a href="module-ol_interaction_Select-Select.html">ol/interaction/Select</a></li>
<li><a href="module-ol_interaction_Draw-Draw.html">ol/interaction/Draw</a></li>
<li><a href="module-ol_interaction_Modify-Modify.html">ol/interaction/Modify</a></li></ul>
<a href="module-ol_interaction_Interaction-Interaction.html">All interactions</a></td>
<td><a href="module-ol_source_Tile-TileSource.html">Tile sources</a> for <a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a>
<br><a href="module-ol_source_Image-ImageSource.html">Image sources</a> for <a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a>
<br><a href="module-ol_source_Vector-VectorSource.html">Vector sources</a> for <a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a>
<br><a href="module-ol_source_VectorTile-VectorTile.html">Vector tile sources</a> for <a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a>
<br><a href="module-ol_format_Feature-FeatureFormat.html">Formats</a> for reading/writing vector data
<br><a href="module-ol_format_WMSCapabilities-WMSCapabilities.html">ol/format/WMSCapabilities</a></td></tr>
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use [ol/proj#transform()](module-ol_proj.html#.transform) and [ol/proj#transformExtent()](module-ol_proj.html#.transformExtent).</p>
[ol/proj](module-ol_proj.html)</td>
<td><p>Changes to all [ol/Object](module-ol_Object-BaseObject.html)s can be observed by calling the [object.on('propertychange')](module-ol_Object-BaseObject.html#on) method. Listeners receive an [ol/Object.ObjectEvent](module-ol_Object-ObjectEvent.html) with information on the changed property and old value.</p>
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
<a href="module-ol_proj.html">ol/proj</a></td>
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
<td>
[ol/Geolocation](module-ol_Geolocation.html)<br>
[ol/Overlay](module-ol_Overlay-Overlay.html)<br></td>
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
</tr></table>
&nbsp;

View File

@@ -1,32 +1,29 @@
const events = {};
const classes = {};
exports.handlers = {
newDoclet: function(e) {
const doclet = e.doclet;
let cls;
if (doclet.kind == 'event') {
cls = doclet.longname.split('#')[0];
if (doclet.kind !== 'event') {
return;
}
const cls = doclet.longname.split('#')[0];
if (!(cls in events)) {
events[cls] = [];
}
events[cls].push(doclet.longname);
} else if (doclet.kind == 'class' && !(doclet.longname in classes)) {
classes[doclet.longname] = doclet;
}
},
parseComplete: function(e) {
const doclets = e.doclets;
let doclet, i, ii, j, jj, event, fires;
for (i = 0, ii = doclets.length - 1; i < ii; ++i) {
doclet = doclets[i];
for (let i = 0, ii = doclets.length - 1; i < ii; ++i) {
const doclet = doclets[i];
if (doclet.fires) {
if (doclet.kind == 'class') {
fires = [];
for (j = 0, jj = doclet.fires.length; j < jj; ++j) {
event = doclet.fires[j].replace('event:', '');
const fires = [];
for (let j = 0, jj = doclet.fires.length; j < jj; ++j) {
const event = doclet.fires[j].replace('event:', '');
if (events[event]) {
fires.push.apply(fires, events[event]);
} else if (doclet.fires[j] !== 'event:ObjectEvent') {

View File

@@ -220,3 +220,11 @@ Duplicate item added to a unique collection. For example, it may be that you tr
### 59
Invalid command found in the PBF. This indicates that the loaded vector tile may be corrupt.
### 60
Missing or invalid `size`.
### 61
Cannot determine IIIF Image API version from provided image information JSON.

View File

@@ -5,7 +5,6 @@
"common": false,
"createMapboxStreetsV6Style": false,
"d3": false,
"domtoimage": false,
"geojsonvt": false,
"GyroNorm": false,
"jsPDF": false,

View File

@@ -6,7 +6,7 @@ docs: >
The example loads TopoJSON geometries and uses d3 (<code>d3.geo.path</code>) to render these geometries to a SVG element.
tags: "d3"
resources:
- https://unpkg.com/d3@4.12.0/build/d3.js
- https://unpkg.com/d3@5.9.2/dist/d3.js
- https://unpkg.com/topojson@3.0.2/dist/topojson.js
---
<div id="map" class="map"></div>

2
examples/d3.js vendored
View File

@@ -85,7 +85,7 @@ const map = new Map({
/**
* Load the topojson data and create an ol/layer/Image for that data.
*/
d3.json('data/topojson/us.json', function(error, us) {
d3.json('data/topojson/us.json').then(function(us) {
const layer = new CanvasLayer({
features: topojson.feature(us, us.objects.counties)

7
examples/data/square.svg Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg">
<g>
<rect width="20" height="20" style="fill:#fff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@@ -40,6 +40,6 @@ gn.init().then(function() {
center[0] -= resolution * gamma * 25;
center[1] += resolution * beta * 25;
view.setCenter(view.constrainCenter(center));
view.setCenter(center);
});
});

6
examples/export-map.css Normal file
View File

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

View File

@@ -3,12 +3,13 @@ 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/dom-to-image-more">dom-to-image-more</a>
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.
tags: "export, png, openstreetmap"
resources:
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
---
<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,9 +1,12 @@
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({
@@ -23,9 +26,23 @@ 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() {
domtoimage.toPng(map.getViewport().querySelector('.ol-layers'))
toPng(map.getTargetElement(), exportOptions)
.then(function(dataURL) {
const link = document.getElementById('image-download');
link.href = dataURL;

View File

@@ -7,7 +7,6 @@ docs: >
tags: "export, pdf, openstreetmap"
resources:
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
---
<div class="row-fluid">
<div class="span12">

View File

@@ -4,6 +4,8 @@ import WKT from '../src/ol/format/WKT.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {toJpeg} from 'html-to-image';
const raster = new TileLayer({
source: new OSM()
});
@@ -41,6 +43,15 @@ const dims = {
a5: [210, 148]
};
// export options for html-to-image.
// See: https://github.com/bubkoo/html-to-image#options
const exportOptions = {
filter: function(element) {
return element.className.indexOf('ol-control') === -1;
}
};
const exportButton = document.getElementById('export-pdf');
exportButton.addEventListener('click', function() {
@@ -57,15 +68,14 @@ exportButton.addEventListener('click', function() {
const extent = map.getView().calculateExtent(size);
map.once('rendercomplete', function() {
domtoimage.toJpeg(map.getViewport().querySelector('.ol-layers')).then(function(dataUrl) {
toJpeg(map.getTargetElement(), exportOptions).then(function(dataUrl) {
const pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().fit(extent, {
size: size,
constrainResolution: false
size: size
});
exportButton.disabled = false;
document.body.style.cursor = 'auto';

View File

@@ -2,7 +2,7 @@ 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';
import {defaults as defaultControls} from '../src/ol/control/util';
import {defaults as defaultControls} from '../src/ol/control.js';
import ZoomSlider from '../src/ol/control/ZoomSlider';
const view = new View({

View File

@@ -1,6 +1,5 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {platformModifierKeyOnly} from '../src/ol/events/condition.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import ExtentInteraction from '../src/ol/interaction/Extent.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
@@ -27,9 +26,7 @@ const map = new Map({
})
});
const extent = new ExtentInteraction({
condition: platformModifierKeyOnly
});
const extent = new ExtentInteraction();
map.addInteraction(extent);
extent.setActive(false);

View File

@@ -10,9 +10,7 @@ import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
import {clamp, lerp} from '../src/ol/math';
import Stamen from '../src/ol/source/Stamen';
const features = [];
const vectorSource = new Vector({
features: [],
attributions: 'NASA'
});
@@ -38,15 +36,16 @@ updateStatusText();
class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
colorCallback: function(feature, vertex, component) {
// component at index 3 is alpha
if (component === 3) {
return 1;
}
colorCallback: function(feature, color) {
// color is interpolated based on year
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
return lerp(oldColor[component], newColor[component], ratio) / 255;
color[0] = lerp(oldColor[0], newColor[0], ratio) / 255;
color[1] = lerp(oldColor[1], newColor[1], ratio) / 255;
color[2] = lerp(oldColor[2], newColor[2], ratio) / 255;
color[3] = 1;
return color;
},
sizeCallback: function(feature) {
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
@@ -109,26 +108,28 @@ function loadData() {
client.open('GET', 'data/csv/meteorite_landings.csv');
client.onload = function() {
const csv = client.responseText;
const features = [];
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
let curIndex;
let prevIndex = 0;
let line;
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
// skip header
if (prevIndex === 0) {
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
if (isNaN(coords[0]) || isNaN(coords[1])) {
// guard against bad data
continue;
}
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
features.push(new Feature({
mass: parseFloat(line[1]) || 0,
year: parseInt(line[2]) || 0,
geometry: new Point(coords)
}));
}
vectorSource.addFeatures(features);
};
client.send();

View File

@@ -1,5 +1,6 @@
.map:-webkit-full-screen {
height: 100%;
margin: 0;
}
.map:-ms-fullscreen {
height: 100%;

View File

@@ -1,5 +1,6 @@
.fullscreen:-webkit-full-screen {
height: 100%;
margin: 0;
}
.fullscreen:-ms-fullscreen {
height: 100%;

View File

@@ -1,5 +1,6 @@
.map:-webkit-full-screen {
height: 100%;
margin: 0;
}
.map:-ms-fullscreen {
height: 100%;

View File

@@ -4,7 +4,7 @@ title: Earthquakes Heatmap
shortdesc: Demonstrates the use of a heatmap layer.
docs: >
This example parses a KML file and renders the features as a <code>ol/layer/Heatmap</code> layer.
tags: "heatmap, kml, vector, style"
tags: "heatmap, kml, vector, style, webgl"
---
<div id="map" class="map"></div>
<form>

View File

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

View File

@@ -10,7 +10,6 @@ import {fromLonLat} from '../src/ol/proj';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
import {lerp} from '../src/ol/math';
const features = [];
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
@@ -39,16 +38,17 @@ class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
texture: texture,
colorCallback: function(feature, vertex, component) {
// component at index 3 is alpha
if (component === 3) {
return 1;
}
colorCallback: function(feature, color) {
// color is interpolated based on year (min is 1910, max is 2013)
// please note: most values are between 2000-2013
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
return lerp(oldColor[component], newColor[component], ratio * ratio) / 255;
color[0] = lerp(oldColor[0], newColor[0], ratio * ratio) / 255;
color[1] = lerp(oldColor[1], newColor[1], ratio * ratio) / 255;
color[2] = lerp(oldColor[2], newColor[2], ratio * ratio) / 255;
color[3] = 1;
return color;
},
texCoordCallback: function(feature, component) {
let coords = shapeTextureCoords[feature.get('shape')];
@@ -70,17 +70,14 @@ function loadData() {
client.open('GET', 'data/csv/ufo_sighting_data.csv');
client.onload = function() {
const csv = client.responseText;
let curIndex;
let prevIndex = 0;
let line;
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
const features = [];
// skip header
if (prevIndex === 0) {
continue;
}
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
let curIndex;
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);

16
examples/iiif.html Normal file
View File

@@ -0,0 +1,16 @@
---
layout: example.html
title: IIIF Image API
shortdesc: Example of a IIIF Image API source.
docs: >
Example of a tile source for an International Image Interoperability Framework (IIIF) Image Service.
Try any Image API version 1 or 2 service.
tags: "IIIF, IIIF Image API, tile source"
---
<div id="map" class="map"></div>
<div class="controls">
<div id="iiif-notification">&nbsp;</div>
Enter <code>info.json</code> URL:
<input type="text" id="imageInfoUrl" value="https://iiif.ub.uni-leipzig.de/iiif/j2k/0000/0107/0000010732/00000072.jpx/info.json">
<button id="display">Display image</button>
</div>

46
examples/iiif.js Normal file
View File

@@ -0,0 +1,46 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import IIIF from '../src/ol/source/IIIF.js';
import IIIFInfo from '../src/ol/format/IIIFInfo.js';
const layer = new TileLayer(),
map = new Map({
layers: [layer],
target: 'map'
}),
notifyDiv = document.getElementById('iiif-notification'),
urlInput = document.getElementById('imageInfoUrl'),
displayButton = document.getElementById('display');
function refreshMap(imageInfoUrl) {
fetch(imageInfoUrl).then(function(response) {
response.json().then(function(imageInfo) {
const options = new IIIFInfo(imageInfo).getTileSourceOptions();
if (options === undefined || options.version === undefined) {
notifyDiv.textContent = 'Data seems to be no valid IIIF image information.';
return;
}
options.zDirection = -1;
const iiifTileSource = new IIIF(options);
layer.setSource(iiifTileSource);
map.setView(new View({
resolutions: iiifTileSource.getTileGrid().getResolutions(),
extent: iiifTileSource.getTileGrid().getExtent(),
constrainOnlyCenter: true
}));
map.getView().fit(iiifTileSource.getTileGrid().getExtent());
notifyDiv.textContent = '';
}).catch(function(body) {
notifyDiv.textContent = 'Could not read image info json. ' + body;
});
}).catch(function() {
notifyDiv.textContent = 'Could not read data from URL.';
});
}
displayButton.addEventListener('click', function() {
refreshMap(urlInput.value);
});
refreshMap(urlInput.value);

View File

@@ -11,9 +11,25 @@
body {
padding-top: 70px;
}
img.header-logo {
padding-left: 18px;
}
input.search-query {
color: #333;
}
@media (max-width: 480px) {
input.search-query {
width: 110px;
}
#count {
display: none;
}
}
@media (max-width: 374px) {
input.search-query {
display: none;
}
}
.example {
display: block;
padding: 10px;
@@ -182,9 +198,9 @@
<body>
<header class="navbar navbar-fixed-top" role="navigation">
<div class="container">
<div class="container-fluid">
<div class="display-table pull-left">
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers Examples</a>
<a class="navbar-brand" href="./"><img class="header-logo" src="./resources/logo-70x70.png">&nbsp;OpenLayers</a>
<form class="navbar-form" role="search">
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search" autofocus>
<span id="count"></span>

View File

@@ -6,9 +6,10 @@ docs: >
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles"
resources:
- https://unpkg.com/mapbox-gl@0.51.0/dist/mapbox-gl.js
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css
cloak:
- key: ER67WIiPdCQvhgsUjoWK
value: Your Mapbox access token from http://mapbox.com/ here
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -1,50 +1,21 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Layer from '../src/ol/layer/Layer';
import {assign} from '../src/ol/obj';
import {getTransform} from '../src/ol/proj';
import SourceState from '../src/ol/source/State';
import {toLonLat, fromLonLat} from '../src/ol/proj';
import {Stroke, Style} from '../src/ol/style.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
class Mapbox extends Layer {
const center = [-98.8, 37.9];
const key = 'ER67WIiPdCQvhgsUjoWK';
/**
* @param {import('./Base.js').Options} options Layer options.
*/
constructor(options) {
const baseOptions = assign({}, options);
super(baseOptions);
this.baseOptions = baseOptions;
/**
* @private
* @type boolean
*/
this.loaded = false;
this.initMap();
}
initMap() {
const map = this.map_;
const view = map.getView();
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
const center = transformToLatLng(view.getCenter());
this.centerLastRender = view.getCenter();
this.zoomLastRender = view.getZoom();
this.centerLastRender = view.getCenter();
this.zoomLastRender = view.getZoom();
const options = assign(this.baseOptions, {
const mbMap = new mapboxgl.Map({
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key,
attributionControl: false,
boxZoom: false,
center,
container: map.getTargetElement(),
center: center,
container: 'map',
doubleClickZoom: false,
dragPan: false,
dragRotate: false,
@@ -52,137 +23,45 @@ class Mapbox extends Layer {
keyboard: false,
pitchWithRotate: false,
scrollZoom: false,
touchZoomRotate: false,
zoom: view.getZoom() - 1
});
touchZoomRotate: false
});
this.mbmap = new mapboxgl.Map(options);
this.mbmap.on('load', function() {
this.mbmap.getCanvas().remove();
this.loaded = true;
this.map_.render();
[
'mapboxgl-control-container'
].forEach(className => document.getElementsByClassName(className)[0].remove());
}.bind(this));
const mbLayer = new Layer({
render: function(frameState) {
const canvas = mbMap.getCanvas();
const viewState = frameState.viewState;
this.mbmap.on('render', function() {
// Reset offset
if (this.centerNextRender) {
this.centerLastRender = this.centerNextRender;
}
if (this.zoomNextRender) {
this.zoomLastRender = this.zoomNextRender;
}
this.updateRenderedPosition([0, 0], 1);
}.bind(this));
const visible = mbLayer.getVisible();
canvas.style.display = visible ? 'block' : 'none';
}
const opacity = mbLayer.getOpacity();
canvas.style.opacity = opacity;
/**
*
* @inheritDoc
*/
render(frameState) {
const map = this.map_;
const view = map.getView();
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
this.centerNextRender = view.getCenter();
const lastRender = map.getPixelFromCoordinate(this.centerLastRender);
const nextRender = map.getPixelFromCoordinate(this.centerNextRender);
const centerOffset = [lastRender[0] - nextRender[0], lastRender[1] - nextRender[1]];
this.zoomNextRender = view.getZoom();
const zoomOffset = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
this.updateRenderedPosition(centerOffset, zoomOffset);
const rotation = frameState.viewState.rotation;
// adjust view parameters in mapbox
const rotation = viewState.rotation;
if (rotation) {
this.mbmap.rotateTo(-rotation * 180 / Math.PI, {
mbMap.rotateTo(-rotation * 180 / Math.PI, {
animate: false
});
}
// Re-render mbmap
const center = transformToLatLng(this.centerNextRender);
const zoom = view.getZoom() - 1;
this.mbmap.jumpTo({
center: center,
zoom: zoom
mbMap.jumpTo({
center: toLonLat(viewState.center),
zoom: viewState.zoom - 1,
animate: false
});
return this.mbmap.getCanvas();
// cancel the scheduled update & trigger synchronous redraw
// see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
// NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX
if (mbMap._frame) {
mbMap._frame.cancel();
mbMap._frame = null;
}
mbMap._render();
updateRenderedPosition(centerOffset, zoomOffset) {
const style = this.mbmap.getCanvas().style;
style.left = Math.round(centerOffset[0]) + 'px';
style.top = Math.round(centerOffset[1]) + 'px';
style.transform = 'scale(' + zoomOffset + ')';
return canvas;
}
setVisible(visible) {
super.setVisible(visible);
const canvas = this.mbmap.getCanvas();
canvas.style.display = visible ? 'block' : 'none';
}
setOpacity(opacity) {
super.setOpacity(opacity);
const canvas = this.mbmap.getCanvas();
canvas.style.opacity = opacity;
}
setZIndex(zindex) {
super.setZIndex(zindex);
const canvas = this.mbmap.getCanvas();
canvas.style.zIndex = zindex;
}
/**
* @inheritDoc
*/
getSourceState() {
return this.loaded ? SourceState.READY : SourceState.UNDEFINED;
}
setMap(map) {
this.map_ = map;
}
}
mapboxgl.Map.prototype._setupContainer = function _setupContainer() {
const container = this._container;
container.classList.add('mapboxgl-map');
const canvasContainer = this._canvasContainer = container.firstChild;
this._canvas = document.createElement('canvas');
canvasContainer.insertBefore(this._canvas, canvasContainer.firstChild);
this._canvas.style.position = 'absolute';
this._canvas.addEventListener('webglcontextlost', this._contextLost, false);
this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false);
this._canvas.setAttribute('tabindex', '0');
this._canvas.setAttribute('aria-label', 'Map');
this._canvas.className = 'mapboxgl-canvas';
const dimensions = this._containerDimensions();
this._resizeCanvas(dimensions[0], dimensions[1]);
this._controlContainer = canvasContainer;
const controlContainer = this._controlContainer = document.createElement('div');
controlContainer.className = 'mapboxgl-control-container';
container.appendChild(controlContainer);
const positions = this._controlPositions = {};
['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function(positionName) {
const elem = document.createElement('div');
elem.className = 'mapboxgl-ctrl-' + positionName;
controlContainer.appendChild(elem);
positions[positionName] = elem;
});
};
});
const style = new Style({
stroke: new Stroke({
@@ -202,21 +81,8 @@ const vectorLayer = new VectorLayer({
const map = new Map({
target: 'map',
view: new View({
center: [-10997148, 4569099],
zoom: 4,
minZoom: 1,
extent: [-Infinity, -20048966.10, Infinity, 20048966.10],
smoothExtentConstraint: false,
smoothResolutionConstraint: false
})
center: fromLonLat(center),
zoom: 4
}),
layers: [mbLayer, vectorLayer]
});
const key = 'ER67WIiPdCQvhgsUjoWK';
const mbLayer = new Mapbox({
map: map,
container: map.getTarget(),
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key
});
map.addLayer(mbLayer);
map.addLayer(vectorLayer);

View File

@@ -9,6 +9,6 @@ resources:
- resources/mapbox-streets-v6-style.js
cloak:
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
value: Your Mapbox access token from http://mapbox.com/ here
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -9,6 +9,6 @@ resources:
- resources/mapbox-streets-v6-style.js
cloak:
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
value: Your Mapbox access token from http://mapbox.com/ here
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -3,9 +3,9 @@ import View from '../src/ol/View.js';
import ImageLayer from '../src/ol/layer/Image.js';
import ImageMapGuide from '../src/ol/source/ImageMapGuide.js';
const mdf = 'Library://Public/Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
const mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
const agentUrl =
'http://www.buoyshark.com/mapguide/mapagent/mapagent.fcgi?';
'http://138.197.230.93:8008/mapguide/mapagent/mapagent.fcgi?';
const bounds = [
-87.865114442365922,
43.665065564837931,
@@ -24,8 +24,9 @@ const map = new Map({
params: {
MAPDEFINITION: mdf,
FORMAT: 'PNG',
USERNAME: 'OpenLayers',
PASSWORD: 'OpenLayers'
VERSION: '3.0.0',
USERNAME: 'OLGuest',
PASSWORD: 'olguest'
},
ratio: 2
})

View File

@@ -11,7 +11,7 @@ docs: >
tags: "raster, pixel operation, flood"
cloak:
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
value: Your Mapbox access token from http://mapbox.com/ here
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>
<label>

View File

@@ -78,7 +78,7 @@
<header class="navbar" role="navigation">
<div class="container">
<div class="display-table pull-left" id="navbar-logo-container">
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers Examples</a>
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers</a>
</div>
<!-- menu items that get hidden below 768px width -->
<nav class='collapse navbar-collapse navbar-responsive-collapse'>
@@ -122,7 +122,7 @@
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
</div>
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;title&gt;{{ title }}&lt;/title&gt;
&lt;!-- The line below is only needed for old environments like Internet Explorer and Android 4.x --&gt;

View File

@@ -8,7 +8,7 @@ docs: >
tags: "utfgrid, tilejson"
cloak:
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
value: Your Mapbox access token from http://mapbox.com/ here
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>
<div style="display: none;">

View File

@@ -19,16 +19,25 @@ module.exports = {
context: src,
target: 'web',
entry: entry,
stats: 'minimal',
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'buble-loader'
},
test: /\.js$/,
include: [
path.join(__dirname, '..', '..', 'src'),
path.join(__dirname, '..')
]
}, {
test: /\.js$/,
use: {
loader: path.join(__dirname, './worker-loader.js')
},
include: [
path.join(__dirname, '../../src/ol/worker')
]
}]
},
optimization: {

View File

@@ -0,0 +1,24 @@
const build = require('../../tasks/serialize-workers').build;
function loader() {
const callback = this.async();
let minify = false;
// TODO: remove when https://github.com/webpack/webpack/issues/6496 is addressed
const compilation = this._compilation;
if (compilation) {
minify = compilation.compiler.options.mode === 'production';
}
build(this.resource, {minify})
.then(chunk => {
for (const filePath in chunk.modules) {
this.addDependency(filePath);
}
callback(null, chunk.code);
})
.catch(callback);
}
module.exports = loader;

View File

@@ -46,7 +46,7 @@ function updateInfo() {
function setTime() {
startDate.setMinutes(startDate.getMinutes() + 15);
if (startDate > Date.now()) {
if (startDate > new Date()) {
startDate = threeHoursAgo();
}
layers[1].getSource().updateParams({'TIME': startDate.toISOString()});

10
examples/worker.html Normal file
View File

@@ -0,0 +1,10 @@
---
layout: example.html
title: Worker
shortdesc: This example should be deleted.
docs: >
When you move the map, a message is sent to a worker. In response, the woker sends a
message back with the version identifier.
tags: "worker"
---
<div id="map" class="map"></div>

35
examples/worker.js Normal file
View File

@@ -0,0 +1,35 @@
/* eslint-disable no-console */
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';
import {create as createVersionWorker} from '../src/ol/worker/version';
const map = new Map({
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
const worker = createVersionWorker();
worker.addEventListener('error', function(error) {
console.error('worker error', error);
});
worker.addEventListener('message', function(event) {
console.log('message from worker:', event.data);
});
map.on('moveend', function(event) {
const state = event.frameState.viewState;
worker.postMessage({zoom: state.zoom, center: state.center});
});

View File

@@ -11,5 +11,6 @@ tags: "zoomify, deep zoom, IIP, pixel, projection"
<select id="zoomifyProtocol">
<option value="zoomify">Zoomify</option>
<option value="iip">IIP</option>
<option value="zoomifyretina">Zoomify Retina</option>
</select>
</div>

View File

@@ -12,6 +12,8 @@ const iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/
const layer = new TileLayer({
source: new Zoomify({
tileSize: 256,
tilePixelRatio: 1,
url: zoomifyUrl,
size: [imgWidth, imgHeight],
crossOrigin: 'anonymous'
@@ -20,12 +22,15 @@ const layer = new TileLayer({
const extent = [0, -imgHeight, imgWidth, 0];
const resolutions = layer.getSource().getTileGrid().getResolutions();
const map = new Map({
layers: [layer],
target: 'map',
view: new View({
// adjust zoom levels to those provided by the source
resolutions: layer.getSource().getTileGrid().getResolutions(),
minResolution: resolutions[resolutions.length - 1],
maxResolution: resolutions[0],
// constrain the center: center cannot be set outside this extent
extent: extent
})
@@ -36,17 +41,73 @@ const control = document.getElementById('zoomifyProtocol');
control.addEventListener('change', function(event) {
const value = event.currentTarget.value;
if (value === 'iip') {
layer.setSource(new Zoomify({
const extent = [0, -imgHeight, imgWidth, 0];
layer.setSource(
new Zoomify({
tileSize: 256,
tilePixelRatio: 1,
url: iipUrl,
size: [imgWidth, imgHeight],
crossOrigin: 'anonymous'
}));
})
);
const resolutions = layer.getSource().getTileGrid().getResolutions();
map.setView(
new View({
// adjust zoom levels to those provided by the source
minResolution: resolutions[resolutions.length - 1],
maxResolution: resolutions[0],
// constrain the center: center cannot be set outside this extent
extent: extent
})
);
map.getView().fit(extent);
} else if (value === 'zoomify') {
layer.setSource(new Zoomify({
const extent = [0, -imgHeight, imgWidth, 0];
layer.setSource(
new Zoomify({
tileSize: 256,
tilePixelRatio: 1,
url: zoomifyUrl,
size: [imgWidth, imgHeight],
crossOrigin: 'anonymous'
}));
})
);
const resolutions = layer.getSource().getTileGrid().getResolutions();
map.setView(
new View({
// adjust zoom levels to those provided by the source
minResolution: resolutions[resolutions.length - 1],
maxResolution: resolutions[0],
// constrain the center: center cannot be set outside this extent
extent: extent
})
);
map.getView().fit(extent);
} else if (value === 'zoomifyretina') {
const pixelRatio = 4;
// Be careful! Image extent will be modified by pixel ratio
const extent = [0, -imgHeight / pixelRatio, imgWidth / pixelRatio, 0];
layer.setSource(
new Zoomify({
tileSize: 256 / pixelRatio,
tilePixelRatio: pixelRatio,
url: zoomifyUrl,
size: [imgWidth / pixelRatio, imgHeight / pixelRatio],
crossOrigin: 'anonymous'
})
);
const resolutions = layer.getSource().getTileGrid().getResolutions();
map.setView(
new View({
// adjust zoom levels to those provided by the source
minResolution: resolutions[resolutions.length - 1] / pixelRatio,
maxResolution: resolutions[0],
// constrain the center: center cannot be set outside this extent
extent: extent
})
);
map.getView().fit(extent);
}
});

11
gatsby-config.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
plugins: [
'gatsby-plugin-emotion',
{
resolve: 'gatsby-plugin-typography',
options: {
pathToConfigModule: 'site/util/typography'
}
}
]
};

23
gatsby-node.js Normal file
View File

@@ -0,0 +1,23 @@
function getDocs() {
// TODO: build if not present
const info = require('./build/api-info.json');
return info.docs.filter(doc => !doc.ignore && (doc.api || doc.kind === 'module' || doc.kind === 'typedef'));
}
function createPages({actions: {createPage}}) {
createPage({
path: '/api',
component: require.resolve('./site/pages/API.js'),
context: {docs: getDocs()}
});
createPage({
path: '/info',
component: require.resolve('./site/pages/Info.js'),
context: {docs: getDocs()}
});
}
exports.createPages = createPages;

20668
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0-beta.6",
"version": "6.0.0-beta.8",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -22,9 +22,12 @@
"build-index": "npm run build-package && node tasks/generate-index",
"build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css",
"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 && tsc --project config/tsconfig-build.json",
"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": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc",
"api-info": "jsdoc --configure config/jsdoc/api-info/conf.json --destination build/api-info.json",
"serve-site": "gatsby develop",
"build-site": "npm run api-info && gatsby build"
},
"main": "index.js",
"repository": {
@@ -38,57 +41,83 @@
"dependencies": {
"pbf": "3.2.0",
"pixelworks": "1.1.0",
"rbush": "2.0.2"
"rbush": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.4",
"@emotion/core": "^10.0.10",
"@emotion/styled": "^10.0.11",
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
"@types/arcgis-rest-api": "^10.4.4",
"@types/geojson": "^7946.0.7",
"@types/pbf": "^3.0.1",
"@types/rbush": "^2.0.2",
"@types/topojson-specification": "^1.0.1",
"babel-loader": "^8.0.5",
"buble": "^0.19.7",
"buble-loader": "^0.5.1",
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^5.0.3",
"coveralls": "3.0.3",
"eslint": "^5.16.0",
"eslint-config-openlayers": "^11.0.0",
"eslint-config-tschaub": "^13.1.0",
"eslint-plugin-react": "^7.13.0",
"expect.js": "0.3.1",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.1",
"glob": "^7.1.2",
"front-matter": "^3.0.2",
"fs-extra": "^8.0.0",
"gatsby": "^2.4.3",
"gatsby-plugin-emotion": "^4.0.6",
"gatsby-plugin-typography": "^2.2.13",
"glob": "^7.1.4",
"globby": "^9.2.0",
"handlebars": "4.1.2",
"html-to-image": "^0.1.0",
"istanbul": "0.4.5",
"jquery": "3.4.0",
"jsdoc": "3.5.5",
"jsdoc-plugin-typescript": "^1.0.7",
"karma": "^4.0.1",
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "3.4.1",
"jsdoc": "3.6.2",
"jsdoc-json": "^2.0.2",
"jsdoc-plugin-typescript": "^2.0.1",
"karma": "^4.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-coverage": "^1.1.2",
"karma-coverage-istanbul-reporter": "^2.0.5",
"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.0",
"loglevelnext": "^3.0.1",
"marked": "0.6.2",
"mocha": "6.1.3",
"ol-mapbox-style": "^4.3.1",
"mocha": "6.1.4",
"ol-mapbox-style": "^5.0.0-beta.2",
"pixelmatch": "^4.0.2",
"pngjs": "^3.4.0",
"proj4": "2.5.0",
"puppeteer": "~1.14.0",
"serve-static": "^1.13.2",
"prop-types": "^15.7.2",
"puppeteer": "~1.16.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-markdown": "^4.0.8",
"react-syntax-highlighter": "^10.2.1",
"react-typography": "^0.16.19",
"rollup": "^1.12.0",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-node-resolve": "^5.0.0",
"rollup-plugin-terser": "^4.0.4",
"serve-static": "^1.14.0",
"shx": "^0.3.2",
"sinon": "^7.3.1",
"sinon": "^7.3.2",
"terser-webpack-plugin": "^1.2.3",
"typescript": "^3.2.2",
"typescript": "^3.4.5",
"typography": "^0.16.19",
"typography-theme-alton": "^0.16.19",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.30.0",
"webpack-cli": "^3.3.0",
"webpack": "4.31.0",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"yargs": "^13.2.2"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -7,6 +7,7 @@ import Point from '../../../src/ol/geom/Point.js';
import Style from '../../../src/ol/style/Style.js';
import Text from '../../../src/ol/style/Text.js';
import CircleStyle from '../../../src/ol/style/Circle.js';
import Fill from '../../../src/ol/style/Fill.js';
import Stroke from '../../../src/ol/style/Stroke.js';
import LineString from '../../../src/ol/geom/LineString.js';
@@ -59,9 +60,10 @@ source1.addFeature(new Feature({
}));
layer1.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
image: new CircleStyle({
radius: 15,
stroke: new Stroke({
fill: new Fill({
color: 'blue'
})
})
@@ -69,7 +71,7 @@ layer1.setStyle(function(feature) {
});
map.addLayer(layer1);
center = [center[0] + 500, center[1] + 500];
center = [center[0] + 500, center[1] + 700];
const feature2 = new Feature({
geometry: new Point(center),
text: 'center',
@@ -88,15 +90,16 @@ source2.addFeature(new Feature({
}));
layer2.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
text: new Text({
text: feature.get('text'),
font: '16px Ubuntu'
font: 'italic bold 18px Ubuntu'
})
});
});
map.addLayer(layer2);
center = [center[0] + 500, center[1] + 500];
center = [center[0] + 500, center[1] + 300];
source3.addFeature(new Feature({
geometry: new Point(center),
text: 'center'
@@ -112,16 +115,17 @@ source3.addFeature(new Feature({
layer3.setStyle(function(feature) {
return new Style({
image: new CircleStyle({
radius: 5,
radius: 10,
stroke: new Stroke({
color: 'red'
color: 'red',
width: 8
})
}),
text: new Text({
text: feature.get('text'),
font: '16px Ubuntu',
font: 'italic bold 18px Ubuntu',
textBaseline: 'bottom',
offsetY: -5
offsetY: -12
})
});
});
@@ -130,11 +134,12 @@ map.addLayer(layer3);
center = [center[0] - 2000, center[1] - 2000];
const point = new Feature(new Point(center));
point.setStyle(new Style({
zIndex: 2,
zIndex: 1,
image: new CircleStyle({
radius: 8,
stroke: new Stroke({
color: 'blue'
color: 'blue',
width: 4
})
})
}));
@@ -143,7 +148,7 @@ const line = new Feature(new LineString([
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new Style({
zIndex: 1,
zIndex: 2,
stroke: new Stroke({
color: '#CCC',
width: 12
@@ -151,7 +156,7 @@ line.setStyle(new Style({
text: new Text({
placement: 'line',
text: 'east-west',
font: '16px Ubuntu',
font: 'italic bold 18px Ubuntu',
overflow: true
})
}));
@@ -159,4 +164,4 @@ source4.addFeature(point);
source4.addFeature(line);
map.addLayer(layer4);
render({tolerance: 0.02});
render({tolerance: 0.007});

View File

@@ -42,7 +42,8 @@ const layer = new VectorLayer({
const view = new View({
center: [-9.5, 78],
zoom: 2,
projection: 'EPSG:4326'
projection: 'EPSG:4326',
multiWorld: true
});
new Map({
pixelRatio: 1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,72 +1,19 @@
import Feature from '../../../src/ol/Feature.js';
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import VectorSource from '../../../src/ol/source/Vector.js';
import Style from '../../../src/ol/style/Style.js';
import Stroke from '../../../src/ol/style/Stroke.js';
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
import CircleStyle from '../../../src/ol/style/Circle.js';
import Feature from '../../../src/ol/Feature.js';
import Point from '../../../src/ol/geom/Point.js';
import LineString from '../../../src/ol/geom/LineString.js';
import Style from '../../../src/ol/style/Style.js';
import Text from '../../../src/ol/style/Text.js';
import CircleStyle from '../../../src/ol/style/Circle.js';
import Fill from '../../../src/ol/style/Fill.js';
import Stroke from '../../../src/ol/style/Stroke.js';
import LineString from '../../../src/ol/geom/LineString.js';
const center = [1825927.7316762917, 6143091.089223046];
const source = new VectorSource();
const vectorLayer1 = new VectorImageLayer({
source: source,
style: function(feature) {
return new Style({
image: new CircleStyle({
radius: 15,
stroke: new Stroke({
color: 'blue'
})
}),
text: new Text({
text: feature.get('text'),
font: '16px Ubuntu'
})
});
}
});
const centerFeature = new Feature({
geometry: new Point(center),
text: 'center'
});
source.addFeature(centerFeature);
source.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west'
}));
source.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east'
}));
const line = new Feature(new LineString([
[center[0] - 650, center[1] - 200],
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new Style({
stroke: new Stroke({
color: '#CCC',
width: 12
}),
text: new Text({
placement: 'line',
text: 'east-west',
font: '16px Ubuntu'
})
}));
source.addFeature(line);
let center = [1825927.7316762917, 6143091.089223046];
const map = new Map({
pixelRatio: 1,
layers: [
vectorLayer1
],
target: 'map',
view: new View({
center: center,
@@ -74,6 +21,147 @@ const map = new Map({
})
});
map.getView().fit(source.getExtent());
const source1 = new VectorSource();
const layer1 = new VectorImageLayer({
declutter: true,
source: source1
});
render({tolerance: 0.02});
const source2 = new VectorSource();
const layer2 = new VectorImageLayer({
declutter: true,
source: source2
});
const source3 = new VectorSource();
const layer3 = new VectorImageLayer({
declutter: true,
source: source3
});
const source4 = new VectorSource();
const layer4 = new VectorImageLayer({
declutter: true,
source: source4
});
const feature1 = new Feature({
geometry: new Point(center),
zIndex: 2
});
source1.addFeature(feature1);
source1.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
zIndex: 3
}));
source1.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
zIndex: 1
}));
layer1.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
image: new CircleStyle({
radius: 15,
fill: new Fill({
color: 'blue'
})
})
});
});
map.addLayer(layer1);
center = [center[0] + 500, center[1] + 700];
const feature2 = new Feature({
geometry: new Point(center),
text: 'center',
zIndex: 2
});
source2.addFeature(feature2);
source2.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west',
zIndex: 3
}));
source2.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east',
zIndex: 1
}));
layer2.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu'
})
});
});
map.addLayer(layer2);
center = [center[0] + 500, center[1] + 300];
source3.addFeature(new Feature({
geometry: new Point(center),
text: 'center'
}));
source3.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west'
}));
source3.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east'
}));
layer3.setStyle(function(feature) {
return new Style({
image: new CircleStyle({
radius: 10,
stroke: new Stroke({
color: 'red',
width: 8
})
}),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu',
textBaseline: 'bottom',
offsetY: -12
})
});
});
map.addLayer(layer3);
center = [center[0] - 2000, center[1] - 2000];
const point = new Feature(new Point(center));
point.setStyle(new Style({
zIndex: 1,
image: new CircleStyle({
radius: 8,
stroke: new Stroke({
color: 'blue',
width: 4
})
})
}));
const line = new Feature(new LineString([
[center[0] - 650, center[1] - 200],
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new Style({
zIndex: 2,
stroke: new Stroke({
color: '#CCC',
width: 12
}),
text: new Text({
placement: 'line',
text: 'east-west',
font: 'italic bold 18px Ubuntu',
overflow: true
})
}));
source4.addFeature(point);
source4.addFeature(line);
map.addLayer(layer4);
render({tolerance: 0.007});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -4,8 +4,10 @@ import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
import {Style, Stroke} from '../../../src/ol/style.js';
import Feature from '../../../src/ol/Feature.js';
import Point from '../../../src/ol/geom/Point.js';
new Map({
const map = new Map({
layers: [
new TileLayer({
source: new XYZ({
@@ -14,6 +16,7 @@ new Map({
})
}),
new VectorLayer({
zIndex: 1,
style: new Style({
stroke: new Stroke({
color: 'rgba(255,255,255,0.5)',
@@ -33,4 +36,11 @@ new Map({
})
});
const unmanaged = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([0, 0]))]
})
});
unmanaged.setMap(map);
render();

3
site/.eslintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "tschaub/react"
}

35
site/components/Class.jsx Normal file
View File

@@ -0,0 +1,35 @@
import {object} from 'prop-types';
import React from 'react';
import Markdown from 'react-markdown';
import Code from './Code';
import Parameter from './Parameter';
function Class({cls, module, helper}) {
const exportedName = module.getExportedName(cls.name);
let importCode;
if (exportedName === 'default') {
importCode = `import ${cls.name} from '${module.id}';`;
} else {
importCode = `import {${exportedName}} from '${module.id}';`;
}
return (
<div>
<h3>{cls.name}</h3>
<Code value={importCode} />
<Markdown source={cls.doc.classdesc} renderers={{code: Code}} />
<h6>Parameters</h6>
<ul>
{cls.doc.params && cls.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
</ul>
</div>
);
}
Class.propTypes = {
cls: object.isRequired,
module: object.isRequired,
helper: object.isRequired
};
export default Class;

26
site/components/Code.jsx Normal file
View File

@@ -0,0 +1,26 @@
import React, {PureComponent} from 'react';
import {string} from 'prop-types';
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter';
import {coy} from 'react-syntax-highlighter/dist/styles/prism';
class Code extends PureComponent {
render() {
let language = this.props.language;
if (!language) {
language = 'js';
}
return (
<SyntaxHighlighter language={language} style={coy}>
{this.props.value}
</SyntaxHighlighter>
);
}
}
Code.propTypes = {
value: string.isRequired,
language: string
};
export default Code;

35
site/components/Func.jsx Normal file
View File

@@ -0,0 +1,35 @@
import {object} from 'prop-types';
import React from 'react';
import Markdown from 'react-markdown';
import Code from './Code';
import Parameter from './Parameter';
function Func({func, module, helper}) {
const exportedName = module.getExportedName(func.name);
let importCode;
if (exportedName === 'default') {
importCode = `import ${func.name} from '${module.id}';`;
} else {
importCode = `import {${exportedName}} from '${module.id}';`;
}
return (
<div>
<h3>{func.name}</h3>
<Code value={importCode} />
<Markdown source={func.doc.description} renderers={{code: Code}} />
<h6>Parameters</h6>
<ul>
{func.doc.params && func.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
</ul>
</div>
);
}
Func.propTypes = {
func: object.isRequired,
module: object.isRequired,
helper: object.isRequired
};
export default Func;

View File

@@ -0,0 +1,26 @@
import {object} from 'prop-types';
import React from 'react';
import Class from './Class';
import Func from './Func';
function Module({module, helper}) {
return (
<div>
<hr />
<h2>{module.id}</h2>
{module.classes.map(cls => (
<Class key={cls.name} cls={cls} module={module} helper={helper} />
))}
{module.functions.map(func => (
<Func key={func.name} func={func} module={module} helper={helper} />
))}
</div>
);
}
Module.propTypes = {
module: object.isRequired,
helper: object.isRequired
};
export default Module;

View File

@@ -0,0 +1,20 @@
import {object} from 'prop-types';
import React from 'react';
import Type from './Type';
function Parameter({param, module, helper}) {
return (
<li>
<code>{param.name}</code> - {param.description} {param.optional && <span>(optional)</span>}<br/>
{param.type.names.map(longName => <Type longName={longName} module={module} helper={helper} />)}
</li>
);
}
Parameter.propTypes = {
param: object.isRequired,
module: object.isRequired,
helper: object.isRequired
};
export default Parameter;

27
site/components/Type.jsx Normal file
View File

@@ -0,0 +1,27 @@
import {object} from 'prop-types';
import React from 'react';
import Parameter from './Parameter';
function Type({longName, module, helper}) {
const type = helper.getTypeDef(longName);
if (!type) {
return <code>{longName}</code>;
}
return (
<div>
<code>{type.doc.type.names}</code>
<ul>
{type.doc.properties && type.doc.properties.map(prop => <Parameter param={prop} module={module} helper={helper} />)}
</ul>
</div>
);
}
Type.propTypes = {
longName: object.isRequired,
module: object.isRequired,
helper: object.isRequired
};
export default Type;

View File

@@ -0,0 +1,8 @@
import styled from '@emotion/styled';
import {baseSpacingPx} from '../util/typography';
export const Page = styled.div({
display: 'flex',
flexDirection: 'column',
margin: 2 * baseSpacingPx
});

26
site/pages/API.js Normal file
View File

@@ -0,0 +1,26 @@
import {object} from 'prop-types';
import React from 'react';
import {Page} from '../components/layout';
import Module from '../components/Module';
import {getHelper} from '../util/api';
function API({pageContext: {docs}}) {
const helper = getHelper(docs);
return (
<Page>
<h1>API</h1>
{helper.modules
.filter(module => module.visible)
.map(module => (
<Module key={module.id} module={module} helper={helper} />
))}
</Page>
);
}
API.propTypes = {
pageContext: object.isRequired
};
export default API;

33
site/pages/Info.js Normal file
View File

@@ -0,0 +1,33 @@
import {object} from 'prop-types';
import React from 'react';
import {Page} from '../components/layout';
function Info({pageContext: {docs}}) {
return (
<Page>
<h1>API</h1>
<table>
<tbody>
<tr>
<th>kind</th>
<th>longname</th>
<th>memberof</th>
</tr>
{docs.map(doc => (
<tr key={doc.longname}>
<td>{doc.kind}</td>
<td>{doc.longname}</td>
<td>{doc.memberof}</td>
</tr>
))}
</tbody>
</table>
</Page>
);
}
Info.propTypes = {
pageContext: object.isRequired
};
export default Info;

205
site/util/api.js Normal file
View File

@@ -0,0 +1,205 @@
class FunctionDoc {
constructor(doc) {
this.name = doc.name;
this.doc = doc;
}
}
class TypedefDoc {
constructor(doc) {
this.name = doc.name;
this.doc = doc;
}
}
class ClassDoc {
constructor(name) {
this.name = name;
}
processDoc(doc) {
if (doc.kind === 'class') {
this.doc = doc;
}
}
}
class ModuleDoc {
constructor(id) {
this.id = id;
this.classLookup = {};
this.classes = [];
this.functionLookup = {};
this.functions = [];
}
processDoc(doc) {
if (doc.kind === 'module') {
this.doc = doc;
//console.log('processing module: ' + doc.longname)
return;
}
if (doc.kind === 'class') {
const name = nameFromLongname(doc.longname);
if (!(name in this.classLookup)) {
const cls = new ClassDoc(name);
this.classLookup[name] = cls;
this.classes.push(cls);
}
this.classLookup[name].processDoc(doc);
return;
}
if (doc.kind === 'function') {
if (nameFromLongname(doc.memberof)) {
// belongs to a class or other
return;
}
if (doc.name in this.functionLookup) {
throw new Error(`Duplicate function ${doc.name} in ${this.id}`);
}
const func = new FunctionDoc(doc);
this.functionLookup[doc.name] = func;
this.functions.push(func);
return;
}
}
finalize() {
this.classes.sort(byName);
this.functions.sort(byName);
this.visible = this.classes.length > 0 || this.functions.length > 0;
}
getExportedName(localName) {
if (!this.doc || !this.doc.exportMap) {
throw new Error(`Expected to find export map in module doc: ${this.id}`);
}
if (!(localName in this.doc.exportMap)) {
throw new Error(
`No local name "${localName}" in export map for module: ${this.id}`
);
}
return this.doc.exportMap[localName];
}
}
const longnameRE = /^module:(?<module>.*?)([~\.](?<name>\w+)(#(?<member>\w+))?(:(?<type>\w+))?)?$/;
function moduleIDFromLongname(longname) {
const match = longname.match(longnameRE);
if (!match) {
throw new Error(`could not match module id in longname: ${longname}`);
}
return match.groups.module;
}
export function nameFromLongname(longname) {
const match = longname.match(longnameRE);
if (!match) {
throw new Error(`could not match name in longname: ${longname}`);
}
return match.groups.name;
}
function memberFromLongname(longname) {
const match = longname.match(longnameRE);
if (!match) {
throw new Error(`could not match member in longname: ${longname}`);
}
return match.groups.member;
}
function byName(a, b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
}
function byModuleId(a, b) {
const aParts = a.id.split('/');
const bParts = b.id.split('/');
const len = Math.max(aParts.length, bParts.length);
for (let i = 0; i < len; ++i) {
if (aParts[i] && bParts[i]) {
if (aParts[i] < bParts[i]) {
return -1;
}
if (aParts[i] > bParts[i]) {
return 1;
}
} else if (!aParts[i]) {
return -1;
} else {
return 1;
}
}
return 0;
}
class DocHelper {
constructor(docs) {
this.moduleLookup = {};
this.modules = [];
this.typedefLookup = {};
docs.forEach(doc => {
// typedef are indexed by long name
if (doc.kind === 'typedef') {
if (doc.name in this.typedefLookup) {
throw new Error(`Duplicate type definition ${doc.name} in ${this.id}`);
}
const type = new TypedefDoc(doc);
this.typedefLookup[doc.longname] = type;
return;
}
const moduleID = moduleIDFromLongname(doc.longname);
if (!(moduleID in this.moduleLookup)) {
const module = new ModuleDoc(moduleID);
this.moduleLookup[moduleID] = module;
this.modules.push(module);
}
const module = this.moduleLookup[moduleID];
module.processDoc(doc);
});
this.modules.sort(byModuleId);
this.modules.forEach(module => module.finalize());
}
getTypeDef(longName) {
this.typedefLookup[longName] && console.log(this.typedefLookup[longName]);
return this.typedefLookup[longName];
}
}
let cachedDocs;
let cachedHelper;
export function getHelper(docs) {
if (docs !== cachedDocs) {
if (cachedDocs) {
console.warn('creating new doc helper'); // eslint-disable-line
}
cachedHelper = new DocHelper(docs);
cachedDocs = docs;
}
return cachedHelper;
}

9
site/util/typography.js Normal file
View File

@@ -0,0 +1,9 @@
import Typography from 'typography';
import theme from 'typography-theme-alton';
const typography = new Typography(theme);
export const baseSpacingPx = parseInt(theme.baseFontSize, 10);
export {theme};
export default typography;

View File

@@ -6,7 +6,6 @@ import {listen} from './events.js';
import Event from './events/Event.js';
import EventType from './events/EventType.js';
import {circular as circularPolygon} from './geom/Polygon.js';
import {GEOLOCATION} from './has.js';
import {toRadians} from './math.js';
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';
@@ -83,7 +82,7 @@ class GeolocationError extends Event {
* window.console.log(geolocation.getPosition());
* });
*
* @fires error
* @fires module:ol/events/Event~Event#event:error
* @api
*/
class Geolocation extends BaseObject {
@@ -160,7 +159,7 @@ class Geolocation extends BaseObject {
* @private
*/
handleTrackingChanged_() {
if (GEOLOCATION) {
if ('geolocation' in navigator) {
const tracking = this.getTracking();
if (tracking && this.watchId_ === undefined) {
this.watchId_ = navigator.geolocation.watchPosition(
@@ -204,12 +203,6 @@ class Geolocation extends BaseObject {
this.changed();
}
/**
* Triggered when the Geolocation returns an error.
* @event error
* @api
*/
/**
* @private
* @param {PositionError} error error object.

View File

@@ -58,9 +58,9 @@ class ImageWrapper extends ImageBase {
/**
* @private
* @type {Array<import("./events.js").EventsKey>}
* @type {function():void}
*/
this.imageListenerKeys_ = null;
this.unlisten_ = null;
/**
* @protected
@@ -120,13 +120,12 @@ class ImageWrapper extends ImageBase {
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
this.state = ImageState.LOADING;
this.changed();
this.imageListenerKeys_ = [
listenOnce(this.image_, EventType.ERROR,
this.handleImageError_, this),
listenOnce(this.image_, EventType.LOAD,
this.handleImageLoad_, this)
];
this.imageLoadFunction_(this, this.src_);
this.unlisten_ = listenImage(
this.image_,
this.handleImageLoad_.bind(this),
this.handleImageError_.bind(this)
);
}
}
@@ -143,9 +142,46 @@ class ImageWrapper extends ImageBase {
* @private
*/
unlistenImage_() {
this.imageListenerKeys_.forEach(unlistenByKey);
this.imageListenerKeys_ = null;
if (this.unlisten_) {
this.unlisten_();
this.unlisten_ = null;
}
}
}
/**
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image element.
* @param {function():any} loadHandler Load callback function.
* @param {function():any} errorHandler Error callback function.
* @return {function():void} Callback to stop listening.
*/
export function listenImage(image, loadHandler, errorHandler) {
const img = /** @type {HTMLImageElement} */ (image);
if (img.decode) {
const promise = img.decode();
let listening = true;
const unlisten = function() {
listening = false;
};
promise.then(function() {
if (listening) {
loadHandler();
}
}).catch(function(error) {
if (listening) {
errorHandler();
}
});
return unlisten;
}
const listenerKeys = [
listenOnce(img, EventType.LOAD, loadHandler),
listenOnce(img, EventType.ERROR, errorHandler)
];
return function unlisten() {
listenerKeys.forEach(unlistenByKey);
};
}

View File

@@ -4,8 +4,7 @@
import Tile from './Tile.js';
import TileState from './TileState.js';
import {createCanvasContext2D} from './dom.js';
import {listenOnce, unlistenByKey} from './events.js';
import EventType from './events/EventType.js';
import {listenImage} from './Image.js';
class ImageTile extends Tile {
@@ -47,9 +46,9 @@ class ImageTile extends Tile {
/**
* @private
* @type {Array<import("./events.js").EventsKey>}
* @type {function():void}
*/
this.imageListenerKeys_ = null;
this.unlisten_ = null;
/**
* @private
@@ -134,13 +133,12 @@ class ImageTile extends Tile {
if (this.state == TileState.IDLE) {
this.state = TileState.LOADING;
this.changed();
this.imageListenerKeys_ = [
listenOnce(this.image_, EventType.ERROR,
this.handleImageError_, this),
listenOnce(this.image_, EventType.LOAD,
this.handleImageLoad_, this)
];
this.tileLoadFunction_(this, this.src_);
this.unlisten_ = listenImage(
this.image_,
this.handleImageLoad_.bind(this),
this.handleImageError_.bind(this)
);
}
}
@@ -150,8 +148,10 @@ class ImageTile extends Tile {
* @private
*/
unlistenImage_() {
this.imageListenerKeys_.forEach(unlistenByKey);
this.imageListenerKeys_ = null;
if (this.unlisten_) {
this.unlisten_();
this.unlisten_ = null;
}
}
}

View File

@@ -2,7 +2,7 @@
* @module ol/Map
*/
import PluggableMap from './PluggableMap.js';
import {defaults as defaultControls} from './control/util.js';
import {defaults as defaultControls} from './control.js';
import {defaults as defaultInteractions} from './interaction.js';
import {assign} from './obj.js';
import CompositeMapRenderer from './renderer/Composite.js';

View File

@@ -39,6 +39,7 @@ import {create as createTransform, apply as applyTransform} from './transform.js
* @property {boolean} animate
* @property {import("./transform.js").Transform} coordinateToPixelTransform
* @property {null|import("./extent.js").Extent} extent
* @property {Array<*>} declutterItems
* @property {import("./coordinate.js").Coordinate} focus
* @property {number} index
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
@@ -292,6 +293,11 @@ class PluggableMap extends BaseObject {
*/
this.interactions = optionsInternal.interactions || new Collection();
/**
* @type {import("./events.js").EventsKey}
*/
this.labelCacheListenerKey_;
/**
* @type {Collection<import("./Overlay.js").default>}
* @private
@@ -497,6 +503,24 @@ class PluggableMap extends BaseObject {
overlay.setMap(this);
}
/**
* Attach a label cache for listening to font changes.
* @param {import("./events/Target.js").default} labelCache Label cache.
*/
attachLabelCache(labelCache) {
this.detachLabelCache();
this.labelCacheListenerKey_ = listen(labelCache, EventType.CLEAR, this.redrawText.bind(this));
}
/**
* Detach the label cache, i.e. no longer listen to font changes.
*/
detachLabelCache() {
if (this.labelCacheListenerKey_) {
unlistenByKey(this.labelCacheListenerKey_);
}
}
/**
*
* @inheritDoc
@@ -514,6 +538,7 @@ class PluggableMap extends BaseObject {
cancelAnimationFrame(this.animationDelayKey_);
this.animationDelayKey_ = undefined;
}
this.detachLabelCache();
this.setTarget(null);
super.disposeInternal();
}
@@ -762,6 +787,21 @@ class PluggableMap extends BaseObject {
return layers;
}
/**
* @return {boolean} Layers have sources that are still loading.
*/
getLoading() {
const layerStatesArray = this.getLayerGroup().getLayerStatesArray();
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
const layer = layerStatesArray[i].layer;
const source = /** @type {import("./layer/Layer.js").default} */ (layer).getSource();
if (source && source.loading) {
return true;
}
}
return false;
}
/**
* Get the pixel for a coordinate. This takes a coordinate in the map view
* projection and returns the corresponding pixel.
@@ -949,7 +989,7 @@ class PluggableMap extends BaseObject {
}
if (frameState && this.hasListener(RenderEventType.RENDERCOMPLETE) && !frameState.animate &&
!this.tileQueue_.getTilesLoading() && !getLoading(this.getLayers().getArray())) {
!this.tileQueue_.getTilesLoading() && !this.getLoading()) {
this.renderer_.dispatchRenderEvent(RenderEventType.RENDERCOMPLETE, frameState);
}
@@ -993,7 +1033,6 @@ class PluggableMap extends BaseObject {
}
if (!targetElement) {
this.renderer_.removeLayerRenderers();
removeNode(this.viewport_);
if (this.handleResize_ !== undefined) {
removeEventListener(EventType.RESIZE, this.handleResize_, false);
@@ -1101,6 +1140,19 @@ class PluggableMap extends BaseObject {
this.animationDelay_();
}
/**
* Redraws all text after new fonts have loaded
*/
redrawText() {
const layerStates = this.getLayerGroup().getLayerStatesArray();
for (let i = 0, ii = layerStates.length; i < ii; ++i) {
const layer = layerStates[i].layer;
if (layer.hasRenderer()) {
layer.getRenderer().handleFontsChanged();
}
}
}
/**
* Request a map rendering (at the next animation frame).
* @api
@@ -1175,6 +1227,7 @@ class PluggableMap extends BaseObject {
frameState = /** @type {FrameState} */ ({
animate: false,
coordinateToPixelTransform: this.coordinateToPixelTransform_,
declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
extent: extent,
focus: this.focus_ ? this.focus_ : viewState.center,
index: this.frameIndex_++,
@@ -1396,23 +1449,3 @@ function createOptionsInternal(options) {
}
export default PluggableMap;
/**
* @param {Array<import("./layer/Base.js").default>} layers Layers.
* @return {boolean} Layers have sources that are still loading.
*/
function getLoading(layers) {
for (let i = 0, ii = layers.length; i < ii; ++i) {
const layer = layers[i];
if (typeof /** @type {?} */ (layer).getLayers === 'function') {
return getLoading(/** @type {LayerGroup} */ (layer).getLayers().getArray());
} else {
const source = /** @type {import("./layer/Layer.js").default} */ (
layer).getSource();
if (source && source.loading) {
return true;
}
}
}
return false;
}

View File

@@ -191,6 +191,11 @@ const DEFAULT_MIN_ZOOM = 0;
* This is the object to act upon to change the center, resolution,
* and rotation of the map.
*
* A View has a `projection`. The projection determines the
* coordinate system of the center, and its units determine the units of the
* resolution (projection units per pixel). The default projection is
* Spherical Mercator (EPSG:3857).
*
* ### The view states
*
* An View is determined by three states: `center`, `resolution`,
@@ -202,11 +207,6 @@ const DEFAULT_MIN_ZOOM = 0;
* methods are available, as well as `getResolutionForZoom` and
* `getZoomForResolution` to switch from one system to the other.
*
* A View has a `projection`. The projection determines the
* coordinate system of the center, and its units determine the units of the
* resolution (projection units per pixel). The default projection is
* Spherical Mercator (EPSG:3857).
*
* ### The constraints
*
* `setCenter`, `setResolution` and `setRotation` can be used to change the
@@ -218,7 +218,7 @@ const DEFAULT_MIN_ZOOM = 0;
*
* The *resolution constraint* typically restricts min/max values and
* snaps to specific resolutions. It is determined by the following
* options: `resolutions`, `maxResolution`, `maxZoom`, and `zoomFactor`.
* options: `resolutions`, `maxResolution`, `maxZoom` and `zoomFactor`.
* If `resolutions` is set, the other three options are ignored. See
* documentation for each option for more information. By default, the view
* only has a min/max restriction and allow intermediary zoom levels when
@@ -226,7 +226,7 @@ const DEFAULT_MIN_ZOOM = 0;
*
* The *rotation constraint* snaps to specific angles. It is determined
* by the following options: `enableRotation` and `constrainRotation`.
* By default the rotation value is snapped to zero when approaching the
* By default rotation is allowed and its value is snapped to zero when approaching the
* horizontal.
*
* The *center constraint* is determined by the `extent` option. By
@@ -1409,11 +1409,19 @@ function animationCallback(callback, returnValue) {
*/
export function createCenterConstraint(options) {
if (options.extent !== undefined) {
return createExtent(options.extent, options.constrainOnlyCenter,
options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true);
} else {
return centerNone;
const smooth = options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true;
return createExtent(options.extent, options.constrainOnlyCenter, smooth);
}
const projection = createProjection(options.projection, 'EPSG:3857');
if (options.multiWorld !== true && projection.isGlobal()) {
const extent = projection.getExtent().slice();
extent[0] = -Infinity;
extent[2] = Infinity;
return createExtent(extent, false, false);
}
return centerNone;
}

View File

@@ -1,6 +1,10 @@
/**
* @module ol/control
*/
import Collection from './Collection.js';
import Attribution from './control/Attribution.js';
import Rotate from './control/Rotate.js';
import Zoom from './control/Zoom.js';
export {default as Attribution} from './control/Attribution.js';
export {default as Control} from './control/Control.js';
@@ -12,4 +16,59 @@ export {default as ScaleLine} from './control/ScaleLine.js';
export {default as Zoom} from './control/Zoom.js';
export {default as ZoomSlider} from './control/ZoomSlider.js';
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
export {defaults} from './control/util.js';
/**
* @typedef {Object} DefaultsOptions
* @property {boolean} [attribution=true] Include
* {@link module:ol/control/Attribution~Attribution}.
* @property {import("./control/Attribution.js").Options} [attributionOptions]
* Options for {@link module:ol/control/Attribution~Attribution}.
* @property {boolean} [rotate=true] Include
* {@link module:ol/control/Rotate~Rotate}.
* @property {import("./control/Rotate.js").Options} [rotateOptions] Options
* for {@link module:ol/control/Rotate~Rotate}.
* @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.
* @property {import("./control/Zoom.js").Options} [zoomOptions] Options for
* {@link module:ol/control/Zoom~Zoom}.
* @api
*/
/**
* Set of controls included in maps by default. Unless configured otherwise,
* this returns a collection containing an instance of each of the following
* controls:
* * {@link module:ol/control/Zoom~Zoom}
* * {@link module:ol/control/Rotate~Rotate}
* * {@link module:ol/control/Attribution~Attribution}
*
* @param {DefaultsOptions=} opt_options
* Defaults options.
* @return {Collection<import("./control/Control.js").default>}
* Controls.
* @api
*/
export function defaults(opt_options) {
const options = opt_options ? opt_options : {};
const controls = new Collection();
const zoomControl = options.zoom !== undefined ? options.zoom : true;
if (zoomControl) {
controls.push(new Zoom(options.zoomOptions));
}
const rotateControl = options.rotate !== undefined ? options.rotate : true;
if (rotateControl) {
controls.push(new Rotate(options.rotateOptions));
}
const attributionControl = options.attribution !== undefined ?
options.attribution : true;
if (attributionControl) {
controls.push(new Attribution(options.attributionOptions));
}
return controls;
}

View File

@@ -1,8 +1,8 @@
/**
* @module ol/control/OverviewMap
*/
import Collection from '../Collection.js';
import Map from '../Map.js';
import PluggableMap from '../PluggableMap.js';
import CompositeMapRenderer from '../renderer/Composite.js';
import MapEventType from '../MapEventType.js';
import MapProperty from '../MapProperty.js';
import {getChangeEventType} from '../Object.js';
@@ -35,6 +35,13 @@ const MAX_RATIO = 0.75;
const MIN_RATIO = 0.1;
class ControlledMap extends PluggableMap {
createRenderer() {
return new CompositeMapRenderer(this);
}
}
/**
* @typedef {Object} Options
* @property {string} [className='ol-overviewmap'] CSS class name.
@@ -143,12 +150,10 @@ class OverviewMap extends Control {
this.ovmapDiv_.className = 'ol-overviewmap-map';
/**
* @type {import("../Map.js").default}
* @type {ControlledMap}
* @private
*/
this.ovmap_ = new Map({
controls: new Collection(),
interactions: new Collection(),
this.ovmap_ = new ControlledMap({
view: options.view
});
const ovmap = this.ovmap_;

View File

@@ -1,65 +0,0 @@
/**
* @module ol/control/util
*/
import Collection from '../Collection.js';
import Attribution from './Attribution.js';
import Rotate from './Rotate.js';
import Zoom from './Zoom.js';
/**
* @typedef {Object} DefaultsOptions
* @property {boolean} [attribution=true] Include
* {@link module:ol/control/Attribution~Attribution}.
* @property {import("./Attribution.js").Options} [attributionOptions]
* Options for {@link module:ol/control/Attribution~Attribution}.
* @property {boolean} [rotate=true] Include
* {@link module:ol/control/Rotate~Rotate}.
* @property {import("./Rotate.js").Options} [rotateOptions] Options
* for {@link module:ol/control/Rotate~Rotate}.
* @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.
* @property {import("./Zoom.js").Options} [zoomOptions] Options for
* {@link module:ol/control/Zoom~Zoom}.
* @api
*/
/**
* Set of controls included in maps by default. Unless configured otherwise,
* this returns a collection containing an instance of each of the following
* controls:
* * {@link module:ol/control/Zoom~Zoom}
* * {@link module:ol/control/Rotate~Rotate}
* * {@link module:ol/control/Attribution~Attribution}
*
* @param {DefaultsOptions=} opt_options
* Defaults options.
* @return {Collection<import("./Control.js").default>}
* Controls.
* @function module:ol/control.defaults
* @api
*/
export function defaults(opt_options) {
const options = opt_options ? opt_options : {};
const controls = new Collection();
const zoomControl = options.zoom !== undefined ? options.zoom : true;
if (zoomControl) {
controls.push(new Zoom(options.zoomOptions));
}
const rotateControl = options.rotate !== undefined ? options.rotate : true;
if (rotateControl) {
controls.push(new Rotate(options.rotateOptions));
}
const attributionControl = options.attribution !== undefined ?
options.attribution : true;
if (attributionControl) {
controls.push(new Attribution(options.attributionOptions));
}
return controls;
}

View File

@@ -14,6 +14,13 @@ export default {
*/
CHANGE: 'change',
/**
* Generic error event. Triggered when an error occurs.
* @event module:ol/events/Event~Event#error
* @api
*/
ERROR: 'error',
CLEAR: 'clear',
CONTEXTMENU: 'contextmenu',
CLICK: 'click',
@@ -21,7 +28,6 @@ export default {
DRAGENTER: 'dragenter',
DRAGOVER: 'dragover',
DROP: 'drop',
ERROR: 'error',
KEYDOWN: 'keydown',
KEYPRESS: 'keypress',
LOAD: 'load',

View File

@@ -7,6 +7,7 @@ export {default as GeoJSON} from './format/GeoJSON.js';
export {default as GML} from './format/GML.js';
export {default as GPX} from './format/GPX.js';
export {default as IGC} from './format/IGC.js';
export {default as IIIFInfo} from './format/IIIFInfo.js';
export {default as KML} from './format/KML.js';
export {default as MVT} from './format/MVT.js';
export {default as OWS} from './format/OWS.js';

431
src/ol/format/IIIFInfo.js Normal file
View File

@@ -0,0 +1,431 @@
/**
* @module ol/format/IIIFInfo
*/
import {assert} from '../asserts.js';
/**
* @typedef {Object} PreferredOptions
* @property {string} [format] Preferred image format. Will be used if the image information
* indicates support for that format.
* @property {string} [quality] IIIF image qualitiy. Will be used if the image information
* indicates support for that quality.
*/
/**
* @typedef {Object} SupportedFeatures
* @property {Array<string>} [supports] Supported IIIF image size and region
* calculation features.
* @property {Array<string>} [formats] Supported image formats.
* @property {Array<string>} [qualities] Supported IIIF image qualities.
*/
/**
* @typedef {Object} ImageInformationResponse1_0
* @property {string} identifier
* @property {number} width
* @property {number} height
* @property {Array<number>} [scale_factors] Resolution scaling factors.
* @property {number} [tile_width]
* @property {number} [tile_height]
* @property {Array<string>} [formats] Supported image formats.
* @property {string} [profile] Compliance level URI.
*/
/**
* @typedef {Object} ImageInformationResponse1_1
* @property {string} "@id" The base URI of the image service.
* @property {string} "@context" JSON-LD context URI.
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {Array<number>} [scale_factors] Resolution scaling factors.
* @property {number} [tile_width]
* @property {number} [tile_height]
* @property {Array<string>} [formats] Supported image formats.
* @property {string} [profile] Compliance level URI.
*/
/**
* @typedef {Object} TileInfo
* @property {Array<number>} scaleFactors Supported resolution scaling factors.
* @property {number} width Tile width in pixels.
* @property {number} [height] Tile height in pixels. Same as tile width if height is
* not given.
*/
/**
* @typedef {Object} IiifProfile
* @property {Array<string>} [formats] Supported image formats for the image service.
* @property {Array<string>} [qualities] Supported IIIF image qualities.
* @property {Array<string>} [supports] Supported features.
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
* @property {number} [maxHeight] Maximum height.
* @property {number} [maxWidth] Maximum width.
*/
/**
* @typedef {Object} ImageInformationResponse2
* @property {string} "@id" The base URI of the image service.
* @property {string} "@context" JSON-LD context IRI
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {Array<string|IiifProfile>} profile Additional informations about the image
* service's capabilities.
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
*/
/**
* @typedef {Object} ImageInformationResponse3
* @property {string} id The base URI of the image service.
* @property {string} "@context" JSON-LD context IRI
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {string} profile Compliance level, one of 'level0', 'level1' or 'level2'
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
* @property {number} [maxHeight] Maximum height.
* @property {number} [maxWidth] Maximum width.
* @property {Array<string>} [extraQualities] IIIF image qualities supported by the
* image service additional to the ones indicated by the compliance level.
* @property {Array<string>} [extraFormats] Image formats supported by the
* image service additional to the ones indicated by the compliance level.
* @property {Array<string>} [extraFeatures] Additional supported features whose support
* is not indicated by the compliance level.
*/
/**
* Enum representing the major IIIF Image API versions
* @enum {string}
*/
const Versions = {
VERSION1: 'version1',
VERSION2: 'version2',
VERSION3: 'version3'
};
/**
* Supported image formats, qualities and supported region / size calculation features
* for different image API versions and compliance levels
* @const
* @type {Object<string, Object<string, SupportedFeatures>>}
*/
const IIIF_PROFILE_VALUES = {};
IIIF_PROFILE_VALUES[Versions.VERSION1] = {
'level0': {
supports: [],
formats: [],
qualities: ['native']
},
'level1': {
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
formats: ['jpg'],
qualities: ['native']
},
'level2': {
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
'sizeByConfinedWh', 'sizeByWh'],
formats: ['jpg', 'png'],
qualities: ['native', 'color', 'grey', 'bitonal']
}
};
IIIF_PROFILE_VALUES[Versions.VERSION2] = {
'level0': {
supports: [],
formats: ['jpg'],
qualities: ['default']
},
'level1': {
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
formats: ['jpg'],
qualities: ['default']
},
'level2': {
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
'sizeByConfinedWh', 'sizeByDistortedWh', 'sizeByWh'],
formats: ['jpg', 'png'],
qualities: ['default', 'bitonal']
}
};
IIIF_PROFILE_VALUES[Versions.VERSION3] = {
'level0': {
supports: [],
formats: ['jpg'],
qualities: ['default']
},
'level1': {
supports: ['regionByPx', 'regionSquare', 'sizeByW', 'sizeByH'],
formats: ['jpg'],
qualities: ['default']
},
'level2': {
supports: ['regionByPx', 'regionSquare', 'regionByPct',
'sizeByW', 'sizeByH', 'sizeByPct', 'sizeByConfinedWh', 'sizeByWh'],
formats: ['jpg'],
qualities: ['default', 'bitonal']
}
};
IIIF_PROFILE_VALUES['none'] = {
'none': {
supports: [],
formats: [],
qualities: []
}
};
const COMPLIANCE_VERSION1 = new RegExp('^https?\:\/\/library\.stanford\.edu\/iiif\/image-api\/(1\.1\/)?compliance\.html#level[0-2]$');
const COMPLIANCE_VERSION2 = new RegExp('^https?\:\/\/iiif\.io\/api\/image\/2\/level[0-2](\.json)?$');
const COMPLIANCE_VERSION3 = new RegExp('(^https?\:\/\/iiif\.io\/api\/image\/3\/level[0-2](\.json)?$)|(^level[0-2]$)');
function generateVersion1Options(iiifInfo) {
let levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
// Version 1.0 and 1.1 do not require a profile.
if (levelProfile === undefined) {
levelProfile = IIIF_PROFILE_VALUES[Versions.VERSION1]['level0'];
}
return {
url: iiifInfo.imageInfo['@id'] === undefined ? undefined : iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
supports: levelProfile.supports,
formats: [...levelProfile.formats, iiifInfo.imageInfo.formats === undefined ?
[] : iiifInfo.imageInfo.formats
],
qualities: [...levelProfile.qualities, iiifInfo.imageInfo.qualities === undefined ?
[] : iiifInfo.imageInfo.qualities
],
resolutions: iiifInfo.imageInfo.scale_factors,
tileSize: iiifInfo.imageInfo.tile_width !== undefined ? (iiifInfo.imageInfo.tile_height !== undefined ?
[iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_height] : [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_width]) :
(iiifInfo.imageInfo.tile_height != undefined ? [iiifInfo.imageInfo.tile_height, iiifInfo.imageInfo.tile_height] : undefined)
};
}
function generateVersion2Options(iiifInfo) {
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
additionalProfile = Array.isArray(iiifInfo.imageInfo.profile) && iiifInfo.imageInfo.profile.length > 1,
profileSupports = additionalProfile && iiifInfo.imageInfo.profile[1].supports ? iiifInfo.imageInfo.profile[1].supports : [],
profileFormats = additionalProfile && iiifInfo.imageInfo.profile[1].formats ? iiifInfo.imageInfo.profile[1].formats : [],
profileQualities = additionalProfile && iiifInfo.imageInfo.profile[1].qualities ? iiifInfo.imageInfo.profile[1].qualities : [];
return {
url: iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
return [size.width, size.height];
}),
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.width;
})[0],
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.height === undefined ? tile.width : tile.height;
})[0]
],
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.scaleFactors;
})[0],
supports: [...levelProfile.supports, ...profileSupports],
formats: [...levelProfile.formats, ...profileFormats],
qualities: [...levelProfile.qualities, ...profileQualities]
};
}
function generateVersion3Options(iiifInfo) {
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
return {
url: iiifInfo.imageInfo['id'],
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
return [size.width, size.height];
}),
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.width;
})[0],
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.height;
})[0]
],
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.scaleFactors;
})[0],
supports: iiifInfo.imageInfo.extraFeatures === undefined ? levelProfile.supports :
[...levelProfile.supports, ...iiifInfo.imageInfo.extraFeatures],
formats: iiifInfo.imageInfo.extraFormats === undefined ? levelProfile.formats :
[...levelProfile.formats, ...iiifInfo.imageInfo.extraFormats],
qualities: iiifInfo.imageInfo.extraQualities === undefined ? levelProfile.qualities :
[...levelProfile.supports, ...iiifInfo.imageInfo.extraQualities],
maxWidth: undefined,
maxHeight: undefined,
maxArea: undefined
};
}
const versionFunctions = {};
versionFunctions[Versions.VERSION1] = generateVersion1Options;
versionFunctions[Versions.VERSION2] = generateVersion2Options;
versionFunctions[Versions.VERSION3] = generateVersion3Options;
/**
* @classdesc
* Format for transforming IIIF Image API image information responses into
* IIIF tile source ready options
*
* @api
*/
class IIIFInfo {
/**
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
* Deserialized image information JSON response object or JSON response as string
*/
constructor(imageInfo) {
this.setImageInfo(imageInfo);
}
/**
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
* Deserialized image information JSON response object or JSON response as string
* @api
*/
setImageInfo(imageInfo) {
if (typeof imageInfo == 'string') {
this.imageInfo = JSON.parse(imageInfo);
} else {
this.imageInfo = imageInfo;
}
}
/**
* @returns {Versions} Major IIIF version.
* @api
*/
getImageApiVersion() {
if (this.imageInfo === undefined) {
return;
}
let context = this.imageInfo['@context'] || 'ol-no-context';
if (typeof context == 'string') {
context = [context];
}
for (let i = 0; i < context.length; i++) {
switch (context[i]) {
case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
case 'http://iiif.io/api/image/1/context.json':
return Versions.VERSION1;
case 'http://iiif.io/api/image/2/context.json':
return Versions.VERSION2;
case 'http://iiif.io/api/image/3/context.json':
return Versions.VERSION3;
case 'ol-no-context':
// Image API 1.0 has no '@context'
if (this.getComplianceLevelEntryFromProfile(Versions.VERSION1) && this.imageInfo.identifier) {
return Versions.VERSION1;
}
break;
default:
}
}
assert(false, 61);
}
/**
* @param {Versions} version Optional IIIF image API version
* @returns {string} Compliance level as it appears in the IIIF image information
* response.
*/
getComplianceLevelEntryFromProfile(version) {
if (this.imageInfo === undefined || this.imageInfo.profile === undefined) {
return;
}
if (version === undefined) {
version = this.getImageApiVersion();
}
switch (version) {
case Versions.VERSION1:
if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
break;
case Versions.VERSION3:
if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
break;
case Versions.VERSION2:
if (typeof this.imageInfo.profile === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
if (Array.isArray(this.imageInfo.profile) && this.imageInfo.profile.length > 0
&& typeof this.imageInfo.profile[0] === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])) {
return this.imageInfo.profile[0];
}
break;
default:
}
}
/**
* @param {Versions} version Optional IIIF image API version
* @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined
*/
getComplianceLevelFromProfile(version) {
const complianceLevel = this.getComplianceLevelEntryFromProfile(version);
if (complianceLevel === undefined) {
return undefined;
}
const level = complianceLevel.match(/level[0-2](\.json)?$/g);
return Array.isArray(level) ? level[0].replace('.json', '') : undefined;
}
/**
* @returns {SupportedFeatures} Image formats, qualities and region / size calculation
* methods that are supported by the IIIF service.
*/
getComplianceLevelSupportedFeatures() {
if (this.imageInfo === undefined) {
return;
}
const version = this.getImageApiVersion();
const level = this.getComplianceLevelFromProfile(version);
if (level === undefined) {
return IIIF_PROFILE_VALUES['none']['none'];
}
return IIIF_PROFILE_VALUES[version][level];
}
/**
* @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality.
* @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
* @api
*/
getTileSourceOptions(opt_preferredOptions) {
const options = opt_preferredOptions || {},
version = this.getImageApiVersion();
if (version === undefined) {
return;
}
const imageOptions = version === undefined ? undefined : versionFunctions[version](this);
if (imageOptions === undefined) {
return;
}
return {
url: imageOptions.url,
version: version,
size: [this.imageInfo.width, this.imageInfo.height],
sizes: imageOptions.sizes,
format: imageOptions.formats.includes(options.format) ? options.format : 'jpg',
supports: imageOptions.supports,
quality: options.quality && imageOptions.qualities.includes(options.quality) ?
options.quality : imageOptions.qualities.includes('native') ? 'native' : 'default',
resolutions: Array.isArray(imageOptions.resolutions) ? imageOptions.resolutions.sort(function(a, b) {
return b - a;
}) : undefined,
tileSize: imageOptions.tileSize
};
}
}
export default IIIFInfo;
export {Versions};

View File

@@ -2684,13 +2684,6 @@ function writePlacemark(node, feature, objectStack) {
return !filter[v];
});
if (keys.length > 0) {
const sequence = makeSequence(properties, keys);
const namesAndValues = {names: keys, values: sequence};
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
}
const styleFunction = feature.getStyleFunction();
if (styleFunction) {
// FIXME the styles returned by the style function are supposed to be
@@ -2713,6 +2706,13 @@ function writePlacemark(node, feature, objectStack) {
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
if (keys.length > 0) {
const sequence = makeSequence(properties, keys);
const namesAndValues = {names: keys, values: sequence};
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
}
// serialize geometry
const options = /** @type {import("./Feature.js").WriteOptions} */ (objectStack[0]);
let geometry = feature.getGeometry();

View File

@@ -16,8 +16,8 @@ import {lerp} from '../../math.js';
* @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width.
* @param {string} font The font.
* @param {Object<string, number>} cache A cache of measured widths.
* @return {Array<Array<*>>} The result array of null if `maxAngle` was
* exceeded. Entries of the array are x, y, anchorX, angle, chunk.
* @return {Array<Array<*>>} The result array (or null if `maxAngle` was
* exceeded). Entries of the array are x, y, anchorX, angle, chunk.
*/
export function drawTextOnPath(
flatCoordinates, offset, end, stride, text, startM, maxAngle, scale, measureAndCacheTextWidth, font, cache) {
@@ -35,16 +35,13 @@ export function drawTextOnPath(
let y2 = flatCoordinates[offset + 1];
let segmentM = 0;
let segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
let angleChanged = false;
let chunk = '';
let chunkLength = 0;
let data, index, previousAngle;
let index, previousAngle;
for (let i = 0; i < numChars; ++i) {
index = reverse ? numChars - i - 1 : i;
const char = text.charAt(index);
chunk = reverse ? char + chunk : chunk + char;
const charLength = scale * measureAndCacheTextWidth(font, chunk, cache) - chunkLength;
chunkLength += charLength;
const char = text[index];
const charLength = scale * measureAndCacheTextWidth(font, char, cache);
const charM = startM + charLength / 2;
while (offset < end - stride && segmentM + segmentLength < charM) {
x1 = x2;
@@ -62,33 +59,18 @@ export function drawTextOnPath(
}
if (previousAngle !== undefined) {
let delta = angle - previousAngle;
angleChanged = angleChanged || delta !== 0;
delta += (delta > Math.PI) ? -2 * Math.PI : (delta < -Math.PI) ? 2 * Math.PI : 0;
if (Math.abs(delta) > maxAngle) {
return null;
}
}
previousAngle = angle;
const interpolate = segmentPos / segmentLength;
const x = lerp(x1, x2, interpolate);
const y = lerp(y1, y2, interpolate);
if (previousAngle == angle) {
if (reverse) {
data[0] = x;
data[1] = y;
data[2] = charLength / 2;
}
data[4] = chunk;
} else {
chunk = char;
chunkLength = charLength;
data = [x, y, charLength / 2, angle, chunk];
if (reverse) {
result.unshift(data);
} else {
result.push(data);
}
previousAngle = angle;
}
result[index] = [x, y, charLength / 2, angle, char];
startM += charLength;
}
return result;
return angleChanged ? result : [[result[0][0], result[0][1], result[0][2], result[0][3], text]];
}

View File

@@ -40,15 +40,6 @@ export const MAC = ua.indexOf('macintosh') !== -1;
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
/**
* Is HTML5 geolocation supported in the current browser?
* @const
* @type {boolean}
* @api
*/
export const GEOLOCATION = 'geolocation' in navigator;
/**
* True if browser supports touch events.
* @const

View File

@@ -73,6 +73,10 @@ class DragPan extends PointerInteraction {
* @inheritDoc
*/
handleDragEvent(mapBrowserEvent) {
if (!this.panning_) {
this.panning_ = true;
this.getMap().getView().beginInteraction();
}
const targetPointers = this.targetPointers;
const centroid = centroidFromPointers(targetPointers);
if (targetPointers.length == this.lastPointersCount_) {
@@ -149,10 +153,6 @@ class DragPan extends PointerInteraction {
if (view.getAnimating()) {
view.cancelAnimations();
}
if (!this.panning_) {
this.panning_ = true;
this.getMap().getView().beginInteraction();
}
if (this.kinetic_) {
this.kinetic_.begin();
}

View File

@@ -38,7 +38,7 @@ import {createEditingStyle} from '../style/Style.js';
const ExtentEventType = {
/**
* Triggered after the extent is changed
* @event ExtentEventType#extentchanged
* @event ExtentEvent#extentchanged
* @api
*/
EXTENTCHANGED: 'extentchanged'
@@ -47,10 +47,10 @@ const ExtentEventType = {
/**
* @classdesc
* Events emitted by {@link module:ol/interaction/Extent~ExtentInteraction} instances are
* Events emitted by {@link module:ol/interaction/Extent~Extent} instances are
* instances of this type.
*/
class ExtentInteractionEvent extends Event {
class ExtentEvent extends Event {
/**
* @param {import("../extent.js").Extent} extent the new extent
@@ -75,10 +75,10 @@ class ExtentInteractionEvent extends Event {
* Once drawn, the vector box can be modified by dragging its vertices or edges.
* This interaction is only supported for mouse devices.
*
* @fires Event
* @fires ExtentEvent
* @api
*/
class ExtentInteraction extends PointerInteraction {
class Extent extends PointerInteraction {
/**
* @param {Options=} opt_options Options.
*/
@@ -399,7 +399,7 @@ class ExtentInteraction extends PointerInteraction {
//Null extent means no bbox
this.extent_ = extent ? extent : null;
this.createOrUpdateExtentFeature_(extent);
this.dispatchEvent(new ExtentInteractionEvent(this.extent_));
this.dispatchEvent(new ExtentEvent(this.extent_));
}
}
@@ -470,4 +470,4 @@ function getSegments(extent) {
}
export default ExtentInteraction;
export default Extent;

View File

@@ -83,19 +83,20 @@ class BaseLayer extends BaseObject {
}
/**
* @param {boolean=} opt_managed Layer is managed.
* @return {import("./Layer.js").State} Layer state.
*/
getLayerState() {
getLayerState(opt_managed) {
/** @type {import("./Layer.js").State} */
const state = this.state_ || /** @type {?} */ ({
layer: this,
managed: true
managed: opt_managed === undefined ? true : opt_managed
});
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
state.sourceState = this.getSourceState();
state.visible = this.getVisible();
state.extent = this.getExtent();
state.zIndex = this.getZIndex() || 0;
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
state.maxResolution = this.getMaxResolution();
state.minResolution = Math.max(this.getMinResolution(), 0);
this.state_ = state;

View File

@@ -8,6 +8,7 @@ import {assign} from '../obj.js';
/**
* @typedef {Object} Options
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
* @property {number} [opacity=1] Opacity (0, 1).
* @property {boolean} [visible=true] Visibility.
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be

View File

@@ -32,8 +32,10 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
* higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will

View File

@@ -10,6 +10,10 @@ import {assign} from '../obj.js';
import RenderEventType from '../render/EventType.js';
import SourceState from '../source/State.js';
/**
* @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
*/
/**
* @typedef {Object} Options
@@ -29,6 +33,8 @@ import SourceState from '../source/State.js';
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
* construction.
* @property {import("../PluggableMap.js").default} [map] Map.
* @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an
* HTML element. Will overwrite the default rendering for the layer.
*/
@@ -47,8 +53,10 @@ import SourceState from '../source/State.js';
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class from which all layer types are derived. This should only be instantiated
* in the case where a custom layer is be added to the map with a custom `render` function.
* Such a function can be specified in the `options` object, and is expected to return an HTML element.
*
* A visual representation of raster or vector map data.
* Layers group together those properties that pertain to how the data is to be
* displayed, irrespective of the source of that data.
@@ -64,6 +72,7 @@ import SourceState from '../source/State.js';
* @fires import("../render/Event.js").RenderEvent#postrender
*
* @template {import("../source/Source.js").default} SourceType
* @api
*/
class Layer extends BaseLayer {
/**
@@ -100,6 +109,11 @@ class Layer extends BaseLayer {
*/
this.renderer_ = null;
// Overwrite default render method with a custom one
if (options.render) {
this.render = options.render;
}
if (options.map) {
this.setMap(options.map);
}
@@ -212,12 +226,7 @@ class Layer extends BaseLayer {
if (map) {
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
const layerState = this.getLayerState();
layerState.managed = false;
if (this.getZIndex() === undefined) {
layerState.zIndex = Infinity;
}
renderEvent.frameState.layerStatesArray.push(layerState);
renderEvent.frameState.layerStatesArray.push(this.getLayerState(false));
}, this);
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
this.changed();
@@ -245,6 +254,13 @@ class Layer extends BaseLayer {
return this.renderer_;
}
/**
* @return {boolean} The layer has a renderer.
*/
hasRenderer() {
return !!this.renderer_;
}
/**
* Create a renderer for this layer.
* @return {import("../renderer/Layer.js").default} A layer renderer.

View File

@@ -30,9 +30,9 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* @property {boolean} [declutter=false] Declutter images and text on this layer. The priority is defined
* by the `zIndex` of the style and the render order of features. Higher z-index means higher priority.
* Within the same z-index, a feature rendered before another has higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will

View File

@@ -46,8 +46,10 @@ import {assign} from '../obj.js';
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
* higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be

View File

@@ -1,7 +1,6 @@
/**
* @module ol/math
*/
import {assert} from './asserts.js';
/**
* Takes a number and clamps it to within the provided bounds.
@@ -43,16 +42,6 @@ export const cosh = (function() {
}());
/**
* @param {number} x X.
* @return {number} The smallest power of two greater than or equal to x.
*/
export function roundUpToPowerOfTwo(x) {
assert(0 < x, 29); // `x` must be greater than `0`
return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
}
/**
* Returns the square of the closest distance between the point (x, y) and the
* line segment (x1, y1) to (x2, y2).

View File

@@ -127,11 +127,6 @@
right: .5em;
top: .5em;
}
@media print {
.ol-control {
display: none;
}
}
.ol-control button {
display: block;

View File

@@ -110,3 +110,23 @@ export function getRenderPixel(event, pixel) {
applyTransform(event.inversePixelTransform.slice(), result);
return result;
}
/**
* @param {import("./PluggableMap.js").FrameState} frameState Frame state.
* @param {?} declutterTree Declutter tree.
* @returns {?} Declutter tree.
*/
export function renderDeclutterItems(frameState, declutterTree) {
if (declutterTree) {
declutterTree.clear();
}
const items = frameState.declutterItems;
for (let z = items.length - 1; z >= 0; --z) {
const zIndexItems = items[z];
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree);
}
}
items.length = 0;
return declutterTree;
}

View File

@@ -21,6 +21,7 @@ import {
import {createCanvasContext2D} from '../../dom.js';
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
import Disposable from '../../Disposable.js';
import RBush from 'rbush';
/**
@@ -58,15 +59,10 @@ class Executor extends Disposable {
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @param {SerializableInstructions} instructions The serializable instructions
*/
constructor(resolution, pixelRatio, overlaps, declutterTree, instructions) {
constructor(resolution, pixelRatio, overlaps, instructions) {
super();
/**
* @type {?}
*/
this.declutterTree = declutterTree;
/**
* @protected
@@ -93,6 +89,11 @@ class Executor extends Disposable {
*/
this.alignFill_;
/**
* @type {Array<*>}
*/
this.declutterItems = [];
/**
* @protected
* @type {Array<*>}
@@ -192,9 +193,10 @@ class Executor extends Disposable {
const width = measureTextWidths(textState.font, lines, widths);
const lineHeight = measureTextHeight(textState.font);
const height = lineHeight * numLines;
const renderWidth = (width + strokeWidth);
const renderWidth = width + strokeWidth;
const context = createCanvasContext2D(
Math.ceil(renderWidth * scale),
// make canvas 2 pixels wider to account for italic text width measurement errors
Math.ceil((renderWidth + 2) * scale),
Math.ceil((height + strokeWidth) * scale));
label = context.canvas;
labelCache.set(key, label);
@@ -219,7 +221,7 @@ class Executor extends Disposable {
context.textBaseline = 'middle';
context.textAlign = 'center';
const leftRight = (0.5 - align);
const x = align * label.width / scale + leftRight * strokeWidth;
const x = align * renderWidth + leftRight * strokeWidth;
let i;
if (strokeKey) {
for (i = 0; i < numLines; ++i) {
@@ -412,8 +414,10 @@ class Executor extends Disposable {
/**
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {import("../../Feature.js").FeatureLike} feature Feature.
* @param {?} declutterTree Declutter tree.
* @return {?} Declutter tree.
*/
renderDeclutter_(declutterGroup, feature) {
renderDeclutter(declutterGroup, feature, declutterTree) {
if (declutterGroup && declutterGroup.length > 5) {
const groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
@@ -425,8 +429,11 @@ class Executor extends Disposable {
maxY: /** @type {number} */ (declutterGroup[3]),
value: feature
};
if (!this.declutterTree.collides(box)) {
this.declutterTree.insert(box);
if (!declutterTree) {
declutterTree = new RBush(9);
}
if (!declutterTree.collides(box)) {
declutterTree.insert(box);
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
const declutterData = /** @type {Array} */ (declutterGroup[j]);
if (declutterData) {
@@ -443,6 +450,7 @@ class Executor extends Disposable {
createOrUpdateEmpty(declutterGroup);
}
}
return declutterTree;
}
/**
@@ -464,7 +472,9 @@ class Executor extends Disposable {
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
const anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
// Remove the 2 pixels we added in getTextImage() for the anchor
const width = label.width / pixelRatio - 2 * textState.scale;
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
return {
@@ -497,6 +507,7 @@ class Executor extends Disposable {
featureCallback,
opt_hitExtent
) {
this.declutterItems.length = 0;
/** @type {Array<number>} */
let pixelCoordinates;
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
@@ -670,7 +681,7 @@ class Executor extends Disposable {
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
}
this.renderDeclutter_(declutterGroup, feature);
this.declutterItems.push(this, declutterGroup, feature);
++i;
break;
case CanvasInstruction.DRAW_CHARS:
@@ -739,7 +750,7 @@ class Executor extends Disposable {
}
}
}
this.renderDeclutter_(declutterGroup, feature);
this.declutterItems.push(this, declutterGroup, feature);
++i;
break;
case CanvasInstruction.END_GEOMETRY:

View File

@@ -35,18 +35,12 @@ class ExecutorGroup extends Disposable {
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The executor group can have overlapping geometries.
* @param {?} declutterTree Declutter tree for declutter processing in postrender.
* @param {!Object<string, !Object<BuilderType, import("./Builder.js").SerializableInstructions>>} allInstructions
* The serializable instructions.
* @param {number=} opt_renderBuffer Optional rendering buffer.
*/
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, allInstructions, opt_renderBuffer) {
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
super();
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = declutterTree;
/**
* @private
@@ -88,7 +82,7 @@ class ExecutorGroup extends Disposable {
* @private
* @type {CanvasRenderingContext2D}
*/
this.hitDetectionContext_ = createCanvasContext2D(1, 1);
this.hitDetectionContext_ = null;
/**
* @private
@@ -128,7 +122,7 @@ class ExecutorGroup extends Disposable {
for (const builderType in instructionByZindex) {
const instructions = instructionByZindex[builderType];
executors[builderType] = new Executor(
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_, instructions);
this.resolution_, this.pixelRatio_, this.overlaps_, instructions);
}
}
}
@@ -143,8 +137,11 @@ class ExecutorGroup extends Disposable {
executors[key].disposeInternal();
}
}
if (this.hitDetectionContext_) {
const canvas = this.hitDetectionContext_.canvas;
canvas.width = canvas.height = 0;
}
super.disposeInternal();
}
@@ -172,7 +169,7 @@ class ExecutorGroup extends Disposable {
* @param {number} hitTolerance Hit tolerance in pixels.
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
* @param {Object<string, import("../canvas.js").DeclutterGroup>} declutterReplays Declutter replays.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|undefined} Callback result.
* @template T
*/
@@ -183,7 +180,7 @@ class ExecutorGroup extends Disposable {
hitTolerance,
skippedFeaturesHash,
callback,
declutterReplays
declutteredFeatures
) {
hitTolerance = Math.round(hitTolerance);
@@ -193,6 +190,10 @@ class ExecutorGroup extends Disposable {
1 / resolution, -1 / resolution,
-rotation,
-coordinate[0], -coordinate[1]);
if (!this.hitDetectionContext_) {
this.hitDetectionContext_ = createCanvasContext2D(contextSize, contextSize);
}
const context = this.hitDetectionContext_;
if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
@@ -213,12 +214,6 @@ class ExecutorGroup extends Disposable {
}
const mask = getCircleArray(hitTolerance);
let declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
return entry.value;
});
}
let builderType;
@@ -261,15 +256,6 @@ class ExecutorGroup extends Disposable {
builderType = ORDER[j];
executor = executors[builderType];
if (executor !== undefined) {
if (declutterReplays &&
(builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) {
const declutter = declutterReplays[zIndexKey];
if (!declutter) {
declutterReplays[zIndexKey] = [executor, transform.slice(0)];
} else {
declutter.push(executor, transform.slice(0));
}
} else {
result = executor.executeHitDetection(context, transform, rotation,
skippedFeaturesHash, featureCallback, hitExtent);
if (result) {
@@ -278,7 +264,6 @@ class ExecutorGroup extends Disposable {
}
}
}
}
return undefined;
}
@@ -446,14 +431,20 @@ export function getCircleArray(radius) {
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
* @param {Array<Array<*>>} declutterItems Declutter items.
*/
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel) {
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) {
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
const skippedFeatureUids = {};
for (let z = 0, zz = zs.length; z < zz; ++z) {
const executorData = declutterReplays[zs[z].toString()];
let currentExecutor;
for (let i = 0, ii = executorData.length; i < ii;) {
const executor = executorData[i++];
if (executor !== currentExecutor) {
currentExecutor = executor;
declutterItems.push(executor.declutterItems);
}
const transform = executorData[i++];
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
}

View File

@@ -8,6 +8,7 @@ import RenderEventType from '../render/EventType.js';
import MapRenderer from './Map.js';
import SourceState from '../source/State.js';
import {replaceChildren} from '../dom.js';
import {labelCache} from '../render/canvas.js';
/**
@@ -22,6 +23,7 @@ class CompositeMapRenderer extends MapRenderer {
*/
constructor(map) {
super(map);
map.attachLabelCache(labelCache);
/**
* @private
@@ -85,7 +87,8 @@ class CompositeMapRenderer extends MapRenderer {
this.children_.length = 0;
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
const layerState = layerStatesArray[i];
if (!visibleAtResolution(layerState, viewResolution) || layerState.sourceState != SourceState.READY) {
if (!visibleAtResolution(layerState, viewResolution) ||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
continue;
}
@@ -94,11 +97,12 @@ class CompositeMapRenderer extends MapRenderer {
if (element) {
const zIndex = layerState.zIndex;
if (zIndex !== element.style.zIndex) {
element.style.zIndex = zIndex;
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex;
}
this.children_.push(element);
}
}
super.renderFrame(frameState);
replaceChildren(this.element_, this.children_);
@@ -109,7 +113,6 @@ class CompositeMapRenderer extends MapRenderer {
this.renderedVisible_ = true;
}
this.scheduleRemoveUnusedLayerRenderers(frameState);
this.scheduleExpireIconCache(frameState);
}
@@ -126,11 +129,8 @@ class CompositeMapRenderer extends MapRenderer {
for (let i = numLayers - 1; i >= 0; --i) {
const layerState = layerStates[i];
const layer = layerState.layer;
if (visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
const layerRenderer = this.getLayerRenderer(layer);
if (!layerRenderer) {
continue;
}
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
const layerRenderer = layer.getRenderer();
const data = layerRenderer.getDataAtPixel(pixel, frameState, hitTolerance);
if (data) {
const result = callback(layer, data);

View File

@@ -89,10 +89,11 @@ class LayerRenderer extends Observable {
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result.
* @template T
*/
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {}
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {}
/**
* @abstract
@@ -114,6 +115,12 @@ class LayerRenderer extends Observable {
return this.layer_;
}
/**
* Perform action necessary to get the layer rendered after new fonts have loaded
* @abstract
*/
handleFontsChanged() {}
/**
* Handle changes in image state.
* @param {import("../events/Event.js").default} event Image change event.

View File

@@ -3,13 +3,12 @@
*/
import {abstract, getUid} from '../util.js';
import Disposable from '../Disposable.js';
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {getWidth} from '../extent.js';
import {TRUE} from '../functions.js';
import {visibleAtResolution} 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';
/**
* @abstract
@@ -30,15 +29,8 @@ class MapRenderer extends Disposable {
/**
* @private
* @type {!Object<string, import("./Layer.js").default>}
*/
this.layerRenderers_ = {};
/**
* @private
* @type {Object<string, import("../events.js").EventsKey>}
*/
this.layerRendererListeners_ = {};
this.declutterTree_ = null;
}
@@ -69,15 +61,6 @@ class MapRenderer extends Disposable {
makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform);
}
/**
* Removes all layer renderers.
*/
removeLayerRenderers() {
for (const key in this.layerRenderers_) {
this.removeLayerRendererByKey_(key).dispose();
}
}
/**
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
@@ -133,18 +116,24 @@ class MapRenderer extends Disposable {
const layerStates = frameState.layerStatesArray;
const numLayers = layerStates.length;
let declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
return entry.value;
});
}
let i;
for (i = numLayers - 1; i >= 0; --i) {
const layerState = layerStates[i];
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
if (visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
const layerRenderer = this.getLayerRenderer(layer);
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
const layerRenderer = layer.getRenderer();
const source = layer.getSource();
if (layerRenderer && source) {
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
result = layerRenderer.forEachFeatureAtCoordinate(
source.getWrapX() ? translatedCoordinate : coordinate,
frameState, hitTolerance, callback);
frameState, hitTolerance, callback, declutteredFeatures);
}
if (result) {
return result;
@@ -191,35 +180,6 @@ class MapRenderer extends Disposable {
return hasFeature !== undefined;
}
/**
* @param {import("../layer/Layer.js").default} layer Layer.
* @protected
* @return {import("./Layer.js").default} Layer renderer. May return null.
*/
getLayerRenderer(layer) {
const layerKey = getUid(layer);
if (layerKey in this.layerRenderers_) {
return this.layerRenderers_[layerKey];
}
const renderer = layer.getRenderer();
if (!renderer) {
return null;
}
this.layerRenderers_[layerKey] = renderer;
this.layerRendererListeners_[layerKey] = listen(renderer, EventType.CHANGE, this.handleLayerRendererChange_, this);
return renderer;
}
/**
* @protected
* @return {Object<string, import("./Layer.js").default>} Layer renderers.
*/
getLayerRenderers() {
return this.layerRenderers_;
}
/**
* @return {import("../PluggableMap.js").default} Map.
*/
@@ -227,36 +187,12 @@ class MapRenderer extends Disposable {
return this.map_;
}
/**
* Handle changes in a layer renderer.
* @private
*/
handleLayerRendererChange_() {
this.map_.render();
}
/**
* @param {string} layerKey Layer key.
* @return {import("./Layer.js").default} Layer renderer.
* @private
*/
removeLayerRendererByKey_(layerKey) {
const layerRenderer = this.layerRenderers_[layerKey];
delete this.layerRenderers_[layerKey];
unlistenByKey(this.layerRendererListeners_[layerKey]);
delete this.layerRendererListeners_[layerKey];
return layerRenderer;
}
/**
* Render.
* @abstract
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
*/
renderFrame(frameState) {
abstract();
this.declutterTree_ = renderDeclutterItems(frameState, this.declutterTree_);
}
/**
@@ -268,21 +204,6 @@ class MapRenderer extends Disposable {
frameState.postRenderFunctions.push(expireIconCache);
}
}
/**
* @param {!import("../PluggableMap.js").FrameState} frameState Frame state.
* @protected
*/
scheduleRemoveUnusedLayerRenderers(frameState) {
const layerStatesMap = getLayerStatesMap(frameState.layerStatesArray);
for (const layerKey in this.layerRenderers_) {
if (!(layerKey in layerStatesMap)) {
frameState.postRenderFunctions.push(function() {
this.removeLayerRendererByKey_(layerKey).dispose();
}.bind(this));
}
}
}
}
@@ -294,15 +215,4 @@ function expireIconCache(map, frameState) {
iconImageCache.expire();
}
/**
* @param {Array<import("../layer/Layer.js").State>} layerStatesArray Layer states array.
* @return {Object<string, import("../layer/Layer.js").State>} States mapped by layer uid.
*/
function getLayerStatesMap(layerStatesArray) {
return layerStatesArray.reduce(function(acc, state) {
acc[getUid(state.layer)] = state;
return acc;
}, {});
}
export default MapRenderer;

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