diff --git a/src/components/Methods/LayerConfig.tsx b/src/components/Methods/LayerConfig.tsx new file mode 100644 index 0000000..bfbe441 --- /dev/null +++ b/src/components/Methods/LayerConfig.tsx @@ -0,0 +1,137 @@ +// src/config/layerConfig.ts + +import { Style, Stroke, Fill } from 'ol/style'; + +export interface LayerConfig { + radius: number; + topic: string; + getUrl: (lon: number, lat: number, radius: number) => string; + style: Style; +} + +const buildUrl = + (topic: string) => + (lon: number, lat: number, radius: number) => + `https://geo.sandag.org/server/rest/services/Hosted/${topic}/FeatureServer/0/query?geometry=${lon},${lat}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelIntersects&distance=${radius}&units=esriSRUnit_Meter&outFields=*&returnGeometry=true&f=geojson`; + +const baseConfigs: Omit[] = [ + { + radius: 1, + topic: 'Parcels', + style: new Style({ + stroke: new Stroke({ color: 'green', width: 1.5 }), + fill: new Fill({ color: 'rgba(0, 255, 0, 0.1)' }), + }), + }, + { + radius: 100, + topic: 'Sewer_Main_SD', + style: new Style({ + stroke: new Stroke({ color: 'purple', width: 2 }), + }), + }, + { + radius: 50, + topic: 'Zoning_Base_SD', + style: new Style({ + stroke: new Stroke({ color: 'red', width: 1 }), + }), + }, + { + radius: 50, + topic: 'Water_Main_SD', + style: new Style({ + stroke: new Stroke({ color: 'blue', width: 5 }), + }), + }, + { + radius: 1000, + topic: 'Sustainable_Development_Areas', + style: new Style({ + stroke: new Stroke({ color: 'green', width: 3 }), + }), + }, + { + radius: 1000, + topic: 'Housing_Solution_Areas', + style: new Style({ + stroke: new Stroke({ color: 'black', width: 2.5 }), + fill: new Fill({ color: 'rgba(255, 200, 0, 0.1)' }), + }), + }, + { + radius: 100000, + topic: 'Promise_Zones_SD', + style: new Style({ + stroke: new Stroke({ color: 'black', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + }, + { + radius: 100000, + topic: 'MHPA_SD', + style: new Style({ + stroke: new Stroke({ color: 'orange', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + }, + { + radius: 100000, + topic: 'Coastal_Zones', + style: new Style({ + stroke: new Stroke({ color: 'skin', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + }, + { + radius: 100000, + topic: 'Community_Plan_Implementation_Overlay_Zone_SD', + style: new Style({ + stroke: new Stroke({ color: 'darkblue', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + + }, + { + radius: 100000, + topic: 'Airport_Influence_Area', + style: new Style({ + stroke: new Stroke({ color: 'darkyellow', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + + }, + { + radius: 100000, + topic: 'Historic_Districts_SD', + style: new Style({ + stroke: new Stroke({ color: 'white', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + + }, + { + radius: 100000, + topic: 'HRB_Designated_Resources_SD', + style: new Style({ + stroke: new Stroke({ color: 'darkgreen', width: 2.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + + }, + { + radius: 100000, + topic: 'Fire_Hazard_Severity_Zones_SD', + style: new Style({ + stroke: new Stroke({ color: 'yellow', width: 1.5 }), + fill: new Fill({ color: 'rgba(116, 3, 255, 0.1)' }), + }), + + }, + +]; + +export const layerConfigs: LayerConfig[] = baseConfigs.map(cfg => ({ + ...cfg, + getUrl: buildUrl(cfg.topic), +})); diff --git a/src/components/OpenLayerMap.tsx b/src/components/OpenLayerMap.tsx index fa002b0..ce5d3f8 100644 --- a/src/components/OpenLayerMap.tsx +++ b/src/components/OpenLayerMap.tsx @@ -8,12 +8,11 @@ import { Coordinate } from 'ol/coordinate'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import Style from 'ol/style/Style'; -import Stroke from 'ol/style/Stroke'; -import Fill from 'ol/style/Fill'; +import { layerConfigs } from './Methods/LayerConfig'; import Icon from 'ol/style/Icon'; import Point from 'ol/geom/Point'; import Feature from 'ol/Feature'; -import {loadAndRenderGeoJsonLayer} from './Methods/Layers' +import { loadAndRenderGeoJsonLayer } from './Methods/Layers' const OpenLayersMap = () => { const [term, setTerm] = useState(''); @@ -38,74 +37,67 @@ const OpenLayersMap = () => { const [clickedCoordinate, setClickedCoordinate] = useState(); const mapRef = useRef(null); const markerLayerRef = useRef(null); - const parcelLayerRef = useRef(null); - const sewerLayerRef = useRef(null); + const layerRefs = useRef>>( + Object.fromEntries( + layerConfigs.map((layer) => [layer.topic, { current: null }]) + ) + ); -useEffect(() => { - if (!mapRef.current) { - const map = new Map({ - target: mapDivRef.current as HTMLDivElement, - layers: [new TileLayer({ source: new OSM() })], - }); - mapRef.current = map; + useEffect(() => { + if (!mapRef.current) { + const map = new Map({ + target: mapDivRef.current as HTMLDivElement, + layers: [new TileLayer({ source: new OSM() })], + }); + mapRef.current = map; - map.on('click', (e) => { - setClickedCoordinate(e.coordinate); - }); - } - - if (address && address.length > 0) { - const lat = parseFloat(address[0].lat); - const lon = parseFloat(address[0].lon); - const coords = fromLonLat([lon, lat]); - - mapRef.current!.setView(new View({ - center: coords, - zoom: 15, - })); - - const markerFeature = new Feature({ - geometry: new Point(coords), - }); - - markerFeature.setStyle(new Style({ - image: new Icon({ - anchor: [0.5, 1], - src: 'https://cdn-icons-png.flaticon.com/512/684/684908.png', - scale: 0.05, - }), - })); - - const markerSource = new VectorSource({ features: [markerFeature] }); - const markerLayer = new VectorLayer({ source: markerSource }); - - if (markerLayerRef.current) { - mapRef.current!.removeLayer(markerLayerRef.current); + map.on('click', (e) => { + setClickedCoordinate(e.coordinate); + }); } - mapRef.current!.addLayer(markerLayer); - markerLayerRef.current = markerLayer; - const radius = 1; - const parcelUrl = `https://geo.sandag.org/server/rest/services/Hosted/Parcels/FeatureServer/0/query?geometry=${lon},${lat}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelIntersects&distance=${radius}&units=esriSRUnit_Meter&outFields=*&returnGeometry=true&f=geojson`; - const sewerUrl = `https://geo.sandag.org/server/rest/services/Hosted/Sewer_Main_SD/FeatureServer/0/query?geometry=${lon},${lat}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelIntersects&distance=${radius}&units=esriSRUnit_Meter&outFields=*&returnGeometry=true&f=geojson`; - loadAndRenderGeoJsonLayer( - parcelUrl, - mapRef.current!, - parcelLayerRef, - new Style({ - stroke: new Stroke({ color: 'green', width: 1.5 }), - fill: new Fill({ color: 'rgba(0, 255, 0, 0.1)' }), - }) - ); + if (address && address.length > 0) { + const lat = parseFloat(address[0].lat); + const lon = parseFloat(address[0].lon); + const coords = fromLonLat([lon, lat]); - loadAndRenderGeoJsonLayer( - sewerUrl, - mapRef.current!, - sewerLayerRef, - new Style({ - stroke: new Stroke({ color: 'blue', width: 2 }), - }) - ); + mapRef.current!.setView(new View({ + center: coords, + zoom: 15, + })); + + const markerFeature = new Feature({ + geometry: new Point(coords), + }); + + markerFeature.setStyle(new Style({ + image: new Icon({ + anchor: [0.5, 1], + src: 'https://cdn-icons-png.flaticon.com/512/684/684908.png', + scale: 0.05, + }), + })); + + const markerSource = new VectorSource({ features: [markerFeature] }); + const markerLayer = new VectorLayer({ source: markerSource }); + + if (markerLayerRef.current) { + mapRef.current!.removeLayer(markerLayerRef.current); + } + mapRef.current!.addLayer(markerLayer); + markerLayerRef.current = markerLayer; + + layerConfigs.forEach((layerConfig) => { + const url = layerConfig.getUrl(lon, lat, layerConfig.radius); + const ref = layerRefs.current[layerConfig.topic]; + + loadAndRenderGeoJsonLayer( + url, + mapRef.current!, + ref, + layerConfig.style + ); + }); } }, [address]);