Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
useOlMapView.ts 2.25 KiB
/* eslint-disable no-magic-numbers */
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';

interface UseOlMapViewInput {
  mapInstance: MapInstance;
}

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,
      y: mapInitialPosition.y,
    };

    const [x, y] = pointToProjection(centerPoint);

    return {
      x,
      y,
    };
  }, [mapInitialPosition, pointToProjection]);

  const viewConfig = useMemo(
    () => ({
      center: [center.x, center.y],
      zoom: mapInitialPosition.z,
      showFullExtent: OPTIONS.showFullExtent,
      zoomFactor: 2 ** (1 / 3),
      maxZoom: mapSize.maxZoom * 3,
      minZoom: mapSize.minZoom,
      extent,
    }),
    [mapInitialPosition.z, mapSize.maxZoom, center, extent],
  );

  const view = useMemo(() => new View(viewConfig), [viewConfig]);

  useEffect(() => {
    if (!mapInstance) {
      return;
    }

    mapInstance.setView(view);
  }, [view, mapInstance]);

  return view;
};