Skip to content

Commit

Permalink
Support Immutable geojson data. Remove lodash.flattendeep and geojson…
Browse files Browse the repository at this point in the history
…-normalize.
  • Loading branch information
Ib Green committed Jan 17, 2017
1 parent d14977d commit 3defd52
Show file tree
Hide file tree
Showing 23 changed files with 860 additions and 1,137 deletions.
22 changes: 9 additions & 13 deletions examples/main/layer-examples.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import {
ChoroplethLayer,
ScatterplotLayer,
ArcLayer,
LineLayer,
ScreenGridLayer,

ScatterplotLayer64,
ArcLayer64,
ChoroplethLayer64,
ExtrudedChoroplethLayer64,
LineLayer64
ChoroplethLayer, ScatterplotLayer, ArcLayer, LineLayer, ScreenGridLayer,
ChoroplethLayer64, ExtrudedChoroplethLayer64, ScatterplotLayer64, ArcLayer64, LineLayer64,
get
} from 'deck.gl';

import * as dataSamples from './data-samples';

// Demonstrate immutable support
import Immutable from 'immutable';
const immutableChoropleths = Immutable.fromJS(dataSamples.choropleths);

const ArcLayerExample = {
layer: ArcLayer,
props: {
Expand Down Expand Up @@ -43,8 +39,8 @@ const ChoroplethLayerExample = {
layer: ChoroplethLayer,
props: {
id: 'choroplethLayerSolid',
data: dataSamples.choropleths,
getColor: f => [((f.properties.ZIP_CODE * 10) % 127) + 128, 0, 0],
data: immutableChoropleths,
getColor: f => [((get(f, 'properties.ZIP_CODE') * 10) % 127) + 128, 0, 0],
opacity: 0.8,
pickable: true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@

import {Layer} from '../../../lib';
import {assembleShaders} from '../../../shader-utils';
import {flatten, normalizeGeojson} from '../../../lib/utils';
import {GL, Model, Geometry} from 'luma.gl';
import earcut from 'earcut';
import flattenDeep from 'lodash.flattendeep';
import normalize from 'geojson-normalize';
import extrudePolyline from 'extrude-polyline';
import {readFileSync} from 'fs';
import {join} from 'path';
Expand Down Expand Up @@ -108,9 +107,8 @@ export default class EnhancedChoroplethLayer extends Layer {
calculatePositions(attribute) {
const {elevation} = this.props;
const positions = this.props.drawContour ?
flattenDeep(this.state.meshes.map(mesh =>
mesh.positions.map(pos => [...pos, elevation]))) :
flattenDeep(this.state.groupedVertices);
flatten(this.state.meshes.map(mesh => mesh.positions.map(pos => [...pos, elevation]))) :
flatten(this.state.groupedVertices);

attribute.value = new Float32Array(positions);
}
Expand All @@ -137,12 +135,12 @@ export default class EnhancedChoroplethLayer extends Layer {
)) :
this.state.groupedVertices.map(
(vertices, choroplethIndex) =>
earcut(flattenDeep(vertices), null, 3).map(
earcut(flatten(vertices), null, 3).map(
index => index + offsets[choroplethIndex]
)
);

attribute.value = new Uint16Array(flattenDeep(indices));
attribute.value = new Uint16Array(flatten(indices));
attribute.target = GL.ELEMENT_ARRAY_BUFFER;
// attribute.isIndexed = true;

Expand Down Expand Up @@ -172,7 +170,7 @@ export default class EnhancedChoroplethLayer extends Layer {
}
);

attribute.value = new Float32Array(flattenDeep(colors));
attribute.value = new Float32Array(flatten(colors));
}

// Override the default picking colors calculation
Expand All @@ -192,12 +190,12 @@ export default class EnhancedChoroplethLayer extends Layer {
)
);

attribute.value = new Float32Array(flattenDeep(colors));
attribute.value = new Float32Array(flatten(colors));
}

extractChoropleths() {
const {data} = this.props;
const normalizedGeojson = normalize(data);
const normalizedGeojson = normalizeGeojson(data);

this.state.choropleths = normalizedGeojson.features.map(choropleth => {
let coordinates = choropleth.geometry.coordinates[0] || [];
Expand Down
8 changes: 1 addition & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,14 @@
"publish-prod": "npm run build && npm run test-fast && npm publish",
"publish-beta": "npm run build && npm run test-fast && npm publish --tag beta",
"test": "npm run lint && npm run test-node",
"test-fast": "npm run lint && node test/node.js | faucet",
"test-node": "npm run build && node test/node.js",
"test-browser": "webpack-dev-server --config webpack.config.test-browser.js --progress --hot --open",
"test-fp64": "(cd test/fp64-test && webpack-dev-server --config webpack.config.test-fp64.js --progress --hot --open)",
"test-rendering": "(cd test/rendering-test && webpack-dev-server --config webpack.config.test-rendering.js --progress --hot --open)"
},
"dependencies": {
"earcut": "^2.0.6",
"geojson-normalize": "0.0.1",
"gl-matrix": "^2.3.2",
"lodash.flattendeep": "^4.4.0",
"viewport-mercator-project": "3.0.0-beta4"
},
"devDependencies": {
Expand All @@ -50,18 +47,15 @@
"eslint-plugin-react": "~6.7.0",
"faucet": "0.0.1",
"gl": "^4.0.3",
"immutable": "^3.7.5",
"jsdom": "^9.9.1",
"immutable": "^3.8.1",
"luma.gl": "3.0.0-alpha.3",
"module-alias": "^2.0.0",
"pre-commit": "^1.2.2",
"raw-loader": "^0.5.1",
"react": "^15.4.0",
"react-addons-test-utils": "^15.4.2",
"react-dom": "^15.4.0",
"react-map-gl": "^1.7.2",
"reify": "^0.4.4",
"sinon": "^1.17.7",
"tap-browser-color": "^0.1.2",
"tape": "^4.5.1",
"tape-catch": "^1.0.4",
Expand Down
117 changes: 23 additions & 94 deletions src/layers/core/choropleth-layer/choropleth-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@

import {Layer} from '../../../lib';
import {assembleShaders} from '../../../shader-utils';
import {get, flatten, extractPolygons} from '../../../lib/utils';
import {GL, Model, Geometry} from 'luma.gl';
import flattenDeep from 'lodash.flattendeep';
import normalize from 'geojson-normalize';
import earcut from 'earcut';
import {readFileSync} from 'fs';
import {join} from 'path';

const DEFAULT_COLOR = [0, 0, 255, 255];

const defaultProps = {
getColor: feature => feature.properties.color,
drawCountour: false,
getColor: feature => get(feature, 'properties.color'),
drawContour: false,
strokeWidth: 1
};

Expand All @@ -55,22 +54,17 @@ export default class ChoroplethLayer extends Layer {
// Primtive attributes
indices: {size: 1, update: this.calculateIndices, isIndexed: true},
positions: {size: 3, update: this.calculatePositions},
colors: {
type: GL.UNSIGNED_BYTE,
size: 4,
update: this.calculateColors
},
colors: {size: 4, type: GL.UNSIGNED_BYTE, update: this.calculateColors},
// Instanced attributes
pickingColors: {
type: GL.UNSIGNED_BYTE,
size: 3,
type: GL.UNSIGNED_BYTE,
update: this.calculatePickingColors,
noAlloc: true
}
});

const IndexType = gl.getExtension('OES_element_index_uint') ?
Uint32Array : Uint16Array;
const IndexType = gl.getExtension('OES_element_index_uint') ? Uint32Array : Uint16Array;

this.setState({
model: this.getModel(gl),
Expand All @@ -82,7 +76,7 @@ export default class ChoroplethLayer extends Layer {
updateState({oldProps, props, changeFlags}) {
const {attributeManager} = this.state;
if (changeFlags.dataChanged) {
this.state.choropleths = extractChoropleths(props.data);
this.state.choropleths = extractPolygons(props.data);
attributeManager.invalidateAll();
}

Expand All @@ -107,7 +101,7 @@ export default class ChoroplethLayer extends Layer {
super.pick(opts);
const {info} = opts;
const index = this.decodePickingColor(info.color);
const feature = index >= 0 ? this.props.data.features[index] : null;
const feature = index >= 0 ? get(this.props.data, ['features', index]) : null;
info.feature = feature;
info.object = feature;
}
Expand Down Expand Up @@ -144,125 +138,60 @@ export default class ChoroplethLayer extends Layer {
(choropleth, choroplethIndex) => this.props.drawContour ?
// 1. get sequentially ordered indices of each choropleth contour
// 2. offset them by the number of indices in previous choropleths
calculateContourIndices(choropleth).map(
index => index + offsets[choroplethIndex]
) :
calculateContourIndices(choropleth).map(index => index + offsets[choroplethIndex]) :
// 1. get triangulated indices for the internal areas
// 2. offset them by the number of indices in previous choropleths
calculateSurfaceIndices(choropleth).map(
index => index + offsets[choroplethIndex]
)
calculateSurfaceIndices(choropleth).map(index => index + offsets[choroplethIndex])
);

attribute.value = new IndexType(flattenDeep(indices));
attribute.value = new IndexType(flatten(indices));
attribute.target = GL.ELEMENT_ARRAY_BUFFER;
this.state.model.setVertexCount(attribute.value.length / attribute.size);
}

calculatePositions(attribute) {
const vertices = flattenDeep(this.state.choropleths);
const vertices = flatten(this.state.choropleths);
attribute.value = new Float32Array(vertices);
}

calculateColors(attribute) {
const {data: {features}, getColor} = this.props;

const {data, getColor} = this.props;
const features = get(data, 'features');
const colors = this.state.choropleths.map(
(choropleth, choroplethIndex) => {
const feature = features[choropleth.featureIndex];
const feature = get(features, choropleth.featureIndex);
const color = getColor(feature) || DEFAULT_COLOR;

// Ensure alpha is set
if (isNaN(color[3])) {
color[3] = DEFAULT_COLOR[3];
}

return choropleth.map(polygon =>
polygon.map(vertex => color)
);
return choropleth.map(polygon => polygon.map(vertex => color));
}
);

attribute.value = new Uint8Array(flattenDeep(colors));
attribute.value = new Uint8Array(flatten(colors));
}

// Override the default picking colors calculation
calculatePickingColors(attribute) {

const colors = this.state.choropleths.map(
(choropleth, choroplethIndex) => {
const {featureIndex} = choropleth;
const color = this.props.drawContour ? [0, 0, 0] : [
(featureIndex + 1) % 256,
Math.floor((featureIndex + 1) / 256) % 256,
Math.floor((featureIndex + 1) / 256 / 256) % 256];
return choropleth.map(polygon =>
polygon.map(vertex => color)
);
Math.floor((featureIndex + 1) / 256 / 256) % 256
];
return choropleth.map(polygon => polygon.map(vertex => color));
}
);

attribute.value = new Uint8Array(flattenDeep(colors));
attribute.value = new Uint8Array(flatten(colors));
}
}

ChoroplethLayer.layerName = 'ChoroplethLayer';

/*
* converts list of features from a GeoJSON object to a list of GeoJSON
* polygon-style coordinates
* @param {Object} data - geojson object
* @returns {[Number,Number,Number][][][]} array of choropleths
*/
function extractChoropleths(data) {
const normalizedGeojson = normalize(data);
const result = [];

normalizedGeojson.features.map((feature, featureIndex) => {
const choropleths = featureToChoropleths(feature);
choropleths.forEach(choropleth => {
choropleth.featureIndex = featureIndex;
});
result.push(...choropleths);
});
return result;
}

/*
* converts one GeoJSON features from object to a list of GeoJSON polygon-style
* coordinates
* @param {Object} data - geojson object
* @returns {[Number,Number,Number][][][]} array of choropleths
*/
function featureToChoropleths(feature) {
const {coordinates, type} = feature.geometry;
let choropleths;

switch (type) {
case 'MultiPolygon':
choropleths = coordinates;
break;
case 'Polygon':
choropleths = [coordinates];
break;
case 'LineString':
// create a LineStringLayer for LineString and MultiLineString?
choropleths = [[coordinates]];
break;
case 'MultiLineString':
choropleths = coordinates.map(coords => [coords]);
break;
default:
choropleths = [];
}
return choropleths.map(
choropleth => choropleth.map(
polygon => polygon.map(
coordinate => [coordinate[0], coordinate[1], coordinate[2] || 0]
)
)
);
}

/*
* get vertex indices for drawing choropleth contour
* @param {[Number,Number,Number][][]} choropleth
Expand Down Expand Up @@ -301,5 +230,5 @@ function calculateSurfaceIndices(choropleth) {
).slice(1, choropleth.length);
}

return earcut(flattenDeep(choropleth), holes, 3);
return earcut(flatten(choropleth), holes, 3);
}
Loading

0 comments on commit 3defd52

Please sign in to comment.