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

Add Brushing extension #3309

Merged
merged 4 commits into from
Jul 3, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
102 changes: 102 additions & 0 deletions docs/extensions/brushing-extension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

# BrushingExtension (experimental)

The `BrushingExtension` adds GPU-based data brushing functionalities to layers. It allows the layer to show/hide objects based on the current pointer position.

```js
import {ScatterplotLayer} from '@deck.gl/layers';
import {BrushingExtension} from '@deck.gl/extensions';

const layer = new ScatterplotLayer({
id: 'points',
data: POINTS,

// props from ScatterplotLayer
getPosition: d => d.position,
getRadius: d => d.radius,

// props added by BrushingExtension
brushingEnabled: true,
brushingRadius: 100000,

// Define extensions
extensions: [new BrushingExtension()]
});
```

## Installation

To install the dependencies from NPM:

```bash
npm install deck.gl
# or
npm install @deck.gl/core @deck.gl/layers @deck.gl/extensions
```

```js
import {BrushingExtension} from '@deck.gl/extensions';
new BrushingExtension();
```

To use pre-bundled scripts:

```html
<script src="https://unpkg.com/deck.gl@~7.0.0/dist.min.js"></script>
<!-- or -->
<script src="https://unpkg.com/@deck.gl/core@~7.0.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/layers@~7.0.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/extensions@~7.0.0/dist.min.js"></script>
```

```js
new deck.BrushingExtension();
```

## Constructor

```js
new BrushingExtension();
```


## Layer Properties

When added to a layer via the `extensions` prop, the `BrushingExtension` adds the following properties to the layer:


##### `brushingRadius` (Number)

The brushing radius centered at the pointer, in meters. If a data object is within this circle, it is rendered; otherwise it is hidden.


##### `brushingEnabled` (Boolean, optional)

* Default: `true`

Enable/disable brushing. If brushing is disabled, all objects are rendered.

Brushing is always disabled when the pointer leaves the current viewport.


##### `brushingTarget` (Enum, optional)

* Default: `source`

The position used to filter each object by. One of the following:

- `'source'`: Use the primary position for each object. This can mean different things depending on the layer. It usually refers to the coordinates returned by `getPosition` or `getSourcePosition` accessors.
- `'target'`: Use the secondary position for each object. This may not be available in some layers. It usually refers to the coordinates returned by `getTargetPosition` accessors.
- `'custom'`: Some layers may not describe their data objects with one or two coordinates, for example `PathLayer` and `PolygonLayer`. Use this option with the `getBrushingTarget` prop to provide a custom position that each object should be filtered by.


##### `getBrushingTarget` ([Function](/docs/developer-guide/using-layers.md#accessors), optional)

* Default: `null`

Called to retrieve an arbitrary position for each object that it will be filtered by. Returns an array `[x, y]`. Only effective if `brushingTarget` is set to `custom`.


## Source

