Compare commits
242 Commits
v6.0.0-bet
...
docs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad39cf69e | ||
|
|
6929cb3001 | ||
|
|
5ee3063d01 | ||
|
|
2322131b01 | ||
|
|
39bb6a8ffe | ||
|
|
0631a121c3 | ||
|
|
c860f15f91 | ||
|
|
c10fd7aaab | ||
|
|
7ced251d19 | ||
|
|
637c823fa6 | ||
|
|
2d655143c3 | ||
|
|
fba95ea3f0 | ||
|
|
40393cd9a4 | ||
|
|
10527bd221 | ||
|
|
4c2b11f6d7 | ||
|
|
512a39bafd | ||
|
|
78c09a0ff6 | ||
|
|
6dc00b75e0 | ||
|
|
6b50f1555b | ||
|
|
a6f098f78b | ||
|
|
6d06f81ca7 | ||
|
|
908ecb39e3 | ||
|
|
6cad19e9d5 | ||
|
|
17d26acb2f | ||
|
|
579fadd797 | ||
|
|
9693336d99 | ||
|
|
335648d613 | ||
|
|
dc906f79e1 | ||
|
|
34a8a484c4 | ||
|
|
0d489f2ea9 | ||
|
|
d49e166506 | ||
|
|
a0e6af425e | ||
|
|
ee9a0bcd05 | ||
|
|
442fbb13d2 | ||
|
|
fddc5bcc5b | ||
|
|
c2058af13a | ||
|
|
bb022050ed | ||
|
|
a8e5cb1e12 | ||
|
|
1628ce8729 | ||
|
|
37f96ddcfa | ||
|
|
1fc75fdc68 | ||
|
|
10c4ec0b37 | ||
|
|
2e34dd0faf | ||
|
|
b7b37f9548 | ||
|
|
05f13bb363 | ||
|
|
e307410301 | ||
|
|
5a4541dadb | ||
|
|
56ec6b093e | ||
|
|
61d753c803 | ||
|
|
f312706269 | ||
|
|
f33ad5e025 | ||
|
|
2e31f716ed | ||
|
|
eafb657264 | ||
|
|
0cee259d0b | ||
|
|
be8797f355 | ||
|
|
d652bfc4a7 | ||
|
|
11607caa81 | ||
|
|
41e958ea1f | ||
|
|
39de2451bc | ||
|
|
e11e3c5f6e | ||
|
|
c705775d75 | ||
|
|
9ca75e9d43 | ||
|
|
5d2b7fe4bb | ||
|
|
fb455891ce | ||
|
|
3e2e45ce6d | ||
|
|
75eb62363a | ||
|
|
523097903a | ||
|
|
c6d214b585 | ||
|
|
c9604dbd69 | ||
|
|
df37519858 | ||
|
|
10c6009ffa | ||
|
|
27e520add4 | ||
|
|
3a429d3f6c | ||
|
|
5e36468245 | ||
|
|
a2d83f5358 | ||
|
|
53b9718381 | ||
|
|
2de282ae49 | ||
|
|
217c6ba764 | ||
|
|
039f21274b | ||
|
|
09fdd30876 | ||
|
|
72551ab506 | ||
|
|
811e5f60eb | ||
|
|
b1ea0fec50 | ||
|
|
98ee52c61c | ||
|
|
f76b9bdd07 | ||
|
|
3a1d927c41 | ||
|
|
9224bfab7d | ||
|
|
b5535f3ba5 | ||
|
|
bfe6d29601 | ||
|
|
807525b1db | ||
|
|
8504a49e17 | ||
|
|
83d317d16d | ||
|
|
55b27c70b5 | ||
|
|
1c13893dd1 | ||
|
|
4a1cda715d | ||
|
|
c9d1725f5c | ||
|
|
4bf314f9e6 | ||
|
|
14f580fe30 | ||
|
|
a2e6d4b324 | ||
|
|
dadc240038 | ||
|
|
dd265623e4 | ||
|
|
23137cdab3 | ||
|
|
1d08eb5752 | ||
|
|
78cee60d91 | ||
|
|
1deabaa1c0 | ||
|
|
88b6b18cc0 | ||
|
|
355fb41748 | ||
|
|
7d2249f652 | ||
|
|
5e288ebedf | ||
|
|
80eb8b62ce | ||
|
|
cdb36a3bf2 | ||
|
|
04a28854c9 | ||
|
|
51cf9ee3a1 | ||
|
|
fbc8580539 | ||
|
|
eeec56fa94 | ||
|
|
17d83b9c20 | ||
|
|
2c9f6b496f | ||
|
|
5006bbe13f | ||
|
|
a1026a50bd | ||
|
|
c117ec79f7 | ||
|
|
b37eb29444 | ||
|
|
4df545dfb0 | ||
|
|
70f5822217 | ||
|
|
d49a41def0 | ||
|
|
e4941f60db | ||
|
|
d1fe22a872 | ||
|
|
5756003c88 | ||
|
|
e5e2129a88 | ||
|
|
c5e6728d6d | ||
|
|
d9b3986c95 | ||
|
|
a67f8e3f38 | ||
|
|
7989991da9 | ||
|
|
afa70e5a1e | ||
|
|
ce9ea5cc93 | ||
|
|
5f5cdc9645 | ||
|
|
6370426d52 | ||
|
|
fb7bd2158d | ||
|
|
387b4188f2 | ||
|
|
c922d4eb8f | ||
|
|
9d4eda2318 | ||
|
|
bd235b7b49 | ||
|
|
7daba05548 | ||
|
|
64e67ae351 | ||
|
|
40ea2a8b7e | ||
|
|
4629fe5028 | ||
|
|
ba2c558b72 | ||
|
|
84f1e0c66e | ||
|
|
72e41d3703 | ||
|
|
6775723840 | ||
|
|
d332b6a0f4 | ||
|
|
f68b8d8df9 | ||
|
|
c2cbae95c6 | ||
|
|
b36ad87cb5 | ||
|
|
b7c004f95c | ||
|
|
7bfaa3b6ad | ||
|
|
0cffee6f83 | ||
|
|
3895a59c5e | ||
|
|
a2b39c9c53 | ||
|
|
12154d98b4 | ||
|
|
c25dba415f | ||
|
|
27d943dcc3 | ||
|
|
66b5b5d7e1 | ||
|
|
3cf9b5aa28 | ||
|
|
b77177ed74 | ||
|
|
f61562a51a | ||
|
|
e4a531de8c | ||
|
|
063bc51c59 | ||
|
|
3f3fbe7e4b | ||
|
|
01a6381756 | ||
|
|
0ab7ad741f | ||
|
|
58efe1f850 | ||
|
|
66b41a53b8 | ||
|
|
c00400c500 | ||
|
|
944af1fe80 | ||
|
|
ea55f39298 | ||
|
|
84db84bc23 | ||
|
|
f366eaea52 | ||
|
|
f5ae41f03e | ||
|
|
6b1bce2b9d | ||
|
|
bd57128ca4 | ||
|
|
5012e4987c | ||
|
|
6e3d3d4877 | ||
|
|
d30f6175ce | ||
|
|
0e08d9e0fd | ||
|
|
81f99f1579 | ||
|
|
4973281f3c | ||
|
|
8f3820be22 | ||
|
|
033a18bc1c | ||
|
|
99fb0bf57e | ||
|
|
49a9f21388 | ||
|
|
e4d25400ee | ||
|
|
1e350677fb | ||
|
|
86f304ae02 | ||
|
|
00c09eb281 | ||
|
|
6c8c8a6477 | ||
|
|
1142caf5e8 | ||
|
|
ba6ac43a28 | ||
|
|
12289b8ef9 | ||
|
|
f69c37566e | ||
|
|
6cfd0b70ed | ||
|
|
d95bcc8594 | ||
|
|
d3e6f4c3b2 | ||
|
|
eb21369d86 | ||
|
|
68a29f1ac6 | ||
|
|
6413badada | ||
|
|
d6485b1e94 | ||
|
|
98a5f552b2 | ||
|
|
067260170b | ||
|
|
9850c0134e | ||
|
|
284c1dff83 | ||
|
|
d166c79242 | ||
|
|
e4f377fb46 | ||
|
|
e22af6dbd6 | ||
|
|
0f998b4522 | ||
|
|
2cdfcf8b21 | ||
|
|
b3e770226f | ||
|
|
981328576f | ||
|
|
3b1a415d6b | ||
|
|
fde36b237e | ||
|
|
dde9c59021 | ||
|
|
a12b323907 | ||
|
|
1687f9bb84 | ||
|
|
9a12a668a2 | ||
|
|
b98268ffee | ||
|
|
4d1ae3d483 | ||
|
|
2f6f110fa3 | ||
|
|
93c25d4f82 | ||
|
|
2ac1095c52 | ||
|
|
d5b868f4a6 | ||
|
|
17081fac46 | ||
|
|
4a18b57021 | ||
|
|
58c4c9ebb8 | ||
|
|
a16234faaa | ||
|
|
154265a2d9 | ||
|
|
440ae897a5 | ||
|
|
86fac0937b | ||
|
|
682102d4d6 | ||
|
|
22774b4821 | ||
|
|
046e73e785 | ||
|
|
a71a823676 | ||
|
|
fc0ed7b96f | ||
|
|
756f63e212 |
@@ -27,6 +27,10 @@ jobs:
|
|||||||
name: Run Tests
|
name: Run Tests
|
||||||
command: npm test
|
command: npm test
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: coverage/
|
||||||
|
destination: coverage
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: rendering/cases/
|
path: rendering/cases/
|
||||||
destination: rendering
|
destination: rendering
|
||||||
@@ -38,3 +42,19 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: build/examples
|
path: build/examples
|
||||||
destination: examples
|
destination: examples
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Build API Docs
|
||||||
|
command: npm run apidoc
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: build/apidoc
|
||||||
|
destination: apidoc
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Build Website
|
||||||
|
command: npm run build-site
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: public
|
||||||
|
destination: website
|
||||||
|
|||||||
2
.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
/coverage/
|
/coverage/
|
||||||
/dist/
|
/dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
/.cache/
|
||||||
|
/public/
|
||||||
|
|||||||
@@ -4,6 +4,28 @@
|
|||||||
|
|
||||||
#### Backwards incompatible changes
|
#### Backwards incompatible changes
|
||||||
|
|
||||||
|
#### Removal of `GEOLOCATION` constant from `ol/has`
|
||||||
|
|
||||||
|
If you were previously using this constant, you can check if `'geolocation'` is define in `navigator` instead.
|
||||||
|
|
||||||
|
```js
|
||||||
|
if ('geolocation' in navigator) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Removal of CSS print rules
|
||||||
|
|
||||||
|
The CSS media print rules were removed from the `ol.css` file. To get the previous behavior, use the following CSS:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@media print {
|
||||||
|
.ol-control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Removal of optional this arguments
|
#### Removal of optional this arguments
|
||||||
|
|
||||||
The optional this (i.e. opt_this) arguments were removed from the following methods.
|
The optional this (i.e. opt_this) arguments were removed from the following methods.
|
||||||
@@ -32,9 +54,9 @@ Previously, this options only constrained the view *center*. This behaviour can
|
|||||||
|
|
||||||
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
|
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
|
||||||
|
|
||||||
##### Zoom is constrained so only one world is visible
|
##### The view is constrained so only one world is visible
|
||||||
|
|
||||||
Previously, maps showed multiple worlds at low zoom levels. Now, the view is restricted to show only one world. To get the previous behavior, configure the `ol/View` with `multiWorld: true`.
|
Previously, maps showed multiple worlds at low zoom levels. In addition, it used to be possible to pan off the north or south edge of the world. Now, the view is restricted to show only one world, and you cannot pan off the edge. To get the previous behavior, configure the `ol/View` with `multiWorld: true`.
|
||||||
|
|
||||||
##### Removal of deprecated methods
|
##### Removal of deprecated methods
|
||||||
|
|
||||||
@@ -98,6 +120,14 @@ If you were previously using `VectorTile` layers with `renderMode: 'vector'`, yo
|
|||||||
|
|
||||||
If you were previously using `Vector` layers with `renderMode: 'image'`, you have to remove this configuration option. Instead, use the new `ol/layer/VectorImage` layer with your `ol/source/Vector`.
|
If you were previously using `Vector` layers with `renderMode: 'image'`, you have to remove this configuration option. Instead, use the new `ol/layer/VectorImage` layer with your `ol/source/Vector`.
|
||||||
|
|
||||||
|
##### New declutter behavior
|
||||||
|
|
||||||
|
If a map has more than one layer with `declutter` set to true, decluttering now considers all `Vector` and `VectorTile` layers, instead of decluttering each layer separately. Only `VectorImage` layers continue to be decluttered separately. The higher the z-index of a layer, the higher the priority of its decluttered items.
|
||||||
|
|
||||||
|
Within a layer, the declutter order has changed. Previously, styles with a lower `zIndex` were prioritized over those with a higher `zIndex`. Now the opposite order is used.
|
||||||
|
|
||||||
|
On vector layers, even if decluttered images or texts have a lower z-Index than polygons or lines, they will now be rendered on top of the polygons or lines. For vector tile layers, this was the case already in previous releases.
|
||||||
|
|
||||||
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
|
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
|
||||||
|
|
||||||
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.
|
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.
|
||||||
|
|||||||
23
config/jsdoc/api-info/conf.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"opts": {
|
||||||
|
"recurse": true,
|
||||||
|
"template": "node_modules/jsdoc-json"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"allowUnknownTags": true
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"includePattern": "\\.js$",
|
||||||
|
"include": [
|
||||||
|
"src/ol"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"jsdoc-plugin-typescript",
|
||||||
|
"config/jsdoc/api-info/plugins/api",
|
||||||
|
"config/jsdoc/api-info/plugins/module"
|
||||||
|
],
|
||||||
|
"typescript": {
|
||||||
|
"moduleRoot": "src"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
config/jsdoc/api-info/plugins/api.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the api annotation.
|
||||||
|
* @param {Object} dictionary The tag dictionary.
|
||||||
|
*/
|
||||||
|
exports.defineTags = dictionary => {
|
||||||
|
|
||||||
|
dictionary.defineTag('api', {
|
||||||
|
onTagged: (doclet, tag) => {
|
||||||
|
doclet.api = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
170
config/jsdoc/api-info/plugins/module.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/**
|
||||||
|
* This plugin adds an `exportMap` property to @module doclets. Each export map
|
||||||
|
* is an object with properties named like the local identifier and values named
|
||||||
|
* like the exported identifier.
|
||||||
|
*
|
||||||
|
* For example, the code below
|
||||||
|
*
|
||||||
|
* export {foo as bar};
|
||||||
|
*
|
||||||
|
* would be a map like `{foo: 'bar'}`.
|
||||||
|
*
|
||||||
|
* In the case of an export declaration with a source, the export identifier is
|
||||||
|
* prefixed by the source. For example, this code
|
||||||
|
*
|
||||||
|
* export {foo as bar} from 'ol/bam';
|
||||||
|
*
|
||||||
|
* would be a map like `{'ol/bam foo': 'bar'}`.
|
||||||
|
*
|
||||||
|
* If a default export is a literal or object expression, the local name will be
|
||||||
|
* an empty string. For example
|
||||||
|
*
|
||||||
|
* export default {foo: 'bar'};
|
||||||
|
*
|
||||||
|
* would be a map like `{'': 'default'}`.
|
||||||
|
*/
|
||||||
|
const assert = require('assert');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lookup of export maps per source filepath.
|
||||||
|
*/
|
||||||
|
const exportMapLookup = {};
|
||||||
|
|
||||||
|
function loc(filepath, node) {
|
||||||
|
return `${filepath}:${node.loc.start.line}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nameFromChildIdentifier(filepath, node) {
|
||||||
|
assert.ok(node.id, `expected identifer in ${loc(filepath, node)}`);
|
||||||
|
assert.strictEqual(node.id.type, 'Identifier', `expected identifer in ${loc(filepath, node)}`);
|
||||||
|
return node.id.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleExportNamedDeclaration(filepath, node) {
|
||||||
|
if (!(filepath in exportMapLookup)) {
|
||||||
|
exportMapLookup[filepath] = {};
|
||||||
|
}
|
||||||
|
const exportMap = exportMapLookup[filepath];
|
||||||
|
|
||||||
|
const declaration = node.declaration;
|
||||||
|
if (declaration) {
|
||||||
|
// `export class Foo{}` or `export function foo() {}`
|
||||||
|
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
|
||||||
|
const name = nameFromChildIdentifier(filepath, declaration);
|
||||||
|
exportMap[name] = name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export const foo = 'bar', bam = 42`
|
||||||
|
if (declaration.type === 'VariableDeclaration') {
|
||||||
|
const declarations = declaration.declarations;
|
||||||
|
assert.ok(declarations.length > 0, `expected variable declarations in ${loc(filepath, declaration)}`);
|
||||||
|
for (const declarator of declarations) {
|
||||||
|
assert.strictEqual(declarator.type, 'VariableDeclarator', `unexpected "${declarator.type}" in ${loc(filepath, declarator)}`);
|
||||||
|
const name = nameFromChildIdentifier(filepath, declarator);
|
||||||
|
exportMap[name] = name;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unexpected named export "${declaration.type}" in ${loc(filepath, declaration)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefix = '';
|
||||||
|
const source = node.source;
|
||||||
|
if (source) {
|
||||||
|
// `export foo from 'bar'`
|
||||||
|
assert.strictEqual(source.type, 'Literal', `unexpected export source "${source.type}" in ${loc(filepath, source)}`);
|
||||||
|
prefix = `${source.value} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
const specifiers = node.specifiers;
|
||||||
|
assert.ok(specifiers.length > 0, `expected export specifiers in ${loc(filepath, node)}`);
|
||||||
|
// `export {foo, bar}` or `export {default as Foo} from 'bar'`
|
||||||
|
for (const specifier of specifiers) {
|
||||||
|
assert.strictEqual(specifier.type, 'ExportSpecifier', `unexpected export specifier in ${loc(filepath, specifier)}`);
|
||||||
|
|
||||||
|
const local = specifier.local;
|
||||||
|
assert.strictEqual(local.type, 'Identifier', `unexpected local specifier "${local.type} in ${loc(filepath, local)}`);
|
||||||
|
|
||||||
|
const exported = specifier.exported;
|
||||||
|
assert.strictEqual(local.type, 'Identifier', `unexpected exported specifier "${exported.type} in ${loc(filepath, exported)}`);
|
||||||
|
|
||||||
|
exportMap[prefix + local.name] = exported.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDefaultDeclaration(filepath, node) {
|
||||||
|
if (!(filepath in exportMapLookup)) {
|
||||||
|
exportMapLookup[filepath] = {};
|
||||||
|
}
|
||||||
|
const exportMap = exportMapLookup[filepath];
|
||||||
|
|
||||||
|
const declaration = node.declaration;
|
||||||
|
if (declaration) {
|
||||||
|
// `export default class Foo{}` or `export default function foo () {}`
|
||||||
|
if (declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') {
|
||||||
|
const name = nameFromChildIdentifier(filepath, declaration);
|
||||||
|
exportMap[name] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export default foo`
|
||||||
|
if (declaration.type === 'Identifier') {
|
||||||
|
exportMap[declaration.name] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `export default {foo: 'bar'}` or `export default 42`
|
||||||
|
if (declaration.type === 'ObjectExpression' || declaration.type === 'Literal') {
|
||||||
|
exportMap[''] = 'default';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unexpected default export "${declaration.type}" in ${loc(filepath, declaration)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.astNodeVisitor = {
|
||||||
|
visitNode: (node, event, parser, filepath) => {
|
||||||
|
if (node.type === 'ExportNamedDeclaration') {
|
||||||
|
return handleExportNamedDeclaration(filepath, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type === 'ExportDefaultDeclaration') {
|
||||||
|
return handleDefaultDeclaration(filepath, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const moduleLookup = {};
|
||||||
|
|
||||||
|
exports.handlers = {
|
||||||
|
|
||||||
|
// create a lookup of @module doclets
|
||||||
|
newDoclet: event => {
|
||||||
|
const doclet = event.doclet;
|
||||||
|
if (doclet.kind === 'module') {
|
||||||
|
const filepath = path.join(doclet.meta.path, doclet.meta.filename);
|
||||||
|
|
||||||
|
assert.ok(!(filepath in moduleLookup), `duplicate @module doc in ${filepath}`);
|
||||||
|
moduleLookup[filepath] = doclet;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// assign the `exportMap` property to @module doclets
|
||||||
|
parseComplete: event => {
|
||||||
|
for (const filepath in moduleLookup) {
|
||||||
|
assert.ok(filepath in exportMapLookup, `missing ${filepath} in export map lookup`);
|
||||||
|
moduleLookup[filepath].exportMap = exportMapLookup[filepath];
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure there was a @module doclet for each export map
|
||||||
|
for (const filepath in exportMapLookup) {
|
||||||
|
assert.ok(filepath in moduleLookup, `missing @module doclet in ${filepath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
@@ -1,43 +1,43 @@
|
|||||||
<table><tr>
|
<table><tr>
|
||||||
<th width="33.3%">Map</th><th width="33.3%">View</th><th width="33.3%">Layers</th>
|
<th width="33.3%">Map</th><th width="33.3%">View</th><th width="33.3%">Layers</th>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><p>A [map](module-ol_Map-Map.html) is made of [layers](module-ol_layer_Base-BaseLayer.html), a [view](module-ol_View-View.html) to visualize them, [interactions](module-ol_interaction_Interaction-Interaction.html) to modify map content and [controls](module-ol_control_Control-Control.html) with UI components.</p>
|
<td><p>A <a href="module-ol_Map-Map.html">map</a> is made of <a href="module-ol_layer_Base-BaseLayer.html">layers</a>, a <a href="module-ol_View-View.html">view</a> to visualize them, <a href="module-ol_interaction_Interaction-Interaction.html">interactions</a> to modify map content and <a href="module-ol_control_Control-Control.html">controls</a> with UI components.</p>
|
||||||
[Overview](module-ol_Map-Map.html)<br>
|
<a href="module-ol_Map-Map.html">Overview</a><br>
|
||||||
[Creation](module-ol_Map-Map.html#Map)<br>
|
<a href="module-ol_Map-Map.html#Map">Creation</a><br>
|
||||||
[Events](module-ol_MapBrowserEvent-MapBrowserEvent.html)</td>
|
<a href="module-ol_MapBrowserEvent-MapBrowserEvent.html">Events</a></td>
|
||||||
<td><p>The view manages the visual parameters of the map view, like resolution or rotation.</p>
|
<td><p>The view manages the visual parameters of the map view, like resolution or rotation.</p>
|
||||||
[View](module-ol_View-View.html) with center, projection, resolution and rotation</td>
|
<a href="module-ol_View-View.html">View</a> with center, projection, resolution and rotation</td>
|
||||||
<td><p>Layers are lightweight containers that get their data from [sources](module-ol_source_Source-Source.html).</p>
|
<td><p>Layers are lightweight containers that get their data from <a href="module-ol_source_Source-Source.html">sources</a>.</p>
|
||||||
[ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)<br>
|
<a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a><br>
|
||||||
[ol/layer/Image](module-ol_layer_Image-ImageLayer.html)<br>
|
<a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a><br>
|
||||||
[ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)<br>
|
<a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a><br>
|
||||||
[ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)</td>
|
<a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a></td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Controls</th><th>Interactions</th><th>Sources and formats</th>
|
<th>Controls</th><th>Interactions</th><th>Sources and formats</th>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>[Map default controls](module-ol_control_util.html#.defaults)<br>
|
<td><a href="module-ol_control_util.html#.defaults">Map default controls</a><br>
|
||||||
[All controls](module-ol_control_Control-Control.html)
|
<a href="module-ol_control_Control-Control.html">All controls</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
[Map default interactions](module-ol_interaction.html#~defaults)<br>
|
<a href="module-ol_interaction.html#~defaults">Map default interactions</a><br>
|
||||||
Interactions for [vector features](module-ol_Feature-Feature.html)
|
Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
|
||||||
<ul><li>[ol/interaction/Select](module-ol_interaction_Select-Select.html)</li>
|
<ul><li><a href="module-ol_interaction_Select-Select.html">ol/interaction/Select</a></li>
|
||||||
<li>[ol/interaction/Draw](module-ol_interaction_Draw-Draw.html)</li>
|
<li><a href="module-ol_interaction_Draw-Draw.html">ol/interaction/Draw</a></li>
|
||||||
<li>[ol/interaction/Modify](module-ol_interaction_Modify-Modify.html)</li></ul>
|
<li><a href="module-ol_interaction_Modify-Modify.html">ol/interaction/Modify</a></li></ul>
|
||||||
[All interactions](module-ol_interaction_Interaction-Interaction.html)</td>
|
<a href="module-ol_interaction_Interaction-Interaction.html">All interactions</a></td>
|
||||||
<td>[Tile sources](module-ol_source_Tile-TileSource.html) for [ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)
|
<td><a href="module-ol_source_Tile-TileSource.html">Tile sources</a> for <a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a>
|
||||||
<br>[Image sources](module-ol_source_Image-ImageSource.html) for [ol/layer/Image](module-ol_layer_Image-ImageLayer.html)
|
<br><a href="module-ol_source_Image-ImageSource.html">Image sources</a> for <a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a>
|
||||||
<br>[Vector sources](module-ol_source_Vector-VectorSource.html) for [ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)
|
<br><a href="module-ol_source_Vector-VectorSource.html">Vector sources</a> for <a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a>
|
||||||
<br>[Vector tile sources](module-ol_source_VectorTile-VectorTile.html) for [ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)
|
<br><a href="module-ol_source_VectorTile-VectorTile.html">Vector tile sources</a> for <a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a>
|
||||||
<br>[Formats](module-ol_format_Feature-FeatureFormat.html) for reading/writing vector data
|
<br><a href="module-ol_format_Feature-FeatureFormat.html">Formats</a> for reading/writing vector data
|
||||||
<br>[ol/format/WMSCapabilities](module-ol_format_WMSCapabilities-WMSCapabilities.html)</td></tr>
|
<br><a href="module-ol_format_WMSCapabilities-WMSCapabilities.html">ol/format/WMSCapabilities</a></td></tr>
|
||||||
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
|
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
|
||||||
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use [ol/proj#transform()](module-ol_proj.html#.transform) and [ol/proj#transformExtent()](module-ol_proj.html#.transformExtent).</p>
|
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
|
||||||
[ol/proj](module-ol_proj.html)</td>
|
<a href="module-ol_proj.html">ol/proj</a></td>
|
||||||
<td><p>Changes to all [ol/Object](module-ol_Object-BaseObject.html)s can be observed by calling the [object.on('propertychange')](module-ol_Object-BaseObject.html#on) method. Listeners receive an [ol/Object.ObjectEvent](module-ol_Object-ObjectEvent.html) with information on the changed property and old value.</p>
|
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||||
<td>
|
<td>
|
||||||
[ol/Geolocation](module-ol_Geolocation.html)<br>
|
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
|
||||||
[ol/Overlay](module-ol_Overlay-Overlay.html)<br></td>
|
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,29 @@
|
|||||||
const events = {};
|
const events = {};
|
||||||
const classes = {};
|
|
||||||
|
|
||||||
exports.handlers = {
|
exports.handlers = {
|
||||||
|
|
||||||
newDoclet: function(e) {
|
newDoclet: function(e) {
|
||||||
const doclet = e.doclet;
|
const doclet = e.doclet;
|
||||||
let cls;
|
if (doclet.kind !== 'event') {
|
||||||
if (doclet.kind == 'event') {
|
return;
|
||||||
cls = doclet.longname.split('#')[0];
|
}
|
||||||
|
|
||||||
|
const cls = doclet.longname.split('#')[0];
|
||||||
if (!(cls in events)) {
|
if (!(cls in events)) {
|
||||||
events[cls] = [];
|
events[cls] = [];
|
||||||
}
|
}
|
||||||
events[cls].push(doclet.longname);
|
events[cls].push(doclet.longname);
|
||||||
} else if (doclet.kind == 'class' && !(doclet.longname in classes)) {
|
|
||||||
classes[doclet.longname] = doclet;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
parseComplete: function(e) {
|
parseComplete: function(e) {
|
||||||
const doclets = e.doclets;
|
const doclets = e.doclets;
|
||||||
let doclet, i, ii, j, jj, event, fires;
|
for (let i = 0, ii = doclets.length - 1; i < ii; ++i) {
|
||||||
for (i = 0, ii = doclets.length - 1; i < ii; ++i) {
|
const doclet = doclets[i];
|
||||||
doclet = doclets[i];
|
|
||||||
if (doclet.fires) {
|
if (doclet.fires) {
|
||||||
if (doclet.kind == 'class') {
|
if (doclet.kind == 'class') {
|
||||||
fires = [];
|
const fires = [];
|
||||||
for (j = 0, jj = doclet.fires.length; j < jj; ++j) {
|
for (let j = 0, jj = doclet.fires.length; j < jj; ++j) {
|
||||||
event = doclet.fires[j].replace('event:', '');
|
const event = doclet.fires[j].replace('event:', '');
|
||||||
if (events[event]) {
|
if (events[event]) {
|
||||||
fires.push.apply(fires, events[event]);
|
fires.push.apply(fires, events[event]);
|
||||||
} else if (doclet.fires[j] !== 'event:ObjectEvent') {
|
} else if (doclet.fires[j] !== 'event:ObjectEvent') {
|
||||||
|
|||||||
@@ -220,3 +220,11 @@ Duplicate item added to a unique collection. For example, it may be that you tr
|
|||||||
### 59
|
### 59
|
||||||
|
|
||||||
Invalid command found in the PBF. This indicates that the loaded vector tile may be corrupt.
|
Invalid command found in the PBF. This indicates that the loaded vector tile may be corrupt.
|
||||||
|
|
||||||
|
### 60
|
||||||
|
|
||||||
|
Missing or invalid `size`.
|
||||||
|
|
||||||
|
### 61
|
||||||
|
|
||||||
|
Cannot determine IIIF Image API version from provided image information JSON.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
"common": false,
|
"common": false,
|
||||||
"createMapboxStreetsV6Style": false,
|
"createMapboxStreetsV6Style": false,
|
||||||
"d3": false,
|
"d3": false,
|
||||||
"domtoimage": false,
|
|
||||||
"geojsonvt": false,
|
"geojsonvt": false,
|
||||||
"GyroNorm": false,
|
"GyroNorm": false,
|
||||||
"jsPDF": false,
|
"jsPDF": false,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ docs: >
|
|||||||
The example loads TopoJSON geometries and uses d3 (<code>d3.geo.path</code>) to render these geometries to a SVG element.
|
The example loads TopoJSON geometries and uses d3 (<code>d3.geo.path</code>) to render these geometries to a SVG element.
|
||||||
tags: "d3"
|
tags: "d3"
|
||||||
resources:
|
resources:
|
||||||
- https://unpkg.com/d3@4.12.0/build/d3.js
|
- https://unpkg.com/d3@5.9.2/dist/d3.js
|
||||||
- https://unpkg.com/topojson@3.0.2/dist/topojson.js
|
- https://unpkg.com/topojson@3.0.2/dist/topojson.js
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
2
examples/d3.js
vendored
@@ -85,7 +85,7 @@ const map = new Map({
|
|||||||
/**
|
/**
|
||||||
* Load the topojson data and create an ol/layer/Image for that data.
|
* Load the topojson data and create an ol/layer/Image for that data.
|
||||||
*/
|
*/
|
||||||
d3.json('data/topojson/us.json', function(error, us) {
|
d3.json('data/topojson/us.json').then(function(us) {
|
||||||
|
|
||||||
const layer = new CanvasLayer({
|
const layer = new CanvasLayer({
|
||||||
features: topojson.feature(us, us.objects.counties)
|
features: topojson.feature(us, us.objects.counties)
|
||||||
|
|||||||
7
examples/data/square.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
|
||||||
|
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g>
|
||||||
|
<rect width="20" height="20" style="fill:#fff" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 194 B |
@@ -40,6 +40,6 @@ gn.init().then(function() {
|
|||||||
center[0] -= resolution * gamma * 25;
|
center[0] -= resolution * gamma * 25;
|
||||||
center[1] += resolution * beta * 25;
|
center[1] += resolution * beta * 25;
|
||||||
|
|
||||||
view.setCenter(view.constrainCenter(center));
|
view.setCenter(center);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
6
examples/export-map.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.overlay {
|
||||||
|
background-color: yellow;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
@@ -3,12 +3,13 @@ layout: example.html
|
|||||||
title: Map Export
|
title: Map Export
|
||||||
shortdesc: Example of exporting a map as a PNG image.
|
shortdesc: Example of exporting a map as a PNG image.
|
||||||
docs: >
|
docs: >
|
||||||
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/dom-to-image-more">dom-to-image-more</a>
|
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/html-to-image">html-to-image</a>
|
||||||
library.
|
library.
|
||||||
tags: "export, png, openstreetmap"
|
tags: "export, png, openstreetmap"
|
||||||
resources:
|
|
||||||
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
|
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
<div style="display: none;">
|
||||||
|
<div class="overlay" id="null">Null Island</div>
|
||||||
|
</div>
|
||||||
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
|
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
|
||||||
<a id="image-download" download="map.png"></a>
|
<a id="image-download" download="map.png"></a>
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import Map from '../src/ol/Map.js';
|
import Map from '../src/ol/Map.js';
|
||||||
import View from '../src/ol/View.js';
|
import View from '../src/ol/View.js';
|
||||||
|
import Overlay from '../src/ol/Overlay.js';
|
||||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||||
|
|
||||||
|
import {toPng} from 'html-to-image';
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
@@ -23,9 +26,23 @@ const map = new Map({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
map.addOverlay(new Overlay({
|
||||||
|
position: [0, 0],
|
||||||
|
element: document.getElementById('null')
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
// export options for html-to-image.
|
||||||
|
// See: https://github.com/bubkoo/html-to-image#options
|
||||||
|
const exportOptions = {
|
||||||
|
filter: function(element) {
|
||||||
|
return element.className ? element.className.indexOf('ol-control') === -1 : true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
document.getElementById('export-png').addEventListener('click', function() {
|
document.getElementById('export-png').addEventListener('click', function() {
|
||||||
map.once('rendercomplete', function() {
|
map.once('rendercomplete', function() {
|
||||||
domtoimage.toPng(map.getViewport().querySelector('.ol-layers'))
|
toPng(map.getTargetElement(), exportOptions)
|
||||||
.then(function(dataURL) {
|
.then(function(dataURL) {
|
||||||
const link = document.getElementById('image-download');
|
const link = document.getElementById('image-download');
|
||||||
link.href = dataURL;
|
link.href = dataURL;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ docs: >
|
|||||||
tags: "export, pdf, openstreetmap"
|
tags: "export, pdf, openstreetmap"
|
||||||
resources:
|
resources:
|
||||||
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
|
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
|
||||||
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
|
|
||||||
---
|
---
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import WKT from '../src/ol/format/WKT.js';
|
|||||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||||
|
|
||||||
|
import {toJpeg} from 'html-to-image';
|
||||||
|
|
||||||
const raster = new TileLayer({
|
const raster = new TileLayer({
|
||||||
source: new OSM()
|
source: new OSM()
|
||||||
});
|
});
|
||||||
@@ -41,6 +43,15 @@ const dims = {
|
|||||||
a5: [210, 148]
|
a5: [210, 148]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// export options for html-to-image.
|
||||||
|
// See: https://github.com/bubkoo/html-to-image#options
|
||||||
|
const exportOptions = {
|
||||||
|
filter: function(element) {
|
||||||
|
return element.className.indexOf('ol-control') === -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const exportButton = document.getElementById('export-pdf');
|
const exportButton = document.getElementById('export-pdf');
|
||||||
|
|
||||||
exportButton.addEventListener('click', function() {
|
exportButton.addEventListener('click', function() {
|
||||||
@@ -57,15 +68,14 @@ exportButton.addEventListener('click', function() {
|
|||||||
const extent = map.getView().calculateExtent(size);
|
const extent = map.getView().calculateExtent(size);
|
||||||
|
|
||||||
map.once('rendercomplete', function() {
|
map.once('rendercomplete', function() {
|
||||||
domtoimage.toJpeg(map.getViewport().querySelector('.ol-layers')).then(function(dataUrl) {
|
toJpeg(map.getTargetElement(), exportOptions).then(function(dataUrl) {
|
||||||
const pdf = new jsPDF('landscape', undefined, format);
|
const pdf = new jsPDF('landscape', undefined, format);
|
||||||
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
|
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
|
||||||
pdf.save('map.pdf');
|
pdf.save('map.pdf');
|
||||||
// Reset original map size
|
// Reset original map size
|
||||||
map.setSize(size);
|
map.setSize(size);
|
||||||
map.getView().fit(extent, {
|
map.getView().fit(extent, {
|
||||||
size: size,
|
size: size
|
||||||
constrainResolution: false
|
|
||||||
});
|
});
|
||||||
exportButton.disabled = false;
|
exportButton.disabled = false;
|
||||||
document.body.style.cursor = 'auto';
|
document.body.style.cursor = 'auto';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
|
|||||||
import View from '../src/ol/View.js';
|
import View from '../src/ol/View.js';
|
||||||
import TileLayer from '../src/ol/layer/Tile.js';
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
import OSM from '../src/ol/source/OSM.js';
|
import OSM from '../src/ol/source/OSM.js';
|
||||||
import {defaults as defaultControls} from '../src/ol/control/util';
|
import {defaults as defaultControls} from '../src/ol/control.js';
|
||||||
import ZoomSlider from '../src/ol/control/ZoomSlider';
|
import ZoomSlider from '../src/ol/control/ZoomSlider';
|
||||||
|
|
||||||
const view = new View({
|
const view = new View({
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Map from '../src/ol/Map.js';
|
import Map from '../src/ol/Map.js';
|
||||||
import View from '../src/ol/View.js';
|
import View from '../src/ol/View.js';
|
||||||
import {platformModifierKeyOnly} from '../src/ol/events/condition.js';
|
|
||||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||||
import ExtentInteraction from '../src/ol/interaction/Extent.js';
|
import ExtentInteraction from '../src/ol/interaction/Extent.js';
|
||||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
@@ -27,9 +26,7 @@ const map = new Map({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const extent = new ExtentInteraction({
|
const extent = new ExtentInteraction();
|
||||||
condition: platformModifierKeyOnly
|
|
||||||
});
|
|
||||||
map.addInteraction(extent);
|
map.addInteraction(extent);
|
||||||
extent.setActive(false);
|
extent.setActive(false);
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
|||||||
import {clamp, lerp} from '../src/ol/math';
|
import {clamp, lerp} from '../src/ol/math';
|
||||||
import Stamen from '../src/ol/source/Stamen';
|
import Stamen from '../src/ol/source/Stamen';
|
||||||
|
|
||||||
const features = [];
|
|
||||||
const vectorSource = new Vector({
|
const vectorSource = new Vector({
|
||||||
features: [],
|
|
||||||
attributions: 'NASA'
|
attributions: 'NASA'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -38,15 +36,16 @@ updateStatusText();
|
|||||||
class WebglPointsLayer extends VectorLayer {
|
class WebglPointsLayer extends VectorLayer {
|
||||||
createRenderer() {
|
createRenderer() {
|
||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
colorCallback: function(feature, vertex, component) {
|
colorCallback: function(feature, color) {
|
||||||
// component at index 3 is alpha
|
|
||||||
if (component === 3) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// color is interpolated based on year
|
// color is interpolated based on year
|
||||||
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
|
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
|
||||||
return lerp(oldColor[component], newColor[component], ratio) / 255;
|
|
||||||
|
color[0] = lerp(oldColor[0], newColor[0], ratio) / 255;
|
||||||
|
color[1] = lerp(oldColor[1], newColor[1], ratio) / 255;
|
||||||
|
color[2] = lerp(oldColor[2], newColor[2], ratio) / 255;
|
||||||
|
color[3] = 1;
|
||||||
|
|
||||||
|
return color;
|
||||||
},
|
},
|
||||||
sizeCallback: function(feature) {
|
sizeCallback: function(feature) {
|
||||||
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
||||||
@@ -109,26 +108,28 @@ function loadData() {
|
|||||||
client.open('GET', 'data/csv/meteorite_landings.csv');
|
client.open('GET', 'data/csv/meteorite_landings.csv');
|
||||||
client.onload = function() {
|
client.onload = function() {
|
||||||
const csv = client.responseText;
|
const csv = client.responseText;
|
||||||
|
const features = [];
|
||||||
|
|
||||||
|
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||||
|
|
||||||
let curIndex;
|
let curIndex;
|
||||||
let prevIndex = 0;
|
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||||
let line;
|
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||||
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
|
|
||||||
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
|
||||||
prevIndex = curIndex + 1;
|
prevIndex = curIndex + 1;
|
||||||
|
|
||||||
// skip header
|
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||||
if (prevIndex === 0) {
|
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||||
|
// guard against bad data
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
|
||||||
|
|
||||||
features.push(new Feature({
|
features.push(new Feature({
|
||||||
mass: parseFloat(line[1]) || 0,
|
mass: parseFloat(line[1]) || 0,
|
||||||
year: parseInt(line[2]) || 0,
|
year: parseInt(line[2]) || 0,
|
||||||
geometry: new Point(coords)
|
geometry: new Point(coords)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
vectorSource.addFeatures(features);
|
vectorSource.addFeatures(features);
|
||||||
};
|
};
|
||||||
client.send();
|
client.send();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.map:-webkit-full-screen {
|
.map:-webkit-full-screen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.map:-ms-fullscreen {
|
.map:-ms-fullscreen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.fullscreen:-webkit-full-screen {
|
.fullscreen:-webkit-full-screen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.fullscreen:-ms-fullscreen {
|
.fullscreen:-ms-fullscreen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.map:-webkit-full-screen {
|
.map:-webkit-full-screen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.map:-ms-fullscreen {
|
.map:-ms-fullscreen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ title: Earthquakes Heatmap
|
|||||||
shortdesc: Demonstrates the use of a heatmap layer.
|
shortdesc: Demonstrates the use of a heatmap layer.
|
||||||
docs: >
|
docs: >
|
||||||
This example parses a KML file and renders the features as a <code>ol/layer/Heatmap</code> layer.
|
This example parses a KML file and renders the features as a <code>ol/layer/Heatmap</code> layer.
|
||||||
tags: "heatmap, kml, vector, style"
|
tags: "heatmap, kml, vector, style, webgl"
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
<form>
|
<form>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ rome.setStyle(new Style({
|
|||||||
image: new Icon({
|
image: new Icon({
|
||||||
color: '#8959A8',
|
color: '#8959A8',
|
||||||
crossOrigin: 'anonymous',
|
crossOrigin: 'anonymous',
|
||||||
src: 'data/dot.png'
|
src: 'data/square.svg'
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {fromLonLat} from '../src/ol/proj';
|
|||||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||||
import {lerp} from '../src/ol/math';
|
import {lerp} from '../src/ol/math';
|
||||||
|
|
||||||
const features = [];
|
|
||||||
const vectorSource = new Vector({
|
const vectorSource = new Vector({
|
||||||
features: [],
|
features: [],
|
||||||
attributions: 'National UFO Reporting Center'
|
attributions: 'National UFO Reporting Center'
|
||||||
@@ -39,16 +38,17 @@ class WebglPointsLayer extends VectorLayer {
|
|||||||
createRenderer() {
|
createRenderer() {
|
||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
texture: texture,
|
texture: texture,
|
||||||
colorCallback: function(feature, vertex, component) {
|
colorCallback: function(feature, color) {
|
||||||
// component at index 3 is alpha
|
|
||||||
if (component === 3) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// color is interpolated based on year (min is 1910, max is 2013)
|
// color is interpolated based on year (min is 1910, max is 2013)
|
||||||
// please note: most values are between 2000-2013
|
// please note: most values are between 2000-2013
|
||||||
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
|
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
|
||||||
return lerp(oldColor[component], newColor[component], ratio * ratio) / 255;
|
|
||||||
|
color[0] = lerp(oldColor[0], newColor[0], ratio * ratio) / 255;
|
||||||
|
color[1] = lerp(oldColor[1], newColor[1], ratio * ratio) / 255;
|
||||||
|
color[2] = lerp(oldColor[2], newColor[2], ratio * ratio) / 255;
|
||||||
|
color[3] = 1;
|
||||||
|
|
||||||
|
return color;
|
||||||
},
|
},
|
||||||
texCoordCallback: function(feature, component) {
|
texCoordCallback: function(feature, component) {
|
||||||
let coords = shapeTextureCoords[feature.get('shape')];
|
let coords = shapeTextureCoords[feature.get('shape')];
|
||||||
@@ -70,17 +70,14 @@ function loadData() {
|
|||||||
client.open('GET', 'data/csv/ufo_sighting_data.csv');
|
client.open('GET', 'data/csv/ufo_sighting_data.csv');
|
||||||
client.onload = function() {
|
client.onload = function() {
|
||||||
const csv = client.responseText;
|
const csv = client.responseText;
|
||||||
let curIndex;
|
const features = [];
|
||||||
let prevIndex = 0;
|
|
||||||
let line;
|
|
||||||
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
|
|
||||||
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
|
||||||
prevIndex = curIndex + 1;
|
|
||||||
|
|
||||||
// skip header
|
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||||
if (prevIndex === 0) {
|
|
||||||
continue;
|
let curIndex;
|
||||||
}
|
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||||
|
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||||
|
prevIndex = curIndex + 1;
|
||||||
|
|
||||||
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
|
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
|
||||||
|
|
||||||
|
|||||||
16
examples/iiif.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: IIIF Image API
|
||||||
|
shortdesc: Example of a IIIF Image API source.
|
||||||
|
docs: >
|
||||||
|
Example of a tile source for an International Image Interoperability Framework (IIIF) Image Service.
|
||||||
|
Try any Image API version 1 or 2 service.
|
||||||
|
tags: "IIIF, IIIF Image API, tile source"
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
|
<div class="controls">
|
||||||
|
<div id="iiif-notification"> </div>
|
||||||
|
Enter <code>info.json</code> URL:
|
||||||
|
<input type="text" id="imageInfoUrl" value="https://iiif.ub.uni-leipzig.de/iiif/j2k/0000/0107/0000010732/00000072.jpx/info.json">
|
||||||
|
<button id="display">Display image</button>
|
||||||
|
</div>
|
||||||
46
examples/iiif.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
|
import IIIF from '../src/ol/source/IIIF.js';
|
||||||
|
import IIIFInfo from '../src/ol/format/IIIFInfo.js';
|
||||||
|
|
||||||
|
const layer = new TileLayer(),
|
||||||
|
map = new Map({
|
||||||
|
layers: [layer],
|
||||||
|
target: 'map'
|
||||||
|
}),
|
||||||
|
notifyDiv = document.getElementById('iiif-notification'),
|
||||||
|
urlInput = document.getElementById('imageInfoUrl'),
|
||||||
|
displayButton = document.getElementById('display');
|
||||||
|
|
||||||
|
function refreshMap(imageInfoUrl) {
|
||||||
|
fetch(imageInfoUrl).then(function(response) {
|
||||||
|
response.json().then(function(imageInfo) {
|
||||||
|
const options = new IIIFInfo(imageInfo).getTileSourceOptions();
|
||||||
|
if (options === undefined || options.version === undefined) {
|
||||||
|
notifyDiv.textContent = 'Data seems to be no valid IIIF image information.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
options.zDirection = -1;
|
||||||
|
const iiifTileSource = new IIIF(options);
|
||||||
|
layer.setSource(iiifTileSource);
|
||||||
|
map.setView(new View({
|
||||||
|
resolutions: iiifTileSource.getTileGrid().getResolutions(),
|
||||||
|
extent: iiifTileSource.getTileGrid().getExtent(),
|
||||||
|
constrainOnlyCenter: true
|
||||||
|
}));
|
||||||
|
map.getView().fit(iiifTileSource.getTileGrid().getExtent());
|
||||||
|
notifyDiv.textContent = '';
|
||||||
|
}).catch(function(body) {
|
||||||
|
notifyDiv.textContent = 'Could not read image info json. ' + body;
|
||||||
|
});
|
||||||
|
}).catch(function() {
|
||||||
|
notifyDiv.textContent = 'Could not read data from URL.';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
displayButton.addEventListener('click', function() {
|
||||||
|
refreshMap(urlInput.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshMap(urlInput.value);
|
||||||
@@ -11,9 +11,25 @@
|
|||||||
body {
|
body {
|
||||||
padding-top: 70px;
|
padding-top: 70px;
|
||||||
}
|
}
|
||||||
|
img.header-logo {
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
input.search-query {
|
input.search-query {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
input.search-query {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
#count {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 374px) {
|
||||||
|
input.search-query {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.example {
|
.example {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -182,9 +198,9 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<header class="navbar navbar-fixed-top" role="navigation">
|
<header class="navbar navbar-fixed-top" role="navigation">
|
||||||
<div class="container">
|
<div class="container-fluid">
|
||||||
<div class="display-table pull-left">
|
<div class="display-table pull-left">
|
||||||
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers Examples</a>
|
<a class="navbar-brand" href="./"><img class="header-logo" src="./resources/logo-70x70.png"> OpenLayers</a>
|
||||||
<form class="navbar-form" role="search">
|
<form class="navbar-form" role="search">
|
||||||
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search" autofocus>
|
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search" autofocus>
|
||||||
<span id="count"></span>
|
<span id="count"></span>
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ docs: >
|
|||||||
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
|
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
|
||||||
tags: "simple, mapbox, vector, tiles"
|
tags: "simple, mapbox, vector, tiles"
|
||||||
resources:
|
resources:
|
||||||
- https://unpkg.com/mapbox-gl@0.51.0/dist/mapbox-gl.js
|
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js
|
||||||
|
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css
|
||||||
cloak:
|
cloak:
|
||||||
- key: ER67WIiPdCQvhgsUjoWK
|
- key: ER67WIiPdCQvhgsUjoWK
|
||||||
value: Your Mapbox access token from http://mapbox.com/ here
|
value: Your Mapbox access token from https://mapbox.com/ here
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -1,50 +1,21 @@
|
|||||||
import Map from '../src/ol/Map.js';
|
import Map from '../src/ol/Map.js';
|
||||||
import View from '../src/ol/View.js';
|
import View from '../src/ol/View.js';
|
||||||
import Layer from '../src/ol/layer/Layer';
|
import Layer from '../src/ol/layer/Layer';
|
||||||
import {assign} from '../src/ol/obj';
|
import {toLonLat, fromLonLat} from '../src/ol/proj';
|
||||||
import {getTransform} from '../src/ol/proj';
|
|
||||||
import SourceState from '../src/ol/source/State';
|
|
||||||
import {Stroke, Style} from '../src/ol/style.js';
|
import {Stroke, Style} from '../src/ol/style.js';
|
||||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||||
import VectorSource from '../src/ol/source/Vector.js';
|
import VectorSource from '../src/ol/source/Vector.js';
|
||||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||||
|
|
||||||
class Mapbox extends Layer {
|
const center = [-98.8, 37.9];
|
||||||
|
const key = 'ER67WIiPdCQvhgsUjoWK';
|
||||||
|
|
||||||
/**
|
const mbMap = new mapboxgl.Map({
|
||||||
* @param {import('./Base.js').Options} options Layer options.
|
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key,
|
||||||
*/
|
|
||||||
constructor(options) {
|
|
||||||
const baseOptions = assign({}, options);
|
|
||||||
super(baseOptions);
|
|
||||||
|
|
||||||
this.baseOptions = baseOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type boolean
|
|
||||||
*/
|
|
||||||
this.loaded = false;
|
|
||||||
|
|
||||||
this.initMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
initMap() {
|
|
||||||
const map = this.map_;
|
|
||||||
const view = map.getView();
|
|
||||||
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
|
|
||||||
const center = transformToLatLng(view.getCenter());
|
|
||||||
|
|
||||||
this.centerLastRender = view.getCenter();
|
|
||||||
this.zoomLastRender = view.getZoom();
|
|
||||||
this.centerLastRender = view.getCenter();
|
|
||||||
this.zoomLastRender = view.getZoom();
|
|
||||||
|
|
||||||
const options = assign(this.baseOptions, {
|
|
||||||
attributionControl: false,
|
attributionControl: false,
|
||||||
boxZoom: false,
|
boxZoom: false,
|
||||||
center,
|
center: center,
|
||||||
container: map.getTargetElement(),
|
container: 'map',
|
||||||
doubleClickZoom: false,
|
doubleClickZoom: false,
|
||||||
dragPan: false,
|
dragPan: false,
|
||||||
dragRotate: false,
|
dragRotate: false,
|
||||||
@@ -52,137 +23,45 @@ class Mapbox extends Layer {
|
|||||||
keyboard: false,
|
keyboard: false,
|
||||||
pitchWithRotate: false,
|
pitchWithRotate: false,
|
||||||
scrollZoom: false,
|
scrollZoom: false,
|
||||||
touchZoomRotate: false,
|
touchZoomRotate: false
|
||||||
zoom: view.getZoom() - 1
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mbmap = new mapboxgl.Map(options);
|
const mbLayer = new Layer({
|
||||||
this.mbmap.on('load', function() {
|
render: function(frameState) {
|
||||||
this.mbmap.getCanvas().remove();
|
const canvas = mbMap.getCanvas();
|
||||||
this.loaded = true;
|
const viewState = frameState.viewState;
|
||||||
this.map_.render();
|
|
||||||
[
|
|
||||||
'mapboxgl-control-container'
|
|
||||||
].forEach(className => document.getElementsByClassName(className)[0].remove());
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
this.mbmap.on('render', function() {
|
const visible = mbLayer.getVisible();
|
||||||
// Reset offset
|
canvas.style.display = visible ? 'block' : 'none';
|
||||||
if (this.centerNextRender) {
|
|
||||||
this.centerLastRender = this.centerNextRender;
|
|
||||||
}
|
|
||||||
if (this.zoomNextRender) {
|
|
||||||
this.zoomLastRender = this.zoomNextRender;
|
|
||||||
}
|
|
||||||
this.updateRenderedPosition([0, 0], 1);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
}
|
const opacity = mbLayer.getOpacity();
|
||||||
|
canvas.style.opacity = opacity;
|
||||||
|
|
||||||
/**
|
// adjust view parameters in mapbox
|
||||||
*
|
const rotation = viewState.rotation;
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
render(frameState) {
|
|
||||||
const map = this.map_;
|
|
||||||
const view = map.getView();
|
|
||||||
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
|
|
||||||
|
|
||||||
this.centerNextRender = view.getCenter();
|
|
||||||
const lastRender = map.getPixelFromCoordinate(this.centerLastRender);
|
|
||||||
const nextRender = map.getPixelFromCoordinate(this.centerNextRender);
|
|
||||||
const centerOffset = [lastRender[0] - nextRender[0], lastRender[1] - nextRender[1]];
|
|
||||||
this.zoomNextRender = view.getZoom();
|
|
||||||
const zoomOffset = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
|
|
||||||
this.updateRenderedPosition(centerOffset, zoomOffset);
|
|
||||||
|
|
||||||
const rotation = frameState.viewState.rotation;
|
|
||||||
if (rotation) {
|
if (rotation) {
|
||||||
this.mbmap.rotateTo(-rotation * 180 / Math.PI, {
|
mbMap.rotateTo(-rotation * 180 / Math.PI, {
|
||||||
animate: false
|
animate: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
mbMap.jumpTo({
|
||||||
// Re-render mbmap
|
center: toLonLat(viewState.center),
|
||||||
const center = transformToLatLng(this.centerNextRender);
|
zoom: viewState.zoom - 1,
|
||||||
const zoom = view.getZoom() - 1;
|
animate: false
|
||||||
this.mbmap.jumpTo({
|
|
||||||
center: center,
|
|
||||||
zoom: zoom
|
|
||||||
});
|
});
|
||||||
return this.mbmap.getCanvas();
|
|
||||||
|
// cancel the scheduled update & trigger synchronous redraw
|
||||||
|
// see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
|
||||||
|
// NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX
|
||||||
|
if (mbMap._frame) {
|
||||||
|
mbMap._frame.cancel();
|
||||||
|
mbMap._frame = null;
|
||||||
}
|
}
|
||||||
|
mbMap._render();
|
||||||
|
|
||||||
updateRenderedPosition(centerOffset, zoomOffset) {
|
return canvas;
|
||||||
const style = this.mbmap.getCanvas().style;
|
|
||||||
style.left = Math.round(centerOffset[0]) + 'px';
|
|
||||||
style.top = Math.round(centerOffset[1]) + 'px';
|
|
||||||
style.transform = 'scale(' + zoomOffset + ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(visible) {
|
|
||||||
super.setVisible(visible);
|
|
||||||
|
|
||||||
const canvas = this.mbmap.getCanvas();
|
|
||||||
canvas.style.display = visible ? 'block' : 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpacity(opacity) {
|
|
||||||
super.setOpacity(opacity);
|
|
||||||
const canvas = this.mbmap.getCanvas();
|
|
||||||
canvas.style.opacity = opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
setZIndex(zindex) {
|
|
||||||
super.setZIndex(zindex);
|
|
||||||
const canvas = this.mbmap.getCanvas();
|
|
||||||
canvas.style.zIndex = zindex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
getSourceState() {
|
|
||||||
return this.loaded ? SourceState.READY : SourceState.UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMap(map) {
|
|
||||||
this.map_ = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mapboxgl.Map.prototype._setupContainer = function _setupContainer() {
|
|
||||||
const container = this._container;
|
|
||||||
container.classList.add('mapboxgl-map');
|
|
||||||
|
|
||||||
const canvasContainer = this._canvasContainer = container.firstChild;
|
|
||||||
|
|
||||||
this._canvas = document.createElement('canvas');
|
|
||||||
canvasContainer.insertBefore(this._canvas, canvasContainer.firstChild);
|
|
||||||
this._canvas.style.position = 'absolute';
|
|
||||||
this._canvas.addEventListener('webglcontextlost', this._contextLost, false);
|
|
||||||
this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false);
|
|
||||||
this._canvas.setAttribute('tabindex', '0');
|
|
||||||
this._canvas.setAttribute('aria-label', 'Map');
|
|
||||||
this._canvas.className = 'mapboxgl-canvas';
|
|
||||||
|
|
||||||
const dimensions = this._containerDimensions();
|
|
||||||
this._resizeCanvas(dimensions[0], dimensions[1]);
|
|
||||||
|
|
||||||
this._controlContainer = canvasContainer;
|
|
||||||
const controlContainer = this._controlContainer = document.createElement('div');
|
|
||||||
controlContainer.className = 'mapboxgl-control-container';
|
|
||||||
container.appendChild(controlContainer);
|
|
||||||
|
|
||||||
const positions = this._controlPositions = {};
|
|
||||||
['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function(positionName) {
|
|
||||||
const elem = document.createElement('div');
|
|
||||||
elem.className = 'mapboxgl-ctrl-' + positionName;
|
|
||||||
controlContainer.appendChild(elem);
|
|
||||||
positions[positionName] = elem;
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const style = new Style({
|
const style = new Style({
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
@@ -202,21 +81,8 @@ const vectorLayer = new VectorLayer({
|
|||||||
const map = new Map({
|
const map = new Map({
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
center: [-10997148, 4569099],
|
center: fromLonLat(center),
|
||||||
zoom: 4,
|
zoom: 4
|
||||||
minZoom: 1,
|
}),
|
||||||
extent: [-Infinity, -20048966.10, Infinity, 20048966.10],
|
layers: [mbLayer, vectorLayer]
|
||||||
smoothExtentConstraint: false,
|
|
||||||
smoothResolutionConstraint: false
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const key = 'ER67WIiPdCQvhgsUjoWK';
|
|
||||||
const mbLayer = new Mapbox({
|
|
||||||
map: map,
|
|
||||||
container: map.getTarget(),
|
|
||||||
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key
|
|
||||||
});
|
|
||||||
|
|
||||||
map.addLayer(mbLayer);
|
|
||||||
map.addLayer(vectorLayer);
|
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ resources:
|
|||||||
- resources/mapbox-streets-v6-style.js
|
- resources/mapbox-streets-v6-style.js
|
||||||
cloak:
|
cloak:
|
||||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||||
value: Your Mapbox access token from http://mapbox.com/ here
|
value: Your Mapbox access token from https://mapbox.com/ here
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ resources:
|
|||||||
- resources/mapbox-streets-v6-style.js
|
- resources/mapbox-streets-v6-style.js
|
||||||
cloak:
|
cloak:
|
||||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||||
value: Your Mapbox access token from http://mapbox.com/ here
|
value: Your Mapbox access token from https://mapbox.com/ here
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import View from '../src/ol/View.js';
|
|||||||
import ImageLayer from '../src/ol/layer/Image.js';
|
import ImageLayer from '../src/ol/layer/Image.js';
|
||||||
import ImageMapGuide from '../src/ol/source/ImageMapGuide.js';
|
import ImageMapGuide from '../src/ol/source/ImageMapGuide.js';
|
||||||
|
|
||||||
const mdf = 'Library://Public/Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
|
const mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
|
||||||
const agentUrl =
|
const agentUrl =
|
||||||
'http://www.buoyshark.com/mapguide/mapagent/mapagent.fcgi?';
|
'http://138.197.230.93:8008/mapguide/mapagent/mapagent.fcgi?';
|
||||||
const bounds = [
|
const bounds = [
|
||||||
-87.865114442365922,
|
-87.865114442365922,
|
||||||
43.665065564837931,
|
43.665065564837931,
|
||||||
@@ -24,8 +24,9 @@ const map = new Map({
|
|||||||
params: {
|
params: {
|
||||||
MAPDEFINITION: mdf,
|
MAPDEFINITION: mdf,
|
||||||
FORMAT: 'PNG',
|
FORMAT: 'PNG',
|
||||||
USERNAME: 'OpenLayers',
|
VERSION: '3.0.0',
|
||||||
PASSWORD: 'OpenLayers'
|
USERNAME: 'OLGuest',
|
||||||
|
PASSWORD: 'olguest'
|
||||||
},
|
},
|
||||||
ratio: 2
|
ratio: 2
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ docs: >
|
|||||||
tags: "raster, pixel operation, flood"
|
tags: "raster, pixel operation, flood"
|
||||||
cloak:
|
cloak:
|
||||||
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
|
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
|
||||||
value: Your Mapbox access token from http://mapbox.com/ here
|
value: Your Mapbox access token from https://mapbox.com/ here
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<header class="navbar" role="navigation">
|
<header class="navbar" role="navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="display-table pull-left" id="navbar-logo-container">
|
<div class="display-table pull-left" id="navbar-logo-container">
|
||||||
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers Examples</a>
|
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- menu items that get hidden below 768px width -->
|
<!-- menu items that get hidden below 768px width -->
|
||||||
<nav class='collapse navbar-collapse navbar-responsive-collapse'>
|
<nav class='collapse navbar-collapse navbar-responsive-collapse'>
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
|
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
|
||||||
</div>
|
</div>
|
||||||
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup"><!DOCTYPE html>
|
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup"><!DOCTYPE html>
|
||||||
<html>
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ docs: >
|
|||||||
tags: "utfgrid, tilejson"
|
tags: "utfgrid, tilejson"
|
||||||
cloak:
|
cloak:
|
||||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||||
value: Your Mapbox access token from http://mapbox.com/ here
|
value: Your Mapbox access token from https://mapbox.com/ here
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
<div style="display: none;">
|
<div style="display: none;">
|
||||||
|
|||||||
@@ -19,16 +19,25 @@ module.exports = {
|
|||||||
context: src,
|
context: src,
|
||||||
target: 'web',
|
target: 'web',
|
||||||
entry: entry,
|
entry: entry,
|
||||||
|
stats: 'minimal',
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [{
|
||||||
|
test: /\.js$/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'buble-loader'
|
loader: 'buble-loader'
|
||||||
},
|
},
|
||||||
test: /\.js$/,
|
|
||||||
include: [
|
include: [
|
||||||
path.join(__dirname, '..', '..', 'src'),
|
path.join(__dirname, '..', '..', 'src'),
|
||||||
path.join(__dirname, '..')
|
path.join(__dirname, '..')
|
||||||
]
|
]
|
||||||
|
}, {
|
||||||
|
test: /\.js$/,
|
||||||
|
use: {
|
||||||
|
loader: path.join(__dirname, './worker-loader.js')
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, '../../src/ol/worker')
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
|
|||||||
24
examples/webpack/worker-loader.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const build = require('../../tasks/serialize-workers').build;
|
||||||
|
|
||||||
|
function loader() {
|
||||||
|
const callback = this.async();
|
||||||
|
|
||||||
|
let minify = false;
|
||||||
|
|
||||||
|
// TODO: remove when https://github.com/webpack/webpack/issues/6496 is addressed
|
||||||
|
const compilation = this._compilation;
|
||||||
|
if (compilation) {
|
||||||
|
minify = compilation.compiler.options.mode === 'production';
|
||||||
|
}
|
||||||
|
|
||||||
|
build(this.resource, {minify})
|
||||||
|
.then(chunk => {
|
||||||
|
for (const filePath in chunk.modules) {
|
||||||
|
this.addDependency(filePath);
|
||||||
|
}
|
||||||
|
callback(null, chunk.code);
|
||||||
|
})
|
||||||
|
.catch(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = loader;
|
||||||
@@ -46,7 +46,7 @@ function updateInfo() {
|
|||||||
|
|
||||||
function setTime() {
|
function setTime() {
|
||||||
startDate.setMinutes(startDate.getMinutes() + 15);
|
startDate.setMinutes(startDate.getMinutes() + 15);
|
||||||
if (startDate > Date.now()) {
|
if (startDate > new Date()) {
|
||||||
startDate = threeHoursAgo();
|
startDate = threeHoursAgo();
|
||||||
}
|
}
|
||||||
layers[1].getSource().updateParams({'TIME': startDate.toISOString()});
|
layers[1].getSource().updateParams({'TIME': startDate.toISOString()});
|
||||||
|
|||||||
10
examples/worker.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: Worker
|
||||||
|
shortdesc: This example should be deleted.
|
||||||
|
docs: >
|
||||||
|
When you move the map, a message is sent to a worker. In response, the woker sends a
|
||||||
|
message back with the version identifier.
|
||||||
|
tags: "worker"
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
35
examples/worker.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
|
import OSM from '../src/ol/source/OSM.js';
|
||||||
|
import {create as createVersionWorker} from '../src/ol/worker/version';
|
||||||
|
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new OSM()
|
||||||
|
})
|
||||||
|
],
|
||||||
|
target: 'map',
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 2
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const worker = createVersionWorker();
|
||||||
|
worker.addEventListener('error', function(error) {
|
||||||
|
console.error('worker error', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
worker.addEventListener('message', function(event) {
|
||||||
|
console.log('message from worker:', event.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on('moveend', function(event) {
|
||||||
|
const state = event.frameState.viewState;
|
||||||
|
worker.postMessage({zoom: state.zoom, center: state.center});
|
||||||
|
});
|
||||||
@@ -11,5 +11,6 @@ tags: "zoomify, deep zoom, IIP, pixel, projection"
|
|||||||
<select id="zoomifyProtocol">
|
<select id="zoomifyProtocol">
|
||||||
<option value="zoomify">Zoomify</option>
|
<option value="zoomify">Zoomify</option>
|
||||||
<option value="iip">IIP</option>
|
<option value="iip">IIP</option>
|
||||||
|
<option value="zoomifyretina">Zoomify Retina</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/
|
|||||||
|
|
||||||
const layer = new TileLayer({
|
const layer = new TileLayer({
|
||||||
source: new Zoomify({
|
source: new Zoomify({
|
||||||
|
tileSize: 256,
|
||||||
|
tilePixelRatio: 1,
|
||||||
url: zoomifyUrl,
|
url: zoomifyUrl,
|
||||||
size: [imgWidth, imgHeight],
|
size: [imgWidth, imgHeight],
|
||||||
crossOrigin: 'anonymous'
|
crossOrigin: 'anonymous'
|
||||||
@@ -20,12 +22,15 @@ const layer = new TileLayer({
|
|||||||
|
|
||||||
const extent = [0, -imgHeight, imgWidth, 0];
|
const extent = [0, -imgHeight, imgWidth, 0];
|
||||||
|
|
||||||
|
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
layers: [layer],
|
layers: [layer],
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
// adjust zoom levels to those provided by the source
|
// adjust zoom levels to those provided by the source
|
||||||
resolutions: layer.getSource().getTileGrid().getResolutions(),
|
minResolution: resolutions[resolutions.length - 1],
|
||||||
|
maxResolution: resolutions[0],
|
||||||
// constrain the center: center cannot be set outside this extent
|
// constrain the center: center cannot be set outside this extent
|
||||||
extent: extent
|
extent: extent
|
||||||
})
|
})
|
||||||
@@ -36,17 +41,73 @@ const control = document.getElementById('zoomifyProtocol');
|
|||||||
control.addEventListener('change', function(event) {
|
control.addEventListener('change', function(event) {
|
||||||
const value = event.currentTarget.value;
|
const value = event.currentTarget.value;
|
||||||
if (value === 'iip') {
|
if (value === 'iip') {
|
||||||
layer.setSource(new Zoomify({
|
const extent = [0, -imgHeight, imgWidth, 0];
|
||||||
|
layer.setSource(
|
||||||
|
new Zoomify({
|
||||||
|
tileSize: 256,
|
||||||
|
tilePixelRatio: 1,
|
||||||
url: iipUrl,
|
url: iipUrl,
|
||||||
size: [imgWidth, imgHeight],
|
size: [imgWidth, imgHeight],
|
||||||
crossOrigin: 'anonymous'
|
crossOrigin: 'anonymous'
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||||
|
map.setView(
|
||||||
|
new View({
|
||||||
|
// adjust zoom levels to those provided by the source
|
||||||
|
minResolution: resolutions[resolutions.length - 1],
|
||||||
|
maxResolution: resolutions[0],
|
||||||
|
// constrain the center: center cannot be set outside this extent
|
||||||
|
extent: extent
|
||||||
|
})
|
||||||
|
);
|
||||||
|
map.getView().fit(extent);
|
||||||
} else if (value === 'zoomify') {
|
} else if (value === 'zoomify') {
|
||||||
layer.setSource(new Zoomify({
|
const extent = [0, -imgHeight, imgWidth, 0];
|
||||||
|
layer.setSource(
|
||||||
|
new Zoomify({
|
||||||
|
tileSize: 256,
|
||||||
|
tilePixelRatio: 1,
|
||||||
url: zoomifyUrl,
|
url: zoomifyUrl,
|
||||||
size: [imgWidth, imgHeight],
|
size: [imgWidth, imgHeight],
|
||||||
crossOrigin: 'anonymous'
|
crossOrigin: 'anonymous'
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||||
|
map.setView(
|
||||||
|
new View({
|
||||||
|
// adjust zoom levels to those provided by the source
|
||||||
|
minResolution: resolutions[resolutions.length - 1],
|
||||||
|
maxResolution: resolutions[0],
|
||||||
|
// constrain the center: center cannot be set outside this extent
|
||||||
|
extent: extent
|
||||||
|
})
|
||||||
|
);
|
||||||
|
map.getView().fit(extent);
|
||||||
|
} else if (value === 'zoomifyretina') {
|
||||||
|
const pixelRatio = 4;
|
||||||
|
// Be careful! Image extent will be modified by pixel ratio
|
||||||
|
const extent = [0, -imgHeight / pixelRatio, imgWidth / pixelRatio, 0];
|
||||||
|
layer.setSource(
|
||||||
|
new Zoomify({
|
||||||
|
tileSize: 256 / pixelRatio,
|
||||||
|
tilePixelRatio: pixelRatio,
|
||||||
|
url: zoomifyUrl,
|
||||||
|
size: [imgWidth / pixelRatio, imgHeight / pixelRatio],
|
||||||
|
crossOrigin: 'anonymous'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||||
|
map.setView(
|
||||||
|
new View({
|
||||||
|
// adjust zoom levels to those provided by the source
|
||||||
|
minResolution: resolutions[resolutions.length - 1] / pixelRatio,
|
||||||
|
maxResolution: resolutions[0],
|
||||||
|
// constrain the center: center cannot be set outside this extent
|
||||||
|
extent: extent
|
||||||
|
})
|
||||||
|
);
|
||||||
|
map.getView().fit(extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
11
gatsby-config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
'gatsby-plugin-emotion',
|
||||||
|
{
|
||||||
|
resolve: 'gatsby-plugin-typography',
|
||||||
|
options: {
|
||||||
|
pathToConfigModule: 'site/util/typography'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
23
gatsby-node.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
function getDocs() {
|
||||||
|
// TODO: build if not present
|
||||||
|
const info = require('./build/api-info.json');
|
||||||
|
|
||||||
|
return info.docs.filter(doc => !doc.ignore && (doc.api || doc.kind === 'module' || doc.kind === 'typedef'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPages({actions: {createPage}}) {
|
||||||
|
createPage({
|
||||||
|
path: '/api',
|
||||||
|
component: require.resolve('./site/pages/API.js'),
|
||||||
|
context: {docs: getDocs()}
|
||||||
|
});
|
||||||
|
|
||||||
|
createPage({
|
||||||
|
path: '/info',
|
||||||
|
component: require.resolve('./site/pages/Info.js'),
|
||||||
|
context: {docs: getDocs()}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createPages = createPages;
|
||||||
20668
package-lock.json
generated
Normal file
73
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ol",
|
"name": "ol",
|
||||||
"version": "6.0.0-beta.6",
|
"version": "6.0.0-beta.8",
|
||||||
"description": "OpenLayers mapping library",
|
"description": "OpenLayers mapping library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"map",
|
"map",
|
||||||
@@ -22,9 +22,12 @@
|
|||||||
"build-index": "npm run build-package && node tasks/generate-index",
|
"build-index": "npm run build-package && node tasks/generate-index",
|
||||||
"build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css",
|
"build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css",
|
||||||
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
||||||
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && tsc --project config/tsconfig-build.json",
|
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json",
|
||||||
"typecheck": "tsc --pretty",
|
"typecheck": "tsc --pretty",
|
||||||
"apidoc": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc",
|
||||||
|
"api-info": "jsdoc --configure config/jsdoc/api-info/conf.json --destination build/api-info.json",
|
||||||
|
"serve-site": "gatsby develop",
|
||||||
|
"build-site": "npm run api-info && gatsby build"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -38,57 +41,83 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pbf": "3.2.0",
|
"pbf": "3.2.0",
|
||||||
"pixelworks": "1.1.0",
|
"pixelworks": "1.1.0",
|
||||||
"rbush": "2.0.2"
|
"rbush": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.4.0",
|
||||||
|
"@babel/preset-env": "^7.4.4",
|
||||||
|
"@emotion/core": "^10.0.10",
|
||||||
|
"@emotion/styled": "^10.0.11",
|
||||||
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
|
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
|
||||||
"@types/arcgis-rest-api": "^10.4.4",
|
"@types/arcgis-rest-api": "^10.4.4",
|
||||||
"@types/geojson": "^7946.0.7",
|
"@types/geojson": "^7946.0.7",
|
||||||
"@types/pbf": "^3.0.1",
|
"@types/pbf": "^3.0.1",
|
||||||
"@types/rbush": "^2.0.2",
|
|
||||||
"@types/topojson-specification": "^1.0.1",
|
"@types/topojson-specification": "^1.0.1",
|
||||||
|
"babel-loader": "^8.0.5",
|
||||||
"buble": "^0.19.7",
|
"buble": "^0.19.7",
|
||||||
"buble-loader": "^0.5.1",
|
"buble-loader": "^0.5.1",
|
||||||
"chaikin-smooth": "^1.0.4",
|
"chaikin-smooth": "^1.0.4",
|
||||||
"clean-css-cli": "4.3.0",
|
"clean-css-cli": "4.3.0",
|
||||||
"copy-webpack-plugin": "^5.0.2",
|
"copy-webpack-plugin": "^5.0.3",
|
||||||
"coveralls": "3.0.3",
|
"coveralls": "3.0.3",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-config-openlayers": "^11.0.0",
|
"eslint-config-openlayers": "^11.0.0",
|
||||||
|
"eslint-config-tschaub": "^13.1.0",
|
||||||
|
"eslint-plugin-react": "^7.13.0",
|
||||||
"expect.js": "0.3.1",
|
"expect.js": "0.3.1",
|
||||||
"front-matter": "^3.0.1",
|
"front-matter": "^3.0.2",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^8.0.0",
|
||||||
"glob": "^7.1.2",
|
"gatsby": "^2.4.3",
|
||||||
|
"gatsby-plugin-emotion": "^4.0.6",
|
||||||
|
"gatsby-plugin-typography": "^2.2.13",
|
||||||
|
"glob": "^7.1.4",
|
||||||
"globby": "^9.2.0",
|
"globby": "^9.2.0",
|
||||||
"handlebars": "4.1.2",
|
"handlebars": "4.1.2",
|
||||||
|
"html-to-image": "^0.1.0",
|
||||||
"istanbul": "0.4.5",
|
"istanbul": "0.4.5",
|
||||||
"jquery": "3.4.0",
|
"istanbul-instrumenter-loader": "^3.0.1",
|
||||||
"jsdoc": "3.5.5",
|
"jquery": "3.4.1",
|
||||||
"jsdoc-plugin-typescript": "^1.0.7",
|
"jsdoc": "3.6.2",
|
||||||
"karma": "^4.0.1",
|
"jsdoc-json": "^2.0.2",
|
||||||
|
"jsdoc-plugin-typescript": "^2.0.1",
|
||||||
|
"karma": "^4.1.0",
|
||||||
"karma-chrome-launcher": "2.2.0",
|
"karma-chrome-launcher": "2.2.0",
|
||||||
"karma-coverage": "^1.1.2",
|
"karma-coverage": "^1.1.2",
|
||||||
|
"karma-coverage-istanbul-reporter": "^2.0.5",
|
||||||
"karma-firefox-launcher": "^1.1.0",
|
"karma-firefox-launcher": "^1.1.0",
|
||||||
"karma-mocha": "1.3.0",
|
"karma-mocha": "1.3.0",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^4.0.0-rc.2",
|
"karma-webpack": "^4.0.0-rc.2",
|
||||||
"loglevelnext": "^3.0.0",
|
"loglevelnext": "^3.0.1",
|
||||||
"marked": "0.6.2",
|
"marked": "0.6.2",
|
||||||
"mocha": "6.1.3",
|
"mocha": "6.1.4",
|
||||||
"ol-mapbox-style": "^4.3.1",
|
"ol-mapbox-style": "^5.0.0-beta.2",
|
||||||
"pixelmatch": "^4.0.2",
|
"pixelmatch": "^4.0.2",
|
||||||
"pngjs": "^3.4.0",
|
"pngjs": "^3.4.0",
|
||||||
"proj4": "2.5.0",
|
"proj4": "2.5.0",
|
||||||
"puppeteer": "~1.14.0",
|
"prop-types": "^15.7.2",
|
||||||
"serve-static": "^1.13.2",
|
"puppeteer": "~1.16.0",
|
||||||
|
"react": "^16.8.6",
|
||||||
|
"react-dom": "^16.8.6",
|
||||||
|
"react-markdown": "^4.0.8",
|
||||||
|
"react-syntax-highlighter": "^10.2.1",
|
||||||
|
"react-typography": "^0.16.19",
|
||||||
|
"rollup": "^1.12.0",
|
||||||
|
"rollup-plugin-babel": "^4.3.2",
|
||||||
|
"rollup-plugin-commonjs": "^10.0.0",
|
||||||
|
"rollup-plugin-node-resolve": "^5.0.0",
|
||||||
|
"rollup-plugin-terser": "^4.0.4",
|
||||||
|
"serve-static": "^1.14.0",
|
||||||
"shx": "^0.3.2",
|
"shx": "^0.3.2",
|
||||||
"sinon": "^7.3.1",
|
"sinon": "^7.3.2",
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^1.2.3",
|
||||||
"typescript": "^3.2.2",
|
"typescript": "^3.4.5",
|
||||||
|
"typography": "^0.16.19",
|
||||||
|
"typography-theme-alton": "^0.16.19",
|
||||||
"url-polyfill": "^1.1.5",
|
"url-polyfill": "^1.1.5",
|
||||||
"walk": "^2.3.9",
|
"walk": "^2.3.9",
|
||||||
"webpack": "4.30.0",
|
"webpack": "4.31.0",
|
||||||
"webpack-cli": "^3.3.0",
|
"webpack-cli": "^3.3.2",
|
||||||
"webpack-dev-middleware": "^3.6.2",
|
"webpack-dev-middleware": "^3.6.2",
|
||||||
"webpack-dev-server": "^3.3.1",
|
"webpack-dev-server": "^3.3.1",
|
||||||
"yargs": "^13.2.2"
|
"yargs": "^13.2.2"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.2 KiB |
@@ -7,6 +7,7 @@ import Point from '../../../src/ol/geom/Point.js';
|
|||||||
import Style from '../../../src/ol/style/Style.js';
|
import Style from '../../../src/ol/style/Style.js';
|
||||||
import Text from '../../../src/ol/style/Text.js';
|
import Text from '../../../src/ol/style/Text.js';
|
||||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||||
|
import Fill from '../../../src/ol/style/Fill.js';
|
||||||
import Stroke from '../../../src/ol/style/Stroke.js';
|
import Stroke from '../../../src/ol/style/Stroke.js';
|
||||||
import LineString from '../../../src/ol/geom/LineString.js';
|
import LineString from '../../../src/ol/geom/LineString.js';
|
||||||
|
|
||||||
@@ -59,9 +60,10 @@ source1.addFeature(new Feature({
|
|||||||
}));
|
}));
|
||||||
layer1.setStyle(function(feature) {
|
layer1.setStyle(function(feature) {
|
||||||
return new Style({
|
return new Style({
|
||||||
|
zIndex: feature.get('zIndex'),
|
||||||
image: new CircleStyle({
|
image: new CircleStyle({
|
||||||
radius: 15,
|
radius: 15,
|
||||||
stroke: new Stroke({
|
fill: new Fill({
|
||||||
color: 'blue'
|
color: 'blue'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -69,7 +71,7 @@ layer1.setStyle(function(feature) {
|
|||||||
});
|
});
|
||||||
map.addLayer(layer1);
|
map.addLayer(layer1);
|
||||||
|
|
||||||
center = [center[0] + 500, center[1] + 500];
|
center = [center[0] + 500, center[1] + 700];
|
||||||
const feature2 = new Feature({
|
const feature2 = new Feature({
|
||||||
geometry: new Point(center),
|
geometry: new Point(center),
|
||||||
text: 'center',
|
text: 'center',
|
||||||
@@ -88,15 +90,16 @@ source2.addFeature(new Feature({
|
|||||||
}));
|
}));
|
||||||
layer2.setStyle(function(feature) {
|
layer2.setStyle(function(feature) {
|
||||||
return new Style({
|
return new Style({
|
||||||
|
zIndex: feature.get('zIndex'),
|
||||||
text: new Text({
|
text: new Text({
|
||||||
text: feature.get('text'),
|
text: feature.get('text'),
|
||||||
font: '16px Ubuntu'
|
font: 'italic bold 18px Ubuntu'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
map.addLayer(layer2);
|
map.addLayer(layer2);
|
||||||
|
|
||||||
center = [center[0] + 500, center[1] + 500];
|
center = [center[0] + 500, center[1] + 300];
|
||||||
source3.addFeature(new Feature({
|
source3.addFeature(new Feature({
|
||||||
geometry: new Point(center),
|
geometry: new Point(center),
|
||||||
text: 'center'
|
text: 'center'
|
||||||
@@ -112,16 +115,17 @@ source3.addFeature(new Feature({
|
|||||||
layer3.setStyle(function(feature) {
|
layer3.setStyle(function(feature) {
|
||||||
return new Style({
|
return new Style({
|
||||||
image: new CircleStyle({
|
image: new CircleStyle({
|
||||||
radius: 5,
|
radius: 10,
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
color: 'red'
|
color: 'red',
|
||||||
|
width: 8
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
text: new Text({
|
text: new Text({
|
||||||
text: feature.get('text'),
|
text: feature.get('text'),
|
||||||
font: '16px Ubuntu',
|
font: 'italic bold 18px Ubuntu',
|
||||||
textBaseline: 'bottom',
|
textBaseline: 'bottom',
|
||||||
offsetY: -5
|
offsetY: -12
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -130,11 +134,12 @@ map.addLayer(layer3);
|
|||||||
center = [center[0] - 2000, center[1] - 2000];
|
center = [center[0] - 2000, center[1] - 2000];
|
||||||
const point = new Feature(new Point(center));
|
const point = new Feature(new Point(center));
|
||||||
point.setStyle(new Style({
|
point.setStyle(new Style({
|
||||||
zIndex: 2,
|
zIndex: 1,
|
||||||
image: new CircleStyle({
|
image: new CircleStyle({
|
||||||
radius: 8,
|
radius: 8,
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
color: 'blue'
|
color: 'blue',
|
||||||
|
width: 4
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
@@ -143,7 +148,7 @@ const line = new Feature(new LineString([
|
|||||||
[center[0] + 650, center[1] - 200]
|
[center[0] + 650, center[1] - 200]
|
||||||
]));
|
]));
|
||||||
line.setStyle(new Style({
|
line.setStyle(new Style({
|
||||||
zIndex: 1,
|
zIndex: 2,
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
color: '#CCC',
|
color: '#CCC',
|
||||||
width: 12
|
width: 12
|
||||||
@@ -151,7 +156,7 @@ line.setStyle(new Style({
|
|||||||
text: new Text({
|
text: new Text({
|
||||||
placement: 'line',
|
placement: 'line',
|
||||||
text: 'east-west',
|
text: 'east-west',
|
||||||
font: '16px Ubuntu',
|
font: 'italic bold 18px Ubuntu',
|
||||||
overflow: true
|
overflow: true
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
@@ -159,4 +164,4 @@ source4.addFeature(point);
|
|||||||
source4.addFeature(line);
|
source4.addFeature(line);
|
||||||
map.addLayer(layer4);
|
map.addLayer(layer4);
|
||||||
|
|
||||||
render({tolerance: 0.02});
|
render({tolerance: 0.007});
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ const layer = new VectorLayer({
|
|||||||
const view = new View({
|
const view = new View({
|
||||||
center: [-9.5, 78],
|
center: [-9.5, 78],
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
projection: 'EPSG:4326'
|
projection: 'EPSG:4326',
|
||||||
|
multiWorld: true
|
||||||
});
|
});
|
||||||
new Map({
|
new Map({
|
||||||
pixelRatio: 1,
|
pixelRatio: 1,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.7 KiB |
@@ -1,72 +1,19 @@
|
|||||||
import Feature from '../../../src/ol/Feature.js';
|
|
||||||
import Map from '../../../src/ol/Map.js';
|
import Map from '../../../src/ol/Map.js';
|
||||||
import View from '../../../src/ol/View.js';
|
import View from '../../../src/ol/View.js';
|
||||||
import VectorSource from '../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||||
import Style from '../../../src/ol/style/Style.js';
|
|
||||||
import Stroke from '../../../src/ol/style/Stroke.js';
|
|
||||||
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
|
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
|
||||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
import Feature from '../../../src/ol/Feature.js';
|
||||||
import Point from '../../../src/ol/geom/Point.js';
|
import Point from '../../../src/ol/geom/Point.js';
|
||||||
import LineString from '../../../src/ol/geom/LineString.js';
|
import Style from '../../../src/ol/style/Style.js';
|
||||||
import Text from '../../../src/ol/style/Text.js';
|
import Text from '../../../src/ol/style/Text.js';
|
||||||
|
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||||
|
import Fill from '../../../src/ol/style/Fill.js';
|
||||||
|
import Stroke from '../../../src/ol/style/Stroke.js';
|
||||||
|
import LineString from '../../../src/ol/geom/LineString.js';
|
||||||
|
|
||||||
const center = [1825927.7316762917, 6143091.089223046];
|
let center = [1825927.7316762917, 6143091.089223046];
|
||||||
|
|
||||||
const source = new VectorSource();
|
|
||||||
const vectorLayer1 = new VectorImageLayer({
|
|
||||||
source: source,
|
|
||||||
style: function(feature) {
|
|
||||||
return new Style({
|
|
||||||
image: new CircleStyle({
|
|
||||||
radius: 15,
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: 'blue'
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
text: new Text({
|
|
||||||
text: feature.get('text'),
|
|
||||||
font: '16px Ubuntu'
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const centerFeature = new Feature({
|
|
||||||
geometry: new Point(center),
|
|
||||||
text: 'center'
|
|
||||||
});
|
|
||||||
source.addFeature(centerFeature);
|
|
||||||
source.addFeature(new Feature({
|
|
||||||
geometry: new Point([center[0] - 540, center[1]]),
|
|
||||||
text: 'west'
|
|
||||||
}));
|
|
||||||
source.addFeature(new Feature({
|
|
||||||
geometry: new Point([center[0] + 540, center[1]]),
|
|
||||||
text: 'east'
|
|
||||||
}));
|
|
||||||
|
|
||||||
const line = new Feature(new LineString([
|
|
||||||
[center[0] - 650, center[1] - 200],
|
|
||||||
[center[0] + 650, center[1] - 200]
|
|
||||||
]));
|
|
||||||
line.setStyle(new Style({
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#CCC',
|
|
||||||
width: 12
|
|
||||||
}),
|
|
||||||
text: new Text({
|
|
||||||
placement: 'line',
|
|
||||||
text: 'east-west',
|
|
||||||
font: '16px Ubuntu'
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
source.addFeature(line);
|
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
pixelRatio: 1,
|
pixelRatio: 1,
|
||||||
layers: [
|
|
||||||
vectorLayer1
|
|
||||||
],
|
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
center: center,
|
center: center,
|
||||||
@@ -74,6 +21,147 @@ const map = new Map({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
map.getView().fit(source.getExtent());
|
const source1 = new VectorSource();
|
||||||
|
const layer1 = new VectorImageLayer({
|
||||||
|
declutter: true,
|
||||||
|
source: source1
|
||||||
|
});
|
||||||
|
|
||||||
render({tolerance: 0.02});
|
const source2 = new VectorSource();
|
||||||
|
const layer2 = new VectorImageLayer({
|
||||||
|
declutter: true,
|
||||||
|
source: source2
|
||||||
|
});
|
||||||
|
|
||||||
|
const source3 = new VectorSource();
|
||||||
|
const layer3 = new VectorImageLayer({
|
||||||
|
declutter: true,
|
||||||
|
source: source3
|
||||||
|
});
|
||||||
|
|
||||||
|
const source4 = new VectorSource();
|
||||||
|
const layer4 = new VectorImageLayer({
|
||||||
|
declutter: true,
|
||||||
|
source: source4
|
||||||
|
});
|
||||||
|
|
||||||
|
const feature1 = new Feature({
|
||||||
|
geometry: new Point(center),
|
||||||
|
zIndex: 2
|
||||||
|
});
|
||||||
|
source1.addFeature(feature1);
|
||||||
|
source1.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] - 540, center[1]]),
|
||||||
|
zIndex: 3
|
||||||
|
}));
|
||||||
|
source1.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] + 540, center[1]]),
|
||||||
|
zIndex: 1
|
||||||
|
}));
|
||||||
|
layer1.setStyle(function(feature) {
|
||||||
|
return new Style({
|
||||||
|
zIndex: feature.get('zIndex'),
|
||||||
|
image: new CircleStyle({
|
||||||
|
radius: 15,
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'blue'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
map.addLayer(layer1);
|
||||||
|
|
||||||
|
center = [center[0] + 500, center[1] + 700];
|
||||||
|
const feature2 = new Feature({
|
||||||
|
geometry: new Point(center),
|
||||||
|
text: 'center',
|
||||||
|
zIndex: 2
|
||||||
|
});
|
||||||
|
source2.addFeature(feature2);
|
||||||
|
source2.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] - 540, center[1]]),
|
||||||
|
text: 'west',
|
||||||
|
zIndex: 3
|
||||||
|
}));
|
||||||
|
source2.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] + 540, center[1]]),
|
||||||
|
text: 'east',
|
||||||
|
zIndex: 1
|
||||||
|
}));
|
||||||
|
layer2.setStyle(function(feature) {
|
||||||
|
return new Style({
|
||||||
|
zIndex: feature.get('zIndex'),
|
||||||
|
text: new Text({
|
||||||
|
text: feature.get('text'),
|
||||||
|
font: 'italic bold 18px Ubuntu'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
map.addLayer(layer2);
|
||||||
|
|
||||||
|
center = [center[0] + 500, center[1] + 300];
|
||||||
|
source3.addFeature(new Feature({
|
||||||
|
geometry: new Point(center),
|
||||||
|
text: 'center'
|
||||||
|
}));
|
||||||
|
source3.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] - 540, center[1]]),
|
||||||
|
text: 'west'
|
||||||
|
}));
|
||||||
|
source3.addFeature(new Feature({
|
||||||
|
geometry: new Point([center[0] + 540, center[1]]),
|
||||||
|
text: 'east'
|
||||||
|
}));
|
||||||
|
layer3.setStyle(function(feature) {
|
||||||
|
return new Style({
|
||||||
|
image: new CircleStyle({
|
||||||
|
radius: 10,
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'red',
|
||||||
|
width: 8
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
text: new Text({
|
||||||
|
text: feature.get('text'),
|
||||||
|
font: 'italic bold 18px Ubuntu',
|
||||||
|
textBaseline: 'bottom',
|
||||||
|
offsetY: -12
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
map.addLayer(layer3);
|
||||||
|
|
||||||
|
center = [center[0] - 2000, center[1] - 2000];
|
||||||
|
const point = new Feature(new Point(center));
|
||||||
|
point.setStyle(new Style({
|
||||||
|
zIndex: 1,
|
||||||
|
image: new CircleStyle({
|
||||||
|
radius: 8,
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'blue',
|
||||||
|
width: 4
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
const line = new Feature(new LineString([
|
||||||
|
[center[0] - 650, center[1] - 200],
|
||||||
|
[center[0] + 650, center[1] - 200]
|
||||||
|
]));
|
||||||
|
line.setStyle(new Style({
|
||||||
|
zIndex: 2,
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#CCC',
|
||||||
|
width: 12
|
||||||
|
}),
|
||||||
|
text: new Text({
|
||||||
|
placement: 'line',
|
||||||
|
text: 'east-west',
|
||||||
|
font: 'italic bold 18px Ubuntu',
|
||||||
|
overflow: true
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
source4.addFeature(point);
|
||||||
|
source4.addFeature(line);
|
||||||
|
map.addLayer(layer4);
|
||||||
|
|
||||||
|
render({tolerance: 0.007});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
@@ -4,8 +4,10 @@ import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js
|
|||||||
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
|
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
|
||||||
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
|
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
|
||||||
import {Style, Stroke} from '../../../src/ol/style.js';
|
import {Style, Stroke} from '../../../src/ol/style.js';
|
||||||
|
import Feature from '../../../src/ol/Feature.js';
|
||||||
|
import Point from '../../../src/ol/geom/Point.js';
|
||||||
|
|
||||||
new Map({
|
const map = new Map({
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
source: new XYZ({
|
source: new XYZ({
|
||||||
@@ -14,6 +16,7 @@ new Map({
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
new VectorLayer({
|
new VectorLayer({
|
||||||
|
zIndex: 1,
|
||||||
style: new Style({
|
style: new Style({
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
color: 'rgba(255,255,255,0.5)',
|
color: 'rgba(255,255,255,0.5)',
|
||||||
@@ -33,4 +36,11 @@ new Map({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const unmanaged = new VectorLayer({
|
||||||
|
source: new VectorSource({
|
||||||
|
features: [new Feature(new Point([0, 0]))]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
unmanaged.setMap(map);
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|||||||
3
site/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "tschaub/react"
|
||||||
|
}
|
||||||
35
site/components/Class.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
import Code from './Code';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Class({cls, module, helper}) {
|
||||||
|
const exportedName = module.getExportedName(cls.name);
|
||||||
|
let importCode;
|
||||||
|
if (exportedName === 'default') {
|
||||||
|
importCode = `import ${cls.name} from '${module.id}';`;
|
||||||
|
} else {
|
||||||
|
importCode = `import {${exportedName}} from '${module.id}';`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>{cls.name}</h3>
|
||||||
|
<Code value={importCode} />
|
||||||
|
<Markdown source={cls.doc.classdesc} renderers={{code: Code}} />
|
||||||
|
<h6>Parameters</h6>
|
||||||
|
<ul>
|
||||||
|
{cls.doc.params && cls.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class.propTypes = {
|
||||||
|
cls: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Class;
|
||||||
26
site/components/Code.jsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React, {PureComponent} from 'react';
|
||||||
|
import {string} from 'prop-types';
|
||||||
|
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter';
|
||||||
|
import {coy} from 'react-syntax-highlighter/dist/styles/prism';
|
||||||
|
|
||||||
|
class Code extends PureComponent {
|
||||||
|
render() {
|
||||||
|
let language = this.props.language;
|
||||||
|
if (!language) {
|
||||||
|
language = 'js';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SyntaxHighlighter language={language} style={coy}>
|
||||||
|
{this.props.value}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Code.propTypes = {
|
||||||
|
value: string.isRequired,
|
||||||
|
language: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Code;
|
||||||
35
site/components/Func.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
import Code from './Code';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Func({func, module, helper}) {
|
||||||
|
const exportedName = module.getExportedName(func.name);
|
||||||
|
let importCode;
|
||||||
|
if (exportedName === 'default') {
|
||||||
|
importCode = `import ${func.name} from '${module.id}';`;
|
||||||
|
} else {
|
||||||
|
importCode = `import {${exportedName}} from '${module.id}';`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>{func.name}</h3>
|
||||||
|
<Code value={importCode} />
|
||||||
|
<Markdown source={func.doc.description} renderers={{code: Code}} />
|
||||||
|
<h6>Parameters</h6>
|
||||||
|
<ul>
|
||||||
|
{func.doc.params && func.doc.params.map(param => <Parameter param={param} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func.propTypes = {
|
||||||
|
func: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Func;
|
||||||
26
site/components/Module.jsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Class from './Class';
|
||||||
|
import Func from './Func';
|
||||||
|
|
||||||
|
function Module({module, helper}) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<hr />
|
||||||
|
<h2>{module.id}</h2>
|
||||||
|
{module.classes.map(cls => (
|
||||||
|
<Class key={cls.name} cls={cls} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
{module.functions.map(func => (
|
||||||
|
<Func key={func.name} func={func} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Module.propTypes = {
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Module;
|
||||||
20
site/components/Parameter.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Type from './Type';
|
||||||
|
|
||||||
|
function Parameter({param, module, helper}) {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<code>{param.name}</code> - {param.description} {param.optional && <span>(optional)</span>}<br/>
|
||||||
|
{param.type.names.map(longName => <Type longName={longName} module={module} helper={helper} />)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter.propTypes = {
|
||||||
|
param: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Parameter;
|
||||||
27
site/components/Type.jsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import Parameter from './Parameter';
|
||||||
|
|
||||||
|
function Type({longName, module, helper}) {
|
||||||
|
const type = helper.getTypeDef(longName);
|
||||||
|
if (!type) {
|
||||||
|
return <code>{longName}</code>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<code>{type.doc.type.names}</code>
|
||||||
|
<ul>
|
||||||
|
{type.doc.properties && type.doc.properties.map(prop => <Parameter param={prop} module={module} helper={helper} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type.propTypes = {
|
||||||
|
longName: object.isRequired,
|
||||||
|
module: object.isRequired,
|
||||||
|
helper: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Type;
|
||||||
8
site/components/layout.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import {baseSpacingPx} from '../util/typography';
|
||||||
|
|
||||||
|
export const Page = styled.div({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
margin: 2 * baseSpacingPx
|
||||||
|
});
|
||||||
26
site/pages/API.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {Page} from '../components/layout';
|
||||||
|
import Module from '../components/Module';
|
||||||
|
import {getHelper} from '../util/api';
|
||||||
|
|
||||||
|
function API({pageContext: {docs}}) {
|
||||||
|
const helper = getHelper(docs);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<h1>API</h1>
|
||||||
|
{helper.modules
|
||||||
|
.filter(module => module.visible)
|
||||||
|
.map(module => (
|
||||||
|
<Module key={module.id} module={module} helper={helper} />
|
||||||
|
))}
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
API.propTypes = {
|
||||||
|
pageContext: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default API;
|
||||||
33
site/pages/Info.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import {object} from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {Page} from '../components/layout';
|
||||||
|
|
||||||
|
function Info({pageContext: {docs}}) {
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<h1>API</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>kind</th>
|
||||||
|
<th>longname</th>
|
||||||
|
<th>memberof</th>
|
||||||
|
</tr>
|
||||||
|
{docs.map(doc => (
|
||||||
|
<tr key={doc.longname}>
|
||||||
|
<td>{doc.kind}</td>
|
||||||
|
<td>{doc.longname}</td>
|
||||||
|
<td>{doc.memberof}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Info.propTypes = {
|
||||||
|
pageContext: object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Info;
|
||||||
205
site/util/api.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
class FunctionDoc {
|
||||||
|
constructor(doc) {
|
||||||
|
this.name = doc.name;
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypedefDoc {
|
||||||
|
constructor(doc) {
|
||||||
|
this.name = doc.name;
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassDoc {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
processDoc(doc) {
|
||||||
|
if (doc.kind === 'class') {
|
||||||
|
this.doc = doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModuleDoc {
|
||||||
|
constructor(id) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.classLookup = {};
|
||||||
|
this.classes = [];
|
||||||
|
|
||||||
|
this.functionLookup = {};
|
||||||
|
this.functions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
processDoc(doc) {
|
||||||
|
if (doc.kind === 'module') {
|
||||||
|
this.doc = doc;
|
||||||
|
//console.log('processing module: ' + doc.longname)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.kind === 'class') {
|
||||||
|
const name = nameFromLongname(doc.longname);
|
||||||
|
if (!(name in this.classLookup)) {
|
||||||
|
const cls = new ClassDoc(name);
|
||||||
|
this.classLookup[name] = cls;
|
||||||
|
this.classes.push(cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.classLookup[name].processDoc(doc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.kind === 'function') {
|
||||||
|
if (nameFromLongname(doc.memberof)) {
|
||||||
|
// belongs to a class or other
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.name in this.functionLookup) {
|
||||||
|
throw new Error(`Duplicate function ${doc.name} in ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const func = new FunctionDoc(doc);
|
||||||
|
this.functionLookup[doc.name] = func;
|
||||||
|
this.functions.push(func);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize() {
|
||||||
|
this.classes.sort(byName);
|
||||||
|
this.functions.sort(byName);
|
||||||
|
this.visible = this.classes.length > 0 || this.functions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getExportedName(localName) {
|
||||||
|
if (!this.doc || !this.doc.exportMap) {
|
||||||
|
throw new Error(`Expected to find export map in module doc: ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(localName in this.doc.exportMap)) {
|
||||||
|
throw new Error(
|
||||||
|
`No local name "${localName}" in export map for module: ${this.id}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.doc.exportMap[localName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const longnameRE = /^module:(?<module>.*?)([~\.](?<name>\w+)(#(?<member>\w+))?(:(?<type>\w+))?)?$/;
|
||||||
|
|
||||||
|
function moduleIDFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match module id in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.module;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function nameFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match name in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function memberFromLongname(longname) {
|
||||||
|
const match = longname.match(longnameRE);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`could not match member in longname: ${longname}`);
|
||||||
|
}
|
||||||
|
return match.groups.member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function byName(a, b) {
|
||||||
|
if (a.name < b.name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function byModuleId(a, b) {
|
||||||
|
const aParts = a.id.split('/');
|
||||||
|
const bParts = b.id.split('/');
|
||||||
|
const len = Math.max(aParts.length, bParts.length);
|
||||||
|
for (let i = 0; i < len; ++i) {
|
||||||
|
if (aParts[i] && bParts[i]) {
|
||||||
|
if (aParts[i] < bParts[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (aParts[i] > bParts[i]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (!aParts[i]) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DocHelper {
|
||||||
|
constructor(docs) {
|
||||||
|
this.moduleLookup = {};
|
||||||
|
this.modules = [];
|
||||||
|
|
||||||
|
this.typedefLookup = {};
|
||||||
|
|
||||||
|
docs.forEach(doc => {
|
||||||
|
// typedef are indexed by long name
|
||||||
|
if (doc.kind === 'typedef') {
|
||||||
|
if (doc.name in this.typedefLookup) {
|
||||||
|
throw new Error(`Duplicate type definition ${doc.name} in ${this.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = new TypedefDoc(doc);
|
||||||
|
this.typedefLookup[doc.longname] = type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleID = moduleIDFromLongname(doc.longname);
|
||||||
|
if (!(moduleID in this.moduleLookup)) {
|
||||||
|
const module = new ModuleDoc(moduleID);
|
||||||
|
this.moduleLookup[moduleID] = module;
|
||||||
|
this.modules.push(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
const module = this.moduleLookup[moduleID];
|
||||||
|
module.processDoc(doc);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.modules.sort(byModuleId);
|
||||||
|
this.modules.forEach(module => module.finalize());
|
||||||
|
}
|
||||||
|
|
||||||
|
getTypeDef(longName) {
|
||||||
|
this.typedefLookup[longName] && console.log(this.typedefLookup[longName]);
|
||||||
|
return this.typedefLookup[longName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedDocs;
|
||||||
|
let cachedHelper;
|
||||||
|
|
||||||
|
export function getHelper(docs) {
|
||||||
|
if (docs !== cachedDocs) {
|
||||||
|
if (cachedDocs) {
|
||||||
|
console.warn('creating new doc helper'); // eslint-disable-line
|
||||||
|
}
|
||||||
|
cachedHelper = new DocHelper(docs);
|
||||||
|
cachedDocs = docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedHelper;
|
||||||
|
}
|
||||||
9
site/util/typography.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Typography from 'typography';
|
||||||
|
import theme from 'typography-theme-alton';
|
||||||
|
|
||||||
|
const typography = new Typography(theme);
|
||||||
|
|
||||||
|
export const baseSpacingPx = parseInt(theme.baseFontSize, 10);
|
||||||
|
|
||||||
|
export {theme};
|
||||||
|
export default typography;
|
||||||
@@ -6,7 +6,6 @@ import {listen} from './events.js';
|
|||||||
import Event from './events/Event.js';
|
import Event from './events/Event.js';
|
||||||
import EventType from './events/EventType.js';
|
import EventType from './events/EventType.js';
|
||||||
import {circular as circularPolygon} from './geom/Polygon.js';
|
import {circular as circularPolygon} from './geom/Polygon.js';
|
||||||
import {GEOLOCATION} from './has.js';
|
|
||||||
import {toRadians} from './math.js';
|
import {toRadians} from './math.js';
|
||||||
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';
|
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';
|
||||||
|
|
||||||
@@ -83,7 +82,7 @@ class GeolocationError extends Event {
|
|||||||
* window.console.log(geolocation.getPosition());
|
* window.console.log(geolocation.getPosition());
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* @fires error
|
* @fires module:ol/events/Event~Event#event:error
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
class Geolocation extends BaseObject {
|
class Geolocation extends BaseObject {
|
||||||
@@ -160,7 +159,7 @@ class Geolocation extends BaseObject {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleTrackingChanged_() {
|
handleTrackingChanged_() {
|
||||||
if (GEOLOCATION) {
|
if ('geolocation' in navigator) {
|
||||||
const tracking = this.getTracking();
|
const tracking = this.getTracking();
|
||||||
if (tracking && this.watchId_ === undefined) {
|
if (tracking && this.watchId_ === undefined) {
|
||||||
this.watchId_ = navigator.geolocation.watchPosition(
|
this.watchId_ = navigator.geolocation.watchPosition(
|
||||||
@@ -204,12 +203,6 @@ class Geolocation extends BaseObject {
|
|||||||
this.changed();
|
this.changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered when the Geolocation returns an error.
|
|
||||||
* @event error
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {PositionError} error error object.
|
* @param {PositionError} error error object.
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ class ImageWrapper extends ImageBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {Array<import("./events.js").EventsKey>}
|
* @type {function():void}
|
||||||
*/
|
*/
|
||||||
this.imageListenerKeys_ = null;
|
this.unlisten_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
@@ -120,13 +120,12 @@ class ImageWrapper extends ImageBase {
|
|||||||
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
|
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
|
||||||
this.state = ImageState.LOADING;
|
this.state = ImageState.LOADING;
|
||||||
this.changed();
|
this.changed();
|
||||||
this.imageListenerKeys_ = [
|
|
||||||
listenOnce(this.image_, EventType.ERROR,
|
|
||||||
this.handleImageError_, this),
|
|
||||||
listenOnce(this.image_, EventType.LOAD,
|
|
||||||
this.handleImageLoad_, this)
|
|
||||||
];
|
|
||||||
this.imageLoadFunction_(this, this.src_);
|
this.imageLoadFunction_(this, this.src_);
|
||||||
|
this.unlisten_ = listenImage(
|
||||||
|
this.image_,
|
||||||
|
this.handleImageLoad_.bind(this),
|
||||||
|
this.handleImageError_.bind(this)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,10 +142,47 @@ class ImageWrapper extends ImageBase {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
unlistenImage_() {
|
unlistenImage_() {
|
||||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
if (this.unlisten_) {
|
||||||
this.imageListenerKeys_ = null;
|
this.unlisten_();
|
||||||
|
this.unlisten_ = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image element.
|
||||||
|
* @param {function():any} loadHandler Load callback function.
|
||||||
|
* @param {function():any} errorHandler Error callback function.
|
||||||
|
* @return {function():void} Callback to stop listening.
|
||||||
|
*/
|
||||||
|
export function listenImage(image, loadHandler, errorHandler) {
|
||||||
|
const img = /** @type {HTMLImageElement} */ (image);
|
||||||
|
if (img.decode) {
|
||||||
|
const promise = img.decode();
|
||||||
|
let listening = true;
|
||||||
|
const unlisten = function() {
|
||||||
|
listening = false;
|
||||||
|
};
|
||||||
|
promise.then(function() {
|
||||||
|
if (listening) {
|
||||||
|
loadHandler();
|
||||||
|
}
|
||||||
|
}).catch(function(error) {
|
||||||
|
if (listening) {
|
||||||
|
errorHandler();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return unlisten;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listenerKeys = [
|
||||||
|
listenOnce(img, EventType.LOAD, loadHandler),
|
||||||
|
listenOnce(img, EventType.ERROR, errorHandler)
|
||||||
|
];
|
||||||
|
return function unlisten() {
|
||||||
|
listenerKeys.forEach(unlistenByKey);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default ImageWrapper;
|
export default ImageWrapper;
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
import Tile from './Tile.js';
|
import Tile from './Tile.js';
|
||||||
import TileState from './TileState.js';
|
import TileState from './TileState.js';
|
||||||
import {createCanvasContext2D} from './dom.js';
|
import {createCanvasContext2D} from './dom.js';
|
||||||
import {listenOnce, unlistenByKey} from './events.js';
|
import {listenImage} from './Image.js';
|
||||||
import EventType from './events/EventType.js';
|
|
||||||
|
|
||||||
|
|
||||||
class ImageTile extends Tile {
|
class ImageTile extends Tile {
|
||||||
@@ -47,9 +46,9 @@ class ImageTile extends Tile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {Array<import("./events.js").EventsKey>}
|
* @type {function():void}
|
||||||
*/
|
*/
|
||||||
this.imageListenerKeys_ = null;
|
this.unlisten_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -134,13 +133,12 @@ class ImageTile extends Tile {
|
|||||||
if (this.state == TileState.IDLE) {
|
if (this.state == TileState.IDLE) {
|
||||||
this.state = TileState.LOADING;
|
this.state = TileState.LOADING;
|
||||||
this.changed();
|
this.changed();
|
||||||
this.imageListenerKeys_ = [
|
|
||||||
listenOnce(this.image_, EventType.ERROR,
|
|
||||||
this.handleImageError_, this),
|
|
||||||
listenOnce(this.image_, EventType.LOAD,
|
|
||||||
this.handleImageLoad_, this)
|
|
||||||
];
|
|
||||||
this.tileLoadFunction_(this, this.src_);
|
this.tileLoadFunction_(this, this.src_);
|
||||||
|
this.unlisten_ = listenImage(
|
||||||
|
this.image_,
|
||||||
|
this.handleImageLoad_.bind(this),
|
||||||
|
this.handleImageError_.bind(this)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +148,10 @@ class ImageTile extends Tile {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
unlistenImage_() {
|
unlistenImage_() {
|
||||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
if (this.unlisten_) {
|
||||||
this.imageListenerKeys_ = null;
|
this.unlisten_();
|
||||||
|
this.unlisten_ = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @module ol/Map
|
* @module ol/Map
|
||||||
*/
|
*/
|
||||||
import PluggableMap from './PluggableMap.js';
|
import PluggableMap from './PluggableMap.js';
|
||||||
import {defaults as defaultControls} from './control/util.js';
|
import {defaults as defaultControls} from './control.js';
|
||||||
import {defaults as defaultInteractions} from './interaction.js';
|
import {defaults as defaultInteractions} from './interaction.js';
|
||||||
import {assign} from './obj.js';
|
import {assign} from './obj.js';
|
||||||
import CompositeMapRenderer from './renderer/Composite.js';
|
import CompositeMapRenderer from './renderer/Composite.js';
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {create as createTransform, apply as applyTransform} from './transform.js
|
|||||||
* @property {boolean} animate
|
* @property {boolean} animate
|
||||||
* @property {import("./transform.js").Transform} coordinateToPixelTransform
|
* @property {import("./transform.js").Transform} coordinateToPixelTransform
|
||||||
* @property {null|import("./extent.js").Extent} extent
|
* @property {null|import("./extent.js").Extent} extent
|
||||||
|
* @property {Array<*>} declutterItems
|
||||||
* @property {import("./coordinate.js").Coordinate} focus
|
* @property {import("./coordinate.js").Coordinate} focus
|
||||||
* @property {number} index
|
* @property {number} index
|
||||||
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
|
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
|
||||||
@@ -292,6 +293,11 @@ class PluggableMap extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
this.interactions = optionsInternal.interactions || new Collection();
|
this.interactions = optionsInternal.interactions || new Collection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("./events.js").EventsKey}
|
||||||
|
*/
|
||||||
|
this.labelCacheListenerKey_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Collection<import("./Overlay.js").default>}
|
* @type {Collection<import("./Overlay.js").default>}
|
||||||
* @private
|
* @private
|
||||||
@@ -497,6 +503,24 @@ class PluggableMap extends BaseObject {
|
|||||||
overlay.setMap(this);
|
overlay.setMap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a label cache for listening to font changes.
|
||||||
|
* @param {import("./events/Target.js").default} labelCache Label cache.
|
||||||
|
*/
|
||||||
|
attachLabelCache(labelCache) {
|
||||||
|
this.detachLabelCache();
|
||||||
|
this.labelCacheListenerKey_ = listen(labelCache, EventType.CLEAR, this.redrawText.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach the label cache, i.e. no longer listen to font changes.
|
||||||
|
*/
|
||||||
|
detachLabelCache() {
|
||||||
|
if (this.labelCacheListenerKey_) {
|
||||||
|
unlistenByKey(this.labelCacheListenerKey_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
@@ -514,6 +538,7 @@ class PluggableMap extends BaseObject {
|
|||||||
cancelAnimationFrame(this.animationDelayKey_);
|
cancelAnimationFrame(this.animationDelayKey_);
|
||||||
this.animationDelayKey_ = undefined;
|
this.animationDelayKey_ = undefined;
|
||||||
}
|
}
|
||||||
|
this.detachLabelCache();
|
||||||
this.setTarget(null);
|
this.setTarget(null);
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
@@ -762,6 +787,21 @@ class PluggableMap extends BaseObject {
|
|||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} Layers have sources that are still loading.
|
||||||
|
*/
|
||||||
|
getLoading() {
|
||||||
|
const layerStatesArray = this.getLayerGroup().getLayerStatesArray();
|
||||||
|
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||||
|
const layer = layerStatesArray[i].layer;
|
||||||
|
const source = /** @type {import("./layer/Layer.js").default} */ (layer).getSource();
|
||||||
|
if (source && source.loading) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the pixel for a coordinate. This takes a coordinate in the map view
|
* Get the pixel for a coordinate. This takes a coordinate in the map view
|
||||||
* projection and returns the corresponding pixel.
|
* projection and returns the corresponding pixel.
|
||||||
@@ -949,7 +989,7 @@ class PluggableMap extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frameState && this.hasListener(RenderEventType.RENDERCOMPLETE) && !frameState.animate &&
|
if (frameState && this.hasListener(RenderEventType.RENDERCOMPLETE) && !frameState.animate &&
|
||||||
!this.tileQueue_.getTilesLoading() && !getLoading(this.getLayers().getArray())) {
|
!this.tileQueue_.getTilesLoading() && !this.getLoading()) {
|
||||||
this.renderer_.dispatchRenderEvent(RenderEventType.RENDERCOMPLETE, frameState);
|
this.renderer_.dispatchRenderEvent(RenderEventType.RENDERCOMPLETE, frameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,7 +1033,6 @@ class PluggableMap extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!targetElement) {
|
if (!targetElement) {
|
||||||
this.renderer_.removeLayerRenderers();
|
|
||||||
removeNode(this.viewport_);
|
removeNode(this.viewport_);
|
||||||
if (this.handleResize_ !== undefined) {
|
if (this.handleResize_ !== undefined) {
|
||||||
removeEventListener(EventType.RESIZE, this.handleResize_, false);
|
removeEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||||
@@ -1101,6 +1140,19 @@ class PluggableMap extends BaseObject {
|
|||||||
this.animationDelay_();
|
this.animationDelay_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redraws all text after new fonts have loaded
|
||||||
|
*/
|
||||||
|
redrawText() {
|
||||||
|
const layerStates = this.getLayerGroup().getLayerStatesArray();
|
||||||
|
for (let i = 0, ii = layerStates.length; i < ii; ++i) {
|
||||||
|
const layer = layerStates[i].layer;
|
||||||
|
if (layer.hasRenderer()) {
|
||||||
|
layer.getRenderer().handleFontsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a map rendering (at the next animation frame).
|
* Request a map rendering (at the next animation frame).
|
||||||
* @api
|
* @api
|
||||||
@@ -1175,6 +1227,7 @@ class PluggableMap extends BaseObject {
|
|||||||
frameState = /** @type {FrameState} */ ({
|
frameState = /** @type {FrameState} */ ({
|
||||||
animate: false,
|
animate: false,
|
||||||
coordinateToPixelTransform: this.coordinateToPixelTransform_,
|
coordinateToPixelTransform: this.coordinateToPixelTransform_,
|
||||||
|
declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
|
||||||
extent: extent,
|
extent: extent,
|
||||||
focus: this.focus_ ? this.focus_ : viewState.center,
|
focus: this.focus_ ? this.focus_ : viewState.center,
|
||||||
index: this.frameIndex_++,
|
index: this.frameIndex_++,
|
||||||
@@ -1396,23 +1449,3 @@ function createOptionsInternal(options) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
export default PluggableMap;
|
export default PluggableMap;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array<import("./layer/Base.js").default>} layers Layers.
|
|
||||||
* @return {boolean} Layers have sources that are still loading.
|
|
||||||
*/
|
|
||||||
function getLoading(layers) {
|
|
||||||
for (let i = 0, ii = layers.length; i < ii; ++i) {
|
|
||||||
const layer = layers[i];
|
|
||||||
if (typeof /** @type {?} */ (layer).getLayers === 'function') {
|
|
||||||
return getLoading(/** @type {LayerGroup} */ (layer).getLayers().getArray());
|
|
||||||
} else {
|
|
||||||
const source = /** @type {import("./layer/Layer.js").default} */ (
|
|
||||||
layer).getSource();
|
|
||||||
if (source && source.loading) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
* This is the object to act upon to change the center, resolution,
|
* This is the object to act upon to change the center, resolution,
|
||||||
* and rotation of the map.
|
* and rotation of the map.
|
||||||
*
|
*
|
||||||
|
* A View has a `projection`. The projection determines the
|
||||||
|
* coordinate system of the center, and its units determine the units of the
|
||||||
|
* resolution (projection units per pixel). The default projection is
|
||||||
|
* Spherical Mercator (EPSG:3857).
|
||||||
|
*
|
||||||
* ### The view states
|
* ### The view states
|
||||||
*
|
*
|
||||||
* An View is determined by three states: `center`, `resolution`,
|
* An View is determined by three states: `center`, `resolution`,
|
||||||
@@ -202,11 +207,6 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
* methods are available, as well as `getResolutionForZoom` and
|
* methods are available, as well as `getResolutionForZoom` and
|
||||||
* `getZoomForResolution` to switch from one system to the other.
|
* `getZoomForResolution` to switch from one system to the other.
|
||||||
*
|
*
|
||||||
* A View has a `projection`. The projection determines the
|
|
||||||
* coordinate system of the center, and its units determine the units of the
|
|
||||||
* resolution (projection units per pixel). The default projection is
|
|
||||||
* Spherical Mercator (EPSG:3857).
|
|
||||||
*
|
|
||||||
* ### The constraints
|
* ### The constraints
|
||||||
*
|
*
|
||||||
* `setCenter`, `setResolution` and `setRotation` can be used to change the
|
* `setCenter`, `setResolution` and `setRotation` can be used to change the
|
||||||
@@ -218,7 +218,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
*
|
*
|
||||||
* The *resolution constraint* typically restricts min/max values and
|
* The *resolution constraint* typically restricts min/max values and
|
||||||
* snaps to specific resolutions. It is determined by the following
|
* snaps to specific resolutions. It is determined by the following
|
||||||
* options: `resolutions`, `maxResolution`, `maxZoom`, and `zoomFactor`.
|
* options: `resolutions`, `maxResolution`, `maxZoom` and `zoomFactor`.
|
||||||
* If `resolutions` is set, the other three options are ignored. See
|
* If `resolutions` is set, the other three options are ignored. See
|
||||||
* documentation for each option for more information. By default, the view
|
* documentation for each option for more information. By default, the view
|
||||||
* only has a min/max restriction and allow intermediary zoom levels when
|
* only has a min/max restriction and allow intermediary zoom levels when
|
||||||
@@ -226,7 +226,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
*
|
*
|
||||||
* The *rotation constraint* snaps to specific angles. It is determined
|
* The *rotation constraint* snaps to specific angles. It is determined
|
||||||
* by the following options: `enableRotation` and `constrainRotation`.
|
* by the following options: `enableRotation` and `constrainRotation`.
|
||||||
* By default the rotation value is snapped to zero when approaching the
|
* By default rotation is allowed and its value is snapped to zero when approaching the
|
||||||
* horizontal.
|
* horizontal.
|
||||||
*
|
*
|
||||||
* The *center constraint* is determined by the `extent` option. By
|
* The *center constraint* is determined by the `extent` option. By
|
||||||
@@ -1409,11 +1409,19 @@ function animationCallback(callback, returnValue) {
|
|||||||
*/
|
*/
|
||||||
export function createCenterConstraint(options) {
|
export function createCenterConstraint(options) {
|
||||||
if (options.extent !== undefined) {
|
if (options.extent !== undefined) {
|
||||||
return createExtent(options.extent, options.constrainOnlyCenter,
|
const smooth = options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true;
|
||||||
options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true);
|
return createExtent(options.extent, options.constrainOnlyCenter, smooth);
|
||||||
} else {
|
|
||||||
return centerNone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const projection = createProjection(options.projection, 'EPSG:3857');
|
||||||
|
if (options.multiWorld !== true && projection.isGlobal()) {
|
||||||
|
const extent = projection.getExtent().slice();
|
||||||
|
extent[0] = -Infinity;
|
||||||
|
extent[2] = Infinity;
|
||||||
|
return createExtent(extent, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return centerNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/control
|
* @module ol/control
|
||||||
*/
|
*/
|
||||||
|
import Collection from './Collection.js';
|
||||||
|
import Attribution from './control/Attribution.js';
|
||||||
|
import Rotate from './control/Rotate.js';
|
||||||
|
import Zoom from './control/Zoom.js';
|
||||||
|
|
||||||
export {default as Attribution} from './control/Attribution.js';
|
export {default as Attribution} from './control/Attribution.js';
|
||||||
export {default as Control} from './control/Control.js';
|
export {default as Control} from './control/Control.js';
|
||||||
@@ -12,4 +16,59 @@ export {default as ScaleLine} from './control/ScaleLine.js';
|
|||||||
export {default as Zoom} from './control/Zoom.js';
|
export {default as Zoom} from './control/Zoom.js';
|
||||||
export {default as ZoomSlider} from './control/ZoomSlider.js';
|
export {default as ZoomSlider} from './control/ZoomSlider.js';
|
||||||
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
|
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
|
||||||
export {defaults} from './control/util.js';
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} DefaultsOptions
|
||||||
|
* @property {boolean} [attribution=true] Include
|
||||||
|
* {@link module:ol/control/Attribution~Attribution}.
|
||||||
|
* @property {import("./control/Attribution.js").Options} [attributionOptions]
|
||||||
|
* Options for {@link module:ol/control/Attribution~Attribution}.
|
||||||
|
* @property {boolean} [rotate=true] Include
|
||||||
|
* {@link module:ol/control/Rotate~Rotate}.
|
||||||
|
* @property {import("./control/Rotate.js").Options} [rotateOptions] Options
|
||||||
|
* for {@link module:ol/control/Rotate~Rotate}.
|
||||||
|
* @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.
|
||||||
|
* @property {import("./control/Zoom.js").Options} [zoomOptions] Options for
|
||||||
|
* {@link module:ol/control/Zoom~Zoom}.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of controls included in maps by default. Unless configured otherwise,
|
||||||
|
* this returns a collection containing an instance of each of the following
|
||||||
|
* controls:
|
||||||
|
* * {@link module:ol/control/Zoom~Zoom}
|
||||||
|
* * {@link module:ol/control/Rotate~Rotate}
|
||||||
|
* * {@link module:ol/control/Attribution~Attribution}
|
||||||
|
*
|
||||||
|
* @param {DefaultsOptions=} opt_options
|
||||||
|
* Defaults options.
|
||||||
|
* @return {Collection<import("./control/Control.js").default>}
|
||||||
|
* Controls.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
export function defaults(opt_options) {
|
||||||
|
|
||||||
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
const controls = new Collection();
|
||||||
|
|
||||||
|
const zoomControl = options.zoom !== undefined ? options.zoom : true;
|
||||||
|
if (zoomControl) {
|
||||||
|
controls.push(new Zoom(options.zoomOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotateControl = options.rotate !== undefined ? options.rotate : true;
|
||||||
|
if (rotateControl) {
|
||||||
|
controls.push(new Rotate(options.rotateOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributionControl = options.attribution !== undefined ?
|
||||||
|
options.attribution : true;
|
||||||
|
if (attributionControl) {
|
||||||
|
controls.push(new Attribution(options.attributionOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
return controls;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/control/OverviewMap
|
* @module ol/control/OverviewMap
|
||||||
*/
|
*/
|
||||||
import Collection from '../Collection.js';
|
import PluggableMap from '../PluggableMap.js';
|
||||||
import Map from '../Map.js';
|
import CompositeMapRenderer from '../renderer/Composite.js';
|
||||||
import MapEventType from '../MapEventType.js';
|
import MapEventType from '../MapEventType.js';
|
||||||
import MapProperty from '../MapProperty.js';
|
import MapProperty from '../MapProperty.js';
|
||||||
import {getChangeEventType} from '../Object.js';
|
import {getChangeEventType} from '../Object.js';
|
||||||
@@ -35,6 +35,13 @@ const MAX_RATIO = 0.75;
|
|||||||
const MIN_RATIO = 0.1;
|
const MIN_RATIO = 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
class ControlledMap extends PluggableMap {
|
||||||
|
createRenderer() {
|
||||||
|
return new CompositeMapRenderer(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {string} [className='ol-overviewmap'] CSS class name.
|
* @property {string} [className='ol-overviewmap'] CSS class name.
|
||||||
@@ -143,12 +150,10 @@ class OverviewMap extends Control {
|
|||||||
this.ovmapDiv_.className = 'ol-overviewmap-map';
|
this.ovmapDiv_.className = 'ol-overviewmap-map';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import("../Map.js").default}
|
* @type {ControlledMap}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.ovmap_ = new Map({
|
this.ovmap_ = new ControlledMap({
|
||||||
controls: new Collection(),
|
|
||||||
interactions: new Collection(),
|
|
||||||
view: options.view
|
view: options.view
|
||||||
});
|
});
|
||||||
const ovmap = this.ovmap_;
|
const ovmap = this.ovmap_;
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/control/util
|
|
||||||
*/
|
|
||||||
import Collection from '../Collection.js';
|
|
||||||
import Attribution from './Attribution.js';
|
|
||||||
import Rotate from './Rotate.js';
|
|
||||||
import Zoom from './Zoom.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} DefaultsOptions
|
|
||||||
* @property {boolean} [attribution=true] Include
|
|
||||||
* {@link module:ol/control/Attribution~Attribution}.
|
|
||||||
* @property {import("./Attribution.js").Options} [attributionOptions]
|
|
||||||
* Options for {@link module:ol/control/Attribution~Attribution}.
|
|
||||||
* @property {boolean} [rotate=true] Include
|
|
||||||
* {@link module:ol/control/Rotate~Rotate}.
|
|
||||||
* @property {import("./Rotate.js").Options} [rotateOptions] Options
|
|
||||||
* for {@link module:ol/control/Rotate~Rotate}.
|
|
||||||
* @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.
|
|
||||||
* @property {import("./Zoom.js").Options} [zoomOptions] Options for
|
|
||||||
* {@link module:ol/control/Zoom~Zoom}.
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set of controls included in maps by default. Unless configured otherwise,
|
|
||||||
* this returns a collection containing an instance of each of the following
|
|
||||||
* controls:
|
|
||||||
* * {@link module:ol/control/Zoom~Zoom}
|
|
||||||
* * {@link module:ol/control/Rotate~Rotate}
|
|
||||||
* * {@link module:ol/control/Attribution~Attribution}
|
|
||||||
*
|
|
||||||
* @param {DefaultsOptions=} opt_options
|
|
||||||
* Defaults options.
|
|
||||||
* @return {Collection<import("./Control.js").default>}
|
|
||||||
* Controls.
|
|
||||||
* @function module:ol/control.defaults
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
export function defaults(opt_options) {
|
|
||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
|
||||||
|
|
||||||
const controls = new Collection();
|
|
||||||
|
|
||||||
const zoomControl = options.zoom !== undefined ? options.zoom : true;
|
|
||||||
if (zoomControl) {
|
|
||||||
controls.push(new Zoom(options.zoomOptions));
|
|
||||||
}
|
|
||||||
|
|
||||||
const rotateControl = options.rotate !== undefined ? options.rotate : true;
|
|
||||||
if (rotateControl) {
|
|
||||||
controls.push(new Rotate(options.rotateOptions));
|
|
||||||
}
|
|
||||||
|
|
||||||
const attributionControl = options.attribution !== undefined ?
|
|
||||||
options.attribution : true;
|
|
||||||
if (attributionControl) {
|
|
||||||
controls.push(new Attribution(options.attributionOptions));
|
|
||||||
}
|
|
||||||
|
|
||||||
return controls;
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,13 @@ export default {
|
|||||||
*/
|
*/
|
||||||
CHANGE: 'change',
|
CHANGE: 'change',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic error event. Triggered when an error occurs.
|
||||||
|
* @event module:ol/events/Event~Event#error
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ERROR: 'error',
|
||||||
|
|
||||||
CLEAR: 'clear',
|
CLEAR: 'clear',
|
||||||
CONTEXTMENU: 'contextmenu',
|
CONTEXTMENU: 'contextmenu',
|
||||||
CLICK: 'click',
|
CLICK: 'click',
|
||||||
@@ -21,7 +28,6 @@ export default {
|
|||||||
DRAGENTER: 'dragenter',
|
DRAGENTER: 'dragenter',
|
||||||
DRAGOVER: 'dragover',
|
DRAGOVER: 'dragover',
|
||||||
DROP: 'drop',
|
DROP: 'drop',
|
||||||
ERROR: 'error',
|
|
||||||
KEYDOWN: 'keydown',
|
KEYDOWN: 'keydown',
|
||||||
KEYPRESS: 'keypress',
|
KEYPRESS: 'keypress',
|
||||||
LOAD: 'load',
|
LOAD: 'load',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export {default as GeoJSON} from './format/GeoJSON.js';
|
|||||||
export {default as GML} from './format/GML.js';
|
export {default as GML} from './format/GML.js';
|
||||||
export {default as GPX} from './format/GPX.js';
|
export {default as GPX} from './format/GPX.js';
|
||||||
export {default as IGC} from './format/IGC.js';
|
export {default as IGC} from './format/IGC.js';
|
||||||
|
export {default as IIIFInfo} from './format/IIIFInfo.js';
|
||||||
export {default as KML} from './format/KML.js';
|
export {default as KML} from './format/KML.js';
|
||||||
export {default as MVT} from './format/MVT.js';
|
export {default as MVT} from './format/MVT.js';
|
||||||
export {default as OWS} from './format/OWS.js';
|
export {default as OWS} from './format/OWS.js';
|
||||||
|
|||||||
431
src/ol/format/IIIFInfo.js
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
/**
|
||||||
|
* @module ol/format/IIIFInfo
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {assert} from '../asserts.js';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} PreferredOptions
|
||||||
|
* @property {string} [format] Preferred image format. Will be used if the image information
|
||||||
|
* indicates support for that format.
|
||||||
|
* @property {string} [quality] IIIF image qualitiy. Will be used if the image information
|
||||||
|
* indicates support for that quality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SupportedFeatures
|
||||||
|
* @property {Array<string>} [supports] Supported IIIF image size and region
|
||||||
|
* calculation features.
|
||||||
|
* @property {Array<string>} [formats] Supported image formats.
|
||||||
|
* @property {Array<string>} [qualities] Supported IIIF image qualities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ImageInformationResponse1_0
|
||||||
|
* @property {string} identifier
|
||||||
|
* @property {number} width
|
||||||
|
* @property {number} height
|
||||||
|
* @property {Array<number>} [scale_factors] Resolution scaling factors.
|
||||||
|
* @property {number} [tile_width]
|
||||||
|
* @property {number} [tile_height]
|
||||||
|
* @property {Array<string>} [formats] Supported image formats.
|
||||||
|
* @property {string} [profile] Compliance level URI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ImageInformationResponse1_1
|
||||||
|
* @property {string} "@id" The base URI of the image service.
|
||||||
|
* @property {string} "@context" JSON-LD context URI.
|
||||||
|
* @property {number} width Full image width.
|
||||||
|
* @property {number} height Full image height.
|
||||||
|
* @property {Array<number>} [scale_factors] Resolution scaling factors.
|
||||||
|
* @property {number} [tile_width]
|
||||||
|
* @property {number} [tile_height]
|
||||||
|
* @property {Array<string>} [formats] Supported image formats.
|
||||||
|
* @property {string} [profile] Compliance level URI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} TileInfo
|
||||||
|
* @property {Array<number>} scaleFactors Supported resolution scaling factors.
|
||||||
|
* @property {number} width Tile width in pixels.
|
||||||
|
* @property {number} [height] Tile height in pixels. Same as tile width if height is
|
||||||
|
* not given.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} IiifProfile
|
||||||
|
* @property {Array<string>} [formats] Supported image formats for the image service.
|
||||||
|
* @property {Array<string>} [qualities] Supported IIIF image qualities.
|
||||||
|
* @property {Array<string>} [supports] Supported features.
|
||||||
|
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
|
||||||
|
* @property {number} [maxHeight] Maximum height.
|
||||||
|
* @property {number} [maxWidth] Maximum width.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ImageInformationResponse2
|
||||||
|
* @property {string} "@id" The base URI of the image service.
|
||||||
|
* @property {string} "@context" JSON-LD context IRI
|
||||||
|
* @property {number} width Full image width.
|
||||||
|
* @property {number} height Full image height.
|
||||||
|
* @property {Array<string|IiifProfile>} profile Additional informations about the image
|
||||||
|
* service's capabilities.
|
||||||
|
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
|
||||||
|
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ImageInformationResponse3
|
||||||
|
* @property {string} id The base URI of the image service.
|
||||||
|
* @property {string} "@context" JSON-LD context IRI
|
||||||
|
* @property {number} width Full image width.
|
||||||
|
* @property {number} height Full image height.
|
||||||
|
* @property {string} profile Compliance level, one of 'level0', 'level1' or 'level2'
|
||||||
|
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
|
||||||
|
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
|
||||||
|
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
|
||||||
|
* @property {number} [maxHeight] Maximum height.
|
||||||
|
* @property {number} [maxWidth] Maximum width.
|
||||||
|
* @property {Array<string>} [extraQualities] IIIF image qualities supported by the
|
||||||
|
* image service additional to the ones indicated by the compliance level.
|
||||||
|
* @property {Array<string>} [extraFormats] Image formats supported by the
|
||||||
|
* image service additional to the ones indicated by the compliance level.
|
||||||
|
* @property {Array<string>} [extraFeatures] Additional supported features whose support
|
||||||
|
* is not indicated by the compliance level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing the major IIIF Image API versions
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
const Versions = {
|
||||||
|
VERSION1: 'version1',
|
||||||
|
VERSION2: 'version2',
|
||||||
|
VERSION3: 'version3'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported image formats, qualities and supported region / size calculation features
|
||||||
|
* for different image API versions and compliance levels
|
||||||
|
* @const
|
||||||
|
* @type {Object<string, Object<string, SupportedFeatures>>}
|
||||||
|
*/
|
||||||
|
const IIIF_PROFILE_VALUES = {};
|
||||||
|
IIIF_PROFILE_VALUES[Versions.VERSION1] = {
|
||||||
|
'level0': {
|
||||||
|
supports: [],
|
||||||
|
formats: [],
|
||||||
|
qualities: ['native']
|
||||||
|
},
|
||||||
|
'level1': {
|
||||||
|
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['native']
|
||||||
|
},
|
||||||
|
'level2': {
|
||||||
|
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
|
||||||
|
'sizeByConfinedWh', 'sizeByWh'],
|
||||||
|
formats: ['jpg', 'png'],
|
||||||
|
qualities: ['native', 'color', 'grey', 'bitonal']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
IIIF_PROFILE_VALUES[Versions.VERSION2] = {
|
||||||
|
'level0': {
|
||||||
|
supports: [],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['default']
|
||||||
|
},
|
||||||
|
'level1': {
|
||||||
|
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['default']
|
||||||
|
},
|
||||||
|
'level2': {
|
||||||
|
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
|
||||||
|
'sizeByConfinedWh', 'sizeByDistortedWh', 'sizeByWh'],
|
||||||
|
formats: ['jpg', 'png'],
|
||||||
|
qualities: ['default', 'bitonal']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
IIIF_PROFILE_VALUES[Versions.VERSION3] = {
|
||||||
|
'level0': {
|
||||||
|
supports: [],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['default']
|
||||||
|
},
|
||||||
|
'level1': {
|
||||||
|
supports: ['regionByPx', 'regionSquare', 'sizeByW', 'sizeByH'],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['default']
|
||||||
|
},
|
||||||
|
'level2': {
|
||||||
|
supports: ['regionByPx', 'regionSquare', 'regionByPct',
|
||||||
|
'sizeByW', 'sizeByH', 'sizeByPct', 'sizeByConfinedWh', 'sizeByWh'],
|
||||||
|
formats: ['jpg'],
|
||||||
|
qualities: ['default', 'bitonal']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
IIIF_PROFILE_VALUES['none'] = {
|
||||||
|
'none': {
|
||||||
|
supports: [],
|
||||||
|
formats: [],
|
||||||
|
qualities: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const COMPLIANCE_VERSION1 = new RegExp('^https?\:\/\/library\.stanford\.edu\/iiif\/image-api\/(1\.1\/)?compliance\.html#level[0-2]$');
|
||||||
|
const COMPLIANCE_VERSION2 = new RegExp('^https?\:\/\/iiif\.io\/api\/image\/2\/level[0-2](\.json)?$');
|
||||||
|
const COMPLIANCE_VERSION3 = new RegExp('(^https?\:\/\/iiif\.io\/api\/image\/3\/level[0-2](\.json)?$)|(^level[0-2]$)');
|
||||||
|
|
||||||
|
function generateVersion1Options(iiifInfo) {
|
||||||
|
let levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
|
||||||
|
// Version 1.0 and 1.1 do not require a profile.
|
||||||
|
if (levelProfile === undefined) {
|
||||||
|
levelProfile = IIIF_PROFILE_VALUES[Versions.VERSION1]['level0'];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url: iiifInfo.imageInfo['@id'] === undefined ? undefined : iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
|
||||||
|
supports: levelProfile.supports,
|
||||||
|
formats: [...levelProfile.formats, iiifInfo.imageInfo.formats === undefined ?
|
||||||
|
[] : iiifInfo.imageInfo.formats
|
||||||
|
],
|
||||||
|
qualities: [...levelProfile.qualities, iiifInfo.imageInfo.qualities === undefined ?
|
||||||
|
[] : iiifInfo.imageInfo.qualities
|
||||||
|
],
|
||||||
|
resolutions: iiifInfo.imageInfo.scale_factors,
|
||||||
|
tileSize: iiifInfo.imageInfo.tile_width !== undefined ? (iiifInfo.imageInfo.tile_height !== undefined ?
|
||||||
|
[iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_height] : [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_width]) :
|
||||||
|
(iiifInfo.imageInfo.tile_height != undefined ? [iiifInfo.imageInfo.tile_height, iiifInfo.imageInfo.tile_height] : undefined)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateVersion2Options(iiifInfo) {
|
||||||
|
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
|
||||||
|
additionalProfile = Array.isArray(iiifInfo.imageInfo.profile) && iiifInfo.imageInfo.profile.length > 1,
|
||||||
|
profileSupports = additionalProfile && iiifInfo.imageInfo.profile[1].supports ? iiifInfo.imageInfo.profile[1].supports : [],
|
||||||
|
profileFormats = additionalProfile && iiifInfo.imageInfo.profile[1].formats ? iiifInfo.imageInfo.profile[1].formats : [],
|
||||||
|
profileQualities = additionalProfile && iiifInfo.imageInfo.profile[1].qualities ? iiifInfo.imageInfo.profile[1].qualities : [];
|
||||||
|
return {
|
||||||
|
url: iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
|
||||||
|
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
|
||||||
|
return [size.width, size.height];
|
||||||
|
}),
|
||||||
|
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.width;
|
||||||
|
})[0],
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.height === undefined ? tile.width : tile.height;
|
||||||
|
})[0]
|
||||||
|
],
|
||||||
|
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.scaleFactors;
|
||||||
|
})[0],
|
||||||
|
supports: [...levelProfile.supports, ...profileSupports],
|
||||||
|
formats: [...levelProfile.formats, ...profileFormats],
|
||||||
|
qualities: [...levelProfile.qualities, ...profileQualities]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateVersion3Options(iiifInfo) {
|
||||||
|
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
|
||||||
|
return {
|
||||||
|
url: iiifInfo.imageInfo['id'],
|
||||||
|
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
|
||||||
|
return [size.width, size.height];
|
||||||
|
}),
|
||||||
|
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.width;
|
||||||
|
})[0],
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.height;
|
||||||
|
})[0]
|
||||||
|
],
|
||||||
|
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
|
||||||
|
iiifInfo.imageInfo.tiles.map(function(tile) {
|
||||||
|
return tile.scaleFactors;
|
||||||
|
})[0],
|
||||||
|
supports: iiifInfo.imageInfo.extraFeatures === undefined ? levelProfile.supports :
|
||||||
|
[...levelProfile.supports, ...iiifInfo.imageInfo.extraFeatures],
|
||||||
|
formats: iiifInfo.imageInfo.extraFormats === undefined ? levelProfile.formats :
|
||||||
|
[...levelProfile.formats, ...iiifInfo.imageInfo.extraFormats],
|
||||||
|
qualities: iiifInfo.imageInfo.extraQualities === undefined ? levelProfile.qualities :
|
||||||
|
[...levelProfile.supports, ...iiifInfo.imageInfo.extraQualities],
|
||||||
|
maxWidth: undefined,
|
||||||
|
maxHeight: undefined,
|
||||||
|
maxArea: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionFunctions = {};
|
||||||
|
versionFunctions[Versions.VERSION1] = generateVersion1Options;
|
||||||
|
versionFunctions[Versions.VERSION2] = generateVersion2Options;
|
||||||
|
versionFunctions[Versions.VERSION3] = generateVersion3Options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @classdesc
|
||||||
|
* Format for transforming IIIF Image API image information responses into
|
||||||
|
* IIIF tile source ready options
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
class IIIFInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
|
||||||
|
* Deserialized image information JSON response object or JSON response as string
|
||||||
|
*/
|
||||||
|
constructor(imageInfo) {
|
||||||
|
this.setImageInfo(imageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
|
||||||
|
* Deserialized image information JSON response object or JSON response as string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
setImageInfo(imageInfo) {
|
||||||
|
if (typeof imageInfo == 'string') {
|
||||||
|
this.imageInfo = JSON.parse(imageInfo);
|
||||||
|
} else {
|
||||||
|
this.imageInfo = imageInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Versions} Major IIIF version.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getImageApiVersion() {
|
||||||
|
if (this.imageInfo === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let context = this.imageInfo['@context'] || 'ol-no-context';
|
||||||
|
if (typeof context == 'string') {
|
||||||
|
context = [context];
|
||||||
|
}
|
||||||
|
for (let i = 0; i < context.length; i++) {
|
||||||
|
switch (context[i]) {
|
||||||
|
case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
|
||||||
|
case 'http://iiif.io/api/image/1/context.json':
|
||||||
|
return Versions.VERSION1;
|
||||||
|
case 'http://iiif.io/api/image/2/context.json':
|
||||||
|
return Versions.VERSION2;
|
||||||
|
case 'http://iiif.io/api/image/3/context.json':
|
||||||
|
return Versions.VERSION3;
|
||||||
|
case 'ol-no-context':
|
||||||
|
// Image API 1.0 has no '@context'
|
||||||
|
if (this.getComplianceLevelEntryFromProfile(Versions.VERSION1) && this.imageInfo.identifier) {
|
||||||
|
return Versions.VERSION1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false, 61);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Versions} version Optional IIIF image API version
|
||||||
|
* @returns {string} Compliance level as it appears in the IIIF image information
|
||||||
|
* response.
|
||||||
|
*/
|
||||||
|
getComplianceLevelEntryFromProfile(version) {
|
||||||
|
if (this.imageInfo === undefined || this.imageInfo.profile === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (version === undefined) {
|
||||||
|
version = this.getImageApiVersion();
|
||||||
|
}
|
||||||
|
switch (version) {
|
||||||
|
case Versions.VERSION1:
|
||||||
|
if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) {
|
||||||
|
return this.imageInfo.profile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Versions.VERSION3:
|
||||||
|
if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) {
|
||||||
|
return this.imageInfo.profile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Versions.VERSION2:
|
||||||
|
if (typeof this.imageInfo.profile === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile)) {
|
||||||
|
return this.imageInfo.profile;
|
||||||
|
}
|
||||||
|
if (Array.isArray(this.imageInfo.profile) && this.imageInfo.profile.length > 0
|
||||||
|
&& typeof this.imageInfo.profile[0] === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])) {
|
||||||
|
return this.imageInfo.profile[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Versions} version Optional IIIF image API version
|
||||||
|
* @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined
|
||||||
|
*/
|
||||||
|
getComplianceLevelFromProfile(version) {
|
||||||
|
const complianceLevel = this.getComplianceLevelEntryFromProfile(version);
|
||||||
|
if (complianceLevel === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const level = complianceLevel.match(/level[0-2](\.json)?$/g);
|
||||||
|
return Array.isArray(level) ? level[0].replace('.json', '') : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {SupportedFeatures} Image formats, qualities and region / size calculation
|
||||||
|
* methods that are supported by the IIIF service.
|
||||||
|
*/
|
||||||
|
getComplianceLevelSupportedFeatures() {
|
||||||
|
if (this.imageInfo === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const version = this.getImageApiVersion();
|
||||||
|
const level = this.getComplianceLevelFromProfile(version);
|
||||||
|
if (level === undefined) {
|
||||||
|
return IIIF_PROFILE_VALUES['none']['none'];
|
||||||
|
}
|
||||||
|
return IIIF_PROFILE_VALUES[version][level];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality.
|
||||||
|
* @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getTileSourceOptions(opt_preferredOptions) {
|
||||||
|
const options = opt_preferredOptions || {},
|
||||||
|
version = this.getImageApiVersion();
|
||||||
|
if (version === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const imageOptions = version === undefined ? undefined : versionFunctions[version](this);
|
||||||
|
if (imageOptions === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url: imageOptions.url,
|
||||||
|
version: version,
|
||||||
|
size: [this.imageInfo.width, this.imageInfo.height],
|
||||||
|
sizes: imageOptions.sizes,
|
||||||
|
format: imageOptions.formats.includes(options.format) ? options.format : 'jpg',
|
||||||
|
supports: imageOptions.supports,
|
||||||
|
quality: options.quality && imageOptions.qualities.includes(options.quality) ?
|
||||||
|
options.quality : imageOptions.qualities.includes('native') ? 'native' : 'default',
|
||||||
|
resolutions: Array.isArray(imageOptions.resolutions) ? imageOptions.resolutions.sort(function(a, b) {
|
||||||
|
return b - a;
|
||||||
|
}) : undefined,
|
||||||
|
tileSize: imageOptions.tileSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IIIFInfo;
|
||||||
|
export {Versions};
|
||||||
@@ -2684,13 +2684,6 @@ function writePlacemark(node, feature, objectStack) {
|
|||||||
return !filter[v];
|
return !filter[v];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (keys.length > 0) {
|
|
||||||
const sequence = makeSequence(properties, keys);
|
|
||||||
const namesAndValues = {names: keys, values: sequence};
|
|
||||||
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
|
||||||
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styleFunction = feature.getStyleFunction();
|
const styleFunction = feature.getStyleFunction();
|
||||||
if (styleFunction) {
|
if (styleFunction) {
|
||||||
// FIXME the styles returned by the style function are supposed to be
|
// FIXME the styles returned by the style function are supposed to be
|
||||||
@@ -2713,6 +2706,13 @@ function writePlacemark(node, feature, objectStack) {
|
|||||||
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
||||||
OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
|
OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
|
||||||
|
|
||||||
|
if (keys.length > 0) {
|
||||||
|
const sequence = makeSequence(properties, keys);
|
||||||
|
const namesAndValues = {names: keys, values: sequence};
|
||||||
|
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
||||||
|
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
|
||||||
|
}
|
||||||
|
|
||||||
// serialize geometry
|
// serialize geometry
|
||||||
const options = /** @type {import("./Feature.js").WriteOptions} */ (objectStack[0]);
|
const options = /** @type {import("./Feature.js").WriteOptions} */ (objectStack[0]);
|
||||||
let geometry = feature.getGeometry();
|
let geometry = feature.getGeometry();
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import {lerp} from '../../math.js';
|
|||||||
* @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width.
|
* @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width.
|
||||||
* @param {string} font The font.
|
* @param {string} font The font.
|
||||||
* @param {Object<string, number>} cache A cache of measured widths.
|
* @param {Object<string, number>} cache A cache of measured widths.
|
||||||
* @return {Array<Array<*>>} The result array of null if `maxAngle` was
|
* @return {Array<Array<*>>} The result array (or null if `maxAngle` was
|
||||||
* exceeded. Entries of the array are x, y, anchorX, angle, chunk.
|
* exceeded). Entries of the array are x, y, anchorX, angle, chunk.
|
||||||
*/
|
*/
|
||||||
export function drawTextOnPath(
|
export function drawTextOnPath(
|
||||||
flatCoordinates, offset, end, stride, text, startM, maxAngle, scale, measureAndCacheTextWidth, font, cache) {
|
flatCoordinates, offset, end, stride, text, startM, maxAngle, scale, measureAndCacheTextWidth, font, cache) {
|
||||||
@@ -35,16 +35,13 @@ export function drawTextOnPath(
|
|||||||
let y2 = flatCoordinates[offset + 1];
|
let y2 = flatCoordinates[offset + 1];
|
||||||
let segmentM = 0;
|
let segmentM = 0;
|
||||||
let segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
let segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||||
|
let angleChanged = false;
|
||||||
|
|
||||||
let chunk = '';
|
let index, previousAngle;
|
||||||
let chunkLength = 0;
|
|
||||||
let data, index, previousAngle;
|
|
||||||
for (let i = 0; i < numChars; ++i) {
|
for (let i = 0; i < numChars; ++i) {
|
||||||
index = reverse ? numChars - i - 1 : i;
|
index = reverse ? numChars - i - 1 : i;
|
||||||
const char = text.charAt(index);
|
const char = text[index];
|
||||||
chunk = reverse ? char + chunk : chunk + char;
|
const charLength = scale * measureAndCacheTextWidth(font, char, cache);
|
||||||
const charLength = scale * measureAndCacheTextWidth(font, chunk, cache) - chunkLength;
|
|
||||||
chunkLength += charLength;
|
|
||||||
const charM = startM + charLength / 2;
|
const charM = startM + charLength / 2;
|
||||||
while (offset < end - stride && segmentM + segmentLength < charM) {
|
while (offset < end - stride && segmentM + segmentLength < charM) {
|
||||||
x1 = x2;
|
x1 = x2;
|
||||||
@@ -62,33 +59,18 @@ export function drawTextOnPath(
|
|||||||
}
|
}
|
||||||
if (previousAngle !== undefined) {
|
if (previousAngle !== undefined) {
|
||||||
let delta = angle - previousAngle;
|
let delta = angle - previousAngle;
|
||||||
|
angleChanged = angleChanged || delta !== 0;
|
||||||
delta += (delta > Math.PI) ? -2 * Math.PI : (delta < -Math.PI) ? 2 * Math.PI : 0;
|
delta += (delta > Math.PI) ? -2 * Math.PI : (delta < -Math.PI) ? 2 * Math.PI : 0;
|
||||||
if (Math.abs(delta) > maxAngle) {
|
if (Math.abs(delta) > maxAngle) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
previousAngle = angle;
|
||||||
const interpolate = segmentPos / segmentLength;
|
const interpolate = segmentPos / segmentLength;
|
||||||
const x = lerp(x1, x2, interpolate);
|
const x = lerp(x1, x2, interpolate);
|
||||||
const y = lerp(y1, y2, interpolate);
|
const y = lerp(y1, y2, interpolate);
|
||||||
if (previousAngle == angle) {
|
result[index] = [x, y, charLength / 2, angle, char];
|
||||||
if (reverse) {
|
|
||||||
data[0] = x;
|
|
||||||
data[1] = y;
|
|
||||||
data[2] = charLength / 2;
|
|
||||||
}
|
|
||||||
data[4] = chunk;
|
|
||||||
} else {
|
|
||||||
chunk = char;
|
|
||||||
chunkLength = charLength;
|
|
||||||
data = [x, y, charLength / 2, angle, chunk];
|
|
||||||
if (reverse) {
|
|
||||||
result.unshift(data);
|
|
||||||
} else {
|
|
||||||
result.push(data);
|
|
||||||
}
|
|
||||||
previousAngle = angle;
|
|
||||||
}
|
|
||||||
startM += charLength;
|
startM += charLength;
|
||||||
}
|
}
|
||||||
return result;
|
return angleChanged ? result : [[result[0][0], result[0][1], result[0][2], result[0][3], text]];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,15 +40,6 @@ export const MAC = ua.indexOf('macintosh') !== -1;
|
|||||||
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
|
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is HTML5 geolocation supported in the current browser?
|
|
||||||
* @const
|
|
||||||
* @type {boolean}
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
export const GEOLOCATION = 'geolocation' in navigator;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if browser supports touch events.
|
* True if browser supports touch events.
|
||||||
* @const
|
* @const
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ class DragPan extends PointerInteraction {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
handleDragEvent(mapBrowserEvent) {
|
handleDragEvent(mapBrowserEvent) {
|
||||||
|
if (!this.panning_) {
|
||||||
|
this.panning_ = true;
|
||||||
|
this.getMap().getView().beginInteraction();
|
||||||
|
}
|
||||||
const targetPointers = this.targetPointers;
|
const targetPointers = this.targetPointers;
|
||||||
const centroid = centroidFromPointers(targetPointers);
|
const centroid = centroidFromPointers(targetPointers);
|
||||||
if (targetPointers.length == this.lastPointersCount_) {
|
if (targetPointers.length == this.lastPointersCount_) {
|
||||||
@@ -149,10 +153,6 @@ class DragPan extends PointerInteraction {
|
|||||||
if (view.getAnimating()) {
|
if (view.getAnimating()) {
|
||||||
view.cancelAnimations();
|
view.cancelAnimations();
|
||||||
}
|
}
|
||||||
if (!this.panning_) {
|
|
||||||
this.panning_ = true;
|
|
||||||
this.getMap().getView().beginInteraction();
|
|
||||||
}
|
|
||||||
if (this.kinetic_) {
|
if (this.kinetic_) {
|
||||||
this.kinetic_.begin();
|
this.kinetic_.begin();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import {createEditingStyle} from '../style/Style.js';
|
|||||||
const ExtentEventType = {
|
const ExtentEventType = {
|
||||||
/**
|
/**
|
||||||
* Triggered after the extent is changed
|
* Triggered after the extent is changed
|
||||||
* @event ExtentEventType#extentchanged
|
* @event ExtentEvent#extentchanged
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
EXTENTCHANGED: 'extentchanged'
|
EXTENTCHANGED: 'extentchanged'
|
||||||
@@ -47,10 +47,10 @@ const ExtentEventType = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
* Events emitted by {@link module:ol/interaction/Extent~ExtentInteraction} instances are
|
* Events emitted by {@link module:ol/interaction/Extent~Extent} instances are
|
||||||
* instances of this type.
|
* instances of this type.
|
||||||
*/
|
*/
|
||||||
class ExtentInteractionEvent extends Event {
|
class ExtentEvent extends Event {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../extent.js").Extent} extent the new extent
|
* @param {import("../extent.js").Extent} extent the new extent
|
||||||
@@ -75,10 +75,10 @@ class ExtentInteractionEvent extends Event {
|
|||||||
* Once drawn, the vector box can be modified by dragging its vertices or edges.
|
* Once drawn, the vector box can be modified by dragging its vertices or edges.
|
||||||
* This interaction is only supported for mouse devices.
|
* This interaction is only supported for mouse devices.
|
||||||
*
|
*
|
||||||
* @fires Event
|
* @fires ExtentEvent
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
class ExtentInteraction extends PointerInteraction {
|
class Extent extends PointerInteraction {
|
||||||
/**
|
/**
|
||||||
* @param {Options=} opt_options Options.
|
* @param {Options=} opt_options Options.
|
||||||
*/
|
*/
|
||||||
@@ -399,7 +399,7 @@ class ExtentInteraction extends PointerInteraction {
|
|||||||
//Null extent means no bbox
|
//Null extent means no bbox
|
||||||
this.extent_ = extent ? extent : null;
|
this.extent_ = extent ? extent : null;
|
||||||
this.createOrUpdateExtentFeature_(extent);
|
this.createOrUpdateExtentFeature_(extent);
|
||||||
this.dispatchEvent(new ExtentInteractionEvent(this.extent_));
|
this.dispatchEvent(new ExtentEvent(this.extent_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,4 +470,4 @@ function getSegments(extent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default ExtentInteraction;
|
export default Extent;
|
||||||
|
|||||||
@@ -83,19 +83,20 @@ class BaseLayer extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {boolean=} opt_managed Layer is managed.
|
||||||
* @return {import("./Layer.js").State} Layer state.
|
* @return {import("./Layer.js").State} Layer state.
|
||||||
*/
|
*/
|
||||||
getLayerState() {
|
getLayerState(opt_managed) {
|
||||||
/** @type {import("./Layer.js").State} */
|
/** @type {import("./Layer.js").State} */
|
||||||
const state = this.state_ || /** @type {?} */ ({
|
const state = this.state_ || /** @type {?} */ ({
|
||||||
layer: this,
|
layer: this,
|
||||||
managed: true
|
managed: opt_managed === undefined ? true : opt_managed
|
||||||
});
|
});
|
||||||
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
||||||
state.sourceState = this.getSourceState();
|
state.sourceState = this.getSourceState();
|
||||||
state.visible = this.getVisible();
|
state.visible = this.getVisible();
|
||||||
state.extent = this.getExtent();
|
state.extent = this.getExtent();
|
||||||
state.zIndex = this.getZIndex() || 0;
|
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
|
||||||
state.maxResolution = this.getMaxResolution();
|
state.maxResolution = this.getMaxResolution();
|
||||||
state.minResolution = Math.max(this.getMinResolution(), 0);
|
state.minResolution = Math.max(this.getMinResolution(), 0);
|
||||||
this.state_ = state;
|
this.state_ = state;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {assign} from '../obj.js';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
|
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
|
||||||
* @property {number} [opacity=1] Opacity (0, 1).
|
* @property {number} [opacity=1] Opacity (0, 1).
|
||||||
* @property {boolean} [visible=true] Visibility.
|
* @property {boolean} [visible=true] Visibility.
|
||||||
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be
|
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
|
|||||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||||
* use {@link module:ol/Map#addLayer}.
|
* use {@link module:ol/Map#addLayer}.
|
||||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
||||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
|
||||||
* means higher priority.
|
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
|
||||||
|
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
|
||||||
|
* higher priority.
|
||||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import {assign} from '../obj.js';
|
|||||||
import RenderEventType from '../render/EventType.js';
|
import RenderEventType from '../render/EventType.js';
|
||||||
import SourceState from '../source/State.js';
|
import SourceState from '../source/State.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
@@ -29,6 +33,8 @@ import SourceState from '../source/State.js';
|
|||||||
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
|
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
|
||||||
* construction.
|
* construction.
|
||||||
* @property {import("../PluggableMap.js").default} [map] Map.
|
* @property {import("../PluggableMap.js").default} [map] Map.
|
||||||
|
* @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an
|
||||||
|
* HTML element. Will overwrite the default rendering for the layer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -47,8 +53,10 @@ import SourceState from '../source/State.js';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
* Abstract base class; normally only used for creating subclasses and not
|
* Base class from which all layer types are derived. This should only be instantiated
|
||||||
* instantiated in apps.
|
* in the case where a custom layer is be added to the map with a custom `render` function.
|
||||||
|
* Such a function can be specified in the `options` object, and is expected to return an HTML element.
|
||||||
|
*
|
||||||
* A visual representation of raster or vector map data.
|
* A visual representation of raster or vector map data.
|
||||||
* Layers group together those properties that pertain to how the data is to be
|
* Layers group together those properties that pertain to how the data is to be
|
||||||
* displayed, irrespective of the source of that data.
|
* displayed, irrespective of the source of that data.
|
||||||
@@ -64,6 +72,7 @@ import SourceState from '../source/State.js';
|
|||||||
* @fires import("../render/Event.js").RenderEvent#postrender
|
* @fires import("../render/Event.js").RenderEvent#postrender
|
||||||
*
|
*
|
||||||
* @template {import("../source/Source.js").default} SourceType
|
* @template {import("../source/Source.js").default} SourceType
|
||||||
|
* @api
|
||||||
*/
|
*/
|
||||||
class Layer extends BaseLayer {
|
class Layer extends BaseLayer {
|
||||||
/**
|
/**
|
||||||
@@ -100,6 +109,11 @@ class Layer extends BaseLayer {
|
|||||||
*/
|
*/
|
||||||
this.renderer_ = null;
|
this.renderer_ = null;
|
||||||
|
|
||||||
|
// Overwrite default render method with a custom one
|
||||||
|
if (options.render) {
|
||||||
|
this.render = options.render;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.map) {
|
if (options.map) {
|
||||||
this.setMap(options.map);
|
this.setMap(options.map);
|
||||||
}
|
}
|
||||||
@@ -212,12 +226,7 @@ class Layer extends BaseLayer {
|
|||||||
if (map) {
|
if (map) {
|
||||||
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
|
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
|
||||||
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
|
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
|
||||||
const layerState = this.getLayerState();
|
renderEvent.frameState.layerStatesArray.push(this.getLayerState(false));
|
||||||
layerState.managed = false;
|
|
||||||
if (this.getZIndex() === undefined) {
|
|
||||||
layerState.zIndex = Infinity;
|
|
||||||
}
|
|
||||||
renderEvent.frameState.layerStatesArray.push(layerState);
|
|
||||||
}, this);
|
}, this);
|
||||||
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
|
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
|
||||||
this.changed();
|
this.changed();
|
||||||
@@ -245,6 +254,13 @@ class Layer extends BaseLayer {
|
|||||||
return this.renderer_;
|
return this.renderer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} The layer has a renderer.
|
||||||
|
*/
|
||||||
|
hasRenderer() {
|
||||||
|
return !!this.renderer_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a renderer for this layer.
|
* Create a renderer for this layer.
|
||||||
* @return {import("../renderer/Layer.js").default} A layer renderer.
|
* @return {import("../renderer/Layer.js").default} A layer renderer.
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
|
|||||||
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
|
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
|
||||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||||
* use {@link module:ol/Map#addLayer}.
|
* use {@link module:ol/Map#addLayer}.
|
||||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
* @property {boolean} [declutter=false] Declutter images and text on this layer. The priority is defined
|
||||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
* by the `zIndex` of the style and the render order of features. Higher z-index means higher priority.
|
||||||
* means higher priority.
|
* Within the same z-index, a feature rendered before another has higher priority.
|
||||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ import {assign} from '../obj.js';
|
|||||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||||
* use {@link module:ol/Map#addLayer}.
|
* use {@link module:ol/Map#addLayer}.
|
||||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
||||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
|
||||||
* means higher priority.
|
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
|
||||||
|
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
|
||||||
|
* higher priority.
|
||||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be
|
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/math
|
* @module ol/math
|
||||||
*/
|
*/
|
||||||
import {assert} from './asserts.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a number and clamps it to within the provided bounds.
|
* Takes a number and clamps it to within the provided bounds.
|
||||||
@@ -43,16 +42,6 @@ export const cosh = (function() {
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} x X.
|
|
||||||
* @return {number} The smallest power of two greater than or equal to x.
|
|
||||||
*/
|
|
||||||
export function roundUpToPowerOfTwo(x) {
|
|
||||||
assert(0 < x, 29); // `x` must be greater than `0`
|
|
||||||
return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the square of the closest distance between the point (x, y) and the
|
* Returns the square of the closest distance between the point (x, y) and the
|
||||||
* line segment (x1, y1) to (x2, y2).
|
* line segment (x1, y1) to (x2, y2).
|
||||||
|
|||||||
@@ -127,11 +127,6 @@
|
|||||||
right: .5em;
|
right: .5em;
|
||||||
top: .5em;
|
top: .5em;
|
||||||
}
|
}
|
||||||
@media print {
|
|
||||||
.ol-control {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ol-control button {
|
.ol-control button {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -110,3 +110,23 @@ export function getRenderPixel(event, pixel) {
|
|||||||
applyTransform(event.inversePixelTransform.slice(), result);
|
applyTransform(event.inversePixelTransform.slice(), result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("./PluggableMap.js").FrameState} frameState Frame state.
|
||||||
|
* @param {?} declutterTree Declutter tree.
|
||||||
|
* @returns {?} Declutter tree.
|
||||||
|
*/
|
||||||
|
export function renderDeclutterItems(frameState, declutterTree) {
|
||||||
|
if (declutterTree) {
|
||||||
|
declutterTree.clear();
|
||||||
|
}
|
||||||
|
const items = frameState.declutterItems;
|
||||||
|
for (let z = items.length - 1; z >= 0; --z) {
|
||||||
|
const zIndexItems = items[z];
|
||||||
|
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
|
||||||
|
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.length = 0;
|
||||||
|
return declutterTree;
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import {createCanvasContext2D} from '../../dom.js';
|
import {createCanvasContext2D} from '../../dom.js';
|
||||||
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||||
import Disposable from '../../Disposable.js';
|
import Disposable from '../../Disposable.js';
|
||||||
|
import RBush from 'rbush';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,15 +59,10 @@ class Executor extends Disposable {
|
|||||||
* @param {number} resolution Resolution.
|
* @param {number} resolution Resolution.
|
||||||
* @param {number} pixelRatio Pixel ratio.
|
* @param {number} pixelRatio Pixel ratio.
|
||||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||||
* @param {?} declutterTree Declutter tree.
|
|
||||||
* @param {SerializableInstructions} instructions The serializable instructions
|
* @param {SerializableInstructions} instructions The serializable instructions
|
||||||
*/
|
*/
|
||||||
constructor(resolution, pixelRatio, overlaps, declutterTree, instructions) {
|
constructor(resolution, pixelRatio, overlaps, instructions) {
|
||||||
super();
|
super();
|
||||||
/**
|
|
||||||
* @type {?}
|
|
||||||
*/
|
|
||||||
this.declutterTree = declutterTree;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
@@ -93,6 +89,11 @@ class Executor extends Disposable {
|
|||||||
*/
|
*/
|
||||||
this.alignFill_;
|
this.alignFill_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<*>}
|
||||||
|
*/
|
||||||
|
this.declutterItems = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
* @type {Array<*>}
|
* @type {Array<*>}
|
||||||
@@ -192,9 +193,10 @@ class Executor extends Disposable {
|
|||||||
const width = measureTextWidths(textState.font, lines, widths);
|
const width = measureTextWidths(textState.font, lines, widths);
|
||||||
const lineHeight = measureTextHeight(textState.font);
|
const lineHeight = measureTextHeight(textState.font);
|
||||||
const height = lineHeight * numLines;
|
const height = lineHeight * numLines;
|
||||||
const renderWidth = (width + strokeWidth);
|
const renderWidth = width + strokeWidth;
|
||||||
const context = createCanvasContext2D(
|
const context = createCanvasContext2D(
|
||||||
Math.ceil(renderWidth * scale),
|
// make canvas 2 pixels wider to account for italic text width measurement errors
|
||||||
|
Math.ceil((renderWidth + 2) * scale),
|
||||||
Math.ceil((height + strokeWidth) * scale));
|
Math.ceil((height + strokeWidth) * scale));
|
||||||
label = context.canvas;
|
label = context.canvas;
|
||||||
labelCache.set(key, label);
|
labelCache.set(key, label);
|
||||||
@@ -219,7 +221,7 @@ class Executor extends Disposable {
|
|||||||
context.textBaseline = 'middle';
|
context.textBaseline = 'middle';
|
||||||
context.textAlign = 'center';
|
context.textAlign = 'center';
|
||||||
const leftRight = (0.5 - align);
|
const leftRight = (0.5 - align);
|
||||||
const x = align * label.width / scale + leftRight * strokeWidth;
|
const x = align * renderWidth + leftRight * strokeWidth;
|
||||||
let i;
|
let i;
|
||||||
if (strokeKey) {
|
if (strokeKey) {
|
||||||
for (i = 0; i < numLines; ++i) {
|
for (i = 0; i < numLines; ++i) {
|
||||||
@@ -412,8 +414,10 @@ class Executor extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
||||||
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
||||||
|
* @param {?} declutterTree Declutter tree.
|
||||||
|
* @return {?} Declutter tree.
|
||||||
*/
|
*/
|
||||||
renderDeclutter_(declutterGroup, feature) {
|
renderDeclutter(declutterGroup, feature, declutterTree) {
|
||||||
if (declutterGroup && declutterGroup.length > 5) {
|
if (declutterGroup && declutterGroup.length > 5) {
|
||||||
const groupCount = declutterGroup[4];
|
const groupCount = declutterGroup[4];
|
||||||
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
|
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
|
||||||
@@ -425,8 +429,11 @@ class Executor extends Disposable {
|
|||||||
maxY: /** @type {number} */ (declutterGroup[3]),
|
maxY: /** @type {number} */ (declutterGroup[3]),
|
||||||
value: feature
|
value: feature
|
||||||
};
|
};
|
||||||
if (!this.declutterTree.collides(box)) {
|
if (!declutterTree) {
|
||||||
this.declutterTree.insert(box);
|
declutterTree = new RBush(9);
|
||||||
|
}
|
||||||
|
if (!declutterTree.collides(box)) {
|
||||||
|
declutterTree.insert(box);
|
||||||
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
|
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
|
||||||
const declutterData = /** @type {Array} */ (declutterGroup[j]);
|
const declutterData = /** @type {Array} */ (declutterGroup[j]);
|
||||||
if (declutterData) {
|
if (declutterData) {
|
||||||
@@ -443,6 +450,7 @@ class Executor extends Disposable {
|
|||||||
createOrUpdateEmpty(declutterGroup);
|
createOrUpdateEmpty(declutterGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return declutterTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -464,7 +472,9 @@ class Executor extends Disposable {
|
|||||||
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
|
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
|
||||||
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
|
|
||||||
const anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
// Remove the 2 pixels we added in getTextImage() for the anchor
|
||||||
|
const width = label.width / pixelRatio - 2 * textState.scale;
|
||||||
|
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
|
||||||
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -497,6 +507,7 @@ class Executor extends Disposable {
|
|||||||
featureCallback,
|
featureCallback,
|
||||||
opt_hitExtent
|
opt_hitExtent
|
||||||
) {
|
) {
|
||||||
|
this.declutterItems.length = 0;
|
||||||
/** @type {Array<number>} */
|
/** @type {Array<number>} */
|
||||||
let pixelCoordinates;
|
let pixelCoordinates;
|
||||||
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
|
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
|
||||||
@@ -670,7 +681,7 @@ class Executor extends Disposable {
|
|||||||
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
|
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
|
||||||
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
|
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
|
||||||
}
|
}
|
||||||
this.renderDeclutter_(declutterGroup, feature);
|
this.declutterItems.push(this, declutterGroup, feature);
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
case CanvasInstruction.DRAW_CHARS:
|
case CanvasInstruction.DRAW_CHARS:
|
||||||
@@ -739,7 +750,7 @@ class Executor extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.renderDeclutter_(declutterGroup, feature);
|
this.declutterItems.push(this, declutterGroup, feature);
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
case CanvasInstruction.END_GEOMETRY:
|
case CanvasInstruction.END_GEOMETRY:
|
||||||
|
|||||||
@@ -35,18 +35,12 @@ class ExecutorGroup extends Disposable {
|
|||||||
* @param {number} resolution Resolution.
|
* @param {number} resolution Resolution.
|
||||||
* @param {number} pixelRatio Pixel ratio.
|
* @param {number} pixelRatio Pixel ratio.
|
||||||
* @param {boolean} overlaps The executor group can have overlapping geometries.
|
* @param {boolean} overlaps The executor group can have overlapping geometries.
|
||||||
* @param {?} declutterTree Declutter tree for declutter processing in postrender.
|
|
||||||
* @param {!Object<string, !Object<BuilderType, import("./Builder.js").SerializableInstructions>>} allInstructions
|
* @param {!Object<string, !Object<BuilderType, import("./Builder.js").SerializableInstructions>>} allInstructions
|
||||||
* The serializable instructions.
|
* The serializable instructions.
|
||||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||||
*/
|
*/
|
||||||
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, allInstructions, opt_renderBuffer) {
|
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
|
||||||
super();
|
super();
|
||||||
/**
|
|
||||||
* Declutter tree.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.declutterTree_ = declutterTree;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -88,7 +82,7 @@ class ExecutorGroup extends Disposable {
|
|||||||
* @private
|
* @private
|
||||||
* @type {CanvasRenderingContext2D}
|
* @type {CanvasRenderingContext2D}
|
||||||
*/
|
*/
|
||||||
this.hitDetectionContext_ = createCanvasContext2D(1, 1);
|
this.hitDetectionContext_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -128,7 +122,7 @@ class ExecutorGroup extends Disposable {
|
|||||||
for (const builderType in instructionByZindex) {
|
for (const builderType in instructionByZindex) {
|
||||||
const instructions = instructionByZindex[builderType];
|
const instructions = instructionByZindex[builderType];
|
||||||
executors[builderType] = new Executor(
|
executors[builderType] = new Executor(
|
||||||
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_, instructions);
|
this.resolution_, this.pixelRatio_, this.overlaps_, instructions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,8 +137,11 @@ class ExecutorGroup extends Disposable {
|
|||||||
executors[key].disposeInternal();
|
executors[key].disposeInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.hitDetectionContext_) {
|
||||||
const canvas = this.hitDetectionContext_.canvas;
|
const canvas = this.hitDetectionContext_.canvas;
|
||||||
canvas.width = canvas.height = 0;
|
canvas.width = canvas.height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +169,7 @@ class ExecutorGroup extends Disposable {
|
|||||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||||
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
|
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
|
||||||
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
|
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
|
||||||
* @param {Object<string, import("../canvas.js").DeclutterGroup>} declutterReplays Declutter replays.
|
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
|
||||||
* @return {T|undefined} Callback result.
|
* @return {T|undefined} Callback result.
|
||||||
* @template T
|
* @template T
|
||||||
*/
|
*/
|
||||||
@@ -183,7 +180,7 @@ class ExecutorGroup extends Disposable {
|
|||||||
hitTolerance,
|
hitTolerance,
|
||||||
skippedFeaturesHash,
|
skippedFeaturesHash,
|
||||||
callback,
|
callback,
|
||||||
declutterReplays
|
declutteredFeatures
|
||||||
) {
|
) {
|
||||||
|
|
||||||
hitTolerance = Math.round(hitTolerance);
|
hitTolerance = Math.round(hitTolerance);
|
||||||
@@ -193,6 +190,10 @@ class ExecutorGroup extends Disposable {
|
|||||||
1 / resolution, -1 / resolution,
|
1 / resolution, -1 / resolution,
|
||||||
-rotation,
|
-rotation,
|
||||||
-coordinate[0], -coordinate[1]);
|
-coordinate[0], -coordinate[1]);
|
||||||
|
|
||||||
|
if (!this.hitDetectionContext_) {
|
||||||
|
this.hitDetectionContext_ = createCanvasContext2D(contextSize, contextSize);
|
||||||
|
}
|
||||||
const context = this.hitDetectionContext_;
|
const context = this.hitDetectionContext_;
|
||||||
|
|
||||||
if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
|
if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
|
||||||
@@ -213,12 +214,6 @@ class ExecutorGroup extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mask = getCircleArray(hitTolerance);
|
const mask = getCircleArray(hitTolerance);
|
||||||
let declutteredFeatures;
|
|
||||||
if (this.declutterTree_) {
|
|
||||||
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
|
|
||||||
return entry.value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let builderType;
|
let builderType;
|
||||||
|
|
||||||
@@ -261,15 +256,6 @@ class ExecutorGroup extends Disposable {
|
|||||||
builderType = ORDER[j];
|
builderType = ORDER[j];
|
||||||
executor = executors[builderType];
|
executor = executors[builderType];
|
||||||
if (executor !== undefined) {
|
if (executor !== undefined) {
|
||||||
if (declutterReplays &&
|
|
||||||
(builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) {
|
|
||||||
const declutter = declutterReplays[zIndexKey];
|
|
||||||
if (!declutter) {
|
|
||||||
declutterReplays[zIndexKey] = [executor, transform.slice(0)];
|
|
||||||
} else {
|
|
||||||
declutter.push(executor, transform.slice(0));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = executor.executeHitDetection(context, transform, rotation,
|
result = executor.executeHitDetection(context, transform, rotation,
|
||||||
skippedFeaturesHash, featureCallback, hitExtent);
|
skippedFeaturesHash, featureCallback, hitExtent);
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -278,7 +264,6 @@ class ExecutorGroup extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,14 +431,20 @@ export function getCircleArray(radius) {
|
|||||||
* @param {CanvasRenderingContext2D} context Context.
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
* @param {number} rotation Rotation.
|
* @param {number} rotation Rotation.
|
||||||
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
|
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
|
||||||
|
* @param {Array<Array<*>>} declutterItems Declutter items.
|
||||||
*/
|
*/
|
||||||
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel) {
|
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) {
|
||||||
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
|
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
|
||||||
const skippedFeatureUids = {};
|
const skippedFeatureUids = {};
|
||||||
for (let z = 0, zz = zs.length; z < zz; ++z) {
|
for (let z = 0, zz = zs.length; z < zz; ++z) {
|
||||||
const executorData = declutterReplays[zs[z].toString()];
|
const executorData = declutterReplays[zs[z].toString()];
|
||||||
|
let currentExecutor;
|
||||||
for (let i = 0, ii = executorData.length; i < ii;) {
|
for (let i = 0, ii = executorData.length; i < ii;) {
|
||||||
const executor = executorData[i++];
|
const executor = executorData[i++];
|
||||||
|
if (executor !== currentExecutor) {
|
||||||
|
currentExecutor = executor;
|
||||||
|
declutterItems.push(executor.declutterItems);
|
||||||
|
}
|
||||||
const transform = executorData[i++];
|
const transform = executorData[i++];
|
||||||
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import RenderEventType from '../render/EventType.js';
|
|||||||
import MapRenderer from './Map.js';
|
import MapRenderer from './Map.js';
|
||||||
import SourceState from '../source/State.js';
|
import SourceState from '../source/State.js';
|
||||||
import {replaceChildren} from '../dom.js';
|
import {replaceChildren} from '../dom.js';
|
||||||
|
import {labelCache} from '../render/canvas.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,6 +23,7 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
*/
|
*/
|
||||||
constructor(map) {
|
constructor(map) {
|
||||||
super(map);
|
super(map);
|
||||||
|
map.attachLabelCache(labelCache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -85,7 +87,8 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
this.children_.length = 0;
|
this.children_.length = 0;
|
||||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||||
const layerState = layerStatesArray[i];
|
const layerState = layerStatesArray[i];
|
||||||
if (!visibleAtResolution(layerState, viewResolution) || layerState.sourceState != SourceState.READY) {
|
if (!visibleAtResolution(layerState, viewResolution) ||
|
||||||
|
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,11 +97,12 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
if (element) {
|
if (element) {
|
||||||
const zIndex = layerState.zIndex;
|
const zIndex = layerState.zIndex;
|
||||||
if (zIndex !== element.style.zIndex) {
|
if (zIndex !== element.style.zIndex) {
|
||||||
element.style.zIndex = zIndex;
|
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex;
|
||||||
}
|
}
|
||||||
this.children_.push(element);
|
this.children_.push(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
super.renderFrame(frameState);
|
||||||
|
|
||||||
replaceChildren(this.element_, this.children_);
|
replaceChildren(this.element_, this.children_);
|
||||||
|
|
||||||
@@ -109,7 +113,6 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
this.renderedVisible_ = true;
|
this.renderedVisible_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scheduleRemoveUnusedLayerRenderers(frameState);
|
|
||||||
this.scheduleExpireIconCache(frameState);
|
this.scheduleExpireIconCache(frameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,11 +129,8 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
for (let i = numLayers - 1; i >= 0; --i) {
|
for (let i = numLayers - 1; i >= 0; --i) {
|
||||||
const layerState = layerStates[i];
|
const layerState = layerStates[i];
|
||||||
const layer = layerState.layer;
|
const layer = layerState.layer;
|
||||||
if (visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
|
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
|
||||||
const layerRenderer = this.getLayerRenderer(layer);
|
const layerRenderer = layer.getRenderer();
|
||||||
if (!layerRenderer) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const data = layerRenderer.getDataAtPixel(pixel, frameState, hitTolerance);
|
const data = layerRenderer.getDataAtPixel(pixel, frameState, hitTolerance);
|
||||||
if (data) {
|
if (data) {
|
||||||
const result = callback(layer, data);
|
const result = callback(layer, data);
|
||||||
|
|||||||
@@ -89,10 +89,11 @@ class LayerRenderer extends Observable {
|
|||||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||||
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
|
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
|
||||||
|
* @param {Array<import("../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
|
||||||
* @return {T|void} Callback result.
|
* @return {T|void} Callback result.
|
||||||
* @template T
|
* @template T
|
||||||
*/
|
*/
|
||||||
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {}
|
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -114,6 +115,12 @@ class LayerRenderer extends Observable {
|
|||||||
return this.layer_;
|
return this.layer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform action necessary to get the layer rendered after new fonts have loaded
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
handleFontsChanged() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle changes in image state.
|
* Handle changes in image state.
|
||||||
* @param {import("../events/Event.js").default} event Image change event.
|
* @param {import("../events/Event.js").default} event Image change event.
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
import {abstract, getUid} from '../util.js';
|
import {abstract, getUid} from '../util.js';
|
||||||
import Disposable from '../Disposable.js';
|
import Disposable from '../Disposable.js';
|
||||||
import {listen, unlistenByKey} from '../events.js';
|
|
||||||
import EventType from '../events/EventType.js';
|
|
||||||
import {getWidth} from '../extent.js';
|
import {getWidth} from '../extent.js';
|
||||||
import {TRUE} from '../functions.js';
|
import {TRUE} from '../functions.js';
|
||||||
import {visibleAtResolution} from '../layer/Layer.js';
|
import {visibleAtResolution} from '../layer/Layer.js';
|
||||||
import {shared as iconImageCache} from '../style/IconImageCache.js';
|
import {shared as iconImageCache} from '../style/IconImageCache.js';
|
||||||
import {compose as composeTransform, makeInverse} from '../transform.js';
|
import {compose as composeTransform, makeInverse} from '../transform.js';
|
||||||
|
import {renderDeclutterItems} from '../render.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -30,15 +29,8 @@ class MapRenderer extends Disposable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {!Object<string, import("./Layer.js").default>}
|
|
||||||
*/
|
*/
|
||||||
this.layerRenderers_ = {};
|
this.declutterTree_ = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {Object<string, import("../events.js").EventsKey>}
|
|
||||||
*/
|
|
||||||
this.layerRendererListeners_ = {};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,15 +61,6 @@ class MapRenderer extends Disposable {
|
|||||||
makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform);
|
makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all layer renderers.
|
|
||||||
*/
|
|
||||||
removeLayerRenderers() {
|
|
||||||
for (const key in this.layerRenderers_) {
|
|
||||||
this.removeLayerRendererByKey_(key).dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||||
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
||||||
@@ -133,18 +116,24 @@ class MapRenderer extends Disposable {
|
|||||||
|
|
||||||
const layerStates = frameState.layerStatesArray;
|
const layerStates = frameState.layerStatesArray;
|
||||||
const numLayers = layerStates.length;
|
const numLayers = layerStates.length;
|
||||||
|
let declutteredFeatures;
|
||||||
|
if (this.declutterTree_) {
|
||||||
|
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
|
||||||
|
return entry.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
let i;
|
let i;
|
||||||
for (i = numLayers - 1; i >= 0; --i) {
|
for (i = numLayers - 1; i >= 0; --i) {
|
||||||
const layerState = layerStates[i];
|
const layerState = layerStates[i];
|
||||||
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
|
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
|
||||||
if (visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
|
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
|
||||||
const layerRenderer = this.getLayerRenderer(layer);
|
const layerRenderer = layer.getRenderer();
|
||||||
const source = layer.getSource();
|
const source = layer.getSource();
|
||||||
if (layerRenderer && source) {
|
if (layerRenderer && source) {
|
||||||
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
||||||
result = layerRenderer.forEachFeatureAtCoordinate(
|
result = layerRenderer.forEachFeatureAtCoordinate(
|
||||||
source.getWrapX() ? translatedCoordinate : coordinate,
|
source.getWrapX() ? translatedCoordinate : coordinate,
|
||||||
frameState, hitTolerance, callback);
|
frameState, hitTolerance, callback, declutteredFeatures);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
@@ -191,35 +180,6 @@ class MapRenderer extends Disposable {
|
|||||||
return hasFeature !== undefined;
|
return hasFeature !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../layer/Layer.js").default} layer Layer.
|
|
||||||
* @protected
|
|
||||||
* @return {import("./Layer.js").default} Layer renderer. May return null.
|
|
||||||
*/
|
|
||||||
getLayerRenderer(layer) {
|
|
||||||
const layerKey = getUid(layer);
|
|
||||||
if (layerKey in this.layerRenderers_) {
|
|
||||||
return this.layerRenderers_[layerKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderer = layer.getRenderer();
|
|
||||||
if (!renderer) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.layerRenderers_[layerKey] = renderer;
|
|
||||||
this.layerRendererListeners_[layerKey] = listen(renderer, EventType.CHANGE, this.handleLayerRendererChange_, this);
|
|
||||||
return renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @protected
|
|
||||||
* @return {Object<string, import("./Layer.js").default>} Layer renderers.
|
|
||||||
*/
|
|
||||||
getLayerRenderers() {
|
|
||||||
return this.layerRenderers_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {import("../PluggableMap.js").default} Map.
|
* @return {import("../PluggableMap.js").default} Map.
|
||||||
*/
|
*/
|
||||||
@@ -227,36 +187,12 @@ class MapRenderer extends Disposable {
|
|||||||
return this.map_;
|
return this.map_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle changes in a layer renderer.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
handleLayerRendererChange_() {
|
|
||||||
this.map_.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} layerKey Layer key.
|
|
||||||
* @return {import("./Layer.js").default} Layer renderer.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
removeLayerRendererByKey_(layerKey) {
|
|
||||||
const layerRenderer = this.layerRenderers_[layerKey];
|
|
||||||
delete this.layerRenderers_[layerKey];
|
|
||||||
|
|
||||||
unlistenByKey(this.layerRendererListeners_[layerKey]);
|
|
||||||
delete this.layerRendererListeners_[layerKey];
|
|
||||||
|
|
||||||
return layerRenderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render.
|
* Render.
|
||||||
* @abstract
|
|
||||||
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
|
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||||
*/
|
*/
|
||||||
renderFrame(frameState) {
|
renderFrame(frameState) {
|
||||||
abstract();
|
this.declutterTree_ = renderDeclutterItems(frameState, this.declutterTree_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,21 +204,6 @@ class MapRenderer extends Disposable {
|
|||||||
frameState.postRenderFunctions.push(expireIconCache);
|
frameState.postRenderFunctions.push(expireIconCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!import("../PluggableMap.js").FrameState} frameState Frame state.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
scheduleRemoveUnusedLayerRenderers(frameState) {
|
|
||||||
const layerStatesMap = getLayerStatesMap(frameState.layerStatesArray);
|
|
||||||
for (const layerKey in this.layerRenderers_) {
|
|
||||||
if (!(layerKey in layerStatesMap)) {
|
|
||||||
frameState.postRenderFunctions.push(function() {
|
|
||||||
this.removeLayerRendererByKey_(layerKey).dispose();
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -294,15 +215,4 @@ function expireIconCache(map, frameState) {
|
|||||||
iconImageCache.expire();
|
iconImageCache.expire();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array<import("../layer/Layer.js").State>} layerStatesArray Layer states array.
|
|
||||||
* @return {Object<string, import("../layer/Layer.js").State>} States mapped by layer uid.
|
|
||||||
*/
|
|
||||||
function getLayerStatesMap(layerStatesArray) {
|
|
||||||
return layerStatesArray.reduce(function(acc, state) {
|
|
||||||
acc[getUid(state.layer)] = state;
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MapRenderer;
|
export default MapRenderer;
|
||||||
|
|||||||