Compare commits
13 Commits
v6.0.0-bet
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e2dc5d20c | ||
|
|
8899c3e3c5 | ||
|
|
10a2b718f5 | ||
|
|
c72f699c90 | ||
|
|
16e132caea | ||
|
|
070c1ec029 | ||
|
|
21c26cabed | ||
|
|
0f73f16cfa | ||
|
|
dfa8506549 | ||
|
|
8fb6ed5c6f | ||
|
|
c6a859d1ed | ||
|
|
b955579a9c | ||
|
|
56f37ab347 |
45717
examples/data/csv/meteorite_landings.csv
Normal file
45717
examples/data/csv/meteorite_landings.csv
Normal file
File diff suppressed because it is too large
Load Diff
25
examples/filter-points-webgl.html
Normal file
25
examples/filter-points-webgl.html
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: Filtering features with WebGL
|
||||||
|
shortdesc: Using WebGL to filter large quantities of features
|
||||||
|
docs: >
|
||||||
|
This example shows how to use `ol/renderer/webgl/PointsLayer` to dynamically filter a large amount
|
||||||
|
of point geometries. The above map is based on a dataset from the NASA containing 45k recorded meteorite
|
||||||
|
landing sites. Each meteorite is marked by a circle on the map (the bigger the circle, the heavier
|
||||||
|
the object). A pulse effect has been added, which is slightly offset by the year of the impact.
|
||||||
|
|
||||||
|
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done using
|
||||||
|
a custom fragment shader on the layer renderer, and by using the `v_opacity` attribute of the rendered objects
|
||||||
|
to store the year of impact.
|
||||||
|
|
||||||
|
tags: "webgl, icon, sprite, filter, feature"
|
||||||
|
---
|
||||||
|
<div id="map" class="map"></div>
|
||||||
|
<form>
|
||||||
|
<div id="status">Show impacts between <span class="min-year"></span> and <span class="max-year"></span></div>
|
||||||
|
|
||||||
|
<label>Minimum year:</label>
|
||||||
|
<input id="min-year" type="range" min="1850" max="2015" step="1" value="1850"/>
|
||||||
|
<label>Maximum year:</label>
|
||||||
|
<input id="max-year" type="range" min="1850" max="2015" step="1" value="2015"/>
|
||||||
|
</form>
|
||||||
162
examples/filter-points-webgl.js
Normal file
162
examples/filter-points-webgl.js
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
|
import Feature from '../src/ol/Feature';
|
||||||
|
import Point from '../src/ol/geom/Point';
|
||||||
|
import VectorLayer from '../src/ol/layer/Vector';
|
||||||
|
import {Vector} from '../src/ol/source';
|
||||||
|
import {fromLonLat} from '../src/ol/proj';
|
||||||
|
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
|
||||||
|
import {clamp, lerp} from '../src/ol/math';
|
||||||
|
import Stamen from '../src/ol/source/Stamen';
|
||||||
|
|
||||||
|
const features = [];
|
||||||
|
const vectorSource = new Vector({
|
||||||
|
features: [],
|
||||||
|
attributions: 'NASA'
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldColor = [180, 140, 140];
|
||||||
|
const newColor = [255, 80, 80];
|
||||||
|
|
||||||
|
const startTime = Date.now() * 0.001;
|
||||||
|
|
||||||
|
// hanle input values & events
|
||||||
|
const minYearInput = document.getElementById('min-year');
|
||||||
|
const maxYearInput = document.getElementById('max-year');
|
||||||
|
function updateStatusText() {
|
||||||
|
const div = document.getElementById('status');
|
||||||
|
div.querySelector('span.min-year').textContent = minYearInput.value;
|
||||||
|
div.querySelector('span.max-year').textContent = maxYearInput.value;
|
||||||
|
}
|
||||||
|
minYearInput.addEventListener('input', updateStatusText);
|
||||||
|
minYearInput.addEventListener('change', updateStatusText);
|
||||||
|
maxYearInput.addEventListener('input', updateStatusText);
|
||||||
|
maxYearInput.addEventListener('change', updateStatusText);
|
||||||
|
updateStatusText();
|
||||||
|
|
||||||
|
class WebglPointsLayer extends VectorLayer {
|
||||||
|
createRenderer() {
|
||||||
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
|
colorCallback: function(feature, vertex, component) {
|
||||||
|
// component at index 3 is alpha
|
||||||
|
if (component === 3) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// color is interpolated based on year
|
||||||
|
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
|
||||||
|
return lerp(oldColor[component], newColor[component], ratio) / 255;
|
||||||
|
},
|
||||||
|
sizeCallback: function(feature) {
|
||||||
|
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
||||||
|
},
|
||||||
|
fragmentShader: [
|
||||||
|
'precision mediump float;',
|
||||||
|
|
||||||
|
'uniform float u_time;',
|
||||||
|
'uniform float u_minYear;',
|
||||||
|
'uniform float u_maxYear;',
|
||||||
|
|
||||||
|
'varying vec2 v_texCoord;',
|
||||||
|
'varying float v_opacity;',
|
||||||
|
'varying vec4 v_color;',
|
||||||
|
|
||||||
|
'void main(void) {',
|
||||||
|
' float impactYear = v_opacity;',
|
||||||
|
|
||||||
|
// filter out pixels if the year is outside of the given range
|
||||||
|
' if (impactYear < u_minYear || v_opacity > u_maxYear) {',
|
||||||
|
' discard;',
|
||||||
|
' }',
|
||||||
|
|
||||||
|
' vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);',
|
||||||
|
' float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;',
|
||||||
|
' float value = 2.0 * (1.0 - sqRadius);',
|
||||||
|
' float alpha = smoothstep(0.0, 1.0, value);',
|
||||||
|
|
||||||
|
' vec3 color = v_color.rgb;',
|
||||||
|
' float period = 8.0;',
|
||||||
|
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + impactYear * 0.025, period) / period));',
|
||||||
|
|
||||||
|
' gl_FragColor = vec4(color, v_color.a);',
|
||||||
|
' gl_FragColor.a *= alpha;',
|
||||||
|
' gl_FragColor.rgb *= gl_FragColor.a;',
|
||||||
|
'}'
|
||||||
|
].join(' '),
|
||||||
|
opacityCallback: function(feature) {
|
||||||
|
// here the opacity channel of the vertices is used to store the year of impact
|
||||||
|
return feature.get('year');
|
||||||
|
},
|
||||||
|
uniforms: {
|
||||||
|
u_time: function() {
|
||||||
|
return Date.now() * 0.001 - startTime;
|
||||||
|
},
|
||||||
|
u_minYear: function() {
|
||||||
|
return parseInt(minYearInput.value);
|
||||||
|
},
|
||||||
|
u_maxYear: function() {
|
||||||
|
return parseInt(maxYearInput.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
const client = new XMLHttpRequest();
|
||||||
|
client.open('GET', 'data/csv/meteorite_landings.csv');
|
||||||
|
client.onload = function() {
|
||||||
|
const csv = client.responseText;
|
||||||
|
let curIndex;
|
||||||
|
let prevIndex = 0;
|
||||||
|
let line;
|
||||||
|
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
|
||||||
|
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||||
|
prevIndex = curIndex + 1;
|
||||||
|
|
||||||
|
// skip header
|
||||||
|
if (prevIndex === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||||
|
|
||||||
|
features.push(new Feature({
|
||||||
|
mass: parseFloat(line[1]) || 0,
|
||||||
|
year: parseInt(line[2]) || 0,
|
||||||
|
geometry: new Point(coords)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
vectorSource.addFeatures(features);
|
||||||
|
};
|
||||||
|
client.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new Stamen({
|
||||||
|
layer: 'toner'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new WebglPointsLayer({
|
||||||
|
source: vectorSource
|
||||||
|
})
|
||||||
|
],
|
||||||
|
target: document.getElementById('map'),
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 2
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// animate the map
|
||||||
|
function animate() {
|
||||||
|
map.render();
|
||||||
|
window.requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
animate();
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ol",
|
"name": "ol",
|
||||||
"version": "6.0.0-beta.4",
|
"version": "6.0.0-beta.5",
|
||||||
"description": "OpenLayers mapping library",
|
"description": "OpenLayers mapping library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"map",
|
"map",
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^4.0.0-rc.2",
|
"karma-webpack": "^4.0.0-rc.2",
|
||||||
"loglevelnext": "^3.0.0",
|
"loglevelnext": "^3.0.0",
|
||||||
"marked": "0.6.1",
|
"marked": "0.6.2",
|
||||||
"mocha": "6.0.2",
|
"mocha": "6.0.2",
|
||||||
"ol-mapbox-style": "^4.2.1",
|
"ol-mapbox-style": "^4.2.1",
|
||||||
"pixelmatch": "^4.0.2",
|
"pixelmatch": "^4.0.2",
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ class Tile extends EventTarget {
|
|||||||
// cleaned up by refreshInterimChain)
|
// cleaned up by refreshInterimChain)
|
||||||
do {
|
do {
|
||||||
if (tile.getState() == TileState.LOADED) {
|
if (tile.getState() == TileState.LOADED) {
|
||||||
|
// Show tile immediately instead of fading it in after loading, because
|
||||||
|
// the interim tile is in place already
|
||||||
|
this.transition_ = 0;
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
tile = tile.interimTile;
|
tile = tile.interimTile;
|
||||||
|
|||||||
@@ -284,8 +284,6 @@ class View extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
this.updateAnimationKey_;
|
this.updateAnimationKey_;
|
||||||
|
|
||||||
this.updateAnimations_ = this.updateAnimations_.bind(this);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @const
|
* @const
|
||||||
@@ -452,6 +450,17 @@ class View extends BaseObject {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
animate(var_args) {
|
animate(var_args) {
|
||||||
|
if (this.isDef() && !this.getAnimating()) {
|
||||||
|
this.resolveConstraints(0);
|
||||||
|
}
|
||||||
|
this.animate_.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {...(AnimationOptions|function(boolean): void)} var_args Animation options.
|
||||||
|
*/
|
||||||
|
animate_(var_args) {
|
||||||
let animationCount = arguments.length;
|
let animationCount = arguments.length;
|
||||||
let callback;
|
let callback;
|
||||||
if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {
|
if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {
|
||||||
@@ -641,11 +650,7 @@ class View extends BaseObject {
|
|||||||
// prune completed series
|
// prune completed series
|
||||||
this.animations_ = this.animations_.filter(Boolean);
|
this.animations_ = this.animations_.filter(Boolean);
|
||||||
if (more && this.updateAnimationKey_ === undefined) {
|
if (more && this.updateAnimationKey_ === undefined) {
|
||||||
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);
|
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_.bind(this));
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.getAnimating()) {
|
|
||||||
setTimeout(this.resolveConstraints.bind(this), 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1085,7 +1090,7 @@ class View extends BaseObject {
|
|||||||
const callback = options.callback ? options.callback : VOID;
|
const callback = options.callback ? options.callback : VOID;
|
||||||
|
|
||||||
if (options.duration !== undefined) {
|
if (options.duration !== undefined) {
|
||||||
this.animate({
|
this.animate_({
|
||||||
resolution: resolution,
|
resolution: resolution,
|
||||||
center: this.getConstrainedCenter(center, resolution),
|
center: this.getConstrainedCenter(center, resolution),
|
||||||
duration: options.duration,
|
duration: options.duration,
|
||||||
@@ -1312,7 +1317,7 @@ class View extends BaseObject {
|
|||||||
this.cancelAnimations();
|
this.cancelAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.animate({
|
this.animate_({
|
||||||
rotation: newRotation,
|
rotation: newRotation,
|
||||||
center: newCenter,
|
center: newCenter,
|
||||||
resolution: newResolution,
|
resolution: newResolution,
|
||||||
@@ -1325,9 +1330,13 @@ class View extends BaseObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the View that an interaction has started.
|
* Notify the View that an interaction has started.
|
||||||
|
* The view state will be resolved to a stable one if needed
|
||||||
|
* (depending on its constraints).
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
beginInteraction() {
|
beginInteraction() {
|
||||||
|
this.resolveConstraints(0);
|
||||||
|
|
||||||
this.setHint(ViewHint.INTERACTING, 1);
|
this.setHint(ViewHint.INTERACTING, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export function pan(view, delta, opt_duration) {
|
|||||||
const currentCenter = view.getCenter();
|
const currentCenter = view.getCenter();
|
||||||
if (currentCenter) {
|
if (currentCenter) {
|
||||||
const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
|
const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
|
||||||
view.animate({
|
view.animate_({
|
||||||
duration: opt_duration !== undefined ? opt_duration : 250,
|
duration: opt_duration !== undefined ? opt_duration : 250,
|
||||||
easing: linear,
|
easing: linear,
|
||||||
center: view.getConstrainedCenter(center)
|
center: view.getConstrainedCenter(center)
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ class Heatmap extends VectorLayer {
|
|||||||
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
|
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
|
||||||
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
|
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
|
||||||
float alpha = smoothstep(0.0, 1.0, value) * v_opacity;
|
float alpha = smoothstep(0.0, 1.0, value) * v_opacity;
|
||||||
gl_FragColor = vec4(1.0, 1.0, 1.0, alpha);
|
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
|
||||||
}`,
|
}`,
|
||||||
uniforms: {
|
uniforms: {
|
||||||
u_size: function() {
|
u_size: function() {
|
||||||
|
|||||||
@@ -110,8 +110,7 @@ const FRAGMENT_SHADER = `
|
|||||||
*
|
*
|
||||||
* The following uniform is used for the main texture: `u_texture`.
|
* The following uniform is used for the main texture: `u_texture`.
|
||||||
*
|
*
|
||||||
* Please note that the main shader output should have premultiplied alpha, otherwise the colors will be blended
|
* Please note that the main shader output should have premultiplied alpha, otherwise visual anomalies may occur.
|
||||||
* additively.
|
|
||||||
*
|
*
|
||||||
* Points are rendered as quads with the following structure:
|
* Points are rendered as quads with the following structure:
|
||||||
*
|
*
|
||||||
@@ -323,6 +322,9 @@ class WebGLPointsLayerRenderer extends LayerRenderer {
|
|||||||
baseIndex + 1, baseIndex + 2, baseIndex + 3
|
baseIndex + 1, baseIndex + 2, baseIndex + 3
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_);
|
||||||
|
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write new data
|
// write new data
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import {getContext} from '../webgl';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} BufferCacheEntry
|
* @typedef {Object} BufferCacheEntry
|
||||||
* @property {import("./Buffer.js").default} buf
|
* @property {import("./Buffer.js").default} buffer
|
||||||
* @property {WebGLBuffer} buffer
|
* @property {WebGLBuffer} webGlBuffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,15 +153,24 @@ export const DefaultAttrib = {
|
|||||||
* ### Binding WebGL buffers and flushing data into them:
|
* ### Binding WebGL buffers and flushing data into them:
|
||||||
*
|
*
|
||||||
* Data that must be passed to the GPU has to be transferred using `WebGLArrayBuffer` objects.
|
* Data that must be passed to the GPU has to be transferred using `WebGLArrayBuffer` objects.
|
||||||
* A buffer has to be created only once, but must be bound everytime the data it holds is changed. Using `WebGLHelper.bindBuffer`
|
* A buffer has to be created only once, but must be bound everytime the buffer content should be used for rendering.
|
||||||
* will bind the buffer and flush the new data to the GPU.
|
* This is done using `WebGLHelper.bindBuffer`.
|
||||||
|
* When the buffer's array content has changed, the new data has to be flushed to the GPU memory; this is done using
|
||||||
|
* `WebGLHelper.flushBufferData`. Note: this operation is expensive and should be done as infrequently as possible.
|
||||||
*
|
*
|
||||||
* For now, the `WebGLHelper` class expects {@link module:ol/webgl/Buffer~WebGLArrayBuffer} objects.
|
* When binding a `WebGLArrayBuffer`, a `target` parameter must be given: it should be either {@link module:ol/webgl~ARRAY_BUFFER}
|
||||||
|
* (if the buffer contains vertices data) or {@link module:ol/webgl~ELEMENT_ARRAY_BUFFER} (if the buffer contains indices data).
|
||||||
|
*
|
||||||
|
* Examples below:
|
||||||
* ```js
|
* ```js
|
||||||
* // at initialization phase
|
* // at initialization phase
|
||||||
* this.verticesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW);
|
* this.verticesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW);
|
||||||
* this.indicesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW);
|
* this.indicesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW);
|
||||||
*
|
*
|
||||||
|
* // when array values have changed
|
||||||
|
* this.context.flushBufferData(ARRAY_BUFFER, this.verticesBuffer);
|
||||||
|
* this.context.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||||
|
*
|
||||||
* // at rendering phase
|
* // at rendering phase
|
||||||
* this.context.bindBuffer(ARRAY_BUFFER, this.verticesBuffer);
|
* this.context.bindBuffer(ARRAY_BUFFER, this.verticesBuffer);
|
||||||
* this.context.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
* this.context.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||||
@@ -342,24 +351,35 @@ class WebGLHelper extends Disposable {
|
|||||||
* Just bind the buffer if it's in the cache. Otherwise create
|
* Just bind the buffer if it's in the cache. Otherwise create
|
||||||
* the WebGL buffer, bind it, populate it, and add an entry to
|
* the WebGL buffer, bind it, populate it, and add an entry to
|
||||||
* the cache.
|
* the cache.
|
||||||
* TODO: improve this, the logic is unclear: we want A/ to bind a buffer and B/ to flush data in it
|
* @param {number} target Target, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
|
||||||
* @param {number} target Target.
|
* @param {import("./Buffer").default} buffer Buffer.
|
||||||
* @param {import("./Buffer").default} buf Buffer.
|
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
bindBuffer(target, buf) {
|
bindBuffer(target, buffer) {
|
||||||
const gl = this.getGL();
|
const gl = this.getGL();
|
||||||
const arr = buf.getArray();
|
const bufferKey = getUid(buffer);
|
||||||
const bufferKey = getUid(buf);
|
|
||||||
let bufferCache = this.bufferCache_[bufferKey];
|
let bufferCache = this.bufferCache_[bufferKey];
|
||||||
if (!bufferCache) {
|
if (!bufferCache) {
|
||||||
const buffer = gl.createBuffer();
|
const webGlBuffer = gl.createBuffer();
|
||||||
bufferCache = this.bufferCache_[bufferKey] = {
|
bufferCache = this.bufferCache_[bufferKey] = {
|
||||||
buf: buf,
|
buffer: buffer,
|
||||||
buffer: buffer
|
webGlBuffer: webGlBuffer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
gl.bindBuffer(target, bufferCache.buffer);
|
gl.bindBuffer(target, bufferCache.webGlBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the data contained in the buffer array; this is required for the
|
||||||
|
* new data to be rendered
|
||||||
|
* @param {number} target Target, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
|
||||||
|
* @param {import("./Buffer").default} buffer Buffer.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
flushBufferData(target, buffer) {
|
||||||
|
const gl = this.getGL();
|
||||||
|
const arr = buffer.getArray();
|
||||||
|
this.bindBuffer(target, buffer);
|
||||||
let /** @type {ArrayBufferView} */ arrayBuffer;
|
let /** @type {ArrayBufferView} */ arrayBuffer;
|
||||||
if (target == ARRAY_BUFFER) {
|
if (target == ARRAY_BUFFER) {
|
||||||
arrayBuffer = new Float32Array(arr);
|
arrayBuffer = new Float32Array(arr);
|
||||||
@@ -367,7 +387,7 @@ class WebGLHelper extends Disposable {
|
|||||||
arrayBuffer = this.hasOESElementIndexUint ?
|
arrayBuffer = this.hasOESElementIndexUint ?
|
||||||
new Uint32Array(arr) : new Uint16Array(arr);
|
new Uint32Array(arr) : new Uint16Array(arr);
|
||||||
}
|
}
|
||||||
gl.bufferData(target, arrayBuffer, buf.getUsage());
|
gl.bufferData(target, arrayBuffer, buffer.getUsage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ const DEFAULT_FRAGMENT_SHADER = `
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_FragColor = texture2D(u_image, v_texCoord);
|
gl_FragColor = texture2D(u_image, v_texCoord);
|
||||||
gl_FragColor.rgb *= gl_FragColor.a;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -59,6 +58,9 @@ const DEFAULT_FRAGMENT_SHADER = `
|
|||||||
* a pixel which is 100% red with an opacity of 50% must have a color of (r=0.5, g=0, b=0, a=0.5).
|
* a pixel which is 100% red with an opacity of 50% must have a color of (r=0.5, g=0, b=0, a=0.5).
|
||||||
* Failing to provide pixel colors with premultiplied alpha will result in render anomalies.
|
* Failing to provide pixel colors with premultiplied alpha will result in render anomalies.
|
||||||
*
|
*
|
||||||
|
* The default post-processing pass does *not* multiply color values with alpha value, it expects color values to be
|
||||||
|
* premultiplied.
|
||||||
|
*
|
||||||
* Default shaders are shown hereafter:
|
* Default shaders are shown hereafter:
|
||||||
*
|
*
|
||||||
* * Vertex shader:
|
* * Vertex shader:
|
||||||
@@ -91,7 +93,6 @@ const DEFAULT_FRAGMENT_SHADER = `
|
|||||||
*
|
*
|
||||||
* void main() {
|
* void main() {
|
||||||
* gl_FragColor = texture2D(u_image, v_texCoord);
|
* gl_FragColor = texture2D(u_image, v_texCoord);
|
||||||
* gl_FragColor.rgb *= gl_FragColor.a;
|
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ describe('ol.interaction.KeyboardPan', function() {
|
|||||||
describe('handleEvent()', function() {
|
describe('handleEvent()', function() {
|
||||||
it('pans on arrow keys', function() {
|
it('pans on arrow keys', function() {
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
const spy = sinon.spy(view, 'animate');
|
const spy = sinon.spy(view, 'animate_');
|
||||||
const event = new MapBrowserEvent('keydown', map, {
|
const event = new MapBrowserEvent('keydown', map, {
|
||||||
type: 'keydown',
|
type: 'keydown',
|
||||||
target: map.getTargetElement(),
|
target: map.getTargetElement(),
|
||||||
@@ -51,7 +51,7 @@ describe('ol.interaction.KeyboardPan', function() {
|
|||||||
expect(spy.getCall(3).args[0].center).to.eql([128, 0]);
|
expect(spy.getCall(3).args[0].center).to.eql([128, 0]);
|
||||||
view.setCenter([0, 0]);
|
view.setCenter([0, 0]);
|
||||||
|
|
||||||
view.animate.restore();
|
view.animate_.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,13 +41,18 @@ describe('ol.renderer.canvas.TileLayer', function() {
|
|||||||
document.body.removeChild(target);
|
document.body.removeChild(target);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('properly handles interim tiles', function() {
|
it('properly handles interim tiles', function(done) {
|
||||||
const layer = map.getLayers().item(0);
|
const layer = map.getLayers().item(0);
|
||||||
|
source.once('tileloadend', function(e) {
|
||||||
|
expect(e.tile.inTransition()).to.be(false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
source.updateParams({TIME: '1'});
|
source.updateParams({TIME: '1'});
|
||||||
map.renderSync();
|
map.renderSync();
|
||||||
const tiles = map.getRenderer().getLayerRenderer(layer).renderedTiles;
|
const tiles = map.getRenderer().getLayerRenderer(layer).renderedTiles;
|
||||||
expect(tiles.length).to.be(1);
|
expect(tiles.length).to.be(1);
|
||||||
expect(tiles[0]).to.equal(tile);
|
expect(tiles[0]).to.equal(tile);
|
||||||
|
expect(tile.inTransition()).to.be(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1801,6 +1801,52 @@ describe('ol.View', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('does not start unexpected animations during interaction', function() {
|
||||||
|
let map;
|
||||||
|
beforeEach(function() {
|
||||||
|
map = new Map({
|
||||||
|
target: createMapDiv(512, 256)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
disposeMap(map);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works when initialized with #setCenter() and #setZoom()', function(done) {
|
||||||
|
const view = map.getView();
|
||||||
|
let callCount = 0;
|
||||||
|
view.on('change:resolution', function() {
|
||||||
|
++callCount;
|
||||||
|
});
|
||||||
|
view.setCenter([0, 0]);
|
||||||
|
view.setZoom(0);
|
||||||
|
view.beginInteraction();
|
||||||
|
view.endInteraction();
|
||||||
|
setTimeout(function() {
|
||||||
|
expect(callCount).to.be(1);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works when initialized with #animate()', function(done) {
|
||||||
|
const view = map.getView();
|
||||||
|
let callCount = 0;
|
||||||
|
view.on('change:resolution', function() {
|
||||||
|
++callCount;
|
||||||
|
});
|
||||||
|
view.animate({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 0
|
||||||
|
});
|
||||||
|
view.beginInteraction();
|
||||||
|
view.endInteraction();
|
||||||
|
setTimeout(function() {
|
||||||
|
expect(callCount).to.be(1);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('ol.View.isNoopAnimation()', function() {
|
describe('ol.View.isNoopAnimation()', function() {
|
||||||
|
|
||||||
const cases = [{
|
const cases = [{
|
||||||
|
|||||||
Reference in New Issue
Block a user