{feature.layer['source-layer']}
{renderProperties(feature)}
diff --git a/src/components/map/InspectionMap.jsx b/src/components/map/InspectionMap.jsx
deleted file mode 100644
index d672698..0000000
--- a/src/components/map/InspectionMap.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import React from 'react'
-import ReactDOM from 'react-dom'
-import MapboxGl from 'mapbox-gl/dist/mapbox-gl.js'
-import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
-import colors from '../../config/colors'
-import style from '../../libs/style'
-import FeaturePropertyPopup from './FeaturePropertyPopup'
-import { colorHighlightedLayer, generateColoredLayers } from '../../libs/stylegen'
-import 'mapbox-gl/dist/mapbox-gl.css'
-import '../../mapboxgl.css'
-
-function convertInspectStyle(mapStyle, sources, highlightedLayer) {
- const coloredLayers = generateColoredLayers(sources)
-
- const layer = colorHighlightedLayer(highlightedLayer)
- if(layer) {
- coloredLayers.push(layer)
- }
-
- const newStyle = {
- ...mapStyle,
- layers: [
- {
- "id": "background",
- "type": "background",
- "paint": {
- "background-color": colors.black,
- }
- },
- ...coloredLayers,
- ]
- }
- return newStyle
-}
-
-function renderPopup(features) {
- var mountNode = document.createElement('div');
- ReactDOM.render(
, mountNode)
- return mountNode.innerHTML;
-}
-
-export default class InspectionMap extends React.Component {
- static propTypes = {
- onDataChange: React.PropTypes.func,
- sources: React.PropTypes.object,
- originalStyle: React.PropTypes.object,
- highlightedLayer: React.PropTypes.object,
- style: 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, nextProps.highlightedLayer), { diff: true})
- }
-
- componentDidMount() {
- MapboxGl.accessToken = this.props.accessToken
-
- const map = new MapboxGl.Map({
- container: this.container,
- style: convertInspectStyle(this.props.mapStyle, this.props.sources, this.props.highlightedLayer),
- hash: true,
- })
-
- const nav = new MapboxGl.NavigationControl();
- map.addControl(nav, 'top-right');
-
- map.on("style.load", () => {
- this.setState({ map });
- })
-
- map.on("data", e => {
- if(e.dataType !== 'tile') return
- this.props.onDataChange({
- map: this.state.map
- })
- })
-
- map.on('click', this.displayPopup.bind(this))
- map.on('mousemove', function(e) {
- var features = map.queryRenderedFeatures(e.point, { layers: this.layers })
- map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''
- })
- }
-
- displayPopup(e) {
- const features = this.state.map.queryRenderedFeatures(e.point, {
- layers: this.layers
- });
-
- if (!features.length) {
- return
- }
-
- // Populate the popup and set its coordinates
- // based on the feature found.
- const popup = new MapboxGl.Popup()
- .setLngLat(e.lngLat)
- .setHTML(renderPopup(features))
- .addTo(this.state.map)
- }
-
- render() {
- return
this.container = x}
- style={{
- position: "fixed",
- top: 0,
- bottom: 0,
- height: "100%",
- width: "100%",
- ...this.props.style,
- }}>
- }
-}
diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx
index 0a2eef8..dc94896 100644
--- a/src/components/map/MapboxGlMap.jsx
+++ b/src/components/map/MapboxGlMap.jsx
@@ -1,24 +1,57 @@
import React from 'react'
import ReactDOM from 'react-dom'
import MapboxGl from 'mapbox-gl/dist/mapbox-gl.js'
+import MapboxInspect from 'mapbox-gl-inspect'
import FeatureLayerTable from './FeatureLayerTable'
+import FeaturePropertyPopup from './FeaturePropertyPopup'
import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
+import colors from '../../config/colors'
import style from '../../libs/style.js'
+import { colorHighlightedLayer } from '../../libs/highlight'
import 'mapbox-gl/dist/mapbox-gl.css'
import '../../mapboxgl.css'
-function renderPopup(features) {
+function renderLayerPopup(features) {
var mountNode = document.createElement('div');
ReactDOM.render(
, mountNode)
return mountNode.innerHTML;
}
+function renderPropertyPopup(features) {
+ var mountNode = document.createElement('div');
+ ReactDOM.render(
, mountNode)
+ return mountNode.innerHTML;
+}
+
+function buildInspectStyle(originalMapStyle, coloredLayers, highlightedLayer) {
+ const backgroundLayer = {
+ "id": "background",
+ "type": "background",
+ "paint": {
+ "background-color": colors.black,
+ }
+ }
+
+ const layer = colorHighlightedLayer(highlightedLayer)
+ if(layer) {
+ coloredLayers.push(layer)
+ }
+
+ const inspectStyle = {
+ ...originalMapStyle,
+ layers: [backgroundLayer].concat(coloredLayers)
+ }
+ return inspectStyle
+}
+
export default class MapboxGlMap extends React.Component {
static propTypes = {
onDataChange: React.PropTypes.func,
mapStyle: React.PropTypes.object.isRequired,
accessToken: React.PropTypes.string,
style: React.PropTypes.object,
+ inspectModeEnabled: React.PropTypes.bool.isRequired,
+ highlightedLayer: React.PropTypes.object,
}
static defaultProps = {
@@ -31,6 +64,7 @@ export default class MapboxGlMap extends React.Component {
MapboxGl.accessToken = props.accessToken
this.state = {
map: null,
+ inspect: null,
isPopupOpen: false,
popupX: 0,
popupY: 0,
@@ -39,12 +73,22 @@ export default class MapboxGlMap extends React.Component {
componentWillReceiveProps(nextProps) {
MapboxGl.accessToken = nextProps.accessToken
-
if(!this.state.map) return
- //Mapbox GL now does diffing natively so we don't need to calculate
- //the necessary operations ourselves!
- this.state.map.setStyle(nextProps.mapStyle, { diff: true})
+ if(!nextProps.inspectModeEnabled) {
+ //Mapbox GL now does diffing natively so we don't need to calculate
+ //the necessary operations ourselves!
+ this.state.map.setStyle(nextProps.mapStyle, { diff: true})
+ }
+ }
+
+ componentDidUpdate(prevProps) {
+ if(this.props.inspectModeEnabled !== prevProps.inspectModeEnabled) {
+ this.state.inspect.toggleInspector()
+ }
+ if(this.props.inspectModeEnabled) {
+ this.state.inspect.render()
+ }
}
componentDidMount() {
@@ -54,11 +98,29 @@ export default class MapboxGlMap extends React.Component {
hash: true,
})
- const nav = new MapboxGl.NavigationControl();
- map.addControl(nav, 'top-right');
+ const nav = new MapboxGl.NavigationControl();
+ map.addControl(nav, 'top-right');
+
+ const inspect = new MapboxInspect({
+ popup: new MapboxGl.Popup({
+ closeButton: false,
+ closeOnClick: false
+ }),
+ showMapPopup: true,
+ showInspectButton: false,
+ buildInspectStyle: (originalMapStyle, coloredLayers) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer),
+ renderPopup: features => {
+ if(this.props.inspectModeEnabled) {
+ return renderPropertyPopup(features)
+ } else {
+ return renderLayerPopup(features)
+ }
+ }
+ })
+ map.addControl(inspect)
map.on("style.load", () => {
- this.setState({ map });
+ this.setState({ map, inspect });
})
map.on("data", e => {
@@ -67,24 +129,6 @@ export default class MapboxGlMap extends React.Component {
map: this.state.map
})
})
-
- map.on('click', this.displayPopup.bind(this));
- map.on('mousemove', function(e) {
- var features = map.queryRenderedFeatures(e.point, { layers: this.layers })
- map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''
- })
- }
-
- displayPopup(e) {
- const features = this.state.map.queryRenderedFeatures(e.point, {
- layers: this.layers
- });
-
- if(features.length < 1) return
- const popup = new MapboxGl.Popup()
- .setLngLat(e.lngLat)
- .setHTML(renderPopup(features))
- .addTo(this.state.map)
}
render() {
@@ -93,7 +137,7 @@ export default class MapboxGlMap extends React.Component {
style={{
position: "fixed",
top: 0,
- left: 550,
+ right: 0,
bottom: 0,
height: "100%",
width: "75%",
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx
index c1f9664..ff8f149 100644
--- a/src/components/modals/SettingsModal.jsx
+++ b/src/components/modals/SettingsModal.jsx
@@ -83,7 +83,6 @@ class SettingsModal extends React.Component {
options={[
['mbgljs', 'MapboxGL JS'],
['ol3', 'Open Layers 3'],
- ['inspection', 'Inspection Mode'],
]}
value={metadata['maputnik:renderer'] || 'mbgljs'}
onChange={this.changeMetadataProperty.bind(this, 'maputnik:renderer')}
diff --git a/src/libs/highlight.js b/src/libs/highlight.js
new file mode 100644
index 0000000..5e050ef
--- /dev/null
+++ b/src/libs/highlight.js
@@ -0,0 +1,36 @@
+import randomColor from 'randomcolor'
+import Color from 'color'
+
+import stylegen from 'mapbox-gl-inspect/lib/stylegen'
+import colors from 'mapbox-gl-inspect/lib/colors'
+
+export function colorHighlightedLayer(layer) {
+ if(!layer || layer.type === 'background' || layer.type === 'raster') return null
+
+ function changeLayer(l) {
+ if(layer.filter) {
+ l.filter = layer.filter
+ } else {
+ delete l['filter']
+ }
+ l.id = l.id + '_highlight'
+ return l
+ }
+
+ const color = colors.brightColor(layer.id, 1)
+ const layers = []
+
+ if(layer.type === "fill" || layer.type === 'fill-extrusion') {
+ return changeLayer(stylegen.polygonLayer(color, color, layer.source, layer['source-layer']))
+ }
+
+ if(layer.type === "symbol" || layer.type === 'circle') {
+ return changeLayer(stylegen.circleLayer(color, layer.source, layer['source-layer']))
+ }
+
+ if(layer.type === 'line') {
+ return changeLayer(stylegen.lineLayer(color, layer.source, layer['source-layer']))
+ }
+
+ return null
+}
diff --git a/src/libs/stylegen.js b/src/libs/stylegen.js
index f4decc5..e69de29 100644
--- a/src/libs/stylegen.js
+++ b/src/libs/stylegen.js
@@ -1,141 +0,0 @@
-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) {
- const layer = {
- id: `${source}_${vectorLayer}_circle`,
- source: source,
- type: 'circle',
- paint: {
- 'circle-color': color,
- 'circle-radius': 2,
- },
- filter: ["==", "$type", "Point"]
- }
- if(vectorLayer) {
- layer['source-layer'] = vectorLayer
- }
- return layer
-}
-
-function polygonLayer(source, vectorLayer, color, fillColor) {
- const layer = {
- id: `${source}_${vectorLayer}_polygon`,
- source: source,
- type: 'fill',
- paint: {
- 'fill-color': fillColor,
- 'fill-antialias': true,
- 'fill-outline-color': color,
- },
- filter: ["==", "$type", "Polygon"]
- }
- if(vectorLayer) {
- layer['source-layer'] = vectorLayer
- }
- return layer
-}
-
-function lineLayer(source, vectorLayer, color) {
- const layer = {
- id: `${source}_${vectorLayer}_line`,
- source: source,
- layout: {
- 'line-join': 'round',
- 'line-cap': 'round'
- },
- type: 'line',
- paint: {
- 'line-color': color,
- },
- filter: ["==", "$type", "LineString"]
- }
- if(vectorLayer) {
- layer['source-layer'] = vectorLayer
- }
- return layer
-}
-
-export function colorHighlightedLayer(layer) {
- if(!layer || layer.type === 'background' || layer.type === 'raster') return null
-
- function changeLayer(l) {
- if(layer.filter) {
- l.filter = layer.filter
- } else {
- delete l['filter']
- }
- l.id = l.id + '_highlight'
- return l
- }
-
- const color = assignVectorLayerColor(layer.id)
- const layers = []
-
- if(layer.type === "fill" || layer.type === 'fill-extrusion') {
- return changeLayer(polygonLayer(layer.source, layer['source-layer'], color, Color(color).alpha(0.2).string()))
- }
-
- if(layer.type === "symbol" || layer.type === 'circle') {
- return changeLayer(circleLayer(layer.source, layer['source-layer'], color))
- }
-
- if(layer.type === 'line') {
- return changeLayer(lineLayer(layer.source, layer['source-layer'], color))
- }
-
- return null
-}
-
-export function generateColoredLayers(sources) {
- const polyLayers = []
- const circleLayers = []
- const lineLayers = []
-
- Object.keys(sources).forEach(sourceId => {
- const layers = sources[sourceId]
-
- // Deal with GeoJSON sources that do not have any source layers
- if(!layers) {
- const color = Color(assignVectorLayerColor(sourceId))
- circleLayers.push(circleLayer(sourceId, null, color.alpha(0.3).string()))
- lineLayers.push(lineLayer(sourceId, null, color.alpha(0.3).string()))
- polyLayers.push(polygonLayer(sourceId, null, color.alpha(0.2).string(), color.alpha(0.05).string()))
- return
- }
-
- layers.forEach(layerId => {
- const color = Color(assignVectorLayerColor(layerId))
- circleLayers.push(circleLayer(sourceId, layerId, color.alpha(0.3).string()))
- lineLayers.push(lineLayer(sourceId, layerId, color.alpha(0.3).string()))
- polyLayers.push(polygonLayer(sourceId, layerId, color.alpha(0.2).string(), color.alpha(0.05).string()))
- })
- })
-
- return polyLayers.concat(lineLayers).concat(circleLayers)
-}
diff --git a/src/mapboxgl.css b/src/mapboxgl.css
index b8e3dd9..5038759 100644
--- a/src/mapboxgl.css
+++ b/src/mapboxgl.css
@@ -49,3 +49,12 @@
.mapboxgl-ctrl-icon.mapboxgl-ctrl-compass > span.arrow {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%0A%09%3Cpolygon%20fill%3D%27%238e8e8e%27%20points%3D%276%2C9%2010%2C1%2014%2C9%27%2F%3E%0A%09%3Cpolygon%20fill%3D%27%23CCCCCC%27%20points%3D%276%2C11%2010%2C19%2014%2C11%20%27%2F%3E%0A%3C%2Fsvg%3E")
}
+
+.mapboxgl-ctrl-inspect {
+ background-image: url('data:image/svg+xml;charset=utf8,