Compare commits

...

157 Commits

Author SHA1 Message Date
ahocevar
5cc1ff0f45 Use beta tag 2019-06-24 09:54:41 +02:00
ahocevar
2df5f85018 Set version to 6.0.0-beta.10 2019-06-24 09:52:07 +02:00
Andreas Hocevar
4a0d6ce43c Merge pull request #9705 from ahocevar/vectortile-render-optimizations
Vector tile renderer optimizations and fixes
2019-06-24 09:50:56 +02:00
Andreas Hocevar
187969cbb3 Merge pull request #9706 from ahocevar/non-browser-screen-check
Do not use self to check browser features
2019-06-24 09:48:59 +02:00
ahocevar
8cdfc6e17c Do not use self to check browser features 2019-06-23 14:26:40 +02:00
ahocevar
9cd35d67a9 Fix clipping and clearing 2019-06-23 14:23:32 +02:00
ahocevar
4d2fa476a3 Simpler z sort 2019-06-23 14:22:56 +02:00
ahocevar
f864c05070 Less frame budget restrictions 2019-06-23 14:07:22 +02:00
ahocevar
3557271e5a Use Image.prototype.decode also in Safari 2019-06-23 14:06:14 +02:00
Andreas Hocevar
8a49e06ebd Merge pull request #9704 from ahocevar/vectortile-reuse-issue
Handle container reuse properly when layers are added/removed
2019-06-22 19:33:59 +02:00
ahocevar
6783f6adb9 Handle container reuse properly when layers are added/removed 2019-06-22 19:12:39 +02:00
Tim Schaub
5eb27f7704 Merge pull request #9703 from openlayers/greenkeeper/eslint-6.0.0
Update eslint to the latest version 🚀
2019-06-22 07:13:34 -06:00
greenkeeper[bot]
df240fe905 chore(package): update eslint to version 6.0.0 2019-06-22 04:08:47 +00:00
Frédéric Junod
300522e3cc Merge pull request #9701 from fredj/overlay_will-change
Remove will-change CSS rule for Overlay container
2019-06-21 16:36:27 +02:00
Tim Schaub
3ede6e32be Merge pull request #9702 from lutzhelm/typecheck-iiif
Fix several TypeScript type check problems
2019-06-21 07:53:59 -06:00
Tim Schaub
ce45a10063 Merge pull request #9700 from KaiVolland/9692-typescript
Solves typescript related issues
2019-06-21 07:48:15 -06:00
Tim Schaub
2438ef167b Merge pull request #9699 from petrsloup/maptiler-url-fix
Fix MapTiler API usage
2019-06-21 07:46:42 -06:00
Lutz Helm
d6dc7a926d Fix several TypeScript type check problems 2019-06-21 15:26:28 +02:00
Frederic Junod
6e6a2cae06 Use version 4 TileJSON from mapbox 2019-06-21 14:33:26 +02:00
Frederic Junod
a6ebad008f Remove will-change CSS rule for Overlay container
Fixes #9467
Fixes #9139

Chrome doesn't force a composition if the `will-change` CSS rule is different from `transform` or `opacity`.
See https://bugs.chromium.org/p/chromium/issues/detail?id=960953
2019-06-21 14:22:46 +02:00
Kai Volland
ed5d4aaf6d Fixes typing issue in mat4.js 2019-06-21 13:35:40 +02:00
Kai Volland
f507efe77d Fixes typing issue in Composite.js 2019-06-21 13:31:27 +02:00
Kai Volland
83173cd385 Fixes typing issue in VectorTile.js 2019-06-21 13:30:35 +02:00
Kai Volland
b6b91abc27 Fixes typing issue in DragPan.js 2019-06-21 13:28:56 +02:00
Petr Sloup
05c791efcd Fix MapTiler API usage 2019-06-21 11:22:24 +02:00
Tim Schaub
2342626a57 Merge pull request #9698 from openlayers/greenkeeper/puppeteer-1.18.0
Update puppeteer to the latest version 🚀
2019-06-20 23:33:59 -06:00
greenkeeper[bot]
7c0a0a4786 chore(package): update puppeteer to version 1.18.0 2019-06-20 22:24:07 +00:00
Frédéric Junod
a35ca03e07 Merge pull request #9636 from fredj/rm_from_webgl
Remove and move code from ol/webgl
2019-06-20 16:16:27 +02:00
Tim Schaub
c522454af1 Merge pull request #9695 from openlayers/greenkeeper/webpack-4.35.0
Update webpack to the latest version 🚀
2019-06-20 07:16:29 -06:00
Frederic Junod
ef10834eb3 Remove unused constants from ol/webgl
And change the `EXTENSIONS` constant to a function
2019-06-20 10:25:22 +02:00
greenkeeper[bot]
8efad7bcff chore(package): update webpack to version 4.35.0 2019-06-20 05:08:42 +00:00
Andreas Hocevar
51c8886d60 Merge pull request #9684 from ahocevar/doc-nav
List complete classes in doc navigation
2019-06-17 15:37:19 +02:00
Frédéric Junod
34a8702202 Merge pull request #9685 from fredj/rm_glContext
Remove glContext from RenderEvent
2019-06-17 14:10:51 +02:00
Frederic Junod
1f00da8d83 Remove glContext from RenderEvent 2019-06-17 13:52:56 +02:00
ahocevar
8d793ad6ec List complete classes in doc navigation 2019-06-17 13:10:02 +02:00
Andreas Hocevar
bd8a7bff16 Merge pull request #9681 from ahocevar/apidoc-fixed-and-improved
Remove duplicates from api docs and make navigation more usable
2019-06-17 08:27:48 +02:00
ahocevar
d059689856 Index classes under modulues 2019-06-17 08:15:49 +02:00
ahocevar
4ea28333f8 Avoid duplicates in api docs 2019-06-17 08:15:17 +02:00
Andreas Hocevar
edebf35135 Merge pull request #9677 from ahocevar/featureformat-tilepixels
Add support for tile pixel projection in feature formats
2019-06-15 08:22:28 +02:00
Frédéric Junod
90b645daa5 Merge pull request #9679 from fredj/cleanup
Set pixelTransform and inversePixelTransform as protected
2019-06-15 07:53:15 +02:00
Andreas Hocevar
9eac927b45 Merge pull request #9678 from ahocevar/geography-class
Update geography class urls
2019-06-14 23:20:47 +02:00
Frederic Junod
ec5e8bfa50 Set pixelTransform and inversePixelTransform as protected
The variables are used in child classes
2019-06-14 14:52:28 +02:00
ahocevar
124e984a6d Fix and simplify geojson-vt example 2019-06-14 14:28:37 +02:00
ahocevar
76f44efbb6 Add support for tile pixels to feature formats 2019-06-14 14:28:37 +02:00
ahocevar
ddaaf6a860 Update geography class urls 2019-06-14 12:53:52 +02:00
Tim Schaub
92c16ecdf5 Merge pull request #9673 from openlayers/greenkeeper/webpack-4.34.0
Update webpack to the latest version 🚀
2019-06-12 19:15:28 -06:00
greenkeeper[bot]
635d7a9189 chore(package): update webpack to version 4.34.0 2019-06-12 23:40:39 +00:00
Tim Schaub
fc6ca5eaf3 Merge pull request #9660 from openlayers/greenkeeper/pixelmatch-5.0.0
Update pixelmatch to the latest version 🚀
2019-06-07 04:08:01 -06:00
greenkeeper[bot]
803f960ded chore(package): update pixelmatch to version 5.0.0 2019-06-07 07:52:43 +00:00
Frédéric Junod
ef1b672323 Merge pull request #9658 from fredj/f9628
Don't use HTMLImageElement.decode method on Safari
2019-06-06 16:34:57 +02:00
Frederic Junod
002dc34455 Don't use HTMLImageElement.decode method on Safari
The decode function is supported by Safari but not when the image is a svg file.
2019-06-06 16:15:36 +02:00
Frédéric Junod
cc8389d588 Merge pull request #9657 from fredj/getFeaturesInExtent_doc
Better documentation for getFeaturesInExtent function
2019-06-06 14:23:11 +02:00
Frederic Junod
a8e0e4e960 Better documentation for getFeaturesInExtent function 2019-06-06 14:08:25 +02:00
Olivier Guyot
9ae7256048 Merge pull request #9562 from jahow/webgl-worker
Optimize the WebGL points renderer using a worker
2019-06-06 08:48:29 +02:00
Frederic Junod
e036767746 Use version 4 TileJSON from mapbox 2019-06-06 08:34:31 +02:00
Frédéric Junod
9a49c91fdd Merge pull request #9653 from openlayers/greenkeeper/coveralls-3.0.4
Update coveralls to the latest version 🚀
2019-06-06 08:19:45 +02:00
greenkeeper[bot]
37ff7f547b chore(package): update coveralls to version 3.0.4 2019-06-06 00:10:14 +00:00
Marc Jansen
c97a728531 Merge pull request #9394 from KaiVolland/docs-import-functions
Introduces import snippets for static functions
2019-06-05 22:20:15 +02:00
Olivier Guyot
811bff0430 Merge pull request #9638 from agpixdev/translate-interaction-filter
#9625: Add filter function to translate interaction
2019-06-05 15:32:29 +02:00
Olivier Guyot
2412fe0211 Webgl / remove handling of element_index_uint extension
From now on we will assume this extension is always enabled.

An error message have been added in the unlikely scenario of a lack
of support.
2019-06-05 14:46:15 +02:00
Tim Schaub
32084a7fce Merge pull request #9649 from openlayers/greenkeeper/webpack-4.33.0
Update webpack to the latest version 🚀
2019-06-04 20:11:55 -07:00
André Garneau
7817cf31c6 Changes following code review
Add a type for FilterFunction and add tests for filter option.
2019-06-04 17:45:28 -04:00
greenkeeper[bot]
2e5aac8dba chore(package): update webpack to version 4.33.0 2019-06-04 20:02:28 +00:00
Frédéric Junod
8b08996703 Merge pull request #9644 from fredj/webgl_layer_compose
Use compose function from ol/transform
2019-06-04 15:35:05 +02:00
Andreas Hocevar
1fbbc56f93 Merge pull request #9645 from ahocevar/no-used-tiles
Handle case of no used tiles
2019-06-04 15:26:27 +02:00
ahocevar
8f77a300de Handle case of no used tiles 2019-06-04 14:07:23 +02:00
Frederic Junod
91d49b26b5 Round the transform values in makeProjectionTransform test 2019-06-04 14:00:39 +02:00
Frederic Junod
02ce2f4bec Use compose function from ol/transform 2019-06-04 13:23:12 +02:00
Andreas Hocevar
d4f98c8e59 Merge pull request #9640 from ahocevar/base-docs
Import options directly instead of importing a typedef
2019-06-04 09:30:38 +02:00
Andreas Hocevar
ab0860a22a Merge pull request #9641 from ahocevar/less-proj-imports
Only import what's needed from projections
2019-06-04 09:27:05 +02:00
ahocevar
dd478167a0 Only import what's needed from projections 2019-06-04 09:14:08 +02:00
ahocevar
2df911e0a8 Import options directly instead of importing a typedef 2019-06-04 08:41:08 +02:00
Andreas Hocevar
e9939ecc38 Merge pull request #9637 from ahocevar/detach-labelcache-on-settarget
Detach label cache on Map#setTarget()
2019-06-03 16:03:30 +02:00
Frédéric Junod
d058439756 Merge pull request #9633 from fredj/rm_typecast
Mark the `layers` property as optional in OverviewMap constructor
2019-06-03 15:46:23 +02:00
ahocevar
8c21c9196d Move label cache listener management to the renderer 2019-06-03 15:13:30 +02:00
ahocevar
68b7831daf Listen to label cache again when we have a target 2019-06-03 14:28:20 +02:00
ahocevar
153e06e4d5 Detach label cache on Map#setTarget() 2019-06-03 14:14:13 +02:00
Andreas Hocevar
9bedfb7cb0 Merge pull request #9634 from ahocevar/remove-old-android-workaround
Remove old Android workaround
2019-06-03 10:17:44 +02:00
ahocevar
1bd23a0c32 Remove old Android workaround 2019-06-03 10:03:53 +02:00
Frederic Junod
50343afa61 Remove unnecessary typecasts in constructors options 2019-06-03 09:08:41 +02:00
Frederic Junod
a9e1ebccd3 Mark the layers property as optional in OverviewMap constructor 2019-06-03 09:07:20 +02:00
Andreas Hocevar
9672142c1e Merge pull request #9629 from ahocevar/reuse-vectortile-overlay
Clear overlay canvas when reusing containers
2019-06-02 18:20:24 +02:00
ahocevar
6123be726a Handle layer removal on shared containers 2019-06-02 13:59:06 +02:00
ahocevar
05d8517686 Clear overlay canvas when reusing containers 2019-06-02 11:07:30 +02:00
Frederic Junod
87d5f4c8bc Use 'helper' from WebGLHelper in tests 2019-06-01 15:35:31 +02:00
Frederic Junod
06be00bbd5 Webgl Helper / add an API for OESElementIndexUint extension 2019-06-01 15:35:27 +02:00
Frederic Junod
7fb113c3dc Mark 'helper' variable protected 2019-06-01 15:33:36 +02:00
Olivier Guyot
98b0c65450 Rendering tests / add custom web worker loader
Also includes a change in the rollup-babel plugin to avoid
adding helpers as dependencies (which would give out errors).
2019-06-01 15:33:36 +02:00
Olivier Guyot
698816030e Webgl points / fix unit tests 2019-06-01 15:33:36 +02:00
Olivier Guyot
03e70bd10e Webgl points / handle using short instead of int for indices
This is controlled by the availability of the OES_element_index_uint
webgl extension.
2019-06-01 15:33:36 +02:00
Olivier Guyot
e0983cb1c6 Webgl worker / add tests, some typing and documentation
The worker currently works by receiving GENERATE_BUFFERS messages and
will send back the same kind of message, with the generated buffers
attached. All properties of the original message are kept, so that
when a GENERATE_BUFFERS message comes back to the main thread it
is possible to know what and how the buffers where generated.

This is typically used for the `projectionTransform` matrix, and
will also be necessary when working with tiles.
2019-06-01 15:33:36 +02:00
Olivier Guyot
a366803cdd Webgl / use the new buffer API in helper & the points renderer 2019-06-01 15:33:36 +02:00
Olivier Guyot
33d007ce01 Webgl buffer / now stores data in typed arrays
The `WebGLBuffer` class API was changed in order to allow populating
the internal array in different ways.
2019-06-01 15:33:31 +02:00
Olivier Guyot
8566cfc227 Webgl points / get back the instructions array from the worker
This means we won't have to recreate a binary buffer (through a typed array)
on every `rebuildBuffer` call.
2019-06-01 15:25:24 +02:00
Olivier Guyot
65be907095 Webgl points / shifts the buffer write logic in a worker
The worker receives a transferable array of instructions
and sends back two transferable arrays (vertex and index buffer).
The projection transform is also sent so that when the main thread
receives the buffers from the worker it also knows which projection to
apply when rendering the geometries.
2019-06-01 15:25:11 +02:00
Olivier Guyot
532b8194b1 Webgl points / use the new typed-array based utils for buffers
`rebuildBuffer` is still a very CPU intensive task and is blocking the
main thread.
2019-06-01 15:20:04 +02:00
Olivier Guyot
eb912d95ca Webgl / refactor utilities to work only on typed arrays
The base webgl renderer module now has two types of utilities:
* `writeXFeatureInstructions` will write a series of values in a given
typed array, which represent how a given feature will be rendered; for points,
this means position, size, color, etc.
* `writeXFeatureToBuffers` will fill up the given index & vertex buffers
with values based on the provided render instructions

As such, the logic for rendering features is:
user-input style > instructions array >(*) index/vertex buffers > draw

(*) this transformation is intended to be done on a worker.
2019-06-01 15:19:37 +02:00
Frédéric Junod
245ded43d4 Merge pull request #9626 from fredj/rm_from_has
Remove TOUCH, POINTER and MSPOINTER from ol/has
2019-06-01 12:09:40 +01:00
Frederic Junod
7c215b2532 Remove TOUCH, POINTER and MSPOINTER from ol/has 2019-06-01 07:18:23 +02:00
Frédéric Junod
579d05a0cb Merge pull request #9624 from fredj/cleanup
Remove typecasts in ol/control/OverviewMap
2019-06-01 06:13:02 +01:00
André Garneau
b42ee8ca0f Add filter function to translate interaction
Add a filter function to the translate interaction. This filter is similar to the one present in the select interaction options and provides the ability to dynamically filter which features to include in the translate interaction. Adding the existing "features" options allows further filtering to take place. In this case the filter is first applied, and features that are passing the filtering need to be present in the "features" options to be further kept. The default filter function always return true (no filtering).
2019-05-31 14:51:13 -04:00
Frederic Junod
ede864c823 Remove typecasts in ol/control/OverviewMap
The `options` type was not correctly detected by the typescript compiler.
2019-05-31 16:18:15 +02:00
ahocevar
a50ef05565 Set version to 6.0.0-beta.9 2019-05-30 15:55:09 +02:00
Tim Schaub
93a607d846 Merge pull request #9615 from tschaub/import-specifiers
Include full filename in import specifier
2019-05-29 09:35:34 -06:00
Tim Schaub
deb00f20fe Include full filename in import specifier 2019-05-29 08:51:10 -06:00
Frédéric Junod
c4e465dcf9 Merge pull request #9592 from fredj/f9587_layerIndex
Remove `layerState` param from `prepareFrame` and `renderFrame` function
2019-05-29 09:27:38 +02:00
Frederic Junod
bfea858306 Add missing extension in import 2019-05-29 09:19:17 +02:00
Frédéric Junod
c92bf29677 Fix spelling
Co-Authored-By: Tim Schaub <tschaub@users.noreply.github.com>
2019-05-29 09:07:05 +02:00
Andreas Hocevar
6675f9be57 Merge pull request #9289 from sbrunner/vector-source-geom
Vector source geom
2019-05-28 11:23:31 +02:00
Frédéric Junod
1a6d67776b Merge pull request #9608 from fredj/md_link
Use markdown link syntax in jsdoc
2019-05-27 14:17:18 +02:00
Stéphane Brunner
889b6a9f43 Removes unnecessary type cast 2019-05-27 11:34:33 +02:00
Stéphane Brunner
970c1bcb66 Make the vector source geometry generic 2019-05-27 11:34:31 +02:00
Frederic Junod
2db953ceb1 Use markdown link syntax in jsdoc 2019-05-27 11:06:12 +02:00
Olivier Guyot
051cc68f24 Merge pull request #9596 from jahow/fix-source-missing-event
Vector source / prevent adding features with duplicate id in the collection
2019-05-26 10:53:58 +02:00
Frederic Junod
40c49a9ce5 Remove layerState param from prepareFrame and renderFrame function 2019-05-25 07:19:10 +02:00
Olivier Guyot
442fa907ce Vector source / prevent adding features with duplicate id...
...in the collection.

Previously two features with the same id could be pushed manually in the
features collection and stay there.

This would cause an error when clearing the source.

