Compare commits
1 Commits
docs
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5891aaadf9 |
@@ -27,10 +27,6 @@ jobs:
|
||||
name: Run Tests
|
||||
command: npm test
|
||||
|
||||
- store_artifacts:
|
||||
path: coverage/
|
||||
destination: coverage
|
||||
|
||||
- store_artifacts:
|
||||
path: rendering/cases/
|
||||
destination: rendering
|
||||
@@ -42,19 +38,3 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: build/examples
|
||||
destination: examples
|
||||
|
||||
- run:
|
||||
name: Build API Docs
|
||||
command: npm run apidoc
|
||||
|
||||
- store_artifacts:
|
||||
path: build/apidoc
|
||||
destination: apidoc
|
||||
|
||||
- run:
|
||||
name: Build Website
|
||||
command: npm run build-site
|
||||
|
||||
- store_artifacts:
|
||||
path: public
|
||||
destination: website
|
||||
|
||||
2
.gitignore
vendored
@@ -2,5 +2,3 @@
|
||||
/coverage/
|
||||
/dist/
|
||||
node_modules/
|
||||
/.cache/
|
||||
/public/
|
||||
|
||||
@@ -4,28 +4,6 @@
|
||||
|
||||
#### Backwards incompatible changes
|
||||
|
||||
#### Removal of `GEOLOCATION` constant from `ol/has`
|
||||
|
||||
If you were previously using this constant, you can check if `'geolocation'` is define in `navigator` instead.
|
||||
|
||||
```js
|
||||
if ('geolocation' in navigator) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Removal of CSS print rules
|
||||
|
||||
The CSS media print rules were removed from the `ol.css` file. To get the previous behavior, use the following CSS:
|
||||
|
||||
```css
|
||||
@media print {
|
||||
.ol-control {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Removal of optional this arguments
|
||||
|
||||
The optional this (i.e. opt_this) arguments were removed from the following methods.
|
||||
@@ -54,9 +32,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.
|
||||
|
||||
##### The view is constrained so only one world is visible
|
||||
##### Zoom is constrained so only one world is visible
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
##### Removal of deprecated methods
|
||||
|
||||
@@ -120,14 +98,6 @@ If you were previously using `VectorTile` layers with `renderMode: 'vector'`, yo
|
||||
|
||||
If you were previously using `Vector` layers with `renderMode: 'image'`, you have to remove this configuration option. Instead, use the new `ol/layer/VectorImage` layer with your `ol/source/Vector`.
|
||||
|
||||
##### New declutter behavior
|
||||
|
||||
If a map has more than one layer with `declutter` set to true, decluttering now considers all `Vector` and `VectorTile` layers, instead of decluttering each layer separately. Only `VectorImage` layers continue to be decluttered separately. The higher the z-index of a layer, the higher the priority of its decluttered items.
|
||||
|
||||
Within a layer, the declutter order has changed. Previously, styles with a lower `zIndex` were prioritized over those with a higher `zIndex`. Now the opposite order is used.
|
||||
|
||||
On vector layers, even if decluttered images or texts have a lower z-Index than polygons or lines, they will now be rendered on top of the polygons or lines. For vector tile layers, this was the case already in previous releases.
|
||||
|
||||
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
|
||||
|
||||
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
/**
|
||||
* Handle the api annotation.
|
||||
* @param {Object} dictionary The tag dictionary.
|
||||
*/
|
||||
exports.defineTags = dictionary => {
|
||||
|
||||
dictionary.defineTag('api', {
|
||||
onTagged: (doclet, tag) => {
|
||||
doclet.api = true;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
* 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>
|
||||
<th width="33.3%">Map</th><th width="33.3%">View</th><th width="33.3%">Layers</th>
|
||||
</tr><tr>
|
||||
<td><p>A <a href="module-ol_Map-Map.html">map</a> is made of <a href="module-ol_layer_Base-BaseLayer.html">layers</a>, a <a href="module-ol_View-View.html">view</a> to visualize them, <a href="module-ol_interaction_Interaction-Interaction.html">interactions</a> to modify map content and <a href="module-ol_control_Control-Control.html">controls</a> with UI components.</p>
|
||||
<a href="module-ol_Map-Map.html">Overview</a><br>
|
||||
<a href="module-ol_Map-Map.html#Map">Creation</a><br>
|
||||
<a href="module-ol_MapBrowserEvent-MapBrowserEvent.html">Events</a></td>
|
||||
<td><p>A [map](module-ol_Map-Map.html) is made of [layers](module-ol_layer_Base-BaseLayer.html), a [view](module-ol_View-View.html) to visualize them, [interactions](module-ol_interaction_Interaction-Interaction.html) to modify map content and [controls](module-ol_control_Control-Control.html) with UI components.</p>
|
||||
[Overview](module-ol_Map-Map.html)<br>
|
||||
[Creation](module-ol_Map-Map.html#Map)<br>
|
||||
[Events](module-ol_MapBrowserEvent-MapBrowserEvent.html)</td>
|
||||
<td><p>The view manages the visual parameters of the map view, like resolution or rotation.</p>
|
||||
<a href="module-ol_View-View.html">View</a> with center, projection, resolution and rotation</td>
|
||||
<td><p>Layers are lightweight containers that get their data from <a href="module-ol_source_Source-Source.html">sources</a>.</p>
|
||||
<a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a><br>
|
||||
<a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a><br>
|
||||
<a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a><br>
|
||||
<a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a></td>
|
||||
[View](module-ol_View-View.html) with center, projection, resolution and rotation</td>
|
||||
<td><p>Layers are lightweight containers that get their data from [sources](module-ol_source_Source-Source.html).</p>
|
||||
[ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)<br>
|
||||
[ol/layer/Image](module-ol_layer_Image-ImageLayer.html)<br>
|
||||
[ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)<br>
|
||||
[ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)</td>
|
||||
</tr><tr>
|
||||
<th>Controls</th><th>Interactions</th><th>Sources and formats</th>
|
||||
</tr><tr>
|
||||
<td><a href="module-ol_control_util.html#.defaults">Map default controls</a><br>
|
||||
<a href="module-ol_control_Control-Control.html">All controls</a>
|
||||
<td>[Map default controls](module-ol_control_util.html#.defaults)<br>
|
||||
[All controls](module-ol_control_Control-Control.html)
|
||||
</td>
|
||||
<td>
|
||||
<a href="module-ol_interaction.html#~defaults">Map default interactions</a><br>
|
||||
Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
|
||||
<ul><li><a href="module-ol_interaction_Select-Select.html">ol/interaction/Select</a></li>
|
||||
<li><a href="module-ol_interaction_Draw-Draw.html">ol/interaction/Draw</a></li>
|
||||
<li><a href="module-ol_interaction_Modify-Modify.html">ol/interaction/Modify</a></li></ul>
|
||||
<a href="module-ol_interaction_Interaction-Interaction.html">All interactions</a></td>
|
||||
<td><a href="module-ol_source_Tile-TileSource.html">Tile sources</a> for <a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a>
|
||||
<br><a href="module-ol_source_Image-ImageSource.html">Image sources</a> for <a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a>
|
||||
<br><a href="module-ol_source_Vector-VectorSource.html">Vector sources</a> for <a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a>
|
||||
<br><a href="module-ol_source_VectorTile-VectorTile.html">Vector tile sources</a> for <a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a>
|
||||
<br><a href="module-ol_format_Feature-FeatureFormat.html">Formats</a> for reading/writing vector data
|
||||
<br><a href="module-ol_format_WMSCapabilities-WMSCapabilities.html">ol/format/WMSCapabilities</a></td></tr>
|
||||
[Map default interactions](module-ol_interaction.html#~defaults)<br>
|
||||
Interactions for [vector features](module-ol_Feature-Feature.html)
|
||||
<ul><li>[ol/interaction/Select](module-ol_interaction_Select-Select.html)</li>
|
||||
<li>[ol/interaction/Draw](module-ol_interaction_Draw-Draw.html)</li>
|
||||
<li>[ol/interaction/Modify](module-ol_interaction_Modify-Modify.html)</li></ul>
|
||||
[All interactions](module-ol_interaction_Interaction-Interaction.html)</td>
|
||||
<td>[Tile sources](module-ol_source_Tile-TileSource.html) for [ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)
|
||||
<br>[Image sources](module-ol_source_Image-ImageSource.html) for [ol/layer/Image](module-ol_layer_Image-ImageLayer.html)
|
||||
<br>[Vector sources](module-ol_source_Vector-VectorSource.html) for [ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)
|
||||
<br>[Vector tile sources](module-ol_source_VectorTile-VectorTile.html) for [ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)
|
||||
<br>[Formats](module-ol_format_Feature-FeatureFormat.html) for reading/writing vector data
|
||||
<br>[ol/format/WMSCapabilities](module-ol_format_WMSCapabilities-WMSCapabilities.html)</td></tr>
|
||||
<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 <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
|
||||
<a href="module-ol_proj.html">ol/proj</a></td>
|
||||
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use [ol/proj#transform()](module-ol_proj.html#.transform) and [ol/proj#transformExtent()](module-ol_proj.html#.transformExtent).</p>
|
||||
[ol/proj](module-ol_proj.html)</td>
|
||||
<td><p>Changes to all [ol/Object](module-ol_Object-BaseObject.html)s can be observed by calling the [object.on('propertychange')](module-ol_Object-BaseObject.html#on) method. Listeners receive an [ol/Object.ObjectEvent](module-ol_Object-ObjectEvent.html) with information on the changed property and old value.</p>
|
||||
<td>
|
||||
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
|
||||
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
|
||||
[ol/Geolocation](module-ol_Geolocation.html)<br>
|
||||
[ol/Overlay](module-ol_Overlay-Overlay.html)<br></td>
|
||||
</tr></table>
|
||||
|
||||
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
const events = {};
|
||||
const classes = {};
|
||||
|
||||
exports.handlers = {
|
||||
|
||||
newDoclet: function(e) {
|
||||
const doclet = e.doclet;
|
||||
if (doclet.kind !== 'event') {
|
||||
return;
|
||||
let cls;
|
||||
if (doclet.kind == 'event') {
|
||||
cls = doclet.longname.split('#')[0];
|
||||
if (!(cls in events)) {
|
||||
events[cls] = [];
|
||||
}
|
||||
events[cls].push(doclet.longname);
|
||||
} else if (doclet.kind == 'class' && !(doclet.longname in classes)) {
|
||||
classes[doclet.longname] = doclet;
|
||||
}
|
||||
|
||||
const cls = doclet.longname.split('#')[0];
|
||||
if (!(cls in events)) {
|
||||
events[cls] = [];
|
||||
}
|
||||
events[cls].push(doclet.longname);
|
||||
},
|
||||
|
||||
parseComplete: function(e) {
|
||||
const doclets = e.doclets;
|
||||
for (let i = 0, ii = doclets.length - 1; i < ii; ++i) {
|
||||
const doclet = doclets[i];
|
||||
let doclet, i, ii, j, jj, event, fires;
|
||||
for (i = 0, ii = doclets.length - 1; i < ii; ++i) {
|
||||
doclet = doclets[i];
|
||||
if (doclet.fires) {
|
||||
if (doclet.kind == 'class') {
|
||||
const fires = [];
|
||||
for (let j = 0, jj = doclet.fires.length; j < jj; ++j) {
|
||||
const event = doclet.fires[j].replace('event:', '');
|
||||
fires = [];
|
||||
for (j = 0, jj = doclet.fires.length; j < jj; ++j) {
|
||||
event = doclet.fires[j].replace('event:', '');
|
||||
if (events[event]) {
|
||||
fires.push.apply(fires, events[event]);
|
||||
} else if (doclet.fires[j] !== 'event:ObjectEvent') {
|
||||
|
||||
@@ -220,11 +220,3 @@ Duplicate item added to a unique collection. For example, it may be that you tr
|
||||
### 59
|
||||
|
||||
Invalid command found in the PBF. This indicates that the loaded vector tile may be corrupt.
|
||||
|
||||
### 60
|
||||
|
||||
Missing or invalid `size`.
|
||||
|
||||
### 61
|
||||
|
||||
Cannot determine IIIF Image API version from provided image information JSON.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"common": false,
|
||||
"createMapboxStreetsV6Style": false,
|
||||
"d3": false,
|
||||
"domtoimage": false,
|
||||
"geojsonvt": false,
|
||||
"GyroNorm": 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.
|
||||
tags: "d3"
|
||||
resources:
|
||||
- https://unpkg.com/d3@5.9.2/dist/d3.js
|
||||
- https://unpkg.com/d3@4.12.0/build/d3.js
|
||||
- https://unpkg.com/topojson@3.0.2/dist/topojson.js
|
||||
---
|
||||
<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.
|
||||
*/
|
||||
d3.json('data/topojson/us.json').then(function(us) {
|
||||
d3.json('data/topojson/us.json', function(error, us) {
|
||||
|
||||
const layer = new CanvasLayer({
|
||||
features: topojson.feature(us, us.objects.counties)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 194 B |
@@ -40,6 +40,6 @@ gn.init().then(function() {
|
||||
center[0] -= resolution * gamma * 25;
|
||||
center[1] += resolution * beta * 25;
|
||||
|
||||
view.setCenter(center);
|
||||
view.setCenter(view.constrainCenter(center));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
.overlay {
|
||||
background-color: yellow;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -3,13 +3,12 @@ layout: example.html
|
||||
title: Map Export
|
||||
shortdesc: Example of exporting a map as a PNG image.
|
||||
docs: >
|
||||
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/html-to-image">html-to-image</a>
|
||||
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>
|
||||
library.
|
||||
tags: "export, png, openstreetmap"
|
||||
resources:
|
||||
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div style="display: none;">
|
||||
<div class="overlay" id="null">Null Island</div>
|
||||
</div>
|
||||
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
|
||||
<a id="image-download" download="map.png"></a>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Overlay from '../src/ol/Overlay.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
import {toPng} from 'html-to-image';
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
@@ -26,23 +23,9 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
map.addOverlay(new Overlay({
|
||||
position: [0, 0],
|
||||
element: document.getElementById('null')
|
||||
}));
|
||||
|
||||
|
||||
// export options for html-to-image.
|
||||
// See: https://github.com/bubkoo/html-to-image#options
|
||||
const exportOptions = {
|
||||
filter: function(element) {
|
||||
return element.className ? element.className.indexOf('ol-control') === -1 : true;
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('export-png').addEventListener('click', function() {
|
||||
map.once('rendercomplete', function() {
|
||||
toPng(map.getTargetElement(), exportOptions)
|
||||
domtoimage.toPng(map.getViewport().querySelector('.ol-layers'))
|
||||
.then(function(dataURL) {
|
||||
const link = document.getElementById('image-download');
|
||||
link.href = dataURL;
|
||||
|
||||
@@ -7,6 +7,7 @@ docs: >
|
||||
tags: "export, pdf, openstreetmap"
|
||||
resources:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
|
||||
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
|
||||
---
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
|
||||
@@ -4,8 +4,6 @@ import WKT from '../src/ol/format/WKT.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
import {toJpeg} from 'html-to-image';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new OSM()
|
||||
});
|
||||
@@ -43,15 +41,6 @@ const dims = {
|
||||
a5: [210, 148]
|
||||
};
|
||||
|
||||
|
||||
// export options for html-to-image.
|
||||
// See: https://github.com/bubkoo/html-to-image#options
|
||||
const exportOptions = {
|
||||
filter: function(element) {
|
||||
return element.className.indexOf('ol-control') === -1;
|
||||
}
|
||||
};
|
||||
|
||||
const exportButton = document.getElementById('export-pdf');
|
||||
|
||||
exportButton.addEventListener('click', function() {
|
||||
@@ -68,14 +57,15 @@ exportButton.addEventListener('click', function() {
|
||||
const extent = map.getView().calculateExtent(size);
|
||||
|
||||
map.once('rendercomplete', function() {
|
||||
toJpeg(map.getTargetElement(), exportOptions).then(function(dataUrl) {
|
||||
domtoimage.toJpeg(map.getViewport().querySelector('.ol-layers')).then(function(dataUrl) {
|
||||
const pdf = new jsPDF('landscape', undefined, format);
|
||||
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
|
||||
pdf.save('map.pdf');
|
||||
// Reset original map size
|
||||
map.setSize(size);
|
||||
map.getView().fit(extent, {
|
||||
size: size
|
||||
size: size,
|
||||
constrainResolution: false
|
||||
});
|
||||
exportButton.disabled = false;
|
||||
document.body.style.cursor = 'auto';
|
||||
|
||||
@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import {defaults as defaultControls} from '../src/ol/control.js';
|
||||
import {defaults as defaultControls} from '../src/ol/control/util';
|
||||
import ZoomSlider from '../src/ol/control/ZoomSlider';
|
||||
|
||||
const view = new View({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {platformModifierKeyOnly} from '../src/ol/events/condition.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import ExtentInteraction from '../src/ol/interaction/Extent.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
@@ -26,7 +27,9 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
const extent = new ExtentInteraction();
|
||||
const extent = new ExtentInteraction({
|
||||
condition: platformModifierKeyOnly
|
||||
});
|
||||
map.addInteraction(extent);
|
||||
extent.setActive(false);
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@ import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||
import {clamp, lerp} from '../src/ol/math';
|
||||
import Stamen from '../src/ol/source/Stamen';
|
||||
|
||||
const features = [];
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
attributions: 'NASA'
|
||||
});
|
||||
|
||||
@@ -36,16 +38,15 @@ updateStatusText();
|
||||
class WebglPointsLayer extends VectorLayer {
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
colorCallback: function(feature, color) {
|
||||
colorCallback: function(feature, vertex, component) {
|
||||
// component at index 3 is alpha
|
||||
if (component === 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// color is interpolated based on year
|
||||
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
|
||||
|
||||
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;
|
||||
return lerp(oldColor[component], newColor[component], ratio) / 255;
|
||||
},
|
||||
sizeCallback: function(feature) {
|
||||
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
||||
@@ -108,28 +109,26 @@ function loadData() {
|
||||
client.open('GET', 'data/csv/meteorite_landings.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
let prevIndex = 0;
|
||||
let line;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
|
||||
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||
// guard against bad data
|
||||
// skip header
|
||||
if (prevIndex === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||
|
||||
features.push(new Feature({
|
||||
mass: parseFloat(line[1]) || 0,
|
||||
year: parseInt(line[2]) || 0,
|
||||
geometry: new Point(coords)
|
||||
}));
|
||||
}
|
||||
|
||||
vectorSource.addFeatures(features);
|
||||
};
|
||||
client.send();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.map:-webkit-full-screen {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.map:-ms-fullscreen {
|
||||
height: 100%;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.fullscreen:-webkit-full-screen {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.fullscreen:-ms-fullscreen {
|
||||
height: 100%;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.map:-webkit-full-screen {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.map:-ms-fullscreen {
|
||||
height: 100%;
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Earthquakes Heatmap
|
||||
shortdesc: Demonstrates the use of a heatmap layer.
|
||||
docs: >
|
||||
This example parses a KML file and renders the features as a <code>ol/layer/Heatmap</code> layer.
|
||||
tags: "heatmap, kml, vector, style, webgl"
|
||||
tags: "heatmap, kml, vector, style"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<form>
|
||||
|
||||
@@ -25,7 +25,7 @@ rome.setStyle(new Style({
|
||||
image: new Icon({
|
||||
color: '#8959A8',
|
||||
crossOrigin: 'anonymous',
|
||||
src: 'data/square.svg'
|
||||
src: 'data/dot.png'
|
||||
})
|
||||
}));
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {fromLonLat} from '../src/ol/proj';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||
import {lerp} from '../src/ol/math';
|
||||
|
||||
const features = [];
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
attributions: 'National UFO Reporting Center'
|
||||
@@ -38,17 +39,16 @@ class WebglPointsLayer extends VectorLayer {
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
texture: texture,
|
||||
colorCallback: function(feature, color) {
|
||||
colorCallback: function(feature, vertex, component) {
|
||||
// component at index 3 is alpha
|
||||
if (component === 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// color is interpolated based on year (min is 1910, max is 2013)
|
||||
// please note: most values are between 2000-2013
|
||||
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
|
||||
|
||||
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;
|
||||
return lerp(oldColor[component], newColor[component], ratio * ratio) / 255;
|
||||
},
|
||||
texCoordCallback: function(feature, component) {
|
||||
let coords = shapeTextureCoords[feature.get('shape')];
|
||||
@@ -70,15 +70,18 @@ function loadData() {
|
||||
client.open('GET', 'data/csv/ufo_sighting_data.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
let prevIndex = 0;
|
||||
let line;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
|
||||
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
// skip header
|
||||
if (prevIndex === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
|
||||
|
||||
// only keep valid points
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
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>
|
||||
@@ -1,46 +0,0 @@
|
||||
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,25 +11,9 @@
|
||||
body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
img.header-logo {
|
||||
padding-left: 18px;
|
||||
}
|
||||
input.search-query {
|
||||
color: #333;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
input.search-query {
|
||||
width: 110px;
|
||||
}
|
||||
#count {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 374px) {
|
||||
input.search-query {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.example {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
@@ -198,9 +182,9 @@
|
||||
<body>
|
||||
|
||||
<header class="navbar navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="container">
|
||||
<div class="display-table pull-left">
|
||||
<a class="navbar-brand" href="./"><img class="header-logo" src="./resources/logo-70x70.png"> OpenLayers</a>
|
||||
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers Examples</a>
|
||||
<form class="navbar-form" role="search">
|
||||
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search" autofocus>
|
||||
<span id="count"></span>
|
||||
|
||||
@@ -6,10 +6,9 @@ docs: >
|
||||
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
|
||||
tags: "simple, mapbox, vector, tiles"
|
||||
resources:
|
||||
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js
|
||||
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css
|
||||
- https://unpkg.com/mapbox-gl@0.51.0/dist/mapbox-gl.js
|
||||
cloak:
|
||||
- key: ER67WIiPdCQvhgsUjoWK
|
||||
value: Your Mapbox access token from https://mapbox.com/ here
|
||||
value: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -1,67 +1,188 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Layer from '../src/ol/layer/Layer';
|
||||
import {toLonLat, fromLonLat} from '../src/ol/proj';
|
||||
import {assign} from '../src/ol/obj';
|
||||
import {getTransform} from '../src/ol/proj';
|
||||
import SourceState from '../src/ol/source/State';
|
||||
import {Stroke, Style} from '../src/ol/style.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
|
||||
const center = [-98.8, 37.9];
|
||||
const key = 'ER67WIiPdCQvhgsUjoWK';
|
||||
class Mapbox extends Layer {
|
||||
|
||||
const mbMap = new mapboxgl.Map({
|
||||
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key,
|
||||
attributionControl: false,
|
||||
boxZoom: false,
|
||||
center: center,
|
||||
container: 'map',
|
||||
doubleClickZoom: false,
|
||||
dragPan: false,
|
||||
dragRotate: false,
|
||||
interactive: false,
|
||||
keyboard: false,
|
||||
pitchWithRotate: false,
|
||||
scrollZoom: false,
|
||||
touchZoomRotate: false
|
||||
});
|
||||
/**
|
||||
* @param {import('./Base.js').Options} options Layer options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const baseOptions = assign({}, options);
|
||||
super(baseOptions);
|
||||
|
||||
const mbLayer = new Layer({
|
||||
render: function(frameState) {
|
||||
const canvas = mbMap.getCanvas();
|
||||
const viewState = frameState.viewState;
|
||||
this.baseOptions = baseOptions;
|
||||
|
||||
const visible = mbLayer.getVisible();
|
||||
canvas.style.display = visible ? 'block' : 'none';
|
||||
/**
|
||||
* @private
|
||||
* @type boolean
|
||||
*/
|
||||
this.loaded = false;
|
||||
|
||||
const opacity = mbLayer.getOpacity();
|
||||
canvas.style.opacity = opacity;
|
||||
this.initMap();
|
||||
}
|
||||
|
||||
// adjust view parameters in mapbox
|
||||
const rotation = viewState.rotation;
|
||||
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,
|
||||
boxZoom: false,
|
||||
center,
|
||||
container: map.getTargetElement(),
|
||||
doubleClickZoom: false,
|
||||
dragPan: false,
|
||||
dragRotate: false,
|
||||
interactive: false,
|
||||
keyboard: false,
|
||||
pitchWithRotate: false,
|
||||
scrollZoom: false,
|
||||
touchZoomRotate: false,
|
||||
zoom: view.getZoom() - 1
|
||||
});
|
||||
|
||||
this.mbmap = new mapboxgl.Map(options);
|
||||
this.mbmap.on('load', function() {
|
||||
this.mbmap.getCanvas().remove();
|
||||
this.loaded = true;
|
||||
this.map_.render();
|
||||
[
|
||||
'mapboxgl-control-container'
|
||||
].forEach(className => document.getElementsByClassName(className)[0].remove());
|
||||
}.bind(this));
|
||||
|
||||
this.mbmap.on('render', function() {
|
||||
// Reset offset
|
||||
if (this.centerNextRender) {
|
||||
this.centerLastRender = this.centerNextRender;
|
||||
}
|
||||
if (this.zoomNextRender) {
|
||||
this.zoomLastRender = this.zoomNextRender;
|
||||
}
|
||||
this.updateRenderedPosition([0, 0], 1);
|
||||
}.bind(this));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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) {
|
||||
mbMap.rotateTo(-rotation * 180 / Math.PI, {
|
||||
this.mbmap.rotateTo(-rotation * 180 / Math.PI, {
|
||||
animate: false
|
||||
});
|
||||
}
|
||||
mbMap.jumpTo({
|
||||
center: toLonLat(viewState.center),
|
||||
zoom: viewState.zoom - 1,
|
||||
animate: false
|
||||
|
||||
// Re-render mbmap
|
||||
const center = transformToLatLng(this.centerNextRender);
|
||||
const zoom = view.getZoom() - 1;
|
||||
this.mbmap.jumpTo({
|
||||
center: center,
|
||||
zoom: zoom
|
||||
});
|
||||
|
||||
// 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();
|
||||
|
||||
return canvas;
|
||||
return this.mbmap.getCanvas();
|
||||
}
|
||||
});
|
||||
|
||||
updateRenderedPosition(centerOffset, zoomOffset) {
|
||||
const style = this.mbmap.getCanvas().style;
|
||||
style.left = Math.round(centerOffset[0]) + 'px';
|
||||
style.top = Math.round(centerOffset[1]) + 'px';
|
||||
style.transform = 'scale(' + zoomOffset + ')';
|
||||
}
|
||||
|
||||
setVisible(visible) {
|
||||
super.setVisible(visible);
|
||||
|
||||
const canvas = this.mbmap.getCanvas();
|
||||
canvas.style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
|
||||
setOpacity(opacity) {
|
||||
super.setOpacity(opacity);
|
||||
const canvas = this.mbmap.getCanvas();
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
setZIndex(zindex) {
|
||||
super.setZIndex(zindex);
|
||||
const canvas = this.mbmap.getCanvas();
|
||||
canvas.style.zIndex = zindex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSourceState() {
|
||||
return this.loaded ? SourceState.READY : SourceState.UNDEFINED;
|
||||
}
|
||||
|
||||
setMap(map) {
|
||||
this.map_ = map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mapboxgl.Map.prototype._setupContainer = function _setupContainer() {
|
||||
const container = this._container;
|
||||
container.classList.add('mapboxgl-map');
|
||||
|
||||
const canvasContainer = this._canvasContainer = container.firstChild;
|
||||
|
||||
this._canvas = document.createElement('canvas');
|
||||
canvasContainer.insertBefore(this._canvas, canvasContainer.firstChild);
|
||||
this._canvas.style.position = 'absolute';
|
||||
this._canvas.addEventListener('webglcontextlost', this._contextLost, false);
|
||||
this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false);
|
||||
this._canvas.setAttribute('tabindex', '0');
|
||||
this._canvas.setAttribute('aria-label', 'Map');
|
||||
this._canvas.className = 'mapboxgl-canvas';
|
||||
|
||||
const dimensions = this._containerDimensions();
|
||||
this._resizeCanvas(dimensions[0], dimensions[1]);
|
||||
|
||||
this._controlContainer = canvasContainer;
|
||||
const controlContainer = this._controlContainer = document.createElement('div');
|
||||
controlContainer.className = 'mapboxgl-control-container';
|
||||
container.appendChild(controlContainer);
|
||||
|
||||
const positions = this._controlPositions = {};
|
||||
['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function(positionName) {
|
||||
const elem = document.createElement('div');
|
||||
elem.className = 'mapboxgl-ctrl-' + positionName;
|
||||
controlContainer.appendChild(elem);
|
||||
positions[positionName] = elem;
|
||||
});
|
||||
};
|
||||
|
||||
const style = new Style({
|
||||
stroke: new Stroke({
|
||||
@@ -81,8 +202,21 @@ const vectorLayer = new VectorLayer({
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: fromLonLat(center),
|
||||
zoom: 4
|
||||
}),
|
||||
layers: [mbLayer, vectorLayer]
|
||||
center: [-10997148, 4569099],
|
||||
zoom: 4,
|
||||
minZoom: 1,
|
||||
extent: [-Infinity, -20048966.10, Infinity, 20048966.10],
|
||||
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
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||
value: Your Mapbox access token from https://mapbox.com/ here
|
||||
value: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -9,6 +9,6 @@ resources:
|
||||
- resources/mapbox-streets-v6-style.js
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||
value: Your Mapbox access token from https://mapbox.com/ here
|
||||
value: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<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 ImageMapGuide from '../src/ol/source/ImageMapGuide.js';
|
||||
|
||||
const mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
|
||||
const mdf = 'Library://Public/Samples/Sheboygan/Maps/Sheboygan.MapDefinition';
|
||||
const agentUrl =
|
||||
'http://138.197.230.93:8008/mapguide/mapagent/mapagent.fcgi?';
|
||||
'http://www.buoyshark.com/mapguide/mapagent/mapagent.fcgi?';
|
||||
const bounds = [
|
||||
-87.865114442365922,
|
||||
43.665065564837931,
|
||||
@@ -24,9 +24,8 @@ const map = new Map({
|
||||
params: {
|
||||
MAPDEFINITION: mdf,
|
||||
FORMAT: 'PNG',
|
||||
VERSION: '3.0.0',
|
||||
USERNAME: 'OLGuest',
|
||||
PASSWORD: 'olguest'
|
||||
USERNAME: 'OpenLayers',
|
||||
PASSWORD: 'OpenLayers'
|
||||
},
|
||||
ratio: 2
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ docs: >
|
||||
tags: "raster, pixel operation, flood"
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
|
||||
value: Your Mapbox access token from https://mapbox.com/ here
|
||||
value: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<label>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<header class="navbar" role="navigation">
|
||||
<div class="container">
|
||||
<div class="display-table pull-left" id="navbar-logo-container">
|
||||
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers</a>
|
||||
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png"> OpenLayers Examples</a>
|
||||
</div>
|
||||
<!-- menu items that get hidden below 768px width -->
|
||||
<nav class='collapse navbar-collapse navbar-responsive-collapse'>
|
||||
@@ -122,7 +122,7 @@
|
||||
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
|
||||
</div>
|
||||
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup"><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
|
||||
@@ -8,7 +8,7 @@ docs: >
|
||||
tags: "utfgrid, tilejson"
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q
|
||||
value: Your Mapbox access token from https://mapbox.com/ here
|
||||
value: Your Mapbox access token from http://mapbox.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div style="display: none;">
|
||||
|
||||
@@ -19,25 +19,16 @@ module.exports = {
|
||||
context: src,
|
||||
target: 'web',
|
||||
entry: entry,
|
||||
stats: 'minimal',
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: 'buble-loader'
|
||||
},
|
||||
test: /\.js$/,
|
||||
include: [
|
||||
path.join(__dirname, '..', '..', 'src'),
|
||||
path.join(__dirname, '..')
|
||||
]
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: path.join(__dirname, './worker-loader.js')
|
||||
},
|
||||
include: [
|
||||
path.join(__dirname, '../../src/ol/worker')
|
||||
]
|
||||
}]
|
||||
},
|
||||
optimization: {
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
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() {
|
||||
startDate.setMinutes(startDate.getMinutes() + 15);
|
||||
if (startDate > new Date()) {
|
||||
if (startDate > Date.now()) {
|
||||
startDate = threeHoursAgo();
|
||||
}
|
||||
layers[1].getSource().updateParams({'TIME': startDate.toISOString()});
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
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>
|
||||
@@ -1,35 +0,0 @@
|
||||
/* 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,6 +11,5 @@ tags: "zoomify, deep zoom, IIP, pixel, projection"
|
||||
<select id="zoomifyProtocol">
|
||||
<option value="zoomify">Zoomify</option>
|
||||
<option value="iip">IIP</option>
|
||||
<option value="zoomifyretina">Zoomify Retina</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,6 @@ const iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/
|
||||
|
||||
const layer = new TileLayer({
|
||||
source: new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
@@ -22,15 +20,12 @@ const layer = new TileLayer({
|
||||
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
|
||||
const map = new Map({
|
||||
layers: [layer],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
resolutions: layer.getSource().getTileGrid().getResolutions(),
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
@@ -41,73 +36,17 @@ const control = document.getElementById('zoomifyProtocol');
|
||||
control.addEventListener('change', function(event) {
|
||||
const value = event.currentTarget.value;
|
||||
if (value === 'iip') {
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
url: iipUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
layer.setSource(new Zoomify({
|
||||
url: iipUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
}));
|
||||
} else if (value === 'zoomify') {
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
} else if (value === 'zoomifyretina') {
|
||||
const pixelRatio = 4;
|
||||
// Be careful! Image extent will be modified by pixel ratio
|
||||
const extent = [0, -imgHeight / pixelRatio, imgWidth / pixelRatio, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256 / pixelRatio,
|
||||
tilePixelRatio: pixelRatio,
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth / pixelRatio, imgHeight / pixelRatio],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1] / pixelRatio,
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
layer.setSource(new Zoomify({
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'gatsby-plugin-emotion',
|
||||
{
|
||||
resolve: 'gatsby-plugin-typography',
|
||||
options: {
|
||||
pathToConfigModule: 'site/util/typography'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
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
73
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.0.0-beta.8",
|
||||
"version": "6.0.0-beta.6",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -22,12 +22,9 @@
|
||||
"build-index": "npm run build-package && node tasks/generate-index",
|
||||
"build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css",
|
||||
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
||||
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && 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 && tsc --project config/tsconfig-build.json",
|
||||
"typecheck": "tsc --pretty",
|
||||
"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"
|
||||
"apidoc": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
||||
},
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -41,83 +38,57 @@
|
||||
"dependencies": {
|
||||
"pbf": "3.2.0",
|
||||
"pixelworks": "1.1.0",
|
||||
"rbush": "^3.0.0"
|
||||
"rbush": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.0",
|
||||
"@babel/preset-env": "^7.4.4",
|
||||
"@emotion/core": "^10.0.10",
|
||||
"@emotion/styled": "^10.0.11",
|
||||
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
|
||||
"@types/arcgis-rest-api": "^10.4.4",
|
||||
"@types/geojson": "^7946.0.7",
|
||||
"@types/pbf": "^3.0.1",
|
||||
"@types/rbush": "^2.0.2",
|
||||
"@types/topojson-specification": "^1.0.1",
|
||||
"babel-loader": "^8.0.5",
|
||||
"buble": "^0.19.7",
|
||||
"buble-loader": "^0.5.1",
|
||||
"chaikin-smooth": "^1.0.4",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"copy-webpack-plugin": "^5.0.2",
|
||||
"coveralls": "3.0.3",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-openlayers": "^11.0.0",
|
||||
"eslint-config-tschaub": "^13.1.0",
|
||||
"eslint-plugin-react": "^7.13.0",
|
||||
"expect.js": "0.3.1",
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^8.0.0",
|
||||
"gatsby": "^2.4.3",
|
||||
"gatsby-plugin-emotion": "^4.0.6",
|
||||
"gatsby-plugin-typography": "^2.2.13",
|
||||
"glob": "^7.1.4",
|
||||
"front-matter": "^3.0.1",
|
||||
"fs-extra": "^7.0.1",
|
||||
"glob": "^7.1.2",
|
||||
"globby": "^9.2.0",
|
||||
"handlebars": "4.1.2",
|
||||
"html-to-image": "^0.1.0",
|
||||
"istanbul": "0.4.5",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jquery": "3.4.1",
|
||||
"jsdoc": "3.6.2",
|
||||
"jsdoc-json": "^2.0.2",
|
||||
"jsdoc-plugin-typescript": "^2.0.1",
|
||||
"karma": "^4.1.0",
|
||||
"jquery": "3.4.0",
|
||||
"jsdoc": "3.5.5",
|
||||
"jsdoc-plugin-typescript": "^1.0.7",
|
||||
"karma": "^4.0.1",
|
||||
"karma-chrome-launcher": "2.2.0",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-coverage-istanbul-reporter": "^2.0.5",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
"karma-mocha": "1.3.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^4.0.0-rc.2",
|
||||
"loglevelnext": "^3.0.1",
|
||||
"loglevelnext": "^3.0.0",
|
||||
"marked": "0.6.2",
|
||||
"mocha": "6.1.4",
|
||||
"ol-mapbox-style": "^5.0.0-beta.2",
|
||||
"mocha": "6.1.3",
|
||||
"ol-mapbox-style": "^4.3.1",
|
||||
"pixelmatch": "^4.0.2",
|
||||
"pngjs": "^3.4.0",
|
||||
"proj4": "2.5.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"puppeteer": "~1.16.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-markdown": "^4.0.8",
|
||||
"react-syntax-highlighter": "^10.2.1",
|
||||
"react-typography": "^0.16.19",
|
||||
"rollup": "^1.12.0",
|
||||
"rollup-plugin-babel": "^4.3.2",
|
||||
"rollup-plugin-commonjs": "^10.0.0",
|
||||
"rollup-plugin-node-resolve": "^5.0.0",
|
||||
"rollup-plugin-terser": "^4.0.4",
|
||||
"serve-static": "^1.14.0",
|
||||
"puppeteer": "~1.14.0",
|
||||
"serve-static": "^1.13.2",
|
||||
"shx": "^0.3.2",
|
||||
"sinon": "^7.3.2",
|
||||
"sinon": "^7.3.1",
|
||||
"terser-webpack-plugin": "^1.2.3",
|
||||
"typescript": "^3.4.5",
|
||||
"typography": "^0.16.19",
|
||||
"typography-theme-alton": "^0.16.19",
|
||||
"typescript": "^3.2.2",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "4.31.0",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack": "4.30.0",
|
||||
"webpack-cli": "^3.3.0",
|
||||
"webpack-dev-middleware": "^3.6.2",
|
||||
"webpack-dev-server": "^3.3.1",
|
||||
"yargs": "^13.2.2"
|
||||
|
||||
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.8 KiB |
@@ -7,7 +7,6 @@ import Point from '../../../src/ol/geom/Point.js';
|
||||
import Style from '../../../src/ol/style/Style.js';
|
||||
import Text from '../../../src/ol/style/Text.js';
|
||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||
import Fill from '../../../src/ol/style/Fill.js';
|
||||
import Stroke from '../../../src/ol/style/Stroke.js';
|
||||
import LineString from '../../../src/ol/geom/LineString.js';
|
||||
|
||||
@@ -60,10 +59,9 @@ source1.addFeature(new Feature({
|
||||
}));
|
||||
layer1.setStyle(function(feature) {
|
||||
return new Style({
|
||||
zIndex: feature.get('zIndex'),
|
||||
image: new CircleStyle({
|
||||
radius: 15,
|
||||
fill: new Fill({
|
||||
stroke: new Stroke({
|
||||
color: 'blue'
|
||||
})
|
||||
})
|
||||
@@ -71,7 +69,7 @@ layer1.setStyle(function(feature) {
|
||||
});
|
||||
map.addLayer(layer1);
|
||||
|
||||
center = [center[0] + 500, center[1] + 700];
|
||||
center = [center[0] + 500, center[1] + 500];
|
||||
const feature2 = new Feature({
|
||||
geometry: new Point(center),
|
||||
text: 'center',
|
||||
@@ -90,16 +88,15 @@ source2.addFeature(new Feature({
|
||||
}));
|
||||
layer2.setStyle(function(feature) {
|
||||
return new Style({
|
||||
zIndex: feature.get('zIndex'),
|
||||
text: new Text({
|
||||
text: feature.get('text'),
|
||||
font: 'italic bold 18px Ubuntu'
|
||||
font: '16px Ubuntu'
|
||||
})
|
||||
});
|
||||
});
|
||||
map.addLayer(layer2);
|
||||
|
||||
center = [center[0] + 500, center[1] + 300];
|
||||
center = [center[0] + 500, center[1] + 500];
|
||||
source3.addFeature(new Feature({
|
||||
geometry: new Point(center),
|
||||
text: 'center'
|
||||
@@ -115,17 +112,16 @@ source3.addFeature(new Feature({
|
||||
layer3.setStyle(function(feature) {
|
||||
return new Style({
|
||||
image: new CircleStyle({
|
||||
radius: 10,
|
||||
radius: 5,
|
||||
stroke: new Stroke({
|
||||
color: 'red',
|
||||
width: 8
|
||||
color: 'red'
|
||||
})
|
||||
}),
|
||||
text: new Text({
|
||||
text: feature.get('text'),
|
||||
font: 'italic bold 18px Ubuntu',
|
||||
font: '16px Ubuntu',
|
||||
textBaseline: 'bottom',
|
||||
offsetY: -12
|
||||
offsetY: -5
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -134,12 +130,11 @@ map.addLayer(layer3);
|
||||
center = [center[0] - 2000, center[1] - 2000];
|
||||
const point = new Feature(new Point(center));
|
||||
point.setStyle(new Style({
|
||||
zIndex: 1,
|
||||
zIndex: 2,
|
||||
image: new CircleStyle({
|
||||
radius: 8,
|
||||
stroke: new Stroke({
|
||||
color: 'blue',
|
||||
width: 4
|
||||
color: 'blue'
|
||||
})
|
||||
})
|
||||
}));
|
||||
@@ -148,7 +143,7 @@ const line = new Feature(new LineString([
|
||||
[center[0] + 650, center[1] - 200]
|
||||
]));
|
||||
line.setStyle(new Style({
|
||||
zIndex: 2,
|
||||
zIndex: 1,
|
||||
stroke: new Stroke({
|
||||
color: '#CCC',
|
||||
width: 12
|
||||
@@ -156,7 +151,7 @@ line.setStyle(new Style({
|
||||
text: new Text({
|
||||
placement: 'line',
|
||||
text: 'east-west',
|
||||
font: 'italic bold 18px Ubuntu',
|
||||
font: '16px Ubuntu',
|
||||
overflow: true
|
||||
})
|
||||
}));
|
||||
@@ -164,4 +159,4 @@ source4.addFeature(point);
|
||||
source4.addFeature(line);
|
||||
map.addLayer(layer4);
|
||||
|
||||
render({tolerance: 0.007});
|
||||
render({tolerance: 0.02});
|
||||
|
||||
@@ -42,8 +42,7 @@ const layer = new VectorLayer({
|
||||
const view = new View({
|
||||
center: [-9.5, 78],
|
||||
zoom: 2,
|
||||
projection: 'EPSG:4326',
|
||||
multiWorld: true
|
||||
projection: 'EPSG:4326'
|
||||
});
|
||||
new Map({
|
||||
pixelRatio: 1,
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.0 KiB |
@@ -1,154 +1,55 @@
|
||||
import Feature from '../../../src/ol/Feature.js';
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
|
||||
import Feature from '../../../src/ol/Feature.js';
|
||||
import Point from '../../../src/ol/geom/Point.js';
|
||||
import Style from '../../../src/ol/style/Style.js';
|
||||
import Text from '../../../src/ol/style/Text.js';
|
||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||
import Fill from '../../../src/ol/style/Fill.js';
|
||||
import Stroke from '../../../src/ol/style/Stroke.js';
|
||||
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
|
||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||
import Point from '../../../src/ol/geom/Point.js';
|
||||
import LineString from '../../../src/ol/geom/LineString.js';
|
||||
import Text from '../../../src/ol/style/Text.js';
|
||||
|
||||
let center = [1825927.7316762917, 6143091.089223046];
|
||||
const map = new Map({
|
||||
pixelRatio: 1,
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: center,
|
||||
zoom: 13
|
||||
})
|
||||
});
|
||||
const center = [1825927.7316762917, 6143091.089223046];
|
||||
|
||||
const source1 = new VectorSource();
|
||||
const layer1 = new VectorImageLayer({
|
||||
declutter: true,
|
||||
source: source1
|
||||
});
|
||||
|
||||
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'
|
||||
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'
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
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({
|
||||
const centerFeature = new Feature({
|
||||
geometry: new Point(center),
|
||||
text: 'center'
|
||||
}));
|
||||
source3.addFeature(new Feature({
|
||||
});
|
||||
source.addFeature(centerFeature);
|
||||
source.addFeature(new Feature({
|
||||
geometry: new Point([center[0] - 540, center[1]]),
|
||||
text: 'west'
|
||||
}));
|
||||
source3.addFeature(new Feature({
|
||||
source.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
|
||||
@@ -156,12 +57,23 @@ line.setStyle(new Style({
|
||||
text: new Text({
|
||||
placement: 'line',
|
||||
text: 'east-west',
|
||||
font: 'italic bold 18px Ubuntu',
|
||||
overflow: true
|
||||
font: '16px Ubuntu'
|
||||
})
|
||||
}));
|
||||
source4.addFeature(point);
|
||||
source4.addFeature(line);
|
||||
map.addLayer(layer4);
|
||||
source.addFeature(line);
|
||||
|
||||
render({tolerance: 0.007});
|
||||
const map = new Map({
|
||||
pixelRatio: 1,
|
||||
layers: [
|
||||
vectorLayer1
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: center,
|
||||
zoom: 13
|
||||
})
|
||||
});
|
||||
|
||||
map.getView().fit(source.getExtent());
|
||||
|
||||
render({tolerance: 0.02});
|
||||
|
||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
@@ -4,10 +4,8 @@ import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js
|
||||
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
|
||||
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
|
||||
import {Style, Stroke} from '../../../src/ol/style.js';
|
||||
import Feature from '../../../src/ol/Feature.js';
|
||||
import Point from '../../../src/ol/geom/Point.js';
|
||||
|
||||
const map = new Map({
|
||||
new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
@@ -16,7 +14,6 @@ const map = new Map({
|
||||
})
|
||||
}),
|
||||
new VectorLayer({
|
||||
zIndex: 1,
|
||||
style: new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255,255,255,0.5)',
|
||||
@@ -36,11 +33,4 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
const unmanaged = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
features: [new Feature(new Point([0, 0]))]
|
||||
})
|
||||
});
|
||||
unmanaged.setMap(map);
|
||||
|
||||
render();
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "tschaub/react"
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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;
|
||||
@@ -1,26 +0,0 @@
|
||||
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;
|
||||
@@ -1,35 +0,0 @@
|
||||
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;
|
||||
@@ -1,26 +0,0 @@
|
||||
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;
|
||||
@@ -1,20 +0,0 @@
|
||||
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;
|
||||
@@ -1,27 +0,0 @@
|
||||
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;
|
||||
@@ -1,8 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
import {baseSpacingPx} from '../util/typography';
|
||||
|
||||
export const Page = styled.div({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
margin: 2 * baseSpacingPx
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
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;
|
||||
@@ -1,33 +0,0 @@
|
||||
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
@@ -1,205 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
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,6 +6,7 @@ import {listen} from './events.js';
|
||||
import Event from './events/Event.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import {circular as circularPolygon} from './geom/Polygon.js';
|
||||
import {GEOLOCATION} from './has.js';
|
||||
import {toRadians} from './math.js';
|
||||
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';
|
||||
|
||||
@@ -82,7 +83,7 @@ class GeolocationError extends Event {
|
||||
* window.console.log(geolocation.getPosition());
|
||||
* });
|
||||
*
|
||||
* @fires module:ol/events/Event~Event#event:error
|
||||
* @fires error
|
||||
* @api
|
||||
*/
|
||||
class Geolocation extends BaseObject {
|
||||
@@ -159,7 +160,7 @@ class Geolocation extends BaseObject {
|
||||
* @private
|
||||
*/
|
||||
handleTrackingChanged_() {
|
||||
if ('geolocation' in navigator) {
|
||||
if (GEOLOCATION) {
|
||||
const tracking = this.getTracking();
|
||||
if (tracking && this.watchId_ === undefined) {
|
||||
this.watchId_ = navigator.geolocation.watchPosition(
|
||||
@@ -203,6 +204,12 @@ class Geolocation extends BaseObject {
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when the Geolocation returns an error.
|
||||
* @event error
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {PositionError} error error object.
|
||||
|
||||
@@ -58,9 +58,9 @@ class ImageWrapper extends ImageBase {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function():void}
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.unlisten_ = null;
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
@@ -120,12 +120,13 @@ class ImageWrapper extends ImageBase {
|
||||
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
|
||||
this.state = ImageState.LOADING;
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.imageLoadFunction_(this, this.src_);
|
||||
this.unlisten_ = listenImage(
|
||||
this.image_,
|
||||
this.handleImageLoad_.bind(this),
|
||||
this.handleImageError_.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,47 +143,10 @@ class ImageWrapper extends ImageBase {
|
||||
* @private
|
||||
*/
|
||||
unlistenImage_() {
|
||||
if (this.unlisten_) {
|
||||
this.unlisten_();
|
||||
this.unlisten_ = null;
|
||||
}
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = 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;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
import {listenImage} from './Image.js';
|
||||
import {listenOnce, unlistenByKey} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
|
||||
|
||||
class ImageTile extends Tile {
|
||||
@@ -46,9 +47,9 @@ class ImageTile extends Tile {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function():void}
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.unlisten_ = null;
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -133,12 +134,13 @@ class ImageTile extends Tile {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.state = TileState.LOADING;
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.tileLoadFunction_(this, this.src_);
|
||||
this.unlisten_ = listenImage(
|
||||
this.image_,
|
||||
this.handleImageLoad_.bind(this),
|
||||
this.handleImageError_.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,10 +150,8 @@ class ImageTile extends Tile {
|
||||
* @private
|
||||
*/
|
||||
unlistenImage_() {
|
||||
if (this.unlisten_) {
|
||||
this.unlisten_();
|
||||
this.unlisten_ = null;
|
||||
}
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @module ol/Map
|
||||
*/
|
||||
import PluggableMap from './PluggableMap.js';
|
||||
import {defaults as defaultControls} from './control.js';
|
||||
import {defaults as defaultControls} from './control/util.js';
|
||||
import {defaults as defaultInteractions} from './interaction.js';
|
||||
import {assign} from './obj.js';
|
||||
import CompositeMapRenderer from './renderer/Composite.js';
|
||||
|
||||
@@ -39,7 +39,6 @@ import {create as createTransform, apply as applyTransform} from './transform.js
|
||||
* @property {boolean} animate
|
||||
* @property {import("./transform.js").Transform} coordinateToPixelTransform
|
||||
* @property {null|import("./extent.js").Extent} extent
|
||||
* @property {Array<*>} declutterItems
|
||||
* @property {import("./coordinate.js").Coordinate} focus
|
||||
* @property {number} index
|
||||
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
|
||||
@@ -293,11 +292,6 @@ class PluggableMap extends BaseObject {
|
||||
*/
|
||||
this.interactions = optionsInternal.interactions || new Collection();
|
||||
|
||||
/**
|
||||
* @type {import("./events.js").EventsKey}
|
||||
*/
|
||||
this.labelCacheListenerKey_;
|
||||
|
||||
/**
|
||||
* @type {Collection<import("./Overlay.js").default>}
|
||||
* @private
|
||||
@@ -503,24 +497,6 @@ class PluggableMap extends BaseObject {
|
||||
overlay.setMap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a label cache for listening to font changes.
|
||||
* @param {import("./events/Target.js").default} labelCache Label cache.
|
||||
*/
|
||||
attachLabelCache(labelCache) {
|
||||
this.detachLabelCache();
|
||||
this.labelCacheListenerKey_ = listen(labelCache, EventType.CLEAR, this.redrawText.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach the label cache, i.e. no longer listen to font changes.
|
||||
*/
|
||||
detachLabelCache() {
|
||||
if (this.labelCacheListenerKey_) {
|
||||
unlistenByKey(this.labelCacheListenerKey_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @inheritDoc
|
||||
@@ -538,7 +514,6 @@ class PluggableMap extends BaseObject {
|
||||
cancelAnimationFrame(this.animationDelayKey_);
|
||||
this.animationDelayKey_ = undefined;
|
||||
}
|
||||
this.detachLabelCache();
|
||||
this.setTarget(null);
|
||||
super.disposeInternal();
|
||||
}
|
||||
@@ -787,21 +762,6 @@ class PluggableMap extends BaseObject {
|
||||
return layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Layers have sources that are still loading.
|
||||
*/
|
||||
getLoading() {
|
||||
const layerStatesArray = this.getLayerGroup().getLayerStatesArray();
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layer = layerStatesArray[i].layer;
|
||||
const source = /** @type {import("./layer/Layer.js").default} */ (layer).getSource();
|
||||
if (source && source.loading) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pixel for a coordinate. This takes a coordinate in the map view
|
||||
* projection and returns the corresponding pixel.
|
||||
@@ -989,7 +949,7 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
|
||||
if (frameState && this.hasListener(RenderEventType.RENDERCOMPLETE) && !frameState.animate &&
|
||||
!this.tileQueue_.getTilesLoading() && !this.getLoading()) {
|
||||
!this.tileQueue_.getTilesLoading() && !getLoading(this.getLayers().getArray())) {
|
||||
this.renderer_.dispatchRenderEvent(RenderEventType.RENDERCOMPLETE, frameState);
|
||||
}
|
||||
|
||||
@@ -1033,6 +993,7 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
|
||||
if (!targetElement) {
|
||||
this.renderer_.removeLayerRenderers();
|
||||
removeNode(this.viewport_);
|
||||
if (this.handleResize_ !== undefined) {
|
||||
removeEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
@@ -1140,19 +1101,6 @@ class PluggableMap extends BaseObject {
|
||||
this.animationDelay_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraws all text after new fonts have loaded
|
||||
*/
|
||||
redrawText() {
|
||||
const layerStates = this.getLayerGroup().getLayerStatesArray();
|
||||
for (let i = 0, ii = layerStates.length; i < ii; ++i) {
|
||||
const layer = layerStates[i].layer;
|
||||
if (layer.hasRenderer()) {
|
||||
layer.getRenderer().handleFontsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a map rendering (at the next animation frame).
|
||||
* @api
|
||||
@@ -1227,7 +1175,6 @@ class PluggableMap extends BaseObject {
|
||||
frameState = /** @type {FrameState} */ ({
|
||||
animate: false,
|
||||
coordinateToPixelTransform: this.coordinateToPixelTransform_,
|
||||
declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
|
||||
extent: extent,
|
||||
focus: this.focus_ ? this.focus_ : viewState.center,
|
||||
index: this.frameIndex_++,
|
||||
@@ -1449,3 +1396,23 @@ function createOptionsInternal(options) {
|
||||
|
||||
}
|
||||
export default PluggableMap;
|
||||
|
||||
/**
|
||||
* @param {Array<import("./layer/Base.js").default>} layers Layers.
|
||||
* @return {boolean} Layers have sources that are still loading.
|
||||
*/
|
||||
function getLoading(layers) {
|
||||
for (let i = 0, ii = layers.length; i < ii; ++i) {
|
||||
const layer = layers[i];
|
||||
if (typeof /** @type {?} */ (layer).getLayers === 'function') {
|
||||
return getLoading(/** @type {LayerGroup} */ (layer).getLayers().getArray());
|
||||
} else {
|
||||
const source = /** @type {import("./layer/Layer.js").default} */ (
|
||||
layer).getSource();
|
||||
if (source && source.loading) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -191,11 +191,6 @@ const DEFAULT_MIN_ZOOM = 0;
|
||||
* This is the object to act upon to change the center, resolution,
|
||||
* and rotation of the map.
|
||||
*
|
||||
* A View has a `projection`. The projection determines the
|
||||
* coordinate system of the center, and its units determine the units of the
|
||||
* resolution (projection units per pixel). The default projection is
|
||||
* Spherical Mercator (EPSG:3857).
|
||||
*
|
||||
* ### The view states
|
||||
*
|
||||
* An View is determined by three states: `center`, `resolution`,
|
||||
@@ -207,6 +202,11 @@ const DEFAULT_MIN_ZOOM = 0;
|
||||
* methods are available, as well as `getResolutionForZoom` and
|
||||
* `getZoomForResolution` to switch from one system to the other.
|
||||
*
|
||||
* A View has a `projection`. The projection determines the
|
||||
* coordinate system of the center, and its units determine the units of the
|
||||
* resolution (projection units per pixel). The default projection is
|
||||
* Spherical Mercator (EPSG:3857).
|
||||
*
|
||||
* ### The constraints
|
||||
*
|
||||
* `setCenter`, `setResolution` and `setRotation` can be used to change the
|
||||
@@ -218,7 +218,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
||||
*
|
||||
* The *resolution constraint* typically restricts min/max values and
|
||||
* snaps to specific resolutions. It is determined by the following
|
||||
* options: `resolutions`, `maxResolution`, `maxZoom` and `zoomFactor`.
|
||||
* options: `resolutions`, `maxResolution`, `maxZoom`, and `zoomFactor`.
|
||||
* If `resolutions` is set, the other three options are ignored. See
|
||||
* documentation for each option for more information. By default, the view
|
||||
* only has a min/max restriction and allow intermediary zoom levels when
|
||||
@@ -226,7 +226,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
||||
*
|
||||
* The *rotation constraint* snaps to specific angles. It is determined
|
||||
* by the following options: `enableRotation` and `constrainRotation`.
|
||||
* By default rotation is allowed and its value is snapped to zero when approaching the
|
||||
* By default the rotation value is snapped to zero when approaching the
|
||||
* horizontal.
|
||||
*
|
||||
* The *center constraint* is determined by the `extent` option. By
|
||||
@@ -1409,19 +1409,11 @@ function animationCallback(callback, returnValue) {
|
||||
*/
|
||||
export function createCenterConstraint(options) {
|
||||
if (options.extent !== undefined) {
|
||||
const smooth = options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true;
|
||||
return createExtent(options.extent, options.constrainOnlyCenter, smooth);
|
||||
return createExtent(options.extent, options.constrainOnlyCenter,
|
||||
options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true);
|
||||
} 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,10 +1,6 @@
|
||||
/**
|
||||
* @module ol/control
|
||||
*/
|
||||
import Collection from './Collection.js';
|
||||
import Attribution from './control/Attribution.js';
|
||||
import Rotate from './control/Rotate.js';
|
||||
import Zoom from './control/Zoom.js';
|
||||
|
||||
export {default as Attribution} from './control/Attribution.js';
|
||||
export {default as Control} from './control/Control.js';
|
||||
@@ -16,59 +12,4 @@ export {default as ScaleLine} from './control/ScaleLine.js';
|
||||
export {default as Zoom} from './control/Zoom.js';
|
||||
export {default as ZoomSlider} from './control/ZoomSlider.js';
|
||||
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
export {defaults} from './control/util.js';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @module ol/control/OverviewMap
|
||||
*/
|
||||
import PluggableMap from '../PluggableMap.js';
|
||||
import CompositeMapRenderer from '../renderer/Composite.js';
|
||||
import Collection from '../Collection.js';
|
||||
import Map from '../Map.js';
|
||||
import MapEventType from '../MapEventType.js';
|
||||
import MapProperty from '../MapProperty.js';
|
||||
import {getChangeEventType} from '../Object.js';
|
||||
@@ -35,13 +35,6 @@ const MAX_RATIO = 0.75;
|
||||
const MIN_RATIO = 0.1;
|
||||
|
||||
|
||||
class ControlledMap extends PluggableMap {
|
||||
createRenderer() {
|
||||
return new CompositeMapRenderer(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} [className='ol-overviewmap'] CSS class name.
|
||||
@@ -150,10 +143,12 @@ class OverviewMap extends Control {
|
||||
this.ovmapDiv_.className = 'ol-overviewmap-map';
|
||||
|
||||
/**
|
||||
* @type {ControlledMap}
|
||||
* @type {import("../Map.js").default}
|
||||
* @private
|
||||
*/
|
||||
this.ovmap_ = new ControlledMap({
|
||||
this.ovmap_ = new Map({
|
||||
controls: new Collection(),
|
||||
interactions: new Collection(),
|
||||
view: options.view
|
||||
});
|
||||
const ovmap = this.ovmap_;
|
||||
|
||||
65
src/ol/control/util.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @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,13 +14,6 @@ export default {
|
||||
*/
|
||||
CHANGE: 'change',
|
||||
|
||||
/**
|
||||
* Generic error event. Triggered when an error occurs.
|
||||
* @event module:ol/events/Event~Event#error
|
||||
* @api
|
||||
*/
|
||||
ERROR: 'error',
|
||||
|
||||
CLEAR: 'clear',
|
||||
CONTEXTMENU: 'contextmenu',
|
||||
CLICK: 'click',
|
||||
@@ -28,6 +21,7 @@ export default {
|
||||
DRAGENTER: 'dragenter',
|
||||
DRAGOVER: 'dragover',
|
||||
DROP: 'drop',
|
||||
ERROR: 'error',
|
||||
KEYDOWN: 'keydown',
|
||||
KEYPRESS: 'keypress',
|
||||
LOAD: 'load',
|
||||
|
||||
@@ -7,7 +7,6 @@ export {default as GeoJSON} from './format/GeoJSON.js';
|
||||
export {default as GML} from './format/GML.js';
|
||||
export {default as GPX} from './format/GPX.js';
|
||||
export {default as IGC} from './format/IGC.js';
|
||||
export {default as IIIFInfo} from './format/IIIFInfo.js';
|
||||
export {default as KML} from './format/KML.js';
|
||||
export {default as MVT} from './format/MVT.js';
|
||||
export {default as OWS} from './format/OWS.js';
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
/**
|
||||
* @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,6 +2684,13 @@ function writePlacemark(node, feature, objectStack) {
|
||||
return !filter[v];
|
||||
});
|
||||
|
||||
if (keys.length > 0) {
|
||||
const sequence = makeSequence(properties, keys);
|
||||
const namesAndValues = {names: keys, values: sequence};
|
||||
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
||||
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
|
||||
}
|
||||
|
||||
const styleFunction = feature.getStyleFunction();
|
||||
if (styleFunction) {
|
||||
// FIXME the styles returned by the style function are supposed to be
|
||||
@@ -2706,13 +2713,6 @@ function writePlacemark(node, feature, objectStack) {
|
||||
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
||||
OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
|
||||
|
||||
if (keys.length > 0) {
|
||||
const sequence = makeSequence(properties, keys);
|
||||
const namesAndValues = {names: keys, values: sequence};
|
||||
pushSerializeAndPop(context, PLACEMARK_SERIALIZERS,
|
||||
EXTENDEDDATA_NODE_FACTORY, [namesAndValues], objectStack);
|
||||
}
|
||||
|
||||
// serialize geometry
|
||||
const options = /** @type {import("./Feature.js").WriteOptions} */ (objectStack[0]);
|
||||
let geometry = feature.getGeometry();
|
||||
|
||||
@@ -16,8 +16,8 @@ import {lerp} from '../../math.js';
|
||||
* @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width.
|
||||
* @param {string} font The font.
|
||||
* @param {Object<string, number>} cache A cache of measured widths.
|
||||
* @return {Array<Array<*>>} The result array (or null if `maxAngle` was
|
||||
* exceeded). Entries of the array are x, y, anchorX, angle, chunk.
|
||||
* @return {Array<Array<*>>} The result array of null if `maxAngle` was
|
||||
* exceeded. Entries of the array are x, y, anchorX, angle, chunk.
|
||||
*/
|
||||
export function drawTextOnPath(
|
||||
flatCoordinates, offset, end, stride, text, startM, maxAngle, scale, measureAndCacheTextWidth, font, cache) {
|
||||
@@ -35,13 +35,16 @@ export function drawTextOnPath(
|
||||
let y2 = flatCoordinates[offset + 1];
|
||||
let segmentM = 0;
|
||||
let segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||
let angleChanged = false;
|
||||
|
||||
let index, previousAngle;
|
||||
let chunk = '';
|
||||
let chunkLength = 0;
|
||||
let data, index, previousAngle;
|
||||
for (let i = 0; i < numChars; ++i) {
|
||||
index = reverse ? numChars - i - 1 : i;
|
||||
const char = text[index];
|
||||
const charLength = scale * measureAndCacheTextWidth(font, char, cache);
|
||||
const char = text.charAt(index);
|
||||
chunk = reverse ? char + chunk : chunk + char;
|
||||
const charLength = scale * measureAndCacheTextWidth(font, chunk, cache) - chunkLength;
|
||||
chunkLength += charLength;
|
||||
const charM = startM + charLength / 2;
|
||||
while (offset < end - stride && segmentM + segmentLength < charM) {
|
||||
x1 = x2;
|
||||
@@ -59,18 +62,33 @@ export function drawTextOnPath(
|
||||
}
|
||||
if (previousAngle !== undefined) {
|
||||
let delta = angle - previousAngle;
|
||||
angleChanged = angleChanged || delta !== 0;
|
||||
delta += (delta > Math.PI) ? -2 * Math.PI : (delta < -Math.PI) ? 2 * Math.PI : 0;
|
||||
if (Math.abs(delta) > maxAngle) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
previousAngle = angle;
|
||||
const interpolate = segmentPos / segmentLength;
|
||||
const x = lerp(x1, x2, interpolate);
|
||||
const y = lerp(y1, y2, interpolate);
|
||||
result[index] = [x, y, charLength / 2, angle, char];
|
||||
if (previousAngle == angle) {
|
||||
if (reverse) {
|
||||
data[0] = x;
|
||||
data[1] = y;
|
||||
data[2] = charLength / 2;
|
||||
}
|
||||
data[4] = chunk;
|
||||
} else {
|
||||
chunk = char;
|
||||
chunkLength = charLength;
|
||||
data = [x, y, charLength / 2, angle, chunk];
|
||||
if (reverse) {
|
||||
result.unshift(data);
|
||||
} else {
|
||||
result.push(data);
|
||||
}
|
||||
previousAngle = angle;
|
||||
}
|
||||
startM += charLength;
|
||||
}
|
||||
return angleChanged ? result : [[result[0][0], result[0][1], result[0][2], result[0][3], text]];
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,15 @@ export const MAC = ua.indexOf('macintosh') !== -1;
|
||||
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
|
||||
|
||||
|
||||
/**
|
||||
* Is HTML5 geolocation supported in the current browser?
|
||||
* @const
|
||||
* @type {boolean}
|
||||
* @api
|
||||
*/
|
||||
export const GEOLOCATION = 'geolocation' in navigator;
|
||||
|
||||
|
||||
/**
|
||||
* True if browser supports touch events.
|
||||
* @const
|
||||
|
||||
@@ -73,10 +73,6 @@ class DragPan extends PointerInteraction {
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleDragEvent(mapBrowserEvent) {
|
||||
if (!this.panning_) {
|
||||
this.panning_ = true;
|
||||
this.getMap().getView().beginInteraction();
|
||||
}
|
||||
const targetPointers = this.targetPointers;
|
||||
const centroid = centroidFromPointers(targetPointers);
|
||||
if (targetPointers.length == this.lastPointersCount_) {
|
||||
@@ -153,6 +149,10 @@ class DragPan extends PointerInteraction {
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
}
|
||||
if (!this.panning_) {
|
||||
this.panning_ = true;
|
||||
this.getMap().getView().beginInteraction();
|
||||
}
|
||||
if (this.kinetic_) {
|
||||
this.kinetic_.begin();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import {createEditingStyle} from '../style/Style.js';
|
||||
const ExtentEventType = {
|
||||
/**
|
||||
* Triggered after the extent is changed
|
||||
* @event ExtentEvent#extentchanged
|
||||
* @event ExtentEventType#extentchanged
|
||||
* @api
|
||||
*/
|
||||
EXTENTCHANGED: 'extentchanged'
|
||||
@@ -47,10 +47,10 @@ const ExtentEventType = {
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/interaction/Extent~Extent} instances are
|
||||
* Events emitted by {@link module:ol/interaction/Extent~ExtentInteraction} instances are
|
||||
* instances of this type.
|
||||
*/
|
||||
class ExtentEvent extends Event {
|
||||
class ExtentInteractionEvent extends Event {
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent the new extent
|
||||
@@ -75,10 +75,10 @@ class ExtentEvent extends Event {
|
||||
* Once drawn, the vector box can be modified by dragging its vertices or edges.
|
||||
* This interaction is only supported for mouse devices.
|
||||
*
|
||||
* @fires ExtentEvent
|
||||
* @fires Event
|
||||
* @api
|
||||
*/
|
||||
class Extent extends PointerInteraction {
|
||||
class ExtentInteraction extends PointerInteraction {
|
||||
/**
|
||||
* @param {Options=} opt_options Options.
|
||||
*/
|
||||
@@ -399,7 +399,7 @@ class Extent extends PointerInteraction {
|
||||
//Null extent means no bbox
|
||||
this.extent_ = extent ? extent : null;
|
||||
this.createOrUpdateExtentFeature_(extent);
|
||||
this.dispatchEvent(new ExtentEvent(this.extent_));
|
||||
this.dispatchEvent(new ExtentInteractionEvent(this.extent_));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,4 +470,4 @@ function getSegments(extent) {
|
||||
}
|
||||
|
||||
|
||||
export default Extent;
|
||||
export default ExtentInteraction;
|
||||
|
||||
@@ -83,20 +83,19 @@ class BaseLayer extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean=} opt_managed Layer is managed.
|
||||
* @return {import("./Layer.js").State} Layer state.
|
||||
*/
|
||||
getLayerState(opt_managed) {
|
||||
getLayerState() {
|
||||
/** @type {import("./Layer.js").State} */
|
||||
const state = this.state_ || /** @type {?} */ ({
|
||||
layer: this,
|
||||
managed: opt_managed === undefined ? true : opt_managed
|
||||
managed: true
|
||||
});
|
||||
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
||||
state.sourceState = this.getSourceState();
|
||||
state.visible = this.getVisible();
|
||||
state.extent = this.getExtent();
|
||||
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
|
||||
state.zIndex = this.getZIndex() || 0;
|
||||
state.maxResolution = this.getMaxResolution();
|
||||
state.minResolution = Math.max(this.getMinResolution(), 0);
|
||||
this.state_ = state;
|
||||
|
||||
@@ -8,7 +8,6 @@ import {assign} from '../obj.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
|
||||
* @property {number} [opacity=1] Opacity (0, 1).
|
||||
* @property {boolean} [visible=true] Visibility.
|
||||
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be
|
||||
|
||||
@@ -32,10 +32,8 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
|
||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||
* use {@link module:ol/Map#addLayer}.
|
||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
||||
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
|
||||
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
|
||||
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
|
||||
* higher priority.
|
||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
||||
* means higher priority.
|
||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
||||
|
||||
@@ -10,10 +10,6 @@ import {assign} from '../obj.js';
|
||||
import RenderEventType from '../render/EventType.js';
|
||||
import SourceState from '../source/State.js';
|
||||
|
||||
/**
|
||||
* @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
@@ -33,8 +29,6 @@ import SourceState from '../source/State.js';
|
||||
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
|
||||
* construction.
|
||||
* @property {import("../PluggableMap.js").default} [map] Map.
|
||||
* @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an
|
||||
* HTML element. Will overwrite the default rendering for the layer.
|
||||
*/
|
||||
|
||||
|
||||
@@ -53,10 +47,8 @@ import SourceState from '../source/State.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Base class from which all layer types are derived. This should only be instantiated
|
||||
* in the case where a custom layer is be added to the map with a custom `render` function.
|
||||
* Such a function can be specified in the `options` object, and is expected to return an HTML element.
|
||||
*
|
||||
* Abstract base class; normally only used for creating subclasses and not
|
||||
* instantiated in apps.
|
||||
* A visual representation of raster or vector map data.
|
||||
* Layers group together those properties that pertain to how the data is to be
|
||||
* displayed, irrespective of the source of that data.
|
||||
@@ -72,7 +64,6 @@ import SourceState from '../source/State.js';
|
||||
* @fires import("../render/Event.js").RenderEvent#postrender
|
||||
*
|
||||
* @template {import("../source/Source.js").default} SourceType
|
||||
* @api
|
||||
*/
|
||||
class Layer extends BaseLayer {
|
||||
/**
|
||||
@@ -109,11 +100,6 @@ class Layer extends BaseLayer {
|
||||
*/
|
||||
this.renderer_ = null;
|
||||
|
||||
// Overwrite default render method with a custom one
|
||||
if (options.render) {
|
||||
this.render = options.render;
|
||||
}
|
||||
|
||||
if (options.map) {
|
||||
this.setMap(options.map);
|
||||
}
|
||||
@@ -226,7 +212,12 @@ class Layer extends BaseLayer {
|
||||
if (map) {
|
||||
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
|
||||
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
|
||||
renderEvent.frameState.layerStatesArray.push(this.getLayerState(false));
|
||||
const layerState = this.getLayerState();
|
||||
layerState.managed = false;
|
||||
if (this.getZIndex() === undefined) {
|
||||
layerState.zIndex = Infinity;
|
||||
}
|
||||
renderEvent.frameState.layerStatesArray.push(layerState);
|
||||
}, this);
|
||||
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
|
||||
this.changed();
|
||||
@@ -254,13 +245,6 @@ class Layer extends BaseLayer {
|
||||
return this.renderer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} The layer has a renderer.
|
||||
*/
|
||||
hasRenderer() {
|
||||
return !!this.renderer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a renderer for this layer.
|
||||
* @return {import("../renderer/Layer.js").default} A layer renderer.
|
||||
|
||||
@@ -30,9 +30,9 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
|
||||
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
|
||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||
* use {@link module:ol/Map#addLayer}.
|
||||
* @property {boolean} [declutter=false] Declutter images and text on this layer. The priority is defined
|
||||
* by the `zIndex` of the style and the render order of features. Higher z-index means higher priority.
|
||||
* Within the same z-index, a feature rendered before another has higher priority.
|
||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
||||
* means higher priority.
|
||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
||||
|
||||
@@ -46,10 +46,8 @@ import {assign} from '../obj.js';
|
||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||
* use {@link module:ol/Map#addLayer}.
|
||||
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
|
||||
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
|
||||
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
|
||||
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
|
||||
* higher priority.
|
||||
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
|
||||
* means higher priority.
|
||||
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
|
||||
* {@link module:ol/style} for default style which will be used if this is not defined.
|
||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @module ol/math
|
||||
*/
|
||||
import {assert} from './asserts.js';
|
||||
|
||||
/**
|
||||
* Takes a number and clamps it to within the provided bounds.
|
||||
@@ -42,6 +43,16 @@ export const cosh = (function() {
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} x X.
|
||||
* @return {number} The smallest power of two greater than or equal to x.
|
||||
*/
|
||||
export function roundUpToPowerOfTwo(x) {
|
||||
assert(0 < x, 29); // `x` must be greater than `0`
|
||||
return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the square of the closest distance between the point (x, y) and the
|
||||
* line segment (x1, y1) to (x2, y2).
|
||||
|
||||
@@ -127,6 +127,11 @@
|
||||
right: .5em;
|
||||
top: .5em;
|
||||
}
|
||||
@media print {
|
||||
.ol-control {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ol-control button {
|
||||
display: block;
|
||||
|
||||
@@ -110,23 +110,3 @@ export function getRenderPixel(event, pixel) {
|
||||
applyTransform(event.inversePixelTransform.slice(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @param {?} declutterTree Declutter tree.
|
||||
* @returns {?} Declutter tree.
|
||||
*/
|
||||
export function renderDeclutterItems(frameState, declutterTree) {
|
||||
if (declutterTree) {
|
||||
declutterTree.clear();
|
||||
}
|
||||
const items = frameState.declutterItems;
|
||||
for (let z = items.length - 1; z >= 0; --z) {
|
||||
const zIndexItems = items[z];
|
||||
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
|
||||
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree);
|
||||
}
|
||||
}
|
||||
items.length = 0;
|
||||
return declutterTree;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import Disposable from '../../Disposable.js';
|
||||
import RBush from 'rbush';
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,10 +58,15 @@ class Executor extends Disposable {
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @param {?} declutterTree Declutter tree.
|
||||
* @param {SerializableInstructions} instructions The serializable instructions
|
||||
*/
|
||||
constructor(resolution, pixelRatio, overlaps, instructions) {
|
||||
constructor(resolution, pixelRatio, overlaps, declutterTree, instructions) {
|
||||
super();
|
||||
/**
|
||||
* @type {?}
|
||||
*/
|
||||
this.declutterTree = declutterTree;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
@@ -89,11 +93,6 @@ class Executor extends Disposable {
|
||||
*/
|
||||
this.alignFill_;
|
||||
|
||||
/**
|
||||
* @type {Array<*>}
|
||||
*/
|
||||
this.declutterItems = [];
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Array<*>}
|
||||
@@ -193,10 +192,9 @@ class Executor extends Disposable {
|
||||
const width = measureTextWidths(textState.font, lines, widths);
|
||||
const lineHeight = measureTextHeight(textState.font);
|
||||
const height = lineHeight * numLines;
|
||||
const renderWidth = width + strokeWidth;
|
||||
const renderWidth = (width + strokeWidth);
|
||||
const context = createCanvasContext2D(
|
||||
// make canvas 2 pixels wider to account for italic text width measurement errors
|
||||
Math.ceil((renderWidth + 2) * scale),
|
||||
Math.ceil(renderWidth * scale),
|
||||
Math.ceil((height + strokeWidth) * scale));
|
||||
label = context.canvas;
|
||||
labelCache.set(key, label);
|
||||
@@ -221,7 +219,7 @@ class Executor extends Disposable {
|
||||
context.textBaseline = 'middle';
|
||||
context.textAlign = 'center';
|
||||
const leftRight = (0.5 - align);
|
||||
const x = align * renderWidth + leftRight * strokeWidth;
|
||||
const x = align * label.width / scale + leftRight * strokeWidth;
|
||||
let i;
|
||||
if (strokeKey) {
|
||||
for (i = 0; i < numLines; ++i) {
|
||||
@@ -414,10 +412,8 @@ class Executor extends Disposable {
|
||||
/**
|
||||
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
||||
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
||||
* @param {?} declutterTree Declutter tree.
|
||||
* @return {?} Declutter tree.
|
||||
*/
|
||||
renderDeclutter(declutterGroup, feature, declutterTree) {
|
||||
renderDeclutter_(declutterGroup, feature) {
|
||||
if (declutterGroup && declutterGroup.length > 5) {
|
||||
const groupCount = declutterGroup[4];
|
||||
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
|
||||
@@ -429,11 +425,8 @@ class Executor extends Disposable {
|
||||
maxY: /** @type {number} */ (declutterGroup[3]),
|
||||
value: feature
|
||||
};
|
||||
if (!declutterTree) {
|
||||
declutterTree = new RBush(9);
|
||||
}
|
||||
if (!declutterTree.collides(box)) {
|
||||
declutterTree.insert(box);
|
||||
if (!this.declutterTree.collides(box)) {
|
||||
this.declutterTree.insert(box);
|
||||
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
|
||||
const declutterData = /** @type {Array} */ (declutterGroup[j]);
|
||||
if (declutterData) {
|
||||
@@ -450,7 +443,6 @@ class Executor extends Disposable {
|
||||
createOrUpdateEmpty(declutterGroup);
|
||||
}
|
||||
}
|
||||
return declutterTree;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -472,9 +464,7 @@ class Executor extends Disposable {
|
||||
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
|
||||
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
|
||||
// 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 anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
||||
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||
|
||||
return {
|
||||
@@ -507,7 +497,6 @@ class Executor extends Disposable {
|
||||
featureCallback,
|
||||
opt_hitExtent
|
||||
) {
|
||||
this.declutterItems.length = 0;
|
||||
/** @type {Array<number>} */
|
||||
let pixelCoordinates;
|
||||
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
|
||||
@@ -681,7 +670,7 @@ class Executor extends Disposable {
|
||||
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
|
||||
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
|
||||
}
|
||||
this.declutterItems.push(this, declutterGroup, feature);
|
||||
this.renderDeclutter_(declutterGroup, feature);
|
||||
++i;
|
||||
break;
|
||||
case CanvasInstruction.DRAW_CHARS:
|
||||
@@ -750,7 +739,7 @@ class Executor extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.declutterItems.push(this, declutterGroup, feature);
|
||||
this.renderDeclutter_(declutterGroup, feature);
|
||||
++i;
|
||||
break;
|
||||
case CanvasInstruction.END_GEOMETRY:
|
||||
|
||||
@@ -35,12 +35,18 @@ class ExecutorGroup extends Disposable {
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {boolean} overlaps The executor group can have overlapping geometries.
|
||||
* @param {?} declutterTree Declutter tree for declutter processing in postrender.
|
||||
* @param {!Object<string, !Object<BuilderType, import("./Builder.js").SerializableInstructions>>} allInstructions
|
||||
* The serializable instructions.
|
||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||
*/
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, allInstructions, opt_renderBuffer) {
|
||||
super();
|
||||
/**
|
||||
* Declutter tree.
|
||||
* @private
|
||||
*/
|
||||
this.declutterTree_ = declutterTree;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -82,7 +88,7 @@ class ExecutorGroup extends Disposable {
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.hitDetectionContext_ = null;
|
||||
this.hitDetectionContext_ = createCanvasContext2D(1, 1);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -122,7 +128,7 @@ class ExecutorGroup extends Disposable {
|
||||
for (const builderType in instructionByZindex) {
|
||||
const instructions = instructionByZindex[builderType];
|
||||
executors[builderType] = new Executor(
|
||||
this.resolution_, this.pixelRatio_, this.overlaps_, instructions);
|
||||
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_, instructions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,11 +143,8 @@ class ExecutorGroup extends Disposable {
|
||||
executors[key].disposeInternal();
|
||||
}
|
||||
}
|
||||
if (this.hitDetectionContext_) {
|
||||
const canvas = this.hitDetectionContext_.canvas;
|
||||
canvas.width = canvas.height = 0;
|
||||
}
|
||||
|
||||
const canvas = this.hitDetectionContext_.canvas;
|
||||
canvas.width = canvas.height = 0;
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
@@ -169,7 +172,7 @@ class ExecutorGroup extends Disposable {
|
||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
|
||||
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
|
||||
* @param {Object<string, import("../canvas.js").DeclutterGroup>} declutterReplays Declutter replays.
|
||||
* @return {T|undefined} Callback result.
|
||||
* @template T
|
||||
*/
|
||||
@@ -180,7 +183,7 @@ class ExecutorGroup extends Disposable {
|
||||
hitTolerance,
|
||||
skippedFeaturesHash,
|
||||
callback,
|
||||
declutteredFeatures
|
||||
declutterReplays
|
||||
) {
|
||||
|
||||
hitTolerance = Math.round(hitTolerance);
|
||||
@@ -190,10 +193,6 @@ class ExecutorGroup extends Disposable {
|
||||
1 / resolution, -1 / resolution,
|
||||
-rotation,
|
||||
-coordinate[0], -coordinate[1]);
|
||||
|
||||
if (!this.hitDetectionContext_) {
|
||||
this.hitDetectionContext_ = createCanvasContext2D(contextSize, contextSize);
|
||||
}
|
||||
const context = this.hitDetectionContext_;
|
||||
|
||||
if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
|
||||
@@ -214,6 +213,12 @@ class ExecutorGroup extends Disposable {
|
||||
}
|
||||
|
||||
const mask = getCircleArray(hitTolerance);
|
||||
let declutteredFeatures;
|
||||
if (this.declutterTree_) {
|
||||
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
|
||||
return entry.value;
|
||||
});
|
||||
}
|
||||
|
||||
let builderType;
|
||||
|
||||
@@ -256,10 +261,20 @@ class ExecutorGroup extends Disposable {
|
||||
builderType = ORDER[j];
|
||||
executor = executors[builderType];
|
||||
if (executor !== undefined) {
|
||||
result = executor.executeHitDetection(context, transform, rotation,
|
||||
skippedFeaturesHash, featureCallback, hitExtent);
|
||||
if (result) {
|
||||
return result;
|
||||
if (declutterReplays &&
|
||||
(builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) {
|
||||
const declutter = declutterReplays[zIndexKey];
|
||||
if (!declutter) {
|
||||
declutterReplays[zIndexKey] = [executor, transform.slice(0)];
|
||||
} else {
|
||||
declutter.push(executor, transform.slice(0));
|
||||
}
|
||||
} else {
|
||||
result = executor.executeHitDetection(context, transform, rotation,
|
||||
skippedFeaturesHash, featureCallback, hitExtent);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,20 +446,14 @@ export function getCircleArray(radius) {
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {number} rotation Rotation.
|
||||
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
|
||||
* @param {Array<Array<*>>} declutterItems Declutter items.
|
||||
*/
|
||||
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) {
|
||||
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel) {
|
||||
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
|
||||
const skippedFeatureUids = {};
|
||||
for (let z = 0, zz = zs.length; z < zz; ++z) {
|
||||
const executorData = declutterReplays[zs[z].toString()];
|
||||
let currentExecutor;
|
||||
for (let i = 0, ii = executorData.length; i < ii;) {
|
||||
const executor = executorData[i++];
|
||||
if (executor !== currentExecutor) {
|
||||
currentExecutor = executor;
|
||||
declutterItems.push(executor.declutterItems);
|
||||
}
|
||||
const transform = executorData[i++];
|
||||
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import RenderEventType from '../render/EventType.js';
|
||||
import MapRenderer from './Map.js';
|
||||
import SourceState from '../source/State.js';
|
||||
import {replaceChildren} from '../dom.js';
|
||||
import {labelCache} from '../render/canvas.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -23,7 +22,6 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
*/
|
||||
constructor(map) {
|
||||
super(map);
|
||||
map.attachLabelCache(labelCache);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -87,8 +85,7 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
this.children_.length = 0;
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layerState = layerStatesArray[i];
|
||||
if (!visibleAtResolution(layerState, viewResolution) ||
|
||||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
|
||||
if (!visibleAtResolution(layerState, viewResolution) || layerState.sourceState != SourceState.READY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -97,12 +94,11 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
if (element) {
|
||||
const zIndex = layerState.zIndex;
|
||||
if (zIndex !== element.style.zIndex) {
|
||||
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex;
|
||||
element.style.zIndex = zIndex;
|
||||
}
|
||||
this.children_.push(element);
|
||||
}
|
||||
}
|
||||
super.renderFrame(frameState);
|
||||
|
||||
replaceChildren(this.element_, this.children_);
|
||||
|
||||
@@ -113,6 +109,7 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
this.scheduleRemoveUnusedLayerRenderers(frameState);
|
||||
this.scheduleExpireIconCache(frameState);
|
||||
}
|
||||
|
||||
@@ -129,8 +126,11 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
for (let i = numLayers - 1; i >= 0; --i) {
|
||||
const layerState = layerStates[i];
|
||||
const layer = layerState.layer;
|
||||
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
|
||||
const layerRenderer = layer.getRenderer();
|
||||
if (visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
|
||||
const layerRenderer = this.getLayerRenderer(layer);
|
||||
if (!layerRenderer) {
|
||||
continue;
|
||||
}
|
||||
const data = layerRenderer.getDataAtPixel(pixel, frameState, hitTolerance);
|
||||
if (data) {
|
||||
const result = callback(layer, data);
|
||||
|
||||
@@ -89,11 +89,10 @@ class LayerRenderer extends Observable {
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
|
||||
* @param {Array<import("../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
|
||||
* @return {T|void} Callback result.
|
||||
* @template T
|
||||
*/
|
||||
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {}
|
||||
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
@@ -115,12 +114,6 @@ class LayerRenderer extends Observable {
|
||||
return this.layer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform action necessary to get the layer rendered after new fonts have loaded
|
||||
* @abstract
|
||||
*/
|
||||
handleFontsChanged() {}
|
||||
|
||||
/**
|
||||
* Handle changes in image state.
|
||||
* @param {import("../events/Event.js").default} event Image change event.
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
*/
|
||||
import {abstract, getUid} from '../util.js';
|
||||
import Disposable from '../Disposable.js';
|
||||
import {listen, unlistenByKey} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {getWidth} from '../extent.js';
|
||||
import {TRUE} from '../functions.js';
|
||||
import {visibleAtResolution} from '../layer/Layer.js';
|
||||
import {shared as iconImageCache} from '../style/IconImageCache.js';
|
||||
import {compose as composeTransform, makeInverse} from '../transform.js';
|
||||
import {renderDeclutterItems} from '../render.js';
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
@@ -29,8 +30,15 @@ class MapRenderer extends Disposable {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, import("./Layer.js").default>}
|
||||
*/
|
||||
this.declutterTree_ = null;
|
||||
this.layerRenderers_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object<string, import("../events.js").EventsKey>}
|
||||
*/
|
||||
this.layerRendererListeners_ = {};
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +69,15 @@ class MapRenderer extends Disposable {
|
||||
makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all layer renderers.
|
||||
*/
|
||||
removeLayerRenderers() {
|
||||
for (const key in this.layerRenderers_) {
|
||||
this.removeLayerRendererByKey_(key).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
||||
@@ -116,24 +133,18 @@ class MapRenderer extends Disposable {
|
||||
|
||||
const layerStates = frameState.layerStatesArray;
|
||||
const numLayers = layerStates.length;
|
||||
let declutteredFeatures;
|
||||
if (this.declutterTree_) {
|
||||
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
|
||||
return entry.value;
|
||||
});
|
||||
}
|
||||
let i;
|
||||
for (i = numLayers - 1; i >= 0; --i) {
|
||||
const layerState = layerStates[i];
|
||||
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
|
||||
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
|
||||
const layerRenderer = layer.getRenderer();
|
||||
if (visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
|
||||
const layerRenderer = this.getLayerRenderer(layer);
|
||||
const source = layer.getSource();
|
||||
if (layerRenderer && source) {
|
||||
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
||||
result = layerRenderer.forEachFeatureAtCoordinate(
|
||||
source.getWrapX() ? translatedCoordinate : coordinate,
|
||||
frameState, hitTolerance, callback, declutteredFeatures);
|
||||
frameState, hitTolerance, callback);
|
||||
}
|
||||
if (result) {
|
||||
return result;
|
||||
@@ -180,6 +191,35 @@ class MapRenderer extends Disposable {
|
||||
return hasFeature !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../layer/Layer.js").default} layer Layer.
|
||||
* @protected
|
||||
* @return {import("./Layer.js").default} Layer renderer. May return null.
|
||||
*/
|
||||
getLayerRenderer(layer) {
|
||||
const layerKey = getUid(layer);
|
||||
if (layerKey in this.layerRenderers_) {
|
||||
return this.layerRenderers_[layerKey];
|
||||
}
|
||||
|
||||
const renderer = layer.getRenderer();
|
||||
if (!renderer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.layerRenderers_[layerKey] = renderer;
|
||||
this.layerRendererListeners_[layerKey] = listen(renderer, EventType.CHANGE, this.handleLayerRendererChange_, this);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @return {Object<string, import("./Layer.js").default>} Layer renderers.
|
||||
*/
|
||||
getLayerRenderers() {
|
||||
return this.layerRenderers_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import("../PluggableMap.js").default} Map.
|
||||
*/
|
||||
@@ -187,12 +227,36 @@ class MapRenderer extends Disposable {
|
||||
return this.map_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changes in a layer renderer.
|
||||
* @private
|
||||
*/
|
||||
handleLayerRendererChange_() {
|
||||
this.map_.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} layerKey Layer key.
|
||||
* @return {import("./Layer.js").default} Layer renderer.
|
||||
* @private
|
||||
*/
|
||||
removeLayerRendererByKey_(layerKey) {
|
||||
const layerRenderer = this.layerRenderers_[layerKey];
|
||||
delete this.layerRenderers_[layerKey];
|
||||
|
||||
unlistenByKey(this.layerRendererListeners_[layerKey]);
|
||||
delete this.layerRendererListeners_[layerKey];
|
||||
|
||||
return layerRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @abstract
|
||||
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
*/
|
||||
renderFrame(frameState) {
|
||||
this.declutterTree_ = renderDeclutterItems(frameState, this.declutterTree_);
|
||||
abstract();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,6 +268,21 @@ class MapRenderer extends Disposable {
|
||||
frameState.postRenderFunctions.push(expireIconCache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @protected
|
||||
*/
|
||||
scheduleRemoveUnusedLayerRenderers(frameState) {
|
||||
const layerStatesMap = getLayerStatesMap(frameState.layerStatesArray);
|
||||
for (const layerKey in this.layerRenderers_) {
|
||||
if (!(layerKey in layerStatesMap)) {
|
||||
frameState.postRenderFunctions.push(function() {
|
||||
this.removeLayerRendererByKey_(layerKey).dispose();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,4 +294,15 @@ function expireIconCache(map, frameState) {
|
||||
iconImageCache.expire();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<import("../layer/Layer.js").State>} layerStatesArray Layer states array.
|
||||
* @return {Object<string, import("../layer/Layer.js").State>} States mapped by layer uid.
|
||||
*/
|
||||
function getLayerStatesMap(layerStatesArray) {
|
||||
return layerStatesArray.reduce(function(acc, state) {
|
||||
acc[getUid(state.layer)] = state;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export default MapRenderer;
|
||||
|
||||