Skip to content
Snippets Groups Projects
Commit 4dce772c authored by Adrian Orłów's avatar Adrian Orłów :fire:
Browse files

Merge branch 'MIN-319-multipin-icon' into 'development'

feat: add multipin icon

Closes MIN-319

See merge request !182
parents 6bb92217 c9af10fe
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!182feat: add multipin icon
Pipeline #89340 passed
Showing
with 476 additions and 72 deletions
......@@ -26,6 +26,7 @@
"molart": "github:davidhoksza/MolArt",
"next": "13.4.19",
"ol": "^8.1.0",
"polished": "^4.3.1",
"postcss": "8.4.29",
"query-string": "7.1.3",
"react": "18.2.0",
......@@ -11127,6 +11128,17 @@
"node": ">=8"
}
},
"node_modules/polished": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
"integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==",
"dependencies": {
"@babel/runtime": "^7.17.8"
},
"engines": {
"node": ">=10"
}
},
"node_modules/postcss": {
"version": "8.4.29",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
......@@ -22127,6 +22139,14 @@
"find-up": "^4.0.0"
}
},
"polished": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
"integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==",
"requires": {
"@babel/runtime": "^7.17.8"
}
},
"postcss": {
"version": "8.4.29",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
......
......@@ -40,6 +40,7 @@
"molart": "github:davidhoksza/MolArt",
"next": "13.4.19",
"ol": "^8.1.0",
"polished": "^4.3.1",
"postcss": "8.4.29",
"query-string": "7.1.3",
"react": "18.2.0",
......
......@@ -16,7 +16,13 @@ import { MockStoreEnhanced } from 'redux-mock-store';
import { BioEntitiesPinsListItem } from './BioEntitiesPinsListItem.component';
import { PinListBioEntity } from './BioEntitiesPinsListItem.types';
const BIO_ENTITY = bioEntitiesContentFixture[0].bioEntity;
const BIO_ENTITY = {
...bioEntitiesContentFixture[0].bioEntity,
fullName: 'fullName_',
name: 'name_',
symbol: 'symbol_',
};
const INITIAL_STORE_WITH_ENTITY_NUMBER: InitialStoreState = {
entityNumber: {
data: {
......
......@@ -73,8 +73,8 @@ describe('BioEntitiesAccordion - component', () => {
});
expect(screen.getByText('Content (10)')).toBeInTheDocument();
expect(screen.getByText('Core PD map (4)')).toBeInTheDocument();
expect(screen.getByText('Core PD map (3)')).toBeInTheDocument();
expect(screen.getByText('Histamine signaling (4)')).toBeInTheDocument();
expect(screen.getByText('PRKN substrates (2)')).toBeInTheDocument();
expect(screen.getByText('PRKN substrates (3)')).toBeInTheDocument();
});
});
/* eslint-disable no-magic-numbers */
import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture';
import { drugsFixture } from '@/models/fixtures/drugFixtures';
import { StoreType } from '@/redux/store';
import {
......@@ -16,12 +15,6 @@ const DRUGS_PINS_LIST = drugsFixture.map(drug => ({
data: drug,
}));
const CHEMICALS_PINS_LIST = chemicalsFixture.map(chemical => ({
id: chemical.id.id,
name: chemical.name,
data: chemical,
}));
const renderComponent = (
pinsList: PinItem[],
initialStoreState: InitialStoreState = {},
......@@ -64,13 +57,4 @@ describe('AccordionsDetails - component', () => {
expect(screen.getByText(firstDrugSynonym, { exact: false })).toBeInTheDocument();
expect(screen.getByText(secondDrugSynonym, { exact: false })).toBeInTheDocument();
});
it('should display direct evidence publications for chemicals', () => {
renderComponent(CHEMICALS_PINS_LIST);
const chemicalsAdditionalInfo = chemicalsFixture[0].directEvidence
? chemicalsFixture[0].directEvidence
: '';
expect(screen.getAllByText(chemicalsAdditionalInfo, { exact: false })[0]).toBeInTheDocument();
});
});
......@@ -79,8 +79,11 @@ describe('PinsListItem - component ', () => {
expect(screen.getByText(firstPinElementType, { exact: false })).toBeInTheDocument();
expect(screen.getByText(firstPinElementResource, { exact: false })).toBeInTheDocument();
expect(screen.getByText(secondPinElementType, { exact: false })).toBeInTheDocument();
expect(screen.getByText(secondPinElementResource, { exact: false })).toBeInTheDocument();
if (!secondPinElementType) {
expect(screen.queryByText(secondPinElementType, { exact: false })).toBeNull();
expect(screen.queryByText(secondPinElementResource, { exact: false })).toBeNull();
}
});
it('should display list of references for pin', () => {
renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', BIO_ENTITY, INITIAL_STORE_STATE);
......
......@@ -91,6 +91,10 @@ export const PinsListItem = ({
<div className="font-bold">Elements:</div>
{'targetParticipants' in pin &&
pin.targetParticipants.map(participant => {
if (!participant?.link) {
return null;
}
return (
// participant.id is almost always = 0
<li key={`${participant.id}-${participant.link}`} className="my-2 px-2">
......
......@@ -9,14 +9,14 @@ const SMALL_TEXT_VALUE = 1;
const MEDIUM_TEXT_VALUE = 10;
const BIG_TEXT_VALUE = 100;
interface Args {
export interface GetCanvasIconArgs {
color: string;
value: number;
textColor?: string;
}
export const drawPinOnCanvas = (
{ color }: Pick<Args, 'color'>,
{ color }: Pick<GetCanvasIconArgs, 'color'>,
ctx: CanvasRenderingContext2D,
): void => {
const path = new Path2D(PIN_PATH2D);
......@@ -43,7 +43,7 @@ export const getTextPosition = (textWidth: number, textHeight: number): Point =>
});
export const drawNumberOnCanvas = (
{ value, textColor }: Pick<Args, 'value' | 'textColor'>,
{ value, textColor }: Pick<GetCanvasIconArgs, 'value' | 'textColor'>,
ctx: CanvasRenderingContext2D,
): void => {
const text = `${value}`;
......@@ -61,7 +61,7 @@ export const drawNumberOnCanvas = (
};
export const getCanvasIcon = (
args: Omit<Args, 'value'> & { value?: number },
args: Omit<GetCanvasIconArgs, 'value'> & { value?: number },
): HTMLCanvasElement => {
const canvas = createCanvas(PIN_SIZE);
const ctx = canvas.getContext('2d');
......@@ -70,6 +70,7 @@ export const getCanvasIcon = (
}
drawPinOnCanvas(args, ctx);
if (args?.value !== undefined) {
drawNumberOnCanvas({ value: args.value, textColor: args?.textColor }, ctx);
}
......
import { MULTIICON_RATIO, PIN_SIZE } from '@/constants/canvas';
import { ONE, ZERO } from '@/constants/common';
import { createCanvas } from '@/utils/canvas/getCanvas';
const drawIconOnCanvas = (
ctx: CanvasRenderingContext2D,
icon: HTMLCanvasElement,
index: number,
): void => {
ctx.drawImage(icon, ZERO, index * PIN_SIZE.height * MULTIICON_RATIO);
};
export const getCavasMultiIcon = (icons: HTMLCanvasElement[]): HTMLCanvasElement => {
const canvas = createCanvas({
width: PIN_SIZE.width,
height: PIN_SIZE.height * (ONE + (icons.length - ONE) * MULTIICON_RATIO),
});
const ctx = canvas.getContext('2d');
if (!ctx) {
return canvas;
}
icons.reverse().forEach((icon, index) => drawIconOnCanvas(ctx, icon, index));
return canvas;
};
import { EntityNumber } from '@/redux/entityNumber/entityNumber.types';
import { BioEntity } from '@/types/models';
import { PinType } from '@/types/pin';
import { BioEntityWithPinType } from '@/types/bioEntity';
import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
import { Feature } from 'ol';
import { getBioEntitySingleFeature } from './getBioEntitySingleFeature';
export const getBioEntitiesFeatures = (
bioEntites: BioEntity[],
bioEntites: BioEntityWithPinType[],
{
pointToProjection,
type,
entityNumber,
activeIds,
}: {
pointToProjection: UsePointToProjectionResult;
type: PinType;
entityNumber: EntityNumber;
activeIds?: (string | number)[];
activeIds: (string | number)[];
},
): Feature[] => {
return bioEntites.map(bioEntity =>
getBioEntitySingleFeature(bioEntity, {
pointToProjection,
type,
type: bioEntity.type,
// pin's index number
value: entityNumber?.[bioEntity.elementId],
isActive: activeIds ? activeIds.includes(bioEntity.id) : true,
isActive: activeIds.includes(bioEntity.id),
}),
);
};
......@@ -27,15 +27,15 @@ describe('getBioEntitiesFeatures - subUtil', () => {
map: initialMapStateFixture,
});
const bioEntititesContent = bioEntitiesContentFixture;
const bioEntities = bioEntititesContent.map(({ bioEntity }) => bioEntity);
const bioEntities = bioEntititesContent.map(({ bioEntity }) => ({
...bioEntity,
type: 'bioEntity' as PinType,
}));
const pointToProjection = getPointToProjection(Wrapper);
const pinTypes: PinType[] = ['bioEntity', 'drugs', 'chemicals'];
it.each(pinTypes)('should return array of instances of Feature with Style type=%s', type => {
it('should return array of instances of Feature with Style type=%s', () => {
const result = getBioEntitiesFeatures(bioEntities, {
pointToProjection,
type,
entityNumber: {},
activeIds: [bioEntities[FIRST_ARRAY_ELEMENT].id],
});
......
import { PINS_COLORS, TEXT_COLOR } from '@/constants/canvas';
import { EntityNumber } from '@/redux/entityNumber/entityNumber.types';
import { BioEntityWithPinType } from '@/types/bioEntity';
import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString';
import { mix } from 'polished';
import { GetCanvasIconArgs } from '../getCanvasIcon';
const INACTIVE_ELEMENT_OPACITY = 0.5;
const DARK_COLOR_MIX_RATIO = 0.25;
interface Options {
entityNumber: EntityNumber;
activeIds: (string | number)[];
isDarkColor?: boolean;
}
export const getMultipinCanvasArgs = (
{ type, ...element }: BioEntityWithPinType,
{ entityNumber, activeIds, isDarkColor }: Options,
): GetCanvasIconArgs => {
const value = entityNumber?.[element.elementId];
const isActive = activeIds.includes(element.id);
const baseColor = isDarkColor
? mix(DARK_COLOR_MIX_RATIO, '#000', PINS_COLORS[type])
: PINS_COLORS[type];
const color = isActive ? baseColor : addAlphaToHexString(baseColor, INACTIVE_ELEMENT_OPACITY);
const textColor = isActive
? TEXT_COLOR
: addAlphaToHexString(TEXT_COLOR, INACTIVE_ELEMENT_OPACITY);
return {
color,
textColor,
value,
};
};
import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
import { EntityNumber } from '@/redux/entityNumber/entityNumber.types';
import { initialMapStateFixture } from '@/redux/map/map.fixtures';
import { MultiPinBioEntity } from '@/types/bioEntity';
import { PinType } from '@/types/pin';
import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection';
import {
GetReduxWrapperUsingSliceReducer,
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { renderHook } from '@testing-library/react';
import { Feature } from 'ol';
import Style from 'ol/style/Style';
import { getMultipinSingleFeature } from './getMultipinSingleFeature';
import * as getMultipinStyle from './getMultipinStyle';
jest.mock('./getMultipinStyle', () => ({
__esModule: true,
...jest.requireActual('./getMultipinStyle'),
}));
const ONE_MULTI_BIO_ENTITIES: MultiPinBioEntity = [
{
...bioEntityContentFixture.bioEntity,
type: 'bioEntity' as PinType,
x: 100,
y: 100,
},
{
...bioEntityContentFixture.bioEntity,
type: 'drugs' as PinType,
x: 100,
y: 100,
},
];
const ENTITY_NUMBER: EntityNumber = {
[ONE_MULTI_BIO_ENTITIES[FIRST_ARRAY_ELEMENT].elementId]: 100,
};
const getMultipinStyleSpy = jest.spyOn(getMultipinStyle, 'getMultipinStyle');
const getPointToProjection = (
wrapper: ReturnType<GetReduxWrapperUsingSliceReducer>['Wrapper'],
): UsePointToProjectionResult => {
const { result: usePointToProjectionHook } = renderHook(() => usePointToProjection(), {
wrapper,
});
return usePointToProjectionHook.current;
};
describe('getMultipinSingleFeature - subUtil', () => {
const { Wrapper } = getReduxWrapperWithStore({
map: initialMapStateFixture,
});
const pointToProjection = getPointToProjection(Wrapper);
it('should return instance of Feature with Style type=%s', () => {
const result = getMultipinSingleFeature(ONE_MULTI_BIO_ENTITIES, {
pointToProjection,
entityNumber: ENTITY_NUMBER,
activeIds: [],
});
const style = result.getStyle() as Style;
expect(result).toBeInstanceOf(Feature);
expect(style).toBeInstanceOf(Style);
});
it('should run getPinStyle with valid args for type=%s', () => {
getMultipinSingleFeature(ONE_MULTI_BIO_ENTITIES, {
pointToProjection,
entityNumber: ENTITY_NUMBER,
activeIds: [],
});
expect(getMultipinStyleSpy).toHaveBeenCalledWith({
pins: [
{ color: '#0c4fa180', textColor: '#FFFFFF80', value: 100 },
{ color: '#F48C4180', textColor: '#FFFFFF80', value: undefined },
],
});
});
});
import { ONE, ZERO } from '@/constants/common';
import { EntityNumber } from '@/redux/entityNumber/entityNumber.types';
import { BioEntityWithPinType, MultiPinBioEntity } from '@/types/bioEntity';
import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
import { Feature } from 'ol';
import { getMultipinCanvasArgs } from './getMultipinCanvasArgs';
import { getMultipinStyle } from './getMultipinStyle';
import { getPinFeature } from './getPinFeature';
export const getMultipinSingleFeature = (
multipin: MultiPinBioEntity,
{
pointToProjection,
entityNumber,
activeIds,
}: {
pointToProjection: UsePointToProjectionResult;
entityNumber: EntityNumber;
activeIds: (string | number)[];
},
): Feature => {
const [mainElement, ...sortedElements] = multipin.sort(
(a, b) => (activeIds.includes(b.id) ? ONE : ZERO) - (activeIds.includes(a.id) ? ONE : ZERO),
);
const feature = getPinFeature(mainElement, pointToProjection);
const canvasPinsArgMainElement = getMultipinCanvasArgs(mainElement, {
activeIds,
entityNumber,
isDarkColor: true,
});
const canvasPinsArgs = sortedElements.map((element: BioEntityWithPinType) =>
getMultipinCanvasArgs(element, {
activeIds,
entityNumber: {}, // additional elements id's should be not visible
}),
);
const style = getMultipinStyle({ pins: [canvasPinsArgMainElement, ...canvasPinsArgs] });
feature.setStyle(style);
return feature;
};
import { MULTIICON_RATIO, PIN_SIZE } from '@/constants/canvas';
import { ONE, ZERO } from '@/constants/common';
import Icon from 'ol/style/Icon';
import Style from 'ol/style/Style';
import { GetCanvasIconArgs, getCanvasIcon } from '../getCanvasIcon';
import { getCavasMultiIcon } from '../getCanvasMultiIcon';
interface Args {
pins: GetCanvasIconArgs[];
}
export const getMultipinStyle = ({ pins }: Args): Style => {
const icons = pins.map(({ color, value, textColor }) =>
getCanvasIcon({
color,
value,
textColor,
}),
);
const img = getCavasMultiIcon(icons);
return new Style({
image: new Icon({
displacement: [ZERO, PIN_SIZE.height * (ONE + (icons.length - ONE) * MULTIICON_RATIO)],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
img,
}),
});
};
import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
import { MultiPinBioEntity } from '@/types/bioEntity';
import { PinType } from '@/types/pin';
import { getMultipinsBioEntities } from './getMultipinsBioEntities';
const ZERO_MULTI_BIO_ENTITIES: MultiPinBioEntity = [
{
...bioEntityContentFixture.bioEntity,
type: 'bioEntity' as PinType,
},
{
...bioEntityContentFixture.bioEntity,
x: 1000,
type: 'bioEntity' as PinType,
},
];
const ONE_MULTI_BIO_ENTITIES: MultiPinBioEntity = [
{
...bioEntityContentFixture.bioEntity,
type: 'bioEntity' as PinType,
x: 100,
y: 100,
},
{
...bioEntityContentFixture.bioEntity,
type: 'drugs' as PinType,
x: 100,
y: 100,
},
];
const FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE: MultiPinBioEntity = [
{
...bioEntityContentFixture.bioEntity,
type: 'bioEntity' as PinType,
x: 100,
y: 100,
},
{
...bioEntityContentFixture.bioEntity,
type: 'drugs' as PinType,
x: 100,
y: 100,
},
{
...bioEntityContentFixture.bioEntity,
type: 'drugs' as PinType,
x: 100,
y: 100,
},
{
...bioEntityContentFixture.bioEntity,
type: 'drugs' as PinType,
x: 100,
y: 100,
},
];
describe('getMultipinsBioEntities - util', () => {
it('should return empty array if theres no multi pins', () => {
expect(getMultipinsBioEntities({ bioEntities: ZERO_MULTI_BIO_ENTITIES })).toStrictEqual([]);
});
it('should return valid multi pins', () => {
expect(getMultipinsBioEntities({ bioEntities: ONE_MULTI_BIO_ENTITIES })).toStrictEqual([
ONE_MULTI_BIO_ENTITIES,
]);
});
it('should return valid multi pins if theres few types of pins', () => {
expect(
getMultipinsBioEntities({ bioEntities: FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE }),
).toStrictEqual([ONE_MULTI_BIO_ENTITIES]);
});
});
import { ONE } from '@/constants/common';
import { BioEntityWithPinType, MultiPinBioEntity } from '@/types/bioEntity';
import { BioEntity } from '@/types/models';
import { PinType } from '@/types/pin';
interface Args {
bioEntities: MultiPinBioEntity;
}
const SEPARATOR = '-';
const POSITION_PRESCISION_SEPERATOR = '.';
const getUniqueKey = (element: Pick<BioEntity, 'x' | 'y'>): string => {
const [x] = `${element.x}`.split(POSITION_PRESCISION_SEPERATOR);
const [y] = `${element.y}`.split(POSITION_PRESCISION_SEPERATOR);
return [x, y].join(SEPARATOR);
};
const groupByPosition = (
accumulator: Record<string, MultiPinBioEntity>,
element: BioEntityWithPinType,
): Record<string, MultiPinBioEntity> => {
const key = getUniqueKey(element);
return {
...accumulator,
[key]: accumulator[key] ? [...accumulator[key], element] : [element],
};
};
const toUniqueTypeMultipin = (multipin: MultiPinBioEntity): MultiPinBioEntity => {
const allTypes: PinType[] = multipin.map(pin => pin.type);
const uniqueTypes = [...new Set(allTypes)];
return uniqueTypes
.map(type => multipin.find(pin => pin.type === type))
.filter((value): value is BioEntityWithPinType => value !== undefined);
};
export const getMultipinsBioEntities = ({ bioEntities }: Args): MultiPinBioEntity[] => {
const multipiledBioEntities = bioEntities.filter(
baseElement =>
bioEntities.filter(element => getUniqueKey(baseElement) === getUniqueKey(element)).length >
ONE,
);
const duplicatedMultipinsGroupedByPosition = multipiledBioEntities.reduce(
groupByPosition,
{} as Record<string, MultiPinBioEntity>,
);
const allGroupedMultipins = Object.values(duplicatedMultipinsGroupedByPosition);
const uniqueTypeGroupedMultipins = allGroupedMultipins.map(toUniqueTypeMultipin);
const multipiledMultiPins = uniqueTypeGroupedMultipins.filter(multipin => multipin.length > ONE);
return multipiledMultiPins;
};
import { MultiPinBioEntity } from '@/types/bioEntity';
export const getMultipinBioEntititesIds = (multipins: MultiPinBioEntity[]): (string | number)[] =>
multipins.flat().map(({ id }) => id);
import { EntityNumber } from '@/redux/entityNumber/entityNumber.types';
import { MultiPinBioEntity } from '@/types/bioEntity';
import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
import { Feature } from 'ol';
import { getMultipinSingleFeature } from './getMultipinSingleFeature';
export const getMultipinFeatures = (
multipins: MultiPinBioEntity[],
{
pointToProjection,
entityNumber,
activeIds,
}: {
pointToProjection: UsePointToProjectionResult;
entityNumber: EntityNumber;
activeIds: (string | number)[];
},
): Feature[] => {
return multipins.map(multipin =>
getMultipinSingleFeature(multipin, {
pointToProjection,
entityNumber,
activeIds,
}),
);
};
/* eslint-disable no-magic-numbers */
import {
allBioEntitesSelectorOfCurrentMap,
allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector,
allBioEntitiesWithTypeOfCurrentMapSelector,
allVisibleBioEntitiesIdsSelector,
} from '@/redux/bioEntity/bioEntity.selectors';
import { allChemicalsBioEntitesOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors';
import { allDrugsBioEntitesOfCurrentMapSelector } from '@/redux/drugs/drugs.selectors';
import { entityNumberDataSelector } from '@/redux/entityNumber/entityNumber.selectors';
import { markersPinsOfCurrentMapDataSelector } from '@/redux/markers/markers.selectors';
import { BioEntity } from '@/types/models';
import { usePointToProjection } from '@/utils/map/usePointToProjection';
import Feature from 'ol/Feature';
import { Geometry } from 'ol/geom';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { getBioEntitiesFeatures } from './getBioEntitiesFeatures';
import { getMarkersFeatures } from './getMarkersFeatures';
import { getMultipinsBioEntities } from './getMultipinsBioEntities';
import { getMultipinBioEntititesIds } from './getMultipinsBioEntitiesIds';
import { getMultipinFeatures } from './getMultipinsFeatures';
export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => {
const pointToProjection = usePointToProjection();
const activeIds = useSelector(allVisibleBioEntitiesIdsSelector);
const contentBioEntites = useSelector(allBioEntitesSelectorOfCurrentMap);
const chemicalsBioEntities = useSelector(allChemicalsBioEntitesOfCurrentMapSelector);
const drugsBioEntities = useSelector(allDrugsBioEntitesOfCurrentMapSelector);
const bioEntities = useSelector(allBioEntitiesWithTypeOfCurrentMapSelector);
const markersEntities = useSelector(markersPinsOfCurrentMapDataSelector);
const entityNumber = useSelector(entityNumberDataSelector);
const submapConnections = useSelector(
allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector,
const multiPinsBioEntities = useMemo(
() =>
getMultipinsBioEntities({
bioEntities,
}),
[bioEntities],
);
const multipinsIds = getMultipinBioEntititesIds(multiPinsBioEntities);
const isMultiPin = useCallback(
(b: BioEntity): boolean => multipinsIds.includes(b.id),
[multipinsIds],
);
const elementsFeatures = useMemo(
() =>
[
getBioEntitiesFeatures(contentBioEntites, {
pointToProjection,
type: 'bioEntity',
entityNumber,
activeIds,
}),
getBioEntitiesFeatures(chemicalsBioEntities, {
pointToProjection,
type: 'chemicals',
entityNumber,
activeIds,
}),
getBioEntitiesFeatures(drugsBioEntities, {
getBioEntitiesFeatures(
bioEntities.filter(b => !isMultiPin(b)),
{
pointToProjection,
entityNumber,
activeIds,
},
),
getMultipinFeatures(multiPinsBioEntities, {
pointToProjection,
type: 'drugs',
entityNumber,
activeIds,
}),
getBioEntitiesFeatures(submapConnections, {
pointToProjection,
type: 'bioEntity',
entityNumber,
}),
getMarkersFeatures(markersEntities, { pointToProjection }),
].flat(),
[
contentBioEntites,
drugsBioEntities,
chemicalsBioEntities,
bioEntities,
pointToProjection,
markersEntities,
entityNumber,
activeIds,
submapConnections,
multiPinsBioEntities,
markersEntities,
isMultiPin,
],
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment