import React from 'react'; import PropTypes from 'prop-types'; import L from 'leaflet'; import 'leaflet-fullscreen/dist/fullscreen.png'; import 'leaflet-fullscreen/dist/leaflet.fullscreen.css'; import 'leaflet-fullscreen/dist/Leaflet.fullscreen.min.js'; import 'leaflet.markercluster/dist/MarkerCluster.css'; import 'leaflet.markercluster/dist/MarkerCluster.Default.css'; import 'leaflet.markercluster/dist/leaflet.markercluster.js'; import 'Leaflet.Control.Opacity/dist/L.Control.Opacity.css'; import 'Leaflet.Control.Opacity/dist/L.Control.Opacity.js'; import 'leaflet.smooth_marker_bouncing/leaflet.smoothmarkerbouncing.js'; const style = { width: '100%', height: '100%' }; // https://github.com/pointhi/leaflet-color-markers const ColorIcon = L.Icon.extend({ options: { shadowUrl: 'img/markers/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] } }); class LeafletMap extends React.Component { componentDidMount() { // https://avaa.tdata.fi/web/kotus/rajapinta // Ilmiƶt: // kotus:paikkatieto_view // Taustakartan rajat: // kotus:pitajat // kotus:rajat-sms-alueosat murrealueenosat // kotus:rajat-lansi-ita // kotus:rajat-sms-alueet murrealueet this.props.getGeoJSON([ 'kotus:pitajat', 'kotus:rajat-sms-alueet', 'kotus:rajat-sms-alueosat', 'kotus:rajat-lansi-ita' ]); // Base layers const OSMBaseLayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }); const topographicalMapNLS = L.tileLayer(this.createNLSUrl('maastokartta'), { attribution: 'National Land Survey of Finland' }); //https://www.maanmittauslaitos.fi/kartat-ja-paikkatieto/asiantuntevalle-kayttajalle/kartta-ja-paikkatietojen-rajapintapalvelut-19 const backgroundMapNLS = L.tileLayer(this.createNLSUrl('taustakartta'), { attribution: 'National Land Survey of Finland' }); // const accessibleMapNLS = L.tileLayer(this.createNLSUrl('selkokartta'), { // attribution: 'National Land Survey of Finland' // }); // // const aerialPhotoMapNLS = L.tileLayer(this.createNLSUrl('ortokuva'), { // attribution: 'National Land Survey of Finland' // }); //console.log(this.createNLSUrl('kiinteistojaotus')); // Overlays const realEstateMapNLS = L.tileLayer(this.createNLSUrl('kiinteistojaotus'), { attribution: 'National Land Survey of Finland' }); const realEstateIdMapNLS = L.tileLayer(this.createNLSUrl('kiinteistotunnukset'), { attribution: 'National Land Survey of Finland' }); const karelianMaps = L.tileLayer('http:///mapwarper.onki.fi/mosaics/tile/4/{z}/{x}/{y}.png', { attribution: 'SeCo' }); const senateAtlas = L.tileLayer('http:///mapwarper.onki.fi/mosaics/tile/5/{z}/{x}/{y}.png', { attribution: 'SeCo' }); const westernFront = L.tileLayer('http://mapwarper.net/mosaics/tile/844/{z}/{x}/{y}.png', { attribution: 'SeCo' }); // Marker layers this.resultMarkerLayer = L.layerGroup(); this.bouncingMarkerObj = null; this.popupMarkerObj = null; if (this.props.mapMode === 'cluster') { this.updateMarkersAndCluster(this.props.results); } else { this.updateMarkers(this.props.results); } // create map this.leafletMap = L.map('map', { center: [65.184809, 27.314050], zoom: 1, layers: [ OSMBaseLayer, this.resultMarkerLayer, ], fullscreenControl: true, }); // layer controls const baseMaps = { 'OpenStreetMap': OSMBaseLayer, 'Topographical map (National Land Survey of Finland)': topographicalMapNLS, 'Background map (National Land Survey of Finland)': backgroundMapNLS, }; const overlayMaps = { 'Search results': this.resultMarkerLayer, 'Real estate boundaries (National Land Survey of Finland)': realEstateMapNLS, 'Real estate ids (National Land Survey of Finland)': realEstateIdMapNLS, 'Karelian maps (MapWarper)': karelianMaps, 'Senate atlas (MapWarper)': senateAtlas, 'Western Front July 1917 (MapWarper)': westernFront }; this.layerControl = L.control.layers( baseMaps, overlayMaps, ).addTo(this.leafletMap); L.control.opacity( overlayMaps, { collapsed: true, position: 'bottomleft' }).addTo(this.leafletMap); L.Marker.setBouncingOptions({ exclusive: true }); // map.on('fullscreenchange', function () { // if (map.isFullscreen()) { // console.log('entered fullscreen'); // } else { // console.log('exited fullscreen'); // } // }); } componentDidUpdate({ results, mapMode, geoJSONKey, bouncingMarkerKey, openPopupMarkerKey }) { if (this.props.bouncingMarker === '' && this.bouncingMarkerObj !== null) { this.leafletMap.removeLayer(this.bouncingMarkerObj); } if (this.props.bouncingMarkerKey !== bouncingMarkerKey) { if (this.props.mapMode === 'cluster') { const m = this.markers[this.props.bouncingMarker]; const latlng = m.getLatLng(); // create a new marker so that the temporary popup can be left open this.bouncingMarkerObj = L.marker(latlng); this.bouncingMarkerObj.addTo(this.leafletMap).bounce(1); } else { this.markers[this.props.bouncingMarker].bounce(1); } } if (this.props.openPopupMarkerKey !== openPopupMarkerKey) { if (this.props.mapMode === 'cluster') { if (this.popupMarkerObj !== null) { this.leafletMap.removeLayer(this.popupMarkerObj); } this.popupMarkerObj = this.markers[this.props.popupMarker]; this.popupMarkerObj.addTo(this.leafletMap).openPopup(); } else { this.markers[this.props.popupMarker].openPopup(); } } // check if results data or mapMode have changed if (this.props.results !== results || this.props.mapMode !== mapMode) { if (this.props.mapMode === 'cluster') { this.updateMarkersAndCluster(this.props.results); } else { this.updateMarkers(this.props.results); } } // check if geoJSON has updated if (this.props.geoJSONKey !== geoJSONKey) { this.props.geoJSON.map(obj => { const layer = L.geoJSON(obj.geoJSON, { onEachFeature: this.onEachFeature }); this.layerControl.addOverlay(layer, obj.layerID); }); } } updateMarkers(results) { this.resultMarkerLayer.clearLayers(); this.markers = {}; results.forEach(result => { if (result.creationPlace !== undefined) { if (Array.isArray(result.creationPlace)) { result.creationPlace.forEach(place => { const marker = this.createMarker(place); //this.markers[result.id] = marker; marker.addTo(this.resultMarkerLayer); }); } else { const marker = this.createMarker(result.creationPlace); marker == null ? null : marker.addTo(this.resultMarkerLayer); } } }); } updateMarkersAndCluster(results) { this.resultMarkerLayer.clearLayers(); this.markers = {}; const clusterer = L.markerClusterGroup(); results.forEach(result => { if (result.creationPlace !== undefined) { if (Array.isArray(result.creationPlace)) { result.creationPlace.forEach(place => { const marker = this.createMarker(place); //this.markers[result.id] = marker; marker == null ? null : clusterer.addLayer(marker); }); } else { const marker = this.createMarker(result.creationPlace); marker == null ? null : clusterer.addLayer(marker); } } }); clusterer.addTo(this.resultMarkerLayer); } createMarker(result) { const color = typeof result.markerColor === 'undefined' ? 'grey' : result.markerColor; const icon = new ColorIcon({iconUrl: 'img/markers/marker-icon-' + color + '.png'}); const { lat, long } = result; if (typeof lat === 'undefined' || typeof long === 'undefined') { return null; } else { const latLng = [+lat, +long]; const marker = L.marker(latLng, {icon: icon}) .bindPopup(this.createPopUpContent(result)); return marker; } } createPopUpContent(result) { // <p>Source: <a target='_blank' rel='noopener noreferrer' href={source}>{source}</a></p> const popUpTemplate = ` <h3>{label}</h3> `; return L.Util.template(popUpTemplate, result); } onEachFeature(feature, layer) { let popupContent = ''; if (feature.id.startsWith('rajat')) { popupContent = '<p>ID: ' + feature.id + '</p>'; } else if (feature.id.startsWith('pitajat')) { if (feature.properties.NIMI) { popupContent += '<p>Nimi: ' + feature.properties.NIMI + '</p>'; } popupContent += '<p>ID: ' + feature.id + '</p>'; } layer.bindPopup(popupContent); } createNLSUrl(layerID) { // return 'https://avoin-karttakuva.maanmittauslaitos.fi/avoin/wmts/1.0.0/' + // layerID + '/default/WGS84_Pseudo-Mercator/{z}/{x}/{y}.png'; return 'https://avoin-karttakuva.maanmittauslaitos.fi/avoin/wmts?service=WMTS' + '&request=GetTile&version=1.0.0&layer=' + layerID + '&style=default' + '&format=image/png&TileMatrixSet=WGS84_Pseudo-Mercator&TileMatrix={z}&TileRow={y}&TileCol={x}'; } createOpacitySlider() { L.Control.OpacitySlider = L.Control.extend({ onAdd: function() { const slider = L.DomUtil.create('input', 'opacity-slider'); slider.type = 'range'; slider.min = 0; slider.max = 100; slider.value = 100; return slider; }, }); L.control.opacitySlider = function(opts) { return new L.Control.OpacitySlider(opts); }; L.control.opacitySlider({ position: 'bottomleft' }).addTo(this.leafletMap); } render() { return <div id="map" style={style} />; } } LeafletMap.propTypes = { results: PropTypes.array, mapMode: PropTypes.string.isRequired, geoJSON: PropTypes.array, geoJSONKey: PropTypes.number.isRequired, getGeoJSON: PropTypes.func.isRequired, bouncingMarker: PropTypes.string.isRequired, popupMarker: PropTypes.string.isRequired, bouncingMarkerKey: PropTypes.number.isRequired, openPopupMarkerKey: PropTypes.number.isRequired, }; export default LeafletMap;