mistercrunch closed pull request #4389: [geo] introduce "Auto Zoom" control
URL: https://github.com/apache/incubator-superset/pull/4389
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/superset/assets/javascripts/chart/Chart.jsx 
b/superset/assets/javascripts/chart/Chart.jsx
index 7bb71aca47..cc18bb4fe6 100644
--- a/superset/assets/javascripts/chart/Chart.jsx
+++ b/superset/assets/javascripts/chart/Chart.jsx
@@ -188,6 +188,7 @@ class Chart extends React.PureComponent {
       });
       this.props.actions.chartRenderingSucceeded(this.props.chartKey);
     } catch (e) {
+      console.error(e);  // eslint-disable-line
       this.props.actions.chartRenderingFailed(e, this.props.chartKey);
     }
   }
diff --git 
a/superset/assets/javascripts/explore/components/controls/TextControl.jsx 
b/superset/assets/javascripts/explore/components/controls/TextControl.jsx
index bfe3f99177..ed1238e509 100644
--- a/superset/assets/javascripts/explore/components/controls/TextControl.jsx
+++ b/superset/assets/javascripts/explore/components/controls/TextControl.jsx
@@ -13,6 +13,7 @@ const propTypes = {
   ]),
   isFloat: PropTypes.bool,
   isInt: PropTypes.bool,
