diff options
author | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-05-07 13:56:52 +0200 |
---|---|---|
committer | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-05-07 13:56:52 +0200 |
commit | 2c1f3727a703634cf62c63cfc4a3d4bb30fe2d9c (patch) | |
tree | c8f9f47f11f7ff239ee9d71bcccc9236316f1729 /sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx | |
parent | 3cb21ac46f62e5c03afef0584af8472a3bb6b13b (diff) |
Add customization of networkmap
Add customization capabilities to the networkmap
Issue-ID: CCSDK-2938
Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com>
Change-Id: Ibd3fe258d02939ea69b21de25569f20d9087f693
Diffstat (limited to 'sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx')
-rw-r--r-- | sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx | 593 |
1 files changed, 0 insertions, 593 deletions
diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx deleted file mode 100644 index 855e5cedf..000000000 --- a/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx +++ /dev/null @@ -1,593 +0,0 @@ -/** - * ============LICENSE_START======================================================================== - * ONAP : ccsdk feature sdnr wt odlux - * ================================================================================================= - * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. - * ================================================================================================= - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * ============LICENSE_END========================================================================== - */ - -import * as React from 'react' -import * as mapboxgl from 'mapbox-gl'; -import { RouteComponentProps, withRouter } from 'react-router-dom'; - - -import { Site } from '../model/site'; -import { SelectSiteAction, ClearHistoryAction, SelectLinkAction } from '../actions/detailsAction'; -import { OSM_STYLE, URL_API, URL_BASEPATH, URL_TILE_API } from '../config'; -import { link } from '../model/link'; -import MapPopup from './mapPopup'; -import { SetPopupPositionAction, SelectMultipleLinksAction, SelectMultipleSitesAction } from '../actions/popupActions'; -import { Feature } from '../model/Feature'; -import { HighlightLinkAction, HighlightSiteAction, SetCoordinatesAction, SetStatistics } from '../actions/mapActions'; -import { addDistance, getUniqueFeatures, increaseBoundingBox } from '../utils/mapUtils'; -import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; -import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect'; -import SearchBar from './searchBar'; -import { verifyResponse, IsTileServerReachableAction, handleConnectionError, setTileServerReachableAction } from '../actions/connectivityAction'; -import ConnectionInfo from './connectionInfo' -import { showIconLayers, addBaseLayers, addBaseSources, addIconLayers } from '../utils/mapLayers'; -import Statistics from './statistics'; -import IconSwitch from './iconSwitch'; -import { addImages } from '../services/mapImagesService'; -import { PopupElement } from '../model/popupElements'; - -type coordinates = { lat: number, lon: number, zoom: number } - -let alarmElements: Feature[] = []; -let map: mapboxgl.Map; -let isLoadingInProgress = false; -let notLoadedBoundingBoxes: mapboxgl.LngLatBounds[] = []; - -let lastBoundingBox: mapboxgl.LngLatBounds | null = null; -let myRef = React.createRef<HTMLDivElement>(); - - -class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { - - constructor(props: mapProps) { - super(props); - //any state stuff - this.state = { isPopupOpen: false } - - } - - componentDidMount() { - - // resize the map, if menu gets collapsed - window.addEventListener("menu-resized", this.handleResize); - - // try if connection to tile + topologyserver is available - - fetch(URL_TILE_API + '/10/0/0.png') - .then(res => { - if (res.ok) { - this.setupMap(); - this.props.setTileServerLoaded(true); - } else { - this.props.setTileServerLoaded(false); - console.error("tileserver " + URL_TILE_API + " can't be reached."); - } - }) - .catch(err => { - this.props.setTileServerLoaded(false); - console.error("tileserver " + URL_TILE_API + " can't be reached."); - }); - - fetch(URL_API + "/info/count/all") - .then(result => verifyResponse(result)) - .catch(error => this.props.handleConnectionError(error)); - } - - setupMap = () => { - - let lat = this.props.lat; - let lon = this.props.lon; - let zoom = this.props.zoom; - - const coordinates = this.extractCoordinatesFromUrl(); - // override lat/lon/zoom with coordinates from url, if available - if (this.areCoordinatesValid(coordinates)) { - lat = coordinates.lat; - lon = coordinates.lon; - zoom = !Number.isNaN(coordinates.zoom) ? coordinates.zoom : zoom; - } - - map = new mapboxgl.Map({ - container: myRef.current!, - style: OSM_STYLE as any, - center: [lon, lat], - zoom: zoom, - accessToken: '' - }); - - map.on('load', (ev) => { - - map.setMaxZoom(18); - const bbox = map.getBounds(); - this.props.updateMapPosition(bbox.getCenter().lat, bbox.getCenter().lng, map.getZoom()) - - addBaseSources(map, this.props.selectedSite, this.props.selectedLink); - - addImages(map, (result: boolean)=>{ - if(map.getZoom()>11) - { - addIconLayers(map, this.props.selectedSite?.properties.id) - }else{ - addBaseLayers(map, this.props.selectedSite, this.props.selectedLink); - } - }); - - const boundingBox = increaseBoundingBox(map); - - fetch(`${URL_API}/links/geojson/${boundingBox.west},${boundingBox.south},${boundingBox.east},${boundingBox.north}`) - .then(result => verifyResponse(result)) - .then(result => result.json()) - .then(features => { - if (map.getSource('lines')) { - (map.getSource('lines') as mapboxgl.GeoJSONSource).setData(features); - } - }) - .catch(error => this.props.handleConnectionError(error)); - - - fetch(`${URL_API}/sites/geojson/${boundingBox.west},${boundingBox.south},${boundingBox.east},${boundingBox.north}`) - .then(result => verifyResponse(result)) - .then(result => result.json()) - .then(features => { - if (map.getSource('points')) { - (map.getSource('points') as mapboxgl.GeoJSONSource).setData(features); - } - }) - .catch(error => this.props.handleConnectionError(error)); - }); - - map.on('click', (e: any) => { - - if (map.getLayer('points')) { // data is shown as points - - var clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], - [e.point.x + 5, e.point.y + 5]], { - layers: ['microwave-lines', 'fibre-lines'] - }), "id"); - - const clickedPoints = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['points'] }), "id"); - const alarmedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['alarmedPoints'] }), "id"); - - if (clickedPoints.length != 0) { - - - if (alarmedSites.length > 0) { - alarmedSites.forEach(alarm => { - const index = clickedPoints.findIndex(item => item.properties!.id === alarm.properties!.id); - - if (index !== -1) { - clickedPoints[index].properties!.alarmed = true; - clickedPoints[index].properties!.type = "alarmed"; - } - }); - } - - this.showSitePopup(clickedPoints, e.point.x, e.point.y); - } else if (clickedLines.length != 0) { - this.showLinkPopup(clickedLines, e.point.x, e.point.y); - } - - - } else { // data is shown as icons - - const clickedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-lamps', 'point-building', 'point-data-center', 'point-factory', 'point-remaining'] }), "id"); - const clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], - [e.point.x + 5, e.point.y + 5]], { - layers: ['microwave-lines', 'fibre-lines'] - }), "id"); - - if (clickedSites.length > 0) - this.showSitePopup(clickedSites, e.point.x, e.point.y); - else if (clickedLines.length != 0) { - this.showLinkPopup(clickedLines, e.point.x, e.point.y); - } - } - - }); - - map.on('moveend', () => { - - const mapZoom = Number(map.getZoom().toFixed(2)); - const lat = Number(map.getCenter().lat.toFixed(4)); - const lon = Number(map.getCenter().lng.toFixed(4)); - - - if (this.props.lat !== lat || this.props.lon !== lon || this.props.zoom !== mapZoom) { - this.props.updateMapPosition(lat, lon, mapZoom) - } - - // update the url to current lat,lon,zoom values - - const currentUrl = window.location.href; - const parts = currentUrl.split(URL_BASEPATH); - if(parts.length>0){ - - const detailsPath = parts[1].split("/details/"); - - if (detailsPath[1] !== undefined && detailsPath[1].length > 0) { - this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}/details/${detailsPath[1]}`) - } - else { - this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}`) - } - } - - - //switch icon layers if applicable - showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); - - //update statistics - const boundingBox = map.getBounds(); - - fetch(`${URL_API}/info/count/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`) - .then(result => verifyResponse(result)) - .then(res => res.json()) - .then(result => { - if (result.links !== this.props.linkCount || result.sites !== this.props.siteCount) { - this.props.setStatistics(result.links, result.sites); - } - }) - .catch(error => this.props.handleConnectionError(error));; - }) - - map.on('move', () => { - const mapZoom = map.getZoom(); - - const boundingBox = map.getBounds(); - - this.loadNetworkData(boundingBox); - if (mapZoom > 9) { - - if (map.getLayer('points')) { - map.setLayoutProperty('selectedPoints', 'visibility', 'visible'); - map.setPaintProperty('points', 'circle-radius', 7); - } - } else { - - // reduce size of points / lines if zoomed out - map.setPaintProperty('points', 'circle-radius', 2); - map.setLayoutProperty('selectedPoints', 'visibility', 'none'); - - if (mapZoom <= 4) { - map.setPaintProperty('fibre-lines', 'line-width', 1); - map.setPaintProperty('microwave-lines', 'line-width', 1); - - } else { - map.setPaintProperty('fibre-lines', 'line-width', 2); - map.setPaintProperty('microwave-lines', 'line-width', 2); - } - } - }); - } - - componentDidUpdate(prevProps: mapProps, prevState: {}) { - - if (map !== undefined) { - if (prevProps.selectedSite?.properties.id !== this.props.selectedSite?.properties.id) { - - if (this.props.selectedSite != null) { - if (map.getSource("selectedLine") !== undefined) { - (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); - (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [this.props.selectedSite] }); - } - - - if (map.getLayer('point-lamps') !== undefined) { - - map.setFilter('point-lamps', ['==', 'type', 'street lamp']); - map.setFilter('point-data-center', ['==', 'type', 'data center']); - map.setFilter('point-building', ['==', 'type', 'high rise building']); - map.setFilter('point-factory', ['==', 'type', 'factory']); - - if (this.props.selectedSite?.properties.type !== undefined) { - switch (this.props.selectedSite?.properties.type) { - case 'street lamp': - map.setFilter('point-lamps', ["all", ['==', 'type', 'street lamp'], ['!=', 'id', this.props.selectedSite.properties.id]]); - break; - case 'data center': - map.setFilter('point-data-center', ["all", ['==', 'type', 'data center'], ['!=', 'id', this.props.selectedSite.properties.id]]); - break; - case 'high rise building': - map.setFilter('point-building', ["all", ['==', 'type', 'high rise building'], ['!=', 'id', this.props.selectedSite.properties.id]]) - break; - case 'factory': - map.setFilter('point-factory', ["all", ['==', 'type', 'factory'], ['!=', 'id', this.props.selectedSite.properties.id]]); - break; - } - } - } - - - } - else - { - if (map.getSource("selectedPoints") !== undefined) - (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); - - } - } - - if (prevProps.selectedLink !== this.props.selectedLink) { - if (this.props.selectedLink != null) { - - if (map.getLayer('point-lamps') !== undefined) { - map.setFilter('point-lamps', ['==', 'type', 'street lamp']); - map.setFilter('point-data-center', ['==', 'type', 'data center']); - map.setFilter('point-building', ['==', 'type', 'high rise building']); - map.setFilter('point-factory', ['==', 'type', 'factory']); - } - - if (map.getSource("selectedLine") !== undefined) { - (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); - (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [this.props.selectedLink] }); - } - } - else - { - if (map.getSource("selectedLine") !== undefined) - (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); - } - } - - if (prevProps.location.pathname !== this.props.location.pathname) { - if (map) { - const coordinates = this.extractCoordinatesFromUrl(); - this.moveMapToCoordinates(coordinates); - } - } - - if (prevProps.alarmlement !== this.props.alarmlement) { - if (this.props.alarmlement !== null && !alarmElements.includes(this.props.alarmlement)) { - if (map.getSource("alarmedPoints")) - (map.getSource("alarmedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: alarmElements }); - alarmElements.push(this.props.alarmlement) - } - } - - if (prevProps.showIcons !== this.props.showIcons) { - if (map && map.getZoom() > 11) { - showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); - } - } - - if (prevProps.zoomToElement !== this.props.zoomToElement) { - if (this.props.zoomToElement !== null) { - const currentZoom = map?.getZoom(); - - map.flyTo({ - center: [ - this.props.zoomToElement.lon, - this.props.zoomToElement.lat - ], zoom: currentZoom < 10 ? 10 : currentZoom, - essential: true - }); - } - } - } - } - - componentWillUnmount(){ - window.removeEventListener("menu-resized", this.handleResize); - lastBoundingBox=null; - } - - handleResize = () => { - if (map) { - // wait a moment until resizing actually happened - window.setTimeout(() => map.resize(), 500); - } - } - - extractCoordinatesFromUrl = (): coordinates => { - const currentUrl = window.location.href; - const mainPathParts = currentUrl.split(URL_BASEPATH); - const coordinatePathPart = mainPathParts[1].split("/details/"); // split by details if present - const allCoordinates = coordinatePathPart[0].replace("/", ""); - const coordinates = allCoordinates.split(","); - return { lat: Number(coordinates[0]), lon: Number(coordinates[1]), zoom: Number(coordinates[2]) } - } - - areCoordinatesValid = (coordinates: coordinates) => { - - if ((!Number.isNaN(coordinates.lat)) && (!Number.isNaN(coordinates.lon))) { - return true; - } else { - return false; - } - } - - moveMapToCoordinates = (coordinates: coordinates) => { - - if (this.areCoordinatesValid(coordinates)) { - let zoom = -1; - - if (!Number.isNaN(coordinates.zoom)) { - zoom = coordinates.zoom; - } - - map.flyTo({ - center: [ - coordinates.lon, - coordinates.lat - ], zoom: zoom !== -1 ? zoom : this.props.zoom, - essential: true - }) - } - } - - loadNetworkData = async (bbox: mapboxgl.LngLatBounds) => { - if (!isLoadingInProgress) { // only load data if loading not in progress - isLoadingInProgress = true; - - if (lastBoundingBox == null) { - lastBoundingBox = bbox; - await this.draw('lines', `${URL_API}/links/geojson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); - await this.draw('points', `${URL_API}/sites/geojson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); - } else { - - // new bbox is bigger than old one - if (bbox.contains(lastBoundingBox.getNorthEast()) && bbox.contains(lastBoundingBox.getSouthWest()) && lastBoundingBox !== bbox) { //if new bb is bigger than old one - - lastBoundingBox = bbox; - - //calculate new boundingBox - const increasedBoundingBox = increaseBoundingBox(map); - - await this.draw('lines', `${URL_API}/links/geojson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); - await this.draw('points', `${URL_API}/sites/geojson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); - - } else if (lastBoundingBox.contains(bbox.getNorthEast()) && lastBoundingBox.contains(bbox.getSouthWest())) { // last one contains new one - // bbox is contained in last one, do nothing - isLoadingInProgress = false; - - } else { // bbox is not fully contained in old one, extend - - lastBoundingBox.extend(bbox); - - await this.draw('lines', `${URL_API}/links/geojson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); - await this.draw('points', `${URL_API}/sites/geojson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); - } - - } - - - if (notLoadedBoundingBoxes.length > 0) { // load last not loaded boundingbox - this.loadNetworkData(notLoadedBoundingBoxes.pop()!) - notLoadedBoundingBoxes = []; - } - - } else { - notLoadedBoundingBoxes.push(bbox); - } - } - - showSitePopup = (sites: mapboxgl.MapboxGeoJSONFeature[], top: number, left: number) => { - if (sites.length > 1) { - const elements: PopupElement[] = sites.map(feature => {return {name: feature.properties!.name, id: feature.properties!.id}}); - - this.props.setPopupPosition(top, left); - this.props.selectMultipleSites(elements); //name, id object container - this.setState({ isPopupOpen: true }); - - } else { - const id = sites[0].properties!.id; - - fetch(`${URL_API}/sites/${id}`) - .then(result => verifyResponse(result)) - .then(res => res.json() as Promise<Site>) - .then(result => { - this.props.selectSite(result); - this.props.highlightSite(result); - this.props.clearDetailsHistory(); - }) - .catch(error => this.props.handleConnectionError(error));; - } - } - - showLinkPopup = (links: mapboxgl.MapboxGeoJSONFeature[], top: number, left: number) => { - - if (links.length > 1) { - - const elements: PopupElement[] = links.map(feature => {return {name: feature.properties!.name, id: feature.properties!.id}}); - - this.props.setPopupPosition(top, left); - this.props.selectMultipleLinks(elements); - this.setState({ isPopupOpen: true }); - - } else { - var id = links[0].properties!.id; - - fetch(`${URL_API}/links/${id}`) - .then(result => verifyResponse(result)) - .then(res => res.json() as Promise<link>) - .then(result => { - this.props.selectLink(result); - this.props.highlightLink(result); - - this.props.clearDetailsHistory(); - }) - .catch(error => this.props.handleConnectionError(error));; - } - } - - draw = async (layer: string, url: string) => { - - fetch(url) - .then(result => verifyResponse(result)) - .then(res => res.json()) - .then(result => { - isLoadingInProgress = false; - if (map.getSource(layer)) { - (map.getSource(layer) as mapboxgl.GeoJSONSource).setData(result); - } - }) - .catch(error => this.props.handleConnectionError(error));; - } - - render() { - - return <> - - <div id="map" style={{ width: "70%", position: 'relative' }} ref={myRef} > - { - this.state.isPopupOpen && - <MapPopup onClose={() => { this.setState({ isPopupOpen: false }); }} /> - } - <SearchBar /> - <Statistics /> - <IconSwitch visible={this.props.zoom>11} /> - <ConnectionInfo /> - </div> - </> - } - -} - -type mapProps = RouteComponentProps & Connect<typeof mapStateToProps, typeof mapDispatchToProps>; - -const mapStateToProps = (state: IApplicationStoreState) => ({ - selectedLink: state.network.map.selectedLink, - selectedSite: state.network.map.selectedSite, - zoomToElement: state.network.map.zoomToElement, - alarmlement: state.network.map.alarmlement, - lat: state.network.map.lat, - lon: state.network.map.lon, - zoom: state.network.map.zoom, - linkCount: state.network.map.statistics.links, - siteCount: state.network.map.statistics.sites, - isTopoServerReachable: state.network.connectivity.isToplogyServerAvailable, - isTileServerReachable: state.network.connectivity.isTileServerAvailable, - showIcons: state.network.map.allowIconSwitch -}); - -const mapDispatchToProps = (dispatcher: IDispatcher) => ({ - selectSite: (site: Site) => dispatcher.dispatch(new SelectSiteAction(site)), - selectLink: (link: link) => dispatcher.dispatch(new SelectLinkAction(link)), - clearDetailsHistory: () => dispatcher.dispatch(new ClearHistoryAction()), - selectMultipleLinks: (ids: PopupElement[]) => dispatcher.dispatch(new SelectMultipleLinksAction(ids)), - selectMultipleSites: (ids: PopupElement[]) => dispatcher.dispatch(new SelectMultipleSitesAction(ids)), - setPopupPosition: (x: number, y: number) => dispatcher.dispatch(new SetPopupPositionAction(x, y)), - highlightLink: (link: link) => dispatcher.dispatch(new HighlightLinkAction(link)), - highlightSite: (site: Site) => dispatcher.dispatch(new HighlightSiteAction(site)), - updateMapPosition: (lat: number, lon: number, zoom: number) => dispatcher.dispatch(new SetCoordinatesAction(lat, lon, zoom)), - setStatistics: (linkCount: string, siteCount: string) => dispatcher.dispatch(new SetStatistics(siteCount, linkCount)), - setTileServerLoaded: (reachable: boolean) => dispatcher.dispatch(setTileServerReachableAction(reachable)), - handleConnectionError: (error: Error) => dispatcher.dispatch(handleConnectionError(error)) -}) - -export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Map));
\ No newline at end of file |