Skip to content

Commit

Permalink
Merge 55c06c0 into 5e22183
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Jun 12, 2019
2 parents 5e22183 + 55c06c0 commit 81b4829
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 25 deletions.
51 changes: 45 additions & 6 deletions modules/layers/src/geojson-layer/geojson-layer.js
Expand Up @@ -24,6 +24,7 @@ import PathLayer from '../path-layer/path-layer';
import {PhongMaterial} from '@luma.gl/core';
// Use primitive layer to avoid "Composite Composite" layers for now
import SolidPolygonLayer from '../solid-polygon-layer/solid-polygon-layer';
import {replaceInRange} from '../utils';

import {
getGeojsonFeatures,
Expand Down Expand Up @@ -94,11 +95,40 @@ export default class GeoJsonLayer extends CompositeLayer {
};
}

updateState({oldProps, props, changeFlags}) {
if (changeFlags.dataChanged) {
const {data} = props;
const features = getGeojsonFeatures(data);
this.state.features = separateGeojsonFeatures(features);
updateState({props, changeFlags}) {
if (!changeFlags.dataChanged) {
return;
}
const features = getGeojsonFeatures(props.data);

if (Array.isArray(changeFlags.dataChanged)) {
const oldFeatures = this.state.features;
const newFeatures = {};
const featuresDiff = {};
for (const key in oldFeatures) {
newFeatures[key] = oldFeatures[key].slice();
featuresDiff[key] = [];
}

for (const dataRange of changeFlags.dataChanged) {
const partialFeatures = separateGeojsonFeatures(features, dataRange);
for (const key in oldFeatures) {
featuresDiff[key].push(
replaceInRange({
data: newFeatures[key],
getIndex: unwrapSourceFeatureIndex,
dataRange,
replace: partialFeatures[key]
})
);
}
}
this.setState({features: newFeatures, featuresDiff});
} else {
this.setState({
features: separateGeojsonFeatures(features),
featuresDiff: {}
});
}
}

Expand All @@ -115,7 +145,7 @@ export default class GeoJsonLayer extends CompositeLayer {

/* eslint-disable complexity */
renderLayers() {
const {features} = this.state;
const {features, featuresDiff} = this.state;
const {pointFeatures, lineFeatures, polygonFeatures, polygonOutlineFeatures} = features;

// Layer composition props
Expand Down Expand Up @@ -158,6 +188,8 @@ export default class GeoJsonLayer extends CompositeLayer {
this.shouldRenderSubLayer('polygons-fill', polygonFeatures) &&
new PolygonFillLayer(
{
_dataDiff: featuresDiff.polygonFeatures && (() => featuresDiff.polygonFeatures),

fp64,
extruded,
elevationScale,
Expand Down Expand Up @@ -195,6 +227,9 @@ export default class GeoJsonLayer extends CompositeLayer {
this.shouldRenderSubLayer('polygons-stroke', polygonOutlineFeatures) &&
new PolygonStrokeLayer(
{
_dataDiff:
featuresDiff.polygonOutlineFeatures && (() => featuresDiff.polygonOutlineFeatures),

fp64,
widthUnits: lineWidthUnits,
widthScale: lineWidthScale,
Expand Down Expand Up @@ -232,6 +267,8 @@ export default class GeoJsonLayer extends CompositeLayer {
this.shouldRenderSubLayer('linestrings', lineFeatures) &&
new LineStringsLayer(
{
_dataDiff: featuresDiff.lineFeatures && (() => featuresDiff.lineFeatures),

fp64,
widthUnits: lineWidthUnits,
widthScale: lineWidthScale,
Expand Down Expand Up @@ -269,6 +306,8 @@ export default class GeoJsonLayer extends CompositeLayer {
this.shouldRenderSubLayer('points', pointFeatures) &&
new PointsLayer(
{
_dataDiff: featuresDiff.pointFeatures && (() => featuresDiff.pointFeatures),

fp64,
stroked,
filled,
Expand Down
5 changes: 3 additions & 2 deletions modules/layers/src/geojson-layer/geojson.js
Expand Up @@ -63,15 +63,16 @@ export function getGeojsonFeatures(geojson) {
}

// Linearize
export function separateGeojsonFeatures(features) {
export function separateGeojsonFeatures(features, dataRange = {}) {
const separated = {
pointFeatures: [],
lineFeatures: [],
polygonFeatures: [],
polygonOutlineFeatures: []
};
const {startRow = 0, endRow = features.length} = dataRange;

for (let featureIndex = 0; featureIndex < features.length; featureIndex++) {
for (let featureIndex = startRow; featureIndex < endRow; featureIndex++) {
const feature = features[featureIndex];

assert(feature && feature.geometry, 'GeoJSON does not have geometry');
Expand Down
44 changes: 36 additions & 8 deletions modules/layers/src/polygon-layer/polygon-layer.js
Expand Up @@ -23,6 +23,7 @@ import {CompositeLayer, createIterable} from '@deck.gl/core';
import SolidPolygonLayer from '../solid-polygon-layer/solid-polygon-layer';
import PathLayer from '../path-layer/path-layer';
import * as Polygon from '../solid-polygon-layer/polygon';
import {replaceInRange} from '../utils';

const defaultLineColor = [0, 0, 0, 255];
const defaultFillColor = [0, 0, 0, 255];
Expand Down Expand Up @@ -73,8 +74,22 @@ export default class PolygonLayer extends CompositeLayer {
(changeFlags.updateTriggersChanged &&
(changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getPolygon));

if (geometryChanged) {
this.state.paths = this._getPaths(props);
if (geometryChanged && Array.isArray(changeFlags.dataChanged)) {
const paths = this.state.paths.slice();
const pathsDiff = changeFlags.dataChanged.map(dataRange =>
replaceInRange({
data: paths,
getIndex: p => p._i,
dataRange,
replace: this._getPaths(dataRange)
})
);
this.setState({paths, pathsDiff});
} else if (geometryChanged) {
this.setState({
paths: this._getPaths(),
pathsDiff: null
});
}
}

Expand All @@ -85,11 +100,13 @@ export default class PolygonLayer extends CompositeLayer {
});
}

_getPaths({data, getPolygon, positionFormat}) {
_getPaths(dataRange = {}) {
const {data, getPolygon, positionFormat} = this.props;
const paths = [];
const positionSize = positionFormat === 'XY' ? 2 : 3;
const {startRow, endRow} = dataRange;

const {iterable, objectInfo} = createIterable(data);
const {iterable, objectInfo} = createIterable(data, startRow, endRow);
for (const object of iterable) {
objectInfo.index++;
const {positions, holeIndices} = Polygon.normalize(
Expand All @@ -106,10 +123,10 @@ export default class PolygonLayer extends CompositeLayer {
holeIndices[i - 1] || 0,
holeIndices[i] || positions.length
);
paths.push({path, object});
paths.push({path, object, _i: objectInfo.index});
}
} else {
paths.push({path: positions, object});
paths.push({path: positions, object, _i: objectInfo.index});
}
}
return paths;
Expand All @@ -125,7 +142,16 @@ export default class PolygonLayer extends CompositeLayer {
/* eslint-disable complexity */
renderLayers() {
// Layer composition props
const {data, stroked, filled, extruded, wireframe, elevationScale, transitions} = this.props;
const {
data,
_dataDiff,
stroked,
filled,
extruded,
wireframe,
elevationScale,
transitions
} = this.props;

// Rendering props underlying layer
const {
Expand All @@ -151,7 +177,7 @@ export default class PolygonLayer extends CompositeLayer {
material
} = this.props;

const {paths} = this.state;
const {paths, pathsDiff} = this.state;

const FillLayer = this.getSubLayerClass('fill', SolidPolygonLayer);
const StrokeLayer = this.getSubLayerClass('stroke', PathLayer);
Expand All @@ -161,6 +187,7 @@ export default class PolygonLayer extends CompositeLayer {
this.shouldRenderSubLayer('fill', paths) &&
new FillLayer(
{
_dataDiff,
extruded,
elevationScale,

Expand Down Expand Up @@ -197,6 +224,7 @@ export default class PolygonLayer extends CompositeLayer {
this.shouldRenderSubLayer('stroke', paths) &&
new StrokeLayer(
{
_dataDiff: pathsDiff && (() => pathsDiff),
fp64,
widthUnits: lineWidthUnits,
widthScale: lineWidthScale,
Expand Down
35 changes: 27 additions & 8 deletions modules/layers/src/text-layer/text-layer.js
Expand Up @@ -29,6 +29,7 @@ import FontAtlasManager, {
DEFAULT_RADIUS,
DEFAULT_CUTOFF
} from './font-atlas-manager';
import {replaceInRange} from '../utils';

const DEFAULT_FONT_SETTINGS = {
fontSize: DEFAULT_FONT_SIZE,
Expand Down Expand Up @@ -91,13 +92,28 @@ export default class TextLayer extends CompositeLayer {
this.updateFontAtlas({oldProps, props});
}

if (
const textChanged =
changeFlags.dataChanged ||
fontChanged ||
(changeFlags.updateTriggersChanged &&
(changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getText))
) {
this.transformStringToLetters();
(changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getText));

if (textChanged && Array.isArray(changeFlags.dataChanged)) {
const data = this.state.data.slice();
const dataDiff = changeFlags.dataChanged.map(dataRange =>
replaceInRange({
data,
getIndex: p => p.objectIndex,
dataRange,
replace: this.transformStringToLetters(dataRange)
})
);
this.setState({data, dataDiff});
} else if (textChanged) {
this.setState({
data: this.transformStringToLetters(),
dataDiff: null
});
}
}

Expand Down Expand Up @@ -160,13 +176,14 @@ export default class TextLayer extends CompositeLayer {
}

/* eslint-disable no-loop-func */
transformStringToLetters() {
transformStringToLetters(dataRange = {}) {
const {data, getText} = this.props;
const {iconMapping} = this.state;
const {startRow, endRow} = dataRange;

const transformedData = [];

const {iterable, objectInfo} = createIterable(data);
const {iterable, objectInfo} = createIterable(data, startRow, endRow);
for (const object of iterable) {
objectInfo.index++;
const text = getText(object, objectInfo);
Expand Down Expand Up @@ -199,7 +216,7 @@ export default class TextLayer extends CompositeLayer {
}
}

this.setState({data: transformedData});
return transformedData;
}
/* eslint-enable no-loop-func */

Expand Down Expand Up @@ -256,7 +273,7 @@ export default class TextLayer extends CompositeLayer {
}

renderLayers() {
const {data, scale, iconAtlas, iconMapping} = this.state;
const {data, dataDiff, scale, iconAtlas, iconMapping} = this.state;

const {
getPosition,
Expand Down Expand Up @@ -285,6 +302,8 @@ export default class TextLayer extends CompositeLayer {
iconAtlas,
iconMapping,

_dataDiff: dataDiff && (() => dataDiff),

getPosition: this._getAccessor(getPosition),
getColor: this._getAccessor(getColor),
getSize: this._getAccessor(getSize),
Expand Down
41 changes: 41 additions & 0 deletions modules/layers/src/utils.js
@@ -0,0 +1,41 @@
// Assume data array is sorted by <accessor>
// Replaces the specified range with a new subarray
// Mutates the data array
// Returns {startRow, endRow} of the inserted items
export function replaceInRange({data, getIndex, dataRange, replace}) {
const {startRow = 0, endRow = Infinity} = dataRange;
const count = data.length;
let replaceStart = count;
let replaceEnd = count;
for (let i = 0; i < count; i++) {
const row = getIndex(data[i]);
if (replaceStart > i && row >= startRow) {
replaceStart = i;
}
if (row >= endRow) {
replaceEnd = i;
break;
}
}
let index = replaceStart;
const dataLengthChanged = replaceEnd - replaceStart !== replace.length;
// Save the items after replaceEnd before we overwrite data
const endChunk = dataLengthChanged && data.slice(replaceEnd);
// Insert new items
for (let i = 0; i < replace.length; i++) {
data[index++] = replace[i];
}
if (dataLengthChanged) {
// Append items after replaceEnd
for (let i = 0; i < endChunk.length; i++) {
data[index++] = endChunk[i];
}
// Trim additional items
data.length = index;
}

return {
startRow: replaceStart,
endRow: replaceStart + replace.length
};
}
12 changes: 11 additions & 1 deletion modules/test-utils/src/generate-layer-tests.js
Expand Up @@ -160,9 +160,15 @@ function makeAltDataTestCases(props, propTypes) {
if (!Array.isArray(originalData)) {
return [];
}
// partial update
const partialUpdateProps = {
data: originalData.slice(),
_dataDiff: () => [{startRow: 0, endRow: 2}]
};
// data should support any iterable
const genIterableProps = {
data: new Set(originalData)
data: new Set(originalData),
_dataDiff: null
};
// data in non-iterable form
const nonIterableProps = {
Expand All @@ -177,6 +183,10 @@ function makeAltDataTestCases(props, propTypes) {
}

return [
{
title: 'Partial update',
props: partialUpdateProps
},
{
title: 'Generic iterable data',
props: genIterableProps
Expand Down

0 comments on commit 81b4829

Please sign in to comment.