diff --git a/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx b/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx
index 0976ec00dfce1..61c9eedc74902 100644
--- a/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx
+++ b/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx
@@ -31,12 +31,14 @@ function getCategories(fd, data) {
}
const propTypes = {
- slice: PropTypes.object.isRequired,
+ formData: PropTypes.object.isRequired,
mapboxApiKey: PropTypes.string.isRequired,
setControlValue: PropTypes.func.isRequired,
viewport: PropTypes.object.isRequired,
getLayer: PropTypes.func.isRequired,
payload: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ onTooltip: PropTypes.func,
};
export default class CategoricalDeckGLContainer extends React.PureComponent {
@@ -49,7 +51,7 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
/* eslint-disable-next-line react/sort-comp */
static getDerivedStateFromProps(nextProps) {
- const fd = nextProps.slice.formData;
+ const fd = nextProps.formData;
const timeGrain = fd.time_grain_sqla || fd.granularity || 'PT1M';
const timestamps = nextProps.payload.data.features.map(f => f.__timestamp);
@@ -70,8 +72,13 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
this.setState(CategoricalDeckGLContainer.getDerivedStateFromProps(nextProps, this.state));
}
getLayers(values) {
- const { getLayer, payload, slice } = this.props;
- const fd = slice.formData;
+ const {
+ getLayer,
+ payload,
+ formData: fd,
+ onAddFilter,
+ onTooltip,
+ } = this.props;
let data = [...payload.data.features];
// Add colors from categories or fixed color
@@ -96,7 +103,7 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
}
payload.data.features = data;
- return [getLayer(fd, payload, slice)];
+ return [getLayer(fd, payload, onAddFilter, onTooltip)];
}
addColor(data, fd) {
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
@@ -142,14 +149,14 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
disabled={this.state.disabled}
viewport={this.props.viewport}
mapboxApiAccessToken={this.props.mapboxApiKey}
- mapStyle={this.props.slice.formData.mapbox_style}
+ mapStyle={this.props.formData.mapbox_style}
setControlValue={this.props.setControlValue}
>
diff --git a/superset/assets/src/visualizations/deckgl/createAdaptor.jsx b/superset/assets/src/visualizations/deckgl/createAdaptor.jsx
new file mode 100644
index 0000000000000..6dfe11b9d9d38
--- /dev/null
+++ b/superset/assets/src/visualizations/deckgl/createAdaptor.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+const IDENTITY = x => x;
+
+class DeckGlChartInput {
+ constructor(slice, payload, setControlValue) {
+ this.formData = slice.formData;
+ this.payload = payload;
+ this.setControlValue = setControlValue;
+ this.viewport = {
+ ...this.formData.viewport,
+ width: slice.width(),
+ height: slice.height(),
+ };
+
+ this.onAddFilter = ((...args) => { slice.addFilter(...args); });
+ this.onTooltip = ((...args) => { slice.tooltip(...args); });
+ }
+}
+
+export default function createAdaptor(Component, transformProps = IDENTITY) {
+ return function adaptor(slice, payload, setControlValue) {
+ const chartInput = new DeckGlChartInput(slice, payload, setControlValue);
+ ReactDOM.render(
+ ,
+ document.querySelector(slice.selector),
+ );
+ };
+}
diff --git a/superset/assets/src/visualizations/deckgl/factory.jsx b/superset/assets/src/visualizations/deckgl/factory.jsx
new file mode 100644
index 0000000000000..fc61e34a5ecf6
--- /dev/null
+++ b/superset/assets/src/visualizations/deckgl/factory.jsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import DeckGLContainer from './DeckGLContainer';
+import CategoricalDeckGLContainer from './CategoricalDeckGLContainer';
+import { fitViewport } from './layers/common';
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ onTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ onTooltip() {},
+};
+
+export function createDeckGLComponent(getLayer, getPoints) {
+ function Component(props) {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ onAddFilter,
+ onTooltip,
+ viewport: originalViewport,
+ } = props;
+
+ const viewport = formData.autozoom
+ ? fitViewport(originalViewport, getPoints(payload.data.features))
+ : originalViewport;
+
+ const layer = getLayer(formData, payload, onAddFilter, onTooltip);
+
+ return (
+
+ );
+ }
+
+ Component.propTypes = propTypes;
+ Component.defaultProps = defaultProps;
+
+ return Component;
+}
+
+export function createCategoricalDeckGLComponent(getLayer, getPoints) {
+ function Component(props) {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ onAddFilter,
+ onTooltip,
+ viewport: originalViewport,
+ } = props;
+
+ const viewport = formData.autozoom
+ ? fitViewport(originalViewport, getPoints(payload.data.features))
+ : originalViewport;
+
+ return (
+
+ );
+ }
+
+ Component.propTypes = propTypes;
+ Component.defaultProps = defaultProps;
+
+ return Component;
+}
diff --git a/superset/assets/src/visualizations/deckgl/layers/arc.jsx b/superset/assets/src/visualizations/deckgl/layers/arc.jsx
index 883ffbd6c68fd..e2a32330574ad 100644
--- a/superset/assets/src/visualizations/deckgl/layers/arc.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/arc.jsx
@@ -1,13 +1,7 @@
-/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-
import { ArcLayer } from 'deck.gl';
-
-import CategoricalDeckGLContainer from '../CategoricalDeckGLContainer';
-
-import * as common from './common';
+import { commonLayerProps } from './common';
+import createAdaptor from '../createAdaptor';
+import { createCategoricalDeckGLComponent } from '../factory';
function getPoints(data) {
const points = [];
@@ -18,7 +12,7 @@ function getPoints(data) {
return points;
}
-function getLayer(fd, payload, slice) {
+export function getLayer(fd, payload, onAddFilter, onTooltip) {
const data = payload.data.features;
const sc = fd.color_picker;
const tc = fd.target_color_picker;
@@ -28,36 +22,8 @@ function getLayer(fd, payload, slice) {
getSourceColor: d => d.sourceColor || d.color || [sc.r, sc.g, sc.b, 255 * sc.a],
getTargetColor: d => d.targetColor || d.color || [tc.r, tc.g, tc.b, 255 * tc.a],
strokeWidth: (fd.stroke_width) ? fd.stroke_width : 3,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
-function deckArc(slice, payload, setControlValue) {
- const fd = slice.formData;
- let viewport = {
- ...fd.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (fd.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckArc,
- getLayer,
-};
+export default createAdaptor(createCategoricalDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/common.jsx b/superset/assets/src/visualizations/deckgl/layers/common.jsx
index 8a3ecc5c7c270..a0b1e137c319b 100644
--- a/superset/assets/src/visualizations/deckgl/layers/common.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/common.jsx
@@ -1,7 +1,6 @@
import React from 'react';
import { fitBounds } from 'viewport-mercator-project';
import d3 from 'd3';
-
import sandboxedEval from '../../../modules/sandbox';
export function getBounds(points) {
@@ -32,7 +31,7 @@ export function fitViewport(viewport, points, padding = 10) {
}
}
-export function commonLayerProps(formData, slice) {
+export function commonLayerProps(formData, onAddFilter, onTooltip) {
const fd = formData;
let onHover;
let tooltipContentGenerator;
@@ -49,13 +48,13 @@ export function commonLayerProps(formData, slice) {
if (tooltipContentGenerator) {
onHover = (o) => {
if (o.picked) {
- slice.setTooltip({
+ onTooltip({
content: tooltipContentGenerator(o),
x: o.x,
y: o.y,
});
} else {
- slice.setTooltip(null);
+ onTooltip(null);
}
};
}
@@ -66,7 +65,7 @@ export function commonLayerProps(formData, slice) {
window.open(href);
};
} else if (fd.table_filter && fd.line_type === 'geohash') {
- onClick = o => slice.addFilter(fd.line_column, [o.object[fd.line_column]], false);
+ onClick = o => onAddFilter(fd.line_column, [o.object[fd.line_column]], false);
}
return {
onClick,
diff --git a/superset/assets/src/visualizations/deckgl/layers/geojson.jsx b/superset/assets/src/visualizations/deckgl/layers/geojson.jsx
index 72790f1efdbba..64a39a9d2111a 100644
--- a/superset/assets/src/visualizations/deckgl/layers/geojson.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/geojson.jsx
@@ -1,12 +1,13 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import PropTypes from 'prop-types';
import { GeoJsonLayer } from 'deck.gl';
// TODO import geojsonExtent from 'geojson-extent';
import DeckGLContainer from './../DeckGLContainer';
-import * as common from './common';
import { hexToRGB } from '../../../modules/colors';
import sandboxedEval from '../../../modules/sandbox';
+import { commonLayerProps } from './common';
+import createAdaptor from '../createAdaptor';
const propertyMap = {
fillColor: 'fillColor',
@@ -57,7 +58,7 @@ const recurseGeoJson = (node, propOverrides, extraProps) => {
}
};
-function getLayer(formData, payload, slice) {
+export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
@@ -88,35 +89,52 @@ function getLayer(formData, payload, slice) {
stroked: fd.stroked,
extruded: fd.extruded,
pointRadiusScale: fd.point_radius_scale,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
-function deckGeoJson(slice, payload, setControlValue) {
- const layer = getLayer(slice.formData, payload, slice);
- const viewport = {
- ...slice.formData.viewport,
- width: slice.width(),
- height: slice.height(),
- };
- if (slice.formData.autozoom) {
- // TODO get this to work
- // viewport = common.fitViewport(viewport, geojsonExtent(payload.data.features));
- }
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ onTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ onTooltip() {},
+};
+
+function deckGeoJson(props) {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ onAddFilter,
+ onTooltip,
+ viewport,
+ } = props;
- ReactDOM.render(
+ // TODO get this to work
+ // if (formData.autozoom) {
+ // viewport = common.fitViewport(viewport, geojsonExtent(payload.data.features));
+ // }
+
+ const layer = getLayer(formData, payload, onAddFilter, onTooltip);
+
+ return (
,
- document.getElementById(slice.containerId),
+ />
);
}
-module.exports = {
- default: deckGeoJson,
- getLayer,
-};
+deckGeoJson.propTypes = propTypes;
+deckGeoJson.defaultProps = defaultProps;
+
+export default createAdaptor(deckGeoJson);
diff --git a/superset/assets/src/visualizations/deckgl/layers/grid.jsx b/superset/assets/src/visualizations/deckgl/layers/grid.jsx
index 16a538c906267..0f5cf3149cca6 100644
--- a/superset/assets/src/visualizations/deckgl/layers/grid.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/grid.jsx
@@ -1,14 +1,10 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
import { GridLayer } from 'deck.gl';
-
-import DeckGLContainer from './../DeckGLContainer';
-
-import * as common from './common';
+import { commonLayerProps } from './common';
import sandboxedEval from '../../../modules/sandbox';
+import createAdaptor from '../createAdaptor';
+import { createDeckGLComponent } from '../factory';
-function getLayer(formData, payload, slice) {
+export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const c = fd.color_picker;
let data = payload.data.features.map(d => ({
@@ -21,6 +17,7 @@ function getLayer(formData, payload, slice) {
const jsFnMutator = sandboxedEval(fd.js_data_mutator);
data = jsFnMutator(data);
}
+
return new GridLayer({
id: `grid-layer-${fd.slice_id}`,
data,
@@ -32,7 +29,7 @@ function getLayer(formData, payload, slice) {
outline: false,
getElevationValue: points => points.reduce((sum, point) => sum + point.weight, 0),
getColorValue: points => points.reduce((sum, point) => sum + point.weight, 0),
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
@@ -40,31 +37,4 @@ function getPoints(data) {
return data.map(d => d.position);
}
-function deckGrid(slice, payload, setControlValue) {
- const layer = getLayer(slice.formData, payload, slice);
- let viewport = {
- ...slice.formData.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (slice.formData.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckGrid,
- getLayer,
-};
+export default createAdaptor(createDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/hex.jsx b/superset/assets/src/visualizations/deckgl/layers/hex.jsx
index 14c9951df42d6..3dabb765dc91e 100644
--- a/superset/assets/src/visualizations/deckgl/layers/hex.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/hex.jsx
@@ -1,14 +1,10 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
import { HexagonLayer } from 'deck.gl';
-
-import DeckGLContainer from './../DeckGLContainer';
-
-import * as common from './common';
+import { commonLayerProps } from './common';
import sandboxedEval from '../../../modules/sandbox';
+import createAdaptor from '../createAdaptor';
+import { createDeckGLComponent } from '../factory';
-function getLayer(formData, payload, slice) {
+export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const c = fd.color_picker;
let data = payload.data.features.map(d => ({
@@ -33,7 +29,7 @@ function getLayer(formData, payload, slice) {
outline: false,
getElevationValue: points => points.reduce((sum, point) => sum + point.weight, 0),
getColorValue: points => points.reduce((sum, point) => sum + point.weight, 0),
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
@@ -41,31 +37,4 @@ function getPoints(data) {
return data.map(d => d.position);
}
-function deckHex(slice, payload, setControlValue) {
- const layer = getLayer(slice.formData, payload, slice);
- let viewport = {
- ...slice.formData.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (slice.formData.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckHex,
- getLayer,
-};
+export default createAdaptor(createDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/index.js b/superset/assets/src/visualizations/deckgl/layers/index.js
index d8d25d5b0e91b..e98f74395b303 100644
--- a/superset/assets/src/visualizations/deckgl/layers/index.js
+++ b/superset/assets/src/visualizations/deckgl/layers/index.js
@@ -18,4 +18,5 @@ const layerGenerators = {
deck_arc,
deck_polygon,
};
+
export default layerGenerators;
diff --git a/superset/assets/src/visualizations/deckgl/layers/path.jsx b/superset/assets/src/visualizations/deckgl/layers/path.jsx
index 0951edd93c166..ede01b2384868 100644
--- a/superset/assets/src/visualizations/deckgl/layers/path.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/path.jsx
@@ -1,14 +1,10 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
import { PathLayer } from 'deck.gl';
-
-import DeckGLContainer from './../DeckGLContainer';
-
-import * as common from './common';
+import { commonLayerProps } from './common';
import sandboxedEval from '../../../modules/sandbox';
+import createAdaptor from '../createAdaptor';
+import { createDeckGLComponent } from '../factory';
-function getLayer(formData, payload, slice) {
+export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const c = fd.color_picker;
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
@@ -29,7 +25,7 @@ function getLayer(formData, payload, slice) {
data,
rounded: true,
widthScale: 1,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
@@ -41,31 +37,4 @@ function getPoints(data) {
return points;
}
-function deckPath(slice, payload, setControlValue) {
- const layer = getLayer(slice.formData, payload, slice);
- let viewport = {
- ...slice.formData.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (slice.formData.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckPath,
- getLayer,
-};
+export default createAdaptor(createDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/polygon.jsx b/superset/assets/src/visualizations/deckgl/layers/polygon.jsx
index e84b943f61783..73537dcaa4e2a 100644
--- a/superset/assets/src/visualizations/deckgl/layers/polygon.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/polygon.jsx
@@ -1,21 +1,17 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
+import d3 from 'd3';
import { PolygonLayer } from 'deck.gl';
import { flatten } from 'lodash';
-import d3 from 'd3';
-
-import DeckGLContainer from './../DeckGLContainer';
-
-import * as common from './common';
import { colorScalerFactory } from '../../../modules/colors';
+import { commonLayerProps } from './common';
import sandboxedEval from '../../../modules/sandbox';
+import createAdaptor from '../createAdaptor';
+import { createDeckGLComponent } from '../factory';
function getPoints(features) {
return flatten(features.map(d => d.polygon), true);
}
-function getLayer(formData, payload, slice) {
+export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
@@ -49,36 +45,8 @@ function getLayer(formData, payload, slice) {
getLineWidth: fd.line_width,
extruded: fd.extruded,
fp64: true,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
-function deckPolygon(slice, payload, setControlValue) {
- const layer = getLayer(slice.formData, payload, slice);
- const fd = slice.formData;
- let viewport = {
- ...slice.formData.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (fd.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckPolygon,
- getLayer,
-};
+export default createAdaptor(createDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/scatter.jsx b/superset/assets/src/visualizations/deckgl/layers/scatter.jsx
index d9474a4770438..b740ce19baf41 100644
--- a/superset/assets/src/visualizations/deckgl/layers/scatter.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/scatter.jsx
@@ -1,20 +1,14 @@
-/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-
import { ScatterplotLayer } from 'deck.gl';
-
-import CategoricalDeckGLContainer from '../CategoricalDeckGLContainer';
-import * as common from './common';
+import { commonLayerProps } from './common';
+import createAdaptor from '../createAdaptor';
+import { createCategoricalDeckGLComponent } from '../factory';
import { unitToRadius } from '../../../modules/geo';
-
function getPoints(data) {
return data.map(d => d.position);
}
-function getLayer(fd, payload, slice) {
+export function getLayer(fd, payload, slice) {
const dataWithRadius = payload.data.features.map((d) => {
let radius = unitToRadius(fd.point_unit, d.radius) || 10;
if (fd.multiplier) {
@@ -35,36 +29,8 @@ function getLayer(fd, payload, slice) {
radiusMinPixels: fd.min_radius || null,
radiusMaxPixels: fd.max_radius || null,
outline: false,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, slice),
});
}
-function deckScatter(slice, payload, setControlValue) {
- const fd = slice.formData;
- let viewport = {
- ...fd.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (fd.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
- ,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckScatter,
- getLayer,
-};
+export default createAdaptor(createCategoricalDeckGLComponent(getLayer, getPoints));
diff --git a/superset/assets/src/visualizations/deckgl/layers/screengrid.jsx b/superset/assets/src/visualizations/deckgl/layers/screengrid.jsx
index b4df577d78253..4331cec5f3974 100644
--- a/superset/assets/src/visualizations/deckgl/layers/screengrid.jsx
+++ b/superset/assets/src/visualizations/deckgl/layers/screengrid.jsx
@@ -1,22 +1,19 @@
/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
import React from 'react';
-import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-
import { ScreenGridLayer } from 'deck.gl';
-
import AnimatableDeckGLContainer from '../AnimatableDeckGLContainer';
-
-import * as common from './common';
import { getPlaySliderParams } from '../../../modules/time';
import sandboxedEval from '../../../modules/sandbox';
+import { commonLayerProps, fitViewport } from './common';
+import createAdaptor from '../createAdaptor';
function getPoints(data) {
return data.map(d => d.position);
}
-function getLayer(formData, payload, slice, filters) {
+export function getLayer(formData, payload, onAddFilter, onTooltip, filters) {
const fd = formData;
const c = fd.color_picker;
let data = payload.data.features.map(d => ({
@@ -47,21 +44,27 @@ function getLayer(formData, payload, slice, filters) {
maxColor: [c.r, c.g, c.b, 255 * c.a],
outline: false,
getWeight: d => d.weight || 0,
- ...common.commonLayerProps(fd, slice),
+ ...commonLayerProps(fd, onAddFilter, onTooltip),
});
}
const propTypes = {
- slice: PropTypes.object.isRequired,
+ formData: PropTypes.object.isRequired,
payload: PropTypes.object.isRequired,
setControlValue: PropTypes.func.isRequired,
viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ onTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ onTooltip() {},
};
class DeckGLScreenGrid extends React.PureComponent {
/* eslint-disable-next-line react/sort-comp */
static getDerivedStateFromProps(nextProps) {
- const fd = nextProps.slice.formData;
+ const fd = nextProps.formData;
const timeGrain = fd.time_grain_sqla || fd.granularity || 'PT1M';
const timestamps = nextProps.payload.data.features.map(f => f.__timestamp);
@@ -89,14 +92,21 @@ class DeckGLScreenGrid extends React.PureComponent {
}
const layer = getLayer(
- this.props.slice.formData,
+ this.props.formData,
this.props.payload,
- this.props.slice,
+ this.props.onAddFilter,
+ this.props.onTooltip,
filters);
return [layer];
}
+
render() {
+ const { formData, payload } = this.props;
+ const viewport = formData.autozoom
+ ? fitViewport(this.props.viewport, getPoints(payload.data.features))
+ : this.props.viewport;
+
return (
@@ -118,31 +128,6 @@ class DeckGLScreenGrid extends React.PureComponent {
}
DeckGLScreenGrid.propTypes = propTypes;
+DeckGLScreenGrid.defaultProps = defaultProps;
-function deckScreenGrid(slice, payload, setControlValue) {
- const fd = slice.formData;
- let viewport = {
- ...fd.viewport,
- width: slice.width(),
- height: slice.height(),
- };
-
- if (fd.autozoom) {
- viewport = common.fitViewport(viewport, getPoints(payload.data.features));
- }
-
- ReactDOM.render(
-
,
- document.getElementById(slice.containerId),
- );
-}
-
-module.exports = {
- default: deckScreenGrid,
- getLayer,
-};
+export default createAdaptor(DeckGLScreenGrid);
diff --git a/superset/assets/src/visualizations/deckgl/multi.jsx b/superset/assets/src/visualizations/deckgl/multi.jsx
index 8b35c86768990..76a70722213b4 100644
--- a/superset/assets/src/visualizations/deckgl/multi.jsx
+++ b/superset/assets/src/visualizations/deckgl/multi.jsx
@@ -1,57 +1,87 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import PropTypes from 'prop-types';
import $ from 'jquery';
-
import DeckGLContainer from './DeckGLContainer';
import { getExploreLongUrl } from '../../explore/exploreUtils';
import layerGenerators from './layers';
+import createAdaptor from './createAdaptor';
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+};
+
+class DeckMulti extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = { subSlicesLayers: {} };
+ }
+
+ componentDidMount() {
+ const { formData, payload } = this.props;
+ this.loadLayers(formData, payload);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const { formData, payload } = nextProps;
+ this.loadLayers(formData, payload);
+ }
+
+ loadLayers(formData, payload) {
+ this.setState({ subSlicesLayers: {} });
+ payload.data.slices.forEach((subslice) => {
+ // Filters applied to multi_deck are passed down to underlying charts
+ // note that dashboard contextual information (filter_immune_slices and such) aren't
+ // taken into consideration here
+ const filters = [
+ ...(subslice.form_data.filters || []),
+ ...(formData.filters || []),
+ ...(formData.extra_filters || []),
+ ];
+ const subsliceCopy = {
+ ...subslice,
+ form_data: {
+ ...subslice.form_data,
+ filters,
+ },
+ };
+ const url = getExploreLongUrl(subsliceCopy.form_data, 'json');
+ $.get(url, (data) => {
+ const layer = layerGenerators[subsliceCopy.form_data.viz_type](
+ subsliceCopy.form_data,
+ data,
+ );
+ this.setState({
+ subSlicesLayers: {
+ ...this.state.subSlicesLayers,
+ [subsliceCopy.slice_id]: layer,
+ },
+ });
+ });
+ });
+ }
+
+ render() {
+ const { payload, viewport, formData, setControlValue } = this.props;
+ const { subSlicesLayers } = this.state;
-function deckMulti(slice, payload, setControlValue) {
- const subSlicesLayers = {};
- const fd = slice.formData;
- const render = () => {
- const viewport = {
- ...fd.viewport,
- width: slice.width(),
- height: slice.height(),
- };
const layers = Object.keys(subSlicesLayers).map(k => subSlicesLayers[k]);
- ReactDOM.render(
+
+ return (
,
- document.getElementById(slice.containerId),
+ />
);
- };
- render();
- payload.data.slices.forEach((subslice) => {
- // Filters applied to multi_deck are passed down to underlying charts
- // note that dashboard contextual information (filter_immune_slices and such) aren't
- // taken into consideration here
- const filters = [
- ...(subslice.form_data.filters || []),
- ...(fd.filters || []),
- ...(fd.extra_filters || []),
- ];
- const subsliceCopy = {
- ...subslice,
- form_data: {
- ...subslice.form_data,
- filters,
- },
- };
-
- const url = getExploreLongUrl(subsliceCopy.form_data, 'json');
- $.get(url, (data) => {
- const layer = layerGenerators[subsliceCopy.form_data.viz_type](subsliceCopy.form_data, data);
- subSlicesLayers[subsliceCopy.slice_id] = layer;
- render();
- });
- });
+ }
}
-module.exports = deckMulti;
+
+DeckMulti.propTypes = propTypes;
+
+export default createAdaptor(DeckMulti);