Skip to content

Instantly share code, notes, and snippets.

@jaronimoe
Last active September 12, 2019 12:55
Show Gist options
  • Save jaronimoe/efdbb58b3f52c2aac63362a921802cfe to your computer and use it in GitHub Desktop.
Save jaronimoe/efdbb58b3f52c2aac63362a921802cfe to your computer and use it in GitHub Desktop.
deck.gl geojson update color on hover test
import React, {Component} from 'react';
import {render} from 'react-dom';
import {StaticMap} from 'react-map-gl';
import DeckGL, {GeoJsonLayer, PolygonLayer} from 'deck.gl';
import {LightingEffect, AmbientLight, _SunLight as SunLight} from '@deck.gl/core';
import {scaleThreshold} from 'd3-scale';
import {getJSONData} from './data_loader'
// 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-common/deck.gl-data/master/examples/geojson/vancouver-blocks.json'; // eslint-disable-line
var feats = {};
export const COLOR_SCALE = scaleThreshold()
.domain([-0.6, -0.45, -0.3, -0.15, 0, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1.05, 1.2])
.range([
[65, 182, 196],
[127, 205, 187],
[199, 233, 180],
[237, 248, 177],
// zero
[255, 255, 204],
[255, 237, 160],
[254, 217, 118],
[254, 178, 76],
[253, 141, 60],
[252, 78, 42],
[227, 26, 28],
[189, 0, 38],
[128, 0, 38]
]);
const INITIAL_VIEW_STATE = {
latitude: 49.254,
longitude: -123.13,
zoom: 11,
maxZoom: 16,
pitch: 45,
bearing: 0
};
const ambientLight = new AmbientLight({
color: [255, 255, 255],
intensity: 1.0
});
const dirLight = new SunLight({
timestamp: Date.UTC(2019, 7, 1, 22),
color: [255, 255, 255],
intensity: 1.0,
_shadow: true
});
const landCover = [[[-123.0, 49.196], [-123.0, 49.324], [-123.306, 49.324], [-123.306, 49.196]]];
export class App extends Component {
constructor(props) {
super(props);
console.log(props)
this.state = {
hoveredObject: null,
features:null
};
this._onHover = this._onHover.bind(this);
this._renderTooltip = this._renderTooltip.bind(this);
const lightingEffect = new LightingEffect({ambientLight, dirLight});
lightingEffect.shadowColor = [0, 0, 0, 0.5];
this._effects = [lightingEffect];
}
componentDidMount() {
let self = this;
let geoJSON_data = getJSONData(DATA_URL);
geoJSON_data.then(function(value) {
console.log("promised...");
console.log(value);
feats = initFeatureSelected(value);
self.setState({features: feats});
});
}
_onHover({x, y, object}) {
if(object) {
object.properties.selected = true;
feats = setFeatureSelected(feats, object);
this.setState({x, y, hoveredObject: object, features: feats});
}
this.setState({x, y, hoveredObject: object});
}
_renderLayers(props) {
const {data} = props;
console.log(props)
return [
// only needed when using shadows - a plane for shadows to drop on
new PolygonLayer({
id: 'ground',
data: landCover,
stroked: false,
getPolygon: f => f,
getFillColor: [0, 0, 0, 0]
}),
new GeoJsonLayer({
id: 'geojson',
data,
opacity: 0.8,
stroked: false,
filled: true,
extruded: true,
wireframe: true,
getElevation: 50, //Math.sqrt(f.properties.valuePerSqm) * 10,
getFillColor: d => d.properties.selected ? [100, 105, 155] : [55, 205, 155], //COLOR_SCALE(f.properties.growth),
getLineColor: [255, 255, 255],
pickable: true,
onHover: this._onHover
})
];
}
_renderTooltip() {
const {x, y, hoveredObject} = this.state;
return (
hoveredObject && (
<div className="tooltip" style={{top: y, left: x}}>
<div>
<b>Average Property Value</b>
</div>
<div>
<div>${hoveredObject.properties.valuePerParcel} / parcel</div>
<div>
${hoveredObject.properties.valuePerSqm} / m<sup>2</sup>
</div>
</div>
<div>
<b>Growth</b>
</div>
<div>{Math.round(hoveredObject.properties.growth * 100)}%</div>
</div>
)
);
}
render() {
const {mapStyle = 'mapbox://styles/mapbox/light-v9'} = this.props;
return (
<DeckGL
layers={this._renderLayers({data: this.state.features})}
effects={this._effects}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
>
<StaticMap
reuseMaps
mapStyle={mapStyle}
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
{this._renderTooltip}
</DeckGL>
);
}
}
export function renderToDOM(container) {
render(<App />, container);
}
function setFeatureSelected(features, selfeat)
{
let selectedID = selfeat.properties.id;
for(let i=0; i<features.features.length; i++)
{
let currentID = features.features[i].properties.id;
if(selectedID == currentID) {
features.features[i].properties.selected = true;
}
}
return features;
}
function initFeatureSelected(features)
{
// let selectedID = selfeat.properties.id;
for(let i=0; i<features.features.length; i++)
{
features.features[i].properties.selected = false;
}
return features;
}
export function getJSONData(datapath)
{
let pdata = new Promise(function(resolve, reject){
loadData(datapath, parseJSONCallback);
function loadData(path, callback)
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = callback;
xmlhttp.open("GET", path, true);
xmlhttp.send();
}
function parseJSONCallback() {
if (this.readyState == 4 && this.status == 200) {
console.log("data loaded...");
// console.log(this.responseText);
var fileresult = JSON.parse(this.responseText);
resolve(fileresult);
}
}
});
return pdata;
}
<!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>
{
"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": {
"d3-scale": "^2.0.0",
"deck.gl": "^7.2.0-beta",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"react-map-gl": "^5.0.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"
}
}
// NOTE: To use this example standalone (e.g. outside of deck.gl repo)
// delete the local development overrides at the bottom of this file
const webpack = require('webpack');
const CONFIG = {
mode: 'development',
entry: {
app: './app.js'
},
output: {
library: 'App'
},
module: {
rules: [
{
// Transpile ES6 to ES5 with babel
// Remove if your app does not use JSX or you don't need to support old browsers
test: /\.js$/,
loader: 'babel-loader',
exclude: [/node_modules/],
options: {
presets: ['@babel/preset-react']
}
}
]
},
// Optional: Enables reading mapbox token from environment variable
plugins: [new webpack.EnvironmentPlugin(['MapboxAccessToken'])]
};
// This line enables bundling against src in this repo rather than installed module
module.exports = env => (env ? require('../../webpack.config.local')(CONFIG)(env) : CONFIG);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment