mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2025-01-15 03:03:26 +01:00
Implement adding public and custom sources
This commit is contained in:
parent
ba271e1fc6
commit
80678af691
4 changed files with 80 additions and 49 deletions
|
@ -5,6 +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,
|
||||||
|
default: React.PropTypes.number,
|
||||||
onChange: React.PropTypes.func,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ class StringInput extends React.Component {
|
||||||
...this.props.style
|
...this.props.style
|
||||||
}}
|
}}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
placeholder={this.props.default}
|
||||||
onChange={e => this.props.onChange(e.target.value)}
|
onChange={e => this.props.onChange(e.target.value)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,19 +118,30 @@ class AddSource extends React.Component {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
mode: 'tilejson',
|
mode: 'tilejson',
|
||||||
source: {
|
sourceId: style.generateId(),
|
||||||
id: style.generateId(),
|
source: this.defaultSource('tilejson'),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSourceIdChange(newId) {
|
defaultSource(mode) {
|
||||||
this.setState({
|
const source = (this.state || {}).source || {}
|
||||||
source: {
|
switch(mode) {
|
||||||
...this.state.source,
|
case 'geojson': return {
|
||||||
id: newId,
|
type: 'geojson',
|
||||||
|
data: source.data || 'http://localhost:3000/geojson.json'
|
||||||
|
}
|
||||||
|
case 'tilejson': return {
|
||||||
|
type: 'vector',
|
||||||
|
url: source.url || 'http://localhost:3000/tilejson.json'
|
||||||
|
}
|
||||||
|
case 'tilexyz': return {
|
||||||
|
type: 'vector',
|
||||||
|
tiles: source.tiles || ['http://localhost:3000/{x}/{y}/{z}.pbf'],
|
||||||
|
minZoom: source.minZoom || 0,
|
||||||
|
maxZoom: source.maxZoom || 14
|
||||||
|
}
|
||||||
|
default: return {}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSourceChange(source) {
|
onSourceChange(source) {
|
||||||
|
@ -143,8 +154,8 @@ class AddSource extends React.Component {
|
||||||
return <div>
|
return <div>
|
||||||
<InputBlock label={"Source ID"}>
|
<InputBlock label={"Source ID"}>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={this.state.source.id}
|
value={this.state.sourceId}
|
||||||
onChange={this.onSourceIdChange.bind(this)}
|
onChange={v => this.setState({ sourceId: v})}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Source Type"}>
|
<InputBlock label={"Source Type"}>
|
||||||
|
@ -154,7 +165,7 @@ class AddSource extends React.Component {
|
||||||
['tilejson', 'Vector (TileJSON URL)'],
|
['tilejson', 'Vector (TileJSON URL)'],
|
||||||
['tilexyz', 'Vector (XYZ URLs)'],
|
['tilexyz', 'Vector (XYZ URLs)'],
|
||||||
]}
|
]}
|
||||||
onChange={v => this.setState({mode: v})}
|
onChange={mode => this.setState({mode: mode, source: this.defaultSource(mode)})}
|
||||||
value={this.state.mode}
|
value={this.state.mode}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
@ -163,7 +174,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.onSourceAdd(this.state.source)}>
|
<Button onClick={() => this.props.onSourceAdd(this.state.sourceId, this.state.source)}>
|
||||||
Add Source
|
Add Source
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -178,10 +189,10 @@ class SourcesModal extends React.Component {
|
||||||
onStyleChanged: React.PropTypes.func.isRequired,
|
onStyleChanged: React.PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
onSourceAdd(source) {
|
onSourceAdd(sourceId, source) {
|
||||||
const changedSources = {
|
const changedSources = {
|
||||||
...this.props.mapStyle.sources,
|
...this.props.mapStyle.sources,
|
||||||
[source.id]: source
|
[sourceId]: source
|
||||||
}
|
}
|
||||||
|
|
||||||
const changedStyle = {
|
const changedStyle = {
|
||||||
|
@ -203,6 +214,12 @@ class SourcesModal extends React.Component {
|
||||||
this.props.onStyleChanged(changedStyle)
|
this.props.onStyleChanged(changedStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stripTitle(source) {
|
||||||
|
const strippedSource = {...source}
|
||||||
|
delete strippedSource['title']
|
||||||
|
return strippedSource
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const activeSources = Object.keys(this.props.mapStyle.sources).map(sourceId => {
|
const activeSources = Object.keys(this.props.mapStyle.sources).map(sourceId => {
|
||||||
const source = this.props.mapStyle.sources[sourceId]
|
const source = this.props.mapStyle.sources[sourceId]
|
||||||
|
@ -214,14 +231,14 @@ class SourcesModal extends React.Component {
|
||||||
/>
|
/>
|
||||||
})
|
})
|
||||||
|
|
||||||
const tilesetOptions = publicSources.filter(source => !(source.id in this.props.mapStyle.sources)).map(source => {
|
const tilesetOptions = Object.keys(publicSources).filter(sourceId => !(sourceId in this.props.mapStyle.sources)).map(sourceId => {
|
||||||
|
const source = publicSources[sourceId]
|
||||||
return <PublicSource
|
return <PublicSource
|
||||||
key={source.id}
|
key={sourceId}
|
||||||
id={source.id}
|
id={sourceId}
|
||||||
type={source.type}
|
type={source.type}
|
||||||
title={source.title}
|
title={source.title}
|
||||||
description={source.description}
|
onSelect={() => this.onSourceAdd(sourceId, this.stripTitle(source))}
|
||||||
onSelect={() => this.onSourceAdd(source)}
|
|
||||||
/>
|
/>
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
|
import NumberInput from '../inputs/NumberInput'
|
||||||
|
|
||||||
class TileJSONSourceEditor extends React.Component {
|
class TileJSONSourceEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
url: React.PropTypes.string.isRequired,
|
source: React.PropTypes.object.isRequired,
|
||||||
onChange: React.PropTypes.func,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"TileJSON URL"}>
|
return <InputBlock label={"TileJSON URL"}>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={this.props.url}
|
value={this.props.source.url}
|
||||||
onChange={this.props.onChange}
|
onChange={url => this.props.onChange({
|
||||||
|
...this.props.source,
|
||||||
|
url: url
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
}
|
}
|
||||||
|
@ -20,15 +24,14 @@ class TileJSONSourceEditor extends React.Component {
|
||||||
|
|
||||||
class TileURLSourceEditor extends React.Component {
|
class TileURLSourceEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
tiles: React.PropTypes.array.isRequired,
|
source: React.PropTypes.object.isRequired,
|
||||||
minZoom: React.PropTypes.number.isRequired,
|
|
||||||
maxZoom: React.PropTypes.number.isRequired,
|
|
||||||
onChange: React.PropTypes.func,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTileUrls() {
|
renderTileUrls() {
|
||||||
const prefix = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th']
|
const prefix = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th']
|
||||||
return this.props.tiles.map((tileUrl, tileIndex) => {
|
const tiles = this.props.source.tiles || []
|
||||||
|
return tiles.map((tileUrl, tileIndex) => {
|
||||||
return <InputBlock key={tileIndex} label={prefix[tileIndex] + " Tile URL"}>
|
return <InputBlock key={tileIndex} label={prefix[tileIndex] + " Tile URL"}>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={tileUrl}
|
value={tileUrl}
|
||||||
|
@ -38,17 +41,24 @@ class TileURLSourceEditor extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log(this.props.tiles)
|
|
||||||
return <div>
|
return <div>
|
||||||
{this.renderTileUrls()}
|
{this.renderTileUrls()}
|
||||||
<InputBlock label={"Min Zoom"}>
|
<InputBlock label={"Min Zoom"}>
|
||||||
<StringInput
|
<NumberInput
|
||||||
value={this.props.minZoom}
|
value={this.props.source.minZoom}
|
||||||
|
onChange={minZoom => this.props.onChange({
|
||||||
|
...this.props.source,
|
||||||
|
minZoom: minZoom
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Max Zoom"}>
|
<InputBlock label={"Max Zoom"}>
|
||||||
<StringInput
|
<NumberInput
|
||||||
value={this.props.maxZoom}
|
value={this.props.source.maxZoom}
|
||||||
|
onChange={maxZoom => this.props.onChange({
|
||||||
|
...this.props.source,
|
||||||
|
maxZoom: maxZoom
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,15 +68,18 @@ class TileURLSourceEditor extends React.Component {
|
||||||
|
|
||||||
class GeoJSONSourceEditor extends React.Component {
|
class GeoJSONSourceEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data: React.PropTypes.string.isRequired,
|
source: React.PropTypes.object.isRequired,
|
||||||
onChange: React.PropTypes.func,
|
onChange: React.PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"GeoJSON Data"}>
|
return <InputBlock label={"GeoJSON Data"}>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={this.props.data}
|
value={this.props.source.data}
|
||||||
onChange={this.props.onChange}
|
onChange={data => this.props.onChange({
|
||||||
|
...this.props.source,
|
||||||
|
data: data
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
}
|
}
|
||||||
|
@ -80,11 +93,14 @@ class SourceTypeEditor extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const source = this.props.source
|
const commonProps = {
|
||||||
|
source: this.props.source,
|
||||||
|
onChange: this.props.onChange,
|
||||||
|
}
|
||||||
switch(this.props.mode) {
|
switch(this.props.mode) {
|
||||||
case 'geojson': return <GeoJSONSourceEditor data={source.data || 'http://localhost:3000/mygeojson.json'} />
|
case 'geojson': return <GeoJSONSourceEditor {...commonProps} />
|
||||||
case 'tilejson': return <TileJSONSourceEditor url={source.url || 'http://localhost:3000/tiles.json'}/>
|
case 'tilejson': return <TileJSONSourceEditor {...commonProps} />
|
||||||
case 'tilexyz': return <TileURLSourceEditor tiles={source.tiles || ['http://localhost:3000/{x}/{y}/{z}.pbf']} minZoom={source.minZoom || 0} maxZoom={source.maxZoom || 14}/>
|
case 'tilexyz': return <TileURLSourceEditor {...commonProps} />
|
||||||
default: return null
|
default: return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
[
|
{
|
||||||
{
|
"mapbox-streets": {
|
||||||
"id": "mapbox-streets",
|
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"url": "mapbox://mapbox.mapbox-streets-v7",
|
"url": "mapbox://mapbox.mapbox-streets-v7",
|
||||||
"title": "Mapbox Streets"
|
"title": "Mapbox Streets"
|
||||||
},
|
},
|
||||||
{
|
"tilezen": {
|
||||||
"id": "tilezen",
|
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"tiles": [
|
"tiles": [
|
||||||
"http://tile.mapzen.com/mapzen/vector/v1/{layers}/{z}/{x}/{y}.pbf?api_key=mapzen-RVcyVL7"
|
"http://tile.mapzen.com/mapzen/vector/v1/{layers}/{z}/{x}/{y}.pbf?api_key=mapzen-RVcyVL7"
|
||||||
|
@ -15,16 +13,14 @@
|
||||||
"maxZoom": 15,
|
"maxZoom": 15,
|
||||||
"title": "Mapzen Vector Tile Service"
|
"title": "Mapzen Vector Tile Service"
|
||||||
},
|
},
|
||||||
{
|
"openmaptiles": {
|
||||||
"id": "openmaptiles",
|
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"url": "https://free.tilehosting.com/data/v3.json?key=25ItXg7aI5wurYDtttD",
|
"url": "https://free.tilehosting.com/data/v3.json?key=25ItXg7aI5wurYDtttD",
|
||||||
"title": "OpenMapTiles CDN"
|
"title": "OpenMapTiles CDN"
|
||||||
},
|
},
|
||||||
{
|
"swissnames-landscape": {
|
||||||
"id": "swissnames-landscape",
|
|
||||||
"type": "geojson",
|
"type": "geojson",
|
||||||
"data": "http://swissnames.lukasmartinelli.ch/data/landscape.geojson",
|
"data": "http://swissnames.lukasmartinelli.ch/data/landscape.geojson",
|
||||||
"title": "Landscape Names GeoJSON"
|
"title": "Landscape Names GeoJSON"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
Loading…
Reference in a new issue