Skip to content

Commit

Permalink
[feat] Update Icon Layer to allow passing in svg icons as a prop to b…
Browse files Browse the repository at this point in the history
…ypass remote resource fetching (#2410)

* [feat] Update Icon Layer to allow passing in svg icons as a prop to bypass remote resource fetching

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* ts

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

---------

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
Co-authored-by: Jacob Wasilkowski <4933392+jwasilgeo@users.noreply.github.com>
  • Loading branch information
igorDykhta and jwasilgeo committed Oct 27, 2023
1 parent 2ff3738 commit 4d72331
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 32 deletions.
10 changes: 5 additions & 5 deletions src/layers/src/base-layer.ts
Expand Up @@ -226,6 +226,10 @@ function* generateColor(): Generator<RGBColor> {

export const colorMaker = generateColor();

export type BaseLayerConstructorProps = {
id?: string;
} & LayerBaseConfigPartial;

class Layer {
id: string;
meta: Record<string, any>;
Expand All @@ -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
Expand Down
42 changes: 28 additions & 14 deletions src/layers/src/icon-layer/icon-layer.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -127,6 +128,7 @@ export default class IconLayer extends Layer {
props: {
id?: string;
iconGeometry?: IconGeometry;
svgIcons?: any[];
} & LayerBaseConfigPartial
) {
super(props);
Expand All @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down
15 changes: 2 additions & 13 deletions test/browser/layer-tests/icon-layer-specs.js
Expand Up @@ -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;
Expand All @@ -534,6 +524,5 @@ test('#IconLayer -> fetch icon geometry -> renderIconModal', t => {
'should render alert icon'
);

stubedFetch.restore();
t.end();
});

0 comments on commit 4d72331

Please sign in to comment.