Skip to content

Commit

Permalink
Merge pull request #1390 from Tampere/feature/new-map-features-and-fixes
Browse files Browse the repository at this point in the history
Feature/new map features and fixes
  • Loading branch information
mmoila authored Nov 8, 2024
2 parents b2bfcb3 + 5d65328 commit d807f59
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 101 deletions.
76 changes: 60 additions & 16 deletions frontend/src/components/Map/DrawMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,25 @@ import { useMapInfoBox } from '@frontend/stores/useMapInfoBox';
import { MapInteraction } from './Map';
import { MapToolbar, ToolType } from './MapToolbar';
import { BaseMapWrapperProps, MapWrapper } from './MapWrapper';
import { NoGeomInfoBox } from './NoGeomInfoBox';
import {
addFeaturesFromGeoJson,
createDrawInteraction,
createDrawLayer,
createModifyInteraction,
createSelectInteraction,
createSelectionLayer,
deleteSelectedFeatures,
getDrawLayer,
getGeoJSONFeaturesString,
getGeometryIconLayer,
getSelectedDrawLayerFeatures,
getSelectionLayer,
} from './mapInteractions';
import { mapOptions } from './mapOptions';
import {
PROJECT_LAYER_Z_INDEX,
PROJECT_OBJECT_LAYER_Z_INDEX,
WFS_LAYER_DEFAULT_Z_INDEX,
} from './styles';

