forked from visgl/deck.gl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add data filter example to the website (visgl#3348)
- Loading branch information
1 parent
f357a6d
commit 9e40523
Showing
15 changed files
with
542 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
This is a minimal standalone version of the DataFilterExtension example | ||
on [deck.gl](http://deck.gl) website. | ||
|
||
### Usage | ||
|
||
Copy the content of this folder to your project. | ||
|
||
To see the base map, you need a [Mapbox access token](https://docs.mapbox.com/help/how-mapbox-works/access-tokens/). You can either set an environment variable: | ||
|
||
```bash | ||
export MapboxAccessToken=<mapbox_access_token> | ||
``` | ||
|
||
Or set `MAPBOX_TOKEN` directly in `app.js`. | ||
|
||
Other options can be found at [using with Mapbox GL](../../../docs/get-started/using-with-mapbox-gl.md). | ||
|
||
```bash | ||
# install dependencies | ||
npm install | ||
# or | ||
yarn | ||
# bundle and serve the app with webpack | ||
npm start | ||
``` | ||
|
||
### Data format | ||
Sample data is stored in [kepler.gl Example Data](https://raw.githubusercontent.com/uber-web/kepler.gl-data/master/earthquakes/). To use your own data, checkout | ||
the [documentation of DataFilterExtension](../../../docs/extensions/data-filter-extension.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import React, {Component, Fragment} from 'react'; | ||
import {render} from 'react-dom'; | ||
import {StaticMap} from 'react-map-gl'; | ||
import DeckGL from '@deck.gl/react'; | ||
import {ScatterplotLayer} from '@deck.gl/layers'; | ||
import {DataFilterExtension} from '@deck.gl/extensions'; | ||
|
||
import RangeInput from './range-input'; | ||
|
||
// Set your mapbox token here | ||
const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line | ||
|
||
// Source data GeoJSON | ||
const DATA_URL = | ||
'https://raw.githubusercontent.com/uber-web/kepler.gl-data/master/earthquakes/data.csv'; // eslint-disable-line | ||
|
||
const INITIAL_VIEW_STATE = { | ||
latitude: 36.5, | ||
longitude: -120, | ||
zoom: 5.5, | ||
pitch: 0, | ||
bearing: 0 | ||
}; | ||
|
||
const MS_PER_DAY = 8.64e7; // milliseconds in a day | ||
|
||
const dataFilter = new DataFilterExtension({filterSize: 1}); | ||
|
||
export class App extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
const timeRange = this._getTimeRange(props.data); | ||
|
||
this.state = { | ||
timeRange, | ||
filterValue: timeRange, | ||
hoveredObject: null | ||
}; | ||
this._onHover = this._onHover.bind(this); | ||
this._renderTooltip = this._renderTooltip.bind(this); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
if (nextProps.data !== this.props.data) { | ||
const timeRange = this._getTimeRange(nextProps.data); | ||
this.setState({timeRange, filterValue: timeRange}); | ||
} | ||
} | ||
|
||
_getTimeRange(data) { | ||
if (!data) { | ||
return null; | ||
} | ||
return data.reduce( | ||
(range, d) => { | ||
const t = d.timestamp / MS_PER_DAY; | ||
range[0] = Math.min(range[0], t); | ||
range[1] = Math.max(range[1], t); | ||
return range; | ||
}, | ||
[Infinity, -Infinity] | ||
); | ||
} | ||
|
||
_onHover({x, y, object}) { | ||
this.setState({x, y, hoveredObject: object}); | ||
} | ||
|
||
_renderLayers() { | ||
const {data} = this.props; | ||
const {filterValue} = this.state; | ||
|
||
return [ | ||
data && | ||
new ScatterplotLayer({ | ||
id: 'earthquakes', | ||
data, | ||
opacity: 0.8, | ||
radiusScale: 100, | ||
radiusMinPixels: 1, | ||
wrapLongitude: true, | ||
|
||
getPosition: d => [d.longitude, d.latitude, -d.depth * 1000], | ||
getRadius: d => Math.pow(2, d.magnitude), | ||
getFillColor: d => { | ||
const r = Math.sqrt(Math.max(d.depth, 0)); | ||
return [255 - r * 15, r * 5, r * 10]; | ||
}, | ||
|
||
getFilterValue: d => d.timestamp / MS_PER_DAY, // in days | ||
filterRange: [filterValue[0], filterValue[1]], | ||
filterSoftRange: [ | ||
filterValue[0] * 0.9 + filterValue[1] * 0.1, | ||
filterValue[0] * 0.1 + filterValue[1] * 0.9 | ||
], | ||
extensions: [dataFilter], | ||
|
||
pickable: true, | ||
onHover: this._onHover | ||
}) | ||
]; | ||
} | ||
|
||
_renderTooltip() { | ||
const {x, y, hoveredObject} = this.state; | ||
return ( | ||
hoveredObject && ( | ||
<div className="tooltip" style={{top: y, left: x}}> | ||
<div> | ||
<b>Time: </b> | ||
<span>{new Date(hoveredObject.timestamp).toUTCString()}</span> | ||
</div> | ||
<div> | ||
<b>Magnitude: </b> | ||
<span>{hoveredObject.magnitude}</span> | ||
</div> | ||
<div> | ||
<b>Depth: </b> | ||
<span>{hoveredObject.depth} km</span> | ||
</div> | ||
</div> | ||
) | ||
); | ||
} | ||
|
||
_formatLabel(t) { | ||
const date = new Date(t * MS_PER_DAY); | ||
return `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}`; | ||
} | ||
|
||
render() { | ||
const {mapStyle = 'mapbox://styles/mapbox/light-v9'} = this.props; | ||
const {timeRange, filterValue} = this.state; | ||
|
||
return ( | ||
<Fragment> | ||
<DeckGL | ||
layers={this._renderLayers()} | ||
initialViewState={INITIAL_VIEW_STATE} | ||
controller={true} | ||
> | ||
<StaticMap | ||
reuseMaps | ||
mapStyle={mapStyle} | ||
preventStyleDiffing={true} | ||
mapboxApiAccessToken={MAPBOX_TOKEN} | ||
/> | ||
|
||
{this._renderTooltip} | ||
</DeckGL> | ||
|
||
{timeRange && ( | ||
<RangeInput | ||
min={timeRange[0]} | ||
max={timeRange[1]} | ||
value={filterValue} | ||
formatLabel={this._formatLabel} | ||
onChange={({value}) => this.setState({filterValue: value})} | ||
/> | ||
)} | ||
</Fragment> | ||
); | ||
} | ||
} | ||
|
||
export function renderToDOM(container) { | ||
render(<App />, container); | ||
require('d3-request').csv(DATA_URL, (error, response) => { | ||
if (!error) { | ||
const data = response.map(row => ({ | ||
timestamp: new Date(`${row.DateTime} UTC`).getTime(), | ||
latitude: Number(row.Latitude), | ||
longitude: Number(row.Longitude), | ||
depth: Number(row.Depth), | ||
magnitude: Number(row.Magnitude) | ||
})); | ||
render(<App data={data} />, container); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>deck.gl Example</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<style> | ||
body {margin: 0; font-family: sans-serif; width: 100vw; height: 100vh; overflow: hidden;} | ||
.tooltip {pointer-events: none; position: absolute; z-index: 9; font-size: 12px; padding: 8px; background: #000; color: #fff; min-width: 160px; max-height: 240px; overflow-y: hidden;} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
</body> | ||
<script type="text/javascript" src="app.js"></script> | ||
<script type="text/javascript"> | ||
App.renderToDOM(document.getElementById('app')); | ||
</script> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "geojson", | ||
"version": "0.0.0", | ||
"license": "MIT", | ||
"scripts": { | ||
"start-local": "webpack-dev-server --env.local --progress --hot --open", | ||
"start": "webpack-dev-server --progress --hot --open" | ||
}, | ||
"dependencies": { | ||
"baseui": "^8.5.1", | ||
"d3-request": "^1.0.5", | ||
"deck.gl": "^7.2.0-alpha.4", | ||
"react": "^16.3.0", | ||
"react-dom": "^16.3.0", | ||
"react-map-gl": "^5.0.0", | ||
"styletron-engine-atomic": "^1.4.0", | ||
"styletron-react": "^5.2.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.4.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-loader": "^8.0.5", | ||
"webpack": "^4.20.2", | ||
"webpack-cli": "^3.1.2", | ||
"webpack-dev-server": "^3.1.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* global requestAnimationFrame, cancelAnimationFrame */ | ||
import React, {PureComponent} from 'react'; | ||
import {Client as Styletron} from 'styletron-engine-atomic'; | ||
import {Provider as StyletronProvider} from 'styletron-react'; | ||
import {LightTheme, BaseProvider, styled} from 'baseui'; | ||
import {Slider} from 'baseui/slider'; | ||
import {Button, SHAPE, SIZE} from 'baseui/button'; | ||
import Start from 'baseui/icon/chevron-right'; | ||
import Stop from 'baseui/icon/delete'; | ||
|
||
const engine = new Styletron(); | ||
|
||
const Container = styled('div', { | ||
position: 'absolute', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
zIndex: 1, | ||
bottom: '20px', | ||
width: '100%' | ||
}); | ||
|
||
const ThumbValue = styled('div', { | ||
position: 'absolute', | ||
top: '-2em' | ||
}); | ||
|
||
const TickBar = styled('div', { | ||
width: '480px', | ||
height: '24px', | ||
maxWidth: '80vw' | ||
}); | ||
|
||
const ANIMATION_SPEED = 30; | ||
|
||
export default class RangeInput extends PureComponent { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
isPlaying: false | ||
}; | ||
|
||
this._renderThumbValue = this._renderThumbValue.bind(this); | ||
this._animate = this._animate.bind(this); | ||
this._toggle = this._toggle.bind(this); | ||
this._animationFrame = null; | ||
} | ||
|
||
componentWillUnmount() { | ||
cancelAnimationFrame(this._animationFrame); | ||
} | ||
|
||
_toggle() { | ||
cancelAnimationFrame(this._animationFrame); | ||
const {isPlaying} = this.state; | ||
if (!isPlaying) { | ||
this._animate(); | ||
} | ||
this.setState({isPlaying: !isPlaying}); | ||
} | ||
|
||
_animate() { | ||
const {min, max, value} = this.props; | ||
const span = value[1] - value[0]; | ||
let newValueMin = value[0] + ANIMATION_SPEED; | ||
if (newValueMin + span >= max) { | ||
newValueMin = min; | ||
} | ||
this.props.onChange({ | ||
value: [newValueMin, newValueMin + span] | ||
}); | ||
|
||
this._animationFrame = requestAnimationFrame(this._animate); | ||
} | ||
|
||
_renderThumbValue({$thumbIndex, $value}) { | ||
const value = $value[$thumbIndex]; | ||
return <ThumbValue>{this.props.formatLabel(value)}</ThumbValue>; | ||
} | ||
|
||
render() { | ||
const {value, min, max} = this.props; | ||
const isButtonEnabled = value[0] > min || value[1] < max; | ||
|
||
return ( | ||
<StyletronProvider value={engine}> | ||
<BaseProvider theme={LightTheme}> | ||
<Container> | ||
<Button | ||
shape={SHAPE.round} | ||
size={SIZE.compact} | ||
disabled={!isButtonEnabled} | ||
onClick={this._toggle} | ||
> | ||
{this.state.isPlaying ? <Stop title="Stop" /> : <Start title="Animate" />} | ||
</Button> | ||
<Slider | ||
{...this.props} | ||
overrides={{ | ||
ThumbValue: this._renderThumbValue, | ||
TickBar: () => <TickBar /> | ||
}} | ||
/> | ||
</Container> | ||
</BaseProvider> | ||
</StyletronProvider> | ||
); | ||
} | ||
} |
Oops, something went wrong.