From def5ebb58736f3d4caf0aba445a101e7d09b2fd7 Mon Sep 17 00:00:00 2001 From: Lukas Martinelli Date: Sat, 24 Dec 2016 15:14:31 +0100 Subject: [PATCH] Show feature table on hover --- src/components/App.jsx | 7 +++- src/components/map/FeaturePropertyTable.jsx | 42 +++++++++++++++++++++ src/components/map/InspectionMap.jsx | 42 +++++++++++++++++++++ src/components/map/MapboxGlMap.jsx | 7 +++- 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/components/map/FeaturePropertyTable.jsx diff --git a/src/components/App.jsx b/src/components/App.jsx index 1d287e14..668862d6 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -124,7 +124,12 @@ export default class App extends React.Component { accessToken: this.state.accessToken, onDataChange: (e) => { this.layerWatcher.analyzeMap(e.map) - } + }, + //TODO: This would actually belong to the layout component + style:{ + top: 40, + //left: 500, + } } const metadata = this.state.mapStyle.metadata || {} diff --git a/src/components/map/FeaturePropertyTable.jsx b/src/components/map/FeaturePropertyTable.jsx new file mode 100644 index 00000000..e88184f9 --- /dev/null +++ b/src/components/map/FeaturePropertyTable.jsx @@ -0,0 +1,42 @@ +import React from 'react' + + +function items(object) { + let arr = []; + for (var key in object) { + arr.push({ key, value: object[key] }); + } + return arr; +} + + +function displayValue(value) { + if (typeof value === "undefined" || value === null) return value; + if (value instanceof Date) return value.toLocaleString(); + if (typeof value === "object" || + typeof value === "number" || + typeof value === "string") return value.toString(); + return value; +} + +class FeaturePropertyTable extends React.Component { + render() { + const rows = items(this.props.feature.properties) + .map(i => { + return + {i.key} + {displayValue(i.value)} + ; + }); + return + {rows} +
;; + } +} + + +export default FeaturePropertyTable diff --git a/src/components/map/InspectionMap.jsx b/src/components/map/InspectionMap.jsx index 365ebc29..c382129f 100644 --- a/src/components/map/InspectionMap.jsx +++ b/src/components/map/InspectionMap.jsx @@ -1,9 +1,12 @@ import React from 'react' +import ReactDOM from 'react-dom' 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 FeaturePropertyTable from './FeaturePropertyTable' import { generateColoredLayers } from '../../libs/stylegen' +import 'mapbox-gl/dist/mapbox-gl.css' function convertInspectStyle(mapStyle, sources) { const newStyle = { @@ -22,11 +25,18 @@ function convertInspectStyle(mapStyle, sources) { return newStyle } +function renderFeaturePropertyTable(feature) { + 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, + style: React.PropTypes.object, } static defaultProps = { @@ -53,6 +63,9 @@ export default class InspectionMap extends React.Component { style: convertInspectStyle(this.props.mapStyle, this.props.sources), }) + const nav = new MapboxGl.NavigationControl(); + map.addControl(nav, 'top-right'); + map.on("style.load", () => { this.setState({ map }); }) @@ -63,6 +76,34 @@ export default class InspectionMap extends React.Component { map: this.state.map }) }) + + map.on('click', this.displayPopup.bind(this)); + } + + displayPopup(e) { + const features = this.state.map.queryRenderedFeatures(e.point, { + layers: this.layers + }); + + if (!features.length) { + return + } + const feature = features[0] + +/* + const clickEvent = e.originalEvent + const x = clickEvent.pageX + const y = clickEvent.pageY + + console.log(e) + console.log('Show feature', feature) +*/ + // Populate the popup and set its coordinates + // based on the feature found. + const popup = new MapboxGl.Popup() + .setLngLat(e.lngLat) + .setHTML(renderFeaturePropertyTable(feature)) + .addTo(this.state.map) } render() { @@ -74,6 +115,7 @@ export default class InspectionMap extends React.Component { bottom: 0, height: "100%", width: "100%", + ...this.props.style, }}> } } diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx index 86055a22..9ea24dd7 100644 --- a/src/components/map/MapboxGlMap.jsx +++ b/src/components/map/MapboxGlMap.jsx @@ -1,14 +1,15 @@ import React from 'react' import MapboxGl from 'mapbox-gl' import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color' - import style from '../../libs/style.js' +import 'mapbox-gl/dist/mapbox-gl.css' 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, } static defaultProps = { @@ -37,6 +38,9 @@ export default class MapboxGlMap extends React.Component { style: this.props.mapStyle, }) + const nav = new MapboxGl.NavigationControl(); + map.addControl(nav, 'top-right'); + map.on("style.load", () => { this.setState({ map }); }) @@ -58,6 +62,7 @@ export default class MapboxGlMap extends React.Component { bottom: 0, height: "100%", width: "100%", + ...this.props.style, }}> } }