Skip to content

Commit

Permalink
Fix controller event propagation (#3345)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress authored Jul 12, 2019
1 parent 4de8312 commit f1585f7
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 133 deletions.
4 changes: 3 additions & 1 deletion docs/api-reference/controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ Utility used by the event handlers, returns pointer position `[x, y]` from any e

Utility used by the event handlers, returns `true` if ctrl/alt/meta key is pressed during any event.

##### `isPointInBounds(pos)`
##### `isPointInBounds(pos, [event])`

Utility used by the event handlers, returns `true` if a pointer position `[x, y]` is inside the current view.

If `event` is provided, returns `false` if the event is already handled, and mark the event as handled if the point is in bounds. This can be used to make sure that certain events are only handled by one controller, when there are overlapping viewports.

##### `isDragging()`

Returns `true` if the user is dragging the view.
Expand Down
19 changes: 13 additions & 6 deletions modules/core/src/controllers/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,17 @@ export default class Controller {
return [offsetCenter.x - x, offsetCenter.y - y];
}

isPointInBounds(pos) {
isPointInBounds(pos, event) {
const {width, height} = this.controllerStateProps;
if (event && event.handled) {
return false;
}

return pos[0] >= 0 && pos[0] <= width && pos[1] >= 0 && pos[1] <= height;
const inside = pos[0] >= 0 && pos[0] <= width && pos[1] >= 0 && pos[1] <= height;
if (inside && event) {
event.stopPropagation();
}
return inside;
}

isFunctionKeyPressed(event) {
Expand Down Expand Up @@ -235,7 +242,7 @@ export default class Controller {
// Default handler for the `panstart` event.
_onPanStart(event) {
const pos = this.getCenter(event);
if (!this.isPointInBounds(pos)) {
if (!this.isPointInBounds(pos, event)) {
return false;
}
const newControllerState = this.controllerState.panStart({pos}).rotateStart({pos});
Expand Down Expand Up @@ -308,7 +315,7 @@ export default class Controller {
event.preventDefault();

const pos = this.getCenter(event);
if (!this.isPointInBounds(pos)) {
if (!this.isPointInBounds(pos, event)) {
return false;
}

Expand All @@ -331,7 +338,7 @@ export default class Controller {
// Default handler for the `pinchstart` event.
_onPinchStart(event) {
const pos = this.getCenter(event);
if (!this.isPointInBounds(pos)) {
if (!this.isPointInBounds(pos, event)) {
return false;
}

Expand Down Expand Up @@ -393,7 +400,7 @@ export default class Controller {
return false;
}
const pos = this.getCenter(event);
if (!this.isPointInBounds(pos)) {
if (!this.isPointInBounds(pos, event)) {
return false;
}

Expand Down
9 changes: 6 additions & 3 deletions modules/core/src/lib/view-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,12 @@ export default class ViewManager {
const {width, height, views} = this;

const oldControllers = this.controllers;
this._viewports = [];
this.controllers = {};

this._viewports = views.map(view => {
// Create controllers in reverse order, so that views on top receive events first
for (let i = views.length; i--; ) {
const view = views[i];
const viewState = this.getViewState(view);
const viewport = view.makeViewport({width, height, viewState});

Expand All @@ -325,8 +328,8 @@ export default class ViewManager {
oldControllers[view.id]
);

return viewport;
});
this._viewports.unshift(viewport);
}

// Remove unused controllers
for (const id in oldControllers) {
Expand Down
160 changes: 89 additions & 71 deletions test/apps/minimap/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {StaticMap} from 'react-map-gl';
import DeckGL from '@deck.gl/react';
import {View, MapView} from '@deck.gl/core';
import {PolygonLayer} from '@deck.gl/layers';
import {TripsLayer} from '@deck.gl/experimental-layers';
import {TripsLayer} from '@deck.gl/geo-layers';

// Set your mapbox token here
const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line
Expand All @@ -18,30 +18,56 @@ const DATA_URL = {
'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/trips/trips.json' // eslint-disable-line
};

const LIGHT_SETTINGS = {
lightsPosition: [-74.05, 40.7, 8000, -73.5, 41, 5000],
ambientRatio: 0.05,
diffuseRatio: 0.6,
specularRatio: 0.8,
lightsStrength: [2.0, 0.0, 0.0, 0.0],
numberOfLights: 2
};

export const INITIAL_VIEW_STATE = {
longitude: -74,
latitude: 40.72,
zoom: 13,
maxZoom: 16,
pitch: 45,
bearing: 0
};
const VIEWS = [
new MapView({
id: 'main',
controller: true
}),
new MapView({
id: 'minimap',

// Position on top of main map
x: '65%',
y: '5%',
width: '30%',
height: '30%',

// Minimap is overlaid on top of an existing view, so need to clear the background
clear: true,

controller: {
maxZoom: 11,
minZoom: 11,
dragRotate: false,
keyboard: false
}
})
];

export class App extends Component {
constructor(props) {
super(props);
this.state = {
time: 0
time: 0,
viewState: {
main: {
longitude: -74.01,
latitude: 40.705,
zoom: 15,
pitch: 45,
bearing: 0
},
minimap: {
longitude: -74.01,
latitude: 40.705,
zoom: 11,
pitch: 0,
bearing: 0
}
}
};

this._onViewStateChange = this._onViewStateChange.bind(this);
}

componentDidMount() {
Expand All @@ -68,6 +94,33 @@ export class App extends Component {
this._animationFrame = window.requestAnimationFrame(this._animate.bind(this));
}

_onViewStateChange({viewState, viewId}) {
const oldViewState = this.state.viewState;
if (viewId === 'minimap') {
this.setState({
viewState: {
main: {
...oldViewState.main,
longitude: viewState.longitude,
latitude: viewState.latitude
},
minimap: viewState
}
});
} else {
this.setState({
viewState: {
main: viewState,
minimap: {
...oldViewState.minimap,
longitude: viewState.longitude,
latitude: viewState.latitude
}
}
});
}
}

_renderLayers() {
const {buildings = DATA_URL.BUILDINGS, trips = DATA_URL.TRIPS, trailLength = 180} = this.props;

Expand All @@ -76,9 +129,9 @@ export class App extends Component {
id: 'trips',
data: trips,
getPath: d => d.segments,
getColor: d => (d.vendor === 0 ? [253, 128, 93] : [23, 184, 190]),
opacity: 0.3,
strokeWidth: 2,
getColor: [253, 128, 93],
getWidth: 5,
lineWidthMinPixels: 2,
trailLength,
currentTime: this.state.time
}),
Expand All @@ -87,71 +140,36 @@ export class App extends Component {
data: buildings,
extruded: true,
wireframe: false,
fp64: true,
opacity: 0.5,
opacity: 1,
getPolygon: f => f.polygon,
getElevation: f => f.height,
getFillColor: [74, 80, 87],
lightSettings: LIGHT_SETTINGS
getFillColor: [74, 80, 87]
})
];
}

render() {
const {controller = true, baseMap = true} = this.props;

return (
<DeckGL
layers={this._renderLayers()}
initialViewState={INITIAL_VIEW_STATE}
views={[
new MapView({id: 'main'}),
new MapView({
id: 'minimap',

// Position on top of main map
x: '65%',
y: '5%',
width: '30%',
height: '30%',

// Minimap is overlaid on top of an existing view, so need to clear the background
clear: true,

viewState: {
// Share the view state id of the main map
id: 'main',

// view state overrides: stay zoomed out and looking straight down, north up
zoom: 11,
pitch: 0,
bearing: 0
},

// No controller in the minimap in this first version
controller: false
})
]}
controller={controller}
viewState={this.state.viewState}
views={VIEWS}
onViewStateChange={this._onViewStateChange}
>
{baseMap && (
<StaticMap
reuseMaps
mapStyle="mapbox://styles/mapbox/dark-v9"
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
<View id="minimap">
<StaticMap
reuseMaps
mapStyle="mapbox://styles/mapbox/dark-v9"
mapStyle="mapbox://styles/mapbox/light-v9"
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
)}
{baseMap && (
<View id="minimap">
<StaticMap
reuseMaps
mapStyle="mapbox://styles/mapbox/light-v9"
preventStyleDiffing={true}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
</View>
)}
</View>
</DeckGL>
);
}
Expand Down
16 changes: 7 additions & 9 deletions test/apps/minimap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
"start": "webpack-dev-server --progress --hot --open"
},
"dependencies": {
"@deck.gl/react": "^6.1.0-alpha.2",
"@deck.gl/core": "^6.1.0-alpha.2",
"@deck.gl/layers": "^6.1.0-alpha.2",
"@deck.gl/experimental-layers": "^6.1.0-alpha.2",
"deck.gl": "^7.1.0",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"react-map-gl": "^3.3.0"
"react-map-gl": "^5.0.0"
},
"devDependencies": {
"buble": "^0.19.3",
"buble-loader": "^0.5.0",
"webpack": "^4.3.0",
"webpack-cli": "^2.0.13",
"@babel/core": "^7.4.0",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.5",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.1"
}
}
22 changes: 9 additions & 13 deletions test/apps/minimap/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,35 @@
// delete the local development overrides at the bottom of this file

// avoid destructuring for older Node version support
const resolve = require('path').resolve;
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const CONFIG = {
mode: 'development',

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

output: {
library: 'App'
},

module: {
rules: [
{
// Compile ES2015 using buble
// Transpile ES6 to ES5 with babel
// Remove if your app does not use JSX or you don't need to support old browsers
test: /\.js$/,
loader: 'buble-loader',
include: [resolve('.')],
loader: 'babel-loader',
exclude: [/node_modules/],
options: {
objectAssign: 'Object.assign'
presets: ['@babel/preset-react']
}
}
]
},

resolve: {
alias: {
// From mapbox-gl-js README. Required for non-browserify bundlers (e.g. webpack):
'mapbox-gl$': resolve('./node_modules/mapbox-gl/dist/mapbox-gl.js')
}
},

// Optional: Enables reading mapbox token from environment variable
plugins: [
new HtmlWebpackPlugin({title: 'deck.gl example'}),
Expand Down
Loading

0 comments on commit f1585f7

Please sign in to comment.