diff --git a/.gitignore b/.gitignore
index 9908478..a399b1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
# Logs
logs
*.log
+*.swp
# Runtime data
pids
diff --git a/src/components/App.jsx b/src/components/App.jsx
index 6e11eed..1d287e1 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -2,6 +2,7 @@ import React from 'react'
import { saveAs } from 'file-saver'
import Mousetrap from 'mousetrap'
+import InspectionMap from './map/InspectionMap'
import MapboxGlMap from './map/MapboxGlMap'
import OpenLayers3Map from './map/OpenLayers3Map'
import LayerList from './layers/LayerList'
@@ -121,8 +122,8 @@ export default class App extends React.Component {
const mapProps = {
mapStyle: this.state.mapStyle,
accessToken: this.state.accessToken,
- onMapLoaded: (map) => {
- this.layerWatcher.map = map
+ onDataChange: (e) => {
+ this.layerWatcher.analyzeMap(e.map)
}
}
@@ -132,6 +133,8 @@ export default class App extends React.Component {
// Check if OL3 code has been loaded?
if(renderer === 'ol3') {
return
+ } else if(renderer === 'inspection') {
+ return
} else {
return
}
diff --git a/src/components/map/InspectionMap.jsx b/src/components/map/InspectionMap.jsx
new file mode 100644
index 0000000..365ebc2
--- /dev/null
+++ b/src/components/map/InspectionMap.jsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import MapboxGl from 'mapbox-gl'
+import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
+import colors from '../../config/colors'
+import style from '../../libs/style'
+import { generateColoredLayers } from '../../libs/stylegen'
+
+function convertInspectStyle(mapStyle, sources) {
+ const newStyle = {
+ ...mapStyle,
+ layers: [
+ {
+ "id": "background",
+ "type": "background",
+ "paint": {
+ "background-color": colors.black,
+ }
+ },
+ ...generateColoredLayers(sources),
+ ]
+ }
+ return newStyle
+}
+
+export default class InspectionMap extends React.Component {
+ static propTypes = {
+ onDataChange: React.PropTypes.func,
+ sources: React.PropTypes.object,
+ originalStyle: React.PropTypes.object,
+ }
+
+ static defaultProps = {
+ onMapLoaded: () => {},
+ onTileLoaded: () => {},
+ }
+
+ constructor(props) {
+ super(props)
+ this.state = { map: null }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if(!this.state.map) return
+
+ this.state.map.setStyle(convertInspectStyle(nextProps.mapStyle, this.props.sources), { diff: true})
+ }
+
+ componentDidMount() {
+ MapboxGl.accessToken = this.props.accessToken
+
+ const map = new MapboxGl.Map({
+ container: this.container,
+ style: convertInspectStyle(this.props.mapStyle, this.props.sources),
+ })
+
+ map.on("style.load", () => {
+ this.setState({ map });
+ })
+
+ map.on("data", e => {
+ if(e.dataType !== 'tile') return
+ this.props.onDataChange({
+ map: this.state.map
+ })
+ })
+ }
+
+ render() {
+ return
this.container = x}
+ style={{
+ position: "fixed",
+ top: 0,
+ bottom: 0,
+ height: "100%",
+ width: "100%",
+ }}>
+ }
+}
diff --git a/src/components/map/Map.jsx b/src/components/map/Map.jsx
deleted file mode 100644
index 83387d4..0000000
--- a/src/components/map/Map.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react'
-
-export default class Map extends React.Component {
- static propTypes = {
- mapStyle: React.PropTypes.object.isRequired,
- accessToken: React.PropTypes.string,
- }
-
- render() {
- return this.container = x}
- style={{
- position: "fixed",
- top: 0,
- bottom: 0,
- height: "100%",
- width: "100%",
- }}>
- }
-}
diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx
index 5eaf3f4..86055a2 100644
--- a/src/components/map/MapboxGlMap.jsx
+++ b/src/components/map/MapboxGlMap.jsx
@@ -2,22 +2,25 @@ import React from 'react'
import MapboxGl from 'mapbox-gl'
import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
-import Map from './Map.jsx'
import style from '../../libs/style.js'
-export default class MapboxGlMap extends Map {
+export default class MapboxGlMap extends React.Component {
static propTypes = {
- onMapLoaded: React.PropTypes.func,
+ onDataChange: React.PropTypes.func,
+ mapStyle: React.PropTypes.object.isRequired,
+ accessToken: React.PropTypes.string,
}
static defaultProps = {
- onMapLoaded: () => {}
+ onMapLoaded: () => {},
+ onDataChange: () => {},
}
constructor(props) {
super(props)
this.state = { map: null }
}
+
componentWillReceiveProps(nextProps) {
if(!this.state.map) return
@@ -32,11 +35,29 @@ export default class MapboxGlMap extends Map {
const map = new MapboxGl.Map({
container: this.container,
style: this.props.mapStyle,
- });
+ })
- map.on("style.load", (...args) => {
- this.props.onMapLoaded(map)
+ map.on("style.load", () => {
this.setState({ map });
- });
+ })
+
+ map.on("data", e => {
+ if(e.dataType !== 'tile') return
+ this.props.onDataChange({
+ map: this.state.map
+ })
+ })
+ }
+
+ render() {
+ return this.container = x}
+ style={{
+ position: "fixed",
+ top: 0,
+ bottom: 0,
+ height: "100%",
+ width: "100%",
+ }}>
}
}
diff --git a/src/components/map/OpenLayers3Map.jsx b/src/components/map/OpenLayers3Map.jsx
index bba2e3b..61b52bc 100644
--- a/src/components/map/OpenLayers3Map.jsx
+++ b/src/components/map/OpenLayers3Map.jsx
@@ -1,10 +1,16 @@
import React from 'react'
-import Map from './Map'
import style from '../../libs/style.js'
-class OpenLayers3Map extends Map {
- constructor(props) {
- super(props)
+class OpenLayers3Map extends React.Component {
+ static propTypes = {
+ onDataChange: React.PropTypes.func,
+ mapStyle: React.PropTypes.object.isRequired,
+ accessToken: React.PropTypes.string,
+ }
+
+ static defaultProps = {
+ onMapLoaded: () => {},
+ onDataChange: () => {},
}
componentWillReceiveProps(nextProps) {
@@ -63,6 +69,18 @@ class OpenLayers3Map extends Map {
this.setState({ map });
})
}
+
+ render() {
+ return this.container = x}
+ style={{
+ position: "fixed",
+ top: 0,
+ bottom: 0,
+ height: "100%",
+ width: "100%",
+ }}>
+ }
}
export default OpenLayers3Map
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx
index 937e51a..54fb043 100644
--- a/src/components/modals/SettingsModal.jsx
+++ b/src/components/modals/SettingsModal.jsx
@@ -72,7 +72,8 @@ class SettingsModal extends React.Component {
{
- if(e.dataType !== 'tile') return
-
+ analyzeMap(map) {
+ Object.keys(map.style.sourceCaches).forEach(sourceId => {
//NOTE: This heavily depends on the internal API of Mapbox GL
//so this breaks between Mapbox GL JS releases
- this._sources[e.sourceId] = e.style.sourceCaches[e.sourceId]._source.vectorLayerIds
- this.throttledAnalyzeVectorLayerFields()
+ this._sources[sourceId] = map.style.sourceCaches[sourceId]._source.vectorLayerIds
})
+ this.throttledAnalyzeVectorLayerFields(map)
}
- analyzeVectorLayerFields() {
+ analyzeVectorLayerFields(map) {
Object.keys(this._sources).forEach(sourceId => {
this._sources[sourceId].forEach(vectorLayerId => {
const knownProperties = this._vectorLayers[vectorLayerId] || {}
const params = { sourceLayer: vectorLayerId }
- this._map.querySourceFeatures(sourceId, params).forEach(feature => {
+ map.querySourceFeatures(sourceId, params).forEach(feature => {
Object.keys(feature.properties).forEach(propertyName => {
const knownPropertyValues = knownProperties[propertyName] || {}
knownPropertyValues[feature.properties[propertyName]] = {}
diff --git a/src/libs/stylegen.js b/src/libs/stylegen.js
new file mode 100644
index 0000000..fccbdf0
--- /dev/null
+++ b/src/libs/stylegen.js
@@ -0,0 +1,88 @@
+import randomColor from 'randomcolor'
+import Color from 'color'
+
+function assignVectorLayerColor(layerId) {
+ let hue = null
+ if(/water|ocean|lake|sea|river/.test(layerId)) {
+ hue = 'blue'
+ }
+
+ if(/road|highway|transport/.test(layerId)) {
+ hue = 'orange'
+ }
+
+ if(/building/.test(layerId)) {
+ hue = 'yellow'
+ }
+
+ if(/wood|forest|park|landcover|landuse/.test(layerId)) {
+ hue = 'green'
+ }
+
+ return randomColor({
+ luminosity: 'bright',
+ hue: hue,
+ seed: layerId,
+ })
+}
+
+function circleLayer(source, vectorLayer, color) {
+ return {
+ id: vectorLayer + Math.random(),
+ source: source,
+ 'source-layer': vectorLayer,
+ interactive: true,
+ type: 'circle',
+ paint: {
+ 'circle-color': color,
+ 'circle-radius': 2,
+ },
+ filter: ["==", "$type", "Point"]
+ }
+}
+
+function polygonLayer(source, vectorLayer, color) {
+ return {
+ id: vectorLayer + Math.random(),
+ source: source,
+ 'source-layer': vectorLayer,
+ interactive: true,
+ type: 'fill',
+ paint: {
+ 'fill-color': Color(color).alpha(0.15).string(),
+ 'fill-antialias': true,
+ 'fill-outline-color': color,
+ },
+ filter: ["==", "$type", "Polygon"]
+ }
+}
+
+function lineLayer(source, vectorLayer, color) {
+ return {
+ id: vectorLayer + Math.random(),
+ source: source,
+ 'source-layer': vectorLayer,
+ interactive: true,
+ layout: {
+ 'line-join': 'round',
+ 'line-cap': 'round'
+ },
+ type: 'line',
+ paint: {'line-color': color},
+ filter: ["==", "$type", "LineString"]
+ }
+}
+
+export function generateColoredLayers(sources) {
+ const styleLayers = []
+ Object.keys(sources).forEach(sourceId => {
+ const layers = sources[sourceId]
+ layers.forEach(layerId => {
+ const color = assignVectorLayerColor(layerId)
+ styleLayers.push(circleLayer(sourceId, layerId, color))
+ styleLayers.push(lineLayer(sourceId, layerId, color))
+ styleLayers.push(polygonLayer(sourceId, layerId, color))
+ })
+ })
+ return styleLayers
+}