Compare commits

..

265 Commits

Author SHA1 Message Date
Andreas Hocevar
e4be8309f7 Merge pull request #10246 from openlayers/release-v6.1.1
Release v6.1.1
2019-11-04 12:25:24 +01:00
Andreas Hocevar
39a5511073 Update package version to 6.1.1 2019-11-04 12:16:04 +01:00
Andreas Hocevar
396f07bea1 Changelog for v6.1.1 2019-11-04 12:14:09 +01:00
Olivier Guyot
33980d0ba8 Merge pull request #10235 from jahow/webgl-optimizations
Various optimizations and fixes for the WebGL points renderer
2019-11-04 10:10:20 +01:00
Olivier Guyot
7da86ae71f Webgl points renderer / slight improvements following review
Also fixes a lint error.
2019-11-04 09:55:54 +01:00
Olivier Guyot
af15cfb815 Icon webgl example / avoid doing hit detection when view is moving 2019-11-04 09:31:38 +01:00
Olivier Guyot
600e1a4647 Webgl points renderer / use a smaller canvas for hit detection render
The hit detection render is now done against a canvas with half the
width/height of the main render. This still provides sufficient precision
while requiring a much smaller memory allocation (especially for
retina devices).
2019-11-04 09:31:38 +01:00
Olivier Guyot
43010c8934 Webgl / return 0 if doing renderTarget.read outside of data width/height
This would happen when WebGLPointsLayerRenderer.forEachFeatureAtCoordinate
is called on "warped" worlds at -360/+360 degrees, and may produce false
positives.
2019-11-04 09:31:38 +01:00
jahow
f7b0f6750b Resolve memory leak when deleting a webgl layer
Various references were kept, preventing the layer and underlying
renderer and webgl context to be garbage collected.

Also, the Helper was simplified because it turns out deleting manually
all Webgl objects is useless: these objects will be released when
the context is garbage collected anyway.

Note: this touches the Layer and BaseLayer classes, as the following were
preventing the layer from being garbage collected:
* layer reference in the `state_` object in BaseLayer
* dangling listener for source change in Layer
2019-11-04 09:31:38 +01:00
Olivier Guyot
e5e03d46a0 Webgl points renderer / more optimizations
Simplify calls in the attributes callback, also less stress
on garbage collection.
2019-11-04 09:31:38 +01:00
Olivier Guyot
e78c14c061 Webgl points renderer / add a cache for features in the source
This allows quicker access to features as well as their geometries
and properties, reducing the time taken by a rebuildBuffers call.
2019-11-04 09:31:38 +01:00
Andreas Hocevar
21f99e01c3 Merge pull request #10244 from ahocevar/no-multi-assign
Update to new eslint config with no-multi-assign
2019-11-02 16:48:46 +01:00
Andreas Hocevar
8098572346 Update package-lock.json 2019-11-02 15:20:35 +01:00
Andreas Hocevar
ac50cc3460 New eslint config with no-multi-assign 2019-11-02 15:20:21 +01:00
Andreas Hocevar
06ae419db6 Merge pull request #10243 from ahocevar/fix-font-measure
Store correct font value
2019-11-02 14:08:03 +01:00
Andreas Hocevar
43d6247671 Add rendering test case 2019-11-01 22:23:34 +01:00
Andreas Hocevar
442213f85b Store correct font value 2019-11-01 22:06:00 +01:00
Andreas Hocevar
2a96b6a8e3 Merge pull request #10239 from ahocevar/simpler-container-reuse
Simpler container reuse
2019-11-01 19:14:05 +01:00
Frédéric Junod
89f92a53b4 Merge pull request #10237 from fredj/zIndex_falsy_value
Fix layer zIndex test with falsy values
2019-11-01 08:25:56 +01:00
Andreas Hocevar
9c26d9d7dd Merge pull request #10221 from Kai-W/source-undefined-bug
Fix for undefined Source
2019-10-31 22:21:45 +01:00
Andreas Hocevar
3de05c249b Fix container transform comparison 2019-10-31 20:29:20 +01:00
Andreas Hocevar
bb2bdb17aa Render vector tile layers to a single canvas 2019-10-31 20:29:19 +01:00
Frederic Junod
b8c70bcbe7 Fix layer zIndex test with falsy values 2019-10-31 15:58:36 +01:00
Frederic Junod
c23d59e3a8 Remove extra argument passed to RenderEvent constructor 2019-10-31 15:47:27 +01:00
Andreas Hocevar
5dec336f94 Merge pull request #10228 from ahocevar/vectortile-hitdetect-rendertile
Use render tiles instead of source tiles for hit detection
2019-10-31 10:44:52 +01:00
Andreas Hocevar
e3f83f3601 Merge pull request #10226 from ahocevar/reproj-tile-abort
ABORT reproj tiles properly
2019-10-30 16:55:35 +01:00
Andreas Hocevar
3d0f7e4af8 Update the vector-tile-selection example 2019-10-30 14:39:54 +01:00
Andreas Hocevar
4b13c6dae0 Speed up rendering by not using alpha 2019-10-30 14:36:23 +01:00
Andreas Hocevar
7097a4c6ba Use render tiles instead of source tiles for hit detection 2019-10-30 11:44:12 +01:00
Andreas Hocevar
79ea5bf9cd Set ABORT state in base class 2019-10-30 10:29:58 +01:00
Andreas Hocevar
97d0d277fb Merge pull request #10224 from ahocevar/hitdetect-vectortiles-fixes
Vector tile hit detection fixes
2019-10-29 22:33:53 +01:00
Andreas Hocevar
025b27bdec Use correct resolution for tile hit canvas 2019-10-29 22:11:46 +01:00
Andreas Hocevar
00af5a87be Only use source tile when it is available 2019-10-29 18:29:42 +01:00
kai.westerkamp
53f6359f8f Fix for undefined Source 2019-10-29 15:38:14 +01:00
Frédéric Junod
bac3a8e9d8 Merge pull request #10218 from fredj/doc_fixes_expression
Documentation fixes in ol/style/expressions
2019-10-29 11:17:27 +01:00
Andreas Hocevar
66eedbfed2 Merge pull request #10216 from ahocevar/changelog-dependabot
Update changelog script to recognize dependabot instead of greenkeeper
2019-10-29 10:56:16 +01:00
Frédéric Junod
7d7228d45c Update src/ol/style/expressions.js
Co-Authored-By: Olivier Guyot <olivier.guyot@camptocamp.com>
2019-10-29 10:50:14 +01:00
Andreas Hocevar
459efede60 Update package-lock.json 2019-10-29 10:47:58 +01:00
Frederic Junod
b0ed775bc6 Documentation fixes 2019-10-29 08:42:11 +01:00
Andreas Hocevar
43ebfc4653 Merge pull request #10215 from openlayers/release-v6.1.0
Release v6.1.0
2019-10-28 22:00:33 +01:00
Andreas Hocevar
49c1486e06 Update changelog script to recognize dependabot instead of greenkeeper 2019-10-28 21:49:18 +01:00
Andreas Hocevar
3902759595 Update package version to 6.1.0 2019-10-28 21:44:02 +01:00
Andreas Hocevar
d71c733d9b Changelog for v6.1.0 2019-10-28 21:44:01 +01:00
Andreas Hocevar
90e1819d76 Merge pull request #10214 from jahow/webgl-layer-boolean-operators
WebGL / Add 'case' operator for style expressions
2019-10-28 21:11:47 +01:00
Olivier Guyot
f84fae8f70 Merge pull request #10198 from jahow/fix-webgl-renderer-loading-extent
WebGL renderer / use the specified loading strategy for the vector data
2019-10-28 16:19:52 +01:00
Olivier Guyot
6c0dd6152d Modified the icon-sprite-webgl example to allow filtering on a string attribute 2019-10-28 15:55:15 +01:00
Olivier Guyot
b96e70e952 Expressions / renamed mod to % to be more in line with MB style spec 2019-10-28 15:55:15 +01:00
Olivier Guyot
501c90b0a2 Expressions / introduced the case operator
This operator is used for if/else control flow
2019-10-28 15:52:31 +01:00
Olivier Guyot
2a2783c086 ShaderBuilder / better handling of strings variables/attributes
Now values which are not mentioned in the style are still added to
the string literals mapping.

Also an error will be thrown if a style references a missing variable.
2019-10-28 15:21:44 +01:00
Olivier Guyot
2f49876180 Expressions / add != operator & slightly better doc 2019-10-28 15:13:43 +01:00
Frédéric Junod
c7161acb6a Merge pull request #10212 from fredj/dependabot_config
Add config file for dependabot
2019-10-28 13:53:07 +01:00
Andreas Hocevar
db6314b6b2 Merge pull request #10187 from ahocevar/tabindex-scrollover
Set touch-action to allow native touch gestures
2019-10-28 13:49:44 +01:00
Tim Schaub
65eb24da68 Merge pull request #10194 from MrSoUndso/dev
Added check to make sure extent array has four objects.
2019-10-28 06:39:11 -06:00
Jakob Gerstmayer
6652192647 fixed spacing issues (again) 2019-10-28 12:55:26 +01:00
Jakob Gerstmayer
bc34fe5b71 incorporated suggestions 2019-10-28 12:51:40 +01:00
Olivier Guyot
80b4473180 Simplify the heatmap example
Use a weight function instead of manually edditing the features.
2019-10-28 10:27:29 +01:00
Olivier Guyot
cd3b222467 Specify an actual extent when loading features in the Webgl points renderer
This means any specified loading strategy will be taken into account.

