From 14f5a91fc084943d14688185969165e4d3aca420 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Wed, 11 Dec 2024 13:35:09 +0100
Subject: [PATCH 1/7] feat(vector-map): add duration to mouseWheelZoom

---
 .../utils/config/reactionsLayer/useOlMapReactionsLayer.ts       | 2 ++
 src/components/Map/MapViewer/utils/useOlMap.ts                  | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

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 bf0d3389..86787f11 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -244,6 +244,8 @@ export const useOlMapReactionsLayer = ({
   return useMemo(() => {
     const vectorLayer = new VectorLayer({
       source: vectorSource,
+      updateWhileAnimating: true,
+      updateWhileInteracting: true,
     });
     vectorLayer.set('type', VECTOR_MAP_LAYER_TYPE);
     return vectorLayer;
diff --git a/src/components/Map/MapViewer/utils/useOlMap.ts b/src/components/Map/MapViewer/utils/useOlMap.ts
index 23d585e0..68ec65bd 100644
--- a/src/components/Map/MapViewer/utils/useOlMap.ts
+++ b/src/components/Map/MapViewer/utils/useOlMap.ts
@@ -65,7 +65,7 @@ export const useOlMap: UseOlMap = ({ target } = {}) => {
         mouseWheelZoom: false,
       }).extend([
         new MouseWheelZoom({
-          duration: 0,
+          duration: 250,
           timeout: 80,
         }),
       ]),
-- 
GitLab


From 7d8aec25002cdac1856dad1a48af5bb303ee6a54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Wed, 11 Dec 2024 13:38:19 +0100
Subject: [PATCH 2/7] bugfix(vector-map): add overlaysOrder state in
 useOlMapReactionsLayer to avoid elements reloading

---
 .../reactionsLayer/useOlMapReactionsLayer.ts  | 19 +++++++++---
 .../utils/shapes/elements/BaseMultiPolygon.ts |  2 +-
 .../shapes/overlay/areOverlayOrdersEqual.ts   | 31 +++++++++++++++++++
 3 files changed, 46 insertions(+), 6 deletions(-)
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/overlay/areOverlayOrdersEqual.ts

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 86787f11..509d5cbb 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -2,7 +2,7 @@
 import { Feature } from 'ol';
 import VectorLayer from 'ol/layer/Vector';
 import VectorSource from 'ol/source/Vector';
-import { useEffect, useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import MapElement from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement';
 import { useSelector } from 'react-redux';
@@ -48,6 +48,8 @@ import { mapBackgroundTypeSelector, mapDataSizeSelector } from '@/redux/map/map.
 import MapBackgroundsEnum from '@/redux/map/map.enums';
 import { setMapBackgroundType } from '@/redux/map/map.slice';
 import { ZOOM_RESCALING_FACTOR } from '@/constants/map';
+import { OverlayOrder } from '@/redux/overlayBioEntity/overlayBioEntity.utils';
+import areOverlayOrdersEqual from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/overlay/areOverlayOrdersEqual';
 
 export const useOlMapReactionsLayer = ({
   mapInstance,
@@ -56,6 +58,7 @@ export const useOlMapReactionsLayer = ({
 }): VectorLayer<VectorSource<Feature>> => {
   const dispatch = useAppDispatch();
 
+  const [overlaysOrderState, setOverlaysOrderState] = useState<Array<OverlayOrder>>([]);
   const currentModelId = useSelector(currentModelIdSelector);
   const shapes = useSelector(bioShapesSelector);
   const mapSize = useSelector(mapDataSizeSelector);
@@ -84,6 +87,12 @@ export const useOlMapReactionsLayer = ({
     return mapSize.maxZoom * ZOOM_RESCALING_FACTOR === mapModelOriginalMaxZoom;
   }, [mapModelOriginalMaxZoom, mapSize.maxZoom]);
 
+  useEffect(() => {
+    if (areOverlayOrdersEqual(overlaysOrderState, overlaysOrder)) {
+      setOverlaysOrderState(overlaysOrder);
+    }
+  }, [overlaysOrder, overlaysOrderState]);
+
   useEffect(() => {
     if (!currentModelId) {
       return;
@@ -97,10 +106,10 @@ export const useOlMapReactionsLayer = ({
   }, [currentModelId, dispatch, reactionsLoading, modelElementsLoading]);
 
   useEffect(() => {
-    if (overlaysOrder.length) {
+    if (overlaysOrderState.length) {
       dispatch(setMapBackgroundType(MapBackgroundsEnum.NETWORK));
     }
-  }, [dispatch, overlaysOrder]);
+  }, [dispatch, overlaysOrderState]);
 
   const groupedElementsOverlays = useMemo(() => {
     const elementsBioEntitesOverlay = debouncedBioEntities.filter(
@@ -202,7 +211,7 @@ export const useOlMapReactionsLayer = ({
       shapes,
       lineTypes,
       groupedElementsOverlays,
-      overlaysOrder,
+      overlaysOrderState,
       getOverlayBioEntityColorByAvailableProperties,
       vectorSource,
       mapInstance,
@@ -216,7 +225,7 @@ export const useOlMapReactionsLayer = ({
     isCorrectMapInstanceViewScale,
     lineTypes,
     groupedElementsOverlays,
-    overlaysOrder,
+    overlaysOrderState,
     getOverlayBioEntityColorByAvailableProperties,
     vectorSource,
     mapInstance,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index c13c61f4..30f48a79 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -309,7 +309,7 @@ export default abstract class BaseMultiPolygon {
               largestExtent,
               this.text,
               scale,
-              this.zIndex + 1000,
+              this.zIndex + 100000,
               this.mapSize,
             ),
           );
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/overlay/areOverlayOrdersEqual.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/overlay/areOverlayOrdersEqual.ts
new file mode 100644
index 00000000..965ef019
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/overlay/areOverlayOrdersEqual.ts
@@ -0,0 +1,31 @@
+/* eslint-disable no-magic-numbers */
+import { OverlayOrder } from '@/redux/overlayBioEntity/overlayBioEntity.utils';
+
+export default function areOverlayOrdersEqual(
+  overlaysOrder1: Array<OverlayOrder>,
+  overlaysOrder2: Array<OverlayOrder>,
+): boolean {
+  if (overlaysOrder1 === overlaysOrder2) {
+    return true;
+  }
+
+  if (overlaysOrder1.length !== overlaysOrder2.length) {
+    return false;
+  }
+
+  for (let index = 0; index < overlaysOrder1.length; index += 1) {
+    const obj1 = overlaysOrder1[index];
+    const obj2 = overlaysOrder2[index];
+
+    if (
+      obj1.id !== obj2.id ||
+      obj1.order !== obj2.order ||
+      obj1.calculatedOrder !== obj2.calculatedOrder ||
+      obj1.index !== obj2.index
+    ) {
+      return false;
+    }
+  }
+
+  return true;
+}
-- 
GitLab


From 20bd0d613a953091ecf1ec3e23870dd68001dd48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Wed, 11 Dec 2024 14:46:42 +0100
Subject: [PATCH 3/7] feat(vector-map): add semantic view as a default and stop
 masking content of elemenets when text labels appear

---
 .../utils/shapes/elements/BaseMultiPolygon.ts | 15 ++---------
 .../utils/shapes/elements/MapElement.ts       |  3 ---
 .../elements/handleSemanticView.test.ts       | 27 +++++--------------
 .../shapes/elements/handleSemanticView.ts     |  3 +--
 .../utils/shapes/reaction/Reaction.ts         |  3 +--
 src/redux/map/map.constants.ts                |  2 +-
 6 files changed, 12 insertions(+), 41 deletions(-)

diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index 30f48a79..fd2f74fd 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -196,8 +196,6 @@ export default abstract class BaseMultiPolygon {
       });
       const textPolygon = new Polygon([[textCoords, textCoords]]);
       textPolygon.set('type', MAP_ELEMENT_TYPES.TEXT);
-      textPolygon.set('text', this.text);
-      textPolygon.set('fontSize', this.fontSize);
       const textStyle = getTextStyle({
         text: this.text,
         fontSize: this.fontSize,
@@ -267,12 +265,11 @@ export default abstract class BaseMultiPolygon {
     feature.set('hidden', false);
 
     let hide = false;
-    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC) {
+    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < 0.34) {
       const semanticViewData = handleSemanticView(
         this.vectorSource,
         feature,
         resolution,
-        scale,
         this.compartmentId,
         this.complexId,
       );
@@ -286,8 +283,6 @@ export default abstract class BaseMultiPolygon {
     }
 
     let type: string;
-    let fontSize: number;
-    let text: string;
     let coverStyle: Style | undefined;
     let strokeStyle: Stroke | undefined;
 
@@ -295,8 +290,6 @@ export default abstract class BaseMultiPolygon {
       const styleGeometry = style.getGeometry();
       if (styleGeometry instanceof Polygon) {
         type = styleGeometry.get('type');
-        text = styleGeometry.get('text');
-        fontSize = styleGeometry.get('fontSize') || 10;
         coverStyle = styleGeometry.get('coverStyle');
         strokeStyle = styleGeometry.get('strokeStyle');
       }
@@ -317,17 +310,13 @@ export default abstract class BaseMultiPolygon {
         return;
       }
 
-      if (
-        [MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) &&
-        scale * fontSize <= 4
-      ) {
+      if ([MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) && scale < 0.34) {
         return;
       }
 
       const textStyle = style.getText();
       if (type === 'text' && textStyle) {
         textStyle.setScale(scale);
-        textStyle.setText(text);
       }
       if (strokeStyle) {
         const lineWidth = strokeStyle.getWidth() || 1;
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
index 77ab7ebc..15a15c3e 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
@@ -221,7 +221,6 @@ export default class MapElement extends BaseMultiPolygon {
         mirror: modification.direction && modification.direction === 'RIGHT',
       });
       modificationPolygon.set('type', MAP_ELEMENT_TYPES.MODIFICATION);
-      modificationPolygon.set('fontSize', modification.fontSize);
       const modificationStrokeStyle = getStroke({ color: rgbToHex(modification.borderColor) });
       const modificationStyle = new Style({
         geometry: modificationPolygon,
@@ -252,8 +251,6 @@ export default class MapElement extends BaseMultiPolygon {
         [modificationTextCoords, modificationTextCoords],
       ]);
       modificationTextPolygon.set('type', MAP_ELEMENT_TYPES.TEXT);
-      modificationTextPolygon.set('text', modificationText);
-      modificationTextPolygon.set('fontSize', modification.fontSize);
       const modificationTextStyle = getTextStyle({
         text: modificationText,
         fontSize: modification.fontSize,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
index 0b7e01e1..3c4ae01b 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
@@ -50,7 +50,7 @@ describe('handleSemanticView', () => {
     (getDividedExtents as jest.Mock).mockReturnValue([[0, 0, 10, 5]]);
     (findLargestExtent as jest.Mock).mockReturnValue([0, 0, 10, 5]);
 
-    const result = handleSemanticView(vectorSource, feature, 1, 0.5, null);
+    const result = handleSemanticView(vectorSource, feature, 1, null);
 
     expect(result).toEqual({
       cover: true,
@@ -69,12 +69,12 @@ describe('handleSemanticView', () => {
       .spyOn(vectorSource, 'getFeatureById')
       .mockImplementation(id => (id === 1 ? complexFeature : null));
 
-    const result = handleSemanticView(vectorSource, feature, 1, 1, null, 1);
+    const result = handleSemanticView(vectorSource, feature, 1, null, 1);
 
     expect(result).toEqual({
-      cover: false,
+      cover: true,
       hide: true,
-      largestExtent: null,
+      largestExtent: [0, 0, 10, 5],
     });
 
     expect(feature.get('hidden')).toBe(true);
@@ -86,27 +86,14 @@ describe('handleSemanticView', () => {
       .spyOn(vectorSource, 'getFeatureById')
       .mockImplementation(id => (id === 2 ? compartmentFeature : null));
 
-    const result = handleSemanticView(vectorSource, feature, 1, 1, 2);
+    const result = handleSemanticView(vectorSource, feature, 1, 2);
 
     expect(result).toEqual({
-      cover: false,
+      cover: true,
       hide: true,
-      largestExtent: null,
+      largestExtent: [0, 0, 10, 5],
     });
 
     expect(feature.get('hidden')).toBe(true);
   });
-
-  it('should return cover = false and hide = false when feature does not meet any conditions', () => {
-    const result = handleSemanticView(vectorSource, feature, 1, 1, null);
-
-    expect(result).toEqual({
-      cover: false,
-      hide: false,
-      largestExtent: null,
-    });
-
-    expect(feature.get('filled')).toBe(false);
-    expect(feature.get('hidden')).toBe(false);
-  });
 });
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index 83269b75..19619484 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -9,7 +9,6 @@ export default function handleSemanticView(
   vectorSource: VectorSource,
   feature: Feature,
   resolution: number,
-  scale: number,
   compartmentId: number | null,
   complexId?: number | null,
 ): { cover: boolean; hide: boolean; largestExtent: Extent | null } {
@@ -28,7 +27,7 @@ export default function handleSemanticView(
         Math.abs(featureExtent[2] - featureExtent[0]) *
         Math.abs(featureExtent[3] - featureExtent[1]);
       coverRatio = compartmentArea / mapArea;
-      if (coverRatio < 0.05 && scale < 1) {
+      if (coverRatio < 0.05) {
         cover = true;
         let remainingExtents = [featureExtent];
         vectorSource.forEachFeatureIntersectingExtent(featureExtent, intersectingFeature => {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
index afeeeeab..0a611adc 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
@@ -364,10 +364,9 @@ export default class Reaction {
     const styles: Array<Style> = [];
     const scale = this.minResolution / resolution;
     const type = feature.get('elementType');
-    const fontSize = feature.get('fontSize');
     let strokeStyle: Stroke | undefined;
 
-    if (type === REACTION_ELEMENT_TYPES.OPERATOR && fontSize * scale <= 4) {
+    if (type === REACTION_ELEMENT_TYPES.OPERATOR && scale < 0.34) {
       return [];
     }
     if (type === REACTION_ELEMENT_TYPES.ARROW && scale <= 0.125) {
diff --git a/src/redux/map/map.constants.ts b/src/redux/map/map.constants.ts
index 90648de6..55b67d50 100644
--- a/src/redux/map/map.constants.ts
+++ b/src/redux/map/map.constants.ts
@@ -73,7 +73,7 @@ export const MAP_INITIAL_STATE: MapState = {
   loading: 'idle',
   error: { name: '', message: '' },
   openedMaps: OPENED_MAPS_INITIAL_STATE,
-  backgroundType: MapBackgroundsEnum.NETWORK,
+  backgroundType: MapBackgroundsEnum.SEMANTIC,
 };
 
 export const INIT_MAP_SIZE_MODEL_ID_ERROR_PREFIX = 'Failed to initialize map size and model ID';
-- 
GitLab


From fe7eacb7198cfa86ad9318a629bde5aaad51a0ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Wed, 11 Dec 2024 15:48:24 +0100
Subject: [PATCH 4/7] feat(vector-map): treating complexes in the same way as
 compartments

---
 .../utils/shapes/elements/BaseMultiPolygon.ts | 37 +++++++------------
 .../utils/shapes/elements/MapElement.ts       | 23 ++++++++----
 .../elements/handleSemanticView.test.ts       | 25 +++++++++++--
 .../shapes/elements/handleSemanticView.ts     | 30 ++++++++++-----
 .../utils/shapes/style/getCoverStyles.test.ts |  4 +-
 .../utils/shapes/style/getCoverStyles.ts      | 32 ++++++++++++----
 .../style/getScaledElementStyle.test.ts       | 36 ++++++++++++++++++
 .../shapes/style/getScaledElementStyle.ts     | 14 +------
 .../shapes/style/getScaledStrokeStyle.test.ts | 35 ++++++++++++++++++
 .../shapes/style/getScaledStrokeStyle.ts      | 16 ++++++++
 10 files changed, 187 insertions(+), 65 deletions(-)
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.test.ts
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.test.ts
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.ts

diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index fd2f74fd..a771638e 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -23,6 +23,7 @@ import { Extent } from 'ol/extent';
 import { MapSize } from '@/redux/map/map.types';
 import getCoverStyles from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles';
 import handleSemanticView from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView';
+import getScaledStrokeStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle';
 
 export interface BaseMapElementProps {
   type: string;
@@ -266,13 +267,14 @@ export default abstract class BaseMultiPolygon {
 
     let hide = false;
     if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < 0.34) {
-      const semanticViewData = handleSemanticView(
-        this.vectorSource,
+      const semanticViewData = handleSemanticView({
+        vectorSource: this.vectorSource,
         feature,
         resolution,
-        this.compartmentId,
-        this.complexId,
-      );
+        sboTerm: this.sboTerm,
+        compartmentId: this.compartmentId,
+        complexId: this.complexId,
+      });
       cover = semanticViewData.cover;
       hide = semanticViewData.hide;
       largestExtent = semanticViewData.largestExtent;
@@ -297,14 +299,15 @@ export default abstract class BaseMultiPolygon {
       if (cover) {
         if (coverStyle && largestExtent) {
           styles.push(
-            ...getCoverStyles(
+            ...getCoverStyles({
               coverStyle,
               largestExtent,
-              this.text,
+              text: this.text,
               scale,
-              this.zIndex + 100000,
-              this.mapSize,
-            ),
+              zIndex: this.zIndex + 100000,
+              mapSize: this.mapSize,
+              strokeStyle,
+            }),
           );
         }
         return;
@@ -319,7 +322,6 @@ export default abstract class BaseMultiPolygon {
         textStyle.setScale(scale);
       }
       if (strokeStyle) {
-        const lineWidth = strokeStyle.getWidth() || 1;
         if (
           !this.overlaysVisible &&
           scale < 0.18 &&
@@ -328,18 +330,7 @@ export default abstract class BaseMultiPolygon {
         ) {
           style.setStroke(null);
         } else {
-          const lineDash = strokeStyle.getLineDash();
-          let newLineDash: Array<number> = [];
-          if (lineDash) {
-            newLineDash = lineDash.map(width => width * scale);
-          }
-          const newStrokeStyle = new Stroke({
-            color: strokeStyle.getColor(),
-            width: lineWidth * scale,
-            lineDash: newLineDash,
-          });
-
-          style.setStroke(newStrokeStyle);
+          style.setStroke(getScaledStrokeStyle(strokeStyle, scale));
         }
       }
       styles.push(style);
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
index 15a15c3e..a8ee5425 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts
@@ -13,6 +13,7 @@ import {
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.types';
 import {
   BLACK_COLOR,
+  COMPLEX_SBO_TERMS,
   MAP_ELEMENT_TYPES,
   TRANSPARENT_COLOR,
   WHITE_COLOR,
@@ -311,14 +312,20 @@ export default class MapElement extends BaseMultiPolygon {
         lineDash: this.lineDash,
         zIndex: this.zIndex,
       });
-      elementPolygon.set(
-        'strokeStyle',
-        getStroke({
-          color: rgbToHex(this.borderColor),
-          width: this.lineWidth,
-          lineDash: this.lineDash,
-        }),
-      );
+      const strokeStyle = getStroke({
+        color: rgbToHex(this.borderColor),
+        width: this.lineWidth,
+        lineDash: this.lineDash,
+      });
+      elementPolygon.set('strokeStyle', strokeStyle);
+      if (COMPLEX_SBO_TERMS.includes(this.sboTerm)) {
+        const coverStyle = new Style({
+          geometry: elementPolygon,
+          fill: getFill({ color: rgbToHex({ ...this.fillColor, alpha: 255 }) }),
+          stroke: strokeStyle,
+        });
+        elementPolygon.set('coverStyle', coverStyle);
+      }
       this.polygons.push(elementPolygon);
       this.styles.push(elementStyle);
     });
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
index 3c4ae01b..ddcf4df5 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
@@ -50,7 +50,13 @@ describe('handleSemanticView', () => {
     (getDividedExtents as jest.Mock).mockReturnValue([[0, 0, 10, 5]]);
     (findLargestExtent as jest.Mock).mockReturnValue([0, 0, 10, 5]);
 
-    const result = handleSemanticView(vectorSource, feature, 1, null);
+    const result = handleSemanticView({
+      vectorSource,
+      feature,
+      resolution: 1,
+      sboTerm: 'SBO:123456',
+      compartmentId: null,
+    });
 
     expect(result).toEqual({
       cover: true,
@@ -69,7 +75,14 @@ describe('handleSemanticView', () => {
       .spyOn(vectorSource, 'getFeatureById')
       .mockImplementation(id => (id === 1 ? complexFeature : null));
 
-    const result = handleSemanticView(vectorSource, feature, 1, null, 1);
+    const result = handleSemanticView({
+      vectorSource,
+      feature,
+      resolution: 1,
+      sboTerm: 'SBO:123456',
+      compartmentId: null,
+      complexId: 1,
+    });
 
     expect(result).toEqual({
       cover: true,
@@ -86,7 +99,13 @@ describe('handleSemanticView', () => {
       .spyOn(vectorSource, 'getFeatureById')
       .mockImplementation(id => (id === 2 ? compartmentFeature : null));
 
-    const result = handleSemanticView(vectorSource, feature, 1, 2);
+    const result = handleSemanticView({
+      vectorSource,
+      feature,
+      resolution: 1,
+      sboTerm: 'SBO:123456',
+      compartmentId: 2,
+    });
 
     expect(result).toEqual({
       cover: true,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index 19619484..a15bc312 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -4,21 +4,33 @@ import findLargestExtent from '@/components/Map/MapViewer/MapViewerVector/utils/
 import Feature from 'ol/Feature';
 import VectorSource from 'ol/source/Vector';
 import { Extent } from 'ol/extent';
+import { COMPLEX_SBO_TERMS } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 
-export default function handleSemanticView(
-  vectorSource: VectorSource,
-  feature: Feature,
-  resolution: number,
-  compartmentId: number | null,
-  complexId?: number | null,
-): { cover: boolean; hide: boolean; largestExtent: Extent | null } {
+export default function handleSemanticView({
+  vectorSource,
+  feature,
+  resolution,
+  sboTerm,
+  compartmentId,
+  complexId,
+}: {
+  vectorSource: VectorSource;
+  feature: Feature;
+  resolution: number;
+  sboTerm: string;
+  compartmentId: number | null;
+  complexId?: number | null;
+}): { cover: boolean; hide: boolean; largestExtent: Extent | null } {
   const type = feature.get('type');
   const getMapExtent = feature.get('getMapExtent');
   let coverRatio = 1;
   let cover = false;
   let hide = false;
   let largestExtent: Extent | null = null;
-  if (getMapExtent instanceof Function && type === 'COMPARTMENT') {
+  if (
+    getMapExtent instanceof Function &&
+    (type === 'COMPARTMENT' || COMPLEX_SBO_TERMS.includes(sboTerm))
+  ) {
     const mapExtent = getMapExtent(resolution);
     const featureExtent = feature.getGeometry()?.getExtent();
     if (featureExtent && mapExtent) {
@@ -51,7 +63,7 @@ export default function handleSemanticView(
 
   if (complexId) {
     const complex = vectorSource.getFeatureById(complexId);
-    if (complex && complex.get('hidden')) {
+    if (complex && (complex.get('hidden') || complex.get('filled'))) {
       hide = true;
     }
   }
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.test.ts
index 0e22293c..8178ab4a 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.test.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.test.ts
@@ -39,7 +39,7 @@ describe('getCoverStyles', () => {
     const mockTextStyle = new Style();
     (getTextStyle as jest.Mock).mockReturnValue(mockTextStyle);
 
-    const result = getCoverStyles(coverStyle, largestExtent, text, scale, zIndex, mapSize);
+    const result = getCoverStyles({ coverStyle, largestExtent, text, scale, zIndex, mapSize });
 
     expect(result).toHaveLength(2);
     expect(result[0]).toBe(coverStyle);
@@ -80,7 +80,7 @@ describe('getCoverStyles', () => {
       fontSize: 0,
     });
 
-    const result = getCoverStyles(coverStyle, largestExtent, text, scale, zIndex, mapSize);
+    const result = getCoverStyles({ coverStyle, largestExtent, text, scale, zIndex, mapSize });
 
     expect(result).toHaveLength(1);
     expect(result[0]).toBe(coverStyle);
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.ts
index ce072c86..78f2ef6b 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getCoverStyles.ts
@@ -7,17 +7,33 @@ import getWrappedTextWithFontSize from '@/components/Map/MapViewer/MapViewerVect
 import { Point } from 'ol/geom';
 import getTextStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextStyle';
 import { MapSize } from '@/redux/map/map.types';
+import { Stroke } from 'ol/style';
+import getScaledStrokeStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle';
 
-export default function getCoverStyles(
-  coverStyle: Style,
-  largestExtent: Extent,
-  text: string,
-  scale: number,
-  zIndex: number,
-  mapSize: MapSize,
-): Array<Style> {
+export default function getCoverStyles({
+  coverStyle,
+  largestExtent,
+  text,
+  scale,
+  zIndex,
+  mapSize,
+  strokeStyle,
+}: {
+  coverStyle: Style;
+  largestExtent: Extent;
+  text: string;
+  scale: number;
+  zIndex: number;
+  mapSize: MapSize;
+  strokeStyle?: Stroke;
+}): Array<Style> {
   const styles: Array<Style> = [];
   coverStyle.setZIndex(zIndex);
+
+  if (coverStyle.getStroke() && strokeStyle) {
+    coverStyle.setStroke(getScaledStrokeStyle(strokeStyle, scale));
+  }
+
   styles.push(coverStyle);
 
   if (text) {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.test.ts
new file mode 100644
index 00000000..5c22d994
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.test.ts
@@ -0,0 +1,36 @@
+/* eslint-disable no-magic-numbers */
+import Style from 'ol/style/Style';
+import { Stroke, Text } from 'ol/style';
+import getScaledStrokeStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle';
+import getScaledElementStyle from './getScaledElementStyle';
+
+jest.mock('./getScaledStrokeStyle');
+
+describe('getScaledElementStyle', () => {
+  it('should scale the stroke style and text scale when strokeStyle is provided', () => {
+    const mockScaledStroke = new Stroke({ color: 'blue', width: 4 });
+    (getScaledStrokeStyle as jest.Mock).mockReturnValue(mockScaledStroke);
+
+    const strokeStyle = new Stroke({ color: 'red', width: 2 });
+    const textStyle = new Text({ text: 'Test', scale: 1 });
+    const style = new Style({ stroke: strokeStyle, text: textStyle });
+    const scale = 2;
+
+    const scaledStyle = getScaledElementStyle(style, strokeStyle, scale);
+
+    expect(getScaledStrokeStyle).toHaveBeenCalledWith(strokeStyle, scale);
+    expect(scaledStyle.getStroke()).toBe(mockScaledStroke);
+    expect(scaledStyle.getText()?.getScale()).toBe(2);
+  });
+
+  it('should scale only text when strokeStyle is not provided', () => {
+    const textStyle = new Text({ text: 'Test', scale: 1 });
+    const style = new Style({ text: textStyle });
+    const scale = 3;
+
+    const scaledStyle = getScaledElementStyle(style, undefined, scale);
+
+    expect(scaledStyle.getStroke()).toBeNull();
+    expect(scaledStyle.getText()?.getScale()).toBe(3);
+  });
+});
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts
index 27c0c515..a91c0309 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts
@@ -1,6 +1,7 @@
 /* eslint-disable no-magic-numbers */
 import Style from 'ol/style/Style';
 import { Stroke } from 'ol/style';
+import getScaledStrokeStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle';
 
 export default function getScaledElementStyle(
   style: Style,
@@ -8,18 +9,7 @@ export default function getScaledElementStyle(
   scale: number,
 ): Style {
   if (strokeStyle) {
-    const lineDash = strokeStyle.getLineDash();
-    let newLineDash: Array<number> = [];
-    if (lineDash) {
-      newLineDash = lineDash.map(width => width * scale);
-    }
-    const newStrokeStyle = new Stroke({
-      color: strokeStyle.getColor(),
-      width: (strokeStyle.getWidth() || 1) * scale,
-      lineDash: newLineDash,
-    });
-
-    style.setStroke(newStrokeStyle);
+    style.setStroke(getScaledStrokeStyle(strokeStyle, scale));
   }
   style.getText()?.setScale(scale);
   return style;
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.test.ts
new file mode 100644
index 00000000..759b88e5
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.test.ts
@@ -0,0 +1,35 @@
+/* eslint-disable no-magic-numbers */
+import { Stroke } from 'ol/style';
+import getScaledStrokeStyle from './getScaledStrokeStyle';
+
+describe('getScaledStrokeStyle', () => {
+  it('should correctly scale the width and lineDash array of a Stroke style', () => {
+    const strokeStyle = new Stroke({
+      color: 'red',
+      width: 2,
+      lineDash: [4, 8],
+    });
+    const scale = 0.2;
+
+    const scaledStroke = getScaledStrokeStyle(strokeStyle, scale);
+
+    expect(scaledStroke.getColor()).toBe('red');
+    expect(scaledStroke.getWidth()).toBe(0.4);
+    expect(scaledStroke.getLineDash()).toEqual([0.8, 1.6]);
+  });
+
+  it('should use a default width of 1 and scale it correctly when getWidth() returns undefined', () => {
+    const strokeStyle = new Stroke({
+      color: 'green',
+      lineDash: [2, 3],
+    });
+    jest.spyOn(strokeStyle, 'getWidth').mockReturnValue(undefined);
+    const scale = 3;
+
+    const scaledStroke = getScaledStrokeStyle(strokeStyle, scale);
+
+    expect(scaledStroke.getColor()).toBe('green');
+    expect(scaledStroke.getWidth()).toBe(3);
+    expect(scaledStroke.getLineDash()).toEqual([6, 9]);
+  });
+});
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.ts
new file mode 100644
index 00000000..111adc06
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledStrokeStyle.ts
@@ -0,0 +1,16 @@
+/* eslint-disable no-magic-numbers */
+import { Stroke } from 'ol/style';
+
+export default function getScaledStrokeStyle(strokeStyle: Stroke, scale: number): Stroke {
+  const lineWidth = strokeStyle.getWidth() || 1;
+  const lineDash = strokeStyle.getLineDash();
+  let newLineDash: Array<number> = [];
+  if (lineDash) {
+    newLineDash = lineDash.map(width => width * scale);
+  }
+  return new Stroke({
+    color: strokeStyle.getColor(),
+    width: lineWidth * scale,
+    lineDash: newLineDash,
+  });
+}
-- 
GitLab


From 03ab127f1065963596916b20d519265fbbfe2de4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Thu, 12 Dec 2024 12:02:16 +0100
Subject: [PATCH 5/7] fix(semantic-view): remove attribute 'hidden' from
 features to optimize styling function

---
 .../mouseClick/mouseLeftClick/onMapLeftClick.ts    |  3 +--
 .../mouseClick/mouseRightClick/onMapRightClick.ts  |  2 +-
 .../reactionsLayer/useOlMapReactionsLayer.ts       |  5 ++++-
 .../utils/shapes/elements/BaseMultiPolygon.ts      |  2 --
 .../shapes/elements/handleSemanticView.test.ts     | 12 +++++-------
 .../utils/shapes/elements/handleSemanticView.ts    |  7 +++----
 .../utils/shapes/reaction/Reaction.ts              | 14 +++++++++-----
 7 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts b/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts
index 62ad872d..3a33837b 100644
--- a/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts
@@ -54,8 +54,7 @@ export const onMapLeftClick =
           const featureZIndex = feature.get('zIndex');
           if (
             (isFeatureFilledCompartment(feature) || isFeatureNotCompartment(feature)) &&
-            (featureZIndex === undefined || featureZIndex >= 0) &&
-            !feature.get('hidden')
+            (featureZIndex === undefined || featureZIndex >= 0)
           ) {
             featureAtPixel = feature;
             return true;
diff --git a/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick.ts b/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick.ts
index 2822685f..74e10fc2 100644
--- a/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick.ts
@@ -40,7 +40,7 @@ export const onMapRightClick =
                     FEATURE_TYPE.REACTION,
                     FEATURE_TYPE.GLYPH
                   ].includes(feature.get('type'))
-                ) && feature.get('zIndex') >= 0 && !feature.get('hidden');
+                ) && feature.get('zIndex') >= 0;
               });
             }
           }
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 509d5cbb..adef459c 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -67,7 +67,10 @@ export const useOlMapReactionsLayer = ({
   const overlaysOrder = useSelector(getOverlayOrderSelector);
   const mapBackgroundType = useSelector(mapBackgroundTypeSelector);
   const currentMarkers = useAppSelector(markersSufraceOfCurrentMapDataSelector);
-  const markersRender = parseSurfaceMarkersToBioEntityRender(currentMarkers);
+  const markersRender = useMemo(() => {
+    return parseSurfaceMarkersToBioEntityRender(currentMarkers);
+  }, [currentMarkers]);
+
   const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector);
   const reactionsForCurrentModel = useAppSelector(newReactionsForCurrentModelSelector);
   const modelElementsLoading = useAppSelector(modelElementsLoadingSelector);
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index a771638e..3a100b05 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -260,10 +260,8 @@ export default abstract class BaseMultiPolygon {
     let largestExtent: Extent | null;
 
     if (this.complexId && !COMPLEX_SBO_TERMS.includes(this.sboTerm) && scale < 0.215) {
-      feature.set('hidden', true);
       return [];
     }
-    feature.set('hidden', false);
 
     let hide = false;
     if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < 0.34) {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
index ddcf4df5..f6360b51 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.test.ts
@@ -24,6 +24,7 @@ describe('handleSemanticView', () => {
       filled: false,
       hidden: false,
     });
+    feature.setId(1);
 
     const mockGeometry = {
       getExtent: jest.fn(() => [2, 0, 10, 10]),
@@ -38,6 +39,7 @@ describe('handleSemanticView', () => {
       .mockImplementation((_, callback) => {
         callback(
           new Feature({
+            id: 1,
             geometry: fromExtent([1, 0, 5, 5]),
             hidden: false,
             type: 'COMPARTMENT',
@@ -55,7 +57,7 @@ describe('handleSemanticView', () => {
       feature,
       resolution: 1,
       sboTerm: 'SBO:123456',
-      compartmentId: null,
+      compartmentId: 2,
     });
 
     expect(result).toEqual({
@@ -69,8 +71,8 @@ describe('handleSemanticView', () => {
     expect(findLargestExtent).toHaveBeenCalled();
   });
 
-  it('should return hide = true when complexId points to a hidden feature', () => {
-    const complexFeature = new Feature({ hidden: true });
+  it('should return hide = true when complexId points to a filled feature', () => {
+    const complexFeature = new Feature({ filled: true });
     jest
       .spyOn(vectorSource, 'getFeatureById')
       .mockImplementation(id => (id === 1 ? complexFeature : null));
@@ -89,8 +91,6 @@ describe('handleSemanticView', () => {
       hide: true,
       largestExtent: [0, 0, 10, 5],
     });
-
-    expect(feature.get('hidden')).toBe(true);
   });
 
   it('should return hide = true when compartmentId points to a filled feature', () => {
@@ -112,7 +112,5 @@ describe('handleSemanticView', () => {
       hide: true,
       largestExtent: [0, 0, 10, 5],
     });
-
-    expect(feature.get('hidden')).toBe(true);
   });
 });
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index a15bc312..d1007e7b 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -44,10 +44,10 @@ export default function handleSemanticView({
         let remainingExtents = [featureExtent];
         vectorSource.forEachFeatureIntersectingExtent(featureExtent, intersectingFeature => {
           if (
-            !intersectingFeature.get('hidden') &&
             intersectingFeature.get('type') === 'COMPARTMENT' &&
             intersectingFeature.get('zIndex') > feature.get('zIndex') &&
-            intersectingFeature.get('filled')
+            intersectingFeature.get('filled') &&
+            intersectingFeature.get('compartmentId') !== feature.getId()
           ) {
             const intersectingFeatureExtent = intersectingFeature.getGeometry()?.getExtent();
             if (intersectingFeatureExtent) {
@@ -63,7 +63,7 @@ export default function handleSemanticView({
 
   if (complexId) {
     const complex = vectorSource.getFeatureById(complexId);
-    if (complex && (complex.get('hidden') || complex.get('filled'))) {
+    if (complex && complex.get('filled')) {
       hide = true;
     }
   }
@@ -73,7 +73,6 @@ export default function handleSemanticView({
       hide = true;
     }
   }
-  (feature as Feature).set('hidden', hide);
 
   return { cover, hide, largestExtent };
 }
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
index 0a611adc..e6e2de63 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
@@ -347,7 +347,15 @@ export default class Reaction {
   protected isAnyOfElementsHidden(): boolean {
     return [...this.products, ...this.reactants, ...this.modifiers].some(reactionElement => {
       const feature = this.vectorSource.getFeatureById(reactionElement.element);
-      return feature && feature.get('hidden');
+      if (!feature) {
+        return false;
+      }
+      const complexId: undefined | number = feature.get('complexId');
+      const compartmentId: undefined | null | number = feature.get('compartmentId');
+      if (complexId && this.vectorSource.getFeatureById(complexId)?.get('filled')) {
+        return true;
+      }
+      return compartmentId && this.vectorSource.getFeatureById(compartmentId)?.get('filled');
     });
   }
 
@@ -356,10 +364,8 @@ export default class Reaction {
       return undefined;
     }
     if (this.isAnyOfElementsHidden()) {
-      feature.set('hidden', true);
       return undefined;
     }
-    feature.set('hidden', false);
 
     const styles: Array<Style> = [];
     const scale = this.minResolution / resolution;
@@ -392,10 +398,8 @@ export default class Reaction {
       return undefined;
     }
     if (this.isAnyOfElementsHidden()) {
-      feature.set('hidden', true);
       return undefined;
     }
-    feature.set('hidden', false);
 
     const styles: Array<Style> = [];
     const style = feature.get('style');
-- 
GitLab


From b6e5677203a5cf5503f21c8b5b2ebaa41fa852db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Thu, 12 Dec 2024 13:34:43 +0100
Subject: [PATCH 6/7] fix(semantic-view): add a function that checks whether a
 feature in a compartment

---
 .../shapes/elements/handleSemanticView.ts     |  7 +-
 .../elements/isFeatureInCompartment.test.ts   | 80 +++++++++++++++++++
 .../shapes/elements/isFeatureInCompartment.ts | 21 +++++
 3 files changed, 107 insertions(+), 1 deletion(-)
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.test.ts
 create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.ts

diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index d1007e7b..22492167 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -5,6 +5,7 @@ import Feature from 'ol/Feature';
 import VectorSource from 'ol/source/Vector';
 import { Extent } from 'ol/extent';
 import { COMPLEX_SBO_TERMS } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
+import isFeatureInCompartment from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment';
 
 export default function handleSemanticView({
   vectorSource,
@@ -21,6 +22,10 @@ export default function handleSemanticView({
   compartmentId: number | null;
   complexId?: number | null;
 }): { cover: boolean; hide: boolean; largestExtent: Extent | null } {
+  const featureId = feature.getId();
+  if (!featureId) {
+    return { cover: false, hide: false, largestExtent: null };
+  }
   const type = feature.get('type');
   const getMapExtent = feature.get('getMapExtent');
   let coverRatio = 1;
@@ -47,7 +52,7 @@ export default function handleSemanticView({
             intersectingFeature.get('type') === 'COMPARTMENT' &&
             intersectingFeature.get('zIndex') > feature.get('zIndex') &&
             intersectingFeature.get('filled') &&
-            intersectingFeature.get('compartmentId') !== feature.getId()
+            !isFeatureInCompartment(+featureId, vectorSource, intersectingFeature)
           ) {
             const intersectingFeatureExtent = intersectingFeature.getGeometry()?.getExtent();
             if (intersectingFeatureExtent) {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.test.ts
new file mode 100644
index 00000000..58c9523c
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.test.ts
@@ -0,0 +1,80 @@
+/* eslint-disable no-magic-numbers */
+import VectorSource from 'ol/source/Vector';
+import Feature from 'ol/Feature';
+import isFeatureInCompartment from './isFeatureInCompartment';
+
+describe('isFeatureInCompartment', () => {
+  let mockVectorSource: jest.Mocked<VectorSource>;
+
+  beforeEach(() => {
+    mockVectorSource = {
+      getFeatureById: jest.fn(),
+    } as unknown as jest.Mocked<VectorSource>;
+  });
+
+  it('should return false if the feature has no compartmentId', () => {
+    const feature = new Feature();
+    feature.set('compartmentId', null);
+
+    const result = isFeatureInCompartment(1, mockVectorSource, feature);
+
+    expect(result).toBe(false);
+  });
+
+  it('should return true if the feature compartmentId matches parentCompartmentId', () => {
+    const feature = new Feature();
+    feature.set('compartmentId', 1);
+
+    const result = isFeatureInCompartment(1, mockVectorSource, feature);
+
+    expect(result).toBe(true);
+  });
+
+  it('should return false if the parent feature does not exist', () => {
+    const feature = new Feature();
+    feature.set('compartmentId', 2);
+
+    mockVectorSource.getFeatureById.mockReturnValueOnce(null);
+
+    const result = isFeatureInCompartment(1, mockVectorSource, feature);
+
+    expect(result).toBe(false);
+    expect(mockVectorSource.getFeatureById).toHaveBeenCalledWith(2);
+  });
+
+  it('should return true if parent feature matches parentCompartmentId in recursive call', () => {
+    const parentFeature = new Feature();
+    parentFeature.set('compartmentId', 1);
+
+    const childFeature = new Feature();
+    childFeature.set('compartmentId', 2);
+
+    mockVectorSource.getFeatureById.mockReturnValueOnce(parentFeature);
+
+    const result = isFeatureInCompartment(1, mockVectorSource, childFeature);
+
+    expect(result).toBe(true);
+    expect(mockVectorSource.getFeatureById).toHaveBeenCalledWith(2);
+  });
+
+  it('should return false if recursive call finds no matching parent', () => {
+    const grandParentFeature = new Feature();
+    grandParentFeature.set('compartmentId', 3);
+
+    const parentFeature = new Feature();
+    parentFeature.set('compartmentId', 2);
+
+    const childFeature = new Feature();
+    childFeature.set('compartmentId', 4);
+
+    mockVectorSource.getFeatureById
+      .mockReturnValueOnce(parentFeature)
+      .mockReturnValueOnce(grandParentFeature);
+
+    const result = isFeatureInCompartment(1, mockVectorSource, childFeature);
+
+    expect(result).toBe(false);
+    expect(mockVectorSource.getFeatureById).toHaveBeenCalledWith(4);
+    expect(mockVectorSource.getFeatureById).toHaveBeenCalledWith(2);
+  });
+});
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.ts
new file mode 100644
index 00000000..15f6c6ad
--- /dev/null
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment.ts
@@ -0,0 +1,21 @@
+import VectorSource from 'ol/source/Vector';
+import Feature from 'ol/Feature';
+
+export default function isFeatureInCompartment(
+  parentCompartmentId: number,
+  vectorSource: VectorSource,
+  feature: Feature,
+): boolean {
+  const compartmentId: undefined | null | number = feature.get('compartmentId');
+  if (!compartmentId) {
+    return false;
+  }
+  if (compartmentId === parentCompartmentId) {
+    return true;
+  }
+  const compartmentFeature = vectorSource.getFeatureById(compartmentId);
+  if (!compartmentFeature) {
+    return false;
+  }
+  return isFeatureInCompartment(parentCompartmentId, vectorSource, compartmentFeature);
+}
-- 
GitLab


From 8de23a71194a99132129f125025e9c8f9a06c26b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl>
Date: Fri, 13 Dec 2024 11:08:40 +0100
Subject: [PATCH 7/7] fix(vector-map): use constants istead of hardcoded values

---
 .../MapViewerVector.constants.ts              | 35 +++++++++++--------
 .../utils/shapes/elements/BaseMultiPolygon.ts | 20 ++++++++---
 .../utils/shapes/elements/Compartment.ts      |  2 +-
 .../shapes/elements/CompartmentPathway.ts     |  2 +-
 .../shapes/elements/handleSemanticView.ts     |  5 +--
 .../utils/shapes/layer/Layer.ts               |  3 +-
 .../utils/shapes/reaction/Reaction.ts         |  9 +++--
 .../MapViewerVector/utils/shapes/text/Text.ts | 12 +++----
 8 files changed, 50 insertions(+), 38 deletions(-)

diff --git a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
index 5bc52a7f..614d3dcf 100644
--- a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
@@ -4,6 +4,11 @@ export const VECTOR_MAP_LAYER_TYPE = 'vectorMapLayer';
 
 export const COMPLEX_SBO_TERMS = ['SBO:0000253', 'SBO:0000297', 'SBO:0000289'];
 
+export const TEXT_CUTOFF_SCALE = 0.34;
+export const OUTLINE_CUTOFF_SCALE = 0.18;
+export const COMPLEX_CONTENTS_CUTOFF_SCALE = 0.215;
+export const REACTION_ELEMENT_CUTOFF_SCALE = 0.125;
+
 export const WHITE_COLOR: Color = {
   alpha: 255,
   rgb: 16777215,
@@ -20,27 +25,27 @@ export const TRANSPARENT_COLOR: Color = {
 };
 
 export const REACTION_ELEMENT_TYPES = {
-  OPERATOR: 'operator',
-  SQUARE: 'square',
-  LINE: 'line',
-  ARROW: 'arrow',
+  OPERATOR: 'OPERATOR',
+  SQUARE: 'SQUARE',
+  LINE: 'LINE',
+  ARROW: 'ARROW',
 };
 
 export const MAP_ELEMENT_TYPES = {
-  TEXT: 'text',
-  MODIFICATION: 'modification',
-  ACTIVITY_BORDER: 'activityBorder',
-  ENTITY: 'entity',
-  OVERLAY: 'overlay',
-  COMPARTMENT: 'compartment',
+  TEXT: 'TEXT',
+  MODIFICATION: 'MODIFICATION',
+  ACTIVITY_BORDER: 'ACTIVITY_BORDER',
+  ENTITY: 'ENTITY',
+  OVERLAY: 'OVERLAY',
+  COMPARTMENT: 'COMPARTMENT',
 };
 
 export const LAYER_ELEMENT_TYPES = {
-  TEXT: 'text',
-  OVAL: 'oval',
-  RECT: 'rect',
-  LINE: 'line',
-  ARROW: 'arrow',
+  TEXT: 'TEXT',
+  OVAL: 'OVAL',
+  RECT: 'RECT',
+  LINE: 'LINE',
+  ARROW: 'ARROW',
 };
 
 export const COMPARTMENT_SQUARE_POINTS: Array<ShapeRelAbs | ShapeRelAbsBezierPoint> = [
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index fd2f74fd..ed6fe198 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -14,8 +14,11 @@ import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shape
 import getTextCoords from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextCoords';
 import { Color } from '@/types/models';
 import {
+  COMPLEX_CONTENTS_CUTOFF_SCALE,
   COMPLEX_SBO_TERMS,
   MAP_ELEMENT_TYPES,
+  OUTLINE_CUTOFF_SCALE,
+  TEXT_CUTOFF_SCALE,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import VectorSource from 'ol/source/Vector';
 import MapBackgroundsEnum from '@/redux/map/map.enums';
@@ -258,14 +261,18 @@ export default abstract class BaseMultiPolygon {
     let cover = false;
     let largestExtent: Extent | null;
 
-    if (this.complexId && !COMPLEX_SBO_TERMS.includes(this.sboTerm) && scale < 0.215) {
+    if (
+      this.complexId &&
+      !COMPLEX_SBO_TERMS.includes(this.sboTerm) &&
+      scale < COMPLEX_CONTENTS_CUTOFF_SCALE
+    ) {
       feature.set('hidden', true);
       return [];
     }
     feature.set('hidden', false);
 
     let hide = false;
-    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < 0.34) {
+    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < TEXT_CUTOFF_SCALE) {
       const semanticViewData = handleSemanticView(
         this.vectorSource,
         feature,
@@ -310,19 +317,22 @@ export default abstract class BaseMultiPolygon {
         return;
       }
 
-      if ([MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) && scale < 0.34) {
+      if (
+        [MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) &&
+        scale < TEXT_CUTOFF_SCALE
+      ) {
         return;
       }
 
       const textStyle = style.getText();
-      if (type === 'text' && textStyle) {
+      if (type === MAP_ELEMENT_TYPES.TEXT && textStyle) {
         textStyle.setScale(scale);
       }
       if (strokeStyle) {
         const lineWidth = strokeStyle.getWidth() || 1;
         if (
           !this.overlaysVisible &&
-          scale < 0.18 &&
+          scale < OUTLINE_CUTOFF_SCALE &&
           !COMPLEX_SBO_TERMS.includes(this.sboTerm) &&
           this.type !== MAP_ELEMENT_TYPES.COMPARTMENT
         ) {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
index 8906e75d..987fd2ce 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
@@ -97,7 +97,7 @@ export default abstract class Compartment extends BaseMultiPolygon {
     mapSize,
   }: CompartmentProps) {
     super({
-      type: 'COMPARTMENT',
+      type: MAP_ELEMENT_TYPES.COMPARTMENT,
       id,
       complexId,
       compartmentId,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
index e758a681..2850176f 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
@@ -87,7 +87,7 @@ export default class CompartmentPathway extends BaseMultiPolygon {
     mapSize,
   }: CompartmentPathwayProps) {
     super({
-      type: 'COMPARTMENT',
+      type: MAP_ELEMENT_TYPES.COMPARTMENT,
       id,
       complexId,
       compartmentId,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index 19619484..b329d609 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -4,6 +4,7 @@ import findLargestExtent from '@/components/Map/MapViewer/MapViewerVector/utils/
 import Feature from 'ol/Feature';
 import VectorSource from 'ol/source/Vector';
 import { Extent } from 'ol/extent';
+import { MAP_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 
 export default function handleSemanticView(
   vectorSource: VectorSource,
@@ -18,7 +19,7 @@ export default function handleSemanticView(
   let cover = false;
   let hide = false;
   let largestExtent: Extent | null = null;
-  if (getMapExtent instanceof Function && type === 'COMPARTMENT') {
+  if (getMapExtent instanceof Function && type === MAP_ELEMENT_TYPES.COMPARTMENT) {
     const mapExtent = getMapExtent(resolution);
     const featureExtent = feature.getGeometry()?.getExtent();
     if (featureExtent && mapExtent) {
@@ -33,7 +34,7 @@ export default function handleSemanticView(
         vectorSource.forEachFeatureIntersectingExtent(featureExtent, intersectingFeature => {
           if (
             !intersectingFeature.get('hidden') &&
-            intersectingFeature.get('type') === 'COMPARTMENT' &&
+            intersectingFeature.get('type') === MAP_ELEMENT_TYPES.COMPARTMENT &&
             intersectingFeature.get('zIndex') > feature.get('zIndex') &&
             intersectingFeature.get('filled')
           ) {
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 29f17e00..0b8d6403 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts
@@ -21,6 +21,7 @@ import Style from 'ol/style/Style';
 import { ArrowTypeDict, LineTypeDict } from '@/redux/shapes/shapes.types';
 import {
   LAYER_ELEMENT_TYPES,
+  REACTION_ELEMENT_CUTOFF_SCALE,
   TRANSPARENT_COLOR,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import getScaledElementStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle';
@@ -305,7 +306,7 @@ export default class Layer {
     let strokeStyle: Stroke | undefined;
     const type = feature.get('elementType');
 
-    if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= 0.08) {
+    if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= REACTION_ELEMENT_CUTOFF_SCALE) {
       return [];
     }
 
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
index 0a611adc..a2a4a38a 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
@@ -7,7 +7,9 @@ import getStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/st
 import Polygon from 'ol/geom/Polygon';
 import Style from 'ol/style/Style';
 import {
+  REACTION_ELEMENT_CUTOFF_SCALE,
   REACTION_ELEMENT_TYPES,
+  TEXT_CUTOFF_SCALE,
   WHITE_COLOR,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import { FeatureLike } from 'ol/Feature';
@@ -366,10 +368,7 @@ export default class Reaction {
     const type = feature.get('elementType');
     let strokeStyle: Stroke | undefined;
 
-    if (type === REACTION_ELEMENT_TYPES.OPERATOR && scale < 0.34) {
-      return [];
-    }
-    if (type === REACTION_ELEMENT_TYPES.ARROW && scale <= 0.125) {
+    if (type === REACTION_ELEMENT_TYPES.OPERATOR && scale < TEXT_CUTOFF_SCALE) {
       return [];
     }
 
@@ -402,7 +401,7 @@ export default class Reaction {
     const scale = this.minResolution / resolution;
     let strokeStyle: Stroke | undefined;
 
-    if (scale <= 0.125) {
+    if (scale <= REACTION_ELEMENT_CUTOFF_SCALE) {
       return [];
     }
 
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
index 6d84b083..27b8ec6f 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
@@ -13,6 +13,7 @@ import { MapInstance } from '@/types/map';
 import getTextCoords from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextCoords';
 import getTextStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextStyle';
 import { Color } from '@/types/models';
+import { TEXT_CUTOFF_SCALE } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 
 export interface TextProps {
   x: number;
@@ -101,15 +102,10 @@ export default class Text {
     if (getTextScale instanceof Function) {
       textScale = getTextScale(resolution);
     }
-
-    if (this.style.getText()) {
-      if (this.fontSize * textScale > 4) {
-        this.style.getText()?.setScale(textScale);
-        this.style.getText()?.setText(this.text);
-      } else {
-        this.style.getText()?.setText(undefined);
-      }
+    if (textScale < TEXT_CUTOFF_SCALE) {
+      return undefined;
     }
+    this.style.getText()?.setScale(textScale);
     return this.style;
   }
 }
-- 
GitLab