From 1ad1bb2359f76074e56982ace10bfd8902cac366 Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Fri, 21 Aug 2020 13:52:37 +0300 Subject: [PATCH] Added OpenlayersMap --- .../DiscodataOpenlayersMapBlock/Edit.jsx | 59 ++ .../DiscodataOpenlayersMapBlock/View.jsx | 996 ++++++++++++++++++ .../DiscodataOpenlayersMapBlock/style.css | 237 +++++ 3 files changed, 1292 insertions(+) create mode 100644 src/components/manage/Blocks/DiscodataOpenlayersMapBlock/Edit.jsx create mode 100644 src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx create mode 100644 src/components/manage/Blocks/DiscodataOpenlayersMapBlock/style.css diff --git a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/Edit.jsx b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/Edit.jsx new file mode 100644 index 00000000..eec102c4 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/Edit.jsx @@ -0,0 +1,59 @@ +import React, { useState, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import _uniqueId from 'lodash/uniqueId'; +import RenderFields from 'volto-addons/Widgets/RenderFields'; +import View from './View'; +import { settings } from '~/config'; + +const getSchema = props => { + return { + draggable: { + type: 'boolean', + title: 'Drraggable', + defaultValue: false, + }, + hasPopups: { + type: 'boolean', + title: 'Has popups', + defaultValue: false, + }, + hasSidebar: { + type: 'boolean', + title: 'Has sidebar', + defaultValue: false, + }, + }; +}; + +const Edit = props => { + const [state, setState] = useState({ + schema: getSchema({ ...props, providerUrl: settings.providerUrl }), + id: _uniqueId('block_'), + }); + useEffect(() => { + setState({ + ...state, + schema: getSchema({ + ...props, + }), + }); + /* eslint-disable-next-line */ + }, [props.data.isExpandable]) + return ( +
+ + +
+ ); +}; + +export default compose( + connect((state, props) => ({ + pathname: state.router.location.pathname, + })), +)(Edit); diff --git a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx new file mode 100644 index 00000000..b790ece3 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx @@ -0,0 +1,996 @@ +/* REACT */ +import React, { useState, useRef, useEffect } from 'react'; +import { useHistory } from 'react-router-dom'; +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; +// HELPERS +import qs from 'query-string'; +import axios from 'axios'; +import jsonp from 'jsonp'; +import { settings } from '~/config'; +// VOLTO +import { Icon as VoltoIcon } from '@plone/volto/components'; +// VOLTO-DATABLOCKS +import { setQueryParam } from 'volto-datablocks/actions'; +// SEMANTIC REACT UI +import { Grid, Header, Loader, Dimmer } from 'semantic-ui-react'; +// SVGs +import clearSVG from '@plone/volto/icons/clear.svg'; +// import pinSVG from '~/icons/pin.svg'; +// import bluePinSVG from '~/icons/blue_pin.svg'; +// STYLES +import 'ol/ol.css'; +import './style.css'; + +const getHtmlAttributes = obj => { + return Object.entries(obj) + .map(([key, value]) => { + return `${key}="${value}"`; + }) + .join(' '); +}; + +const splitBy = (arr, delimiter) => { + if (Array.isArray(arr)) { + return ( + arr + .filter(value => value) + .map(value => `'${value}'`) + .join(delimiter) || '' + ); + } + return ''; +}; + +// const encodedPinSVG = encodeURIComponent( +// `${pinSVG.content}`, +// ); + +// const encodedBluePinSVG = encodeURIComponent( +// `${ +// bluePinSVG.content +// }`, +// ); + +let Map, + View, + Overlay, + EsriJSON, + VectorSource, + VectorSourceEvent, + XYZ, + fromLonLat, + toLonLat, + toStringHDMS, + createXYZ, + CircleStyle, + Fill, + Stroke, + Style, + TileLayer, + VectorLayer, + Group, + tile, + Control, + defaultsControls, + defaultsInteractions; +let OL_LOADED = false; +const initialExtent = [ + -10686671.0000035, + -2430148.00000588, + 6199975.99999531, + 10421410.9999871, +]; +const OpenlayersMapView = props => { + const stateRef = useRef({ + map: { + element: null, + sitesSourceQuery: { whereStatements: {}, where: '' }, + oldSitesSourceQuery: { whereStatements: {}, where: '' }, + sitesSourceLayer: null, + }, + popup: { element: null, properties: {} }, + popupDetails: { element: null, properties: {} }, + locationTerm: null, + updateMapPosition: null, + }); + const [state, setState] = useState({ + map: { + element: null, + sitesSourceQuery: { whereStatements: {}, where: '' }, + oldSitesSourceQuery: { whereStatements: {}, where: '' }, + sitesSourceLayer: null, + }, + popup: { element: null, properties: {} }, + popupDetails: { element: null, properties: {} }, + locationTerm: null, + updateMapPosition: null, + }); + // const [loader, setLoader] = useState(false); + const [mapRendered, setMapRendered] = useState(false); + const [firstFilteringUpdate, setFirstFilteringUpdate] = useState(false); + const ToggleSidebarControl = useRef(null); + const history = useHistory(); + const draggable = !!props.data?.draggable?.value; + const hasPopups = !!props.data?.hasPopups?.value; + const hasSidebar = !!props.data?.hasSidebar?.value; + const zoomSwitch = 6; + const currentMapZoom = state.map?.element + ? state.map.element.getView().getZoom() + : null; + + if (mapRendered && !firstFilteringUpdate) { + updateFilters(); + setFirstFilteringUpdate(true); + } + + useEffect(() => { + if (__CLIENT__ && document) { + // MOuNT + if (!OL_LOADED) { + Map = require('ol/Map').default; + View = require('ol/View').default; + Overlay = require('ol/Overlay').default; + EsriJSON = require('ol/format/EsriJSON').default; + VectorSource = require('ol/source/Vector').default; + VectorSourceEvent = require('ol/source/Vector').VectorSourceEvent; + XYZ = require('ol/source/XYZ').default; + fromLonLat = require('ol/proj').fromLonLat; + toLonLat = require('ol/proj').toLonLat; + toStringHDMS = require('ol/coordinate').toStringHDMS; + createXYZ = require('ol/tilegrid').createXYZ; + CircleStyle = require('ol/style/Circle.js').default; + Fill = require('ol/style/Fill.js').default; + Stroke = require('ol/style/Stroke.js').default; + Style = require('ol/style/Style.js').default; + TileLayer = require('ol/layer/Tile.js').default; + VectorLayer = require('ol/layer/Vector.js').default; + Group = require('ol/layer/Group.js').default; + tile = require('ol/loadingstrategy').tile; + Control = require('ol/control/Control.js').default; + defaultsControls = require('ol/control.js').defaults; + defaultsInteractions = require('ol/interaction.js').defaults; + OL_LOADED = true; + } + if (OL_LOADED && !ToggleSidebarControl.current && hasSidebar) { + ToggleSidebarControl.current = /*@__PURE__*/ (function(Control) { + function ToggleSidebarControl(opt_options) { + const options = opt_options || {}; + const buttonContainer = document.getElementById( + 'dynamic-filter-toggle', + ); + Control.call(this, { + element: buttonContainer, + target: options.target, + }); + } + if (Control) ToggleSidebarControl.__proto__ = Control; + ToggleSidebarControl.prototype = Object.create( + Control && Control.prototype, + ); + ToggleSidebarControl.prototype.constructor = ToggleSidebarControl; + + return ToggleSidebarControl; + })(Control); + } + renderMap(); + setMapRendered(true); + } + return () => { + // UNMOUNT + }; + /* eslint-disable-next-line */ + }, []) + + useEffect(() => { + if (mapRendered) { + updateFilters(); + } + /* eslint-disable-next-line */ + }, [ + JSON.stringify(props.discodata_query.search.siteTerm), + JSON.stringify(props.discodata_query.search.locationTerm), + JSON.stringify(props.discodata_query.search.EEASector), + JSON.stringify(props.discodata_query.search.siteCountry), + JSON.stringify(props.discodata_query.search.region), + JSON.stringify(props.discodata_query.search.riverBasin), + JSON.stringify(props.discodata_query.search.townVillage), + // JSON.stringify(props.discodata_query.search.pollutantGroup), + JSON.stringify(props.discodata_query.search.pollutant), + JSON.stringify(props.discodata_query.search.reportingYear), + JSON.stringify(props.discodata_query.search.batConclusionCode), + ]); + + useEffect(() => { + stateRef.current = { ...state }; + /* eslint-disable-next-line */ + }, [state]) + + useEffect(() => { + if (mapRendered) { + if (state.updateMapPosition === 'byLocationTermNoRefresh') { + const options = { + duration: 2000, + maxZoom: 15, + }; + getLocation(options, true); + setState({ + ...state, + updateMapPosition: null, + }); + } else { + console.log('UPDATE FILTERS', state.map.sitesSourceQuery); + state.map.sitesSourceLayer && + state.map.sitesSourceLayer.getSource().refresh(); + } + } + /* eslint-disable-next-line */ + }, [state.map.sitesSourceQuery?.where, state.locationTerm?.text]) + + function updateFilters() { + const sitesSourceQuery = { ...state.map.sitesSourceQuery }; + const locationTerm = props.discodata_query.search.locationTerm || null; + if (hasSidebar) { + sitesSourceQuery.whereStatements = { + ...sitesSourceQuery.whereStatements, + siteTerm: { + sql: `(sitename LIKE ':options%')`, + type: 'string', + }, + //? Industries + EEASector: { + sql: `(EEASector IN (:options))`, + }, + // Country + siteCountry: { + sql: `(country IN (:options))`, + }, + //? Regions + region: { + sql: `(region IN (:options))`, + }, + //? River Basin + riverBasin: { + sql: `(riverBasinDistrict IN (:options))`, + }, + //? Town/Village + townVillage: { + sql: `(townVillage IN (:options))`, + }, + // Pollutant groups + // pollutantGroup: { + // sql: `(pollutantGroup IN (:options))`, + // }, + // Pollutants + pollutant: { + sql: `(pollutants IN (:options))`, + }, + // Reporting year + reportingYear: { + sql: `(rep_yr IN (:options))`, + }, + //! Installation specifics + //? BAT conclusion + batConclusionCode: { + sql: `(batConclusion IN (:options))`, + }, + //! BAT conclusion year + //! Permit type + //! Permit year + }; + } else { + sitesSourceQuery.whereStatements = { + ...sitesSourceQuery.whereStatements, + // Country + siteCountry: { + sql: `(country = ':options')`, + type: 'string', + }, + // Site inspire id + siteId: { + sql: `(id = ':options')`, + type: 'string', + }, + }; + } + + Object.entries(sitesSourceQuery.whereStatements).forEach(([id, where]) => { + let options; + if (where.type === 'string') { + options = props.discodata_query.search[id]; + } else if (!props.discodata_query.search[id]) { + options = null; + } else { + options = splitBy(props.discodata_query.search[id], ','); + } + where.sql = options ? where.sql.replace(':options', options) : null; + if (!where.sql) delete sitesSourceQuery.whereStatements[id]; + }); + + sitesSourceQuery.where = Object.entries(sitesSourceQuery.whereStatements) + .map(([id, where]) => where.sql) + .join(' AND '); + + if ( + sitesSourceQuery.where !== state.map.sitesSourceQuery.where || + locationTerm?.text !== state.locationTerm?.text + ) { + let updateMapPosition = null; + if ( + sitesSourceQuery.whereStatements.siteTerm?.sql || + sitesSourceQuery.whereStatements.siteId?.sql + ) { + updateMapPosition = 'bySiteTerm'; + } else if (locationTerm?.text) { + updateMapPosition = 'byLocationTerm'; + } else if ( + sitesSourceQuery.whereStatements.siteCountry?.sql || + sitesSourceQuery.whereStatements.region?.sql + ) { + updateMapPosition = 'byRegion'; + } + // setLoader(true); + if (sitesSourceQuery.where !== state.map.sitesSourceQuery.where) { + setState({ + ...state, + map: { + ...state.map, + sitesSourceQuery, + }, + updateMapPosition, + locationTerm, + }); + } else if (locationTerm?.text !== state.locationTerm?.text) { + setState({ + ...state, + updateMapPosition: 'byLocationTermNoRefresh', + locationTerm, + }); + } + } + } + + function makeMap() { + if (document.getElementById('map')) { + document.getElementById('map').innerHTML = ''; + const map = new Map({ + controls: draggable + ? hasSidebar + ? defaultsControls().extend([new ToggleSidebarControl.current()]) + : defaultsControls() + : [], + interactions: draggable ? defaultsInteractions() : [], + target: document.getElementById('map'), + view: new View({ + center: fromLonLat([20, 50]), + zoom: 4.5, + }), + }); + return map; + } + return false; + } + + function makeTileLayer(url, visible, title) { + const layer = new TileLayer({ + source: new XYZ({ + url, + }), + visible, + title, + }); + return layer; + } + + function makeOverlay(element, className, positioning, stopEvent) { + if (element) { + return new Overlay({ + element, + className, + positioning, + stopEvent, + }); + } + return false; + } + + function getLocation(options, noRefresh = false) { + axios + .get( + encodeURI( + 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?SingleLine=' + + stateRef.current.locationTerm?.text + + '&f=json&outSR={"wkid":102100,"latestWkid":3857}&outFields=Match_addr,Addr_type,StAddr,City&magicKey=' + + stateRef.current.locationTerm?.magicKey + + '&maxLocations=6', + ), + ) + .then(response => { + const data = JSON.parse(response.request.response) || {}; + if (data.error) { + // setLoader(false); + } else if (data.candidates?.length > 0) { + stateRef.current.map.element + .getView() + .fit( + [ + data.candidates[0].extent.xmin, + data.candidates[0].extent.ymin, + data.candidates[0].extent.xmax, + data.candidates[0].extent.ymax, + ], + { + ...options, + callback: function() { + if (noRefresh) { + // setLoader(false); + stateRef.current.map.sitesSourceLayer && + stateRef.current.map.sitesSourceLayer + .getSource() + .refresh(); + } + }, + }, + ); + } + }) + .catch(error => {}); + } + + function onSourceChange(source) { + const options = { + duration: 2000, + maxZoom: 15, + }; + const extent = source.getExtent().map((coordinate, index) => { + if (coordinate === Infinity || coordinate === -Infinity) { + return initialExtent[index]; + } + return coordinate; + }); + if (stateRef.current.updateMapPosition === 'bySiteTerm' && extent) { + stateRef.current.map.element.getView().fit(extent, options); + } + if ( + stateRef.current.updateMapPosition === 'byLocationTerm' && + stateRef.current.locationTerm?.text && + stateRef.current.locationTerm?.magicKey && + extent + ) { + getLocation(options); + } + if (stateRef.current.updateMapPosition === 'byRegion' && extent) { + stateRef.current.map.element.getView().fit(extent); + } + // UPDATE OLD FILTERS + if ( + stateRef.current.map.sitesSourceQuery.where !== + stateRef.current.map.oldSitesSourceQuery.where || + stateRef.current.updateMapPosition !== null + ) { + console.log('ON SOURCE CHANGE'); + setState({ + ...stateRef.current, + map: { + ...stateRef.current.map, + oldSitesSourceQuery: { + ...stateRef.current.map.sitesSourceQuery, + }, + }, + updateMapPosition: null, + }); + } + } + + function centerPosition(map, position, zoom) { + map + .getView() + .setCenter( + fromLonLat([position.coords.longitude, position.coords.latitude]), + ); + map.getView().setZoom(zoom); + } + + function setFeatureInfo(map, pixel, coordinate, detailed) { + let features = []; + map.forEachFeatureAtPixel(pixel, function(feature) { + features.push(feature); + }); + if (features.length) { + let hdms = toStringHDMS( + toLonLat(features[0].getGeometry().flatCoordinates), + ); + const featuresProperties = features[0].getProperties(); + if ( + detailed && + JSON.stringify(stateRef.current.popupDetails.properties) !== + JSON.stringify(featuresProperties) + ) { + // axios.get() + setState({ + ...stateRef.current, + popupDetails: { + ...stateRef.current.popupDetails, + properties: { ...featuresProperties, hdms }, + }, + }); + } else if ( + !detailed && + JSON.stringify(stateRef.current.popup.properties) !== + JSON.stringify(featuresProperties) + ) { + setState({ + ...stateRef.current, + popup: { + ...stateRef.current.popup, + properties: { ...featuresProperties, hdms }, + }, + }); + } + return true; + } + return false; + } + + function displayPopup(map, pixel, coordinate, popup, detailed = false) { + if (setFeatureInfo(map, pixel, coordinate, detailed)) { + map.getTarget().style.cursor = 'pointer'; + popup.element.classList.add('show'); + popup.setPosition(coordinate); + } else { + map.getTarget().style.cursor = ''; + if (!detailed) { + popup.element.classList.remove('show'); + popup.setPosition(undefined); + } + } + } + + function renderMap() { + // MAP + const map = makeMap(); + // Layers + let worldLightGrayBase, worldHillshade; + // Overlayers + let popup, popupDetails, dynamicFilters; + // Features Formater + let esrijsonFormat = new EsriJSON(); + // Vector Layers + let sitesSourceLayer, regionsSourceLayer; + // Vector Sources + let sitesSource, regionsSource; + // Global variables + let currentZoom; + if (map) { + /* ======== TILE LAYERS ======== */ + // Make TileLayers + worldLightGrayBase = makeTileLayer( + 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', + true, + 'World_Light_Gray_Base', + ); + worldHillshade = makeTileLayer( + 'https://server.arcgisonline.com/ArcGIS/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}', + false, + 'World_Hillshade', + ); + /* ======== OVERLAYS ======== */ + // Make popups overlays + if (hasPopups) { + popup = makeOverlay( + document.getElementById('popup'), + 'ol-overlay-container ol-popup', + 'center-center', + true, + ); + popupDetails = makeOverlay( + document.getElementById('popup-details'), + 'ol-overlay-container ol-popup-details', + 'center-center', + true, + ); + } + // Make dynamic filters overlay + if (hasSidebar) { + dynamicFilters = makeOverlay( + document.getElementById(`dynamic-filter`), + 'ol-dynamic-filter', + 'center-center', + true, + ); + } + /* ======== SOURCES ======== */ + // Make sites source + let reqs = 0; + sitesSource = new VectorSource({ + loader: function(extent, resolution, projection) { + const updateMapPosition = + !!stateRef.current.updateMapPosition && + !['byLocationTerm', 'byLocationTermNoRefresh'].includes( + stateRef.current.updateMapPosition, + ); + var url = + 'https://services.arcgis.com/LcQjj2sL7Txk9Lag/arcgis/rest/services/ly_IED_SiteMap_WM/FeatureServer/0/query/?f=json&' + + 'returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' + + encodeURIComponent( + '{"xmin":' + + (updateMapPosition ? initialExtent[0] : extent[0]) + + ',"ymin":' + + (updateMapPosition ? initialExtent[1] : extent[1]) + + ',"xmax":' + + (updateMapPosition ? initialExtent[2] : extent[2]) + + ',"ymax":' + + (updateMapPosition ? initialExtent[3] : extent[3]) + + ',"spatialReference":{"wkid":102100}}', + ) + + '&geometryType=esriGeometryEnvelope&inSR=102100&outFields=*' + + '&outSR=102100'; + // setLoader(true); + reqs++; + jsonp( + url, + { + param: + qs.stringify({ + where: stateRef.current.map.sitesSourceQuery.where, + }) + '&callback', + }, + (error, response) => { + reqs--; + if (error) { + // setLoader(false); + console.log(error.message); + } else { + var features = esrijsonFormat.readFeatures(response, { + featureProjection: projection, + }); + if (features.length > 0) { + sitesSource.addFeatures(features); + sitesSource.dispatchEvent( + new VectorSourceEvent('updateFilters', features), + ); + } else { + // setLoader(false); + } + } + }, + ); + }, + strategy: tile( + createXYZ({ + tileSize: 512, + }), + ), + }); + // Make regions source layer + regionsSource = new VectorSource({ + loader: function(extent, resolution, projection) { + var url = + 'https://services.arcgis.com/LcQjj2sL7Txk9Lag/ArcGIS/rest/services/ly_IED_SiteClusters_WM/FeatureServer/0/query/?f=json' + + '&returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' + + encodeURIComponent( + '{"xmin":' + + extent[0] + + ',"ymin":' + + extent[1] + + ',"xmax":' + + extent[2] + + ',"ymax":' + + extent[3] + + ',"spatialReference":{"wkid":102100}}', + ) + + '&geometryType=esriGeometryEnvelope&inSR=102100&outFields=*' + + '&outSR=102100'; + jsonp(url, null, (error, response) => { + if (error) { + console.log(error.message); + } else { + var features = esrijsonFormat.readFeatures(response, { + featureProjection: projection, + }); + if (features.length > 0) { + regionsSource.addFeatures(features); + } + } + }); + }, + strategy: tile( + createXYZ({ + tileSize: 512, + }), + ), + }); + /* ======== SOURCE LAYERS ======== */ + // Sites source layer + sitesSourceLayer = new VectorLayer({ + source: sitesSource, + style: new Style({ + image: new CircleStyle({ + radius: 3, + fill: new Fill({ color: '#000' }), + stroke: new Stroke({ color: '#6A6A6A', width: 1 }), + }), + }), + visible: true, + title: 'ly_IED_SiteMap_WM', + }); + // Regions source layer + regionsSourceLayer = new VectorLayer({ + source: regionsSource, + style: new Style({ + image: new CircleStyle({ + radius: 3, + fill: new Fill({ color: '#4296B2' }), + stroke: new Stroke({ color: '#6A6A6A', width: 1 }), + }), + }), + visible: true, + title: 'ly_IED_SiteClusters_WM', + }); + /* ======== APPEND TO THE MAP ======== */ + // Append TileLayers to the map + map.addLayer( + new Group({ + layers: [worldLightGrayBase, worldHillshade], + }), + ); + // Append popups to the map + popup && map.addOverlay(popup); + popupDetails && map.addOverlay(popupDetails); + // Append dynamic filters to the map + dynamicFilters && map.addOverlay(dynamicFilters); + dynamicFilters && dynamicFilters.setPosition([0, 0]); + // Append source layers to the map + map.addLayer( + new Group({ + layers: [sitesSourceLayer, regionsSourceLayer], + }), + ); + // Center by user location + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition(position => + centerPosition(map, position, 12), + ); + } + // Events + sitesSource.on('updateFilters', function(e) { + if (!reqs && e.target.getState() === 'ready') { + // setLoader(false); + onSourceChange(e.target); + } + }); + if (hasPopups) { + map.on('pointermove', function(evt) { + if (evt.dragging) { + return; + } + const pixel = map.getEventPixel(evt.originalEvent); + displayPopup(map, pixel, evt.coordinate, popup); + }); + map.on('click', function(evt) { + let newZoom = map.getView().getZoom(); + if (newZoom > zoomSwitch) { + displayPopup(map, evt.pixel, evt.coordinate, popupDetails, true); + } + }); + } + map.on('moveend', function(e) { + if (hasSidebar && document.getElementById('dynamic-filter')) { + document.getElementById('dynamic-filter').dispatchEvent( + new CustomEvent('featurechange', { + detail: { + features: sitesSource.getFeaturesInExtent( + map.getView().calculateExtent(), + ), + }, + }), + ); + } + let newZoom = map.getView().getZoom(); + if (currentZoom !== newZoom) { + if (newZoom > zoomSwitch) { + sitesSourceLayer.setVisible(true); + regionsSourceLayer.setVisible(false); + } else if (newZoom > 2) { + sitesSourceLayer.setVisible(false); + regionsSourceLayer.setVisible(true); + } else { + sitesSourceLayer.setVisible(false); + regionsSourceLayer.setVisible(false); + } + currentZoom = newZoom; + } + }); + setState({ + ...stateRef.current, + map: { + ...stateRef.current.map, + element: map, + sitesSourceLayer, + }, + popup: { + ...stateRef.current.popup, + element: popup, + }, + popupDetails: { + ...stateRef.current.popupDetails, + element: popupDetails, + }, + }); + } + } + + const setSiteQueryParams = () => { + axios + .get( + encodeURI( + `${ + settings.providerUrl + }?query=SELECT DISTINCT siteId, siteInspireId FROM [IED].[latest].[FacilitiesPerSite] WHERE siteId = '${ + state.popupDetails.properties.id + }'`, + ), + ) + .then(response => { + const data = JSON.parse(response.request.response); + props.setQueryParam({ + queryParam: { + siteInspireId: data.results[0].siteInspireId, + siteId: state.popupDetails.properties.id, + siteName: state.popupDetails.properties.sitename, + reportingYear: state.popupDetails.properties.rep_yr, + }, + }); + }) + .catch(error => {}); + }; + + return ( + +
+ + + + + + + ); +}; + +export default compose( + connect( + (state, props) => ({ + query: state.router.location.search, + content: + state.prefetch?.[state.router.location.pathname] || state.content.data, + discodata_query: state.discodata_query, + }), + { + setQueryParam, + }, + ), +)(OpenlayersMapView); diff --git a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/style.css b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/style.css new file mode 100644 index 00000000..f3d531b8 --- /dev/null +++ b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/style.css @@ -0,0 +1,237 @@ +.map { + width: 100%; + height: 100%; +} + +#map-loader.ui.active { + position: absolute !important; + pointer-events: auto !important; + transform: none !important; + top: 0 !important; + left: 0 !important; + right: unset !important; + bottom: unset !important; + width: 100% !important; + height: 100% !important; +} + +#popup.popup { + min-width: 280px; + max-width: 280px; + background-color: white; + position: absolute; + bottom: 10px; + transform: translateX(-50%); +} + +#popup-details { + min-width: 420px; + background-color: white; +} + +.ol-popup-details { + position: absolute !important; + pointer-events: auto !important; + transform: translate(-50%, -50%) !important; + top: 50% !important; + left: 50% !important; + right: unset !important; + bottom: unset !important; +} + +.ol-overlay-container.show #popup.popup, +.ol-overlay-container.show #popup-details.popup { + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); + border-radius: .3rem; + border: 1px solid #cccccc; +} + +.ol-overlay-container.show #popup-details.popup { + border: 2px solid #417283; +} + +.ol-overlay-container.show #popup.popup:after, +.ol-overlay-container.show #popup.popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.ol-overlay-container.show #popup.popup:after { + border-top-color: white; + border-width: 10px; + left: 50%; + transform: translateX(-50%); +} + +.ol-overlay-container.show #popup.popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 50%; + margin-left: -11px; +} + +#popup-details:after, +#popup-details:before { + display: none; +} + +#popup-details .popover-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 2rem; +} + +#popup-details .popover-actions { + background-color: transparent; + border-bottom: none; +} + +#popup-details .popover-body { + padding: 1rem 2rem; +} + +#popup-details .popover-actions button.solid { + padding: 1rem 2rem; +} + +#popup-details .popover-header .ui.header, +#popup-details .popover-body .ui.header, +#dynamic-filter .ui.header { + margin-bottom: 0; + color: #59A3BC; + font-weight: bold; +} + +#popup-details .popover-body a { + text-decoration: underline; +} + +#popup-details .popover-body .row { + margin-bottom: 1rem; +} + +#popup-details .popover-body .row:last-child { + margin-bottom: 0; +} + +#popup-details .popover-header .icon { + fill: #E16D5D !important; + cursor: pointer; +} + +#popup-details .popover-header .icon:hover { + fill: #c96052 !important; +} + +.ol-dynamic-filter { + position: absolute !important; + pointer-events: auto !important; + transform: none !important; + height: 100% !important; + top: 0 !important; + left: 6rem !important; +} + +.popover-header { + padding: .5rem .75rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-top-left-radius: calc(.3rem - 1px); + border-top-right-radius: calc(.3rem - 1px); +} + +.popover-actions { + text-align: center; + padding: 1rem 2rem; + background-color: #f7f7f7; + border-top: 1px solid #ebebeb; + border-bottom-left-radius: calc(.3rem - 1px); + border-bottom-right-radius: calc(.3rem - 1px); +} + +.popover-body { + padding: .5rem .75rem; +} + +.popover-body code { + font-size: 87.5%; + color: #e83e8c; + word-wrap: break-word; +} + +.ol-dynamic-filter #dynamic-filter { + display: block; + position: relative; + padding: 0; + background-color: #fff; + height: 100%; + min-width: 300px; + max-width: 300px; +} + +.ol-dynamic-filter #dynamic-filter .dynamic-filter-header, +.ol-dynamic-filter #dynamic-filter .dynamic-filter-body, +.ol-dynamic-filter #dynamic-filter .dynamic-filter-actions { + padding-bottom: 1rem; + padding-left: 2rem; + padding-right: 2rem; +} + +.ol-dynamic-filter #dynamic-filter .dynamic-filter-header { + padding-top: 3rem; +} + +.ol-dynamic-filter #dynamic-filter .dynamic-filter-body, +.ol-dynamic-filter #dynamic-filter .dynamic-filter-actions { + padding-top: 1rem; +} + +.ol-overlaycontainer-stopevent #dynamic-filter-toggle { + display: none; + top: 65px; + left: .5em; +} + +@media only screen and (max-width: 600px) { + .ol-dynamic-filter { + left: 0 !important; + width: 100% !important; + } + + .ol-dynamic-filter #dynamic-filter { + width: 0; + min-width: unset; + max-width: unset; + overflow: hidden; + transition: width .5s ease-in-out; + } + + .ol-dynamic-filter #dynamic-filter.show { + width: 100%; + } + + .ol-overlaycontainer-stopevent #dynamic-filter-toggle { + display: block; + } + + .ol-dynamic-filter #dynamic-filter .dynamic-filter-header, + .ol-dynamic-filter #dynamic-filter .dynamic-filter-body, + .ol-dynamic-filter #dynamic-filter .dynamic-filter-actions { + padding-left: 4rem; + padding-right: 4rem; + } +} + + +p.mb-1, +p.mb-1:first-child { + margin-bottom: 1rem; +} \ No newline at end of file