Reuse map function: reparenting child nodes when reusing the saved map (#457)

* Update readme

* Remove unused code

* Add comments

* Import data from examples/data
This commit is contained in:
Javid 2018-02-09 16:46:14 -07:00 committed by GitHub
parent 125a5d3a6d
commit c776dcf0e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 265 additions and 2 deletions

View File

@ -0,0 +1,7 @@
<div align="center">
<img src="https://avatars3.githubusercontent.com/u/2105791?v=3&s=200" />
</div>
## Example: Reuse Map
This example showcases how to reuse the same map without destroying it.

View File

@ -0,0 +1,30 @@
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif;
}
.control-panel {
position: absolute;
top: 0;
right: 0;
max-width: 320px;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
padding: 12px 24px;
margin: 20px;
font-size: 13px;
line-height: 2;
color: #6b6b76;
text-transform: uppercase;
outline: none;
}
label {
display: inline-block;
width: 160px;
}
input {
margin-left: 20px;
max-width: 60px;
}

View File

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset='UTF-8' />
<title>react-map-gl Interaction Example</title>
<link rel="stylesheet" type="text/css" href="app.css" />
</head>
<body>
<script src='bundle.js'></script>
</body>
</html>

View File

@ -0,0 +1,20 @@
{
"scripts": {
"start": "webpack-dev-server --progress --hot --open",
"start-local": "webpack-dev-server --env.local --progress --hot --open"
},
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-map-gl": "^3.2.0"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-2": "^6.18.0",
"webpack": "^2.4.0",
"webpack-dev-server": "^2.4.0"
}
}

View File

@ -0,0 +1,27 @@
import React, {Component} from 'react';
import {render} from 'react-dom';
import BartMap from './bart-map';
export default class App extends Component {
state = {
showMap: true
};
_toggleMap() {
this.setState({showMap: !this.state.showMap});
}
render() {
const {showMap} = this.state;
return (
<div>
<div onClick={this._toggleMap.bind(this)}>
Toggle Map
</div>
{showMap && <BartMap />}
</div>
);
}
}

View File

@ -0,0 +1,65 @@
import React, {Component} from 'react';
import MapGL, {Marker} from '../../../src';
import bartStations from '../../data/bart-station.json';
const MAPBOX_TOKEN = ''; // Set your mapbox token here
import MARKER_STYLE from './marker-style';
export default class BartMap extends Component {
state = {
viewport: {
latitude: 37.729,
longitude: -122.36,
zoom: 11,
bearing: 0,
pitch: 50,
width: 500,
height: 500
},
settings: {
dragPan: true,
dragRotate: true,
scrollZoom: true,
touchZoom: true,
touchRotate: true,
keyboard: true,
doubleClickZoom: true,
minZoom: 0,
maxZoom: 20,
minPitch: 0,
maxPitch: 85
}
};
_onViewportChange = viewport => this.setState({viewport});
_renderMarker(station, i) {
const {name, coordinates} = station;
return (
<Marker key={i} longitude={coordinates[0]} latitude={coordinates[1]} >
<div className="station"><span>{name}</span></div>
</Marker>
);
}
render() {
const {viewport, settings} = this.state;
return (
<MapGL
{...viewport}
{...settings}
mapStyle="mapbox://styles/mapbox/dark-v9"
onViewportChange={this._onViewportChange}
mapboxApiAccessToken={MAPBOX_TOKEN}
reuseMaps={true}
>
<style>{MARKER_STYLE}</style>
{ bartStations.map(this._renderMarker) }
</MapGL>
);
}
}

View File

@ -0,0 +1,30 @@
export default `
.station:before {
content: ' ';
display: inline-block;
width: 8px;
height: 8px;
background: red;
border-radius: 8px;
margin: 0 8px;
}
.station {
border-radius: 20px;
padding-right: 12px;
margin: -12px;
color: transparent;
line-height: 24px;
font-size: 13px;
white-space: nowrap;
}
.station span {
display: none;
}
.station:hover {
background: rgba(0,0,0,0.8);
color: #fff;
}
.station:hover span {
display: inline-block;
}
`;

View File

@ -0,0 +1,6 @@
/* global document */
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
ReactDOM.render(<App/>, document.body.appendChild(document.createElement('div')));

View File

@ -0,0 +1,57 @@
// NOTE: To use this example standalone (e.g. outside of deck.gl repo)
// 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');
// Otherwise modules imported from outside this directory does not compile.
// Also needed if modules from this directory were imported elsewhere
// Seems to be a Babel bug
// https://github.com/babel/babel-loader/issues/149#issuecomment-191991686
const BABEL_CONFIG = {
presets: [
'es2015',
'react',
'stage-2'
].map(function configMap(name) {
return require.resolve(`babel-preset-${name}`);
})
};
const config = {
entry: {
app: resolve('./src/root.js')
},
devtool: 'source-map',
module: {
rules: [{
// Compile ES2015 using bable
test: /\.js$/,
include: [resolve('.')],
exclude: [/node_modules/],
use: [{
loader: 'babel-loader',
options: BABEL_CONFIG
}]
}]
},
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 webpack.EnvironmentPlugin(['MapboxAccessToken'])
]
};
// Enables bundling against src in this repo rather than the installed version
module.exports = env => env && env.local ?
require('../webpack.config.local')(config)(env) : config;

View File

@ -33,8 +33,7 @@ function noop() {}
const propTypes = {
// Creation parameters
// container: PropTypes.DOMElement || String
container: PropTypes.object, /** The container to have the map. */
mapboxApiAccessToken: PropTypes.string, /** Mapbox API access token for Mapbox tiles/styles. */
attributionControl: PropTypes.bool, /** Show attribution control or not. */
preserveDrawingBuffer: PropTypes.bool, /** Useful when you want to export the canvas as a PNG. */
@ -163,6 +162,17 @@ export default class Mapbox {
// Reuse a saved map, if available
if (props.reuseMaps && Mapbox.savedMap) {
this._map = this.map = Mapbox.savedMap;
// When reusing the saved map, we need to reparent the map(canvas) and other child nodes
// intoto the new container from the props.
// Step1: reparenting child nodes from old container to new container
const oldContainer = this._map.getContainer();
const newContainer = props.container;
newContainer.classList.add('mapboxgl-map');
while (oldContainer.childNodes.length > 0) {
newContainer.appendChild(oldContainer.childNodes[0]);
}
// Step2: replace the internal container with new container from the react component
this._map._container = newContainer;
Mapbox.savedMap = null;
// TODO - need to call onload again, need to track with Promise?
props.onLoad();