Compare commits
1 Commits
v6.0.0-bet
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7853ad839b |
8
.github/FUNDING.yml
vendored
8
.github/FUNDING.yml
vendored
@@ -1,8 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: openlayers
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
custom: # Replace with a single custom sponsorship URL
|
||||
17
.github/stale.yml
vendored
17
.github/stale.yml
vendored
@@ -1,17 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- blocker
|
||||
- regression
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
|
||||
/** @type {VectorSource<import("../src/ol/geom/SimpleGeometry.js").default>} */
|
||||
const source = new VectorSource({
|
||||
url: 'data/geojson/switzerland.geojson',
|
||||
format: new GeoJSON()
|
||||
@@ -52,21 +51,21 @@ const zoomtoswitzerland =
|
||||
document.getElementById('zoomtoswitzerland');
|
||||
zoomtoswitzerland.addEventListener('click', function() {
|
||||
const feature = source.getFeatures()[0];
|
||||
const polygon = feature.getGeometry();
|
||||
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
||||
view.fit(polygon, {padding: [170, 50, 30, 150]});
|
||||
}, false);
|
||||
|
||||
const zoomtolausanne = document.getElementById('zoomtolausanne');
|
||||
zoomtolausanne.addEventListener('click', function() {
|
||||
const feature = source.getFeatures()[1];
|
||||
const point = feature.getGeometry();
|
||||
const point = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
||||
view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50});
|
||||
}, false);
|
||||
|
||||
const centerlausanne = document.getElementById('centerlausanne');
|
||||
centerlausanne.addEventListener('click', function() {
|
||||
const feature = source.getFeatures()[1];
|
||||
const point = feature.getGeometry();
|
||||
const point = /** @type {import("../src/ol/geom/Point.js").default} */ (feature.getGeometry());
|
||||
const size = map.getSize();
|
||||
view.centerOn(point.getCoordinates(), size, [570, 500]);
|
||||
}, 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>
|
||||
|
||||
4
examples/d3.js
vendored
4
examples/d3.js
vendored
@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {getWidth, getCenter} from '../src/ol/extent.js';
|
||||
import {Layer, Tile as TileLayer} from '../src/ol/layer.js';
|
||||
import SourceState from '../src/ol/source/State.js';
|
||||
import SourceState from '../src/ol/source/State';
|
||||
import {fromLonLat, toLonLat} from '../src/ol/proj.js';
|
||||
import Stamen from '../src/ol/source/Stamen.js';
|
||||
|
||||
@@ -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 |
@@ -1,6 +0,0 @@
|
||||
.overlay {
|
||||
background-color: yellow;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -8,8 +8,5 @@ docs: >
|
||||
tags: "export, png, openstreetmap"
|
||||
---
|
||||
<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,6 +1,5 @@
|
||||
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';
|
||||
@@ -26,17 +25,11 @@ 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;
|
||||
return element.className.indexOf('ol-control') === -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ 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 ZoomSlider from '../src/ol/control/ZoomSlider.js';
|
||||
import {defaults as defaultControls} from '../src/ol/control/util';
|
||||
import ZoomSlider from '../src/ol/control/ZoomSlider';
|
||||
|
||||
const view = new View({
|
||||
center: [328627.563458, 5921296.662223],
|
||||
|
||||
@@ -67,10 +67,10 @@ const routeFeature = new Feature({
|
||||
type: 'route',
|
||||
geometry: route
|
||||
});
|
||||
const geoMarker = /** @type Feature<import("../src/ol/geom/Point").default> */(new Feature({
|
||||
const geoMarker = new Feature({
|
||||
type: 'geoMarker',
|
||||
geometry: new Point(routeCoords[0])
|
||||
}));
|
||||
});
|
||||
const startMarker = new Feature({
|
||||
type: 'icon',
|
||||
geometry: new Point(routeCoords[0])
|
||||
@@ -191,7 +191,7 @@ function stopAnimation(ended) {
|
||||
|
||||
// if animation cancelled set the marker at the beginning
|
||||
const coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
|
||||
const geometry = geoMarker.getGeometry();
|
||||
const geometry = /** @type {import("../src/ol/geom/Point").default} */ (geoMarker.getGeometry());
|
||||
geometry.setCoordinates(coord);
|
||||
//remove listener
|
||||
vectorLayer.un('postrender', moveFeature);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import {Vector} from '../src/ol/source.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||
import {clamp, lerp} from '../src/ol/math.js';
|
||||
import Stamen from '../src/ol/source/Stamen.js';
|
||||
import Feature from '../src/ol/Feature';
|
||||
import Point from '../src/ol/geom/Point';
|
||||
import VectorLayer from '../src/ol/layer/Vector';
|
||||
import {Vector} from '../src/ol/source';
|
||||
import {fromLonLat} from '../src/ol/proj';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||
import {clamp, lerp} from '../src/ol/math';
|
||||
import Stamen from '../src/ol/source/Stamen';
|
||||
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
attributions: 'NASA'
|
||||
});
|
||||
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import TileJSON from '../src/ol/source/TileJSON.js';
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import {Vector} from '../src/ol/source.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||
import {lerp} from '../src/ol/math.js';
|
||||
import TileJSON from '../src/ol/source/TileJSON';
|
||||
import Feature from '../src/ol/Feature';
|
||||
import Point from '../src/ol/geom/Point';
|
||||
import VectorLayer from '../src/ol/layer/Vector';
|
||||
import {Vector} from '../src/ol/source';
|
||||
import {fromLonLat} from '../src/ol/proj';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||
import {lerp} from '../src/ol/math';
|
||||
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
|
||||
@@ -7,9 +7,8 @@ docs: >
|
||||
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
|
||||
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,183 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Layer from '../src/ol/layer/Layer.js';
|
||||
import {toLonLat, fromLonLat} from '../src/ol/proj.js';
|
||||
import Layer from '../src/ol/layer/Layer';
|
||||
import {assign} from '../src/ol/obj';
|
||||
import {toLonLat} 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('../src/ol/layer/Layer').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 center = toLonLat(view.getCenter(), view.getProjection());
|
||||
|
||||
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();
|
||||
this.mbmap.getContainer().querySelector('.mapboxgl-control-container').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();
|
||||
|
||||
this.centerNextRender = view.getCenter();
|
||||
const lastRender = map.getPixelFromCoordinate(this.centerLastRender);
|
||||
const nextRender = map.getPixelFromCoordinate(this.centerNextRender);
|
||||
this.zoomNextRender = view.getZoom();
|
||||
const scale = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
|
||||
this.updateRenderedPosition(lastRender[0] - nextRender[0], lastRender[1] - nextRender[1], scale);
|
||||
|
||||
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 = toLonLat(this.centerNextRender, view.getProjection());
|
||||
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(left, top, scale) {
|
||||
const style = this.mbmap.getCanvas().style;
|
||||
style.left = Math.round(left) + 'px';
|
||||
style.top = Math.round(top) + 'px';
|
||||
style.transform = 'scale(' + scale + ')';
|
||||
}
|
||||
|
||||
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 +197,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>
|
||||
|
||||
@@ -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,17 +0,0 @@
|
||||
const build = require('../../tasks/serialize-workers').build;
|
||||
|
||||
function loader() {
|
||||
const callback = this.async();
|
||||
const minify = this.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;
|
||||
@@ -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.js';
|
||||
|
||||
|
||||
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'
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
26
package.json
26
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.0.0-beta.9",
|
||||
"version": "6.0.0-beta.7",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -22,7 +22,7 @@
|
||||
"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"
|
||||
},
|
||||
@@ -38,15 +38,16 @@
|
||||
"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",
|
||||
"@babel/preset-env": "^7.4.2",
|
||||
"@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",
|
||||
@@ -56,7 +57,7 @@
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"coveralls": "3.0.3",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-openlayers": "^12.0.0",
|
||||
"eslint-config-openlayers": "^11.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^8.0.0",
|
||||
@@ -67,8 +68,8 @@
|
||||
"istanbul": "0.4.5",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jquery": "3.4.1",
|
||||
"jsdoc": "3.6.2",
|
||||
"jsdoc-plugin-typescript": "^2.0.1",
|
||||
"jsdoc": "3.6.1",
|
||||
"jsdoc-plugin-typescript": "^2.0.0",
|
||||
"karma": "^4.1.0",
|
||||
"karma-chrome-launcher": "2.2.0",
|
||||
"karma-coverage": "^1.1.2",
|
||||
@@ -80,16 +81,11 @@
|
||||
"loglevelnext": "^3.0.1",
|
||||
"marked": "0.6.2",
|
||||
"mocha": "6.1.4",
|
||||
"ol-mapbox-style": "^5.0.0-beta.2",
|
||||
"ol-mapbox-style": "^4.3.1",
|
||||
"pixelmatch": "^4.0.2",
|
||||
"pngjs": "^3.4.0",
|
||||
"proj4": "2.5.0",
|
||||
"puppeteer": "~1.17.0",
|
||||
"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": "^5.0.0",
|
||||
"puppeteer": "~1.15.0",
|
||||
"serve-static": "^1.14.0",
|
||||
"shx": "^0.3.2",
|
||||
"sinon": "^7.3.2",
|
||||
@@ -97,7 +93,7 @@
|
||||
"typescript": "^3.4.5",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "4.32.2",
|
||||
"webpack": "4.31.0",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-middleware": "^3.6.2",
|
||||
"webpack-dev-server": "^3.3.1",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {Heatmap as HeatmapLayer} from '../../../src/ol/layer.js';
|
||||
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||
import KML from '../../../src/ol/format/KML.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
import {Heatmap as HeatmapLayer} from '../../../src/ol/layer';
|
||||
import VectorSource from '../../../src/ol/source/Vector';
|
||||
import KML from '../../../src/ol/format/KML';
|
||||
|
||||
const vector = new HeatmapLayer({
|
||||
source: new VectorSource({
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB |
@@ -1,30 +0,0 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import {Group as LayerGroup, Tile as TileLayer} from '../../../src/ol/layer.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
|
||||
new Map({
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 3
|
||||
}),
|
||||
layers: new LayerGroup({
|
||||
opacity: 0.75,
|
||||
layers: [
|
||||
new TileLayer({
|
||||
opacity: 0.25,
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
|
||||
})
|
||||
}),
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/stamen-labels/{z}/{x}/{y}.png'
|
||||
})
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
render();
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
get as getProjection,
|
||||
transform,
|
||||
transformExtent
|
||||
} from '../../../src/ol/proj.js';
|
||||
} from '../../../src/ol/proj';
|
||||
import ImageLayer from '../../../src/ol/layer/Image.js';
|
||||
const center = transform([-122.416667, 37.783333], 'EPSG:4326', 'EPSG:3857');
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj';
|
||||
import {transformExtent} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
|
||||
const center = fromLonLat([7, 50]);
|
||||
const extent = transformExtent([2, 47, 10, 53], 'EPSG:4326', 'EPSG:3857');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
||||
|
||||
const center = [-10997148, 4569099];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
|
||||
const center = fromLonLat([8.6, 50.1]);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
|
||||
const center = fromLonLat([8.6, 50.1]);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
|
||||
const center = fromLonLat([8.6, 50.1]);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
|
||||
const center = fromLonLat([8.6, 50.1]);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile.js';
|
||||
import MVT from '../../../src/ol/format/MVT.js';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile';
|
||||
import MVT from '../../../src/ol/format/MVT';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile';
|
||||
|
||||
const map = new Map({
|
||||
pixelRatio: 2,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile.js';
|
||||
import MVT from '../../../src/ol/format/MVT.js';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
|
||||
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||
import Feature from '../../../src/ol/Feature.js';
|
||||
import Point from '../../../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../../../src/ol/layer/Vector.js';
|
||||
import Style from '../../../src/ol/style/Style.js';
|
||||
import CircleStyle from '../../../src/ol/style/Circle.js';
|
||||
import Fill from '../../../src/ol/style/Fill.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile';
|
||||
import MVT from '../../../src/ol/format/MVT';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile';
|
||||
import VectorSource from '../../../src/ol/source/Vector';
|
||||
import Feature from '../../../src/ol/Feature';
|
||||
import Point from '../../../src/ol/geom/Point';
|
||||
import VectorLayer from '../../../src/ol/layer/Vector';
|
||||
import Style from '../../../src/ol/style/Style';
|
||||
import CircleStyle from '../../../src/ol/style/Circle';
|
||||
import Fill from '../../../src/ol/style/Fill';
|
||||
|
||||
const vectorSource = new VectorSource({
|
||||
features: [
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile.js';
|
||||
import MVT from '../../../src/ol/format/MVT.js';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile';
|
||||
import MVT from '../../../src/ol/format/MVT';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile';
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile.js';
|
||||
import MVT from '../../../src/ol/format/MVT.js';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile.js';
|
||||
import VectorTileSource from '../../../src/ol/source/VectorTile';
|
||||
import MVT from '../../../src/ol/format/MVT';
|
||||
import {createXYZ} from '../../../src/ol/tilegrid';
|
||||
import VectorTileLayer from '../../../src/ol/layer/VectorTile';
|
||||
|
||||
new Map({
|
||||
layers: [
|
||||
|
||||
@@ -9,6 +9,12 @@ import Point from '../../../src/ol/geom/Point.js';
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
|
||||
maxZoom: 3
|
||||
})
|
||||
}),
|
||||
new VectorLayer({
|
||||
zIndex: 1,
|
||||
style: new Style({
|
||||
@@ -21,12 +27,6 @@ const map = new Map({
|
||||
url: '/data/countries.json',
|
||||
format: new GeoJSON()
|
||||
})
|
||||
}),
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
|
||||
maxZoom: 3
|
||||
})
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {Vector as VectorLayer} from '../../../src/ol/layer.js';
|
||||
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||
import KML from '../../../src/ol/format/KML.js';
|
||||
import WebGLPointsLayerRenderer from '../../../src/ol/renderer/webgl/PointsLayer.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ';
|
||||
import {Vector as VectorLayer} from '../../../src/ol/layer';
|
||||
import VectorSource from '../../../src/ol/source/Vector';
|
||||
import KML from '../../../src/ol/format/KML';
|
||||
import WebGLPointsLayerRenderer from '../../../src/ol/renderer/webgl/PointsLayer';
|
||||
|
||||
class CustomLayer extends VectorLayer {
|
||||
createRenderer() {
|
||||
|
||||
@@ -57,11 +57,10 @@ import BaseObject, {getChangeEventType} from './Object.js';
|
||||
* ```
|
||||
*
|
||||
* @api
|
||||
* @template {import("./geom/Geometry.js").default} Geometry
|
||||
*/
|
||||
class Feature extends BaseObject {
|
||||
/**
|
||||
* @param {Geometry|Object<string, *>=} opt_geometryOrProperties
|
||||
* @param {import("./geom/Geometry.js").default|Object<string, *>=} opt_geometryOrProperties
|
||||
* You may pass a Geometry object directly, or an object literal containing
|
||||
* properties. If you pass an object literal, you may include a Geometry
|
||||
* associated with a `geometry` key.
|
||||
@@ -107,7 +106,7 @@ class Feature extends BaseObject {
|
||||
|
||||
if (opt_geometryOrProperties) {
|
||||
if (typeof /** @type {?} */ (opt_geometryOrProperties).getSimplifiedGeometry === 'function') {
|
||||
const geometry = /** @type {Geometry} */ (opt_geometryOrProperties);
|
||||
const geometry = /** @type {import("./geom/Geometry.js").default} */ (opt_geometryOrProperties);
|
||||
this.setGeometry(geometry);
|
||||
} else {
|
||||
/** @type {Object<string, *>} */
|
||||
@@ -141,13 +140,13 @@ class Feature extends BaseObject {
|
||||
* Get the feature's default geometry. A feature may have any number of named
|
||||
* geometries. The "default" geometry (the one that is rendered by default) is
|
||||
* set when calling {@link module:ol/Feature~Feature#setGeometry}.
|
||||
* @return {Geometry|undefined} The default geometry for the feature.
|
||||
* @return {import("./geom/Geometry.js").default|undefined} The default geometry for the feature.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
getGeometry() {
|
||||
return (
|
||||
/** @type {Geometry|undefined} */ (this.get(this.geometryName_))
|
||||
/** @type {import("./geom/Geometry.js").default|undefined} */ (this.get(this.geometryName_))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -219,7 +218,7 @@ class Feature extends BaseObject {
|
||||
/**
|
||||
* Set the default geometry for the feature. This will update the property
|
||||
* with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
|
||||
* @param {Geometry|undefined} geometry The new geometry.
|
||||
* @param {import("./geom/Geometry.js").default|undefined} geometry The new geometry.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
|
||||
@@ -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,11 +39,10 @@ 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>} declutterItems
|
||||
* @property {Array<*>} declutterItems
|
||||
* @property {import("./coordinate.js").Coordinate} focus
|
||||
* @property {number} index
|
||||
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
|
||||
* @property {number} layerIndex
|
||||
* @property {import("./transform.js").Transform} pixelToCoordinateTransform
|
||||
* @property {Array<PostRenderFunction>} postRenderFunctions
|
||||
* @property {import("./size.js").Size} size
|
||||
@@ -55,13 +54,6 @@ import {create as createTransform, apply as applyTransform} from './transform.js
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} DeclutterItems
|
||||
* @property {Array<*>} items Declutter items of an executor.
|
||||
* @property {number} opacity Layer opacity.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction
|
||||
*/
|
||||
@@ -301,11 +293,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
|
||||
@@ -511,24 +498,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
|
||||
@@ -546,7 +515,6 @@ class PluggableMap extends BaseObject {
|
||||
cancelAnimationFrame(this.animationDelayKey_);
|
||||
this.animationDelayKey_ = undefined;
|
||||
}
|
||||
this.detachLabelCache();
|
||||
this.setTarget(null);
|
||||
super.disposeInternal();
|
||||
}
|
||||
@@ -795,21 +763,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.
|
||||
@@ -997,7 +950,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);
|
||||
}
|
||||
|
||||
@@ -1041,6 +994,7 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
|
||||
if (!targetElement) {
|
||||
this.renderer_.removeLayerRenderers();
|
||||
removeNode(this.viewport_);
|
||||
if (this.handleResize_ !== undefined) {
|
||||
removeEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
@@ -1058,7 +1012,7 @@ class PluggableMap extends BaseObject {
|
||||
|
||||
if (!this.handleResize_) {
|
||||
this.handleResize_ = this.updateSize.bind(this);
|
||||
window.addEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
addEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,19 +1102,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
|
||||
@@ -1232,14 +1173,13 @@ class PluggableMap extends BaseObject {
|
||||
if (size !== undefined && hasArea(size) && view && view.isDef()) {
|
||||
const viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);
|
||||
viewState = view.getState(this.pixelRatio_);
|
||||
frameState = {
|
||||
frameState = /** @type {FrameState} */ ({
|
||||
animate: false,
|
||||
coordinateToPixelTransform: this.coordinateToPixelTransform_,
|
||||
declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
|
||||
extent: extent,
|
||||
focus: this.focus_ ? this.focus_ : viewState.center,
|
||||
index: this.frameIndex_++,
|
||||
layerIndex: 0,
|
||||
layerStatesArray: this.getLayerGroup().getLayerStatesArray(),
|
||||
pixelRatio: this.pixelRatio_,
|
||||
pixelToCoordinateTransform: this.pixelToCoordinateTransform_,
|
||||
@@ -1252,7 +1192,7 @@ class PluggableMap extends BaseObject {
|
||||
viewState: viewState,
|
||||
viewHints: viewHints,
|
||||
wantedTiles: {}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (frameState) {
|
||||
@@ -1458,3 +1398,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;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import {clamp, modulo} from './math.js';
|
||||
import {assign} from './obj.js';
|
||||
import {createProjection, METERS_PER_UNIT} from './proj.js';
|
||||
import Units from './proj/Units.js';
|
||||
import {equals} from './coordinate.js';
|
||||
import {easeOut} from './easing.js';
|
||||
import {createMinMaxResolution} from './resolutionconstraint.js';
|
||||
import {equals} from './coordinate';
|
||||
import {easeOut} from './easing';
|
||||
import {createMinMaxResolution} from './resolutionconstraint';
|
||||
|
||||
|
||||
/**
|
||||
@@ -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
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',
|
||||
|
||||
@@ -97,10 +97,9 @@ import {assert} from '../asserts.js';
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enum representing the major IIIF Image API versions
|
||||
* @enum {string}
|
||||
*/
|
||||
const Versions = {
|
||||
* @enum {string}
|
||||
*/
|
||||
export const Versions = {
|
||||
VERSION1: 'version1',
|
||||
VERSION2: 'version2',
|
||||
VERSION3: 'version3'
|
||||
@@ -276,7 +275,7 @@ versionFunctions[Versions.VERSION3] = generateVersion3Options;
|
||||
class IIIFInfo {
|
||||
|
||||
/**
|
||||
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
|
||||
* @param {ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3|string} imageInfo
|
||||
* Deserialized image information JSON response object or JSON response as string
|
||||
*/
|
||||
constructor(imageInfo) {
|
||||
@@ -284,9 +283,8 @@ class IIIFInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3} imageInfo
|
||||
* Deserialized image information JSON response object or JSON response as string
|
||||
* @api
|
||||
* @param {Object|string} imageInfo Deserialized image information JSON response
|
||||
* object or JSON response as string
|
||||
*/
|
||||
setImageInfo(imageInfo) {
|
||||
if (typeof imageInfo == 'string') {
|
||||
@@ -298,7 +296,6 @@ class IIIFInfo {
|
||||
|
||||
/**
|
||||
* @returns {Versions} Major IIIF version.
|
||||
* @api
|
||||
*/
|
||||
getImageApiVersion() {
|
||||
if (this.imageInfo === undefined) {
|
||||
@@ -397,7 +394,6 @@ class IIIFInfo {
|
||||
/**
|
||||
* @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 || {},
|
||||
@@ -428,4 +424,3 @@ class IIIFInfo {
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -174,8 +174,9 @@ class Geometry extends BaseObject {
|
||||
|
||||
/**
|
||||
* Create a simplified version of this geometry. For linestrings, this uses
|
||||
* the [Douglas Peucker](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)
|
||||
* algorithm. For polygons, a quantization-based
|
||||
* the the {@link
|
||||
* https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* Douglas Peucker} algorithm. For polygons, a quantization-based
|
||||
* simplification is used to preserve topology.
|
||||
* @param {number} tolerance The tolerance distance for simplification.
|
||||
* @return {Geometry} A new, simplified version of the original geometry.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js';
|
||||
import {easeOut} from '../easing.js';
|
||||
import {noModifierKeys, primaryAction} from '../events/condition.js';
|
||||
import {noModifierKeys} from '../events/condition.js';
|
||||
import {FALSE} from '../functions.js';
|
||||
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
||||
|
||||
@@ -12,7 +12,7 @@ import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js
|
||||
* @typedef {Object} Options
|
||||
* @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
|
||||
* to indicate whether that event should be handled.
|
||||
* Default is {@link module:ol/events/condition~noModifierKeys} and {@link module:ol/events/condition~primaryAction}.
|
||||
* Default is {@link module:ol/events/condition~noModifierKeys}.
|
||||
* @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
|
||||
*/
|
||||
|
||||
@@ -59,7 +59,7 @@ class DragPan extends PointerInteraction {
|
||||
* @private
|
||||
* @type {import("../events/condition.js").Condition}
|
||||
*/
|
||||
this.condition_ = options.condition ? options.condition : defaultCondition;
|
||||
this.condition_ = options.condition ? options.condition : noModifierKeys;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -166,12 +166,4 @@ class DragPan extends PointerInteraction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
|
||||
* @return {boolean} Combined condition result.
|
||||
*/
|
||||
function defaultCondition(mapBrowserEvent) {
|
||||
return noModifierKeys(mapBrowserEvent) && primaryAction(mapBrowserEvent);
|
||||
}
|
||||
|
||||
export default DragPan;
|
||||
|
||||
@@ -373,7 +373,7 @@ class Draw extends PointerInteraction {
|
||||
|
||||
/**
|
||||
* Sketch point.
|
||||
* @type {Feature<Point>}
|
||||
* @type {Feature}
|
||||
* @private
|
||||
*/
|
||||
this.sketchPoint_ = null;
|
||||
@@ -387,7 +387,7 @@ class Draw extends PointerInteraction {
|
||||
|
||||
/**
|
||||
* Sketch line. Used when drawing polygon.
|
||||
* @type {Feature<LineString>}
|
||||
* @type {Feature}
|
||||
* @private
|
||||
*/
|
||||
this.sketchLine_ = null;
|
||||
@@ -669,7 +669,7 @@ class Draw extends PointerInteraction {
|
||||
this.sketchPoint_ = new Feature(new Point(coordinates));
|
||||
this.updateSketchFeatures_();
|
||||
} else {
|
||||
const sketchPointGeom = this.sketchPoint_.getGeometry();
|
||||
const sketchPointGeom = /** @type {Point} */ (this.sketchPoint_.getGeometry());
|
||||
sketchPointGeom.setCoordinates(coordinates);
|
||||
}
|
||||
}
|
||||
@@ -711,7 +711,7 @@ class Draw extends PointerInteraction {
|
||||
*/
|
||||
modifyDrawing_(event) {
|
||||
let coordinate = event.coordinate;
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry());
|
||||
let coordinates, last;
|
||||
if (this.mode_ === Mode.POINT) {
|
||||
last = this.sketchCoords_;
|
||||
@@ -730,7 +730,7 @@ class Draw extends PointerInteraction {
|
||||
last[1] = coordinate[1];
|
||||
this.geometryFunction_(/** @type {!LineCoordType} */ (this.sketchCoords_), geometry);
|
||||
if (this.sketchPoint_) {
|
||||
const sketchPointGeom = this.sketchPoint_.getGeometry();
|
||||
const sketchPointGeom = /** @type {Point} */ (this.sketchPoint_.getGeometry());
|
||||
sketchPointGeom.setCoordinates(coordinate);
|
||||
}
|
||||
/** @type {LineString} */
|
||||
@@ -740,8 +740,8 @@ class Draw extends PointerInteraction {
|
||||
if (!this.sketchLine_) {
|
||||
this.sketchLine_ = new Feature();
|
||||
}
|
||||
const ring = geometry.getLinearRing(0);
|
||||
sketchLineGeom = this.sketchLine_.getGeometry();
|
||||
const ring = /** @type {Polygon} */ (geometry).getLinearRing(0);
|
||||
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry());
|
||||
if (!sketchLineGeom) {
|
||||
sketchLineGeom = new LineString(ring.getFlatCoordinates(), ring.getLayout());
|
||||
this.sketchLine_.setGeometry(sketchLineGeom);
|
||||
@@ -751,7 +751,7 @@ class Draw extends PointerInteraction {
|
||||
sketchLineGeom.changed();
|
||||
}
|
||||
} else if (this.sketchLineCoords_) {
|
||||
sketchLineGeom = this.sketchLine_.getGeometry();
|
||||
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry());
|
||||
sketchLineGeom.setCoordinates(this.sketchLineCoords_);
|
||||
}
|
||||
this.updateSketchFeatures_();
|
||||
@@ -764,7 +764,7 @@ class Draw extends PointerInteraction {
|
||||
*/
|
||||
addToDrawing_(event) {
|
||||
const coordinate = event.coordinate;
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry());
|
||||
let done;
|
||||
let coordinates;
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
@@ -808,7 +808,7 @@ class Draw extends PointerInteraction {
|
||||
if (!this.sketchFeature_) {
|
||||
return;
|
||||
}
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (this.sketchFeature_.getGeometry());
|
||||
let coordinates;
|
||||
/** @type {LineString} */
|
||||
let sketchLineGeom;
|
||||
@@ -822,7 +822,7 @@ class Draw extends PointerInteraction {
|
||||
} else if (this.mode_ === Mode.POLYGON) {
|
||||
coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0];
|
||||
coordinates.splice(-2, 1);
|
||||
sketchLineGeom = this.sketchLine_.getGeometry();
|
||||
sketchLineGeom = /** @type {LineString} */ (this.sketchLine_.getGeometry());
|
||||
sketchLineGeom.setCoordinates(coordinates);
|
||||
this.geometryFunction_(this.sketchCoords_, geometry);
|
||||
}
|
||||
@@ -846,7 +846,7 @@ class Draw extends PointerInteraction {
|
||||
return;
|
||||
}
|
||||
let coordinates = this.sketchCoords_;
|
||||
const geometry = sketchFeature.getGeometry();
|
||||
const geometry = /** @type {import("../geom/SimpleGeometry.js").default} */ (sketchFeature.getGeometry());
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
// remove the redundant last point
|
||||
coordinates.pop();
|
||||
@@ -900,12 +900,12 @@ class Draw extends PointerInteraction {
|
||||
* Extend an existing geometry by adding additional points. This only works
|
||||
* on features with `LineString` geometries, where the interaction will
|
||||
* extend lines by adding points to the end of the coordinates array.
|
||||
* @param {!Feature<LineString>} feature Feature to be extended.
|
||||
* @param {!Feature} feature Feature to be extended.
|
||||
* @api
|
||||
*/
|
||||
extend(feature) {
|
||||
const geometry = feature.getGeometry();
|
||||
const lineString = geometry;
|
||||
const lineString = /** @type {LineString} */ (geometry);
|
||||
this.sketchFeature_ = feature;
|
||||
this.sketchCoords_ = lineString.getCoordinates();
|
||||
const last = this.sketchCoords_[this.sketchCoords_.length - 1];
|
||||
|
||||
@@ -126,7 +126,7 @@ class Extent extends PointerInteraction {
|
||||
|
||||
/**
|
||||
* Feature for displaying the visible pointer
|
||||
* @type {Feature<Point>}
|
||||
* @type {Feature}
|
||||
* @private
|
||||
*/
|
||||
this.vertexFeature_ = null;
|
||||
@@ -265,7 +265,7 @@ class Extent extends PointerInteraction {
|
||||
this.vertexFeature_ = vertexFeature;
|
||||
this.vertexOverlay_.getSource().addFeature(vertexFeature);
|
||||
} else {
|
||||
const geometry = vertexFeature.getGeometry();
|
||||
const geometry = /** @type {Point} */ (vertexFeature.getGeometry());
|
||||
geometry.setCoordinates(vertex);
|
||||
}
|
||||
return vertexFeature;
|
||||
|
||||
@@ -660,7 +660,7 @@ class Modify extends PointerInteraction {
|
||||
this.vertexFeature_ = vertexFeature;
|
||||
this.overlay_.getSource().addFeature(vertexFeature);
|
||||
} else {
|
||||
const geometry = vertexFeature.getGeometry();
|
||||
const geometry = /** @type {Point} */ (vertexFeature.getGeometry());
|
||||
geometry.setCoordinates(coordinates);
|
||||
}
|
||||
return vertexFeature;
|
||||
@@ -785,7 +785,7 @@ class Modify extends PointerInteraction {
|
||||
const vertexFeature = this.vertexFeature_;
|
||||
if (vertexFeature) {
|
||||
const insertVertices = [];
|
||||
const geometry = vertexFeature.getGeometry();
|
||||
const geometry = /** @type {Point} */ (vertexFeature.getGeometry());
|
||||
const vertex = geometry.getCoordinates();
|
||||
const vertexExtent = boundingExtent([vertex]);
|
||||
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
|
||||
|
||||
@@ -83,9 +83,6 @@ class BaseLayer extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is not meant to be called by layers or layer renderers because the state
|
||||
* is incorrect if the layer is included in a layer group.
|
||||
*
|
||||
* @param {boolean=} opt_managed Layer is managed.
|
||||
* @return {import("./Layer.js").State} Layer state.
|
||||
*/
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
*/
|
||||
import VectorLayer from './Vector.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {degreesToStringHDMS} from '../coordinate.js';
|
||||
import Text from '../style/Text.js';
|
||||
import Fill from '../style/Fill.js';
|
||||
import Stroke from '../style/Stroke.js';
|
||||
import {degreesToStringHDMS} from '../coordinate';
|
||||
import Text from '../style/Text';
|
||||
import Fill from '../style/Fill';
|
||||
import Stroke from '../style/Stroke';
|
||||
import LineString from '../geom/LineString.js';
|
||||
import VectorSource from '../source/Vector.js';
|
||||
import VectorSource from '../source/Vector';
|
||||
import {
|
||||
equivalent as equivalentProjection,
|
||||
get as getProjection,
|
||||
getTransform,
|
||||
transformExtent
|
||||
} from '../proj.js';
|
||||
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent.js';
|
||||
import {clamp} from '../math.js';
|
||||
import Style from '../style/Style.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {bbox} from '../loadingstrategy.js';
|
||||
import {meridian, parallel} from '../geom/flat/geodesic.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
import Point from '../geom/Point.js';
|
||||
import Collection from '../Collection.js';
|
||||
} from '../proj';
|
||||
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent';
|
||||
import {clamp} from '../math';
|
||||
import Style from '../style/Style';
|
||||
import Feature from '../Feature';
|
||||
import {bbox} from '../loadingstrategy';
|
||||
import {meridian, parallel} from '../geom/flat/geodesic';
|
||||
import GeometryLayout from '../geom/GeometryLayout';
|
||||
import Point from '../geom/Point';
|
||||
import Collection from '../Collection';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@ import {getChangeEventType} from '../Object.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import VectorLayer from './Vector.js';
|
||||
import {assign} from '../obj.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -189,15 +175,13 @@ class Layer extends BaseLayer {
|
||||
* In charge to manage the rendering of the layer. One layer type is
|
||||
* bounded with one layer renderer.
|
||||
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @param {HTMLElement} target Target which the renderer may (but need not) use
|
||||
* for rendering its content.
|
||||
* @return {HTMLElement} The rendered element.
|
||||
*/
|
||||
render(frameState, target) {
|
||||
render(frameState) {
|
||||
const layerRenderer = this.getRenderer();
|
||||
|
||||
if (layerRenderer.prepareFrame(frameState)) {
|
||||
return layerRenderer.renderFrame(frameState, target);
|
||||
const layerState = this.getLayerState();
|
||||
if (layerRenderer.prepareFrame(frameState, layerState)) {
|
||||
return layerRenderer.renderFrame(frameState, layerState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,13 +240,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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -122,10 +122,9 @@ export function renderDeclutterItems(frameState, declutterTree) {
|
||||
}
|
||||
const items = frameState.declutterItems;
|
||||
for (let z = items.length - 1; z >= 0; --z) {
|
||||
const item = items[z];
|
||||
const zIndexItems = item.items;
|
||||
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], item.opacity, declutterTree);
|
||||
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree);
|
||||
}
|
||||
}
|
||||
items.length = 0;
|
||||
|
||||
@@ -403,7 +403,7 @@ export function drawImage(context,
|
||||
|
||||
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
|
||||
|
||||
if (opacity != 1) {
|
||||
if (alpha) {
|
||||
context.globalAlpha = alpha;
|
||||
}
|
||||
if (transform) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import Disposable from '../../Disposable.js';
|
||||
import RBush from 'rbush';
|
||||
import rbush from 'rbush';
|
||||
|
||||
|
||||
/**
|
||||
@@ -193,10 +193,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 +220,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) {
|
||||
@@ -362,12 +361,10 @@ class Executor extends Disposable {
|
||||
const declutterArgs = intersects ?
|
||||
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
|
||||
null;
|
||||
if (declutterArgs) {
|
||||
if (fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
if (declutterArgs && fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
} else if (intersects) {
|
||||
if (fillStroke) {
|
||||
this.replayTextBackground_(context, p1, p2, p3, p4,
|
||||
@@ -416,11 +413,10 @@ class Executor extends Disposable {
|
||||
/**
|
||||
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
||||
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
||||
* @param {number} opacity Layer opacity.
|
||||
* @param {?} declutterTree Declutter tree.
|
||||
* @return {?} Declutter tree.
|
||||
*/
|
||||
renderDeclutter(declutterGroup, feature, opacity, declutterTree) {
|
||||
renderDeclutter(declutterGroup, feature, declutterTree) {
|
||||
if (declutterGroup && declutterGroup.length > 5) {
|
||||
const groupCount = declutterGroup[4];
|
||||
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
|
||||
@@ -433,25 +429,19 @@ class Executor extends Disposable {
|
||||
value: feature
|
||||
};
|
||||
if (!declutterTree) {
|
||||
declutterTree = new RBush(9);
|
||||
declutterTree = rbush(9, undefined);
|
||||
}
|
||||
if (!declutterTree.collides(box)) {
|
||||
declutterTree.insert(box);
|
||||
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
|
||||
const declutterData = /** @type {Array} */ (declutterGroup[j]);
|
||||
const context = declutterData[0];
|
||||
const currentAlpha = context.globalAlpha;
|
||||
if (currentAlpha !== opacity) {
|
||||
context.globalAlpha = opacity;
|
||||
}
|
||||
if (declutterData.length > 11) {
|
||||
this.replayTextBackground_(declutterData[0],
|
||||
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
|
||||
declutterData[11], declutterData[12]);
|
||||
}
|
||||
drawImage.apply(undefined, declutterData);
|
||||
if (currentAlpha !== opacity) {
|
||||
context.globalAlpha = currentAlpha;
|
||||
if (declutterData) {
|
||||
if (declutterData.length > 11) {
|
||||
this.replayTextBackground_(declutterData[0],
|
||||
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
|
||||
declutterData[11], declutterData[12]);
|
||||
}
|
||||
drawImage.apply(undefined, declutterData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,9 +471,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 {
|
||||
|
||||
@@ -82,7 +82,7 @@ class ExecutorGroup extends Disposable {
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.hitDetectionContext_ = null;
|
||||
this.hitDetectionContext_ = createCanvasContext2D(1, 1);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -137,11 +137,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();
|
||||
}
|
||||
|
||||
@@ -190,10 +187,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) {
|
||||
@@ -430,11 +423,10 @@ export function getCircleArray(radius) {
|
||||
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {number} rotation Rotation.
|
||||
* @param {number} opacity Opacity.
|
||||
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
|
||||
* @param {Array<import("../../PluggableMap.js").DeclutterItems>} declutterItems Declutter items.
|
||||
* @param {Array<Array<*>>} declutterItems Declutter items.
|
||||
*/
|
||||
export function replayDeclutter(declutterReplays, context, rotation, opacity, snapToPixel, declutterItems) {
|
||||
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) {
|
||||
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
|
||||
const skippedFeatureUids = {};
|
||||
for (let z = 0, zz = zs.length; z < zz; ++z) {
|
||||
@@ -444,10 +436,7 @@ export function replayDeclutter(declutterReplays, context, rotation, opacity, sn
|
||||
const executor = executorData[i++];
|
||||
if (executor !== currentExecutor) {
|
||||
currentExecutor = executor;
|
||||
declutterItems.push({
|
||||
items: executor.declutterItems,
|
||||
opacity: opacity
|
||||
});
|
||||
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
|
||||
@@ -81,26 +79,24 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
this.calculateMatrices2D(frameState);
|
||||
this.dispatchRenderEvent(RenderEventType.PRECOMPOSE, frameState);
|
||||
|
||||
const layerStatesArray = frameState.layerStatesArray.sort(function(a, b) {
|
||||
return a.zIndex - b.zIndex;
|
||||
});
|
||||
const layerStatesArray = frameState.layerStatesArray;
|
||||
const viewResolution = frameState.viewState.resolution;
|
||||
|
||||
this.children_.length = 0;
|
||||
let previousElement = null;
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layerState = layerStatesArray[i];
|
||||
frameState.layerIndex = i;
|
||||
if (!visibleAtResolution(layerState, viewResolution) ||
|
||||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
|
||||
if (!visibleAtResolution(layerState, viewResolution) || layerState.sourceState != SourceState.READY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const layer = layerState.layer;
|
||||
const element = layer.render(frameState, previousElement);
|
||||
if (element !== previousElement) {
|
||||
const element = layer.render(frameState);
|
||||
if (element) {
|
||||
const zIndex = layerState.zIndex;
|
||||
if (zIndex !== element.style.zIndex) {
|
||||
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex;
|
||||
}
|
||||
this.children_.push(element);
|
||||
previousElement = element;
|
||||
}
|
||||
}
|
||||
super.renderFrame(frameState);
|
||||
@@ -114,6 +110,7 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
this.scheduleRemoveUnusedLayerRenderers(frameState);
|
||||
this.scheduleExpireIconCache(frameState);
|
||||
}
|
||||
|
||||
@@ -130,8 +127,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);
|
||||
|
||||
@@ -29,9 +29,10 @@ class LayerRenderer extends Observable {
|
||||
* Determine whether render should be called.
|
||||
* @abstract
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @param {import("../layer/Layer.js").State} layerState Layer state.
|
||||
* @return {boolean} Layer is ready to be rendered.
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
prepareFrame(frameState, layerState) {
|
||||
return abstract();
|
||||
}
|
||||
|
||||
@@ -39,10 +40,10 @@ class LayerRenderer extends Observable {
|
||||
* Render the layer.
|
||||
* @abstract
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @param {HTMLElement} target Target that may be used to render content to.
|
||||
* @param {import("../layer/Layer.js").State} layerState Layer state.
|
||||
* @return {HTMLElement} The rendered element.
|
||||
*/
|
||||
renderFrame(frameState, target) {
|
||||
renderFrame(frameState, layerState) {
|
||||
return abstract();
|
||||
}
|
||||
|
||||
@@ -114,12 +115,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,6 +3,8 @@
|
||||
*/
|
||||
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';
|
||||
@@ -32,6 +34,18 @@ class MapRenderer extends Disposable {
|
||||
*/
|
||||
this.declutterTree_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, import("./Layer.js").default>}
|
||||
*/
|
||||
this.layerRenderers_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object<string, import("../events.js").EventsKey>}
|
||||
*/
|
||||
this.layerRendererListeners_ = {};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +75,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.
|
||||
@@ -126,8 +149,8 @@ class MapRenderer extends Disposable {
|
||||
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);
|
||||
@@ -180,6 +203,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,6 +239,29 @@ 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.
|
||||
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
@@ -204,6 +279,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 +305,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;
|
||||
|
||||
@@ -38,8 +38,7 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
prepareFrame(frameState, layerState) {
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const viewState = frameState.viewState;
|
||||
const viewResolution = viewState.resolution;
|
||||
@@ -73,12 +72,11 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
renderFrame(frameState, target) {
|
||||
renderFrame(frameState, layerState) {
|
||||
const image = this.image_;
|
||||
const imageExtent = image.getExtent();
|
||||
const imageResolution = image.getResolution();
|
||||
const imagePixelRatio = image.getPixelRatio();
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const viewState = frameState.viewState;
|
||||
const viewCenter = viewState.center;
|
||||
@@ -103,15 +101,13 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
);
|
||||
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
|
||||
|
||||
this.useContainer(target, this.pixelTransform_, layerState.opacity);
|
||||
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
if (canvas.width != width || canvas.height != height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
} else if (!this.containerReused) {
|
||||
} else {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
@@ -142,17 +138,8 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
|
||||
this.preRender(context, frameState);
|
||||
if (dw >= 0.5 && dh >= 0.5) {
|
||||
const opacity = layerState.opacity;
|
||||
let previousAlpha;
|
||||
if (opacity !== 1) {
|
||||
previousAlpha = this.context.globalAlpha;
|
||||
this.context.globalAlpha = opacity;
|
||||
}
|
||||
this.context.drawImage(img, 0, 0, +img.width, +img.height,
|
||||
Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
|
||||
if (opacity !== 1) {
|
||||
this.context.globalAlpha = previousAlpha;
|
||||
}
|
||||
}
|
||||
this.postRender(context, frameState);
|
||||
|
||||
@@ -160,12 +147,17 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
context.restore();
|
||||
}
|
||||
|
||||
const opacity = layerState.opacity;
|
||||
if (opacity !== parseFloat(canvas.style.opacity)) {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
const canvasTransform = transformToString(this.pixelTransform_);
|
||||
if (canvasTransform !== canvas.style.transform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
|
||||
return this.container;
|
||||
return canvas;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import RenderEvent from '../../render/Event.js';
|
||||
import RenderEventType from '../../render/EventType.js';
|
||||
import {rotateAtOffset} from '../../render/canvas.js';
|
||||
import LayerRenderer from '../Layer.js';
|
||||
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
|
||||
import {create as createTransform, apply as applyTransform, compose as composeTransform} from '../../transform.js';
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
@@ -21,12 +21,6 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
|
||||
super(layer);
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.container = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
@@ -61,57 +55,20 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
* @protected
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.context = null;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.containerReused = false;
|
||||
this.context = createCanvasContext2D();
|
||||
|
||||
const canvas = this.context.canvas;
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.transformOrigin = 'top left';
|
||||
canvas.className = this.getLayer().getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a rendering container from an existing target, if compatible.
|
||||
* @param {HTMLElement} target Potential render target.
|
||||
* @param {import("../../transform").Transform} transform Transform.
|
||||
* @param {number} opacity Opacity.
|
||||
* @inheritDoc
|
||||
*/
|
||||
useContainer(target, transform, opacity) {
|
||||
const layerClassName = this.getLayer().getClassName();
|
||||
let container, context;
|
||||
if (target && target.style.opacity === '' && target.className === layerClassName) {
|
||||
const canvas = target.firstElementChild;
|
||||
if (canvas instanceof HTMLCanvasElement) {
|
||||
context = canvas.getContext('2d');
|
||||
}
|
||||
}
|
||||
if (context && context.canvas.style.transform === transformToString(transform)) {
|
||||
// Container of the previous layer renderer can be used.
|
||||
this.container = target;
|
||||
this.context = context;
|
||||
this.containerReused = true;
|
||||
} else if (this.containerReused) {
|
||||
// Previously reused container cannot be used any more.
|
||||
this.container = null;
|
||||
this.context = null;
|
||||
this.containerReused = false;
|
||||
}
|
||||
if (!this.container) {
|
||||
container = document.createElement('div');
|
||||
container.className = layerClassName;
|
||||
let style = container.style;
|
||||
style.position = 'absolute';
|
||||
style.width = '100%';
|
||||
style.height = '100%';
|
||||
context = createCanvasContext2D();
|
||||
const canvas = context.canvas;
|
||||
container.appendChild(canvas);
|
||||
style = canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
this.container = container;
|
||||
this.context = context;
|
||||
}
|
||||
disposeInternal() {
|
||||
this.context.canvas.width = this.context.canvas.height = 0;
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,7 +125,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
prepareFrame(frameState, layerState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,8 +137,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
* @inheritDoc
|
||||
* @returns {HTMLElement} The rendered element.
|
||||
*/
|
||||
renderFrame(frameState, target) {
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
renderFrame(frameState, layerState) {
|
||||
const context = this.context;
|
||||
const viewState = frameState.viewState;
|
||||
const projection = viewState.projection;
|
||||
const viewResolution = viewState.resolution;
|
||||
@@ -224,6 +224,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
}
|
||||
|
||||
|
||||
const canvas = context.canvas;
|
||||
const canvasScale = tileResolution / viewResolution;
|
||||
|
||||
// set forward and inverse pixel transforms
|
||||
@@ -233,11 +234,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
rotation,
|
||||
-width / 2, -height / 2
|
||||
);
|
||||
|
||||
this.useContainer(target, this.pixelTransform_, layerState.opacity);
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
|
||||
|
||||
// set scale transform for calculating tile positions on the canvas
|
||||
@@ -251,7 +247,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
if (canvas.width != width || canvas.height != height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
} else if (!this.containerReused) {
|
||||
} else {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
@@ -263,7 +259,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
|
||||
this.renderedTiles.length = 0;
|
||||
/** @type {Array<number>} */
|
||||
let zs = Object.keys(tilesToDrawByZ).map(Number);
|
||||
const zs = Object.keys(tilesToDrawByZ).map(Number);
|
||||
zs.sort(function(a, b) {
|
||||
if (a === z) {
|
||||
return 1;
|
||||
@@ -274,14 +270,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
}
|
||||
});
|
||||
|
||||
let clips, clipZs, currentClip;
|
||||
if (layerState.opacity === 1 && (!this.containerReused || tileSource.getOpaque(frameState.viewState.projection))) {
|
||||
zs = zs.reverse();
|
||||
} else {
|
||||
clips = [];
|
||||
clipZs = [];
|
||||
}
|
||||
for (let i = zs.length - 1; i >= 0; --i) {
|
||||
for (let i = 0, ii = zs.length; i < ii; ++i) {
|
||||
const currentZ = zs[i];
|
||||
const currentTilePixelSize = tileSource.getTilePixelSize(currentZ, pixelRatio, projection);
|
||||
const currentResolution = tileGrid.getResolution(currentZ);
|
||||
@@ -309,36 +298,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
const y = Math.round(floatY);
|
||||
const w = nextX - x;
|
||||
const h = nextY - y;
|
||||
const transition = z === currentZ;
|
||||
|
||||
if (clips && (!transition || tile.getAlpha(getUid(this), frameState.time) === 1)) {
|
||||
// Clip mask for regions in this tile that already filled by a higher z tile
|
||||
context.save();
|
||||
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
|
||||
for (let i = 0, ii = clips.length; i < ii; ++i) {
|
||||
if (z !== currentZ && currentZ < clipZs[i]) {
|
||||
const clip = clips[i];
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher z tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
}
|
||||
}
|
||||
clips.push(currentClip);
|
||||
clipZs.push(currentZ);
|
||||
}
|
||||
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, transition, layerState.opacity);
|
||||
if (clips) {
|
||||
context.restore();
|
||||
}
|
||||
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, z === currentZ);
|
||||
this.renderedTiles.push(tile);
|
||||
this.updateUsedTiles(frameState.usedTiles, tileSource, tile);
|
||||
}
|
||||
@@ -361,12 +322,17 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
context.restore();
|
||||
}
|
||||
|
||||
const opacity = layerState.opacity;
|
||||
if (opacity !== parseFloat(canvas.style.opacity)) {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
const canvasTransform = transformToString(this.pixelTransform_);
|
||||
if (canvasTransform !== canvas.style.transform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
|
||||
return this.container;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,15 +344,19 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
* @param {number} h Height of the tile.
|
||||
* @param {number} gutter Tile gutter.
|
||||
* @param {boolean} transition Apply an alpha transition.
|
||||
* @param {number} opacity Opacity.
|
||||
*/
|
||||
drawTileImage(tile, frameState, x, y, w, h, gutter, transition, opacity) {
|
||||
drawTileImage(tile, frameState, x, y, w, h, gutter, transition) {
|
||||
const image = this.getTileImage(tile);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
const uid = getUid(this);
|
||||
const alpha = opacity * (transition ? tile.getAlpha(uid, frameState.time) : 1);
|
||||
const alpha = transition ? tile.getAlpha(uid, frameState.time) : 1;
|
||||
const tileLayer = /** @type {import("../../layer/Tile.js").default} */ (this.getLayer());
|
||||
const tileSource = tileLayer.getSource();
|
||||
if (alpha === 1 && !tileSource.getOpaque(frameState.viewState.projection)) {
|
||||
this.context.clearRect(x, y, w, h);
|
||||
}
|
||||
const alphaChanged = alpha !== this.context.globalAlpha;
|
||||
if (alphaChanged) {
|
||||
this.context.save();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @module ol/renderer/canvas/VectorImageLayer
|
||||
* @module ol/renderer/canvas/ImageLayer
|
||||
*/
|
||||
import ImageCanvas from '../../ImageCanvas.js';
|
||||
import ViewHint from '../../ViewHint.js';
|
||||
@@ -56,14 +56,7 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleFontsChanged() {
|
||||
this.vectorRenderer_.handleFontsChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
prepareFrame(frameState, layerState) {
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const viewState = frameState.viewState;
|
||||
const viewResolution = viewState.resolution;
|
||||
@@ -78,7 +71,6 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
|
||||
|
||||
if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) {
|
||||
let skippedFeatures = this.skippedFeatures_;
|
||||
vectorRenderer.useContainer(null, null, 1);
|
||||
const context = vectorRenderer.context;
|
||||
const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, {
|
||||
declutterItems: [],
|
||||
@@ -92,10 +84,10 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
|
||||
}));
|
||||
const newSkippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort();
|
||||
const image = new ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas, function(callback) {
|
||||
if (vectorRenderer.prepareFrame(imageFrameState) &&
|
||||
if (vectorRenderer.prepareFrame(imageFrameState, layerState) &&
|
||||
(vectorRenderer.replayGroupChanged ||
|
||||
!equals(skippedFeatures, newSkippedFeatures))) {
|
||||
vectorRenderer.renderFrame(imageFrameState, null);
|
||||
vectorRenderer.renderFrame(imageFrameState, layerState);
|
||||
renderDeclutterItems(imageFrameState, null);
|
||||
skippedFeatures = newSkippedFeatures;
|
||||
callback();
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
*/
|
||||
import {getUid} from '../../util.js';
|
||||
import ViewHint from '../../ViewHint.js';
|
||||
import {listen, unlisten} from '../../events.js';
|
||||
import EventType from '../../events/EventType.js';
|
||||
import {buffer, createEmpty, containsExtent, getWidth} from '../../extent.js';
|
||||
import {labelCache} from '../../render/canvas.js';
|
||||
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
||||
import ExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
@@ -65,42 +68,39 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.replayGroupChanged = true;
|
||||
|
||||
listen(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
useContainer(target, transform, opacity) {
|
||||
if (opacity < 1) {
|
||||
target = null;
|
||||
}
|
||||
super.useContainer(target, transform, opacity);
|
||||
disposeInternal() {
|
||||
unlisten(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
renderFrame(frameState, target) {
|
||||
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
|
||||
// set forward and inverse pixel transforms
|
||||
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
|
||||
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
|
||||
|
||||
this.useContainer(target, this.pixelTransform_, layerState.opacity);
|
||||
renderFrame(frameState, layerState) {
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
const replayGroup = this.replayGroup_;
|
||||
if (!replayGroup || replayGroup.isEmpty()) {
|
||||
if (!this.containerReused && canvas.width > 0) {
|
||||
if (canvas.width > 0) {
|
||||
canvas.width = 0;
|
||||
}
|
||||
return this.container;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
|
||||
// set forward and inverse pixel transforms
|
||||
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
|
||||
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
|
||||
|
||||
// resize and clear
|
||||
const width = Math.round(frameState.size[0] * pixelRatio);
|
||||
const height = Math.round(frameState.size[1] * pixelRatio);
|
||||
@@ -111,7 +111,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
} else if (!this.containerReused) {
|
||||
} else {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
if (declutterReplays) {
|
||||
const viewHints = frameState.viewHints;
|
||||
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
|
||||
replayDeclutter(declutterReplays, context, rotation, 1, hifi, frameState.declutterItems);
|
||||
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems);
|
||||
}
|
||||
|
||||
if (clipped) {
|
||||
@@ -175,12 +175,11 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
this.postRender(context, frameState);
|
||||
|
||||
const opacity = layerState.opacity;
|
||||
const container = this.container;
|
||||
if (opacity !== parseFloat(container.style.opacity)) {
|
||||
container.style.opacity = opacity === 1 ? '' : opacity;
|
||||
if (opacity !== parseFloat(canvas.style.opacity)) {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
return this.container;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +191,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
} else {
|
||||
const resolution = frameState.viewState.resolution;
|
||||
const rotation = frameState.viewState.rotation;
|
||||
const layer = /** @type {import("../../layer/Vector").default} */ (this.getLayer());
|
||||
const layer = this.getLayer();
|
||||
/** @type {!Object<string, boolean>} */
|
||||
const features = {};
|
||||
const result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance, {},
|
||||
@@ -206,15 +205,15 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
features[key] = true;
|
||||
return callback(feature, layer);
|
||||
}
|
||||
}, layer.getDeclutter() ? declutteredFeatures : null);
|
||||
}, declutteredFeatures);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param {import("../../events/Event.js").default} event Event.
|
||||
*/
|
||||
handleFontsChanged() {
|
||||
handleFontsChanged_(event) {
|
||||
const layer = this.getLayer();
|
||||
if (layer.getVisible() && this.replayGroup_) {
|
||||
layer.changed();
|
||||
@@ -233,7 +232,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
prepareFrame(frameState, layerState) {
|
||||
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
|
||||
const vectorSource = vectorLayer.getSource();
|
||||
|
||||
|
||||
@@ -5,17 +5,19 @@ import {getUid} from '../../util.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import TileState from '../../TileState.js';
|
||||
import ViewHint from '../../ViewHint.js';
|
||||
import {listen, unlistenByKey} from '../../events.js';
|
||||
import {listen, unlisten, unlistenByKey} from '../../events.js';
|
||||
import EventType from '../../events/EventType.js';
|
||||
import {buffer, containsCoordinate, equals, getIntersection, intersects} from '../../extent.js';
|
||||
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
||||
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
||||
import ReplayType from '../../render/canvas/BuilderType.js';
|
||||
import {labelCache} from '../../render/canvas.js';
|
||||
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
||||
import CanvasTileLayerRenderer from './TileLayer.js';
|
||||
import {getSquaredTolerance as getSquaredRenderTolerance, renderFeature} from '../vector.js';
|
||||
import {
|
||||
apply as applyTransform,
|
||||
create as createTransform,
|
||||
compose as composeTransform,
|
||||
reset as resetTransform,
|
||||
scale as scaleTransform,
|
||||
translate as translateTransform,
|
||||
@@ -24,6 +26,7 @@ import {
|
||||
makeInverse
|
||||
} from '../../transform.js';
|
||||
import CanvasExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
|
||||
import {clear, isEmpty} from '../../obj.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,11 +61,32 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
constructor(layer) {
|
||||
super(layer);
|
||||
|
||||
const baseCanvas = this.context.canvas;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.overlayContext_ = null;
|
||||
this.overlayContext_ = createCanvasContext2D();
|
||||
|
||||
const overlayCanvas = this.overlayContext_.canvas;
|
||||
overlayCanvas.style.position = 'absolute';
|
||||
overlayCanvas.style.transformOrigin = 'top left';
|
||||
|
||||
const container = document.createElement('div');
|
||||
const style = container.style;
|
||||
style.position = 'absolute';
|
||||
style.width = '100%';
|
||||
style.height = '100%';
|
||||
|
||||
container.appendChild(baseCanvas);
|
||||
container.appendChild(overlayCanvas);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.container_ = container;
|
||||
|
||||
/**
|
||||
* The transform for rendered pixels to viewport CSS pixels for the overlay canvas.
|
||||
@@ -109,48 +133,26 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
|
||||
// Use nearest lower resolution.
|
||||
this.zDirection = 1;
|
||||
|
||||
listen(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
useContainer(target, transform, opacity) {
|
||||
let overlayContext;
|
||||
if (target && target.childElementCount === 2) {
|
||||
overlayContext = target.lastElementChild.getContext('2d');
|
||||
if (!overlayContext) {
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
const containerReused = this.containerReused;
|
||||
super.useContainer(target, transform, opacity);
|
||||
if (containerReused && !this.containerReused && !overlayContext) {
|
||||
this.overlayContext_ = null;
|
||||
}
|
||||
if (this.containerReused && overlayContext) {
|
||||
this.overlayContext_ = overlayContext;
|
||||
}
|
||||
if (!this.overlayContext_) {
|
||||
const overlayContext = createCanvasContext2D();
|
||||
const style = overlayContext.canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
this.overlayContext_ = overlayContext;
|
||||
}
|
||||
if (this.container.childElementCount === 1) {
|
||||
this.container.appendChild(this.overlayContext_.canvas);
|
||||
}
|
||||
disposeInternal() {
|
||||
unlisten(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||
this.overlayContext_.canvas.width = this.overlayContext_.canvas.height = 0;
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../VectorRenderTile.js").default} tile Tile.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {import("../../proj/Projection").default} projection Projection.
|
||||
* @param {boolean} queue Queue tile for rendering.
|
||||
* @return {boolean} Tile needs to be rendered.
|
||||
*/
|
||||
prepareTile(tile, pixelRatio, projection, queue) {
|
||||
let render = false;
|
||||
prepareTile(tile, pixelRatio, projection) {
|
||||
const tileUid = getUid(tile);
|
||||
const state = tile.getState();
|
||||
if (((state === TileState.LOADED && tile.hifi) ||
|
||||
@@ -162,13 +164,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
if (state === TileState.LOADED || state === TileState.ERROR) {
|
||||
this.updateExecutorGroup_(tile, pixelRatio, projection);
|
||||
if (this.tileImageNeedsRender_(tile, pixelRatio, projection)) {
|
||||
render = true;
|
||||
if (queue) {
|
||||
this.renderTileImageQueue_[tileUid] = tile;
|
||||
}
|
||||
this.renderTileImageQueue_[tileUid] = tile;
|
||||
}
|
||||
}
|
||||
return render;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +182,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
tile.wantedResolution = resolution;
|
||||
const tileUid = getUid(tile);
|
||||
if (!(tileUid in this.tileListenerKeys_)) {
|
||||
const listenerKey = listen(tile, EventType.CHANGE, this.prepareTile.bind(this, tile, pixelRatio, projection, true));
|
||||
const listenerKey = listen(tile, EventType.CHANGE, this.prepareTile.bind(this, tile, pixelRatio, projection));
|
||||
this.tileListenerKeys_[tileUid] = listenerKey;
|
||||
}
|
||||
} else {
|
||||
@@ -193,10 +191,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
if (hifi || !tile.wantedResolution) {
|
||||
tile.wantedResolution = resolution;
|
||||
}
|
||||
const render = this.prepareTile(tile, pixelRatio, projection, false);
|
||||
if (render) {
|
||||
this.renderTileImage_(tile, frameState);
|
||||
}
|
||||
this.prepareTile(tile, pixelRatio, projection);
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
@@ -218,13 +213,13 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
prepareFrame(frameState, layerState) {
|
||||
const layerRevision = this.getLayer().getRevision();
|
||||
if (this.renderedLayerRevision_ != layerRevision) {
|
||||
this.renderedTiles.length = 0;
|
||||
}
|
||||
this.renderedLayerRevision_ = layerRevision;
|
||||
return super.prepareFrame(frameState);
|
||||
return super.prepareFrame(frameState, layerState);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,16 +357,45 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
features[key] = true;
|
||||
return callback(feature, layer);
|
||||
}
|
||||
}, layer.getDeclutter() ? declutteredFeatures : null);
|
||||
}, declutteredFeatures);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param {import("../../VectorTile.js").default} tile Tile.
|
||||
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @return {import("../../transform.js").Transform} transform Transform.
|
||||
* @private
|
||||
*/
|
||||
handleFontsChanged() {
|
||||
getReplayTransform_(tile, frameState) {
|
||||
const layer = this.getLayer();
|
||||
const source = layer.getSource();
|
||||
const tileGrid = source.getTileGrid();
|
||||
const tileCoord = tile.tileCoord;
|
||||
const tileResolution = tileGrid.getResolution(tileCoord[0]);
|
||||
const viewState = frameState.viewState;
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const renderResolution = viewState.resolution / pixelRatio;
|
||||
const tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||
const center = viewState.center;
|
||||
const origin = getTopLeft(tileExtent);
|
||||
const size = frameState.size;
|
||||
const offsetX = Math.round(pixelRatio * size[0] / 2);
|
||||
const offsetY = Math.round(pixelRatio * size[1] / 2);
|
||||
return composeTransform(this.tmpTransform_,
|
||||
offsetX, offsetY,
|
||||
tileResolution / renderResolution, tileResolution / renderResolution,
|
||||
viewState.rotation,
|
||||
(origin[0] - center[0]) / tileResolution,
|
||||
(center[1] - origin[1]) / tileResolution);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../events/Event.js").default} event Event.
|
||||
*/
|
||||
handleFontsChanged_(event) {
|
||||
const layer = this.getLayer();
|
||||
if (layer.getVisible() && this.renderedLayerRevision_ !== undefined) {
|
||||
layer.changed();
|
||||
@@ -390,30 +414,26 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
renderFrame(frameState, target) {
|
||||
const viewHints = frameState.viewHints;
|
||||
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
|
||||
this.renderQueuedTileImages_(hifi, frameState);
|
||||
|
||||
super.renderFrame(frameState, target);
|
||||
renderFrame(frameState, layerState) {
|
||||
super.renderFrame(frameState, layerState);
|
||||
|
||||
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
|
||||
const viewHints = frameState.viewHints;
|
||||
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
|
||||
const renderMode = layer.getRenderMode();
|
||||
if (renderMode === VectorTileRenderType.IMAGE) {
|
||||
return this.container;
|
||||
this.renderTileImages_(hifi, frameState);
|
||||
return this.container_;
|
||||
}
|
||||
|
||||
const source = layer.getSource();
|
||||
// Unqueue tiles from the image queue when we don't need any more
|
||||
const usedTiles = frameState.usedTiles[getUid(source)];
|
||||
for (const tileUid in this.renderTileImageQueue_) {
|
||||
if (!(tileUid in usedTiles)) {
|
||||
delete this.renderTileImageQueue_[tileUid];
|
||||
}
|
||||
if (!isEmpty(this.renderTileImageQueue_) && !this.extentChanged) {
|
||||
this.renderTileImages_(hifi, frameState);
|
||||
return this.container_;
|
||||
}
|
||||
|
||||
const context = this.overlayContext_;
|
||||
const declutterReplays = layer.getDeclutter() ? {} : null;
|
||||
const source = layer.getSource();
|
||||
const replayTypes = VECTOR_REPLAYS[renderMode];
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
const rotation = frameState.viewState.rotation;
|
||||
@@ -434,14 +454,13 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
} else if (!this.containerReused) {
|
||||
} else {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
const tiles = this.renderedTiles;
|
||||
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
const clips = [];
|
||||
const clipZs = [];
|
||||
for (let i = tiles.length - 1; i >= 0; --i) {
|
||||
const tile = /** @type {import("../../VectorRenderTile.js").default} */ (tiles[i]);
|
||||
if (tile.getState() == TileState.ABORT) {
|
||||
@@ -452,7 +471,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tileExtent[0];
|
||||
const transform = this.getRenderTransform(frameState, width, height, worldOffset);
|
||||
const executorGroups = tile.executorGroups[getUid(layer)];
|
||||
let clipped = false;
|
||||
for (let t = 0, tt = executorGroups.length; t < tt; ++t) {
|
||||
const executorGroup = executorGroups[t];
|
||||
if (!executorGroup.hasExecutors(replayTypes)) {
|
||||
@@ -460,8 +478,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
continue;
|
||||
}
|
||||
const currentZ = tile.tileCoord[0];
|
||||
let currentClip;
|
||||
if (!declutterReplays && !clipped) {
|
||||
let zs, currentClip;
|
||||
if (!declutterReplays) {
|
||||
zs = [];
|
||||
currentClip = executorGroup.getClipCoords(transform);
|
||||
context.save();
|
||||
|
||||
@@ -469,7 +488,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
// already filled by a higher resolution tile
|
||||
for (let j = 0, jj = clips.length; j < jj; ++j) {
|
||||
const clip = clips[j];
|
||||
if (currentZ < clipZs[j]) {
|
||||
if (currentZ < zs[j]) {
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
@@ -486,38 +505,51 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
}
|
||||
}
|
||||
executorGroup.execute(context, transform, rotation, {}, hifi, replayTypes, declutterReplays);
|
||||
if (!declutterReplays && !clipped) {
|
||||
if (!declutterReplays) {
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
clipZs.push(currentZ);
|
||||
clipped = true;
|
||||
zs.push(currentZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (declutterReplays) {
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
replayDeclutter(declutterReplays, context, rotation, layerState.opacity, hifi, frameState.declutterItems);
|
||||
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
const opacity = layerState.opacity;
|
||||
if (opacity !== parseFloat(canvas.style.opacity)) {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
// Now that we have rendered the tiles we have already, let's prepare new tile images
|
||||
// for the next frame
|
||||
this.renderTileImages_(hifi, frameState);
|
||||
|
||||
return this.container_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} hifi We have time to render a high fidelity map image.
|
||||
* @param {import('../../PluggableMap.js').FrameState} frameState Frame state.
|
||||
*/
|
||||
renderQueuedTileImages_(hifi, frameState) {
|
||||
renderTileImages_(hifi, frameState) {
|
||||
// When we don't have time to render hifi, only render tiles until we have used up
|
||||
// half of the frame budget of 16 ms
|
||||
for (const uid in this.renderTileImageQueue_) {
|
||||
if (!hifi && Date.now() - frameState.time > 8) {
|
||||
frameState.animate = true;
|
||||
break;
|
||||
}
|
||||
const tile = this.renderTileImageQueue_[uid];
|
||||
frameState.animate = true;
|
||||
delete this.renderTileImageQueue_[uid];
|
||||
this.renderTileImage_(tile, frameState);
|
||||
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
|
||||
const viewState = frameState.viewState;
|
||||
const tileGrid = layer.getSource().getTileGridForProjection(viewState.projection);
|
||||
const tileResolution = tileGrid.getResolution(tile.tileCoord[0]);
|
||||
const renderPixelRatio = frameState.pixelRatio / tile.wantedResolution * tileResolution;
|
||||
this.renderTileImage_(tile, frameState.pixelRatio, renderPixelRatio, viewState.projection);
|
||||
}
|
||||
clear(this.renderTileImageQueue_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,47 +596,40 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
|
||||
/**
|
||||
* @param {import("../../VectorRenderTile.js").default} tile Tile.
|
||||
* @param {import("../../PluggableMap").FrameState} frameState Frame state.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {number} renderPixelRatio Render pixel ratio.
|
||||
* @param {import("../../proj/Projection.js").default} projection Projection.
|
||||
* @private
|
||||
*/
|
||||
renderTileImage_(tile, frameState) {
|
||||
renderTileImage_(tile, pixelRatio, renderPixelRatio, projection) {
|
||||
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
|
||||
const replayState = tile.getReplayState(layer);
|
||||
const revision = layer.getRevision();
|
||||
const executorGroups = tile.executorGroups[getUid(layer)];
|
||||
replayState.renderedTileRevision = revision;
|
||||
replayState.renderedTileZ = tile.sourceZ;
|
||||
|
||||
const tileCoord = tile.wrappedTileCoord;
|
||||
const z = tileCoord[0];
|
||||
const source = layer.getSource();
|
||||
let pixelRatio = frameState.pixelRatio;
|
||||
const viewState = frameState.viewState;
|
||||
const projection = viewState.projection;
|
||||
const tileGrid = source.getTileGridForProjection(projection);
|
||||
const tileResolution = tileGrid.getResolution(tile.tileCoord[0]);
|
||||
const renderPixelRatio = frameState.pixelRatio / tile.wantedResolution * tileResolution;
|
||||
const resolution = tileGrid.getResolution(z);
|
||||
const context = tile.getContext(layer);
|
||||
|
||||
// Increase tile size when overzooming for low pixel ratio, to avoid blurry tiles
|
||||
pixelRatio = Math.max(pixelRatio, renderPixelRatio / pixelRatio);
|
||||
const size = source.getTilePixelSize(z, pixelRatio, projection);
|
||||
context.canvas.width = size[0];
|
||||
context.canvas.height = size[1];
|
||||
const canvasTransform = resetTransform(this.tmpTransform_);
|
||||
const renderScale = pixelRatio / renderPixelRatio;
|
||||
if (renderScale !== 1) {
|
||||
const canvasTransform = resetTransform(this.tmpTransform_);
|
||||
scaleTransform(canvasTransform, renderScale, renderScale);
|
||||
context.setTransform.apply(context, canvasTransform);
|
||||
}
|
||||
scaleTransform(canvasTransform, renderScale, renderScale);
|
||||
context.setTransform.apply(context, canvasTransform);
|
||||
const tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||
const pixelScale = renderPixelRatio / resolution;
|
||||
const transform = resetTransform(this.tmpTransform_);
|
||||
scaleTransform(transform, pixelScale, -pixelScale);
|
||||
translateTransform(transform, -tileExtent[0], -tileExtent[3]);
|
||||
for (let i = 0, ii = executorGroups.length; i < ii; ++i) {
|
||||
const executorGroup = executorGroups[i];
|
||||
const pixelScale = renderPixelRatio / resolution;
|
||||
const transform = resetTransform(this.tmpTransform_);
|
||||
scaleTransform(transform, pixelScale, -pixelScale);
|
||||
translateTransform(transform, -tileExtent[0], -tileExtent[3]);
|
||||
executorGroup.execute(context, transform, 0, {}, true, IMAGE_REPLAYS[layer.getRenderMode()]);
|
||||
}
|
||||
replayState.renderedTileResolution = tile.wantedResolution;
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
* @module ol/renderer/webgl/Layer
|
||||
*/
|
||||
import LayerRenderer from '../Layer.js';
|
||||
import WebGLHelper from '../../webgl/Helper.js';
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} PostProcessesOptions
|
||||
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
|
||||
* the main canvas that will then be sampled up (useful for saving resource on blur steps).
|
||||
* @property {string} [vertexShader] Vertex shader source
|
||||
* @property {string} [fragmentShader] Fragment shader source
|
||||
* @property {Object.<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process step
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Object.<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process steps
|
||||
* @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Base WebGL renderer class.
|
||||
* Holds all logic related to data manipulation & some common rendering logic
|
||||
*/
|
||||
class WebGLLayerRenderer extends LayerRenderer {
|
||||
|
||||
/**
|
||||
* @param {import("../../layer/Layer.js").default} layer Layer.
|
||||
* @param {Options=} [opt_options] Options.
|
||||
*/
|
||||
constructor(layer, opt_options) {
|
||||
super(layer);
|
||||
|
||||
const options = opt_options || {};
|
||||
|
||||
this.helper_ = new WebGLHelper({
|
||||
postProcesses: options.postProcesses,
|
||||
uniforms: options.uniforms
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return the last shader compilation errors. If no error happened, will return null;
|
||||
* @return {string|null} Errors, or null if last compilation was successful
|
||||
* @api
|
||||
*/
|
||||
getShaderCompileErrors() {
|
||||
return this.helper_.getShaderCompileErrors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pushes vertices and indices to the given buffers using the geometry coordinates and the following properties
|
||||
* from the feature:
|
||||
* - `color`
|
||||
* - `opacity`
|
||||
* - `size` (for points)
|
||||
* - `u0`, `v0`, `u1`, `v1` (for points)
|
||||
* - `rotateWithView` (for points)
|
||||
* - `width` (for lines)
|
||||
* Custom attributes can be designated using the `opt_attributes` argument, otherwise other properties on the
|
||||
* feature will be ignored.
|
||||
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer in which new vertices will be pushed.
|
||||
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer in which new indices will be pushed.
|
||||
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature in geojson format, coordinates
|
||||
* expressed in EPSG:4326.
|
||||
* @param {Array<string>} [opt_attributes] Custom attributes. An array of properties which will be read from the
|
||||
* feature and pushed in the buffer in the given order. Note: attributes can only be numerical! Any other type or
|
||||
* NaN will result in `0` being pushed in the buffer.
|
||||
*/
|
||||
export function pushFeatureToBuffer(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) {
|
||||
if (!geojsonFeature.geometry) {
|
||||
return;
|
||||
}
|
||||
switch (geojsonFeature.geometry.type) {
|
||||
case 'Point':
|
||||
pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const tmpArray_ = [];
|
||||
|
||||
/**
|
||||
* Pushes a quad (two triangles) based on a point geometry
|
||||
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer
|
||||
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer
|
||||
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature
|
||||
* @param {Array<string>} [opt_attributes] Custom attributes
|
||||
* @private
|
||||
*/
|
||||
function pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) {
|
||||
const stride = 12 + (opt_attributes !== undefined ? opt_attributes.length : 0);
|
||||
|
||||
const x = geojsonFeature.geometry.coordinates[0];
|
||||
const y = geojsonFeature.geometry.coordinates[1];
|
||||
const u0 = geojsonFeature.properties.u0;
|
||||
const v0 = geojsonFeature.properties.v0;
|
||||
const u1 = geojsonFeature.properties.u1;
|
||||
const v1 = geojsonFeature.properties.v1;
|
||||
const size = geojsonFeature.properties.size;
|
||||
const opacity = geojsonFeature.properties.opacity;
|
||||
const rotateWithView = geojsonFeature.properties.rotateWithView;
|
||||
const color = geojsonFeature.properties.color;
|
||||
const red = color[0];
|
||||
const green = color[1];
|
||||
const blue = color[2];
|
||||
const alpha = color[3];
|
||||
const baseIndex = vertexBuffer.getArray().length / stride;
|
||||
|
||||
// read custom numerical attributes on the feature
|
||||
const customAttributeValues = tmpArray_;
|
||||
customAttributeValues.length = opt_attributes ? opt_attributes.length : 0;
|
||||
for (let i = 0; i < customAttributeValues.length; i++) {
|
||||
customAttributeValues[i] = parseFloat(geojsonFeature.properties[opt_attributes[i]]) || 0;
|
||||
}
|
||||
|
||||
// push vertices for each of the four quad corners (first standard then custom attributes)
|
||||
vertexBuffer.getArray().push(x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha);
|
||||
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
|
||||
|
||||
vertexBuffer.getArray().push(x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha);
|
||||
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
|
||||
|
||||
vertexBuffer.getArray().push(x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha);
|
||||
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
|
||||
|
||||
vertexBuffer.getArray().push(x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha);
|
||||
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
|
||||
|
||||
indexBuffer.getArray().push(
|
||||
baseIndex, baseIndex + 1, baseIndex + 3,
|
||||
baseIndex + 1, baseIndex + 2, baseIndex + 3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a texture of 1x1 pixel, white
|
||||
* @private
|
||||
* @return {ImageData} Image data.
|
||||
*/
|
||||
export function getBlankTexture() {
|
||||
const canvas = document.createElement('canvas');
|
||||
const image = canvas.getContext('2d').createImageData(1, 1);
|
||||
image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255;
|
||||
return image;
|
||||
}
|
||||
|
||||
export default WebGLLayerRenderer;
|
||||
@@ -1,21 +1,11 @@
|
||||
/**
|
||||
* @module ol/renderer/webgl/PointsLayer
|
||||
*/
|
||||
import WebGLArrayBuffer from '../../webgl/Buffer.js';
|
||||
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl.js';
|
||||
import {DefaultAttrib, DefaultUniform} from '../../webgl/Helper.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import WebGLLayerRenderer, {getBlankTexture, pushFeatureToBuffer} from './Layer.js';
|
||||
import GeoJSON from '../../format/GeoJSON.js';
|
||||
import {getUid} from '../../util.js';
|
||||
import ViewHint from '../../ViewHint.js';
|
||||
import {createEmpty, equals} from '../../extent.js';
|
||||
import {
|
||||
create as createTransform,
|
||||
makeInverse as makeInverseTransform,
|
||||
multiply as multiplyTransform,
|
||||
apply as applyTransform
|
||||
} from '../../transform.js';
|
||||
import LayerRenderer from '../Layer';
|
||||
import WebGLArrayBuffer from '../../webgl/Buffer';
|
||||
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl';
|
||||
import WebGLHelper, {DefaultAttrib} from '../../webgl/Helper';
|
||||
import GeometryType from '../../geom/GeometryType';
|
||||
|
||||
const VERTEX_SHADER = `
|
||||
precision mediump float;
|
||||
@@ -25,15 +15,15 @@ const VERTEX_SHADER = `
|
||||
attribute vec2 a_offsets;
|
||||
attribute float a_opacity;
|
||||
attribute vec4 a_color;
|
||||
|
||||
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying float v_opacity;
|
||||
varying vec4 v_color;
|
||||
|
||||
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
if (a_rotateWithView == 1.0) {
|
||||
@@ -48,13 +38,13 @@ const VERTEX_SHADER = `
|
||||
|
||||
const FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying float v_opacity;
|
||||
varying vec4 v_color;
|
||||
|
||||
|
||||
void main(void) {
|
||||
if (v_opacity == 0.0) {
|
||||
discard;
|
||||
@@ -65,6 +55,15 @@ const FRAGMENT_SHADER = `
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`;
|
||||
|
||||
/**
|
||||
* @typedef {Object} PostProcessesOptions
|
||||
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
|
||||
* the main canvas that will then be sampled up (useful for saving resource on blur steps).
|
||||
* @property {string} [vertexShader] Vertex shader source
|
||||
* @property {string} [fragmentShader] Fragment shader source
|
||||
* @property {Object.<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process step
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {function(import("../../Feature").default):number} [sizeCallback] Will be called on every feature in the
|
||||
@@ -92,7 +91,7 @@ const FRAGMENT_SHADER = `
|
||||
* @property {string} [fragmentShader] Fragment shader source
|
||||
* @property {Object.<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process steps
|
||||
* Please note that `u_texture` is reserved for the main texture slot.
|
||||
* @property {Array<import("./Layer").PostProcessesOptions>} [postProcesses] Post-processes definitions
|
||||
* @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -187,23 +186,22 @@ const FRAGMENT_SHADER = `
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
class WebGLPointsLayerRenderer extends LayerRenderer {
|
||||
|
||||
/**
|
||||
* @param {import("../../layer/Vector.js").default} vectorLayer Vector layer.
|
||||
* @param {Options=} [opt_options] Options.
|
||||
*/
|
||||
constructor(vectorLayer, opt_options) {
|
||||
super(vectorLayer);
|
||||
|
||||
const options = opt_options || {};
|
||||
|
||||
const uniforms = options.uniforms || {};
|
||||
uniforms.u_texture = options.texture || getBlankTexture();
|
||||
const projectionMatrixTransform = createTransform();
|
||||
uniforms[DefaultUniform.PROJECTION_MATRIX] = projectionMatrixTransform;
|
||||
|
||||
super(vectorLayer, {
|
||||
uniforms: uniforms,
|
||||
postProcesses: options.postProcesses
|
||||
uniforms.u_texture = options.texture || this.getDefaultTexture();
|
||||
this.helper_ = new WebGLHelper({
|
||||
postProcesses: options.postProcesses,
|
||||
uniforms: uniforms
|
||||
});
|
||||
|
||||
this.sourceRevision_ = -1;
|
||||
@@ -222,7 +220,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
return 1;
|
||||
};
|
||||
this.coordCallback_ = options.coordCallback || function(feature, index) {
|
||||
const geom = feature.getGeometry();
|
||||
const geom = /** @type {import("../../geom/Point").default} */ (feature.getGeometry());
|
||||
return geom.getCoordinates()[index];
|
||||
};
|
||||
this.opacityCallback_ = options.opacityCallback || function() {
|
||||
@@ -240,38 +238,6 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.rotateWithViewCallback_ = options.rotateWithViewCallback || function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
this.geojsonFormat_ = new GeoJSON();
|
||||
|
||||
/**
|
||||
* @type {Object<string, import("../../format/GeoJSON").GeoJSONFeature>}
|
||||
* @private
|
||||
*/
|
||||
this.geojsonFeatureCache_ = {};
|
||||
|
||||
this.previousExtent_ = createEmpty();
|
||||
|
||||
/**
|
||||
* This transform is updated on every frame and is the composition of:
|
||||
* - invert of the world->screen transform that was used when rebuilding buffers (see `this.renderTransform_`)
|
||||
* - current world->screen transform
|
||||
* @type {import("../../transform.js").Transform}
|
||||
* @private
|
||||
*/
|
||||
this.currentTransform_ = projectionMatrixTransform;
|
||||
|
||||
/**
|
||||
* This transform is updated when buffers are rebuilt and converts world space coordinates to screen space
|
||||
* @type {import("../../transform.js").Transform}
|
||||
* @private
|
||||
*/
|
||||
this.renderTransform_ = createTransform();
|
||||
|
||||
/**
|
||||
* @type {import("../../transform.js").Transform}
|
||||
* @private
|
||||
*/
|
||||
this.invertRenderTransform_ = createTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,8 +250,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
renderFrame(frameState) {
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
renderFrame(frameState, layerState) {
|
||||
this.helper_.drawElements(0, this.indicesBuffer_.getArray().length);
|
||||
this.helper_.finalizeDraw(frameState);
|
||||
const canvas = this.helper_.getCanvas();
|
||||
@@ -304,35 +269,58 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
prepareFrame(frameState) {
|
||||
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
|
||||
const vectorSource = vectorLayer.getSource();
|
||||
const viewState = frameState.viewState;
|
||||
|
||||
// TODO: get this from somewhere...
|
||||
const stride = 12;
|
||||
|
||||
// the source has changed: clear the feature cache & reload features
|
||||
const sourceChanged = this.sourceRevision_ < vectorSource.getRevision();
|
||||
if (sourceChanged) {
|
||||
this.sourceRevision_ = vectorSource.getRevision();
|
||||
this.geojsonFeatureCache_ = {};
|
||||
this.helper_.prepareDraw(frameState);
|
||||
|
||||
if (this.sourceRevision_ < vectorSource.getRevision()) {
|
||||
this.sourceRevision_ = vectorSource.getRevision();
|
||||
this.verticesBuffer_.getArray().length = 0;
|
||||
this.indicesBuffer_.getArray().length = 0;
|
||||
|
||||
const viewState = frameState.viewState;
|
||||
const projection = viewState.projection;
|
||||
const resolution = viewState.resolution;
|
||||
|
||||
// loop on features to fill the buffer
|
||||
vectorSource.loadFeatures([-Infinity, -Infinity, Infinity, Infinity], resolution, projection);
|
||||
vectorSource.forEachFeature((feature) => {
|
||||
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
|
||||
return;
|
||||
}
|
||||
const x = this.coordCallback_(feature, 0);
|
||||
const y = this.coordCallback_(feature, 1);
|
||||
const u0 = this.texCoordCallback_(feature, 0);
|
||||
const v0 = this.texCoordCallback_(feature, 1);
|
||||
const u1 = this.texCoordCallback_(feature, 2);
|
||||
const v1 = this.texCoordCallback_(feature, 3);
|
||||
const size = this.sizeCallback_(feature);
|
||||
const opacity = this.opacityCallback_(feature);
|
||||
const rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0;
|
||||
const color = this.colorCallback_(feature, this.colorArray_);
|
||||
const red = color[0];
|
||||
const green = color[1];
|
||||
const blue = color[2];
|
||||
const alpha = color[3];
|
||||
const baseIndex = this.verticesBuffer_.getArray().length / stride;
|
||||
|
||||
this.verticesBuffer_.getArray().push(
|
||||
x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha,
|
||||
x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha,
|
||||
x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha,
|
||||
x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha
|
||||
);
|
||||
this.indicesBuffer_.getArray().push(
|
||||
baseIndex, baseIndex + 1, baseIndex + 3,
|
||||
baseIndex + 1, baseIndex + 2, baseIndex + 3
|
||||
);
|
||||
});
|
||||
|
||||
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_);
|
||||
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
|
||||
}
|
||||
|
||||
const viewNotMoving = !frameState.viewHints[ViewHint.ANIMATING] && !frameState.viewHints[ViewHint.INTERACTING];
|
||||
const extentChanged = !equals(this.previousExtent_, frameState.extent);
|
||||
if ((sourceChanged || extentChanged) && viewNotMoving) {
|
||||
this.rebuildBuffers_(frameState);
|
||||
this.previousExtent_ = frameState.extent.slice();
|
||||
}
|
||||
|
||||
// apply the current projection transform with the invert of the one used to fill buffers
|
||||
this.helper_.makeProjectionTransform(frameState, this.currentTransform_);
|
||||
multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
|
||||
|
||||
this.helper_.prepareDraw(frameState);
|
||||
|
||||
// write new data
|
||||
this.helper_.bindBuffer(ARRAY_BUFFER, this.verticesBuffer_);
|
||||
this.helper_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
|
||||
@@ -349,54 +337,24 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild internal webgl buffers based on current view extent; costly, should not be called too much
|
||||
* @param {import("../../PluggableMap").FrameState} frameState Frame state.
|
||||
* @private
|
||||
* Will return the last shader compilation errors. If no error happened, will return null;
|
||||
* @return {string|null} Errors, or null if last compilation was successful
|
||||
* @api
|
||||
*/
|
||||
rebuildBuffers_(frameState) {
|
||||
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
|
||||
const vectorSource = vectorLayer.getSource();
|
||||
getShaderCompileErrors() {
|
||||
return this.helper_.getShaderCompileErrors();
|
||||
}
|
||||
|
||||
this.verticesBuffer_.getArray().length = 0;
|
||||
this.indicesBuffer_.getArray().length = 0;
|
||||
|
||||
// saves the projection transform for the current frame state
|
||||
this.helper_.makeProjectionTransform(frameState, this.renderTransform_);
|
||||
makeInverseTransform(this.invertRenderTransform_, this.renderTransform_);
|
||||
|
||||
// loop on features to fill the buffer
|
||||
const features = vectorSource.getFeatures();
|
||||
let feature;
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
feature = features[i];
|
||||
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let geojsonFeature = this.geojsonFeatureCache_[getUid(feature)];
|
||||
if (!geojsonFeature) {
|
||||
geojsonFeature = this.geojsonFormat_.writeFeatureObject(feature);
|
||||
this.geojsonFeatureCache_[getUid(feature)] = geojsonFeature;
|
||||
}
|
||||
|
||||
geojsonFeature.geometry.coordinates[0] = this.coordCallback_(feature, 0);
|
||||
geojsonFeature.geometry.coordinates[1] = this.coordCallback_(feature, 1);
|
||||
applyTransform(this.renderTransform_, geojsonFeature.geometry.coordinates);
|
||||
geojsonFeature.properties = geojsonFeature.properties || {};
|
||||
geojsonFeature.properties.color = this.colorCallback_(feature, this.colorArray_);
|
||||
geojsonFeature.properties.u0 = this.texCoordCallback_(feature, 0);
|
||||
geojsonFeature.properties.v0 = this.texCoordCallback_(feature, 1);
|
||||
geojsonFeature.properties.u1 = this.texCoordCallback_(feature, 2);
|
||||
geojsonFeature.properties.v1 = this.texCoordCallback_(feature, 3);
|
||||
geojsonFeature.properties.size = this.sizeCallback_(feature);
|
||||
geojsonFeature.properties.opacity = this.opacityCallback_(feature);
|
||||
geojsonFeature.properties.rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0;
|
||||
|
||||
pushFeatureToBuffer(this.verticesBuffer_, this.indicesBuffer_, geojsonFeature);
|
||||
}
|
||||
|
||||
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_);
|
||||
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
|
||||
/**
|
||||
* Returns a texture of 1x1 pixel, white
|
||||
* @private
|
||||
* @return {ImageData} Image data.
|
||||
*/
|
||||
getDefaultTexture() {
|
||||
const canvas = document.createElement('canvas');
|
||||
const image = canvas.getContext('2d').createImageData(1, 1);
|
||||
image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* @module ol/resolutionconstraint
|
||||
*/
|
||||
import {linearFindNearest} from './array.js';
|
||||
import {getHeight, getWidth} from './extent.js';
|
||||
import {clamp} from './math.js';
|
||||
import {getHeight, getWidth} from './extent';
|
||||
import {clamp} from './math';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,7 +76,7 @@ class Cluster extends VectorSource {
|
||||
* @protected
|
||||
*/
|
||||
this.geometryFunction = options.geometryFunction || function(feature) {
|
||||
const geometry = feature.getGeometry();
|
||||
const geometry = /** @type {Point} */ (feature.getGeometry());
|
||||
assert(geometry.getType() == GeometryType.POINT,
|
||||
10); // The default `geometryFunction` can only handle `Point` geometries
|
||||
return geometry;
|
||||
|
||||
@@ -56,11 +56,6 @@ function formatPercentage(percentage) {
|
||||
*/
|
||||
class IIIF extends TileImage {
|
||||
|
||||
/**
|
||||
* @param {Options} opt_options Tile source options. Use {@link import("../format/IIIFInfo.js").IIIFInfo}
|
||||
* to parse Image API service information responses into constructor options.
|
||||
* @api
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
const options = opt_options || {};
|
||||
@@ -75,7 +70,6 @@ class IIIF extends TileImage {
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
const tileSize = options.tileSize;
|
||||
const tilePixelRatio = options.tilePixelRatio || 1;
|
||||
const format = options.format || 'jpg';
|
||||
const quality = options.quality || (options.version == Versions.VERSION1 ? 'native' : 'default');
|
||||
let resolutions = options.resolutions || [];
|
||||
@@ -261,7 +255,7 @@ class IIIF extends TileImage {
|
||||
return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format;
|
||||
};
|
||||
|
||||
const IiifTileClass = CustomTile.bind(null, tilePixelRatio, tileGrid);
|
||||
const IiifTileClass = CustomTile.bind(null, tileGrid);
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {createCanvasContext2D} from '../dom.js';
|
||||
import {listen} from '../events.js';
|
||||
import Event from '../events/Event.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {Processor} from 'pixelworks/lib/index.js';
|
||||
import {Processor} from 'pixelworks/lib/index';
|
||||
import {equals, getCenter, getHeight, getWidth} from '../extent.js';
|
||||
import ImageLayer from '../layer/Image.js';
|
||||
import TileLayer from '../layer/Tile.js';
|
||||
@@ -214,7 +214,6 @@ class RasterSource extends ImageSource {
|
||||
extent: null,
|
||||
focus: null,
|
||||
index: 0,
|
||||
layerIndex: 0,
|
||||
layerStatesArray: getLayerStatesArray(this.layers_),
|
||||
pixelRatio: 1,
|
||||
pixelToCoordinateTransform: createTransform(),
|
||||
@@ -359,8 +358,7 @@ class RasterSource extends ImageSource {
|
||||
const len = this.layers_.length;
|
||||
const imageDatas = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
frameState.layerIndex = i;
|
||||
const imageData = getImageData(this.layers_[i], frameState);
|
||||
const imageData = getImageData(this.layers_[i], frameState, frameState.layerStatesArray[i]);
|
||||
if (imageData) {
|
||||
imageDatas[i] = imageData;
|
||||
} else {
|
||||
@@ -432,24 +430,21 @@ let sharedContext = null;
|
||||
* Get image data from a layer.
|
||||
* @param {import("../layer/Layer.js").default} layer Layer to render.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState The frame state.
|
||||
* @param {import("../layer/Layer.js").State} layerState The layer state.
|
||||
* @return {ImageData} The image data.
|
||||
*/
|
||||
function getImageData(layer, frameState) {
|
||||
function getImageData(layer, frameState, layerState) {
|
||||
const renderer = layer.getRenderer();
|
||||
if (!renderer) {
|
||||
throw new Error('Unsupported layer type: ' + layer);
|
||||
}
|
||||
|
||||
if (!renderer.prepareFrame(frameState)) {
|
||||
if (!renderer.prepareFrame(frameState, layerState)) {
|
||||
return null;
|
||||
}
|
||||
const width = frameState.size[0];
|
||||
const height = frameState.size[1];
|
||||
const container = renderer.renderFrame(frameState, null);
|
||||
let element;
|
||||
if (container) {
|
||||
element = container.firstElementChild;
|
||||
}
|
||||
const element = renderer.renderFrame(frameState, layerState);
|
||||
if (!(element instanceof HTMLCanvasElement)) {
|
||||
throw new Error('Unsupported rendered element: ' + element);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// FIXME check order of async callbacks
|
||||
|
||||
/**
|
||||
* See https://mapbox.com/developers/api/.
|
||||
* See http://mapbox.com/developers/api/.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -35,13 +35,12 @@ import RBush from '../structs/RBush.js';
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/source/Vector} instances are instances of this
|
||||
* type.
|
||||
* @template {import("../geom/Geometry.js").default} Geometry
|
||||
*/
|
||||
export class VectorSourceEvent extends Event {
|
||||
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../Feature.js").default<Geometry>=} opt_feature Feature.
|
||||
* @param {import("../Feature.js").default=} opt_feature Feature.
|
||||
*/
|
||||
constructor(type, opt_feature) {
|
||||
|
||||
@@ -49,7 +48,7 @@ export class VectorSourceEvent extends Event {
|
||||
|
||||
/**
|
||||
* The feature being added or removed.
|
||||
* @type {import("../Feature.js").default<Geometry>|undefined}
|
||||
* @type {import("../Feature.js").default|undefined}
|
||||
* @api
|
||||
*/
|
||||
this.feature = opt_feature;
|
||||
@@ -155,9 +154,8 @@ export class VectorSourceEvent extends Event {
|
||||
* by this source are suitable for editing. See {@link module:ol/source/VectorTile~VectorTile} for
|
||||
* vector data that is optimized for rendering.
|
||||
*
|
||||
* @fires VectorSourceEvent<Geometry>
|
||||
* @fires VectorSourceEvent
|
||||
* @api
|
||||
* @template {import("../geom/Geometry.js").default} Geometry
|
||||
*/
|
||||
class VectorSource extends Source {
|
||||
/**
|
||||
@@ -217,7 +215,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {RBush<import("../Feature.js").default<Geometry>>}
|
||||
* @type {RBush<import("../Feature.js").default>}
|
||||
*/
|
||||
this.featuresRtree_ = useSpatialIndex ? new RBush() : null;
|
||||
|
||||
@@ -229,21 +227,21 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, import("../Feature.js").default<Geometry>>}
|
||||
* @type {!Object<string, import("../Feature.js").default>}
|
||||
*/
|
||||
this.nullGeometryFeatures_ = {};
|
||||
|
||||
/**
|
||||
* A lookup of features by id (the return from feature.getId()).
|
||||
* @private
|
||||
* @type {!Object<string, import("../Feature.js").default<Geometry>>}
|
||||
* @type {!Object<string, import("../Feature.js").default>}
|
||||
*/
|
||||
this.idIndex_ = {};
|
||||
|
||||
/**
|
||||
* A lookup of features without id (keyed by getUid(feature)).
|
||||
* @private
|
||||
* @type {!Object<string, import("../Feature.js").default<Geometry>>}
|
||||
* @type {!Object<string, import("../Feature.js").default>}
|
||||
*/
|
||||
this.undefIdIndex_ = {};
|
||||
|
||||
@@ -255,7 +253,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Collection<import("../Feature.js").default<Geometry>>}
|
||||
* @type {Collection<import("../Feature.js").default>}
|
||||
*/
|
||||
this.featuresCollection_ = null;
|
||||
|
||||
@@ -284,10 +282,7 @@ class VectorSource extends Source {
|
||||
* instead. A feature will not be added to the source if feature with
|
||||
* the same id is already there. The reason for this behavior is to avoid
|
||||
* feature duplication when using bbox or tile loading strategies.
|
||||
* Note: this also applies if an {@link module:ol/Collection} is used for features,
|
||||
* meaning that if a feature with a duplicate id is added in the collection, it will
|
||||
* be removed from it right away.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature to add.
|
||||
* @param {import("../Feature.js").default} feature Feature to add.
|
||||
* @api
|
||||
*/
|
||||
addFeature(feature) {
|
||||
@@ -298,16 +293,13 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Add a feature without firing a `change` event.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature.
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @protected
|
||||
*/
|
||||
addFeatureInternal(feature) {
|
||||
const featureKey = getUid(feature);
|
||||
|
||||
if (!this.addToIndex_(featureKey, feature)) {
|
||||
if (this.featuresCollection_) {
|
||||
this.featuresCollection_.remove(feature);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -330,7 +322,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* @param {string} featureKey Unique identifier for the feature.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature The feature.
|
||||
* @param {import("../Feature.js").default} feature The feature.
|
||||
* @private
|
||||
*/
|
||||
setupChangeEvents_(featureKey, feature) {
|
||||
@@ -345,7 +337,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* @param {string} featureKey Unique identifier for the feature.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature The feature.
|
||||
* @param {import("../Feature.js").default} feature The feature.
|
||||
* @return {boolean} The feature is "valid", in the sense that it is also a
|
||||
* candidate for insertion into the Rtree.
|
||||
* @private
|
||||
@@ -370,7 +362,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Add a batch of features to the source.
|
||||
* @param {Array<import("../Feature.js").default<Geometry>>} features Features to add.
|
||||
* @param {Array<import("../Feature.js").default>} features Features to add.
|
||||
* @api
|
||||
*/
|
||||
addFeatures(features) {
|
||||
@@ -381,7 +373,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Add features without firing a `change` event.
|
||||
* @param {Array<import("../Feature.js").default<Geometry>>} features Features.
|
||||
* @param {Array<import("../Feature.js").default>} features Features.
|
||||
* @protected
|
||||
*/
|
||||
addFeaturesInternal(features) {
|
||||
@@ -422,14 +414,14 @@ class VectorSource extends Source {
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Collection<import("../Feature.js").default<Geometry>>} collection Collection.
|
||||
* @param {!Collection<import("../Feature.js").default>} collection Collection.
|
||||
* @private
|
||||
*/
|
||||
bindFeaturesCollection_(collection) {
|
||||
let modifyingCollection = false;
|
||||
listen(this, VectorEventType.ADDFEATURE,
|
||||
/**
|
||||
* @param {VectorSourceEvent<Geometry>} evt The vector source event
|
||||
* @param {VectorSourceEvent} evt The vector source event
|
||||
*/
|
||||
function(evt) {
|
||||
if (!modifyingCollection) {
|
||||
@@ -440,7 +432,7 @@ class VectorSource extends Source {
|
||||
});
|
||||
listen(this, VectorEventType.REMOVEFEATURE,
|
||||
/**
|
||||
* @param {VectorSourceEvent<Geometry>} evt The vector source event
|
||||
* @param {VectorSourceEvent} evt The vector source event
|
||||
*/
|
||||
function(evt) {
|
||||
if (!modifyingCollection) {
|
||||
@@ -456,7 +448,7 @@ class VectorSource extends Source {
|
||||
function(evt) {
|
||||
if (!modifyingCollection) {
|
||||
modifyingCollection = true;
|
||||
this.addFeature(/** @type {import("../Feature.js").default<Geometry>} */ (evt.element));
|
||||
this.addFeature(/** @type {import("../Feature.js").default} */ (evt.element));
|
||||
modifyingCollection = false;
|
||||
}
|
||||
}, this);
|
||||
@@ -467,7 +459,7 @@ class VectorSource extends Source {
|
||||
function(evt) {
|
||||
if (!modifyingCollection) {
|
||||
modifyingCollection = true;
|
||||
this.removeFeature(/** @type {import("../Feature.js").default<Geometry>} */ (evt.element));
|
||||
this.removeFeature(/** @type {import("../Feature.js").default} */ (evt.element));
|
||||
modifyingCollection = false;
|
||||
}
|
||||
}, this);
|
||||
@@ -520,7 +512,7 @@ class VectorSource extends Source {
|
||||
* stop and the function will return the same value.
|
||||
* Note: this function only iterate through the feature that have a defined geometry.
|
||||
*
|
||||
* @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature
|
||||
* @param {function(import("../Feature.js").default): T} callback Called with each feature
|
||||
* on the source. Return a truthy value to stop iteration.
|
||||
* @return {T|undefined} The return value from the last call to the callback.
|
||||
* @template T
|
||||
@@ -542,7 +534,7 @@ class VectorSource extends Source {
|
||||
* value.
|
||||
*
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature
|
||||
* @param {function(import("../Feature.js").default): T} callback Called with each feature
|
||||
* whose goemetry contains the provided coordinate.
|
||||
* @return {T|undefined} The return value from the last call to the callback.
|
||||
* @template T
|
||||
@@ -573,7 +565,7 @@ class VectorSource extends Source {
|
||||
* features, equivalent to {@link module:ol/source/Vector~VectorSource#forEachFeature #forEachFeature()}.
|
||||
*
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature
|
||||
* @param {function(import("../Feature.js").default): T} callback Called with each feature
|
||||
* whose bounding box intersects the provided extent.
|
||||
* @return {T|undefined} The return value from the last call to the callback.
|
||||
* @template T
|
||||
@@ -597,7 +589,7 @@ class VectorSource extends Source {
|
||||
* {@link module:ol/source/Vector~VectorSource#forEachFeatureInExtent #forEachFeatureInExtent()} method instead.
|
||||
*
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature
|
||||
* @param {function(import("../Feature.js").default): T} callback Called with each feature
|
||||
* whose geometry intersects the provided extent.
|
||||
* @return {T|undefined} The return value from the last call to the callback.
|
||||
* @template T
|
||||
@@ -606,7 +598,7 @@ class VectorSource extends Source {
|
||||
forEachFeatureIntersectingExtent(extent, callback) {
|
||||
return this.forEachFeatureInExtent(extent,
|
||||
/**
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature.
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @return {T|undefined} The return value from the last call to the callback.
|
||||
*/
|
||||
function(feature) {
|
||||
@@ -625,7 +617,7 @@ class VectorSource extends Source {
|
||||
* Get the features collection associated with this source. Will be `null`
|
||||
* unless the source was configured with `useSpatialIndex` set to `false`, or
|
||||
* with an {@link module:ol/Collection} as `features`.
|
||||
* @return {Collection<import("../Feature.js").default<Geometry>>} The collection of features.
|
||||
* @return {Collection<import("../Feature.js").default>} The collection of features.
|
||||
* @api
|
||||
*/
|
||||
getFeaturesCollection() {
|
||||
@@ -635,7 +627,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Get all features on the source in random order.
|
||||
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
||||
* @return {Array<import("../Feature.js").default>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeatures() {
|
||||
@@ -649,7 +641,7 @@ class VectorSource extends Source {
|
||||
}
|
||||
}
|
||||
return (
|
||||
/** @type {Array<import("../Feature.js").default<Geometry>>} */ (features)
|
||||
/** @type {Array<import("../Feature.js").default>} */ (features)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -657,7 +649,7 @@ class VectorSource extends Source {
|
||||
/**
|
||||
* Get all features whose geometry intersects the provided coordinate.
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
||||
* @return {Array<import("../Feature.js").default>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeaturesAtCoordinate(coordinate) {
|
||||
@@ -677,7 +669,7 @@ class VectorSource extends Source {
|
||||
* This method is not available when the source is configured with
|
||||
* `useSpatialIndex` set to `false`.
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
||||
* @return {Array<import("../Feature.js").default>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeaturesInExtent(extent) {
|
||||
@@ -691,10 +683,10 @@ class VectorSource extends Source {
|
||||
* This method is not available when the source is configured with
|
||||
* `useSpatialIndex` set to `false`.
|
||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {function(import("../Feature.js").default<Geometry>):boolean=} opt_filter Feature filter function.
|
||||
* @param {function(import("../Feature.js").default):boolean=} opt_filter Feature filter function.
|
||||
* The filter function will receive one argument, the {@link module:ol/Feature feature}
|
||||
* and it should return a boolean value. By default, no filtering is made.
|
||||
* @return {import("../Feature.js").default<Geometry>} Closest feature.
|
||||
* @return {import("../Feature.js").default} Closest feature.
|
||||
* @api
|
||||
*/
|
||||
getClosestFeatureToCoordinate(coordinate, opt_filter) {
|
||||
@@ -714,7 +706,7 @@ class VectorSource extends Source {
|
||||
const filter = opt_filter ? opt_filter : TRUE;
|
||||
this.featuresRtree_.forEachInExtent(extent,
|
||||
/**
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature.
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
*/
|
||||
function(feature) {
|
||||
if (filter(feature)) {
|
||||
@@ -761,7 +753,7 @@ class VectorSource extends Source {
|
||||
* `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.
|
||||
*
|
||||
* @param {string|number} id Feature identifier.
|
||||
* @return {import("../Feature.js").default<Geometry>} The feature (or `null` if not found).
|
||||
* @return {import("../Feature.js").default} The feature (or `null` if not found).
|
||||
* @api
|
||||
*/
|
||||
getFeatureById(id) {
|
||||
@@ -805,7 +797,7 @@ class VectorSource extends Source {
|
||||
* @private
|
||||
*/
|
||||
handleFeatureChange_(event) {
|
||||
const feature = /** @type {import("../Feature.js").default<Geometry>} */ (event.target);
|
||||
const feature = /** @type {import("../Feature.js").default} */ (event.target);
|
||||
const featureKey = getUid(feature);
|
||||
const geometry = feature.getGeometry();
|
||||
if (!geometry) {
|
||||
@@ -853,7 +845,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Returns true if the feature is contained within the source.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature.
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @return {boolean} Has feature.
|
||||
* @api
|
||||
*/
|
||||
@@ -935,7 +927,7 @@ class VectorSource extends Source {
|
||||
* Remove a single feature from the source. If you want to remove all features
|
||||
* at once, use the {@link module:ol/source/Vector~VectorSource#clear #clear()} method
|
||||
* instead.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature to remove.
|
||||
* @param {import("../Feature.js").default} feature Feature to remove.
|
||||
* @api
|
||||
*/
|
||||
removeFeature(feature) {
|
||||
@@ -954,7 +946,7 @@ class VectorSource extends Source {
|
||||
|
||||
/**
|
||||
* Remove feature without firing a `change` event.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature Feature.
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @protected
|
||||
*/
|
||||
removeFeatureInternal(feature) {
|
||||
@@ -975,7 +967,7 @@ class VectorSource extends Source {
|
||||
/**
|
||||
* Remove a feature from the id index. Called internally when the feature id
|
||||
* may have changed.
|
||||
* @param {import("../Feature.js").default<Geometry>} feature The feature.
|
||||
* @param {import("../Feature.js").default} feature The feature.
|
||||
* @return {boolean} Removed the feature from the index.
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,6 @@ const TierSizeCalculation = {
|
||||
export class CustomTile extends ImageTile {
|
||||
|
||||
/**
|
||||
* @param {number} tilePixelRatio Tile pixel ratio to display the tile
|
||||
* @param {import("../tilegrid/TileGrid.js").default} tileGrid TileGrid that the tile belongs to.
|
||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {TileState} state State.
|
||||
@@ -35,7 +34,8 @@ export class CustomTile extends ImageTile {
|
||||
* @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {import("../Tile.js").Options=} opt_options Tile options.
|
||||
*/
|
||||
constructor(tilePixelRatio, tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
||||
constructor(tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
||||
|
||||
super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);
|
||||
|
||||
/**
|
||||
@@ -48,11 +48,8 @@ export class CustomTile extends ImageTile {
|
||||
* @private
|
||||
* @type {import("../size.js").Size}
|
||||
*/
|
||||
this.tileSize_ = toSize(tileGrid.getTileSize(tileCoord[0])).map(
|
||||
function(x) {
|
||||
return x * tilePixelRatio;
|
||||
}
|
||||
);
|
||||
this.tileSize_ = toSize(tileGrid.getTileSize(tileCoord[0]));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +143,6 @@ class Zoomify extends TileImage {
|
||||
const extent = options.extent || [0, -size[1], size[0], 0];
|
||||
const tierSizeInTiles = [];
|
||||
const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
|
||||
const tilePixelRatio = options.tilePixelRatio || 1;
|
||||
let tileSizeForTierSizeCalculation = tileSize;
|
||||
|
||||
switch (tierSizeCalculation) {
|
||||
@@ -246,14 +242,14 @@ class Zoomify extends TileImage {
|
||||
|
||||
const tileUrlFunction = createFromTileUrlFunctions(urls.map(createFromTemplate));
|
||||
|
||||
const ZoomifyTileClass = CustomTile.bind(null, tilePixelRatio, tileGrid);
|
||||
const ZoomifyTileClass = CustomTile.bind(null, tileGrid);
|
||||
|
||||
super({
|
||||
attributions: options.attributions,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin: options.crossOrigin,
|
||||
projection: options.projection,
|
||||
tilePixelRatio: tilePixelRatio,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileClass: ZoomifyTileClass,
|
||||
tileGrid: tileGrid,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @module ol/structs/RBush
|
||||
*/
|
||||
import {getUid} from '../util.js';
|
||||
import RBush_ from 'rbush';
|
||||
import rbush from 'rbush';
|
||||
import {createOrUpdate, equals} from '../extent.js';
|
||||
import {isEmpty} from '../obj.js';
|
||||
|
||||
@@ -31,7 +31,7 @@ class RBush {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.rbush_ = new RBush_(opt_maxEntries);
|
||||
this.rbush_ = rbush(opt_maxEntries, undefined);
|
||||
|
||||
/**
|
||||
* A mapping between the objects added to this rbush wrapper
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
*/
|
||||
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {listenOnce, unlistenByKey} from '../events.js';
|
||||
import EventTarget from '../events/Target.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import ImageState from '../ImageState.js';
|
||||
import {shared as iconImageCache} from './IconImageCache.js';
|
||||
import {listenImage} from '../Image.js';
|
||||
|
||||
|
||||
class IconImage extends EventTarget {
|
||||
/**
|
||||
@@ -53,9 +52,9 @@ class IconImage extends EventTarget {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function():void}
|
||||
* @type {Array<import("../events.js").EventsKey>}
|
||||
*/
|
||||
this.unlisten_ = null;
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -186,16 +185,17 @@ class IconImage extends EventTarget {
|
||||
load() {
|
||||
if (this.imageState_ == ImageState.IDLE) {
|
||||
this.imageState_ = ImageState.LOADING;
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
try {
|
||||
/** @type {HTMLImageElement} */ (this.image_).src = this.src_;
|
||||
} catch (e) {
|
||||
this.handleImageError_();
|
||||
}
|
||||
this.unlisten_ = listenImage(
|
||||
this.image_,
|
||||
this.handleImageLoad_.bind(this),
|
||||
this.handleImageError_.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,10 +233,8 @@ class IconImage extends EventTarget {
|
||||
* @private
|
||||
*/
|
||||
unlistenImage_() {
|
||||
if (this.unlisten_) {
|
||||
this.unlisten_();
|
||||
this.unlisten_ = null;
|
||||
}
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user