Using user-defined Javascript to customize geospatial visualization (#4173)

* Using JS to customize spatial viz and tooltips

* Add missing deck_multi.png

* Improve GeoJSON layer with JS support and extra controls

* Addressing comments
This commit is contained in:
Maxime Beauchemin
2018-01-11 15:42:44 -08:00
committed by GitHub
parent ee63ebc8ec
commit 87c3e831a8
13 changed files with 237 additions and 54 deletions

View File

@@ -6,7 +6,7 @@ import layerGenerators from './layers';
export default function deckglFactory(slice, payload, setControlValue) {
const fd = slice.formData;
const layer = layerGenerators[fd.viz_type](fd, payload);
const layer = layerGenerators[fd.viz_type](fd, payload, slice);
const viewport = {
...fd.viewport,
width: slice.width(),

View File

@@ -0,0 +1,33 @@
import dompurify from 'dompurify';
import sandboxedEval from '../../../javascripts/modules/sandbox';
export function commonLayerProps(formData, slice) {
const fd = formData;
let onHover;
if (fd.js_tooltip) {
const jsTooltip = sandboxedEval(fd.js_tooltip);
onHover = (o) => {
if (o.picked) {
slice.setTooltip({
content: dompurify.sanitize(jsTooltip(o)),
x: o.x,
y: o.y,
});
} else {
slice.setTooltip(null);
}
};
}
let onClick;
if (fd.js_onclick_href) {
onClick = (o) => {
const href = sandboxedEval(fd.js_onclick_href)(o);
window.open(href);
};
}
return {
onClick,
onHover,
pickable: Boolean(onHover),
};
}

View File

@@ -1,6 +1,8 @@
import { GeoJsonLayer } from 'deck.gl';
import { hexToRGB } from '../../../javascripts/modules/colors';
import * as common from './common';
import { hexToRGB } from '../../../javascripts/modules/colors';
import sandboxedEval from '../../../javascripts/modules/sandbox';
const propertyMap = {
fillColor: 'fillColor',
@@ -23,11 +25,11 @@ const convertGeoJsonColorProps = (p, colors) => {
};
};
export default function geoJsonLayer(formData, payload) {
export default function geoJsonLayer(formData, payload, slice) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
const data = payload.data.geojson.features.map(d => ({
let data = payload.data.geojson.features.map(d => ({
...d,
properties: convertGeoJsonColorProps(
d.properties, {
@@ -36,12 +38,19 @@ export default function geoJsonLayer(formData, payload) {
}),
}));
if (fd.js_datapoint_mutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_datapoint_mutator);
data = data.map(jsFnMutator);
}
return new GeoJsonLayer({
id: `path-layer-${fd.slice_id}`,
data,
filled: true,
stroked: false,
extruded: true,
filled: fd.filled,
stroked: fd.stroked,
extruded: fd.extruded,
pointRadiusScale: fd.point_radius_scale,
...common.commonLayerProps(fd, slice),
});
}

View File

@@ -1,19 +1,29 @@
import { PathLayer } from 'deck.gl';
export default function getLayer(formData, payload) {
import * as common from './common';
import sandboxedEval from '../../../javascripts/modules/sandbox';
export default function getLayer(formData, payload, slice) {
const fd = formData;
const c = fd.color_picker;
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
const data = payload.data.paths.map(path => ({
path,
let data = payload.data.features.map(feature => ({
...feature,
path: feature.path,
width: fd.line_width,
color: fixedColor,
}));
if (fd.js_datapoint_mutator) {
const jsFnMutator = sandboxedEval(fd.js_datapoint_mutator);
data = data.map(jsFnMutator);
}
return new PathLayer({
id: `path-layer-${fd.slice_id}`,
data,
rounded: true,
widthScale: 1,
...common.commonLayerProps(fd, slice),
});
}

View File

@@ -1,14 +1,16 @@
import { ScatterplotLayer } from 'deck.gl';
import * as common from './common';
import { getColorFromScheme, hexToRGB } from '../../../javascripts/modules/colors';
import { unitToRadius } from '../../../javascripts/modules/geo';
import sandboxedEval from '../../../javascripts/modules/sandbox';
export default function getLayer(formData, payload) {
export default function getLayer(formData, payload, slice) {
const fd = formData;
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
const data = payload.data.features.map((d) => {
let data = payload.data.features.map((d) => {
let radius = unitToRadius(fd.point_unit, d.radius) || 10;
if (fd.multiplier) {
radius *= fd.multiplier;
@@ -25,11 +27,18 @@ export default function getLayer(formData, payload) {
color,
};
});
if (fd.js_datapoint_mutator) {
// Applying user defined data mutator if defined
const jsFnMutator = sandboxedEval(fd.js_datapoint_mutator);
data = data.map(jsFnMutator);
}
return new ScatterplotLayer({
id: `scatter-layer-${fd.slice_id}`,
data,
pickable: true,
fp64: true,
outline: false,
...common.commonLayerProps(fd, slice),
});
}