Load OL3 code only once we need it

This commit is contained in:
Lukas Martinelli 2016-12-22 18:08:42 +01:00
parent 607e920548
commit 3ee1473a49
8 changed files with 123 additions and 46 deletions

View file

@ -110,8 +110,10 @@ export default class App extends React.Component {
const metadata = this.state.mapStyle.metadata || {}
const renderer = metadata['maputnik:renderer'] || 'mbgljs'
// Check if OL3 code has been loaded?
if(renderer === 'ol3') {
return <OpenLayers3Map {...mapProps} />
return <OpenLayers3Map {...mapProps} />
} else {
return <MapboxGlMap {...mapProps} />
}

View file

@ -5,7 +5,7 @@ class StringInput extends React.Component {
static propTypes = {
value: React.PropTypes.string,
style: React.PropTypes.object,
onChange: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func,
}
render() {

View file

@ -1,38 +1,61 @@
import React from 'react'
import ol from 'openlayers'
import olms from 'ol-mapbox-style'
import Map from './Map'
import style from '../../libs/style.js'
export default class OpenLayers3Map extends Map {
class OpenLayers3Map extends Map {
constructor(props) {
super(props)
const tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22})
this.resolutions = tilegrid.getResolutions()
this.layer = new ol.layer.VectorTile({
source: new ol.source.VectorTile({
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
'© <a href="http://www.openstreetmap.org/copyright">' +
'OpenStreetMap contributors</a>',
format: new ol.format.MVT(),
tileGrid: tilegrid,
tilePixelRatio: 8,
url: 'http://osm2vectortiles-0.tileserver.com/v2/{z}/{x}/{y}.pbf'
this.state = {
map: null,
ol: null,
olms: null
}
//Load OpenLayers dynamically once we need it
//TODO: Make this more convenient
require.ensure(["openlayers", "ol-mapbox-style"], ()=> {
const ol = require('openlayers')
const olms = require('ol-mapbox-style')
const tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22})
this.resolutions = tilegrid.getResolutions()
this.layer = new ol.layer.VectorTile({
source: new ol.source.VectorTile({
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
'© <a href="http://www.openstreetmap.org/copyright">' +
'OpenStreetMap contributors</a>',
format: new ol.format.MVT(),
tileGrid: tilegrid,
tilePixelRatio: 8,
url: 'http://osm2vectortiles-0.tileserver.com/v2/{z}/{x}/{y}.pbf'
})
})
this.setState({
ol: ol,
olms: olms,
})
console.log('Loaded OpenLayers3 renderer')
})
}
componentWillReceiveProps(nextProps) {
const olms = this.state.olms
const ol = this.state.ol
if(!olms || !ol) return
const jsonStyle = style.toJSON(nextProps.mapStyle)
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
this.layer.setStyle(styleFunc)
this.state.map.render()
}
componentDidMount() {
const olms = this.state.olms
const ol = this.state.ol
if(!olms || !ol) return
const jsonStyle = style.toJSON(this.props.mapStyle)
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
this.layer.setStyle(styleFunc)
@ -49,3 +72,5 @@ export default class OpenLayers3Map extends Map {
this.setState({ map });
}
}
export default OpenLayers3Map

View file

@ -23,8 +23,14 @@ class SettingsModal extends React.Component {
this.props.onStyleChanged(changedStyle)
}
onRendererChange(e) {
const changedStyle = this.props.mapStyle.setIn(['metadata', 'maputnik:renderer'], e.target.value)
onRendererChange(renderer) {
const changedStyle = {
...this.props.mapStyle,
metadata: {
...this.props.mapStyle.metadata,
'maputnik:renderer': renderer,
}
}
this.props.onStyleChanged(changedStyle)
}

View file

@ -8,6 +8,7 @@ import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import SourceTypeEditor from '../sources/SourceTypeEditor'
import style from '../../libs/style'
import publicSources from '../../config/tilesets.json'
import colors from '../../config/colors'
import { margins, fontSizes } from '../../config/scales'
@ -34,12 +35,15 @@ class PublicSource extends React.Component {
fontSize: fontSizes[4],
color: colors.lowgray,
}}>
<Button style={{
backgroundColor: 'transparent',
padding: margins[2],
display: 'flex',
flexDirection: 'row',
}}>
<Button
onClick={() => this.props.onSelect(this.props.id)}
style={{
backgroundColor: 'transparent',
padding: margins[2],
display: 'flex',
flexDirection: 'row',
}}
>
<div>
<span style={{fontWeight: 700}}>{this.props.title}</span>
<br/>
@ -114,10 +118,21 @@ class AddSource extends React.Component {
super(props)
this.state = {
mode: 'tilejson',
source: {}
source: {
id: style.generateId(),
}
}
}
onSourceIdChange(newId) {
this.setState({
source: {
...this.state.source,
id: newId,
}
})
}
onSourceChange(source) {
this.setState({
source: source
@ -128,7 +143,8 @@ class AddSource extends React.Component {
return <div>
<InputBlock label={"Source ID"}>
<StringInput
value={'blubid'}
value={this.state.source.id}
onChange={this.onSourceIdChange.bind(this)}
/>
</InputBlock>
<InputBlock label={"Source Type"}>
@ -147,7 +163,7 @@ class AddSource extends React.Component {
mode={this.state.mode}
source={this.state.source}
/>
<Button onClick={() => this.props.onSourceAdd(this.state.source)}>
<Button onClick={() => this.onSourceAdd(this.state.source)}>
Add Source
</Button>
</div>
@ -159,6 +175,21 @@ class SourcesModal extends React.Component {
mapStyle: React.PropTypes.object.isRequired,
isOpen: React.PropTypes.bool.isRequired,
onOpenToggle: React.PropTypes.func.isRequired,
onStyleChanged: React.PropTypes.func.isRequired,
}
onSourceAdd(source) {
const changedSources = {
...this.props.mapStyle.sources,
[source.id]: source
}
const changedStyle = {
...this.props.mapStyle,
sources: changedSources
}
this.props.onStyleChanged(changedStyle)
}
render() {
@ -167,12 +198,14 @@ class SourcesModal extends React.Component {
return <SourceEditorLayout sourceId={sourceId} source={source} />
})
const tilesetOptions = publicSources.filter(tileset => !(tileset.id in this.props.mapStyle.sources)).map(tileset => {
const tilesetOptions = publicSources.filter(source => !(source.id in this.props.mapStyle.sources)).map(source => {
return <PublicSource
id={tileset.id}
type={tileset.type}
title={tileset.title}
description={tileset.description}
key={source.id}
id={source.id}
type={source.type}
title={source.title}
description={source.description}
onSelect={() => this.onSourceAdd(source)}
/>
})
@ -188,7 +221,7 @@ class SourcesModal extends React.Component {
<Heading level={4}>Add New Source</Heading>
<div style={{maxWidth: 300}}>
<p style={{color: colors.lowgray, fontSize: fontSizes[5]}}>Add a new source to your style. You can only choose the source type and id at creation time!</p>
<AddSource />
<AddSource onSourceAdd={this.onSourceAdd.bind(this)} />
</div>
<Heading level={4}>Choose Public Source</Heading>

View file

@ -5,7 +5,7 @@ import StringInput from '../inputs/StringInput'
class TileJSONSourceEditor extends React.Component {
static propTypes = {
url: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func,
}
render() {
@ -23,7 +23,7 @@ class TileURLSourceEditor extends React.Component {
tiles: React.PropTypes.array.isRequired,
minZoom: React.PropTypes.number.isRequired,
maxZoom: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func,
}
renderTileUrls() {
@ -59,7 +59,7 @@ class TileURLSourceEditor extends React.Component {
class GeoJSONSourceEditor extends React.Component {
static propTypes = {
data: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func,
}
render() {

View file

@ -8,9 +8,13 @@ const emptyStyle = ensureMetadataExists({
layers: [],
})
function generateId() {
return Math.random().toString(36).substr(2, 9)
}
function ensureHasId(style) {
if('id' in style) return style
style.id = Math.random().toString(36).substr(2, 9)
style.id = generateId()
return style
}
@ -37,4 +41,5 @@ export default {
ensureMetadataExists,
emptyStyle,
indexOfLayer,
generateId,
}

View file

@ -28,26 +28,32 @@ module.exports = {
app: './src/index.jsx',
vendor: [
'file-saver',
'immutable',
'mapbox-gl',
//TODO: Cannot resolve migrations file?
//TODO: Build failure because cannot resolve migrations file
//"mapbox-gl-style-spec",
"radium",
"randomcolor",
"lodash.clonedeep",
"lodash.throttle",
"lodash.topairs",
'color',
'react',
"react-dom",
"react-color",
"react-file-reader-input",
"react-collapse",
"react-height",
"react-icon-base",
"react-motion",
"react-sortable-hoc",
"request",
//TODO: Icons raise multi vendor errors?
//"react-icons",
// Open Layers
'openlayers',
'ol-mapbox-style'
]
},
output: {
path: path.join(__dirname, 'public'),
filename: '[chunkhash].app.js'
filename: '[name].[chunkhash].js',
chunkFilename: '[chunkhash].js'
},
resolve: {
alias: {