[modules/extensions/src/brushing](https://github.com/uber/deck.gl/tree/master/modules/extensions/src/brushing)
99 changes: 41 additions & 58 deletions examples/website/brushing/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import React, {Component} from 'react';
import {render} from 'react-dom';
import {StaticMap} from 'react-map-gl';
import DeckGL from 'deck.gl';
import ArcBrushingLayer from './brushing-layers/arc-brushing-layer';
import ScatterplotBrushingLayer from './brushing-layers/scatterplot-brushing-layer';
import DeckGL from '@deck.gl/react';
import {ScatterplotLayer, ArcLayer} from '@deck.gl/layers';
import {BrushingExtension} from '@deck.gl/extensions';
import {scaleLinear} from 'd3-scale';

// Set your mapbox token here
Expand Down Expand Up @@ -42,6 +42,8 @@ const INITIAL_VIEW_STATE = {
bearing: 0
};

const brushingExtension = new BrushingExtension();

/* eslint-disable react/no-deprecated */
export class App extends Component {
constructor(props) {
Expand All @@ -50,11 +52,8 @@ export class App extends Component {
arcs: [],
targets: [],
sources: [],
mousePosition: null,
...this._getLayerData(props)
};
this._onMouseMove = this._onMouseMove.bind(this);
this._onMouseLeave = this._onMouseLeave.bind(this);
this._onHover = this._onHover.bind(this);
}

Expand All @@ -66,16 +65,6 @@ export class App extends Component {
}
}

_onMouseMove(evt) {
if (evt.nativeEvent) {
this.setState({mousePosition: [evt.nativeEvent.offsetX, evt.nativeEvent.offsetY]});
}
}

_onMouseLeave() {
this.setState({mousePosition: null});
}

_onHover({x, y, object}) {
this.setState({x, y, hoveredObject: object});
}
Expand Down Expand Up @@ -172,68 +161,63 @@ export class App extends Component {
opacity = 0.7
} = this.props;

const {arcs, targets, sources, mousePosition} = this.state;

const isMouseover = mousePosition !== null;
const startBrushing = Boolean(isMouseover && enableBrushing);
const {arcs, targets, sources} = this.state;

if (!arcs || !targets) {
return null;
}

return [
new ScatterplotBrushingLayer({
new ScatterplotLayer({
id: 'sources',
data: sources,
brushRadius,
brushTarget: true,
mousePosition,
brushingRadius: brushRadius,
opacity: 1,
enableBrushing: startBrushing,
brushingEnabled: enableBrushing,
pickable: false,
// only show source points when brushing
radiusScale: startBrushing ? 3000 : 0,
radiusScale: enableBrushing ? 3000 : 0,
getFillColor: d => (d.gain > 0 ? TARGET_COLOR : SOURCE_COLOR),
getTargetPosition: d => [d.position[0], d.position[1], 0]
extensions: [brushingExtension]
}),
new ScatterplotBrushingLayer({
new ScatterplotLayer({
id: 'targets-ring',
data: targets,
brushRadius,
mousePosition,
brushingRadius: brushRadius,
lineWidthMinPixels: 2,
stroked: true,
filled: false,
opacity: 1,
enableBrushing: startBrushing,
brushingEnabled: enableBrushing,
// only show rings when brushing
radiusScale: startBrushing ? 4000 : 0,
getLineColor: d => (d.net > 0 ? TARGET_COLOR : SOURCE_COLOR)
radiusScale: enableBrushing ? 4000 : 0,
getLineColor: d => (d.net > 0 ? TARGET_COLOR : SOURCE_COLOR),
extensions: [brushingExtension]
}),
new ScatterplotBrushingLayer({
new ScatterplotLayer({
id: 'targets',
data: targets,
brushRadius,
mousePosition,
brushingRadius: brushRadius,
opacity: 1,
enableBrushing: startBrushing,
brushingEnabled: enableBrushing,
pickable: true,
radiusScale: 3000,
onHover: this._onHover,
getFillColor: d => (d.net > 0 ? TARGET_COLOR : SOURCE_COLOR)
getFillColor: d => (d.net > 0 ? TARGET_COLOR : SOURCE_COLOR),
extensions: [brushingExtension]
}),
new ArcBrushingLayer({
new ArcLayer({
id: 'arc',
data: arcs,
getWidth: strokeWidth,
opacity,
brushRadius,
enableBrushing: startBrushing,
mousePosition,
brushingRadius: brushRadius,
brushingEnabled: enableBrushing,
getSourcePosition: d => d.source,
getTargetPosition: d => d.target,
getSourceColor: SOURCE_COLOR,
getTargetColor: TARGET_COLOR
getTargetColor: TARGET_COLOR,
extensions: [brushingExtension]
})
];
}
Expand All @@ -242,22 +226,21 @@ export class App extends Component {
const {mapStyle = 'mapbox://styles/mapbox/light-v9'} = this.props;

return (
<div onMouseMove={this._onMouseMove} onMouseLeave={this._onMouseLeave}>
{this._renderTooltip()}
<DeckGL
ref={this._deckRef}
layers={this._renderLayers()}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
>
<StaticMap
reuseMaps
mapStyle={mapStyle}
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>

<DeckGL
layers={this._renderLayers()}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
>
<StaticMap
reuseMaps
mapStyle={mapStyle}
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
</DeckGL>
</div>
{this._renderTooltip()}
</DeckGL>
);
}
}
Expand Down
72 changes: 0 additions & 72 deletions examples/website/brushing/brushing-layers/arc-brushing-layer.js

This file was deleted.

Loading