Skip to content

Commit

Permalink
Viewport doc overhaul (#927)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Sep 15, 2017
1 parent ff8adc5 commit 387301e
Show file tree
Hide file tree
Showing 36 changed files with 1,457 additions and 982 deletions.
26 changes: 22 additions & 4 deletions dev-docs/RFCs/vNext/projection-mode-improvements-rfc.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,44 @@ Notes:
Cartographic Projections are a core functionality of deck.gl.


## Use Cases

* Performance
* Support non-Web-Mercator-Projections

## Proposal: Support for 64 bit position attributes in 32 bit mode

Without using full 64 bit shader processing. 64 bits could be used only for an initial center subtraction, the remaining processing could be done in 32 bits.


## Proposal: Automatic Offset Mode

Big precision advantages comes when using offset mode. Could we allow the app to specify a center point and auto calculate offsets. Especially effective combined with previous proposal.


## Proposal: Support Preprojected Web Mercator Coordinates (Tile 0)

Add a `COORDINATE_SYSTEM.TILE_ZERO` mode. It would allow the app to preproject lng/lats in JavaScript to numbers between 0-512.

* The shader already knows the scale so it could apply it without the app having to modify distance scales.
* Implementing this mode is easy. I mainly want to make sure there is a use case for these modes before we add more complexity to the framework.

The main advantage I see would be somewhat faster rendering (no need for vertex shader to reproject lng/lats every frame).
The main advantages:
* Somewhat better precision in 32-bit mode as the projections (trigonometry etc) are done in JavaScript 64 bits. Results are reported to be "between 32 and 64 bit".
* Somewhat faster rendering (no need for vertex shader to reproject lng/lats every frame). The improvement may be limited in fp32 mode as rendering is typically fragment bound, although it may have bigger impact in 64-bit mode.
* A bit more flexibility for the application when converting coordinates from other systems to web mercator

But note that the precision advantages only comes when we use offsets instead of absolute coordinates, so this mode would need to support fp64.
Note that the full "precision" advantages only come when we use offsets instead of absolute coordinates, so this mode would ideally need to support `fp64`.

Maybe we would also add a `COORDINATE_SYSTEM.TILE_ZERO_OFFSETS` mode? But that makes things ever more complex to describe...
Questions:
* Maybe we could also add a `COORDINATE_SYSTEM.TILE_ZERO_OFFSETS` mode? But that makes the setup ever more complex... And what would the reference point be? lngLat or tile 0?


## Proposal: Prop to supply JavaScript Project Function

What I have been thinking is to offer the user to provide a simple JS function that maps any position (from any other coordinates) to one of our supported coordinate systems. This function would be called during position attribute generation. I.e we'd still show a mercator projected world but be able to correctly position coordinates specified in other projections. If the project function projected to TILE_ZERO it would have perf advantages during render too.



## Proposal: Replaceable Project Shader Module for Custom Projections

The shadertools module system was designed with a focus on interfaces, with an intention of allowing modules to be replaced with similar modules implementing the same interface. It would take a little more work on shadertools, but it is almost there. This was mostly intended for replacing e.g. lighting but would most likely work for projections as well.
Expand Down
14 changes: 11 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
<p align="right">
<p align="center">
These docs are for
<a href="https://github.com/uber/deck.gl/blob/4.2-release/docs/README.md">
<img src="https://img.shields.io/badge/deck.gl-v4.2-brightgreen.svg?style=flat-square" />
</a>
Looking for an old version?
<a href="https://github.com/uber/deck.gl/blob/4.1-release/docs/README.md">
<img src="https://img.shields.io/badge/current-v4.1-brightgreen.svg?style=flat-square" />
<img src="https://img.shields.io/badge/deck.gl-v4.1-green.svg?style=flat-square" />
</a>
<a href="https://github.com/uber/deck.gl/blob/4.0-release/docs/README.md">
<img src="https://img.shields.io/badge/deck.gl-v4.0-green.svg?style=flat-square" />
</a>
<a href="https://github.com/uber/deck.gl/tree/3.0-release/docs">
<img src="https://img.shields.io/badge/legacy-v3-green.svg?style=flat-square" />
<img src="https://img.shields.io/badge/deck.gl-v3.0-green.svg?style=flat-square" />
</a>
</p>

Expand Down
24 changes: 24 additions & 0 deletions docs/advanced/controllers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Controllers

deck.gl supports several models of event handling and viewport controls


## Viewport Controls


## React Integration

Use the [`ViewportController`](docs/api-reference/react/viewport-controller.md) component.


## States

...


## Customizing Controls



## About Event Handling

18 changes: 9 additions & 9 deletions docs/advanced/coordinate-systems.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Coordinate Systems

By default deck.gl layers interprets positions in the [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator coordinate system, so when working with geospatial data (i.e your data has longitude and latitude encoded positions) deck.gl will automatically interpret them correctly.
By default deck.gl layers interprets positions in the [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator) coordinate system, so when working with geospatial data (i.e with longitude and latitude encoded positions) deck.gl will automatically interpret it correctly.

deck.gl also supports a meter offset based coordinate system, which can be very convenient when modelling geographical data on small (city/city block) scales.
In addition, deck.gl supports "meter offset" based local coordinate systems, which can be extremely convenient when modelling geographical data on small scales (e.g. city block level).

Naturally, positions specified in non-geospatial coordinates can also be used when working with non-geospatial data sets.
Naturally, non-geospatial coordinates can also be used when working with non-geospatial data sets

Supported Coordinate systems are:
## Supported Coordinate Systems

| Coordinate System Mode | Coordinates | Description |
| --- | ---
| `COORDINATE_SYSTEM.LNGLAT` (default) | [longitude, latitude, altitude] | Longitude and latitude are specified as **Web Mercator coordinates** in degrees from Greenwich meridian / equator respectively, and altitude is specified in meters above sea level. |
| `COORDINATE_SYSTEM.METER_OFFSETS` | [Δx, Δy, Δz] | Positions are given in meter offsets from a reference point that is specified separately (the `coordinateOrigin` prop) |
| `COORDINATE_SYSTEM.IDENTITY` | [x, y, z] | A linear system with no interpretation for pure info-vis layers. Non-geospatial viewports should be used. |
| `COORDINATE_SYSTEM.IDENTITY` | [x, y, z] | A linear system with no interpretation for pure info-vis layers. Viewports can be used without supplying geospatial reference points. |


## Choosing the Right Coordinate System

The choice of coordinate system is often dictated by your data. If your data is specified in `lng`/`lat`s or meter offsets the natural thing is to just use the corresponding coordinate system mode in deck.gl.

It is however important to be aware that the different coordinate systems come with different trade-offs. Specifying mercator coordinates (lng/lats) will cause every coordinate to be individually projected on the GPU and will yield the most correct results when visualizing data spread out over large distances (e.g. several degrees of longitude or latitude, i.e. 100s of kilometers).
It is however important to be aware that the different coordinate systems come with different trade-offs. Specifying mercator coordinates (lng/lats) will cause every coordinate to be individually projected on the GPU and will yield the most correct results when visualizing data spread out over large distances (e.g. several degrees of longitude or latitude, or hundreds of kilometers/miles).

However, longitude and latitude coordinates tend to run into precision issues at high zoom levels on a map, (around 1 million times, or about the city block level), which can lead to some "jitter" or "wobble". This can be mitigated by activating 64-bit computation, but this in turn can have an impact on rendering performance (for very large data sets). Many visualization apps focus on countries and counties, and at those scale there is no issue, but for other visualizations high-precision operation at city-block level is critical.

Expand All @@ -28,11 +28,11 @@ The meter offset system on the other hand is very performant, but uses a lineari

## Combining Different Coordinate Systems

The choice of coordinate system can be specified per layer, meaning that different layers can have data with positions specified in "different" coordinate systems. However, if some care is taken, they can all be rendered and drawn at the same time, and correctly overlaid.
The choice of coordinate system can be specified per layer, meaning that different layers can have data with positions specified in "different" coordinate systems. If some care is taken, they can all be rendered and drawn at the same time, and correctly overlaid.

An example of a common technique is to:
An example of a use case where different coordinate systems are combined:
* Render a layer showing 3D buildings could have vertices specified in longitudes and latitudes (simply because available building data sources tend to be encoded this way)
* Render layer showing cars or pedestrians moving between the buildings with all positions specified using meter offsets from an anchor point somewhere in the city), because meter offsets make more sense..
* Render layer showing cars or pedestrians moving between the buildings with all positions specified using meter offsets from an anchor point somewhere in the city), because meter offsets are more natural encoding for this data.


