diff --git a/package.json b/package.json index 13a8e76d..68001008 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sitrep", - "version": "24.1.0", + "version": "24.1.1", "private": true, "dependencies": { "@apollo/client": "^3.8.10", @@ -8,7 +8,7 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", - "@mapbox/mapbox-gl-draw": "~1.3.0", + "@mapbox/mapbox-gl-draw": "^1.3.0", "@svgr/webpack": "^8.1.0", "@testing-library/dom": "^9.3.4", "@turf/bearing": "^6.5.0", diff --git a/public/index.html b/public/index.html index 7220d2ff..2b64f0da 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,7 @@ + content="default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; style-src-attr 'self'; child-src 'none'; worker-src 'self' blob:; script-src-elem 'self' https://api.mapbox.com; connect-src 'self' ws://* wss://* https://*;" /> diff --git a/src/components/map/EnrichedLayerFeatures.tsx b/src/components/map/EnrichedLayerFeatures.tsx new file mode 100644 index 00000000..0c7dc8fc --- /dev/null +++ b/src/components/map/EnrichedLayerFeatures.tsx @@ -0,0 +1,134 @@ +import bearing from '@turf/bearing'; +import { point } from '@turf/helpers'; +import { BabsIcon, Schaeden, Others } from 'components/BabsIcons'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; +import { Layer, Source } from "react-map-gl"; + +const enrichFeature = (f: Feature): Feature[] => { + + if (f === undefined) { + return [] + } + + let features: Feature[] = []; + + if (f.geometry.type === "LineString") { + let enrich: EnrichLineConfig | undefined = EnrichLineStringMap[f.properties?.lineType] + if (enrich !== undefined) { + if (enrich.iconStart) { + let startPoint = point(f.geometry.coordinates[0]); + startPoint.id = f.id + ":start"; + startPoint.properties = { + parent: f.id, + icon: enrich.iconStart.name, + iconRotation: bearing(point(f.geometry.coordinates[0]), point(f.geometry.coordinates[1])) + enrich.iconRotation, + } + features.push(startPoint) + } + + if (enrich.iconEnd) { + let endPoint = point(f.geometry.coordinates.slice(-1)[0]); + endPoint.id = f.id + ":end"; + endPoint.properties = { + parent: f.id, + icon: enrich.iconEnd.name, + iconRotation: bearing(f.geometry.coordinates.slice(-1)[0], point(f.geometry.coordinates.slice(-2)[0])) + enrich.iconRotation, + }; + features.push(endPoint); + } + } + } + + return features +} + +type EnrichLineConfig = { + iconStart?: BabsIcon; + iconEnd?: BabsIcon; + iconRotation: number; +} + +const EnrichLineStringMap: { [key: string]: EnrichLineConfig } = { + "begehbar": { + iconStart: Schaeden.Beschaedigung, + iconEnd: Schaeden.Beschaedigung, + iconRotation: 90, + }, + "schwerBegehbar": { + iconStart: Schaeden.Teilzerstoerung, + iconEnd: Schaeden.Teilzerstoerung, + iconRotation: 90, + }, + "unpassierbar": { + iconStart: Schaeden.Totalzerstoerung, + iconEnd: Schaeden.Totalzerstoerung, + iconRotation: 90, + }, + "beabsichtigteErkundung": { + iconStart: undefined, + iconEnd: Others.Verschiebung, + iconRotation: 90, + }, + "durchgeführteErkundung": { + iconStart: undefined, + iconEnd: Others.Verschiebung, + iconRotation: 90, + }, + "beabsichtigteVerschiebung": { + iconStart: undefined, + iconEnd: Others.Verschiebung, + iconRotation: 90, + }, + "rettungsAchse": { + iconStart: undefined, + iconEnd: Others.Verschiebung, + iconRotation: 90, + }, + "durchgeführteVerschiebung": { + iconStart: undefined, + iconEnd: Others.Verschiebung, + iconRotation: 90, + }, + "beabsichtigterEinsatz": { + iconStart: undefined, + iconEnd: Others.Einsatz, + iconRotation: 90, + }, + "durchgeführterEinsatz": { + iconStart: undefined, + iconEnd: Others.Einsatz, + iconRotation: 90, + }, +} + + + +const EnrichedSymbolSource = (props: EnrichedFeaturesProps) => { + let enrichedFC: FeatureCollection = { "type": "FeatureCollection", "features": [] }; + enrichedFC.features = Object.assign([], props.featureCollection.features.filter(f => f.properties?.deletedAt === undefined).filter(f => f.id !== props.selectedFeature).flatMap(f => enrichFeature(f))) + + return + + +} + +export const EnrichedFeaturesSource = (props: EnrichedFeaturesProps) => { + + return <> + + +} + +interface EnrichedFeaturesProps { + featureCollection: FeatureCollection; + selectedFeature: string | number | undefined +} + +export default EnrichedFeaturesSource; \ No newline at end of file diff --git a/src/views/map/FeatureDetails.tsx b/src/views/map/FeatureDetails.tsx index a205ff9c..33708dbb 100644 --- a/src/views/map/FeatureDetails.tsx +++ b/src/views/map/FeatureDetails.tsx @@ -1,6 +1,6 @@ import bearing from "@turf/bearing"; import { LineString, point } from "@turf/helpers"; -import { BabsIcon, IconGroups, Others, Schaeden } from "components/BabsIcons"; +import { BabsIcon, IconGroups, } from "components/BabsIcons"; import { Feature, GeoJsonProperties } from "geojson"; import { isEmpty, isUndefined, omitBy } from "lodash"; import { SetStateAction, memo, useCallback, useEffect, useState } from "react"; @@ -79,7 +79,7 @@ function FeatureDetail(props: { onUpdate: (e: any) => void, feature: Feature | u return (
-

Eigenschaften

+ < h3 className='title is-size-5' > Eigenschaften {feature && feature.geometry.type === "Point" ?
@@ -184,40 +184,40 @@ const ZoneTypes: SelectableTypes = { const LineTypes: SelectableTypes = { "Rutschgebiet": { - name: "Rutschgebiet", description: "Rutschgebiet", color: Colors.Red, icon: undefined, + name: "Rutschgebiet", description: "Rutschgebiet", color: Colors.Red, }, "RutschgebietGespiegelt": { - name: "RutschgebietGespiegelt", description: "Rutschgebiet (umgekehrt)", color: Colors.Red, icon: undefined, + name: "RutschgebietGespiegelt", description: "Rutschgebiet (umgekehrt)", color: Colors.Red, }, "begehbar": { - name: "begehbar", description: "Strasse erschwert befahrbar / begehbar", color: Colors.Red, icon: Schaeden.Beschaedigung, + name: "begehbar", description: "Strasse erschwert befahrbar / begehbar", color: Colors.Red, }, "schwerBegehbar": { - name: "schwerBegehbar", description: "Strasse nicht befahrbar / schwer Begehbar", color: Colors.Red, icon: Schaeden.Teilzerstoerung, + name: "schwerBegehbar", description: "Strasse nicht befahrbar / schwer Begehbar", color: Colors.Red, }, "unpassierbar": { - name: "unpassierbar", description: "Strasse unpassierbar / gesperrt", color: Colors.Red, icon: Schaeden.Totalzerstoerung, + name: "unpassierbar", description: "Strasse unpassierbar / gesperrt", color: Colors.Red, }, "beabsichtigteErkundung": { - name: "beabsichtigteErkundung", description: "Beabsichtigte Erkundung", color: Colors.Blue, icon: Others.Verschiebung, + name: "beabsichtigteErkundung", description: "Beabsichtigte Erkundung", color: Colors.Blue, }, "durchgeführteErkundung": { - name: "durchgeführteErkundung", description: "Durchgeführte Erkundung", color: Colors.Blue, icon: Others.Verschiebung, + name: "durchgeführteErkundung", description: "Durchgeführte Erkundung", color: Colors.Blue, }, "beabsichtigteVerschiebung": { - name: "beabsichtigteVerschiebung", description: "Beabsichtigte Verschiebung", color: Colors.Blue, icon: Others.Verschiebung, + name: "beabsichtigteVerschiebung", description: "Beabsichtigte Verschiebung", color: Colors.Blue, }, "rettungsAchse": { - name: "rettungsAchse", description: "Rettungs Achse", color: Colors.Blue, icon: Others.Verschiebung, + name: "rettungsAchse", description: "Rettungs Achse", color: Colors.Blue, }, "durchgeführteVerschiebung": { - name: "durchgeführteVerschiebung", description: "Durchgeführte Verschiebung", color: Colors.Blue, icon: Others.Verschiebung, + name: "durchgeführteVerschiebung", description: "Durchgeführte Verschiebung", color: Colors.Blue, }, "beabsichtigterEinsatz": { - name: "beabsichtigterEinsatz", description: "Beabsichtigter Einsatz", color: Colors.Blue, icon: Others.Einsatz, + name: "beabsichtigterEinsatz", description: "Beabsichtigter Einsatz", color: Colors.Blue, }, "durchgeführterEinsatz": { - name: "durchgeführterEinsatz", description: "Durchgeführter Einsatz", color: Colors.Blue, icon: Others.Einsatz, + name: "durchgeführterEinsatz", description: "Durchgeführter Einsatz", color: Colors.Blue, }, }; diff --git a/src/views/map/Map.tsx b/src/views/map/Map.tsx index 84b5f560..cdf89b46 100644 --- a/src/views/map/Map.tsx +++ b/src/views/map/Map.tsx @@ -4,7 +4,7 @@ import "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css"; import DefaultMaker from 'assets/marker.svg'; import { AllIcons, LinePatterns, ZonePatterns } from 'components/BabsIcons'; -import { Feature, FeatureCollection, Geometry, GeoJsonProperties } from 'geojson'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; import hat from 'hat'; import { isEqual, unionBy } from 'lodash'; import isEmpty from 'lodash/isEmpty'; @@ -15,13 +15,14 @@ import { FullscreenControl, Map, MapRef, NavigationControl, ScaleControl } from import { useParams } from 'react-router-dom'; import Notification from 'utils/Notification'; import useLocalStorage from 'utils/useLocalStorage'; +import FeatureDetail from './FeatureDetails'; import './control-panel.css'; import DrawControl from './controls/DrawControl'; import ExportControl from './controls/ExportControl'; -import FeatureDetailControlPanel from './controls/FeatureDetailControl'; +import FeatureDetailControl from './controls/FeatureDetailControl'; import StyleSwitcherControl from './controls/StyleSwitcherControl'; -import FeatureDetail from './FeatureDetails'; -import style from './style'; +import { drawStyle } from './style'; +import EnrichedLayerFeatures from 'components/map/EnrichedLayerFeatures'; const modes = { ...MapboxDraw.modes, @@ -45,13 +46,9 @@ function MapComponent() { const { incidentId } = useParams(); const [features, setFeatures] = useLocalStorage(`map-incident-${incidentId}`, { "type": "FeatureCollection", "features": [], }); - // const [features, setFeatures] = useState({ "type": "FeatureCollection", "features": [] }); - - const onCreate = useCallback((e: { features: Feature[]; }) => { + const onCreate = useCallback((e: any) => { setFeatures(curFeatureCollection => { - console.log("[update]: current features created", e) - const newFeatureCollection = { ...curFeatureCollection }; const createdFeatures: Feature[] = e.features; createdFeatures.forEach(f => { @@ -60,14 +57,14 @@ function MapComponent() { newFeatureCollection.features.push(f); } }) - - console.log("Creating feature", createdFeatures) newFeatureCollection.features = unionBy(newFeatureCollection.features, curFeatureCollection.features, 'id'); return newFeatureCollection; }); }, [setFeatures]); - const onUpdate = useCallback((e: { features: Feature[]; }) => { + const onUpdate = useCallback((e: any) => { + console.log("[onUpdate]", e) + setFeatures(curFeatureCollection => { // an update creates a deleted feature with the old properties and adds a new one with the new properties const newFeatureCollection = { ...curFeatureCollection }; @@ -76,22 +73,18 @@ function MapComponent() { const updatedFeatures: Feature[] = e.features; const modifiedFeatures: Feature[] = []; updatedFeatures.forEach(f => { - console.log("[update]: current features updated", e) if (f.properties) { // fetch the old element let cur: Feature | undefined = curFeatureCollection.features.find(c => c.id === f.id) // make sure the old element is not identical to the current if (cur && isEqual(cur, f) && isEqual(cur?.properties, f?.properties)) { - console.log("[update]: current ", cur) - console.log("[update]: identical") return; } // if we found the old one and it got changed, close it if (cur && cur.properties) { cur.properties['deletedAt'] = new Date(); - console.log("[update] storing deleted feature", cur) modifiedFeatures.push(cur); } @@ -99,24 +92,20 @@ function MapComponent() { f.id = hat(); f.properties['createdAt'] = new Date(); f.properties['achestorID'] = cur?.id; - console.log("[update] storing added feature", f) - modifiedFeatures.push(f); } }); - console.log("[update] modified features", modifiedFeatures) - newFeatureCollection.features = [...curFeatureCollection.features, ...modifiedFeatures]; - console.log("[update] resulting feature collection", newFeatureCollection) return newFeatureCollection; }); + }, [setFeatures]); - const onDelete = useCallback((e: { features: Feature[]; }) => { - setFeatures(curFeatureCollection => { - console.log("[delete]: current features updated", e) + const onDelete = useCallback((e: any) => { + console.log("[onDelete]", e); + setFeatures(curFeatureCollection => { const newFeatureCollection = { ...curFeatureCollection }; const deletedFeatures: Feature[] = e.features; deletedFeatures.forEach(f => { @@ -125,7 +114,7 @@ function MapComponent() { let cur: Feature | undefined = curFeatureCollection.features.find(c => c.id === f.id) if (cur && cur.properties) { cur.properties['deletedAt'] = new Date(); - newFeatureCollection.features.push(cur); + newFeatureCollection.features.push(f); } } }); @@ -133,47 +122,38 @@ function MapComponent() { return newFeatureCollection; }); - }, [setFeatures]); - - const onCombine = useCallback((e: { createdFeatures: Feature[]; deletedFeatures: Feature[]; }) => { - console.log("onCombine", e); - setFeatures(curFeatureCollection => { - const createdFeatures: Feature[] = e.createdFeatures; - const deletedFeatures: Feature[] = e.deletedFeatures; - deletedFeatures.forEach(f => { if (f.properties) { f.properties['deletedAt'] = Date.now() } }) - createdFeatures.forEach(f => { if (f.properties) { f.properties['createdAt'] = Date.now() } }) - - const newFeatureCollection = { ...curFeatureCollection }; - - // newFeatureCollection.features = pullAllBy(curFeatureCollection.features, deletedFeatures, 'id'); - newFeatureCollection.features = unionBy(createdFeatures, newFeatureCollection.features, 'id'); - return newFeatureCollection; - }); - }, [setFeatures]); + setSelectedFeature(undefined); + }, [setFeatures, setSelectedFeature]); const onSelectionChange = useCallback((e: { features: Feature[]; }) => { + console.log("[onSelectionChange]", e) const features: Feature[] = e.features; - if (features.length === 1) { - setSelectedFeature(features[0].id); + if (features.length >= 1) { + const feature = features[0]; + // always work on the parent feature + if (feature.properties?.parent) { + setSelectedFeature(feature.properties.parent); + draw?.changeMode('simple_select', { featureIds: [feature.properties.parent] }) + return + } + setSelectedFeature(feature.id); } else { setSelectedFeature(undefined); } - }, [setSelectedFeature]); + }, [setSelectedFeature, draw]); useEffect(() => { if (!mapRef || !isMapLoaded || !draw || !features || isEmpty(features.features)) { return; } - - console.log("current features", features) let filteredFC: FeatureCollection = { "type": "FeatureCollection", "features": [] }; + filteredFC.features = Object.assign([], features.features.filter(f => f.properties?.deletedAt === undefined)) - console.log("applied features", filteredFC) draw.set(filteredFC); - }, [draw, mapRef, features, isMapLoaded]); + }, [draw, mapRef, features, isMapLoaded, selectedFeature]); const onMapLoad = useCallback(() => { // Add the default marker @@ -225,14 +205,14 @@ function MapComponent() { position="top-right" setDraw={setDraw} displayControlsDefault={false} - styles={style} + styles={drawStyle} controls={{ polygon: true, trash: true, point: true, line_string: true, - combine_features: true, - uncombine_features: true, + combine_features: false, + uncombine_features: false, }} boxSelect={false} clickBuffer={10} @@ -241,10 +221,12 @@ function MapComponent() { onCreate={onCreate} onUpdate={onUpdate} onDelete={onDelete} - onCombine={onCombine} + // onCombine={onCombine} onSelectionChange={onSelectionChange} userProperties={true} /> + + { onMapLoad(); return true } } }} /> - f.id === selectedFeature).shift()}> + f.id === selectedFeature).shift()}> f.id === selectedFeature).shift()} /> - +
diff --git a/src/views/map/controls/DrawControl.tsx b/src/views/map/controls/DrawControl.tsx index b0a19cc6..913b7a1e 100644 --- a/src/views/map/controls/DrawControl.tsx +++ b/src/views/map/controls/DrawControl.tsx @@ -7,11 +7,11 @@ import type { ControlPosition } from "react-map-gl/maplibre"; type DrawControlProps = ConstructorParameters[0] & { position?: ControlPosition; setDraw: Dispatch> - onCreate: (evt: any) => void; - onUpdate: (evt: any) => void; - onDelete: (evt: any) => void; - onCombine: (evt: any) => void; - onSelectionChange: (evt: any) => void; + onCreate: (e: any) => void; + onUpdate: (e: any) => void; + onDelete: (e: any) => void; + onCombine: (e: any) => void; + onSelectionChange: (e: any) => void; }; function DrawControl(props: DrawControlProps) { @@ -24,12 +24,15 @@ function DrawControl(props: DrawControlProps) { useControl( ({ map }) => { - map.on("draw.create", props.onCreate); - map.on("draw.update", props.onUpdate); - map.on("draw.combine", props.onCombine); - map.on("draw.uncombine", props.onCombine); - map.on("draw.delete", props.onDelete); - map.on("draw.selectionchange", props.onSelectionChange) + + // map.on("draw.create", (e) => console.log("onCreate:", e)); + // map.on("draw.update", (e) => console.log("onUpdate:", e)); + map.on("draw.create", (e) => props.onCreate(e)); + map.on("draw.update", (e) => props.onUpdate(e)); + map.on("draw.combine", (e) => props.onCombine(e)); + map.on("draw.uncombine", (e) => props.onCombine(e)); + map.on("draw.delete", (e) => props.onDelete(e)); + map.on("draw.selectionchange", (e) => props.onSelectionChange(e)) const draw = new MapboxDraw(props); setDraw(draw); @@ -37,11 +40,12 @@ function DrawControl(props: DrawControlProps) { return draw; }, ({ map }) => { - map.off("draw.create", props.onCreate); - map.off("draw.update", props.onUpdate); - map.off("draw.combine", props.onCombine); - map.off("draw.uncombine", props.onCombine); - map.off("draw.delete", props.onDelete); + map.off("draw.create", (e) => props.onCreate(e)); + map.off("draw.update", (e) => props.onUpdate(e)); + map.off("draw.combine", (e) => props.onCombine(e)); + map.off("draw.uncombine", (e) => props.onCombine(e)); + map.off("draw.delete", (e) => props.onDelete(e)); + map.off("draw.selectionchange", (e) => props.onSelectionChange(e)) }, { position: props.position @@ -54,9 +58,9 @@ function DrawControl(props: DrawControlProps) { DrawControl.defaultProps = { // eslint-disable-next-line @typescript-eslint/no-empty-function - onCreate: () => { }, + onCreate: (e: any) => console.log("onCreate:", e), // eslint-disable-next-line @typescript-eslint/no-empty-function - onUpdate: () => { }, + onUpdate: (e: any) => console.log("onCreate:", e), // eslint-disable-next-line @typescript-eslint/no-empty-function onDelete: () => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/src/views/map/style.ts b/src/views/map/style.ts index b2a3c715..cc0da34c 100644 --- a/src/views/map/style.ts +++ b/src/views/map/style.ts @@ -1,5 +1,5 @@ -export const style = [ +export const drawStyle = [ { 'id': 'gl-draw-polygon-no-fill-pattern', 'type': 'fill', @@ -464,4 +464,456 @@ export const style = [ } ]; -export default style; \ No newline at end of file +export const displayStyle = [ + + { + 'id': 'gl-polygon-special-fill-pattern', + 'type': 'fill', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'Polygon'], + ['has', 'zoneType'], + ['in', 'zoneType', 'Brandzone', 'Zerstoerung'], + ['!=', 'mode', 'static'] + ], + 'paint': { + 'fill-pattern': ['match', ['get', 'zoneType'], 'Brandzone', 'PatternBrandzone', 'Zerstoerung', 'PatternZerstoert', 'PatternBrandzone'], + 'fill-opacity': 0.9 + } + }, + { + 'id': 'gl-polygon-fill-inactive', + 'type': 'fill', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'Polygon'], + ['!in', 'zoneType', 'Brandzone', 'Zerstoerung', 'Schadengebiet', 'Einsatzraum'], + ['!=', 'mode', 'static'] + ], + 'paint': { + 'fill-color': ['coalesce', ['get', 'color'], '#000000'], + 'fill-outline-color': ['coalesce', ['get', 'color'], '#000000'], + 'fill-opacity': 0.5 + } + }, + { + 'id': 'gl-polygon-fill-active', + 'type': 'fill', + 'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']], + 'paint': { + 'fill-color': '#fbb03b', + 'fill-outline-color': '#fbb03b', + 'fill-opacity': 0.3 + } + }, + { + 'id': 'gl-polygon-midpoint', + 'type': 'circle', + 'filter': ['all', + ['==', '$type', 'Point'], + ['==', 'meta', 'midpoint']], + 'paint': { + 'circle-radius': 4, + 'circle-color': '#fbb03b' + } + }, + { + 'id': 'gl-polygon-stroke-inactive', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'Polygon'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': ['coalesce', ['get', 'color'], '#000000'], + 'line-width': 2 + } + }, + { + 'id': 'gl-polygon-stroke-active', + 'type': 'line', + 'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': '#fbb03b', + 'line-dasharray': [0.2, 2], + 'line-width': 2 + } + }, + { + 'id': 'gl-line-inactive', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['!has', 'lineType'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': ['coalesce', ['get', 'color'], '#000000'], + 'line-opacity': 0.7, + 'line-width': 2, + } + }, + { + 'id': 'gl-line-inactive-normalLine', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['in', 'lineType', '', 'normal'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': ['coalesce', ['get', 'color'], '#000000'], + 'line-opacity': 0.7, + 'line-width': 2, + } + }, + { + 'id': 'gl-line-inactive-pattern', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['in', 'lineType', 'unpassierbar', 'beabsichtigteErkundung', 'durchgeführteErkundung', 'Rutschgebiet', 'RutschgebietGespiegelt', 'rettungsAchse'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-pattern': ['match', ['get', 'lineType'], 'unpassierbar', 'PatternLineUnpassierbar', 'beabsichtigteErkundung', 'PatternLineBeabsichtigteErkundung', 'durchgeführteErkundung', 'PatternLineErkundung', 'Rutschgebiet', 'PatternLineRutschgebiet', 'RutschgebietGespiegelt', 'PatternLineRutschgebietGespiegelt', 'PatternLineUnpassierbar', 'rettungsAchse', 'PatternLineRettungsachse'], + 'line-opacity': 0.7, + 'line-width': ['interpolate', ['exponential', 1], ['zoom'], 12, 2, 19, 22], + } + }, + { + 'id': 'gl-line-inactive-solidlines', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['in', 'lineType', 'schwerBegehbar', 'durchgeführteVerschiebung', 'durchgeführterEinsatz'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': ['coalesce', ['get', 'color'], '#000000'], + 'line-opacity': 0.7, + 'line-width': 2, + } + }, + { + 'id': 'gl-line-inactive-dashlines', + 'type': 'line', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['in', 'lineType', 'begehbar', 'beabsichtigteVerschiebung', 'beabsichtigterEinsatz'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': ['coalesce', ['get', 'color'], '#000000'], + 'line-dasharray': [6, 4], + 'line-width': 2, + } + }, + { + 'id': 'gl-line-symbol', + 'type': 'symbol', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['==', 'meta', 'feature'], + ['has', 'icon'], + ['!has', 'iconRotation'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'icon-image': ["get", "icon"], + 'icon-allow-overlap': true, + 'icon-size': ['interpolate', ['linear'], ['zoom'], 12, 0.1, 17, 1], + } + }, + { + 'id': 'gl-line-symbol-active', + 'type': 'symbol', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'LineString'], + ['==', 'meta', 'feature'], + ['has', 'iconRotation'], + ['has', 'icon'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'icon-image': ["get", "icon"], + 'icon-size': ['interpolate', ['linear'], ['zoom'], 12, 0.1, 17, 1], + 'icon-allow-overlap': true, + 'icon-rotation-alignment': 'map', + 'icon-pitch-alignment': 'map', + 'icon-rotate': ['coalesce', ["get", "iconRotation"], 0], + } + }, + { + 'id': 'gl-line-active', + 'type': 'line', + 'filter': ['all', + ['==', '$type', 'LineString'], + ['==', 'active', 'true'] + ], + 'layout': { + 'line-cap': 'round', + 'line-join': 'round' + }, + 'paint': { + 'line-color': '#fbb03b', + 'line-dasharray': [0.2, 2], + 'line-width': 2 + } + }, + { + 'id': 'gl-polygon-and-line-vertex-stroke-inactive', + 'type': 'circle', + 'filter': ['all', + ['==', 'meta', 'vertex'], + ['==', '$type', 'Point'], + ['!=', 'mode', 'static'] + ], + 'paint': { + 'circle-radius': 5, + 'circle-color': '#fff' + } + }, + { + 'id': 'gl-polygon-and-line-vertex-inactive', + 'type': 'circle', + 'filter': ['all', + ['==', 'meta', 'vertex'], + ['==', '$type', 'Point'], + ['!=', 'mode', 'static'] + ], + 'paint': { + 'circle-radius': 3, + 'circle-color': '#fbb03b' + } + }, + { + 'id': 'gl-point-icon', + 'type': 'symbol', + 'filter': ['all', + ['==', '$type', 'Point'], + ['==', 'meta', 'feature'], + ['has', 'icon'], + ['!has', 'iconRotation'], + ], + 'layout': { + 'icon-image': ['coalesce', ["get", "icon"], 'default_marker'], + 'icon-pitch-alignment': 'viewport', + 'icon-allow-overlap': true, + 'icon-size': ['interpolate', ['linear'], ['zoom'], 12, 0.1, 17, 1], + } + }, + { + 'id': 'gl-point-icon-rotation', + 'type': 'symbol', + 'filter': ['all', + ['==', '$type', 'Point'], + ['==', 'meta', 'feature'], + ['has', 'icon'], + ['has', 'iconRotation'], + ], + 'layout': { + 'icon-image': ['coalesce', ["get", "icon"], 'default_marker'], + 'icon-allow-overlap': true, + 'icon-size': ['interpolate', ['linear'], ['zoom'], 12, 0.1, 17, 1], + 'icon-rotation-alignment': 'map', + 'icon-pitch-alignment': 'map', + 'icon-rotate': ['coalesce', ["get", "iconRotation"], 0] + } + }, + { + 'id': 'gl-text-special-placement-points-center', + 'type': 'symbol', + 'filter': ['all', + ['==', 'meta', 'feature'], + ['==', '$type', 'Point'], + ['has', 'name'], + ['has', 'icon'], + ['in', 'icon', 'EingesperrteAbgeschnittene', 'Obdachlose'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'text-field': ["coalesce", ["get", "name"], ""], + 'text-font': ["Frutiger Neue Condensed Bold"], + 'text-anchor': 'center', + 'text-offset': [0, 0], + 'text-ignore-placement': true, + 'text-size': ['interpolate', ['linear'], ['zoom'], 12, 4, 17, 22] + }, + 'paint': { + 'text-color': '#ff0000', + } + }, + { + 'id': 'gl-text-special-placement-points-right', + 'type': 'symbol', + 'filter': ['all', + ['==', 'meta', 'feature'], + ['==', '$type', 'Point'], + ['has', 'name'], + ['has', 'icon'], + ['in', 'icon', 'Tote', 'Vermisste', 'Verletzte'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'text-field': ["coalesce", ["get", "name"], ""], + 'text-font': ["Frutiger Neue Condensed Bold"], + 'text-anchor': 'right', + 'text-offset': [2.25, 0.25], + 'text-ignore-placement': true, + 'text-size': ['interpolate', ['linear'], ['zoom'], 12, 4, 17, 22] + }, + 'paint': { + 'text-color': '#ff0000', + } + }, + { + 'id': 'gl-text-name-point', + 'type': 'symbol', + 'filter': ['all', + ['==', 'meta', 'feature'], + ['has', 'name'], + ['!in', 'icon', 'EingesperrteAbgeschnittene', 'Obdachlose', 'Tote', 'Vermisste', 'Verletzte'], + ['==', '$type', 'Point'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'text-field': ["coalesce", ["get", "name"], ""], + 'text-font': ["Frutiger Neue Condensed Bold"], + 'text-anchor': 'center', + 'text-offset': [0, 1.75], + 'text-ignore-placement': true, + 'text-size': ['interpolate', ['linear'], ['zoom'], 11, 2, 17, 16] + }, + 'paint': { + 'text-color': ['coalesce', ['get', 'color'], '#000000'], + } + }, + { + 'id': 'gl-text-name-Polygon', + 'type': 'symbol', + 'filter': ['all', + ['==', 'meta', 'feature'], + ['has', 'name'], + ['==', '$type', 'Polygon'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'text-field': ["coalesce", ["get", "name"], ""], + 'text-font': ["Frutiger Neue Condensed Bold"], + 'text-size': ['interpolate', ['linear'], ['zoom'], 12, 2, 17, 20], + 'symbol-placement': 'line', + 'text-offset': [0, 0.5], + 'text-ignore-placement': true, + 'text-anchor': 'center' + }, + 'paint': { + 'text-color': ['coalesce', ['get', 'color'], '#000000'], + 'text-halo-color': '#fff' + } + }, + { + 'id': 'gl-text-name-LineString', + 'type': 'symbol', + 'filter': ['all', + ['==', 'meta', 'feature'], + ['has', 'name'], + ['==', '$type', 'LineString'], + ['!=', 'mode', 'static'] + ], + 'layout': { + 'text-field': ["coalesce", ["get", "name"], ""], + 'text-font': ["Frutiger Neue Condensed Bold"], + 'text-size': ['interpolate', ['linear'], ['zoom'], 12, 2, 17, 20], + 'symbol-placement': 'line-center', + 'text-offset': [0, 1], + 'text-ignore-placement': true, + 'text-anchor': 'center' + }, + 'paint': { + 'text-color': ['coalesce', ['get', 'color'], '#000000'], + 'text-halo-color': '#fff' + } + }, + { + 'id': 'gl-point-inactive', + 'type': 'circle', + 'filter': ['all', + ['==', 'active', 'false'], + ['==', '$type', 'Point'], + ['==', 'meta', 'feature'], + ['!has', 'icon'], + ['!=', 'mode', 'static'] + ], + 'paint': { + 'circle-radius': 5, + 'circle-color': '#0055ff' + }, + }, + { + 'id': 'gl-point-stroke-active', + 'type': 'circle', + 'filter': ['all', + ['==', '$type', 'Point'], + ['==', 'active', 'true'], + ['!has', 'icon'], + ['!=', 'meta', 'midpoint'] + ], + 'paint': { + 'circle-radius': 7, + 'circle-color': '#fff' + } + }, + { + 'id': 'gl-point-active', + 'type': 'circle', + 'filter': ['all', + ['==', '$type', 'Point'], + ['!=', 'meta', 'midpoint'], + ['!has', 'icon'], + ['==', 'active', 'true']], + 'paint': { + 'circle-radius': 5, + 'circle-color': '#fbb03b' + } + } +]; + + +export default drawStyle; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a1355af3..d0d2c538 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2567,7 +2567,7 @@ __metadata: languageName: node linkType: hard -"@mapbox/geojson-extent@npm:^1.0.0": +"@mapbox/geojson-extent@npm:^1.0.1": version: 1.0.1 resolution: "@mapbox/geojson-extent@npm:1.0.1" dependencies: @@ -2616,18 +2616,18 @@ __metadata: languageName: node linkType: hard -"@mapbox/mapbox-gl-draw@npm:~1.3.0": - version: 1.3.0 - resolution: "@mapbox/mapbox-gl-draw@npm:1.3.0" +"@mapbox/mapbox-gl-draw@npm:^1.3.0": + version: 1.4.3 + resolution: "@mapbox/mapbox-gl-draw@npm:1.4.3" dependencies: "@mapbox/geojson-area": ^0.2.2 - "@mapbox/geojson-extent": ^1.0.0 + "@mapbox/geojson-extent": ^1.0.1 "@mapbox/geojson-normalize": ^0.0.1 "@mapbox/point-geometry": ^0.1.0 hat: 0.0.3 lodash.isequal: ^4.5.0 xtend: ^4.0.2 - checksum: 51d32271d9f9941268ca99b45de05bfd3a21080a2a7456eb4996985ce01ba78760a44501753d38cbc0ea1950bddc0927b5d2ea9559cea45320a1bfb2b3c38a40 + checksum: 5426173bd10f8b181567f73ebbb285175f6e05b09015ba9fba24aea5b056591f5326195091b37cd9df239be1e688ce72ed29f318047b52e130213d640bf269bf languageName: node linkType: hard @@ -13654,7 +13654,7 @@ __metadata: "@fortawesome/free-regular-svg-icons": ^6.5.1 "@fortawesome/free-solid-svg-icons": ^6.5.1 "@fortawesome/react-fontawesome": ^0.2.0 - "@mapbox/mapbox-gl-draw": ~1.3.0 + "@mapbox/mapbox-gl-draw": ^1.3.0 "@svgr/webpack": ^8.1.0 "@testing-library/dom": ^9.3.4 "@testing-library/jest-dom": ^6.3.0