diff --git a/examples/custom-xviz-layers/README.md b/examples/custom-xviz-layers/README.md
new file mode 100644
index 00000000..e7fa5355
--- /dev/null
+++ b/examples/custom-xviz-layers/README.md
@@ -0,0 +1,5 @@
+# streetscape.gl Starter Kit
+
+This is an example showing the use of custom xviz layers for custom xviz streams.
+
+[Instructions for running this application](../../docs/get-started/starter-kit.md)
diff --git a/examples/custom-xviz-layers/index.html b/examples/custom-xviz-layers/index.html
new file mode 100644
index 00000000..eb7a7e83
--- /dev/null
+++ b/examples/custom-xviz-layers/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+ streetscape.gl quick start
+
+
+
+
+
+
+
+
diff --git a/examples/custom-xviz-layers/package.json b/examples/custom-xviz-layers/package.json
new file mode 100644
index 00000000..b45e1fee
--- /dev/null
+++ b/examples/custom-xviz-layers/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "streetscape.gl-quick-start",
+ "description": "A template app of streetscape.gl",
+ "version": "0.1.0",
+ "scripts": {
+ "start-local": "webpack-dev-server --env.local --progress --hot --open",
+ "start-streaming-local": "webpack-dev-server --env.local --env.stream --progress --hot --open",
+ "start-live-local": "webpack-dev-server --env.local --env.live --progress --hot --open",
+ "start": "webpack-dev-server --progress --hot --open",
+ "start-streaming": "webpack-dev-server --env.stream --progress --hot --open",
+ "start-live": "webpack-dev-server --env.live --progress --hot --open"
+ },
+ "dependencies": {
+ "@deck.gl/extensions": "^8.4.13",
+ "react": "^16.3.0",
+ "react-dom": "^16.3.0",
+ "streetscape.gl": "^1.0.0"
+ },
+ "devDependencies": {
+ "@babel/cli": "^7.0.0",
+ "@babel/core": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.0.0",
+ "@babel/preset-env": "^7.0.0",
+ "@babel/preset-react": "^7.0.0",
+ "babel-loader": "^8.0.0",
+ "source-map-loader": "^0.2.3",
+ "webpack": "^4.20.0",
+ "webpack-cli": "^3.1.2",
+ "webpack-dev-server": "^3.1.1"
+ },
+ "resolutions": {
+ "@deck.gl/core": "8.4.12"
+ }
+}
diff --git a/examples/custom-xviz-layers/src/app.js b/examples/custom-xviz-layers/src/app.js
new file mode 100644
index 00000000..6ef8edf6
--- /dev/null
+++ b/examples/custom-xviz-layers/src/app.js
@@ -0,0 +1,172 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/* global document, console */
+/* eslint-disable no-console, no-unused-vars, no-undef */
+import React, {PureComponent} from 'react';
+import {render} from 'react-dom';
+import {PathStyleExtension} from '@deck.gl/extensions';
+import {setXVIZConfig, getXVIZConfig} from '@xviz/parser';
+import {
+ LaneLayer,
+ LogViewer,
+ PlaybackControl,
+ StreamSettingsPanel,
+ MeterWidget,
+ TrafficLightWidget,
+ TurnSignalWidget,
+ XVIZPanel,
+ VIEW_MODE
+} from 'streetscape.gl';
+import {Form} from '@streetscape.gl/monochrome';
+
+import {XVIZ_CONFIG, APP_SETTINGS, MAPBOX_TOKEN, MAP_STYLE, XVIZ_STYLE, CAR} from './constants';
+
+setXVIZConfig(XVIZ_CONFIG);
+
+const TIMEFORMAT_SCALE = getXVIZConfig().TIMESTAMP_FORMAT === 'seconds' ? 1000 : 1;
+
+// __IS_STREAMING__ and __IS_LIVE__ are defined in webpack.config.js
+const exampleLog = require(__IS_STREAMING__
+ ? './log-from-stream'
+ : __IS_LIVE__
+ ? './log-from-live'
+ : './log-from-file').default;
+
+class Example extends PureComponent {
+ state = {
+ log: exampleLog,
+ settings: {
+ viewMode: 'PERSPECTIVE',
+ showTooltip: false
+ }
+ };
+
+ componentDidMount() {
+ this.state.log.on('error', console.error).connect();
+ }
+
+ _onSettingsChange = changedSettings => {
+ this.setState({
+ settings: {...this.state.settings, ...changedSettings}
+ });
+ };
+
+ render() {
+ const {log, settings} = this.state;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
{
+ //
+ return streamMetadata.primitive_type === 'polyline';
+ },
+ /*
+ * Defines props to spread into `this.getSublayerProps` in the XVIZLayer
+ * @param {Object} xvizLayerProps - all props passed into XVIZLayer
+ * @param {Object} primitiveLayerProps - all layer-type props that are used for the primitive layer
+ * @param {Object} state - the XVIZLayer state
+ */
+ getSubProps: ({xvizLayerProps, primitiveLayerProps, state}) => {
+ return {
+ id: 'path-dual',
+ getWidth: [0.1, 0.1, 0.1],
+ getPath: f => f.vertices,
+ getDashArray: () => [1, 2],
+ getDashArray2: () => [2, 4],
+ getColor2: state.layerProps.getColor,
+ extensions: [new PathStyleExtension({dash: true})]
+ };
+ }
+ }
+ ]}
+ />
+
+
+
+
+
+
+
+ (x > 6 ? 'FAST' : '')}
+ min={0}
+ max={20}
+ />
+
+
+
+
new Date(x * TIMEFORMAT_SCALE).toUTCString()}
+ />
+
+
+
+ );
+ }
+}
+
+render(, document.getElementById('app'));
diff --git a/examples/custom-xviz-layers/src/constants.js b/examples/custom-xviz-layers/src/constants.js
new file mode 100644
index 00000000..ef7bf779
--- /dev/null
+++ b/examples/custom-xviz-layers/src/constants.js
@@ -0,0 +1,54 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+import {CarMesh} from 'streetscape.gl';
+
+/* eslint-disable camelcase */
+export const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line
+
+export const MAP_STYLE = 'mapbox://styles/mapbox/light-v9';
+
+export const XVIZ_CONFIG = {
+ PLAYBACK_FRAME_RATE: 10
+};
+
+export const CAR = CarMesh.sedan({
+ origin: [1.08, -0.32, 0],
+ length: 4.3,
+ width: 2.2,
+ height: 1.5,
+ color: [160, 160, 160]
+});
+
+export const APP_SETTINGS = {
+ viewMode: {
+ type: 'select',
+ title: 'View Mode',
+ data: {TOP_DOWN: 'Top Down', PERSPECTIVE: 'Perspective', DRIVER: 'Driver'}
+ },
+ showTooltip: {
+ type: 'toggle',
+ title: 'Show Tooltip'
+ }
+};
+
+export const XVIZ_STYLE = {
+ '/tracklets/objects': [{name: 'selected', style: {fill_color: '#ff8000aa'}}],
+ '/lidar/points': [{style: {point_color_mode: 'ELEVATION'}}]
+};
diff --git a/examples/custom-xviz-layers/src/log-from-file.js b/examples/custom-xviz-layers/src/log-from-file.js
new file mode 100644
index 00000000..0d375df4
--- /dev/null
+++ b/examples/custom-xviz-layers/src/log-from-file.js
@@ -0,0 +1,31 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import {XVIZFileLoader} from 'streetscape.gl';
+
+export default new XVIZFileLoader({
+ timingsFilePath:
+ 'https://raw.githubusercontent.com/uber/xviz-data/master/kitti/2011_09_26_drive_0005_sync/0-frame.json',
+ getFilePath: index =>
+ `https://raw.githubusercontent.com/uber/xviz-data/master/kitti/2011_09_26_drive_0005_sync/${index +
+ 1}-frame.glb`,
+ worker: true,
+ maxConcurrency: 4
+});
diff --git a/examples/custom-xviz-layers/src/log-from-live.js b/examples/custom-xviz-layers/src/log-from-live.js
new file mode 100644
index 00000000..c1a9beb9
--- /dev/null
+++ b/examples/custom-xviz-layers/src/log-from-live.js
@@ -0,0 +1,32 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import {XVIZLiveLoader} from 'streetscape.gl';
+
+export default new XVIZLiveLoader({
+ logGuid: 'mock',
+ bufferLength: 10,
+ serverConfig: {
+ defaultLogLength: 30,
+ serverUrl: 'ws://localhost:8081'
+ },
+ worker: true,
+ maxConcurrency: 4
+});
diff --git a/examples/custom-xviz-layers/src/log-from-stream.js b/examples/custom-xviz-layers/src/log-from-stream.js
new file mode 100644
index 00000000..6e4eba38
--- /dev/null
+++ b/examples/custom-xviz-layers/src/log-from-stream.js
@@ -0,0 +1,32 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import {XVIZStreamLoader} from 'streetscape.gl';
+
+export default new XVIZStreamLoader({
+ logGuid: 'mock',
+ // bufferLength: 15,
+ serverConfig: {
+ defaultLogLength: 30,
+ serverUrl: 'ws://localhost:8081'
+ },
+ worker: true,
+ maxConcurrency: 4
+});
diff --git a/examples/custom-xviz-layers/webpack.config.js b/examples/custom-xviz-layers/webpack.config.js
new file mode 100644
index 00000000..11877aa3
--- /dev/null
+++ b/examples/custom-xviz-layers/webpack.config.js
@@ -0,0 +1,73 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/* eslint-disable no-process-env */
+const {resolve} = require('path');
+const webpack = require('webpack');
+
+const BABEL_CONFIG = {
+ presets: ['@babel/preset-env', '@babel/preset-react'],
+ plugins: ['@babel/proposal-class-properties']
+};
+
+const CONFIG = {
+ mode: 'development',
+ entry: {
+ app: resolve('./src/app.js')
+ },
+ devtool: 'source-map',
+ output: {
+ path: resolve('./dist'),
+ filename: 'bundle.js'
+ },
+ module: {
+ noParse: /(mapbox-gl)\.js$/,
+ rules: [
+ {
+ // Compile ES2015 using bable
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ options: BABEL_CONFIG
+ }
+ ]
+ },
+ plugins: [
+ new webpack.HotModuleReplacementPlugin(),
+ new webpack.EnvironmentPlugin(['MapboxAccessToken'])
+ ]
+};
+
+module.exports = (env = {}) => {
+ let config = Object.assign({}, CONFIG);
+
+ // This switch between streaming and static file loading
+ config.plugins = config.plugins.concat([
+ new webpack.DefinePlugin({__IS_STREAMING__: JSON.stringify(Boolean(env.stream))}),
+ new webpack.DefinePlugin({__IS_LIVE__: JSON.stringify(Boolean(env.live))})
+ ]);
+
+ if (env.local) {
+ // This line enables bundling against src in this repo rather than installed module
+ config = require('../webpack.config.local')(config)(env);
+ }
+
+ return config;
+};
diff --git a/modules/core/src/components/log-viewer/core-3d-viewer.js b/modules/core/src/components/log-viewer/core-3d-viewer.js
index 5658cb0f..a03a15a0 100644
--- a/modules/core/src/components/log-viewer/core-3d-viewer.js
+++ b/modules/core/src/components/log-viewer/core-3d-viewer.js
@@ -74,6 +74,7 @@ export default class Core3DViewer extends PureComponent {
PropTypes.func
]),
customLayers: PropTypes.array,
+ customXVIZLayers: PropTypes.array,
renderObjectLabel: PropTypes.func,
getTransformMatrix: PropTypes.func,
viewOptions: PropTypes.object,
@@ -100,6 +101,7 @@ export default class Core3DViewer extends PureComponent {
viewMode: VIEW_MODE.PERSPECTIVE,
xvizStyles: {},
customLayers: [],
+ customXVIZLayers: [],
onMapLoad: noop,
onDeckLoad: noop,
onViewStateChange: noop,
@@ -245,6 +247,7 @@ export default class Core3DViewer extends PureComponent {
streamsMetadata,
objectStates,
customLayers,
+ customXVIZLayers,
getTransformMatrix,
styleParser
} = opts;
@@ -286,7 +289,6 @@ export default class Core3DViewer extends PureComponent {
...coordinateProps,
pickable: true,
-
data: primitives,
style: stylesheet,
objectStates,
@@ -297,7 +299,9 @@ export default class Core3DViewer extends PureComponent {
zIndex: Z_INDEX[primitives[0].type] || 0,
// Selection props (app defined, not used by deck.gl)
- streamName
+ streamName,
+ streamMetadata: streamsMetadata[streamName],
+ customXVIZLayers
});
}
return null;
@@ -397,7 +401,8 @@ export default class Core3DViewer extends PureComponent {
viewMode,
viewState,
viewOffset,
- showMap
+ showMap,
+ customXVIZLayers
} = this.props;
const {styleParser, views} = this.state;
const layers = this.getLayers({
@@ -408,7 +413,8 @@ export default class Core3DViewer extends PureComponent {
objectStates,
customLayers,
getTransformMatrix,
- styleParser
+ styleParser,
+ customXVIZLayers
});
const viewStates = this.getViewState({viewMode, frame, viewState, viewOffset});
diff --git a/modules/core/src/layers/xviz-layer.js b/modules/core/src/layers/xviz-layer.js
index c307e8cb..234f795d 100644
--- a/modules/core/src/layers/xviz-layer.js
+++ b/modules/core/src/layers/xviz-layer.js
@@ -107,6 +107,129 @@ const STYLE_TO_LAYER_PROP = {
text_baseline: 'getAlignmentBaseline'
}
};
+/*
+ ####### EXTENDING XVIZ LAYER FOR PRIMITIVES #########
+*/
+// not sure if necessary, just to have enums for existing primitives
+const LAYER_TYPES = {
+ SCATTERPLOT: 'scatterplot',
+ PATH: 'path',
+ POINTCLOUD: 'pointcloud',
+ STADIUM: 'stadium',
+ POLYGON: 'polygon',
+ TEXT: 'text'
+};
+
+// Defines the way that each primitive layer type is handled in the application
+const LAYER_HANDLERS = {
+ [LAYER_TYPES.SCATTERPLOT]: {
+ layerType: LAYER_TYPES.SCATTERPLOT,
+ layerClass: ScatterplotLayer,
+ // returns data to hold in state
+ // updateState calls `getState({data: preprocessData})`
+ preprocessData: props => {
+ const {data} = props;
+ if (data[0].vertices && Array.isArray(data[0].vertices[0])) {
+ const processedData = data.reduce((arr, multiPoints) => {
+ multiPoints.vertices.forEach(pt => {
+ arr.push({...multiPoints, vertices: pt});
+ });
+ return arr;
+ }, []);
+ return processedData;
+ }
+ return data;
+ },
+ getLayerTypeProps: ({xvizLayerProps, layerProps}) => {
+ const {updateTriggers} = layerProps;
+ return {
+ // `vertices` is used xviz V1 and `center` is used by xviz V2
+ getPosition: f => f.vertices || f.center,
+ updateTriggers: deepExtend(updateTriggers, {
+ getFillColor: {useSemanticColor: xvizLayerProps.useSemanticColor}
+ })
+ };
+ }
+ },
+ [LAYER_TYPES.STADIUM]: {
+ layerType: LAYER_TYPES.STADIUM,
+ layerClass: PathLayer,
+ getLayerTypeProps: ({xvizLayerProps, layerProps}) => {
+ const {updateTriggers} = layerProps;
+ return {
+ getPath: f => [f.start, f.end],
+ rounded: true,
+ updateTriggers: deepExtend(updateTriggers, {
+ getColor: {useSemanticColor: xvizLayerProps.useSemanticColor}
+ })
+ };
+ }
+ },
+ [LAYER_TYPES.POINTCLOUD]: {
+ layerType: LAYER_TYPES.POINTCLOUD,
+ layerClass: PointCloudLayer,
+ getLayerTypeProps: ({xvizLayerProps, state}) => {
+ const {data} = state;
+ return {
+ data: {
+ length: data[0].points.length / 3,
+ attributes: {
+ getPosition: data[0].points,
+ getColor: data[0].colors
+ }
+ },
+ vehicleRelativeTransform: xvizLayerProps.vehicleRelativeTransform,
+ getPosition: p => p
+ };
+ }
+ },
+ [LAYER_TYPES.PATH]: {
+ layerType: LAYER_TYPES.PATH,
+ layerClass: PathLayer,
+ getLayerTypeProps: ({xvizLayerProps, layerProps}) => {
+ const {updateTriggers} = layerProps;
+ return {
+ getPath: f => f.vertices,
+ updateTriggers: deepExtend(updateTriggers, {
+ getColor: {useSemanticColor: xvizLayerProps.useSemanticColor}
+ })
+ };
+ }
+ },
+ [LAYER_TYPES.POLYGON]: {
+ layerType: LAYER_TYPES.POLYGON,
+ layerClass: PolygonLayer,
+ getLayerTypeProps: ({xvizLayerProps, layerProps}) => {
+ const {updateTriggers} = layerProps;
+ const {lightSettings, useSemanticColor, opacity} = xvizLayerProps;
+ const {stroked} = layerProps;
+ return {
+ opacity: opacity || 1,
+ lightSettings,
+ wireframe: stroked,
+ getPolygon: f => f.vertices,
+ updateTriggers: deepExtend(updateTriggers, {
+ getLineColor: {useSemanticColor},
+ getFillColor: {useSemanticColor}
+ })
+ };
+ }
+ },
+ [LAYER_TYPES.TEXT]: {
+ layerType: LAYER_TYPES.TEXT,
+ layerClass: TextLayer,
+ getLayerTypeProps: ({xvizLayerProps, layerProps}) => {
+ const {updateTriggers} = layerProps;
+ const {useSemanticColor} = xvizLayerProps;
+ return {
+ getText: f => f.text,
+ updateTriggers: deepExtend(updateTriggers, {
+ getColor: {useSemanticColor}
+ })
+ };
+ }
+ }
+};
const EMPTY_OBJECT = {};
@@ -267,15 +390,9 @@ export default class XVIZLayer extends CompositeLayer {
let data = props.data;
const dataType = this._getLayerType(data);
type = XVIZ_TO_LAYER_TYPE[dataType];
-
- if (type === 'scatterplot' && data[0].vertices && Array.isArray(data[0].vertices[0])) {
- // is multi point
- data = data.reduce((arr, multiPoints) => {
- multiPoints.vertices.forEach(pt => {
- arr.push({...multiPoints, vertices: pt});
- });
- return arr;
- }, []);
+ const layerHandler = LAYER_HANDLERS[type];
+ if (layerHandler && layerHandler.preprocessData) {
+ data = layerHandler.preprocessData(props);
}
this.setState({data});
@@ -289,120 +406,69 @@ export default class XVIZLayer extends CompositeLayer {
}
renderLayers() {
- const {lightSettings} = this.props;
const {type, data} = this.state;
if (!type) {
return null;
}
- const {linkTitle, streamName, objectType} = this.props;
+ const {linkTitle, streamName, streamMetadata, objectType} = this.props;
const layerProps = this._getLayerProps();
- const updateTriggers = layerProps.updateTriggers;
const forwardProps = {
linkTitle,
streamName,
objectType
};
-
- switch (type) {
- case 'scatterplot':
- return new ScatterplotLayer(
- forwardProps,
- layerProps,
- this.getSubLayerProps({
- id: 'scatterplot',
- data,
- // `vertices` is used xviz V1 and `center` is used by xviz V2
- getPosition: f => f.vertices || f.center,
- updateTriggers: deepExtend(updateTriggers, {
- getFillColor: {useSemanticColor: this.props.useSemanticColor}
- })
- })
- );
-
- case 'pointcloud':
- return new PointCloudLayer(
- forwardProps,
- layerProps,
- this.getSubLayerProps({
- id: 'pointcloud',
- data: {
- length: data[0].points.length / 3,
- attributes: {
- getPosition: data[0].points,
- getColor: data[0].colors
- }
- },
- vehicleRelativeTransform: this.props.vehicleRelativeTransform,
- getPosition: p => p
- })
- );
-
- case 'path':
- return new PathLayer(
- forwardProps,
+ // multiple layers?
+ const customXvizLayerMatch = this.props.customXVIZLayers.find(({streamMatch}) =>
+ streamMatch(streamName, streamMetadata)
+ );
+
+ if (customXvizLayerMatch) {
+ let primitiveLayerProps = {};
+ const parentLayerHandler = LAYER_HANDLERS[customXvizLayerMatch.extendPrimitive];
+ if (parentLayerHandler) {
+ primitiveLayerProps = parentLayerHandler.getLayerTypeProps({
+ xvizLayerProps: this.props,
layerProps,
- this.getSubLayerProps({
- id: 'path',
- data,
- getPath: f => f.vertices,
- updateTriggers: deepExtend(updateTriggers, {
- getColor: {useSemanticColor: this.props.useSemanticColor}
- })
- })
- );
-
- case 'stadium':
- return new PathLayer(
- forwardProps,
- layerProps,
- this.getSubLayerProps({
- id: 'stadium',
- data,
- getPath: f => [f.start, f.end],
- rounded: true,
- updateTriggers: deepExtend(updateTriggers, {
- getColor: {useSemanticColor: this.props.useSemanticColor}
- })
- })
- );
+ state: this.state
+ });
+ }
- case 'polygon':
- return new PolygonLayer(
- forwardProps,
- layerProps,
- this.getSubLayerProps({
- id: 'polygon',
- opacity: this.props.opacity || 1,
- data,
- lightSettings,
- wireframe: layerProps.stroked,
- getPolygon: f => f.vertices,
- updateTriggers: deepExtend(updateTriggers, {
- getLineColor: {useSemanticColor: this.props.useSemanticColor},
- getFillColor: {useSemanticColor: this.props.useSemanticColor}
- })
+ const LayerClass = customXvizLayerMatch.layerClass || parentLayerHandler?.layerClass;
+ return new LayerClass(
+ forwardProps,
+ layerProps,
+ this.getSubLayerProps({
+ id: customXvizLayerMatch.id,
+ data,
+ ...primitiveLayerProps,
+ ...customXvizLayerMatch.getSubProps({
+ xvizLayerProps: this.props,
+ primitiveLayerProps,
+ state: this.state
})
- );
+ })
+ );
+ }
+ if (!LAYER_HANDLERS[type]) {
+ return null;
+ }
- case 'text':
- return new TextLayer(
- forwardProps,
+ const {layerClass: LayerClass, getLayerTypeProps} = LAYER_HANDLERS[type];
+ return new LayerClass(
+ forwardProps,
+ layerProps,
+ this.getSubLayerProps({
+ id: type,
+ data,
+ ...getLayerTypeProps({
+ xvizLayerProps: this.props,
layerProps,
- this.getSubLayerProps({
- id: 'text',
- data,
- getText: f => f.text,
- updateTriggers: deepExtend(updateTriggers, {
- getColor: {useSemanticColor: this.props.useSemanticColor}
- })
- })
- );
-
- default:
- return null;
- }
+ state: this.state
+ })
+ })
+ );
}
}