Fixes #6183.
2019-05-24 23:29:48 +02:00
Bart van den Eijnden
7044e30529 Merge pull request #9604 from bartvde/window-global
Use window instead of global in addEventListener
2019-05-24 15:17:07 +02:00
Frédéric Junod
7cfe047feb Merge pull request #9599 from openlayers/github_funding
Create FUNDING.yml
2019-05-24 15:14:26 +02:00
Tim Schaub
796f20385d Merge pull request #9598 from openlayers/greenkeeper/puppeteer-1.17.0
Update puppeteer to the latest version 🚀
2019-05-24 06:58:00 -06:00
bartvde
c76aa76743 Use window instead of global in addEventListener 2019-05-24 14:51:32 +02:00
Bart van den Eijnden
2969c9e8fb Merge pull request #9601 from bartvde/fix-addeventlistener2
Use global addEventListener in PluggableMap
2019-05-24 14:11:26 +02:00
bartvde
119c24faa2 Use global addEventListener in PluggableMap 2019-05-24 13:45:19 +02:00
Frédéric Junod
93711ea806 Create FUNDING.yml 2019-05-24 11:19:37 +02:00
Andreas Hocevar
96331c5d95 Merge pull request #9584 from ahocevar/reuse-render-target
Reuse render target
2019-05-24 10:33:36 +02:00
ahocevar
d8f41a9d73 Only reuse target when className is the same 2019-05-24 10:16:20 +02:00
greenkeeper[bot]
311900e441 chore(package): update puppeteer to version 1.17.0 2019-05-24 00:18:21 +00:00
ahocevar
bdb87f06f9 Rework tile image render queue 2019-05-23 15:55:29 +02:00
Frédéric Junod
ddb7da3733 Merge pull request #6217 from fredj/dragpan_primary
Add primaryAction condition to DragPan
2019-05-23 09:50:55 +02:00
Tim Schaub
a358521b2b Merge pull request #9594 from openlayers/greenkeeper/webpack-4.32.2
Update webpack to the latest version 🚀
2019-05-22 21:12:52 -06:00
greenkeeper[bot]
4f833501d7 chore(package): update webpack to version 4.32.2 2019-05-22 23:39:55 +00:00
ahocevar
ace5c65ee5 Smarter opacity handling 2019-05-22 16:47:23 +02:00
ahocevar
ae47d3df58 Use opacity from layer state 2019-05-22 16:47:22 +02:00
ahocevar
4c8effe6fa No tile transition when layer opacity is set 2019-05-22 16:47:22 +02:00
ahocevar
c56ad4363d Canvas opacity instead of css 2019-05-22 16:47:22 +02:00
ahocevar
7895b16043 Reuse container for raster and vector image layers 2019-05-22 16:47:20 +02:00
ahocevar
a45e704be2 Smarter reuse detection 2019-05-22 16:46:46 +02:00
ahocevar
d1f1b468b1 Reuse target for image layers 2019-05-22 16:46:46 +02:00
ahocevar
a55505b36a Reuse containers for tile, vector and vector tile layers 2019-05-22 16:46:40 +02:00
ahocevar
930318ab7a Clip high res tiles out of low res tiles only once 2019-05-22 15:57:15 +02:00
ahocevar
5fe9e06535 Use clipping to not render high res tiles on top of low res 2019-05-22 15:57:15 +02:00
ahocevar
606443bc6d Pass render target of previous layer to next layer 2019-05-22 15:56:51 +02:00
Frederic Junod
ec811bfa1f Add primaryAction condition to DragPan interaction 2019-05-22 15:21:17 +02:00
Tim Schaub
5e8d7f666e Merge pull request #9589 from openlayers/greenkeeper/webpack-4.32.1
Update webpack to the latest version 🚀
2019-05-22 06:35:21 -06:00
greenkeeper[bot]
4f9057f066 chore(package): update webpack to version 4.32.1 2019-05-22 06:59:26 +00:00
Tim Schaub
4ed6413635 Merge pull request #9586 from openlayers/greenkeeper/rollup-plugin-terser-5.0.0
Update rollup-plugin-terser to the latest version 🚀
2019-05-21 18:34:20 -06:00
greenkeeper[bot]
bb5ebaa1ab chore(package): update rollup-plugin-terser to version 5.0.0 2019-05-21 22:32:01 +00:00
Tim Schaub
c9491ed023 Merge pull request #9569 from engsterhold/patch-1
Fix for change in Zoomify.js/CustomTile signature
2019-05-21 06:52:51 -06:00
Tim Schaub
3db13fa3bb Merge pull request #9582 from tschaub/stale
Add app to mark inactive issues as stale
2019-05-21 06:49:56 -06:00
robert
7e4e113ac9 lint fix
Signed-off-by: robert <24939343+engsterhold@users.noreply.github.com>
2019-05-21 12:32:30 +02:00
Tim Schaub
dc4ce62fab Merge pull request #9581 from tschaub/update-webpack
Update webpack and use mode in the loader
2019-05-20 19:43:37 -06:00
Tim Schaub
6288744d70 Configure Stale app
See https://github.com/organizations/openlayers/settings/installations/1008384
2019-05-20 17:56:30 -06:00
Tim Schaub
c0339f167b Use mode from the loader context
See https://github.com/webpack/webpack/pull/9140.
2019-05-20 10:33:59 -06:00
greenkeeper[bot]
60007d8e3c chore(package): update webpack to version 4.32.0 2019-05-20 10:33:20 -06:00
engsterhold
f77b0941b8 fixed styling 2019-05-17 13:52:10 +02:00
ahocevar
b0fae46aa6 Do not use css z-index 2019-05-16 22:29:32 +02:00
engsterhold
e69b15d33e Bandaid fix for change in Zoomify.js/CustomTile signature
The recent addition of tilePixelRatio to the Zoomify.js/CustomTile constructor broke parameter binding in IIIF.js/IIIF.
The fix mirrors the change in the  Zoomify.js/Zoomify constructor
2019-05-16 16:10:58 +02:00
Kai Volland
9860699d5f Introduces import snippets for static functions
Adds snippets for import of modules and their
exported functions to the API documentation.
2019-04-04 10:07:55 +02:00
129 changed files with 1745 additions and 1206 deletions

8
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: openlayers
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: # Replace with a single custom sponsorship URL

17
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- blocker
- regression
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -4,9 +4,19 @@
#### Backwards incompatible changes #### Backwards incompatible changes
#### Removal of `TOUCH` constant from `ol/has`
If you were previously using this constant, you can check if `'ontouchstart'` is defined in `window` instead.
```js
if ('ontouchstart' in window) {
// ...
}
```
#### Removal of `GEOLOCATION` constant from `ol/has` #### Removal of `GEOLOCATION` constant from `ol/has`
If you were previously using this constant, you can check if `'geolocation'` is define in `navigator` instead. If you were previously using this constant, you can check if `'geolocation'` is defined in `navigator` instead.
```js ```js
if ('geolocation' in navigator) { if ('geolocation' in navigator) {

View File

@@ -59,7 +59,9 @@ function includeAugments(doclet) {
}); });
} }
cls._hideConstructor = true; cls._hideConstructor = true;
delete cls.undocumented; if (!cls.undocumented) {
cls._documented = true;
}
} }
} }
} }
@@ -150,6 +152,9 @@ exports.handlers = {
// Remove all other undocumented symbols // Remove all other undocumented symbols
doclet.undocumented = true; doclet.undocumented = true;
} }
if (doclet._documented) {
delete doclet.undocumented;
}
} }
} }

View File

@@ -214,55 +214,39 @@ function buildNav(members) {
} }
return 0; return 0;
}); });
function createEntry(type, v) {
return {
type: type,
longname: v.longname,
name: v.name,
classes: find({
kind: 'class',
memberof: v.longname
}).map(createEntry.bind(this, 'class')),
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
events: find({
kind: 'event',
memberof: v.longname
})
};
}
_.each(merged, function(v) { _.each(merged, function(v) {
// exclude interfaces from sidebar // exclude interfaces from sidebar
if (v.interface !== true) { if (v.interface !== true) {
if (v.kind == 'module') { if (v.kind == 'module') {
nav.push({ nav.push(createEntry('module', v));
type: 'module',
longname: v.longname,
name: v.name,
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
events: find({
kind: 'event',
memberof: v.longname
})
});
}
if (v.kind == 'class') {
nav.push({
type: 'class',
longname: v.longname,
name: v.name,
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
fires: v.fires,
events: find({
kind: 'event',
memberof: v.longname
})
});
} }
} }
}); });

View File

@@ -12,13 +12,18 @@ $(function () {
var $item = $(v); var $item = $(v);
if ($item.data('name') && regexp.test($item.data('name'))) { if ($item.data('name') && regexp.test($item.data('name'))) {
const container = $item.parent().parent().parent();
container.show();
container.closest('.itemMembers').show();
container.closest('.item').show();
$item.show(); $item.show();
$item.closest('.itemMembers').show(); $item.closest('.itemMembers').show();
$item.closest('.item').show(); $item.closest('.item').show();
} }
}); });
} else { } else {
$el.find('.item, .itemMembers').show(); $el.find('.item, .itemMembers').hide();
$('.navigation>ul>li').show();
} }
$el.find('.list').scrollTop(0); $el.find('.list').scrollTop(0);

View File

@@ -18,7 +18,7 @@
<sup class="variation"><?js= doc.variation ?></sup> <sup class="variation"><?js= doc.variation ?></sup>
<?js } ?></h2> <?js } ?></h2>
<br> <br>
<?js if (doc.stability || doc.kind == 'namespace') { <?js if (doc.stability || doc.kind == 'namespace' || doc.kind == 'module') {
var ancestors = doc.ancestors.map(a => a.replace(/>\./g, '>').replace(/\.</g, '<')).join('/'); var ancestors = doc.ancestors.map(a => a.replace(/>\./g, '>').replace(/\.</g, '<')).join('/');
var parts = []; var parts = [];
if (ancestors) { if (ancestors) {
@@ -26,7 +26,20 @@
} }
var importPath = parts.join('/'); var importPath = parts.join('/');
?> ?>
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre> <?js
var nameParts = doc.name.split('/');
var moduleName = nameParts[nameParts.length - 1];
if(moduleName) {
var firstChar = moduleName.charAt(0);
moduleName = firstChar.toUpperCase() + moduleName.slice(1);
var isClassModule = firstChar.toUpperCase() === firstChar;
}
?>
<?js if (doc.kind == 'module' && !isClassModule && nameParts.length < 3) {?>
<pre class="prettyprint source"><code>import * as ol<?js= moduleName ?> from '<?js= doc.name ?>';</code></pre>
<?js } else if(doc.kind !== 'module') { ?>
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre>
<?js } ?>
<?js } ?> <?js } ?>
<?js if (doc.classdesc) { ?> <?js if (doc.classdesc) { ?>
<div class="class-description"><?js= doc.classdesc ?></div> <div class="class-description"><?js= doc.classdesc ?></div>
@@ -143,6 +156,7 @@
<h3 class="subsection-title">Methods</h3> <h3 class="subsection-title">Methods</h3>
<dl><?js methods.forEach(function(m) { ?> <dl><?js methods.forEach(function(m) { ?>
<?js m.parent = doc ?>
<?js= self.partial('method.tmpl', m) ?> <?js= self.partial('method.tmpl', m) ?>
<?js }); ?></dl> <?js }); ?></dl>
<?js } ?> <?js } ?>

View File

