From efe42021f14933df90143b0b81611a1f07ad9fe5 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 29 May 2019 17:37:55 +0100 Subject: [PATCH 1/7] Some more openlayers improvments as well as initial work for projection support --- package.json | 1 + src/components/App.jsx | 30 ++++- src/components/Toolbar.jsx | 1 + src/components/map/FeatureLayerPopup.jsx | 17 ++- src/components/map/OpenLayersMap.jsx | 152 ++++++++++++++++++++--- src/components/modals/DebugModal.js | 13 +- src/components/modals/SettingsModal.jsx | 15 +++ src/styles/_map.scss | 62 ++++++++- src/styles/_popup.scss | 2 +- 9 files changed, 267 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 6fe3fd18..7591efdd 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "maputnik-design": "github:maputnik/design", "ol": "^6.0.0-beta.8", "ol-mapbox-style": "^5.0.0-beta.2", + "proj4": "^2.5.0", "prop-types": "^15.6.2", "react": "^16.5.2", "react-aria-menubutton": "^6.0.1", diff --git a/src/components/App.jsx b/src/components/App.jsx index b24cb1b7..2c088cdd 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -218,6 +218,11 @@ export default class App extends React.Component { showCollisionBoxes: false, showOverdrawInspector: false, }, + openlayersDebugOptions: { + // TODO: For future projection work + // enableProjections: true, + debugToolbox: true, + }, } this.layerWatcher = new LayerWatcher({ @@ -478,10 +483,16 @@ export default class App extends React.Component { return metadata['maputnik:renderer'] || 'mbgljs'; } + getProjectionCode () { + const metadata = this.state.mapStyle.metadata || {}; + return this.state.openlayersDebugOptions.enableProjections ? metadata['maputnik:projection'] : "EPSG:3857"; + } + mapRenderer() { + const metadata = this.state.mapStyle.metadata || {}; + const mapProps = { mapStyle: style.replaceAccessTokens(this.state.mapStyle, {allowFallback: true}), - options: this.state.mapboxGlDebugOptions, onDataChange: (e) => { this.layerWatcher.analyzeMap(e.map) this.fetchSources(); @@ -496,9 +507,13 @@ export default class App extends React.Component { if(renderer === 'ol') { mapElement = } else { mapElement = @@ -540,6 +555,15 @@ export default class App extends React.Component { this.setModal(modalName, !this.state.isOpen[modalName]); } + onChangeOpenlayersDebug = (key, value) => { + this.setState({ + openlayersDebugOptions: { + ...this.state.openlayersDebugOptions, + [key]: value, + } + }); + } + onChangeMaboxGlDebug = (key, value) => { this.setState({ mapboxGlDebugOptions: { @@ -555,6 +579,7 @@ export default class App extends React.Component { const metadata = this.state.mapStyle.metadata || {} const toolbar = @@ -617,6 +644,7 @@ export default class App extends React.Component { onStyleChanged={this.onStyleChanged} isOpen={this.state.isOpen.settings} onOpenToggle={this.toggleModal.bind(this, 'settings')} + openlayersDebugOptions={this.state.openlayersDebugOptions} /> - + {feature.layer.type && + + } {feature.layer.id} {feature.counter && × {feature.counter}} diff --git a/src/components/map/OpenLayersMap.jsx b/src/components/map/OpenLayersMap.jsx index 9cb5ee24..f70bd2fa 100644 --- a/src/components/map/OpenLayersMap.jsx +++ b/src/components/map/OpenLayersMap.jsx @@ -3,10 +3,32 @@ import {throttle} from 'lodash'; import PropTypes from 'prop-types' import { loadJSON } from '../../libs/urlopen' +import FeatureLayerPopup from './FeatureLayerPopup'; + import 'ol/ol.css' import {apply} from 'ol-mapbox-style'; -import {Map, View} from 'ol'; +import {Map, View, Proj, Overlay} from 'ol'; +import proj4 from 'proj4'; +import {register} from 'ol/proj/proj4'; +import {get as getProjection, toLonLat} from 'ol/proj'; +import {toStringHDMS} from 'ol/coordinate'; + +// Register some projections... +proj4.defs('EPSG:3031', '+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs '); +register(proj4); + + +function renderCoords (coords) { + if (!coords || coords.length < 2) { + return null; + } + else { + return + {coords.map((coord) => String(coord).padStart(7, "\u00A0")).join(', ')} + + } +} export default class OpenLayersMap extends React.Component { static propTypes = { @@ -14,15 +36,23 @@ export default class OpenLayersMap extends React.Component { mapStyle: PropTypes.object.isRequired, accessToken: PropTypes.string, style: PropTypes.object, + onLayerSelect: PropTypes.func.isRequired, } static defaultProps = { onMapLoaded: () => {}, onDataChange: () => {}, + onLayerSelect: () => {}, } constructor(props) { super(props); + this.state = { + zoom: 0, + rotation: 0, + cursor: [], + center: [], + }; this.updateStyle = throttle(this._updateStyle.bind(this), 200); } @@ -34,33 +64,125 @@ export default class OpenLayersMap extends React.Component { apply(this.map, newMapStyle); } - componentDidUpdate() { - this.updateStyle(this.props.mapStyle); + updateProjection () { + this.projection = getProjection(this.props.projectionCode || "EPSG:3857"); + } + + componentDidUpdate(prevProps) { + if (this.props.projectionCode !== prevProps.projectionCode) { + this.updateProjection(); + this.map.setView( + new View({ + projection: this.projection, + zoom: 1, + center: [180, -90] + }) + ); + } + if (this.props.mapStyle !== prevProps.mapStyle) { + this.updateStyle(this.props.mapStyle); + } } componentDidMount() { - this.updateStyle(this.props.mapStyle); + this.overlay = new Overlay({ + element: this.popupContainer, + autoPan: true, + autoPanAnimation: { + duration: 250 + } + }); + + this.updateProjection(); const map = new Map({ target: this.container, - layers: [], + overlays: [this.overlay], view: new View({ - zoom: 2, - center: [52.5, -78.4] + projection: this.projection, + zoom: 1, + center: [180, -90], + }) + }); + + map.on('pointermove', (evt) => { + var coords = toLonLat(evt.coordinate, this.projection); + this.setState({ + cursor: [ + coords[0].toFixed(2), + coords[1].toFixed(2) + ] }) }) + + map.on('postrender', (evt) => { + const center = toLonLat(map.getView().getCenter(), this.projection); + this.setState({ + center: [ + center[0].toFixed(2), + center[1].toFixed(2), + ], + rotation: map.getView().getRotation().toFixed(2), + zoom: map.getView().getZoom().toFixed(2) + }); + }); + + + this.map = map; + this.updateStyle(this.props.mapStyle); + } + + closeOverlay = (e) => { + e.target.blur(); + this.overlay.setPosition(undefined); } render() { - return
this.container = x} - style={{ - width: "100%", - height: "100%", - backgroundColor: '#fff', - ...this.props.style, - }}> + return
+
this.popupContainer = x} + style={{background: "black"}} + className="maputnik-popup" + > + + +
+
+ Zoom level: {this.state.zoom} +
+ {this.props.debugToolbox && +
+
+ + {renderCoords(this.state.cursor)} +
+
+ + {renderCoords(this.state.center)} +
+
+ + {this.state.rotation} +
+
+ } +
this.container = x} + style={{ + ...this.props.style, + }}> +
} } diff --git a/src/components/modals/DebugModal.js b/src/components/modals/DebugModal.js index bddb48f3..6f57d6ed 100644 --- a/src/components/modals/DebugModal.js +++ b/src/components/modals/DebugModal.js @@ -11,6 +11,7 @@ class DebugModal extends React.Component { onChangeMaboxGlDebug: PropTypes.func.isRequired, onOpenToggle: PropTypes.func.isRequired, mapboxGlDebugOptions: PropTypes.object, + openlayersDebugOptions: PropTypes.object, } render() { @@ -33,9 +34,15 @@ class DebugModal extends React.Component { } {this.props.renderer === 'ol' && -
- No debug options available for the OpenLayers renderer -
+
    + {Object.entries(this.props.openlayersDebugOptions).map(([key, val]) => { + return
  • + +
  • + })} +
}
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 6d38b2dc..80c93b4c 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -109,6 +109,21 @@ class SettingsModal extends React.Component { onChange={this.changeMetadataProperty.bind(this, 'maputnik:renderer')} /> + + {this.props.openlayersDebugOptions.enableProjections && + + + + } + } diff --git a/src/styles/_map.scss b/src/styles/_map.scss index 951c654a..15e08cef 100644 --- a/src/styles/_map.scss +++ b/src/styles/_map.scss @@ -1,7 +1,13 @@ //OPENLAYERS .maputnik-layout { .ol-zoom { - top: 10px; + top: 40px; + right: 10px; + left: auto; + } + + .ol-rotate { + top: 94px; right: 10px; left: auto; } @@ -20,3 +26,57 @@ } } } + + +.maputnik-ol { + width: 100%; + height: 100%; +} + +.maputnik-ol-popup { + background: $color-black; + +} + +.maputnik-coords { + font-family: monospace; + &:before { + content: '['; + color: #888; + } + &:after { + content: ']'; + color: #888; + } +} + +.maputnik-ol-debug { + font-family: monospace; + font-size: smaller; + position: absolute; + bottom: 10px; + left: 10px; + background: rgb(28, 31, 36); + padding: 6px 8px; + border-radius: 2px; + z-indeX: 9999; +} + +.maputnik-ol-zoom { + position: absolute; + right: 10px; + top: 10px; + background: #1c1f24; + border-radius: 2px; + padding: 6px 8px; + color: $color-lowgray; + z-indeX: 9999; + font-size: 12px; + font-weight: bold; +} + +.maputnik-ol-container { + display: flex; + flex: 1; + position: relative; +} diff --git a/src/styles/_popup.scss b/src/styles/_popup.scss index dc6caf96..2338f899 100644 --- a/src/styles/_popup.scss +++ b/src/styles/_popup.scss @@ -22,7 +22,7 @@ .maputnik-popup-layer-id { padding-left: $margin-2; - padding-right: $margin-2; + padding-right: 1.6em; background-color: $color-midgray; color: $color-white; } From 884dc6fa493268b57689878f468b3e72316a4cab Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 29 May 2019 18:28:47 +0100 Subject: [PATCH 2/7] Fixed typos. --- src/styles/_map.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/_map.scss b/src/styles/_map.scss index 15e08cef..c45eab3a 100644 --- a/src/styles/_map.scss +++ b/src/styles/_map.scss @@ -59,7 +59,7 @@ background: rgb(28, 31, 36); padding: 6px 8px; border-radius: 2px; - z-indeX: 9999; + z-index: 9999; } .maputnik-ol-zoom { @@ -70,7 +70,7 @@ border-radius: 2px; padding: 6px 8px; color: $color-lowgray; - z-indeX: 9999; + z-index: 9999; font-size: 12px; font-weight: bold; } From cb6c6e0d9f5ccd43467c8da0b0dfcf7e51e1b9cf Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 29 May 2019 18:54:32 +0100 Subject: [PATCH 3/7] Remove projection code for now. --- package.json | 1 - src/components/App.jsx | 6 ----- src/components/map/OpenLayersMap.jsx | 29 +++---------------------- src/components/modals/SettingsModal.jsx | 14 ------------ 4 files changed, 3 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 7591efdd..6fe3fd18 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "maputnik-design": "github:maputnik/design", "ol": "^6.0.0-beta.8", "ol-mapbox-style": "^5.0.0-beta.2", - "proj4": "^2.5.0", "prop-types": "^15.6.2", "react": "^16.5.2", "react-aria-menubutton": "^6.0.1", diff --git a/src/components/App.jsx b/src/components/App.jsx index 2c088cdd..bd840268 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -483,11 +483,6 @@ export default class App extends React.Component { return metadata['maputnik:renderer'] || 'mbgljs'; } - getProjectionCode () { - const metadata = this.state.mapStyle.metadata || {}; - return this.state.openlayersDebugOptions.enableProjections ? metadata['maputnik:projection'] : "EPSG:3857"; - } - mapRenderer() { const metadata = this.state.mapStyle.metadata || {}; @@ -507,7 +502,6 @@ export default class App extends React.Component { if(renderer === 'ol') { mapElement = diff --git a/src/components/map/OpenLayersMap.jsx b/src/components/map/OpenLayersMap.jsx index f70bd2fa..cc87e1ec 100644 --- a/src/components/map/OpenLayersMap.jsx +++ b/src/components/map/OpenLayersMap.jsx @@ -9,15 +9,9 @@ import 'ol/ol.css' import {apply} from 'ol-mapbox-style'; import {Map, View, Proj, Overlay} from 'ol'; -import proj4 from 'proj4'; -import {register} from 'ol/proj/proj4'; -import {get as getProjection, toLonLat} from 'ol/proj'; +import {toLonLat} from 'ol/proj'; import {toStringHDMS} from 'ol/coordinate'; -// Register some projections... -proj4.defs('EPSG:3031', '+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs '); -register(proj4); - function renderCoords (coords) { if (!coords || coords.length < 2) { @@ -64,21 +58,7 @@ export default class OpenLayersMap extends React.Component { apply(this.map, newMapStyle); } - updateProjection () { - this.projection = getProjection(this.props.projectionCode || "EPSG:3857"); - } - componentDidUpdate(prevProps) { - if (this.props.projectionCode !== prevProps.projectionCode) { - this.updateProjection(); - this.map.setView( - new View({ - projection: this.projection, - zoom: 1, - center: [180, -90] - }) - ); - } if (this.props.mapStyle !== prevProps.mapStyle) { this.updateStyle(this.props.mapStyle); } @@ -93,20 +73,17 @@ export default class OpenLayersMap extends React.Component { } }); - this.updateProjection(); - const map = new Map({ target: this.container, overlays: [this.overlay], view: new View({ - projection: this.projection, zoom: 1, center: [180, -90], }) }); map.on('pointermove', (evt) => { - var coords = toLonLat(evt.coordinate, this.projection); + var coords = toLonLat(evt.coordinate); this.setState({ cursor: [ coords[0].toFixed(2), @@ -116,7 +93,7 @@ export default class OpenLayersMap extends React.Component { }) map.on('postrender', (evt) => { - const center = toLonLat(map.getView().getCenter(), this.projection); + const center = toLonLat(map.getView().getCenter()); this.setState({ center: [ center[0].toFixed(2), diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 80c93b4c..5e7e4ea9 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -110,20 +110,6 @@ class SettingsModal extends React.Component { /> - {this.props.openlayersDebugOptions.enableProjections && - - - - } - } From 24c52074b8f23c270134101b28ae87e00496b1bf Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 29 May 2019 18:59:26 +0100 Subject: [PATCH 4/7] Fixed lint errors. --- src/components/Toolbar.jsx | 1 + src/components/map/OpenLayersMap.jsx | 3 ++- src/components/modals/DebugModal.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Toolbar.jsx b/src/components/Toolbar.jsx index f6c65223..8917935c 100644 --- a/src/components/Toolbar.jsx +++ b/src/components/Toolbar.jsx @@ -114,6 +114,7 @@ export default class Toolbar extends React.Component { onToggleModal: PropTypes.func, onSetMapState: PropTypes.func, mapState: PropTypes.string, + renderer: PropTypes.string, } state = { diff --git a/src/components/map/OpenLayersMap.jsx b/src/components/map/OpenLayersMap.jsx index cc87e1ec..b1ee83a7 100644 --- a/src/components/map/OpenLayersMap.jsx +++ b/src/components/map/OpenLayersMap.jsx @@ -31,6 +31,7 @@ export default class OpenLayersMap extends React.Component { accessToken: PropTypes.string, style: PropTypes.object, onLayerSelect: PropTypes.func.isRequired, + debugToolbox: PropTypes.bool.isRequired, } static defaultProps = { @@ -123,7 +124,7 @@ export default class OpenLayersMap extends React.Component { className="maputnik-popup" >