Skip to content

Commit

Permalink
Add bing maps integration (visgl#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress authored Jun 25, 2021
1 parent b991951 commit 579fb3e
Show file tree
Hide file tree
Showing 13 changed files with 496 additions and 0 deletions.
26 changes: 26 additions & 0 deletions examples/bing-maps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Example: Use deck.gl with Bing Maps

This is an example integrating deck.gl with Bing Maps using the deck.gl-bing-maps module.

## Usage

To run this example, you need a [Bing Maps API key](https://www.microsoft.com/en-us/maps/create-a-bing-maps-key). You can either set an environment variable:

```bash
export BingMapsAPIKey=<bing_maps_api_key>
```

Or set the `BING_MAPS_API_KEY` variable in `app.js`.

To install dependencies:

```bash
npm install
# or
yarn
```

Commands:

- `npm start` is the development target, to serve the app and hot reload.
- `npm run build` is the production target, to create the final bundle and write to disk.
60 changes: 60 additions & 0 deletions examples/bing-maps/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* global document, process */
import {loadModule} from 'deck.gl-bing-maps';
import {GeoJsonLayer, ArcLayer} from 'deck.gl';

// set your Bing Maps API key here
const BING_MAPS_API_KEY = process.env.BingMapsAPIKey; // eslint-disable-line

// source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz
const AIR_PORTS =
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson';

loadModule().then(({Map, MapTypeId, Location, DeckOverlay}) => {
// Create map
const map = new Map(document.getElementById('map'), {
credentials: BING_MAPS_API_KEY,
supportedMapTypes: [MapTypeId.aerial, MapTypeId.canvasLight, MapTypeId.canvasDark],
disableBirdsEye: true,
disableStreetside: true
});

map.setView({
center: new Location(51.47, 0.45),
zoom: 4
});

// Add deck.gl overlay
const deckOverlay = new DeckOverlay({
layers: [
new GeoJsonLayer({
id: 'airports',
data: AIR_PORTS,
// Styles
filled: true,
pointRadiusMinPixels: 2,
pointRadiusScale: 2000,
getRadius: f => 11 - f.properties.scalerank,
getFillColor: [200, 0, 80, 180],
// Interactive props
pickable: true,
autoHighlight: true,
onClick: info =>
// eslint-disable-next-line
info.object && alert(`${info.object.properties.name} (${info.object.properties.abbrev})`)
}),
new ArcLayer({
id: 'arcs',
data: AIR_PORTS,
dataTransform: d => d.features.filter(f => f.properties.scalerank < 4),
// Styles
getSourcePosition: f => [-0.4531566, 51.4709959], // London
getTargetPosition: f => f.geometry.coordinates,
getSourceColor: [0, 128, 200],
getTargetColor: [200, 0, 80],
getWidth: 1
})
],
getTooltip: info => info.object && info.object.properties.name
});
map.layers.insert(deckOverlay);
});
23 changes: 23 additions & 0 deletions examples/bing-maps/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<meta charset='UTF-8' />
<title>deck.gl w/ Bing Maps example</title>
<style>
#map {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.deck-tooltip {
white-space: nowrap;
}
</style>
</head>
<body>
<div id="map"></div>
<script src='app.js'></script>
</body>
</html>
16 changes: 16 additions & 0 deletions examples/bing-maps/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"license": "MIT",
"scripts": {
"start": "webpack-dev-server --progress --hot --open",
"start-local": "webpack-dev-server --env.local --progress --hot --open",
"build": "webpack -p"
},
"dependencies": {
"deck.gl": "^8.4.0"
},
"devDependencies": {
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.11"
}
}
13 changes: 13 additions & 0 deletions examples/bing-maps/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const webpack = require('webpack');

const config = {
mode: 'development',

entry: {
app: './app.js'
},

plugins: [new webpack.EnvironmentPlugin(['BingMapsAPIKey'])]
};

module.exports = env => (env && env.local ? require('../webpack.config.local')(config) : config);
96 changes: 96 additions & 0 deletions modules/bing-maps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# deck.gl-bing-maps

