From 8774c56e05f76266144b84a3994fba7b76f51744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl> Date: Wed, 11 Dec 2024 10:34:49 +0100 Subject: [PATCH] Feat/optimization --- .../MapViewerVector.constants.ts | 2 +- .../reactionsLayer/processModelElements.ts | 1 + .../reactionsLayer/useOlMapReactionsLayer.ts | 4 +- .../utils/shapes/coords/getBezierCurve.ts | 2 +- .../utils/shapes/coords/getEllipseCoords.ts | 2 +- .../shapes/coords/getLineSegments.test.ts | 46 ++++ .../utils/shapes/coords/getLineSegments.ts | 21 ++ .../utils/shapes/coords/getPolygonCoords.ts | 2 +- .../utils/shapes/elements/BaseMultiPolygon.ts | 71 +++---- .../utils/shapes/elements/Compartment.ts | 30 ++- .../shapes/elements/CompartmentCircle.test.ts | 1 + .../shapes/elements/CompartmentCircle.ts | 7 +- .../elements/CompartmentPathway.test.ts | 1 + .../shapes/elements/CompartmentPathway.ts | 13 +- .../shapes/elements/CompartmentSquare.test.ts | 1 + .../shapes/elements/CompartmentSquare.ts | 3 + .../utils/shapes/elements/MapElement.ts | 29 ++- .../utils/shapes/elements/getArrowFeature.ts | 9 + .../utils/shapes/layer/Layer.ts | 23 +- .../utils/shapes/reaction/Reaction.test.ts | 5 +- .../utils/shapes/reaction/Reaction.ts | 197 +++++++++++------- .../shapes/style/getScaledElementStyle.ts | 27 ++- .../Map/MapViewer/utils/useOlMap.ts | 2 +- 23 files changed, 342 insertions(+), 157 deletions(-) create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.test.ts create mode 100644 src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.ts diff --git a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts index 79fab6da..5bc52a7f 100644 --- a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts +++ b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts @@ -2,7 +2,7 @@ import { Color, ShapeRelAbs, ShapeRelAbsBezierPoint } from '@/types/models'; export const VECTOR_MAP_LAYER_TYPE = 'vectorMapLayer'; -export const COMPLEX_SBO_TERM = 'SBO:0000253'; +export const COMPLEX_SBO_TERMS = ['SBO:0000253', 'SBO:0000297', 'SBO:0000289']; export const WHITE_COLOR: Color = { alpha: 255, 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 2e5bbf99..2f5b97ba 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/processModelElements.ts @@ -54,6 +54,7 @@ export default function processModelElements( if (element.sboTerm === 'SBO:0000290') { const compartmentProps = { id: element.id, + sboTerm: element.sboTerm, complexId: element.complex, compartmentId: element.compartment, x: element.x, 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 6f2aafa1..bf0d3389 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts @@ -178,7 +178,7 @@ export const useOlMapReactionsLayer = ({ vectorSource, mapInstance, }); - return reactionObject.features; + return [reactionObject.lineFeature, ...reactionObject.reactionFeatures]; }); }, [ reactionsForCurrentModel, @@ -244,8 +244,6 @@ 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/MapViewerVector/utils/shapes/coords/getBezierCurve.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getBezierCurve.ts index 814e7aac..b086befa 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getBezierCurve.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getBezierCurve.ts @@ -6,7 +6,7 @@ export default function getBezierCurve({ p1, p2, p3, - numPoints = 50, + numPoints = 3, }: { p0: Coordinate; p1: Coordinate; diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getEllipseCoords.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getEllipseCoords.ts index aca8a892..c617ffaf 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getEllipseCoords.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getEllipseCoords.ts @@ -13,7 +13,7 @@ export default function getEllipseCoords({ height, width, pointToProjection, - points = 20, + points = 30, }: { x: number; y: number; diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.test.ts new file mode 100644 index 00000000..ec6d5a70 --- /dev/null +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.test.ts @@ -0,0 +1,46 @@ +/* eslint-disable no-magic-numbers */ +import { Line } from '@/types/models'; +import { BLACK_COLOR } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; +import getLineSegments from './getLineSegments'; + +describe('getLineSegments', () => { + it('should return flattened array of projected coordinates for all line segments', () => { + const pointToProjection = jest.fn(({ x, y }) => [x * 10, y * 10]); + + const line = { + id: 1, + width: 1, + color: BLACK_COLOR, + z: 1, + startArrow: { + arrowType: 'NONE', + angle: 2.748893571891069, + lineType: 'SOLID', + length: 15.0, + }, + endArrow: { + arrowType: 'NONE', + angle: 2.748893571891069, + lineType: 'SOLID', + length: 15.0, + }, + segments: [ + { x1: 1, y1: 2, x2: 3, y2: 4 }, + { x1: 3, y1: 4, x2: 5, y2: 6 }, + ], + } as Line; + + const result = getLineSegments(line, pointToProjection); + + expect(pointToProjection).toHaveBeenCalledTimes(3); + expect(pointToProjection).toHaveBeenNthCalledWith(1, { x: 1, y: 2 }); + expect(pointToProjection).toHaveBeenNthCalledWith(2, { x: 3, y: 4 }); + expect(pointToProjection).toHaveBeenNthCalledWith(3, { x: 5, y: 6 }); + + expect(result).toEqual([ + [10, 20], + [30, 40], + [50, 60], + ]); + }); +}); diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.ts new file mode 100644 index 00000000..c7afcc53 --- /dev/null +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments.ts @@ -0,0 +1,21 @@ +/* eslint-disable no-magic-numbers */ +import { Coordinate } from 'ol/coordinate'; +import { Line } from '@/types/models'; +import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; + +export default function getLineSegments( + line: Line, + pointToProjection: UsePointToProjectionResult, +): Array<Coordinate> { + return line.segments + .map((segment, index) => { + if (index === 0) { + return [ + pointToProjection({ x: segment.x1, y: segment.y1 }), + pointToProjection({ x: segment.x2, y: segment.y2 }), + ]; + } + return [pointToProjection({ x: segment.x2, y: segment.y2 })]; + }) + .flat(); +} diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts index 69af893a..9f68ed47 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts @@ -47,6 +47,6 @@ export default function getPolygonCoords({ const { p1, p2, p3 } = getCurveCoords({ x, y, point, height, width, pointToProjection }); const p0 = lastPoint; lastPoint = p3; - return getBezierCurve({ p0, p1, p2, p3, numPoints: 20 }); + return getBezierCurve({ p0, p1, p2, p3, numPoints: 3 }); }); } 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 351fef81..c13c61f4 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts @@ -1,12 +1,11 @@ /* eslint-disable no-magic-numbers */ import Polygon from 'ol/geom/Polygon'; -import { Style } from 'ol/style'; +import { Stroke, Style } from 'ol/style'; import Feature, { FeatureLike } from 'ol/Feature'; import { MultiPolygon } from 'ol/geom'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { HorizontalAlign, - ScaleFunction, VerticalAlign, } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.types'; import { MapInstance } from '@/types/map'; @@ -15,7 +14,7 @@ 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_SBO_TERM, + COMPLEX_SBO_TERMS, MAP_ELEMENT_TYPES, } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; import VectorSource from 'ol/source/Vector'; @@ -27,7 +26,7 @@ import handleSemanticView from '@/components/Map/MapViewer/MapViewerVector/utils export interface BaseMapElementProps { type: string; - sboTerm?: string; + sboTerm: string; id: number; complexId?: number | null; compartmentId: number | null; @@ -52,12 +51,13 @@ export interface BaseMapElementProps { vectorSource: VectorSource; mapBackgroundType: number; mapSize: MapSize; + mapInstance: MapInstance; } export default abstract class BaseMultiPolygon { type: string; - sboTerm: string | undefined; + sboTerm: string; id: number; @@ -118,6 +118,8 @@ export default abstract class BaseMultiPolygon { [number, number, number, number] >(); + minResolution: number; + constructor({ type, sboTerm, @@ -145,6 +147,7 @@ export default abstract class BaseMultiPolygon { vectorSource, mapBackgroundType, mapSize, + mapInstance, }: BaseMapElementProps) { this.type = type; this.sboTerm = sboTerm; @@ -172,6 +175,9 @@ export default abstract class BaseMultiPolygon { this.vectorSource = vectorSource; this.mapBackgroundType = mapBackgroundType; this.mapSize = mapSize; + + const maxZoom = mapInstance?.getView().get('originalMaxZoom'); + this.minResolution = mapInstance?.getView().getResolutionForZoom(maxZoom) || 1; } protected abstract createPolygons(): void; @@ -200,6 +206,7 @@ export default abstract class BaseMultiPolygon { horizontalAlign: this.nameHorizontalAlign, }); textStyle.setGeometry(textPolygon); + textPolygon.set('style', textStyle); this.styles.push(textStyle); this.polygons.push(textPolygon); } @@ -209,19 +216,6 @@ export default abstract class BaseMultiPolygon { this.feature = new Feature({ geometry: new MultiPolygon(this.polygons), zIndex: this.zIndex, - getScale: ((): ScaleFunction => { - const maxZoom = mapInstance?.getView().get('originalMaxZoom'); - const minResolution = maxZoom - ? mapInstance?.getView().getResolutionForZoom(maxZoom) - : undefined; - - return (resolution: number): number => { - if (minResolution) { - return minResolution / resolution; - } - return 1; - }; - })(), getMapExtent: (resolution: number): [number, number, number, number] | undefined => { if (this.mapExtentCache.has(resolution)) { return this.mapExtentCache.get(resolution); @@ -262,14 +256,15 @@ export default abstract class BaseMultiPolygon { return undefined; } const styles: Array<Style> = []; - const getScale = feature.get('getScale'); - let scale = 1; + const scale = this.minResolution / resolution; let cover = false; let largestExtent: Extent | null; - if (getScale instanceof Function) { - scale = getScale(resolution); + 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) { @@ -292,9 +287,9 @@ export default abstract class BaseMultiPolygon { let type: string; let fontSize: number; - let lineWidth: number; let text: string; let coverStyle: Style | undefined; + let strokeStyle: Stroke | undefined; this.styles.forEach(style => { const styleGeometry = style.getGeometry(); @@ -302,8 +297,8 @@ export default abstract class BaseMultiPolygon { type = styleGeometry.get('type'); text = styleGeometry.get('text'); fontSize = styleGeometry.get('fontSize') || 10; - lineWidth = styleGeometry.get('lineWidth'); coverStyle = styleGeometry.get('coverStyle'); + strokeStyle = styleGeometry.get('strokeStyle'); } if (cover) { @@ -329,30 +324,36 @@ export default abstract class BaseMultiPolygon { return; } - const clonedStyle = style.clone(); - const textStyle = clonedStyle.getText(); - const strokeStyle = clonedStyle.getStroke(); + const textStyle = style.getText(); if (type === 'text' && textStyle) { textStyle.setScale(scale); textStyle.setText(text); } - if (strokeStyle && lineWidth) { + if (strokeStyle) { + const lineWidth = strokeStyle.getWidth() || 1; if ( !this.overlaysVisible && - lineWidth * scale < 0.08 && - this.sboTerm !== COMPLEX_SBO_TERM + scale < 0.18 && + !COMPLEX_SBO_TERMS.includes(this.sboTerm) && + this.type !== MAP_ELEMENT_TYPES.COMPARTMENT ) { - clonedStyle.setStroke(null); + style.setStroke(null); } else { - strokeStyle.setWidth(lineWidth * scale); const lineDash = strokeStyle.getLineDash(); + let newLineDash: Array<number> = []; if (lineDash) { - const newLineDash = lineDash.map(width => width * scale); - strokeStyle.setLineDash(newLineDash); + newLineDash = lineDash.map(width => width * scale); } + const newStrokeStyle = new Stroke({ + color: strokeStyle.getColor(), + width: lineWidth * scale, + lineDash: newLineDash, + }); + + style.setStroke(newStrokeStyle); } } - styles.push(clonedStyle); + styles.push(style); }); return styles; 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 b851e10a..8906e75d 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts @@ -7,7 +7,7 @@ import { import BaseMultiPolygon from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon'; import { Coordinate } from 'ol/coordinate'; import Polygon from 'ol/geom/Polygon'; -import { Style } from 'ol/style'; +import { Stroke, Style } from 'ol/style'; import getFill from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getFill'; import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/rgbToHex'; import getStroke from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getStroke'; @@ -24,6 +24,7 @@ export interface CompartmentProps { id: number; complexId?: number | null; compartmentId: number | null; + sboTerm: string; x: number; y: number; width: number; @@ -68,6 +69,7 @@ export default abstract class Compartment extends BaseMultiPolygon { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -99,6 +101,7 @@ export default abstract class Compartment extends BaseMultiPolygon { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -120,6 +123,7 @@ export default abstract class Compartment extends BaseMultiPolygon { vectorSource, mapBackgroundType, mapSize, + mapInstance, }); this.outerWidth = outerWidth; this.innerWidth = innerWidth; @@ -161,13 +165,17 @@ export default abstract class Compartment extends BaseMultiPolygon { const outerPolygon = new Polygon([this.outerCoords]); outerPolygon.set('type', MAP_ELEMENT_TYPES.COMPARTMENT); - outerPolygon.set('lineWidth', this.outerWidth); + let outerPolygonStroke: Stroke | undefined; + if (this.overlaysVisible) { + outerPolygonStroke = getStroke({ width: this.outerWidth }); + } else { + outerPolygonStroke = getStroke({ color: rgbToHex(this.borderColor), width: this.outerWidth }); + } + outerPolygon.set('strokeStyle', outerPolygonStroke); this.styles.push( new Style({ geometry: outerPolygon, - stroke: this.overlaysVisible - ? getStroke({ width: this.outerWidth }) - : getStroke({ color: rgbToHex(this.borderColor), width: this.outerWidth }), + stroke: outerPolygonStroke, zIndex: this.zIndex, }), ); @@ -175,13 +183,17 @@ export default abstract class Compartment extends BaseMultiPolygon { const innerPolygon = new Polygon([this.innerCoords]); innerPolygon.set('type', MAP_ELEMENT_TYPES.COMPARTMENT); - innerPolygon.set('lineWidth', this.innerWidth); + let innerPolygonStroke: Stroke | undefined; + if (this.overlaysVisible) { + innerPolygonStroke = getStroke({ width: this.innerWidth }); + } else { + innerPolygonStroke = getStroke({ color: rgbToHex(this.borderColor), width: this.innerWidth }); + } + innerPolygon.set('strokeStyle', innerPolygonStroke); this.styles.push( new Style({ geometry: innerPolygon, - stroke: this.overlaysVisible - ? getStroke({ width: this.innerWidth }) - : getStroke({ color: rgbToHex(this.borderColor), width: this.innerWidth }), + stroke: innerPolygonStroke, fill: this.overlaysVisible ? getFill({ color: rgbToHex(TRANSPARENT_COLOR) }) : getFill({ color: rgbToHex({ ...this.fillColor, alpha: 9 }) }), diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.test.ts index 876dd762..7c5956c6 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.test.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.test.ts @@ -46,6 +46,7 @@ describe('CompartmentCircle', () => { id: 1, complexId: null, compartmentId: null, + sboTerm: 'SBO:0000253', x: 0, y: 0, width: 100, diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.ts index 3dd38183..94a65df8 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentCircle.ts @@ -21,6 +21,7 @@ export type CompartmentCircleProps = { id: number; complexId?: number | null; compartmentId: number | null; + sboTerm: string; x: number; y: number; width: number; @@ -53,6 +54,7 @@ export default class CompartmentCircle extends Compartment { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -83,6 +85,7 @@ export default class CompartmentCircle extends Compartment { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -119,7 +122,7 @@ export default class CompartmentCircle extends Compartment { radius: COMPARTMENT_CIRCLE_RADIUS, height: this.height, width: this.width, - points: 40, + points: 36, pointToProjection: this.pointToProjection, }); this.innerCoords = getEllipseCoords({ @@ -129,7 +132,7 @@ export default class CompartmentCircle extends Compartment { radius: COMPARTMENT_CIRCLE_RADIUS, height: this.height - 2 * this.thickness, width: this.width - 2 * this.thickness, - points: 40, + points: 20, pointToProjection: this.pointToProjection, }); } diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.test.ts index 5e1df810..00c1931b 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.test.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.test.ts @@ -46,6 +46,7 @@ describe('CompartmentPathway', () => { id: 1, complexId: null, compartmentId: null, + sboTerm: 'SBO:0000253', x: 0, y: 0, width: 100, 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 d51153e6..e758a681 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts @@ -20,11 +20,13 @@ import { Style } from 'ol/style'; import getFill from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getFill'; import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/rgbToHex'; import { MapSize } from '@/redux/map/map.types'; +import getStroke from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getStroke'; export type CompartmentPathwayProps = { id: number; complexId?: number | null; compartmentId: number | null; + sboTerm: string; x: number; y: number; width: number; @@ -59,6 +61,7 @@ export default class CompartmentPathway extends BaseMultiPolygon { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -88,6 +91,7 @@ export default class CompartmentPathway extends BaseMultiPolygon { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -109,6 +113,7 @@ export default class CompartmentPathway extends BaseMultiPolygon { vectorSource, mapBackgroundType, mapSize, + mapInstance, }); this.outerWidth = outerWidth; this.overlaysVisible = overlaysVisible; @@ -128,12 +133,18 @@ export default class CompartmentPathway extends BaseMultiPolygon { ], ]); compartmentPolygon.set('type', MAP_ELEMENT_TYPES.COMPARTMENT); - compartmentPolygon.set('lineWidth', this.outerWidth); const coverStyle = new Style({ geometry: compartmentPolygon, fill: getFill({ color: rgbToHex({ ...this.fillColor, alpha: 255 }) }), }); compartmentPolygon.set('coverStyle', coverStyle); + compartmentPolygon.set( + 'strokeStyle', + getStroke({ + color: rgbToHex(this.borderColor), + width: this.outerWidth, + }), + ); this.styles.push( getStyle({ geometry: compartmentPolygon, diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.test.ts index c7721148..53fff2ff 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.test.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.test.ts @@ -44,6 +44,7 @@ describe('CompartmentSquare', () => { id: 1, complexId: null, compartmentId: null, + sboTerm: 'SBO:0000253', x: 0, y: 0, width: 100, diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.ts index b4905d61..8f033df3 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentSquare.ts @@ -20,6 +20,7 @@ export type CompartmentSquareProps = { id: number; complexId?: number | null; compartmentId: number | null; + sboTerm: string; x: number; y: number; width: number; @@ -52,6 +53,7 @@ export default class CompartmentSquare extends Compartment { id, complexId, compartmentId, + sboTerm, x, y, width, @@ -82,6 +84,7 @@ export default class CompartmentSquare extends Compartment { id, complexId, compartmentId, + sboTerm, x, y, width, 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 6ef7a733..77ab7ebc 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/MapElement.ts @@ -163,6 +163,7 @@ export default class MapElement extends BaseMultiPolygon { overlaysVisible, mapBackgroundType, mapSize, + mapInstance, }); this.shapes = shapes; this.lineWidth = lineWidth; @@ -221,13 +222,14 @@ export default class MapElement extends BaseMultiPolygon { }); modificationPolygon.set('type', MAP_ELEMENT_TYPES.MODIFICATION); modificationPolygon.set('fontSize', modification.fontSize); - modificationPolygon.set('lineWidth', 1); + const modificationStrokeStyle = getStroke({ color: rgbToHex(modification.borderColor) }); const modificationStyle = new Style({ geometry: modificationPolygon, - stroke: getStroke({ color: rgbToHex(modification.borderColor) }), + stroke: modificationStrokeStyle, fill: getFill({ color: rgbToHex(modification.fillColor) }), zIndex: modification.z, }); + modificationPolygon.set('strokeStyle', modificationStrokeStyle); this.polygons.push(modificationPolygon); this.styles.push(modificationStyle); }); @@ -276,13 +278,18 @@ export default class MapElement extends BaseMultiPolygon { pointToProjection: this.pointToProjection, }); activityBorderPolygon.set('type', MAP_ELEMENT_TYPES.ACTIVITY_BORDER); - activityBorderPolygon.set('lineWidth', 1); const activityBorderStyle = getStyle({ geometry: activityBorderPolygon, fillColor: TRANSPARENT_COLOR, lineDash: [3, 5], zIndex: this.zIndex, }); + activityBorderPolygon.set( + 'strokeStyle', + getStroke({ + lineDash: [3, 5], + }), + ); this.polygons.push(activityBorderPolygon); this.styles.push(activityBorderStyle); }); @@ -299,7 +306,6 @@ export default class MapElement extends BaseMultiPolygon { pointToProjection: this.pointToProjection, }); elementPolygon.set('type', MAP_ELEMENT_TYPES.ENTITY); - elementPolygon.set('lineWidth', this.lineWidth); const elementStyle = getStyle({ geometry: elementPolygon, borderColor: this.borderColor, @@ -308,6 +314,14 @@ 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, + }), + ); this.polygons.push(elementPolygon); this.styles.push(elementStyle); }); @@ -335,13 +349,18 @@ export default class MapElement extends BaseMultiPolygon { ], ]); polygon.set('type', MAP_ELEMENT_TYPES.OVERLAY); - polygon.set('lineWidth', 1); const style = getStyle({ geometry: polygon, borderColor: color, fillColor: color, zIndex: this.zIndex, }); + polygon.set( + 'strokeStyle', + getStroke({ + color, + }), + ); this.polygons.push(polygon); this.styles.push(style); }); diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature.ts index 02e0ab19..c8f46d9d 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature.ts @@ -9,6 +9,8 @@ import getShapePolygon from '@/components/Map/MapViewer/MapViewerVector/utils/sh import Polygon from 'ol/geom/Polygon'; import { WHITE_COLOR } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; import { ArrowTypeDict } from '@/redux/shapes/shapes.types'; +import getStroke from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getStroke'; +import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/rgbToHex'; export default function getArrowFeature({ arrowTypes, @@ -53,6 +55,13 @@ export default function getArrowFeature({ fillColor: shape.fill === false ? WHITE_COLOR : color, lineWidth, }); + arrowPolygon.set( + 'strokeStyle', + getStroke({ + color: rgbToHex(color), + width: lineWidth, + }), + ); arrowPolygon.rotate(rotation, pointToProjection({ x, y })); arrowStyles.push(style); arrowPolygons.push(arrowPolygon); 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 ec4cab79..a842f5f2 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts @@ -24,6 +24,7 @@ import { TRANSPARENT_COLOR, } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; import getScaledElementStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle'; +import { Stroke } from 'ol/style'; export interface LayerProps { texts: Array<LayerText>; @@ -171,7 +172,7 @@ export default class Layer { height: oval.height, width: oval.width, pointToProjection: this.pointToProjection, - points: 36, + points: 20, }); const polygon = new Polygon([coords]); const polygonStyle = getStyle({ @@ -264,7 +265,6 @@ export default class Layer { }); if (endArrowFeature) { endArrowFeature.set('elementType', LAYER_ELEMENT_TYPES.ARROW); - endArrowFeature.set('lineWidth', line.width); endArrowFeature.setStyle(this.getStyle.bind(this)); arrowsFeatures.push(endArrowFeature); } @@ -302,22 +302,27 @@ export default class Layer { } const scale = minResolution / resolution; - const lineWidth = feature.get('lineWidth'); + let strokeStyle: Stroke | undefined; const type = feature.get('elementType'); if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= 0.08) { return []; } + const stylesToProcess: Array<Style> = []; if (style instanceof Style) { - styles.push(getScaledElementStyle(style, lineWidth, scale)); + stylesToProcess.push(style); } else if (Array.isArray(style)) { - style.forEach(singleStyle => { - if (singleStyle instanceof Style) { - styles.push(getScaledElementStyle(singleStyle, lineWidth, scale)); - } - }); + stylesToProcess.push(...style); } + stylesToProcess.forEach(singleStyle => { + const styleGeometry = singleStyle.getGeometry(); + if (styleGeometry instanceof Polygon || styleGeometry instanceof LineString) { + strokeStyle = styleGeometry.get('strokeStyle'); + } + styles.push(getScaledElementStyle(singleStyle, strokeStyle, scale)); + }); + return styles; } } diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.test.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.test.ts index 70c5b3e4..0e6dce24 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.test.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.test.ts @@ -51,7 +51,8 @@ describe('Layer', () => { it('should initialize a Reaction class', () => { const reaction = new Reaction(props); - expect(reaction.features.length).toBe(12); - expect(reaction.features).toBeInstanceOf(Array<Feature>); + expect(reaction.reactionFeatures.length).toBe(3); + expect(reaction.reactionFeatures).toBeInstanceOf(Array<Feature>); + expect(reaction.lineFeature).toBeInstanceOf(Feature); }); }); 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 43310864..afeeeeab 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts @@ -2,11 +2,8 @@ import { Line, Operator, ReactionProduct, Shape } from '@/types/models'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { Feature } from 'ol'; -import { Circle, LineString, MultiPolygon } from 'ol/geom'; -import getRotation from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getRotation'; +import { Circle, LineString, MultiLineString, MultiPolygon } from 'ol/geom'; import getStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getStyle'; -import getArrowFeature from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature'; -import getShapePolygon from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getShapePolygon'; import Polygon from 'ol/geom/Polygon'; import Style from 'ol/style/Style'; import { @@ -15,12 +12,18 @@ import { } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; import { FeatureLike } from 'ol/Feature'; import { MapInstance } from '@/types/map'; -import getTextStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextStyle'; import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/rgbToHex'; import { ArrowTypeDict, LineTypeDict } from '@/redux/shapes/shapes.types'; import { FEATURE_TYPE } from '@/constants/features'; import getScaledElementStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle'; import VectorSource from 'ol/source/Vector'; +import getStroke from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getStroke'; +import { Stroke } from 'ol/style'; +import getLineSegments from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getLineSegments'; +import getRotation from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getRotation'; +import getArrowFeature from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getArrowFeature'; +import getShapePolygon from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/getShapePolygon'; +import getTextStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextStyle'; export interface ReactionProps { id: number; @@ -63,9 +66,13 @@ export default class Reaction { vectorSource: VectorSource; - mapInstance: MapInstance; + lineFeature: Feature<MultiLineString> = new Feature(); + + reactionFeatures: Array<Feature<MultiPolygon> | Feature<Circle>> = []; - features: Array<Feature> = []; + lineStyles: Array<Style> = []; + + minResolution: number; constructor({ id, @@ -94,56 +101,51 @@ export default class Reaction { this.shapes = shapes; this.pointToProjection = pointToProjection; this.vectorSource = vectorSource; - this.mapInstance = mapInstance; + + const maxZoom = mapInstance?.getView().get('originalMaxZoom'); + this.minResolution = mapInstance?.getView().getResolutionForZoom(maxZoom) || 1; this.drawReaction(); } private drawReaction(): void { const reactionSquareFeature = this.getReactionSquare(); - this.features.push(reactionSquareFeature); - let lineFeature = this.getLineFeature(this.line); - this.features.push(lineFeature.lineFeature); - this.features.push(...lineFeature.arrowsFeatures); - this.products.forEach(product => { - lineFeature = this.getLineFeature(product.line); - this.features.push(lineFeature.lineFeature); - this.features.push(...lineFeature.arrowsFeatures); + this.reactionFeatures.push(reactionSquareFeature); + + const lineStringElements: Array<LineString> = []; + let lineStringWithArrows = this.getLineStringWithArrows(this.line); + lineStringElements.push(lineStringWithArrows.lineString); + this.reactionFeatures.push(...lineStringWithArrows.arrowsFeatures); + [...this.products, ...this.reactants, ...this.modifiers].forEach(element => { + lineStringWithArrows = this.getLineStringWithArrows(element.line); + lineStringElements.push(lineStringWithArrows.lineString); + this.reactionFeatures.push(...lineStringWithArrows.arrowsFeatures); }); - this.reactants.forEach(reactant => { - lineFeature = this.getLineFeature(reactant.line); - this.features.push(lineFeature.lineFeature); - this.features.push(...lineFeature.arrowsFeatures); + [...this.operators].forEach(operator => { + lineStringWithArrows = this.getLineStringWithArrows(operator.line); + lineStringElements.push(lineStringWithArrows.lineString); + this.reactionFeatures.push(...lineStringWithArrows.arrowsFeatures); + this.reactionFeatures.push(this.getOperator(operator)); }); - this.operators.forEach(operator => { - lineFeature = this.getLineFeature(operator.line); - this.features.push(lineFeature.lineFeature); - this.features.push(...lineFeature.arrowsFeatures); - this.features.push(this.getOperator(operator)); - }); - this.modifiers.forEach(modifier => { - lineFeature = this.getLineFeature(modifier.line); - this.features.push(lineFeature.lineFeature); - this.features.push(...lineFeature.arrowsFeatures); + + const multiLineString = new MultiLineString(lineStringElements); + + this.lineFeature = new Feature<MultiLineString>({ + geometry: multiLineString, + id: this.id, + type: FEATURE_TYPE.REACTION, + elementType: REACTION_ELEMENT_TYPES.LINE, + zIndex: this.zIndex, }); + this.lineFeature.setStyle(this.getLineStyle.bind(this)); } - private getLineFeature(line: Line): { - lineFeature: Feature<LineString>; + private getLineStringWithArrows(line: Line): { + lineString: LineString; arrowsFeatures: Array<Feature<MultiPolygon>>; } { const arrowsFeatures: Array<Feature<MultiPolygon>> = []; - const points = line.segments - .map((segment, index) => { - if (index === 0) { - return [ - this.pointToProjection({ x: segment.x1, y: segment.y1 }), - this.pointToProjection({ x: segment.x2, y: segment.y2 }), - ]; - } - return [this.pointToProjection({ x: segment.x2, y: segment.y2 })]; - }) - .flat(); + const points = getLineSegments(line, this.pointToProjection); if (line.startArrow.arrowType !== 'NONE') { const firstSegment = line.segments[0]; @@ -168,8 +170,7 @@ export default class Reaction { }); if (startArrowFeature) { startArrowFeature.set('elementType', REACTION_ELEMENT_TYPES.ARROW); - startArrowFeature.set('lineWidth', line.width); - startArrowFeature.setStyle(this.getStyle.bind(this)); + startArrowFeature.setStyle(this.getReactionObjectStyle.bind(this)); arrowsFeatures.push(startArrowFeature); } } @@ -196,8 +197,7 @@ export default class Reaction { }); if (endArrowFeature) { endArrowFeature.set('elementType', REACTION_ELEMENT_TYPES.ARROW); - endArrowFeature.set('lineWidth', line.width); - endArrowFeature.setStyle(this.getStyle.bind(this)); + endArrowFeature.setStyle(this.getReactionObjectStyle.bind(this)); arrowsFeatures.push(endArrowFeature); } } @@ -212,18 +212,17 @@ export default class Reaction { lineDash, zIndex: this.zIndex, }); - const lineFeature = new Feature<LineString>({ - geometry: lineString, - style: lineStyle, - lineWidth: line.width, - id: this.id, - type: FEATURE_TYPE.REACTION, - elementType: REACTION_ELEMENT_TYPES.LINE, - zIndex: this.zIndex, - }); - lineFeature.setStyle(this.getStyle.bind(this)); + lineString.set( + 'strokeStyle', + getStroke({ + color: rgbToHex(line.color), + width: line.width, + lineDash, + }), + ); + this.lineStyles.push(lineStyle); - return { lineFeature, arrowsFeatures }; + return { lineString, arrowsFeatures }; } private getReactionSquare(): Feature<MultiPolygon> { @@ -252,6 +251,13 @@ export default class Reaction { borderColor: this.line.color, zIndex: this.zIndex + 1, }); + squarePolygon.set( + 'strokeStyle', + getStroke({ + color: rgbToHex(this.line.color), + width: this.line.width, + }), + ); squarePolygon.rotate( squareRotation, this.pointToProjection({ @@ -271,7 +277,7 @@ export default class Reaction { elementType: REACTION_ELEMENT_TYPES.SQUARE, zIndex: this.zIndex, }); - squareFeature.setStyle(this.getStyle.bind(this)); + squareFeature.setStyle(this.getReactionObjectStyle.bind(this)); return squareFeature; } @@ -304,6 +310,12 @@ export default class Reaction { borderColor: operator.line.color, fillColor: operator.line.color, }); + circle.set( + 'strokeStyle', + getStroke({ + color: rgbToHex(operator.line.color), + }), + ); if (operator.operatorText) { circleStyle.getFill()?.setColor(rgbToHex(WHITE_COLOR)); @@ -328,7 +340,7 @@ export default class Reaction { fontSize: 10, zIndex: this.zIndex, }); - circleFeature.setStyle(this.getStyle.bind(this)); + circleFeature.setStyle(this.getReactionObjectStyle.bind(this)); return circleFeature; } @@ -339,7 +351,7 @@ export default class Reaction { }); } - protected getStyle(feature: FeatureLike, resolution: number): Style | Array<Style> | void { + protected getLineStyle(feature: FeatureLike, resolution: number): Style | Array<Style> | void { if (!(feature instanceof Feature)) { return undefined; } @@ -350,34 +362,65 @@ export default class Reaction { feature.set('hidden', false); const styles: Array<Style> = []; - const maxZoom = this.mapInstance?.getView().get('originalMaxZoom'); - const minResolution = this.mapInstance?.getView().getResolutionForZoom(maxZoom); - const style = feature.get('style'); - if (!minResolution || !style) { - return []; - } - - const scale = minResolution / resolution; - const lineWidth = feature.get('lineWidth'); + 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) { return []; } - if (type === REACTION_ELEMENT_TYPES.ARROW && scale <= 0.08) { + if (type === REACTION_ELEMENT_TYPES.ARROW && scale <= 0.125) { return []; } + this.lineStyles.forEach(style => { + const styleGeometry = style.getGeometry(); + if (styleGeometry instanceof Polygon || styleGeometry instanceof LineString) { + strokeStyle = styleGeometry.get('strokeStyle'); + } + styles.push(getScaledElementStyle(style, strokeStyle, scale)); + }); + + return styles; + } + + protected getReactionObjectStyle( + feature: FeatureLike, + resolution: number, + ): Style | Array<Style> | void { + if (!(feature instanceof Feature)) { + return undefined; + } + if (this.isAnyOfElementsHidden()) { + feature.set('hidden', true); + return undefined; + } + feature.set('hidden', false); + + const styles: Array<Style> = []; + const style = feature.get('style'); + const scale = this.minResolution / resolution; + let strokeStyle: Stroke | undefined; + + if (scale <= 0.125) { + return []; + } + + const stylesToProcess: Array<Style> = []; if (style instanceof Style) { - styles.push(getScaledElementStyle(style, lineWidth, scale)); + stylesToProcess.push(style); } else if (Array.isArray(style)) { - style.forEach(singleStyle => { - if (singleStyle instanceof Style) { - styles.push(getScaledElementStyle(singleStyle, lineWidth, scale)); - } - }); + stylesToProcess.push(...style); } + stylesToProcess.forEach(singleStyle => { + const styleGeometry = singleStyle.getGeometry(); + if (styleGeometry instanceof Polygon || styleGeometry instanceof LineString) { + strokeStyle = styleGeometry.get('strokeStyle'); + } + styles.push(getScaledElementStyle(singleStyle, strokeStyle, scale)); + }); + return styles; } } 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 f4a4f77a..27c0c515 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle.ts @@ -1,17 +1,26 @@ +/* eslint-disable no-magic-numbers */ import Style from 'ol/style/Style'; +import { Stroke } from 'ol/style'; export default function getScaledElementStyle( style: Style, - lineWidth: number, + strokeStyle: Stroke | undefined, scale: number, ): Style { - const clonedStyle = style.clone(); - const lineDash = clonedStyle.getStroke()?.getLineDash(); - if (lineDash) { - const newLineDash = lineDash.map(width => width * scale); - clonedStyle.getStroke()?.setLineDash(newLineDash); + 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); } - clonedStyle.getStroke()?.setWidth(lineWidth * scale); - clonedStyle.getText()?.setScale(scale); - return clonedStyle; + style.getText()?.setScale(scale); + return style; } diff --git a/src/components/Map/MapViewer/utils/useOlMap.ts b/src/components/Map/MapViewer/utils/useOlMap.ts index 68ec65bd..23d585e0 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: 250, + duration: 0, timeout: 80, }), ]), -- GitLab