diff --git a/src/layers/src/base-layer.ts b/src/layers/src/base-layer.ts index 2541e98018..d1c2fe0a32 100644 --- a/src/layers/src/base-layer.ts +++ b/src/layers/src/base-layer.ts @@ -226,6 +226,10 @@ function* generateColor(): Generator { export const colorMaker = generateColor(); +export type BaseLayerConstructorProps = { + id?: string; +} & LayerBaseConfigPartial; + class Layer { id: string; meta: Record; @@ -239,11 +243,7 @@ class Layer { isValid: boolean; errorMessage: string | null; - constructor( - props: { - id?: string; - } & LayerBaseConfigPartial - ) { + constructor(props: BaseLayerConstructorProps) { this.id = props.id || generateHashId(LAYER_ID_LENGTH); // meta diff --git a/src/layers/src/icon-layer/icon-layer.ts b/src/layers/src/icon-layer/icon-layer.ts index f34ea4c7ce..7992097a2a 100644 --- a/src/layers/src/icon-layer/icon-layer.ts +++ b/src/layers/src/icon-layer/icon-layer.ts @@ -28,6 +28,7 @@ import {ICON_FIELDS, KEPLER_UNFOLDED_BUCKET, ColorRange} from '@kepler.gl/consta import IconInfoModalFactory from './icon-info-modal'; import Layer, {LayerBaseConfig, LayerBaseConfigPartial, LayerColumn} from '../base-layer'; import {assignPointPairToLayerColumn} from '../layer-utils'; +import {isTest} from '@kepler.gl/utils'; import {getTextOffsetByRadius, formatTextLabelData} from '../layer-text-label'; import {default as KeplerTable} from '@kepler.gl/table'; import {DataContainerInterface} from '@kepler.gl/utils'; @@ -127,6 +128,7 @@ export default class IconLayer extends Layer { props: { id?: string; iconGeometry?: IconGeometry; + svgIcons?: any[]; } & LayerBaseConfigPartial ) { super(props); @@ -136,10 +138,19 @@ export default class IconLayer extends Layer { iconPosAccessor(this.config.columns)(dataContainer); this.getIconAccessor = dataContainer => iconAccessor(this.config.columns)(dataContainer); - // prepare layer info modal - this._layerInfoModal = IconInfoModalFactory(); + this._layerInfoModal = IconInfoModalFactory(props.svgIcons); this.iconGeometry = props.iconGeometry || null; - this.getSvgIcons(); + + if (isTest()) { + return; + } + if (props.svgIcons) { + // if svg icons are passed in then bypass fetching of remote svg icons + this.setSvgIcons(props.svgIcons); + } else { + // prepare layer info modal and fetch remote svg icons + this.getSvgIcons(); + } } get svgIconUrl() { @@ -201,25 +212,28 @@ export default class IconLayer extends Layer { cache: 'no-cache' }; - if (window.fetch) { + if (window.fetch && this.svgIconUrl) { window .fetch(this.svgIconUrl, fetchConfig) .then(response => response.json()) .then((parsed: {svgIcons?: any[]} = {}) => { - const {svgIcons = []} = parsed; - this.iconGeometry = svgIcons.reduce( - (accu, curr) => ({ - ...accu, - [curr.id]: flatterIconPositions(curr) - }), - {} - ); - - this._layerInfoModal = IconInfoModalFactory(svgIcons); + this.setSvgIcons(parsed.svgIcons); }); } } + setSvgIcons(svgIcons: any[] = []) { + this.iconGeometry = svgIcons.reduce( + (accu, curr) => ({ + ...accu, + [curr.id]: flatterIconPositions(curr) + }), + {} + ); + + this._layerInfoModal = IconInfoModalFactory(svgIcons); + } + static findDefaultLayerProps({fieldPairs = [], fields = []}: KeplerTable) { const notFound = {props: []}; if (!fieldPairs.length || !fields.length) { diff --git a/test/browser/layer-tests/icon-layer-specs.js b/test/browser/layer-tests/icon-layer-specs.js index 13b63727f9..f2a32bc42f 100644 --- a/test/browser/layer-tests/icon-layer-specs.js +++ b/test/browser/layer-tests/icon-layer-specs.js @@ -499,19 +499,9 @@ test('#IconLayer -> renderLayer', t => { t.end(); }); -test('#IconLayer -> fetch icon geometry -> renderIconModal', t => { - const mockSuccessResponse = {svgIcons: mockSvgIcons}; - const mockJsonPromise = sinon.stub().returnsPromise(); - mockJsonPromise.resolves(mockSuccessResponse); - - const stubedFetch = sinon.stub(global, 'fetch').returnsPromise(); - - stubedFetch.resolves({ - json: mockJsonPromise - }); - +test('#IconLayer -> svg icons as constructor props -> renderIconModal', t => { // initialize iconLayer - const iconLayer = new IconLayer({dataId: ''}); + const iconLayer = new IconLayer({dataId: '', svgIcons: mockSvgIcons}); t.deepEqual(iconLayer.iconGeometry, iconLayer.iconGeometry, 'should create correct iconGeometry'); let wrapper; @@ -534,6 +524,5 @@ test('#IconLayer -> fetch icon geometry -> renderIconModal', t => { 'should render alert icon' ); - stubedFetch.restore(); t.end(); });