Skip to content

Commit

Permalink
Flatten CompositeLayer.renderLayer() output (visgl#676)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen authored Jun 1, 2017
1 parent f886632 commit e5fe18f
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 17 deletions.
2 changes: 1 addition & 1 deletion demo/src/components/demos/layer-demo-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export default function createLayerDemoClass(settings) {
renderLayer(data, params, {
onHover: this._onHover
})
].filter(Boolean);
];

return (
<div>
Expand Down
19 changes: 18 additions & 1 deletion docs/api-reference/composite-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ to help create sublayers and handle events.
If you intend to implement a layer that generates other layers, it is recommended
that you extend this class.

## Usage

Define a composite layer that renders a set of sublayers, one of them conditionally
```js
class MyCompositeLayer extends CompositeLayer {
renderLayers() {
return [
this._renderGroupOfSubLayers(), // returns an array of layers
this.props.showScatterplot && new ScatterplotLayer(...)
];
}
}
```


## Methods

##### `draw`
Expand All @@ -22,10 +37,12 @@ Allows a layer to "render" or insert one or more deck.gl layers after itself.
Called after a layer has been updated.

Returns:
- `null`, a single `Layer` instance, or an array of layers.
- `null`, a single `Layer` instance, or a (nested) array of layers.

The default implementation of `renderLayers` returns `null`.

`renderLayers` can return a nested arrays with `null` values. deck.gl will automatically flatten and filter the array. See usage above.


##### `getPickingInfo`

Expand Down
6 changes: 6 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# deck.gl v4.1

## CompositeLayer

* `CompositeLayer.renderLayers` can now return a nested arrays with `null` values. deck.gl will automatically flatten and filter the array. This is a small convenience that makes the `renderLayers methods in complex composite layers a little more readable.

# deck.gl v4.0

Release date: March 31, 2017
Expand Down
2 changes: 1 addition & 1 deletion examples/graph/graph-layer/graph-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export default class GraphLayer extends CompositeLayer {
linksLayer,
nodesLayer,
nodeIconsLayer
].filter(Boolean);
];
}

}
Expand Down
2 changes: 1 addition & 1 deletion examples/point-cloud-laz/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class Example extends PureComponent {
viewport={glViewport}
layers={[
this._renderLazPointCloudLayer()
].filter(Boolean)}
]}
onWebGLInitialized={this._onInitialized}/>
</OrbitController>
);
Expand Down
2 changes: 1 addition & 1 deletion examples/point-cloud-ply/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class Example extends PureComponent {
viewport={glViewport}
layers={[
this._renderPointCloudLayer()
].filter(Boolean)}
]}
onWebGLInitialized={this._onInitialized}/>
</OrbitController>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default class OutlinePolygonLayer extends CompositeLayer {
return [
polygonFillLayer
// polygonOutlineLayer
].filter(Boolean);
];
}
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"publish-prod": "npm run build && npm run test && npm run test-dist && npm publish",
"publish-beta": "npm run build && npm run test && npm run test-dist && npm publish --tag beta",
"test": "npm run lint && npm run build && npm run test-node",
"test-fast": "npm run test-node",
"test-cover": "NODE_ENV=test tape -r babel-register test/node.js && nyc report",
"test-node": "node test/node.js",
"test-dist": "node test/node-dist.js",
Expand Down
2 changes: 1 addition & 1 deletion src/layers/core/geojson-layer/geojson-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export default class GeoJsonLayer extends CompositeLayer {
pointLayer,
// If extruded: draw fill layer last for correct blending behavior
extruded && polygonFillLayer
].filter(Boolean);
];
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/layers/core/polygon-layer/polygon-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export default class PolygonLayer extends CompositeLayer {
polygonLineLayer,
// If extruded: draw fill layer last for correct blending behavior
extruded && polygonLayer
].filter(Boolean);
];
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/lib/layer-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
/* eslint-disable no-try-catch */
import Layer from './layer';
import {log} from './utils';
import {flatten} from './utils/flatten';
import assert from 'assert';
import {drawLayers, pickLayers} from './draw-and-pick';
import {LIFECYCLE} from './constants';
Expand Down Expand Up @@ -263,7 +264,10 @@ export default class LayerManager {
// End layer lifecycle method: render sublayers

if (sublayers) {
sublayers = Array.isArray(sublayers) ? sublayers : [sublayers];
// Flatten the returned array, removing any null, undefined or false
// this allows layers to render sublayers conditionally
// (see CompositeLayer.renderLayers docs)
sublayers = flatten(sublayers, {filter: Boolean});

// populate reference to parent layer
sublayers.forEach(layer => {
Expand Down
24 changes: 19 additions & 5 deletions src/lib/utils/flatten.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,32 @@
// THE SOFTWARE.

/**
* Flattens a nested array into a single level array
* Flattens a nested array into a single level array,
* or a single value into an array with one value
* @example flatten([[1, [2]], [3], 4]) => [1, 2, 3, 4]
* @example flatten(1) => [1]
* @param {Array} array The array to flatten.
* @return {Array} Returns the new flattened array.
* @param {Function} filter= - Optional predicate called on each `value` to
* determine if it should be included (pushed onto) the resulting array.
* @param {Array} result=[] - Optional array to push value into
* @return {Array} Returns the new flattened array (new array or `result` if provided)
*/
export function flatten(array, result = []) {
export function flatten(array, {
filter = () => true,
result = []
} = {}) {
array = Array.isArray(array) ? array : [array];
return flattenArray(array, filter, result);
}

// Deep flattens an array. Helper to `flatten`, see its parameters
function flattenArray(array, filter, result) {
let index = -1;
while (++index < array.length) {
const value = array[index];
if (Array.isArray(value)) {
flatten(value, result);
} else {
flattenArray(value, filter, result);
} else if (filter(value)) {
result.push(value);
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/layers/geojson-layer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ test('GeoJsonLayer#updates', t => {
},
assert: (layer, oldState) => {
t.ok(layer.state, 'should update layer state');
const subLayers = layer.renderLayers();
const subLayers = layer.renderLayers().filter(Boolean);
t.ok(subLayers.length === 2, 'should render 2 subLayers');
}
}, {
Expand Down
14 changes: 12 additions & 2 deletions test/lib/utils/flatten.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ const FLATTEN_TEST_CASES = [
title: 'nested three levels',
argument: [1, [[2], 3], [[4, [5]], 6]],
result: [1, 2, 3, 4, 5, 6]
}, {
title: 'nested three levels with predicate',
opts: {
filter: Boolean
},
argument: [1, [[2], null], [[4, [null]], 6]],
result: [1, 2, 4, 6]
}
];

Expand All @@ -62,7 +69,10 @@ test('flatten#import', t => {

test('flatten#tests', t => {
for (const tc of FLATTEN_TEST_CASES) {
const result = flatten(tc.argument);
t.comment(tc.title + JSON.stringify(tc.opts));
const result = tc.opts ?
flatten(tc.argument, tc.opts) :
flatten(tc.argument);
t.deepEqual(result, tc.result, `flatten ${tc.title} returned expected result`);
}
t.end();
Expand All @@ -71,7 +81,7 @@ test('flatten#tests', t => {
test('fillArray#tests', t => {
for (const tc of FILL_ARRAY_TEST_CASES) {
const result = fillArray(tc.arguments);
t.deepEqual(result, tc.result, `flatten ${tc.title} returned expected result`);
t.deepEqual(result, tc.result, `fillArray ${tc.title} returned expected result`);
}
t.end();
});

0 comments on commit e5fe18f

Please sign in to comment.