Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapbox Custom Layers + Example w. deck/mapbox layer interleaving #2264

Merged
merged 2 commits into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions aliases.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,28 @@ function getSubmodules() {
}

function getAliases(mode = 'src') {
const aliases = {};
const aliases = {
// Important - these must be defined before the alias of `deck.gl`
// to be resolved correctly
'deck.gl/test': resolve(__dirname, './test')
};

const submodules = getSubmodules();

for (const moduleName in submodules) {
const subPath = mode === 'src' ? 'src' : submodules[moduleName].main.replace('/index.js', '');
aliases[moduleName] = resolve(__dirname, 'node_modules', moduleName, subPath);
if (mode === 'src') {
let name = moduleName.split('/').length > 1 ? moduleName.split('/')[1] : moduleName;
if (name === 'deck.gl') {
name = 'main';
}
aliases[moduleName] = resolve(__dirname, 'modules', name, 'src');
} else {
const subPath = submodules[moduleName].main.replace('/index.js', '');
aliases[moduleName] = resolve(__dirname, 'node_modules', moduleName, subPath);
}
}

return Object.assign({
// Important - these must be defined before the alias of `deck.gl`
// to be resolved correctly
'deck.gl/test': resolve(__dirname, './test')
}, aliases);
return aliases;
}

module.exports = getAliases;
Expand Down
8 changes: 6 additions & 2 deletions modules/core/src/lib/deck.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,9 @@ export default class Deck {
}

_updateCursor() {
this.canvas.style.cursor = this.props.getCursor(this.interactiveState);
if (this.canvas) {
this.canvas.style.cursor = this.props.getCursor(this.interactiveState);
}
}

// Updates animation props on the layer context
Expand All @@ -439,6 +441,7 @@ export default class Deck {

// if external context...
if (this.props._customRender) {
this.canvas = gl.canvas;
trackContextState(gl, {enable: true, copyState: true});
}

Expand Down Expand Up @@ -524,7 +527,8 @@ export default class Deck {
viewports: this.viewManager.getViewports(),
views: this.viewManager.getViews(),
redrawReason,
drawPickingColors: this.props.drawPickingColors // Debug picking, helps in framebuffered layers
drawPickingColors: this.props.drawPickingColors, // Debug picking, helps in framebuffered layers
customRender: this.props._customRender
});

