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",
|
||||
"devDependencies": {
|
||||
"@superset-ui/build-config": "^0.1.0",
|
||||
"@superset-ui/commit-config": "^0.0.9",
|
||||
"@superset-ui/chart": "^0.12.1",
|
||||
"@superset-ui/chart-composition": "^0.12.1",
|
||||
"@superset-ui/color": "^0.12.1",
|
||||
"@superset-ui/commit-config": "^0.0.9",
|
||||
"@superset-ui/connection": "^0.12.0",
|
||||
"@superset-ui/core": "^0.12.0",
|
||||
"@superset-ui/dimension": "^0.12.0",
|
||||
@ -59,6 +59,7 @@
|
||||
"husky": "^3.0.3",
|
||||
"lerna": "^3.2.1",
|
||||
"lint-staged": "^9.2.1",
|
||||
"luma.gl": "^7.3.0",
|
||||
"react": "^16.6.0",
|
||||
"react-dom": "^16.6.0",
|
||||
"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