Skip to content

Commit

Permalink
[deck polygon] add support for geohash (apache#5712)
Browse files Browse the repository at this point in the history
* [deck polygon] add support for geohash

+ improvements:
* added autozoom support
* support for metric & aggregations (only aggregates if metric is picked)
* fixed stroke
* fixed opacity
* introduced a SliderControl

* addressing comments, fixing build

* Addressing comments

(cherry picked from commit 60ecd72)
  • Loading branch information
mistercrunch authored and youngyjd committed Oct 17, 2018
1 parent 18a37de commit 88e1689
Show file tree
Hide file tree
Showing 18 changed files with 343 additions and 119 deletions.
3 changes: 1 addition & 2 deletions superset/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"d3-tip": "^0.9.1",
"datamaps": "^0.5.8",
"datatables.net-bs": "^1.10.15",
"deck.gl": "^5.1.4",
"deck.gl": "^5.3.4",
"distributions": "^1.0.0",
"dnd-core": "^2.6.0",
"dompurify": "^1.0.3",
Expand All @@ -72,7 +72,6 @@
"jed": "^1.1.1",
"jquery": "3.1.1",
"lodash.throttle": "^4.1.1",
"luma.gl": "^5.1.4",
"mapbox-gl": "^0.45.0",
"mathjs": "^3.20.2",
"moment": "^2.20.1",
Expand Down
2 changes: 1 addition & 1 deletion superset/assets/src/chart/Chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class Chart extends React.PureComponent {
className="chart-tooltip"
id="chart-tooltip"
placement="right"
positionTop={this.state.tooltip.y - 10}
positionTop={this.state.tooltip.y + 30}
positionLeft={this.state.tooltip.x + 30}
arrowOffsetTop={10}
>
Expand Down
8 changes: 8 additions & 0 deletions superset/assets/src/components/BootstrapSliderWrapper.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.BootstrapSliderWrapper .slider-selection {
background: #efefef;
}

.BootstrapSliderWrapper .slider-handle {
background: #b3b3b3;
}

12 changes: 12 additions & 0 deletions superset/assets/src/components/BootstrapSliderWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import ReactBootstrapSlider from 'react-bootstrap-slider';
import 'bootstrap-slider/dist/css/bootstrap-slider.min.css';
import './BootstrapSliderWrapper.css';

export default function BootstrapSliderWrapper(props) {
return (
<span className="BootstrapSliderWrapper">
<ReactBootstrapSlider {...props} />
</span>
);
}
62 changes: 25 additions & 37 deletions superset/assets/src/dashboard/reducers/dashboardState.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,46 +95,34 @@ export default function dashboardStateReducer(state = {}, action) {
let filters = state.filters;
const { chart, col, vals: nextVals, merge, refresh } = action;
const sliceId = chart.id;
const filterKeys = [
'__time_range',
'__time_col',
'__time_grain',
'__time_origin',
'__granularity',
];
if (
filterKeys.indexOf(col) >= 0 ||
action.chart.formData.groupby.indexOf(col) !== -1
) {
let newFilter = {};
if (!(sliceId in filters)) {
// if no filters existed for the slice, set them
newFilter = { [col]: nextVals };
} else if ((filters[sliceId] && !(col in filters[sliceId])) || !merge) {
// If no filters exist for this column, or we are overwriting them
newFilter = { ...filters[sliceId], [col]: nextVals };
} else if (filters[sliceId][col] instanceof Array) {
newFilter[col] = [...filters[sliceId][col], ...nextVals];
} else {
newFilter[col] = [filters[sliceId][col], ...nextVals];
}
filters = { ...filters, [sliceId]: newFilter };
let newFilter = {};
if (!(sliceId in filters)) {
// if no filters existed for the slice, set them
newFilter = { [col]: nextVals };
} else if ((filters[sliceId] && !(col in filters[sliceId])) || !merge) {
// If no filters exist for this column, or we are overwriting them
newFilter = { ...filters[sliceId], [col]: nextVals };
} else if (filters[sliceId][col] instanceof Array) {
newFilter[col] = [...filters[sliceId][col], ...nextVals];
} else {
newFilter[col] = [filters[sliceId][col], ...nextVals];
}
filters = { ...filters, [sliceId]: newFilter };

// remove any empty filters so they don't pollute the logs
Object.keys(filters).forEach(chartId => {
Object.keys(filters[chartId]).forEach(column => {
if (
!filters[chartId][column] ||
filters[chartId][column].length === 0
) {
delete filters[chartId][column];
}
});
if (Object.keys(filters[chartId]).length === 0) {
delete filters[chartId];
// remove any empty filters so they don't pollute the logs
Object.keys(filters).forEach(chartId => {
Object.keys(filters[chartId]).forEach(column => {
if (
!filters[chartId][column] ||
filters[chartId][column].length === 0
) {
delete filters[chartId][column];
}
});
}
if (Object.keys(filters[chartId]).length === 0) {
delete filters[chartId];
}
});
return { ...state, filters, refresh };
},
[SET_UNSAVED_CHANGES]() {
Expand Down
35 changes: 35 additions & 0 deletions superset/assets/src/explore/components/controls/SliderControl.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';

import BootstrapSliderWrapper from '../../../components/BootstrapSliderWrapper';
import ControlHeader from '../ControlHeader';

const propTypes = {
onChange: PropTypes.func,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
};

const defaultProps = {
onChange: () => {},
};

export default function SliderControl(props) {
// This wouldn't be necessary but might as well
return (
<div>
<ControlHeader {...props} />
<BootstrapSliderWrapper
{...props}
change={(obj) => {
props.onChange(obj.target.value);
}}
/>
</div>
);
}

SliderControl.propTypes = propTypes;
SliderControl.defaultProps = defaultProps;
2 changes: 2 additions & 0 deletions superset/assets/src/explore/components/controls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import FixedOrMetricControl from './FixedOrMetricControl';
import HiddenControl from './HiddenControl';
import SelectAsyncControl from './SelectAsyncControl';
import SelectControl from './SelectControl';
import SliderControl from './SliderControl';
import SpatialControl from './SpatialControl';
import TextAreaControl from './TextAreaControl';
import TextControl from './TextControl';
Expand All @@ -32,6 +33,7 @@ const controlMap = {
HiddenControl,
SelectAsyncControl,
SelectControl,
SliderControl,
SpatialControl,
TextAreaControl,
TextControl,
Expand Down
18 changes: 15 additions & 3 deletions superset/assets/src/explore/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1468,10 +1468,10 @@ export const controls = {

table_filter: {
type: 'CheckboxControl',
label: t('Table Filter'),
label: t('Emit Filter Events'),
renderTrigger: true,
default: false,
description: t('Whether to apply filter when table cell is clicked'),
description: t('Whether to apply filter when items are clicked'),
},

align_pn: {
Expand Down Expand Up @@ -1812,6 +1812,17 @@ export const controls = {
'Between 0 and 1.'),
},

opacity: {
type: 'SliderControl',
label: t('Opacity'),
default: 80,
step: 1,
min: 0,
max: 100,
renderTrigger: true,
description: t('Opacity, expects values between 0 and 100'),
},

viewport: {
type: 'ViewportControl',
label: t('Viewport'),
Expand Down Expand Up @@ -2156,6 +2167,7 @@ export const controls = {
choices: [
['polyline', 'Polyline'],
['json', 'JSON'],
['geohash', 'geohash (square)'],
],
},

Expand Down Expand Up @@ -2277,7 +2289,7 @@ export const controls = {
label: t('Filled'),
renderTrigger: true,
description: t('Whether to fill the objects'),
default: false,
default: true,
},

normalized: {
Expand Down
33 changes: 29 additions & 4 deletions superset/assets/src/explore/visTypes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,14 @@ export const visTypes = {
],
},
],
controlOverrides: {
line_type: {
choices: [
['polyline', 'Polyline'],
['json', 'JSON'],
],
},
},
},

deck_screengrid: {
Expand Down Expand Up @@ -754,25 +762,31 @@ export const visTypes = {
label: t('Query'),
expanded: true,
controlSetRows: [
['line_column', 'line_type'],
['row_limit', 'filter_nulls'],
['adhoc_filters'],
['metric'],
['row_limit', null],
['line_column', 'line_type'],
['reverse_long_lat', 'filter_nulls'],
],
},
{
label: t('Map'),
expanded: true,
controlSetRows: [
['mapbox_style', 'viewport'],
['reverse_long_lat', null],
['autozoom', null],
],
},
{
label: t('Polygon Settings'),
expanded: true,
controlSetRows: [
['fill_color_picker', 'stroke_color_picker'],
['filled', 'stroked'],
['extruded', null],
['point_radius_scale', null],
['line_width', null],
['linear_color_scheme', 'opacity'],
['table_filter', null],
],
},
{
Expand All @@ -785,6 +799,17 @@ export const visTypes = {
],
},
],
controlOverrides: {
metric: {
validators: [],
},
line_column: {
label: t('Polygon Column'),
},
line_type: {
label: t('Polygon Encoding'),
},
},
},

deck_arc: {
Expand Down
28 changes: 16 additions & 12 deletions superset/assets/src/modules/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,16 @@ export const spectrums = {
],
};

export function hexToRGB(hex, alpha = 255) {
if (!hex) {
return [0, 0, 0, alpha];
}
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}

/**
* Get a color from a scheme specific palette (scheme)
* The function cycles through the palette while memoizing labels
Expand Down Expand Up @@ -566,7 +576,7 @@ export const getColorFromScheme = (function () {
};
}());

export const colorScalerFactory = function (colors, data, accessor, extents) {
export const colorScalerFactory = function (colors, data, accessor, extents, outputRGBA = false) {
// Returns a linear scaler our of an array of color
if (!Array.isArray(colors)) {
/* eslint no-param-reassign: 0 */
Expand All @@ -581,15 +591,9 @@ export const colorScalerFactory = function (colors, data, accessor, extents) {
}
const chunkSize = (ext[1] - ext[0]) / (colors.length - 1);
const points = colors.map((col, i) => ext[0] + (i * chunkSize));
return d3.scale.linear().domain(points).range(colors).clamp(true);
};

export function hexToRGB(hex, alpha = 255) {
if (!hex) {
return [0, 0, 0, alpha];
const scaler = d3.scale.linear().domain(points).range(colors).clamp(true);
if (outputRGBA) {
return v => hexToRGB(scaler(v));
}
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}
return scaler;
};
8 changes: 0 additions & 8 deletions superset/assets/src/visualizations/PlaySlider.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@
margin: 0;
}

.slider-selection {
background: #efefef;
}

.slider-handle {
background: #b3b3b3;
}

.slider.slider-horizontal {
width: 100% !important;
}
Expand Down
5 changes: 2 additions & 3 deletions superset/assets/src/visualizations/PlaySlider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { Row, Col } from 'react-bootstrap';

import Mousetrap from 'mousetrap';

import 'bootstrap-slider/dist/css/bootstrap-slider.min.css';
import ReactBootstrapSlider from 'react-bootstrap-slider';
import BootrapSliderWrapper from '../components/BootstrapSliderWrapper';
import './PlaySlider.css';

import { t } from '../locales';
Expand Down Expand Up @@ -120,7 +119,7 @@ export default class PlaySlider extends React.PureComponent {
<i className="fa fa-step-forward fa-lg slider-button " onClick={this.step} />
</Col>
<Col md={11} className="padded">
<ReactBootstrapSlider
<BootrapSliderWrapper
value={range ? values : values[0]}
range={range}
formatter={this.formatter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import 'mapbox-gl/dist/mapbox-gl.css';
const propTypes = {
viewport: PropTypes.object.isRequired,
layers: PropTypes.array.isRequired,
setControlValue: PropTypes.func.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 {
Expand Down
Loading

0 comments on commit 88e1689

Please sign in to comment.