diff --git a/src/components/map/OpenLayers3Map.jsx b/src/components/map/OpenLayers3Map.jsx index 7c88dfe..f1251b3 100644 --- a/src/components/map/OpenLayers3Map.jsx +++ b/src/components/map/OpenLayers3Map.jsx @@ -1,5 +1,32 @@ import React from 'react' import style from '../../libs/style.js' +import isEqual from 'lodash.isequal' + + +function suitableVectorSource(mapStyle) { + const sources = Object.keys(mapStyle.sources) + .map(sourceId => { + return { + id: sourceId, + source: mapStyle.sources[sourceId] + } + }) + .filter(({source}) => source.type === 'vector' && source.tiles && source.tiles.length > 0) + .filter(({source}) => source.tiles.length > 0) + return sources[0] +} + +function toVectorLayer(source, tilegrid) { + const ol = require('openlayers') + return new ol.layer.VectorTile({ + source: new ol.source.VectorTile({ + format: new ol.format.MVT(), + tileGrid: tilegrid, + tilePixelRatio: 8, + url: source.tiles[0] + }) + }) +} class OpenLayers3Map extends React.Component { static propTypes = { @@ -13,20 +40,41 @@ class OpenLayers3Map extends React.Component { onDataChange: () => {}, } + constructor(props) { + super(props) + this.tilegrid = null + this.resolutions = null + this.layer = null + this.map = null + } + + updateStyle(newMapStyle) { + const oldSource = suitableVectorSource(this.props.mapStyle) + const newSource = suitableVectorSource(newMapStyle) + + if(newSource) { + if(!this.layer) { + this.layer = toVectorLayer(newSource.source, this.tilegrid) + this.map.addLayer(this.layer) + } else if(!isEqual(oldSource, newSource)) { + this.map.removeLayer(this.layer) + this.layer = toVectorLayer(newSource.source, this.tilegrid) + this.map.addLayer(this.layer) + } + const olms = require('ol-mapbox-style') + const styleFunc = olms.getStyleFunction(newMapStyle, newSource.id, this.resolutions) + this.layer.setStyle(styleFunc) + //NOTE: We need to mark the source as changed in order + //to trigger a rerender + this.layer.getSource().changed() + this.map.render() + } + } + componentWillReceiveProps(nextProps) { - require.ensure(["openlayers", "ol-mapbox-style"], ()=> { - const ol = require('openlayers') - const olms = require('ol-mapbox-style') - const jsonStyle = nextProps.mapStyle - const styleFunc = olms.getStyleFunction(jsonStyle, 'openmaptiles', this.resolutions) - - const layer = this.layer - layer.setStyle(styleFunc) - //NOTE: We need to mark the source as changed in order - //to trigger a rerender - layer.getSource().changed() - - this.state.map.render() + require.ensure(["openlayers", "ol-mapbox-style"], () => { + if(!this.map || !this.resolutions) return + this.updateStyle(nextProps.mapStyle) }) } @@ -39,46 +87,36 @@ class OpenLayers3Map extends React.Component { const ol = require('openlayers') const olms = require('ol-mapbox-style') - const tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22}) - this.resolutions = tilegrid.getResolutions() - this.layer = new ol.layer.VectorTile({ - source: new ol.source.VectorTile({ - attributions: '© OpenStreetMap contributors', - format: new ol.format.MVT(), - tileGrid: tilegrid, - tilePixelRatio: 8, - url: 'https://free-0.tilehosting.com/data/v3/{z}/{x}/{y}.pbf?key=tXiQqN3lIgskyDErJCeY' - }) - }) - - const jsonStyle = this.props.mapStyle - const styleFunc = olms.getStyleFunction(jsonStyle, 'openmaptiles', this.resolutions) - this.layer.setStyle(styleFunc) + this.tilegrid = ol.tilegrid.createXYZ({tileSize: 512, maxZoom: 22}) + this.resolutions = this.tilegrid.getResolutions() const map = new ol.Map({ target: this.container, - layers: [this.layer], + layers: [], view: new ol.View({ - center: jsonStyle.center, zoom: 2, - //zoom: jsonStyle.zoom, + center: [52.5, -78.4] }) }) - map.addControl(new ol.control.Zoom()); - this.setState({ map }); + map.addControl(new ol.control.Zoom()) + this.map = map + this.updateStyle(this.props.mapStyle) }) } render() { return