Skip to content

Commit

Permalink
[Maps] Convert maki icons to SDF sprites on-the-fly (#119245)
Browse files Browse the repository at this point in the history
* Convert SVG maki icons to SDF on-the-fly
  • Loading branch information
nickpeihl authored Dec 7, 2021
1 parent 5d44d79 commit c838709
Show file tree
Hide file tree
Showing 15 changed files with 933 additions and 170 deletions.
2 changes: 1 addition & 1 deletion NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ MIT License http://www.opensource.org/licenses/mit-license
---
This product includes code that is adapted from mapbox-gl-js, which is
available under a "BSD-3-Clause" license.
https://github.com/mapbox/mapbox-gl-js/blob/master/src/util/image.js
https://github.com/mapbox/mapbox-gl-js/blob/v1.13.2/src/util/image.js

Copyright (c) 2016, Mapbox

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
"@elastic/ems-client": "8.0.0",
"@elastic/eui": "41.0.0",
"@elastic/filesaver": "1.1.2",
"@elastic/maki": "6.3.0",
"@elastic/node-crypto": "1.2.1",
"@elastic/numeral": "^2.5.1",
"@elastic/react-search-ui": "^1.6.0",
Expand Down Expand Up @@ -196,8 +195,10 @@
"archiver": "^5.2.0",
"axios": "^0.21.1",
"base64-js": "^1.3.1",
"bitmap-sdf": "^1.0.3",
"brace": "0.11.1",
"broadcast-channel": "^4.7.0",
"canvg": "^3.0.9",
"chalk": "^4.1.0",
"cheerio": "^1.0.0-rc.10",
"chokidar": "^3.4.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@

import type { Map as MbMap, Layer as MbLayer, Style as MbStyle } from '@kbn/mapbox-gl';
import _ from 'lodash';
// @ts-expect-error
import { RGBAImage } from './image_utils';
import { AbstractLayer } from '../layer';
import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../../../common/constants';
import { LayerDescriptor } from '../../../../common/descriptor_types';
import { DataRequest } from '../../util/data_request';
import { isRetina } from '../../../util';
import {
addSpriteSheetToMapFromImageData,
loadSpriteSheetImageData,
} from '../../../connected_components/mb_map/utils';
import { DataRequestContext } from '../../../actions';
import { EMSTMSSource } from '../../sources/ems_tms_source';
import { TileStyle } from '../../styles/tile/tile_style';
Expand Down Expand Up @@ -118,7 +116,7 @@ export class EmsVectorTileLayer extends AbstractLayer {
startLoading(SOURCE_DATA_REQUEST_ID, requestToken, nextMeta);
const styleAndSprites = await this.getSource().getVectorStyleSheetAndSpriteMeta(isRetina());
const spriteSheetImageData = styleAndSprites.spriteMeta
? await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png)
? await this._loadSpriteSheetImageData(styleAndSprites.spriteMeta.png)
: undefined;
const data = {
...styleAndSprites,
Expand Down Expand Up @@ -210,6 +208,60 @@ export class EmsVectorTileLayer extends AbstractLayer {
});
}

_getImageData(img: HTMLImageElement) {
const canvas = window.document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) {
throw new Error('failed to create canvas 2d context');
}
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0, img.width, img.height);
return context.getImageData(0, 0, img.width, img.height);
}

_isCrossOriginUrl(url: string) {
const a = window.document.createElement('a');
a.href = url;
return (
a.protocol !== window.document.location.protocol ||
a.host !== window.document.location.host ||
a.port !== window.document.location.port
);
}

_loadSpriteSheetImageData(imgUrl: string): Promise<ImageData> {
return new Promise((resolve, reject) => {
const image = new Image();
if (this._isCrossOriginUrl(imgUrl)) {
image.crossOrigin = 'Anonymous';
}
image.onload = (event) => {
resolve(this._getImageData(image));
};
image.onerror = (e) => {
reject(e);
};
image.src = imgUrl;
});
}

_addSpriteSheetToMapFromImageData(json: EmsSpriteSheet, imgData: ImageData, mbMap: MbMap) {
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;
}

const data = new RGBAImage({ width, height });
RGBAImage.copy(imgData, data, { x, y }, { x: 0, y: 0 }, { width, height });
mbMap.addImage(imageId, data, { pixelRatio, sdf });
}
}

syncLayerWithMB(mbMap: MbMap) {
const vectorStyle = this._getVectorStyle();
if (!vectorStyle) {
Expand Down Expand Up @@ -252,7 +304,7 @@ export class EmsVectorTileLayer extends AbstractLayer {
if (!imageData) {
return;
}
addSpriteSheetToMapFromImageData(newJson, imageData, mbMap);
this._addSpriteSheetToMapFromImageData(newJson, imageData, mbMap);

// sync layers
const layers = vectorStyle.layers ? vectorStyle.layers : [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/* @notice
* This product includes code that is adapted from mapbox-gl-js, which is
* available under a "BSD-3-Clause" license.
* https://github.com/mapbox/mapbox-gl-js/blob/master/src/util/image.js
* https://github.com/mapbox/mapbox-gl-js/blob/v1.13.2/src/util/image.js
*
* Copyright (c) 2016, Mapbox
*
Expand Down
Loading

0 comments on commit c838709

Please sign in to comment.