mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2024-12-28 02:05:25 +01:00
Load OL3 code only once we need it
This commit is contained in:
parent
607e920548
commit
3ee1473a49
8 changed files with 123 additions and 46 deletions
|
@ -110,8 +110,10 @@ export default class App extends React.Component {
|
||||||
|
|
||||||
const metadata = this.state.mapStyle.metadata || {}
|
const metadata = this.state.mapStyle.metadata || {}
|
||||||
const renderer = metadata['maputnik:renderer'] || 'mbgljs'
|
const renderer = metadata['maputnik:renderer'] || 'mbgljs'
|
||||||
|
|
||||||
|
// Check if OL3 code has been loaded?
|
||||||
if(renderer === 'ol3') {
|
if(renderer === 'ol3') {
|
||||||
return <OpenLayers3Map {...mapProps} />
|
return <OpenLayers3Map {...mapProps} />
|
||||||
} else {
|
} else {
|
||||||
return <MapboxGlMap {...mapProps} />
|
return <MapboxGlMap {...mapProps} />
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ class StringInput extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: React.PropTypes.string,
|
value: React.PropTypes.string,
|
||||||
style: React.PropTypes.object,
|
style: React.PropTypes.object,
|
||||||
onChange: React.PropTypes.func.isRequired,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,38 +1,61 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ol from 'openlayers'
|
|
||||||
import olms from 'ol-mapbox-style'
|
|
||||||
|
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
import style from '../../libs/style.js'
|
import style from '../../libs/style.js'
|
||||||
|
|
||||||
export default class OpenLayers3Map extends Map {
|
class OpenLayers3Map extends Map {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22})
|
this.state = {
|
||||||
this.resolutions = tilegrid.getResolutions()
|
map: null,
|
||||||
this.layer = new ol.layer.VectorTile({
|
ol: null,
|
||||||
source: new ol.source.VectorTile({
|
olms: null
|
||||||
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
|
}
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">' +
|
|
||||||
'OpenStreetMap contributors</a>',
|
//Load OpenLayers dynamically once we need it
|
||||||
format: new ol.format.MVT(),
|
//TODO: Make this more convenient
|
||||||
tileGrid: tilegrid,
|
require.ensure(["openlayers", "ol-mapbox-style"], ()=> {
|
||||||
tilePixelRatio: 8,
|
const ol = require('openlayers')
|
||||||
url: 'http://osm2vectortiles-0.tileserver.com/v2/{z}/{x}/{y}.pbf'
|
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) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
const olms = this.state.olms
|
||||||
|
const ol = this.state.ol
|
||||||
|
if(!olms || !ol) return
|
||||||
|
|
||||||
const jsonStyle = style.toJSON(nextProps.mapStyle)
|
const jsonStyle = style.toJSON(nextProps.mapStyle)
|
||||||
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
|
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
|
||||||
this.layer.setStyle(styleFunc)
|
this.layer.setStyle(styleFunc)
|
||||||
this.state.map.render()
|
this.state.map.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const olms = this.state.olms
|
||||||
|
const ol = this.state.ol
|
||||||
|
if(!olms || !ol) return
|
||||||
|
|
||||||
const jsonStyle = style.toJSON(this.props.mapStyle)
|
const jsonStyle = style.toJSON(this.props.mapStyle)
|
||||||
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
|
const styleFunc = olms.getStyleFunction(jsonStyle, 'mapbox', this.resolutions)
|
||||||
this.layer.setStyle(styleFunc)
|
this.layer.setStyle(styleFunc)
|
||||||
|
@ -49,3 +72,5 @@ export default class OpenLayers3Map extends Map {
|
||||||
this.setState({ map });
|
this.setState({ map });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default OpenLayers3Map
|
||||||
|
|
|
@ -23,8 +23,14 @@ class SettingsModal extends React.Component {
|
||||||
this.props.onStyleChanged(changedStyle)
|
this.props.onStyleChanged(changedStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
onRendererChange(e) {
|
onRendererChange(renderer) {
|
||||||
const changedStyle = this.props.mapStyle.setIn(['metadata', 'maputnik:renderer'], e.target.value)
|
const changedStyle = {
|
||||||
|
...this.props.mapStyle,
|
||||||
|
metadata: {
|
||||||
|
...this.props.mapStyle.metadata,
|
||||||
|
'maputnik:renderer': renderer,
|
||||||
|
}
|
||||||
|
}
|
||||||
this.props.onStyleChanged(changedStyle)
|
this.props.onStyleChanged(changedStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
import SelectInput from '../inputs/SelectInput'
|
||||||
import SourceTypeEditor from '../sources/SourceTypeEditor'
|
import SourceTypeEditor from '../sources/SourceTypeEditor'
|
||||||
|
|
||||||
|
import style from '../../libs/style'
|
||||||
import publicSources from '../../config/tilesets.json'
|
import publicSources from '../../config/tilesets.json'
|
||||||
import colors from '../../config/colors'
|
import colors from '../../config/colors'
|
||||||
import { margins, fontSizes } from '../../config/scales'
|
import { margins, fontSizes } from '../../config/scales'
|
||||||
|
@ -34,12 +35,15 @@ class PublicSource extends React.Component {
|
||||||
fontSize: fontSizes[4],
|
fontSize: fontSizes[4],
|
||||||
color: colors.lowgray,
|
color: colors.lowgray,
|
||||||
}}>
|
}}>
|
||||||
<Button style={{
|
<Button
|
||||||
backgroundColor: 'transparent',
|
onClick={() => this.props.onSelect(this.props.id)}
|
||||||
padding: margins[2],
|
style={{
|
||||||
display: 'flex',
|
backgroundColor: 'transparent',
|
||||||
flexDirection: 'row',
|
padding: margins[2],
|
||||||
}}>
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span style={{fontWeight: 700}}>{this.props.title}</span>
|
<span style={{fontWeight: 700}}>{this.props.title}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -114,10 +118,21 @@ class AddSource extends React.Component {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
mode: 'tilejson',
|
mode: 'tilejson',
|
||||||
source: {}
|
source: {
|
||||||
|
id: style.generateId(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSourceIdChange(newId) {
|
||||||
|
this.setState({
|
||||||
|
source: {
|
||||||
|
...this.state.source,
|
||||||
|
id: newId,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onSourceChange(source) {
|
onSourceChange(source) {
|
||||||
this.setState({
|
this.setState({
|
||||||
source: source
|
source: source
|
||||||
|
@ -128,7 +143,8 @@ class AddSource extends React.Component {
|
||||||
return <div>
|
return <div>
|
||||||
<InputBlock label={"Source ID"}>
|
<InputBlock label={"Source ID"}>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={'blubid'}
|
value={this.state.source.id}
|
||||||
|
onChange={this.onSourceIdChange.bind(this)}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Source Type"}>
|
<InputBlock label={"Source Type"}>
|
||||||
|
@ -147,7 +163,7 @@ class AddSource extends React.Component {
|
||||||
mode={this.state.mode}
|
mode={this.state.mode}
|
||||||
source={this.state.source}
|
source={this.state.source}
|
||||||
/>
|
/>
|
||||||
<Button onClick={() => this.props.onSourceAdd(this.state.source)}>
|
<Button onClick={() => this.onSourceAdd(this.state.source)}>
|
||||||
Add Source
|
Add Source
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,6 +175,21 @@ class SourcesModal extends React.Component {
|
||||||
mapStyle: React.PropTypes.object.isRequired,
|
mapStyle: React.PropTypes.object.isRequired,
|
||||||
isOpen: React.PropTypes.bool.isRequired,
|
isOpen: React.PropTypes.bool.isRequired,
|
||||||
onOpenToggle: React.PropTypes.func.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() {
|
render() {
|
||||||
|
@ -167,12 +198,14 @@ class SourcesModal extends React.Component {
|
||||||
return <SourceEditorLayout sourceId={sourceId} source={source} />
|
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
|
return <PublicSource
|
||||||
id={tileset.id}
|
key={source.id}
|
||||||
type={tileset.type}
|
id={source.id}
|
||||||
title={tileset.title}
|
type={source.type}
|
||||||
description={tileset.description}
|
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>
|
<Heading level={4}>Add New Source</Heading>
|
||||||
<div style={{maxWidth: 300}}>
|
<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>
|
<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>
|
</div>
|
||||||
|
|
||||||
<Heading level={4}>Choose Public Source</Heading>
|
<Heading level={4}>Choose Public Source</Heading>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import StringInput from '../inputs/StringInput'
|
||||||
class TileJSONSourceEditor extends React.Component {
|
class TileJSONSourceEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
url: React.PropTypes.string.isRequired,
|
url: React.PropTypes.string.isRequired,
|
||||||
onChange: React.PropTypes.func.isRequired,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -23,7 +23,7 @@ class TileURLSourceEditor extends React.Component {
|
||||||
tiles: React.PropTypes.array.isRequired,
|
tiles: React.PropTypes.array.isRequired,
|
||||||
minZoom: React.PropTypes.number.isRequired,
|
minZoom: React.PropTypes.number.isRequired,
|
||||||
maxZoom: React.PropTypes.number.isRequired,
|
maxZoom: React.PropTypes.number.isRequired,
|
||||||
onChange: React.PropTypes.func.isRequired,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTileUrls() {
|
renderTileUrls() {
|
||||||
|
@ -59,7 +59,7 @@ class TileURLSourceEditor extends React.Component {
|
||||||
class GeoJSONSourceEditor extends React.Component {
|
class GeoJSONSourceEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data: React.PropTypes.string.isRequired,
|
data: React.PropTypes.string.isRequired,
|
||||||
onChange: React.PropTypes.func.isRequired,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -8,9 +8,13 @@ const emptyStyle = ensureMetadataExists({
|
||||||
layers: [],
|
layers: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function generateId() {
|
||||||
|
return Math.random().toString(36).substr(2, 9)
|
||||||
|
}
|
||||||
|
|
||||||
function ensureHasId(style) {
|
function ensureHasId(style) {
|
||||||
if('id' in style) return style
|
if('id' in style) return style
|
||||||
style.id = Math.random().toString(36).substr(2, 9)
|
style.id = generateId()
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,4 +41,5 @@ export default {
|
||||||
ensureMetadataExists,
|
ensureMetadataExists,
|
||||||
emptyStyle,
|
emptyStyle,
|
||||||
indexOfLayer,
|
indexOfLayer,
|
||||||
|
generateId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,26 +28,32 @@ module.exports = {
|
||||||
app: './src/index.jsx',
|
app: './src/index.jsx',
|
||||||
vendor: [
|
vendor: [
|
||||||
'file-saver',
|
'file-saver',
|
||||||
'immutable',
|
|
||||||
'mapbox-gl',
|
'mapbox-gl',
|
||||||
//TODO: Cannot resolve migrations file?
|
//TODO: Build failure because cannot resolve migrations file
|
||||||
//"mapbox-gl-style-spec",
|
//"mapbox-gl-style-spec",
|
||||||
"radium",
|
|
||||||
"randomcolor",
|
"randomcolor",
|
||||||
|
"lodash.clonedeep",
|
||||||
|
"lodash.throttle",
|
||||||
|
"lodash.topairs",
|
||||||
|
'color',
|
||||||
'react',
|
'react',
|
||||||
"react-dom",
|
"react-dom",
|
||||||
"react-color",
|
"react-color",
|
||||||
"react-file-reader-input",
|
"react-file-reader-input",
|
||||||
|
"react-collapse",
|
||||||
|
"react-height",
|
||||||
|
"react-icon-base",
|
||||||
|
"react-motion",
|
||||||
|
"react-sortable-hoc",
|
||||||
|
"request",
|
||||||
//TODO: Icons raise multi vendor errors?
|
//TODO: Icons raise multi vendor errors?
|
||||||
//"react-icons",
|
//"react-icons",
|
||||||
// Open Layers
|
|
||||||
'openlayers',
|
|
||||||
'ol-mapbox-style'
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'public'),
|
path: path.join(__dirname, 'public'),
|
||||||
filename: '[chunkhash].app.js'
|
filename: '[name].[chunkhash].js',
|
||||||
|
chunkFilename: '[chunkhash].js'
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
Loading…
Reference in a new issue