Add background to MapboxVector layer
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
.map {
|
|
||||||
background: #f8f4f0;
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,17 @@
|
|||||||
*/
|
*/
|
||||||
import BaseEvent from '../events/Event.js';
|
import BaseEvent from '../events/Event.js';
|
||||||
import EventType from '../events/EventType.js';
|
import EventType from '../events/EventType.js';
|
||||||
|
import GeometryType from '../geom/GeometryType.js';
|
||||||
import MVT from '../format/MVT.js';
|
import MVT from '../format/MVT.js';
|
||||||
|
import RenderFeature from '../render/Feature.js';
|
||||||
import SourceState from '../source/State.js';
|
import SourceState from '../source/State.js';
|
||||||
|
import TileEventType from '../source/TileEventType.js';
|
||||||
import VectorTileLayer from '../layer/VectorTile.js';
|
import VectorTileLayer from '../layer/VectorTile.js';
|
||||||
import VectorTileSource from '../source/VectorTile.js';
|
import VectorTileSource from '../source/VectorTile.js';
|
||||||
|
import {Fill, Style} from '../style.js';
|
||||||
import {applyStyle, setupVectorSource} from 'ol-mapbox-style';
|
import {applyStyle, setupVectorSource} from 'ol-mapbox-style';
|
||||||
|
import {fromExtent} from '../geom/Polygon.js';
|
||||||
|
import {getValue} from 'ol-mapbox-style/dist/stylefunction.js';
|
||||||
|
|
||||||
const mapboxBaseUrl = 'https://api.mapbox.com';
|
const mapboxBaseUrl = 'https://api.mapbox.com';
|
||||||
|
|
||||||
@@ -153,7 +159,10 @@ const SourceType = {
|
|||||||
/**
|
/**
|
||||||
* @typedef {Object} LayerObject
|
* @typedef {Object} LayerObject
|
||||||
* @property {string} id The layer id.
|
* @property {string} id The layer id.
|
||||||
|
* @property {string} type The layer type.
|
||||||
* @property {string} source The source id.
|
* @property {string} source The source id.
|
||||||
|
* @property {Object} layout The layout.
|
||||||
|
* @property {Object} paint The paint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,6 +300,7 @@ class MapboxVectorLayer extends VectorTileLayer {
|
|||||||
|
|
||||||
this.sourceId = options.source;
|
this.sourceId = options.source;
|
||||||
this.layers = options.layers;
|
this.layers = options.layers;
|
||||||
|
|
||||||
if (options.accessToken) {
|
if (options.accessToken) {
|
||||||
this.accessToken = options.accessToken;
|
this.accessToken = options.accessToken;
|
||||||
} else {
|
} else {
|
||||||
@@ -409,7 +419,7 @@ class MapboxVectorLayer extends VectorTileLayer {
|
|||||||
);
|
);
|
||||||
applyStyle(this, style, sourceIdOrLayersList)
|
applyStyle(this, style, sourceIdOrLayersList)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
source.setState(SourceState.READY);
|
this.configureSource(source, style);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.handleError(error);
|
this.handleError(error);
|
||||||
@@ -431,16 +441,87 @@ class MapboxVectorLayer extends VectorTileLayer {
|
|||||||
).then((source) => {
|
).then((source) => {
|
||||||
applyStyle(this, style, sourceIdOrLayersList)
|
applyStyle(this, style, sourceIdOrLayersList)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setSource(source);
|
this.configureSource(source, style);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.setSource(source);
|
this.configureSource(source, style);
|
||||||
this.handleError(error);
|
this.handleError(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies configuration from the provided source to this layer's source,
|
||||||
|
* and reconfigures the loader to add a feature that renders the background,
|
||||||
|
* if the style is configured with a background.
|
||||||
|
* @param {import("../source/VectorTile.js").default} source The source to configure from.
|
||||||
|
* @param {StyleObject} style The style to configure the background from.
|
||||||
|
*/
|
||||||
|
configureSource(source, style) {
|
||||||
|
const targetSource = this.getSource();
|
||||||
|
if (source !== targetSource) {
|
||||||
|
targetSource.setAttributions(source.getAttributions());
|
||||||
|
targetSource.setTileUrlFunction(source.getTileUrlFunction());
|
||||||
|
targetSource.setTileLoadFunction(source.getTileLoadFunction());
|
||||||
|
targetSource.tileGrid = source.tileGrid;
|
||||||
|
}
|
||||||
|
const background = style.layers.find(
|
||||||
|
(layer) => layer.type === 'background'
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!background ||
|
||||||
|
!background.layout ||
|
||||||
|
background.layout.visibility !== 'none'
|
||||||
|
) {
|
||||||
|
const style = new Style({
|
||||||
|
fill: new Fill(),
|
||||||
|
});
|
||||||
|
targetSource.addEventListener(TileEventType.TILELOADEND, (event) => {
|
||||||
|
const tile = /** @type {import("../VectorTile.js").default} */ (
|
||||||
|
/** @type {import("../source/Tile.js").TileSourceEvent} */ (event)
|
||||||
|
.tile
|
||||||
|
);
|
||||||
|
const styleFuntion = () => {
|
||||||
|
const opacity =
|
||||||
|
/** @type {number} */ (
|
||||||
|
getValue(
|
||||||
|
background,
|
||||||
|
'paint',
|
||||||
|
'background-opacity',
|
||||||
|
tile.tileCoord[0]
|
||||||
|
)
|
||||||
|
) || 1;
|
||||||
|
const color = /** @type {*} */ (
|
||||||
|
getValue(background, 'paint', 'background-color', tile.tileCoord[0])
|
||||||
|
);
|
||||||
|
style
|
||||||
|
.getFill()
|
||||||
|
.setColor([
|
||||||
|
color.r * 255,
|
||||||
|
color.g * 255,
|
||||||
|
color.b * 255,
|
||||||
|
color.a * opacity,
|
||||||
|
]);
|
||||||
|
return style;
|
||||||
|
};
|
||||||
|
const extentGeometry = fromExtent(
|
||||||
|
targetSource.tileGrid.getTileCoordExtent(tile.tileCoord)
|
||||||
|
);
|
||||||
|
const renderFeature = new RenderFeature(
|
||||||
|
GeometryType.POLYGON,
|
||||||
|
extentGeometry.getFlatCoordinates(),
|
||||||
|
extentGeometry.getEnds(),
|
||||||
|
{layer: background.id},
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
renderFeature.styleFunction = styleFuntion;
|
||||||
|
tile.getFeatures().unshift(renderFeature);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
targetSource.setState(SourceState.READY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle configuration or loading error.
|
* Handle configuration or loading error.
|
||||||
* @param {Error} error The error.
|
* @param {Error} error The error.
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ class RenderFeature {
|
|||||||
* @param {number|string|undefined} id Feature id.
|
* @param {number|string|undefined} id Feature id.
|
||||||
*/
|
*/
|
||||||
constructor(type, flatCoordinates, ends, properties, id) {
|
constructor(type, flatCoordinates, ends, properties, id) {
|
||||||
|
/**
|
||||||
|
* @type {import("../style/Style.js").StyleFunction|undefined}
|
||||||
|
*/
|
||||||
|
this.styleFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("../extent.js").Extent|undefined}
|
* @type {import("../extent.js").Extent|undefined}
|
||||||
@@ -259,10 +264,10 @@ class RenderFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {undefined}
|
* @return {import('../style/Style.js').StyleFunction|undefined} Style
|
||||||
*/
|
*/
|
||||||
getStyleFunction() {
|
getStyleFunction() {
|
||||||
return undefined;
|
return this.styleFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ class TileSource extends Source {
|
|||||||
options.tilePixelRatio !== undefined ? options.tilePixelRatio : 1;
|
options.tilePixelRatio !== undefined ? options.tilePixelRatio : 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
|
||||||
* @type {import("../tilegrid/TileGrid.js").default}
|
* @type {import("../tilegrid/TileGrid.js").default}
|
||||||
*/
|
*/
|
||||||
this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;
|
this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import MapboxVectorLayer, {
|
|||||||
normalizeSpriteUrl,
|
normalizeSpriteUrl,
|
||||||
normalizeStyleUrl,
|
normalizeStyleUrl,
|
||||||
} from '../../../../../src/ol/layer/MapboxVector.js';
|
} from '../../../../../src/ol/layer/MapboxVector.js';
|
||||||
|
import {get} from '../../../../../src/ol/proj.js';
|
||||||
|
import {unByKey} from '../../../../../src/ol/Observable.js';
|
||||||
|
|
||||||
describe('ol/layer/MapboxVector', () => {
|
describe('ol/layer/MapboxVector', () => {
|
||||||
describe('getMapboxPath()', () => {
|
describe('getMapboxPath()', () => {
|
||||||
@@ -112,13 +114,67 @@ describe('ol/layer/MapboxVector', () => {
|
|||||||
type: 'vector',
|
type: 'vector',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
layers: [],
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
layer.on('change:source', function () {
|
const source = layer.getSource();
|
||||||
// we only get here when a new source was set, which is what ol-mapbox-style's
|
const key = source.on('change', function () {
|
||||||
// setupVectorSource() does.
|
if (source.getState() === 'ready') {
|
||||||
done();
|
unByKey(key);
|
||||||
|
expect(source.getTileUrlFunction()([0, 0, 0])).to.be(
|
||||||
|
'http://a.tiles.mapbox.com/v3/mapbox.geography-class/0/0/0.png'
|
||||||
|
);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('background', function () {
|
||||||
|
it('adds a feature for the background', function (done) {
|
||||||
|
const layer = new MapboxVectorLayer({
|
||||||
|
styleUrl:
|
||||||
|
'data:,' +
|
||||||
|
encodeURIComponent(
|
||||||
|
JSON.stringify({
|
||||||
|
version: 8,
|
||||||
|
sources: {
|
||||||
|
'foo': {
|
||||||
|
url: '/spec/ol/data/{z}-{x}-{y}.vector.pbf',
|
||||||
|
type: 'vector',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id: 'background',
|
||||||
|
type: 'background',
|
||||||
|
paint: {
|
||||||
|
'background-color': '#ff0000',
|
||||||
|
'background-opacity': 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
|
const source = layer.getSource();
|
||||||
|
const key = source.on('change', function () {
|
||||||
|
if (source.getState() === 'ready') {
|
||||||
|
unByKey(key);
|
||||||
|
source.getTile(14, 8938, 5680, 1, get('EPSG:3857')).load();
|
||||||
|
source.once('tileloadend', (event) => {
|
||||||
|
const features = event.tile.getFeatures();
|
||||||
|
if (!features) {
|
||||||
|
event.tile.setFeatures([]);
|
||||||
|
}
|
||||||
|
expect(features[0].get('layer')).to.be('background');
|
||||||
|
expect(
|
||||||
|
features[0].getStyleFunction()().getFill().getColor()
|
||||||
|
).to.eql([255, 0, 0, 0.8]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user