+  disabled: PropTypes.bool,
 };
 
 const defaultProps = {
@@ -21,6 +22,7 @@ const defaultProps = {
   value: '',
   isInt: false,
   isFloat: false,
+  disabled: false,
 };
 
 export default class TextControl extends React.Component {
@@ -63,6 +65,7 @@ export default class TextControl extends React.Component {
             onChange={this.onChange}
             onFocus={this.props.onFocus}
             value={value}
+            disabled={this.props.disabled}
           />
         </FormGroup>
       </div>
diff --git a/superset/assets/javascripts/explore/stores/controls.jsx 
b/superset/assets/javascripts/explore/stores/controls.jsx
index 8e3420bd81..e8a34d950d 100644
--- a/superset/assets/javascripts/explore/stores/controls.jsx
+++ b/superset/assets/javascripts/explore/stores/controls.jsx
@@ -331,6 +331,14 @@ export const controls = {
     default: false,
   },
 
+  autozoom: {
+    type: 'CheckboxControl',
+    label: t('Auto Zoom'),
+    default: true,
+    renderTrigger: true,
+    description: t('When checked, the map will zoom to your data after each 
query'),
+  },
+
   show_perc: {
     type: 'CheckboxControl',
     label: t('Show percentage'),
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js 
b/superset/assets/javascripts/explore/stores/visTypes.js
index 9d62eada88..3135b2613d 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -369,7 +369,7 @@ export const visTypes = {
         label: t('Map'),
         controlSetRows: [
           ['mapbox_style', 'viewport'],
-          ['color_picker', null],
+          ['color_picker', 'autozoom'],
           ['grid_size', 'extruded'],
         ],
       },
@@ -407,7 +407,7 @@ export const visTypes = {
         label: t('Map'),
         controlSetRows: [
           ['mapbox_style', 'viewport'],
-          ['color_picker', null],
+          ['color_picker', 'autozoom'],
           ['grid_size', 'extruded'],
         ],
       },
@@ -448,7 +448,7 @@ export const visTypes = {
         controlSetRows: [
           ['mapbox_style', 'viewport'],
           ['color_picker', 'line_width'],
-          ['reverse_long_lat', null],
+          ['reverse_long_lat', 'autozoom'],
         ],
       },
       {
@@ -479,6 +479,7 @@ export const visTypes = {
         label: t('Map'),
         controlSetRows: [
           ['mapbox_style', 'viewport'],
+          ['autozoom', null],
         ],
       },
       {
@@ -521,6 +522,7 @@ export const visTypes = {
         label: t('Map'),
         controlSetRows: [
           ['mapbox_style', 'viewport'],
+          // TODO ['autozoom', null],
         ],
       },
       {
@@ -600,6 +602,7 @@ export const visTypes = {
         label: t('Map'),
         controlSetRows: [
           ['mapbox_style', 'viewport'],
+          ['autozoom', null],
         ],
       },
       {
@@ -635,8 +638,10 @@ export const visTypes = {
       },
       {
         label: t('Map'),
+        expanded: true,
         controlSetRows: [
           ['mapbox_style', 'viewport'],
+          ['autozoom', null],
         ],
       },
       {
diff --git a/superset/assets/package.json b/superset/assets/package.json
index abc978c079..fbfa32a27d 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -60,6 +60,7 @@
     "distributions": "^1.0.0",
     "dompurify": "^1.0.3",
     "fastdom": "^1.0.6",
+    "geojson-extent": "^0.3.2",
     "geolib": "^2.0.24",
     "immutable": "^3.8.2",
     "jed": "^1.1.1",
@@ -105,7 +106,7 @@
     "supercluster": 
"https://github.com/georgeke/supercluster/tarball/ac3492737e7ce98e07af679623aad452373bbc40";,
     "underscore": "^1.8.3",
     "urijs": "^1.18.10",
-    "viewport-mercator-project": "^2.1.0"
+    "viewport-mercator-project": "^5.0.0"
   },
   "devDependencies": {
     "babel-cli": "^6.14.0",
@@ -137,6 +138,7 @@
     "less": "^2.6.1",
     "less-loader": "^4.0.3",
     "mocha": "^3.2.0",
+    "npm-check-updates": "^2.14.0",
     "react-addons-test-utils": "^15.6.2",
     "react-test-renderer": "^15.6.2",
     "redux-mock-store": "^1.2.3",
diff --git a/superset/assets/visualizations/deckgl/DeckGLContainer.jsx 
b/superset/assets/visualizations/deckgl/DeckGLContainer.jsx
index 3166917744..1b7ca317ca 100644
--- a/superset/assets/visualizations/deckgl/DeckGLContainer.jsx
+++ b/superset/assets/visualizations/deckgl/DeckGLContainer.jsx
@@ -33,6 +33,7 @@ export default class DeckGLContainer extends React.Component {
   componentWillReceiveProps(nextProps) {
     this.setState(() => ({
       viewport: { ...nextProps.viewport },
+      previousViewport: this.state.viewport,
     }));
   }
   componentWillUnmount() {
diff --git a/superset/assets/visualizations/deckgl/layers/arc.jsx 
b/superset/assets/visualizations/deckgl/layers/arc.jsx
index ebeff3cb89..43583e0170 100644
--- a/superset/assets/visualizations/deckgl/layers/arc.jsx
+++ b/superset/assets/visualizations/deckgl/layers/arc.jsx
@@ -8,6 +8,15 @@ import DeckGLContainer from './../DeckGLContainer';
 import * as common from './common';
 import sandboxedEval from '../../../javascripts/modules/sandbox';
 
+function getPoints(data) {
+  const points = [];
+  data.forEach((d) => {
+    points.push(d.sourcePosition);
+    points.push(d.targetPosition);
+  });
+  return points;
+}
+
 function getLayer(formData, payload, slice) {
   const fd = formData;
   const fc = fd.color_picker;
@@ -32,11 +41,15 @@ function getLayer(formData, payload, slice) {
 
 function deckArc(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
+  let viewport = {
     ...slice.formData.viewport,
     width: slice.width(),
     height: slice.height(),
   };
+
+  if (slice.formData.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.arcs));
+  }
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/assets/visualizations/deckgl/layers/common.js 
b/superset/assets/visualizations/deckgl/layers/common.js
index 7f11213b6c..4692401cf8 100644
--- a/superset/assets/visualizations/deckgl/layers/common.js
+++ b/superset/assets/visualizations/deckgl/layers/common.js
@@ -1,6 +1,30 @@
 import dompurify from 'dompurify';
+import { fitBounds } from 'viewport-mercator-project';
+
 import sandboxedEval from '../../../javascripts/modules/sandbox';
 
+export function getBounds(points) {
+  const latExt = d3.extent(points, d => d[1]);
+  const lngExt = d3.extent(points, d => d[0]);
+  return [
+    [lngExt[0], latExt[0]],
+    [lngExt[1], latExt[1]],
+  ];
+}
+
+export function fitViewport(viewport, points, padding = 10) {
+  const bounds = getBounds(points);
+  return {
+    ...viewport,
+    ...fitBounds({
+      height: viewport.height,
+      width: viewport.width,
+      padding,
+      bounds,
+    }),
+  };
+}
+
 export function commonLayerProps(formData, slice) {
   const fd = formData;
   let onHover;
diff --git a/superset/assets/visualizations/deckgl/layers/geojson.jsx 
b/superset/assets/visualizations/deckgl/layers/geojson.jsx
index 7f0936304e..fe7805a279 100644
--- a/superset/assets/visualizations/deckgl/layers/geojson.jsx
+++ b/superset/assets/visualizations/deckgl/layers/geojson.jsx
@@ -1,10 +1,9 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-
 import { GeoJsonLayer } from 'deck.gl';
+// TODO import geojsonExtent from 'geojson-extent';
 
 import DeckGLContainer from './../DeckGLContainer';
-
 import * as common from './common';
 import { hexToRGB } from '../../../javascripts/modules/colors';
 import sandboxedEval from '../../../javascripts/modules/sandbox';
@@ -100,6 +99,11 @@ function deckGeoJson(slice, payload, setControlValue) {
     width: slice.width(),
     height: slice.height(),
   };
+  if (slice.formData.autozoom) {
+    // TODO get this to work
+    // viewport = common.fitViewport(viewport, 
geojsonExtent(payload.data.features));
+  }
+
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/assets/visualizations/deckgl/layers/grid.jsx 
b/superset/assets/visualizations/deckgl/layers/grid.jsx
index 1e7ff1d70b..6f92f0688c 100644
--- a/superset/assets/visualizations/deckgl/layers/grid.jsx
+++ b/superset/assets/visualizations/deckgl/layers/grid.jsx
@@ -37,13 +37,22 @@ function getLayer(formData, payload, slice) {
   });
 }
 
+function getPoints(data) {
+  return data.map(d => d.position);
+}
+
 function deckGrid(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
+  let viewport = {
     ...slice.formData.viewport,
     width: slice.width(),
     height: slice.height(),
   };
+
+  if (slice.formData.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.features));
+  }
+
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/assets/visualizations/deckgl/layers/hex.jsx 
b/superset/assets/visualizations/deckgl/layers/hex.jsx
index 7dc4d8b025..f0fb925da5 100644
--- a/superset/assets/visualizations/deckgl/layers/hex.jsx
+++ b/superset/assets/visualizations/deckgl/layers/hex.jsx
@@ -37,13 +37,22 @@ function getLayer(formData, payload, slice) {
   });
 }
 
+function getPoints(data) {
+  return data.map(d => d.position);
+}
+
 function deckHex(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
+  let viewport = {
     ...slice.formData.viewport,
     width: slice.width(),
     height: slice.height(),
   };
+
+  if (slice.formData.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.features));
+  }
+
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/assets/visualizations/deckgl/layers/path.jsx 
b/superset/assets/visualizations/deckgl/layers/path.jsx
index a20c2bbdb0..4b45a0ba13 100644
--- a/superset/assets/visualizations/deckgl/layers/path.jsx
+++ b/superset/assets/visualizations/deckgl/layers/path.jsx
@@ -33,13 +33,26 @@ function getLayer(formData, payload, slice) {
   });
 }
 
+function getPoints(data) {
+  let points = [];
+  data.forEach((d) => {
+    points = points.concat(d.path);
+  });
+  return points;
+}
+
 function deckPath(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
+  let viewport = {
     ...slice.formData.viewport,
     width: slice.width(),
     height: slice.height(),
   };
+
+  if (slice.formData.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.features));
+  }
+
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/assets/visualizations/deckgl/layers/scatter.jsx 
b/superset/assets/visualizations/deckgl/layers/scatter.jsx
index ed1dd792af..646a9afef7 100644
--- a/superset/assets/visualizations/deckgl/layers/scatter.jsx
+++ b/superset/assets/visualizations/deckgl/layers/scatter.jsx
@@ -1,15 +1,17 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-
 import { ScatterplotLayer } from 'deck.gl';
 
 import DeckGLContainer from './../DeckGLContainer';
-
 import * as common from './common';
 import { getColorFromScheme, hexToRGB } from 
'../../../javascripts/modules/colors';
 import { unitToRadius } from '../../../javascripts/modules/geo';
 import sandboxedEval from '../../../javascripts/modules/sandbox';
 
+function getPoints(data) {
+  return data.map(d => d.position);
+}
+
 function getLayer(formData, payload, slice) {
   const fd = formData;
   const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
@@ -50,17 +52,25 @@ function getLayer(formData, payload, slice) {
 
 function deckScatter(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
-    ...slice.formData.viewport,
-    width: slice.width(),
-    height: slice.height(),
+  const fd = slice.formData;
+  const width = slice.width();
+  const height = slice.height();
+  let viewport = {
+    ...fd.viewport,
+    width,
+    height,
   };
+
+  if (fd.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.features));
+  }
+
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
       viewport={viewport}
       layers={[layer]}
-      mapStyle={slice.formData.mapbox_style}
+      mapStyle={fd.mapbox_style}
       setControlValue={setControlValue}
     />,
     document.getElementById(slice.containerId),
diff --git a/superset/assets/visualizations/deckgl/layers/screengrid.jsx 
b/superset/assets/visualizations/deckgl/layers/screengrid.jsx
index 7494c67d3d..7d6742e6e8 100644
--- a/superset/assets/visualizations/deckgl/layers/screengrid.jsx
+++ b/superset/assets/visualizations/deckgl/layers/screengrid.jsx
@@ -37,13 +37,20 @@ function getLayer(formData, payload, slice) {
   });
 }
 
+function getPoints(data) {
+  return data.map(d => d.position);
+}
+
 function deckScreenGrid(slice, payload, setControlValue) {
   const layer = getLayer(slice.formData, payload, slice);
-  const viewport = {
+  let viewport = {
     ...slice.formData.viewport,
     width: slice.width(),
     height: slice.height(),
   };
+  if (slice.formData.autozoom) {
+    viewport = common.fitViewport(viewport, getPoints(payload.data.features));
+  }
   ReactDOM.render(
     <DeckGLContainer
       mapboxApiAccessToken={payload.data.mapboxApiKey}
diff --git a/superset/data/__init__.py b/superset/data/__init__.py
index e1d0b67558..be89c1a7ec 100644
--- a/superset/data/__init__.py
+++ b/superset/data/__init__.py
@@ -1266,10 +1266,10 @@ def load_deck_dash():
         "point_radius_fixed": {"type": "metric", "value": "count"},
         "point_unit": "square_m",
         "row_limit": 5000,
-        "since": "2014-01-01",
+        "since": None,
         "size": "count",
         "time_grain_sqla": "Time Column",
-        "until": "now",
+        "until": None,
         "viewport": {
             "bearing": -4.952916738791771,
             "latitude": 37.78926922909199,
@@ -1305,9 +1305,9 @@ def load_deck_dash():
         "granularity_sqla": "date",
         "size": "count",
         "viz_type": "deck_screengrid",
-        "since": "2014-01-01",
+        "since": None,
         "point_radius": "Auto",
-        "until": "now",
+        "until": None,
         "color_picker": {
             "a": 1,
             "r": 14,
@@ -1352,10 +1352,10 @@ def load_deck_dash():
         "granularity_sqla": "date",
         "size": "count",
         "viz_type": "deck_hex",
-        "since": "2014-01-01",
+        "since": None,
         "point_radius_unit": "Pixels",
         "point_radius": "Auto",
-        "until": "now",
+        "until": None,
         "color_picker": {
             "a": 1,
             "r": 14,
@@ -1401,10 +1401,10 @@ def load_deck_dash():
         "granularity_sqla": "date",
         "size": "count",
         "viz_type": "deck_grid",
-        "since": "2014-01-01",
+        "since": None,
         "point_radius_unit": "Pixels",
         "point_radius": "Auto",
-        "until": "now",
+        "until": None,
         "color_picker": {
             "a": 1,
             "r": 14,
@@ -1446,8 +1446,8 @@ def load_deck_dash():
             "slice_id": 41,
             "granularity_sqla": None,
             "time_grain_sqla": None,
-            "since": "7 days ago",
-            "until": "now",
+            "since": None,
+            "until": None,
             "line_column": "contour",
             "line_type": "json",
             "mapbox_style": "mapbox://styles/mapbox/light-v9",
@@ -1515,8 +1515,8 @@ def load_deck_dash():
             "slice_id": 42,
             "granularity_sqla": "date",
             "time_grain_sqla": "Time Column",
-            "since": "2014-01-01",
-            "until": "now",
+            "since": None,
+            "until": None,
             "start_spatial": {
                 "type": "latlong",
                 "latCol": "LATITUDE",
@@ -1573,8 +1573,8 @@ def load_deck_dash():
         "slice_id": 43,
         "viz_type": "deck_path",
         "time_grain_sqla": "Time Column",
-        "since": "7 days ago",
-        "until": "now",
+        "since": None,
+        "until": None,
         "line_column": "path_json",
         "line_type": "json",
         "row_limit": 5000,
diff --git a/superset/viz.py b/superset/viz.py
index 5c36e40891..c09b3cf51a 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -291,7 +291,6 @@ def get_payload(self, query_obj=None):
         if df is not None and len(df.index) == 0:
             raise Exception('No data')
         payload['data'] = self.get_data(df)
-
         del payload['df']
         return payload
 
@@ -1932,7 +1931,6 @@ def process_spatial_data_obj(self, key, df):
         spatial = self.form_data.get(key)
         if spatial is None:
             raise ValueError(_('Bad spatial key'))
-
         if spatial.get('type') == 'latlong':
             df[key] = list(zip(df[spatial.get('lonCol')], 
df[spatial.get('latCol')]))
         elif spatial.get('type') == 'delimited':


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to