### About Geospatial Positions
Expand Down
37 changes: 10 additions & 27 deletions docs/advanced/custom-layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,14 @@

## Preparations

Before creating a new layer, it is recommended that you verify that you
can not achive the desired effect either through layer subclassing or
through using composite layers.

There are a couple of ways to build a layer in deck.gl, and it is helpful
to consider what approach will serve you best before starting:

* **[Create a composite layer](/docs/advanced/composite-layers.md)** -
Composite layer is a special kind of layers that creates
other layers. This allows you to build e.g. a "semantic layer" - a layer that
presents a different interface (set of props) than an existing layer, transforms
those props into a format that fits and existing layer, etc.
* **[Subclass a layer](/docs/advanced/subclassed-layers.md)** -
Subclassed layer is a new layer created by subclassing
another layers. This allows the developer to reuse all of the interfaces and implementations
of an existing layer unless they are explicitly overriden.
* **[Implement a layer from scratch](/docs/advanced/primitive-layers.md)** -
If you want to draw something completely different
and you are comfortable around WebGL, this option gives you the most flexibility. You
have full control of the layer lifecycle, manage your own model(s) an directly
manipulate the WebGL context.

> There is no strict division between layers that draw and composite
layers, a layer could do both. That said, it often makes sense to keep your
layers simple and focused on doing one thing well.
Before creating a new layer, it is recommended that you verify that you can not achive the desired effect either through layer subclassing or through using composite layers.

