mirror of
https://github.com/apache/superset.git
synced 2024-09-17 11:09:47 -04:00
feat: add plugin for Kepler (#2)
* feat: add plugin for Kepler * fix: add dep and update naming for consistency * fix: lint issues
This commit is contained in:
parent
317f185d36
commit
cac4e07bfe
@ -40,10 +40,10 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@superset-ui/build-config": "^0.1.0",
|
"@superset-ui/build-config": "^0.1.0",
|
||||||
"@superset-ui/commit-config": "^0.0.9",
|
|
||||||
"@superset-ui/chart": "^0.12.1",
|
"@superset-ui/chart": "^0.12.1",
|
||||||
"@superset-ui/chart-composition": "^0.12.1",
|
"@superset-ui/chart-composition": "^0.12.1",
|
||||||
"@superset-ui/color": "^0.12.1",
|
"@superset-ui/color": "^0.12.1",
|
||||||
|
"@superset-ui/commit-config": "^0.0.9",
|
||||||
"@superset-ui/connection": "^0.12.0",
|
"@superset-ui/connection": "^0.12.0",
|
||||||
"@superset-ui/core": "^0.12.0",
|
"@superset-ui/core": "^0.12.0",
|
||||||
"@superset-ui/dimension": "^0.12.0",
|
"@superset-ui/dimension": "^0.12.0",
|
||||||
@ -59,6 +59,7 @@
|
|||||||
"husky": "^3.0.3",
|
"husky": "^3.0.3",
|
||||||
"lerna": "^3.2.1",
|
"lerna": "^3.2.1",
|
||||||
"lint-staged": "^9.2.1",
|
"lint-staged": "^9.2.1",
|
||||||
|
"luma.gl": "^7.3.0",
|
||||||
"react": "^16.6.0",
|
"react": "^16.6.0",
|
||||||
"react-dom": "^16.6.0",
|
"react-dom": "^16.6.0",
|
||||||
"yarn": "^1.9.4"
|
"yarn": "^1.9.4"
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
## @superset-ui/legacy-preset-chart-deckgl
|
||||||
|
|
||||||
|
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-preset-chart-deckgl.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-preset-chart-deckgl.svg?style=flat-square)
|
||||||
|
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-preset-chart-deckgl&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-preset-chart-deckgl)
|
||||||
|
|
||||||
|
This plugin provides `deck.gl` for Superset.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Import the preset and register. This will register all the chart plugins under `deck.gl`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { DeckGLChartPreset } from '@superset-ui/legacy-preset-chart-deckgl';
|
||||||
|
|
||||||
|
new DeckGLChartPreset().register();
|
||||||
|
```
|
||||||
|
|
||||||
|
or register charts one by one. Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ArcChartPlugin } from '@superset-ui/legacy-preset-chart-deckgl';
|
||||||
|
|
||||||
|
new ArcChartPlugin()
|
||||||
|
.configure({ key: 'deck_arc' })
|
||||||
|
.register();
|
||||||
|
```
|
||||||
|
|
||||||
|
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-plugins-deckgl) for more details.
|
||||||
|
|
||||||
|
```js
|
||||||
|
<SuperChart
|
||||||
|
chartType="deck_arc"
|
||||||
|
width={600}
|
||||||
|
height={600}
|
||||||
|
formData={...}
|
||||||
|
queryData={{
|
||||||
|
data: {...},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
```
|
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "@superset-ui/legacy-preset-chart-kepler",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Superset Chart - kerpler.gl",
|
||||||
|
"sideEffects": true,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "esm/index.js",
|
||||||
|
"files": [
|
||||||
|
"esm",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/apache-superset/superset-ui-plugins-deckgl.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"superset"
|
||||||
|
],
|
||||||
|
"author": "Superset",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/apache-superset/superset-ui-plugins-deckgl/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/apache-superset/superset-ui-plugins-deckgl#readme",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"kepler.gl": "1.1.8",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"mapbox-gl": "^0.53.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-palm": "^3.1.2",
|
||||||
|
"shortid": "^2.2.15",
|
||||||
|
"styled-components": "^4.4.0",
|
||||||
|
"viewport-mercator-project": "^6.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@superset-ui/chart": "^0.12.0",
|
||||||
|
"@superset-ui/color": "^0.12.0",
|
||||||
|
"@superset-ui/connection": "^0.12.0",
|
||||||
|
"@superset-ui/core": "^0.12.0",
|
||||||
|
"@superset-ui/dimension": "^0.12.0",
|
||||||
|
"@superset-ui/number-format": "^0.12.0",
|
||||||
|
"@superset-ui/time-format": "^0.12.0",
|
||||||
|
"@superset-ui/translation": "^0.12.0",
|
||||||
|
"react": "^15 || ^16"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
.kepler {
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
/* eslint-disable prefer-destructuring */
|
||||||
|
/* eslint-disable react/destructuring-assignment */
|
||||||
|
/* eslint-disable react/jsx-handler-names */
|
||||||
|
/* eslint-disable react/no-deprecated */
|
||||||
|
/* eslint-disable no-negated-condition */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
/* eslint-disable react/require-default-props */
|
||||||
|
/* eslint-disable sort-keys */
|
||||||
|
/**
|
||||||
|
* 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 { connect, Provider } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import KeplerGl from 'kepler.gl';
|
||||||
|
import KeplerGlSchema from 'kepler.gl/schemas';
|
||||||
|
import { addDataToMap } from 'kepler.gl/actions';
|
||||||
|
import Processors from 'kepler.gl/processors';
|
||||||
|
import shortid from 'shortid';
|
||||||
|
|
||||||
|
import getKeplerStore from './store';
|
||||||
|
import './Kepler.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
height: PropTypes.number,
|
||||||
|
setControlValue: PropTypes.func,
|
||||||
|
readonly: PropTypes.boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Kepler extends React.PureComponent {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.setMapConfig = this.setMapConfig.bind(this);
|
||||||
|
this.state = {
|
||||||
|
keplerId: shortid.generate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.addDataToMap(this.props);
|
||||||
|
this.setMapConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.features !== this.props.features) {
|
||||||
|
this.addDataToMap(nextProps, false);
|
||||||
|
this.setMapConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentConfig() {
|
||||||
|
try {
|
||||||
|
const { keplerGl } = this.props;
|
||||||
|
|
||||||
|
return KeplerGlSchema.getConfigToSave(keplerGl[this.state.keplerId]);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMapConfig() {
|
||||||
|
const { setControlValue } = this.props;
|
||||||
|
const config = this.getCurrentConfig();
|
||||||
|
if (config) {
|
||||||
|
setControlValue('config', JSON.stringify(this.getCurrentConfig(), null, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addDataToMap(props, useControlConfig = true) {
|
||||||
|
let config = props.config;
|
||||||
|
if (!config) {
|
||||||
|
config = {};
|
||||||
|
} else {
|
||||||
|
config = useControlConfig ? JSON.parse(config) : this.getCurrentConfig();
|
||||||
|
}
|
||||||
|
const data = Processors.processRowObject(props.features);
|
||||||
|
const datasets = [
|
||||||
|
{
|
||||||
|
data,
|
||||||
|
info: {
|
||||||
|
id: 'main',
|
||||||
|
label: 'Superset Data',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const options = { readOnly: this.props.readonly };
|
||||||
|
if (this.props.autozoom) {
|
||||||
|
options.centerMap = true;
|
||||||
|
if (config && config.config) {
|
||||||
|
config.config.mapState = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.dispatch(addDataToMap({ datasets, config, options }));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<KeplerGl
|
||||||
|
id={this.state.keplerId}
|
||||||
|
onSaveMap={this.setMapConfig}
|
||||||
|
theme="light"
|
||||||
|
{...this.props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kepler.displayName = 'Kepler';
|
||||||
|
Kepler.propTypes = propTypes;
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({ keplerGl: state.keplerGl });
|
||||||
|
const dispatchToProps = dispatch => ({ dispatch });
|
||||||
|
const KeplerConnected = connect(
|
||||||
|
mapStateToProps,
|
||||||
|
dispatchToProps,
|
||||||
|
)(Kepler);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/no-multi-comp
|
||||||
|
export default class SubApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.store = getKeplerStore(props.setControlValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={this.store}>
|
||||||
|
<KeplerConnected {...this.props} />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/* eslint-disable sort-keys */
|
||||||
|
/**
|
||||||
|
* 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 { t } from '@superset-ui/translation';
|
||||||
|
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||||
|
import transformProps from './transformProps';
|
||||||
|
import thumbnail from './images/thumbnail.png';
|
||||||
|
|
||||||
|
const metadata = new ChartMetadata({
|
||||||
|
name: t('Kepler.gl'),
|
||||||
|
description: '',
|
||||||
|
credits: ['https://github.com/uber/kepler.gl'],
|
||||||
|
thumbnail,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default class KeplerChartPlugin extends ChartPlugin {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
metadata,
|
||||||
|
transformProps,
|
||||||
|
loadChart: () => import('./Kepler'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
Binary file not shown.
After Width: | Height: | Size: 324 KiB |
@ -0,0 +1,2 @@
|
|||||||
|
export { default as KeplerChartPreset } from './preset';
|
||||||
|
export { default as KeplerChartPlugin } from './KeplerChartPlugin';
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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 { Preset } from '@superset-ui/core';
|
||||||
|
import KeplerChartPlugin from './KeplerChartPlugin';
|
||||||
|
|
||||||
|
export default class KeplerChartPreset extends Preset {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
name: 'Kepler charts',
|
||||||
|
plugins: [new KeplerChartPlugin().configure({ key: 'kepler' })],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* eslint-disable babel/new-cap */
|
||||||
|
/* eslint-disable babel/no-invalid-this */
|
||||||
|
/* eslint-disable compat/compat */
|
||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
/* eslint-disable no-magic-numbers */
|
||||||
|
/* eslint-disable sort-keys */
|
||||||
|
/**
|
||||||
|
* 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 { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
||||||
|
import keplerGlReducer from 'kepler.gl/reducers';
|
||||||
|
import KeplerGlSchema from 'kepler.gl/schemas';
|
||||||
|
import { taskMiddleware } from 'react-palm/tasks';
|
||||||
|
|
||||||
|
let previousValue = null;
|
||||||
|
|
||||||
|
// Rates limit and only runs the latest call
|
||||||
|
function RateLimit(fn, delay, context) {
|
||||||
|
let latestCall = null;
|
||||||
|
let timer = null;
|
||||||
|
|
||||||
|
function processLatestCall() {
|
||||||
|
if (latestCall) {
|
||||||
|
fn.apply(latestCall.context, latestCall.arguments);
|
||||||
|
clearInterval(timer);
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function limited(...args) {
|
||||||
|
latestCall = {
|
||||||
|
context: context || this,
|
||||||
|
arguments: [].slice.call(args),
|
||||||
|
};
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
timer = setInterval(processLatestCall, delay);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfigControl(store, setControlValue) {
|
||||||
|
const keplerState = Object.values(store.getState().keplerGl)[0];
|
||||||
|
const stateToSave = KeplerGlSchema.getConfigToSave(keplerState);
|
||||||
|
const config = JSON.stringify(stateToSave, null, 2);
|
||||||
|
if (previousValue !== config) {
|
||||||
|
setControlValue('config', config);
|
||||||
|
previousValue = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rateLimitedUpdateConfigControl = RateLimit(updateConfigControl, 1000);
|
||||||
|
|
||||||
|
export default function getKeplerStore(setControlValue) {
|
||||||
|
// Using react-palm middleware to intercept changes and
|
||||||
|
// save the state into the config control as text
|
||||||
|
const stateChangeMiddleware = store => next => action => {
|
||||||
|
const returnValue = next(action);
|
||||||
|
rateLimitedUpdateConfigControl(store, setControlValue);
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
const reducers = combineReducers({
|
||||||
|
keplerGl: keplerGlReducer,
|
||||||
|
readonly: false,
|
||||||
|
});
|
||||||
|
const middlewares = [taskMiddleware, stateChangeMiddleware];
|
||||||
|
const enhancers = [applyMiddleware(...middlewares)];
|
||||||
|
const store = createStore(reducers, {}, compose(...enhancers));
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/* eslint-disable sort-keys */
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export default function transformProps(chartProps) {
|
||||||
|
const { formData, height, width, queryData, hooks } = chartProps;
|
||||||
|
const { mapboxApiAccessToken, features } = queryData.data;
|
||||||
|
const { config, autozoom, readonly } = formData;
|
||||||
|
|
||||||
|
return {
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
config,
|
||||||
|
autozoom,
|
||||||
|
readonly,
|
||||||
|
features,
|
||||||
|
setControlValue: hooks.setControlValue,
|
||||||
|
mapboxApiAccessToken,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user