Also added some tests to make sure the interaction with the source is
correct.
2019-10-28 10:26:31 +01:00
Andreas Hocevar
6e4259359b Merge pull request #10208 from openlayers/dependabot/npm_and_yarn/pixelmatch-5.1.0
Bump pixelmatch from 5.0.2 to 5.1.0
2019-10-28 09:24:39 +01:00
Frederic Junod
a2e6119da1 Add config file for dependabot 2019-10-28 09:24:35 +01:00
dependabot-preview[bot]
c992cea9a4 Bump pixelmatch from 5.0.2 to 5.1.0
Bumps [pixelmatch](https://github.com/mapbox/pixelmatch) from 5.0.2 to 5.1.0.
- [Release notes](https://github.com/mapbox/pixelmatch/releases)
- [Commits](https://github.com/mapbox/pixelmatch/compare/v5.0.2...v5.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-28 08:14:17 +00:00
Andreas Hocevar
ced327e9a0 Merge pull request #10210 from openlayers/dependabot/npm_and_yarn/glob-7.1.5
Bump glob from 7.1.4 to 7.1.5
2019-10-28 09:14:06 +01:00
Andreas Hocevar
df1fcc0d90 Merge pull request #10209 from openlayers/dependabot/npm_and_yarn/karma-4.4.1
Bump karma from 4.1.0 to 4.4.1
2019-10-28 09:13:19 +01:00
Andreas Hocevar
b13cbe8cb8 Merge pull request #10207 from openlayers/dependabot/npm_and_yarn/ol-mapbox-style-5.0.2
Bump ol-mapbox-style from 5.0.0-beta.3 to 5.0.2
2019-10-28 09:12:19 +01:00
dependabot-preview[bot]
2abc88d41c Bump glob from 7.1.4 to 7.1.5
Bumps [glob](https://github.com/isaacs/node-glob) from 7.1.4 to 7.1.5.
- [Release notes](https://github.com/isaacs/node-glob/releases)
- [Changelog](https://github.com/isaacs/node-glob/blob/master/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v7.1.4...v7.1.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-28 07:55:53 +00:00
dependabot-preview[bot]
3e0494aa9e Bump karma from 4.1.0 to 4.4.1
Bumps [karma](https://github.com/karma-runner/karma) from 4.1.0 to 4.4.1.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v4.1.0...v4.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-28 07:55:02 +00:00
dependabot-preview[bot]
aa5487b67b Bump ol-mapbox-style from 5.0.0-beta.3 to 5.0.2
Bumps [ol-mapbox-style](https://github.com/openlayers/ol-mapbox-style) from 5.0.0-beta.3 to 5.0.2.
- [Release notes](https://github.com/openlayers/ol-mapbox-style/releases)
- [Changelog](https://github.com/openlayers/ol-mapbox-style/blob/master/CHANGELOG.md)
- [Commits](https://github.com/openlayers/ol-mapbox-style/compare/v5.0.0-beta.3...v5.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-28 07:52:59 +00:00
Tim Schaub
76333f72ba Merge pull request #10204 from tschaub/doc-layout
Avoid scrolling over navigation
2019-10-27 17:05:39 -06:00
Tim Schaub
3ac08bcbef Merge pull request #10205 from tschaub/inline-default
Add the default to the type column
2019-10-27 17:04:17 -06:00
Andreas Hocevar
15a64e657d Merge pull request #10178 from TieSKey/master
Make ol/interaction/Select#handleEvent return always true.
2019-10-27 22:58:39 +01:00
TigerShark
4f0431edd5 Restore pointerMove in condition.js and example.
Wrongly removed on previous commit as pointed by @ahocevar.
2019-10-27 11:45:53 -03:00
Tim Schaub
0f87df0ade Add the default to the type column 2019-10-26 17:27:04 -06:00
Tim Schaub
1c21853269 Avoid scrolling over navigation 2019-10-26 16:56:14 -06:00
Tim Schaub
1cd9256771 Merge pull request #10203 from tschaub/exempt-milestones
Keep issues assigned to a milestone from going stale
2019-10-26 16:29:28 -06:00
Tim Schaub
fcb95ced5f Merge pull request #10200 from tschaub/carbon
Carbon add on API docs
2019-10-26 13:11:21 -06:00
Tim Schaub
ffab886964 Keep issues assigned to a milestone from going stale 2019-10-26 13:10:16 -06:00
Tim Schaub
27cbbaf97b Less jumpy 2019-10-26 12:30:38 -06:00
Tim Schaub
c0831cc64b Carbon add on API docs 2019-10-26 11:11:04 -06:00
Olivier Guyot
c40263c38b Merge pull request #10196 from jahow/webgl-add-string-operators
Webgl / add support for string and arrays in style expressions
2019-10-25 17:27:39 +02:00
Frederic Junod
daaf9695ff Add assertNumbers function in ol/style/expressions 2019-10-25 15:46:49 +02:00
Andreas Hocevar
5d358a7367 Merge pull request #10197 from ahocevar/restore-node8-compatibility
Restore node v8 compatibility
2019-10-25 15:21:23 +02:00
Andreas Hocevar
80abb8fb15 Merge pull request #10195 from mike-000/patch-2
Treat hsl/hsla as named colors
2019-10-25 15:17:30 +02:00
Olivier Guyot
e63bb45e6f Webgl points layer / allow disabling hit detection
Having hit detection enabled has an overhead as it means
continously generating additional render instructions and rendering
to an offscreen canvas
2019-10-25 15:11:37 +02:00
Andreas Hocevar
edc02dbde2 Restore node v8 compatibility 2019-10-25 15:11:11 +02:00
Olivier Guyot
4462608991 Expressions / adds color and array conversion operators
Also fixes existing error throwingtests which were essentially doing nothing.
2019-10-25 14:55:44 +02:00
Olivier Guyot
ff3cc9b4d0 Expressions / renamed operator pow to ^
To be more in line with Mapbox style spec
2019-10-25 14:55:44 +02:00
Olivier Guyot
a844691d7b Added new example styles in the webgl points layer example 2019-10-25 14:55:44 +02:00
Olivier Guyot
acf973751b Webgl / added time and resolution as default uniforms
Also added the `zoom` and `resolution` style operators
2019-10-25 14:55:44 +02:00
Olivier Guyot
e843b2cfc0 Expressions / adaptation and cleanup after stretch operator removal
The examples have been fixed as well.
2019-10-25 14:55:44 +02:00
Olivier Guyot
719495587c Expressions / rework the interpolate operator
This operator is now able to map numbers to output ranges as well as colors,
making the stretch operator unnecessary. Also allows giving multiple stops,
like in Mapbox style spec.
2019-10-25 14:55:44 +02:00
Olivier Guyot
9e010631c1 Expressions / refactor operators to avoid linting errors
Previously the utilities used the Operators dict before its definition.
2019-10-25 14:55:44 +02:00
Olivier Guyot
a64f2eb720 Update the icon-sprite-webgl example to use a WebGLPoints layer 2019-10-25 14:55:44 +02:00
Olivier Guyot
d643951a74 Shader Builder / add option to generate hit detection shaders 2019-10-25 14:55:44 +02:00
Olivier Guyot
a39f751981 Shader Builder / adapt logic & test to the new expression types
Also fixes a sneaky bug where the two last texture coordinates were inverted.
2019-10-25 14:55:44 +02:00
Olivier Guyot
fc98704bcb Expressions / adds a test for a complex combination of operators 2019-10-25 14:55:44 +02:00
Olivier Guyot
27c530ec64 Expressions / introduce the match operator
This operator allows mapping from input values to output values of different
kinds and handles variable arguments count.
2019-10-25 14:55:44 +02:00
Olivier Guyot
e3f7d29bb2 Expressions / add utilities for using strings in GLSL & more type checking
It is now possible to specify a type hint when parsing an expression, which
helps determine the output value type.

When no single output type can be inferred, an error is thrown.

For strings, every literal value will be replaced by a number and a map of
these associations will be kept in the parsing context, which is passed
recursively.
2019-10-25 14:55:44 +02:00
Olivier Guyot
44347a9ed3 Adapt the icon-sprite-webgl example to the new expressions module 2019-10-25 14:55:44 +02:00
Olivier Guyot
31dae929f5 ShaderBuilder / adapt logic & tests to new expressions module 2019-10-25 14:55:44 +02:00
Olivier Guyot
5712792772 Expressions / add more tests for conversion to GLSL 2019-10-25 14:55:44 +02:00
Olivier Guyot
bcf7649b9a Expressions / store the variables & attributes in the context 2019-10-25 14:55:44 +02:00
Olivier Guyot
7e4119d580 Expressions / restored the parsing logic with better type checking
Converting expressions to GLSL is now done in ol/style/expressions, with the
same logic as before in ol/webgl/ShaderBuilder.
2019-10-25 14:55:44 +02:00
Olivier Guyot
72903d6454 Expressions / added operator declarations & type checking logic 2019-10-25 14:55:44 +02:00
Olivier Guyot
35af80b433 Style / add an ol/style/expressions module
This module will contain the utilities and operator declarations
for literal style expressions, boh for type checking and parsing
2019-10-25 14:55:44 +02:00
mike-000
ad6d91b9ae Treat hsl/hsla as named colors
hsl/hsla values produce an assertion error in fromStringInternal_  This simplest solution is to treat them as named colors.
2019-10-25 13:31:18 +01:00
Jakob Gerstmayer
37cbb8e43e fixed spacing issues 2019-10-25 12:06:15 +02:00
Jakob Gerstmayer
e0329febc4 Added check to make sure extent array has four objects. 2019-10-25 11:43:18 +02:00
Andreas Hocevar
cff00f1c3b Merge pull request #10188 from ahocevar/renderevent-docs
Document that map render events do not have a context set
2019-10-24 17:14:40 +02:00
Andreas Hocevar
61c4fa8cd6 Document that map render events do not have a context set 2019-10-24 16:32:04 +02:00
Andreas Hocevar
cc24ec1be6 Set touch-action to allow page scrolling 2019-10-24 16:18:40 +02:00
Frédéric Junod
2b0256140e Merge pull request #10184 from fredj/heatmap_weight
Clamp the weight value between 0 and 1
2019-10-24 15:34:17 +02:00
Frederic Junod
88bbb8c1ae Clamp the weight value between 0 and 1 2019-10-24 13:52:59 +02:00
TigerShark
e60dc93e0e Make ol/interaction/Select#handleEvent return always true.
Previously it was returning true only if the event was a pointerMove
which prevented multiple Select objects with other event types from
working.
2019-10-23 17:30:56 -03:00
Tim Schaub
599835e818 Merge pull request #10175 from tschaub/untagged
Remove description from type tag
2019-10-23 13:57:15 -06:00
Tim Schaub
afa688273b Merge pull request #10176 from tschaub/toggle
Avoid toggling when clicking the title
2019-10-23 13:56:58 -06:00
Tim Schaub
6b4e00e6ac Remove description from type tag 2019-10-23 10:27:56 -06:00
Tim Schaub
10379920d2 Avoid toggling when clicking the title 2019-10-23 10:26:21 -06:00
Andreas Hocevar
ebae0386bd Merge pull request #10172 from ahocevar/apidoc-geometry-inherited
Ensure inherited docs are shown
2019-10-23 15:40:08 +02:00
Andreas Hocevar
bf7af07657 Ensure inherited docs are shown 2019-10-23 14:40:27 +02:00
Andreas Hocevar
327fe11344 Merge pull request #10171 from mike-000/patch-1
Open default attributions links in a new tab or window
2019-10-23 13:48:05 +02:00
Andreas Hocevar
319efedb14 Merge pull request #10047 from KaiVolland/apidoc-changes
Apidoc changes
2019-10-23 13:41:03 +02:00
Andreas Hocevar
4fe16d0281 Tidy up navigation 2019-10-23 13:26:56 +02:00
mike-000
ce8b63a67e Open default attributions links in new tab/window 2019-10-23 12:10:55 +01:00
mike-000
6b25f713cd Open default attributions links in new tab/window 2019-10-23 12:08:40 +01:00
mike-000
4b79818797 Open default attributions links in new tab/window 2019-10-23 12:03:01 +01:00
Andreas Hocevar
062614388c Merge pull request #10161 from ahocevar/vectorimage-getfeatures
Implement getFeatures() for ol/layer/VectorImage
2019-10-23 11:26:08 +02:00
Olivier Guyot
8c5be52462 Merge pull request #10168 from jahow/webgl-style-add-filter
Webgl / Add support for filtering and color interpolation in style expressions
2019-10-23 09:45:16 +02:00
Frédéric Junod
b6d694050e Merge pull request #10170 from openlayers/select-feature_html
Add back html from select-features example
2019-10-23 09:24:43 +02:00
Olivier Guyot
fc555241ea ShaderBuilder / simplify check/parse code a bit 2019-10-23 09:22:12 +02:00
Frederic Junod
33b0f88771 Add back html from select-features example
The example was removed and added back in 38124d770b but the html file was missing
2019-10-23 09:03:19 +02:00
Olivier Guyot
1fe5a68e16 Fix the triangles style in the wbegl-points-layer example 2019-10-22 23:27:26 +02:00
Olivier Guyot
948003ff27 Rewrite to filter-points-webgl example to use a Webgl points layer
The demonstrated features have been recreated using a literal
style (filtering, pulse animation).
2019-10-22 23:17:00 +02:00
Olivier Guyot
d837166a1b Literal Style / add new math operators 2019-10-22 23:17:00 +02:00
Olivier Guyot
c659c05de8 ShaderBuilder / fix stretch operator GLSL expression 2019-10-22 23:17:00 +02:00
Olivier Guyot
485ade42b5 Literal Style / add support for color interpolation 2019-10-22 23:17:00 +02:00
Olivier Guyot
85c3aae454 ShaderBuilder / add support for color interpolation in parse 2019-10-22 23:17:00 +02:00
Olivier Guyot
a29fc016f5 ShaderBuilder / formatColor/Array utilities now output vecX(...) 2019-10-22 23:17:00 +02:00
Olivier Guyot
19eadaea24 Shader Builder / add type checking in expressions parsing
All expressions will now be type checked before actually being parsed.
2019-10-22 23:17:00 +02:00
Olivier Guyot
b8e8d30df0 Shader Builder / add utilities for checking an expression type
Type checking is done either against a literal value (number, string...)
or against the operator in case of an expression.

Sometimes it is not possible to infer only one type, for example
the value 'transparent' could either be a color or a string. This
is covered by the fact that all operators expect exactly one type
for their arguments.
2019-10-22 23:17:00 +02:00
Olivier Guyot
f43637cc33 Shader Builder / support strings in formatColor 2019-10-22 23:17:00 +02:00
Olivier Guyot
56faf4c3ad Color / add an isStringColor utility function 2019-10-22 23:17:30 +02:00
Olivier Guyot
a0b271a812 Literal Style / add support for variables in the style
These variables are accessed using the `var` operator, and are meant
to be mutated directly in the style object. When doing so,
the new value will always be used for the render.

This is intended to be used for modifying the style through external
parameters such as an input field, a slider, mouse position etc.
2019-10-22 23:17:00 +02:00
Olivier Guyot
a1c00744d1 Webgl points renderer / throw if shader compilation fails
This should only happen if providing handcrafted shaders to the renderer.
2019-10-22 23:17:00 +02:00
Olivier Guyot
94b8cf6af3 Webgl / add support for a time operator in literal styles
This required adding `u_time` as one of the default uniforms provided by the
webgl helper.
2019-10-22 23:17:23 +02:00
Olivier Guyot
0c0c8c5d56 Literal Style / add support for a filter property 2019-10-22 23:17:00 +02:00
Andreas Hocevar
fef4d4e9b7 Merge pull request #10093 from mike-000/patch-3
Set label text for Graticule option styles
2019-10-22 15:23:01 +02:00
Tim Schaub
8e4fbe3e74 Merge pull request #10160 from ejn/minor/improve-test-10158
Improve test in case of async call
2019-10-22 07:06:36 -06:00
mike-000
110c17cf9e Remove label style caches 2019-10-22 12:04:06 +01:00
Olivier Guyot
e38250ee14 ShaderBuilder / add fragment discard expression in shader params 2019-10-22 11:39:30 +02:00
Andreas Hocevar
39012a58f8 Implement getFeatures() for ol/layer/VectorImage 2019-10-22 11:27:26 +02:00
Olivier Guyot
7b66b294a8 ShaderBuilder / attempt to clarify the way attributes are handled in parseSymbolStyle 2019-10-22 11:18:39 +02:00
Olivier Guyot
9ee93cd2cf ShaderBuilder / refactoring to use an actual builder pattern
There is now a ShaderBuilder class with chainable methods
to specify more easily the contents of the final shaders.
This is to avoid passing around large objects to different functions,
and allow for a richer API.

The documentation has also been corrected and clarified.
2019-10-22 11:12:06 +02:00
Edward Nash
ed18310136 Improve test in case of async call 2019-10-22 10:21:52 +02:00
Andreas Hocevar
a3c137cff1 Merge pull request #10159 from ejn/bugfix/10158-target-name-collision
Fix target name collision in event.Target and Control
2019-10-22 09:53:19 +02:00
Edward Nash
9eb4816b27 Fix property name collision target_ with Control
* As described in #10158, Control uses the property target_ for
   a custom parent HTMLElement, leading to Events on the Control being
   dispatched with that as the target and not the Control itself.

 * Solved by renaming the target_ property on Target to eventTarget_
2019-10-22 09:37:05 +02:00
Edward Nash
ee653a8e0d Add regression test for event target on Control
* Check possible name collision of target element with EventTarget
2019-10-22 09:37:05 +02:00
mike-000
7edd10d66f Test that label text is set in styles 2019-10-21 16:00:54 +01:00
Frédéric Junod
e0cab3d3ba Merge pull request #10157 from openlayers/dependabot/npm_and_yarn/karma-coverage-istanbul-reporter-2.1.0
Bump karma-coverage-istanbul-reporter from 2.0.5 to 2.1.0
2019-10-21 16:01:30 +02:00
Frédéric Junod
34ed3c684e Merge pull request #10155 from openlayers/dependabot/npm_and_yarn/types/pbf-3.0.2
Bump @types/pbf from 3.0.1 to 3.0.2
2019-10-21 15:42:55 +02:00
Frédéric Junod
d0811ea286 Merge pull request #10153 from openlayers/dependabot/npm_and_yarn/yargs-14.2.0
Bump yargs from 14.0.0 to 14.2.0
2019-10-21 15:42:37 +02:00
Frédéric Junod
54c5330203 Merge pull request #10154 from openlayers/dependabot/npm_and_yarn/babel/core-7.6.4
Bump @babel/core from 7.4.4 to 7.6.4
2019-10-21 15:42:03 +02:00
dependabot-preview[bot]
09768c6634 Bump karma-coverage-istanbul-reporter from 2.0.5 to 2.1.0
Bumps [karma-coverage-istanbul-reporter](https://github.com/mattlewis92/karma-coverage-istanbul-reporter) from 2.0.5 to 2.1.0.
- [Release notes](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/releases)
- [Changelog](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/compare/v2.0.5...v2.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 13:33:34 +00:00
dependabot-preview[bot]
dfdb498d0d Bump @types/pbf from 3.0.1 to 3.0.2
Bumps [@types/pbf](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/pbf) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/pbf)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 13:32:16 +00:00
dependabot-preview[bot]
d1aec83ca2 Bump @babel/core from 7.4.4 to 7.6.4
Bumps [@babel/core](https://github.com/babel/babel) from 7.4.4 to 7.6.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.4.4...v7.6.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 13:31:44 +00:00
dependabot-preview[bot]
2937513cb3 Bump yargs from 14.0.0 to 14.2.0
Bumps [yargs](https://github.com/yargs/yargs) from 14.0.0 to 14.2.0.
- [Release notes](https://github.com/yargs/yargs/releases)
- [Changelog](https://github.com/yargs/yargs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/yargs/compare/v14.0.0...v14.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 13:31:06 +00:00
Frédéric Junod
b46e985af0 Merge pull request #10151 from openlayers/dependabot/npm_and_yarn/rollup-plugin-babel-4.3.3
Bump rollup-plugin-babel from 4.3.2 to 4.3.3
2019-10-21 15:05:07 +02:00
dependabot-preview[bot]
e50662f0a1 Bump rollup-plugin-babel from 4.3.2 to 4.3.3
Bumps [rollup-plugin-babel](https://github.com/rollup/rollup-plugin-babel) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/rollup/rollup-plugin-babel/releases)
- [Changelog](https://github.com/rollup/rollup-plugin-babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup-plugin-babel/compare/v4.3.2...v4.3.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 12:22:12 +00:00
Frédéric Junod
bcdb191de2 Merge pull request #10148 from openlayers/dependabot/npm_and_yarn/rollup-plugin-node-resolve-5.2.0
Bump rollup-plugin-node-resolve from 5.0.0 to 5.2.0
2019-10-21 14:19:56 +02:00
dependabot-preview[bot]
775bf82631 Bump rollup-plugin-node-resolve from 5.0.0 to 5.2.0
Bumps [rollup-plugin-node-resolve](https://github.com/rollup/rollup-plugin-node-resolve) from 5.0.0 to 5.2.0.
- [Release notes](https://github.com/rollup/rollup-plugin-node-resolve/releases)
- [Changelog](https://github.com/rollup/rollup-plugin-node-resolve/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup-plugin-node-resolve/compare/v5.0.0...v5.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 12:06:29 +00:00
Frédéric Junod
fc9123947d Merge pull request #10150 from openlayers/dependabot/npm_and_yarn/copy-webpack-plugin-5.0.4
Bump copy-webpack-plugin from 5.0.3 to 5.0.4
2019-10-21 14:06:22 +02:00
Frédéric Junod
636c65da69 Merge pull request #10149 from openlayers/dependabot/npm_and_yarn/rbush-3.0.1
Bump rbush from 3.0.0 to 3.0.1
2019-10-21 14:05:08 +02:00
Frédéric Junod
adcbd0bb50 Merge pull request #10147 from openlayers/dependabot/npm_and_yarn/rollup-1.25.1
Bump rollup from 1.12.0 to 1.25.1
2019-10-21 14:04:18 +02:00
dependabot-preview[bot]
89c0eaef8d Bump copy-webpack-plugin from 5.0.3 to 5.0.4
Bumps [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/webpack-contrib/copy-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/copy-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v5.0.3...v5.0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 11:55:42 +00:00
dependabot-preview[bot]
889eef66c1 Bump rbush from 3.0.0 to 3.0.1
Bumps [rbush](https://github.com/mourner/rbush) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/mourner/rbush/releases)
- [Commits](https://github.com/mourner/rbush/compare/v3.0.0...v3.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 11:55:03 +00:00
dependabot-preview[bot]
de851e9b29 Bump rollup from 1.12.0 to 1.25.1
Bumps [rollup](https://github.com/rollup/rollup) from 1.12.0 to 1.25.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v1.12.0...v1.25.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-21 11:53:47 +00:00
Andreas Hocevar
cb6b716b98 Merge pull request #10145 from openlayers/greenkeeper/handlebars-4.4.5
Greenkeeper/handlebars 4.4.5
2019-10-21 12:02:35 +02:00
greenkeeper[bot]
2980a0a168 chore(package): update lockfile package-lock.json 2019-10-20 21:11:28 +00:00
greenkeeper[bot]
829aac1860 chore(package): update handlebars to version 4.4.5
Closes #10081
2019-10-20 21:11:23 +00:00
Andreas Hocevar
3d351a53e6 Merge pull request #10142 from ahocevar/fix-tilechange-events
Fix tilechange events
2019-10-19 09:06:12 +02:00
Tim Schaub
a0ceebfb2f Merge pull request #10132 from openlayers/greenkeeper/webpack-4.41.2
Update webpack to the latest version 🚀
2019-10-18 21:46:42 -06:00
Tim Schaub
a9d93fe151 Merge pull request #10143 from openlayers/greenkeeper/mocha-6.2.2
Update mocha to the latest version 🚀
2019-10-18 21:46:17 -06:00
greenkeeper[bot]
b4257779f1 chore(package): update lockfile package-lock.json 2019-10-18 21:17:40 +00:00
greenkeeper[bot]
0f3778ce00 chore(package): update mocha to version 6.2.2 2019-10-18 21:17:31 +00:00
Andreas Hocevar
36a366bfeb Do not stop event propagation in prepareTile 2019-10-18 20:50:01 +02:00
Olivier Guyot
95bcb574b7 Merge pull request #10138 from wirdehall/master
Should be able to ovveride defaultvalue of style in selection.
2019-10-18 09:57:55 +02:00
wirdehall
bd5510b62a Updated docs for Select style.
Updated docs for Select style with new option of false.
2019-10-18 00:20:05 +02:00
wirdehall
a34e7ddd99 Should be able to ovveride defaultvalue of style in selection.
null or false should be able to prevent overriding the style.
As discussed here: https://github.com/openlayers/openlayers/issues/10131
2019-10-17 15:05:30 +02:00
Tim Schaub
1de0d09acb Merge pull request #10135 from mike-000/patch-1
Revise the description of applyTransform for geometries
2019-10-16 12:54:32 -06:00
mike-000
2b1417df3f Revise the description of applyTransform
Revise the description of applyTransform and transformFn (loosely based on that used in ol/extent) to avoid any misunderstanding that the function is called inside a forEach method.
2019-10-16 13:59:38 +01:00
Andreas Hocevar
cfac31799b Merge pull request #10133 from ahocevar/unlisten-source-change
Properly unregister source tile change listeners
2019-10-15 23:16:18 +02:00
Andreas Hocevar
61fc71c30f Properly unregister source tile change listeners 2019-10-15 21:23:37 +02:00
greenkeeper[bot]
9f3052211b chore(package): update lockfile package-lock.json 2019-10-15 13:46:36 +00:00
greenkeeper[bot]
4450981b0d chore(package): update webpack to version 4.41.2 2019-10-15 13:46:30 +00:00
Andreas Hocevar
54884314ee Merge pull request #10094 from ahocevar/immediate-hitdetection
New Layer#getFeatures method with fast hit detection
2019-10-14 22:21:08 +02:00
Frédéric Junod
a75ea2cc6b Merge pull request #10117 from openlayers/greenkeeper/pbf-3.2.1
Update pbf to the latest version 🚀
2019-10-14 15:35:22 +02:00
Frédéric Junod
aba93e7b9c Merge pull request #10104 from openlayers/attribution_font_size
Remove font sizing from the attribution control
2019-10-14 15:28:02 +02:00
Andreas Hocevar
90d6a6f441 Move hit detection to its own module 2019-10-14 14:40:06 +02:00
Andreas Hocevar
7454df0c2f Resolve empty when tile not loaded yet 2019-10-14 14:13:57 +02:00
Frederic Junod
a126702e95 Add back max-width for the attribution control in examples 2019-10-14 09:24:18 +02:00
Tim Schaub
dd788b406c Merge pull request #10114 from openlayers/greenkeeper/coveralls-3.0.7
Update coveralls to the latest version 🚀
2019-10-13 08:02:53 -06:00
Tim Schaub
c97a26ae26 Merge pull request #10116 from openlayers/greenkeeper/webpack-4.41.1
Update webpack to the latest version 🚀
2019-10-13 08:02:06 -06:00
Tim Schaub
f475387d39 Merge pull request #10108 from notnotse/issue/9814-fix-documentation-for-handlemoveevent
Fix documentation for handleMoveEvent
2019-10-12 08:14:39 -06:00
Tim Schaub
5af4dfa623 Merge pull request #10118 from mike-000/patch-7
Document the OSM crossOrigin default
2019-10-12 08:13:17 -06:00
Andreas Hocevar
e3666f18da Merge pull request #10112 from ahocevar/rendertile-no-error
No ERROR state for render tiles
2019-10-11 21:52:12 +02:00
mike-000
046b78cca7 Document the OSM crossOrigin default 2019-10-11 18:16:19 +01:00
greenkeeper[bot]
b349058c58 chore(package): update lockfile package-lock.json 2019-10-11 14:50:07 +00:00
greenkeeper[bot]
8a53947f44 fix(package): update pbf to version 3.2.1 2019-10-11 14:50:02 +00:00
Olivier Guyot
9acba8f82a Merge pull request #10115 from jahow/improve-heatmap-test
Improve Heatmap hit detection test
2019-10-11 16:40:07 +02:00
Andreas Hocevar
0cb9d73848 No ERROR state for render tiles 2019-10-11 14:58:22 +02:00
greenkeeper[bot]
7069e2688d chore(package): update lockfile package-lock.json 2019-10-11 12:26:52 +00:00
greenkeeper[bot]
0c72fce1ff chore(package): update webpack to version 4.41.1 2019-10-11 12:26:47 +00:00
Olivier Guyot
87414256e2 Heatmap / use worker events instead of timeout for test 2019-10-11 14:06:27 +02:00
greenkeeper[bot]
9e7e15ed5c chore(package): update lockfile package-lock.json 2019-10-10 23:19:36 +00:00
greenkeeper[bot]
68850c7ddc chore(package): update coveralls to version 3.0.7 2019-10-10 23:19:29 +00:00
Frédéric Junod
f277206631 Merge pull request #10111 from mike-000/patch-6
Correct the defaulting of ol/source/VectorTile maxZoom
2019-10-10 16:05:51 +02:00
mike-000
2a2cc40d42 Correct the defaulting of maxZoom
Only default if undefined as maxZoom: 0 should be valid as it is for all other tile sources
2019-10-10 14:08:10 +01:00
Bobo Häggström
395b59c01e Fix documentation for handleMoveEvent
This fixes #9814
2019-10-10 10:40:47 +02:00
Frédéric Junod
58b4b6eeea Merge pull request #10102 from KlausBenndorf/type-fixes
Cosmetic type fixes
2019-10-10 09:43:53 +02:00
Simon Seyock
5b1106ac23 some type corrections 2019-10-10 09:07:35 +02:00
Frédéric Junod
2483fbd26b Merge pull request #10107 from mike-000/patch-5
Update Vector Tile Info example test for no features
2019-10-10 08:47:40 +02:00
Frédéric Junod
736ef88473 Merge pull request #10097 from fredj/text-align
Align layer canvas to the left
2019-10-10 08:31:36 +02:00
Andreas Hocevar
873999ec7d Merge pull request #10105 from openlayers/greenkeeper/jsdoc-plugin-typescript-2.0.4
Update jsdoc-plugin-typescript to the latest version 🚀
2019-10-09 20:19:51 +02:00
mike-000
cbf0ecfd75 Update test for no features 2019-10-09 18:25:04 +01:00
Frederic Junod
97ded06ee4 Remove attribution control custom style in examples 2019-10-09 16:48:19 +02:00
greenkeeper[bot]
782ff6e9f5 chore(package): update lockfile package-lock.json 2019-10-09 14:45:37 +00:00
greenkeeper[bot]
dc2137b622 chore(package): update jsdoc-plugin-typescript to version 2.0.4 2019-10-09 14:45:32 +00:00
Frederic Junod
c5eb80e610 Remove font sizing from the attribution control 2019-10-09 14:19:24 +02:00
Olivier Guyot
d1ee300968 Merge pull request #10101 from jahow/add-heatmap-hit-detection
Add hit detection support on the Heatmap layer
2019-10-08 14:45:53 +02:00
Olivier Guyot
b44a6ab26a Heatmap / add hit detection shaders 2019-10-08 13:27:31 +02:00
Kai Volland
3cb0aae796 Removes modulelink 2019-10-08 10:12:29 +02:00
Kai Volland
490bef8d40 Readds modules without classes to navigation 2019-10-08 10:12:12 +02:00
Andreas Hocevar
f477fc18f2 Add tests 2019-10-08 08:23:38 +02:00
Andreas Hocevar
3c243b0236 getFeature() for VectorTile layer 2019-10-08 08:23:38 +02:00
Andreas Hocevar
e9785317eb Move hit detection code to Immediate.js 2019-10-08 08:23:38 +02:00
Andreas Hocevar
315695eeb8 New Layer#getFeatures method with fast hit detection for VectorLayer 2019-10-08 08:23:38 +02:00
Frederic Junod
f20db28901 Align layer canvas to the left
So that the position is not affected by the `text-align` css rule.
2019-10-07 13:48:32 +02:00
Frederic Junod
2ce14a50a1 Add a rendering test case for text-align css property 2019-10-07 13:25:04 +02:00
Andreas Hocevar
057cc92716 Merge pull request #10087 from petrsloup/vector-tiles-4326-example
Add example showing vector tiles in EPSG:4326
2019-10-07 10:07:30 +02:00
Kai Volland
5786121cd5 Adapts linktext to module 2019-10-07 09:50:14 +02:00
mike-000
b727e4f45e Set label text for option styles
Set label text for lonLabelStyle and latLabelStyle options
2019-10-04 22:00:20 +01:00
Andreas Hocevar
fb9673465a Simpler way to use EPSG:4326 as projection 2019-10-04 14:07:13 +02:00
Andreas Hocevar
babdce4819 Merge pull request #10086 from petrsloup/update-mapbox-style-example
Update mapbox-style example
2019-10-03 20:39:47 +02:00
Petr Sloup
684e305bc8 Minor mapbox-style example docs update 2019-10-03 19:16:19 +02:00
Olivier Guyot
deb541791a Merge pull request #10083 from MoonE/example-webgl
webgl points layer example fixes
2019-10-03 17:43:22 +02:00
Maximilian Krög
db49842f63 Display error message instead of 'style not valid yet...' 2019-10-03 17:06:39 +02:00
Maximilian Krög
8fe8302dc2 Remove duplicate type definition for style 2019-10-03 15:45:35 +02:00
Maximilian Krög
b1a9f765fc Parse the style in the constructor.
This detects errors earlier and allows the caller to handle the thrown exception.
Remove assertion 65 as it should no longer be needed.
2019-10-03 14:36:48 +02:00
Petr Sloup
db583be0f9 Add example showing vector tiles in EPSG:4326 2019-10-03 13:00:47 +02:00
Maximilian Krög
d0cd1064ff Also check predefined styles for validity. 2019-10-03 03:02:58 +02:00
Maximilian Krög
b4a996e760 Catch errors in style definition
Do not replace the layer if the style is invalid.
Thrown errors are caught and the layer will not be changed.
2019-10-03 01:59:42 +02:00
Maximilian Krög
dee114d4c4 Guard against JSON.parse errors.
Also show successful style parse status after a style error was corrected
but it is the same style as previously.
2019-10-03 01:59:42 +02:00
Maximilian Krög
db34a338d6 Reset status message when selecting from select element. 2019-10-03 01:59:21 +02:00
Maximilian Krög
0eac5007e8 Reserve the height for the style parse messages. 2019-10-03 01:59:00 +02:00
Maximilian Krög
c1921a6b16 Preselect the 'circles' style in the select input
The text in the editor element already is from the circles style..
2019-10-03 01:57:49 +02:00
Maximilian Krög
dc28590cff Remove invalid option from style select
When this option was selected the text field contained 'undefined'
as it is not one of the predefined styles.
2019-10-03 01:48:45 +02:00
Frédéric Junod
3ab32ff744 Merge pull request #10076 from fredj/rm_typecast
Remove unnecessary typecast
2019-10-02 14:57:55 +02:00
Frederic Junod
daaaff5ac7 Remove unnecessary typecast
Remove typecast where typescript is able to correctly deduce the type.
2019-10-02 10:44:06 +02:00
Tim Schaub
fa0258a323 Merge pull request #10074 from mike-000/patch-2
Remove offsets from mouse position calculation
2019-10-01 09:29:47 -06:00
mike-000
4f83392b76 Remove offsets from mouse position calculation
and remove space
2019-10-01 15:55:30 +01:00
mike-000
8a04f5059d Remove offsets from mouse position calculation
Fixes #10073

Remove unneeded offsets from mouse position calculation as box position was centered in #9919
2019-10-01 15:47:36 +01:00
Frédéric Junod
92f70c225f Merge pull request #10072 from fredj/better_typing
Better typing
2019-10-01 15:27:27 +02:00
Frederic Junod
41b7893523 Mark properties as nullable 2019-10-01 10:47:07 +02:00
Frederic Junod
89becd4c6d Remove unused variables 2019-10-01 08:34:00 +02:00
Tim Schaub
7eb60fae23 Merge pull request #10070 from openlayers/release-v6.0.1
Changes for 6.0.1
2019-09-30 12:44:56 -06:00
Kai Volland
d08c0baff9 Introduces apidoc changes
- Removes modules from the apidoc navigation
- Adds a weight paramater to the search to be
more accurate on searchresults
2019-09-27 17:25:01 +02:00
Kai Volland
b045e4ee5b Removes unused *.less files 2019-09-27 17:19:19 +02:00
142 changed files with 5344 additions and 2158 deletions

7
.dependabot/config.yml Normal file
View File

@@ -0,0 +1,7 @@
# See https://dependabot.com/docs/config-file/
version: 1
update_configs:
- package_manager: "javascript"
directory: "/"
update_schedule: "weekly"
version_requirement_updates: "increase_versions_if_necessary"

2
.github/stale.yml vendored
View File

@@ -8,6 +8,8 @@ exemptLabels:
- regression
- bug
- 'pull request accepted'
# Issues assigned to a milestone will not go stale
exemptMilestones: true
# 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

86
changelog/v6.1.0.md Normal file
View File

@@ -0,0 +1,86 @@
# 6.1.0
With 47 pull requests, this release keeps up the momentum of the v6.x effort and brings several bug fixes, performance improvements and new features. In addition to that, we added some missing documentation to our API docs and gave them some usability improvements.
## New features
* A new, performance optimized hit detection API on the layer level, `Layer#getFeatures(pixel)` has been introduced. At this point it is implemented for vector, vector tile and image vector layers, and is recommended when performance is critical, e.g. for hit detection on mouseover.
* For the WebGLPoints layer, we made several additions to the style expressions system. This includes a `case` operator, support for array and string types, and type checking.
## List of all changes
* [#10214](https://github.com/openlayers/openlayers/pull/10214) - WebGL / Add 'case' operator for style expressions ([@jahow](https://github.com/jahow))
* [#10198](https://github.com/openlayers/openlayers/pull/10198) - WebGL renderer / use the specified loading strategy for the vector data ([@jahow](https://github.com/jahow))
* [#10212](https://github.com/openlayers/openlayers/pull/10212) - Add config file for dependabot ([@fredj](https://github.com/fredj))
* [#10187](https://github.com/openlayers/openlayers/pull/10187) - Set touch-action to allow native touch gestures ([@ahocevar](https://github.com/ahocevar))
* [#10194](https://github.com/openlayers/openlayers/pull/10194) - Added check to make sure extent array has four objects. ([@MrSoUndso](https://github.com/MrSoUndso))
* [#10204](https://github.com/openlayers/openlayers/pull/10204) - Avoid scrolling over navigation ([@tschaub](https://github.com/tschaub))
* [#10205](https://github.com/openlayers/openlayers/pull/10205) - Add the default to the type column ([@tschaub](https://github.com/tschaub))
* [#10178](https://github.com/openlayers/openlayers/pull/10178) - Make ol/interaction/Select#handleEvent return always true. ([@TieSKey](https://github.com/TieSKey))
* [#10203](https://github.com/openlayers/openlayers/pull/10203) - Keep issues assigned to a milestone from going stale ([@tschaub](https://github.com/tschaub))
* [#10200](https://github.com/openlayers/openlayers/pull/10200) - Carbon add on API docs ([@tschaub](https://github.com/tschaub))
* [#10196](https://github.com/openlayers/openlayers/pull/10196) - Webgl / add support for string and arrays in style expressions ([@jahow](https://github.com/jahow))
* [#10197](https://github.com/openlayers/openlayers/pull/10197) - Restore node v8 compatibility ([@ahocevar](https://github.com/ahocevar))
* [#10195](https://github.com/openlayers/openlayers/pull/10195) - Treat hsl/hsla as named colors ([@mike-000](https://github.com/mike-000))
* [#10188](https://github.com/openlayers/openlayers/pull/10188) - Document that map render events do not have a context set ([@ahocevar](https://github.com/ahocevar))
* [#10184](https://github.com/openlayers/openlayers/pull/10184) - Clamp the weight value between 0 and 1 ([@fredj](https://github.com/fredj))
* [#10175](https://github.com/openlayers/openlayers/pull/10175) - Remove description from type tag ([@tschaub](https://github.com/tschaub))
* [#10176](https://github.com/openlayers/openlayers/pull/10176) - Avoid toggling when clicking the title ([@tschaub](https://github.com/tschaub))
* [#10172](https://github.com/openlayers/openlayers/pull/10172) - Ensure inherited docs are shown ([@ahocevar](https://github.com/ahocevar))
* [#10171](https://github.com/openlayers/openlayers/pull/10171) - Open default attributions links in a new tab or window ([@mike-000](https://github.com/mike-000))
* [#10047](https://github.com/openlayers/openlayers/pull/10047) - Apidoc changes ([@KaiVolland](https://github.com/KaiVolland))
* [#10161](https://github.com/openlayers/openlayers/pull/10161) - Implement getFeatures() for ol/layer/VectorImage ([@ahocevar](https://github.com/ahocevar))
* [#10168](https://github.com/openlayers/openlayers/pull/10168) - Webgl / Add support for filtering and color interpolation in style expressions ([@jahow](https://github.com/jahow))
* [#10170](https://github.com/openlayers/openlayers/pull/10170) - Add back html from select-features example ([@openlayers](https://github.com/openlayers))
* [#10093](https://github.com/openlayers/openlayers/pull/10093) - Set label text for Graticule option styles ([@mike-000](https://github.com/mike-000))
* [#10160](https://github.com/openlayers/openlayers/pull/10160) - Improve test in case of async call ([@ejn](https://github.com/ejn))
* [#10159](https://github.com/openlayers/openlayers/pull/10159) - Fix target name collision in event.Target and Control ([@ejn](https://github.com/ejn))
* [#10142](https://github.com/openlayers/openlayers/pull/10142) - Fix tilechange events ([@ahocevar](https://github.com/ahocevar))
* [#10138](https://github.com/openlayers/openlayers/pull/10138) - Should be able to ovveride defaultvalue of style in selection. ([@wirdehall](https://github.com/wirdehall))
* [#10135](https://github.com/openlayers/openlayers/pull/10135) - Revise the description of applyTransform for geometries ([@mike-000](https://github.com/mike-000))
* [#10133](https://github.com/openlayers/openlayers/pull/10133) - Properly unregister source tile change listeners ([@ahocevar](https://github.com/ahocevar))
* [#10094](https://github.com/openlayers/openlayers/pull/10094) - New Layer#getFeatures method with fast hit detection ([@ahocevar](https://github.com/ahocevar))
* [#10104](https://github.com/openlayers/openlayers/pull/10104) - Remove font sizing from the attribution control ([@openlayers](https://github.com/openlayers))
* [#10108](https://github.com/openlayers/openlayers/pull/10108) - Fix documentation for handleMoveEvent ([@notnotse](https://github.com/notnotse))
* [#10118](https://github.com/openlayers/openlayers/pull/10118) - Document the OSM crossOrigin default ([@mike-000](https://github.com/mike-000))
* [#10112](https://github.com/openlayers/openlayers/pull/10112) - No ERROR state for render tiles ([@ahocevar](https://github.com/ahocevar))
* [#10115](https://github.com/openlayers/openlayers/pull/10115) - Improve Heatmap hit detection test ([@jahow](https://github.com/jahow))
* [#10111](https://github.com/openlayers/openlayers/pull/10111) - Correct the defaulting of ol/source/VectorTile maxZoom ([@mike-000](https://github.com/mike-000))
* [#10102](https://github.com/openlayers/openlayers/pull/10102) - Cosmetic type fixes ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#10107](https://github.com/openlayers/openlayers/pull/10107) - Update Vector Tile Info example test for no features ([@mike-000](https://github.com/mike-000))
* [#10097](https://github.com/openlayers/openlayers/pull/10097) - Align layer canvas to the left ([@fredj](https://github.com/fredj))
* [#10101](https://github.com/openlayers/openlayers/pull/10101) - Add hit detection support on the Heatmap layer ([@jahow](https://github.com/jahow))
* [#10087](https://github.com/openlayers/openlayers/pull/10087) - Add example showing vector tiles in EPSG:4326 ([@petrsloup](https://github.com/petrsloup))
* [#10086](https://github.com/openlayers/openlayers/pull/10086) - Update mapbox-style example ([@petrsloup](https://github.com/petrsloup))
* [#10083](https://github.com/openlayers/openlayers/pull/10083) - webgl points layer example fixes ([@MoonE](https://github.com/MoonE))
* [#10076](https://github.com/openlayers/openlayers/pull/10076) - Remove unnecessary typecast ([@fredj](https://github.com/fredj))
* [#10074](https://github.com/openlayers/openlayers/pull/10074) - Remove offsets from mouse position calculation ([@mike-000](https://github.com/mike-000))
* [#10072](https://github.com/openlayers/openlayers/pull/10072) - Better typing ([@fredj](https://github.com/fredj))
<details>
<summary>Dependency Updates</summary>
* [#10208](https://github.com/openlayers/openlayers/pull/10208) - Bump pixelmatch from 5.0.2 to 5.1.0 ([@openlayers](https://github.com/openlayers))
* [#10210](https://github.com/openlayers/openlayers/pull/10210) - Bump glob from 7.1.4 to 7.1.5 ([@openlayers](https://github.com/openlayers))
* [#10209](https://github.com/openlayers/openlayers/pull/10209) - Bump karma from 4.1.0 to 4.4.1 ([@openlayers](https://github.com/openlayers))
* [#10207](https://github.com/openlayers/openlayers/pull/10207) - Bump ol-mapbox-style from 5.0.0-beta.3 to 5.0.2 ([@openlayers](https://github.com/openlayers))
* [#10157](https://github.com/openlayers/openlayers/pull/10157) - Bump karma-coverage-istanbul-reporter from 2.0.5 to 2.1.0 ([@openlayers](https://github.com/openlayers))
* [#10155](https://github.com/openlayers/openlayers/pull/10155) - Bump @types/pbf from 3.0.1 to 3.0.2 ([@openlayers](https://github.com/openlayers))
* [#10153](https://github.com/openlayers/openlayers/pull/10153) - Bump yargs from 14.0.0 to 14.2.0 ([@openlayers](https://github.com/openlayers))
* [#10154](https://github.com/openlayers/openlayers/pull/10154) - Bump @babel/core from 7.4.4 to 7.6.4 ([@openlayers](https://github.com/openlayers))
* [#10151](https://github.com/openlayers/openlayers/pull/10151) - Bump rollup-plugin-babel from 4.3.2 to 4.3.3 ([@openlayers](https://github.com/openlayers))
* [#10148](https://github.com/openlayers/openlayers/pull/10148) - Bump rollup-plugin-node-resolve from 5.0.0 to 5.2.0 ([@openlayers](https://github.com/openlayers))
* [#10150](https://github.com/openlayers/openlayers/pull/10150) - Bump copy-webpack-plugin from 5.0.3 to 5.0.4 ([@openlayers](https://github.com/openlayers))
* [#10149](https://github.com/openlayers/openlayers/pull/10149) - Bump rbush from 3.0.0 to 3.0.1 ([@openlayers](https://github.com/openlayers))
* [#10147](https://github.com/openlayers/openlayers/pull/10147) - Bump rollup from 1.12.0 to 1.25.1 ([@openlayers](https://github.com/openlayers))
* [#10145](https://github.com/openlayers/openlayers/pull/10145) - Greenkeeper/handlebars 4.4.5 ([@openlayers](https://github.com/openlayers))
* [#10132](https://github.com/openlayers/openlayers/pull/10132) - Update webpack to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10143](https://github.com/openlayers/openlayers/pull/10143) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10117](https://github.com/openlayers/openlayers/pull/10117) - Update pbf to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10114](https://github.com/openlayers/openlayers/pull/10114) - Update coveralls to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10116](https://github.com/openlayers/openlayers/pull/10116) - Update webpack to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10105](https://github.com/openlayers/openlayers/pull/10105) - Update jsdoc-plugin-typescript to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
</details>

17
changelog/v6.1.1.md Normal file
View File

@@ -0,0 +1,17 @@
# 6.1.1
Hot on the heels of OpenLayers 6.x, this patch release includes a few fixes for existing functionality. There should be nothing special needed to upgrade an application from 6.x to 6.1.1. See the 6.0.0 release notes for details on upgrading from an older version.
## Changes
* [#10235](https://github.com/openlayers/openlayers/pull/10235) - Various optimizations and fixes for the WebGL points renderer ([@jahow](https://github.com/jahow))
* [#10244](https://github.com/openlayers/openlayers/pull/10244) - Update to new eslint config with no-multi-assign ([@ahocevar](https://github.com/ahocevar))
* [#10243](https://github.com/openlayers/openlayers/pull/10243) - Store correct font value ([@ahocevar](https://github.com/ahocevar))
* [#10239](https://github.com/openlayers/openlayers/pull/10239) - Simpler container reuse ([@ahocevar](https://github.com/ahocevar))
* [#10237](https://github.com/openlayers/openlayers/pull/10237) - Fix layer zIndex test with falsy values ([@fredj](https://github.com/fredj))
* [#10221](https://github.com/openlayers/openlayers/pull/10221) - Fix for undefined Source ([@Kai-W](https://github.com/Kai-W))
* [#10228](https://github.com/openlayers/openlayers/pull/10228) - Use render tiles instead of source tiles for hit detection ([@ahocevar](https://github.com/ahocevar))
* [#10226](https://github.com/openlayers/openlayers/pull/10226) - ABORT reproj tiles properly ([@ahocevar](https://github.com/ahocevar))
* [#10224](https://github.com/openlayers/openlayers/pull/10224) - Vector tile hit detection fixes ([@ahocevar](https://github.com/ahocevar))
* [#10218](https://github.com/openlayers/openlayers/pull/10218) - Documentation fixes in ol/style/expressions ([@fredj](https://github.com/fredj))
* [#10216](https://github.com/openlayers/openlayers/pull/10216) - Update changelog script to recognize dependabot instead of greenkeeper ([@ahocevar](https://github.com/ahocevar))

View File

@@ -1,9 +0,0 @@
@navWidth: 250px;
@colorSubtitle: rgb(119, 156, 52);
@colorRed: rgb(238, 125, 125);
@colorLink: #2a6496;
@colorBgNavi: #2a2a2a;
.font-description () {
font-family: "freight-text-pro",Georgia,Cambria,"Times New Roman",Times,serif
}

View File

@@ -1,10 +0,0 @@
@import "common.less";
footer {
margin: 15px 0;
padding-top: 15px;
border-top: 1px solid #e1e1e1;
.font-description();
font-size: 0.8em;
color: gray;
}

View File

@@ -1,22 +0,0 @@
@import "common.less";
// normalize
html, body {
font: 1em "jaf-bernino-sans","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif;
background-color: #fff;
}
ul, ol {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
#wrap {
position: relative;
}
@import "navigation.less";
@import "main.less";
@import "footer.less";

View File

@@ -1,288 +0,0 @@
@import "common.less";
.main {
padding: 20px 20px;
margin-left: @navWidth;
.page-title {
display: none;
}
h1 {
font-weight: bold;
font-size: 1.6em;
margin: 0;
}
h2 {
font-weight: bold;
font-size: 1.5em;
margin: 0;
}
h3 {
font-weight: bold;
font-size: 12px;
margin: 5px 0;
}
h4 {
font-weight: bold;
font-size: 1em;
}
h5 {
font-weight: bold;
font-size: 12px;
}
dd {
font-size: 12px;
}
h4.name {
span.type-signature {
display: inline-block;
border-radius: 3px;
background-color: gray;
color: #fff;
font-size: 0.7em;
padding: 2px 4px;
}
span.type {
margin-left: 5px;
}
span.glyphicon {
display: inline-block;
vertical-align: middle;
color: #e1e1e1;
margin-left: 7px;
}
span.returnType {
margin-left: 3px;
background-color: transparent!important;
color: gray!important;
}
}
span.static {
display: inline-block;
border-radius: 3px;
background-color: @colorSubtitle!important;
color: #fff;
font-size: 0.7em;
padding: 2px 4px;
margin-right: 8px;
}
span.number {
background-color: #ccc!important;
color: #2fa2b1!important;
}
span.string {
background-color: #ccc!important;
color: #2fa2b1!important;
}
span.object {
background-color: #ccc!important;
color: #2fa2b1!important;
}
span.array {
background-color: #ccc!important;
color: #2fa2b1!important;
}
span.boolean {
background-color: #ccc!important;
color: #2fa2b1!important;
}
.subsection-title {
font-size: 14px;
margin-top: 30px;
color: @colorSubtitle;
}
.description {
margin-top: 10px;
// .font-description();
font-size: 13px;
p {
font-size: 13px;
}
}
.tag-source {
font-size: 12px;
}
dt.tag-source {
margin-top: 5px;
}
dt.tag-todo {
font-size: 10px;
display: inline-block;
background-color: @colorLink;
color: #fff;
padding: 2px 4px;
border-radius: 5px;
}
.type-signature {
font-size: 12px;
}
.tag-deprecated {
display: inline-block;
font-size: 10px;
}
.important {
background-color: @colorRed;
color: #fff;
padding: 2px 4px;
border-radius: 5px;
}
.nameContainer {
position: relative;
margin-top: 20px;
padding-top: 5px;
border-top: 1px solid #e1e1e1;
.inherited {
display: inline-block;
border-radius: 3px;
background-color: #888!important;
font-size: 0.7em;
padding: 2px 4px;
margin-right: 5px;
a {
color: #fff;
}
}
.tag-source {
position: absolute;
top: 17px;
right: 0;
font-size: 10px;
a {
color: gray;
}
}
&.inherited {
color: gray;
}
h4 {
margin-right: 150px;
line-height: 1.3;
.signature {
font-size: 13px;
font-weight: normal;
font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
}
}
}
pre {
font-size: 11px;
}
table {
width: 100%;
margin-bottom: 15px;
th {
padding: 3px 3px;
}
td {
vertical-align: top;
padding: 5px 3px;
}
.name {
width: 110px;
}
.type {
width: 60px;
color: #aaa;
font-size: 11px;
}
.attributes {
width: 80px;
color: #aaa;
font-size: 11px;
}
.description {
font-size: 12px;
p {
margin: 0;
}
}
.optional {
float: left;
border-radius: 3px;
background-color: #ddd!important;
font-size: 0.7em;
padding: 2px 4px;
margin-right: 5px;
color: gray;
}
}
.readme {
p {
margin-top: 15px;
line-height: 1.2;
font-size: 0.85em;
}
h1 {
font-size: 1.7em;
}
h2 {
margin-top: 30px;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #e1e1e1;
}
li {
font-size: 0.9em;
margin-bottom: 10px;
}
}
article {
ol, ul {
margin-left: 25px;
}
ol > li {
list-style-type: decimal;
margin-bottom: 5px;
}
ul > li {
margin-bottom: 5px;
list-style-type: disc;
}
}
}

View File

@@ -1,103 +0,0 @@
@import "common.less";
::-webkit-scrollbar {
width: 8px;
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: gray;
border-radius: 4px;
}
.navigation {
position: fixed;
float: left;
width: @navWidth;
height: 100%;
background-color: @colorBgNavi;
.applicationName {
margin: 0;
margin-top: 15px;
padding: 10px 15px;
font: bold 1.25em Helvetica;
color: #fff;
a {
color: #fff;
}
}
.search {
padding: 10px 15px;
input {
background-color: #333;
color: #fff;
border-color: #555;
}
}
.list {
padding: 10px 15px 0 15px;
position: relative;
overflow: auto;
width: 100%;
}
li.item {
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid #333;
a {
color: #bbb;
&:hover {
color: #fff;
}
}
.title {
cursor: pointer;
position: relative;
a {
color: #e1e1e1;
&:hover {
color: #fff;
}
}
display: block;
font-size: 0.8em;
.static {
display: block;
border-radius: 3px;
background-color: @colorSubtitle;
color: #000;
font-size: 0.7em;
padding: 2px 4px;
float: right;
}
}
.subtitle {
margin-top: 10px;
font: bold 0.65em Helvetica;
color: @colorSubtitle;
display: block;
}
ul {
& > li {
font-size: 0.7em;
padding-left: 8px;
margin-top: 2px;
}
}
.itemMembers {
display: none;
}
}
}

View File

@@ -215,15 +215,20 @@ function buildNav(members) {
return 0;
});
function createEntry(type, v) {
return {
type: type,
_.each(merged, function(v) {
// exclude interfaces from sidebar
if (v.interface !== true && v.kind === 'class') {
nav.push({
type: 'class',
longname: v.longname,
prettyname: v.longname
.split('~')[0]
.replace('module:', ''),
name: v.name,
classes: find({
kind: 'class',
memberof: v.longname
}).map(createEntry.bind(this, 'class')),
module: find({
kind: 'module',
longname: v.memberof
})[0],
members: find({
kind: 'member',
memberof: v.longname
@@ -236,17 +241,48 @@ function buildNav(members) {
kind: 'typedef',
memberof: v.longname
}),
fires: v.fires,
events: find({
kind: 'event',
memberof: v.longname
})
};
}
_.each(merged, function(v) {
// exclude interfaces from sidebar
if (v.interface !== true) {
if (v.kind == 'module') {
nav.push(createEntry('module', v));
});
} else if (v.kind == 'module') {
const classes = find({
kind: 'class',
memberof: v.longname
});
const members = find({
kind: 'member',
memberof: v.longname
});
const methods = find({
kind: 'function',
memberof: v.longname
});
const typedefs = find({
kind: 'typedef',
memberof: v.longname
});
const events = find({
kind: 'event',
memberof: v.longname
});
// only add modules that have more to show than just a single class
if (classes.length !== 1 && (classes.length + members.length + methods.length + typedefs.length + events.length > 0)) {
nav.push({
type: 'module',
longname: v.longname,
prettyname: v.longname
.split('~')[0]
.replace('module:', ''),
name: v.name,
members: members,
methods: methods,
typedefs: typedefs,
fires: v.fires,
events: events
});
}
}
});

View File

@@ -1,37 +1,74 @@
$(function () {
// Search Items
$('#include_modules').change(function (e) {
console.log('change');
if ($(this).is(':checked')) {
} else {
}
});
var getSearchWeight = function (searchTerm, $matchedItem) {
let weight = 0;
// We could get smarter on the weight here
if ($matchedItem.data('shortname')
&& $matchedItem.data('shortname').toLowerCase() === searchTerm.toLowerCase()) {
weight++;
}
return weight;
};
// sort function callback
var weightSorter = function (a, b) {
var aW = $(a).data('weight') || 0;
var bW = $(b).data('weight') || 0;
return bW - aW;
};
// Search Items
$('#search').on('keyup', function (e) {
var value = $(this).val();
var $el = $('.navigation');
if (value) {
if (value && value.length > 1) {
var regexp = new RegExp(value, 'i');
$el.find('li, .itemMembers').hide();
$el.find('li').each(function (i, v) {
var $item = $(v);
const $item = $(v);
const name = $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();
if (name && regexp.test(name)) {
const $classEntry = $item.closest('.item');
const $members = $item.closest('.itemMembers');
// Do the weight thing
$classEntry.removeData('weight');
$classEntry.show();
const weight = getSearchWeight(value, $classEntry);
$classEntry.data('weight', weight);
$members.show();
$classEntry.show();
$item.show();
$item.closest('.itemMembers').show();
$item.closest('.item').show();
}
});
$(".navigation ul.list li.item:visible")
.sort(weightSorter) // sort elements
.appendTo(".navigation ul.list"); // append again to the list
} else {
$el.find('.item, .itemMembers').hide();
$('.navigation>ul>li').show();
$el.find('.item, .itemMembers').show();
}
$el.find('.list').scrollTop(0);
});
// Toggle when click an item element
$('.navigation').on('click', '.title', function (e) {
$(this).parent().find('.itemMembers').toggle();
$('.navigation').on('click', '.toggle', function (e) {
$(this).parent().parent().find('.itemMembers').toggle();
});
// Show an item related a current documentation automatically
@@ -75,7 +112,7 @@ $(function () {
var branchSearch = url.match(/\/([^\/]*)\/apidoc\//);
var cookieText = 'dismissed=-' + latestVersion + '-';
var dismissed = document.cookie.indexOf(cookieText) != -1;
if (!dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
if (branchSearch && !dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
var link = url.replace(branchSearch[0], '/latest/apidoc/');
fetch(link, {method: 'head'}).then(function(response) {
var a = document.getElementById('latest-link');

View File

@@ -36,7 +36,7 @@
.navbar-inverse .navbar-nav>li>a:hover,
.navbar-inverse .navbar-nav>li>a:focus,
.navbar-inverse .navbar-nav>li>a.active
{
{
outline:0;
color: #fff;
background-color: #268591;
@@ -106,6 +106,15 @@ li {
.navigation .applicationName a {
color: #fff;
}
.navigation .include-modules {
color: #e1e1e1;
float: right;
font-size: 0.75em;
padding: 5px 15px;
}
.navigation .include-modules input {
vertical-align: text-bottom;
}
.navigation .search {
padding: 10px 15px;
}
@@ -125,6 +134,11 @@ li {
padding-bottom: 8px;
border-bottom: 1px solid #333;
}
.navigation li.perfect-match {
border: 5px solid orange;
}
.navigation li.item a {
color: #bbb;
}
@@ -158,6 +172,12 @@ li {
color: #1F6B75;
display: block;
}
.navigation li.item .modulelink {
position: relative;
font-size: 0.75em;
padding-left: 5px;
top: -5px;
}
.navigation li.item ul > li {
font-size: 0.75em;
padding-left: 8px;
@@ -165,6 +185,7 @@ li {
}
.navigation li.item .itemMembers {
display: none;
padding-left: 8px;
}
.main {
padding: 20px 20px;

View File

@@ -0,0 +1,81 @@
/* Carbon adds (see https://sell.buysellads.com) */
#ad {
margin-left: 1em;
float: right;
width: 330px;
min-height: 125px;
}
#carbonads {
font-family: "Quattrocento Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
}
#carbonads {
display: flex;
}
#carbonads a {
color: inherit;
text-decoration: none;
}
#carbonads a:hover {
color: inherit;
}
#carbonads span {
position: relative;
display: block;
overflow: hidden;
}
#carbonads .carbon-wrap {
display: flex;
}
.carbon-img {
display: block;
margin: 0;
line-height: 1;
}
.carbon-img img {
display: block;
}
.carbon-text {
font-size: 13px;
padding: 10px;
line-height: 1.5;
text-align: left;
}
.carbon-poweredby {
display: block;
padding: 8px 10px;
text-align: center;
text-transform: uppercase;
letter-spacing: .5px;
font-weight: 600;
font-size: 9px;
line-height: 1;
}
#carbonads a.carbon-poweredby {
color: #aaa;
}
/* Clear the float after the advertisement. */
.container-overview {
clear: both;
}
pre.source {
clear: both;
}
section.content {
overflow-y: auto;
}

View File

@@ -9,7 +9,7 @@
<?js= self.partial('source.tmpl', doc) ?>
<?js } else { ?>
<section>
<section class="content">
<header>
<h2><?js if (doc.ancestors && doc.ancestors.length) { ?>
@@ -41,6 +41,9 @@
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre>
<?js } ?>
<?js } ?>
<div id="ad">
<script async type="text/javascript" src="https://cdn.carbonads.com/carbon.js?serve=CE7DV53U&placement=openlayersorg" id="_carbonads_js"></script>
</div>
<?js if (doc.classdesc) { ?>
<div class="class-description"><?js= doc.classdesc ?></div>
<?js } ?>

View File

@@ -73,6 +73,7 @@ var version = obj.packageInfo.version;
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
<link type="text/css" rel="stylesheet" href="styles/jaguar.css">
<link type="text/css" rel="stylesheet" href="styles/site.css">
</head>
<body>

View File

@@ -10,12 +10,16 @@ function toShortName(name) {
</div>
<ul class="list">
<?js
let navbuilder;
this.nav.forEach(navbuilder = function (item) {
this.nav.forEach(function (item) {
?>
<li class="item" data-name="<?js= item.longname ?>">
<li class="item" data-name="<?js= item.longname ?>" data-shortname="<?js= item.name.toLowerCase() ?>">
<span class="title">
<?js= self.linkto(item.longname, item.type === 'module' ? item.longname.replace('module:', '') : item.name) ?>
<?js if (item.type === 'module') { ?>
<span class="glyphicon glyphicon-plus toggle"></span>
<?js } else if (item.type === 'class') { ?>
<span class="glyphicon glyphicon-chevron-right toggle"></span>
<?js } ?>
<?js= self.linkto(item.longname, item.prettyname) ?>
<?js if (item.type === 'namespace' &&
(item.members.length + item.typedefs.length + item.methods.length +
item.events.length > 0)) { ?>
@@ -23,18 +27,6 @@ function toShortName(name) {
</span>
<ul class="members itemMembers">
<?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) {
?>
<span class="subtitle">Members</span>

View File

@@ -16,9 +16,8 @@
}
});
/* determine if we need extra columns, "attributes" and "default" */
/* determine if we need extra "attributes" column */
params.hasAttributes = false;
params.hasDefault = false;
params.hasName = false;
var colspan = 2;
@@ -40,10 +39,6 @@
params.hasName = true;
}
if (typeof param.defaultvalue !== 'undefined') {
++colspan;
params.hasDefault = true;
}
});
?>
@@ -56,10 +51,6 @@
<th>Type</th>
<?js if (params.hasDefault) {?>
<th>Default</th>
<?js } ?>
<th class="last">Description</th>
</tr>
</thead>
@@ -80,16 +71,12 @@
<td class="type">
<?js if (param.type && param.type.names) {?>
<?js= self.partial('type.tmpl', param.type.names) ?>
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
(defaults to <?js= self.htmlsafe(param.defaultvalue) ?>)
<?js } ?>
<?js } ?>
</td>
<?js if (params.hasDefault) {?>
<td class="default">
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
<?js= self.htmlsafe(param.defaultvalue) ?>
<?js } ?>
</td>
<?js } ?>
<?js } ?>
<td<?js= (param.subparams ? ' colspan=' + colspan : ' ') ?> class="description last">

View File

@@ -241,10 +241,6 @@ Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL
Layer opacity must be a number.
### 65
A symbol literal representation must be defined on the style supplied to a `WebGLPointsLayer` instance.
### 66
`forEachFeatureAtCoordinate` cannot be used on a WebGL layer if the hit detection logic has not been enabled.

View File

@@ -3,14 +3,14 @@ layout: example.html
title: Filtering features with WebGL
shortdesc: Using WebGL to filter large quantities of features
docs: >
This example shows how to use `ol/renderer/webgl/PointsLayer` to dynamically filter a large amount
This example shows how to use `ol/layer/WebGLPoints` with a literal style to dynamically filter a large amount
of point geometries. The above map is based on a dataset from the NASA containing 45k recorded meteorite
landing sites. Each meteorite is marked by a circle on the map (the bigger the circle, the heavier
the object). A pulse effect has been added, which is slightly offset by the year of the impact.
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done using
a custom fragment shader on the layer renderer, and by using the `v_opacity` attribute of the rendered objects
to store the year of impact.
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done
by mutating the variables in the `style` object provided to the WebGL layer. Also note that the last snippet
of code is necessary to make sure the map refreshes itself every frame.
tags: "webgl, icon, sprite, filter, feature"
experimental: true

View File

@@ -3,133 +3,89 @@ import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import Feature from '../src/ol/Feature.js';
import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import {Vector} from '../src/ol/source.js';
import {fromLonLat} from '../src/ol/proj.js';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
import {clamp} from '../src/ol/math.js';
import Stamen from '../src/ol/source/Stamen.js';
import {formatColor} from '../src/ol/webgl/ShaderBuilder.js';
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
const vectorSource = new Vector({
attributions: 'NASA'
});
const oldColor = [180, 140, 140];
const newColor = [255, 80, 80];
const oldColor = 'rgba(242,56,22,0.61)';
const newColor = '#ffe52c';
const period = 12; // animation period in seconds
const animRatio =
['^',
['/',
['%',
['+',
['time'],
[
'interpolate',
['linear'],
['get', 'year'],
1850, 0,
2015, period
]
],
period
],
period
],
0.5
];
const startTime = Date.now() * 0.001;
const style = {
variables: {
minYear: 1850,
maxYear: 2015
},
filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']],
symbol: {
symbolType: 'circle',
size: ['*',
['interpolate', ['linear'], ['get', 'mass'], 0, 8, 200000, 26],
['-', 1.75, ['*', animRatio, 0.75]]
],
color: ['interpolate',
['linear'],
animRatio,
0, newColor,
1, oldColor
],
opacity: ['-', 1.0, ['*', animRatio, 0.75]]
}
};
// hanle input values & events
// handle input values & events
const minYearInput = document.getElementById('min-year');
const maxYearInput = document.getElementById('max-year');
function updateMinYear() {
style.variables.minYear = parseInt(minYearInput.value);
updateStatusText();
}
function updateMaxYear() {
style.variables.maxYear = parseInt(maxYearInput.value);
updateStatusText();
}
function updateStatusText() {
const div = document.getElementById('status');
div.querySelector('span.min-year').textContent = minYearInput.value;
div.querySelector('span.max-year').textContent = maxYearInput.value;
}
minYearInput.addEventListener('input', updateStatusText);
minYearInput.addEventListener('change', updateStatusText);
maxYearInput.addEventListener('input', updateStatusText);
maxYearInput.addEventListener('change', updateStatusText);
minYearInput.addEventListener('input', updateMinYear);
minYearInput.addEventListener('change', updateMinYear);
maxYearInput.addEventListener('input', updateMaxYear);
maxYearInput.addEventListener('change', updateMaxYear);
updateStatusText();
class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
attributes: [
{
name: 'size',
callback: function(feature) {
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
}
},
{
name: 'year',
callback: function(feature) {
return feature.get('year');
}
}
],
vertexShader: [
'precision mediump float;',
'uniform mat4 u_projectionMatrix;',
'uniform mat4 u_offsetScaleMatrix;',
'uniform mat4 u_offsetRotateMatrix;',
'attribute vec2 a_position;',
'attribute float a_index;',
'attribute float a_size;',
'attribute float a_year;',
'varying vec2 v_texCoord;',
'varying float v_year;',
'void main(void) {',
' mat4 offsetMatrix = u_offsetScaleMatrix;',
' float offsetX = a_index == 0.0 || a_index == 3.0 ? -a_size / 2.0 : a_size / 2.0;',
' float offsetY = a_index == 0.0 || a_index == 1.0 ? -a_size / 2.0 : a_size / 2.0;',
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
' float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;',
' float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;',
' v_texCoord = vec2(u, v);',
' v_year = a_year;',
'}'
].join(' '),
fragmentShader: [
'precision mediump float;',
'uniform float u_time;',
'uniform float u_minYear;',
'uniform float u_maxYear;',
'varying vec2 v_texCoord;',
'varying float v_year;',
'void main(void) {',
// filter out pixels if the year is outside of the given range
' if (v_year < u_minYear || v_year > u_maxYear) {',
' discard;',
' }',
' vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);',
' float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;',
' float value = 2.0 * (1.0 - sqRadius);',
' float alpha = smoothstep(0.0, 1.0, value);',
// color is interpolated based on year
' float ratio = clamp((v_year - 1800.0) / (2013.0 - 1800.0), 0.0, 1.1);',
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
' vec3(' + formatColor(newColor) + '), ratio);',
' float period = 8.0;',
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + v_year * 0.025, period) / period));',
' gl_FragColor = vec4(color, 1.0);',
' gl_FragColor.a *= alpha;',
' gl_FragColor.rgb *= gl_FragColor.a;',
'}'
].join(' '),
uniforms: {
u_time: function() {
return Date.now() * 0.001 - startTime;
},
u_minYear: function() {
return parseInt(minYearInput.value);
},
u_maxYear: function() {
return parseInt(maxYearInput.value);
}
}
});
}
}
function loadData() {
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/meteorite_landings.csv');
client.onload = function() {
// load data
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/meteorite_landings.csv');
client.onload = function() {
const csv = client.responseText;
const features = [];
@@ -154,11 +110,8 @@ function loadData() {
}
vectorSource.addFeatures(features);
};
client.send();
}
loadData();
};
client.send();
const map = new Map({
layers: [
@@ -167,8 +120,10 @@ const map = new Map({
layer: 'toner'
})
}),
new WebglPointsLayer({
source: vectorSource
new WebGLPointsLayer({
style: style,
source: vectorSource,
disableHitDetection: true
})
],
target: document.getElementById('map'),

View File

@@ -16,16 +16,15 @@ const vector = new HeatmapLayer({
})
}),
blur: parseInt(blur.value, 10),
radius: parseInt(radius.value, 10)
});
vector.getSource().on('addfeature', function(event) {
radius: parseInt(radius.value, 10),
weight: function(feature) {
// 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a
// standards-violating <magnitude> tag in each Placemark. We extract it from
// the Placemark's name instead.
const name = event.feature.get('name');
const name = feature.get('name');
const magnitude = parseFloat(name.substr(2));
event.feature.set('weight', magnitude - 5);
return magnitude - 5;
}
});
const raster = new TileLayer({
@@ -34,7 +33,7 @@ const raster = new TileLayer({
})
});
const map = new Map({
new Map({
layers: [raster, vector],
target: 'map',
view: new View({

View File

@@ -0,0 +1,15 @@
---
layout: example.html
title: Vector Layer Hit Detection
shortdesc: Example of hit detection on a countries vector layer with country information.
docs: >
The countries are loaded from a GeoJSON file. Information about countries is
on hover and click is retrieved using the layer's `getFeatures()` method. For
vector layers, this function resolves with an array of only the topmost
feature. It uses a very efficient hit detection algorithm, at the cost of
accuracy. For pixel exact hit detection, when performance is not a concern,
use the map's `getFeaturesAtPixel()` or `forEachFeatureAtPixel()` methods.
tags: "vector, geojson, click, hover, hit detection"
---
<div id="map" class="map"></div>
<div id="info">&nbsp;</div>

View File

@@ -0,0 +1,113 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Fill, Stroke, Style, Text} from '../src/ol/style.js';
const style = new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.6)'
}),
stroke: new Stroke({
color: '#319FD3',
width: 1
}),
text: new Text({
font: '12px Calibri,sans-serif',
fill: new Fill({
color: '#000'
}),
stroke: new Stroke({
color: '#fff',
width: 3
})
})
});
const vectorLayer = new VectorLayer({
source: new VectorSource({
url: 'data/geojson/countries.geojson',
format: new GeoJSON()
}),
style: function(feature) {
style.getText().setText(feature.get('name'));
return style;
}
});
const map = new Map({
layers: [vectorLayer],
target: 'map',
view: new View({
center: [0, 0],
zoom: 1
})
});
const highlightStyle = new Style({
stroke: new Stroke({
color: '#f00',
width: 1
}),
fill: new Fill({
color: 'rgba(255,0,0,0.1)'
}),
text: new Text({
font: '12px Calibri,sans-serif',
fill: new Fill({
color: '#000'
}),
stroke: new Stroke({
color: '#f00',
width: 3
})
})
});
const featureOverlay = new VectorLayer({
source: new VectorSource(),
map: map,
style: function(feature) {
highlightStyle.getText().setText(feature.get('name'));
return highlightStyle;
}
});
let highlight;
const displayFeatureInfo = function(pixel) {
vectorLayer.getFeatures(pixel).then(function(features) {
const feature = features.length ? features[0] : undefined;
const info = document.getElementById('info');
if (features.length) {
info.innerHTML = feature.getId() + ': ' + feature.get('name');
} else {
info.innerHTML = '&nbsp;';
}
if (feature !== highlight) {
if (highlight) {
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}
});
};
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
map.on('click', function(evt) {
displayFeatureInfo(evt.pixel);
});

View File

@@ -3,13 +3,13 @@ layout: example.html
title: Icon Sprites with WebGL
shortdesc: Rendering many icons with WebGL
docs: >
This example shows how to use `ol/renderer/webgl/PointsLayer` to render
This example shows how to use `ol/layer/WebGLPoints` to render
a very large amount of sprites. The above map is based on a dataset from the National UFO Reporting Center: each
icon marks a UFO sighting according to its reported shape (disk, light, fireball...). The older the sighting, the redder
the icon.
A very simple sprite atlas is used in the form of a PNG file containing all icons on a grid. Then, the `texCoordCallback`
option of the `ol/renderer/webgl/PointsLayer` constructor is used to specify which sprite to use according to the sighting shape.
A very simple sprite atlas is used in the form of a PNG file containing all icons on a grid. Then, the `style` object
given to the `ol/layer/WebGLPoints` constructor is used to specify which sprite to use according to the sighting shape.
The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings
tags: "webgl, icon, sprite, point, ufo"
@@ -20,3 +20,7 @@ cloak:
---
<div id="map" class="map"></div>
<div>Current sighting: <span id="info"></span></div>
<div>
Filter by UFO shape:
<select id="shape-filter"></select>
</div>

View File

@@ -4,179 +4,103 @@ import TileLayer from '../src/ol/layer/Tile.js';
import TileJSON from '../src/ol/source/TileJSON.js';
import Feature from '../src/ol/Feature.js';
import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import {Vector} from '../src/ol/source.js';
import {fromLonLat} from '../src/ol/proj.js';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
import {formatColor, formatNumber} from '../src/ol/webgl/ShaderBuilder.js';
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
const map = new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key,
crossOrigin: 'anonymous'
})
})
],
target: document.getElementById('map'),
view: new View({
center: [0, 4000000],
zoom: 2
})
});
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
});
const texture = new Image();
texture.src = 'data/ufo_shapes.png';
// This describes the content of the associated sprite sheet
// coords are u0, v0 for a given shape (all icons have a size of 0.25 x 0.5)
const shapeTextureCoords = {
'light': [0, 0],
'sphere': [0.25, 0],
'circle': [0.25, 0],
'disc': [0.5, 0],
'oval': [0.5, 0],
'triangle': [0.75, 0],
'fireball': [0, 0.5],
'default': [0.75, 0.5]
};
const oldColor = [255, 160, 110];
const newColor = [180, 255, 200];
const size = 16;
class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
attributes: [
{
name: 'year',
callback: function(feature) {
return feature.get('year');
}
const style = {
variables: {
filterShape: 'all'
},
{
name: 'texCoordU',
callback: function(feature) {
let coords = shapeTextureCoords[feature.get('shape')];
if (!coords) {
coords = shapeTextureCoords['default'];
}
return coords[0];
}
},
{
name: 'texCoordV',
callback: function(feature) {
let coords = shapeTextureCoords[feature.get('shape')];
if (!coords) {
coords = shapeTextureCoords['default'];
}
return coords[1];
}
}
filter: [
'case',
['!=', ['var', 'filterShape'], 'all'],
['==', ['get', 'shape'], ['var', 'filterShape']],
true
],
uniforms: {
u_texture: texture
},
vertexShader: [
'precision mediump float;',
'uniform mat4 u_projectionMatrix;',
'uniform mat4 u_offsetScaleMatrix;',
'uniform mat4 u_offsetRotateMatrix;',
'attribute vec2 a_position;',
'attribute float a_index;',
'attribute float a_year;',
'attribute float a_texCoordU;',
'attribute float a_texCoordV;',
'varying vec2 v_texCoord;',
'varying float v_year;',
'void main(void) {',
' mat4 offsetMatrix = u_offsetScaleMatrix;',
' float offsetX = a_index == 0.0 || a_index == 3.0 ? ',
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
' float offsetY = a_index == 0.0 || a_index == 1.0 ? ',
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
' float u = a_index == 0.0 || a_index == 3.0 ? a_texCoordU : a_texCoordU + 0.25;',
' float v = a_index == 2.0 || a_index == 3.0 ? a_texCoordV : a_texCoordV + 0.5;',
' v_texCoord = vec2(u, v);',
' v_year = a_year;',
'}'
].join(' '),
fragmentShader: [
'precision mediump float;',
'uniform float u_time;',
'uniform float u_minYear;',
'uniform float u_maxYear;',
'uniform sampler2D u_texture;',
'varying vec2 v_texCoord;',
'varying float v_year;',
'void main(void) {',
' vec4 textureColor = texture2D(u_texture, v_texCoord);',
' if (textureColor.a < 0.1) {',
' discard;',
' }',
// color is interpolated based on year
' float ratio = clamp((v_year - 1950.0) / (2013.0 - 1950.0), 0.0, 1.1);',
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
' vec3(' + formatColor(newColor) + '), ratio);',
' gl_FragColor = vec4(color, 1.0) * textureColor;',
' gl_FragColor.rgb *= gl_FragColor.a;',
'}'
].join(' '),
hitVertexShader: [
'precision mediump float;',
'uniform mat4 u_projectionMatrix;',
'uniform mat4 u_offsetScaleMatrix;',
'uniform mat4 u_offsetRotateMatrix;',
'attribute vec2 a_position;',
'attribute float a_index;',
'attribute vec4 a_hitColor;',
'attribute float a_texCoordU;',
'attribute float a_texCoordV;',
'varying vec2 v_texCoord;',
'varying vec4 v_hitColor;',
'void main(void) {',
' mat4 offsetMatrix = u_offsetScaleMatrix;',
' float offsetX = a_index == 0.0 || a_index == 3.0 ? ',
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
' float offsetY = a_index == 0.0 || a_index == 1.0 ? ',
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
' float u = a_index == 0.0 || a_index == 3.0 ? a_texCoordU : a_texCoordU + 0.25;',
' float v = a_index == 2.0 || a_index == 3.0 ? a_texCoordV : a_texCoordV + 0.5;',
' v_texCoord = vec2(u, v);',
' v_hitColor = a_hitColor;',
'}'
].join(' '),
hitFragmentShader: [
'precision mediump float;',
'uniform sampler2D u_texture;',
'varying vec2 v_texCoord;',
'varying vec4 v_hitColor;',
'void main(void) {',
' vec4 textureColor = texture2D(u_texture, v_texCoord);',
' if (textureColor.a < 0.1) {',
' discard;',
' }',
' gl_FragColor = v_hitColor;',
'}'
].join(' ')
});
symbol: {
symbolType: 'image',
src: 'data/ufo_shapes.png',
size: size,
color: [
'interpolate',
['linear'],
['get', 'year'],
1950, oldColor,
2013, newColor
],
rotateWithView: false,
offset: [
0,
0
],
textureCoord: [
'match',
['get', 'shape'],
'light', [0, 0, 0.25, 0.5],
'sphere', [0.25, 0, 0.5, 0.5],
'circle', [0.25, 0, 0.5, 0.5],
'disc', [0.5, 0, 0.75, 0.5],
'oval', [0.5, 0, 0.75, 0.5],
'triangle', [0.75, 0, 1, 0.5],
'fireball', [0, 0.5, 0.25, 1],
[0.75, 0.5, 1, 1]
]
}
};
// key is shape name, value is sightings count
const shapeTypes = {
all: 0
};
const shapeSelect = document.getElementById('shape-filter');
shapeSelect.addEventListener('input', function() {
style.variables.filterShape = shapeSelect.options[shapeSelect.selectedIndex].value;
map.render();
});
function fillShapeSelect() {
Object.keys(shapeTypes)
.sort(function(a, b) {
return shapeTypes[b] - shapeTypes[a];
})
.forEach(function(shape) {
const option = document.createElement('option');
option.text = `${shape} (${shapeTypes[shape]} sightings)`;
option.value = shape;
shapeSelect.appendChild(option);
});
}
function loadData() {
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/ufo_sighting_data.csv');
client.onload = function() {
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/ufo_sighting_data.csv');
client.onload = function() {
const csv = client.responseText;
const features = [];
@@ -194,43 +118,33 @@ function loadData() {
continue;
}
const shape = line[2];
shapeTypes[shape] = (shapeTypes[shape] ? shapeTypes[shape] : 0) + 1;
shapeTypes['all']++;
features.push(new Feature({
datetime: line[0],
year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
shape: line[2],
shape: shape,
duration: line[3],
geometry: new Point(coords)
}));
}
vectorSource.addFeatures(features);
};
client.send();
}
fillShapeSelect();
};
client.send();
loadData();
const map = new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key,
crossOrigin: 'anonymous'
map.addLayer(
new WebGLPointsLayer({
source: vectorSource,
style: style
})
}),
new WebglPointsLayer({
source: vectorSource
})
],
target: document.getElementById('map'),
view: new View({
center: [0, 4000000],
zoom: 2
})
});
);
const info = document.getElementById('info');
map.on('pointermove', function(evt) {
if (map.getView().getInteracting()) {
if (map.getView().getInteracting() || map.getView().getAnimating()) {
return;
}
const pixel = evt.pixel;
@@ -242,7 +156,3 @@ map.on('pointermove', function(evt) {
info.innerText = 'On ' + datetime + ', lasted ' + duration + ' seconds and had a "' + shape + '" shape.';
});
});
texture.addEventListener('load', function() {
map.render();
});

View File

@@ -56,9 +56,8 @@ const featureOverlay = new VectorLayer({
let highlight;
const displayFeatureInfo = function(pixel) {
const feature = map.forEachFeatureAtPixel(pixel, function(feature) {
return feature;
});
map.getLayers().item(0).getFeatures(pixel).then(function(features) {
const feature = features.length > 0 ? features[0] : undefined;
const info = document.getElementById('info');
if (feature) {
@@ -76,15 +75,13 @@ const displayFeatureInfo = function(pixel) {
}
highlight = feature;
}
});
};
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
if (!evt.dragging) {
displayFeatureInfo(evt.pixel);
}
const pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
map.on('click', function(evt) {

View File

@@ -1,7 +1,10 @@
---
layout: example-verbatim.html
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 maptiler.com.
docs: >
Example of using `ol-mapbox-style` with tiles from maptiler.com.
**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: "vector tiles, mapbox style, ol-mapbox-style, maptiler"
cloak:
- key: get_your_own_D6rA4zTHduk6KOKTXzGB

View File

@@ -74,13 +74,9 @@ ol.inline>li {
.ol-attribution.ol-logo-only,
.ol-attribution.ol-uncollapsible {
max-width: calc(100% - 3em);
height: 1.5em;
}
.ol-attribution ul {
font-size: 1rem;
}
.ol-control button, .ol-attribution, .ol-scale-line-inner {
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
font-size: 14px;
}
.iframe-info iframe {
width: 100%;

View File

@@ -0,0 +1,22 @@
---
layout: example.html
title: Select Features
shortdesc: Example of using the Select interaction.
docs: >
Choose between <code>Single-click</code>, <code>Click</code>, <code>Hover</code> and <code>Alt+Click</code> as the event type for selection in the combobox below. When using <code>Single-click</code> or <code>Click</code> you can hold do <code>Shift</code> key to toggle the feature in the selection.</p>
<p>Note: when <code>Single-click</code> is used double-clicks won't select features. This in contrast to <code>Click</code>, where a double-click will both select the feature and zoom the map (because of the <code>DoubleClickZoom</code> interaction). Note that <code>Single-click</code> is less responsive than <code>Click</code> because of the delay it uses to detect double-clicks.</p>
<p>In this example, a listener is registered for the Select interaction's <code>select</code> event in order to update the selection status above.
tags: "select, vector"
---
<div id="map" class="map"></div>
<form class="form-inline">
<label>Action type &nbsp;</label>
<select id="type" class="form-control">
<option value="click" selected>Click</option>
<option value="singleclick">Single-click</option>
<option value="pointermove">Hover</option>
<option value="altclick">Alt+Click</option>
<option value="none">None</option>
</select>
<span id="status">&nbsp;0 selected features</span>
</form>

View File

@@ -23,7 +23,7 @@ map.on('pointermove', showInfo);
const info = document.getElementById('info');
function showInfo(event) {
const features = map.getFeaturesAtPixel(event.pixel);
if (!features) {
if (features.length == 0) {
info.innerText = '';
info.style.opacity = 0;
return;

View File

@@ -7,18 +7,19 @@ import {Fill, Stroke, Style} from '../src/ol/style.js';
// lookup for selection objects
let selection = {};
// feature property to act as identifier
const idProp = 'iso_a3';
const vtLayer = new VectorTileLayer({
declutter: true,
source: new VectorTileSource({
format: new MVT(),
maxZoom: 15,
format: new MVT({
idProperty: 'iso_a3'
}),
url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' +
'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
}),
style: function(feature) {
const selected = !!selection[feature.get(idProp)];
const selected = !!selection[feature.getId()];
return new Style({
stroke: new Stroke({
color: selected ? 'rgba(200,20,20,0.8)' : 'gray',
@@ -45,8 +46,8 @@ const map = new Map({
const selectElement = document.getElementById('type');
map.on('click', function(event) {
const features = map.getFeaturesAtPixel(event.pixel);
if (!features) {
vtLayer.getFeatures(event.pixel).then(function(features) {
if (!features.length) {
selection = {};
// force redraw of layer style
vtLayer.setStyle(vtLayer.getStyle());
@@ -56,8 +57,7 @@ map.on('click', function(event) {
if (!feature) {
return;
}
const fid = feature.get(idProp);
const fid = feature.getId();
if (selectElement.value === 'singleselect') {
selection = {};
@@ -67,4 +67,6 @@ map.on('click', function(event) {
// force redraw of layer style
vtLayer.setStyle(vtLayer.getStyle());
});
});

View File

@@ -0,0 +1,13 @@
---
layout: example.html
title: Vector tiles in EPSG:4326
shortdesc: Example showing vector tiles in EPSG:4326 (styled using ol-mapbox-style)
docs: >
Example showing vector tiles in EPSG:4326 (styled using `ol-mapbox-style`) loaded from maptiler.com.
**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: "vector tiles, epsg4326, mapbox style, ol-mapbox-style, maptiler"
cloak:
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<div id="map" class="map" style="background:none;"></div>

View File

@@ -0,0 +1,50 @@
import View from '../src/ol/View.js';
import MVT from '../src/ol/format/MVT.js';
import VectorTileSource from '../src/ol/source/VectorTile.js';
import TileGrid from '../src/ol/tilegrid/TileGrid.js';
import olms from 'ol-mapbox-style';
import {defaultResolutions} from 'ol-mapbox-style/util.js';
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
// Match the server resolutions
const maxResolution = 360 / 512;
defaultResolutions.length = 14;
for (let i = 0; i < 14; ++i) {
defaultResolutions[i] = maxResolution / Math.pow(2, i + 1);
}
olms('map', 'https://api.maptiler.com/maps/basic-4326/style.json?key=' + key).then(function(map) {
// Custom tile grid for the EPSG:4326 projection
const tileGrid = new TileGrid({
extent: [-180, -90, 180, 90],
tileSize: 512,
resolutions: defaultResolutions
});
const mapboxStyle = map.get('mapbox-style');
// Replace the source with a EPSG:4326 projection source for each vector tile layer
map.getLayers().forEach(function(layer) {
const mapboxSource = layer.get('mapbox-source');
if (mapboxSource && mapboxStyle.sources[mapboxSource].type === 'vector') {
const source = layer.getSource();
layer.setSource(new VectorTileSource({
format: new MVT(),
projection: 'EPSG:4326',
urls: source.getUrls(),
tileGrid: tileGrid
}));
}
});
// Configure the map with a view with EPSG:4326 projection
map.setView(new View({
projection: 'EPSG:4326',
zoom: mapboxStyle.zoom,
center: mapboxStyle.center
}));
});

View File

@@ -24,15 +24,15 @@ experimental: true
<div id="map" class="map"></div>
<label>Choose a predefined style from the list below or edit it as JSON manually.</label><br>
<select id="style-select">
<option>Predefined styles</option>
<option value="icons">Icons</option>
<option value="triangles">Triangles, color related to population</option>
<option value="triangles-latitude">Triangles, color related to latitude</option>
<option value="circles">Circles, size related to population</option>
<option value="circles-zoom">Circles, size related to zoom</option>
</select>
<textarea style="width: 100%; height: 20rem; font-family: monospace; font-size: small;" id="style-editor"></textarea>
<small id="style-valid" style="display: none; color: forestgreen">
✓ style is valid
</small>
<small id="style-invalid" style="display: none; color: grey">
✗ style not yet valid...
<small>
<span id="style-valid" style="display: none; color: forestgreen">✓ style is valid</span>
<span id="style-invalid" style="display: none; color: grey"><span>style not yet valid...</span></span>
&nbsp;
</small>

View File

@@ -27,27 +27,76 @@ const predefinedStyles = {
symbolType: 'triangle',
size: 18,
color: [
['stretch', ['get', 'population'], 20000, 300000, 0.1, 1.0],
['stretch', ['get', 'population'], 20000, 300000, 0.6, 0.3],
0.6,
1.0
'interpolate',
['linear'],
['get', 'population'],
20000, '#5aca5b',
300000, '#ff6a19'
],
rotateWithView: true
}
},
'triangles-latitude': {
symbol: {
symbolType: 'triangle',
size: [
'interpolate',
['linear'],
['get', 'population'],
40000, 12,
2000000, 24
],
color: [
'interpolate',
['linear'],
['get', 'latitude'],
-60, '#ff14c3',
-20, '#ff621d',
20, '#ffed02',
60, '#00ff67'
],
offset: [0, 0],
opacity: 0.95
}
},
'circles': {
symbol: {
symbolType: 'circle',
size: ['stretch', ['get', 'population'], 40000, 2000000, 8, 28],
size: [
'interpolate',
['linear'],
['get', 'population'],
40000, 8,
2000000, 28
],
color: '#006688',
rotateWithView: false,
offset: [0, 0],
opacity: ['stretch', ['get', 'population'], 40000, 2000000, 0.6, 0.92]
opacity: [
'interpolate',
['linear'],
['get', 'population'],
40000, 0.6,
2000000, 0.92
]
}
},
'circles-zoom': {
symbol: {
symbolType: 'circle',
size: [
'interpolate',
['exponential', 2.5],
['zoom'],
2, 1,
14, 32
],
color: '#240572',
offset: [0, 0],
opacity: 0.95
}
}
};
let literalStyle = predefinedStyles['circles'];
let pointsLayer;
const map = new Map({
layers: [
@@ -62,45 +111,59 @@ const map = new Map({
})
});
const editor = document.getElementById('style-editor');
editor.value = JSON.stringify(literalStyle, null, 2);
function refreshLayer() {
if (pointsLayer) {
map.removeLayer(pointsLayer);
}
let literalStyle;
let pointsLayer;
function refreshLayer(newStyle) {
const previousLayer = pointsLayer;
pointsLayer = new WebGLPointsLayer({
source: vectorSource,
style: literalStyle
style: newStyle,
disableHitDetection: true
});
map.addLayer(pointsLayer);
if (previousLayer) {
map.removeLayer(previousLayer);
previousLayer.dispose();
}
literalStyle = newStyle;
}
function setStyleStatus(valid) {
document.getElementById('style-valid').style.display = valid ? 'initial' : 'none';
document.getElementById('style-invalid').style.display = !valid ? 'initial' : 'none';
const spanValid = document.getElementById('style-valid');
const spanInvalid = document.getElementById('style-invalid');
function setStyleStatus(errorMsg) {
const isError = typeof errorMsg === 'string';
spanValid.style.display = errorMsg === null ? 'initial' : 'none';
spanInvalid.firstElementChild.innerText = isError ? errorMsg : '';
spanInvalid.style.display = isError ? 'initial' : 'none';
}
const editor = document.getElementById('style-editor');
editor.addEventListener('input', function() {
const textStyle = editor.value;
if (JSON.stringify(JSON.parse(textStyle)) === JSON.stringify(literalStyle)) {
return;
}
try {
literalStyle = JSON.parse(textStyle);
refreshLayer();
setStyleStatus(true);
const newLiteralStyle = JSON.parse(textStyle);
if (JSON.stringify(newLiteralStyle) !== JSON.stringify(literalStyle)) {
refreshLayer(newLiteralStyle);
}
setStyleStatus(null);
} catch (e) {
setStyleStatus(false);
setStyleStatus(e.message);
}
});
refreshLayer();
const select = document.getElementById('style-select');
select.addEventListener('change', function() {
select.value = 'circles';
function onSelectChange() {
const style = select.value;
literalStyle = predefinedStyles[style];
editor.value = JSON.stringify(literalStyle, null, 2);
refreshLayer();
});
const newLiteralStyle = predefinedStyles[style];
editor.value = JSON.stringify(newLiteralStyle, null, 2);
try {
refreshLayer(newLiteralStyle);
setStyleStatus();
} catch (e) {
setStyleStatus(e.message);
}
}
onSelectChange();
select.addEventListener('change', onSelectChange);

745
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.1",
"version": "6.1.1",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -37,59 +37,59 @@
},
"dependencies": {
"@openlayers/pepjs": "^0.5.3",
"pbf": "3.2.0",
"pbf": "3.2.1",
"pixelworks": "1.1.0",
"rbush": "^3.0.0"
"rbush": "^3.0.1"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.4.4",
"@openlayers/eslint-plugin": "^4.0.0",
"@types/arcgis-rest-api": "^10.4.4",
"@types/geojson": "^7946.0.7",
"@types/pbf": "^3.0.1",
"@types/pbf": "^3.0.2",
"@types/topojson-specification": "^1.0.1",
"babel-loader": "^8.0.5",
"buble": "^0.19.7",
"buble-loader": "^0.5.1",
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.3",
"coveralls": "3.0.6",
"copy-webpack-plugin": "^5.0.4",
"coveralls": "3.0.7",
"eslint": "^6.0.0",
"eslint-config-openlayers": "^12.0.0",
"eslint-config-openlayers": "^13.0.0",
"expect.js": "0.3.1",
"front-matter": "^3.0.2",
"fs-extra": "^8.0.0",
"glob": "^7.1.4",
"glob": "^7.1.5",
"globby": "^10.0.0",
"handlebars": "4.4.0",
"handlebars": "4.4.5",
"html-to-image": "^0.1.0",
"istanbul": "0.4.5",
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "3.4.1",
"jsdoc": "3.6.3",
"jsdoc-plugin-typescript": "2.0.3",
"karma": "^4.1.0",
"jsdoc-plugin-typescript": "^2.0.5",
"karma": "^4.4.1",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "^2.0.1",
"karma-coverage-istanbul-reporter": "^2.0.5",
"karma-coverage-istanbul-reporter": "^2.1.0",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "1.3.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-rc.2",
"loglevelnext": "^3.0.1",
"marked": "0.7.0",
"mocha": "6.2.1",
"ol-mapbox-style": "^5.0.0-beta.3",
"pixelmatch": "^5.0.0",
"mocha": "6.2.2",
"ol-mapbox-style": "^5.0.2",
"pixelmatch": "^5.1.0",
"pngjs": "^3.4.0",
"proj4": "2.5.0",
"puppeteer": "~1.20.0",
"rollup": "^1.12.0",
"rollup-plugin-babel": "^4.3.2",
"rollup": "^1.25.1",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-node-resolve": "^5.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^5.0.0",
"serve-static": "^1.14.0",
"shx": "^0.3.2",
@@ -98,11 +98,11 @@
"typescript": "3.5.3",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.41.0",
"webpack": "4.41.2",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"yargs": "^14.0.0"
"yargs": "^14.2.0"
},
"eslintConfig": {
"extends": "openlayers",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
width: 100%;
height: 100%;
text-align: right;
}
.ol-control {
display: none;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="main.js"></script>
</body>
</script>
</html>

View File

@@ -0,0 +1,24 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js';
import {fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ.js';
new Map({
layers: [
new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
})
})
],
target: 'map',
view: new View({
rotation: Math.PI / 3,
center: fromLonLat([8.6, 50.1]),
zoom: 3
})
});
render();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -65,6 +65,22 @@ feature.setStyle(new Style({
}));
vectorSource.addFeature(feature);
// align left
feature = new Feature({
geometry: new Point([50, 50])
});
feature.setStyle(new Style({
text: new Text({
font: 'Ubuntu',
text: 'align left',
textAlign: 'left',
stroke: new Stroke({
color: [10, 10, 10, 0.5]
})
})
}));
vectorSource.addFeature(feature);
// background and padding
feature = new Feature({
geometry: new Point([-10, 0])

View File

@@ -46,7 +46,7 @@ class ImageCanvas extends ImageBase {
/**
* @private
* @type {Error}
* @type {?Error}
*/
this.error_ = null;
@@ -54,7 +54,7 @@ class ImageCanvas extends ImageBase {
/**
* Get any error associated with asynchronous rendering.
* @return {Error} Any error that occurred during rendering.
* @return {?Error} Any error that occurred during rendering.
*/
getError() {
return this.error_;

View File

@@ -69,8 +69,6 @@ class ImageTile extends Tile {
if (this.interimTile) {
this.interimTile.dispose();
}
this.state = TileState.ABORT;
this.changed();
super.disposeInternal();
}

View File

@@ -61,7 +61,6 @@ class MapBrowserEventHandler extends EventTarget {
this.down_ = null;
const element = this.map_.getViewport();
element.setAttribute('touch-action', 'none');
/**
* @type {number}

View File

@@ -512,15 +512,18 @@ class Overlay extends BaseObject {
positioning == OverlayPositioning.CENTER_RIGHT ||
positioning == OverlayPositioning.TOP_RIGHT) {
if (this.rendered.left_ !== '') {
this.rendered.left_ = style.left = '';
this.rendered.left_ = '';
style.left = '';
}
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
if (this.rendered.right_ != right) {
this.rendered.right_ = style.right = right;
this.rendered.right_ = right;
style.right = right;
}
} else {
if (this.rendered.right_ !== '') {
this.rendered.right_ = style.right = '';
this.rendered.right_ = '';
style.right = '';
}
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
positioning == OverlayPositioning.CENTER_CENTER ||
@@ -529,22 +532,26 @@ class Overlay extends BaseObject {
}
const left = Math.round(pixel[0] + offsetX) + 'px';
if (this.rendered.left_ != left) {
this.rendered.left_ = style.left = left;
this.rendered.left_ = left;
style.left = left;
}
}
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
positioning == OverlayPositioning.BOTTOM_CENTER ||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
if (this.rendered.top_ !== '') {
this.rendered.top_ = style.top = '';
this.rendered.top_ = '';
style.top = '';
}
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
if (this.rendered.bottom_ != bottom) {
this.rendered.bottom_ = style.bottom = bottom;
this.rendered.bottom_ = bottom;
style.bottom = bottom;
}
} else {
if (this.rendered.bottom_ !== '') {
this.rendered.bottom_ = style.bottom = '';
this.rendered.bottom_ = '';
style.bottom = '';
}
if (positioning == OverlayPositioning.CENTER_LEFT ||
positioning == OverlayPositioning.CENTER_CENTER ||
@@ -553,7 +560,8 @@ class Overlay extends BaseObject {
}
const top = Math.round(pixel[1] + offsetY) + 'px';
if (this.rendered.top_ != top) {
this.rendered.top_ = style.top = top;
this.rendered.top_ = 'top';
style.top = top;
}
}
}

View File

@@ -131,6 +131,17 @@ import {toUserCoordinate, fromUserCoordinate} from './proj.js';
*/
/**
* @param {HTMLElement} element Element.
* @param {string} touchAction Value for `touch-action'.
*/
function setTouchAction(element, touchAction) {
element.style.msTouchAction = touchAction;
element.style.touchAction = touchAction;
element.setAttribute('touch-action', touchAction);
}
/**
* @fires import("./MapBrowserEvent.js").MapBrowserEvent
* @fires import("./MapEvent.js").MapEvent
@@ -246,9 +257,7 @@ class PluggableMap extends BaseObject {
this.viewport_.style.overflow = 'hidden';
this.viewport_.style.width = '100%';
this.viewport_.style.height = '100%';
// prevent page zoom on IE >= 10 browsers
this.viewport_.style.msTouchAction = 'none';
this.viewport_.style.touchAction = 'none';
/**
* @private
@@ -296,6 +305,12 @@ class PluggableMap extends BaseObject {
*/
this.keyHandlerKeys_ = null;
/**
* @private
* @type {?Array<import("./events.js").EventsKey>}
*/
this.focusHandlerKeys_ = null;
const handleBrowserEvent = this.handleBrowserEvent.bind(this);
this.viewport_.addEventListener(EventType.CONTEXTMENU, handleBrowserEvent, false);
this.viewport_.addEventListener(EventType.WHEEL, handleBrowserEvent, false);
@@ -312,16 +327,6 @@ class PluggableMap extends BaseObject {
*/
this.interactions = optionsInternal.interactions || new Collection();
/**
* @type {import("./events/Target.js").default}
*/
this.labelCache_ = null;
/**
* @type {import("./events.js").EventsKey}
*/
this.labelCacheListenerKey_;
/**
* @type {Collection<import("./Overlay.js").default>}
* @private
@@ -342,7 +347,7 @@ class PluggableMap extends BaseObject {
this.renderer_ = null;
/**
* @type {function(Event): void|undefined}
* @type {undefined|function(Event): void}
* @private
*/
this.handleResize_;
@@ -549,8 +554,7 @@ class PluggableMap extends BaseObject {
return;
}
const coordinate = this.getCoordinateFromPixelInternal(pixel);
opt_options = opt_options !== undefined ? opt_options :
/** @type {AtPixelOptions} */ ({});
opt_options = opt_options !== undefined ? opt_options : {};
const hitTolerance = opt_options.hitTolerance !== undefined ?
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
const layerFilter = opt_options.layerFilter !== undefined ?
@@ -602,7 +606,7 @@ class PluggableMap extends BaseObject {
if (!this.frameState_) {
return;
}
const options = opt_options || /** @type {AtPixelOptions} */ ({});
const options = opt_options || {};
const hitTolerance = options.hitTolerance !== undefined ?
options.hitTolerance * this.frameState_.pixelRatio : 0;
const layerFilter = options.layerFilter || TRUE;
@@ -622,8 +626,7 @@ class PluggableMap extends BaseObject {
return false;
}
const coordinate = this.getCoordinateFromPixelInternal(pixel);
opt_options = opt_options !== undefined ? opt_options :
/** @type {AtPixelOptions} */ ({});
opt_options = opt_options !== undefined ? opt_options : {};
const layerFilter = opt_options.layerFilter !== undefined ? opt_options.layerFilter : TRUE;
const hitTolerance = opt_options.hitTolerance !== undefined ?
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
@@ -1040,6 +1043,12 @@ class PluggableMap extends BaseObject {
targetElement = this.getTargetElement();
}
if (this.focusHandlerKeys_) {
for (let i = 0, ii = this.focusHandlerKeys_.length; i < ii; ++i) {
unlistenByKey(this.focusHandlerKeys_[i]);
}
this.focusHandlerKeys_ = null;
}
if (this.keyHandlerKeys_) {
for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
unlistenByKey(this.keyHandlerKeys_[i]);
@@ -1068,6 +1077,15 @@ class PluggableMap extends BaseObject {
if (!this.renderer_) {
this.renderer_ = this.createRenderer();
}
let hasFocus = true;
if (targetElement.hasAttribute('tabindex')) {
hasFocus = document.activeElement === targetElement;
this.focusHandlerKeys_ = [
listen(targetElement, EventType.FOCUS, setTouchAction.bind(this, this.viewport_, 'none')),
listen(targetElement, EventType.BLUR, setTouchAction.bind(this, this.viewport_, 'auto'))
];
}
setTouchAction(this.viewport_, hasFocus ? 'none' : 'auto');
const keyboardEventTarget = !this.keyboardEventTarget_ ?
targetElement : this.keyboardEventTarget_;

View File

@@ -144,6 +144,13 @@ class Tile extends EventTarget {
this.dispatchEvent(EventType.CHANGE);
}
/**
* @inheritDoc
*/
disposeInternal() {
this.setState(TileState.ABORT);
}
/**
* @return {string} Key.
*/

View File

@@ -3,8 +3,8 @@
*/
import {getUid} from './util.js';
import Tile from './Tile.js';
import TileState from './TileState.js';
import {createCanvasContext2D} from './dom.js';
import {unlistenByKey} from './events.js';
/**
@@ -24,7 +24,7 @@ class VectorRenderTile extends Tile {
/**
* @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
* @param {TileState} state State.
* @param {import("./TileState.js").default} state State.
* @param {import("./tilecoord.js").TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
* @param {import("./tilegrid/TileGrid.js").default} sourceTileGrid Tile grid of the source.
* @param {function(VectorRenderTile):Array<import("./VectorTile").default>} getSourceTiles Function
@@ -60,6 +60,11 @@ class VectorRenderTile extends Tile {
*/
this.errorSourceTileKeys = {};
/**
* @type {ImageData}
*/
this.hitDetectionImageData = null;
/**
* @private
* @type {!Object<string, ReplayState>}
@@ -72,9 +77,9 @@ class VectorRenderTile extends Tile {
this.wantedResolution;
/**
* @type {!function(import("./VectorRenderTile.js").default):Array<import("./VectorTile.js").default>}
* @type {!function():Array<import("./VectorTile.js").default>}
*/
this.getSourceTiles_ = getSourceTiles;
this.getSourceTiles = getSourceTiles.bind(this, this);
/**
* @type {!function(import("./VectorRenderTile.js").default):void}
@@ -87,6 +92,11 @@ class VectorRenderTile extends Tile {
*/
this.sourceTileGrid_ = sourceTileGrid;
/**
* @type {Array<import("./events.js").EventsKey>}
*/
this.sourceTileListenerKeys = [];
/**
* z of the source tiles of the last getSourceTiles call.
* @type {number}
@@ -109,10 +119,13 @@ class VectorRenderTile extends Tile {
* @inheritDoc
*/
disposeInternal() {
this.sourceTileListenerKeys.forEach(unlistenByKey);
this.sourceTileListenerKeys.length = 0;
this.removeSourceTiles_(this);
for (const key in this.context_) {
const canvas = this.context_[key].canvas;
canvas.width = canvas.height = 0;
canvas.width = 0;
canvas.height = 0;
}
for (const key in this.executorGroups) {
const executorGroups = this.executorGroups[key];
@@ -120,7 +133,6 @@ class VectorRenderTile extends Tile {
executorGroups[i].disposeInternal();
}
}
this.setState(TileState.ABORT);
super.disposeInternal();
}
@@ -178,7 +190,7 @@ class VectorRenderTile extends Tile {
* @inheritDoc
*/
load() {
this.getSourceTiles_(this);
this.getSourceTiles();
}
}

View File

@@ -73,14 +73,6 @@ class VectorTile extends Tile {
}
/**
* @inheritDoc
*/
disposeInternal() {
this.setState(TileState.ABORT);
super.disposeInternal();
}
/**
* Get the feature format assigned for reading this tile's features.
* @return {import("./format/Feature.js").default} Feature format.

View File

@@ -37,10 +37,12 @@ export function createExtent(extent, onlyCenter, smooth) {
// note: when zooming out of bounds, min and max values for x and y may
// end up inverted (min > max); this has to be accounted for
if (minX > maxX) {
minX = maxX = (maxX + minX) / 2;
minX = (maxX + minX) / 2;
maxX = minX;
}
if (minY > maxY) {
minY = maxY = (maxY + minY) / 2;
minY = (maxY + minY) / 2;
maxY = minY;
}
let x = clamp(center[0], minX, maxX);

View File

@@ -30,7 +30,7 @@ const HEX_COLOR_RE_ = /^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i;
* @type {RegExp}
* @private
*/
const NAMED_COLOR_RE_ = /^([a-z]*)$/i;
const NAMED_COLOR_RE_ = /^([a-z]*)$|^hsla?\(.*\)$/i;
/**
@@ -223,3 +223,14 @@ export function toString(color) {
const a = color[3] === undefined ? 1 : color[3];
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
}
/**
* @param {string} s String.
* @return {boolean} Whether the string is actually a valid color
*/
export function isStringColor(s) {
if (NAMED_COLOR_RE_.test(s)) {
s = fromNamed(s);
}
return HEX_COLOR_RE_.test(s) || s.indexOf('rgba(') === 0 || s.indexOf('rgb(') === 0;
}

View File

@@ -216,8 +216,8 @@ class OverviewMap extends Control {
const computeDesiredMousePosition = function(mousePosition) {
return {
clientX: mousePosition.clientX - (overlayBox.offsetWidth / 2),
clientY: mousePosition.clientY + (overlayBox.offsetHeight / 2)
clientX: mousePosition.clientX,
clientY: mousePosition.clientY
};
};

View File

@@ -126,7 +126,7 @@ class ScaleLine extends Control {
this.addEventListener(getChangeEventType(UNITS_PROP), this.handleUnitsChanged_);
this.setUnits(/** @type {Units} */ (options.units) || Units.METRIC);
this.setUnits(options.units || Units.METRIC);
/**
* @private

View File

@@ -21,6 +21,7 @@ export default {
*/
ERROR: 'error',
BLUR: 'blur',
CLEAR: 'clear',
CONTEXTMENU: 'contextmenu',
CLICK: 'click',
@@ -28,6 +29,7 @@ export default {
DRAGENTER: 'dragenter',
DRAGOVER: 'dragover',
DROP: 'drop',
FOCUS: 'focus',
KEYDOWN: 'keydown',
KEYPRESS: 'keypress',
LOAD: 'load',

View File

@@ -40,7 +40,7 @@ class Target extends Disposable {
* @private
* @type {*}
*/
this.target_ = opt_target;
this.eventTarget_ = opt_target;
/**
* @private
@@ -72,7 +72,8 @@ class Target extends Disposable {
}
let listeners = this.listeners_[type];
if (!listeners) {
listeners = this.listeners_[type] = [];
listeners = [];
this.listeners_[type] = listeners;
}
if (listeners.indexOf(listener) === -1) {
listeners.push(listener);
@@ -96,7 +97,7 @@ class Target extends Disposable {
const evt = typeof event === 'string' ? new Event(event) : event;
const type = evt.type;
if (!evt.target) {
evt.target = this.target_ || this;
evt.target = this.eventTarget_ || this;
}
const listeners = this.listeners_[type];
let propagate;

View File

@@ -1777,7 +1777,9 @@ function setCommonGeometryProperties(multiGeometry, geometries) {
const tessellates = new Array(geometries.length);
const altitudeModes = new Array(geometries.length);
let hasExtrude, hasTessellate, hasAltitudeMode;
hasExtrude = hasTessellate = hasAltitudeMode = false;
hasExtrude = false;
hasTessellate = false;
hasAltitudeMode = false;
for (let i = 0; i < ii; ++i) {
const geometry = geometries[i];
extrudes[i] = geometry.get('extrude');

View File

@@ -31,6 +31,9 @@ class Bbox extends Filter {
* @type {import("../../extent.js").Extent}
*/
this.extent = extent;
if (extent.length !== 4) {
throw new Error('Expected an extent with four values ([minX, minY, maxX, maxY])');
}
/**
* @type {string|undefined}

View File

@@ -39,10 +39,10 @@ export function VOID() {}
export function memoizeOne(fn) {
let called = false;
/** @type ReturnType */
/** @type {ReturnType} */
let lastResult;
/** @type Array<any> */
/** @type {Array<any>} */
let lastArgs;
let lastThis;

View File

@@ -229,12 +229,13 @@ class Geometry extends BaseObject {
}
/**
* Apply a transform function to each coordinate of the geometry.
* Apply a transform function to the coordinates of the geometry.
* The geometry is modified in place.
* If you do not want the geometry modified in place, first `clone()` it and
* then use this function on the clone.
* @abstract
* @param {import("../proj.js").TransformFunction} transformFn Transform.
* @param {import("../proj.js").TransformFunction} transformFn Transform function.
* Called with a flat array of geometry coordinates.
*/
applyTransform(transformFn) {
abstract();

View File

@@ -187,7 +187,12 @@ class SimpleGeometry extends Geometry {
}
/**
* @inheritDoc
* Apply a transform function to the coordinates of the geometry.
* The geometry is modified in place.
* If you do not want the geometry modified in place, first `clone()` it and
* then use this function on the clone.
* @param {import("../proj.js").TransformFunction} transformFn Transform function.
* Called with a flat array of geometry coordinates.
* @api
*/
applyTransform(transformFn) {
@@ -198,7 +203,10 @@ class SimpleGeometry extends Geometry {
}
/**
* @inheritDoc
* Rotate the geometry around a given coordinate. This modifies the geometry
* coordinates in place.
* @param {number} angle Rotation angle in radians.
* @param {import("../coordinate.js").Coordinate} anchor The rotation center.
* @api
*/
rotate(angle, anchor) {
@@ -213,7 +221,13 @@ class SimpleGeometry extends Geometry {
}
/**
* @inheritDoc
* Scale the geometry (with an optional origin). This modifies the geometry
* coordinates in place.
* @param {number} sx The scaling factor in the x-direction.
* @param {number=} opt_sy The scaling factor in the y-direction (defaults to
* sx).
* @param {import("../coordinate.js").Coordinate=} opt_anchor The scale origin (defaults to the center
* of the geometry extent).
* @api
*/
scale(sx, opt_sy, opt_anchor) {
@@ -236,7 +250,10 @@ class SimpleGeometry extends Geometry {
}
/**
* @inheritDoc
* Translate the geometry. This modifies the geometry coordinates in place. If
* instead you want a new geometry, first `clone()` this geometry.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @api
*/
translate(deltaX, deltaY) {

View File

@@ -654,7 +654,8 @@ class Modify extends PointerInteraction {
};
const featureSegments = [centerSegmentData, circumferenceSegmentData];
centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
centerSegmentData.featureSegments = featureSegments;
circumferenceSegmentData.featureSegments = featureSegments;
this.rBush_.insert(createExtent(coordinates), centerSegmentData);
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
}
@@ -746,12 +747,14 @@ class Modify extends PointerInteraction {
switch (geometry.getType()) {
case GeometryType.POINT:
coordinates = vertex;
segment[0] = segment[1] = vertex;
segment[0] = vertex;
segment[1] = vertex;
break;
case GeometryType.MULTI_POINT:
coordinates = geometry.getCoordinates();
coordinates[segmentData.index] = vertex;
segment[0] = segment[1] = vertex;
segment[0] = vertex;
segment[1] = vertex;
break;
case GeometryType.LINE_STRING:
coordinates = geometry.getCoordinates();
@@ -774,7 +777,8 @@ class Modify extends PointerInteraction {
segment[index] = vertex;
break;
case GeometryType.CIRCLE:
segment[0] = segment[1] = vertex;
segment[0] = vertex;
segment[1] = vertex;
if (segmentData.index === CIRCLE_CENTER_INDEX) {
this.changingFeature_ = true;
geometry.setCenter(vertex);
@@ -889,8 +893,10 @@ class Modify extends PointerInteraction {
const coordinates = geometry.getCenter();
const centerSegmentData = segmentData.featureSegments[0];
const circumferenceSegmentData = segmentData.featureSegments[1];
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
centerSegmentData.segment[0] = coordinates;
centerSegmentData.segment[1] = coordinates;
circumferenceSegmentData.segment[0] = coordinates;
circumferenceSegmentData.segment[1] = coordinates;
this.rBush_.update(createExtent(coordinates), centerSegmentData);
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
} else {

View File

@@ -20,9 +20,11 @@ import {getValues} from '../obj.js';
* propagation of the event to other interactions in the map's interactions
* chain.
* @property {function(import("../MapBrowserPointerEvent.js").default)} [handleMoveEvent]
* Function handling "move" events. This function is called on "move" events,
* also during a drag sequence (so during a drag sequence both the
* `handleDragEvent` function and this function are called).
* Function handling "move" events. This function is called on "move" events.
* This functions is also called during a drag sequence, so during a drag
* sequence both the `handleDragEvent` function and this function are called.
* If `handleDownEvent` is defined and it returns true this function will not
* be called during a drag sequence.
* @property {function(import("../MapBrowserPointerEvent.js").default):boolean} [handleUpEvent]
* Function handling "up" events. If the function returns `false` then the
* current drag sequence is stopped.

View File

@@ -5,7 +5,7 @@ import {getUid} from '../util.js';
import CollectionEventType from '../CollectionEventType.js';
import {extend, includes} from '../array.js';
import Event from '../events/Event.js';
import {singleClick, never, shiftKeyOnly, pointerMove} from '../events/condition.js';
import {singleClick, never, shiftKeyOnly} from '../events/condition.js';
import {TRUE} from '../functions.js';
import GeometryType from '../geom/GeometryType.js';
import Interaction from './Interaction.js';
@@ -61,6 +61,7 @@ const SelectEventType = {
* @property {import("../style/Style.js").StyleLike} [style]
* Style for the selected features. By default the default edit style is used
* (see {@link module:ol/style}).
* If set to `false` the selected feature's style will not change.
* @property {import("../events/condition.js").Condition} [removeCondition] A function
* that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether that event should be handled.
@@ -206,7 +207,7 @@ class Select extends Interaction {
* @private
* @type {import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction|null}
*/
this.style_ = options.style ? options.style : getDefaultStyleFunction();
this.style_ = options.style !== undefined ? options.style : getDefaultStyleFunction();
/**
* An association between selected feature (key)
@@ -467,7 +468,7 @@ function handleEvent(mapBrowserEvent) {
new SelectEvent(SelectEventType.SELECT,
selected, deselected, mapBrowserEvent));
}
return pointerMove(mapBrowserEvent);
return true;
}

View File

@@ -198,7 +198,7 @@ class Translate extends PointerInteraction {
handleDownEvent(event) {
this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
if (!this.lastCoordinate_ && this.lastFeature_) {
this.startCoordinate_ =
this.startCoordinate_ = event.coordinate;
this.lastCoordinate_ = event.coordinate;
this.handleMoveEvent(event);

View File

@@ -105,14 +105,14 @@ class BaseLayer extends BaseObject {
/** @type {import("./Layer.js").State} */
const state = this.state_ || /** @type {?} */ ({
layer: this,
managed: opt_managed === undefined ? true : opt_managed,
hasOverlay: false
managed: opt_managed === undefined ? true : opt_managed
});
const zIndex = this.getZIndex();
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
state.sourceState = this.getSourceState();
state.visible = this.getVisible();
state.extent = this.getExtent();
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
state.zIndex = zIndex !== undefined ? zIndex : (state.managed === false ? Infinity : 0);
state.maxResolution = this.getMaxResolution();
state.minResolution = Math.max(this.getMinResolution(), 0);
state.minZoom = this.getMinZoom();
@@ -320,6 +320,17 @@ class BaseLayer extends BaseObject {
setZIndex(zindex) {
this.set(LayerProperty.Z_INDEX, zindex);
}
/**
* @inheritDoc
*/
disposeInternal() {
if (this.state_) {
this.state_.layer = null;
this.state_ = null;
}
super.disposeInternal();
}
}

View File

@@ -135,6 +135,24 @@ class BaseVectorLayer extends Layer {
return this.declutter_;
}
/**
* Get the topmost feature that intersects the given pixel on the viewport. Returns a promise
* that resolves with an array of features. The array will either contain the topmost feature
* when a hit was detected, or it will be empty.
*
* The hit detection algorithm used for this method is optimized for performance, but is less
* accurate than the one used in {@link import("../PluggableMap.js").default#getFeaturesAtPixel}: Text
* is not considered, and icons are only represented by their bounding box instead of the exact
* image.
*
* @param {import("../pixel.js").Pixel} pixel Pixel.
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with an array of features.
* @api
*/
getFeatures(pixel) {
return super.getFeatures(pixel);
}
/**
* @return {number|undefined} Render buffer.
*/

View File

@@ -318,23 +318,12 @@ class Graticule extends VectorLayer {
options.latLabelPosition;
/**
* @type {Object.<string,Style>}
* @type {Style}
* @private
*/
this.lonLabelStyleCache_ = {};
/**
* @private
* @param {import("../Feature").default} feature Feature
* @return {Style} style
*/
this.lonLabelStyle_ = function(feature) {
const label = feature.get('graticule_label');
if (!this.lonLabelStyleCache_[label]) {
this.lonLabelStyleCache_[label] = new Style({
text: options.lonLabelStyle !== undefined ? options.lonLabelStyle :
this.lonLabelStyleBase_ = new Style({
text: options.lonLabelStyle !== undefined ? options.lonLabelStyle.clone() :
new Text({
text: label,
font: '12px Calibri,sans-serif',
textBaseline: 'bottom',
fill: new Fill({
@@ -346,28 +335,25 @@ class Graticule extends VectorLayer {
})
})
});
}
return this.lonLabelStyleCache_[label];
}.bind(this);
/**
* @type {Object.<string,Style>}
* @private
*/
this.latLabelStyleCache_ = {};
/**
* @private
* @param {import("../Feature").default} feature Feature
* @return {Style} style
*/
this.latLabelStyle_ = function(feature) {
this.lonLabelStyle_ = function(feature) {
const label = feature.get('graticule_label');
if (!this.latLabelStyleCache_[label]) {
this.latLabelStyleCache_[label] = new Style({
text: options.latLabelStyle !== undefined ? options.latLabelStyle :
this.lonLabelStyleBase_.getText().setText(label);
return this.lonLabelStyleBase_;
}.bind(this);
/**
* @type {Style}
* @private
*/
this.latLabelStyleBase_ = new Style({
text: options.latLabelStyle !== undefined ? options.latLabelStyle.clone() :
new Text({
text: label,
font: '12px Calibri,sans-serif',
textAlign: 'right',
fill: new Fill({
@@ -379,8 +365,16 @@ class Graticule extends VectorLayer {
})
})
});
}
return this.latLabelStyleCache_[label];
/**
* @private
* @param {import("../Feature").default} feature Feature
* @return {Style} style
*/
this.latLabelStyle_ = function(feature) {
const label = feature.get('graticule_label');
this.latLabelStyleBase_.getText().setText(label);
return this.latLabelStyleBase_;
}.bind(this);
this.meridiansLabels_ = [];
@@ -421,7 +415,7 @@ class Graticule extends VectorLayer {
});
/**
* @type {import("../extent.js").Extent}
* @type {?import("../extent.js").Extent}
*/
this.renderedExtent_ = null;
@@ -587,7 +581,8 @@ class Graticule extends VectorLayer {
createGraticule_(extent, center, resolution, squaredTolerance) {
const interval = this.getInterval_(resolution);
if (interval == -1) {
this.meridians_.length = this.parallels_.length = 0;
this.meridians_.length = 0;
this.parallels_.length = 0;
if (this.meridiansLabels_) {
this.meridiansLabels_.length = 0;
}
@@ -714,7 +709,8 @@ class Graticule extends VectorLayer {
const flatCoordinates = meridian(lon, minLat, maxLat, this.projection_, squaredTolerance);
let lineString = this.meridians_[index];
if (!lineString) {
lineString = this.meridians_[index] = new LineString(flatCoordinates, GeometryLayout.XY);
lineString = new LineString(flatCoordinates, GeometryLayout.XY);
this.meridians_[index] = lineString;
} else {
lineString.setFlatCoordinates(GeometryLayout.XY, flatCoordinates);
lineString.changed();

View File

@@ -4,6 +4,7 @@
import {getChangeEventType} from '../Object.js';
import {createCanvasContext2D} from '../dom.js';
import VectorLayer from './Vector.js';
import {clamp} from '../math.js';
import {assign} from '../obj.js';
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
@@ -180,7 +181,10 @@ class Heatmap extends VectorLayer {
attributes: [
{
name: 'weight',
callback: this.weightFunction_
callback: function(feature) {
const weight = this.weightFunction_(feature);
return weight !== undefined ? clamp(weight, 0, 1) : 1;
}.bind(this)
}
],
vertexShader: `
@@ -220,6 +224,51 @@ class Heatmap extends VectorLayer {
float alpha = smoothstep(0.0, 1.0, value) * v_weight;
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
}`,
hitVertexShader: `
precision mediump float;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
uniform float u_size;
attribute vec2 a_position;
attribute float a_index;
attribute float a_weight;
attribute vec4 a_hitColor;
varying vec2 v_texCoord;
varying float v_weight;
varying vec4 v_hitColor;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix;
float offsetX = a_index == 0.0 || a_index == 3.0 ? -u_size / 2.0 : u_size / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? -u_size / 2.0 : u_size / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;
v_texCoord = vec2(u, v);
v_hitColor = a_hitColor;
v_weight = a_weight;
}`,
hitFragmentShader: `
precision mediump float;
uniform float u_blurSlope;
varying vec2 v_texCoord;
varying float v_weight;
varying vec4 v_hitColor;
void main(void) {
vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
float alpha = smoothstep(0.0, 1.0, value) * v_weight;
if (alpha < 0.05) {
discard;
}
gl_FragColor = v_hitColor;
}`,
uniforms: {
u_size: function() {
return (this.get(Property.RADIUS) + this.get(Property.BLUR)) * 2;

View File

@@ -46,7 +46,6 @@ import SourceState from '../source/State.js';
* @property {SourceState} sourceState
* @property {boolean} visible
* @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 {number} zIndex
* @property {number} maxResolution
@@ -192,6 +191,15 @@ class Layer extends BaseLayer {
this.changed();
}
/**
* @param {import("../pixel").Pixel} pixel Pixel.
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with
* an array of features.
*/
getFeatures(pixel) {
return this.renderer_.getFeatures(pixel);
}
/**
* In charge to manage the rendering of the layer. One layer type is
* bounded with one layer renderer.
@@ -279,6 +287,13 @@ class Layer extends BaseLayer {
return null;
}
/**
* @inheritDoc
*/
disposeInternal() {
this.setSource(null);
super.disposeInternal();
}
}

View File

@@ -116,6 +116,24 @@ class VectorTileLayer extends BaseVectorLayer {
return new CanvasVectorTileLayerRenderer(this);
}
/**
* Get the topmost feature that intersects the given pixel on the viewport. Returns a promise
* that resolves with an array of features. The array will either contain the topmost feature
* when a hit was detected, or it will be empty.
*
* The hit detection algorithm used for this method is optimized for performance, but is less
* accurate than the one used in {@link import("../PluggableMap.js").default#getFeaturesAtPixel}: Text
* is not considered, and icons are only represented by their bounding box instead of the exact
* image.
*
* @param {import("../pixel.js").Pixel} pixel Pixel.
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with an array of features.
* @api
*/
getFeatures(pixel) {
return super.getFeatures(pixel);
}
/**
* @return {VectorTileRenderType} The render mode.
*/

View File

@@ -3,8 +3,7 @@
*/
import {assign} from '../obj.js';
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
import {getSymbolFragmentShader, getSymbolVertexShader, parseSymbolStyle} from '../webgl/ShaderBuilder.js';
import {assert} from '../asserts.js';
import {parseLiteralStyle} from '../webgl/ShaderBuilder.js';
import Layer from './Layer.js';
@@ -25,6 +24,8 @@ import Layer from './Layer.js';
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {import("../source/Vector.js").default} [source] Source.
* @property {boolean} [disableHitDetection] Setting this to true will provide a slight performance boost, but will
* prevent all hit detection on the layer.
*/
@@ -56,6 +57,9 @@ import Layer from './Layer.js';
* }
* ```
*
* **Important: a `WebGLPoints` layer must be manually disposed when removed, otherwise the underlying WebGL context
* will not be garbage collected.**
*
* Note that any property set in the options is set as a {@link module:ol/Object~BaseObject}
* property on the layer object; for example, setting `title: 'My Title'` in the
* options means that `title` is observable, and has get/set accessors.
@@ -72,26 +76,42 @@ class WebGLPointsLayer extends Layer {
super(baseOptions);
/**
* @type {import('../style/LiteralStyle.js').LiteralStyle}
* @private
* @type {import('../webgl/ShaderBuilder.js').StyleParseResult}
*/
this.style = options.style;
this.parseResult_ = parseLiteralStyle(options.style);
assert(this.style.symbol !== undefined, 65);
/**
* @private
* @type {boolean}
*/
this.hitDetectionDisabled_ = !!options.disableHitDetection;
}
/**
* @inheritDoc
*/
createRenderer() {
const parseResult = parseSymbolStyle(this.style.symbol);
return new WebGLPointsLayerRenderer(this, {
vertexShader: getSymbolVertexShader(parseResult.params),
fragmentShader: getSymbolFragmentShader(parseResult.params),
uniforms: parseResult.uniforms,
attributes: parseResult.attributes
vertexShader: this.parseResult_.builder.getSymbolVertexShader(),
fragmentShader: this.parseResult_.builder.getSymbolFragmentShader(),
hitVertexShader: !this.hitDetectionDisabled_ &&
this.parseResult_.builder.getSymbolVertexShader(true),
hitFragmentShader: !this.hitDetectionDisabled_ &&
this.parseResult_.builder.getSymbolFragmentShader(true),
uniforms: this.parseResult_.uniforms,
attributes: this.parseResult_.attributes
});
}
/**
*
* @inheritDoc
*/
disposeInternal() {
this.renderer_.dispose();
super.disposeInternal();
}
}
export default WebGLPointsLayer;

View File

@@ -182,15 +182,12 @@
.ol-attribution ul {
margin: 0;
padding: 0 .5em;
font-size: .7rem;
line-height: 1.375em;
color: #000;
text-shadow: 0 0 2px #fff;
}
.ol-attribution li {
display: inline;
list-style: none;
line-height: inherit;
}
.ol-attribution li:not(:last-child):after {
content: " ";
@@ -213,8 +210,6 @@
bottom: 0;
right: 0;
border-radius: 4px 0 0;
height: 1.1em;
line-height: 1em;
}
.ol-attribution.ol-uncollapsible img {
margin-top: -.2em;

View File

@@ -499,7 +499,7 @@ export function transformWithProjections(point, sourceProjection, destinationPro
}
/**
* @type {Projection}
* @type {?Projection}
*/
let userProjection = null;
@@ -526,7 +526,7 @@ export function clearUserProjection() {
* Get the projection for coordinates supplied from and returned by API methods.
* Note that this method is not yet a part of the stable API. Support for user
* projections is not yet complete and should be considered experimental.
* @returns {Projection} The user projection (or null if not set).
* @returns {?Projection} The user projection (or null if not set).
*/
export function getUserProjection() {
return userProjection;

View File

@@ -74,7 +74,10 @@ class RenderBox extends Disposable {
if (this.map_) {
this.map_.getOverlayContainer().removeChild(this.element_);
const style = this.element_.style;
style.left = style.top = style.width = style.height = 'inherit';
style.left = 'inherit';
style.top = 'inherit';
style.width = 'inherit';
style.height = 'inherit';
}
this.map_ = map;
if (this.map_) {

View File

@@ -33,8 +33,8 @@ class RenderEvent extends Event {
this.frameState = opt_frameState;
/**
* Canvas context. Only available when a Canvas renderer is used, null
* otherwise.
* Canvas context. Not available when the event is dispatched by the map. Only available
* when a Canvas renderer is used, null otherwise.
* @type {CanvasRenderingContext2D|null|undefined}
* @api
*/

View File

@@ -23,6 +23,7 @@ export default {
/**
* Triggered before layers are rendered.
* The event object will not have a `context` set.
* @event module:ol/render/Event~RenderEvent#precompose
* @api
*/
@@ -30,6 +31,7 @@ export default {
/**
* Triggered after all layers are rendered.
* The event object will not have a `context` set.
* @event module:ol/render/Event~RenderEvent#postcompose
* @api
*/
@@ -38,6 +40,7 @@ export default {
/**
* Triggered when rendering is complete, i.e. all sources and tiles have
* finished loading for the current viewport, and all tiles are faded in.
* The event object will not have a `context` set.
* @event module:ol/render/Event~RenderEvent#rendercomplete
* @api
*/

View File

@@ -268,10 +268,10 @@ class RenderFeature {
/**
* @return {Array<number>|Array<Array<number>>} Ends or endss.
*/
RenderFeature.prototype.getEnds =
RenderFeature.prototype.getEndss = function() {
RenderFeature.prototype.getEnds = function() {
return this.ends_;
};
RenderFeature.prototype.getEndss = RenderFeature.prototype.getEnds;
/**

View File

@@ -311,13 +311,15 @@ export const measureTextHeight = (function() {
if (!div) {
div = document.createElement('div');
div.innerHTML = 'M';
div.style.margin = div.style.padding = '0 !important';
div.style.margin = '0 !important';
div.style.padding = '0 !important';
div.style.position = 'absolute !important';
div.style.left = '-99999px !important';
}
div.style.font = font;
document.body.appendChild(div);
height = heights[font] = div.offsetHeight;
height = div.offsetHeight;
heights[font] = height;
document.body.removeChild(div);
}
return height;
@@ -333,7 +335,8 @@ export const measureTextHeight = (function() {
export function measureTextWidth(font, text) {
const measureContext = getMeasureContext();
if (font != measureFont) {
measureContext.font = measureFont = font;
measureContext.font = font;
measureFont = measureContext.font;
}
return measureContext.measureText(text).width;
}
@@ -350,7 +353,8 @@ export function measureAndCacheTextWidth(font, text, cache) {
if (text in cache) {
return cache[text];
}
const width = cache[text] = measureTextWidth(font, text);
const width = measureTextWidth(font, text);
cache[text] = width;
return width;
}

View File

@@ -87,7 +87,8 @@ class BuilderGroup {
declutter = this.declutterGroups_;
/** @type {number} */ (declutter[0][4])++;
} else {
declutter = this.declutterGroups_ = [createEmpty()];
declutter = [createEmpty()];
this.declutterGroups_ = declutter;
declutter[0].push(1);
}
}

View File

@@ -315,10 +315,14 @@ class Executor extends Disposable {
const boxY = y - padding[0];
if (fillStroke || rotation !== 0) {
p1[0] = p4[0] = boxX;
p1[1] = p2[1] = boxY;
p2[0] = p3[0] = boxX + boxW;
p3[1] = p4[1] = boxY + boxH;
p1[0] = boxX;
p4[0] = boxX;
p1[1] = boxY;
p2[1] = boxY;
p2[0] = boxX + boxW;
p3[0] = p2[0];
p3[1] = boxY + boxH;
p4[1] = p3[1];
}
let transform = null;
@@ -537,6 +541,7 @@ class Executor extends Disposable {
let lastStrokeInstruction = null;
const coordinateCache = this.coordinateCache_;
const viewRotation = this.viewRotation_;
const viewRotationFromTransform = Math.round(Math.atan2(-transform[1], transform[0]) * 1e12) / 1e12;
const state = /** @type {import("../../render.js").State} */ ({
context: context,
@@ -575,7 +580,8 @@ class Executor extends Disposable {
}
if (!pendingFill && !pendingStroke) {
context.beginPath();
prevX = prevY = NaN;
prevX = NaN;
prevY = NaN;
}
++i;
break;
@@ -643,13 +649,18 @@ class Executor extends Disposable {
strokeKey = /** @type {string} */ (instruction[20]);
fillKey = /** @type {string} */ (instruction[21]);
const labelWithAnchor = this.drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey);
image = instruction[3] = labelWithAnchor.label;
image = labelWithAnchor.label;
instruction[3] = image;
const textOffsetX = /** @type {number} */ (instruction[22]);
anchorX = instruction[4] = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
instruction[4] = anchorX;
const textOffsetY = /** @type {number} */ (instruction[23]);
anchorY = instruction[5] = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
height = instruction[7] = image.height;
width = instruction[14] = image.width;
anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
instruction[5] = anchorY;
height = image.height;
instruction[7] = height;
width = image.width;
instruction[14] = width;
}
let geometryWidths;
@@ -664,11 +675,16 @@ class Executor extends Disposable {
backgroundStroke = /** @type {boolean} */ (instruction[17]);
} else {
padding = defaultPadding;
backgroundFill = backgroundStroke = false;
backgroundFill = false;
backgroundStroke = false;
}
if (rotateWithView) {
if (rotateWithView && viewRotationFromTransform) {
// Canvas is expected to be rotated to reverse view rotation.
rotation += viewRotation;
} else if (!rotateWithView && !viewRotationFromTransform) {
// Canvas is not rotated, images need to be rotated back to be north-up.
rotation -= viewRotation;
}
let widthIndex = 0;
let declutterGroupIndex = 0;
@@ -725,7 +741,8 @@ class Executor extends Disposable {
if (font in this.widths_) {
cachedWidths = this.widths_[font];
} else {
cachedWidths = this.widths_[font] = {};
cachedWidths = {};
this.widths_[font] = cachedWidths;
}
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);

View File

@@ -116,7 +116,8 @@ class ExecutorGroup extends Disposable {
for (const zIndex in allInstructions) {
let executors = this.executorsByZIndex_[zIndex];
if (executors === undefined) {
this.executorsByZIndex_[zIndex] = executors = {};
executors = {};
this.executorsByZIndex_[zIndex] = executors;
}
const instructionByZindex = allInstructions[zIndex];
for (const builderType in instructionByZindex) {
@@ -139,7 +140,8 @@ class ExecutorGroup extends Disposable {
}
if (this.hitDetectionContext_) {
const canvas = this.hitDetectionContext_.canvas;
canvas.width = canvas.height = 0;
canvas.width = 0;
canvas.height = 0;
}
super.disposeInternal();

View File

@@ -15,6 +15,7 @@ import VectorContext from '../VectorContext.js';
import {defaultTextAlign, defaultFillStyle, defaultLineCap, defaultLineDash, defaultLineDashOffset, defaultLineJoin, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline, defaultFont} from '../canvas.js';
import {create as createTransform, compose as composeTransform} from '../../transform.js';
/**
* @classdesc
* A concrete subclass of {@link module:ol/render/VectorContext} that implements
@@ -438,6 +439,13 @@ class CanvasImmediateRenderer extends VectorContext {
this.setTextStyle(style.getText());
}
/**
* @param {import("../../transform.js").Transform} transform Transform.
*/
setTransform(transform) {
this.transform_ = transform;
}
/**
* Render a geometry into the canvas. Call
* {@link module:ol/render/canvas/Immediate#setStyle} first to set the rendering style.
@@ -711,7 +719,8 @@ class CanvasImmediateRenderer extends VectorContext {
};
} else {
if (contextFillState.fillStyle != fillState.fillStyle) {
contextFillState.fillStyle = context.fillStyle = fillState.fillStyle;
contextFillState.fillStyle = fillState.fillStyle;
context.fillStyle = fillState.fillStyle;
}
}
}
@@ -744,30 +753,33 @@ class CanvasImmediateRenderer extends VectorContext {
};
} else {
if (contextStrokeState.lineCap != strokeState.lineCap) {
contextStrokeState.lineCap = context.lineCap = strokeState.lineCap;
contextStrokeState.lineCap = strokeState.lineCap;
context.lineCap = strokeState.lineCap;
}
if (context.setLineDash) {
if (!equals(contextStrokeState.lineDash, strokeState.lineDash)) {
context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);
}
if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) {
contextStrokeState.lineDashOffset = context.lineDashOffset =
strokeState.lineDashOffset;
contextStrokeState.lineDashOffset = strokeState.lineDashOffset;
context.lineDashOffset = strokeState.lineDashOffset;
}
}
if (contextStrokeState.lineJoin != strokeState.lineJoin) {
contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin;
contextStrokeState.lineJoin = strokeState.lineJoin;
context.lineJoin = strokeState.lineJoin;
}
if (contextStrokeState.lineWidth != strokeState.lineWidth) {
contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth;
contextStrokeState.lineWidth = strokeState.lineWidth;
context.lineWidth = strokeState.lineWidth;
}
if (contextStrokeState.miterLimit != strokeState.miterLimit) {
contextStrokeState.miterLimit = context.miterLimit =
strokeState.miterLimit;
contextStrokeState.miterLimit = strokeState.miterLimit;
context.miterLimit = strokeState.miterLimit;
}
if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {
contextStrokeState.strokeStyle = context.strokeStyle =
strokeState.strokeStyle;
contextStrokeState.strokeStyle = strokeState.strokeStyle;
context.strokeStyle = strokeState.strokeStyle;
}
}
}
@@ -792,14 +804,16 @@ class CanvasImmediateRenderer extends VectorContext {
};
} else {
if (contextTextState.font != textState.font) {
contextTextState.font = context.font = textState.font;
contextTextState.font = textState.font;
context.font = textState.font;
}
if (contextTextState.textAlign != textAlign) {
contextTextState.textAlign = context.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
contextTextState.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
context.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
}
if (contextTextState.textBaseline != textState.textBaseline) {
contextTextState.textBaseline = context.textBaseline =
/** @type {CanvasTextBaseline} */ (textState.textBaseline);
contextTextState.textBaseline = /** @type {CanvasTextBaseline} */ (textState.textBaseline);
context.textBaseline = /** @type {CanvasTextBaseline} */ (textState.textBaseline);
}
}
}

View File

@@ -50,7 +50,8 @@ class LabelCache extends LRUCache {
}
}
const canvas = this.pop();
canvas.width = canvas.height = 0;
canvas.width = 0;
canvas.height = 0;
for (const consumerId in this.consumers) {
delete this.consumers[consumerId][key];
}

View File

@@ -392,11 +392,13 @@ class CanvasTextBuilder extends CanvasBuilder {
const textFillStyle = textStyle.getFill();
if (!textFillStyle) {
fillState = this.textFillState_ = null;
fillState = null;
this.textFillState_ = fillState;
} else {
fillState = this.textFillState_;
if (!fillState) {
fillState = this.textFillState_ = /** @type {import("../canvas.js").FillState} */ ({});
fillState = /** @type {import("../canvas.js").FillState} */ ({});
this.textFillState_ = fillState;
}
fillState.fillStyle = asColorLike(
textFillStyle.getColor() || defaultFillStyle);
@@ -404,11 +406,13 @@ class CanvasTextBuilder extends CanvasBuilder {
const textStrokeStyle = textStyle.getStroke();
if (!textStrokeStyle) {
strokeState = this.textStrokeState_ = null;
strokeState = null;
this.textStrokeState_ = strokeState;
} else {
strokeState = this.textStrokeState_;
if (!strokeState) {
strokeState = this.textStrokeState_ = /** @type {import("../canvas.js").StrokeState} */ ({});
strokeState = /** @type {import("../canvas.js").StrokeState} */ ({});
this.textStrokeState_ = strokeState;
}
const lineDash = textStrokeStyle.getLineDash();
const lineDashOffset = textStrokeStyle.getLineDashOffset();

View File

@@ -0,0 +1,147 @@
/**
* @module ol/render/canvas/hitdetet
*/
import CanvasImmediateRenderer from './Immediate.js';
import {createCanvasContext2D} from '../../dom.js';
import {Icon} from '../../style.js';
import IconAnchorUnits from '../../style/IconAnchorUnits.js';
import GeometryType from '../../geom/GeometryType.js';
import {intersects} from '../../extent.js';
import {numberSafeCompareFunction} from '../../array.js';
/**
* @param {import("../../size.js").Size} size Canvas size in css pixels.
* @param {Array<import("../../transform.js").Transform>} transforms Transforms
* for rendering features to all worlds of the viewport, from coordinates to css
* pixels.
* @param {Array<import("../../Feature.js").FeatureLike>} features
* Features to consider for hit detection.
* @param {import("../../style/Style.js").StyleFunction|undefined} styleFunction
* Layer style function.
* @param {import("../../extent.js").Extent} extent Extent.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @return {ImageData} Hit detection image data.
*/
export function createHitDetectionImageData(size, transforms, features, styleFunction, extent, resolution, rotation) {
const width = size[0] / 2;
const height = size[1] / 2;
const context = createCanvasContext2D(width, height);
context.imageSmoothingEnabled = false;
const canvas = context.canvas;
const renderer = new CanvasImmediateRenderer(context, 0.5, extent, null, rotation);
const featureCount = features.length;
// Stretch hit detection index to use the whole available color range
const indexFactor = Math.ceil((256 * 256 * 256) / featureCount);
const featuresByZIndex = {};
for (let i = 0; i < featureCount; ++i) {
const feature = features[i];
const featureStyleFunction = feature.getStyleFunction() || styleFunction;
if (!styleFunction) {
continue;
}
let styles = featureStyleFunction(feature, resolution);
if (!Array.isArray(styles)) {
styles = [styles];
}
const index = i * indexFactor;
const color = '#' + ('000000' + index.toString(16)).slice(-6);
for (let j = 0, jj = styles.length; j < jj; ++j) {
const originalStyle = styles[j];
const style = originalStyle.clone();
const fill = style.getFill();
if (fill) {
fill.setColor(color);
}
const stroke = style.getStroke();
if (stroke) {
stroke.setColor(color);
}
style.setText(undefined);
const image = originalStyle.getImage();
if (image) {
const imgSize = image.getImageSize();
const canvas = document.createElement('canvas');
canvas.width = imgSize[0];
canvas.height = imgSize[1];
const imgContext = canvas.getContext('2d', {alpha: false});
imgContext.fillStyle = color;
const img = imgContext.canvas;
imgContext.fillRect(0, 0, img.width, img.height);
const width = imgSize ? imgSize[0] : img.width;
const height = imgSize ? imgSize[1] : img.height;
const iconContext = createCanvasContext2D(width, height);
iconContext.drawImage(img, 0, 0);
style.setImage(new Icon({
img: img,
imgSize: imgSize,
anchor: image.getAnchor(),
anchorXUnits: IconAnchorUnits.PIXELS,
anchorYUnits: IconAnchorUnits.PIXELS,
offset: image.getOrigin(),
size: image.getSize(),
opacity: image.getOpacity(),
scale: image.getScale(),
rotation: image.getRotation(),
rotateWithView: image.getRotateWithView()
}));
}
const zIndex = Number(style.getZIndex());
let byGeometryType = featuresByZIndex[zIndex];
if (!byGeometryType) {
byGeometryType = {};
featuresByZIndex[zIndex] = byGeometryType;
byGeometryType[GeometryType.POLYGON] = [];
byGeometryType[GeometryType.CIRCLE] = [];
byGeometryType[GeometryType.LINE_STRING] = [];
byGeometryType[GeometryType.POINT] = [];
}
const geometry = style.getGeometryFunction()(feature);
if (geometry && intersects(extent, geometry.getExtent())) {
byGeometryType[geometry.getType().replace('Multi', '')].push(geometry, style);
}
}
}
const zIndexKeys = Object.keys(featuresByZIndex).map(Number).sort(numberSafeCompareFunction);
for (let i = 0, ii = zIndexKeys.length; i < ii; ++i) {
const byGeometryType = featuresByZIndex[zIndexKeys[i]];
for (const type in byGeometryType) {
const geomAndStyle = byGeometryType[type];
for (let j = 0, jj = geomAndStyle.length; j < jj; j += 2) {
renderer.setStyle(geomAndStyle[j + 1]);
for (let k = 0, kk = transforms.length; k < kk; ++k) {
renderer.setTransform(transforms[k]);
renderer.drawGeometry(geomAndStyle[j]);
}
}
}
}
return context.getImageData(0, 0, canvas.width, canvas.height);
}
/**
* @param {import("../../pixel").Pixel} pixel Pixel coordinate on the hit
* detection canvas in css pixels.
* @param {Array<import("../../Feature").FeatureLike>} features Features. Has to
* match the `features` array that was passed to `createHitDetectionImageData()`.
* @param {ImageData} imageData Hit detection image data generated by
* `createHitDetectionImageData()`.
* @return {Array<import("../../Feature").FeatureLike>} features Features.
*/
export function hitDetect(pixel, features, imageData) {
const resultFeatures = [];
if (imageData) {
const index = (Math.round(pixel[0] / 2) + Math.round(pixel[1] / 2) * imageData.width) * 4;
const r = imageData.data[index];
const g = imageData.data[index + 1];
const b = imageData.data[index + 2];
const i = b + (256 * (g + (256 * r)));
const indexFactor = Math.ceil((256 * 256 * 256) / features.length);
if (i % indexFactor === 0) {
resultFeatures.push(features[i / indexFactor]);
}
}
return resultFeatures;
}

View File

@@ -98,11 +98,9 @@ class CompositeMapRenderer extends MapRenderer {
const viewState = frameState.viewState;
this.children_.length = 0;
let hasOverlay = false;
let previousElement = null;
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
const layerState = layerStatesArray[i];
hasOverlay = hasOverlay || layerState.hasOverlay;
frameState.layerIndex = i;
if (!inView(layerState, viewState) ||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
@@ -114,13 +112,8 @@ class CompositeMapRenderer extends MapRenderer {
if (!element) {
continue;
}
const childElementCount = element.childElementCount;
if ((element !== previousElement || i == ii - 1) && childElementCount === 2 && !hasOverlay) {
element.removeChild(element.lastElementChild);
}
if (element !== previousElement) {
this.children_.push(element);
hasOverlay = childElementCount === 2;
previousElement = element;
}
}

View File

@@ -30,6 +30,16 @@ class LayerRenderer extends Observable {
}
/**
* Asynchronous layer level hit detection.
* @param {import("../pixel.js").Pixel} pixel Pixel.
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with
* an array of features.
*/
getFeatures(pixel) {
return abstract();
}
/**
* Determine whether render should be called.
* @abstract

View File

@@ -134,8 +134,8 @@ class MapRenderer extends Disposable {
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
const layerRenderer = layer.getRenderer();
const source = layer.getSource();
const coordinates = source.getWrapX() ? translatedCoordinate : coordinate;
if (layerRenderer && source) {
const coordinates = source.getWrapX() ? translatedCoordinate : coordinate;
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
tmpCoord[0] = coordinates[0] + offsets[i][0];
tmpCoord[1] = coordinates[1] + offsets[i][1];

View File

@@ -7,7 +7,7 @@ import {containsExtent, intersects} from '../../extent.js';
import {fromUserExtent} from '../../proj.js';
import {getIntersection, isEmpty} from '../../extent.js';
import CanvasLayerRenderer from './Layer.js';
import {compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
import {compose as composeTransform, makeInverse} from '../../transform.js';
/**
* @classdesc
@@ -92,7 +92,8 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
const rotation = viewState.rotation;
if (rotation) {
const size = Math.round(Math.sqrt(width * width + height * height));
width = height = size;
width = size;
height = size;
}
// set forward and inverse pixel transforms
@@ -104,7 +105,9 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
);
makeInverse(this.inversePixelTransform, this.pixelTransform);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const canvasTransform = this.createTransformString(this.pixelTransform);
this.useContainer(target, canvasTransform, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
@@ -162,7 +165,6 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
context.restore();
}
const canvasTransform = transformToString(this.pixelTransform);
if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform;
}

View File

@@ -7,7 +7,7 @@ import RenderEvent from '../../render/Event.js';
import RenderEventType from '../../render/EventType.js';
import {rotateAtOffset} from '../../render/canvas.js';
import LayerRenderer from '../Layer.js';
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString} from '../../transform.js';
/**
* @abstract
@@ -69,12 +69,18 @@ class CanvasLayerRenderer extends LayerRenderer {
*/
this.containerReused = false;
/**
* @type {HTMLCanvasElement}
* @private
*/
this.createTransformStringCanvas_ = createCanvasContext2D(1, 1).canvas;
}
/**
* Get a rendering container from an existing target, if compatible.
* @param {HTMLElement} target Potential render target.
* @param {import("../../transform").Transform} transform Transform.
* @param {string} transform CSS Transform.
* @param {number} opacity Opacity.
*/
useContainer(target, transform, opacity) {
@@ -86,7 +92,7 @@ class CanvasLayerRenderer extends LayerRenderer {
context = canvas.getContext('2d');
}
}
if (context && context.canvas.style.transform === transformToString(transform)) {
if (context && context.canvas.style.transform === transform) {
// Container of the previous layer renderer can be used.
this.container = target;
this.context = context;
@@ -109,6 +115,7 @@ class CanvasLayerRenderer extends LayerRenderer {
container.appendChild(canvas);
style = canvas.style;
style.position = 'absolute';
style.left = '0';
style.transformOrigin = 'top left';
this.container = container;
this.context = context;
@@ -213,23 +220,24 @@ class CanvasLayerRenderer extends LayerRenderer {
/**
* Creates a transform for rendering to an element that will be rotated after rendering.
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
* @param {import("../../coordinate.js").Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {number} pixelRatio Pixel ratio.
* @param {number} width Width of the rendered element (in pixels).
* @param {number} height Height of the rendered element (in pixels).
* @param {number} offsetX Offset on the x-axis in view coordinates.
* @protected
* @return {!import("../../transform.js").Transform} Transform.
*/
getRenderTransform(frameState, width, height, offsetX) {
const viewState = frameState.viewState;
const pixelRatio = frameState.pixelRatio;
getRenderTransform(center, resolution, rotation, pixelRatio, width, height, offsetX) {
const dx1 = width / 2;
const dy1 = height / 2;
const sx = pixelRatio / viewState.resolution;
const sx = pixelRatio / resolution;
const sy = -sx;
const dx2 = -viewState.center[0] + offsetX;
const dy2 = -viewState.center[1];
return composeTransform(this.tempTransform_, dx1, dy1, sx, sy, -viewState.rotation, dx2, dy2);
const dx2 = -center[0] + offsetX;
const dy2 = -center[1];
return composeTransform(this.tempTransform_, dx1, dy1, sx, sy, -rotation, dx2, dy2);
}
/**
@@ -261,6 +269,15 @@ class CanvasLayerRenderer extends LayerRenderer {
return data;
}
/**
* @param {import("../../transform.js").Transform} transform Transform.
* @return {string} CSS transform.
*/
createTransformString(transform) {
this.createTransformStringCanvas_.style.transform = toString(transform);
return this.createTransformStringCanvas_.style.transform;
}
}
export default CanvasLayerRenderer;

View File

@@ -7,7 +7,7 @@ import TileRange from '../../TileRange.js';
import TileState from '../../TileState.js';
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.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} from '../../transform.js';
import {numberSafeCompareFunction} from '../../array.js';
/**
@@ -31,10 +31,22 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
/**
* @private
* @type {import("../../extent.js").Extent}
* @type {?import("../../extent.js").Extent}
*/
this.renderedExtent_ = null;
/**
* @protected
* @type {number}
*/
this.renderedPixelRatio;
/**
* @protected
* @type {import("../../proj/Projection.js").default}
*/
this.renderedProjection = null;
/**
* @protected
* @type {number}
@@ -163,7 +175,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
if (rotation) {
const size = Math.round(Math.sqrt(width * width + height * height));
width = height = size;
width = size;
height = size;
}
const dx = tileResolution * width / 2 / tilePixelRatio;
@@ -230,7 +243,9 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
-width / 2, -height / 2
);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const canvasTransform = this.createTransformString(this.pixelTransform);
this.useContainer(target, canvasTransform, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
@@ -342,6 +357,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
this.renderedResolution = tileResolution;
this.extentChanged = !this.renderedExtent_ || !equals(this.renderedExtent_, canvasExtent);
this.renderedExtent_ = canvasExtent;
this.renderedPixelRatio = pixelRatio;
this.renderedProjection = projection;
this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
projection, extent, z, tileLayer.getPreload());
@@ -354,7 +371,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
context.restore();
}
const canvasTransform = transformToString(this.pixelTransform);
if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform;
}

View File

@@ -10,6 +10,7 @@ import CanvasVectorLayerRenderer from './VectorLayer.js';
import EventType from '../../events/EventType.js';
import ImageState from '../../ImageState.js';
import {renderDeclutterItems} from '../../render.js';
import {apply, compose, create} from '../../transform.js';
/**
* @classdesc
@@ -36,6 +37,18 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
*/
this.layerImageRatio_ = layer.getImageRatio();
/**
* @private
* @type {import("../../transform.js").Transform}
*/
this.coordinateToVectorPixelTransform_ = create();
/**
* @private
* @type {import("../../transform.js").Transform}
*/
this.renderedPixelToCoordinateTransform_ = null;
}
/**
@@ -46,6 +59,22 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
super.disposeInternal();
}
/**
* @inheritDoc
*/
getFeatures(pixel) {
if (this.vectorRenderer_) {
const vectorPixel = apply(this.coordinateToVectorPixelTransform_,
apply(this.renderedPixelToCoordinateTransform_, pixel.slice()));
return this.vectorRenderer_.getFeatures(vectorPixel);
} else {
const promise = new Promise(function(resolve, reject) {
resolve([]);
});
return promise;
}
}
/**
* @inheritDoc
*/
@@ -68,16 +97,15 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
renderedExtent = renderedExtent.slice(0);
scaleFromCenter(renderedExtent, this.layerImageRatio_);
}
const width = getWidth(renderedExtent) / viewResolution;
const height = getHeight(renderedExtent) / viewResolution;
if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) {
vectorRenderer.useContainer(null, null, 1);
const context = vectorRenderer.context;
const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, {
declutterItems: [],
size: [
getWidth(renderedExtent) / viewResolution,
getHeight(renderedExtent) / viewResolution
],
size: [width, height],
viewState: /** @type {import("../../View.js").State} */ (assign({}, frameState.viewState, {
rotation: 0
}))
@@ -102,7 +130,14 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
const image = this.image_;
const imageResolution = image.getResolution();
const imagePixelRatio = image.getPixelRatio();
this.renderedResolution = imageResolution * pixelRatio / imagePixelRatio;
const renderedResolution = imageResolution * pixelRatio / imagePixelRatio;
this.renderedResolution = renderedResolution;
this.renderedPixelToCoordinateTransform_ = frameState.pixelToCoordinateTransform.slice();
this.coordinateToVectorPixelTransform_ = compose(this.coordinateToVectorPixelTransform_,
width / 2, height / 2,
1 / renderedResolution, -1 / renderedResolution,
0,
-viewState.center[0], -viewState.center[1]);
}
return !!this.image_;

View File

@@ -9,7 +9,8 @@ import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import ExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
import CanvasLayerRenderer from './Layer.js';
import {defaultOrder as defaultRenderOrder, getTolerance as getRenderTolerance, getSquaredTolerance as getSquaredRenderTolerance, renderFeature} from '../vector.js';
import {toString as transformToString, makeScale, makeInverse} from '../../transform.js';
import {toString as transformToString, makeScale, makeInverse, apply} from '../../transform.js';
import {createHitDetectionImageData, hitDetect} from '../../render/canvas/hitdetect.js';
/**
* @classdesc
@@ -28,6 +29,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/** @private */
this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
/**
* @type {boolean}
*/
this.animatingOrInteracting_;
/**
* @private
@@ -35,6 +40,16 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
*/
this.dirty_ = false;
/**
* @type {ImageData}
*/
this.hitDetectionImageData_ = null;
/**
* @type {Array<import("../../Feature.js").default>}
*/
this.renderedFeatures_ = null;
/**
* @private
* @type {number}
@@ -53,6 +68,24 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
*/
this.renderedExtent_ = createEmpty();
/**
* @private
* @type {number}
*/
this.renderedRotation_;
/**
* @private
* @type {import("../../coordinate").Coordinate}
*/
this.renderedCenter_ = null;
/**
* @private
* @type {import("../../proj/Projection").default}
*/
this.renderedProjection_ = null;
/**
* @private
* @type {function(import("../../Feature.js").default, import("../../Feature.js").default): number|null}
@@ -94,7 +127,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
makeScale(this.pixelTransform, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform, this.pixelTransform);
this.useContainer(target, this.pixelTransform, layerState.opacity);
const canvasTransform = transformToString(this.pixelTransform);
this.useContainer(target, canvasTransform, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
@@ -112,7 +147,6 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (canvas.width != width || canvas.height != height) {
canvas.width = width;
canvas.height = height;
const canvasTransform = transformToString(this.pixelTransform);
if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform;
}
@@ -124,6 +158,8 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const extent = frameState.extent;
const viewState = frameState.viewState;
const center = viewState.center;
const resolution = viewState.resolution;
const projection = viewState.projection;
const rotation = viewState.rotation;
const projectionExtent = projection.getExtent();
@@ -143,7 +179,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const viewHints = frameState.viewHints;
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
const transform = this.getRenderTransform(frameState, width, height, 0);
const transform = this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, 0);
const declutterReplays = this.getLayer().getDeclutter() ? {} : null;
replayGroup.execute(context, transform, rotation, snapToPixel, undefined, declutterReplays);
@@ -155,7 +191,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
while (startX < projectionExtent[0]) {
--world;
offsetX = worldWidth * world;
const transform = this.getRenderTransform(frameState, width, height, offsetX);
const transform = this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, offsetX);
replayGroup.execute(context, transform, rotation, snapToPixel, undefined, declutterReplays);
startX += worldWidth;
}
@@ -164,7 +200,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
while (startX > projectionExtent[2]) {
++world;
offsetX = worldWidth * world;
const transform = this.getRenderTransform(frameState, width, height, offsetX);
const transform = this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, offsetX);
replayGroup.execute(context, transform, rotation, snapToPixel, undefined, declutterReplays);
startX -= worldWidth;
}
@@ -190,6 +226,58 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
return this.container;
}
/**
* @inheritDoc
*/
getFeatures(pixel) {
return new Promise(function(resolve, reject) {
if (!this.hitDetectionImageData_ && !this.animatingOrInteracting_) {
requestAnimationFrame(function() {
const size = [this.context.canvas.width, this.context.canvas.height];
apply(this.pixelTransform, size);
const center = this.renderedCenter_;
const resolution = this.renderedResolution_;
const rotation = this.renderedRotation_;
const projection = this.renderedProjection_;
const extent = this.renderedExtent_;
const layer = this.getLayer();
const transforms = [];
const width = size[0] / 2;
const height = size[1] / 2;
transforms.push(this.getRenderTransform(center, resolution, rotation, 0.5, width, height, 0).slice());
const source = layer.getSource();
const projectionExtent = projection.getExtent();
if (source.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) {
let startX = extent[0];
const worldWidth = getWidth(projectionExtent);
let world = 0;
let offsetX;
while (startX < projectionExtent[0]) {
--world;
offsetX = worldWidth * world;
transforms.push(this.getRenderTransform(center, resolution, rotation, 0.5, width, height, offsetX).slice());
startX += worldWidth;
}
world = 0;
startX = extent[2];
while (startX > projectionExtent[2]) {
++world;
offsetX = worldWidth * world;
transforms.push(this.getRenderTransform(center, resolution, rotation, 0.5, width, height, offsetX).slice());
startX -= worldWidth;
}
}
this.hitDetectionImageData_ = createHitDetectionImageData(size, transforms,
this.renderedFeatures_, layer.getStyleFunction(), extent, resolution, rotation);
resolve(hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_));
}.bind(this));
} else {
resolve(hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_));
}
}.bind(this));
}
/**
* @inheritDoc
*/
@@ -253,8 +341,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (!this.dirty_ && (!updateWhileAnimating && animating) ||
(!updateWhileInteracting && interacting)) {
this.animatingOrInteracting_ = true;
return true;
}
this.animatingOrInteracting_ = false;
const frameStateExtent = frameState.extent;
const viewState = frameState.viewState;
@@ -269,6 +359,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
vectorLayerRenderOrder = defaultRenderOrder;
}
const center = viewState.center.slice();
const extent = buffer(frameStateExtent,
vectorLayerRenderBuffer * resolution);
const projectionExtent = viewState.projection.getExtent();
@@ -284,6 +375,8 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const gutter = Math.max(getWidth(extent) / 2, worldWidth);
extent[0] = projectionExtent[0] - gutter;
extent[2] = projectionExtent[2] + gutter;
const worldsAway = Math.floor((center[0] - projectionExtent[0]) / worldWidth);
center[0] -= (worldsAway * worldWidth);
}
if (!this.dirty_ &&
@@ -334,23 +427,15 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
}.bind(this);
const userExtent = toUserExtent(extent, projection);
if (vectorLayerRenderOrder) {
/** @type {Array<import("../../Feature.js").default>} */
const features = [];
vectorSource.forEachFeatureInExtent(userExtent,
/**
* @param {import("../../Feature.js").default} feature Feature.
*/
function(feature) {
features.push(feature);
});
const features = vectorSource.getFeaturesInExtent(userExtent);
if (vectorLayerRenderOrder) {
features.sort(vectorLayerRenderOrder);
}
for (let i = 0, ii = features.length; i < ii; ++i) {
render(features[i]);
}
} else {
vectorSource.forEachFeatureInExtent(userExtent, render);
}
this.renderedFeatures_ = features;
const replayGroupInstructions = replayGroup.finish();
const executorGroup = new ExecutorGroup(extent, resolution,
@@ -361,7 +446,11 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
this.renderedRevision_ = vectorLayerRevision;
this.renderedRenderOrder_ = vectorLayerRenderOrder;
this.renderedExtent_ = extent;
this.renderedRotation_ = viewState.rotation;
this.renderedCenter_ = center;
this.renderedProjection_ = projection;
this.replayGroup_ = executorGroup;
this.hitDetectionImageData_ = null;
this.replayGroupChanged = true;
return true;

View File

@@ -2,16 +2,16 @@
* @module ol/renderer/canvas/VectorTileLayer
*/
import {getUid} from '../../util.js';
import {createCanvasContext2D} from '../../dom.js';
import TileState from '../../TileState.js';
import ViewHint from '../../ViewHint.js';
import {listen, unlistenByKey} from '../../events.js';
import EventType from '../../events/EventType.js';
import {buffer, containsCoordinate, equals, getIntersection, intersects} from '../../extent.js';
import {buffer, containsCoordinate, equals, getIntersection, intersects, containsExtent, getWidth, getTopLeft} from '../../extent.js';
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
import ReplayType from '../../render/canvas/BuilderType.js';
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import CanvasTileLayerRenderer from './TileLayer.js';
import {toSize} from '../../size.js';
import {getSquaredTolerance as getSquaredRenderTolerance, renderFeature} from '../vector.js';
import {
apply as applyTransform,
@@ -19,12 +19,12 @@ import {
reset as resetTransform,
scale as scaleTransform,
translate as translateTransform,
toString as transformToString,
makeScale,
makeInverse
multiply,
scale
} from '../../transform.js';
import CanvasExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
import {clear} from '../../obj.js';
import {createHitDetectionImageData, hitDetect} from '../../render/canvas/hitdetect.js';
/**
@@ -62,31 +62,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/** @private */
this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.overlayContext_ = null;
/**
* @type {string}
*/
this.overlayContextUid_;
/**
* The transform for rendered pixels to viewport CSS pixels for the overlay canvas.
* @private
* @type {import("../../transform.js").Transform}
*/
this.overlayPixelTransform_ = createTransform();
/**
* The transform for viewport CSS pixels to rendered pixels for the overlay canvas.
* @private
* @type {import("../../transform.js").Transform}
*/
this.inverseOverlayPixelTransform_ = createTransform();
/**
* @private
* @type {boolean}
@@ -99,6 +74,18 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/
this.renderedLayerRevision_;
/**
* @private
* @type {import("../../transform").Transform}
*/
this.renderedPixelToCoordinateTransform_ = null;
/**
* @private
* @type {number}
*/
this.renderedRotation_;
/**
* @private
* @type {!Object<string, import("../../VectorRenderTile.js").default>}
@@ -117,45 +104,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
this.tmpTransform_ = createTransform();
}
/**
* @inheritDoc
*/
useContainer(target, transform, opacity) {
let overlayContext;
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 {number} pixelRatio Pixel ratio.
* @param {import("../../proj/Projection").default} projection Projection.
* @param {boolean} queue Queue tile for rendering.
* @return {boolean} Tile needs to be rendered.
* @return {boolean|undefined} Tile needs to be rendered.
*/
prepareTile(tile, pixelRatio, projection, queue) {
let render = false;
let render;
const tileUid = getUid(tile);
const state = tile.getState();
if (((state === TileState.LOADED && tile.hifi) ||
@@ -224,8 +181,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @inheritDoc
*/
prepareFrame(frameState) {
const layerState = frameState.layerStatesArray[frameState.layerIndex];
layerState.hasOverlay = true;
const layerRevision = this.getLayer().getRevision();
if (this.renderedLayerRevision_ != layerRevision) {
this.renderedTiles.length = 0;
@@ -266,6 +221,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
executorGroups[i].dispose();
}
}
tile.hitDetectionImageData = null;
tile.executorGroups[layerUid] = [];
for (let t = 0, tt = sourceTiles.length; t < tt; ++t) {
const sourceTile = sourceTiles[t];
@@ -379,6 +335,69 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
return found;
}
/**
* @inheritDoc
*/
getFeatures(pixel) {
return new Promise(function(resolve, reject) {
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const source = layer.getSource();
const projection = this.renderedProjection;
const projectionExtent = projection.getExtent();
const resolution = this.renderedResolution;
const tileGrid = source.getTileGridForProjection(projection);
const coordinate = applyTransform(this.renderedPixelToCoordinateTransform_, pixel.slice());
const tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
let tile;
for (let i = 0, ii = this.renderedTiles.length; i < ii; ++i) {
if (tileCoord.toString() === this.renderedTiles[i].tileCoord.toString()) {
tile = this.renderedTiles[i];
if (tile.getState() === TileState.LOADED && tile.hifi) {
const extent = tileGrid.getTileCoordExtent(tile.tileCoord);
if (source.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) {
const worldWidth = getWidth(projectionExtent);
const worldsAway = Math.floor((coordinate[0] - projectionExtent[0]) / worldWidth);
coordinate[0] -= (worldsAway * worldWidth);
}
break;
}
tile = undefined;
}
}
if (!tile) {
resolve([]);
return;
}
const extent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
const corner = getTopLeft(extent);
const tilePixel = [
(coordinate[0] - corner[0]) / resolution,
(corner[1] - coordinate[1]) / resolution
];
const features = tile.getSourceTiles().reduce(function(accumulator, sourceTile) {
return accumulator.concat(sourceTile.getFeatures());
}, []);
if (!tile.hitDetectionImageData) {
const tileSize = toSize(tileGrid.getTileSize(tileGrid.getZForResolution(resolution)));
const size = [tileSize[0] / 2, tileSize[1] / 2];
const rotation = this.renderedRotation_;
const transforms = [
this.getRenderTransform(tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
resolution, 0, 0.5, size[0], size[1], 0)
];
requestAnimationFrame(function() {
tile.hitDetectionImageData = createHitDetectionImageData(tileSize, transforms,
features, layer.getStyleFunction(),
tileGrid.getTileCoordExtent(tile.wrappedTileCoord),
tile.getReplayState(layer).renderedResolution, rotation);
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData));
});
} else {
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData));
}
}.bind(this));
}
/**
* @inheritDoc
*/
@@ -408,6 +427,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
this.renderQueuedTileImages_(hifi, frameState);
super.renderFrame(frameState, target);
this.renderedPixelToCoordinateTransform_ = frameState.pixelToCoordinateTransform.slice();
this.renderedRotation_ = frameState.viewState.rotation;
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const renderMode = layer.getRenderMode();
@@ -424,31 +446,18 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
}
}
const context = this.overlayContext_;
const context = this.context;
const declutterReplays = layer.getDeclutter() ? {} : null;
const replayTypes = VECTOR_REPLAYS[renderMode];
const pixelRatio = frameState.pixelRatio;
const rotation = frameState.viewState.rotation;
const viewState = frameState.viewState;
const center = viewState.center;
const resolution = viewState.resolution;
const rotation = viewState.rotation;
const size = frameState.size;
// set forward and inverse pixel transforms
makeScale(this.overlayPixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inverseOverlayPixelTransform_, this.overlayPixelTransform_);
// resize and clear
const canvas = context.canvas;
const width = Math.round(size[0] * pixelRatio);
const height = Math.round(size[1] * pixelRatio);
if (canvas.width != width || canvas.height != height) {
canvas.width = width;
canvas.height = height;
const canvasTransform = transformToString(this.overlayPixelTransform_);
if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform;
}
} else if (getUid(context) === this.overlayContextUid_) {
context.clearRect(0, 0, width, height);
}
const tiles = this.renderedTiles;
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
@@ -462,7 +471,10 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
const tileCoord = tile.tileCoord;
const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tileExtent[0];
const transform = this.getRenderTransform(frameState, width, height, worldOffset);
const transform = multiply(
scale(this.inversePixelTransform.slice(), 1 / pixelRatio, 1 / pixelRatio),
this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, worldOffset)
);
const executorGroups = tile.executorGroups[getUid(layer)];
let clipped = false;
for (let t = 0, tt = executorGroups.length; t < tt; ++t) {
@@ -622,34 +634,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
replayState.renderedTileResolution = tile.wantedResolution;
}
/**
* @inheritDoc
*/
getDataAtPixel(pixel, frameState, hitTolerance) {
let data = super.getDataAtPixel(pixel, frameState, hitTolerance);
if (data) {
return data;
}
const renderPixel = applyTransform(this.inverseOverlayPixelTransform_, pixel.slice());
const context = this.overlayContext_;
try {
data = context.getImageData(Math.round(renderPixel[0]), Math.round(renderPixel[1]), 1, 1).data;
} catch (err) {
if (err.name === 'SecurityError') {
// tainted canvas, we assume there is data at the given pixel (although there might not be)
return new Uint8Array();
}
return data;
}
if (data[3] === 0) {
return null;
}
return data;
}
}

View File

@@ -71,7 +71,7 @@ class WebGLLayerRenderer extends LayerRenderer {
* @inheritDoc
*/
disposeInternal() {
this.helper.disposeInternal();
this.helper.dispose();
super.disposeInternal();
}
@@ -169,7 +169,10 @@ export function writePointFeatureToBuffers(instructions, elementIndex, vertexBuf
export function getBlankImageData() {
const canvas = document.createElement('canvas');
const image = canvas.getContext('2d').createImageData(1, 1);
image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255;
image.data[0] = 255;
image.data[1] = 255;
image.data[2] = 255;
image.data[3] = 255;
return image;
}

View File

@@ -7,7 +7,7 @@ import {AttributeType, DefaultUniform} from '../../webgl/Helper.js';
import GeometryType from '../../geom/GeometryType.js';
import WebGLLayerRenderer, {colorDecodeId, colorEncodeId, WebGLWorkerMessageType} from './Layer.js';
import ViewHint from '../../ViewHint.js';
import {createEmpty, equals} from '../../extent.js';
import {buffer, createEmpty, equals} from '../../extent.js';
import {
apply as applyTransform,
create as createTransform,
@@ -18,13 +18,24 @@ import {create as createWebGLWorker} from '../../worker/webgl.js';
import {getUid} from '../../util.js';
import WebGLRenderTarget from '../../webgl/RenderTarget.js';
import {assert} from '../../asserts.js';
import BaseVector from '../../layer/BaseVector.js';
import {listen, unlistenByKey} from '../../events.js';
import VectorEventType from '../../source/VectorEventType.js';
/**
* @typedef {Object} CustomAttribute A description of a custom attribute to be passed on to the GPU, with a value different
* for each feature.
* @property {string} name Attribute name.
* @property {function(import("../../Feature").default):number} callback This callback computes the numerical value of the
* attribute for a given feature.
* @property {function(import("../../Feature").default, Object<string, *>):number} callback This callback computes the numerical value of the
* attribute for a given feature (properties are available as 2nd arg for quicker access).
*/
/**
* @typedef {Object} FeatureCacheItem Object that holds a reference to a feature, its geometry and properties. Used to optimize
* rebuildBuffers by accessing these objects quicker.
* @property {import("../../Feature").default} feature Feature
* @property {Object<string, *>} properties Feature properties
* @property {import("../../geom").Geometry} geometry Feature geometry
*/
/**
@@ -132,6 +143,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
options.vertexShader
);
if (this.getShaderCompileErrors()) {
throw new Error(this.getShaderCompileErrors());
}
/**
* @type {boolean}
* @private
@@ -143,6 +158,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
options.hitVertexShader
);
if (this.getShaderCompileErrors()) {
throw new Error(this.getShaderCompileErrors());
}
const customAttributes = options.attributes ?
options.attributes.map(function(attribute) {
return {
@@ -260,6 +279,72 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.getLayer().changed();
}
}.bind(this));
/**
* This object will be updated when the source changes. Key is uid.
* @type {Object<string, FeatureCacheItem>}
* @private
*/
this.featureCache_ = {};
/**
* Amount of features in the cache.
* @type {number}
* @private
*/
this.featureCount_ = 0;
const source = this.getLayer().getSource();
this.sourceListenKeys_ = [
listen(source, VectorEventType.ADDFEATURE, this.handleSourceFeatureAdded_, this),
listen(source, VectorEventType.CHANGEFEATURE, this.handleSourceFeatureChanged_, this),
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this)
];
source.forEachFeature(function(feature) {
this.featureCache_[getUid(feature)] = {
feature: feature,
properties: feature.getProperties(),
geometry: feature.getGeometry()
};
this.featureCount_++;
}.bind(this));
}
/**
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
* @private
*/
handleSourceFeatureAdded_(event) {
const feature = event.feature;
this.featureCache_[getUid(feature)] = {
feature: feature,
properties: feature.getProperties(),
geometry: feature.getGeometry()
};
this.featureCount_++;
}
/**
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
* @private
*/
handleSourceFeatureChanged_(event) {
const feature = event.feature;
this.featureCache_[getUid(feature)] = {
feature: feature,
properties: feature.getProperties(),
geometry: feature.getGeometry()
};
}
/**
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
* @private
*/
handleSourceFeatureDelete_(event) {
const feature = event.feature;
delete this.featureCache_[getUid(feature)];
this.featureCount_--;
}
/**
@@ -292,20 +377,22 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const layer = this.getLayer();
const vectorSource = layer.getSource();
const viewState = frameState.viewState;
// the source has changed: clear the feature cache & reload features
const sourceChanged = this.sourceRevision_ < vectorSource.getRevision();
if (sourceChanged) {
this.sourceRevision_ = vectorSource.getRevision();
const projection = viewState.projection;
const resolution = viewState.resolution;
vectorSource.loadFeatures([-Infinity, -Infinity, Infinity, Infinity], resolution, projection);
}
const viewNotMoving = !frameState.viewHints[ViewHint.ANIMATING] && !frameState.viewHints[ViewHint.INTERACTING];
const extentChanged = !equals(this.previousExtent_, frameState.extent);
if ((sourceChanged || extentChanged) && viewNotMoving) {
const sourceChanged = this.sourceRevision_ < vectorSource.getRevision();
if (sourceChanged) {
this.sourceRevision_ = vectorSource.getRevision();
}
if (viewNotMoving && (extentChanged || sourceChanged)) {
const projection = viewState.projection;
const resolution = viewState.resolution;
const renderBuffer = layer instanceof BaseVector ? layer.getRenderBuffer() : 0;
const extent = buffer(frameState.extent, renderBuffer * resolution);
vectorSource.loadFeatures(extent, resolution, projection);
this.rebuildBuffers_(frameState);
this.previousExtent_ = frameState.extent.slice();
}
@@ -332,45 +419,41 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
* @private
*/
rebuildBuffers_(frameState) {
const layer = this.getLayer();
const vectorSource = layer.getSource();
// saves the projection transform for the current frame state
const projectionTransform = createTransform();
this.helper.makeProjectionTransform(frameState, projectionTransform);
const features = vectorSource.getFeatures();
// here we anticipate the amount of render instructions that we well generate
// this can be done since we know that for normal render we only have x, y as base instructions,
// and x, y, r, g, b, a and featureUid for hit render instructions
// and we also know the amount of custom attributes to append to these
const totalInstructionsCount = (2 + this.customAttributes.length) * features.length;
const totalInstructionsCount = (2 + this.customAttributes.length) * this.featureCount_;
if (!this.renderInstructions_ || this.renderInstructions_.length !== totalInstructionsCount) {
this.renderInstructions_ = new Float32Array(totalInstructionsCount);
}
if (this.hitDetectionEnabled_) {
const totalHitInstructionsCount = (7 + this.customAttributes.length) * features.length;
const totalHitInstructionsCount = (7 + this.customAttributes.length) * this.featureCount_;
if (!this.hitRenderInstructions_ || this.hitRenderInstructions_.length !== totalHitInstructionsCount) {
this.hitRenderInstructions_ = new Float32Array(totalHitInstructionsCount);
}
}
// loop on features to fill the buffer
let feature;
let featureCache, geometry;
const tmpCoords = [];
const tmpColor = [];
let renderIndex = 0;
let hitIndex = 0;
let hitColor;
for (let i = 0; i < features.length; i++) {
feature = features[i];
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
for (const featureUid in this.featureCache_) {
featureCache = this.featureCache_[featureUid];
geometry = /** @type {import("../../geom").Point} */(featureCache.geometry);
if (!geometry || geometry.getType() !== GeometryType.POINT) {
continue;
}
tmpCoords[0] = feature.getGeometry().getFlatCoordinates()[0];
tmpCoords[1] = feature.getGeometry().getFlatCoordinates()[1];
tmpCoords[0] = geometry.getFlatCoordinates()[0];
tmpCoords[1] = geometry.getFlatCoordinates()[1];
applyTransform(projectionTransform, tmpCoords);
hitColor = colorEncodeId(hitIndex + 6, tmpColor);
@@ -387,13 +470,13 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.hitRenderInstructions_[hitIndex++] = hitColor[1];
this.hitRenderInstructions_[hitIndex++] = hitColor[2];
this.hitRenderInstructions_[hitIndex++] = hitColor[3];
this.hitRenderInstructions_[hitIndex++] = Number(getUid(feature));
this.hitRenderInstructions_[hitIndex++] = Number(featureUid);
}
// pushing custom attributes
let value;
for (let j = 0; j < this.customAttributes.length; j++) {
value = this.customAttributes[j].callback(feature);
value = this.customAttributes[j].callback(featureCache.feature, featureCache.properties);
this.renderInstructions_[renderIndex++] = value;
if (this.hitDetectionEnabled_) {
this.hitRenderInstructions_[hitIndex++] = value;
@@ -401,7 +484,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
}
}
/** @type import('./Layer').WebGLWorkerGenerateBuffersMessage */
/** @type {import('./Layer').WebGLWorkerGenerateBuffersMessage} */
const message = {
type: WebGLWorkerMessageType.GENERATE_BUFFERS,
renderInstructions: this.renderInstructions_.buffer,
@@ -412,7 +495,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.worker_.postMessage(message, [this.renderInstructions_.buffer]);
this.renderInstructions_ = null;
/** @type import('./Layer').WebGLWorkerGenerateBuffersMessage */
/** @type {import('./Layer').WebGLWorkerGenerateBuffersMessage} */
if (this.hitDetectionEnabled_) {
const hitMessage = {
type: WebGLWorkerMessageType.GENERATE_BUFFERS,
@@ -437,7 +520,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const pixel = applyTransform(frameState.coordinateToPixelTransform, coordinate.slice());
const data = this.hitRenderTarget_.readPixel(pixel[0], pixel[1]);
const data = this.hitRenderTarget_.readPixel(pixel[0] / 2, pixel[1] / 2);
const color = [
data[0] / 255,
data[1] / 255,
@@ -465,7 +548,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
return;
}
this.hitRenderTarget_.setSize(frameState.size);
this.hitRenderTarget_.setSize([
Math.floor(frameState.size[0] / 2),
Math.floor(frameState.size[1] / 2)
]);
this.helper.useProgram(this.hitProgram_);
this.helper.prepareDrawToRenderTarget(frameState, this.hitRenderTarget_, true);
@@ -484,6 +570,11 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
*/
disposeInternal() {
this.worker_.terminate();
this.layer_ = null;
this.sourceListenKeys_.forEach(function(key) {
unlistenByKey(key);
});
this.sourceListenKeys_ = null;
super.disposeInternal();
}
}

View File

@@ -70,7 +70,8 @@ export function toSize(size, opt_size) {
if (opt_size === undefined) {
opt_size = [size, size];
} else {
opt_size[0] = opt_size[1] = /** @type {number} */ (size);
opt_size[0] = size;
opt_size[1] = size;
}
return opt_size;
}

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