diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx index 8095d60e53fdca8b3fe19cf285e37612339545a9..87a2adf0578a7bf8ad89e483aa97330e84da2d25 100644 --- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx @@ -140,7 +140,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => { }; const getGlyphDataMock = jest.fn(() => glyphData); jest.spyOn(layerObjectFeature, 'get').mockImplementation(key => { - if (key === 'setGlyph') return (): void => {}; + if (key === 'update') return (): void => {}; if (key === 'getGlyphData') return getGlyphDataMock; return undefined; }); diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx index 589b3a14c24b319247e8e34e3161dc860ce165d7..1af8c76a0440848f64c8bf2c2b493499b0302837 100644 --- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx +++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx @@ -14,7 +14,8 @@ import { showToast } from '@/utils/showToast'; import { closeModal } from '@/redux/modal/modal.slice'; import { SerializedError } from '@reduxjs/toolkit'; import { useMapInstance } from '@/utils/context/mapInstanceContext'; -import VectorSource from 'ol/source/Vector'; +import updateGlyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/updateGlyph'; +import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; export const LayerImageObjectEditFactoryModal: React.FC = () => { const layerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector); @@ -55,19 +56,8 @@ export const LayerImageObjectEditFactoryModal: React.FC = () => { ).unwrap(); if (layerImage) { dispatch(layerUpdateImage({ modelId: currentModelId, layerId: activeLayer, layerImage })); - mapInstance?.getAllLayers().forEach(layer => { - if (layer.get('id') === activeLayer) { - const source = layer.getSource(); - if (source instanceof VectorSource) { - const feature = source.getFeatureById(layerImage.id); - const setGlyph = feature?.get('setGlyph'); - if (setGlyph && setGlyph instanceof Function) { - setGlyph(layerImage.glyph); - feature.changed(); - } - } - } - }); + dispatch(mapEditToolsSetLayerObject(layerImage)); + updateGlyph(mapInstance, activeLayer, layerImage); } showToast({ type: 'success', diff --git a/src/components/Map/MapDrawActions/MapDrawEditActions.component.tsx b/src/components/Map/MapDrawActions/MapDrawEditActions.component.tsx index 153e93ad7fdf79e3fe66c9f2b64844cd206b80f3..6c30f1c195abdfaa9c156e395fbb89d944c0d411 100644 --- a/src/components/Map/MapDrawActions/MapDrawEditActions.component.tsx +++ b/src/components/Map/MapDrawActions/MapDrawEditActions.component.tsx @@ -4,6 +4,13 @@ import { mapEditToolsLayerImageObjectSelector } from '@/redux/mapEditTools/mapEd import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { MapDrawActionsButton } from '@/components/Map/MapDrawActions/MapDrawActionsButton.component'; import { openLayerImageObjectEditFactoryModal } from '@/redux/modal/modal.slice'; +import { updateLayerImageObject } from '@/redux/layers/layers.thunks'; +import { mapModelIdSelector } from '@/redux/map/map.selectors'; +import { layersActiveLayerSelector } from '@/redux/layers/layers.selectors'; +import { layerUpdateImage } from '@/redux/layers/layers.slice'; +import { useMapInstance } from '@/utils/context/mapInstanceContext'; +import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; +import updateGlyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/updateGlyph'; type MapDrawEditActionsComponentProps = { toggleMapEditAction: () => void; @@ -14,13 +21,35 @@ export const MapDrawEditActionsComponent = ({ toggleMapEditAction, isActive, }: MapDrawEditActionsComponentProps): React.JSX.Element => { + const currentModelId = useAppSelector(mapModelIdSelector); + const activeLayer = useAppSelector(layersActiveLayerSelector); const layerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector); const dispatch = useAppDispatch(); + const { mapInstance } = useMapInstance(); const editMapObject = (): void => { dispatch(openLayerImageObjectEditFactoryModal()); }; + const updateZIndex = async (value: number): Promise<void> => { + if (!activeLayer || !layerImageObject) { + return; + } + const layerImage = await dispatch( + updateLayerImageObject({ + modelId: currentModelId, + layerId: activeLayer, + ...layerImageObject, + z: layerImageObject.z + value, + }), + ).unwrap(); + if (layerImage) { + dispatch(layerUpdateImage({ modelId: currentModelId, layerId: activeLayer, layerImage })); + dispatch(mapEditToolsSetLayerObject(layerImage)); + updateGlyph(mapInstance, activeLayer, layerImage); + } + }; + return ( <div className="flex flex-row-reverse gap-4"> <MapDrawActionsButton @@ -43,6 +72,18 @@ export const MapDrawEditActionsComponent = ({ icon="trash" title="Remove image" /> + <MapDrawActionsButton + isActive={false} + toggleMapEditAction={() => updateZIndex(1)} + icon="arrow-double-up" + title="Remove image" + /> + <MapDrawActionsButton + isActive={false} + toggleMapEditAction={() => updateZIndex(-1)} + icon="arrow-double-down" + title="Remove image" + /> </> )} </div> diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts index 60746292152eec5fc819559449a89c7c19d1a342..d832a64bbe2456c5da73901820fec74292a8d52d 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts @@ -3,7 +3,7 @@ import MapElement from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/ import CompartmentCircle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle'; import CompartmentSquare from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare'; import CompartmentPathway from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway'; -import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph'; +import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph'; import { HorizontalAlign, VerticalAlign, diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts index bcf5cac42c328c5f93f416344e39817c802a7588..fd83ac6fcc695f07df5cf56ffa2b61d3b3f806d6 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts @@ -21,7 +21,7 @@ import { getModelElementsForModel } from '@/redux/modelElements/modelElements.th import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import CompartmentSquare from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare'; import CompartmentCircle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle'; -import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph'; +import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph'; import CompartmentPathway from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway'; import Reaction from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction'; import { diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.test.ts similarity index 98% rename from src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.test.ts rename to src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.test.ts index bef1e03750a22e80784dc3272d1d9b4d55310096..ff2a0ac2b62520a7447bdf70d34897e3ed0b23b2 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.test.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.test.ts @@ -4,7 +4,7 @@ import { Style } from 'ol/style'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import Glyph, { GlyphProps, -} from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph'; +} from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph'; import { MapInstance } from '@/types/map'; import Polygon from 'ol/geom/Polygon'; diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.ts similarity index 90% rename from src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.ts rename to src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.ts index f2046aebdf8fd863b8f7d0ef1120d5e6c7a2949c..a0676acd89b279e3388d8c65e73a7d74cb8a8221 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph.ts @@ -154,15 +154,12 @@ export default class Glyph { this.feature.set('setCoordinates', this.setCoordinates.bind(this)); this.feature.set('getGlyphData', this.getGlyphData.bind(this)); - this.feature.set('reset', this.reset.bind(this)); - this.feature.set('setGlyph', this.setGlyph.bind(this)); + this.feature.set('refreshPolygon', this.refreshPolygon.bind(this)); + this.feature.set('update', this.update.bind(this)); this.feature.setId(this.elementId); this.feature.setStyle(this.getStyle.bind(this)); - if (!this.glyphId) { - return; - } - this.setGlyph(this.glyphId); + this.drawImage(); } private drawPolygon(): void { @@ -177,12 +174,34 @@ export default class Glyph { ]); } - private reset(): void { + private refreshPolygon(): void { this.drawPolygon(); this.polygonStyle.setGeometry(this.polygon); this.feature.setGeometry(this.polygon); } + private refreshZIndex(): void { + this.polygonStyle.setZIndex(this.zIndex); + this.noGlyphStyle.setZIndex(this.zIndex); + this.style.setZIndex(this.zIndex); + this.feature.changed(); + } + + private update(imageObject: LayerImage): void { + this.elementId = imageObject.id; + this.x = imageObject.x; + this.y = imageObject.y; + this.zIndex = imageObject.z; + this.width = imageObject.width; + this.height = imageObject.height; + this.glyphId = imageObject.glyph; + + this.refreshPolygon(); + this.refreshZIndex(); + this.drawImage(); + this.feature.changed(); + } + protected setImageScaleAndDimensions(height: number, width: number): void { this.widthOnMap = width; this.heightOnMap = height; @@ -209,7 +228,10 @@ export default class Glyph { } } - private setGlyph(glyph: number): void { + private drawImage(): void { + if (!this.glyphId) { + return; + } const img = new Image(); img.onload = (): void => { this.imageWidth = img.naturalWidth; @@ -228,8 +250,7 @@ export default class Glyph { zIndex: this.zIndex, }); }; - img.src = `${BASE_NEW_API_URL}${apiPath.getGlyphImage(glyph)}`; - this.glyphId = glyph; + img.src = `${BASE_NEW_API_URL}${apiPath.getGlyphImage(this.glyphId)}`; } private getGlyphData(): LayerImage { diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/updateGlyph.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/updateGlyph.ts new file mode 100644 index 0000000000000000000000000000000000000000..054189738b3ace4ef4fb68d64a3113500496ce43 --- /dev/null +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/updateGlyph.ts @@ -0,0 +1,23 @@ +import VectorSource from 'ol/source/Vector'; +import { LayerImage } from '@/types/models'; +import { MapInstance } from '@/types/map'; + +export default function updateGlyph( + mapInstance: MapInstance, + layerId: number, + layerImage: LayerImage, +): void { + mapInstance?.getAllLayers().forEach(layer => { + if (layer.get('id') === layerId) { + const source = layer.getSource(); + if (source instanceof VectorSource) { + const feature = source.getFeatureById(layerImage.id); + const update = feature?.get('update'); + if (update && update instanceof Function) { + update(layerImage); + feature.changed(); + } + } + } + }); +} diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts index 65c6f6132f43884169e4963ee1d3eb7d00cc873b..84c3f3176b59ffaf4d8194c448e8f04cdf528274 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts @@ -26,7 +26,7 @@ import { } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; import getScaledElementStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle'; import { Stroke } from 'ol/style'; -import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph'; +import Glyph from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Glyph/Glyph'; import { MapSize } from '@/redux/map/map.types'; export interface LayerProps { diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/getTransformImageInteraction.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/getTransformImageInteraction.ts index 8bb46cfee9e6e18cbdaa3620648bd782e2207d78..eecc366517ef57ca2320438d3a2e15ffcc67aef8 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/getTransformImageInteraction.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/getTransformImageInteraction.ts @@ -108,7 +108,7 @@ export default function getTransformImageInteraction( const { feature } = transformEvent; const setCoordinates = feature.get('setCoordinates'); const getGlyphData = feature.get('getGlyphData'); - const reset = feature.get('reset'); + const refreshPolygon = feature.get('refreshPolygon'); const geometry = feature.getGeometry(); if (geometry && getGlyphData instanceof Function) { const glyphData = getGlyphData(); @@ -119,14 +119,15 @@ export default function getTransformImageInteraction( ).unwrap(); if (layerImage) { dispatch(layerUpdateImage({ modelId, layerId: activeLayer, layerImage })); + dispatch(mapEditToolsSetLayerObject(layerImage)); } if (geometry instanceof Polygon && setCoordinates instanceof Function) { setCoordinates(geometry.getCoordinates()); geometry.changed(); } } catch { - if (reset instanceof Function) { - reset(); + if (refreshPolygon instanceof Function) { + refreshPolygon(); } } } diff --git a/src/shared/Icon/Icon.component.tsx b/src/shared/Icon/Icon.component.tsx index e9cf537cf1761891f28c7ca443f757524c78e3a7..44cade94e8d360309f074c2d3365b858d453b2f7 100644 --- a/src/shared/Icon/Icon.component.tsx +++ b/src/shared/Icon/Icon.component.tsx @@ -23,6 +23,8 @@ import { ResizeImageIcon } from '@/shared/Icon/Icons/ResizeImageIcon'; import { PencilIcon } from '@/shared/Icon/Icons/PencilIcon'; import { EditImageIcon } from '@/shared/Icon/Icons/EditImageIcon'; import { TrashIcon } from '@/shared/Icon/Icons/TrashIcon'; +import { ArrowDoubleUpIcon } from '@/shared/Icon/Icons/ArrowDoubleUpIcon'; +import { ArrowDoubleDownIcon } from '@/shared/Icon/Icons/ArrowDoubleDownIcon'; import { LocationIcon } from './Icons/LocationIcon'; import { MaginfierZoomInIcon } from './Icons/MagnifierZoomIn'; import { MaginfierZoomOutIcon } from './Icons/MagnifierZoomOut'; @@ -69,6 +71,8 @@ const icons: Record<IconTypes, IconComponentType> = { 'edit-image': EditImageIcon, trash: TrashIcon, pencil: PencilIcon, + 'arrow-double-up': ArrowDoubleUpIcon, + 'arrow-double-down': ArrowDoubleDownIcon, } as const; export const Icon = ({ name, className = '', ...rest }: IconProps): JSX.Element => { diff --git a/src/shared/Icon/Icons/ArrowDoubleDownIcon.tsx b/src/shared/Icon/Icons/ArrowDoubleDownIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d7ab4e38d5c047e12d2a89159481e942d6770e3d --- /dev/null +++ b/src/shared/Icon/Icons/ArrowDoubleDownIcon.tsx @@ -0,0 +1,38 @@ +interface ArrowDoubleDownIconProps { + className?: string; +} + +export const ArrowDoubleDownIcon = ({ className }: ArrowDoubleDownIconProps): JSX.Element => ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + className={className} + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M8 8L8 18M8 18L5 15M8 18L11 15" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M16 8L16 18M16 18L13 15M16 18L19 15" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <line + x1="4" + y1="6" + x2="20" + y2="6" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + /> + </svg> +); diff --git a/src/shared/Icon/Icons/ArrowDoubleUpIcon.tsx b/src/shared/Icon/Icons/ArrowDoubleUpIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ed51a6021ab3163e987db190b0b5d0d8b9ac10f9 --- /dev/null +++ b/src/shared/Icon/Icons/ArrowDoubleUpIcon.tsx @@ -0,0 +1,38 @@ +interface ArrowDoubleUpIconProps { + className?: string; +} + +export const ArrowDoubleUpIcon = ({ className }: ArrowDoubleUpIconProps): JSX.Element => ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + className={className} + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M8 16L8 6M8 6L5 9M8 6L11 9" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M16 16L16 6M16 6L13 9M16 6L19 9" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <line + x1="4" + y1="18" + x2="20" + y2="18" + stroke="currentColor" + strokeWidth="1.5" + strokeLinecap="round" + /> + </svg> +); diff --git a/src/types/iconTypes.ts b/src/types/iconTypes.ts index dc1ee2b11f2cabe00fd84164c4ea43910f1ef9b0..a631d12ae52d5dbe4f51ac9c488c15e0077fed48 100644 --- a/src/types/iconTypes.ts +++ b/src/types/iconTypes.ts @@ -29,6 +29,8 @@ export type IconTypes = | 'resize-image' | 'edit-image' | 'trash' - | 'pencil'; + | 'pencil' + | 'arrow-double-up' + | 'arrow-double-down'; export type IconComponentType = ({ className }: { className: string }) => JSX.Element;