@@ -27,6 +27,10 @@ var self = this;
</dt> </dt>
<dd class="<?js= (data.stability && data.stability !== 'stable') ? 'unstable' : '' ?>"> <dd class="<?js= (data.stability && data.stability !== 'stable') ? 'unstable' : '' ?>">
<?js if (data.parent && data.parent.kind == 'module' && data.parent.name.split('ol/').length < 3) { ?>
<pre class="prettyprint source"><code>import {<?js= data.name ?>} from '<?js= data.parent.name ?>';</code></pre>
<?js } ?>
<?js if (data.description) { ?> <?js if (data.description) { ?>
<div class="description"> <div class="description">
<?js= data.description ?> <?js= data.description ?>

View File

@@ -10,11 +10,12 @@ function toShortName(name) {
</div> </div>
<ul class="list"> <ul class="list">
<?js <?js
this.nav.forEach(function (item) { let navbuilder;
this.nav.forEach(navbuilder = function (item) {
?> ?>
<li class="item" data-name="<?js= item.longname ?>"> <li class="item" data-name="<?js= item.longname ?>">
<span class="title"> <span class="title">
<?js= self.linkto(item.longname, item.longname.replace('module:', '')) ?> <?js= self.linkto(item.longname, item.type === 'module' ? item.longname.replace('module:', '') : item.name) ?>
<?js if (item.type === 'namespace' && <?js if (item.type === 'namespace' &&
(item.members.length + item.typedefs.length + item.methods.length + (item.members.length + item.typedefs.length + item.methods.length +
item.events.length > 0)) { ?> item.events.length > 0)) { ?>
@@ -22,6 +23,18 @@ function toShortName(name) {
</span> </span>
<ul class="members itemMembers"> <ul class="members itemMembers">
<?js <?js
if (item.classes.length) {
?>
<span class="subtitle">Classes</span>
<?js
item.classes.forEach(function (v) {
navbuilder(v);
});
}
?>
</ul>
<ul class="members itemMembers">
<?js
if (item.members.length) { if (item.members.length) {
?> ?>
<span class="subtitle">Members</span> <span class="subtitle">Members</span>

View File

@@ -228,3 +228,11 @@ Missing or invalid `size`.
### 61 ### 61
Cannot determine IIIF Image API version from provided image information JSON. Cannot determine IIIF Image API version from provided image information JSON.
### 62
A `WebGLArrayBuffer` must either be of type `ELEMENT_ARRAY_BUFFER` or `ARRAY_BUFFER`.
### 63
Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL layers.

View File

@@ -5,6 +5,7 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
/** @type {VectorSource<import("../src/ol/geom/SimpleGeometry.js").default>} */
const source = new VectorSource({ const source = new VectorSource({
url: 'data/geojson/switzerland.geojson', url: 'data/geojson/switzerland.geojson',
format: new GeoJSON() format: new GeoJSON()
@@ -51,21 +52,21 @@ const zoomtoswitzerland =
document.getElementById('zoomtoswitzerland'); document.getElementById('zoomtoswitzerland');
zoomtoswitzerland.addEventListener('click', function() { zoomtoswitzerland.addEventListener('click', function() {
const feature = source.getFeatures()[0]; const feature = source.getFeatures()[0];
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry()); const polygon = feature.getGeometry();
view.fit(polygon, {padding: [170, 50, 30, 150]}); view.fit(polygon, {padding: [170, 50, 30, 150]});
}, false); }, false);
const zoomtolausanne = document.getElementById('zoomtolausanne'); const zoomtolausanne = document.getElementById('zoomtolausanne');
zoomtolausanne.addEventListener('click', function() { zoomtolausanne.addEventListener('click', function() {
const feature = source.getFeatures()[1]; const feature = source.getFeatures()[1];
const point = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry()); const point = feature.getGeometry();
view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50}); view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50});
}, false); }, false);
const centerlausanne = document.getElementById('centerlausanne'); const centerlausanne = document.getElementById('centerlausanne');
centerlausanne.addEventListener('click', function() { centerlausanne.addEventListener('click', function() {
const feature = source.getFeatures()[1]; const feature = source.getFeatures()[1];
const point = /** @type {import("../src/ol/geom/Point.js").default} */ (feature.getGeometry()); const point = feature.getGeometry();
const size = map.getSize(); const size = map.getSize();
view.centerOn(point.getCoordinates(), size, [570, 500]); view.centerOn(point.getCoordinates(), size, [570, 500]);
}, false); }, false);

View File

@@ -129,7 +129,7 @@ const map = new Map({
layers: [ layers: [
new TileLayer({ new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure' url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json'
}) })
}), }),
new VectorLayer({ new VectorLayer({

2
examples/d3.js vendored
View File

@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import {getWidth, getCenter} from '../src/ol/extent.js'; import {getWidth, getCenter} from '../src/ol/extent.js';
import {Layer, Tile as TileLayer} from '../src/ol/layer.js'; import {Layer, Tile as TileLayer} from '../src/ol/layer.js';
import SourceState from '../src/ol/source/State'; import SourceState from '../src/ol/source/State.js';
import {fromLonLat, toLonLat} from '../src/ol/proj.js'; import {fromLonLat, toLonLat} from '../src/ol/proj.js';
import Stamen from '../src/ol/source/Stamen.js'; import Stamen from '../src/ol/source/Stamen.js';

View File

@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js'; import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js'; import OSM from '../src/ol/source/OSM.js';
import {defaults as defaultControls} from '../src/ol/control.js'; import {defaults as defaultControls} from '../src/ol/control.js';
import ZoomSlider from '../src/ol/control/ZoomSlider'; import ZoomSlider from '../src/ol/control/ZoomSlider.js';
const view = new View({ const view = new View({
center: [328627.563458, 5921296.662223], center: [328627.563458, 5921296.662223],

View File

@@ -67,10 +67,10 @@ const routeFeature = new Feature({
type: 'route', type: 'route',
geometry: route geometry: route
}); });
const geoMarker = new Feature({ const geoMarker = /** @type Feature<import("../src/ol/geom/Point").default> */(new Feature({
type: 'geoMarker', type: 'geoMarker',
geometry: new Point(routeCoords[0]) geometry: new Point(routeCoords[0])
}); }));
const startMarker = new Feature({ const startMarker = new Feature({
type: 'icon', type: 'icon',
geometry: new Point(routeCoords[0]) geometry: new Point(routeCoords[0])
@@ -191,7 +191,7 @@ function stopAnimation(ended) {
// if animation cancelled set the marker at the beginning // if animation cancelled set the marker at the beginning
const coord = ended ? routeCoords[routeLength - 1] : routeCoords[0]; const coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
const geometry = /** @type {import("../src/ol/geom/Point").default} */ (geoMarker.getGeometry()); const geometry = geoMarker.getGeometry();
geometry.setCoordinates(coord); geometry.setCoordinates(coord);
//remove listener //remove listener
vectorLayer.un('postrender', moveFeature); vectorLayer.un('postrender', moveFeature);

View File

@@ -1,14 +1,14 @@
import Map from '../src/ol/Map.js'; import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js'; import TileLayer from '../src/ol/layer/Tile.js';
import Feature from '../src/ol/Feature'; import Feature from '../src/ol/Feature.js';
import Point from '../src/ol/geom/Point'; import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector'; import VectorLayer from '../src/ol/layer/Vector.js';
import {Vector} from '../src/ol/source'; import {Vector} from '../src/ol/source.js';
import {fromLonLat} from '../src/ol/proj'; import {fromLonLat} from '../src/ol/proj.js';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer'; import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
import {clamp, lerp} from '../src/ol/math'; import {clamp, lerp} from '../src/ol/math.js';
import Stamen from '../src/ol/source/Stamen'; import Stamen from '../src/ol/source/Stamen.js';
const vectorSource = new Vector({ const vectorSource = new Vector({
attributions: 'NASA' attributions: 'NASA'

View File

@@ -6,7 +6,7 @@ import VectorTileSource from '../src/ol/source/VectorTile.js';
import {Tile as TileLayer, VectorTile as VectorTileLayer} from '../src/ol/layer.js'; import {Tile as TileLayer, VectorTile as VectorTileLayer} from '../src/ol/layer.js';
import Projection from '../src/ol/proj/Projection.js'; import Projection from '../src/ol/proj/Projection.js';
// Converts geojson-vt data to GeoJSON
const replacer = function(key, value) { const replacer = function(key, value) {
if (value.geometry) { if (value.geometry) {
let type; let type;
@@ -46,11 +46,6 @@ const replacer = function(key, value) {
} }
}; };
const tilePixels = new Projection({
code: 'TILE_PIXELS',
units: 'tile-pixels'
});
const map = new Map({ const map = new Map({
layers: [ layers: [
new TileLayer({ new TileLayer({
@@ -73,23 +68,22 @@ fetch(url).then(function(response) {
debug: 1 debug: 1
}); });
const vectorSource = new VectorTileSource({ const vectorSource = new VectorTileSource({
format: new GeoJSON(), format: new GeoJSON({
tileLoadFunction: function(tile) { // Data returned from geojson-vt is in tile pixel units
const format = tile.getFormat(); dataProjection: new Projection({
const tileCoord = tile.getTileCoord(); code: 'TILE_PIXELS',
units: 'tile-pixels',
extent: [0, 0, 4096, 4096]
})
}),
tileUrlFunction: function(tileCoord) {
const data = tileIndex.getTile(tileCoord[0], tileCoord[1], tileCoord[2]); const data = tileIndex.getTile(tileCoord[0], tileCoord[1], tileCoord[2]);
const geojson = JSON.stringify({
const features = format.readFeatures( type: 'FeatureCollection',
JSON.stringify({ features: data ? data.features : []
type: 'FeatureCollection', }, replacer);
features: data ? data.features : [] return 'data:application/json;charset=UTF-8,' + geojson;
}, replacer)); }
tile.setLoader(function() {
tile.setFeatures(features);
tile.setProjection(tilePixels);
});
},
url: 'data:' // arbitrary url, we don't use it in the tileLoadFunction
}); });
const vectorLayer = new VectorTileLayer({ const vectorLayer = new VectorTileLayer({
source: vectorSource source: vectorSource

View File

@@ -56,7 +56,7 @@ const vectorLayer = new VectorLayer({
const rasterLayer = new TileLayer({ const rasterLayer = new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure', url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
crossOrigin: '' crossOrigin: ''
}) })
}); });

View File

@@ -13,5 +13,8 @@ docs: >
The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings
tags: "webgl, icon, sprite, point, ufo" tags: "webgl, icon, sprite, point, ufo"
cloak:
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
value: Your Mapbox access token from https://mapbox.com/ here
--- ---
<div id="map" class="map"></div> <div id="map" class="map"></div>

View File

@@ -1,14 +1,16 @@
import Map from '../src/ol/Map.js'; import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js'; import TileLayer from '../src/ol/layer/Tile.js';
import TileJSON from '../src/ol/source/TileJSON'; import TileJSON from '../src/ol/source/TileJSON.js';
import Feature from '../src/ol/Feature'; import Feature from '../src/ol/Feature.js';
import Point from '../src/ol/geom/Point'; import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector'; import VectorLayer from '../src/ol/layer/Vector.js';
import {Vector} from '../src/ol/source'; import {Vector} from '../src/ol/source.js';
import {fromLonLat} from '../src/ol/proj'; import {fromLonLat} from '../src/ol/proj.js';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer'; import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
import {lerp} from '../src/ol/math'; import {lerp} from '../src/ol/math.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
const vectorSource = new Vector({ const vectorSource = new Vector({
features: [], features: [],
@@ -105,7 +107,7 @@ new Map({
layers: [ layers: [
new TileLayer({ new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.world-dark.json?secure', url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?access_token=' + key,
crossOrigin: 'anonymous' crossOrigin: 'anonymous'
}) })
}), }),

View File

@@ -37,7 +37,7 @@ const vectorLayer = new VectorLayer({
const rasterLayer = new TileLayer({ const rasterLayer = new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure', url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
crossOrigin: '' crossOrigin: ''
}) })
}); });

View File

@@ -3,13 +3,13 @@ layout: example.html
title: Mapbox-gl Layer title: Mapbox-gl Layer
shortdesc: Example of a Mapbox-gl-js layer integration. shortdesc: Example of a Mapbox-gl-js layer integration.
docs: > 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. Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own API key at https://www.maptiler.com/cloud/ when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles" tags: "simple, mapbox, vector, tiles, maptiler"
resources: resources:
- https://unpkg.com/mapbox-gl@0.54.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 - https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css
cloak: cloak:
- key: ER67WIiPdCQvhgsUjoWK - key: ER67WIiPdCQvhgsUjoWK
value: Your Mapbox access token from https://mapbox.com/ here value: Get your own API key at https://www.maptiler.com/cloud/
--- ---
<div id="map" class="map"></div> <div id="map" class="map"></div>

View File

@@ -1,7 +1,7 @@
import Map from '../src/ol/Map.js'; import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import Layer from '../src/ol/layer/Layer'; import Layer from '../src/ol/layer/Layer.js';
import {toLonLat, fromLonLat} from '../src/ol/proj'; import {toLonLat, fromLonLat} from '../src/ol/proj.js';
import {Stroke, Style} from '../src/ol/style.js'; import {Stroke, Style} from '../src/ol/style.js';
import VectorLayer from '../src/ol/layer/Vector.js'; import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js'; import VectorSource from '../src/ol/source/Vector.js';
@@ -11,7 +11,7 @@ const center = [-98.8, 37.9];
const key = 'ER67WIiPdCQvhgsUjoWK'; const key = 'ER67WIiPdCQvhgsUjoWK';
const mbMap = new mapboxgl.Map({ const mbMap = new mapboxgl.Map({
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key, style: 'https://api.maptiler.com/maps/bright/style.json?key=' + key,
attributionControl: false, attributionControl: false,
boxZoom: false, boxZoom: false,
center: center, center: center,

View File

@@ -2,10 +2,10 @@
layout: example-verbatim.html layout: example-verbatim.html
title: Vector tiles created from a Mapbox Style object title: Vector tiles created from a Mapbox Style object
shortdesc: Example of using ol-mapbox-style with tiles from tilehosting.com. shortdesc: Example of using ol-mapbox-style with tiles from tilehosting.com.
tags: "vector tiles, mapbox style, ol-mapbox-style" tags: "vector tiles, mapbox style, ol-mapbox-style, maptiler"
cloak: cloak:
- key: lirfd6Fegsjkvs0lshxe - key: ER67WIiPdCQvhgsUjoWK
value: Your API key from http://tilehosting.com/ here value: Get your own API key at https://www.maptiler.com/cloud/
--- ---
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">

View File

@@ -1,3 +1,3 @@
import apply from 'ol-mapbox-style'; import apply from 'ol-mapbox-style';
apply('map', 'https://maps.tilehosting.com/styles/topo/style.json?key=ER67WIiPdCQvhgsUjoWK'); apply('map', 'https://api.maptiler.com/maps/topo/style.json?key=ER67WIiPdCQvhgsUjoWK');

View File

@@ -7,6 +7,9 @@ docs: >
Click on the map to get a popup. The popup is composed of a few basic elements: a container, a close button, and a place for the content. To anchor the popup to the map, an <code>ol/Overlay</code> is created with the popup container. A listener is registered for the map's <code>click</code> event to display the popup, and another listener is set as the <code>click</code> handler for the close button to hide the popup. Click on the map to get a popup. The popup is composed of a few basic elements: a container, a close button, and a place for the content. To anchor the popup to the map, an <code>ol/Overlay</code> is created with the popup container. A listener is registered for the map's <code>click</code> event to display the popup, and another listener is set as the <code>click</code> handler for the close button to hide the popup.
</p> </p>
tags: "overlay, popup" tags: "overlay, popup"
cloak:
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
value: Your Mapbox access token from https://mapbox.com/ here
--- ---
<div id="map" class="map"></div> <div id="map" class="map"></div>
<div id="popup" class="ol-popup"> <div id="popup" class="ol-popup">

View File

@@ -6,6 +6,7 @@ import TileLayer from '../src/ol/layer/Tile.js';
import {toLonLat} from '../src/ol/proj.js'; import {toLonLat} from '../src/ol/proj.js';
import TileJSON from '../src/ol/source/TileJSON.js'; import TileJSON from '../src/ol/source/TileJSON.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
/** /**
* Elements that make up the popup. * Elements that make up the popup.
@@ -45,7 +46,7 @@ const map = new Map({
layers: [ layers: [
new TileLayer({ new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.natural-earth-hypso-bathy.json?secure', url: 'https://api.tiles.mapbox.com/v4/mapbox.natural-earth-hypso-bathy.json?access_token=' + key,
crossOrigin: 'anonymous' crossOrigin: 'anonymous'
}) })
}) })

View File

@@ -8,7 +8,7 @@ const map = new Map({
layers: [ layers: [
new TileLayer({ new TileLayer({
source: new TileJSON({ source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure', url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
crossOrigin: 'anonymous' crossOrigin: 'anonymous'
}) })
}) })

View File

@@ -4,7 +4,7 @@ title: UTFGrid
shortdesc: This example shows how to read data from a UTFGrid source. shortdesc: This example shows how to read data from a UTFGrid source.
docs: > docs: >
<p>Point to a country to see its name and flag.</p> <p>Point to a country to see its name and flag.</p>
Tiles made with [TileMill](http://tilemill.com). Hosting on MapBox.com or with open-source [TileServer](https://github.com/klokantech/tileserver-php/). Tiles made with <a href="http://tilemill.com">TileMill</a>. Hosting on <a href="mapbox.com">mapbox.com</a> or with open-source <a href="https://github.com/klokantech/tileserver-php/">TileServer</a>.
tags: "utfgrid, tilejson" tags: "utfgrid, tilejson"
cloak: cloak:
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q - key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q

View File

@@ -2,14 +2,7 @@ const build = require('../../tasks/serialize-workers').build;
function loader() { function loader() {
const callback = this.async(); const callback = this.async();
const minify = this.mode === 'production';
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}) build(this.resource, {minify})
.then(chunk => { .then(chunk => {

View File

@@ -4,7 +4,7 @@ import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js'; import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js'; import OSM from '../src/ol/source/OSM.js';
import {create as createVersionWorker} from '../src/ol/worker/version'; import {create as createVersionWorker} from '../src/ol/worker/version.js';
const map = new Map({ const map = new Map({

View File

@@ -1,6 +1,6 @@
{ {
"name": "ol", "name": "ol",
"version": "6.0.0-beta.8", "version": "6.0.0-beta.10",
"description": "OpenLayers mapping library", "description": "OpenLayers mapping library",
"keywords": [ "keywords": [
"map", "map",
@@ -54,9 +54,9 @@
"chaikin-smooth": "^1.0.4", "chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0", "clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.3", "copy-webpack-plugin": "^5.0.3",
"coveralls": "3.0.3", "coveralls": "3.0.4",
"eslint": "^5.16.0", "eslint": "^6.0.0",
"eslint-config-openlayers": "^11.0.0", "eslint-config-openlayers": "^12.0.0",
"expect.js": "0.3.1", "expect.js": "0.3.1",
"front-matter": "^3.0.2", "front-matter": "^3.0.2",
"fs-extra": "^8.0.0", "fs-extra": "^8.0.0",
@@ -81,15 +81,15 @@
"marked": "0.6.2", "marked": "0.6.2",
"mocha": "6.1.4", "mocha": "6.1.4",
"ol-mapbox-style": "^5.0.0-beta.2", "ol-mapbox-style": "^5.0.0-beta.2",
"pixelmatch": "^4.0.2", "pixelmatch": "^5.0.0",
"pngjs": "^3.4.0", "pngjs": "^3.4.0",
"proj4": "2.5.0", "proj4": "2.5.0",
"puppeteer": "~1.16.0", "puppeteer": "~1.18.0",
"rollup": "^1.12.0", "rollup": "^1.12.0",
"rollup-plugin-babel": "^4.3.2", "rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^10.0.0", "rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-node-resolve": "^5.0.0", "rollup-plugin-node-resolve": "^5.0.0",
"rollup-plugin-terser": "^4.0.4", "rollup-plugin-terser": "^5.0.0",
"serve-static": "^1.14.0", "serve-static": "^1.14.0",
"shx": "^0.3.2", "shx": "^0.3.2",
"sinon": "^7.3.2", "sinon": "^7.3.2",
@@ -97,7 +97,7 @@
"typescript": "^3.4.5", "typescript": "^3.4.5",
"url-polyfill": "^1.1.5", "url-polyfill": "^1.1.5",
"walk": "^2.3.9", "walk": "^2.3.9",
"webpack": "4.31.0", "webpack": "4.35.0",
"webpack-cli": "^3.3.2", "webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2", "webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1", "webpack-dev-server": "^3.3.1",

View File

@@ -1,10 +1,10 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
import {Heatmap as HeatmapLayer} from '../../../src/ol/layer'; import {Heatmap as HeatmapLayer} from '../../../src/ol/layer.js';
import VectorSource from '../../../src/ol/source/Vector'; import VectorSource from '../../../src/ol/source/Vector.js';
import KML from '../../../src/ol/format/KML'; import KML from '../../../src/ol/format/KML.js';
const vector = new HeatmapLayer({ const vector = new HeatmapLayer({
source: new VectorSource({ source: new VectorSource({

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,30 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import {Group as LayerGroup, Tile as TileLayer} from '../../../src/ol/layer.js';
import XYZ from '../../../src/ol/source/XYZ.js';
new Map({
target: 'map',
view: new View({
center: [0, 0],
zoom: 3
}),
layers: new LayerGroup({
opacity: 0.75,
layers: [
new TileLayer({
opacity: 0.25,
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
})
}),
new TileLayer({
source: new XYZ({
url: '/data/tiles/stamen-labels/{z}/{x}/{y}.png'
})
})
]
})
});
render();

View File

@@ -5,7 +5,7 @@ import {
get as getProjection, get as getProjection,
transform, transform,
transformExtent transformExtent
} from '../../../src/ol/proj'; } from '../../../src/ol/proj.js';
import ImageLayer from '../../../src/ol/layer/Image.js'; import ImageLayer from '../../../src/ol/layer/Image.js';
const center = transform([-122.416667, 37.783333], 'EPSG:4326', 'EPSG:3857'); const center = transform([-122.416667, 37.783333], 'EPSG:4326', 'EPSG:3857');

View File

@@ -5,9 +5,9 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj'; import {fromLonLat} from '../../../src/ol/proj.js';
import {transformExtent} from '../../../src/ol/proj.js'; import {transformExtent} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
const center = fromLonLat([7, 50]); const center = fromLonLat([7, 50]);
const extent = transformExtent([2, 47, 10, 53], 'EPSG:4326', 'EPSG:3857'); const extent = transformExtent([2, 47, 10, 53], 'EPSG:4326', 'EPSG:3857');

View File

@@ -1,7 +1,7 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
import {createXYZ} from '../../../src/ol/tilegrid.js'; import {createXYZ} from '../../../src/ol/tilegrid.js';
const center = [-10997148, 4569099]; const center = [-10997148, 4569099];

View File

@@ -1,8 +1,8 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj'; import {fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
const center = fromLonLat([8.6, 50.1]); const center = fromLonLat([8.6, 50.1]);

View File

@@ -1,8 +1,8 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj'; import {fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
const center = fromLonLat([8.6, 50.1]); const center = fromLonLat([8.6, 50.1]);

View File

@@ -1,8 +1,8 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj'; import {fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
const center = fromLonLat([8.6, 50.1]); const center = fromLonLat([8.6, 50.1]);

View File

@@ -1,8 +1,8 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj'; import {fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
const center = fromLonLat([8.6, 50.1]); const center = fromLonLat([8.6, 50.1]);

View File

@@ -1,9 +1,9 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import VectorTileSource from '../../../src/ol/source/VectorTile'; import VectorTileSource from '../../../src/ol/source/VectorTile.js';
import MVT from '../../../src/ol/format/MVT'; import MVT from '../../../src/ol/format/MVT.js';
import {createXYZ} from '../../../src/ol/tilegrid'; import {createXYZ} from '../../../src/ol/tilegrid.js';
import VectorTileLayer from '../../../src/ol/layer/VectorTile'; import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
const map = new Map({ const map = new Map({
pixelRatio: 2, pixelRatio: 2,

View File

@@ -1,16 +1,16 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import VectorTileSource from '../../../src/ol/source/VectorTile'; import VectorTileSource from '../../../src/ol/source/VectorTile.js';
import MVT from '../../../src/ol/format/MVT'; import MVT from '../../../src/ol/format/MVT.js';
import {createXYZ} from '../../../src/ol/tilegrid'; import {createXYZ} from '../../../src/ol/tilegrid.js';
import VectorTileLayer from '../../../src/ol/layer/VectorTile'; import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
import VectorSource from '../../../src/ol/source/Vector'; import VectorSource from '../../../src/ol/source/Vector.js';
import Feature from '../../../src/ol/Feature'; import Feature from '../../../src/ol/Feature.js';
import Point from '../../../src/ol/geom/Point'; import Point from '../../../src/ol/geom/Point.js';
import VectorLayer from '../../../src/ol/layer/Vector'; import VectorLayer from '../../../src/ol/layer/Vector.js';
import Style from '../../../src/ol/style/Style'; import Style from '../../../src/ol/style/Style.js';
import CircleStyle from '../../../src/ol/style/Circle'; import CircleStyle from '../../../src/ol/style/Circle.js';
import Fill from '../../../src/ol/style/Fill'; import Fill from '../../../src/ol/style/Fill.js';
const vectorSource = new VectorSource({ const vectorSource = new VectorSource({
features: [ features: [

View File

@@ -1,9 +1,9 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import VectorTileSource from '../../../src/ol/source/VectorTile'; import VectorTileSource from '../../../src/ol/source/VectorTile.js';
import MVT from '../../../src/ol/format/MVT'; import MVT from '../../../src/ol/format/MVT.js';
import {createXYZ} from '../../../src/ol/tilegrid'; import {createXYZ} from '../../../src/ol/tilegrid.js';
import VectorTileLayer from '../../../src/ol/layer/VectorTile'; import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
const map = new Map({ const map = new Map({
layers: [ layers: [

View File

@@ -1,9 +1,9 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import VectorTileSource from '../../../src/ol/source/VectorTile'; import VectorTileSource from '../../../src/ol/source/VectorTile.js';
import MVT from '../../../src/ol/format/MVT'; import MVT from '../../../src/ol/format/MVT.js';
import {createXYZ} from '../../../src/ol/tilegrid'; import {createXYZ} from '../../../src/ol/tilegrid.js';
import VectorTileLayer from '../../../src/ol/layer/VectorTile'; import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
new Map({ new Map({
layers: [ layers: [

View File

@@ -9,12 +9,6 @@ import Point from '../../../src/ol/geom/Point.js';
const map = new Map({ const map = new Map({
layers: [ layers: [
new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
maxZoom: 3
})
}),
new VectorLayer({ new VectorLayer({
zIndex: 1, zIndex: 1,
style: new Style({ style: new Style({
@@ -27,6 +21,12 @@ const map = new Map({
url: '/data/countries.json', url: '/data/countries.json',
format: new GeoJSON() format: new GeoJSON()
}) })
}),
new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
maxZoom: 3
})
}) })
], ],
target: 'map', target: 'map',

View File

@@ -1,11 +1,11 @@
import Map from '../../../src/ol/Map.js'; import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js'; import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js'; import TileLayer from '../../../src/ol/layer/Tile.js';
import XYZ from '../../../src/ol/source/XYZ'; import XYZ from '../../../src/ol/source/XYZ.js';
import {Vector as VectorLayer} from '../../../src/ol/layer'; import {Vector as VectorLayer} from '../../../src/ol/layer.js';
import VectorSource from '../../../src/ol/source/Vector'; import VectorSource from '../../../src/ol/source/Vector.js';
import KML from '../../../src/ol/format/KML'; import KML from '../../../src/ol/format/KML.js';
import WebGLPointsLayerRenderer from '../../../src/ol/renderer/webgl/PointsLayer'; import WebGLPointsLayerRenderer from '../../../src/ol/renderer/webgl/PointsLayer.js';
class CustomLayer extends VectorLayer { class CustomLayer extends VectorLayer {
createRenderer() { createRenderer() {

View File

@@ -22,5 +22,16 @@ module.exports = {
context: __dirname, context: __dirname,
target: 'web', target: 'web',
entry: entry, entry: entry,
devtool: 'source-map' devtool: 'source-map',
module: {
rules: [{
test: /\.js$/,
use: {
loader: path.join(__dirname, '../examples/webpack/worker-loader.js')
},
include: [
path.join(__dirname, '../src/ol/worker')
]
}]
}
}; };

View File

@@ -57,10 +57,11 @@ import BaseObject, {getChangeEventType} from './Object.js';
* ``` * ```
* *
* @api * @api
* @template {import("./geom/Geometry.js").default} Geometry
*/ */
class Feature extends BaseObject { class Feature extends BaseObject {
/** /**
* @param {import("./geom/Geometry.js").default|Object<string, *>=} opt_geometryOrProperties * @param {Geometry|Object<string, *>=} opt_geometryOrProperties
* You may pass a Geometry object directly, or an object literal containing * You may pass a Geometry object directly, or an object literal containing
* properties. If you pass an object literal, you may include a Geometry * properties. If you pass an object literal, you may include a Geometry
* associated with a `geometry` key. * associated with a `geometry` key.
@@ -106,7 +107,7 @@ class Feature extends BaseObject {
if (opt_geometryOrProperties) { if (opt_geometryOrProperties) {
if (typeof /** @type {?} */ (opt_geometryOrProperties).getSimplifiedGeometry === 'function') { if (typeof /** @type {?} */ (opt_geometryOrProperties).getSimplifiedGeometry === 'function') {
const geometry = /** @type {import("./geom/Geometry.js").default} */ (opt_geometryOrProperties); const geometry = /** @type {Geometry} */ (opt_geometryOrProperties);
this.setGeometry(geometry); this.setGeometry(geometry);
} else { } else {
/** @type {Object<string, *>} */ /** @type {Object<string, *>} */
@@ -140,13 +141,13 @@ class Feature extends BaseObject {
* Get the feature's default geometry. A feature may have any number of named * Get the feature's default geometry. A feature may have any number of named
* geometries. The "default" geometry (the one that is rendered by default) is * geometries. The "default" geometry (the one that is rendered by default) is
* set when calling {@link module:ol/Feature~Feature#setGeometry}. * set when calling {@link module:ol/Feature~Feature#setGeometry}.
* @return {import("./geom/Geometry.js").default|undefined} The default geometry for the feature. * @return {Geometry|undefined} The default geometry for the feature.
* @api * @api
* @observable * @observable
*/ */
getGeometry() { getGeometry() {
return ( return (
/** @type {import("./geom/Geometry.js").default|undefined} */ (this.get(this.geometryName_)) /** @type {Geometry|undefined} */ (this.get(this.geometryName_))
); );
} }
@@ -218,7 +219,7 @@ class Feature extends BaseObject {
/** /**
* Set the default geometry for the feature. This will update the property * Set the default geometry for the feature. This will update the property
* with the name returned by {@link module:ol/Feature~Feature#getGeometryName}. * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
* @param {import("./geom/Geometry.js").default|undefined} geometry The new geometry. * @param {Geometry|undefined} geometry The new geometry.
* @api * @api
* @observable * @observable
*/ */

View File

@@ -6,6 +6,7 @@ import ImageState from './ImageState.js';
import {listenOnce, unlistenByKey} from './events.js'; import {listenOnce, unlistenByKey} from './events.js';
import EventType from './events/EventType.js'; import EventType from './events/EventType.js';
import {getHeight} from './extent.js'; import {getHeight} from './extent.js';
import {IMAGE_DECODE} from './has.js';
/** /**
@@ -157,7 +158,8 @@ class ImageWrapper extends ImageBase {
*/ */
export function listenImage(image, loadHandler, errorHandler) { export function listenImage(image, loadHandler, errorHandler) {
const img = /** @type {HTMLImageElement} */ (image); const img = /** @type {HTMLImageElement} */ (image);
if (img.decode) {
if (IMAGE_DECODE) {
const promise = img.decode(); const promise = img.decode();
let listening = true; let listening = true;
const unlisten = function() { const unlisten = function() {
@@ -169,7 +171,13 @@ export function listenImage(image, loadHandler, errorHandler) {
} }
}).catch(function(error) { }).catch(function(error) {
if (listening) { if (listening) {
errorHandler(); // FIXME: Unconditionally call errorHandler() when this bug is fixed upstream:
// https://bugs.webkit.org/show_bug.cgi?id=198527
if (error.name === 'EncodingError' && error.message === 'Invalid image type.') {
loadHandler();
} else {
errorHandler();
}
} }
}); });
return unlisten; return unlisten;

View File

@@ -260,12 +260,6 @@ class MapBrowserEventHandler extends EventTarget {
this.dragging_); this.dragging_);
this.dispatchEvent(newEvent); this.dispatchEvent(newEvent);
} }
// Some native android browser triggers mousemove events during small period
// of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
// https://code.google.com/p/android/issues/detail?id=19827
// ex: Galaxy Tab P3110 + Android 4.1.1
pointerEvent.preventDefault();
} }
/** /**

View File

@@ -22,7 +22,7 @@ import {listen, unlistenByKey, unlisten} from './events.js';
import EventType from './events/EventType.js'; import EventType from './events/EventType.js';
import {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js'; import {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';
import {TRUE} from './functions.js'; import {TRUE} from './functions.js';
import {DEVICE_PIXEL_RATIO, TOUCH} from './has.js'; import {DEVICE_PIXEL_RATIO, IMAGE_DECODE} from './has.js';
import LayerGroup from './layer/Group.js'; import LayerGroup from './layer/Group.js';
import {hasArea} from './size.js'; import {hasArea} from './size.js';
import {DROP} from './structs/PriorityQueue.js'; import {DROP} from './structs/PriorityQueue.js';
@@ -39,10 +39,11 @@ import {create as createTransform, apply as applyTransform} from './transform.js
* @property {boolean} animate * @property {boolean} animate
* @property {import("./transform.js").Transform} coordinateToPixelTransform * @property {import("./transform.js").Transform} coordinateToPixelTransform
* @property {null|import("./extent.js").Extent} extent * @property {null|import("./extent.js").Extent} extent
* @property {Array<*>} declutterItems * @property {Array<DeclutterItems>} declutterItems
* @property {import("./coordinate.js").Coordinate} focus * @property {import("./coordinate.js").Coordinate} focus
* @property {number} index * @property {number} index
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray * @property {Array<import("./layer/Layer.js").State>} layerStatesArray
* @property {number} layerIndex
* @property {import("./transform.js").Transform} pixelToCoordinateTransform * @property {import("./transform.js").Transform} pixelToCoordinateTransform
* @property {Array<PostRenderFunction>} postRenderFunctions * @property {Array<PostRenderFunction>} postRenderFunctions
* @property {import("./size.js").Size} size * @property {import("./size.js").Size} size
@@ -54,6 +55,13 @@ import {create as createTransform, apply as applyTransform} from './transform.js
*/ */
/**
* @typedef {Object} DeclutterItems
* @property {Array<*>} items Declutter items of an executor.
* @property {number} opacity Layer opacity.
*/
/** /**
* @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction * @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction
*/ */
@@ -222,7 +230,7 @@ class PluggableMap extends BaseObject {
* @type {!HTMLElement} * @type {!HTMLElement}
*/ */
this.viewport_ = document.createElement('div'); this.viewport_ = document.createElement('div');
this.viewport_.className = 'ol-viewport' + (TOUCH ? ' ol-touch' : ''); this.viewport_.className = 'ol-viewport' + ('ontouchstart' in window ? ' ol-touch' : '');
this.viewport_.style.position = 'relative'; this.viewport_.style.position = 'relative';
this.viewport_.style.overflow = 'hidden'; this.viewport_.style.overflow = 'hidden';
this.viewport_.style.width = '100%'; this.viewport_.style.width = '100%';
@@ -293,6 +301,11 @@ class PluggableMap extends BaseObject {
*/ */
this.interactions = optionsInternal.interactions || new Collection(); this.interactions = optionsInternal.interactions || new Collection();
/**
* @type {import("./events/Target.js").default}
*/
this.labelCache_ = null;
/** /**
* @type {import("./events.js").EventsKey} * @type {import("./events.js").EventsKey}
*/ */
@@ -315,7 +328,7 @@ class PluggableMap extends BaseObject {
* @type {import("./renderer/Map.js").default} * @type {import("./renderer/Map.js").default}
* @private * @private
*/ */
this.renderer_ = this.createRenderer(); this.renderer_ = null;
/** /**
* @type {function(Event): void|undefined} * @type {function(Event): void|undefined}
@@ -503,24 +516,6 @@ class PluggableMap extends BaseObject {
overlay.setMap(this); 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 * @inheritDoc
@@ -534,11 +529,6 @@ class PluggableMap extends BaseObject {
removeEventListener(EventType.RESIZE, this.handleResize_, false); removeEventListener(EventType.RESIZE, this.handleResize_, false);
this.handleResize_ = undefined; this.handleResize_ = undefined;
} }
if (this.animationDelayKey_) {
cancelAnimationFrame(this.animationDelayKey_);
this.animationDelayKey_ = undefined;
}
this.detachLabelCache();
this.setTarget(null); this.setTarget(null);
super.disposeInternal(); super.disposeInternal();
} }
@@ -977,7 +967,7 @@ class PluggableMap extends BaseObject {
if (frameState) { if (frameState) {
const hints = frameState.viewHints; const hints = frameState.viewHints;
if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) { if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) {
const lowOnFrameBudget = Date.now() - frameState.time > 8; const lowOnFrameBudget = !IMAGE_DECODE && Date.now() - frameState.time > 8;
maxTotalLoading = lowOnFrameBudget ? 0 : 8; maxTotalLoading = lowOnFrameBudget ? 0 : 8;
maxNewLoads = lowOnFrameBudget ? 0 : 2; maxNewLoads = lowOnFrameBudget ? 0 : 2;
} }
@@ -1033,6 +1023,14 @@ class PluggableMap extends BaseObject {
} }
if (!targetElement) { if (!targetElement) {
if (this.renderer_) {
this.renderer_.dispose();
this.renderer_ = null;
}
if (this.animationDelayKey_) {
cancelAnimationFrame(this.animationDelayKey_);
this.animationDelayKey_ = undefined;
}
removeNode(this.viewport_); removeNode(this.viewport_);
if (this.handleResize_ !== undefined) { if (this.handleResize_ !== undefined) {
removeEventListener(EventType.RESIZE, this.handleResize_, false); removeEventListener(EventType.RESIZE, this.handleResize_, false);
@@ -1040,6 +1038,9 @@ class PluggableMap extends BaseObject {
} }
} else { } else {
targetElement.appendChild(this.viewport_); targetElement.appendChild(this.viewport_);
if (!this.renderer_) {
this.renderer_ = this.createRenderer();
}
const keyboardEventTarget = !this.keyboardEventTarget_ ? const keyboardEventTarget = !this.keyboardEventTarget_ ?
targetElement : this.keyboardEventTarget_; targetElement : this.keyboardEventTarget_;
@@ -1050,7 +1051,7 @@ class PluggableMap extends BaseObject {
if (!this.handleResize_) { if (!this.handleResize_) {
this.handleResize_ = this.updateSize.bind(this); this.handleResize_ = this.updateSize.bind(this);
addEventListener(EventType.RESIZE, this.handleResize_, false); window.addEventListener(EventType.RESIZE, this.handleResize_, false);
} }
} }
@@ -1158,7 +1159,7 @@ class PluggableMap extends BaseObject {
* @api * @api
*/ */
render() { render() {
if (this.animationDelayKey_ === undefined) { if (this.renderer_ && this.animationDelayKey_ === undefined) {
this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_); this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_);
} }
} }
@@ -1224,13 +1225,14 @@ class PluggableMap extends BaseObject {
if (size !== undefined && hasArea(size) && view && view.isDef()) { if (size !== undefined && hasArea(size) && view && view.isDef()) {
const viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined); const viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);
viewState = view.getState(this.pixelRatio_); viewState = view.getState(this.pixelRatio_);
frameState = /** @type {FrameState} */ ({ frameState = {
animate: false, animate: false,
coordinateToPixelTransform: this.coordinateToPixelTransform_, coordinateToPixelTransform: this.coordinateToPixelTransform_,
declutterItems: previousFrameState ? previousFrameState.declutterItems : [], declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
extent: extent, extent: extent,
focus: this.focus_ ? this.focus_ : viewState.center, focus: this.focus_ ? this.focus_ : viewState.center,
index: this.frameIndex_++, index: this.frameIndex_++,
layerIndex: 0,
layerStatesArray: this.getLayerGroup().getLayerStatesArray(), layerStatesArray: this.getLayerGroup().getLayerStatesArray(),
pixelRatio: this.pixelRatio_, pixelRatio: this.pixelRatio_,
pixelToCoordinateTransform: this.pixelToCoordinateTransform_, pixelToCoordinateTransform: this.pixelToCoordinateTransform_,
@@ -1243,7 +1245,7 @@ class PluggableMap extends BaseObject {
viewState: viewState, viewState: viewState,
viewHints: viewHints, viewHints: viewHints,
wantedTiles: {} wantedTiles: {}
}); };
} }
if (frameState) { if (frameState) {

View File

@@ -21,9 +21,9 @@ import {clamp, modulo} from './math.js';
import {assign} from './obj.js'; import {assign} from './obj.js';
import {createProjection, METERS_PER_UNIT} from './proj.js'; import {createProjection, METERS_PER_UNIT} from './proj.js';
import Units from './proj/Units.js'; import Units from './proj/Units.js';
import {equals} from './coordinate'; import {equals} from './coordinate.js';
import {easeOut} from './easing'; import {easeOut} from './easing.js';
import {createMinMaxResolution} from './resolutionconstraint'; import {createMinMaxResolution} from './resolutionconstraint.js';
/** /**

View File

@@ -51,8 +51,8 @@ class ControlledMap extends PluggableMap {
* @property {boolean} [collapsible=true] Whether the control can be collapsed or not. * @property {boolean} [collapsible=true] Whether the control can be collapsed or not.
* @property {string|HTMLElement} [label='»'] Text label to use for the collapsed * @property {string|HTMLElement} [label='»'] Text label to use for the collapsed
* overviewmap button. Instead of text, also an element (e.g. a `span` element) can be used. * overviewmap button. Instead of text, also an element (e.g. a `span` element) can be used.
* @property {Array<import("../layer/Layer.js").default>|import("../Collection.js").default<import("../layer/Layer.js").default>} layers * @property {Array<import("../layer/Layer.js").default>|import("../Collection.js").default<import("../layer/Layer.js").default>} [layers]
* Layers for the overview map (mandatory). * Layers for the overview map.
* @property {function(import("../MapEvent.js").default)} [render] Function called when the control * @property {function(import("../MapEvent.js").default)} [render] Function called when the control
* should be re-rendered. This is called in a `requestAnimationFrame` callback. * should be re-rendered. This is called in a `requestAnimationFrame` callback.
* @property {HTMLElement|string} [target] Specify a target if you want the control * @property {HTMLElement|string} [target] Specify a target if you want the control
@@ -159,13 +159,9 @@ class OverviewMap extends Control {
const ovmap = this.ovmap_; const ovmap = this.ovmap_;
if (options.layers) { if (options.layers) {
/** @type {Array<import("../layer/Layer.js").default>} */ (options.layers).forEach( options.layers.forEach(function(layer) {
/** ovmap.addLayer(layer);
* @param {import("../layer/Layer.js").default} layer Layer. });
*/
(function(layer) {
ovmap.addLayer(layer);
}).bind(this));
} }
const box = document.createElement('div'); const box = document.createElement('div');

View File

@@ -13,8 +13,10 @@ import {get as getProjection, equivalent as equivalentProjection, transformExten
* the `dataProjection` of the format is assigned (where set). If the projection * the `dataProjection` of the format is assigned (where set). If the projection
* can not be derived from the data and if no `dataProjection` is set for a format, * can not be derived from the data and if no `dataProjection` is set for a format,
* the features will not be reprojected. * the features will not be reprojected.
* @property {import("../extent.js").Extent} [extent] Tile extent of the tile being read. This is only used and * @property {import("../extent.js").Extent} [extent] Tile extent in map units of the tile being read.
* required for {@link module:ol/format/MVT}. * This is only required when reading data with tile pixels as geometry units. When configured,
* a `dataProjection` with `TILE_PIXELS` as `units` and the tile's pixel extent as `extent` needs to be
* provided.
* @property {import("../proj.js").ProjectionLike} [featureProjection] Projection of the feature geometries * @property {import("../proj.js").ProjectionLike} [featureProjection] Projection of the feature geometries
* created by the format reader. If not provided, features will be returned in the * created by the format reader. If not provided, features will be returned in the
* `dataProjection`. * `dataProjection`.
@@ -86,9 +88,14 @@ class FeatureFormat {
getReadOptions(source, opt_options) { getReadOptions(source, opt_options) {
let options; let options;
if (opt_options) { if (opt_options) {
let dataProjection = opt_options.dataProjection ?
opt_options.dataProjection : this.readProjection(source);
if (opt_options.extent) {
dataProjection = getProjection(dataProjection);
dataProjection.setWorldExtent(opt_options.extent);
}
options = { options = {
dataProjection: opt_options.dataProjection ? dataProjection: dataProjection,
opt_options.dataProjection : this.readProjection(source),
featureProjection: opt_options.featureProjection featureProjection: opt_options.featureProjection
}; };
} }

View File

@@ -174,9 +174,8 @@ class Geometry extends BaseObject {
/** /**
* Create a simplified version of this geometry. For linestrings, this uses * Create a simplified version of this geometry. For linestrings, this uses
* the the {@link * the [Douglas Peucker](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)
* https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm * algorithm. For polygons, a quantization-based
* Douglas Peucker} algorithm. For polygons, a quantization-based
* simplification is used to preserve topology. * simplification is used to preserve topology.
* @param {number} tolerance The tolerance distance for simplification. * @param {number} tolerance The tolerance distance for simplification.
* @return {Geometry} A new, simplified version of the original geometry. * @return {Geometry} A new, simplified version of the original geometry.

View File

@@ -39,30 +39,8 @@ export const MAC = ua.indexOf('macintosh') !== -1;
*/ */
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1; export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
/** /**
* True if browser supports touch events. * Image.prototype.decode() is supported.
* @const
* @type {boolean}
* @api
*/
export const TOUCH = 'ontouchstart' in window;
/**
* True if browser supports pointer events.
* @const
* @type {boolean} * @type {boolean}
*/ */
export const POINTER = 'PointerEvent' in window; export const IMAGE_DECODE = typeof Image !== 'undefined' && Image.prototype.decode;
/**
* True if browser supports ms pointer events (IE 10).
* @const
* @type {boolean}
*/
export const MSPOINTER = !!(navigator.msPointerEnabled);
export {HAS as WEBGL} from './webgl.js';

View File

@@ -3,7 +3,7 @@
*/ */
import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js'; import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js';
import {easeOut} from '../easing.js'; import {easeOut} from '../easing.js';
import {noModifierKeys} from '../events/condition.js'; import {noModifierKeys, primaryAction} from '../events/condition.js';
import {FALSE} from '../functions.js'; import {FALSE} from '../functions.js';
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js'; import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
@@ -12,7 +12,7 @@ import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js
* @typedef {Object} Options * @typedef {Object} Options
* @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean * @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
* to indicate whether that event should be handled. * to indicate whether that event should be handled.
* Default is {@link module:ol/events/condition~noModifierKeys}. * Default is {@link module:ol/events/condition~noModifierKeys} and {@link module:ol/events/condition~primaryAction}.
* @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan. * @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
*/ */
@@ -59,7 +59,7 @@ class DragPan extends PointerInteraction {
* @private * @private
* @type {import("../events/condition.js").Condition} * @type {import("../events/condition.js").Condition}
*/ */
this.condition_ = options.condition ? options.condition : noModifierKeys; this.condition_ = options.condition ? options.condition : defaultCondition;
/** /**
* @private * @private
@@ -166,4 +166,12 @@ class DragPan extends PointerInteraction {
} }
} }
/**
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Browser event.
* @return {boolean} Combined condition result.
*/
function defaultCondition(mapBrowserEvent) {
return noModifierKeys(mapBrowserEvent) && primaryAction(mapBrowserEvent);
}
export default DragPan; export default DragPan;

View File

@@ -373,7 +373,7 @@ class Draw extends PointerInteraction {
/** /**
* Sketch point. * Sketch point.
* @type {Feature} * @type {Feature<Point>}
* @private * @private
*/ */
this.sketchPoint_ = null; this.sketchPoint_ = null;
@@ -387,7 +387,7 @@ class Draw extends PointerInteraction {
/** /**
* Sketch line. Used when drawing polygon. * Sketch line. Used when drawing polygon.
* @type {Feature} * @type {Feature<LineString>}
* @private * @private
*/ */
this.sketchLine_ = null; this.sketchLine_ = null;
@@ -669,7 +669,7 @@ class Draw extends PointerInteraction {
this.sketchPoint_ = new Feature(new Point(coordinates)); this.sketchPoint_ = new Feature(new Point(coordinates));
this.updateSketchFeatures_(); this.updateSketchFeatures_();
} else { } else {
const sketchPointGeom = /** @type {Point} */ (this.sketchPoint_.getGeometry()); const sketchPointGeom = this.sketchPoint_.getGeometry();
sketchPointGeom.setCoordinates(coordinates); sketchPointGeom.setCoordinates(coordinates);
} }
} }
@@ -711,7 +711,7 @@ class Draw extends PointerInteraction {
*/ */
modifyDrawing_(event) { modifyDrawing_(event) {
let coordinate = event.coordinate; let coordinate = event.coordinate;
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry()); const geometry = this.sketchFeature_.getGeometry();
let coordinates, last; let coordinates, last;
if (this.mode_ === Mode.POINT) { if (this.mode_ === Mode.POINT) {
last = this.sketchCoords_; last = this.sketchCoords_;
@@ -730,7 +730,7 @@ class Draw extends PointerInteraction {
last[1] = coordinate[1]; last[1] = coordinate[1];
this.geometryFunction_(/** @type {!LineCoordType} */ (this.sketchCoords_), geometry); this.geometryFunction_(/** @type {!LineCoordType} */ (this.sketchCoords_), geometry);
if (this.sketchPoint_) { if (this.sketchPoint_) {
const sketchPointGeom = /** @type {Point} */ (this.sketchPoint_.getGeometry()); const sketchPointGeom = this.sketchPoint_.getGeometry();
sketchPointGeom.setCoordinates(coordinate); sketchPointGeom.setCoordinates(coordinate);
} }
/** @type {LineString} */ /** @type {LineString} */
@@ -740,8 +740,8 @@ class Draw extends PointerInteraction {
if (!this.sketchLine_) { if (!this.sketchLine_) {
this.sketchLine_ = new Feature(); this.sketchLine_ = new Feature();
} }
const ring = /** @type {Polygon} */ (geometry).getLinearRing(0); const ring = geometry.getLinearRing(0);
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry()); sketchLineGeom = this.sketchLine_.getGeometry();
if (!sketchLineGeom) { if (!sketchLineGeom) {
sketchLineGeom = new LineString(ring.getFlatCoordinates(), ring.getLayout()); sketchLineGeom = new LineString(ring.getFlatCoordinates(), ring.getLayout());
this.sketchLine_.setGeometry(sketchLineGeom); this.sketchLine_.setGeometry(sketchLineGeom);
@@ -751,7 +751,7 @@ class Draw extends PointerInteraction {
sketchLineGeom.changed(); sketchLineGeom.changed();
} }
} else if (this.sketchLineCoords_) { } else if (this.sketchLineCoords_) {
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry()); sketchLineGeom = this.sketchLine_.getGeometry();
sketchLineGeom.setCoordinates(this.sketchLineCoords_); sketchLineGeom.setCoordinates(this.sketchLineCoords_);
} }
this.updateSketchFeatures_(); this.updateSketchFeatures_();
@@ -764,7 +764,7 @@ class Draw extends PointerInteraction {
*/ */
addToDrawing_(event) { addToDrawing_(event) {
const coordinate = event.coordinate; const coordinate = event.coordinate;
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry()); const geometry = this.sketchFeature_.getGeometry();
let done; let done;
let coordinates; let coordinates;
if (this.mode_ === Mode.LINE_STRING) { if (this.mode_ === Mode.LINE_STRING) {
@@ -808,7 +808,7 @@ class Draw extends PointerInteraction {
if (!this.sketchFeature_) { if (!this.sketchFeature_) {
return; return;
} }
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry()); const geometry = this.sketchFeature_.getGeometry();
let coordinates; let coordinates;
/** @type {LineString} */ /** @type {LineString} */
let sketchLineGeom; let sketchLineGeom;
@@ -822,7 +822,7 @@ class Draw extends PointerInteraction {
} else if (this.mode_ === Mode.POLYGON) { } else if (this.mode_ === Mode.POLYGON) {
coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0]; coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0];
coordinates.splice(-2, 1); coordinates.splice(-2, 1);
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry()); sketchLineGeom = this.sketchLine_.getGeometry();
sketchLineGeom.setCoordinates(coordinates); sketchLineGeom.setCoordinates(coordinates);
this.geometryFunction_(this.sketchCoords_, geometry); this.geometryFunction_(this.sketchCoords_, geometry);
} }
@@ -846,7 +846,7 @@ class Draw extends PointerInteraction {
return; return;
} }
let coordinates = this.sketchCoords_; let coordinates = this.sketchCoords_;
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (sketchFeature.getGeometry()); const geometry = sketchFeature.getGeometry();
if (this.mode_ === Mode.LINE_STRING) { if (this.mode_ === Mode.LINE_STRING) {
// remove the redundant last point // remove the redundant last point
coordinates.pop(); coordinates.pop();
@@ -900,12 +900,12 @@ class Draw extends PointerInteraction {
* Extend an existing geometry by adding additional points. This only works * Extend an existing geometry by adding additional points. This only works
* on features with `LineString` geometries, where the interaction will * on features with `LineString` geometries, where the interaction will
* extend lines by adding points to the end of the coordinates array. * extend lines by adding points to the end of the coordinates array.
* @param {!Feature} feature Feature to be extended. * @param {!Feature<LineString>} feature Feature to be extended.
* @api * @api
*/ */
extend(feature) { extend(feature) {
const geometry = feature.getGeometry(); const geometry = feature.getGeometry();
const lineString = /** @type {LineString} */ (geometry); const lineString = geometry;
this.sketchFeature_ = feature; this.sketchFeature_ = feature;
this.sketchCoords_ = lineString.getCoordinates(); this.sketchCoords_ = lineString.getCoordinates();
const last = this.sketchCoords_[this.sketchCoords_.length - 1]; const last = this.sketchCoords_[this.sketchCoords_.length - 1];

View File

@@ -126,7 +126,7 @@ class Extent extends PointerInteraction {
/** /**
* Feature for displaying the visible pointer * Feature for displaying the visible pointer
* @type {Feature} * @type {Feature<Point>}
* @private * @private
*/ */
this.vertexFeature_ = null; this.vertexFeature_ = null;
@@ -265,7 +265,7 @@ class Extent extends PointerInteraction {
this.vertexFeature_ = vertexFeature; this.vertexFeature_ = vertexFeature;
this.vertexOverlay_.getSource().addFeature(vertexFeature); this.vertexOverlay_.getSource().addFeature(vertexFeature);
} else { } else {
const geometry = /** @type {Point} */ (vertexFeature.getGeometry()); const geometry = vertexFeature.getGeometry();
geometry.setCoordinates(vertex); geometry.setCoordinates(vertex);
} }
return vertexFeature; return vertexFeature;

View File

@@ -660,7 +660,7 @@ class Modify extends PointerInteraction {
this.vertexFeature_ = vertexFeature; this.vertexFeature_ = vertexFeature;
this.overlay_.getSource().addFeature(vertexFeature); this.overlay_.getSource().addFeature(vertexFeature);
} else { } else {
const geometry = /** @type {Point} */ (vertexFeature.getGeometry()); const geometry = vertexFeature.getGeometry();
geometry.setCoordinates(coordinates); geometry.setCoordinates(coordinates);
} }
return vertexFeature; return vertexFeature;
@@ -785,7 +785,7 @@ class Modify extends PointerInteraction {
const vertexFeature = this.vertexFeature_; const vertexFeature = this.vertexFeature_;
if (vertexFeature) { if (vertexFeature) {
const insertVertices = []; const insertVertices = [];
const geometry = /** @type {Point} */ (vertexFeature.getGeometry()); const geometry = vertexFeature.getGeometry();
const vertex = geometry.getCoordinates(); const vertex = geometry.getCoordinates();
const vertexExtent = boundingExtent([vertex]); const vertexExtent = boundingExtent([vertex]);
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent); const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);

View File

@@ -35,6 +35,13 @@ const TranslateEventType = {
TRANSLATEEND: 'translateend' TRANSLATEEND: 'translateend'
}; };
/**
* A function that takes an {@link module:ol/Feature} or
* {@link module:ol/render/Feature} and an
* {@link module:ol/layer/Layer} and returns `true` if the feature may be
* translated or `false` otherwise.
* @typedef {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default):boolean} FilterFunction
*/
/** /**
* @typedef {Object} Options * @typedef {Object} Options
@@ -45,6 +52,10 @@ const TranslateEventType = {
* function will be called for each layer in the map and should return * function will be called for each layer in the map and should return
* `true` for layers that you want to be translatable. If the option is * `true` for layers that you want to be translatable. If the option is
* absent, all visible layers will be considered translatable. * absent, all visible layers will be considered translatable.
* @property {FilterFunction} [filter] A function
* that takes an {@link module:ol/Feature} and an
* {@link module:ol/layer/Layer} and returns `true` if the feature may be
* translated or `false` otherwise.
* @property {number} [hitTolerance=0] Hit-detection tolerance. Pixels inside the radius around the given position * @property {number} [hitTolerance=0] Hit-detection tolerance. Pixels inside the radius around the given position
* will be checked for features. * will be checked for features.
*/ */
@@ -136,6 +147,12 @@ class Translate extends PointerInteraction {
*/ */
this.layerFilter_ = layerFilter; this.layerFilter_ = layerFilter;
/**
* @private
* @type {FilterFunction}
*/
this.filter_ = options.filter ? options.filter : TRUE;
/** /**
* @private * @private
* @type {number} * @type {number}
@@ -245,9 +262,11 @@ class Translate extends PointerInteraction {
*/ */
featuresAtPixel_(pixel, map) { featuresAtPixel_(pixel, map) {
return map.forEachFeatureAtPixel(pixel, return map.forEachFeatureAtPixel(pixel,
function(feature) { function(feature, layer) {
if (!this.features_ || includes(this.features_.getArray(), feature)) { if (this.filter_(feature, layer)) {
return feature; if (!this.features_ || includes(this.features_.getArray(), feature)) {
return feature;
}
} }
}.bind(this), { }.bind(this), {
layerFilter: this.layerFilter_, layerFilter: this.layerFilter_,

View File

@@ -83,6 +83,9 @@ class BaseLayer extends BaseObject {
} }
/** /**
* This method is not meant to be called by layers or layer renderers because the state
* is incorrect if the layer is included in a layer group.
*
* @param {boolean=} opt_managed Layer is managed. * @param {boolean=} opt_managed Layer is managed.
* @return {import("./Layer.js").State} Layer state. * @return {import("./Layer.js").State} Layer state.
*/ */
@@ -90,7 +93,8 @@ class BaseLayer extends BaseObject {
/** @type {import("./Layer.js").State} */ /** @type {import("./Layer.js").State} */
const state = this.state_ || /** @type {?} */ ({ const state = this.state_ || /** @type {?} */ ({
layer: this, layer: this,
managed: opt_managed === undefined ? true : opt_managed managed: opt_managed === undefined ? true : opt_managed,
hasOverlay: false
}); });
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1); state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
state.sourceState = this.getSourceState(); state.sourceState = this.getSourceState();

View File

@@ -72,8 +72,7 @@ class BaseVectorLayer extends Layer {
* @param {Options=} opt_options Options. * @param {Options=} opt_options Options.
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options ? const options = opt_options ? opt_options : {};
opt_options : /** @type {Options} */ ({});
const baseOptions = assign({}, options); const baseOptions = assign({}, options);

View File

@@ -3,27 +3,27 @@
*/ */
import VectorLayer from './Vector.js'; import VectorLayer from './Vector.js';
import {assign} from '../obj.js'; import {assign} from '../obj.js';
import {degreesToStringHDMS} from '../coordinate'; import {degreesToStringHDMS} from '../coordinate.js';
import Text from '../style/Text'; import Text from '../style/Text.js';
import Fill from '../style/Fill'; import Fill from '../style/Fill.js';
import Stroke from '../style/Stroke'; import Stroke from '../style/Stroke.js';
import LineString from '../geom/LineString.js'; import LineString from '../geom/LineString.js';
import VectorSource from '../source/Vector'; import VectorSource from '../source/Vector.js';
import { import {
equivalent as equivalentProjection, equivalent as equivalentProjection,
get as getProjection, get as getProjection,
getTransform, getTransform,
transformExtent transformExtent
} from '../proj'; } from '../proj.js';
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent'; import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent.js';
import {clamp} from '../math'; import {clamp} from '../math.js';
import Style from '../style/Style'; import Style from '../style/Style.js';
import Feature from '../Feature'; import Feature from '../Feature.js';
import {bbox} from '../loadingstrategy'; import {bbox} from '../loadingstrategy.js';
import {meridian, parallel} from '../geom/flat/geodesic'; import {meridian, parallel} from '../geom/flat/geodesic.js';
import GeometryLayout from '../geom/GeometryLayout'; import GeometryLayout from '../geom/GeometryLayout.js';
import Point from '../geom/Point'; import Point from '../geom/Point.js';
import Collection from '../Collection'; import Collection from '../Collection.js';
/** /**

View File

@@ -6,7 +6,7 @@ import {getChangeEventType} from '../Object.js';
import {createCanvasContext2D} from '../dom.js'; import {createCanvasContext2D} from '../dom.js';
import VectorLayer from './Vector.js'; import VectorLayer from './Vector.js';
import {assign} from '../obj.js'; import {assign} from '../obj.js';
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer'; import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
/** /**

View File

@@ -45,6 +45,7 @@ import SourceState from '../source/State.js';
* @property {SourceState} sourceState * @property {SourceState} sourceState
* @property {boolean} visible * @property {boolean} visible
* @property {boolean} managed * @property {boolean} managed
* @property {boolean} hasOverlay Set by the renderer when an overlay for points and text is used.
* @property {import("../extent.js").Extent} [extent] * @property {import("../extent.js").Extent} [extent]
* @property {number} zIndex * @property {number} zIndex
* @property {number} maxResolution * @property {number} maxResolution
@@ -189,13 +190,15 @@ class Layer extends BaseLayer {
* In charge to manage the rendering of the layer. One layer type is * In charge to manage the rendering of the layer. One layer type is
* bounded with one layer renderer. * bounded with one layer renderer.
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state. * @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {HTMLElement} target Target which the renderer may (but need not) use
* for rendering its content.
* @return {HTMLElement} The rendered element. * @return {HTMLElement} The rendered element.
*/ */
render(frameState) { render(frameState, target) {
const layerRenderer = this.getRenderer(); const layerRenderer = this.getRenderer();
const layerState = this.getLayerState();
if (layerRenderer.prepareFrame(frameState, layerState)) { if (layerRenderer.prepareFrame(frameState)) {
return layerRenderer.renderFrame(frameState, layerState); return layerRenderer.renderFrame(frameState, target);
} }
} }

View File

@@ -5,11 +5,6 @@ import BaseTileLayer from './BaseTile.js';
import CanvasTileLayerRenderer from '../renderer/canvas/TileLayer.js'; import CanvasTileLayerRenderer from '../renderer/canvas/TileLayer.js';
/**
* @typedef {import("./BaseTile.js").Options} Options
*/
/** /**
* @classdesc * @classdesc
* For layer sources that provide pre-rendered, tiled images in grids that are * For layer sources that provide pre-rendered, tiled images in grids that are
@@ -23,7 +18,7 @@ import CanvasTileLayerRenderer from '../renderer/canvas/TileLayer.js';
class TileLayer extends BaseTileLayer { class TileLayer extends BaseTileLayer {
/** /**
* @param {Options=} opt_options Tile layer options. * @param {import("./BaseTile.js").Options=} opt_options Tile layer options.
*/ */
constructor(opt_options) { constructor(opt_options) {
super(opt_options); super(opt_options);

View File

@@ -5,11 +5,6 @@ import BaseVectorLayer from './BaseVector.js';
import CanvasVectorLayerRenderer from '../renderer/canvas/VectorLayer.js'; import CanvasVectorLayerRenderer from '../renderer/canvas/VectorLayer.js';
/**
* @typedef {import("./BaseVector.js").Options} Options
*/
/** /**
* @classdesc * @classdesc
* Vector data that is rendered client-side. * Vector data that is rendered client-side.
@@ -22,7 +17,7 @@ import CanvasVectorLayerRenderer from '../renderer/canvas/VectorLayer.js';
*/ */
class VectorLayer extends BaseVectorLayer { class VectorLayer extends BaseVectorLayer {
/** /**
* @param {Options=} opt_options Options. * @param {import("./BaseVector.js").Options=} opt_options Options.
*/ */
constructor(opt_options) { constructor(opt_options) {
super(opt_options); super(opt_options);

View File

@@ -60,7 +60,7 @@ class VectorImageLayer extends BaseVectorLayer {
* @param {Options=} opt_options Options. * @param {Options=} opt_options Options.
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options ? opt_options : /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
const baseOptions = assign({}, options); const baseOptions = assign({}, options);
delete baseOptions.imageRatio; delete baseOptions.imageRatio;

View File

@@ -86,12 +86,12 @@ class VectorTileLayer extends BaseVectorLayer {
delete baseOptions.preload; delete baseOptions.preload;
delete baseOptions.useInterimTilesOnError; delete baseOptions.useInterimTilesOnError;
super(/** @type {import("./Vector.js").Options} */ (baseOptions)); super(/** @type {import("./BaseVector.js").Options} */ (baseOptions));
const renderMode = options.renderMode || VectorTileRenderType.HYBRID; const renderMode = options.renderMode || VectorTileRenderType.HYBRID;
assert(renderMode == undefined || assert(renderMode == undefined ||
renderMode == VectorTileRenderType.IMAGE || renderMode == VectorTileRenderType.IMAGE ||
renderMode == VectorTileRenderType.HYBRID, renderMode == VectorTileRenderType.HYBRID,
28); // `renderMode` must be `'image'` or `'hybrid'` 28); // `renderMode` must be `'image'` or `'hybrid'`
/** /**

View File

@@ -63,10 +63,6 @@
border: 1px solid black; border: 1px solid black;
} }
.ol-overlay-container {
will-change: left,right,top,bottom;
}
.ol-unsupported { .ol-unsupported {
display: none; display: none;
} }

View File

@@ -34,7 +34,6 @@
import {listen, unlisten} from '../events.js'; import {listen, unlisten} from '../events.js';
import EventTarget from '../events/Target.js'; import EventTarget from '../events/Target.js';
import {POINTER, MSPOINTER, TOUCH} from '../has.js';
import PointerEventType from './EventType.js'; import PointerEventType from './EventType.js';
import MouseSource, {prepareEvent as prepareMouseEvent} from './MouseSource.js'; import MouseSource, {prepareEvent as prepareMouseEvent} from './MouseSource.js';
import MsSource from './MsSource.js'; import MsSource from './MsSource.js';
@@ -124,15 +123,15 @@ class PointerEventHandler extends EventTarget {
* that generate pointer events. * that generate pointer events.
*/ */
registerSources() { registerSources() {
if (POINTER) { if ('PointerEvent' in window) {
this.registerSource('native', new NativeSource(this)); this.registerSource('native', new NativeSource(this));
} else if (MSPOINTER) { } else if (window.navigator.msPointerEnabled) {
this.registerSource('ms', new MsSource(this)); this.registerSource('ms', new MsSource(this));
} else { } else {
const mouseSource = new MouseSource(this); const mouseSource = new MouseSource(this);
this.registerSource('mouse', mouseSource); this.registerSource('mouse', mouseSource);
if (TOUCH) { if ('ontouchstart' in window) {
this.registerSource('touch', new TouchSource(this, mouseSource)); this.registerSource('touch', new TouchSource(this, mouseSource));
} }
} }

View File

@@ -60,8 +60,8 @@ import {toEPSG4326, fromEPSG4326, PROJECTIONS as EPSG3857_PROJECTIONS} from './p
import {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js'; import {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js';
import Projection from './proj/Projection.js'; import Projection from './proj/Projection.js';
import Units, {METERS_PER_UNIT} from './proj/Units.js'; import Units, {METERS_PER_UNIT} from './proj/Units.js';
import * as projections from './proj/projections.js';
import {add as addTransformFunc, clear as clearTransformFuncs, get as getTransformFunc} from './proj/transforms.js'; import {add as addTransformFunc, clear as clearTransformFuncs, get as getTransformFunc} from './proj/transforms.js';
import {add as addProj, clear as clearProj, get as getProj} from './proj/projections.js';
/** /**
@@ -133,7 +133,7 @@ export function identityTransform(input, opt_output, opt_dimension) {
* @api * @api
*/ */
export function addProjection(projection) { export function addProjection(projection) {
projections.add(projection.getCode(), projection); addProj(projection.getCode(), projection);
addTransformFunc(projection, projection, cloneTransform); addTransformFunc(projection, projection, cloneTransform);
} }
@@ -157,7 +157,7 @@ export function addProjections(projections) {
*/ */
export function get(projectionLike) { export function get(projectionLike) {
return typeof projectionLike === 'string' ? return typeof projectionLike === 'string' ?
projections.get(/** @type {string} */ (projectionLike)) : getProj(/** @type {string} */ (projectionLike)) :
(/** @type {Projection} */ (projectionLike) || null); (/** @type {Projection} */ (projectionLike) || null);
} }
@@ -271,7 +271,7 @@ export function addEquivalentTransforms(projections1, projections2, forwardTrans
* Clear all cached projections and transforms. * Clear all cached projections and transforms.
*/ */
export function clearAllProjections() { export function clearAllProjections() {
projections.clear(); clearProj();
clearTransformFuncs(); clearTransformFuncs();
} }

View File

@@ -122,9 +122,10 @@ export function renderDeclutterItems(frameState, declutterTree) {
} }
const items = frameState.declutterItems; const items = frameState.declutterItems;
for (let z = items.length - 1; z >= 0; --z) { for (let z = items.length - 1; z >= 0; --z) {
const zIndexItems = items[z]; const item = items[z];
const zIndexItems = item.items;
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) { for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree); declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], item.opacity, declutterTree);
} }
} }
items.length = 0; items.length = 0;

View File

@@ -12,9 +12,8 @@ class RenderEvent extends Event {
* CSS pixels to rendered pixels. * CSS pixels to rendered pixels.
* @param {import("../PluggableMap.js").FrameState=} opt_frameState Frame state. * @param {import("../PluggableMap.js").FrameState=} opt_frameState Frame state.
* @param {?CanvasRenderingContext2D=} opt_context Context. * @param {?CanvasRenderingContext2D=} opt_context Context.
* @param {?import("../webgl/Helper.js").default=} opt_glContext WebGL Context.
*/ */
constructor(type, opt_inversePixelTransform, opt_frameState, opt_context, opt_glContext) { constructor(type, opt_inversePixelTransform, opt_frameState, opt_context) {
super(type); super(type);
@@ -41,14 +40,6 @@ class RenderEvent extends Event {
*/ */
this.context = opt_context; this.context = opt_context;
/**
* WebGL context. Only available when a WebGL renderer is used, null
* otherwise.
* @type {import("../webgl/Helper.js").default|null|undefined}
* @api
*/
this.glContext = opt_glContext;
} }
} }

View File

@@ -403,7 +403,7 @@ export function drawImage(context,
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale); context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
if (alpha) { if (opacity != 1) {
context.globalAlpha = alpha; context.globalAlpha = alpha;
} }
if (transform) { if (transform) {

View File

@@ -362,10 +362,12 @@ class Executor extends Disposable {
const declutterArgs = intersects ? const declutterArgs = intersects ?
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] : [context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
null; null;
if (declutterArgs && fillStroke) { if (declutterArgs) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4); if (fillStroke) {
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
}
declutterGroup.push(declutterArgs);
} }
declutterGroup.push(declutterArgs);
} else if (intersects) { } else if (intersects) {
if (fillStroke) { if (fillStroke) {
this.replayTextBackground_(context, p1, p2, p3, p4, this.replayTextBackground_(context, p1, p2, p3, p4,
@@ -414,10 +416,11 @@ class Executor extends Disposable {
/** /**
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group. * @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {import("../../Feature.js").FeatureLike} feature Feature. * @param {import("../../Feature.js").FeatureLike} feature Feature.
* @param {number} opacity Layer opacity.
* @param {?} declutterTree Declutter tree. * @param {?} declutterTree Declutter tree.
* @return {?} Declutter tree. * @return {?} Declutter tree.
*/ */
renderDeclutter(declutterGroup, feature, declutterTree) { renderDeclutter(declutterGroup, feature, opacity, declutterTree) {
if (declutterGroup && declutterGroup.length > 5) { if (declutterGroup && declutterGroup.length > 5) {
const groupCount = declutterGroup[4]; const groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) { if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
@@ -436,13 +439,19 @@ class Executor extends Disposable {
declutterTree.insert(box); declutterTree.insert(box);
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) { for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
const declutterData = /** @type {Array} */ (declutterGroup[j]); const declutterData = /** @type {Array} */ (declutterGroup[j]);
if (declutterData) { const context = declutterData[0];
if (declutterData.length > 11) { const currentAlpha = context.globalAlpha;
this.replayTextBackground_(declutterData[0], if (currentAlpha !== opacity) {
declutterData[13], declutterData[14], declutterData[15], declutterData[16], context.globalAlpha = opacity;
declutterData[11], declutterData[12]); }
} if (declutterData.length > 11) {
drawImage.apply(undefined, declutterData); this.replayTextBackground_(declutterData[0],
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
declutterData[11], declutterData[12]);
}
drawImage.apply(undefined, declutterData);
if (currentAlpha !== opacity) {
context.globalAlpha = currentAlpha;
} }
} }
} }

View File

@@ -430,10 +430,11 @@ export function getCircleArray(radius) {
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays. * @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
* @param {CanvasRenderingContext2D} context Context. * @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation. * @param {number} rotation Rotation.
* @param {number} opacity Opacity.
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels. * @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
* @param {Array<Array<*>>} declutterItems Declutter items. * @param {Array<import("../../PluggableMap.js").DeclutterItems>} declutterItems Declutter items.
*/ */
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) { export function replayDeclutter(declutterReplays, context, rotation, opacity, snapToPixel, declutterItems) {
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction); const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
const skippedFeatureUids = {}; const skippedFeatureUids = {};
for (let z = 0, zz = zs.length; z < zz; ++z) { for (let z = 0, zz = zs.length; z < zz; ++z) {
@@ -443,7 +444,10 @@ export function replayDeclutter(declutterReplays, context, rotation, snapToPixel
const executor = executorData[i++]; const executor = executorData[i++];
if (executor !== currentExecutor) { if (executor !== currentExecutor) {
currentExecutor = executor; currentExecutor = executor;
declutterItems.push(executor.declutterItems); declutterItems.push({
items: executor.declutterItems,
opacity: opacity
});
} }
const transform = executorData[i++]; const transform = executorData[i++];
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel); executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);

View File

@@ -9,6 +9,8 @@ import MapRenderer from './Map.js';
import SourceState from '../source/State.js'; import SourceState from '../source/State.js';
import {replaceChildren} from '../dom.js'; import {replaceChildren} from '../dom.js';
import {labelCache} from '../render/canvas.js'; import {labelCache} from '../render/canvas.js';
import EventType from '../events/EventType.js';
import {listen, unlistenByKey} from '../events.js';
/** /**
@@ -23,7 +25,11 @@ class CompositeMapRenderer extends MapRenderer {
*/ */
constructor(map) { constructor(map) {
super(map); super(map);
map.attachLabelCache(labelCache);
/**
* @type {import("../events.js").EventsKey}
*/
this.labelCacheKey_ = listen(labelCache, EventType.CLEAR, map.redrawText.bind(map));
/** /**
* @private * @private
@@ -66,6 +72,11 @@ class CompositeMapRenderer extends MapRenderer {
} }
} }
disposeInternal() {
unlistenByKey(this.labelCacheKey_);
super.disposeInternal();
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -81,25 +92,35 @@ class CompositeMapRenderer extends MapRenderer {
this.calculateMatrices2D(frameState); this.calculateMatrices2D(frameState);
this.dispatchRenderEvent(RenderEventType.PRECOMPOSE, frameState); this.dispatchRenderEvent(RenderEventType.PRECOMPOSE, frameState);
const layerStatesArray = frameState.layerStatesArray; const layerStatesArray = frameState.layerStatesArray.sort(function(a, b) {
return a.zIndex - b.zIndex;
});
const viewResolution = frameState.viewState.resolution; const viewResolution = frameState.viewState.resolution;
this.children_.length = 0; this.children_.length = 0;
let hasOverlay = false;
let previousElement = null;
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
const layerState = layerStatesArray[i]; const layerState = layerStatesArray[i];
hasOverlay = hasOverlay || layerState.hasOverlay;
frameState.layerIndex = i;
if (!visibleAtResolution(layerState, viewResolution) || if (!visibleAtResolution(layerState, viewResolution) ||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) { (layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
continue; continue;
} }
const layer = layerState.layer; const layer = layerState.layer;
const element = layer.render(frameState); const element = layer.render(frameState, previousElement);
if (element) { if (!element) {
const zIndex = layerState.zIndex; continue;
if (zIndex !== element.style.zIndex) { }
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex; if ((element !== previousElement || i == ii - 1) && element.childElementCount === 2 && !hasOverlay) {
} element.removeChild(element.lastElementChild);
}
if (element !== previousElement) {
this.children_.push(element); this.children_.push(element);
hasOverlay = false;
previousElement = element;
} }
} }
super.renderFrame(frameState); super.renderFrame(frameState);

View File

@@ -29,10 +29,9 @@ class LayerRenderer extends Observable {
* Determine whether render should be called. * Determine whether render should be called.
* @abstract * @abstract
* @param {import("../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {import("../layer/Layer.js").State} layerState Layer state.
* @return {boolean} Layer is ready to be rendered. * @return {boolean} Layer is ready to be rendered.
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
return abstract(); return abstract();
} }
@@ -40,10 +39,10 @@ class LayerRenderer extends Observable {
* Render the layer. * Render the layer.
* @abstract * @abstract
* @param {import("../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {import("../layer/Layer.js").State} layerState Layer state. * @param {HTMLElement} target Target that may be used to render content to.
* @return {HTMLElement} The rendered element. * @return {HTMLElement} The rendered element.
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState, target) {
return abstract(); return abstract();
} }

View File

@@ -38,7 +38,8 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
const layerState = frameState.layerStatesArray[frameState.layerIndex];
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
const viewState = frameState.viewState; const viewState = frameState.viewState;
const viewResolution = viewState.resolution; const viewResolution = viewState.resolution;
@@ -72,11 +73,12 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState, target) {
const image = this.image_; const image = this.image_;
const imageExtent = image.getExtent(); const imageExtent = image.getExtent();
const imageResolution = image.getResolution(); const imageResolution = image.getResolution();
const imagePixelRatio = image.getPixelRatio(); const imagePixelRatio = image.getPixelRatio();
const layerState = frameState.layerStatesArray[frameState.layerIndex];
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
const viewState = frameState.viewState; const viewState = frameState.viewState;
const viewCenter = viewState.center; const viewCenter = viewState.center;
@@ -93,13 +95,15 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
} }
// set forward and inverse pixel transforms // set forward and inverse pixel transforms
composeTransform(this.pixelTransform_, composeTransform(this.pixelTransform,
frameState.size[0] / 2, frameState.size[1] / 2, frameState.size[0] / 2, frameState.size[1] / 2,
1 / pixelRatio, 1 / pixelRatio, 1 / pixelRatio, 1 / pixelRatio,
rotation, rotation,
-width / 2, -height / 2 -width / 2, -height / 2
); );
makeInverse(this.inversePixelTransform_, this.pixelTransform_); makeInverse(this.inversePixelTransform, this.pixelTransform);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const context = this.context; const context = this.context;
const canvas = context.canvas; const canvas = context.canvas;
@@ -107,7 +111,7 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
if (canvas.width != width || canvas.height != height) { if (canvas.width != width || canvas.height != height) {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
} else { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
@@ -138,8 +142,17 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
this.preRender(context, frameState); this.preRender(context, frameState);
if (dw >= 0.5 && dh >= 0.5) { if (dw >= 0.5 && dh >= 0.5) {
const opacity = layerState.opacity;
let previousAlpha;
if (opacity !== 1) {
previousAlpha = this.context.globalAlpha;
this.context.globalAlpha = opacity;
}
this.context.drawImage(img, 0, 0, +img.width, +img.height, this.context.drawImage(img, 0, 0, +img.width, +img.height,
Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh)); Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
if (opacity !== 1) {
this.context.globalAlpha = previousAlpha;
}
} }
this.postRender(context, frameState); this.postRender(context, frameState);
@@ -147,17 +160,12 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
context.restore(); context.restore();
} }
const opacity = layerState.opacity; const canvasTransform = transformToString(this.pixelTransform);
if (opacity !== parseFloat(canvas.style.opacity)) {
canvas.style.opacity = opacity;
}
const canvasTransform = transformToString(this.pixelTransform_);
if (canvasTransform !== canvas.style.transform) { if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
return canvas; return this.container;
} }

View File

@@ -7,7 +7,7 @@ import RenderEvent from '../../render/Event.js';
import RenderEventType from '../../render/EventType.js'; import RenderEventType from '../../render/EventType.js';
import {rotateAtOffset} from '../../render/canvas.js'; import {rotateAtOffset} from '../../render/canvas.js';
import LayerRenderer from '../Layer.js'; import LayerRenderer from '../Layer.js';
import {create as createTransform, apply as applyTransform, compose as composeTransform} from '../../transform.js'; import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
/** /**
* @abstract * @abstract
@@ -21,6 +21,12 @@ class CanvasLayerRenderer extends LayerRenderer {
super(layer); super(layer);
/**
* @protected
* @type {HTMLElement}
*/
this.container = null;
/** /**
* @protected * @protected
* @type {number} * @type {number}
@@ -38,37 +44,74 @@ class CanvasLayerRenderer extends LayerRenderer {
/** /**
* The transform for rendered pixels to viewport CSS pixels. This transform must * The transform for rendered pixels to viewport CSS pixels. This transform must
* be set when rendering a frame and may be used by other functions after rendering. * be set when rendering a frame and may be used by other functions after rendering.
* @private * @protected
* @type {import("../../transform.js").Transform} * @type {import("../../transform.js").Transform}
*/ */
this.pixelTransform_ = createTransform(); this.pixelTransform = createTransform();
/** /**
* The transform for viewport CSS pixels to rendered pixels. This transform must * The transform for viewport CSS pixels to rendered pixels. This transform must
* be set when rendering a frame and may be used by other functions after rendering. * be set when rendering a frame and may be used by other functions after rendering.
* @private * @protected
* @type {import("../../transform.js").Transform} * @type {import("../../transform.js").Transform}
*/ */
this.inversePixelTransform_ = createTransform(); this.inversePixelTransform = createTransform();
/** /**
* @protected * @protected
* @type {CanvasRenderingContext2D} * @type {CanvasRenderingContext2D}
*/ */
this.context = createCanvasContext2D(); this.context = null;
/**
* @type {boolean}
*/
this.containerReused = false;
const canvas = this.context.canvas;
canvas.style.position = 'absolute';
canvas.style.transformOrigin = 'top left';
canvas.className = this.getLayer().getClassName();
} }
/** /**
* @inheritDoc * Get a rendering container from an existing target, if compatible.
* @param {HTMLElement} target Potential render target.
* @param {import("../../transform").Transform} transform Transform.
* @param {number} opacity Opacity.
*/ */
disposeInternal() { useContainer(target, transform, opacity) {
this.context.canvas.width = this.context.canvas.height = 0; const layerClassName = this.getLayer().getClassName();
super.disposeInternal(); let container, context;
if (target && target.style.opacity === '' && target.className === layerClassName) {
const canvas = target.firstElementChild;
if (canvas instanceof HTMLCanvasElement) {
context = canvas.getContext('2d');
}
}
if (context && context.canvas.style.transform === transformToString(transform)) {
// Container of the previous layer renderer can be used.
this.container = target;
this.context = context;
this.containerReused = true;
} else if (this.containerReused) {
// Previously reused container cannot be used any more.
this.container = null;
this.context = null;
this.containerReused = false;
}
if (!this.container) {
container = document.createElement('div');
container.className = layerClassName;
let style = container.style;
style.position = 'absolute';
style.width = '100%';
style.height = '100%';
context = createCanvasContext2D();
const canvas = context.canvas;
container.appendChild(canvas);
style = canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
this.container = container;
this.context = context;
}
} }
/** /**
@@ -120,7 +163,7 @@ class CanvasLayerRenderer extends LayerRenderer {
applyTransform(frameState.coordinateToPixelTransform, bottomRight); applyTransform(frameState.coordinateToPixelTransform, bottomRight);
applyTransform(frameState.coordinateToPixelTransform, bottomLeft); applyTransform(frameState.coordinateToPixelTransform, bottomLeft);
const inverted = this.inversePixelTransform_; const inverted = this.inversePixelTransform;
applyTransform(inverted, topLeft); applyTransform(inverted, topLeft);
applyTransform(inverted, topRight); applyTransform(inverted, topRight);
applyTransform(inverted, bottomRight); applyTransform(inverted, bottomRight);
@@ -144,7 +187,7 @@ class CanvasLayerRenderer extends LayerRenderer {
dispatchRenderEvent_(type, context, frameState) { dispatchRenderEvent_(type, context, frameState) {
const layer = this.getLayer(); const layer = this.getLayer();
if (layer.hasListener(type)) { if (layer.hasListener(type)) {
const event = new RenderEvent(type, this.inversePixelTransform_, frameState, context, null); const event = new RenderEvent(type, this.inversePixelTransform, frameState, context);
layer.dispatchEvent(event); layer.dispatchEvent(event);
} }
} }
@@ -197,7 +240,7 @@ class CanvasLayerRenderer extends LayerRenderer {
* returned, and empty array will be returned. * returned, and empty array will be returned.
*/ */
getDataAtPixel(pixel, frameState, hitTolerance) { getDataAtPixel(pixel, frameState, hitTolerance) {
const renderPixel = applyTransform(this.inversePixelTransform_, pixel.slice()); const renderPixel = applyTransform(this.inversePixelTransform, pixel.slice());
const context = this.context; const context = this.context;
let data; let data;

View File

@@ -7,6 +7,7 @@ import TileState from '../../TileState.js';
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js'; import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js';
import CanvasLayerRenderer from './Layer.js'; import CanvasLayerRenderer from './Layer.js';
import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js'; import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
import {numberSafeCompareFunction} from '../../array.js';
/** /**
* @classdesc * @classdesc
@@ -125,7 +126,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
return true; return true;
} }
@@ -137,8 +138,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
* @inheritDoc * @inheritDoc
* @returns {HTMLElement} The rendered element. * @returns {HTMLElement} The rendered element.
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState, target) {
const context = this.context; const layerState = frameState.layerStatesArray[frameState.layerIndex];
const viewState = frameState.viewState; const viewState = frameState.viewState;
const projection = viewState.projection; const projection = viewState.projection;
const viewResolution = viewState.resolution; const viewResolution = viewState.resolution;
@@ -224,17 +225,21 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
} }
const canvas = context.canvas;
const canvasScale = tileResolution / viewResolution; const canvasScale = tileResolution / viewResolution;
// set forward and inverse pixel transforms // set forward and inverse pixel transforms
composeTransform(this.pixelTransform_, composeTransform(this.pixelTransform,
frameState.size[0] / 2, frameState.size[1] / 2, frameState.size[0] / 2, frameState.size[1] / 2,
1 / tilePixelRatio, 1 / tilePixelRatio, 1 / tilePixelRatio, 1 / tilePixelRatio,
rotation, rotation,
-width / 2, -height / 2 -width / 2, -height / 2
); );
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
makeInverse(this.inversePixelTransform, this.pixelTransform);
// set scale transform for calculating tile positions on the canvas // set scale transform for calculating tile positions on the canvas
composeTransform(this.tempTransform_, composeTransform(this.tempTransform_,
@@ -247,7 +252,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
if (canvas.width != width || canvas.height != height) { if (canvas.width != width || canvas.height != height) {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
} else { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
@@ -259,18 +264,17 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
this.renderedTiles.length = 0; this.renderedTiles.length = 0;
/** @type {Array<number>} */ /** @type {Array<number>} */
const zs = Object.keys(tilesToDrawByZ).map(Number); let zs = Object.keys(tilesToDrawByZ).map(Number);
zs.sort(function(a, b) { zs.sort(numberSafeCompareFunction);
if (a === z) {
return 1;
} else if (b === z) {
return -1;
} else {
return a > b ? 1 : a < b ? -1 : 0;
}
});
for (let i = 0, ii = zs.length; i < ii; ++i) { let clips, clipZs, currentClip;
if (layerState.opacity === 1 && (!this.containerReused || tileSource.getOpaque(frameState.viewState.projection))) {
zs = zs.reverse();
} else {
clips = [];
clipZs = [];
}
for (let i = zs.length - 1; i >= 0; --i) {
const currentZ = zs[i]; const currentZ = zs[i];
const currentTilePixelSize = tileSource.getTilePixelSize(currentZ, pixelRatio, projection); const currentTilePixelSize = tileSource.getTilePixelSize(currentZ, pixelRatio, projection);
const currentResolution = tileGrid.getResolution(currentZ); const currentResolution = tileGrid.getResolution(currentZ);
@@ -298,8 +302,41 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
const y = Math.round(floatY); const y = Math.round(floatY);
const w = nextX - x; const w = nextX - x;
const h = nextY - y; const h = nextY - y;
const transition = z === currentZ;
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, z === currentZ); const inTransition = transition && tile.getAlpha(getUid(this), frameState.time) !== 1;
if (!inTransition) {
if (clips) {
// Clip mask for regions in this tile that already filled by a higher z tile
context.save();
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
for (let i = 0, ii = clips.length; i < ii; ++i) {
if (z !== currentZ && currentZ < clipZs[i]) {
const clip = clips[i];
context.beginPath();
// counter-clockwise (outer ring) for current tile
context.moveTo(currentClip[0], currentClip[1]);
context.lineTo(currentClip[2], currentClip[3]);
context.lineTo(currentClip[4], currentClip[5]);
context.lineTo(currentClip[6], currentClip[7]);
// clockwise (inner ring) for higher z tile
context.moveTo(clip[6], clip[7]);
context.lineTo(clip[4], clip[5]);
context.lineTo(clip[2], clip[3]);
context.lineTo(clip[0], clip[1]);
context.clip();
}
}
clips.push(currentClip);
clipZs.push(currentZ);
} else {
context.clearRect(x, y, w, h);
}
}
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, transition, layerState.opacity);
if (clips && !inTransition) {
context.restore();
}
this.renderedTiles.push(tile); this.renderedTiles.push(tile);
this.updateUsedTiles(frameState.usedTiles, tileSource, tile); this.updateUsedTiles(frameState.usedTiles, tileSource, tile);
} }
@@ -322,17 +359,12 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
context.restore(); context.restore();
} }
const opacity = layerState.opacity; const canvasTransform = transformToString(this.pixelTransform);
if (opacity !== parseFloat(canvas.style.opacity)) {
canvas.style.opacity = opacity;
}
const canvasTransform = transformToString(this.pixelTransform_);
if (canvasTransform !== canvas.style.transform) { if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
return canvas; return this.container;
} }
/** /**
@@ -344,19 +376,15 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
* @param {number} h Height of the tile. * @param {number} h Height of the tile.
* @param {number} gutter Tile gutter. * @param {number} gutter Tile gutter.
* @param {boolean} transition Apply an alpha transition. * @param {boolean} transition Apply an alpha transition.
* @param {number} opacity Opacity.
*/ */
drawTileImage(tile, frameState, x, y, w, h, gutter, transition) { drawTileImage(tile, frameState, x, y, w, h, gutter, transition, opacity) {
const image = this.getTileImage(tile); const image = this.getTileImage(tile);
if (!image) { if (!image) {
return; return;
} }
const uid = getUid(this); const uid = getUid(this);
const alpha = transition ? tile.getAlpha(uid, frameState.time) : 1; const alpha = opacity * (transition ? tile.getAlpha(uid, frameState.time) : 1);
const tileLayer = /** @type {import("../../layer/Tile.js").default} */ (this.getLayer());
const tileSource = tileLayer.getSource();
if (alpha === 1 && !tileSource.getOpaque(frameState.viewState.projection)) {
this.context.clearRect(x, y, w, h);
}
const alphaChanged = alpha !== this.context.globalAlpha; const alphaChanged = alpha !== this.context.globalAlpha;
if (alphaChanged) { if (alphaChanged) {
this.context.save(); this.context.save();

View File

@@ -63,7 +63,7 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
const viewState = frameState.viewState; const viewState = frameState.viewState;
const viewResolution = viewState.resolution; const viewResolution = viewState.resolution;
@@ -78,6 +78,7 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) { if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) {
let skippedFeatures = this.skippedFeatures_; let skippedFeatures = this.skippedFeatures_;
vectorRenderer.useContainer(null, null, 1);
const context = vectorRenderer.context; const context = vectorRenderer.context;
const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, { const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, {
declutterItems: [], declutterItems: [],
@@ -91,10 +92,10 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
})); }));
const newSkippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort(); const newSkippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort();
const image = new ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas, function(callback) { const image = new ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas, function(callback) {
if (vectorRenderer.prepareFrame(imageFrameState, layerState) && if (vectorRenderer.prepareFrame(imageFrameState) &&
(vectorRenderer.replayGroupChanged || (vectorRenderer.replayGroupChanged ||
!equals(skippedFeatures, newSkippedFeatures))) { !equals(skippedFeatures, newSkippedFeatures))) {
vectorRenderer.renderFrame(imageFrameState, layerState); vectorRenderer.renderFrame(imageFrameState, null);
renderDeclutterItems(imageFrameState, null); renderDeclutterItems(imageFrameState, null);
skippedFeatures = newSkippedFeatures; skippedFeatures = newSkippedFeatures;
callback(); callback();

View File

@@ -70,35 +70,48 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
renderFrame(frameState, layerState) { useContainer(target, transform, opacity) {
if (opacity < 1) {
target = null;
}
super.useContainer(target, transform, opacity);
}
/**
* @inheritDoc
*/
renderFrame(frameState, target) {
const pixelRatio = frameState.pixelRatio;
const layerState = frameState.layerStatesArray[frameState.layerIndex];
// set forward and inverse pixel transforms
makeScale(this.pixelTransform, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform, this.pixelTransform);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const context = this.context; const context = this.context;
const canvas = context.canvas; const canvas = context.canvas;
const replayGroup = this.replayGroup_; const replayGroup = this.replayGroup_;
if (!replayGroup || replayGroup.isEmpty()) { if (!replayGroup || replayGroup.isEmpty()) {
if (canvas.width > 0) { if (!this.containerReused && canvas.width > 0) {
canvas.width = 0; canvas.width = 0;
} }
return canvas; return this.container;
} }
const pixelRatio = frameState.pixelRatio;
// set forward and inverse pixel transforms
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
// resize and clear // resize and clear
const width = Math.round(frameState.size[0] * pixelRatio); const width = Math.round(frameState.size[0] * pixelRatio);
const height = Math.round(frameState.size[1] * pixelRatio); const height = Math.round(frameState.size[1] * pixelRatio);
if (canvas.width != width || canvas.height != height) { if (canvas.width != width || canvas.height != height) {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
const canvasTransform = transformToString(this.pixelTransform_); const canvasTransform = transformToString(this.pixelTransform);
if (canvas.style.transform !== canvasTransform) { if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
} else { } else if (!this.containerReused) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
@@ -152,7 +165,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (declutterReplays) { if (declutterReplays) {
const viewHints = frameState.viewHints; const viewHints = frameState.viewHints;
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); replayDeclutter(declutterReplays, context, rotation, 1, hifi, frameState.declutterItems);
} }
if (clipped) { if (clipped) {
@@ -162,11 +175,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
this.postRender(context, frameState); this.postRender(context, frameState);
const opacity = layerState.opacity; const opacity = layerState.opacity;
if (opacity !== parseFloat(canvas.style.opacity)) { const container = this.container;
canvas.style.opacity = opacity; if (opacity !== parseFloat(container.style.opacity)) {
container.style.opacity = opacity === 1 ? '' : opacity;
} }
return canvas; return this.container;
} }
/** /**
@@ -219,7 +233,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer()); const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
const vectorSource = vectorLayer.getSource(); const vectorSource = vectorLayer.getSource();

View File

@@ -24,7 +24,6 @@ import {
makeInverse makeInverse
} from '../../transform.js'; } from '../../transform.js';
import CanvasExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js'; import CanvasExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
import {clear, isEmpty} from '../../obj.js';
/** /**
@@ -59,32 +58,16 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
constructor(layer) { constructor(layer) {
super(layer); super(layer);
const baseCanvas = this.context.canvas;
/** /**
* @private * @private
* @type {CanvasRenderingContext2D} * @type {CanvasRenderingContext2D}
*/ */
this.overlayContext_ = createCanvasContext2D(); this.overlayContext_ = null;
const overlayCanvas = this.overlayContext_.canvas;
overlayCanvas.style.position = 'absolute';
overlayCanvas.style.transformOrigin = 'top left';
const container = document.createElement('div');
const style = container.style;
style.position = 'absolute';
style.width = '100%';
style.height = '100%';
container.appendChild(baseCanvas);
container.appendChild(overlayCanvas);
/** /**
* @private * @type {string}
* @type {HTMLElement}
*/ */
this.container_ = container; this.overlayContextUid_;
/** /**
* The transform for rendered pixels to viewport CSS pixels for the overlay canvas. * The transform for rendered pixels to viewport CSS pixels for the overlay canvas.
@@ -136,17 +119,42 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
disposeInternal() { useContainer(target, transform, opacity) {
this.overlayContext_.canvas.width = this.overlayContext_.canvas.height = 0; let overlayContext;
super.disposeInternal(); if (target && target.childElementCount === 2) {
overlayContext = target.lastElementChild.getContext('2d');
if (!overlayContext) {
target = null;
}
}
const containerReused = this.containerReused;
super.useContainer(target, transform, opacity);
if (containerReused) {
this.overlayContext_ = overlayContext || null;
this.overlayContextUid_ = overlayContext ? getUid(overlayContext) : undefined;
}
if (!this.overlayContext_) {
const overlayContext = createCanvasContext2D();
const style = overlayContext.canvas.style;
style.position = 'absolute';
style.transformOrigin = 'top left';
this.overlayContext_ = overlayContext;
this.overlayContextUid_ = getUid(overlayContext);
}
if (this.container.childElementCount === 1) {
this.container.appendChild(this.overlayContext_.canvas);
}
} }
/** /**
* @param {import("../../VectorRenderTile.js").default} tile Tile. * @param {import("../../VectorRenderTile.js").default} tile Tile.
* @param {number} pixelRatio Pixel ratio. * @param {number} pixelRatio Pixel ratio.
* @param {import("../../proj/Projection").default} projection Projection. * @param {import("../../proj/Projection").default} projection Projection.
* @param {boolean} queue Queue tile for rendering.
* @return {boolean} Tile needs to be rendered.
*/ */
prepareTile(tile, pixelRatio, projection) { prepareTile(tile, pixelRatio, projection, queue) {
let render = false;
const tileUid = getUid(tile); const tileUid = getUid(tile);
const state = tile.getState(); const state = tile.getState();
if (((state === TileState.LOADED && tile.hifi) || if (((state === TileState.LOADED && tile.hifi) ||
@@ -158,9 +166,13 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (state === TileState.LOADED || state === TileState.ERROR) { if (state === TileState.LOADED || state === TileState.ERROR) {
this.updateExecutorGroup_(tile, pixelRatio, projection); this.updateExecutorGroup_(tile, pixelRatio, projection);
if (this.tileImageNeedsRender_(tile, pixelRatio, projection)) { if (this.tileImageNeedsRender_(tile, pixelRatio, projection)) {
this.renderTileImageQueue_[tileUid] = tile; render = true;
if (queue) {
this.renderTileImageQueue_[tileUid] = tile;
}
} }
} }
return render;
} }
/** /**
@@ -176,7 +188,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
tile.wantedResolution = resolution; tile.wantedResolution = resolution;
const tileUid = getUid(tile); const tileUid = getUid(tile);
if (!(tileUid in this.tileListenerKeys_)) { if (!(tileUid in this.tileListenerKeys_)) {
const listenerKey = listen(tile, EventType.CHANGE, this.prepareTile.bind(this, tile, pixelRatio, projection)); const listenerKey = listen(tile, EventType.CHANGE, this.prepareTile.bind(this, tile, pixelRatio, projection, true));
this.tileListenerKeys_[tileUid] = listenerKey; this.tileListenerKeys_[tileUid] = listenerKey;
} }
} else { } else {
@@ -185,7 +197,10 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (hifi || !tile.wantedResolution) { if (hifi || !tile.wantedResolution) {
tile.wantedResolution = resolution; tile.wantedResolution = resolution;
} }
this.prepareTile(tile, pixelRatio, projection); const render = this.prepareTile(tile, pixelRatio, projection, false);
if (render) {
this.renderTileImage_(tile, frameState);
}
} }
return tile; return tile;
} }
@@ -207,13 +222,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
prepareFrame(frameState, layerState) { prepareFrame(frameState) {
const layerState = frameState.layerStatesArray[frameState.layerIndex];
layerState.hasOverlay = true;
const layerRevision = this.getLayer().getRevision(); const layerRevision = this.getLayer().getRevision();
if (this.renderedLayerRevision_ != layerRevision) { if (this.renderedLayerRevision_ != layerRevision) {
this.renderedTiles.length = 0; this.renderedTiles.length = 0;
} }
this.renderedLayerRevision_ = layerRevision; this.renderedLayerRevision_ = layerRevision;
return super.prepareFrame(frameState, layerState); return super.prepareFrame(frameState);
} }
/** /**
@@ -379,26 +396,30 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState, target) {
super.renderFrame(frameState, layerState);
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const viewHints = frameState.viewHints; const viewHints = frameState.viewHints;
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
this.renderQueuedTileImages_(hifi, frameState);
super.renderFrame(frameState, target);
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const renderMode = layer.getRenderMode(); const renderMode = layer.getRenderMode();
if (renderMode === VectorTileRenderType.IMAGE) { if (renderMode === VectorTileRenderType.IMAGE) {
this.renderTileImages_(hifi, frameState); return this.container;
return this.container_;
} }
if (!isEmpty(this.renderTileImageQueue_) && !this.extentChanged) { const source = layer.getSource();
this.renderTileImages_(hifi, frameState); // Unqueue tiles from the image queue when we don't need any more
return this.container_; const usedTiles = frameState.usedTiles[getUid(source)];
for (const tileUid in this.renderTileImageQueue_) {
if (!usedTiles || !(tileUid in usedTiles)) {
delete this.renderTileImageQueue_[tileUid];
}
} }
const context = this.overlayContext_; const context = this.overlayContext_;
const declutterReplays = layer.getDeclutter() ? {} : null; const declutterReplays = layer.getDeclutter() ? {} : null;
const source = layer.getSource();
const replayTypes = VECTOR_REPLAYS[renderMode]; const replayTypes = VECTOR_REPLAYS[renderMode];
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
const rotation = frameState.viewState.rotation; const rotation = frameState.viewState.rotation;
@@ -419,13 +440,14 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (canvas.style.transform !== canvasTransform) { if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform; canvas.style.transform = canvasTransform;
} }
} else { } else if (getUid(context) === this.overlayContextUid_) {
context.clearRect(0, 0, width, height); context.clearRect(0, 0, width, height);
} }
const tiles = this.renderedTiles; const tiles = this.renderedTiles;
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection); const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
const clips = []; const clips = [];
const clipZs = [];
for (let i = tiles.length - 1; i >= 0; --i) { for (let i = tiles.length - 1; i >= 0; --i) {
const tile = /** @type {import("../../VectorRenderTile.js").default} */ (tiles[i]); const tile = /** @type {import("../../VectorRenderTile.js").default} */ (tiles[i]);
if (tile.getState() == TileState.ABORT) { if (tile.getState() == TileState.ABORT) {
@@ -436,6 +458,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tileExtent[0]; const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tileExtent[0];
const transform = this.getRenderTransform(frameState, width, height, worldOffset); const transform = this.getRenderTransform(frameState, width, height, worldOffset);
const executorGroups = tile.executorGroups[getUid(layer)]; const executorGroups = tile.executorGroups[getUid(layer)];
let clipped = false;
for (let t = 0, tt = executorGroups.length; t < tt; ++t) { for (let t = 0, tt = executorGroups.length; t < tt; ++t) {
const executorGroup = executorGroups[t]; const executorGroup = executorGroups[t];
if (!executorGroup.hasExecutors(replayTypes)) { if (!executorGroup.hasExecutors(replayTypes)) {
@@ -443,9 +466,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
continue; continue;
} }
const currentZ = tile.tileCoord[0]; const currentZ = tile.tileCoord[0];
let zs, currentClip; let currentClip;
if (!declutterReplays) { if (!declutterReplays && !clipped) {
zs = [];
currentClip = executorGroup.getClipCoords(transform); currentClip = executorGroup.getClipCoords(transform);
context.save(); context.save();
@@ -453,7 +475,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
// already filled by a higher resolution tile // already filled by a higher resolution tile
for (let j = 0, jj = clips.length; j < jj; ++j) { for (let j = 0, jj = clips.length; j < jj; ++j) {
const clip = clips[j]; const clip = clips[j];
if (currentZ < zs[j]) { if (currentZ < clipZs[j]) {
context.beginPath(); context.beginPath();
// counter-clockwise (outer ring) for current tile // counter-clockwise (outer ring) for current tile
context.moveTo(currentClip[0], currentClip[1]); context.moveTo(currentClip[0], currentClip[1]);
@@ -470,51 +492,38 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
} }
} }
executorGroup.execute(context, transform, rotation, {}, hifi, replayTypes, declutterReplays); executorGroup.execute(context, transform, rotation, {}, hifi, replayTypes, declutterReplays);
if (!declutterReplays) { if (!declutterReplays && !clipped) {
context.restore(); context.restore();
clips.push(currentClip); clips.push(currentClip);
zs.push(currentZ); clipZs.push(currentZ);
clipped = true;
} }
} }
} }
if (declutterReplays) { if (declutterReplays) {
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); const layerState = frameState.layerStatesArray[frameState.layerIndex];
replayDeclutter(declutterReplays, context, rotation, layerState.opacity, hifi, frameState.declutterItems);
} }
const opacity = layerState.opacity; return this.container;
if (opacity !== parseFloat(canvas.style.opacity)) {
canvas.style.opacity = opacity;
}
// Now that we have rendered the tiles we have already, let's prepare new tile images
// for the next frame
this.renderTileImages_(hifi, frameState);
return this.container_;
} }
/** /**
* @param {boolean} hifi We have time to render a high fidelity map image. * @param {boolean} hifi We have time to render a high fidelity map image.
* @param {import('../../PluggableMap.js').FrameState} frameState Frame state. * @param {import('../../PluggableMap.js').FrameState} frameState Frame state.
*/ */
renderTileImages_(hifi, frameState) { renderQueuedTileImages_(hifi, frameState) {
// When we don't have time to render hifi, only render tiles until we have used up // When we don't have time to render hifi, only render tiles until we have used up
// half of the frame budget of 16 ms // half of the frame budget of 16 ms
for (const uid in this.renderTileImageQueue_) { for (const uid in this.renderTileImageQueue_) {
if (!hifi && Date.now() - frameState.time > 8) { if (!hifi && Date.now() - frameState.time > 8) {
frameState.animate = true;
break; break;
} }
const tile = this.renderTileImageQueue_[uid]; const tile = this.renderTileImageQueue_[uid];
frameState.animate = true;
delete this.renderTileImageQueue_[uid]; delete this.renderTileImageQueue_[uid];
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer()); this.renderTileImage_(tile, frameState);
const viewState = frameState.viewState;
const tileGrid = layer.getSource().getTileGridForProjection(viewState.projection);
const tileResolution = tileGrid.getResolution(tile.tileCoord[0]);
const renderPixelRatio = frameState.pixelRatio / tile.wantedResolution * tileResolution;
this.renderTileImage_(tile, frameState.pixelRatio, renderPixelRatio, viewState.projection);
} }
clear(this.renderTileImageQueue_);
} }
/** /**
@@ -561,24 +570,29 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/** /**
* @param {import("../../VectorRenderTile.js").default} tile Tile. * @param {import("../../VectorRenderTile.js").default} tile Tile.
* @param {number} pixelRatio Pixel ratio. * @param {import("../../PluggableMap").FrameState} frameState Frame state.
* @param {number} renderPixelRatio Render pixel ratio.
* @param {import("../../proj/Projection.js").default} projection Projection.
* @private * @private
*/ */
renderTileImage_(tile, pixelRatio, renderPixelRatio, projection) { renderTileImage_(tile, frameState) {
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer()); const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const replayState = tile.getReplayState(layer); const replayState = tile.getReplayState(layer);
const revision = layer.getRevision(); const revision = layer.getRevision();
const executorGroups = tile.executorGroups[getUid(layer)]; const executorGroups = tile.executorGroups[getUid(layer)];
replayState.renderedTileRevision = revision; replayState.renderedTileRevision = revision;
replayState.renderedTileZ = tile.sourceZ; replayState.renderedTileZ = tile.sourceZ;
const tileCoord = tile.wrappedTileCoord; const tileCoord = tile.wrappedTileCoord;
const z = tileCoord[0]; const z = tileCoord[0];
const source = layer.getSource(); const source = layer.getSource();
let pixelRatio = frameState.pixelRatio;
const viewState = frameState.viewState;
const projection = viewState.projection;
const tileGrid = source.getTileGridForProjection(projection); const tileGrid = source.getTileGridForProjection(projection);
const tileResolution = tileGrid.getResolution(tile.tileCoord[0]);
const renderPixelRatio = frameState.pixelRatio / tile.wantedResolution * tileResolution;
const resolution = tileGrid.getResolution(z); const resolution = tileGrid.getResolution(z);
const context = tile.getContext(layer); const context = tile.getContext(layer);
// Increase tile size when overzooming for low pixel ratio, to avoid blurry tiles // Increase tile size when overzooming for low pixel ratio, to avoid blurry tiles
pixelRatio = Math.max(pixelRatio, renderPixelRatio / pixelRatio); pixelRatio = Math.max(pixelRatio, renderPixelRatio / pixelRatio);
const size = source.getTilePixelSize(z, pixelRatio, projection); const size = source.getTilePixelSize(z, pixelRatio, projection);

View File

@@ -2,9 +2,29 @@
* @module ol/renderer/webgl/Layer * @module ol/renderer/webgl/Layer
*/ */
import LayerRenderer from '../Layer.js'; import LayerRenderer from '../Layer.js';
import WebGLHelper from '../../webgl/Helper'; import WebGLHelper from '../../webgl/Helper.js';
/**
* @enum {string}
*/
export const WebGLWorkerMessageType = {
GENERATE_BUFFERS: 'GENERATE_BUFFERS'
};
/**
* @typedef {Object} WebGLWorkerGenerateBuffersMessage
* This message will trigger the generation of a vertex and an index buffer based on the given render instructions.
* When the buffers are generated, the worked will send a message of the same type to the main thread, with
* the generated buffers in it.
* Note that any addition properties present in the message *will* be sent back to the main thread.
* @property {WebGLWorkerMessageType} type Message type
* @property {ArrayBuffer} renderInstructions Render instructions raw binary buffer.
* @property {ArrayBuffer} [vertexBuffer] Vertices array raw binary buffer (sent by the worker).
* @property {ArrayBuffer} [indexBuffer] Indices array raw binary buffer (sent by the worker).
* @property {number} [customAttributesCount] Amount of custom attributes count in the render instructions.
*/
/** /**
* @typedef {Object} PostProcessesOptions * @typedef {Object} PostProcessesOptions
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than * @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
@@ -36,7 +56,11 @@ class WebGLLayerRenderer extends LayerRenderer {
const options = opt_options || {}; const options = opt_options || {};
this.helper_ = new WebGLHelper({ /**
* @type {WebGLHelper}
* @protected
*/
this.helper = new WebGLHelper({
postProcesses: options.postProcesses, postProcesses: options.postProcesses,
uniforms: options.uniforms uniforms: options.uniforms
}); });
@@ -55,96 +79,151 @@ class WebGLLayerRenderer extends LayerRenderer {
* @api * @api
*/ */
getShaderCompileErrors() { getShaderCompileErrors() {
return this.helper_.getShaderCompileErrors(); return this.helper.getShaderCompileErrors();
} }
} }
/** /**
* Pushes vertices and indices to the given buffers using the geometry coordinates and the following properties * @param {Float32Array} instructions Instructons array in which to write.
* from the feature: * @param {number} elementIndex Index from which render instructions will be written.
* - `color` * @param {number} x Point center X coordinate
* - `opacity` * @param {number} y Point center Y coordinate
* - `size` (for points) * @param {number} u0 Left texture coordinate
* - `u0`, `v0`, `u1`, `v1` (for points) * @param {number} v0 Bottom texture coordinate
* - `rotateWithView` (for points) * @param {number} u1 Right texture coordinate
* - `width` (for lines) * @param {number} v1 Top texture coordinate
* Custom attributes can be designated using the `opt_attributes` argument, otherwise other properties on the * @param {number} size Radius of the point
* feature will be ignored. * @param {number} opacity Opacity
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer in which new vertices will be pushed. * @param {boolean} rotateWithView If true, the point will stay aligned with the view
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer in which new indices will be pushed. * @param {Array<number>} color Array holding red, green, blue, alpha values
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature in geojson format, coordinates * @return {number} Index from which the next element should be written
* expressed in EPSG:4326. * @private
* @param {Array<string>} [opt_attributes] Custom attributes. An array of properties which will be read from the
* feature and pushed in the buffer in the given order. Note: attributes can only be numerical! Any other type or
* NaN will result in `0` being pushed in the buffer.
*/ */
export function pushFeatureToBuffer(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) { export function writePointFeatureInstructions(instructions, elementIndex, x, y, u0, v0, u1, v1, size, opacity, rotateWithView, color) {
if (!geojsonFeature.geometry) { let i = elementIndex;
return; instructions[i++] = x;
} instructions[i++] = y;
switch (geojsonFeature.geometry.type) { instructions[i++] = u0;
case 'Point': instructions[i++] = v0;
pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes); instructions[i++] = u1;
return; instructions[i++] = v1;
default: instructions[i++] = size;
return; instructions[i++] = opacity;
} instructions[i++] = rotateWithView ? 1 : 0;
instructions[i++] = color[0];
instructions[i++] = color[1];
instructions[i++] = color[2];
instructions[i++] = color[3];
return i;
} }
const tmpArray_ = []; const tmpArray_ = [];
const bufferPositions_ = {vertexPosition: 0, indexPosition: 0};
export const POINT_INSTRUCTIONS_COUNT = 13;
export const POINT_VERTEX_STRIDE = 12;
function writePointVertex(buffer, pos, x, y, offsetX, offsetY, u, v, opacity, rotateWithView, red, green, blue, alpha) {
buffer[pos + 0] = x;
buffer[pos + 1] = y;
buffer[pos + 2] = offsetX;
buffer[pos + 3] = offsetY;
buffer[pos + 4] = u;
buffer[pos + 5] = v;
buffer[pos + 6] = opacity;
buffer[pos + 7] = rotateWithView;
buffer[pos + 8] = red;
buffer[pos + 9] = green;
buffer[pos + 10] = blue;
buffer[pos + 11] = alpha;
}
function writeCustomAttrs(buffer, pos, customAttrs) {
if (customAttrs.length) {
buffer.set(customAttrs, pos);
}
}
/**
* An object holding positions both in an index and a vertex buffer.
* @typedef {Object} BufferPositions
* @property {number} vertexPosition Position in the vertex buffer
* @property {number} indexPosition Position in the index buffer
*/
/** /**
* Pushes a quad (two triangles) based on a point geometry * Pushes a quad (two triangles) based on a point geometry
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer * @param {Float32Array} instructions Array of render instructions for points.
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer * @param {number} elementIndex Index from which render instructions will be read.
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature * @param {Float32Array} vertexBuffer Buffer in the form of a typed array.
* @param {Array<string>} [opt_attributes] Custom attributes * @param {Uint32Array} indexBuffer Buffer in the form of a typed array.
* @param {BufferPositions} [bufferPositions] Buffer write positions; if not specified, positions will be set at 0.
* @param {number} [count] Amount of render instructions that will be read. Default value is POINT_INSTRUCTIONS_COUNT
* but a higher value can be provided; all values beyond the default count will be put in the vertices buffer as
* is, thus allowing specifying custom attributes. Please note: this value should not vary inside the same buffer or
* rendering will break.
* @return {BufferPositions} New buffer positions where to write next
* @property {number} vertexPosition New position in the vertex buffer where future writes should start.
* @property {number} indexPosition New position in the index buffer where future writes should start.
* @private * @private
*/ */
function pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) { export function writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer, bufferPositions, count) {
const stride = 12 + (opt_attributes !== undefined ? opt_attributes.length : 0); const count_ = count > POINT_INSTRUCTIONS_COUNT ? count : POINT_INSTRUCTIONS_COUNT;
const x = geojsonFeature.geometry.coordinates[0]; const x = instructions[elementIndex + 0];
const y = geojsonFeature.geometry.coordinates[1]; const y = instructions[elementIndex + 1];
const u0 = geojsonFeature.properties.u0; const u0 = instructions[elementIndex + 2];
const v0 = geojsonFeature.properties.v0; const v0 = instructions[elementIndex + 3];
const u1 = geojsonFeature.properties.u1; const u1 = instructions[elementIndex + 4];
const v1 = geojsonFeature.properties.v1; const v1 = instructions[elementIndex + 5];
const size = geojsonFeature.properties.size; const size = instructions[elementIndex + 6];
const opacity = geojsonFeature.properties.opacity; const opacity = instructions[elementIndex + 7];
const rotateWithView = geojsonFeature.properties.rotateWithView; const rotateWithView = instructions[elementIndex + 8];
const color = geojsonFeature.properties.color; const red = instructions[elementIndex + 9];
const red = color[0]; const green = instructions[elementIndex + 10];
const green = color[1]; const blue = instructions[elementIndex + 11];
const blue = color[2]; const alpha = instructions[elementIndex + 12];
const alpha = color[3];
const baseIndex = vertexBuffer.getArray().length / stride; // the default vertex buffer stride is 12, plus additional custom values if any
const baseStride = POINT_VERTEX_STRIDE;
const stride = baseStride + count_ - POINT_INSTRUCTIONS_COUNT;
// read custom numerical attributes on the feature // read custom numerical attributes on the feature
const customAttributeValues = tmpArray_; const customAttrs = tmpArray_;
customAttributeValues.length = opt_attributes ? opt_attributes.length : 0; customAttrs.length = count_ - POINT_INSTRUCTIONS_COUNT;
for (let i = 0; i < customAttributeValues.length; i++) { for (let i = 0; i < customAttrs.length; i++) {
customAttributeValues[i] = parseFloat(geojsonFeature.properties[opt_attributes[i]]) || 0; customAttrs[i] = instructions[elementIndex + POINT_INSTRUCTIONS_COUNT + i];
} }
let vPos = bufferPositions ? bufferPositions.vertexPosition : 0;
let iPos = bufferPositions ? bufferPositions.indexPosition : 0;
const baseIndex = vPos / stride;
// push vertices for each of the four quad corners (first standard then custom attributes) // push vertices for each of the four quad corners (first standard then custom attributes)
vertexBuffer.getArray().push(x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha); writePointVertex(vertexBuffer, vPos, x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues); writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha); writePointVertex(vertexBuffer, vPos, x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues); writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha); writePointVertex(vertexBuffer, vPos, x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues); writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha); writePointVertex(vertexBuffer, vPos, x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues); writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
indexBuffer.getArray().push( indexBuffer[iPos++] = baseIndex; indexBuffer[iPos++] = baseIndex + 1; indexBuffer[iPos++] = baseIndex + 3;
baseIndex, baseIndex + 1, baseIndex + 3, indexBuffer[iPos++] = baseIndex + 1; indexBuffer[iPos++] = baseIndex + 2; indexBuffer[iPos++] = baseIndex + 3;
baseIndex + 1, baseIndex + 2, baseIndex + 3
); bufferPositions_.vertexPosition = vPos;
bufferPositions_.indexPosition = iPos;
return bufferPositions_;
} }
/** /**

View File

@@ -1,21 +1,24 @@
/** /**
* @module ol/renderer/webgl/PointsLayer * @module ol/renderer/webgl/PointsLayer
*/ */
import WebGLArrayBuffer from '../../webgl/Buffer'; import WebGLArrayBuffer from '../../webgl/Buffer.js';
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl'; import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl.js';
import {DefaultAttrib, DefaultUniform} from '../../webgl/Helper'; import {DefaultAttrib, DefaultUniform} from '../../webgl/Helper.js';
import GeometryType from '../../geom/GeometryType'; import GeometryType from '../../geom/GeometryType.js';
import WebGLLayerRenderer, {getBlankTexture, pushFeatureToBuffer} from './Layer'; import WebGLLayerRenderer, {
import GeoJSON from '../../format/GeoJSON'; getBlankTexture,
import {getUid} from '../../util'; POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE, WebGLWorkerMessageType,
import ViewHint from '../../ViewHint'; writePointFeatureInstructions
import {createEmpty, equals} from '../../extent'; } from './Layer.js';
import ViewHint from '../../ViewHint.js';
import {createEmpty, equals} from '../../extent.js';
import { import {
create as createTransform, create as createTransform,
makeInverse as makeInverseTransform, makeInverse as makeInverseTransform,
multiply as multiplyTransform, multiply as multiplyTransform,
apply as applyTransform apply as applyTransform
} from '../../transform'; } from '../../transform.js';
import {create as createWebGLWorker} from '../../worker/webgl.js';
const VERTEX_SHADER = ` const VERTEX_SHADER = `
precision mediump float; precision mediump float;
@@ -25,15 +28,15 @@ const VERTEX_SHADER = `
attribute vec2 a_offsets; attribute vec2 a_offsets;
attribute float a_opacity; attribute float a_opacity;
attribute vec4 a_color; attribute vec4 a_color;
uniform mat4 u_projectionMatrix; uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix; uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix; uniform mat4 u_offsetRotateMatrix;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity; varying float v_opacity;
varying vec4 v_color; varying vec4 v_color;
void main(void) { void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix; mat4 offsetMatrix = u_offsetScaleMatrix;
if (a_rotateWithView == 1.0) { if (a_rotateWithView == 1.0) {
@@ -48,13 +51,13 @@ const VERTEX_SHADER = `
const FRAGMENT_SHADER = ` const FRAGMENT_SHADER = `
precision mediump float; precision mediump float;
uniform sampler2D u_texture; uniform sampler2D u_texture;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity; varying float v_opacity;
varying vec4 v_color; varying vec4 v_color;
void main(void) { void main(void) {
if (v_opacity == 0.0) { if (v_opacity == 0.0) {
discard; discard;
@@ -208,21 +211,21 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.sourceRevision_ = -1; this.sourceRevision_ = -1;
this.verticesBuffer_ = new WebGLArrayBuffer([], DYNAMIC_DRAW); this.verticesBuffer_ = new WebGLArrayBuffer(ARRAY_BUFFER, DYNAMIC_DRAW);
this.indicesBuffer_ = new WebGLArrayBuffer([], DYNAMIC_DRAW); this.indicesBuffer_ = new WebGLArrayBuffer(ELEMENT_ARRAY_BUFFER, DYNAMIC_DRAW);
this.program_ = this.helper_.getProgram( this.program_ = this.helper.getProgram(
options.fragmentShader || FRAGMENT_SHADER, options.fragmentShader || FRAGMENT_SHADER,
options.vertexShader || VERTEX_SHADER options.vertexShader || VERTEX_SHADER
); );
this.helper_.useProgram(this.program_); this.helper.useProgram(this.program_);
this.sizeCallback_ = options.sizeCallback || function() { this.sizeCallback_ = options.sizeCallback || function() {
return 1; return 1;
}; };
this.coordCallback_ = options.coordCallback || function(feature, index) { this.coordCallback_ = options.coordCallback || function(feature, index) {
const geom = /** @type {import("../../geom/Point").default} */ (feature.getGeometry()); const geom = feature.getGeometry();
return geom.getCoordinates()[index]; return geom.getCoordinates()[index];
}; };
this.opacityCallback_ = options.opacityCallback || function() { this.opacityCallback_ = options.opacityCallback || function() {
@@ -241,14 +244,6 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
return false; return false;
}; };
this.geojsonFormat_ = new GeoJSON();
/**
* @type {Object<string, import("../../format/GeoJSON").GeoJSONFeature>}
* @private
*/
this.geojsonFeatureCache_ = {};
this.previousExtent_ = createEmpty(); this.previousExtent_ = createEmpty();
/** /**
@@ -272,6 +267,30 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
* @private * @private
*/ */
this.invertRenderTransform_ = createTransform(); this.invertRenderTransform_ = createTransform();
/**
* @type {Float32Array}
* @private
*/
this.renderInstructions_ = new Float32Array(0);
this.worker_ = createWebGLWorker();
this.worker_.addEventListener('message', function(event) {
const received = event.data;
if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) {
const projectionTransform = received.projectionTransform;
this.verticesBuffer_.fromArrayBuffer(received.vertexBuffer);
this.indicesBuffer_.fromArrayBuffer(received.indexBuffer);
this.helper.flushBufferData(this.verticesBuffer_);
this.helper.flushBufferData(this.indicesBuffer_);
// saves the projection transform for the current frame state
this.renderTransform_ = projectionTransform;
makeInverseTransform(this.invertRenderTransform_, this.renderTransform_);
this.renderInstructions_ = new Float32Array(event.data.renderInstructions);
}
}.bind(this));
} }
/** /**
@@ -284,11 +303,13 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
/** /**
* @inheritDoc * @inheritDoc
*/ */
renderFrame(frameState, layerState) { renderFrame(frameState) {
this.helper_.drawElements(0, this.indicesBuffer_.getArray().length); const renderCount = this.indicesBuffer_.getArray() ? this.indicesBuffer_.getArray().length : 0;
this.helper_.finalizeDraw(frameState); this.helper.drawElements(0, renderCount);
const canvas = this.helper_.getCanvas(); this.helper.finalizeDraw(frameState);
const canvas = this.helper.getCanvas();
const layerState = frameState.layerStatesArray[frameState.layerIndex];
const opacity = layerState.opacity; const opacity = layerState.opacity;
if (opacity !== parseFloat(canvas.style.opacity)) { if (opacity !== parseFloat(canvas.style.opacity)) {
canvas.style.opacity = opacity; canvas.style.opacity = opacity;
@@ -305,8 +326,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const vectorSource = vectorLayer.getSource(); const vectorSource = vectorLayer.getSource();
const viewState = frameState.viewState; const viewState = frameState.viewState;
// TODO: get this from somewhere... const stride = POINT_VERTEX_STRIDE;
const stride = 12;
// the source has changed: clear the feature cache & reload features // the source has changed: clear the feature cache & reload features
const sourceChanged = this.sourceRevision_ < vectorSource.getRevision(); const sourceChanged = this.sourceRevision_ < vectorSource.getRevision();
@@ -327,22 +347,22 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
} }
// apply the current projection transform with the invert of the one used to fill buffers // apply the current projection transform with the invert of the one used to fill buffers
this.helper_.makeProjectionTransform(frameState, this.currentTransform_); this.helper.makeProjectionTransform(frameState, this.currentTransform_);
multiplyTransform(this.currentTransform_, this.invertRenderTransform_); multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
this.helper_.prepareDraw(frameState); this.helper.prepareDraw(frameState);
// write new data // write new data
this.helper_.bindBuffer(ARRAY_BUFFER, this.verticesBuffer_); this.helper.bindBuffer(this.verticesBuffer_);
this.helper_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); this.helper.bindBuffer(this.indicesBuffer_);
const bytesPerFloat = Float32Array.BYTES_PER_ELEMENT; const bytesPerFloat = Float32Array.BYTES_PER_ELEMENT;
this.helper_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * stride, 0); this.helper.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * stride, 0);
this.helper_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 2); this.helper.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 2);
this.helper_.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 4); this.helper.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 4);
this.helper_.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6); this.helper.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6);
this.helper_.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7); this.helper.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7);
this.helper_.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8); this.helper.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8);
return true; return true;
} }
@@ -356,47 +376,59 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer()); const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
const vectorSource = vectorLayer.getSource(); const vectorSource = vectorLayer.getSource();
this.verticesBuffer_.getArray().length = 0;
this.indicesBuffer_.getArray().length = 0;
// saves the projection transform for the current frame state // saves the projection transform for the current frame state
this.helper_.makeProjectionTransform(frameState, this.renderTransform_); const projectionTransform = createTransform();
makeInverseTransform(this.invertRenderTransform_, this.renderTransform_); this.helper.makeProjectionTransform(frameState, projectionTransform);
const features = vectorSource.getFeatures();
const totalInstructionsCount = POINT_INSTRUCTIONS_COUNT * features.length;
if (!this.renderInstructions_ || this.renderInstructions_.length !== totalInstructionsCount) {
this.renderInstructions_ = new Float32Array(totalInstructionsCount);
}
// loop on features to fill the buffer // loop on features to fill the buffer
const features = vectorSource.getFeatures();
let feature; let feature;
const tmpCoords = [];
let elementIndex = 0;
for (let i = 0; i < features.length; i++) { for (let i = 0; i < features.length; i++) {
feature = features[i]; feature = features[i];
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) { if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
continue; continue;
} }
let geojsonFeature = this.geojsonFeatureCache_[getUid(feature)]; tmpCoords[0] = this.coordCallback_(feature, 0);
if (!geojsonFeature) { tmpCoords[1] = this.coordCallback_(feature, 1);
geojsonFeature = this.geojsonFormat_.writeFeatureObject(feature); applyTransform(projectionTransform, tmpCoords);
this.geojsonFeatureCache_[getUid(feature)] = geojsonFeature;
}
geojsonFeature.geometry.coordinates[0] = this.coordCallback_(feature, 0); elementIndex = writePointFeatureInstructions(
geojsonFeature.geometry.coordinates[1] = this.coordCallback_(feature, 1); this.renderInstructions_,
applyTransform(this.renderTransform_, geojsonFeature.geometry.coordinates); elementIndex,
geojsonFeature.properties = geojsonFeature.properties || {}; tmpCoords[0],
geojsonFeature.properties.color = this.colorCallback_(feature, this.colorArray_); tmpCoords[1],
geojsonFeature.properties.u0 = this.texCoordCallback_(feature, 0); this.texCoordCallback_(feature, 0),
geojsonFeature.properties.v0 = this.texCoordCallback_(feature, 1); this.texCoordCallback_(feature, 1),
geojsonFeature.properties.u1 = this.texCoordCallback_(feature, 2); this.texCoordCallback_(feature, 2),
geojsonFeature.properties.v1 = this.texCoordCallback_(feature, 3); this.texCoordCallback_(feature, 3),
geojsonFeature.properties.size = this.sizeCallback_(feature); this.sizeCallback_(feature),
geojsonFeature.properties.opacity = this.opacityCallback_(feature); this.opacityCallback_(feature),
geojsonFeature.properties.rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0; this.rotateWithViewCallback_(feature),
this.colorCallback_(feature, this.colorArray_)
pushFeatureToBuffer(this.verticesBuffer_, this.indicesBuffer_, geojsonFeature); );
} }
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_); /** @type import('./Layer').WebGLWorkerGenerateBuffersMessage */
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); const message = {
type: WebGLWorkerMessageType.GENERATE_BUFFERS,
renderInstructions: this.renderInstructions_.buffer
};
// additional properties will be sent back as-is by the worker
message['projectionTransform'] = projectionTransform;
this.worker_.postMessage(message, [this.renderInstructions_.buffer]);
this.renderInstructions_ = null;
} }
} }
export default WebGLPointsLayerRenderer; export default WebGLPointsLayerRenderer;

View File

@@ -2,8 +2,8 @@
* @module ol/resolutionconstraint * @module ol/resolutionconstraint
*/ */
import {linearFindNearest} from './array.js'; import {linearFindNearest} from './array.js';
import {getHeight, getWidth} from './extent'; import {getHeight, getWidth} from './extent.js';
import {clamp} from './math'; import {clamp} from './math.js';
/** /**

View File

@@ -76,7 +76,7 @@ class Cluster extends VectorSource {
* @protected * @protected
*/ */
this.geometryFunction = options.geometryFunction || function(feature) { this.geometryFunction = options.geometryFunction || function(feature) {
const geometry = /** @type {Point} */ (feature.getGeometry()); const geometry = feature.getGeometry();
assert(geometry.getType() == GeometryType.POINT, assert(geometry.getType() == GeometryType.POINT,
10); // The default `geometryFunction` can only handle `Point` geometries 10); // The default `geometryFunction` can only handle `Point` geometries
return geometry; return geometry;

View File

@@ -23,6 +23,7 @@ import TileImage from './TileImage.js';
* for version 1, 'default' for versions 2 and 3. * for version 1, 'default' for versions 2 and 3.
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels). * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
* Higher values can increase reprojection performance, but decrease precision. * Higher values can increase reprojection performance, but decrease precision.
* @property {Array<number>} [resolutions] Supported resolutions as given in IIIF 'scaleFactors'
* @property {import("../size.js").Size} size Size of the image [width, height]. * @property {import("../size.js").Size} size Size of the image [width, height].
* @property {import("../size.js").Size[]} [sizes] Supported scaled image sizes. * @property {import("../size.js").Size[]} [sizes] Supported scaled image sizes.
* Content of the IIIF info.json 'sizes' property, but as array of Size objects. * Content of the IIIF info.json 'sizes' property, but as array of Size objects.
@@ -37,7 +38,7 @@ import TileImage from './TileImage.js';
* are supported), the default tilesize is 256. * are supported), the default tilesize is 256.
* @property {number} [transition] * @property {number} [transition]
* @property {string} [url] Base URL of the IIIF Image service. * @property {string} [url] Base URL of the IIIF Image service.
* This should be the same as the IIIF Image @id. * This should be the same as the IIIF Image ID.
* @property {Versions} [version=Versions.VERSION2] Service's IIIF Image API version. * @property {Versions} [version=Versions.VERSION2] Service's IIIF Image API version.
* @property {number} [zDirection] Indicate which resolution should be used * @property {number} [zDirection] Indicate which resolution should be used
* by a renderer if the views resolution does not match any resolution of the tile source. * by a renderer if the views resolution does not match any resolution of the tile source.
@@ -63,6 +64,9 @@ class IIIF extends TileImage {
*/ */
constructor(opt_options) { constructor(opt_options) {
/**
* @type {Partial<Options>} options
*/
const options = opt_options || {}; const options = opt_options || {};
let baseUrl = options.url || ''; let baseUrl = options.url || '';
@@ -75,6 +79,7 @@ class IIIF extends TileImage {
const width = size[0]; const width = size[0];
const height = size[1]; const height = size[1];
const tileSize = options.tileSize; const tileSize = options.tileSize;
const tilePixelRatio = options.tilePixelRatio || 1;
const format = options.format || 'jpg'; const format = options.format || 'jpg';
const quality = options.quality || (options.version == Versions.VERSION1 ? 'native' : 'default'); const quality = options.quality || (options.version == Versions.VERSION1 ? 'native' : 'default');
let resolutions = options.resolutions || []; let resolutions = options.resolutions || [];
@@ -82,7 +87,7 @@ class IIIF extends TileImage {
const extent = options.extent || [0, -height, width, 0]; const extent = options.extent || [0, -height, width, 0];
const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0; const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
const supportsListedTiles = tileSize != undefined && (Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0); const supportsListedTiles = tileSize != undefined && (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) && const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) &&
(supports.includes('regionByPx') || supports.includes('regionByPct')) && (supports.includes('regionByPx') || supports.includes('regionByPct')) &&
(supports.includes('sizeByWh') || supports.includes('sizeByH') || (supports.includes('sizeByWh') || supports.includes('sizeByH') ||
@@ -98,7 +103,7 @@ class IIIF extends TileImage {
if (supportsListedTiles || supportsArbitraryTiling) { if (supportsListedTiles || supportsArbitraryTiling) {
if (tileSize != undefined) { if (tileSize != undefined) {
if (Number.isInteger(tileSize) && tileSize > 0) { if (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0) {
tileWidth = tileSize; tileWidth = tileSize;
tileHeight = tileSize; tileHeight = tileSize;
} else if (Array.isArray(tileSize) && tileSize.length > 0) { } else if (Array.isArray(tileSize) && tileSize.length > 0) {
@@ -130,7 +135,7 @@ class IIIF extends TileImage {
resolutions.push(Math.pow(2, i)); resolutions.push(Math.pow(2, i));
} }
} else { } else {
const maxScaleFactor = Math.max([...resolutions]); const maxScaleFactor = Math.max(...resolutions);
// TODO maxScaleFactor might not be a power to 2 // TODO maxScaleFactor might not be a power to 2
maxZoom = Math.round(Math.log(maxScaleFactor) / Math.LN2); maxZoom = Math.round(Math.log(maxScaleFactor) / Math.LN2);
} }
@@ -260,7 +265,7 @@ class IIIF extends TileImage {
return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format; return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format;
}; };
const IiifTileClass = CustomTile.bind(null, tileGrid); const IiifTileClass = CustomTile.bind(null, tilePixelRatio, tileGrid);
super({ super({
attributions: options.attributions, attributions: options.attributions,

View File

@@ -56,7 +56,7 @@ class ImageArcGISRest extends ImageSource {
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options || /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
super({ super({
attributions: options.attributions, attributions: options.attributions,

View File

@@ -53,7 +53,7 @@ class ImageCanvasSource extends ImageSource {
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options || /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
super({ super({
attributions: options.attributions, attributions: options.attributions,

View File

@@ -63,7 +63,7 @@ class ImageWMS extends ImageSource {
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options || /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
super({ super({
attributions: options.attributions, attributions: options.attributions,

View File

@@ -7,7 +7,7 @@ import {createCanvasContext2D} from '../dom.js';
import {listen} from '../events.js'; import {listen} from '../events.js';
import Event from '../events/Event.js'; import Event from '../events/Event.js';
import EventType from '../events/EventType.js'; import EventType from '../events/EventType.js';
import {Processor} from 'pixelworks/lib/index'; import {Processor} from 'pixelworks/lib/index.js';
import {equals, getCenter, getHeight, getWidth} from '../extent.js'; import {equals, getCenter, getHeight, getWidth} from '../extent.js';
import ImageLayer from '../layer/Image.js'; import ImageLayer from '../layer/Image.js';
import TileLayer from '../layer/Tile.js'; import TileLayer from '../layer/Tile.js';
@@ -214,6 +214,7 @@ class RasterSource extends ImageSource {
extent: null, extent: null,
focus: null, focus: null,
index: 0, index: 0,
layerIndex: 0,
layerStatesArray: getLayerStatesArray(this.layers_), layerStatesArray: getLayerStatesArray(this.layers_),
pixelRatio: 1, pixelRatio: 1,
pixelToCoordinateTransform: createTransform(), pixelToCoordinateTransform: createTransform(),
@@ -358,7 +359,8 @@ class RasterSource extends ImageSource {
const len = this.layers_.length; const len = this.layers_.length;
const imageDatas = new Array(len); const imageDatas = new Array(len);
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
const imageData = getImageData(this.layers_[i], frameState, frameState.layerStatesArray[i]); frameState.layerIndex = i;
const imageData = getImageData(this.layers_[i], frameState);
if (imageData) { if (imageData) {
imageDatas[i] = imageData; imageDatas[i] = imageData;
} else { } else {
@@ -430,21 +432,24 @@ let sharedContext = null;
* Get image data from a layer. * Get image data from a layer.
* @param {import("../layer/Layer.js").default} layer Layer to render. * @param {import("../layer/Layer.js").default} layer Layer to render.
* @param {import("../PluggableMap.js").FrameState} frameState The frame state. * @param {import("../PluggableMap.js").FrameState} frameState The frame state.
* @param {import("../layer/Layer.js").State} layerState The layer state.
* @return {ImageData} The image data. * @return {ImageData} The image data.
*/ */
function getImageData(layer, frameState, layerState) { function getImageData(layer, frameState) {
const renderer = layer.getRenderer(); const renderer = layer.getRenderer();
if (!renderer) { if (!renderer) {
throw new Error('Unsupported layer type: ' + layer); throw new Error('Unsupported layer type: ' + layer);
} }
if (!renderer.prepareFrame(frameState, layerState)) { if (!renderer.prepareFrame(frameState)) {
return null; return null;
} }
const width = frameState.size[0]; const width = frameState.size[0];
const height = frameState.size[1]; const height = frameState.size[1];
const element = renderer.renderFrame(frameState, layerState); const container = renderer.renderFrame(frameState, null);
let element;
if (container) {
element = container.firstElementChild;
}
if (!(element instanceof HTMLCanvasElement)) { if (!(element instanceof HTMLCanvasElement)) {
throw new Error('Unsupported rendered element: ' + element); throw new Error('Unsupported rendered element: ' + element);
} }

View File

@@ -75,7 +75,7 @@ class TileSource extends Source {
if (tileGrid) { if (tileGrid) {
toSize(tileGrid.getTileSize(tileGrid.getMinZoom()), tileSize); toSize(tileGrid.getTileSize(tileGrid.getMinZoom()), tileSize);
} }
const canUseScreen = 'screen' in self; const canUseScreen = typeof screen !== 'undefined';
const width = canUseScreen ? (screen.availWidth || screen.width) : 1920; const width = canUseScreen ? (screen.availWidth || screen.width) : 1920;
const height = canUseScreen ? (screen.availHeight || screen.height) : 1080; const height = canUseScreen ? (screen.availHeight || screen.height) : 1080;
cacheSize = 4 * Math.ceil(width / tileSize[0]) * Math.ceil(height / tileSize[1]); cacheSize = 4 * Math.ceil(width / tileSize[0]) * Math.ceil(height / tileSize[1]);

View File

@@ -64,7 +64,7 @@ class TileArcGISRest extends TileImage {
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options || /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
super({ super({
attributions: options.attributions, attributions: options.attributions,

View File

@@ -81,7 +81,7 @@ class TileWMS extends TileImage {
*/ */
constructor(opt_options) { constructor(opt_options) {
const options = opt_options || /** @type {Options} */ ({}); const options = opt_options ? opt_options : {};
const params = options.params || {}; const params = options.params || {};

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