This module allows [deck.gl](https://deck.gl) to be used as a Bing Maps custom layer.

## Installation

```bash
npm install deck.gl deck.gl-bing-maps
```

## Usage

```js
import {loadModules} from 'deck.gl-bing-maps';
import {GeoJsonLayer} from 'deck.gl';

loadModules().then(({Maps, Location, DeckOverlay}) => {
// Create map
const map = new Map(document.getElementById('map'), {
credentials: 'YOUR_API_KEY',
// Disable modes that are not supported
disableBirdsEye: true,
disableStreetside: true
});

map.setView({
center: new Location(37.78, -122.45),
zoom: 10
});

// Add deck.gl overlay
const deckOverlay = new DeckOverlay({
layers: [
new GeoJsonLayer({
data:
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson',
lineWidthMinPixels: 2,
getLineColor: [60, 60, 60],
getFillColor: [200, 200, 200]
})
]
});
map.layers.insert(deckOverlay);
});
```

## API Reference

### loadModules

`loadModules(moduleNames)`

Arguments:

- `moduleNames` (Array<String>?) - Optional modules to load, e.g. `'Microsoft.Maps.GeoJson'`, `'Microsoft.Maps.DrawingTools'`

Returns a Promise that resolves to the global `Microsoft.Maps` namespace. A custom class, `DeckOverlay`, is also added to the namespace.

### DeckOverlay

An implementation of [CustomOverlay](https://docs.microsoft.com/en-us/bingmaps/v8-web-control/map-control-api/customoverlay-class).

```js
const deckOverlay = new DeckOverlay({...});
map.layers.insert(deckOverlay);
```

The constructor accepts a props object that is passed to the [Deck](https://deck.gl/docs/api-reference/core/deck) constructor. See the [limitations](#supported-features-and-limitations) section below for more details.

The following [Deck methods](https://deck.gl/docs/api-reference/core/deck#methods) can be called directly from a `DeckOverlay` instance:

- `deckOverlay.setProps`
- `deckOverlay.pickObject`
- `deckOverlay.pickMultipleObjects`
- `deckOverlay.pickObjects`
- `deckOverlay.redraw`
- `deckOverlay.finalize`

## Supported Features and Limitations

Supported deck.gl features:

- Layers
- Effects
- Auto-highlighting
- Attribute transitions
- `onHover` and `onClick` callbacks
- Tooltip

Not supported features:

- Tilting
- Multiple views
- Controller
- React integration
- Gesture event callbacks (e.g. `onDrag*`)
3 changes: 3 additions & 0 deletions modules/bing-maps/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# deck.gl-bing-maps

This module allows [deck.gl](https://deck.gl) to be used as a Bing Maps custom layer.
30 changes: 30 additions & 0 deletions modules/bing-maps/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "deck.gl-bing-maps",
"description": "deck.gl integration with Bing Maps",
"license": "MIT",
"version": "0.1.0-beta.0",
"publishConfig": {
"access": "public"
},
"keywords": [
"webgl",
"visualization",
"bing maps"
],
"repository": {
"type": "git",
"url": "https://github.com/visgl/deck.gl-community.gl.git"
},
"main": "dist/es5/index.js",
"module": "dist/esm/index.js",
"files": [
"dist",
"src"
],
"sideEffects": false,
"scripts": {},
"dependencies": {},
"peerDependencies": {
"@deck.gl/core": "^8.0.0"
}
}
68 changes: 68 additions & 0 deletions modules/bing-maps/src/deck-overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {createContainer, createDeckInstance, destroyDeckInstance, getViewState} from './utils';

const HIDE_ALL_LAYERS = () => false;

export default function getDeckOverlay({CustomOverlay, Events, MapTypeId}) {
class DeckOverlay extends CustomOverlay {
constructor(props = {}) {
super();
this.props = props;
}

setProps(props) {
Object.assign(this.props, props);
if (this.deck) {
this.deck.setProps(props);
}
}

pickObject(params) {
return this.deck && this.deck.pickObject(params);
}

pickMultipleObjects(params) {
return this.deck && this.deck.pickMultipleObjects(params);
}

pickObjects(params) {
return this.deck && this.deck.pickObjects(params);
}

finalize() {
destroyDeckInstance(this.deck, Events);
}

// Set up DOM elements, and use setHtmlElement to bind it with the overlay.
onAdd() {
this.container = createContainer(this.props.style);
// Add the container to the overlay
this.setHtmlElement(this.container);
}

// Perform custom operations after adding the overlay to the map.
onLoad() {
const map = this.getMap();
this.deck = createDeckInstance(map, this, this.props, Events);
}

// Remove all event handlers from the map.
onRemove() {
destroyDeckInstance(this.deck, Events);
this.deck = null;
}

redraw() {
const map = this.getMap();
const {deck} = this;
const mapType = map.getMapTypeId();
const canSyncWithMap = mapType !== MapTypeId.streetside && mapType !== MapTypeId.birdseye;
deck.setProps({
...getViewState(map),
layerFilter: canSyncWithMap ? this.props.layerFilter : HIDE_ALL_LAYERS
});
// deck.redraw();
}
}

return DeckOverlay;
}
1 change: 1 addition & 0 deletions modules/bing-maps/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default as loadModule} from './load-module';
36 changes: 36 additions & 0 deletions modules/bing-maps/src/load-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* global document, window */
import getDeckOverlay from './deck-overlay';

const BING_MAPS_API_URL = 'https://www.bing.com/api/maps/mapcontrol?callback=__loadBingMaps';

export default function loadModule(moduleNames) {
return new Promise(resolve => {
// Callback
window.__loadBingMaps = () => {
/* global Microsoft */
const namespace = Microsoft.Maps;
namespace.DeckOverlay = getDeckOverlay(namespace);
delete window.__loadBingMaps;

if (moduleNames) {
Promise.all(moduleNames.map(m => awaitCallback(namespace.loadModule, m))).then(() =>
resolve(namespace)
);
} else {
resolve(namespace);
}
};

const script = document.createElement('script');
script.type = 'text/javascript';
script.src = BING_MAPS_API_URL;
const head = document.querySelector('head');
head.appendChild(script);
});
}

function awaitCallback(func, ...args) {
return new Promise(resolve => {
func(...args, resolve);
});
}
Loading

0 comments on commit 579fb3e

Please sign in to comment.