diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/package.json b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/package.json
index f10175b43448..03b4bba1dc3f 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/package.json
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/package.json
@@ -1,7 +1,7 @@
{
- "name": "@superset-ui/plugins-monorepo",
+ "name": "@superset-ui/plugins-deckgl-monorepo",
"version": "0.0.0-master",
- "description": "Superset UI Plugins",
+ "description": "Superset UI Plugins - deck.gl",
"private": true,
"scripts": {
"build": "yarn build:cjs && yarn build:esm && yarn run type:dts && yarn build:assets",
@@ -24,7 +24,7 @@
"test": "yarn run type && yarn run jest",
"test:watch": "yarn run lint:fix && beemo create-config jest --react && jest --watch"
},
- "repository": "https://github.com/apache-superset/superset-ui-plugins.git",
+ "repository": "https://github.com/apache-superset/superset-ui-plugins-deckgl.git",
"keywords": [
"apache",
"superset",
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/Stories.tsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/Stories.tsx
deleted file mode 100644
index 403d09ae5dc6..000000000000
--- a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/Stories.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/* eslint-disable sort-keys, no-magic-numbers */
-import React from 'react';
-import { SuperChart } from '@superset-ui/chart';
-import data from './data';
-import dummyDatasource from '../../shared/dummyDatasource';
-
-export default [
- {
- renderStory: () => (
-
- ),
- storyName: 'Basic',
- storyPath: 'legacy-|plugin-chart-calendar|CalendarChartPlugin',
- },
-];
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/data.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/data.js
deleted file mode 100644
index b4a02b996efa..000000000000
--- a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/data.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/* eslint-disable sort-keys */
-export default {
- data: {
- count: {
- '1518652800.0': 3,
- '1518048000.0': 2,
- '1518220800.0': 2,
- '1523145600.0': 2,
- '1529798400.0': 2,
- '1534204800.0': 2,
- '1541289600.0': 2,
- '1542672000.0': 2,
- '1543881600.0': 2,
- '1517616000.0': 1,
- '1517875200.0': 1,
- '1517961600.0': 1,
- '1518307200.0': 1,
- '1518393600.0': 1,
- '1519257600.0': 1,
- '1519516800.0': 1,
- '1519776000.0': 1,
- '1520208000.0': 1,
- '1520294400.0': 1,
- '1520985600.0': 1,
- '1521072000.0': 1,
- '1521244800.0': 1,
- '1521331200.0': 1,
- '1521676800.0': 1,
- '1522108800.0': 1,
- '1522627200.0': 1,
- '1522800000.0': 1,
- '1522972800.0': 1,
- '1523491200.0': 1,
- '1524096000.0': 1,
- '1524268800.0': 1,
- '1524614400.0': 1,
- '1524960000.0': 1,
- '1525305600.0': 1,
- '1525564800.0': 1,
- '1525737600.0': 1,
- '1525824000.0': 1,
- '1525910400.0': 1,
- '1526083200.0': 1,
- '1526256000.0': 1,
- '1526688000.0': 1,
- '1527033600.0': 1,
- '1527292800.0': 1,
- '1527465600.0': 1,
- '1527638400.0': 1,
- '1528070400.0': 1,
- '1528329600.0': 1,
- '1529539200.0': 1,
- '1529625600.0': 1,
- '1529712000.0': 1,
- '1529971200.0': 1,
- '1530144000.0': 1,
- '1530576000.0': 1,
- '1531267200.0': 1,
- '1531353600.0': 1,
- '1531440000.0': 1,
- '1532736000.0': 1,
- '1533081600.0': 1,
- '1533168000.0': 1,
- '1533945600.0': 1,
- '1534377600.0': 1,
- '1534809600.0': 1,
- '1535155200.0': 1,
- '1535328000.0': 1,
- '1535932800.0': 1,
- '1536710400.0': 1,
- '1537056000.0': 1,
- '1537142400.0': 1,
- '1537488000.0': 1,
- '1537660800.0': 1,
- '1538611200.0': 1,
- '1538697600.0': 1,
- '1539475200.0': 1,
- '1540771200.0': 1,
- '1541116800.0': 1,
- '1541376000.0': 1,
- '1541635200.0': 1,
- '1542153600.0': 1,
- '1542931200.0': 1,
- '1543190400.0': 1,
- '1545177600.0': 1,
- '1545436800.0': 1,
- '1545782400.0': 1,
- '1545868800.0': 1,
- '1546300800.0': 1,
- '1546732800.0': 1,
- '1547769600.0': 1,
- '1547942400.0': 1,
- '1548633600.0': 1,
- },
- },
- start: 1517270400000.0,
- domain: 'month',
- range: 13,
- subdomain: 'day',
-};
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/index.js
deleted file mode 100644
index 8a8a7f1a4ea2..000000000000
--- a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-plugins-demo/storybook/stories/legacy-plugin-chart-calendar/index.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import CalendarChartPlugin from '../../../../superset-ui-legacy-plugin-chart-calendar';
-import Stories from './Stories';
-
-new CalendarChartPlugin().configure({ key: 'calendar' }).register();
-
-export default {
- examples: [...Stories],
-};
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/README.md b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/README.md
new file mode 100644
index 000000000000..2a009657924e
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/README.md
@@ -0,0 +1,43 @@
+## @superset-ui/legacy-preset-chart-nvd3
+
+[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-preset-chart-nvd3.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-preset-chart-nvd3.svg?style=flat-square)
+[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-preset-chart-nvd3&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-preset-chart-nvd3)
+
+This plugin provides Big Number for Superset.
+
+### Usage
+
+Import the preset and register. This will register all the chart plugins under nvd3.
+
+```js
+import { NVD3ChartPreset } from '@superset-ui/legacy-preset-chart-nvd3';
+
+new NVD3ChartPreset().register();
+```
+
+or register charts one by one. Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
+
+```js
+import { AreaChartPlugin, LineChartPlugin } from '@superset-ui/legacy-preset-chart-nvd3';
+
+new AreaChartPlugin()
+ .configure({ key: 'area' })
+ .register();
+new LineChartPlugin()
+ .configure({ key: 'line' })
+ .register();
+```
+
+Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-nvd3) for more details.
+
+```js
+
+```
\ No newline at end of file
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/package.json b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/package.json
new file mode 100644
index 000000000000..7f5a43e5b315
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@superset-ui/legacy-preset-chart-deckgl",
+ "version": "0.11.0",
+ "description": "Superset Legacy Chart - deck.gl",
+ "sideEffects": [
+ "*.css"
+ ],
+ "main": "lib/index.js",
+ "module": "esm/index.js",
+ "files": [
+ "esm",
+ "lib"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/apache-superset/superset-ui-plugins-deckgl.git"
+ },
+ "keywords": [
+ "superset"
+ ],
+ "author": "Superset",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/apache-superset/superset-ui-plugins-deckgl/issues"
+ },
+ "homepage": "https://github.com/apache-superset/superset-ui-plugins-deckgl#readme",
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "@data-ui/xy-chart": "^0.0.80",
+ "d3": "^3.5.17",
+ "d3-tip": "^0.9.1",
+ "dompurify": "^1.0.3",
+ "fast-safe-stringify": "^2.0.6",
+ "lodash": "^4.17.11",
+ "mathjs": "^3.20.2",
+ "moment": "^2.20.1",
+ "nvd3": "1.8.6",
+ "prop-types": "^15.6.2",
+ "urijs": "^1.18.10"
+ },
+ "peerDependencies": {
+ "@superset-ui/chart": "^0.12.0",
+ "@superset-ui/color": "^0.12.0",
+ "@superset-ui/core": "^0.12.0",
+ "@superset-ui/dimension": "^0.12.0",
+ "@superset-ui/number-format": "^0.12.0",
+ "@superset-ui/time-format": "^0.12.0",
+ "@superset-ui/translation": "^0.12.0",
+ "react": "^15 || ^16"
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/AnimatableDeckGLContainer.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/AnimatableDeckGLContainer.jsx
new file mode 100644
index 000000000000..fe2c7165db7c
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/AnimatableDeckGLContainer.jsx
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import DeckGLContainer from './DeckGLContainer';
+import PlaySlider from '../PlaySlider';
+
+const PLAYSLIDER_HEIGHT = 20; // px
+
+const propTypes = {
+ getLayers: PropTypes.func.isRequired,
+ start: PropTypes.number.isRequired,
+ end: PropTypes.number.isRequired,
+ getStep: PropTypes.func,
+ values: PropTypes.array.isRequired,
+ aggregation: PropTypes.bool,
+ disabled: PropTypes.bool,
+ viewport: PropTypes.object.isRequired,
+ children: PropTypes.node,
+ mapStyle: PropTypes.string,
+ mapboxApiAccessToken: PropTypes.string.isRequired,
+ setControlValue: PropTypes.func,
+ onViewportChange: PropTypes.func,
+ onValuesChange: PropTypes.func,
+};
+
+const defaultProps = {
+ aggregation: false,
+ disabled: false,
+ mapStyle: 'light',
+ setControlValue: () => {},
+ onViewportChange: () => {},
+ onValuesChange: () => {},
+};
+
+export default class AnimatableDeckGLContainer extends React.Component {
+ constructor(props) {
+ super(props);
+ this.onViewportChange = this.onViewportChange.bind(this);
+ }
+ onViewportChange(viewport) {
+ const originalViewport = this.props.disabled
+ ? { ...viewport }
+ : { ...viewport, height: viewport.height + PLAYSLIDER_HEIGHT };
+ this.props.onViewportChange(originalViewport);
+ }
+ render() {
+ const {
+ start,
+ end,
+ getStep,
+ disabled,
+ aggregation,
+ children,
+ getLayers,
+ values,
+ onValuesChange,
+ viewport,
+ setControlValue,
+ mapStyle,
+ mapboxApiAccessToken,
+ } = this.props;
+ const layers = getLayers(values);
+
+ // leave space for the play slider
+ const modifiedViewport = {
+ ...viewport,
+ height: disabled ? viewport.height : viewport.height - PLAYSLIDER_HEIGHT,
+ };
+
+ return (
+
+
+ {!disabled &&
+
+ }
+ {children}
+
+ );
+ }
+}
+
+AnimatableDeckGLContainer.propTypes = propTypes;
+AnimatableDeckGLContainer.defaultProps = defaultProps;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/CategoricalDeckGLContainer.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/CategoricalDeckGLContainer.jsx
new file mode 100644
index 000000000000..2a3e7b3c717a
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/CategoricalDeckGLContainer.jsx
@@ -0,0 +1,248 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { CategoricalColorNamespace } from '@superset-ui/color';
+import AnimatableDeckGLContainer from './AnimatableDeckGLContainer';
+import Legend from '../Legend';
+import { hexToRGB } from '../../modules/colors';
+import { getPlaySliderParams } from '../../modules/time';
+import sandboxedEval from '../../modules/sandbox';
+import { fitViewport } from './layers/common';
+
+const { getScale } = CategoricalColorNamespace;
+
+function getCategories(fd, data) {
+ 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 colorFn = getScale(fd.color_scheme);
+ const categories = {};
+ data.forEach((d) => {
+ if (d.cat_color != null && !categories.hasOwnProperty(d.cat_color)) {
+ let color;
+ if (fd.dimension) {
+ color = hexToRGB(colorFn(d.cat_color), c.a * 255);
+ } else {
+ color = fixedColor;
+ }
+ categories[d.cat_color] = { color, enabled: true };
+ }
+ });
+ return categories;
+}
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ mapboxApiKey: PropTypes.string.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ getLayer: PropTypes.func.isRequired,
+ getPoints: PropTypes.func.isRequired,
+ payload: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ setTooltip: PropTypes.func,
+};
+
+export default class CategoricalDeckGLContainer extends React.PureComponent {
+ /*
+ * A Deck.gl container that handles categories.
+ *
+ * The container will have an interactive legend, populated from the
+ * categories present in the data.
+ */
+ constructor(props) {
+ super(props);
+ this.state = this.getStateFromProps(props);
+
+ this.getLayers = this.getLayers.bind(this);
+ this.onValuesChange = this.onValuesChange.bind(this);
+ this.onViewportChange = this.onViewportChange.bind(this);
+ this.toggleCategory = this.toggleCategory.bind(this);
+ this.showSingleCategory = this.showSingleCategory.bind(this);
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ if (nextProps.payload.form_data !== this.state.formData) {
+ this.setState({ ...this.getStateFromProps(nextProps) });
+ }
+ }
+ onValuesChange(values) {
+ this.setState({
+ values: Array.isArray(values)
+ ? values
+ : [values, values + this.state.getStep(values)],
+ });
+ }
+ onViewportChange(viewport) {
+ this.setState({ viewport });
+ }
+ getStateFromProps(props, state) {
+ const features = props.payload.data.features || [];
+ const timestamps = features.map(f => f.__timestamp);
+ const categories = getCategories(props.formData, features);
+
+ // the state is computed only from the payload; if it hasn't changed, do
+ // not recompute state since this would reset selections and/or the play
+ // slider position due to changes in form controls
+ if (state && props.payload.form_data === state.formData) {
+ return { ...state, categories };
+ }
+
+ // the granularity has to be read from the payload form_data, not the
+ // props formData which comes from the instantaneous controls state
+ const granularity = (
+ props.payload.form_data.time_grain_sqla ||
+ props.payload.form_data.granularity ||
+ 'P1D'
+ );
+
+ const {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ } = getPlaySliderParams(timestamps, granularity);
+
+ const viewport = props.formData.autozoom
+ ? fitViewport(props.viewport, props.getPoints(features))
+ : props.viewport;
+
+ return {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ viewport,
+ selected: [],
+ lastClick: 0,
+ formData: props.payload.form_data,
+ categories,
+ };
+ }
+ getLayers(values) {
+ const {
+ getLayer,
+ payload,
+ formData: fd,
+ onAddFilter,
+ setTooltip,
+ } = this.props;
+ let features = payload.data.features
+ ? [...payload.data.features]
+ : [];
+
+ // Add colors from categories or fixed color
+ features = this.addColor(features, fd);
+
+ // Apply user defined data mutator if defined
+ if (fd.js_data_mutator) {
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ features = jsFnMutator(features);
+ }
+
+ // Filter by time
+ if (values[0] === values[1] || values[1] === this.end) {
+ features = features.filter(d => d.__timestamp >= values[0] && d.__timestamp <= values[1]);
+ } else {
+ features = features.filter(d => d.__timestamp >= values[0] && d.__timestamp < values[1]);
+ }
+
+ // Show only categories selected in the legend
+ const cats = this.state.categories;
+ if (fd.dimension) {
+ features = features.filter(d => cats[d.cat_color] && cats[d.cat_color].enabled);
+ }
+
+ const filteredPayload = {
+ ...payload,
+ data: { ...payload.data, features },
+ };
+
+ return [getLayer(fd, filteredPayload, onAddFilter, setTooltip)];
+ }
+ addColor(data, fd) {
+ const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
+ const colorFn = getScale(fd.color_scheme);
+ return data.map((d) => {
+ let color;
+ if (fd.dimension) {
+ color = hexToRGB(colorFn(d.cat_color), c.a * 255);
+ return { ...d, color };
+ }
+ return d;
+ });
+ }
+ toggleCategory(category) {
+ const categoryState = this.state.categories[category];
+ const categories = {
+ ...this.state.categories,
+ [category]: {
+ ...categoryState,
+ enabled: !categoryState.enabled,
+ },
+ };
+
+ // if all categories are disabled, enable all -- similar to nvd3
+ if (Object.values(categories).every(v => !v.enabled)) {
+ /* eslint-disable no-param-reassign */
+ Object.values(categories).forEach((v) => { v.enabled = true; });
+ }
+ this.setState({ categories });
+ }
+ showSingleCategory(category) {
+ const categories = { ...this.state.categories };
+ /* eslint-disable no-param-reassign */
+ Object.values(categories).forEach((v) => { v.enabled = false; });
+ categories[category].enabled = true;
+ this.setState({ categories });
+ }
+ render() {
+ return (
+
+ );
+ }
+}
+
+CategoricalDeckGLContainer.propTypes = propTypes;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/DeckGLContainer.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/DeckGLContainer.jsx
new file mode 100644
index 000000000000..ff414bfc0ad9
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/DeckGLContainer.jsx
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import MapGL from 'react-map-gl';
+import DeckGL from 'deck.gl';
+import 'mapbox-gl/dist/mapbox-gl.css';
+import { isEqual } from 'lodash';
+import '../stylesheets/deckgl.css';
+
+const TICK = 2000; // milliseconds
+
+const propTypes = {
+ viewport: PropTypes.object.isRequired,
+ layers: PropTypes.array.isRequired,
+ setControlValue: PropTypes.func,
+ mapStyle: PropTypes.string,
+ mapboxApiAccessToken: PropTypes.string.isRequired,
+ onViewportChange: PropTypes.func,
+};
+const defaultProps = {
+ mapStyle: 'light',
+ onViewportChange: () => {},
+ setControlValue: () => {},
+};
+
+export default class DeckGLContainer extends React.Component {
+ constructor(props) {
+ super(props);
+ this.tick = this.tick.bind(this);
+ this.onViewportChange = this.onViewportChange.bind(this);
+ // This has to be placed after this.tick is bound to this
+ this.state = {
+ previousViewport: props.viewport,
+ timer: setInterval(this.tick, TICK),
+ };
+ }
+ static getDerivedStateFromProps(nextProps, prevState) {
+ if (nextProps.viewport !== prevState.viewport) {
+ return {
+ viewport: { ...nextProps.viewport },
+ previousViewport: prevState.viewport,
+ };
+ }
+ return null;
+ }
+ componentWillUnmount() {
+ clearInterval(this.state.timer);
+ }
+ onViewportChange(viewport) {
+ const vp = Object.assign({}, viewport);
+ // delete vp.width;
+ // delete vp.height;
+ const newVp = { ...this.state.previousViewport, ...vp };
+
+ // this.setState(() => ({ viewport: newVp }));
+ this.props.onViewportChange(newVp);
+ }
+ tick() {
+ // Limiting updating viewport controls through Redux at most 1*sec
+ // Deep compare is needed as shallow equality doesn't work here, viewport object
+ // changes id at every change
+ if (this.state && !isEqual(this.state.previousViewport, this.props.viewport)) {
+ const setCV = this.props.setControlValue;
+ const vp = this.props.viewport;
+ if (setCV) {
+ setCV('viewport', vp);
+ }
+ this.setState(() => ({ previousViewport: this.props.viewport }));
+ }
+ }
+ layers() {
+ // Support for layer factory
+ if (this.props.layers.some(l => typeof l === 'function')) {
+ return this.props.layers.map(l => typeof l === 'function' ? l() : l);
+ }
+ return this.props.layers;
+ }
+ render() {
+ const { viewport } = this.props;
+ return (
+
+
+
+ );
+ }
+}
+
+DeckGLContainer.propTypes = propTypes;
+DeckGLContainer.defaultProps = defaultProps;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/Multi.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/Multi.jsx
new file mode 100644
index 000000000000..335ba3a7e02b
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/Multi.jsx
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import _ from 'lodash';
+import PropTypes from 'prop-types';
+import { SupersetClient } from '@superset-ui/connection';
+
+import DeckGLContainer from '../DeckGLContainer';
+import { getExploreLongUrl } from '../../../explore/exploreUtils';
+import layerGenerators from '../layers';
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ setTooltip: PropTypes.func,
+ onSelect: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ setTooltip() {},
+ onSelect() {},
+};
+
+class DeckMulti extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = { subSlicesLayers: {} };
+ this.onViewportChange = this.onViewportChange.bind(this);
+ }
+
+ componentDidMount() {
+ const { formData, payload } = this.props;
+ this.loadLayers(formData, payload);
+ }
+
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ const { formData, payload } = nextProps;
+ const hasChanges = !_.isEqual(this.props.formData.deck_slices, nextProps.formData.deck_slices);
+ if (hasChanges) {
+ this.loadLayers(formData, payload);
+ }
+ }
+
+ onViewportChange(viewport) {
+ this.setState({ viewport });
+ }
+
+ loadLayers(formData, payload, viewport) {
+ this.setState({ subSlicesLayers: {}, viewport });
+ 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,
+ },
+ };
+
+ SupersetClient.get({
+ endpoint: getExploreLongUrl(subsliceCopy.form_data, 'json'),
+ })
+ .then(({ json }) => {
+ const layer = layerGenerators[subsliceCopy.form_data.viz_type](
+ subsliceCopy.form_data,
+ json,
+ this.props.onAddFilter,
+ this.props.setTooltip,
+ [],
+ this.props.onSelect,
+ );
+ this.setState({
+ subSlicesLayers: {
+ ...this.state.subSlicesLayers,
+ [subsliceCopy.slice_id]: layer,
+ },
+ });
+ })
+ .catch(() => {});
+ });
+ }
+
+ render() {
+ const { payload, formData, setControlValue } = this.props;
+ const { subSlicesLayers } = this.state;
+
+ const layers = Object.values(subSlicesLayers);
+
+ return (
+
+ );
+ }
+}
+
+DeckMulti.propTypes = propTypes;
+DeckMulti.defaultProps = defaultProps;
+
+export default DeckMulti;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnail.png
new file mode 100644
index 000000000000..acedd5ba5145
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnailLarge.png
new file mode 100644
index 000000000000..21c27c048997
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/index.js
new file mode 100644
index 000000000000..c3cae628ac6c
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/Multi/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Multiple Layers'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class MultiChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Multi.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/TooltipRow.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/TooltipRow.jsx
new file mode 100644
index 000000000000..cc85bfd984ed
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/TooltipRow.jsx
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.string.isRequired,
+};
+
+
+export default class TooltipRow extends React.PureComponent {
+ render() {
+ return (
+ {this.props.label}{this.props.value}
+ );
+ }
+}
+
+TooltipRow.propTypes = propTypes;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/factory.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/factory.jsx
new file mode 100644
index 000000000000..abbdcca0db43
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/factory.jsx
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import { isEqual } from 'lodash';
+
+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,
+ setTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ setTooltip() {},
+};
+
+export function createDeckGLComponent(getLayer, getPoints) {
+ // Higher order component
+ class Component extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ const originalViewport = props.viewport;
+ const viewport = props.formData.autozoom
+ ? fitViewport(originalViewport, getPoints(props.payload.data.features))
+ : originalViewport;
+ this.state = {
+ viewport,
+ layer: this.computeLayer(props),
+ };
+ this.onViewportChange = this.onViewportChange.bind(this);
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ // Only recompute the layer if anything BUT the viewport has changed
+ const nextFdNoVP = { ...nextProps.formData, viewport: null };
+ const currFdNoVP = { ...this.props.formData, viewport: null };
+ if (
+ !isEqual(nextFdNoVP, currFdNoVP) ||
+ nextProps.payload !== this.props.payload
+ ) {
+ this.setState({ layer: this.computeLayer(nextProps) });
+ }
+ }
+ onViewportChange(viewport) {
+ this.setState({ viewport });
+ }
+ computeLayer(props) {
+ const {
+ formData,
+ payload,
+ onAddFilter,
+ setTooltip,
+ } = props;
+ return getLayer(formData, payload, onAddFilter, setTooltip);
+ }
+ render() {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ } = this.props;
+ const {
+ layer,
+ viewport,
+ } = this.state;
+ return (
+ );
+ }
+ }
+ Component.propTypes = propTypes;
+ Component.defaultProps = defaultProps;
+ return Component;
+}
+
+export function createCategoricalDeckGLComponent(getLayer, getPoints) {
+ function Component(props) {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ onAddFilter,
+ setTooltip,
+ viewport,
+ } = props;
+
+ return (
+
+ );
+ }
+
+ Component.propTypes = propTypes;
+ Component.defaultProps = defaultProps;
+
+ return Component;
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/index.js
new file mode 100644
index 000000000000..c98f3d1d65ad
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/index.js
@@ -0,0 +1,10 @@
+export { default as DeckGLChartPreset } from './preset';
+export { default as ArcChartPlugin } from './layers/Arc';
+export { default as GeoJsonChartPlugin } from './layers/Geojson';
+export { default as GridChartPlugin } from './layers/Grid';
+export { default as HexChartPlugin } from './layers/Hex';
+export { default as MultiChartPlugin } from './Multi';
+export { default as PathChartPlugin } from './layers/Path';
+export { default as PolygonChartPlugin } from './layers/Polygon';
+export { default as ScatterChartPlugin } from './layers/Scatter';
+export { default as ScreengridChartPlugin } from './layers/Screengrid';
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/Arc.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/Arc.jsx
new file mode 100644
index 000000000000..2c0a99b096ec
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/Arc.jsx
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ArcLayer } from 'deck.gl';
+import React from 'react';
+import { t } from '@superset-ui/translation';
+import { commonLayerProps } from '../common';
+import { createCategoricalDeckGLComponent } from '../../factory';
+import TooltipRow from '../../TooltipRow';
+
+function getPoints(data) {
+ const points = [];
+ data.forEach((d) => {
+ points.push(d.sourcePosition);
+ points.push(d.targetPosition);
+ });
+ return points;
+}
+
+function setTooltipContent(formData) {
+ return o => (
+
+
+
+ {
+ formData.dimension &&
+ }
+
+ );
+}
+
+export function getLayer(fd, payload, onAddFilter, setTooltip) {
+ const data = payload.data.features;
+ const sc = fd.color_picker;
+ const tc = fd.target_color_picker;
+ return new ArcLayer({
+ id: `path-layer-${fd.slice_id}`,
+ data,
+ 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,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent(fd)),
+ });
+}
+
+export default createCategoricalDeckGLComponent(getLayer, getPoints);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnail.png
new file mode 100644
index 000000000000..02b84b1e7535
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnailLarge.png
new file mode 100644
index 000000000000..f79f28349191
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/index.js
new file mode 100644
index 000000000000..8f597631da48
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Arc/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Arc'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class ArcChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Arc.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/Geojson.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/Geojson.jsx
new file mode 100644
index 000000000000..7488a3ddf56a
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/Geojson.jsx
@@ -0,0 +1,171 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import { GeoJsonLayer } from 'deck.gl';
+// TODO import geojsonExtent from 'geojson-extent';
+
+import DeckGLContainer from '../../DeckGLContainer';
+import { hexToRGB } from '../../../../modules/colors';
+import sandboxedEval from '../../../../modules/sandbox';
+import { commonLayerProps } from '../common';
+import TooltipRow from '../../TooltipRow';
+
+const propertyMap = {
+ fillColor: 'fillColor',
+ color: 'fillColor',
+ fill: 'fillColor',
+ 'fill-color': 'fillColor',
+ strokeColor: 'strokeColor',
+ 'stroke-color': 'strokeColor',
+ 'stroke-width': 'strokeWidth',
+};
+
+const alterProps = (props, propOverrides) => {
+ const newProps = {};
+ Object.keys(props).forEach((k) => {
+ if (k in propertyMap) {
+ newProps[propertyMap[k]] = props[k];
+ } else {
+ newProps[k] = props[k];
+ }
+ });
+ if (typeof props.fillColor === 'string') {
+ newProps.fillColor = hexToRGB(props.fillColor);
+ }
+ if (typeof props.strokeColor === 'string') {
+ newProps.strokeColor = hexToRGB(props.strokeColor);
+ }
+ return {
+ ...newProps,
+ ...propOverrides,
+ };
+};
+let features;
+const recurseGeoJson = (node, propOverrides, extraProps) => {
+ if (node && node.features) {
+ node.features.forEach((obj) => {
+ recurseGeoJson(obj, propOverrides, node.extraProps || extraProps);
+ });
+ }
+ if (node && node.geometry) {
+ const newNode = {
+ ...node,
+ properties: alterProps(node.properties, propOverrides),
+ };
+ if (!newNode.extraProps) {
+ newNode.extraProps = extraProps;
+ }
+ features.push(newNode);
+ }
+};
+
+function setTooltipContent(o) {
+ return (
+ o.object.extraProps &&
+
+ {
+ Object.keys(o.object.extraProps).map((prop, index) =>
+ ,
+ )
+ }
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip) {
+ const fd = formData;
+ const fc = fd.fill_color_picker;
+ const sc = fd.stroke_color_picker;
+ const fillColor = [fc.r, fc.g, fc.b, 255 * fc.a];
+ const strokeColor = [sc.r, sc.g, sc.b, 255 * sc.a];
+ const propOverrides = {};
+ if (fillColor[3] > 0) {
+ propOverrides.fillColor = fillColor;
+ }
+ if (strokeColor[3] > 0) {
+ propOverrides.strokeColor = strokeColor;
+ }
+
+ features = [];
+ recurseGeoJson(payload.data, propOverrides);
+
+ let jsFnMutator;
+ if (fd.js_data_mutator) {
+ // Applying user defined data mutator if defined
+ jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ features = jsFnMutator(features);
+ }
+
+ return new GeoJsonLayer({
+ id: `geojson-layer-${fd.slice_id}`,
+ filled: fd.filled,
+ data: features,
+ stroked: fd.stroked,
+ extruded: fd.extruded,
+ pointRadiusScale: fd.point_radius_scale,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent),
+ });
+}
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ setTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ setTooltip() {},
+};
+
+function deckGeoJson(props) {
+ const {
+ formData,
+ payload,
+ setControlValue,
+ onAddFilter,
+ setTooltip,
+ viewport,
+ } = props;
+
+ // TODO get this to work
+ // if (formData.autozoom) {
+ // viewport = common.fitViewport(viewport, geojsonExtent(payload.data.features));
+ // }
+
+ const layer = getLayer(formData, payload, onAddFilter, setTooltip);
+
+ return (
+
+ );
+}
+
+deckGeoJson.propTypes = propTypes;
+deckGeoJson.defaultProps = defaultProps;
+
+export default deckGeoJson;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnail.png
new file mode 100644
index 000000000000..9c1a732cd593
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnailLarge.png
new file mode 100644
index 000000000000..acc452cf0325
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/index.js
new file mode 100644
index 000000000000..06fded5de738
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Geojson/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Geojson'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class GeojsonChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Geojson.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/Grid.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/Grid.jsx
new file mode 100644
index 000000000000..a0cc8613faff
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/Grid.jsx
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { GridLayer } from 'deck.gl';
+import React from 'react';
+import { t } from '@superset-ui/translation';
+
+import { commonLayerProps, getAggFunc } from '../common';
+import sandboxedEval from '../../../../modules/sandbox';
+import { createDeckGLComponent } from '../../factory';
+import TooltipRow from '../../TooltipRow';
+
+function setTooltipContent(o) {
+ return (
+
+
+
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip) {
+ const fd = formData;
+ const c = fd.color_picker;
+ let data = payload.data.features.map(d => ({
+ ...d,
+ color: [c.r, c.g, c.b, 255 * c.a],
+ }));
+
+ if (fd.js_data_mutator) {
+ // Applying user defined data mutator if defined
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ data = jsFnMutator(data);
+ }
+
+ const aggFunc = getAggFunc(fd.js_agg_function, p => p.weight);
+ return new GridLayer({
+ id: `grid-layer-${fd.slice_id}`,
+ data,
+ pickable: true,
+ cellSize: fd.grid_size,
+ minColor: [0, 0, 0, 0],
+ extruded: fd.extruded,
+ maxColor: [c.r, c.g, c.b, 255 * c.a],
+ outline: false,
+ getElevationValue: aggFunc,
+ getColorValue: aggFunc,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent),
+ });
+}
+
+function getPoints(data) {
+ return data.map(d => d.position);
+}
+
+export default createDeckGLComponent(getLayer, getPoints);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnail.png
new file mode 100644
index 000000000000..2710d9f128db
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnailLarge.png
new file mode 100644
index 000000000000..cd9396510633
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/index.js
new file mode 100644
index 000000000000..291b967afcdb
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Grid/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Grid'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class GridChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Grid.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/Hex.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/Hex.jsx
new file mode 100644
index 000000000000..9901b22628bd
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/Hex.jsx
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { HexagonLayer } from 'deck.gl';
+import React from 'react';
+import { t } from '@superset-ui/translation';
+
+import { commonLayerProps, getAggFunc } from '../common';
+import sandboxedEval from '../../../../modules/sandbox';
+import { createDeckGLComponent } from '../../factory';
+import TooltipRow from '../../TooltipRow';
+
+function setTooltipContent(o) {
+ return (
+
+
+
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip) {
+ const fd = formData;
+ const c = fd.color_picker;
+ let data = payload.data.features.map(d => ({
+ ...d,
+ color: [c.r, c.g, c.b, 255 * c.a],
+ }));
+
+ if (fd.js_data_mutator) {
+ // Applying user defined data mutator if defined
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ data = jsFnMutator(data);
+ }
+ const aggFunc = getAggFunc(fd.js_agg_function, p => p.weight);
+ return new HexagonLayer({
+ id: `hex-layer-${fd.slice_id}`,
+ data,
+ pickable: true,
+ radius: fd.grid_size,
+ minColor: [0, 0, 0, 0],
+ extruded: fd.extruded,
+ maxColor: [c.r, c.g, c.b, 255 * c.a],
+ outline: false,
+ getElevationValue: aggFunc,
+ getColorValue: aggFunc,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent),
+ });
+}
+
+function getPoints(data) {
+ return data.map(d => d.position);
+}
+
+export default createDeckGLComponent(getLayer, getPoints);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnail.png
new file mode 100644
index 000000000000..99149dbc109d
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnailLarge.png
new file mode 100644
index 000000000000..31feff5c8fb0
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/index.js
new file mode 100644
index 000000000000..940ae5bac0e7
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Hex/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl 3D Hexagon'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class HexChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Hex.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/Path.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/Path.jsx
new file mode 100644
index 000000000000..7bf0982419e2
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/Path.jsx
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { PathLayer } from 'deck.gl';
+import React from 'react';
+import { commonLayerProps } from '../common';
+import sandboxedEval from '../../../../modules/sandbox';
+import { createDeckGLComponent } from '../../factory';
+import TooltipRow from '../../TooltipRow';
+
+function setTooltipContent(o) {
+ return (
+ o.object.extraProps &&
+
+ {
+ Object.keys(o.object.extraProps).map((prop, index) =>
+ ,
+ )
+ }
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip) {
+ const fd = formData;
+ const c = fd.color_picker;
+ const fixedColor = [c.r, c.g, c.b, 255 * c.a];
+ let data = payload.data.features.map(feature => ({
+ ...feature,
+ path: feature.path,
+ width: fd.line_width,
+ color: fixedColor,
+ }));
+
+ if (fd.js_data_mutator) {
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ data = jsFnMutator(data);
+ }
+
+ return new PathLayer({
+ id: `path-layer-${fd.slice_id}`,
+ data,
+ rounded: true,
+ widthScale: 1,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent),
+ });
+}
+
+function getPoints(data) {
+ let points = [];
+ data.forEach((d) => {
+ points = points.concat(d.path);
+ });
+ return points;
+}
+
+export default createDeckGLComponent(getLayer, getPoints);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnail.png
new file mode 100644
index 000000000000..d783a143312d
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnailLarge.png
new file mode 100644
index 000000000000..eede9da44ce7
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/index.js
new file mode 100644
index 000000000000..5b584c530a7d
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Path/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Path'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class PathChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Path.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx
new file mode 100644
index 000000000000..891856d04302
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx
@@ -0,0 +1,288 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { PolygonLayer } from 'deck.gl';
+
+import AnimatableDeckGLContainer from '../../AnimatableDeckGLContainer';
+import Legend from '../../../Legend';
+import TooltipRow from '../../TooltipRow';
+import { getBuckets, getBreakPointColorScaler } from '../../utils';
+
+import { commonLayerProps, fitViewport } from '../common';
+import { getPlaySliderParams } from '../../../../modules/time';
+import sandboxedEval from '../../../../modules/sandbox';
+
+const DOUBLE_CLICK_TRESHOLD = 250; // milliseconds
+
+function getPoints(features) {
+ return features.map(d => d.polygon).flat();
+}
+
+function getElevation(d, colorScaler) {
+ /* in deck.gl 5.3.4 (used in Superset as of 2018-10-24), if a polygon has
+ * opacity zero it will make everything behind it have opacity zero,
+ * effectively showing the map layer no matter what other polygons are
+ * behind it.
+ */
+ return colorScaler(d)[3] === 0
+ ? 0
+ : d.elevation;
+}
+
+function setTooltipContent(formData) {
+ return (o) => {
+ const metricLabel = formData.metric.label || formData.metric;
+ return (
+
+
+ {formData.metric && }
+
+ );
+ };
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip, selected, onSelect, filters) {
+ const fd = formData;
+ const fc = fd.fill_color_picker;
+ const sc = fd.stroke_color_picker;
+ let data = [...payload.data.features];
+
+ if (filters != null) {
+ filters.forEach((f) => {
+ data = data.filter(f);
+ });
+ }
+
+ if (fd.js_data_mutator) {
+ // Applying user defined data mutator if defined
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ data = jsFnMutator(data);
+ }
+
+ const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
+ const accessor = d => d[metricLabel];
+ // base color for the polygons
+ const baseColorScaler = fd.metric === null
+ ? () => [fc.r, fc.g, fc.b, 255 * fc.a]
+ : getBreakPointColorScaler(fd, data, accessor);
+
+ // when polygons are selected, reduce the opacity of non-selected polygons
+ const colorScaler = (d) => {
+ const baseColor = baseColorScaler(d);
+ if (selected.length > 0 && selected.indexOf(d[fd.line_column]) === -1) {
+ baseColor[3] /= 2;
+ }
+ return baseColor;
+ };
+ const tooltipContentGenerator = (fd.line_column && fd.metric && ['geohash', 'zipcode'].indexOf(fd.line_type) >= 0)
+ ? setTooltipContent(fd)
+ : undefined;
+ return new PolygonLayer({
+ id: `path-layer-${fd.slice_id}`,
+ data,
+ pickable: true,
+ filled: fd.filled,
+ stroked: fd.stroked,
+ getPolygon: d => d.polygon,
+ getFillColor: colorScaler,
+ getLineColor: [sc.r, sc.g, sc.b, 255 * sc.a],
+ getLineWidth: fd.line_width,
+ extruded: fd.extruded,
+ getElevation: d => getElevation(d, colorScaler),
+ elevationScale: fd.multiplier,
+ fp64: true,
+ ...commonLayerProps(fd, setTooltip, tooltipContentGenerator, onSelect),
+ });
+}
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ setTooltip: PropTypes.func,
+};
+
+const defaultProps = {
+ onAddFilter() {},
+ setTooltip() {},
+};
+
+class DeckGLPolygon extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = DeckGLPolygon.getDerivedStateFromProps(props);
+
+ this.getLayers = this.getLayers.bind(this);
+ this.onSelect = this.onSelect.bind(this);
+ this.onValuesChange = this.onValuesChange.bind(this);
+ this.onViewportChange = this.onViewportChange.bind(this);
+ }
+ static getDerivedStateFromProps(props, state) {
+ // the state is computed only from the payload; if it hasn't changed, do
+ // not recompute state since this would reset selections and/or the play
+ // slider position due to changes in form controls
+ if (state && props.payload.form_data === state.formData) {
+ return null;
+ }
+
+ const features = props.payload.data.features || [];
+ const timestamps = features.map(f => f.__timestamp);
+
+ // the granularity has to be read from the payload form_data, not the
+ // props formData which comes from the instantaneous controls state
+ const granularity = (
+ props.payload.form_data.time_grain_sqla ||
+ props.payload.form_data.granularity ||
+ 'P1D'
+ );
+
+ const {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ } = getPlaySliderParams(timestamps, granularity);
+
+ const viewport = props.formData.autozoom
+ ? fitViewport(props.viewport, getPoints(features))
+ : props.viewport;
+
+ return {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ viewport,
+ selected: [],
+ lastClick: 0,
+ formData: props.payload.form_data,
+ };
+ }
+ onSelect(polygon) {
+ const { formData, onAddFilter } = this.props;
+
+ const now = new Date();
+ const doubleClick = (now - this.state.lastClick) <= DOUBLE_CLICK_TRESHOLD;
+
+ // toggle selected polygons
+ const selected = [...this.state.selected];
+ if (doubleClick) {
+ selected.splice(0, selected.length, polygon);
+ } else if (formData.toggle_polygons) {
+ const i = selected.indexOf(polygon);
+ if (i === -1) {
+ selected.push(polygon);
+ } else {
+ selected.splice(i, 1);
+ }
+ } else {
+ selected.splice(0, 1, polygon);
+ }
+
+ this.setState({ selected, lastClick: now });
+ if (formData.table_filter) {
+ onAddFilter(formData.line_column, selected, false, true);
+ }
+ }
+ onValuesChange(values) {
+ this.setState({
+ values: Array.isArray(values)
+ ? values
+ : [values, values + this.state.getStep(values)],
+ });
+ }
+ onViewportChange(viewport) {
+ this.setState({ viewport });
+ }
+ getLayers(values) {
+ if (this.props.payload.data.features === undefined) {
+ return [];
+ }
+
+ const filters = [];
+
+ // time filter
+ if (values[0] === values[1] || values[1] === this.end) {
+ filters.push(d => d.__timestamp >= values[0] && d.__timestamp <= values[1]);
+ } else {
+ filters.push(d => d.__timestamp >= values[0] && d.__timestamp < values[1]);
+ }
+
+ const layer = getLayer(
+ this.props.formData,
+ this.props.payload,
+ this.props.onAddFilter,
+ this.props.setTooltip,
+ this.state.selected,
+ this.onSelect,
+ filters);
+
+ return [layer];
+ }
+ render() {
+ const { payload, formData, setControlValue } = this.props;
+ const { start, end, getStep, values, disabled, viewport } = this.state;
+
+ const fd = formData;
+ const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
+ const accessor = d => d[metricLabel];
+
+ const buckets = getBuckets(formData, payload.data.features, accessor);
+ return (
+
+
+ {formData.metric !== null &&
+ }
+
+
+ );
+ }
+}
+
+DeckGLPolygon.propTypes = propTypes;
+DeckGLPolygon.defaultProps = defaultProps;
+
+export default DeckGLPolygon;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnail.png
new file mode 100644
index 000000000000..b32c540e8ba1
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnailLarge.png
new file mode 100644
index 000000000000..dfae8616ffac
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/index.js
new file mode 100644
index 000000000000..4b5f7c051365
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Polygon/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Polygon'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class PolygonChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Polygon.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx
new file mode 100644
index 000000000000..42dd7c8df4a8
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ScatterplotLayer } from 'deck.gl';
+import React from 'react';
+import { t } from '@superset-ui/translation';
+import { commonLayerProps } from '../common';
+import { createCategoricalDeckGLComponent } from '../../factory';
+import TooltipRow from '../../TooltipRow';
+import { unitToRadius } from '../../../../modules/geo';
+
+function getPoints(data) {
+ return data.map(d => d.position);
+}
+
+function setTooltipContent(formData) {
+ return o => (
+
+
+ {
+ o.object.cat_color &&
+ }
+ {
+ o.object.metric &&
+ }
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip) {
+ const fd = formData;
+ const dataWithRadius = payload.data.features.map((d) => {
+ let radius = unitToRadius(fd.point_unit, d.radius) || 10;
+ if (fd.multiplier) {
+ radius *= fd.multiplier;
+ }
+ if (d.color) {
+ return { ...d, radius };
+ }
+ const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
+ const color = [c.r, c.g, c.b, c.a * 255];
+ return { ...d, radius, color };
+ });
+
+ return new ScatterplotLayer({
+ id: `scatter-layer-${fd.slice_id}`,
+ data: dataWithRadius,
+ fp64: true,
+ radiusMinPixels: fd.min_radius || null,
+ radiusMaxPixels: fd.max_radius || null,
+ outline: false,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent(fd)),
+ });
+}
+
+export default createCategoricalDeckGLComponent(getLayer, getPoints);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnail.png
new file mode 100644
index 000000000000..a111a158abc7
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnailLarge.png
new file mode 100644
index 000000000000..11f38ccc8dbf
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/index.js
new file mode 100644
index 000000000000..093a751d5e9d
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Scatter/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Scatterplot'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class ScatterChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Scatter.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx
new file mode 100644
index 000000000000..d9fba4c70439
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { ScreenGridLayer } from 'deck.gl';
+import { t } from '@superset-ui/translation';
+import AnimatableDeckGLContainer from '../../AnimatableDeckGLContainer';
+import { getPlaySliderParams } from '../../../../modules/time';
+import sandboxedEval from '../../../../modules/sandbox';
+import { commonLayerProps, fitViewport } from '../common';
+import TooltipRow from '../../TooltipRow';
+
+function getPoints(data) {
+ return data.map(d => d.position);
+}
+
+function setTooltipContent(o) {
+ return (
+
+
+
+
+ );
+}
+
+export function getLayer(formData, payload, onAddFilter, setTooltip, selected, onSelect, filters) {
+ const fd = formData;
+ const c = fd.color_picker;
+ let data = payload.data.features.map(d => ({
+ ...d,
+ color: [c.r, c.g, c.b, 255 * c.a],
+ }));
+
+ if (fd.js_data_mutator) {
+ // Applying user defined data mutator if defined
+ const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+ data = jsFnMutator(data);
+ }
+
+ if (filters != null) {
+ filters.forEach((f) => {
+ data = data.filter(f);
+ });
+ }
+
+ // Passing a layer creator function instead of a layer since the
+ // layer needs to be regenerated at each render
+ return new ScreenGridLayer({
+ id: `screengrid-layer-${fd.slice_id}`,
+ data,
+ pickable: true,
+ cellSizePixels: fd.grid_size,
+ minColor: [c.r, c.g, c.b, 0],
+ maxColor: [c.r, c.g, c.b, 255 * c.a],
+ outline: false,
+ getWeight: d => d.weight || 0,
+ ...commonLayerProps(fd, setTooltip, setTooltipContent),
+ });
+}
+
+const propTypes = {
+ formData: PropTypes.object.isRequired,
+ payload: PropTypes.object.isRequired,
+ setControlValue: PropTypes.func.isRequired,
+ viewport: PropTypes.object.isRequired,
+ onAddFilter: PropTypes.func,
+ setTooltip: PropTypes.func,
+};
+const defaultProps = {
+ onAddFilter() {},
+ setTooltip() {},
+};
+
+class DeckGLScreenGrid extends React.PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = DeckGLScreenGrid.getDerivedStateFromProps(props);
+
+ this.getLayers = this.getLayers.bind(this);
+ this.onValuesChange = this.onValuesChange.bind(this);
+ this.onViewportChange = this.onViewportChange.bind(this);
+ }
+ static getDerivedStateFromProps(props, state) {
+ // the state is computed only from the payload; if it hasn't changed, do
+ // not recompute state since this would reset selections and/or the play
+ // slider position due to changes in form controls
+ if (state && props.payload.form_data === state.formData) {
+ return null;
+ }
+
+ const features = props.payload.data.features || [];
+ const timestamps = features.map(f => f.__timestamp);
+
+ // the granularity has to be read from the payload form_data, not the
+ // props formData which comes from the instantaneous controls state
+ const granularity = (
+ props.payload.form_data.time_grain_sqla ||
+ props.payload.form_data.granularity ||
+ 'P1D'
+ );
+
+ const {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ } = getPlaySliderParams(timestamps, granularity);
+
+ const viewport = props.formData.autozoom
+ ? fitViewport(props.viewport, getPoints(features))
+ : props.viewport;
+
+ return {
+ start,
+ end,
+ getStep,
+ values,
+ disabled,
+ viewport,
+ selected: [],
+ lastClick: 0,
+ formData: props.payload.form_data,
+ };
+ }
+ onValuesChange(values) {
+ this.setState({
+ values: Array.isArray(values)
+ ? values
+ : [values, values + this.state.getStep(values)],
+ });
+ }
+ onViewportChange(viewport) {
+ this.setState({ viewport });
+ }
+ getLayers(values) {
+ const filters = [];
+
+ // time filter
+ if (values[0] === values[1] || values[1] === this.end) {
+ filters.push(d => d.__timestamp >= values[0] && d.__timestamp <= values[1]);
+ } else {
+ filters.push(d => d.__timestamp >= values[0] && d.__timestamp < values[1]);
+ }
+
+ const layer = getLayer(
+ this.props.formData,
+ this.props.payload,
+ this.props.onAddFilter,
+ this.props.setTooltip,
+ filters);
+
+ return [layer];
+ }
+
+ render() {
+ const { formData, payload, setControlValue } = this.props;
+ return (
+
+ );
+ }
+}
+
+DeckGLScreenGrid.propTypes = propTypes;
+DeckGLScreenGrid.defaultProps = defaultProps;
+
+export default DeckGLScreenGrid;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnail.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnail.png
new file mode 100644
index 000000000000..78a26e67c14f
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnail.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnailLarge.png b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnailLarge.png
new file mode 100644
index 000000000000..d5da29c99be9
Binary files /dev/null and b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/images/thumbnailLarge.png differ
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/index.js
new file mode 100644
index 000000000000..dc96758fca5c
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/Screengrid/index.js
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { t } from '@superset-ui/translation';
+import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
+import thumbnail from './images/thumbnail.png';
+import transformProps from '../../transformProps';
+
+const metadata = new ChartMetadata({
+ name: t('deck.gl Screen Grid'),
+ description: '',
+ credits: ['https://uber.github.io/deck.gl'],
+ thumbnail,
+});
+
+export default class ScreengridChartPlugin extends ChartPlugin {
+ constructor() {
+ super({
+ metadata,
+ loadChart: () => import('./Screengrid.jsx'),
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/common.jsx b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/common.jsx
new file mode 100644
index 000000000000..aaee55361500
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/common.jsx
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { fitBounds } from 'viewport-mercator-project';
+import * as d3array from 'd3-array';
+import sandboxedEval from '../../../modules/sandbox';
+
+const PADDING = 0.25;
+const GEO_BOUNDS = {
+ LAT_MIN: -90,
+ LAT_MAX: 90,
+ LNG_MIN: -180,
+ LNG_MAX: 180,
+};
+
+/**
+ * Get the latitude bounds if latitude is a single coordinate
+ * @param latExt Latitude range
+ */
+function getLatBoundsForSingleCoordinate(latExt) {
+ const latMin = latExt[0] - PADDING < GEO_BOUNDS.LAT_MIN
+ ? GEO_BOUNDS.LAT_MIN
+ : latExt[0] - PADDING;
+ const latMax = latExt[1] + PADDING > GEO_BOUNDS.LAT_MAX
+ ? GEO_BOUNDS.LAT_MAX
+ : latExt[1] + PADDING;
+ return [latMin, latMax];
+}
+
+/**
+ * Get the longitude bounds if longitude is a single coordinate
+ * @param lngExt Longitude range
+ */
+function getLngBoundsForSingleCoordinate(lngExt) {
+ const lngMin = lngExt[0] - PADDING < GEO_BOUNDS.LNG_MIN
+ ? GEO_BOUNDS.LNG_MIN
+ : lngExt[0] - PADDING;
+ const lngMax = lngExt[1] + PADDING > GEO_BOUNDS.LNG_MAX
+ ? GEO_BOUNDS.LNG_MAX
+ : lngExt[1] + PADDING;
+ return [lngMin, lngMax];
+}
+
+export function getBounds(points) {
+ const latExt = d3array.extent(points, d => d[1]);
+ const lngExt = d3array.extent(points, d => d[0]);
+ const latBounds = latExt[0] === latExt[1] ? getLatBoundsForSingleCoordinate(latExt) : latExt;
+ const lngBounds = lngExt[0] === lngExt[1] ? getLngBoundsForSingleCoordinate(lngExt) : lngExt;
+ return [
+ [lngBounds[0], latBounds[0]],
+ [lngBounds[1], latBounds[1]],
+ ];
+}
+
+export function fitViewport(viewport, points, padding = 10) {
+ try {
+ const bounds = getBounds(points);
+ return {
+ ...viewport,
+ ...fitBounds({
+ height: viewport.height,
+ width: viewport.width,
+ padding,
+ bounds,
+ }),
+ };
+ } catch (e) {
+ /* eslint no-console: 0 */
+ console.error('Could not auto zoom', e);
+ return viewport;
+ }
+}
+
+export function commonLayerProps(formData, setTooltip, setTooltipContent, onSelect) {
+ const fd = formData;
+ let onHover;
+ let tooltipContentGenerator = setTooltipContent;
+ if (fd.js_tooltip) {
+ tooltipContentGenerator = sandboxedEval(fd.js_tooltip);
+ }
+ if (tooltipContentGenerator) {
+ onHover = (o) => {
+ if (o.picked) {
+ setTooltip({
+ content: tooltipContentGenerator(o),
+ x: o.x,
+ y: o.y + 30,
+ });
+ } else {
+ setTooltip(null);
+ }
+ };
+ }
+ let onClick;
+ if (fd.js_onclick_href) {
+ onClick = (o) => {
+ const href = sandboxedEval(fd.js_onclick_href)(o);
+ window.open(href);
+ };
+ } else if (fd.table_filter && onSelect !== undefined) {
+ onClick = o => onSelect(o.object[fd.line_column]);
+ }
+ return {
+ onClick,
+ onHover,
+ pickable: Boolean(onHover),
+ };
+}
+
+const percentiles = {
+ p1: 0.01,
+ p5: 0.05,
+ p95: 0.95,
+ p99: 0.99,
+};
+
+/* Get an a stat function that operates on arrays, aligns with control=js_agg_function */
+export function getAggFunc(type = 'sum', accessor = null) {
+ if (type === 'count') {
+ return arr => arr.length;
+ }
+ let d3func;
+ if (type in percentiles) {
+ d3func = (arr, acc) => {
+ let sortedArr;
+ if (accessor) {
+ sortedArr = arr.sort((o1, o2) => d3array.ascending(accessor(o1), accessor(o2)));
+ } else {
+ sortedArr = arr.sort(d3array.ascending);
+ }
+ return d3array.quantile(sortedArr, percentiles[type], acc);
+ };
+ } else {
+ d3func = d3array[type];
+ }
+ if (!accessor) {
+ return arr => d3func(arr);
+ }
+ return arr => d3func(arr.map(accessor));
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/index.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/index.js
new file mode 100644
index 000000000000..b77d5bd12c49
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/layers/index.js
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/* eslint camelcase: 0 */
+import { getLayer as deck_grid } from './Grid/Grid';
+import { getLayer as deck_screengrid } from './Screengrid/Screengrid';
+import { getLayer as deck_path } from './Path/Path';
+import { getLayer as deck_hex } from './Hex/Hex';
+import { getLayer as deck_scatter } from './Scatter/Scatter';
+import { getLayer as deck_geojson } from './Geojson/Geojson';
+import { getLayer as deck_arc } from './Arc/Arc';
+import { getLayer as deck_polygon } from './Polygon/Polygon';
+
+const layerGenerators = {
+ deck_grid,
+ deck_screengrid,
+ deck_path,
+ deck_hex,
+ deck_scatter,
+ deck_geojson,
+ deck_arc,
+ deck_polygon,
+};
+
+export default layerGenerators;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/preset.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/preset.js
new file mode 100644
index 000000000000..9360bb44d38e
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/preset.js
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { Preset } from '@superset-ui/core';
+import ArcChartPlugin from './layers/Arc';
+import GeoJsonChartPlugin from './layers/Geojson';
+import GridChartPlugin from './layers/Grid';
+import HexChartPlugin from './layers/Hex';
+import MultiChartPlugin from './Multi';
+import PathChartPlugin from './layers/Path';
+import PolygonChartPlugin from './layers/Polygon';
+import ScatterChartPlugin from './layers/Scatter';
+import ScreengridChartPlugin from './layers/Screengrid';
+
+export default class DeckGLChartPreset extends Preset {
+ constructor() {
+ super({
+ name: 'deck.gl charts',
+ plugins: [
+ new ArcChartPlugin().configure({ key: 'deck_arc' }),
+ new GeoJsonChartPlugin().configure({ key: 'deck_geojson' }),
+ new GridChartPlugin().configure({ key: 'deck_grid' }),
+ new HexChartPlugin().configure({ key: 'deck_hex' }),
+ new MultiChartPlugin().configure({ key: 'deck_multi' }),
+ new PathChartPlugin().configure({ key: 'deck_path' }),
+ new PolygonChartPlugin().configure({ key: 'deck_polygon' }),
+ new ScatterChartPlugin().configure({ key: 'deck_scatter' }),
+ new ScreengridChartPlugin().configure({ key: 'deck_screengrid' }),
+ ],
+ });
+ }
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/transformProps.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/transformProps.js
new file mode 100644
index 000000000000..9e7350baed17
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/transformProps.js
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+const NOOP = () => {};
+
+export default function transformProps(chartProps) {
+ const {
+ width,
+ height,
+ rawFormData,
+ queryData,
+ hooks,
+ } = chartProps;
+ const { onAddFilter = NOOP, setControlValue = NOOP, setTooltip = NOOP } = hooks;
+
+ return {
+ formData: rawFormData,
+ payload: queryData,
+ setControlValue,
+ viewport: {
+ ...rawFormData.viewport,
+ width,
+ height,
+ },
+ onAddFilter,
+ setTooltip,
+ };
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/utils.js b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/utils.js
new file mode 100644
index 000000000000..246e31b46c71
--- /dev/null
+++ b/superset-frontend/temporary_superset_ui/superset-ui-plugins-deckgl/packages/superset-ui-preset-chart-deckgl/src/utils.js
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { extent } from 'd3-array';
+import { scaleThreshold } from 'd3-scale';
+import { getSequentialSchemeRegistry, SequentialScheme } from '@superset-ui/color';
+import { hexToRGB } from '../../modules/colors';
+
+const DEFAULT_NUM_BUCKETS = 10;
+
+export function getBreakPoints(
+ { break_points: formDataBreakPoints, num_buckets: formDataNumBuckets },
+ features,
+ accessor,
+) {
+ if (!features) {
+ return [];
+ }
+ if (formDataBreakPoints === undefined || formDataBreakPoints.length === 0) {
+ // compute evenly distributed break points based on number of buckets
+ const numBuckets = formDataNumBuckets ? parseInt(formDataNumBuckets, 10) : DEFAULT_NUM_BUCKETS;
+ const [minValue, maxValue] = extent(features, accessor);
+ if (minValue === undefined) {
+ return [];
+ }
+ const delta = (maxValue - minValue) / numBuckets;
+ const precision = delta === 0 ? 0 : Math.max(0, Math.ceil(Math.log10(1 / delta)));
+ const extraBucket = maxValue > maxValue.toFixed(precision) ? 1 : 0;
+
+return Array(numBuckets + 1 + extraBucket)
+ .fill()
+ .map((_, i) => (minValue + i * delta).toFixed(precision));
+ }
+
+return formDataBreakPoints.sort((a, b) => parseFloat(a) - parseFloat(b));
+}
+
+export function getBreakPointColorScaler(
+ {
+ break_points: formDataBreakPoints,
+ num_buckets: formDataNumBuckets,
+ linear_color_scheme: linearColorScheme,
+ opacity,
+ },
+ features,
+ accessor,
+) {
+ const breakPoints =
+ formDataBreakPoints || formDataNumBuckets
+ ? getBreakPoints(
+ {
+ break_points: formDataBreakPoints,
+ num_buckets: formDataNumBuckets,
+ },
+ features,
+ accessor,
+ )
+ : null;
+ const colorScheme = Array.isArray(linearColorScheme)
+ ? new SequentialScheme({
+ id: 'custom',
+ colors: linearColorScheme,
+ })
+ : getSequentialSchemeRegistry().get(linearColorScheme);
+
+ let scaler;
+ let maskPoint;
+ if (breakPoints !== null) {
+ // bucket colors into discrete colors
+ const n = breakPoints.length - 1;
+ const bucketedColors =
+ n > 1 ? colorScheme.getColors(n) : [colorScheme.colors[colorScheme.colors.length - 1]];
+
+ // repeat ends
+ const first = bucketedColors[0];
+ const last = bucketedColors[bucketedColors.length - 1];
+ bucketedColors.unshift(first);
+ bucketedColors.push(last);
+
+ const points = breakPoints.map(p => parseFloat(p));
+ scaler = scaleThreshold()
+ .domain(points)
+ .range(bucketedColors);
+ maskPoint = value => value > breakPoints[n] || value < breakPoints[0];
+ } else {
+ // interpolate colors linearly
+ scaler = colorScheme.createLinearScale(extent(features, accessor));
+ maskPoint = () => false;
+ }
+
+ return d => {
+ const v = accessor(d);
+ const c = hexToRGB(scaler(v));
+ if (maskPoint(v)) {
+ c[3] = 0;
+ } else {
+ c[3] = (opacity / 100.0) * 255;
+ }
+
+return c;
+ };
+}
+
+export function getBuckets(fd, features, accessor) {
+ const breakPoints = getBreakPoints(fd, features, accessor);
+ const colorScaler = getBreakPointColorScaler(fd, features, accessor);
+ const buckets = {};
+ breakPoints.slice(1).forEach((value, i) => {
+ const range = `${breakPoints[i] } - ${ breakPoints[i + 1]}`;
+ const mid = 0.5 * (parseFloat(breakPoints[i]) + parseFloat(breakPoints[i + 1]));
+ // fix polygon doesn't show
+ const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
+ buckets[range] = {
+ color: colorScaler({ [metricLabel || fd.metric]: mid }),
+ enabled: true,
+ };
+ });
+
+return buckets;
+}