Merge remote-tracking branch 'origin/master' into fix_triangulation
Conflicts: src/ol/TileCache.js
@@ -34,7 +34,7 @@ Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
|
||||
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
|
||||
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
|
||||
<a href="module-ol_proj.html">ol/proj</a></td>
|
||||
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object.ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||
<td>
|
||||
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
|
||||
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Settable</th>
|
||||
<th><a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> type</th>
|
||||
<th><a href="module-ol_Object.ObjectEvent.html">ol/Object.ObjectEvent</a> type</th>
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -111,7 +111,7 @@ Features for `updates` must have an id set by the feature reader or `ol.Feature#
|
||||
|
||||
### 28
|
||||
|
||||
`renderMode` must be `'image'` or `'hybrid'`.
|
||||
`renderMode` must be `'image'`, `'hybrid'` or `'vector'`.
|
||||
|
||||
### 29
|
||||
|
||||
|
||||
5188
examples/data/world.svg
Normal file
|
After Width: | Height: | Size: 3.2 MiB |
@@ -6,10 +6,10 @@ docs: >
|
||||
This example shows how to use <b>postrender</b> events and a <b>vector context</b> to
|
||||
animate a marker feature along a line. In this example an encoded polyline
|
||||
is being used.
|
||||
tags: "animation, feature, postrender, polyline"
|
||||
tags: "animation, feature, postrender, polyline, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<label for="speed">
|
||||
|
||||
@@ -4,7 +4,7 @@ import View from '../src/ol/View.js';
|
||||
import Polyline from '../src/ol/format/Polyline.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from '../src/ol/style.js';
|
||||
import {getVectorContext} from '../src/ol/render.js';
|
||||
@@ -121,6 +121,10 @@ const vectorLayer = new VectorLayer({
|
||||
}
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const center = [-5639523.95, -3501274.52];
|
||||
const map = new Map({
|
||||
target: document.getElementById('map'),
|
||||
@@ -132,9 +136,10 @@ const map = new Map({
|
||||
}),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
imagerySet: 'AerialWithLabelsOnDemand',
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=' + key,
|
||||
tileSize: 512
|
||||
})
|
||||
}),
|
||||
vectorLayer
|
||||
|
||||
@@ -5,9 +5,9 @@ shortdesc: Example of drag rotate and zoom control with full screen effect.
|
||||
docs: >
|
||||
<p>Hold down <code>Shift+Drag</code> to rotate and zoom. Click the button in the top right corner to go full screen. Then do the <code>Shift+Drag</code> thing again.</p>
|
||||
<p>If there is no button on the map, your browser does not support the <a href="http://caniuse.com/#feat=fullscreen">Full Screen API</a>.</p>
|
||||
tags: "full-screen, drag, rotate, zoom, bing, bing-maps"
|
||||
tags: "full-screen, drag, rotate, zoom, xyz, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -3,9 +3,13 @@ import View from '../src/ol/View.js';
|
||||
import {defaults as defaultControls, FullScreen} from '../src/ol/control.js';
|
||||
import {defaults as defaultInteractions, DragRotateAndZoom} from '../src/ol/interaction.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const map = new Map({
|
||||
controls: defaultControls().extend([
|
||||
new FullScreen()
|
||||
@@ -15,13 +19,13 @@ const map = new Map({
|
||||
]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
})
|
||||
],
|
||||
// Use the canvas renderer because it's currently the fastest
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [-33519607, 5616436],
|
||||
|
||||
@@ -5,9 +5,9 @@ shortdesc: Example of a full screen control.
|
||||
docs: >
|
||||
<p>Click the control in the top right corner to go full screen. Click it again to exit full screen.</p>
|
||||
<p>If there is no button on the map, your browser does not support the <a href="http://caniuse.com/#feat=fullscreen">Full Screen API</a>.</p>
|
||||
tags: "full-screen, bing, bing-maps"
|
||||
tags: "full-screen, xyz, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {defaults as defaultControls, FullScreen} from '../src/ol/control.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
|
||||
const view = new View({
|
||||
@@ -10,15 +10,20 @@ const view = new View({
|
||||
zoom: 14
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const map = new Map({
|
||||
controls: defaultControls().extend([
|
||||
new FullScreen()
|
||||
]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
})
|
||||
],
|
||||
|
||||
@@ -4,10 +4,10 @@ title: GPX Data
|
||||
shortdesc: Example of using the GPX source.
|
||||
docs: >
|
||||
Example of using the GPX source.
|
||||
tags: "GPX"
|
||||
tags: "GPX, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div id="info"> </div>
|
||||
|
||||
@@ -2,14 +2,19 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import GPX from '../src/ol/format/GPX.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new BingMaps({
|
||||
imagerySet: 'Aerial',
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ docs: >
|
||||
<p>Layer rendering can be manipulated in <code>prerender</code> and <code>postrender</code> event listeners.
|
||||
These listeners get an event with a reference to the Canvas rendering context.
|
||||
In this example, the <code>postrender</code> listener applies a filter to the image data.</p>
|
||||
tags: "filter, image manipulation"
|
||||
tags: "filter, image manipulation, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<select id="kernel" name="kernel">
|
||||
|
||||
@@ -2,12 +2,19 @@ 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 BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'Aerial'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: ''
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Interaction Options
|
||||
shortdesc: Shows interaction options for custom scroll and zoom behavior.
|
||||
docs: >
|
||||
This example uses a custom `ol/interaction/defaults` configuration:
|
||||
by default, wheel/trackpad zoom and drag panning is always active, which
|
||||
can be unexpected on pages with a lot of scrollable content and an embedded
|
||||
map. To perform wheel/trackpad zoom and drag-pan actions only when the map
|
||||
has the focus, set `onFocusOnly: true` as option. This requires a map div
|
||||
with a `tabindex` attribute set.
|
||||
tags: "trackpad, mousewheel, zoom, scroll, interaction, fractional"
|
||||
---
|
||||
<div tabindex="1" id="map" class="map"></div>
|
||||
@@ -18,11 +18,17 @@ const map = new Map({
|
||||
|
||||
osm.on('prerender', function(event) {
|
||||
const ctx = event.context;
|
||||
|
||||
// calculate the pixel ratio and rotation of the canvas
|
||||
const matrix = event.inversePixelTransform;
|
||||
const canvasPixelRatio = Math.sqrt(matrix[0] * matrix[0] + matrix[1] * matrix[1]);
|
||||
const canvasRotation = -Math.atan2(matrix[1], matrix[0]);
|
||||
ctx.save();
|
||||
const pixelRatio = event.frameState.pixelRatio;
|
||||
const size = map.getSize();
|
||||
ctx.translate(size[0] / 2 * pixelRatio, size[1] / 2 * pixelRatio);
|
||||
ctx.scale(3 * pixelRatio, 3 * pixelRatio);
|
||||
// center the canvas and remove rotation to position clipping
|
||||
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
|
||||
ctx.rotate(-canvasRotation);
|
||||
|
||||
ctx.scale(3 * canvasPixelRatio, 3 * canvasPixelRatio);
|
||||
ctx.translate(-75, -80);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(75, 40);
|
||||
@@ -34,8 +40,11 @@ osm.on('prerender', function(event) {
|
||||
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
|
||||
ctx.clip();
|
||||
ctx.translate(75, 80);
|
||||
ctx.scale(1 / 3 / pixelRatio, 1 / 3 / pixelRatio);
|
||||
ctx.translate(-size[0] / 2 * pixelRatio, -size[1] / 2 * pixelRatio);
|
||||
ctx.scale(1 / 3 / canvasPixelRatio, 1 / 3 / canvasPixelRatio);
|
||||
|
||||
// reapply canvas rotation and position
|
||||
ctx.rotate(canvasRotation);
|
||||
ctx.translate(-ctx.canvas.width / 2, -ctx.canvas.height / 2);
|
||||
});
|
||||
|
||||
osm.on('postrender', function(event) {
|
||||
|
||||
@@ -8,9 +8,9 @@ docs: >
|
||||
In this example, the <code>prerender</code> listener sets a clipping mask around the most
|
||||
recent mouse position, giving you a spyglass effect for viewing one layer over another.</p>
|
||||
<p>Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the spyglass size.</p>
|
||||
tags: "spy, image manipulation"
|
||||
tags: "spy, image manipulation, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -2,16 +2,28 @@ 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 BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import {getRenderPixel} from '../src/ol/render.js';
|
||||
|
||||
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const roads = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'RoadOnDemand'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=' + key,
|
||||
tileSize: 512,
|
||||
maxZoom: 22
|
||||
})
|
||||
});
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'Aerial'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
});
|
||||
|
||||
const container = document.getElementById('map');
|
||||
@@ -54,14 +66,15 @@ container.addEventListener('mouseout', function() {
|
||||
// before rendering the layer, do some clipping
|
||||
imagery.on('prerender', function(event) {
|
||||
const ctx = event.context;
|
||||
const pixelRatio = event.frameState.pixelRatio;
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
if (mousePosition) {
|
||||
// only show a circle around the mouse
|
||||
ctx.arc(mousePosition[0] * pixelRatio, mousePosition[1] * pixelRatio,
|
||||
radius * pixelRatio, 0, 2 * Math.PI);
|
||||
ctx.lineWidth = 5 * pixelRatio;
|
||||
const pixel = getRenderPixel(event, mousePosition);
|
||||
const offset = getRenderPixel(event, [mousePosition[0] + radius, mousePosition[1]]);
|
||||
const canvasRadius = Math.sqrt(Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2));
|
||||
ctx.arc(pixel[0], pixel[1], canvasRadius, 0, 2 * Math.PI);
|
||||
ctx.lineWidth = 5 * canvasRadius / radius;
|
||||
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ title: Layer Swipe
|
||||
shortdesc: Example of a Layer swipe map.
|
||||
docs: >
|
||||
Example of a Layer swipe map.
|
||||
tags: "swipe, openstreetmap"
|
||||
tags: "swipe, openstreetmap, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<input id="swipe" type="range" style="width: 100%">
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import {getRenderPixel} from '../src/ol/render.js';
|
||||
|
||||
const osm = new TileLayer({
|
||||
source: new OSM()
|
||||
});
|
||||
const bing = new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const aerial = new TileLayer({
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [osm, bing],
|
||||
layers: [osm, aerial],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
@@ -25,17 +32,26 @@ const map = new Map({
|
||||
|
||||
const swipe = document.getElementById('swipe');
|
||||
|
||||
bing.on('prerender', function(event) {
|
||||
aerial.on('prerender', function(event) {
|
||||
const ctx = event.context;
|
||||
const width = ctx.canvas.width * (swipe.value / 100);
|
||||
const mapSize = map.getSize();
|
||||
const width = mapSize[0] * (swipe.value / 100);
|
||||
const tl = getRenderPixel(event, [width, 0]);
|
||||
const tr = getRenderPixel(event, [mapSize[0], 0]);
|
||||
const bl = getRenderPixel(event, [width, mapSize[1]]);
|
||||
const br = getRenderPixel(event, mapSize);
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(width, 0, ctx.canvas.width - width, ctx.canvas.height);
|
||||
ctx.moveTo(tl[0], tl[1]);
|
||||
ctx.lineTo(bl[0], bl[1]);
|
||||
ctx.lineTo(br[0], br[1]);
|
||||
ctx.lineTo(tr[0], tr[1]);
|
||||
ctx.closePath();
|
||||
ctx.clip();
|
||||
});
|
||||
|
||||
bing.on('postrender', function(event) {
|
||||
aerial.on('postrender', function(event) {
|
||||
const ctx = event.context;
|
||||
ctx.restore();
|
||||
});
|
||||
|
||||
@@ -6,9 +6,9 @@ docs: >
|
||||
<p>This example makes use of the <code>postrender</code> event listener to
|
||||
oversample imagery in a circle around the pointer location. Listeners for this event have access to the Canvas context and can manipulate image data.</p>
|
||||
<p>Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the magnified circle size.</p>
|
||||
tags: "magnify, image manipulation"
|
||||
tags: "magnify, image manipulation, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -2,13 +2,20 @@ 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 BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import {getRenderPixel} from '../src/ol/render.js';
|
||||
|
||||
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'Aerial'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: ''
|
||||
})
|
||||
});
|
||||
|
||||
const container = document.getElementById('map');
|
||||
|
||||
10
examples/page-scroll.html
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Page Scrolling
|
||||
shortdesc: Shows a map that does not interrupt page scrolling.
|
||||
docs: >
|
||||
To perform wheel/trackpad zoom and drag-pan actions only when the map
|
||||
has the focus, configure your map div with a `tabindex` attribute.
|
||||
tags: "trackpad, mousewheel, zoom, scroll, page"
|
||||
---
|
||||
<div tabindex="1" id="map" class="map"></div>
|
||||
@@ -1,14 +1,10 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {defaults as defaultInteractions} from '../src/ol/interaction.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
|
||||
|
||||
const map = new Map({
|
||||
interactions: defaultInteractions({
|
||||
onFocusOnly: true
|
||||
}),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM()
|
||||
@@ -1,8 +1,7 @@
|
||||
.ol-popup {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
-webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
|
||||
filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #cccccc;
|
||||
|
||||
@@ -18,12 +18,12 @@ docs: >
|
||||
those pixels based on a threshold value (values above the
|
||||
threshold are green and those below are transparent).
|
||||
</p>
|
||||
tags: "raster, pixel"
|
||||
tags: "raster, pixel, maptiler"
|
||||
resources:
|
||||
- https://unpkg.com/d3@4.12.0/build/d3.js
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div class="rel">
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import RasterSource from '../src/ol/source/Raster.js';
|
||||
|
||||
const minVgi = 0;
|
||||
@@ -46,9 +46,16 @@ function summarize(value, counts) {
|
||||
/**
|
||||
* Use aerial imagery as the input data for the raster source.
|
||||
*/
|
||||
const bing = new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const aerial = new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: ''
|
||||
});
|
||||
|
||||
|
||||
@@ -57,7 +64,7 @@ const bing = new BingMaps({
|
||||
* be colored green.
|
||||
*/
|
||||
const raster = new RasterSource({
|
||||
sources: [bing],
|
||||
sources: [aerial],
|
||||
/**
|
||||
* Run calculations on pixel data.
|
||||
* @param {Array} pixels List of pixels (one per source).
|
||||
@@ -110,7 +117,7 @@ raster.on('afteroperations', function(event) {
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: bing
|
||||
source: aerial
|
||||
}),
|
||||
new ImageLayer({
|
||||
source: raster
|
||||
|
||||
@@ -23,10 +23,10 @@ docs: >
|
||||
This example also shows how an additional function can be made available
|
||||
to the operation.
|
||||
</p>
|
||||
tags: "raster, region growing"
|
||||
tags: "raster, region growing, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map" style="cursor: pointer"></div>
|
||||
<table class="controls">
|
||||
|
||||
@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import RasterSource from '../src/ol/source/Raster.js';
|
||||
|
||||
function growRegion(inputs, data) {
|
||||
@@ -72,10 +72,17 @@ function next4Edges(edge) {
|
||||
];
|
||||
}
|
||||
|
||||
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'Aerial'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: ''
|
||||
})
|
||||
});
|
||||
|
||||
const raster = new RasterSource({
|
||||
|
||||
@@ -55,15 +55,6 @@ proj54009.setExtent([-18e6, -9e6, 18e6, 9e6]);
|
||||
|
||||
const layers = {};
|
||||
|
||||
layers['bng'] = new TileLayer({
|
||||
source: new XYZ({
|
||||
projection: 'EPSG:27700',
|
||||
url: 'https://tileserver.maptiler.com/miniscale/{z}/{x}/{y}.png',
|
||||
crossOrigin: '',
|
||||
maxZoom: 6
|
||||
})
|
||||
});
|
||||
|
||||
layers['osm'] = new TileLayer({
|
||||
source: new OSM()
|
||||
});
|
||||
@@ -95,9 +86,11 @@ layers['wms21781'] = new TileLayer({
|
||||
});
|
||||
|
||||
const parser = new WMTSCapabilities();
|
||||
const url = 'https://map1.vis.earthdata.nasa.gov/wmts-arctic/' +
|
||||
|
||||
layers['wmts3413'] = new TileLayer();
|
||||
const urlA = 'https://map1.vis.earthdata.nasa.gov/wmts-arctic/' +
|
||||
'wmts.cgi?SERVICE=WMTS&request=GetCapabilities';
|
||||
fetch(url).then(function(response) {
|
||||
fetch(urlA).then(function(response) {
|
||||
return response.text();
|
||||
}).then(function(text) {
|
||||
const result = parser.read(text);
|
||||
@@ -108,9 +101,23 @@ fetch(url).then(function(response) {
|
||||
options.crossOrigin = '';
|
||||
options.projection = 'EPSG:3413';
|
||||
options.wrapX = false;
|
||||
layers['wmts3413'] = new TileLayer({
|
||||
source: new WMTS(options)
|
||||
layers['wmts3413'].setSource(new WMTS(options));
|
||||
});
|
||||
|
||||
layers['bng'] = new TileLayer();
|
||||
const urlB = 'https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Raster/MapServer/WMTS';
|
||||
fetch(urlB).then(function(response) {
|
||||
return response.text();
|
||||
}).then(function(text) {
|
||||
const result = parser.read(text);
|
||||
const options = optionsFromCapabilities(result, {
|
||||
layer: 'OS_Open_Raster'
|
||||
});
|
||||
options.attributions = 'Contains OS data © Crown Copyright and database right 2019';
|
||||
options.crossOrigin = '';
|
||||
options.projection = 'EPSG:27700';
|
||||
options.wrapX = false;
|
||||
layers['bng'].setSource(new WMTS(options));
|
||||
});
|
||||
|
||||
layers['grandcanyon'] = new TileLayer({
|
||||
|
||||
@@ -8,6 +8,11 @@ docs: >
|
||||
<a href="https://www.mapbox.com/blog/terrain-rgb/">Mapbox Terrain-RGB tiles</a>
|
||||
to "flood" areas below the elevation shown on the sea level slider.
|
||||
</p>
|
||||
<p>
|
||||
<code>ol/source/Raster</code> can take either a tile source or layer.
|
||||
In this case a layer is used to allow disabling at the <code>prerender</code> event
|
||||
of image smoothing which would change the precise elevation values set in the pixels.
|
||||
</p>
|
||||
tags: "raster, pixel operation, flood"
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
|
||||
|
||||
@@ -22,9 +22,15 @@ function flood(pixels, data) {
|
||||
}
|
||||
|
||||
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
|
||||
const elevation = new XYZ({
|
||||
url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
|
||||
crossOrigin: 'anonymous'
|
||||
const elevation = new TileLayer({
|
||||
source: new XYZ({
|
||||
url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
});
|
||||
elevation.on('prerender', function(evt) {
|
||||
evt.context.imageSmoothingEnabled = false;
|
||||
evt.context.msImageSmoothingEnabled = false;
|
||||
});
|
||||
|
||||
const raster = new RasterSource({
|
||||
|
||||
@@ -4,10 +4,10 @@ title: Shared Views
|
||||
shortdesc: Two maps share view properties
|
||||
docs: >
|
||||
Two maps (one Road, one Aerial) share the same center, resolution and rotation.
|
||||
tags: "side-by-side, bing, bing-maps"
|
||||
tags: "side-by-side, xyz, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div class="wrapper">
|
||||
<div class="half">
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const roadLayer = new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'RoadOnDemand',
|
||||
maxZoom: 19
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=' + key,
|
||||
tileSize: 512,
|
||||
maxZoom: 22
|
||||
})
|
||||
});
|
||||
|
||||
const aerialLayer = new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial',
|
||||
maxZoom: 19
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ title: Street Labels
|
||||
shortdesc: Render street names.
|
||||
docs: >
|
||||
Example showing the use of a text style with `placement: 'line'` to render text along a path.
|
||||
tags: "vector, label, streets"
|
||||
tags: "vector, label, streets, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
|
||||
import {getCenter} from '../src/ol/extent.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import {Fill, Style, Text} from '../src/ol/style.js';
|
||||
|
||||
@@ -17,12 +17,17 @@ const style = new Style({
|
||||
})
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const viewExtent = [1817379, 6139595, 1827851, 6143616];
|
||||
const map = new Map({
|
||||
layers: [new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
}), new VectorLayer({
|
||||
declutter: true,
|
||||
|
||||
7
examples/svg-layer.css
Normal file
@@ -0,0 +1,7 @@
|
||||
#map {
|
||||
background: black;
|
||||
}
|
||||
|
||||
.svg-layer path:hover {
|
||||
opacity: 0.4;
|
||||
}
|
||||
9
examples/svg-layer.html
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: SVG Layer
|
||||
shortdesc: Example of a map with an interactive svg layer.
|
||||
docs: >
|
||||
With a plain `ol/Layer` and a `render` function, we can use an interactive svg as layer. Hover over countries to see the interactivity that is defined purely with a css `:hover` pseudo-class.
|
||||
tags: "svg, layer, render, transform"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
48
examples/svg-layer.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Layer from '../src/ol/layer/Layer.js';
|
||||
import {composeCssTransform} from '../src/ol/transform.js';
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
extent: [-180, -90, 180, 90],
|
||||
projection: 'EPSG:4326',
|
||||
zoom: 2
|
||||
})
|
||||
});
|
||||
|
||||
const svgContainer = document.createElement('div');
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'data/world.svg');
|
||||
xhr.addEventListener('load', function() {
|
||||
const svg = xhr.responseXML.documentElement;
|
||||
svgContainer.ownerDocument.importNode(svg);
|
||||
svgContainer.appendChild(svg);
|
||||
});
|
||||
xhr.send();
|
||||
|
||||
const width = 2560;
|
||||
const height = 1280;
|
||||
const svgResolution = 360 / width;
|
||||
svgContainer.style.width = width + 'px';
|
||||
svgContainer.style.height = height + 'px';
|
||||
svgContainer.style.transformOrigin = 'top left';
|
||||
svgContainer.className = 'svg-layer';
|
||||
|
||||
map.addLayer(new Layer({
|
||||
render: function(frameState) {
|
||||
const scale = svgResolution / frameState.viewState.resolution;
|
||||
const center = frameState.viewState.center;
|
||||
const size = frameState.size;
|
||||
const cssTransform = composeCssTransform(
|
||||
size[0] / 2, size[1] / 2,
|
||||
scale, scale,
|
||||
frameState.viewState.rotation,
|
||||
-center[0] / svgResolution - width / 2, center[1] / svgResolution - height / 2);
|
||||
svgContainer.style.transform = cssTransform;
|
||||
svgContainer.style.opacity = this.getOpacity();
|
||||
return svgContainer;
|
||||
}
|
||||
}));
|
||||
@@ -108,7 +108,14 @@
|
||||
<div class="row-fluid">
|
||||
<a class="codepen-button pull-right"><i class="fa fa-codepen"></i> Edit</a>
|
||||
<div class="span12">
|
||||
<h4 id="title">{{ title }}</h4>
|
||||
<h4 id="title">
|
||||
{{ title }}
|
||||
</h4>
|
||||
<p class="tags">
|
||||
{{#each tags}}
|
||||
<a href="./index.html?q={{.}}" class="label label-primary">{{.}}</a>
|
||||
{{/each}}
|
||||
</p>
|
||||
{{{ contents }}}
|
||||
</div>
|
||||
<form method="POST" id="codepen-form" target="_blank" action="https://codesandbox.io/api/v1/sandboxes/define">
|
||||
|
||||
12
examples/two-finger-pan-scroll.html
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Panning and page scrolling
|
||||
shortdesc: Shows a map that allows page scrolling unless two fingers or Cmd/Ctrl are used to pan the map.
|
||||
docs: >
|
||||
This example shows a common behavior for page scrolling: on touch devices, when one finger
|
||||
is placed on the map, it can be used to scroll the page. Only two fingers will perform drag pan.
|
||||
For mouse or trackpad devices, the platform modifier key (Cmd or Ctrl) will enable drag pan on
|
||||
the map, otherwise the page will scroll.
|
||||
tags: "trackpad, mousewheel, zoom, scroll, page"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
29
examples/two-finger-pan-scroll.js
Normal file
@@ -0,0 +1,29 @@
|
||||
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, DragPan, MouseWheelZoom} from '../src/ol/interaction.js';
|
||||
import {platformModifierKeyOnly} from '../src/ol/events/condition.js';
|
||||
|
||||
const map = new Map({
|
||||
interactions: defaults({dragPan: false, mouseWheelZoom: false}).extend([
|
||||
new DragPan({
|
||||
condition: function(event) {
|
||||
return this.getPointerCount() === 2 || platformModifierKeyOnly(event);
|
||||
}
|
||||
}),
|
||||
new MouseWheelZoom({
|
||||
condition: platformModifierKeyOnly
|
||||
})
|
||||
]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM()
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2
|
||||
})
|
||||
});
|
||||
@@ -5,7 +5,11 @@ shortdesc: Select features from vector tiles.
|
||||
docs: >
|
||||
<p>
|
||||
Click a rendered vector-tile feature to highlight it on the map. Click on an empty spot (ocean) to reset the selection.
|
||||
By changing the action type to "Multi Select" you can select multiple features at a time.
|
||||
By changing the action type to "Multi Select" you can select multiple features at a time. With "Single Select on hover",
|
||||
features will be higlighted when the pointer is above them.
|
||||
</p><p>
|
||||
The selection layer is configured with `renderMode: 'vector'` for better performance on frequent redraws,
|
||||
i.e. when 'Single select on hover' is selected.
|
||||
</p>
|
||||
tags: "vector tiles, selection"
|
||||
---
|
||||
@@ -15,5 +19,6 @@ tags: "vector tiles, selection"
|
||||
<select id="type" class="form-control">
|
||||
<option value="singleselect" selected>Single Select</option>
|
||||
<option value="multiselect">Multi Select</option>
|
||||
<option value="singleselect-hover">Single Select on hover</option>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
@@ -8,6 +8,25 @@ import {Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
// lookup for selection objects
|
||||
let selection = {};
|
||||
|
||||
const country = new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'gray',
|
||||
width: 1
|
||||
}),
|
||||
fill: new Fill({
|
||||
color: 'rgba(20,20,20,0.9)'
|
||||
})
|
||||
});
|
||||
const selectedCountry = new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(200,20,20,0.8)',
|
||||
width: 2
|
||||
}),
|
||||
fill: new Fill({
|
||||
color: 'rgba(200,20,20,0.4)'
|
||||
})
|
||||
});
|
||||
|
||||
const vtLayer = new VectorTileLayer({
|
||||
declutter: true,
|
||||
source: new VectorTileSource({
|
||||
@@ -18,18 +37,7 @@ const vtLayer = new VectorTileLayer({
|
||||
url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' +
|
||||
'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
|
||||
}),
|
||||
style: function(feature) {
|
||||
const selected = !!selection[feature.getId()];
|
||||
return new Style({
|
||||
stroke: new Stroke({
|
||||
color: selected ? 'rgba(200,20,20,0.8)' : 'gray',
|
||||
width: selected ? 2 : 1
|
||||
}),
|
||||
fill: new Fill({
|
||||
color: selected ? 'rgba(200,20,20,0.2)' : 'rgba(20,20,20,0.9)'
|
||||
})
|
||||
});
|
||||
}
|
||||
style: country
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
@@ -39,18 +47,34 @@ const map = new Map({
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2
|
||||
zoom: 2,
|
||||
multiWorld: true
|
||||
})
|
||||
});
|
||||
|
||||
// Selection
|
||||
const selectionLayer = new VectorTileLayer({
|
||||
map: map,
|
||||
renderMode: 'vector',
|
||||
source: vtLayer.getSource(),
|
||||
style: function(feature) {
|
||||
if (feature.getId() in selection) {
|
||||
return selectedCountry;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const selectElement = document.getElementById('type');
|
||||
|
||||
map.on('click', function(event) {
|
||||
map.on(['click', 'pointermove'], function(event) {
|
||||
if (selectElement.value === 'singleselect-hover' && event.type !== 'pointermove' ||
|
||||
selectElement.value !== 'singleselect-hover' && event.type === 'pointermove') {
|
||||
return;
|
||||
}
|
||||
vtLayer.getFeatures(event.pixel).then(function(features) {
|
||||
if (!features.length) {
|
||||
selection = {};
|
||||
// force redraw of layer style
|
||||
vtLayer.setStyle(vtLayer.getStyle());
|
||||
selectionLayer.changed();
|
||||
return;
|
||||
}
|
||||
const feature = features[0];
|
||||
@@ -59,14 +83,12 @@ map.on('click', function(event) {
|
||||
}
|
||||
const fid = feature.getId();
|
||||
|
||||
if (selectElement.value === 'singleselect') {
|
||||
if (selectElement.value.startsWith('singleselect')) {
|
||||
selection = {};
|
||||
}
|
||||
// add selected feature to lookup
|
||||
selection[fid] = feature;
|
||||
|
||||
// force redraw of layer style
|
||||
vtLayer.setStyle(vtLayer.getStyle());
|
||||
selectionLayer.changed();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -3,19 +3,67 @@ layout: example.html
|
||||
title: WebGL points layer
|
||||
shortdesc: Using a WebGL-optimized layer to render a large quantities of points
|
||||
docs: >
|
||||
<p>This example shows how to use a <code>WebGLPointsLayer</code> to show a large amount of points on the map.</p>
|
||||
<p>The layer is given a style in JSON format which allows a certain level of customization of the final reprensentation.</p>
|
||||
<p>
|
||||
The following operators can be used for numerical values:
|
||||
<ul>
|
||||
<li><code>["get", "attributeName"]</code> fetches a numeric attribute value for each feature</li>
|
||||
<li><code>["+", value, value]</code> adds two values (which an either be numeric, or the result of another operator)</li>
|
||||
<li><code>["*", value, value]</code> multiplies two values</li>
|
||||
<li><code>["clamp", value, min, max]</code> outputs a value between <code>min</code> and <code>max</code></li>
|
||||
<li><code>["stretch", value, low1, high1, low2, high2]</code> outputs a value which has been mapped from the
|
||||
<code>low1..high1</code> range to the <code>low2..high2</code> range</li>
|
||||
</ul>
|
||||
</p>
|
||||
This example shows how to use a `WebGLPointsLayer` to show a large amount of points on the map.
|
||||
The layer is given a style in JSON format which allows a certain level of customization of the final reprensentation.
|
||||
|
||||
The following operators can be used:
|
||||
|
||||
* Reading operators:
|
||||
* `['get', 'attributeName']` fetches a feature attribute (it will be prefixed by `a_` in the shader)
|
||||
Note: those will be taken from the attributes provided to the renderer
|
||||
* `['var', 'varName']` fetches a value from the style variables, or 0 if undefined
|
||||
* `['time']` returns the time in seconds since the creation of the layer
|
||||
* `['zoom']` returns the current zoom level
|
||||
* `['resolution']` returns the current resolution
|
||||
|
||||
* Math operators:
|
||||
* `['*', value1, value2]` multiplies `value1` by `value2`
|
||||
* `['/', value1, value2]` divides `value1` by `value2`
|
||||
* `['+', value1, value2]` adds `value1` and `value2`
|
||||
* `['-', value1, value2]` subtracts `value2` from `value1`
|
||||
* `['clamp', value, low, high]` clamps `value` between `low` and `high`
|
||||
* `['%', value1, value2]` returns the result of `value1 % value2` (modulo)
|
||||
* `['^', value1, value2]` returns the value of `value1` raised to the `value2` power
|
||||
|
||||
* Transform operators:
|
||||
* `['case', condition1, output1, ...conditionN, outputN, fallback]` selects the first output whose corresponding
|
||||
condition evaluates to `true`. If no match is found, returns the `fallback` value.
|
||||
All conditions should be `boolean`, output and fallback can be any kind.
|
||||
* `['match', input, match1, output1, ...matchN, outputN, fallback]` compares the `input` value against all
|
||||
provided `matchX` values, returning the output associated with the first valid match. If no match is found,
|
||||
returns the `fallback` value.
|
||||
`input` and `matchX` values must all be of the same type, and can be `number` or `string`. `outputX` and
|
||||
`fallback` values must be of the same type, and can be of any kind.
|
||||
* `['interpolate', interpolation, input, stop1, output1, ...stopN, outputN]` returns a value by interpolating between
|
||||
pairs of inputs and outputs; `interpolation` can either be `['linear']` or `['exponential', base]` where `base` is
|
||||
the rate of increase from stop A to stop B (i.e. power to which the interpolation ratio is raised); a value
|
||||
of 1 is equivalent to `['linear']`.
|
||||
`input` and `stopX` values must all be of type `number`. `outputX` values can be `number` or `color` values.
|
||||
Note: `input` will be clamped between `stop1` and `stopN`, meaning that all output values will be comprised
|
||||
between `output1` and `outputN`.
|
||||
|
||||
* Logical operators:
|
||||
* `['<', value1, value2]` returns `true` if `value1` is strictly lower than `value2`, or `false` otherwise.
|
||||
* `['<=', value1, value2]` returns `true` if `value1` is lower than or equals `value2`, or `false` otherwise.
|
||||
* `['>', value1, value2]` returns `true` if `value1` is strictly greater than `value2`, or `false` otherwise.
|
||||
* `['>=', value1, value2]` returns `true` if `value1` is greater than or equals `value2`, or `false` otherwise.
|
||||
* `['==', value1, value2]` returns `true` if `value1` equals `value2`, or `false` otherwise.
|
||||
* `['!=', value1, value2]` returns `true` if `value1` does not equal `value2`, or `false` otherwise.
|
||||
* `['!', value1]` returns `false` if `value1` is `true` or greater than `0`, or `true` otherwise.
|
||||
* `['between', value1, value2, value3]` returns `true` if `value1` is contained between `value2` and `value3`
|
||||
(inclusively), or `false` otherwise.
|
||||
|
||||
* Conversion operators:
|
||||
* `['array', value1, ...valueN]` creates a numerical array from `number` values; please note that the amount of
|
||||
values can currently only be 2, 3 or 4.
|
||||
* `['color', red, green, blue, alpha]` creates a `color` value from `number` values; the `alpha` parameter is
|
||||
optional; if not specified, it will be set to 1.
|
||||
Note: `red`, `green` and `blue` components must be values between 0 and 255; `alpha` between 0 and 1.
|
||||
Values can either be literals or another operator, as they will be evaluated recursively.
|
||||
Literal values can be of the following types:
|
||||
* `boolean`
|
||||
* `number`
|
||||
* `string`
|
||||
|
||||
tags: "webgl, point, layer, feature"
|
||||
experimental: true
|
||||
@@ -29,6 +77,7 @@ experimental: true
|
||||
<option value="triangles-latitude">Triangles, color related to latitude</option>
|
||||
<option value="circles">Circles, size related to population</option>
|
||||
<option value="circles-zoom">Circles, size related to zoom</option>
|
||||
<option value="rotating-bars">Rotating bars</option>
|
||||
</select>
|
||||
<textarea style="width: 100%; height: 20rem; font-family: monospace; font-size: small;" id="style-editor"></textarea>
|
||||
<small>
|
||||
|
||||
@@ -95,6 +95,35 @@ const predefinedStyles = {
|
||||
offset: [0, 0],
|
||||
opacity: 0.95
|
||||
}
|
||||
},
|
||||
'rotating-bars': {
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
rotation: ['*', [
|
||||
'time'
|
||||
], 0.1],
|
||||
size: ['array', 4, [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, 4,
|
||||
300000, 28]
|
||||
],
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, '#ffdc00',
|
||||
300000, '#ff5b19'
|
||||
],
|
||||
offset: ['array', 0, [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, 2,
|
||||
300000, 14]
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -167,3 +196,10 @@ function onSelectChange() {
|
||||
}
|
||||
onSelectChange();
|
||||
select.addEventListener('change', onSelectChange);
|
||||
|
||||
// animate the map
|
||||
function animate() {
|
||||
map.render();
|
||||
window.requestAnimationFrame(animate);
|
||||
}
|
||||
animate();
|
||||
|
||||
@@ -138,9 +138,13 @@ ExampleBuilder.prototype.apply = function(compiler) {
|
||||
.filter(chunk => chunk.names[0] !== this.common);
|
||||
|
||||
const exampleData = [];
|
||||
const uniqueTags = new Set();
|
||||
const promises = chunks.map(async chunk => {
|
||||
const [assets, data] = await this.render(compiler.context, chunk);
|
||||
|
||||
// collect tags for main page... TODO: implement index tag links
|
||||
data.tags.forEach(tag => uniqueTags.add(tag));
|
||||
|
||||
exampleData.push({
|
||||
link: data.filename,
|
||||
example: data.filename,
|
||||
@@ -158,7 +162,8 @@ ExampleBuilder.prototype.apply = function(compiler) {
|
||||
|
||||
const info = {
|
||||
examples: exampleData,
|
||||
index: createWordIndex(exampleData)
|
||||
index: createWordIndex(exampleData),
|
||||
tags: Array.from(uniqueTags)
|
||||
};
|
||||
|
||||
const indexSource = `var info = ${JSON.stringify(info)}`;
|
||||
@@ -182,6 +187,13 @@ ExampleBuilder.prototype.render = async function(dir, chunk) {
|
||||
data.olVersion = pkg.version;
|
||||
data.filename = htmlName;
|
||||
|
||||
// process tags
|
||||
if (data.tags) {
|
||||
data.tags = data.tags.replace(/[\s"]+/g, '').split(',');
|
||||
} else {
|
||||
data.tags = [];
|
||||
}
|
||||
|
||||
// add in script tag
|
||||
const jsName = `${name}.js`;
|
||||
let jsSource = getJsSource(chunk, path.join('.', jsName));
|
||||
|
||||
@@ -12,4 +12,4 @@ tags: "GetLegendGraphic, getLegendUrl, WMS"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
Legend:
|
||||
<div><img id="legend" src=""/></div>
|
||||
<div><img id="legend"/></div>
|
||||
|
||||
@@ -4,9 +4,9 @@ title: Constrained Zoom
|
||||
shortdesc: Example of a zoom constrained view.
|
||||
docs: >
|
||||
This map has a view that is constrained between zoom levels 9 and 13. This is done using the `minZoom` and `maxZoom` view options.
|
||||
tags: "bing, zoom, minZoom, maxZoom"
|
||||
tags: "maptiler, zoom, minZoom, maxZoom"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||
imagerySet: 'Aerial'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key
|
||||
})
|
||||
})
|
||||
],
|
||||
|
||||
4034
package-lock.json
generated
20
package.json
@@ -36,7 +36,7 @@
|
||||
"url": "https://github.com/openlayers/openlayers/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openlayers/pepjs": "^0.5.3",
|
||||
"elm-pep": "^1.0.2",
|
||||
"pbf": "3.2.1",
|
||||
"pixelworks": "1.1.0",
|
||||
"rbush": "^3.0.1"
|
||||
@@ -55,7 +55,7 @@
|
||||
"chaikin-smooth": "^1.0.4",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"coveralls": "3.0.7",
|
||||
"coveralls": "3.0.9",
|
||||
"eslint": "^6.0.0",
|
||||
"eslint-config-openlayers": "^13.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
@@ -63,7 +63,7 @@
|
||||
"fs-extra": "^8.0.0",
|
||||
"glob": "^7.1.5",
|
||||
"globby": "^10.0.0",
|
||||
"handlebars": "4.4.5",
|
||||
"handlebars": "4.5.3",
|
||||
"html-to-image": "^0.1.0",
|
||||
"istanbul": "0.4.5",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
@@ -79,13 +79,13 @@
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^4.0.0-rc.2",
|
||||
"loglevelnext": "^3.0.1",
|
||||
"marked": "0.7.0",
|
||||
"mocha": "6.2.2",
|
||||
"marked": "0.8.0",
|
||||
"mocha": "7.0.0",
|
||||
"ol-mapbox-style": "^5.0.2",
|
||||
"pixelmatch": "^5.1.0",
|
||||
"pngjs": "^3.4.0",
|
||||
"proj4": "2.5.0",
|
||||
"puppeteer": "~1.20.0",
|
||||
"proj4": "2.6.0",
|
||||
"puppeteer": "~2.0.0",
|
||||
"rollup": "^1.25.1",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-commonjs": "^10.0.0",
|
||||
@@ -93,16 +93,16 @@
|
||||
"rollup-plugin-terser": "^5.0.0",
|
||||
"serve-static": "^1.14.0",
|
||||
"shx": "^0.3.2",
|
||||
"sinon": "^7.3.2",
|
||||
"sinon": "^8.0.0",
|
||||
"terser-webpack-plugin": "^2.0.1",
|
||||
"typescript": "3.5.3",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "4.41.2",
|
||||
"webpack": "4.41.5",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-middleware": "^3.6.2",
|
||||
"webpack-dev-server": "^3.3.1",
|
||||
"yargs": "^14.2.0"
|
||||
"yargs": "^15.0.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "openlayers",
|
||||
|
||||
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.6 KiB |
BIN
rendering/cases/layer-vectortile-rendermode-vector/expected.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
31
rendering/cases/layer-vectortile-rendermode-vector/main.js
Normal file
@@ -0,0 +1,31 @@
|
||||
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 VectorTileRenderType from '../../../src/ol/layer/VectorTileRenderType.js';
|
||||
|
||||
new Map({
|
||||
layers: [
|
||||
new VectorTileLayer({
|
||||
renderMode: VectorTileRenderType.VECTOR,
|
||||
source: new VectorTileSource({
|
||||
format: new MVT(),
|
||||
tileGrid: createXYZ(),
|
||||
url: '/data/tiles/mapbox-streets-v6/{z}/{x}/{y}.vector.pbf',
|
||||
transition: 0
|
||||
})
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [1825927.7316762917, 6143091.089223046],
|
||||
zoom: 14
|
||||
})
|
||||
});
|
||||
|
||||
render({
|
||||
message: 'Vector tile layer renders with vector render mode',
|
||||
tolerance: 0.01
|
||||
});
|
||||
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 23 KiB |
@@ -58,20 +58,6 @@ class ImageTile extends Tile {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state == TileState.LOADING) {
|
||||
this.unlistenImage_();
|
||||
this.image_ = getBlankImage();
|
||||
}
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
* @module ol/MapBrowserEventHandler
|
||||
*/
|
||||
|
||||
import '@openlayers/pepjs';
|
||||
import {DEVICE_PIXEL_RATIO} from './has.js';
|
||||
import 'elm-pep';
|
||||
import {DEVICE_PIXEL_RATIO, PASSIVE_EVENT_LISTENERS} from './has.js';
|
||||
import MapBrowserEventType from './MapBrowserEventType.js';
|
||||
import MapBrowserPointerEvent from './MapBrowserPointerEvent.js';
|
||||
import {listen, unlistenByKey} from './events.js';
|
||||
import EventTarget from './events/Target.js';
|
||||
import PointerEventType from './pointer/EventType.js';
|
||||
import EventType from './events/EventType.js';
|
||||
|
||||
class MapBrowserEventHandler extends EventTarget {
|
||||
|
||||
@@ -84,6 +85,12 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
PointerEventType.POINTERDOWN,
|
||||
this.handlePointerDown_, this);
|
||||
|
||||
/**
|
||||
* @type {PointerEvent}
|
||||
* @private
|
||||
*/
|
||||
this.originalPointerMoveEvent_;
|
||||
|
||||
/**
|
||||
* @type {?import("./events.js").EventsKey}
|
||||
* @private
|
||||
@@ -92,6 +99,13 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
PointerEventType.POINTERMOVE,
|
||||
this.relayEvent_, this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.boundHandleTouchMove_ = this.handleTouchMove_.bind(this);
|
||||
|
||||
this.element_.addEventListener(EventType.TOUCHMOVE, this.boundHandleTouchMove_,
|
||||
PASSIVE_EVENT_LISTENERS ? {passive: false} : false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,11 +260,26 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
* @private
|
||||
*/
|
||||
relayEvent_(pointerEvent) {
|
||||
this.originalPointerMoveEvent_ = pointerEvent;
|
||||
const dragging = !!(this.down_ && this.isMoving_(pointerEvent));
|
||||
this.dispatchEvent(new MapBrowserPointerEvent(
|
||||
pointerEvent.type, this.map_, pointerEvent, dragging));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flexible handling of a `touch-action: none` css equivalent: because calling
|
||||
* `preventDefault()` on a `pointermove` event does not stop native page scrolling
|
||||
* and zooming, we also listen for `touchmove` and call `preventDefault()` on it
|
||||
* when an interaction (currently `DragPan` handles the event.
|
||||
* @param {TouchEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
handleTouchMove_(event) {
|
||||
if (this.originalPointerMoveEvent_.defaultPrevented) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
@@ -271,6 +300,8 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
unlistenByKey(this.relayedListenerKey_);
|
||||
this.relayedListenerKey_ = null;
|
||||
}
|
||||
this.element_.removeEventListener(EventType.TOUCHMOVE, this.boundHandleTouchMove_);
|
||||
|
||||
if (this.pointerdownListenerKey_) {
|
||||
unlistenByKey(this.pointerdownListenerKey_);
|
||||
this.pointerdownListenerKey_ = null;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/PluggableMap
|
||||
*/
|
||||
import {getUid} from './util.js';
|
||||
import Collection from './Collection.js';
|
||||
import CollectionEventType from './CollectionEventType.js';
|
||||
import MapBrowserEvent from './MapBrowserEvent.js';
|
||||
@@ -22,7 +21,7 @@ import {listen, unlistenByKey} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import {clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';
|
||||
import {TRUE} from './functions.js';
|
||||
import {DEVICE_PIXEL_RATIO, IMAGE_DECODE} from './has.js';
|
||||
import {DEVICE_PIXEL_RATIO, IMAGE_DECODE, PASSIVE_EVENT_LISTENERS} from './has.js';
|
||||
import LayerGroup from './layer/Group.js';
|
||||
import {hasArea} from './size.js';
|
||||
import {DROP} from './structs/PriorityQueue.js';
|
||||
@@ -131,17 +130,6 @@ import {toUserCoordinate, fromUserCoordinate} from './proj.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element Element.
|
||||
* @param {string} touchAction Value for `touch-action'.
|
||||
*/
|
||||
function setTouchAction(element, touchAction) {
|
||||
element.style.msTouchAction = touchAction;
|
||||
element.style.touchAction = touchAction;
|
||||
element.setAttribute('touch-action', touchAction);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @fires import("./MapBrowserEvent.js").MapBrowserEvent
|
||||
* @fires import("./MapEvent.js").MapEvent
|
||||
@@ -305,15 +293,10 @@ class PluggableMap extends BaseObject {
|
||||
*/
|
||||
this.keyHandlerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.focusHandlerKeys_ = null;
|
||||
|
||||
const handleBrowserEvent = this.handleBrowserEvent.bind(this);
|
||||
this.viewport_.addEventListener(EventType.CONTEXTMENU, handleBrowserEvent, false);
|
||||
this.viewport_.addEventListener(EventType.WHEEL, handleBrowserEvent, false);
|
||||
this.viewport_.addEventListener(EventType.WHEEL, handleBrowserEvent,
|
||||
PASSIVE_EVENT_LISTENERS ? {passive: false} : false);
|
||||
|
||||
/**
|
||||
* @type {Collection<import("./control/Control.js").default>}
|
||||
@@ -949,12 +932,14 @@ class PluggableMap extends BaseObject {
|
||||
// coordinates so interactions cannot be used.
|
||||
return;
|
||||
}
|
||||
let target = mapBrowserEvent.originalEvent.target;
|
||||
while (target instanceof HTMLElement) {
|
||||
if (target.parentElement === this.overlayContainerStopEvent_) {
|
||||
return;
|
||||
let target = /** @type {Node} */ (mapBrowserEvent.originalEvent.target);
|
||||
if (!mapBrowserEvent.dragging) {
|
||||
while (target && target !== this.viewport_) {
|
||||
if (target.parentElement === this.overlayContainerStopEvent_) {
|
||||
return;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
mapBrowserEvent.frameState = this.frameState_;
|
||||
const interactionsArray = this.getInteractions().getArray();
|
||||
@@ -1043,12 +1028,6 @@ class PluggableMap extends BaseObject {
|
||||
targetElement = this.getTargetElement();
|
||||
}
|
||||
|
||||
if (this.focusHandlerKeys_) {
|
||||
for (let i = 0, ii = this.focusHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.focusHandlerKeys_[i]);
|
||||
}
|
||||
this.focusHandlerKeys_ = null;
|
||||
}
|
||||
if (this.keyHandlerKeys_) {
|
||||
for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.keyHandlerKeys_[i]);
|
||||
@@ -1077,15 +1056,6 @@ class PluggableMap extends BaseObject {
|
||||
if (!this.renderer_) {
|
||||
this.renderer_ = this.createRenderer();
|
||||
}
|
||||
let hasFocus = true;
|
||||
if (targetElement.hasAttribute('tabindex')) {
|
||||
hasFocus = document.activeElement === targetElement;
|
||||
this.focusHandlerKeys_ = [
|
||||
listen(targetElement, EventType.FOCUS, setTouchAction.bind(this, this.viewport_, 'none')),
|
||||
listen(targetElement, EventType.BLUR, setTouchAction.bind(this, this.viewport_, 'auto'))
|
||||
];
|
||||
}
|
||||
setTouchAction(this.viewport_, hasFocus ? 'none' : 'auto');
|
||||
|
||||
const keyboardEventTarget = !this.keyboardEventTarget_ ?
|
||||
targetElement : this.keyboardEventTarget_;
|
||||
@@ -1133,7 +1103,8 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
const view = this.getView();
|
||||
if (view) {
|
||||
this.viewport_.setAttribute('data-view', getUid(view));
|
||||
this.updateViewportSize_();
|
||||
|
||||
this.viewPropertyListenerKey_ = listen(
|
||||
view, ObjectEventType.PROPERTYCHANGE,
|
||||
this.handleViewPropertyChanged_, this);
|
||||
@@ -1391,6 +1362,27 @@ class PluggableMap extends BaseObject {
|
||||
parseFloat(computedStyle['borderBottomWidth'])
|
||||
]);
|
||||
}
|
||||
|
||||
this.updateViewportSize_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recomputes the viewport size and save it on the view object (if any)
|
||||
* @private
|
||||
*/
|
||||
updateViewportSize_() {
|
||||
const view = this.getView();
|
||||
if (view) {
|
||||
let size = undefined;
|
||||
const computedStyle = getComputedStyle(this.viewport_);
|
||||
if (computedStyle.width && computedStyle.height) {
|
||||
size = [
|
||||
parseInt(computedStyle.width, 10),
|
||||
parseInt(computedStyle.height, 10)
|
||||
];
|
||||
}
|
||||
view.setViewportSize(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,10 +145,9 @@ class Tile extends EventTarget {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Called by the tile cache when the tile is removed from the cache due to expiry
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
release() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,15 +6,6 @@ import {fromKey, getKey} from './tilecoord.js';
|
||||
|
||||
class TileCache extends LRUCache {
|
||||
|
||||
/**
|
||||
* @param {number=} opt_highWaterMark High water mark.
|
||||
*/
|
||||
constructor(opt_highWaterMark) {
|
||||
|
||||
super(opt_highWaterMark);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object<string, import("./TileRange.js").default>} usedTiles Used tiles.
|
||||
*/
|
||||
@@ -24,8 +15,7 @@ class TileCache extends LRUCache {
|
||||
if (tile.getKey() in usedTiles) {
|
||||
break;
|
||||
} else {
|
||||
// This lets the GC clean up the object
|
||||
this.pop();
|
||||
this.pop().release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +33,7 @@ class TileCache extends LRUCache {
|
||||
this.forEach(function(tile) {
|
||||
if (tile.tileCoord[0] !== z) {
|
||||
this.remove(getKey(tile.tileCoord));
|
||||
tile.dispose();
|
||||
tile.release();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ class TileQueue extends PriorityQueue {
|
||||
handleTileChange(event) {
|
||||
const tile = /** @type {import("./Tile.js").default} */ (event.target);
|
||||
const state = tile.getState();
|
||||
if (tile.hifi && state === TileState.LOADED || state === TileState.ERROR ||
|
||||
state === TileState.EMPTY || state === TileState.ABORT) {
|
||||
if (tile.hifi && state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
|
||||
tile.removeEventListener(EventType.CHANGE, this.boundHandleTileChange_);
|
||||
const tileKey = tile.getKey();
|
||||
if (tileKey in this.tilesLoadingKeys_) {
|
||||
@@ -102,27 +101,19 @@ class TileQueue extends PriorityQueue {
|
||||
*/
|
||||
loadMoreTiles(maxTotalLoading, maxNewLoads) {
|
||||
let newLoads = 0;
|
||||
let abortedTiles = false;
|
||||
let state, tile, tileKey;
|
||||
while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
|
||||
this.getCount() > 0) {
|
||||
tile = /** @type {import("./Tile.js").default} */ (this.dequeue()[0]);
|
||||
tileKey = tile.getKey();
|
||||
state = tile.getState();
|
||||
if (state === TileState.ABORT) {
|
||||
abortedTiles = true;
|
||||
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
tile.load();
|
||||
}
|
||||
}
|
||||
if (newLoads === 0 && abortedTiles) {
|
||||
// Do not stop the render loop when all wanted tiles were aborted due to
|
||||
// a small, saturated tile cache.
|
||||
this.tileChangeCallback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,5 @@ export default {
|
||||
* @type {number}
|
||||
*/
|
||||
ERROR: 3,
|
||||
EMPTY: 4,
|
||||
ABORT: 5
|
||||
EMPTY: 4
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
import {unlistenByKey} from './events.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -19,6 +18,10 @@ import {unlistenByKey} from './events.js';
|
||||
* @property {number} renderedTileZ
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Array<HTMLCanvasElement>}
|
||||
*/
|
||||
const canvasPool = [];
|
||||
|
||||
class VectorRenderTile extends Tile {
|
||||
|
||||
@@ -26,13 +29,10 @@ class VectorRenderTile extends Tile {
|
||||
* @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("./TileState.js").default} state State.
|
||||
* @param {import("./tilecoord.js").TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {import("./tilegrid/TileGrid.js").default} sourceTileGrid Tile grid of the source.
|
||||
* @param {function(VectorRenderTile):Array<import("./VectorTile").default>} getSourceTiles Function
|
||||
* to get an source tiles for this tile.
|
||||
* @param {function(VectorRenderTile):void} removeSourceTiles Function to remove this tile from its
|
||||
* source tiles's consumer count.
|
||||
* to get source tiles for this tile.
|
||||
*/
|
||||
constructor(tileCoord, state, urlTileCoord, sourceTileGrid, getSourceTiles, removeSourceTiles) {
|
||||
constructor(tileCoord, state, urlTileCoord, getSourceTiles) {
|
||||
|
||||
super(tileCoord, state, {transition: 0});
|
||||
|
||||
@@ -61,9 +61,9 @@ class VectorRenderTile extends Tile {
|
||||
this.errorSourceTileKeys = {};
|
||||
|
||||
/**
|
||||
* @type {ImageData}
|
||||
* @type {Object<number, ImageData>}
|
||||
*/
|
||||
this.hitDetectionImageData = null;
|
||||
this.hitDetectionImageData = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -71,6 +71,11 @@ class VectorRenderTile extends Tile {
|
||||
*/
|
||||
this.replayState_ = {};
|
||||
|
||||
/**
|
||||
* @type {Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.sourceTiles = null;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@@ -79,23 +84,7 @@ class VectorRenderTile extends Tile {
|
||||
/**
|
||||
* @type {!function():Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.getSourceTiles = getSourceTiles.bind(this, this);
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):void}
|
||||
*/
|
||||
this.removeSourceTiles_ = removeSourceTiles;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./tilegrid/TileGrid.js").default}
|
||||
*/
|
||||
this.sourceTileGrid_ = sourceTileGrid;
|
||||
|
||||
/**
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.sourceTileListenerKeys = [];
|
||||
this.getSourceTiles = getSourceTiles.bind(undefined, this);
|
||||
|
||||
/**
|
||||
* z of the source tiles of the last getSourceTiles call.
|
||||
@@ -115,27 +104,6 @@ class VectorRenderTile extends Tile {
|
||||
this.wrappedTileCoord = urlTileCoord;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.sourceTileListenerKeys.forEach(unlistenByKey);
|
||||
this.sourceTileListenerKeys.length = 0;
|
||||
this.removeSourceTiles_(this);
|
||||
for (const key in this.context_) {
|
||||
const canvas = this.context_[key].canvas;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
for (const key in this.executorGroups) {
|
||||
const executorGroups = this.executorGroups[key];
|
||||
for (let i = 0, ii = executorGroups.length; i < ii; ++i) {
|
||||
executorGroups[i].disposeInternal();
|
||||
}
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Layer.js").default} layer Layer.
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
@@ -143,7 +111,7 @@ class VectorRenderTile extends Tile {
|
||||
getContext(layer) {
|
||||
const key = getUid(layer);
|
||||
if (!(key in this.context_)) {
|
||||
this.context_[key] = createCanvasContext2D();
|
||||
this.context_[key] = createCanvasContext2D(1, 1, canvasPool);
|
||||
}
|
||||
return this.context_[key];
|
||||
}
|
||||
@@ -192,6 +160,16 @@ class VectorRenderTile extends Tile {
|
||||
load() {
|
||||
this.getSourceTiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
release() {
|
||||
for (const key in this.context_) {
|
||||
canvasPool.push(this.context_[key].canvas);
|
||||
}
|
||||
super.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,11 +18,6 @@ class VectorTile extends Tile {
|
||||
|
||||
super(tileCoord, state, opt_options);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* Extent of this tile; set by the source.
|
||||
* @type {import("./extent.js").Extent}
|
||||
@@ -105,7 +100,9 @@ class VectorTile extends Tile {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
this.tileLoadFunction_(this, this.url_);
|
||||
this.loader_(this.extent, this.resolution, this.projection);
|
||||
if (this.loader_) {
|
||||
this.loader_(this.extent, this.resolution, this.projection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @module ol/View
|
||||
*/
|
||||
import {DEFAULT_TILE_SIZE} from './tilegrid/common.js';
|
||||
import {getUid} from './util.js';
|
||||
import {VOID} from './functions.js';
|
||||
import {createExtent, none as centerNone} from './centerconstraint.js';
|
||||
import BaseObject from './Object.js';
|
||||
@@ -294,6 +293,12 @@ class View extends BaseObject {
|
||||
*/
|
||||
this.projection_ = createProjection(options.projection, 'EPSG:3857');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./size.js").Size}
|
||||
*/
|
||||
this.viewportSize_ = [100, 100];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./coordinate.js").Coordinate|undefined}
|
||||
@@ -312,6 +317,12 @@ class View extends BaseObject {
|
||||
*/
|
||||
this.targetRotation_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./coordinate.js").Coordinate|undefined}
|
||||
*/
|
||||
this.cancelAnchor_ = undefined;
|
||||
|
||||
if (options.center) {
|
||||
options.center = fromUserCoordinate(options.center, this.projection_);
|
||||
}
|
||||
@@ -584,13 +595,19 @@ class View extends BaseObject {
|
||||
*/
|
||||
cancelAnimations() {
|
||||
this.setHint(ViewHint.ANIMATING, -this.hints_[ViewHint.ANIMATING]);
|
||||
let anchor;
|
||||
for (let i = 0, ii = this.animations_.length; i < ii; ++i) {
|
||||
const series = this.animations_[i];
|
||||
if (series[0].callback) {
|
||||
animationCallback(series[0].callback, false);
|
||||
}
|
||||
anchor = anchor ||
|
||||
series.filter(function(animation) {
|
||||
return !animation.complete;
|
||||
})[0].anchor;
|
||||
}
|
||||
this.animations_.length = 0;
|
||||
this.cancelAnchor_ = anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,7 +654,7 @@ class View extends BaseObject {
|
||||
animation.targetResolution :
|
||||
animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
|
||||
if (animation.anchor) {
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
const constrainedResolution = this.constraints_.resolution(resolution, 0, size, true);
|
||||
this.targetCenter_ = this.calculateCenterZoom(constrainedResolution, animation.anchor);
|
||||
}
|
||||
@@ -710,26 +727,33 @@ class View extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current viewport size.
|
||||
* @private
|
||||
* @param {number=} opt_rotation Take into account the rotation of the viewport when giving the size
|
||||
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
||||
*/
|
||||
getSizeFromViewport_(opt_rotation) {
|
||||
const size = [100, 100];
|
||||
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
const metrics = getComputedStyle(element);
|
||||
size[0] = parseInt(metrics.width, 10);
|
||||
size[1] = parseInt(metrics.height, 10);
|
||||
}
|
||||
getViewportSize_(opt_rotation) {
|
||||
const size = this.viewportSize_;
|
||||
if (opt_rotation) {
|
||||
const w = size[0];
|
||||
const h = size[1];
|
||||
size[0] = Math.abs(w * Math.cos(opt_rotation)) + Math.abs(h * Math.sin(opt_rotation));
|
||||
size[1] = Math.abs(w * Math.sin(opt_rotation)) + Math.abs(h * Math.cos(opt_rotation));
|
||||
return [
|
||||
Math.abs(w * Math.cos(opt_rotation)) + Math.abs(h * Math.sin(opt_rotation)),
|
||||
Math.abs(w * Math.sin(opt_rotation)) + Math.abs(h * Math.cos(opt_rotation))
|
||||
];
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the viewport size on the view. The viewport size is not read every time from the DOM
|
||||
* to avoid performance hit and layout reflow.
|
||||
* This should be done on map size change.
|
||||
* @param {import("./size.js").Size=} opt_size Viewport size; if undefined, [100, 100] is assumed
|
||||
*/
|
||||
setViewportSize(opt_size) {
|
||||
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -780,8 +804,8 @@ class View extends BaseObject {
|
||||
* The size is the pixel dimensions of the box into which the calculated extent
|
||||
* should fit. In most cases you want to get the extent of the entire map,
|
||||
* that is `map.getSize()`.
|
||||
* @param {import("./size.js").Size=} opt_size Box pixel size. If not provided, the size of the
|
||||
* first map that uses this view will be used.
|
||||
* @param {import("./size.js").Size=} opt_size Box pixel size. If not provided, the size
|
||||
* of the map that uses this view will be used.
|
||||
* @return {import("./extent.js").Extent} Extent.
|
||||
* @api
|
||||
*/
|
||||
@@ -796,7 +820,7 @@ class View extends BaseObject {
|
||||
* @return {import("./extent.js").Extent} Extent.
|
||||
*/
|
||||
calculateExtentInternal(opt_size) {
|
||||
const size = opt_size || this.getSizeFromViewport_();
|
||||
const size = opt_size || this.getViewportSize_();
|
||||
const center = /** @type {!import("./coordinate.js").Coordinate} */ (this.getCenterInternal());
|
||||
assert(center, 1); // The view center is not defined
|
||||
const resolution = /** @type {!number} */ (this.getResolution());
|
||||
@@ -919,7 +943,7 @@ class View extends BaseObject {
|
||||
* the given size.
|
||||
*/
|
||||
getResolutionForExtentInternal(extent, opt_size) {
|
||||
const size = opt_size || this.getSizeFromViewport_();
|
||||
const size = opt_size || this.getViewportSize_();
|
||||
const xResolution = getWidth(extent) / size[0];
|
||||
const yResolution = getHeight(extent) / size[1];
|
||||
return Math.max(xResolution, yResolution);
|
||||
@@ -933,7 +957,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
getResolutionForValueFunction(opt_power) {
|
||||
const power = opt_power || 2;
|
||||
const maxResolution = this.maxResolution_;
|
||||
const maxResolution = this.getConstrainedResolution(this.maxResolution_);
|
||||
const minResolution = this.minResolution_;
|
||||
const max = Math.log(maxResolution / minResolution) / Math.log(power);
|
||||
return (
|
||||
@@ -964,17 +988,17 @@ class View extends BaseObject {
|
||||
* @return {function(number): number} Value for resolution function.
|
||||
*/
|
||||
getValueForResolutionFunction(opt_power) {
|
||||
const power = opt_power || 2;
|
||||
const maxResolution = this.maxResolution_;
|
||||
const logPower = Math.log(opt_power || 2);
|
||||
const maxResolution = this.getConstrainedResolution(this.maxResolution_);
|
||||
const minResolution = this.minResolution_;
|
||||
const max = Math.log(maxResolution / minResolution) / Math.log(power);
|
||||
const max = Math.log(maxResolution / minResolution) / logPower;
|
||||
return (
|
||||
/**
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {number} Value.
|
||||
*/
|
||||
function(resolution) {
|
||||
const value = (Math.log(maxResolution / resolution) / Math.log(power)) / max;
|
||||
const value = (Math.log(maxResolution / resolution) / logPower) / max;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
@@ -1067,7 +1091,7 @@ class View extends BaseObject {
|
||||
* @api
|
||||
*/
|
||||
fit(geometryOrExtent, opt_options) {
|
||||
const options = assign({size: this.getSizeFromViewport_()}, opt_options || {});
|
||||
const options = assign({size: this.getViewportSize_()}, opt_options || {});
|
||||
|
||||
/** @type {import("./geom/SimpleGeometry.js").default} */
|
||||
let geometry;
|
||||
@@ -1085,7 +1109,7 @@ class View extends BaseObject {
|
||||
} else {
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ (geometry.clone().transform(userProjection, this.getProjection()));
|
||||
geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ (geometryOrExtent.clone().transform(userProjection, this.getProjection()));
|
||||
} else {
|
||||
geometry = geometryOrExtent;
|
||||
}
|
||||
@@ -1102,7 +1126,7 @@ class View extends BaseObject {
|
||||
const options = opt_options || {};
|
||||
let size = options.size;
|
||||
if (!size) {
|
||||
size = this.getSizeFromViewport_();
|
||||
size = this.getViewportSize_();
|
||||
}
|
||||
const padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
|
||||
const nearest = options.nearest !== undefined ? options.nearest : false;
|
||||
@@ -1249,10 +1273,10 @@ class View extends BaseObject {
|
||||
*/
|
||||
adjustResolutionInternal(ratio, opt_anchor) {
|
||||
const isMoving = this.getAnimating() || this.getInteracting();
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_ * ratio, 0, size, isMoving);
|
||||
|
||||
if (opt_anchor !== undefined) {
|
||||
if (opt_anchor) {
|
||||
this.targetCenter_ = this.calculateCenterZoom(newResolution, opt_anchor);
|
||||
}
|
||||
|
||||
@@ -1292,7 +1316,7 @@ class View extends BaseObject {
|
||||
adjustRotationInternal(delta, opt_anchor) {
|
||||
const isMoving = this.getAnimating() || this.getInteracting();
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_ + delta, isMoving);
|
||||
if (opt_anchor !== undefined) {
|
||||
if (opt_anchor) {
|
||||
this.targetCenter_ = this.calculateCenterRotate(newRotation, opt_anchor);
|
||||
}
|
||||
this.targetRotation_ += delta;
|
||||
@@ -1373,7 +1397,7 @@ class View extends BaseObject {
|
||||
|
||||
// compute rotation
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_, isMoving);
|
||||
const size = this.getSizeFromViewport_(newRotation);
|
||||
const size = this.getViewportSize_(newRotation);
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_, 0, size, isMoving);
|
||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size, isMoving);
|
||||
|
||||
@@ -1390,6 +1414,7 @@ class View extends BaseObject {
|
||||
if (this.getAnimating() && !opt_doNotCancelAnims) {
|
||||
this.cancelAnimations();
|
||||
}
|
||||
this.cancelAnchor_ = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1406,11 +1431,11 @@ class View extends BaseObject {
|
||||
const direction = opt_resolutionDirection || 0;
|
||||
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_);
|
||||
const size = this.getSizeFromViewport_(newRotation);
|
||||
const size = this.getViewportSize_(newRotation);
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_, direction, size);
|
||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size);
|
||||
|
||||
if (duration === 0) {
|
||||
if (duration === 0 && !this.cancelAnchor_) {
|
||||
this.targetResolution_ = newResolution;
|
||||
this.targetRotation_ = newRotation;
|
||||
this.targetCenter_ = newCenter;
|
||||
@@ -1418,6 +1443,9 @@ class View extends BaseObject {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchor = opt_anchor || (duration === 0 ? this.cancelAnchor_ : undefined);
|
||||
this.cancelAnchor_ = undefined;
|
||||
|
||||
if (this.getResolution() !== newResolution ||
|
||||
this.getRotation() !== newRotation ||
|
||||
!this.getCenterInternal() ||
|
||||
@@ -1433,7 +1461,7 @@ class View extends BaseObject {
|
||||
resolution: newResolution,
|
||||
duration: duration,
|
||||
easing: easeOut,
|
||||
anchor: opt_anchor
|
||||
anchor: anchor
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1484,7 +1512,7 @@ class View extends BaseObject {
|
||||
* @return {import("./coordinate.js").Coordinate|undefined} Valid center position.
|
||||
*/
|
||||
getConstrainedCenter(targetCenter, opt_targetResolution) {
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
return this.constraints_.center(targetCenter, opt_targetResolution || this.getResolution(), size);
|
||||
}
|
||||
|
||||
@@ -1513,7 +1541,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
getConstrainedResolution(targetResolution, opt_direction) {
|
||||
const direction = opt_direction || 0;
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
|
||||
return this.constraints_.resolution(targetResolution, direction, size);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* @module ol/control/MousePosition
|
||||
*/
|
||||
|
||||
import 'elm-pep';
|
||||
import {listen} from '../events.js';
|
||||
import EventType from '../pointer/EventType.js';
|
||||
import {getChangeEventType} from '../Object.js';
|
||||
import Control from './Control.js';
|
||||
import {getTransformFromProjections, identityTransform, get as getProjection, getUserProjection} from '../proj.js';
|
||||
import '@openlayers/pepjs';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -304,6 +304,8 @@ class OverviewMap extends Control {
|
||||
*/
|
||||
bindView_(view) {
|
||||
view.addEventListener(getChangeEventType(ViewProperty.ROTATION), this.boundHandleRotationChanged_);
|
||||
// Sync once with the new view
|
||||
this.handleRotationChanged_();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* @module ol/control/ZoomSlider
|
||||
*/
|
||||
|
||||
import 'elm-pep';
|
||||
import Control from './Control.js';
|
||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
|
||||
import {easeOut} from '../easing.js';
|
||||
@@ -9,7 +11,6 @@ import {stopPropagation} from '../events/Event.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {clamp} from '../math.js';
|
||||
import PointerEventType from '../pointer/EventType.js';
|
||||
import '@openlayers/pepjs';
|
||||
|
||||
|
||||
/**
|
||||
@@ -135,7 +136,6 @@ class ZoomSlider extends Control {
|
||||
thumbElement.setAttribute('type', 'button');
|
||||
thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE;
|
||||
const containerElement = this.element;
|
||||
containerElement.setAttribute('touch-action', 'none');
|
||||
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
containerElement.appendChild(thumbElement);
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
* Create an html canvas element and returns its 2d context.
|
||||
* @param {number=} opt_width Canvas width.
|
||||
* @param {number=} opt_height Canvas height.
|
||||
* @param {Array<HTMLCanvasElement>=} opt_canvasPool Canvas pool to take existing canvas from.
|
||||
* @return {CanvasRenderingContext2D} The context.
|
||||
*/
|
||||
export function createCanvasContext2D(opt_width, opt_height) {
|
||||
const canvas = document.createElement('canvas');
|
||||
export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) {
|
||||
const canvas = opt_canvasPool && opt_canvasPool.length ?
|
||||
opt_canvasPool.shift() : document.createElement('canvas');
|
||||
if (opt_width) {
|
||||
canvas.width = opt_width;
|
||||
}
|
||||
|
||||
@@ -34,5 +34,6 @@ export default {
|
||||
KEYPRESS: 'keypress',
|
||||
LOAD: 'load',
|
||||
RESIZE: 'resize',
|
||||
TOUCHMOVE: 'touchmove',
|
||||
WHEEL: 'wheel'
|
||||
};
|
||||
|
||||
@@ -207,12 +207,9 @@ export const shiftKeyOnly = function(mapBrowserEvent) {
|
||||
* @api
|
||||
*/
|
||||
export const targetNotEditable = function(mapBrowserEvent) {
|
||||
const target = mapBrowserEvent.target;
|
||||
const tagName = /** @type {Element} */ (target).tagName;
|
||||
return (
|
||||
tagName !== 'INPUT' &&
|
||||
tagName !== 'SELECT' &&
|
||||
tagName !== 'TEXTAREA');
|
||||
const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent);
|
||||
const tagName = /** @type {Element} */ (originalEvent.target).tagName;
|
||||
return tagName !== 'INPUT' && tagName !== 'SELECT' && tagName !== 'TEXTAREA';
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -386,6 +386,8 @@ function createStyleDefaults() {
|
||||
* @property {Array<Style>} [defaultStyle] Default style. The
|
||||
* default default style is the same as Google Earth.
|
||||
* @property {boolean} [writeStyles=true] Write styles into KML.
|
||||
* @property {null|string} [crossOrigin='anonymous'] The `crossOrigin` attribute for loaded images. Note that you must provide a
|
||||
* `crossOrigin` value if you want to access pixel data with the Canvas renderer.
|
||||
*/
|
||||
|
||||
|
||||
@@ -458,6 +460,13 @@ class KML extends XMLFeature {
|
||||
this.showPointNames_ = options.showPointNames !== undefined ?
|
||||
options.showPointNames : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {null|string}
|
||||
*/
|
||||
this.crossOrigin_ = options.crossOrigin !== undefined ?
|
||||
options.crossOrigin : 'anonymous';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -494,7 +503,7 @@ class KML extends XMLFeature {
|
||||
*/
|
||||
readPlacemark_(node, objectStack) {
|
||||
const object = pushParseAndPop({'geometry': null},
|
||||
PLACEMARK_PARSERS, node, objectStack);
|
||||
PLACEMARK_PARSERS, node, objectStack, this);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -537,7 +546,7 @@ class KML extends XMLFeature {
|
||||
readSharedStyle_(node, objectStack) {
|
||||
const id = node.getAttribute('id');
|
||||
if (id !== null) {
|
||||
const style = readStyle(node, objectStack);
|
||||
const style = readStyle.call(this, node, objectStack);
|
||||
if (style) {
|
||||
let styleUri;
|
||||
let baseURI = node.baseURI;
|
||||
@@ -565,7 +574,7 @@ class KML extends XMLFeature {
|
||||
if (id === null) {
|
||||
return;
|
||||
}
|
||||
const styleMapValue = readStyleMapValue(node, objectStack);
|
||||
const styleMapValue = readStyleMapValue.call(this, node, objectStack);
|
||||
if (!styleMapValue) {
|
||||
return;
|
||||
}
|
||||
@@ -1112,13 +1121,14 @@ const STYLE_MAP_PARSERS = makeStructureNS(
|
||||
|
||||
|
||||
/**
|
||||
* @this {KML}
|
||||
* @param {Element} node Node.
|
||||
* @param {Array<*>} objectStack Object stack.
|
||||
* @return {Array<Style>|string|undefined} StyleMap.
|
||||
*/
|
||||
function readStyleMapValue(node, objectStack) {
|
||||
return pushParseAndPop(undefined,
|
||||
STYLE_MAP_PARSERS, node, objectStack);
|
||||
STYLE_MAP_PARSERS, node, objectStack, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1137,6 +1147,7 @@ const ICON_STYLE_PARSERS = makeStructureNS(
|
||||
|
||||
|
||||
/**
|
||||
* @this {KML}
|
||||
* @param {Element} node Node.
|
||||
* @param {Array<*>} objectStack Object stack.
|
||||
*/
|
||||
@@ -1223,7 +1234,7 @@ function iconStyleParser(node, objectStack) {
|
||||
anchorOrigin: anchorOrigin,
|
||||
anchorXUnits: anchorXUnits,
|
||||
anchorYUnits: anchorYUnits,
|
||||
crossOrigin: 'anonymous', // FIXME should this be configurable?
|
||||
crossOrigin: this.crossOrigin_,
|
||||
offset: offset,
|
||||
offsetOrigin: IconOrigin.BOTTOM_LEFT,
|
||||
rotation: rotation,
|
||||
@@ -1719,13 +1730,14 @@ const STYLE_PARSERS = makeStructureNS(
|
||||
|
||||
|
||||
/**
|
||||
* @this {KML}
|
||||
* @param {Element} node Node.
|
||||
* @param {Array<*>} objectStack Object stack.
|
||||
* @return {Array<Style>} Style.
|
||||
*/
|
||||
function readStyle(node, objectStack) {
|
||||
const styleObject = pushParseAndPop(
|
||||
{}, STYLE_PARSERS, node, objectStack);
|
||||
{}, STYLE_PARSERS, node, objectStack, this);
|
||||
if (!styleObject) {
|
||||
return null;
|
||||
}
|
||||
@@ -1885,7 +1897,7 @@ const PAIR_PARSERS = makeStructureNS(
|
||||
*/
|
||||
function pairDataParser(node, objectStack) {
|
||||
const pairObject = pushParseAndPop(
|
||||
{}, PAIR_PARSERS, node, objectStack);
|
||||
{}, PAIR_PARSERS, node, objectStack, this);
|
||||
if (!pairObject) {
|
||||
return;
|
||||
}
|
||||
@@ -1907,11 +1919,12 @@ function pairDataParser(node, objectStack) {
|
||||
|
||||
|
||||
/**
|
||||
* @this {KML}
|
||||
* @param {Element} node Node.
|
||||
* @param {Array<*>} objectStack Object stack.
|
||||
*/
|
||||
function placemarkStyleMapParser(node, objectStack) {
|
||||
const styleMapValue = readStyleMapValue(node, objectStack);
|
||||
const styleMapValue = readStyleMapValue.call(this, node, objectStack);
|
||||
if (!styleMapValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {abstract} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import FeatureFormat from '../format/Feature.js';
|
||||
import FormatType from '../format/FormatType.js';
|
||||
import {isDocument, parse} from '../xml.js';
|
||||
import {isDocument, parse, getXMLSerializer} from '../xml.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -23,7 +23,7 @@ class XMLFeature extends FeatureFormat {
|
||||
* @type {XMLSerializer}
|
||||
* @private
|
||||
*/
|
||||
this.xmlSerializer_ = new XMLSerializer();
|
||||
this.xmlSerializer_ = getXMLSerializer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/format/xsd
|
||||
*/
|
||||
import {getAllTextContent, DOCUMENT} from '../xml.js';
|
||||
import {getAllTextContent, getDocument} from '../xml.js';
|
||||
import {padNumber} from '../string.js';
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ export function writeBooleanTextNode(node, bool) {
|
||||
* @param {string} string String.
|
||||
*/
|
||||
export function writeCDATASection(node, string) {
|
||||
node.appendChild(DOCUMENT.createCDATASection(string));
|
||||
node.appendChild(getDocument().createCDATASection(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ export function writeDateTimeTextNode(node, dateTime) {
|
||||
padNumber(date.getUTCHours(), 2) + ':' +
|
||||
padNumber(date.getUTCMinutes(), 2) + ':' +
|
||||
padNumber(date.getUTCSeconds(), 2) + 'Z';
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ export function writeDateTimeTextNode(node, dateTime) {
|
||||
*/
|
||||
export function writeDecimalTextNode(node, decimal) {
|
||||
const string = decimal.toPrecision();
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ export function writeDecimalTextNode(node, decimal) {
|
||||
*/
|
||||
export function writeNonNegativeIntegerTextNode(node, nonNegativeInteger) {
|
||||
const string = nonNegativeInteger.toString();
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -157,5 +157,5 @@ export function writeNonNegativeIntegerTextNode(node, nonNegativeInteger) {
|
||||
* @param {string} string String.
|
||||
*/
|
||||
export function writeStringTextNode(node, string) {
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
@@ -44,3 +44,23 @@ export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const IMAGE_DECODE = typeof Image !== 'undefined' && Image.prototype.decode;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const PASSIVE_EVENT_LISTENERS = (function() {
|
||||
let passive = false;
|
||||
try {
|
||||
const options = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
passive = true;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('_', null, options);
|
||||
window.removeEventListener('_', null, options);
|
||||
} catch (error) {
|
||||
// passive not supported
|
||||
}
|
||||
return passive;
|
||||
})();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
// FIXME draw drag box
|
||||
import Event from '../events/Event.js';
|
||||
import {always, mouseOnly, mouseActionButton} from '../events/condition.js';
|
||||
import {mouseActionButton} from '../events/condition.js';
|
||||
import {VOID} from '../functions.js';
|
||||
import PointerInteraction from './Pointer.js';
|
||||
import RenderBox from '../render/Box.js';
|
||||
@@ -22,7 +22,7 @@ import RenderBox from '../render/Box.js';
|
||||
* @property {string} [className='ol-dragbox'] CSS class name for styling the box.
|
||||
* @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 ol/events/condition~always}.
|
||||
* Default is {@link ol/events/condition~mouseActionButton}.
|
||||
* @property {number} [minArea=64] The minimum area of the box in pixel, this value is used by the default
|
||||
* `boxEndCondition` function.
|
||||
* @property {EndCondition} [boxEndCondition] A function that takes a {@link module:ol/MapBrowserEvent~MapBrowserEvent} and two
|
||||
@@ -104,8 +104,6 @@ class DragBoxEvent extends Event {
|
||||
* (see {@link module:ol/interaction/DragZoom~DragZoom} and
|
||||
* {@link module:ol/interaction/DragRotateAndZoom}).
|
||||
*
|
||||
* This interaction is only supported for mouse devices.
|
||||
*
|
||||
* @fires DragBoxEvent
|
||||
* @api
|
||||
*/
|
||||
@@ -148,7 +146,7 @@ class DragBox extends PointerInteraction {
|
||||
* @private
|
||||
* @type {import("../events/condition.js").Condition}
|
||||
*/
|
||||
this.condition_ = options.condition ? options.condition : always;
|
||||
this.condition_ = options.condition ? options.condition : mouseActionButton;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -186,10 +184,6 @@ class DragBox extends PointerInteraction {
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleDragEvent(mapBrowserEvent) {
|
||||
if (!mouseOnly(mapBrowserEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel);
|
||||
|
||||
this.dispatchEvent(new DragBoxEvent(DragBoxEventType.BOXDRAG,
|
||||
@@ -200,10 +194,6 @@ class DragBox extends PointerInteraction {
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleUpEvent(mapBrowserEvent) {
|
||||
if (!mouseOnly(mapBrowserEvent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.box_.setMap(null);
|
||||
|
||||
if (this.boxEndCondition_(mapBrowserEvent, this.startPixel_, mapBrowserEvent.pixel)) {
|
||||
@@ -218,12 +208,7 @@ class DragBox extends PointerInteraction {
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleDownEvent(mapBrowserEvent) {
|
||||
if (!mouseOnly(mapBrowserEvent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mouseActionButton(mapBrowserEvent) &&
|
||||
this.condition_(mapBrowserEvent)) {
|
||||
if (this.condition_(mapBrowserEvent)) {
|
||||
this.startPixel_ = mapBrowserEvent.pixel;
|
||||
this.box_.setMap(mapBrowserEvent.map);
|
||||
this.box_.setPixels(this.startPixel_, this.startPixel_);
|
||||
|
||||
@@ -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, primaryAction, focus} from '../events/condition.js';
|
||||
import {FALSE} from '../functions.js';
|
||||
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
||||
|
||||
@@ -69,6 +69,20 @@ class DragPan extends PointerInteraction {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {import("../MapBrowserEvent").default} mapBrowserEvent Event.
|
||||
* @return {boolean} Condition passes.
|
||||
*/
|
||||
conditionInternal_(mapBrowserEvent) {
|
||||
let pass = true;
|
||||
if (mapBrowserEvent.map.getTargetElement().hasAttribute('tabindex')) {
|
||||
pass = focus(mapBrowserEvent);
|
||||
}
|
||||
return pass && this.condition_(mapBrowserEvent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -101,6 +115,7 @@ class DragPan extends PointerInteraction {
|
||||
}
|
||||
this.lastCentroid = centroid;
|
||||
this.lastPointersCount_ = targetPointers.length;
|
||||
mapBrowserEvent.originalEvent.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +160,7 @@ class DragPan extends PointerInteraction {
|
||||
* @inheritDoc
|
||||
*/
|
||||
handleDownEvent(mapBrowserEvent) {
|
||||
if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
|
||||
if (this.targetPointers.length > 0 && this.conditionInternal_(mapBrowserEvent)) {
|
||||
const map = mapBrowserEvent.map;
|
||||
const view = map.getView();
|
||||
this.lastCentroid = null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import InteractionProperty from './Property.js';
|
||||
import VectorLayer from '../layer/Vector.js';
|
||||
import VectorSource from '../source/Vector.js';
|
||||
import {createEditingStyle} from '../style/Style.js';
|
||||
import {fromUserCoordinate, getUserProjection} from '../proj.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -104,11 +105,12 @@ import {createEditingStyle} from '../style/Style.js';
|
||||
|
||||
|
||||
/**
|
||||
* Function that takes an array of coordinates and an optional existing geometry as
|
||||
* arguments, and returns a geometry. The optional existing geometry is the
|
||||
* geometry that is returned when the function is called without a second
|
||||
* argument.
|
||||
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=):
|
||||
* Function that takes an array of coordinates and an optional existing geometry
|
||||
* and a projection as arguments, and returns a geometry. The optional existing
|
||||
* geometry is the geometry that is returned when the function is called without
|
||||
* a second argument.
|
||||
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=,
|
||||
* import("../proj/Projection.js").default):
|
||||
* import("../geom/SimpleGeometry.js").default} GeometryFunction
|
||||
*/
|
||||
|
||||
@@ -296,14 +298,20 @@ class Draw extends PointerInteraction {
|
||||
/**
|
||||
* @param {!LineCoordType} coordinates The coordinates.
|
||||
* @param {import("../geom/SimpleGeometry.js").default=} opt_geometry Optional geometry.
|
||||
* @param {import("../proj/Projection.js").default} projection The view projection.
|
||||
* @return {import("../geom/SimpleGeometry.js").default} A geometry.
|
||||
*/
|
||||
geometryFunction = function(coordinates, opt_geometry) {
|
||||
geometryFunction = function(coordinates, opt_geometry, projection) {
|
||||
const circle = opt_geometry ? /** @type {Circle} */ (opt_geometry) :
|
||||
new Circle([NaN, NaN]);
|
||||
const center = fromUserCoordinate(coordinates[0], projection);
|
||||
const squaredLength = squaredCoordinateDistance(
|
||||
coordinates[0], coordinates[1]);
|
||||
circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength));
|
||||
center, fromUserCoordinate(coordinates[1], projection));
|
||||
circle.setCenterAndRadius(center, Math.sqrt(squaredLength));
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
circle.transform(projection, userProjection);
|
||||
}
|
||||
return circle;
|
||||
};
|
||||
} else {
|
||||
@@ -319,9 +327,10 @@ class Draw extends PointerInteraction {
|
||||
/**
|
||||
* @param {!LineCoordType} coordinates The coordinates.
|
||||
* @param {import("../geom/SimpleGeometry.js").default=} opt_geometry Optional geometry.
|
||||
* @param {import("../proj/Projection.js").default} projection The view projection.
|
||||
* @return {import("../geom/SimpleGeometry.js").default} A geometry.
|
||||
*/
|
||||
geometryFunction = function(coordinates, opt_geometry) {
|
||||
geometryFunction = function(coordinates, opt_geometry, projection) {
|
||||
let geometry = opt_geometry;
|
||||
if (geometry) {
|
||||
if (mode === Mode.POLYGON) {
|
||||
@@ -675,6 +684,7 @@ class Draw extends PointerInteraction {
|
||||
*/
|
||||
startDrawing_(event) {
|
||||
const start = event.coordinate;
|
||||
const projection = event.map.getView().getProjection();
|
||||
this.finishCoordinate_ = start;
|
||||
if (this.mode_ === Mode.POINT) {
|
||||
this.sketchCoords_ = start.slice();
|
||||
@@ -688,7 +698,7 @@ class Draw extends PointerInteraction {
|
||||
this.sketchLine_ = new Feature(
|
||||
new LineString(this.sketchLineCoords_));
|
||||
}
|
||||
const geometry = this.geometryFunction_(this.sketchCoords_);
|
||||
const geometry = this.geometryFunction_(this.sketchCoords_, undefined, projection);
|
||||
this.sketchFeature_ = new Feature();
|
||||
if (this.geometryName_) {
|
||||
this.sketchFeature_.setGeometryName(this.geometryName_);
|
||||
@@ -706,6 +716,7 @@ class Draw extends PointerInteraction {
|
||||
modifyDrawing_(event) {
|
||||
let coordinate = event.coordinate;
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const projection = event.map.getView().getProjection();
|
||||
let coordinates, last;
|
||||
if (this.mode_ === Mode.POINT) {
|
||||
last = this.sketchCoords_;
|
||||
@@ -722,7 +733,7 @@ class Draw extends PointerInteraction {
|
||||
}
|
||||
last[0] = coordinate[0];
|
||||
last[1] = coordinate[1];
|
||||
this.geometryFunction_(/** @type {!LineCoordType} */ (this.sketchCoords_), geometry);
|
||||
this.geometryFunction_(/** @type {!LineCoordType} */ (this.sketchCoords_), geometry, projection);
|
||||
if (this.sketchPoint_) {
|
||||
const sketchPointGeom = this.sketchPoint_.getGeometry();
|
||||
sketchPointGeom.setCoordinates(coordinate);
|
||||
@@ -759,6 +770,7 @@ class Draw extends PointerInteraction {
|
||||
addToDrawing_(event) {
|
||||
const coordinate = event.coordinate;
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const projection = event.map.getView().getProjection();
|
||||
let done;
|
||||
let coordinates;
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
@@ -772,7 +784,7 @@ class Draw extends PointerInteraction {
|
||||
}
|
||||
}
|
||||
coordinates.push(coordinate.slice());
|
||||
this.geometryFunction_(coordinates, geometry);
|
||||
this.geometryFunction_(coordinates, geometry, projection);
|
||||
} else if (this.mode_ === Mode.POLYGON) {
|
||||
coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0];
|
||||
if (coordinates.length >= this.maxPoints_) {
|
||||
@@ -786,7 +798,7 @@ class Draw extends PointerInteraction {
|
||||
if (done) {
|
||||
this.finishCoordinate_ = coordinates[0];
|
||||
}
|
||||
this.geometryFunction_(this.sketchCoords_, geometry);
|
||||
this.geometryFunction_(this.sketchCoords_, geometry, projection);
|
||||
}
|
||||
this.updateSketchFeatures_();
|
||||
if (done) {
|
||||
@@ -803,13 +815,14 @@ class Draw extends PointerInteraction {
|
||||
return;
|
||||
}
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const projection = this.getMap().getView().getProjection();
|
||||
let coordinates;
|
||||
/** @type {LineString} */
|
||||
let sketchLineGeom;
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
coordinates = /** @type {LineCoordType} */ (this.sketchCoords_);
|
||||
coordinates.splice(-2, 1);
|
||||
this.geometryFunction_(coordinates, geometry);
|
||||
this.geometryFunction_(coordinates, geometry, projection);
|
||||
if (coordinates.length >= 2) {
|
||||
this.finishCoordinate_ = coordinates[coordinates.length - 2].slice();
|
||||
}
|
||||
@@ -818,7 +831,7 @@ class Draw extends PointerInteraction {
|
||||
coordinates.splice(-2, 1);
|
||||
sketchLineGeom = this.sketchLine_.getGeometry();
|
||||
sketchLineGeom.setCoordinates(coordinates);
|
||||
this.geometryFunction_(this.sketchCoords_, geometry);
|
||||
this.geometryFunction_(this.sketchCoords_, geometry, projection);
|
||||
}
|
||||
|
||||
if (coordinates.length === 0) {
|
||||
@@ -841,14 +854,15 @@ class Draw extends PointerInteraction {
|
||||
}
|
||||
let coordinates = this.sketchCoords_;
|
||||
const geometry = sketchFeature.getGeometry();
|
||||
const projection = this.getMap().getView().getProjection();
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
// remove the redundant last point
|
||||
coordinates.pop();
|
||||
this.geometryFunction_(coordinates, geometry);
|
||||
this.geometryFunction_(coordinates, geometry, projection);
|
||||
} else if (this.mode_ === Mode.POLYGON) {
|
||||
// remove the redundant last point in ring
|
||||
/** @type {PolyCoordType} */ (coordinates)[0].pop();
|
||||
this.geometryFunction_(coordinates, geometry);
|
||||
this.geometryFunction_(coordinates, geometry, projection);
|
||||
coordinates = geometry.getCoordinates();
|
||||
}
|
||||
|
||||
@@ -881,12 +895,10 @@ class Draw extends PointerInteraction {
|
||||
abortDrawing_() {
|
||||
this.finishCoordinate_ = null;
|
||||
const sketchFeature = this.sketchFeature_;
|
||||
if (sketchFeature) {
|
||||
this.sketchFeature_ = null;
|
||||
this.sketchPoint_ = null;
|
||||
this.sketchLine_ = null;
|
||||
this.overlay_.getSource().clear(true);
|
||||
}
|
||||
this.sketchFeature_ = null;
|
||||
this.sketchPoint_ = null;
|
||||
this.sketchLine_ = null;
|
||||
this.overlay_.getSource().clear(true);
|
||||
return sketchFeature;
|
||||
}
|
||||
|
||||
@@ -968,9 +980,9 @@ function getDefaultStyleFunction() {
|
||||
* @api
|
||||
*/
|
||||
export function createRegularPolygon(opt_sides, opt_angle) {
|
||||
return function(coordinates, opt_geometry) {
|
||||
const center = /** @type {LineCoordType} */ (coordinates)[0];
|
||||
const end = /** @type {LineCoordType} */ (coordinates)[1];
|
||||
return function(coordinates, opt_geometry, projection) {
|
||||
const center = fromUserCoordinate(/** @type {LineCoordType} */ (coordinates)[0], projection);
|
||||
const end = fromUserCoordinate(/** @type {LineCoordType} */ (coordinates)[1], projection);
|
||||
const radius = Math.sqrt(
|
||||
squaredCoordinateDistance(center, end));
|
||||
const geometry = opt_geometry ? /** @type {Polygon} */ (opt_geometry) :
|
||||
@@ -982,6 +994,10 @@ export function createRegularPolygon(opt_sides, opt_angle) {
|
||||
angle = Math.atan(y / x) - (x < 0 ? Math.PI : 0);
|
||||
}
|
||||
makeRegular(geometry, center, radius, angle);
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
geometry.transform(projection, userProjection);
|
||||
}
|
||||
return geometry;
|
||||
};
|
||||
}
|
||||
@@ -996,8 +1012,10 @@ export function createRegularPolygon(opt_sides, opt_angle) {
|
||||
*/
|
||||
export function createBox() {
|
||||
return (
|
||||
function(coordinates, opt_geometry) {
|
||||
const extent = boundingExtent(/** @type {LineCoordType} */ (coordinates));
|
||||
function(coordinates, opt_geometry, projection) {
|
||||
const extent = boundingExtent(/** @type {LineCoordType} */ (coordinates).map(function(coordinate) {
|
||||
return fromUserCoordinate(coordinate, projection);
|
||||
}));
|
||||
const boxCoordinates = [[
|
||||
getBottomLeft(extent),
|
||||
getBottomRight(extent),
|
||||
@@ -1011,6 +1029,10 @@ export function createBox() {
|
||||
} else {
|
||||
geometry = new Polygon(boxCoordinates);
|
||||
}
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
geometry.transform(projection, userProjection);
|
||||
}
|
||||
return geometry;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -807,8 +807,8 @@ class Modify extends PointerInteraction {
|
||||
if (!this.condition_(evt)) {
|
||||
return false;
|
||||
}
|
||||
this.handlePointerAtPixel_(evt.pixel, evt.map);
|
||||
const pixelCoordinate = evt.coordinate;
|
||||
this.handlePointerAtPixel_(evt.pixel, evt.map, pixelCoordinate);
|
||||
this.dragSegments_.length = 0;
|
||||
this.modified_ = false;
|
||||
const vertexFeature = this.vertexFeature_;
|
||||
@@ -916,16 +916,17 @@ class Modify extends PointerInteraction {
|
||||
*/
|
||||
handlePointerMove_(evt) {
|
||||
this.lastPixel_ = evt.pixel;
|
||||
this.handlePointerAtPixel_(evt.pixel, evt.map);
|
||||
this.handlePointerAtPixel_(evt.pixel, evt.map, evt.coordinate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../pixel.js").Pixel} pixel Pixel
|
||||
* @param {import("../PluggableMap.js").default} map Map.
|
||||
* @param {import("../coordinate.js").Coordinate=} opt_coordinate The pixel Coordinate.
|
||||
* @private
|
||||
*/
|
||||
handlePointerAtPixel_(pixel, map) {
|
||||
const pixelCoordinate = map.getCoordinateFromPixel(pixel);
|
||||
handlePointerAtPixel_(pixel, map, opt_coordinate) {
|
||||
const pixelCoordinate = opt_coordinate || map.getCoordinateFromPixel(pixel);
|
||||
const projection = map.getView().getProjection();
|
||||
const sortByDistance = function(a, b) {
|
||||
return projectedDistanceToSegmentDataSquared(pixelCoordinate, a, projection) -
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/interaction/MouseWheelZoom
|
||||
*/
|
||||
import {always} from '../events/condition.js';
|
||||
import {always, focus} from '../events/condition.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {DEVICE_PIXEL_RATIO, FIREFOX} from '../has.js';
|
||||
import Interaction, {zoomByDelta} from './Interaction.js';
|
||||
@@ -134,13 +134,27 @@ class MouseWheelZoom extends Interaction {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {import("../MapBrowserEvent").default} mapBrowserEvent Event.
|
||||
* @return {boolean} Condition passes.
|
||||
*/
|
||||
conditionInternal_(mapBrowserEvent) {
|
||||
let pass = true;
|
||||
if (mapBrowserEvent.map.getTargetElement().hasAttribute('tabindex')) {
|
||||
pass = focus(mapBrowserEvent);
|
||||
}
|
||||
return pass && this.condition_(mapBrowserEvent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
endInteraction_() {
|
||||
this.trackpadTimeoutId_ = undefined;
|
||||
const view = this.getMap().getView();
|
||||
view.endInteraction(undefined, Math.sign(this.lastDelta_), this.lastAnchor_);
|
||||
view.endInteraction(undefined, this.lastDelta_ ? (this.lastDelta_ > 0 ? 1 : -1) : 0, this.lastAnchor_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +163,7 @@ class MouseWheelZoom extends Interaction {
|
||||
* @override
|
||||
*/
|
||||
handleEvent(mapBrowserEvent) {
|
||||
if (!this.condition_(mapBrowserEvent)) {
|
||||
if (!this.conditionInternal_(mapBrowserEvent)) {
|
||||
return true;
|
||||
}
|
||||
const type = mapBrowserEvent.type;
|
||||
|
||||
@@ -95,6 +95,16 @@ class PointerInteraction extends Interaction {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current number of pointers involved in the interaction,
|
||||
* e.g. `2` when two fingers are used.
|
||||
* @return {number} The number of pointers.
|
||||
* @api
|
||||
*/
|
||||
getPointerCount() {
|
||||
return this.targetPointers.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle pointer down events.
|
||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
||||
@@ -136,9 +146,6 @@ class PointerInteraction extends Interaction {
|
||||
} else {
|
||||
if (mapBrowserEvent.type == MapBrowserEventType.POINTERDOWN) {
|
||||
const handled = this.handleDownEvent(mapBrowserEvent);
|
||||
if (handled) {
|
||||
mapBrowserEvent.preventDefault();
|
||||
}
|
||||
this.handlingDownUpSequence = handled;
|
||||
stopEvent = this.stopDown(handled);
|
||||
} else if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE) {
|
||||
|
||||
@@ -294,7 +294,9 @@ class Heatmap extends VectorLayer {
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`,
|
||||
uniforms: {
|
||||
u_gradientTexture: this.gradient_
|
||||
u_gradientTexture: function() {
|
||||
return this.gradient_;
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -40,7 +40,9 @@ import {assign} from '../obj.js';
|
||||
* * `'hybrid'`: Polygon and line elements are rendered as images, so pixels are scaled during zoom
|
||||
* animations. Point symbols and texts are accurately rendered as vectors and can stay upright on
|
||||
* rotated views.
|
||||
*
|
||||
* * `'vector'`: Everything is rendered as vectors. Use this mode for improved performance on vector
|
||||
* tile layers with only a few rendered features (e.g. for highlighting a subset of features of
|
||||
* another layer with the same source).
|
||||
* @property {import("../source/VectorTile.js").default} [source] Source.
|
||||
* @property {import("../PluggableMap.js").default} [map] Sets the layer as overlay on a map. The map will not manage
|
||||
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
|
||||
@@ -92,8 +94,9 @@ class VectorTileLayer extends BaseVectorLayer {
|
||||
const renderMode = options.renderMode || VectorTileRenderType.HYBRID;
|
||||
assert(renderMode == undefined ||
|
||||
renderMode == VectorTileRenderType.IMAGE ||
|
||||
renderMode == VectorTileRenderType.HYBRID,
|
||||
28); // `renderMode` must be `'image'` or `'hybrid'`
|
||||
renderMode == VectorTileRenderType.HYBRID ||
|
||||
renderMode == VectorTileRenderType.VECTOR,
|
||||
28); // `renderMode` must be `'image'`, `'hybrid'` or `'vector'`.
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -11,9 +11,14 @@
|
||||
* * `'hybrid'`: Polygon and line elements are rendered as images, so pixels
|
||||
* are scaled during zoom animations. Point symbols and texts are accurately
|
||||
* rendered as vectors and can stay upright on rotated views.
|
||||
* * `'vector'`: Everything is rendered as vectors. Use this mode for improved
|
||||
* performance on vector tile layers with only a few rendered features (e.g.
|
||||
* for highlighting a subset of features of another layer with the same
|
||||
* source).
|
||||
* @api
|
||||
*/
|
||||
export default {
|
||||
IMAGE: 'image',
|
||||
HYBRID: 'hybrid'
|
||||
HYBRID: 'hybrid',
|
||||
VECTOR: 'vector'
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ import Layer from './Layer.js';
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {import("../source/Vector.js").default} [source] Source.
|
||||
* @property {boolean} [disableHitDetection] Setting this to true will provide a slight performance boost, but will
|
||||
* @property {boolean} [disableHitDetection=false] Setting this to true will provide a slight performance boost, but will
|
||||
* prevent all hit detection on the layer.
|
||||
*/
|
||||
|
||||
|
||||
@@ -74,6 +74,12 @@
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
.ol-overlaycontainer, .ol-overlaycontainer-stopevent {
|
||||
pointer-events: none;
|
||||
}
|
||||
.ol-overlaycontainer > *, .ol-overlaycontainer-stopevent > * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.ol-selectable {
|
||||
-webkit-touch-callout: default;
|
||||
-webkit-user-select: text;
|
||||
@@ -144,6 +150,9 @@
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
.ol-control button span {
|
||||
pointer-events: none;
|
||||
}
|
||||
.ol-zoom-extent button {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
@@ -216,15 +216,12 @@ export const checkFont = (function() {
|
||||
* @return {boolean} Font with style and weight is available
|
||||
*/
|
||||
function isAvailable(fontStyle, fontWeight, fontFamily) {
|
||||
const context = getMeasureContext();
|
||||
let available = true;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const referenceFont = referenceFonts[i];
|
||||
context.font = fontStyle + ' ' + fontWeight + ' ' + size + referenceFont;
|
||||
referenceWidth = context.measureText(text).width;
|
||||
referenceWidth = measureTextWidth(fontStyle + ' ' + fontWeight + ' ' + size + referenceFont, text);
|
||||
if (fontFamily != referenceFont) {
|
||||
context.font = fontStyle + ' ' + fontWeight + ' ' + size + fontFamily + ',' + referenceFont;
|
||||
const width = context.measureText(text).width;
|
||||
const width = measureTextWidth(fontStyle + ' ' + fontWeight + ' ' + size + fontFamily + ',' + referenceFont, text);
|
||||
// If width and referenceWidth are the same, then the fallback was used
|
||||
// instead of the font we wanted, so the font is not available.
|
||||
available = available && width != referenceWidth;
|
||||
@@ -284,17 +281,6 @@ export const checkFont = (function() {
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* @return {CanvasRenderingContext2D} Measure context.
|
||||
*/
|
||||
function getMeasureContext() {
|
||||
if (!measureContext) {
|
||||
measureContext = createCanvasContext2D(1, 1);
|
||||
}
|
||||
return measureContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} font Font to use for measuring.
|
||||
* @return {import("../size.js").Size} Measurement.
|
||||
@@ -333,7 +319,9 @@ export const measureTextHeight = (function() {
|
||||
* @return {number} Width.
|
||||
*/
|
||||
export function measureTextWidth(font, text) {
|
||||
const measureContext = getMeasureContext();
|
||||
if (!measureContext) {
|
||||
measureContext = createCanvasContext2D(1, 1);
|
||||
}
|
||||
if (font != measureFont) {
|
||||
measureContext.font = font;
|
||||
measureFont = measureContext.font;
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
} from '../../transform.js';
|
||||
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/rbush.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -52,7 +51,7 @@ const p3 = [];
|
||||
const p4 = [];
|
||||
|
||||
|
||||
class Executor extends Disposable {
|
||||
class Executor {
|
||||
/**
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
@@ -60,7 +59,6 @@ class Executor extends Disposable {
|
||||
* @param {SerializableInstructions} instructions The serializable instructions
|
||||
*/
|
||||
constructor(resolution, pixelRatio, overlaps, instructions) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
@@ -156,15 +154,6 @@ class Executor extends Disposable {
|
||||
this.widths_ = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
labelCache.release(this);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} text Text.
|
||||
* @param {string} textKey Text style key.
|
||||
|
||||
@@ -10,7 +10,6 @@ import {isEmpty} from '../../obj.js';
|
||||
import BuilderType from './BuilderType.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../../transform.js';
|
||||
import Executor from './Executor.js';
|
||||
import Disposable from '../../Disposable.js';
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -26,7 +25,7 @@ const ORDER = [
|
||||
];
|
||||
|
||||
|
||||
class ExecutorGroup extends Disposable {
|
||||
class ExecutorGroup {
|
||||
/**
|
||||
* @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a
|
||||
* `maxExtent` was set on the Buillder for this executor group, the same `maxExtent`
|
||||
@@ -40,7 +39,6 @@ class ExecutorGroup extends Disposable {
|
||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||
*/
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -128,24 +126,6 @@ class ExecutorGroup extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
for (const z in this.executorsByZIndex_) {
|
||||
const executors = this.executorsByZIndex_[z];
|
||||
for (const key in executors) {
|
||||
executors[key].disposeInternal();
|
||||
}
|
||||
}
|
||||
if (this.hitDetectionContext_) {
|
||||
const canvas = this.hitDetectionContext_.canvas;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<BuilderType>} executors Executors.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {getUid} from '../../util.js';
|
||||
import LRUCache from '../../structs/LRUCache.js';
|
||||
|
||||
/**
|
||||
@@ -11,59 +10,11 @@ import LRUCache from '../../structs/LRUCache.js';
|
||||
*/
|
||||
class LabelCache extends LRUCache {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
constructor(opt_highWaterMark) {
|
||||
super(opt_highWaterMark);
|
||||
this.consumers = {};
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.consumers = {};
|
||||
super.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {string} key Label key.
|
||||
* @param {import("./Executor.js").default} consumer Label consumer.
|
||||
* @return {HTMLCanvasElement} Label.
|
||||
*/
|
||||
get(key, consumer) {
|
||||
const canvas = super.get(key);
|
||||
const consumerId = getUid(consumer);
|
||||
if (!(consumerId in this.consumers)) {
|
||||
this.consumers[consumerId] = {};
|
||||
}
|
||||
this.consumers[consumerId][key] = true;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
prune() {
|
||||
outer:
|
||||
expireCache() {
|
||||
while (this.canExpireCache()) {
|
||||
const key = this.peekLastKey();
|
||||
for (const consumerId in this.consumers) {
|
||||
if (key in this.consumers[consumerId]) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
const canvas = this.pop();
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
for (const consumerId in this.consumers) {
|
||||
delete this.consumers[consumerId][key];
|
||||
}
|
||||
this.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./Executor.js").default} consumer Label consumer.
|
||||
*/
|
||||
release(consumer) {
|
||||
delete this.consumers[getUid(consumer)];
|
||||
}
|
||||
}
|
||||
|
||||
export default LabelCache;
|
||||
|
||||
@@ -131,8 +131,6 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
* @type {string}
|
||||
*/
|
||||
this.strokeKey_ = '';
|
||||
|
||||
labelCache.prune();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,6 +138,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
*/
|
||||
finish() {
|
||||
const instructions = super.finish();
|
||||
labelCache.expireCache();
|
||||
instructions.textStates = this.textStates;
|
||||
instructions.fillStates = this.fillStates;
|
||||
instructions.strokeStates = this.strokeStates;
|
||||
@@ -461,7 +460,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
strokeState.lineCap + strokeState.lineDashOffset + '|' + strokeState.lineWidth +
|
||||
strokeState.lineJoin + strokeState.miterLimit + '[' + strokeState.lineDash.join() + ']' :
|
||||
'';
|
||||
this.textKey_ = textState.font + textState.scale + (textState.textAlign || '?');
|
||||
this.textKey_ = textState.font + textState.scale + (textState.textAlign || '?') + (textState.textBaseline || '?');
|
||||
this.fillKey_ = fillState ?
|
||||
(typeof fillState.fillStyle == 'string' ? fillState.fillStyle : ('|' + getUid(fillState.fillStyle))) :
|
||||
'';
|
||||
|
||||
@@ -33,15 +33,18 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
const renderer = new CanvasImmediateRenderer(context, 0.5, extent, null, rotation);
|
||||
const featureCount = features.length;
|
||||
// Stretch hit detection index to use the whole available color range
|
||||
const indexFactor = Math.ceil((256 * 256 * 256) / featureCount);
|
||||
const indexFactor = Math.ceil((256 * 256 * 256 - 1) / featureCount);
|
||||
const featuresByZIndex = {};
|
||||
for (let i = 0; i < featureCount; ++i) {
|
||||
const feature = features[i];
|
||||
for (let i = 1; i <= featureCount; ++i) {
|
||||
const feature = features[i - 1];
|
||||
const featureStyleFunction = feature.getStyleFunction() || styleFunction;
|
||||
if (!styleFunction) {
|
||||
continue;
|
||||
}
|
||||
let styles = featureStyleFunction(feature, resolution);
|
||||
if (!styles) {
|
||||
continue;
|
||||
}
|
||||
if (!Array.isArray(styles)) {
|
||||
styles = [styles];
|
||||
}
|
||||
@@ -138,9 +141,9 @@ export function hitDetect(pixel, features, imageData) {
|
||||
const g = imageData.data[index + 1];
|
||||
const b = imageData.data[index + 2];
|
||||
const i = b + (256 * (g + (256 * r)));
|
||||
const indexFactor = Math.ceil((256 * 256 * 256) / features.length);
|
||||
if (i % indexFactor === 0) {
|
||||
resultFeatures.push(features[i / indexFactor]);
|
||||
const indexFactor = Math.ceil((256 * 256 * 256 - 1) / features.length);
|
||||
if (i && i % indexFactor === 0) {
|
||||
resultFeatures.push(features[i / indexFactor - 1]);
|
||||
}
|
||||
}
|
||||
return resultFeatures;
|
||||
|
||||
@@ -74,6 +74,7 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
|
||||
disposeInternal() {
|
||||
unlistenByKey(this.labelCacheKey_);
|
||||
this.element_.parentNode.removeChild(this.element_);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
|
||||