this.props.onAfterRender({gl});
Expand Down
7 changes: 5 additions & 2 deletions modules/core/src/lib/draw-layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,13 @@ export function drawLayers(
layerFilter = null,
pass = 'draw',
redrawReason = '',
stats
stats,
customRender
}
) {
clearCanvas(gl, {useDevicePixels});
if (!customRender) {
clearCanvas(gl, {useDevicePixels});
}

// effectManager.preDraw();

Expand Down
11 changes: 9 additions & 2 deletions modules/core/src/lib/layer-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,13 @@ export default class LayerManager {
//

// Draw all layers in all views
drawLayers({pass = 'render to screen', viewports, views, redrawReason = 'unknown reason'}) {
drawLayers({
pass = 'render to screen',
viewports,
views,
redrawReason = 'unknown reason',
customRender = false
}) {
const {drawPickingColors} = this;
const {gl, useDevicePixels} = this.context;

Expand All @@ -251,7 +257,8 @@ export default class LayerManager {
drawPickingColors,
pass,
layerFilter: this.layerFilter,
redrawReason
redrawReason,
customRender
});
}

Expand Down
57 changes: 57 additions & 0 deletions modules/mapbox-layers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# @deck.gl/mapbox-layers

Enables the use deck.gl layers as custom mapbox layers, enabling seamless interleaving of mapbox and deck.gl layers.

See [deck.gl](http://deck.gl) for documentation.


## DeckLayer

The `DeckLayer` is a custom mapbox layer class that renders a list of deck.gl layers inside the mapbox canvas / WebGL context. This is in contrast to the typical deck.gl/mapbox integration where the deck.gl layers are rendered separately


## Advantages and Limitations

Advantages:

* mapbox and deck.gl layers can be freely "interleaved", enabling a number of important uses cases as described below.
* mapbox and deck.gl will share a single canvas and WebGL context, saving system resources.

Disadvantages:

* deck.gl's multi view system, including controllers and viewport transitions cannot be used
* WebGL2 based deck.gl features, such as attribute transitions and GPU accelerated aggregation layers cannot be used.
* At the moment, 3D layer integration is not yet complete, meaning that using 3D layers from both mapbox and deck.gl typically will not work.



## Mixing deck and mapbox layers

There is a range of use cases for mixing layers, with increasing complexity.


### Adding deck layers to the top of the mapbox layer stack

In simple cases, the application just wants a mapbox basemap, combined with the ability to interleave useful visualization layers from both the deck.gl and mapbox layer catalogs. In this case, the mapbox [`map.addLayer(layer)`](https://www.mapbox.com/mapbox-gl-js/api/#map#addlayer) API method can be used to add a mix of deck.gl and mapbox layers to the top of the layer stack from the currently loaded mapbox style.


### Injecting deck layers into an existing mapbox layer stack

A bit more control is provided by the optional `before` parameter of the mapbox [`map.addLayer(layer, before?)`](https://www.mapbox.com/mapbox-gl-js/api/#map#addlayer) API. Using this parameter, it is possible to inject a `DeckLayers` instance just before any existing mapbox layer in the layer stack of the currently loaded style.

That sounds good, but which mapbox layer should the application pick as its "injection point", and how does the application get a reference to it?

One major use case for mixing deck.gl and mapbox layers is that some important information in the mapbox map is hidden by a deck.gl visualization layer, and controlling opacity is not enough. A typical example of this is labels and roads, where it is desirable to have a deck.gl visualization layer render on top of the mapbox geography, but where one might still want to see e.g. labels and/or roads. Alternatively, the deck.gl visualization should cover the ground, but not the roads and labels.

Mapbox provides an example of [finding the first label layer](https://www.mapbox.com/mapbox-gl-js/example/geojson-layer-in-stack/). For more sophisticated injection point lookups, refer to Mapbox' documentation on the format of mapbox style layers, see [Mapbox Style Spec](https://www.mapbox.com/mapbox-gl-js/style-spec/#layers).


### Building a mixed mapbox and deck layer stack from scratch

mapbox allows for complete control of the stack of layers, see e.g. [Mapbox GL JS labels on top of radar raster](https://bl.ocks.org/danswick/c19fec2e92e00967458d). In such scenario it is of course easy to control where any `DeckLayer` instances should be added. However, "hand coding" a complete layer stack can require a lot of work and can result in reduced flexibility as it doesn't let the application take advantage of predefined styles.


### 3D Layer / Depth Buffer Integration

> 3D (i.e. depth buffer) synchronization between Mapbox and deck.gl is still under development. The current "deep" layer integration between deck.gl and mapbox-gl is focused on 2D layers, as described above.

38 changes: 38 additions & 0 deletions modules/mapbox-layers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@deck.gl/mapbox-layers",
"description": "Use deck.gl layers as custom mapbox-gl-js layers",
"license": "MIT",
"version": "6.1.0-alpha.2",
"publishConfig": {
"access": "public"
},
"keywords": [
"webgl",
"visualization",
"overlay",
"layer"
],
"repository": {
"type": "git",
"url": "https://github.com/uber/deck.gl.git"
},
"main": "dist/index.js",
"module": "dist-es6/index.js",
"files": [
"dist",
"dist-es6",
"src"
],
"sideEffects": false,
"scripts": {
"build-clean": "rm -fr dist dist-es6 && mkdir -p dist dist-es6",
"build-es6": "rm -fr dist-es6 && BABEL_ENV=es6 babel src --out-dir dist-es6 --source-maps inline",
"build-es5": "rm -fr dist && BABEL_ENV=es5 babel src --out-dir dist --source-maps inline",
"build": "npm run build-clean && npm run build-es6 && npm run build-es5",
"test": "npm run lint && npm run build && npm run test-node",
"test-node": "node test/node.js"
},
"dependencies": {
"@deck.gl/core": "^6.1.0-rc.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ export default class DeckLayer {
constructor({id = 'deck-layer', layers}) {
this.id = id;
this.type = 'custom';

this.renderingMode = '3d';
this.deck = null;

this.layers = layers;
}

Expand Down Expand Up @@ -39,9 +38,10 @@ export default class DeckLayer {
this.deck.setProps({layers: this.layers});
}

render3D(gl, matrix) {
render(gl, matrix) {
const viewState = this._getViewState();
// console.log('render3D', viewState, matrix);
// gl.depthRange(0.9999, 1.0);

this.deck.setProps({viewState});
this.deck._drawLayers();
Expand Down
2 changes: 2 additions & 0 deletions modules/mapbox-layers/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {default} from './deck-layer';
export {default as DeckLayer} from './deck-layer';
59 changes: 59 additions & 0 deletions test/apps/mapbox-layers/app-2d.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import mapboxgl from './mapbox-gl-dev';
import {GeoJsonLayer} from '@deck.gl/layers';

import DeckLayer from '@deck.gl/mapbox-layers';

// Outlines of US States. Source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz
const US_MAP_GEOJSON =
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_1_states_provinces_shp.geojson'; //eslint-disable-line

const INITIAL_VIEW_STATE = {
latitude: 40.70708981756565,
longitude: -74.01194070150844,
zoom: 5.2,
bearing: 20,
pitch: 60
};

// Set your mapbox token here
mapboxgl.accessToken = process.env.MapboxAccessToken; // eslint-disable-line

const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
center: [INITIAL_VIEW_STATE.longitude, INITIAL_VIEW_STATE.latitude],
zoom: INITIAL_VIEW_STATE.zoom,
bearing: INITIAL_VIEW_STATE.bearing,
pitch: INITIAL_VIEW_STATE.pitch
});

map.on('load', () => {
const deckLayer = new DeckLayer({
layers: [
new GeoJsonLayer({
data: US_MAP_GEOJSON,
stroked: true,
filled: true,
lineWidthMinPixels: 2,
opacity: 1,
getLineColor: () => [255, 0, 0],
getFillColor: () => [200, 200, 0, 200]
})
]
});

map.addLayer(deckLayer, getFirstTextLayerId(map.getStyle()));
});

function getFirstTextLayerId(style) {
const layers = style.layers;
// Find the index of the first symbol (i.e. label) layer in the map style
let firstSymbolId;
for (let i = 0; i < layers.length; i++) {
if (layers[i].type === 'symbol') {
firstSymbolId = layers[i].id;
break;
}
}
return firstSymbolId;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import mapboxgl from './mapbox-gl-dev';
import DeckLayer from './deck-layer';
import {GeoJsonLayer} from '@deck.gl/layers';

import DeckLayer from '@deck.gl/mapbox-layers';

// Outlines of US States. Source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz
const US_MAP_GEOJSON =
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_1_states_provinces_shp.geojson'; //eslint-disable-line
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const CONFIG = {
mode: 'development',

entry: {
app: resolve('./app.js')
app: resolve('./app-2d.js')
},

resolve: {
Expand Down