export interface DrawOptions {
drawGeom: { isLoading: boolean; isFetching: boolean; geoJson: string | object | null };
Expand Down Expand Up @@ -89,6 +96,7 @@ export const DrawMap = forwardRef(function DrawMap(

const selectionSource = useAtomValue(selectionSourceAtom);
const drawSource = useMemo(() => propDrawSource ?? new VectorSource({ wrapX: false }), []);
const geometryCenterIconSource = useMemo(() => new VectorSource({ wrapX: false }), []);

useImperativeHandle(
ref,
Expand All @@ -115,18 +123,25 @@ export const DrawMap = forwardRef(function DrawMap(

/** Layers */

const selectionLayer = useMemo(() => createSelectionLayer(selectionSource), []);
const selectionLayer = useMemo(() => getSelectionLayer(selectionSource), []);

const drawLayer = useMemo(
() => createDrawLayer(drawSource, drawOptions?.drawStyle, drawOptions?.drawItemType),
() => getDrawLayer(drawSource, drawOptions.drawStyle, drawOptions.drawItemType),
[],
);

const geometryCenterIconLayer = useMemo(
() => getGeometryIconLayer(geometryCenterIconSource, drawOptions.drawItemType),
[],
);

const vectorLayers = useMemo(() => {
if (!selectedItemLayers || !propVectorLayers) return [];
return propVectorLayers.filter(
(layer) => selectedItemLayers.findIndex((l) => l.id === layer.getProperties().id) !== -1,
);
return propVectorLayers
.filter(
(layer) => selectedItemLayers.findIndex((l) => l.id === layer.getProperties().id) !== -1,
)
.concat(geometryCenterIconLayer);
}, [selectedItemLayers, propVectorLayers]);

/** Interactions */
Expand Down Expand Up @@ -207,22 +222,23 @@ export const DrawMap = forwardRef(function DrawMap(

if (props.drawOptions?.coversMunicipality === false) {
addFeaturesFromGeoJson(drawSource, props.drawOptions.drawGeom.geoJson, { editing });
addFeaturesFromGeoJson(geometryCenterIconSource, props.drawOptions.drawGeom.geoJson, {
editing,
});
}
drawFinished();
}, [props.drawOptions?.coversMunicipality]);

useEffect(() => {
if (drawOptions.drawGeom.isFetching) {
if (drawOptions.drawGeom.isFetching || props.drawOptions?.coversMunicipality) {
return;
}

if (drawOptions?.drawGeom.geoJson) {
addFeaturesFromGeoJson(drawSource, drawOptions.drawGeom.geoJson, { editing });
if (editing) {
drawLayer.setZIndex(101);
} else {
drawLayer.setZIndex(0);
}
addFeaturesFromGeoJson(geometryCenterIconSource, props.drawOptions.drawGeom.geoJson, {
editing,
});
}

if (!extent) {
Expand Down Expand Up @@ -250,7 +266,19 @@ export const DrawMap = forwardRef(function DrawMap(
}
}
// GeoJSON can change without fetching if editing status is changed
}, [drawOptions.drawGeom.geoJson, drawOptions.drawGeom.isFetching]);
}, [drawOptions.drawGeom.geoJson, drawOptions.drawGeom.isFetching, vectorLayers]);

useEffect(() => {
if (editing) {
drawLayer.setZIndex(WFS_LAYER_DEFAULT_Z_INDEX - 1);
} else {
drawLayer.setZIndex(
drawOptions.drawItemType === 'project'
? PROJECT_LAYER_Z_INDEX
: PROJECT_OBJECT_LAYER_Z_INDEX,
);
}
}, [editing]);

useEffect(() => {
switch (selectedTool) {
Expand Down Expand Up @@ -303,6 +331,9 @@ export const DrawMap = forwardRef(function DrawMap(
setDirtyAndValidViews((prev) => ({ ...prev, map: { isDirtyAndValid: false } }));
selectionSource.clear();
addFeaturesFromGeoJson(drawSource, drawOptions.drawGeom.geoJson, { editing });
addFeaturesFromGeoJson(geometryCenterIconSource, props.drawOptions.drawGeom.geoJson, {
editing,
});
}

function getGeometryForSave() {
Expand Down Expand Up @@ -334,6 +365,7 @@ export const DrawMap = forwardRef(function DrawMap(
return feature;
});
drawSource.addFeatures(featuresToCopy);
geometryCenterIconSource.addFeatures(featuresToCopy);
selectionSource.clear();
drawFinished();
setDirtyAndValidViews((prev) => ({ ...prev, map: { isDirtyAndValid: true } }));
Expand Down Expand Up @@ -373,7 +405,14 @@ export const DrawMap = forwardRef(function DrawMap(
setExtent(drawSource.getExtent());
}

if (drawOptions.drawGeom.isLoading || (!editing && !extent && drawOptions.drawGeom.geoJson)) {
const featuresAvailable =
props.drawOptions.drawGeom.geoJson ||
vectorLayers.some((layer) => {
const features = layer.getSource()?.getFeatures();
return features && features.length > 0;
});

if (drawOptions.drawGeom.isLoading || (!editing && !extent && featuresAvailable)) {
return <Skeleton variant="rectangular" height="100%" />;
}

Expand All @@ -397,7 +436,12 @@ export const DrawMap = forwardRef(function DrawMap(
interactionLayers={[selectionLayer, drawLayer]}
resetSelectInteractions={resetSelectInteractions}
/>

<NoGeomInfoBox
drawItemType={props.drawOptions.drawItemType}
isVisible={
!editing && !props.drawOptions.drawGeom.geoJson && !props.drawOptions.coversMunicipality
}
/>
{drawOptions.editable && (
<MapToolbar
geometryExists={drawSource.getFeatures().length > 0}
Expand Down
12 changes: 2 additions & 10 deletions frontend/src/components/Map/Map.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { css } from '@mui/material';
import Feature from 'ol/Feature';
import OLMap from 'ol/Map';
import View from 'ol/View';
import { ScaleLine } from 'ol/control';
import { Control, ScaleLine } from 'ol/control';
import { isEmpty } from 'ol/extent';
import { Geometry } from 'ol/geom';
import { defaults as defaultInteractions } from 'ol/interaction';
Expand All @@ -16,7 +17,6 @@ import { ReactNode, useEffect, useRef, useState } from 'react';
import { getMapProjection, registerProjection } from '@frontend/components/Map/mapFunctions';

import { mapOptions } from './mapOptions';
import { VECTOR_LAYER_DEFAULT_Z_INDEX, WFS_LAYER_DEFAULT_Z_INDEX } from './styles';

export type MapInteraction = (map: OLMap) => void;

Expand Down Expand Up @@ -156,7 +156,6 @@ export function Map({
}
});
wfsLayers.forEach((layer) => {
layer.setZIndex(WFS_LAYER_DEFAULT_Z_INDEX);
olMap.addLayer(layer);
});
}, [wfsLayers]);
Expand All @@ -170,13 +169,6 @@ export function Map({
}
});
vectorLayers?.forEach((layer) => {
const layerId = layer.getProperties().id;
if (layerId === 'projectClusterResults' || layerId === 'projectObjectClusterResults') {
layer.setZIndex(WFS_LAYER_DEFAULT_Z_INDEX + 1);
} else {
layer.setZIndex(VECTOR_LAYER_DEFAULT_Z_INDEX);
}

olMap.addLayer(layer);
});
}, [vectorLayers]);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Map/MapWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export function MapWrapper<TProject extends ProjectData, TProjectObject extends
wfsLayers={WFSLayers}
vectorLayers={props.activeVectorLayers ?? []}
interactions={props.interactions ?? []}
interactionLayers={props?.interactionLayers ?? []}
interactionLayers={props.interactionLayers ?? []}
{...(wholeMunicipalityInfoBoxButtonVisible &&
wholeMunicipalityInfoBoxVisible && { handleSingleClickEvent: handleMapClickEvent })}
>
Expand Down
58 changes: 58 additions & 0 deletions frontend/src/components/Map/NoGeomInfoBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Close } from '@mui/icons-material';
import { Box, IconButton, Typography, css } from '@mui/material';
import { useAtom } from 'jotai';

import { useTranslations } from '@frontend/stores/lang';
import { noGeomInfoBoxAtom } from '@frontend/stores/map';

interface Props {
drawItemType: 'project' | 'projectObject';
isVisible: boolean;
}

export function NoGeomInfoBox(props: Props) {
const [available, setAvailable] = useAtom(noGeomInfoBoxAtom);
const tr = useTranslations();

if (!available || !props.isVisible) {
return null;
}

return (
<Box
css={css`
--container-width: 420px;
background-color: #ffffff99;
position: absolute;
left: calc(50% - var(--container-width) / 2);
top: calc(50% - var(--container-width) / 2);
width: var(--container-width);
padding: 3em 2em;
`}
>
<Typography
css={css`
font-weight: 500;
font-size: 36px;
text-align: center;
color: #848484;
line-height: 34px;
`}
>
{props.drawItemType === 'project'
? tr('map.noProjectGeometry')
: tr('map.noProjectObjectGeometry')}
</Typography>
<IconButton
onClick={() => setAvailable(false)}
css={css`
position: absolute;
top: 2px;
right: 2px;
`}
>
<Close />
</IconButton>
</Box>
);
}
4 changes: 2 additions & 2 deletions frontend/src/components/Map/SearchResultsMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useMapInfoBox } from '@frontend/stores/useMapInfoBox';

import { MapInteraction } from './Map';
import { BaseMapWrapperProps, MapWrapper } from './MapWrapper';
import { createSelectInteraction, createSelectionLayer } from './mapInteractions';
import { createSelectInteraction, getSelectionLayer } from './mapInteractions';

interface Props extends BaseMapWrapperProps {
interactiveLayers?: VectorItemLayerKey[];
Expand All @@ -33,7 +33,7 @@ export function SearchResultsMap(props: Props) {

/** Layers */

const selectionLayer = useMemo(() => createSelectionLayer(selectionSource), []);
const selectionLayer = useMemo(() => getSelectionLayer(selectionSource), []);

const vectorLayers = useMemo(() => {
if (!selectedItemLayers || !propVectorLayers) return [];
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/Map/mapFunctions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import proj4 from 'proj4';
import { WFSLayer } from '@frontend/components/Map/mapOptions';
import { AtLeast } from '@frontend/stores/misc';

import { WFS_LAYER_DEFAULT_Z_INDEX } from './styles';

/**
* Default map projection is EPSG:3857 Web Mercator. Uncommon projections,
* e.g. EPSG:3067 used in Finland, have to be separately added to OpenLayers via
Expand Down Expand Up @@ -166,6 +168,7 @@ export function createVectorSource(url: string) {
export function createWFSLayer(layer: WFSLayer) {
return new VectorImageLayer({
source: createVectorSource(layer.url),
zIndex: WFS_LAYER_DEFAULT_Z_INDEX,
style: (feature) =>
new Style({
fill: new Fill({
Expand Down
42 changes: 29 additions & 13 deletions frontend/src/components/Map/mapInteractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ import Style, { StyleLike } from 'ol/style/Style';
import {
DEFAULT_DRAW_STYLE,
DEFAULT_POINT_STYLE,
getStyleWithGeomCenterIcon,
DRAW_LAYER_Z_INDEX,
GEOMETRY_ICON_LAYER_Z_INDEX,
PROJECT_LAYER_Z_INDEX,
PROJECT_OBJECT_LAYER_Z_INDEX,
SELECTION_LAYER_Z_INDEX,
getDrawViewGeometryCenterIconStyle,
getStyleWithPointIcon,
selectionLayerStyle,
} from '@frontend/components/Map/styles';
Expand All @@ -35,8 +40,6 @@ interface DrawOptions {

let pointerEventKeys: EventsKey[] = [];

export const DRAW_LAYER_Z_INDEX = 101;

const defaultStyles = { Polygon: DEFAULT_DRAW_STYLE, Point: DEFAULT_POINT_STYLE };

function setCrosshairCursor(map: OLMap) {
Expand All @@ -46,19 +49,32 @@ function setCrosshairCursor(map: OLMap) {
map.getViewport().style.cursor = 'crosshair';
}

export function createDrawLayer(
export function getDrawLayer(
source: VectorSource<Feature<Geometry>>,
style?: Style | Style[],
itemType?: 'project' | 'projectObject',
style: Style | Style[],
itemType: 'project' | 'projectObject',
) {
const itemTypeZIndex = {
project: PROJECT_LAYER_Z_INDEX,
projectObject: PROJECT_OBJECT_LAYER_Z_INDEX,
};
return new VectorLayer({
source,
zIndex: DRAW_LAYER_Z_INDEX,
zIndex: itemTypeZIndex[itemType],
properties: { id: 'drawLayer' },
style:
style && itemType
? getStyleWithGeomCenterIcon(getStyleWithPointIcon(style, false), itemType)
: DEFAULT_DRAW_STYLE,
style: getStyleWithPointIcon(style, false),
});
}

export function getGeometryIconLayer(
source: VectorSource<Feature<Geometry>>,
itemType: 'project' | 'projectObject',
) {
return new VectorLayer({
source,
properties: { id: 'geometryIconLayer', type: 'vector' },
zIndex: GEOMETRY_ICON_LAYER_Z_INDEX,
style: getDrawViewGeometryCenterIconStyle(itemType),
});
}

Expand Down Expand Up @@ -134,11 +150,11 @@ export function createDrawInteraction(opts: DrawOptions) {
* Selection tool
*/

export function createSelectionLayer(source: VectorSource<Feature<Geometry>>) {
export function getSelectionLayer(source: VectorSource<Feature<Geometry>>) {
return new VectorLayer({
source,
properties: { id: 'selectionLayer' },
zIndex: DRAW_LAYER_Z_INDEX + 1,
zIndex: SELECTION_LAYER_Z_INDEX,
style: selectionLayerStyle,
});
}
Expand Down
Loading

0 comments on commit d807f59

Please sign in to comment.