From 46787eda1e465e1a998e76ee98f5209f4e6ba6fc Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 22 Oct 2019 14:18:25 -0400 Subject: [PATCH 1/2] remove race-condition in image loading --- .../connected_components/map/mb/utils.js | 51 ++++++++++++------- .../maps/public/layers/vector_tile_layer.js | 27 ++++++++-- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js index dfe50a015eb24..d7ea18440dc8c 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js @@ -109,25 +109,38 @@ function getImageData(img) { return context.getImageData(0, 0, img.width, img.height); } -export async function addSpritesheetToMap(json, imgUrl, mbMap) { - - const image = new Image(); - image.crossOrigin = 'Anonymous'; - image.onload = (el) => { - const imgData = getImageData(el.currentTarget); - for (const imageId in json) { - if (!(json.hasOwnProperty(imageId) && !mbMap.hasImage(imageId))) { - continue; - } - const { width, height, x, y, sdf, pixelRatio } = json[imageId]; - if (typeof width !== 'number' || typeof height !== 'number') { - continue; - } +export async function loadSpriteSheetImageData(imgUrl) { + return new Promise((resolve, reject) => { + const image = new Image(); + image.crossOrigin = 'Anonymous'; + image.onload = (el) => { + const imgData = getImageData(el.currentTarget); + resolve(imgData); + }; + image.onerror = (e) =>{ + reject(e); + }; + image.src = imgUrl; + }); +} - const data = new RGBAImage({ width, height }); - RGBAImage.copy(imgData, data, { x, y }, { x: 0, y: 0 }, { width, height }); - mbMap.addImage(imageId, data, { pixelRatio, sdf }); +export function addSpriteSheetToMapFromImageData(json, imgData, mbMap) { + for (const imageId in json) { + if (!(json.hasOwnProperty(imageId) && !mbMap.hasImage(imageId))) { + continue; } - }; - image.src = imgUrl; + const { width, height, x, y, sdf, pixelRatio } = json[imageId]; + if (typeof width !== 'number' || typeof height !== 'number') { + continue; + } + + const data = new RGBAImage({ width, height }); + RGBAImage.copy(imgData, data, { x, y }, { x: 0, y: 0 }, { width, height }); + mbMap.addImage(imageId, data, { pixelRatio, sdf }); + } +} + +export async function addSpritesheetToMap(json, imgUrl, mbMap) { + const imgData = await loadSpriteSheetImageData(imgUrl); + addSpriteSheetToMapFromImageData(json, imgData, mbMap); } diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js index a7f0346b09ef5..2d4fdd634ecc8 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js @@ -8,7 +8,10 @@ import { TileLayer } from './tile_layer'; import _ from 'lodash'; import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants'; import { isRetina } from '../meta'; -import { addSpritesheetToMap } from '../connected_components/map/mb/utils';//todo move this implementation +import { + addSpriteSheetToMapFromImageData, + loadSpriteSheetImageData +} from '../connected_components/map/mb/utils';//todo move this implementation const MB_STYLE_TYPE_TO_OPACITY = { 'fill': ['fill-opacity'], @@ -45,7 +48,12 @@ export class VectorTileLayer extends TileLayer { startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters); try { const styleAndSprites = await this._source.getVectorStyleSheetAndSpriteMeta(isRetina()); - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, styleAndSprites, {}); + const spriteSheetImageData = await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png); + const data = { + ...styleAndSprites, + spriteSheetImageData: spriteSheetImageData + }; + stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data, {}); } catch(error) { onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); } @@ -76,6 +84,15 @@ export class VectorTileLayer extends TileLayer { return vectorStyleAndSprites.spriteMeta; } + _getSpriteImageData() { + const sourceDataRequest = this.getSourceDataRequest(); + if (!sourceDataRequest) { + return null; + } + const vectorStyleAndSprites = sourceDataRequest.getData(); + return vectorStyleAndSprites.spriteSheetImageData; + } + getMbLayerIds() { const vectorStyle = this._getVectorStyle(); if (!vectorStyle) { @@ -118,8 +135,6 @@ export class VectorTileLayer extends TileLayer { } let initialBootstrapCompleted = false; - - //sync sources const sourceIds = Object.keys(vectorStyle.sources); sourceIds.forEach(sourceId => { if (initialBootstrapCompleted) { @@ -149,7 +164,9 @@ export class VectorTileLayer extends TileLayer { newJson[namespacedImageId] = spriteMeta.json[imageId]; } } - addSpritesheetToMap(newJson, spriteMeta.png, mbMap); + + const imageData = this._getSpriteImageData(); + addSpriteSheetToMapFromImageData(newJson, imageData, mbMap); //sync layers vectorStyle.layers.forEach(layer => { From 971ba490921286ea629f4baae7c4535547d44e23 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Fri, 15 Nov 2019 15:13:25 -0500 Subject: [PATCH 2/2] review --- .../legacy/plugins/maps/public/layers/vector_tile_layer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js index 2d4fdd634ecc8..d714ac3b092f6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js @@ -51,7 +51,7 @@ export class VectorTileLayer extends TileLayer { const spriteSheetImageData = await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png); const data = { ...styleAndSprites, - spriteSheetImageData: spriteSheetImageData + spriteSheetImageData }; stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data, {}); } catch(error) { @@ -166,6 +166,9 @@ export class VectorTileLayer extends TileLayer { } const imageData = this._getSpriteImageData(); + if (!imageData) { + return; + } addSpriteSheetToMapFromImageData(newJson, imageData, mbMap); //sync layers