There are a couple of ways to build a layer in deck.gl, and it is helpful to consider what approach will serve you best before starting:

* **[Create a composite layer](/docs/advanced/composite-layers.md)** - A composite layer is a special kind of layer that creates other layers. This allows you to build e.g. a "semantic layer" - a layer that presents a different interface (set of props) than an existing layer, transforms those props into a format that fits and existing layer, etc.
* **[Subclass a layer](/docs/advanced/subclassed-layers.md)** - Subclassed layer is a new layer created by subclassing another layers. This allows the developer to reuse all of the interfaces and implementations of an existing layer unless they are explicitly overriden.
* **[Implement a layer from scratch](/docs/advanced/primitive-layers.md)** - If you want to draw something completely different and you are comfortable with WebGL and shader programming, this option gives you the most flexibility. You have full control of the layer lifecycle, you can manage your own model(s) and directly manipulate the WebGL context.


## Creating The Layer class

Expand All @@ -38,7 +21,7 @@ class AwesomeLayer extends Layer {...}
```
It can be a direct subclass of `Layer`, or extend another layer.

### Naming your Layer
### Naming Your Layer

Store the layer name in the `layerName` static property on your `Layer` subclass:
```js
Expand All @@ -49,7 +32,7 @@ The layer name will be used as the default id of layer instances and also during
debugging.


### Defining layer properties
### Defining Layer Properties

The list of properties is the main API your new layer will provide to
applications. So it makes sense to carefully consider what properties
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/picking.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Picking

Make sure you have read [Interactivity](/docs/get-started/interactivity.md) before reading this section.
> Make sure you have read [Interactivity](/docs/get-started/interactivity.md) before reading this section.
## How It Works

Expand Down
22 changes: 15 additions & 7 deletions docs/advanced/updates.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Updates

The key is getting good performance and desired behavior from deck.gl is to understand how and when deck.gl updates data.
One of the keys to getting good performance and desired behavior from deck.gl is to understand how and when deck.gl updates data.


## The Reactive Programming Paradigm

Before jumping into the details, it might be helpful review the reactive programming paradigm that the deck.gl is architecture is based on:

- In a reactive application, the entire UI is "re-rendered" every time something in the application state changes.
- There is no application logic that checks what part of the state changed to check what UI updates are required.
- Instead, the UI framework makes the choices about what to update, by comparing (or "diffing") the newly rendered UI a against the last rendered UI.
- The framework (deck.gl) then the makes minimal changes to the DOM or to WebGL state to account for the differences, and redraws.
- In a reactive application, a complete UI description is "re-rendered" every time something in the application state changes (in the case of a deck.gl application, a new list of layers is created whenever something changes).
- The UI framework (in this case, deck.gl) makes the choices about what to update, by comparing (or "diffing") the newly rendered UI description with the last rendered UI description.
- The framework then the makes minimal necessary changes to account for the differences, and then redraws.
- The required changes are made to "WebGL state" in case of deck.gl, and to the Browser's DOM (HTML element tree) in case of React.


