Added remaining JS controls to DeckGL layers
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js b/superset/assets/javascripts/explore/stores/visTypes.js
index e1d5e64..aeb6f09 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -373,6 +373,15 @@
           ['grid_size', 'extruded'],
         ],
       },
+      {
+        label: t('Advanced'),
+        controlSetRows: [
+          ['js_columns'],
+          ['js_data_mutator'],
+          ['js_tooltip'],
+          ['js_onclick_href'],
+        ],
+      },
     ],
     controlOverrides: {
       size: {
@@ -402,6 +411,15 @@
           ['grid_size', 'extruded'],
         ],
       },
+      {
+        label: t('Advanced'),
+        controlSetRows: [
+          ['js_columns'],
+          ['js_data_mutator'],
+          ['js_tooltip'],
+          ['js_onclick_href'],
+        ],
+      },
     ],
     controlOverrides: {
       size: {
@@ -469,6 +487,15 @@
           ['grid_size', 'color_picker'],
         ],
       },
+      {
+        label: t('Advanced'),
+        controlSetRows: [
+          ['js_columns'],
+          ['js_data_mutator'],
+          ['js_tooltip'],
+          ['js_onclick_href'],
+        ],
+      },
     ],
     controlOverrides: {
       size: {
@@ -622,6 +649,15 @@
           ['stroke_width', null],
         ],
       },
+      {
+        label: t('Advanced'),
+        controlSetRows: [
+          ['js_columns'],
+          ['js_data_mutator'],
+          ['js_tooltip'],
+          ['js_onclick_href'],
+        ],
+      },
     ],
   },
 
diff --git a/superset/assets/visualizations/deckgl/layers/arc.jsx b/superset/assets/visualizations/deckgl/layers/arc.jsx
index 38bd1e8..8e04e9a 100644
--- a/superset/assets/visualizations/deckgl/layers/arc.jsx
+++ b/superset/assets/visualizations/deckgl/layers/arc.jsx
@@ -1,16 +1,26 @@
 import { ArcLayer } from 'deck.gl';
 
-export default function arcLayer(formData, payload) {
+import * as common from './common';
+import sandboxedEval from '../../../javascripts/modules/sandbox';
+
+export default function arcLayer(formData, payload, slice) {
   const fd = formData;
   const fc = fd.color_picker;
-  const data = payload.data.arcs.map(d => ({
+  let data = payload.data.arcs.map(d => ({
     ...d,
     color: [fc.r, fc.g, fc.b, 255 * fc.a],
   }));
 
+  if (fd.js_data_mutator) {
+    // Applying user defined data mutator if defined
+    const jsFnMutator = sandboxedEval(fd.js_data_mutator);
+    data = jsFnMutator(data);
+  }
+
   return new ArcLayer({
     id: `path-layer-${fd.slice_id}`,
     data,
     strokeWidth: (fd.stroke_width) ? fd.stroke_width : 3,
+    ...common.commonLayerProps(fd, slice),
   });
 }
diff --git a/superset/assets/visualizations/deckgl/layers/grid.jsx b/superset/assets/visualizations/deckgl/layers/grid.jsx
index a461eb98..ed970d2 100644
--- a/superset/assets/visualizations/deckgl/layers/grid.jsx
+++ b/superset/assets/visualizations/deckgl/layers/grid.jsx
@@ -1,12 +1,22 @@
 import { GridLayer } from 'deck.gl';
 
-export default function getLayer(formData, payload) {
+import * as common from './common';
+import sandboxedEval from '../../../javascripts/modules/sandbox';
+
+export default function getLayer(formData, payload, slice) {
   const fd = formData;
   const c = fd.color_picker;
-  const data = payload.data.features.map(d => ({
+  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);
+  }
+
   return new GridLayer({
     id: `grid-layer-${fd.slice_id}`,
     data,
@@ -18,5 +28,6 @@
     outline: false,
     getElevationValue: points => points.reduce((sum, point) => sum + point.weight, 0),
     getColorValue: points => points.reduce((sum, point) => sum + point.weight, 0),
+    ...common.commonLayerProps(fd, slice),
   });
 }
diff --git a/superset/assets/visualizations/deckgl/layers/hex.jsx b/superset/assets/visualizations/deckgl/layers/hex.jsx
index 0e33e94..86fb534 100644
--- a/superset/assets/visualizations/deckgl/layers/hex.jsx
+++ b/superset/assets/visualizations/deckgl/layers/hex.jsx
@@ -1,13 +1,22 @@
 import { HexagonLayer } from 'deck.gl';
 
-export default function getLayer(formData, payload) {
+import * as common from './common';
+import sandboxedEval from '../../../javascripts/modules/sandbox';
+
+export default function getLayer(formData, payload, slice) {
   const fd = formData;
   const c = fd.color_picker;
-  const data = payload.data.features.map(d => ({
+  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);
+  }
+
   return new HexagonLayer({
     id: `hex-layer-${fd.slice_id}`,
     data,
@@ -19,5 +28,6 @@
     outline: false,
     getElevationValue: points => points.reduce((sum, point) => sum + point.weight, 0),
     getColorValue: points => points.reduce((sum, point) => sum + point.weight, 0),
+    ...common.commonLayerProps(fd, slice),
   });
 }
diff --git a/superset/assets/visualizations/deckgl/layers/screengrid.jsx b/superset/assets/visualizations/deckgl/layers/screengrid.jsx
index 54edd9e..ca589cd 100644
--- a/superset/assets/visualizations/deckgl/layers/screengrid.jsx
+++ b/superset/assets/visualizations/deckgl/layers/screengrid.jsx
@@ -1,13 +1,22 @@
 import { ScreenGridLayer } from 'deck.gl';
 
-export default function getLayer(formData, payload) {
+import * as common from './common';
+import sandboxedEval from '../../../javascripts/modules/sandbox';
+
+export default function getLayer(formData, payload, slice) {
   const fd = formData;
   const c = fd.color_picker;
-  const data = payload.data.features.map(d => ({
+  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);
+  }
+
   // Passing a layer creator function instead of a layer since the
   // layer needs to be regenerated at each render
   return new ScreenGridLayer({
@@ -19,5 +28,6 @@
     maxColor: [c.r, c.g, c.b, 255 * c.a],
     outline: false,
     getWeight: d => d.weight || 0,
+    ...common.commonLayerProps(fd, slice),
   });
 }
diff --git a/superset/viz.py b/superset/viz.py
index 27eac63..6fa7d98 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -2077,7 +2077,7 @@
         arcs = d['features']
 
         return {
-            'arcs': [arc['position'] for arc in arcs],
+            'arcs': arcs,
             'mapboxApiKey': config.get('MAPBOX_API_KEY'),
         }