Merge remote-tracking branch 'origin/master' into fix_triangulation

Conflicts:
	src/ol/TileCache.js
This commit is contained in:
philip
2020-01-11 17:36:40 +00:00
139 changed files with 10057 additions and 2161 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

@@ -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">

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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],

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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
})
})
],

View File

@@ -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">&nbsp;</div>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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
})
});

View File

@@ -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">

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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({

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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();
}

View File

@@ -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%">

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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();
});

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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
View 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>

View File

@@ -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()

View File

@@ -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;

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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

View File

@@ -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">

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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({

View File

@@ -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({

View File

@@ -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

View File

@@ -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({

View File

@@ -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">

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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
})
});

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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
View File

@@ -0,0 +1,7 @@
#map {
background: black;
}
.svg-layer path:hover {
opacity: 0.4;
}

9
examples/svg-layer.html Normal file
View 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
View 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;
}
}));

View File

@@ -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">

View 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>

View 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
})
});

View File

@@ -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>

View File

@@ -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();
});
});

View File

@@ -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>

View File

@@ -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();

View File

@@ -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));

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">&copy; MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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

File diff suppressed because it is too large Load Diff

View File

@@ -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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View 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
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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() {
}
/**

View File

@@ -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));
}

View File

@@ -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_();
}
}
}

View File

@@ -14,6 +14,5 @@ export default {
* @type {number}
*/
ERROR: 3,
EMPTY: 4,
ABORT: 5
EMPTY: 4
};

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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';
/**

View File

@@ -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_();
}
/**

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -34,5 +34,6 @@ export default {
KEYPRESS: 'keypress',
LOAD: 'load',
RESIZE: 'resize',
TOUCHMOVE: 'touchmove',
WHEEL: 'wheel'
};

View File

@@ -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';
};

View File

@@ -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;
}

View File

@@ -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();
}
/**

View File

@@ -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));
}

View File

@@ -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;
})();

View File

@@ -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_);

View File

@@ -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;

View File

@@ -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;
}
);

View File

@@ -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) -

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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)
}
}
]

View File

@@ -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

View File

@@ -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'
};

View File

@@ -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.
*/

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;

View File

@@ -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))) :
'';

View File

@@ -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;

View File

@@ -74,6 +74,7 @@ class CompositeMapRenderer extends MapRenderer {
disposeInternal() {
unlistenByKey(this.labelCacheKey_);
this.element_.parentNode.removeChild(this.element_);
super.disposeInternal();
}

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