## Creating new layers on every render?
## Creating New Layers on Every Render?

The deck.gl model means that applications are expected to create a new set of on layers every time application state changes, which can seem surprisingly inefficient to someone who hasn't done reactive programming before. The trick is that internally, the new layers are efficiently matched against existing layers so that no updates are performed unless actually needed.
The deck.gl model means that applications are expected to create a new set of on layers every time application state changes, which can seem surprisingly inefficient to someone who hasn't done reactive programming before. The trick is that layers are just descriptor objects that are very cheap to instantiate, and internally, the new layers are efficiently matched against existing layers so that no updates are performed unless actually needed.

So, even though the application creates new "layers", those layers are only "descriptors" containing props that specify what needs to be rendered and how. All calculated state (WebGL "programs", "vertex attributes" etc) are stored in a state object and this state object is moved forward to the newly matched layer on every render cycle. The new layer ends up with the state of the old layer (and the props of the new layer), while the old layer is simply discarded for garbage collecion.

Expand Down Expand Up @@ -87,6 +87,14 @@ In the above code, deck.gl compares the value of the `getColor` update trigger w
While the built-in attribute generation functionality is a major part of a `Layer`s functionality, it is possible for applications to bypass it, and supply the layer with precalculated attributes.


### shouldUpdateState

When rendering with many viewports there is a concern that `updateState` gets called many times per frame (potentially recalculating other things that have nothing to do with viewport updates, in less strictly coded layers). Because of this, since most layers do not need to update state when viewport changes, the `updateState` function is not automatically called on viewport change. To make sure it is called, the layer needs to override `shouldUpdateState`.

So layers that want `updateState` to be called when viewports change (like `ScreenGridLayer`) need to redefine `shouldUpdateState`. This will mean that even though all layer’s will have `shouldUpdateState` called every viewport every frame, only a few will typically get calls to `updateState`.



## Future Possibilities

The following optimizations have not yet been implemented.
Expand Down
26 changes: 7 additions & 19 deletions docs/advanced/using-standalone.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
# Using deck.gl Standalone

The deck.gl core library and layers have no dependencies on React or
Mapbox GL and can be used by any JavaScript application.
The deck.gl core library and layers have no dependencies on React or Mapbox GL and can be used by any JavaScript application.

Note: This is a brief introduction to how an application might
do a standalone integration with deck.gl. Using deck.gl this way will
likely involve extra effort and is not recommended for casual
applications.
Note: This is a brief introduction to how an application might do a standalone integration with deck.gl. Using deck.gl this way will likely involve extra effort and is not recommended for casual applications.

## Using deck.gl without react-map-gl

It is possible to use deck.gl without react-map-gl. In this case
the application will have to implement its own event handling
(to zoom and pan the viewport, and forward hover and click events to deck.gl.
Note that all deck.gl examples currently rely on react-map-gl's event
handling.
It is possible to use deck.gl without react-map-gl. In this case the application will have to implement its own event handling (to zoom and pan the viewport, and forward hover and click events to deck.gl. Note that all deck.gl examples currently rely on react-map-gl's event handling.

## Using deck.gl without React

The deck.gl [LayerManager](/docs/api-reference/layer-manager.md) class handles updates, drawing and picking for a set of layers. To use deck.gl without React, you may create
your own instance of the `LayerManager` and implement the animation cycles:
The deck.gl [LayerManager](/docs/api-reference/layer-manager.md) class handles updates, drawing and picking for a set of layers. To use deck.gl without React, you may create your own instance of the `LayerManager` and implement the animation cycles:

* Use the `setViewport` method to update viewport.
* Use the `updateLayers` method to update the list of layers with a
freshly rendered list.
* You can use the `drawLayers` method to draw the layers - it will only
draw if some layer (some prop in some layer) has actually changed.
* Call the `pickLayers` method on mouse and touch events to implement
picking.
* Use the `updateLayers` method to update the list of layers with a freshly rendered list.
* You can use the `drawLayers` method to draw the layers - it will only draw if some layer (some prop in some layer) has actually changed.
* Call the `pickLayers` method on mouse and touch events to implement picking.

0 comments on commit 387301e

Please sign in to comment.