diff --git a/superset/assets/src/visualizations/deckgl/DeckGLContainer.jsx b/superset/assets/src/visualizations/deckgl/DeckGLContainer.jsx index c10f16ac9..ff414bfc0 100644 --- a/superset/assets/src/visualizations/deckgl/DeckGLContainer.jsx +++ b/superset/assets/src/visualizations/deckgl/DeckGLContainer.jsx @@ -22,6 +22,7 @@ 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 diff --git a/superset/assets/src/visualizations/deckgl/TooltipRow.jsx b/superset/assets/src/visualizations/deckgl/TooltipRow.jsx new file mode 100644 index 000000000..cc85bfd98 --- /dev/null +++ b/superset/assets/src/visualizations/deckgl/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/assets/src/visualizations/deckgl/layers/Arc/Arc.jsx b/superset/assets/src/visualizations/deckgl/layers/Arc/Arc.jsx index b6adbbfbf..2c0a99b09 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Arc/Arc.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Arc/Arc.jsx @@ -17,8 +17,11 @@ * 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 = []; @@ -29,6 +32,18 @@ function getPoints(data) { 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; @@ -39,7 +54,7 @@ export function getLayer(fd, payload, onAddFilter, setTooltip) { 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), + ...commonLayerProps(fd, setTooltip, setTooltipContent(fd)), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Geojson/Geojson.jsx b/superset/assets/src/visualizations/deckgl/layers/Geojson/Geojson.jsx index 1dd3cdb47..7488a3ddf 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Geojson/Geojson.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Geojson/Geojson.jsx @@ -25,6 +25,7 @@ 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', @@ -75,6 +76,19 @@ const recurseGeoJson = (node, propOverrides, extraProps) => { } }; +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; @@ -106,7 +120,7 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { stroked: fd.stroked, extruded: fd.extruded, pointRadiusScale: fd.point_radius_scale, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Grid/Grid.jsx b/superset/assets/src/visualizations/deckgl/layers/Grid/Grid.jsx index 67c4bfd83..a0cc8613f 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Grid/Grid.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Grid/Grid.jsx @@ -17,10 +17,22 @@ * 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; @@ -48,7 +60,7 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { outline: false, getElevationValue: aggFunc, getColorValue: aggFunc, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Hex/Hex.jsx b/superset/assets/src/visualizations/deckgl/layers/Hex/Hex.jsx index f8562254e..9901b2262 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Hex/Hex.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Hex/Hex.jsx @@ -17,10 +17,22 @@ * 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; @@ -47,7 +59,7 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { outline: false, getElevationValue: aggFunc, getColorValue: aggFunc, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Path/Path.jsx b/superset/assets/src/visualizations/deckgl/layers/Path/Path.jsx index 633ccec9e..7bf098241 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Path/Path.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Path/Path.jsx @@ -17,9 +17,24 @@ * 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; @@ -42,7 +57,7 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { data, rounded: true, widthScale: 1, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Polygon/Polygon.jsx b/superset/assets/src/visualizations/deckgl/layers/Polygon/Polygon.jsx index 8a3c2f402..ca7d4132a 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Polygon/Polygon.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Polygon/Polygon.jsx @@ -25,6 +25,7 @@ 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'; @@ -48,6 +49,18 @@ function getElevation(d, colorScaler) { : d.elevation; } +function setTooltipContent(formData) { + return (o) => { + const metricLabel = formData.metric.label || formData.metric; + return ( +
+ + {formData.metric && } +
+ ); + }; +} + export function getLayer(formData, payload, setTooltip, selected, onSelect, filters) { const fd = formData; const fc = fd.fill_color_picker; @@ -95,7 +108,7 @@ export function getLayer(formData, payload, setTooltip, selected, onSelect, filt getElevation: d => getElevation(d, colorScaler), elevationScale: fd.multiplier, fp64: true, - ...commonLayerProps(fd, setTooltip, onSelect), + ...commonLayerProps(fd, setTooltip, setTooltipContent(fd), onSelect), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Scatter/Scatter.jsx b/superset/assets/src/visualizations/deckgl/layers/Scatter/Scatter.jsx index 194a7755a..8ca13aac4 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Scatter/Scatter.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Scatter/Scatter.jsx @@ -17,14 +17,31 @@ * 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(fd, payload, onAddFilter, setTooltip) { const dataWithRadius = payload.data.features.map((d) => { let radius = unitToRadius(fd.point_unit, d.radius) || 10; @@ -46,7 +63,7 @@ export function getLayer(fd, payload, onAddFilter, setTooltip) { radiusMinPixels: fd.min_radius || null, radiusMaxPixels: fd.max_radius || null, outline: false, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent(fd)), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/Screengrid/Screengrid.jsx b/superset/assets/src/visualizations/deckgl/layers/Screengrid/Screengrid.jsx index a4bdede05..1efefae21 100644 --- a/superset/assets/src/visualizations/deckgl/layers/Screengrid/Screengrid.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/Screengrid/Screengrid.jsx @@ -21,15 +21,26 @@ 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, filters) { const fd = formData; const c = fd.color_picker; @@ -61,7 +72,7 @@ export function getLayer(formData, payload, onAddFilter, setTooltip, filters) { maxColor: [c.r, c.g, c.b, 255 * c.a], outline: false, getWeight: d => d.weight || 0, - ...commonLayerProps(fd, setTooltip), + ...commonLayerProps(fd, setTooltip, setTooltipContent), }); } diff --git a/superset/assets/src/visualizations/deckgl/layers/common.jsx b/superset/assets/src/visualizations/deckgl/layers/common.jsx index b9b271640..7adf3b789 100644 --- a/superset/assets/src/visualizations/deckgl/layers/common.jsx +++ b/superset/assets/src/visualizations/deckgl/layers/common.jsx @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; - import { fitBounds } from 'viewport-mercator-project'; import * as d3array from 'd3-array'; import sandboxedEval from '../../../modules/sandbox'; @@ -50,20 +48,12 @@ export function fitViewport(viewport, points, padding = 10) { } } -export function commonLayerProps(formData, setTooltip, onSelect) { +export function commonLayerProps(formData, setTooltip, setTooltipContent, onSelect) { const fd = formData; let onHover; - let tooltipContentGenerator; + let tooltipContentGenerator = setTooltipContent; if (fd.js_tooltip) { tooltipContentGenerator = sandboxedEval(fd.js_tooltip); - } else if (fd.line_column && fd.metric && ['geohash', 'zipcode'].indexOf(fd.line_type) >= 0) { - const metricLabel = fd.metric.label || fd.metric; - tooltipContentGenerator = o => ( -
-
{fd.line_column}: {o.object[fd.line_column]}
- {fd.metric && -
{metricLabel}: {o.object[metricLabel]}
} -
); } if (tooltipContentGenerator) { onHover = (o) => { diff --git a/superset/assets/src/visualizations/stylesheets/deckgl.css b/superset/assets/src/visualizations/stylesheets/deckgl.css new file mode 100644 index 000000000..b085d1c6b --- /dev/null +++ b/superset/assets/src/visualizations/stylesheets/deckgl.css @@ -0,0 +1,22 @@ +/** + * 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. + */ + .deckgl-tooltip > div { + overflow: hidden; + text-overflow: ellipsis; + }