Work on Popups
This commit is contained in:
parent
a810f87461
commit
0d509d4e00
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||||
|
}
|
|
@ -10,8 +10,8 @@ import MapImageLayer from '@arcgis/core/layers/MapImageLayer';
|
||||||
import Sublayer from '@arcgis/core/layers/support/Sublayer';
|
import Sublayer from '@arcgis/core/layers/support/Sublayer';
|
||||||
import ButtonMenuItem from '@arcgis/core/widgets/FeatureTable/Grid/support/ButtonMenuItem';
|
import ButtonMenuItem from '@arcgis/core/widgets/FeatureTable/Grid/support/ButtonMenuItem';
|
||||||
|
|
||||||
export default function Layers({ view, tableRoot }: { view: MapView; tableRoot: HTMLDivElement }) {
|
export default function Layers({ view, tableDiv }: { view: MapView; tableDiv: HTMLDivElement }) {
|
||||||
const htmlDiv = useRef<HTMLDivElement>(null);
|
const layerListDiv = useRef<HTMLDivElement | null>(null);
|
||||||
const featureTable = useRef<FeatureTable | null>(null);
|
const featureTable = useRef<FeatureTable | null>(null);
|
||||||
const rendered = useRef<boolean>(false);
|
const rendered = useRef<boolean>(false);
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ export default function Layers({ view, tableRoot }: { view: MapView; tableRoot:
|
||||||
const tableContainer = document.createElement('div');
|
const tableContainer = document.createElement('div');
|
||||||
tableContainer.className = 'h-full w-full';
|
tableContainer.className = 'h-full w-full';
|
||||||
|
|
||||||
if (tableRoot) {
|
if (tableDiv) {
|
||||||
tableRoot.classList.remove('hidden');
|
tableDiv.classList.remove('hidden');
|
||||||
tableRoot.append(tableContainer);
|
tableDiv.append(tableContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const featureLayer = await layer.createFeatureLayer();
|
const featureLayer = await layer.createFeatureLayer();
|
||||||
|
@ -43,8 +43,8 @@ export default function Layers({ view, tableRoot }: { view: MapView; tableRoot:
|
||||||
iconClass: 'esri-icon-close',
|
iconClass: 'esri-icon-close',
|
||||||
clickFunction: function () {
|
clickFunction: function () {
|
||||||
featureTable.current?.destroy();
|
featureTable.current?.destroy();
|
||||||
if (tableRoot) {
|
if (tableDiv) {
|
||||||
tableRoot.classList.add('hidden');
|
tableDiv.classList.add('hidden');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
} as unknown as ButtonMenuItem,
|
} as unknown as ButtonMenuItem,
|
||||||
|
@ -53,13 +53,13 @@ export default function Layers({ view, tableRoot }: { view: MapView; tableRoot:
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (htmlDiv.current) {
|
if (layerListDiv.current) {
|
||||||
const arcGISAPIWidgetContainer = document.createElement('div');
|
const arcGISAPIWidgetContainer = document.createElement('div');
|
||||||
htmlDiv.current.append(arcGISAPIWidgetContainer);
|
layerListDiv.current.append(arcGISAPIWidgetContainer);
|
||||||
|
|
||||||
const layerList = new LayerList({
|
const layerList = new LayerList({
|
||||||
view,
|
view,
|
||||||
container: htmlDiv.current,
|
container: layerListDiv.current,
|
||||||
selectionEnabled: true,
|
selectionEnabled: true,
|
||||||
listItemCreatedFunction: async function (event) {
|
listItemCreatedFunction: async function (event) {
|
||||||
const item = event.item;
|
const item = event.item;
|
||||||
|
@ -139,9 +139,7 @@ export default function Layers({ view, tableRoot }: { view: MapView; tableRoot:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}, [t, tableDiv, view]);
|
||||||
|
|
||||||
return () => {};
|
return <div ref={layerListDiv}></div>;
|
||||||
});
|
|
||||||
|
|
||||||
return <div ref={htmlDiv}></div>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
import { useRef, useState, useEffect } from 'react';
|
import { useRef, useState, useEffect } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { Root, createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
|
@ -10,22 +12,24 @@ import WebMap from '@arcgis/core/WebMap';
|
||||||
import esriConfig from '@arcgis/core/config';
|
import esriConfig from '@arcgis/core/config';
|
||||||
import ScaleBar from '@arcgis/core/widgets/ScaleBar';
|
import ScaleBar from '@arcgis/core/widgets/ScaleBar';
|
||||||
import Legend from '@arcgis/core/widgets/Legend';
|
import Legend from '@arcgis/core/widgets/Legend';
|
||||||
import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer';
|
|
||||||
import TileLayer from '@arcgis/core/layers/TileLayer';
|
|
||||||
import Map from '@arcgis/core/Map.js';
|
|
||||||
import Basemap from '@arcgis/core/Basemap';
|
|
||||||
import * as intl from '@arcgis/core/intl';
|
import * as intl from '@arcgis/core/intl';
|
||||||
|
import TextContent from '@arcgis/core/popup/content/TextContent';
|
||||||
|
import ExpressionContent from '@arcgis/core/popup/content/ExpressionContent';
|
||||||
|
import ElementExpressionInfo from '@arcgis/core/popup/ElementExpressionInfo';
|
||||||
|
import { watch } from '@arcgis/core/core/reactiveUtils';
|
||||||
|
// @ts-ignore
|
||||||
|
import { getColorsForRendererValues } from '@arcgis/core/renderers/support/utils';
|
||||||
|
|
||||||
// set asset path for ArcGIS Maps SDK widgets
|
// set asset path for ArcGIS Maps SDK widgets
|
||||||
esriConfig.assetsPath = './assets';
|
esriConfig.assetsPath = '/assets';
|
||||||
|
|
||||||
// ids of web map items in portal
|
// ids of web map items in portal
|
||||||
const webMapDEID = '7d0768f73d3e4be2b32c22274c600cb3';
|
const webMapDEID = '7d0768f73d3e4be2b32c22274c600cb3';
|
||||||
const webMapENID = 'dbf5532d06954c6a989d4f022de83f70';
|
const webMapENID = 'dbf5532d06954c6a989d4f022de83f70';
|
||||||
|
|
||||||
// lazy load components
|
// lazy load components
|
||||||
const Print = dynamic(() => import('./print'));
|
|
||||||
const Layers = dynamic(() => import('./layer-list'));
|
const Layers = dynamic(() => import('./layer-list'));
|
||||||
|
const Print = dynamic(() => import('./print'));
|
||||||
const Basemaps = dynamic(() => import('./basemap-list'));
|
const Basemaps = dynamic(() => import('./basemap-list'));
|
||||||
const Search = dynamic(() => import('./search'));
|
const Search = dynamic(() => import('./search'));
|
||||||
|
|
||||||
|
@ -48,20 +52,30 @@ import {
|
||||||
CalciteAction,
|
CalciteAction,
|
||||||
CalcitePanel,
|
CalcitePanel,
|
||||||
} from '@esri/calcite-components-react';
|
} from '@esri/calcite-components-react';
|
||||||
|
import MapImageLayer from '@arcgis/core/layers/MapImageLayer';
|
||||||
|
|
||||||
export default function MapComponent({ locale }: { locale: string }) {
|
export default function MapComponent({ locale }: { locale: string }) {
|
||||||
const legendRoot = useRef<HTMLDivElement>(null);
|
const maskRef = useRef<HTMLDivElement>(null);
|
||||||
const maskRoot = useRef<HTMLDivElement>(null);
|
const tableRef = useRef<HTMLDivElement>(null);
|
||||||
const tableRoot = useRef<HTMLDivElement>(null);
|
|
||||||
const mapView = useRef<MapView | null>(null);
|
const mapView = useRef<MapView | null>(null);
|
||||||
const previousId = useRef<string | null>(null);
|
const previousId = useRef<string | null>(null);
|
||||||
|
const mapRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const layersRef = useRef<HTMLDivElement>(null);
|
||||||
|
const layersRoot = useRef<Root | null>(null);
|
||||||
|
const legendRef = useRef<HTMLDivElement>(null);
|
||||||
|
const basemapsRef = useRef<HTMLDivElement>(null);
|
||||||
|
const basemapsRoot = useRef<Root | null>(null);
|
||||||
|
const printRef = useRef<HTMLDivElement>(null);
|
||||||
|
const printRoot = useRef<Root | null>(null);
|
||||||
|
const searchRef = useRef<HTMLDivElement>(document.createElement('div'));
|
||||||
|
const searchRoot = useRef<Root | null>(null);
|
||||||
|
|
||||||
const [actionBarExpanded, setActionBarExpanded] = useState<boolean>(false);
|
const [actionBarExpanded, setActionBarExpanded] = useState<boolean>(false);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mapView.current) {
|
if (mapRef.current) {
|
||||||
// set locale for ArcGIS Maps SDK widgets
|
// set locale for ArcGIS Maps SDK widgets
|
||||||
intl.setLocale(locale);
|
intl.setLocale(locale);
|
||||||
|
|
||||||
|
@ -74,40 +88,16 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const lightgrayBase = new VectorTileLayer({
|
|
||||||
url: 'https://gis.geosphere.at/portal/sharing/rest/content/items/291da5eab3a0412593b66d384379f89f/resources/styles/root.json',
|
|
||||||
opacity: 0.5,
|
|
||||||
});
|
|
||||||
const lightGrayReference = new VectorTileLayer({
|
|
||||||
url: 'https://gis.geosphere.at/portal/sharing/rest/content/items/1768e8369a214dfab4e2167d5c5f2454/resources/styles/root.json',
|
|
||||||
opacity: 1,
|
|
||||||
});
|
|
||||||
const worldHillshade = new TileLayer({
|
|
||||||
url: 'https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer',
|
|
||||||
});
|
|
||||||
const basemapEsri = new Basemap({
|
|
||||||
baseLayers: [worldHillshade, lightgrayBase, lightGrayReference],
|
|
||||||
title: 'Esri',
|
|
||||||
thumbnailUrl:
|
|
||||||
'https://gis.geosphere.at/portal/sharing/rest/content/items/3eb1510943be4f29ae01c01ce229d8ba/data',
|
|
||||||
});
|
|
||||||
|
|
||||||
const map = new Map({
|
|
||||||
basemap: basemapEsri,
|
|
||||||
});
|
|
||||||
|
|
||||||
const view = new MapView({
|
const view = new MapView({
|
||||||
container: 'map-container',
|
container: mapRef.current,
|
||||||
map: map,
|
map: webMap,
|
||||||
padding: {
|
padding: {
|
||||||
left: 49,
|
left: 49,
|
||||||
},
|
},
|
||||||
popup: {
|
popup: {
|
||||||
dockOptions: {
|
dockOptions: {
|
||||||
position: 'auto',
|
position: 'top-right',
|
||||||
breakpoint: {
|
breakpoint: false,
|
||||||
width: 5000,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
dockEnabled: true,
|
dockEnabled: true,
|
||||||
},
|
},
|
||||||
|
@ -120,17 +110,15 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
wkid: 3857,
|
wkid: 3857,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ui: {
|
||||||
|
components: ['attribution'],
|
||||||
|
},
|
||||||
|
popupEnabled: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
mapView.current = view;
|
mapView.current = view;
|
||||||
view.ui.empty('top-left');
|
|
||||||
|
|
||||||
webMap.load().then(() => {
|
// add ScaleBar
|
||||||
map.layers = webMap.layers;
|
|
||||||
createRoot(document.createElement('div')).render(<Search view={view}></Search>);
|
|
||||||
});
|
|
||||||
|
|
||||||
// add further map related UI components
|
|
||||||
const scaleBar = new ScaleBar({
|
const scaleBar = new ScaleBar({
|
||||||
view: view,
|
view: view,
|
||||||
unit: 'metric',
|
unit: 'metric',
|
||||||
|
@ -138,16 +126,124 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
|
|
||||||
view.ui.add([scaleBar], 'bottom-left');
|
view.ui.add([scaleBar], 'bottom-left');
|
||||||
|
|
||||||
if (legendRoot.current) {
|
// render Legend component
|
||||||
|
if (legendRef.current) {
|
||||||
new Legend({
|
new Legend({
|
||||||
view: view,
|
view: view,
|
||||||
container: legendRoot.current,
|
container: legendRef.current,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return () => {};
|
// render Search component
|
||||||
}, [locale]);
|
if (searchRef.current) {
|
||||||
|
if (!searchRoot.current) {
|
||||||
|
searchRoot.current = createRoot(searchRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRoot.current.render(<Search view={view}></Search>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render Layers component
|
||||||
|
if (layersRef.current) {
|
||||||
|
if (!layersRoot.current) {
|
||||||
|
layersRoot.current = createRoot(layersRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tableRef.current) {
|
||||||
|
layersRoot.current.render(<Layers view={view} tableDiv={tableRef.current}></Layers>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render Basemaps component
|
||||||
|
if (basemapsRef.current) {
|
||||||
|
if (!basemapsRoot.current) {
|
||||||
|
basemapsRoot.current = createRoot(basemapsRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
basemapsRoot.current.render(<Basemaps view={mapView.current}></Basemaps>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // render Print component
|
||||||
|
if (printRef.current) {
|
||||||
|
if (!printRoot.current) {
|
||||||
|
printRoot.current = createRoot(printRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maskRef.current) {
|
||||||
|
printRoot.current.render(<Print view={mapView.current} maskDiv={maskRef.current}></Print>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => view.popup?.viewModel?.active,
|
||||||
|
() => console.log(view.popup?.selectedFeature)
|
||||||
|
);
|
||||||
|
|
||||||
|
// view.on('immediate-click', (event) => {
|
||||||
|
// const mapImageLayer = view.map.layers.find((layer) => layer.title === 'Profilschnitte') as MapImageLayer;
|
||||||
|
// if (mapImageLayer) {
|
||||||
|
// mapImageLayer.allSublayers.forEach((sublayer) => {
|
||||||
|
// if (sublayer.title === 'Bohrprofile') {
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// This function fires each time a LayerView is created
|
||||||
|
// view.on('layerview-create', function (event) {
|
||||||
|
// // The LayerView for the desired layer
|
||||||
|
// if (event.layer.type === 'map-image') {
|
||||||
|
// (event.layer as MapImageLayer).allSublayers.forEach((sublayer) => {
|
||||||
|
// if (sublayer.title === 'Bohrprofile') {
|
||||||
|
// let textElement = new TextContent();
|
||||||
|
// textElement.text = 'Das ist nur ein Test.';
|
||||||
|
// if (Array.isArray(sublayer.popupTemplate.content)) sublayer.popupTemplate.content.push(textElement);
|
||||||
|
|
||||||
|
// sublayer.load().then(async () => {
|
||||||
|
// const renderer = sublayer.renderer;
|
||||||
|
// const fieldToValueColorMap = await getColorsForRendererValues(renderer);
|
||||||
|
|
||||||
|
// let classBreaks: number[] = [];
|
||||||
|
// let colors: object[] = [];
|
||||||
|
// for (const [key, classBreaksToColorMap] of fieldToValueColorMap) {
|
||||||
|
// for (const [classBreack, color] of classBreaksToColorMap) {
|
||||||
|
// colors.push(color);
|
||||||
|
// classBreaks.push(classBreack);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // while (!stopIteration) {
|
||||||
|
// // if ($feature['${key}'] > ${classBreaks}[index]) {
|
||||||
|
// // stopIteration = true;
|
||||||
|
// // color = ${colors}[index]
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// const expressionContent = new ExpressionContent({
|
||||||
|
// expressionInfo: {
|
||||||
|
// title: 'Legende',
|
||||||
|
// expression: `
|
||||||
|
// var stopIteration = true;
|
||||||
|
// var index = 0;
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// type: "text",
|
||||||
|
// text: "First class break for key ${key}: ${classBreaks[0]} and value: " + $feature['${key}']
|
||||||
|
// }
|
||||||
|
// `,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (Array.isArray(sublayer.popupTemplate.content)) {
|
||||||
|
// sublayer.popupTemplate.content.push(expressionContent);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}, [locale, t]);
|
||||||
|
|
||||||
const handleCalciteActionBarToggle = () => {
|
const handleCalciteActionBarToggle = () => {
|
||||||
setActionBarExpanded(!actionBarExpanded);
|
setActionBarExpanded(!actionBarExpanded);
|
||||||
|
@ -155,13 +251,13 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
mapView.current.padding = !actionBarExpanded ? { left: 150 } : { left: 49 };
|
mapView.current.padding = !actionBarExpanded ? { left: 150 } : { left: 49 };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tableRoot.current) {
|
if (tableRef.current) {
|
||||||
if (!actionBarExpanded) {
|
if (!actionBarExpanded) {
|
||||||
tableRoot.current.classList.add('left-40');
|
tableRef.current.classList.add('left-40');
|
||||||
tableRoot.current.classList.remove('left-14');
|
tableRef.current.classList.remove('left-14');
|
||||||
} else {
|
} else {
|
||||||
tableRoot.current.classList.add('left-14');
|
tableRef.current.classList.add('left-14');
|
||||||
tableRoot.current.classList.remove('left-40');
|
tableRef.current.classList.remove('left-40');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -180,7 +276,7 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousId.current === 'print') {
|
if (previousId.current === 'print') {
|
||||||
maskRoot.current?.classList.add('hidden');
|
maskRef.current?.classList.add('hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +286,7 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
previousId.current = nextId;
|
previousId.current = nextId;
|
||||||
|
|
||||||
if (nextId === 'print') {
|
if (nextId === 'print') {
|
||||||
maskRoot.current?.classList.remove('hidden');
|
maskRef.current?.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
previousId.current = null;
|
previousId.current = null;
|
||||||
|
@ -234,32 +330,30 @@ export default function MapComponent({ locale }: { locale: string }) {
|
||||||
</CalciteActionBar>
|
</CalciteActionBar>
|
||||||
|
|
||||||
<CalcitePanel data-panel-id="layers" heading={t('layers.title')} hidden>
|
<CalcitePanel data-panel-id="layers" heading={t('layers.title')} hidden>
|
||||||
{mapView.current && tableRoot.current && (
|
<div ref={layersRef}></div>
|
||||||
<Layers view={mapView.current} tableRoot={tableRoot.current}></Layers>
|
|
||||||
)}
|
|
||||||
</CalcitePanel>
|
</CalcitePanel>
|
||||||
|
|
||||||
<CalcitePanel data-panel-id="basemaps" heading={t('basemaps.title')} hidden>
|
<CalcitePanel data-panel-id="basemaps" heading={t('basemaps.title')} hidden>
|
||||||
{mapView.current && <Basemaps view={mapView.current}></Basemaps>}
|
<div ref={basemapsRef}></div>
|
||||||
</CalcitePanel>
|
</CalcitePanel>
|
||||||
|
|
||||||
<CalcitePanel data-panel-id="legend" heading={t('legend.title')} hidden>
|
<CalcitePanel data-panel-id="legend" heading={t('legend.title')} hidden>
|
||||||
<div ref={legendRoot}></div>
|
<div ref={legendRef}></div>
|
||||||
</CalcitePanel>
|
</CalcitePanel>
|
||||||
|
|
||||||
<CalcitePanel data-panel-id="print" heading={t('print.heading')} hidden>
|
<CalcitePanel data-panel-id="print" heading={t('print.heading')} hidden>
|
||||||
{mapView.current && maskRoot.current && <Print view={mapView.current} maskRoot={maskRoot.current}></Print>}
|
<div ref={printRef}></div>
|
||||||
</CalcitePanel>
|
</CalcitePanel>
|
||||||
|
|
||||||
<CalcitePanel data-panel-id="info" heading="Info" hidden>
|
<CalcitePanel data-panel-id="info" heading="Info" hidden>
|
||||||
<div id="info-container"></div>
|
<div id="info-container"></div>
|
||||||
</CalcitePanel>
|
</CalcitePanel>
|
||||||
</CalciteShellPanel>
|
</CalciteShellPanel>
|
||||||
<div className="h-screen w-full" id="map-container">
|
<div className="h-screen w-full" ref={mapRef}>
|
||||||
<div ref={tableRoot} className="hidden absolute left-14 bottom-5 h-1/3 right-2 border border-gray-400"></div>
|
<div ref={tableRef} className="hidden absolute left-14 bottom-5 h-1/3 right-2 border border-gray-400"></div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref={maskRoot}
|
ref={maskRef}
|
||||||
className="hidden absolute bg-red-300 border-2 border-red-600 opacity-50 pointer-events-none"
|
className="hidden absolute bg-red-300 border-2 border-red-600 opacity-50 pointer-events-none"
|
||||||
></div>
|
></div>
|
||||||
</CalciteShell>
|
</CalciteShell>
|
||||||
|
|
|
@ -63,7 +63,7 @@ const formats: Format = {
|
||||||
'A3 Querformat mit Legende': [400, 215],
|
'A3 Querformat mit Legende': [400, 215],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Print({ view, maskRoot }: { view: MapView; maskRoot: HTMLDivElement }) {
|
export default function Print({ view, maskDiv }: { view: MapView; maskDiv: HTMLDivElement }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [title, setTitle] = useState<string>('GeoSphere Austria');
|
const [title, setTitle] = useState<string>('GeoSphere Austria');
|
||||||
|
@ -183,11 +183,11 @@ export default function Print({ view, maskRoot }: { view: MapView; maskRoot: HTM
|
||||||
const maskWidth = clamp(Math.round(lowerRight.x - upperLeft.x), 0, view.width);
|
const maskWidth = clamp(Math.round(lowerRight.x - upperLeft.x), 0, view.width);
|
||||||
const maskHeight = clamp(Math.round(lowerRight.y - upperLeft.y), 0, view.height);
|
const maskHeight = clamp(Math.round(lowerRight.y - upperLeft.y), 0, view.height);
|
||||||
|
|
||||||
if (maskRoot) {
|
if (maskDiv) {
|
||||||
maskRoot.style.left = left + 'px';
|
maskDiv.style.left = left + 'px';
|
||||||
maskRoot.style.top = top + 'px';
|
maskDiv.style.top = top + 'px';
|
||||||
maskRoot.style.width = maskWidth + 'px';
|
maskDiv.style.width = maskWidth + 'px';
|
||||||
maskRoot.style.height = maskHeight + 'px';
|
maskDiv.style.height = maskHeight + 'px';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useRef, useState, useEffect } from 'react';
|
import { useRef, useState, useEffect, MouseEventHandler } from 'react';
|
||||||
import { Root, createRoot } from 'react-dom/client';
|
import { Root, createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -40,14 +40,17 @@ import SimpleLineSymbol from '@arcgis/core/symbols/SimpleLineSymbol';
|
||||||
import SimpleMarkerSymbol from '@arcgis/core/symbols/SimpleMarkerSymbol';
|
import SimpleMarkerSymbol from '@arcgis/core/symbols/SimpleMarkerSymbol';
|
||||||
import Sublayer from '@arcgis/core/layers/support/Sublayer';
|
import Sublayer from '@arcgis/core/layers/support/Sublayer';
|
||||||
import PopupTemplate from '@arcgis/core/PopupTemplate';
|
import PopupTemplate from '@arcgis/core/PopupTemplate';
|
||||||
|
import { watch } from '@arcgis/core/core/reactiveUtils';
|
||||||
|
|
||||||
// create feaure layer from URL of data index layer
|
// create feaure layer from URL of data index layer
|
||||||
const datenIndexURL = 'https://gis.geosphere.at/maps/rest/services/datenindex/raster_5000/MapServer/0';
|
const datenIndexURL = 'https://gis.geosphere.at/maps/rest/services/datenindex/raster_1000/MapServer/0';
|
||||||
const indexLayer = new FeatureLayer({
|
const indexLayer = new FeatureLayer({
|
||||||
url: datenIndexURL,
|
url: datenIndexURL,
|
||||||
title: 'Datenindex 1:5.000',
|
title: 'Datenindex 1:1.000',
|
||||||
opacity: 0,
|
opacity: 1,
|
||||||
legendEnabled: false,
|
legendEnabled: false,
|
||||||
|
visible: false,
|
||||||
|
listMode: 'hide',
|
||||||
});
|
});
|
||||||
|
|
||||||
// custom type definitions
|
// custom type definitions
|
||||||
|
@ -70,6 +73,61 @@ interface LayerToFeaturesMap {
|
||||||
[key: string]: string[];
|
[key: string]: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create query from cellcode for 3x3 neighbourhood
|
||||||
|
const createQueryFromCellcode = (cellcode: string) => {
|
||||||
|
const { north, east }: any = cellcode.match(/N(?<north>\d+)E(?<east>\d+)/)?.groups;
|
||||||
|
const northNumber = parseInt(north);
|
||||||
|
const eastNumber = parseInt(east);
|
||||||
|
const operations = [
|
||||||
|
[1, -1],
|
||||||
|
[1, 0],
|
||||||
|
[1, 1],
|
||||||
|
[0, -1],
|
||||||
|
[0, 1],
|
||||||
|
[-1, -1],
|
||||||
|
[-1, 0],
|
||||||
|
[-1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
const cellcodeQueries = operations.map(
|
||||||
|
(operation) => `cellcode = '1kmN${northNumber + operation[0]}E${eastNumber + operation[1]}'`
|
||||||
|
);
|
||||||
|
return `cellcode = '${cellcode}' OR ` + cellcodeQueries.join(' OR ');
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove layers from layer tree by given filter
|
||||||
|
const removeLayers = (layers: (CustomGroupLayer | CustomLayer)[], keepLayer: any): any => {
|
||||||
|
return layers
|
||||||
|
.filter((layer) => keepLayer(layer))
|
||||||
|
.map((layer) => {
|
||||||
|
if (layer.type === 'group' && (layer as CustomGroupLayer).layers) {
|
||||||
|
return { ...layer, layers: removeLayers((layer as CustomGroupLayer).layers, keepLayer) };
|
||||||
|
} else {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// get custom layer objects from layer tree
|
||||||
|
const getLayerObjects = (layers: any) => {
|
||||||
|
return layers.map((layer: any) => {
|
||||||
|
if (layer.layers) {
|
||||||
|
return {
|
||||||
|
id: layer.id,
|
||||||
|
type: layer.type,
|
||||||
|
title: layer.title,
|
||||||
|
visible: layer.visible,
|
||||||
|
layers: getLayerObjects(layer.layers.toArray()),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return { id: layer.id, type: layer.type, title: layer.title, visible: layer.visible };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// build query string for custom search source (BEV geocoding service)
|
||||||
|
const buildQueryString = (searchTerm: string) => `?term=${encodeURI(searchTerm)}`;
|
||||||
|
|
||||||
// custom React component
|
// custom React component
|
||||||
export default function SearchComponent({ view }: { view: MapView }) {
|
export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
const [currentTarget, setCurrentTarget] = useState<Graphic | null>(null);
|
const [currentTarget, setCurrentTarget] = useState<Graphic | null>(null);
|
||||||
|
@ -80,173 +138,6 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
// get map image layer from sublayer
|
|
||||||
const getMapImageLayer = (layerURL: string): MapImageLayer | undefined => {
|
|
||||||
if (view) {
|
|
||||||
const filteredLayerViews = view.allLayerViews.filter((layerView) => {
|
|
||||||
const regex = /^https:\/\/.+\/MapServer/g;
|
|
||||||
const matches = layerURL.match(regex);
|
|
||||||
let mapImageLayerURL;
|
|
||||||
if (matches && matches.length > 0) mapImageLayerURL = matches[0];
|
|
||||||
|
|
||||||
if (layerView.layer.type === 'map-image') {
|
|
||||||
return (layerView.layer as MapImageLayer).url === mapImageLayerURL;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mapImageLayer;
|
|
||||||
if (filteredLayerViews.length > 0) {
|
|
||||||
mapImageLayer = filteredLayerViews.at(0).layer as MapImageLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapImageLayer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle toggle layer visibility
|
|
||||||
const handleToggleVisibility = (event: any) => {
|
|
||||||
const layerItem = event.target;
|
|
||||||
|
|
||||||
const layerId = layerItem.getAttribute('text');
|
|
||||||
const icon = layerItem.getAttribute('icon');
|
|
||||||
|
|
||||||
if (layerId) {
|
|
||||||
const layer = view.map?.findLayerById(layerId);
|
|
||||||
if (icon === 'view-hide') {
|
|
||||||
layerItem.setAttribute('icon', 'view-visible');
|
|
||||||
if (layer) {
|
|
||||||
layer.visible = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
layerItem.setAttribute('icon', 'view-hide');
|
|
||||||
if (layer) {
|
|
||||||
layer.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle zoom to feature
|
|
||||||
const handleZoomTo = async (event: any) => {
|
|
||||||
const layerURL = event.target.getAttribute('text');
|
|
||||||
const res = await fetch(layerURL + '?f=json');
|
|
||||||
const json = await res.json();
|
|
||||||
|
|
||||||
const mapImageLayer = getMapImageLayer(layerURL);
|
|
||||||
const sr = mapImageLayer?.spatialReference;
|
|
||||||
const geometry = json.feature?.geometry;
|
|
||||||
|
|
||||||
view.graphics.removeAll();
|
|
||||||
const higlightOptions = view.highlightOptions;
|
|
||||||
if (geometry.x && geometry.y && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
|
||||||
const point = new Point({
|
|
||||||
x: geometry.x,
|
|
||||||
y: geometry.y,
|
|
||||||
spatialReference: sr,
|
|
||||||
});
|
|
||||||
const graphic = new Graphic({
|
|
||||||
geometry: point,
|
|
||||||
symbol: {
|
|
||||||
type: 'simple-marker',
|
|
||||||
style: 'circle',
|
|
||||||
size: '8px',
|
|
||||||
color: [
|
|
||||||
higlightOptions.color.r,
|
|
||||||
higlightOptions.color.g,
|
|
||||||
higlightOptions.color.b,
|
|
||||||
higlightOptions.fillOpacity,
|
|
||||||
],
|
|
||||||
outline: {
|
|
||||||
color: [higlightOptions.color.r, higlightOptions.color.g, higlightOptions.color.b, higlightOptions.color.a],
|
|
||||||
width: 1,
|
|
||||||
},
|
|
||||||
} as unknown as SimpleMarkerSymbol,
|
|
||||||
});
|
|
||||||
view.graphics.add(graphic);
|
|
||||||
view.goTo(geodesicBuffer(point, 1000, 'meters'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geometry.paths && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
|
||||||
const polyline = new Polyline({
|
|
||||||
paths: geometry.paths,
|
|
||||||
spatialReference: sr,
|
|
||||||
});
|
|
||||||
const graphic = new Graphic({
|
|
||||||
geometry: polyline,
|
|
||||||
symbol: {
|
|
||||||
type: 'simple-line',
|
|
||||||
color: [higlightOptions.color.r, higlightOptions.color.g, higlightOptions.color.b],
|
|
||||||
width: '2px',
|
|
||||||
} as unknown as SimpleLineSymbol,
|
|
||||||
});
|
|
||||||
view.graphics.add(graphic);
|
|
||||||
view.goTo(geodesicBuffer(polyline.extent.center, 5000, 'meters'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geometry.rings && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
|
||||||
const polygon = new Polygon({
|
|
||||||
rings: geometry.rings,
|
|
||||||
spatialReference: sr,
|
|
||||||
});
|
|
||||||
const graphic = new Graphic({
|
|
||||||
geometry: polygon,
|
|
||||||
symbol: {
|
|
||||||
type: 'simple-fill',
|
|
||||||
color: [
|
|
||||||
higlightOptions.color.r,
|
|
||||||
higlightOptions.color.g,
|
|
||||||
higlightOptions.color.b,
|
|
||||||
higlightOptions.fillOpacity,
|
|
||||||
],
|
|
||||||
outline: {
|
|
||||||
color: [higlightOptions.color.r, higlightOptions.color.g, higlightOptions.color.b, higlightOptions.color.a],
|
|
||||||
width: 1,
|
|
||||||
},
|
|
||||||
} as unknown as SimpleFillSymbol,
|
|
||||||
});
|
|
||||||
view.graphics.add(graphic);
|
|
||||||
view.goTo(polygon);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// remove layers from layer tree by given filter
|
|
||||||
const removeLayers = (layers: (CustomGroupLayer | CustomLayer)[], keepLayer: any): any => {
|
|
||||||
return layers
|
|
||||||
.filter((layer) => keepLayer(layer))
|
|
||||||
.map((layer) => {
|
|
||||||
if (layer.type === 'group' && (layer as CustomGroupLayer).layers) {
|
|
||||||
return { ...layer, layers: removeLayers((layer as CustomGroupLayer).layers, keepLayer) };
|
|
||||||
} else {
|
|
||||||
return layer;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// get custom layer objects from layer tree
|
|
||||||
const getLayerObjects = (layers: any) => {
|
|
||||||
return layers.map((layer: any) => {
|
|
||||||
if (layer.layers) {
|
|
||||||
return {
|
|
||||||
id: layer.id,
|
|
||||||
type: layer.type,
|
|
||||||
title: layer.title,
|
|
||||||
visible: layer.visible,
|
|
||||||
layers: getLayerObjects(layer.layers.toArray()),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return { id: layer.id, type: layer.type, title: layer.title, visible: layer.visible };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// build query string for custom search source (BEV geocoding service)
|
|
||||||
const buildQueryString = (searchTerm: string) => `?term=${encodeURI(searchTerm)}`;
|
|
||||||
|
|
||||||
const url = 'https://kataster.bev.gv.at/api/all4map';
|
const url = 'https://kataster.bev.gv.at/api/all4map';
|
||||||
const customSearchSource = new SearchSource({
|
const customSearchSource = new SearchSource({
|
||||||
placeholder: t('search.placeholder'),
|
placeholder: t('search.placeholder'),
|
||||||
|
@ -340,32 +231,171 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// create query from cellcode for 3x3 neighbourhood
|
// get map image layer from sublayer
|
||||||
const createQueryFromCellcode = (cellcode: string) => {
|
const getMapImageLayer = (layerURL: string): MapImageLayer | undefined => {
|
||||||
const { north, east }: any = cellcode.match(/N(?<north>\d+)E(?<east>\d+)/)?.groups;
|
if (view) {
|
||||||
const northNumber = parseInt(north);
|
const filteredLayerViews = view.allLayerViews.filter((layerView) => {
|
||||||
const eastNumber = parseInt(east);
|
const regex = /^https:\/\/.+\/MapServer/g;
|
||||||
const operations = [
|
const matches = layerURL.match(regex);
|
||||||
[1, -1],
|
let mapImageLayerURL;
|
||||||
[1, 0],
|
if (matches && matches.length > 0) mapImageLayerURL = matches[0];
|
||||||
[1, 1],
|
|
||||||
[0, -1],
|
|
||||||
[0, 1],
|
|
||||||
[-1, -1],
|
|
||||||
[-1, 0],
|
|
||||||
[-1, 1],
|
|
||||||
];
|
|
||||||
|
|
||||||
const cellcodeQueries = operations.map(
|
if (layerView.layer.type === 'map-image') {
|
||||||
(operation) => `cellcode = '10kmN${northNumber + operation[0]}E${eastNumber + operation[1]}'`
|
return (layerView.layer as MapImageLayer).url === mapImageLayerURL;
|
||||||
);
|
} else {
|
||||||
return `cellcode = '${cellcode}' OR ` + cellcodeQueries.join(' OR ');
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mapImageLayer;
|
||||||
|
if (filteredLayerViews.length > 0) {
|
||||||
|
mapImageLayer = filteredLayerViews.at(0).layer as MapImageLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapImageLayer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle toggle layer visibility
|
||||||
|
const handleToggleVisibility = (event: any) => {
|
||||||
|
const layerItem = event.target;
|
||||||
|
|
||||||
|
const layerId = layerItem.getAttribute('text');
|
||||||
|
const icon = layerItem.getAttribute('icon');
|
||||||
|
|
||||||
|
if (layerId) {
|
||||||
|
const layer = view.map?.findLayerById(layerId);
|
||||||
|
if (icon === 'view-hide') {
|
||||||
|
layerItem.setAttribute('icon', 'view-visible');
|
||||||
|
if (layer) {
|
||||||
|
layer.visible = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
layerItem.setAttribute('icon', 'view-hide');
|
||||||
|
if (layer) {
|
||||||
|
layer.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (rendered.current) return;
|
// handle zoom to feature
|
||||||
rendered.current = true;
|
const handleZoomTo = async (event: any) => {
|
||||||
|
const layerURL = event.target.getAttribute('text');
|
||||||
|
const res = await fetch(layerURL + '?f=json');
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
const mapImageLayer = getMapImageLayer(layerURL);
|
||||||
|
const sr = mapImageLayer?.spatialReference;
|
||||||
|
const geometry = json.feature?.geometry;
|
||||||
|
|
||||||
|
view.graphics.removeAll();
|
||||||
|
const higlightOptions = view.highlightOptions;
|
||||||
|
if (geometry.x && geometry.y && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
||||||
|
const point = new Point({
|
||||||
|
x: geometry.x,
|
||||||
|
y: geometry.y,
|
||||||
|
spatialReference: sr,
|
||||||
|
});
|
||||||
|
const graphic = new Graphic({
|
||||||
|
geometry: point,
|
||||||
|
symbol: {
|
||||||
|
type: 'simple-marker',
|
||||||
|
style: 'circle',
|
||||||
|
size: '8px',
|
||||||
|
color: [
|
||||||
|
higlightOptions.color.r,
|
||||||
|
higlightOptions.color.g,
|
||||||
|
higlightOptions.color.b,
|
||||||
|
higlightOptions.fillOpacity,
|
||||||
|
],
|
||||||
|
outline: {
|
||||||
|
color: [
|
||||||
|
higlightOptions.color.r,
|
||||||
|
higlightOptions.color.g,
|
||||||
|
higlightOptions.color.b,
|
||||||
|
higlightOptions.color.a,
|
||||||
|
],
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
} as unknown as SimpleMarkerSymbol,
|
||||||
|
});
|
||||||
|
view.graphics.add(graphic);
|
||||||
|
view.goTo(geodesicBuffer(point, 1000, 'meters'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry.paths && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
||||||
|
const polyline = new Polyline({
|
||||||
|
paths: geometry.paths,
|
||||||
|
spatialReference: sr,
|
||||||
|
});
|
||||||
|
const graphic = new Graphic({
|
||||||
|
geometry: polyline,
|
||||||
|
symbol: {
|
||||||
|
type: 'simple-line',
|
||||||
|
color: [higlightOptions.color.r, higlightOptions.color.g, higlightOptions.color.b],
|
||||||
|
width: '2px',
|
||||||
|
} as unknown as SimpleLineSymbol,
|
||||||
|
});
|
||||||
|
view.graphics.add(graphic);
|
||||||
|
view.goTo(geodesicBuffer(polyline.extent.center, 5000, 'meters'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry.rings && higlightOptions && higlightOptions.color && higlightOptions.fillOpacity) {
|
||||||
|
const polygon = new Polygon({
|
||||||
|
rings: geometry.rings,
|
||||||
|
spatialReference: sr,
|
||||||
|
});
|
||||||
|
const graphic = new Graphic({
|
||||||
|
geometry: polygon,
|
||||||
|
symbol: {
|
||||||
|
type: 'simple-fill',
|
||||||
|
color: [
|
||||||
|
higlightOptions.color.r,
|
||||||
|
higlightOptions.color.g,
|
||||||
|
higlightOptions.color.b,
|
||||||
|
higlightOptions.fillOpacity,
|
||||||
|
],
|
||||||
|
outline: {
|
||||||
|
color: [
|
||||||
|
higlightOptions.color.r,
|
||||||
|
higlightOptions.color.g,
|
||||||
|
higlightOptions.color.b,
|
||||||
|
higlightOptions.color.a,
|
||||||
|
],
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
} as unknown as SimpleFillSymbol,
|
||||||
|
});
|
||||||
|
view.graphics.add(graphic);
|
||||||
|
view.goTo(polygon);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// watch for visibility changes
|
||||||
|
const handle = watch(
|
||||||
|
() => view.map.allLayers.map((layer) => [layer.id, layer.visible]),
|
||||||
|
(newValues, oldValues) => {
|
||||||
|
newValues.forEach((value, key) => {
|
||||||
|
// visibility changed
|
||||||
|
if (oldValues.at(key) && value[1] !== oldValues.at(key)[1]) {
|
||||||
|
const layerId = value[0] as string;
|
||||||
|
const calciteAction = document.querySelector(`calcite-action[text='${layerId}']`);
|
||||||
|
if (calciteAction) {
|
||||||
|
if (value[1]) {
|
||||||
|
calciteAction.setAttribute('icon', 'view-visible');
|
||||||
|
} else {
|
||||||
|
calciteAction.setAttribute('icon', 'view-hide');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
// add data index layer
|
// add data index layer
|
||||||
view.map.layers.push(indexLayer);
|
view.map.layers.push(indexLayer);
|
||||||
|
|
||||||
|
@ -377,11 +407,13 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
includeDefaultSources: false,
|
includeDefaultSources: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// empty top-left corner of MapView for Search component
|
||||||
view.ui.add(search, 'top-left');
|
view.ui.add(search, 'top-left');
|
||||||
|
|
||||||
// add event handler for select-result events
|
// add event handler for select-result events
|
||||||
search.on('select-result', (event) => {
|
search.on('select-result', (event) => {
|
||||||
view.closePopup();
|
view.closePopup();
|
||||||
|
view.graphics.removeAll();
|
||||||
|
|
||||||
// get selected feature and display it on map
|
// get selected feature and display it on map
|
||||||
const graphic = event.result.feature;
|
const graphic = event.result.feature;
|
||||||
|
@ -396,9 +428,6 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
setCurrentTarget(graphic);
|
setCurrentTarget(graphic);
|
||||||
}
|
}
|
||||||
|
|
||||||
view.graphics.removeAll();
|
|
||||||
view.graphics.add(graphic);
|
|
||||||
|
|
||||||
// query for intersecting features
|
// query for intersecting features
|
||||||
indexLayer
|
indexLayer
|
||||||
.queryFeatures({
|
.queryFeatures({
|
||||||
|
@ -496,19 +525,69 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = sublayer?.id ? sublayer?.id.toString() : '';
|
const text = sublayer?.id ? sublayer?.id.toString() : '';
|
||||||
|
|
||||||
|
let sublayerWasVisible: boolean = false;
|
||||||
|
let mapImageLayerWasVisible: boolean = false;
|
||||||
|
const handleMouseEnter: MouseEventHandler<HTMLCalciteAccordionItemElement> = (event) => {
|
||||||
|
(event.target as HTMLElement).classList.add('bg-gray-100');
|
||||||
|
if (mapImageLayer && !mapImageLayer.visible) {
|
||||||
|
mapImageLayerWasVisible = false;
|
||||||
|
mapImageLayer.visible = true;
|
||||||
|
} else {
|
||||||
|
mapImageLayerWasVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sublayer && !sublayer.visible) {
|
||||||
|
sublayerWasVisible = false;
|
||||||
|
sublayer.visible = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseLeave: MouseEventHandler<HTMLCalciteAccordionItemElement> = (event) => {
|
||||||
|
(event.target as HTMLElement).classList.remove('bg-gray-100');
|
||||||
|
if (mapImageLayer && !mapImageLayerWasVisible) {
|
||||||
|
mapImageLayer.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sublayer && !sublayerWasVisible) {
|
||||||
|
sublayer.visible = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSublayerVisibilityToggle: MouseEventHandler<HTMLCalciteActionElement> = (event: any) => {
|
||||||
|
if (mapImageLayer && sublayer) {
|
||||||
|
if (event.target?.getAttribute('icon') === 'view-hide') {
|
||||||
|
mapImageLayerWasVisible = true;
|
||||||
|
mapImageLayer.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.target?.getAttribute('icon') === 'view-visible') {
|
||||||
|
event.target?.setAttribute('icon', 'view-hide');
|
||||||
|
sublayer.visible = false;
|
||||||
|
sublayerWasVisible = false;
|
||||||
|
} else {
|
||||||
|
event.target?.setAttribute('icon', 'view-visible');
|
||||||
|
sublayer.visible = true;
|
||||||
|
sublayerWasVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// create UI item for sublayer
|
// create UI item for sublayer
|
||||||
const accordionItem = (
|
const accordionItem = (
|
||||||
<CalciteAccordionItem heading={sublayer?.title} key={sublayer?.id}>
|
<CalciteAccordionItem
|
||||||
|
heading={sublayer?.title}
|
||||||
|
key={sublayer?.id}
|
||||||
|
onMouseEnter={handleMouseEnter}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
>
|
||||||
<CalciteAction
|
<CalciteAction
|
||||||
slot="actions-end"
|
slot="actions-end"
|
||||||
icon={sublayer?.visible ? 'view-visible' : 'view-hide'}
|
icon={sublayer?.visible ? 'view-visible' : 'view-hide'}
|
||||||
text={text}
|
text={text}
|
||||||
appearance="transparent"
|
appearance="transparent"
|
||||||
onClick={() => {
|
scale="s"
|
||||||
if (sublayer) {
|
onClick={handleSublayerVisibilityToggle}
|
||||||
sublayer.visible = !sublayer.visible;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
></CalciteAction>
|
></CalciteAction>
|
||||||
|
|
||||||
<CalciteList>
|
<CalciteList>
|
||||||
|
@ -565,7 +644,7 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
(layer.type === 'group' &&
|
(layer.type === 'group' &&
|
||||||
((layer as CustomGroupLayer).layers.length === 0 ||
|
((layer as CustomGroupLayer).layers.length === 0 ||
|
||||||
(layer as CustomGroupLayer).layers.every(
|
(layer as CustomGroupLayer).layers.every(
|
||||||
(child) => child.type === 'imagery' || child.type === 'imagery-tile'
|
(child) => child.type === 'imagery' || child.type === 'imagery-tile' || child.type === 'tile'
|
||||||
))) ||
|
))) ||
|
||||||
layer.type === 'feature' ||
|
layer.type === 'feature' ||
|
||||||
layer.type === 'imagery' ||
|
layer.type === 'imagery' ||
|
||||||
|
@ -666,7 +745,7 @@ export default function SearchComponent({ view }: { view: MapView }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
indexLayer.popupTemplate = popupTemplate as unknown as PopupTemplate;
|
indexLayer.popupTemplate = popupTemplate as unknown as PopupTemplate;
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: 'standalone',
|
// output: 'standalone',
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|
713
package-lock.json
generated
713
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -3,11 +3,12 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env NODE_OPTIONS='--inspect' next dev -p 5000",
|
"dev": "next dev",
|
||||||
"build": "npm run copy && next build",
|
"build": "npm run copy-arcgis-maps-assets && npm run copy-calcite-components-assets && next build",
|
||||||
"start": "npm run copy && next start -p 5000",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"copy": "ncp ./node_modules/@arcgis/core/assets ./public/assets"
|
"copy-arcgis-maps-assets": "ncp ./node_modules/@arcgis/core/assets ./public/assets",
|
||||||
|
"copy-calcite-components-assets": "ncp ./node_modules/@esri/calcite-components/dist/calcite/assets ./public/assets/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arcgis/core": "^4.27.6",
|
"@arcgis/core": "^4.27.6",
|
||||||
|
@ -19,17 +20,18 @@
|
||||||
"eslint": "8.45.0",
|
"eslint": "8.45.0",
|
||||||
"eslint-config-next": "13.4.12",
|
"eslint-config-next": "13.4.12",
|
||||||
"i18next": "^23.4.4",
|
"i18next": "^23.4.4",
|
||||||
"ncp": "^2.0.0",
|
|
||||||
"negotiator": "^0.6.3",
|
"negotiator": "^0.6.3",
|
||||||
"next": "^13.5.2",
|
"next": "^13.5.2",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-i18next": "^13.2.2",
|
"react-i18next": "^13.2.2",
|
||||||
|
"sharp": "^0.32.6",
|
||||||
"typescript": "5.1.6"
|
"typescript": "5.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"ncp": "^2.0.0",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.27",
|
||||||
"tailwindcss": "^3.3.3"
|
"tailwindcss": "^3.3.3"
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 912 KiB |
Loading…
Reference in New Issue
Block a user