mirror of
https://github.com/apache/superset.git
synced 2026-05-12 19:35:17 +00:00
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:
committed by
GitHub
parent
ee63ebc8ec
commit
87c3e831a8
@@ -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(),
|
||||
|
||||
33
superset/assets/visualizations/deckgl/layers/common.js
Normal file
33
superset/assets/visualizations/deckgl/layers/common.js
Normal 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),
|
||||
};
|
||||
}
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user