From dfca2762c72b8c83a9d5e0d69d671fe4efc62ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=82osz=20Grocholewski?= <m.grocholewski@atcomp.pl> Date: Mon, 4 Nov 2024 10:10:31 +0100 Subject: [PATCH] feat(vector-map): implement reaction square element --- .../reactionsLayer/useOlMapReactionsLayer.ts | 7 +- .../utils/shapes/coords/getPolygonCoords.ts | 4 +- .../utils/shapes/reaction/Reaction.test.ts | 4 +- .../utils/shapes/reaction/Reaction.ts | 67 +++++++++++++++++-- 4 files changed, 73 insertions(+), 9 deletions(-) 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 66ddd448..2b3680b0 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/config/reactionsLayer/useOlMapReactionsLayer.ts @@ -50,6 +50,10 @@ export const useOlMapReactionsLayer = ({ const reactions = useMemo(() => { return modelReactions.map(reaction => { + const shape = shapes.find(bioShape => bioShape.sboTerm === reaction.sboTerm); + if (!shape) { + return []; + } const reactionObject = new Reaction({ line: reaction.line, products: reaction.products, @@ -57,11 +61,12 @@ export const useOlMapReactionsLayer = ({ zIndex: reaction.z, lineTypes, arrowTypes, + shapes: shape.shapes, pointToProjection, }); return reactionObject.features; }); - }, [arrowTypes, lineTypes, modelReactions, pointToProjection]); + }, [arrowTypes, lineTypes, modelReactions, pointToProjection, shapes]); const elements: Array< MapElement | CompartmentCircle | CompartmentSquare | CompartmentPathway | Glyph 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 f0fd77ba..69af893a 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getPolygonCoords.ts @@ -45,6 +45,8 @@ export default function getPolygonCoords({ return [[...lastPoint]]; } const { p1, p2, p3 } = getCurveCoords({ x, y, point, height, width, pointToProjection }); - return getBezierCurve({ p0: lastPoint, p1, p2, p3, numPoints: 20 }); + const p0 = lastPoint; + lastPoint = p3; + return getBezierCurve({ p0, p1, p2, p3, numPoints: 20 }); }); } 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 b3d84f4b..2b3e02ca 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 @@ -6,6 +6,7 @@ import Reaction, { import { newReactionFixture } from '@/models/fixtures/newReactionFixture'; import { lineTypesFixture } from '@/models/fixtures/lineTypesFixture'; import { arrowTypesFixture } from '@/models/fixtures/arrowTypesFixture'; +import { shapesFixture } from '@/models/fixtures/shapesFixture'; describe('Layer', () => { let props: ReactionProps; @@ -15,6 +16,7 @@ describe('Layer', () => { line: newReactionFixture.line, products: newReactionFixture.products, reactants: newReactionFixture.reactants, + shapes: shapesFixture, zIndex: newReactionFixture.z, pointToProjection: jest.fn(() => [10, 10]), lineTypes: lineTypesFixture, @@ -25,7 +27,7 @@ describe('Layer', () => { it('should initialize a Reaction class', () => { const reaction = new Reaction(props); - expect(reaction.features.length).toBe(5); + expect(reaction.features.length).toBe(6); expect(reaction.features).toBeInstanceOf(Array<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 4b084d81..d1ace47e 100644 --- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts +++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts @@ -1,11 +1,15 @@ /* eslint-disable no-magic-numbers */ -import { ArrowType, Line, LineType, ReactionProduct } from '@/types/models'; +import { ArrowType, Line, LineType, ReactionProduct, Shape } from '@/types/models'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { Feature } from 'ol'; import { LineString, MultiPolygon } from 'ol/geom'; import getRotation from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/coords/getRotation'; 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 { WHITE_COLOR } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants'; export interface ReactionProps { line: Line; @@ -14,6 +18,7 @@ export interface ReactionProps { zIndex: number; lineTypes: Array<LineType>; arrowTypes: Array<ArrowType>; + shapes: Array<Shape>; pointToProjection: UsePointToProjectionResult; } @@ -30,6 +35,8 @@ export default class Reaction { arrowTypes: Array<ArrowType>; + shapes: Array<Shape>; + pointToProjection: UsePointToProjectionResult; features: Array<Feature> = []; @@ -41,6 +48,7 @@ export default class Reaction { zIndex, lineTypes, arrowTypes, + shapes, pointToProjection, }: ReactionProps) { this.line = line; @@ -49,7 +57,15 @@ export default class Reaction { this.zIndex = zIndex; this.lineTypes = lineTypes; this.arrowTypes = arrowTypes; + this.shapes = shapes; this.pointToProjection = pointToProjection; + + 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); @@ -65,12 +81,10 @@ export default class Reaction { }); } - private getLineFeature = ( - line: Line, - ): { + private getLineFeature(line: Line): { lineFeature: Feature<LineString>; arrowsFeatures: Array<Feature<MultiPolygon>>; - } => { + } { const arrowsFeatures: Array<Feature<MultiPolygon>> = []; const points = line.segments .map((segment, index) => { @@ -155,5 +169,46 @@ export default class Reaction { lineFeature.setStyle(lineStyle); return { lineFeature, arrowsFeatures }; - }; + } + + private getReactionSquare(): Feature<MultiPolygon> { + const polygons: Array<Polygon> = []; + const styles: Array<Style> = []; + const firstSegment = this.line.segments[0]; + const squareRotation = getRotation( + [firstSegment.x1, firstSegment.y1], + [firstSegment.x2, firstSegment.y2], + ); + const squareX = (firstSegment.x1 + firstSegment.x2) / 2; + const squareY = (firstSegment.y1 + firstSegment.y2) / 2; + this.shapes.forEach(shape => { + const squarePolygon = getShapePolygon({ + shape, + x: squareX - 5, + y: squareY - 5, + width: 10, + height: 10, + pointToProjection: this.pointToProjection, + }); + const squareStyle = getStyle({ + geometry: squarePolygon, + fillColor: WHITE_COLOR, + zIndex: this.zIndex + 1, + }); + squarePolygon.rotate( + squareRotation, + this.pointToProjection({ + x: squareX, + y: squareY, + }), + ); + polygons.push(squarePolygon); + styles.push(squareStyle); + }); + const squareFeature = new Feature({ + geometry: new MultiPolygon(polygons), + }); + squareFeature.setStyle(styles); + return squareFeature; + } } -- GitLab