From 863891f7bacc186f269911666c5904214c1dbb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com> Date: Fri, 8 Mar 2024 02:07:43 +0100 Subject: [PATCH] feat: fix the map is not quite centered --- .../utils/useAdditionalActions.test.ts | 6 ++-- .../utils/config/useOlMapTileLayer.ts | 21 +++++++++++++- .../utils/config/useOlMapView.test.ts | 4 +-- .../MapViewer/utils/config/useOlMapView.ts | 28 +++++++++++++++++-- src/constants/map.ts | 3 +- src/redux/map/map.thunks.test.ts | 10 +++---- 6 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts index f711b392..9fd36d00 100644 --- a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts +++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts @@ -1,13 +1,13 @@ /* eslint-disable no-magic-numbers */ import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; +import { modelsFixture } from '@/models/fixtures/modelsFixture'; import { MAP_DATA_INITIAL_STATE } from '@/redux/map/map.constants'; +import { initialMapDataFixture } from '@/redux/map/map.fixtures'; import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; import { renderHook } from '@testing-library/react'; import Map from 'ol/Map'; -import { initialMapDataFixture } from '@/redux/map/map.fixtures'; -import { modelsFixture } from '@/models/fixtures/modelsFixture'; import { useAddtionalActions } from './useAdditionalActions'; import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates'; @@ -185,7 +185,7 @@ describe('useAddtionalActions - hook', () => { const position = store.getState().map?.data.position; expect(position?.last).toEqual(MAP_CONFIG.position); expect(actions[0]).toEqual({ - payload: { x: 1750, y: 1000, z: 5 }, + payload: { x: 1750, y: 1000, z: 4 }, type: 'map/setMapPosition', }); }); diff --git a/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts index b50d5c15..a636c57f 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.ts @@ -3,6 +3,9 @@ import { OPTIONS } from '@/constants/map'; import { currentBackgroundImagePathSelector } from '@/redux/backgrounds/background.selectors'; import { mapDataSizeSelector } from '@/redux/map/map.selectors'; import { projectDataSelector } from '@/redux/project/project.selectors'; +import { Point } from '@/types/map'; +import { usePointToProjection } from '@/utils/map/usePointToProjection'; +import { Extent, boundingExtent } from 'ol/extent'; import BaseLayer from 'ol/layer/Base'; import TileLayer from 'ol/layer/Tile'; import { XYZ } from 'ol/source'; @@ -16,6 +19,21 @@ export const useOlMapTileLayer = (): BaseLayer => { const mapSize = useSelector(mapDataSizeSelector); const currentBackgroundImagePath = useSelector(currentBackgroundImagePathSelector); const project = useSelector(projectDataSelector); + const pointToProjection = usePointToProjection(); + + const tileExtent = useMemo((): Extent => { + const topLeftPoint: Point = { + x: mapSize.width, + y: mapSize.height, + }; + + const bottomRightPoint: Point = { + x: 0, + y: 0, + }; + + return boundingExtent([topLeftPoint, bottomRightPoint].map(pointToProjection)); + }, [pointToProjection, mapSize]); const sourceUrl = useMemo( () => getMapTileUrl({ projectDirectory: project?.directory, currentBackgroundImagePath }), @@ -39,8 +57,9 @@ export const useOlMapTileLayer = (): BaseLayer => { new TileLayer({ visible: true, source, + extent: tileExtent, }), - [source], + [source, tileExtent], ); return tileLayer; diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts index 48b643ce..1b52b84c 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts @@ -48,7 +48,7 @@ describe('useOlMapView - util', () => { }); const setViewSpy = jest.spyOn(hohResult.current.mapInstance as Map, 'setView'); - const CALLED_ONCE = 1; + const CALLED_TWICE = 2; await act(() => { store.dispatch( @@ -63,7 +63,7 @@ describe('useOlMapView - util', () => { wrapper: Wrapper, }); - await waitFor(() => expect(setViewSpy).toBeCalledTimes(CALLED_ONCE)); + await waitFor(() => expect(setViewSpy).toBeCalledTimes(CALLED_TWICE)); }); it('should return valid View instance', async () => { diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.ts index 4a4d9dc1..174d0a13 100644 --- a/src/components/Map/MapViewer/utils/config/useOlMapView.ts +++ b/src/components/Map/MapViewer/utils/config/useOlMapView.ts @@ -1,9 +1,10 @@ /* eslint-disable no-magic-numbers */ -import { OPTIONS } from '@/constants/map'; -import { mapDataInitialPositionSelector } from '@/redux/map/map.selectors'; +import { EXTENT_PADDING_MULTIPLICATOR, OPTIONS } from '@/constants/map'; +import { mapDataInitialPositionSelector, mapDataSizeSelector } from '@/redux/map/map.selectors'; import { MapInstance, Point } from '@/types/map'; import { usePointToProjection } from '@/utils/map/usePointToProjection'; import { View } from 'ol'; +import { Extent, boundingExtent } from 'ol/extent'; import { useEffect, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { MapConfig } from '../../MapViewer.types'; @@ -14,8 +15,28 @@ interface UseOlMapViewInput { export const useOlMapView = ({ mapInstance }: UseOlMapViewInput): MapConfig['view'] => { const mapInitialPosition = useSelector(mapDataInitialPositionSelector); + const mapSize = useSelector(mapDataSizeSelector); const pointToProjection = usePointToProjection(); + const extent = useMemo((): Extent => { + const extentPadding = { + horizontal: mapSize.width * EXTENT_PADDING_MULTIPLICATOR, + vertical: mapSize.height * EXTENT_PADDING_MULTIPLICATOR, + }; + + const topLeftPoint: Point = { + x: mapSize.width + extentPadding.horizontal, + y: mapSize.height + extentPadding.vertical, + }; + + const bottomRightPoint: Point = { + x: -extentPadding.horizontal, + y: -extentPadding.vertical, + }; + + return boundingExtent([topLeftPoint, bottomRightPoint].map(pointToProjection)); + }, [pointToProjection, mapSize]); + const center = useMemo((): Point => { const centerPoint: Point = { x: mapInitialPosition.x, @@ -35,8 +56,9 @@ export const useOlMapView = ({ mapInstance }: UseOlMapViewInput): MapConfig['vie center: [center.x, center.y], zoom: mapInitialPosition.z, showFullExtent: OPTIONS.showFullExtent, + extent, }), - [center.x, center.y, mapInitialPosition.z], + [mapInitialPosition.z, center, extent], ); const view = useMemo(() => new View(viewConfig), [viewConfig]); diff --git a/src/constants/map.ts b/src/constants/map.ts index 47d6c6ce..ae669ac9 100644 --- a/src/constants/map.ts +++ b/src/constants/map.ts @@ -5,11 +5,12 @@ import { HALF_SECOND_MS, ONE_HUNDRED_MS } from './time'; export const DEFAULT_TILE_SIZE = 256; export const DEFAULT_MIN_ZOOM = 2; export const DEFAULT_MAX_ZOOM = 9; -export const DEFAULT_ZOOM = 5; +export const DEFAULT_ZOOM = 4; export const DEFAULT_CENTER_X = 0; export const DEFAULT_CENTER_Y = 0; // eslint-disable-next-line no-magic-numbers export const LATLNG_FALLBACK: LatLng = [0, 0]; +export const EXTENT_PADDING_MULTIPLICATOR = 1; export const DEFAULT_CENTER_POINT: Point = { x: DEFAULT_CENTER_X, diff --git a/src/redux/map/map.thunks.test.ts b/src/redux/map/map.thunks.test.ts index 6d5e94a4..bdcf388d 100644 --- a/src/redux/map/map.thunks.test.ts +++ b/src/redux/map/map.thunks.test.ts @@ -2,16 +2,16 @@ import { MODELS_MOCK } from '@/models/mocks/modelsMock'; /* eslint-disable no-magic-numbers */ import { QueryData } from '@/types/query'; import { BACKGROUNDS_MOCK, BACKGROUND_INITIAL_STATE_MOCK } from '../backgrounds/background.mock'; -import { RootState } from '../store'; -import { INITIAL_STORE_STATE_MOCK } from '../root/root.fixtures'; import { MODELS_INITIAL_STATE_MOCK } from '../models/models.mock'; +import { INITIAL_STORE_STATE_MOCK } from '../root/root.fixtures'; +import { RootState } from '../store'; +import { initialMapDataFixture, initialMapStateFixture } from './map.fixtures'; import { getBackgroundId, getInitMapPosition, getInitMapSizeAndModelId, getOpenedMaps, } from './map.thunks'; -import { initialMapDataFixture, initialMapStateFixture } from './map.fixtures'; const EMPTY_QUERY_DATA: QueryData = { modelId: undefined, @@ -84,8 +84,8 @@ describe('map thunks - utils', () => { it('should return valid map position if query params do not include position', () => { const position = getInitMapPosition(STATE_WITH_MODELS, EMPTY_QUERY_DATA); expect(position).toEqual({ - initial: { x: 13389.625, y: 6751.5, z: 5 }, - last: { x: 13389.625, y: 6751.5, z: 5 }, + initial: { x: 13389.625, y: 6751.5, z: 4 }, + last: { x: 13389.625, y: 6751.5, z: 4 }, }); }); it('should return default map position', () => { -- GitLab