Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIP-5] Remove references to slice from all deck.gl components. #6039

Merged
merged 19 commits into from
Oct 12, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ function getCategories(fd, data) {
}

const propTypes = {
slice: PropTypes.object.isRequired,
formData: PropTypes.object.isRequired,
mapboxApiKey: PropTypes.string.isRequired,
setControlValue: PropTypes.func.isRequired,
viewport: PropTypes.object.isRequired,
getLayer: PropTypes.func.isRequired,
payload: PropTypes.object.isRequired,
onAddFilter: PropTypes.func,
onTooltip: PropTypes.func,
};

export default class CategoricalDeckGLContainer extends React.PureComponent {
Expand All @@ -49,7 +51,7 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {

/* eslint-disable-next-line react/sort-comp */
static getDerivedStateFromProps(nextProps) {
const fd = nextProps.slice.formData;
const fd = nextProps.formData;

const timeGrain = fd.time_grain_sqla || fd.granularity || 'PT1M';
const timestamps = nextProps.payload.data.features.map(f => f.__timestamp);
Expand All @@ -70,8 +72,13 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
this.setState(CategoricalDeckGLContainer.getDerivedStateFromProps(nextProps, this.state));
}
getLayers(values) {
const { getLayer, payload, slice } = this.props;
const fd = slice.formData;
const {
getLayer,
payload,
formData: fd,
onAddFilter,
onTooltip,
} = this.props;
let data = [...payload.data.features];

// Add colors from categories or fixed color
Expand All @@ -96,7 +103,7 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
}

payload.data.features = data;
return [getLayer(fd, payload, slice)];
return [getLayer(fd, payload, onAddFilter, onTooltip)];
}
addColor(data, fd) {
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
Expand Down Expand Up @@ -142,14 +149,14 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
disabled={this.state.disabled}
viewport={this.props.viewport}
mapboxApiAccessToken={this.props.mapboxApiKey}
mapStyle={this.props.slice.formData.mapbox_style}
mapStyle={this.props.formData.mapbox_style}
setControlValue={this.props.setControlValue}
>
<Legend
categories={this.state.categories}
toggleCategory={this.toggleCategory}
showSingleCategory={this.showSingleCategory}
position={this.props.slice.formData.legend_position}
position={this.props.formData.legend_position}
/>
</AnimatableDeckGLContainer>
</div>
Expand Down
30 changes: 30 additions & 0 deletions superset/assets/src/visualizations/deckgl/createAdaptor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import ReactDOM from 'react-dom';

const IDENTITY = x => x;

class DeckGlChartInput {
constructor(slice, payload, setControlValue) {
this.formData = slice.formData;
this.payload = payload;
this.setControlValue = setControlValue;
this.viewport = {
...this.formData.viewport,
width: slice.width(),
height: slice.height(),
};

this.onAddFilter = ((...args) => { slice.addFilter(...args); });
this.onTooltip = ((...args) => { slice.tooltip(...args); });
}
}

export default function createAdaptor(Component, transformProps = IDENTITY) {
return function adaptor(slice, payload, setControlValue) {
const chartInput = new DeckGlChartInput(slice, payload, setControlValue);
ReactDOM.render(
<Component {...transformProps(chartInput)} />,
document.querySelector(slice.selector),
);
};
}
87 changes: 87 additions & 0 deletions superset/assets/src/visualizations/deckgl/factory.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import PropTypes from 'prop-types';
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,
onTooltip: PropTypes.func,
};
const defaultProps = {
onAddFilter() {},
onTooltip() {},
};

export function createDeckGLComponent(getLayer, getPoints) {
function Component(props) {
const {
formData,
payload,
setControlValue,
onAddFilter,
onTooltip,
viewport: originalViewport,
} = props;

const viewport = formData.autozoom
? fitViewport(originalViewport, getPoints(payload.data.features))
: originalViewport;

const layer = getLayer(formData, payload, onAddFilter, onTooltip);

return (
<DeckGLContainer
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={formData.mapbox_style}
setControlValue={setControlValue}
/>
);
}

Component.propTypes = propTypes;
Component.defaultProps = defaultProps;

return Component;
}

export function createCategoricalDeckGLComponent(getLayer, getPoints) {
function Component(props) {
const {
formData,
payload,
setControlValue,
onAddFilter,
onTooltip,
viewport: originalViewport,
} = props;

const viewport = formData.autozoom
? fitViewport(originalViewport, getPoints(payload.data.features))
: originalViewport;

return (
<CategoricalDeckGLContainer
formData={formData}
mapboxApiKey={payload.data.mapboxApiKey}
setControlValue={setControlValue}
viewport={viewport}
getLayer={getLayer}
payload={payload}
onAddFilter={onAddFilter}
onTooltip={onTooltip}
/>
);
}

Component.propTypes = propTypes;
Component.defaultProps = defaultProps;

return Component;
}
46 changes: 6 additions & 40 deletions superset/assets/src/visualizations/deckgl/layers/arc.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
/* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */

import React from 'react';
import ReactDOM from 'react-dom';

import { ArcLayer } from 'deck.gl';

import CategoricalDeckGLContainer from '../CategoricalDeckGLContainer';

import * as common from './common';
import { commonLayerProps } from './common';
import createAdaptor from '../createAdaptor';
import { createCategoricalDeckGLComponent } from '../factory';

function getPoints(data) {
const points = [];
Expand All @@ -18,7 +12,7 @@ function getPoints(data) {
return points;
}

function getLayer(fd, payload, slice) {
export function getLayer(fd, payload, onAddFilter, onTooltip) {
const data = payload.data.features;
const sc = fd.color_picker;
const tc = fd.target_color_picker;
Expand All @@ -28,36 +22,8 @@ function getLayer(fd, payload, slice) {
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,
...common.commonLayerProps(fd, slice),
...commonLayerProps(fd, onAddFilter, onTooltip),
});
}

function deckArc(slice, payload, setControlValue) {
const fd = slice.formData;
let viewport = {
...fd.viewport,
width: slice.width(),
height: slice.height(),
};

if (fd.autozoom) {
viewport = common.fitViewport(viewport, getPoints(payload.data.features));
}

ReactDOM.render(
<CategoricalDeckGLContainer
slice={slice}
mapboxApiKey={payload.data.mapboxApiKey}
setControlValue={setControlValue}
viewport={viewport}
getLayer={getLayer}
payload={payload}
/>,
document.getElementById(slice.containerId),
);
}

module.exports = {
default: deckArc,
getLayer,
};
export default createAdaptor(createCategoricalDeckGLComponent(getLayer, getPoints));
9 changes: 4 additions & 5 deletions superset/assets/src/visualizations/deckgl/layers/common.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { fitBounds } from 'viewport-mercator-project';
import d3 from 'd3';

import sandboxedEval from '../../../modules/sandbox';

export function getBounds(points) {
Expand Down Expand Up @@ -32,7 +31,7 @@ export function fitViewport(viewport, points, padding = 10) {
}
}

export function commonLayerProps(formData, slice) {
export function commonLayerProps(formData, onAddFilter, onTooltip) {
const fd = formData;
let onHover;
let tooltipContentGenerator;
Expand All @@ -49,13 +48,13 @@ export function commonLayerProps(formData, slice) {
if (tooltipContentGenerator) {
onHover = (o) => {
if (o.picked) {
slice.setTooltip({
onTooltip({
content: tooltipContentGenerator(o),
x: o.x,
y: o.y,
});
} else {
slice.setTooltip(null);
onTooltip(null);
}
};
}
Expand All @@ -66,7 +65,7 @@ export function commonLayerProps(formData, slice) {
window.open(href);
};
} else if (fd.table_filter && fd.line_type === 'geohash') {
onClick = o => slice.addFilter(fd.line_column, [o.object[fd.line_column]], false);
onClick = o => onAddFilter(fd.line_column, [o.object[fd.line_column]], false);
}
return {
onClick,
Expand Down
64 changes: 41 additions & 23 deletions superset/assets/src/visualizations/deckgl/layers/geojson.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { GeoJsonLayer } from 'deck.gl';
// TODO import geojsonExtent from 'geojson-extent';

import DeckGLContainer from './../DeckGLContainer';
import * as common from './common';
import { hexToRGB } from '../../../modules/colors';
import sandboxedEval from '../../../modules/sandbox';
import { commonLayerProps } from './common';
import createAdaptor from '../createAdaptor';

const propertyMap = {
fillColor: 'fillColor',
Expand Down Expand Up @@ -57,7 +58,7 @@ const recurseGeoJson = (node, propOverrides, extraProps) => {
}
};

function getLayer(formData, payload, slice) {
export function getLayer(formData, payload, onAddFilter, onTooltip) {
const fd = formData;
const fc = fd.fill_color_picker;
const sc = fd.stroke_color_picker;
Expand Down Expand Up @@ -88,35 +89,52 @@ function getLayer(formData, payload, slice) {
stroked: fd.stroked,
extruded: fd.extruded,
pointRadiusScale: fd.point_radius_scale,
...common.commonLayerProps(fd, slice),
...commonLayerProps(fd, onAddFilter, onTooltip),
});
}

function deckGeoJson(slice, payload, setControlValue) {
const layer = getLayer(slice.formData, payload, slice);
const viewport = {
...slice.formData.viewport,
width: slice.width(),
height: slice.height(),
};
if (slice.formData.autozoom) {
// TODO get this to work
// viewport = common.fitViewport(viewport, geojsonExtent(payload.data.features));
}
const propTypes = {
formData: PropTypes.object.isRequired,
payload: PropTypes.object.isRequired,
setControlValue: PropTypes.func.isRequired,
viewport: PropTypes.object.isRequired,
onAddFilter: PropTypes.func,
onTooltip: PropTypes.func,
};
const defaultProps = {
onAddFilter() {},
onTooltip() {},
};

function deckGeoJson(props) {
const {
formData,
payload,
setControlValue,
onAddFilter,
onTooltip,
viewport,
} = props;

ReactDOM.render(
// TODO get this to work
// if (formData.autozoom) {
// viewport = common.fitViewport(viewport, geojsonExtent(payload.data.features));
// }

const layer = getLayer(formData, payload, onAddFilter, onTooltip);

return (
<DeckGLContainer
mapboxApiAccessToken={payload.data.mapboxApiKey}
viewport={viewport}
layers={[layer]}
mapStyle={slice.formData.mapbox_style}
mapStyle={formData.mapbox_style}
setControlValue={setControlValue}
/>,
document.getElementById(slice.containerId),
/>
);
}

module.exports = {
default: deckGeoJson,
getLayer,
};
deckGeoJson.propTypes = propTypes;
deckGeoJson.defaultProps = defaultProps;

export default createAdaptor(deckGeoJson);
Loading