From 318a6df1f27024b3c60bb5e5c0e58372e12f512a Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 16 Apr 2024 10:45:47 +0200 Subject: [PATCH] migrate react-map-gl ControlScale --- apps/fishing-map/features/map/Map.tsx | 7 ++- .../map/controls/MapControls.module.css | 4 +- .../features/map/controls/MapInfo.tsx | 4 +- .../map/controls/MapScaleControl.module.css | 10 ++++ .../features/map/controls/MapScaleControl.tsx | 52 +++++++++++++++++++ .../features/map/map-layers.hooks.ts | 12 ----- .../features/map/popups/PopupWrapper.tsx | 3 -- apps/fishing-map/pages/index.tsx | 10 +--- .../public/locales/source/translations.json | 1 + 9 files changed, 72 insertions(+), 31 deletions(-) create mode 100644 apps/fishing-map/features/map/controls/MapScaleControl.module.css create mode 100644 apps/fishing-map/features/map/controls/MapScaleControl.tsx diff --git a/apps/fishing-map/features/map/Map.tsx b/apps/fishing-map/features/map/Map.tsx index 4642d84e07..67bce47e2c 100644 --- a/apps/fishing-map/features/map/Map.tsx +++ b/apps/fishing-map/features/map/Map.tsx @@ -4,7 +4,6 @@ import { DeckGL, DeckGLRef } from '@deck.gl/react' import { LayersList } from '@deck.gl/core' import dynamic from 'next/dynamic' // import { atom, useAtom } from 'jotai' -import { ViewState } from 'react-map-gl' import { RulersLayer } from '@globalfishingwatch/deck-layers' import { useIsDeckLayersLoading, @@ -25,6 +24,7 @@ import { useMapRulersDrag } from 'features/map/overlays/rulers/rulers-drag.hooks import ErrorNotification from 'features/map/overlays/error-notification/ErrorNotification' import { useMapDeckLayers } from 'features/map/map-layers.hooks' import MapPopups from 'features/map/popups/MapPopups' +import { MapCoordinates } from 'types' import { MAP_VIEW, useViewStateAtom, @@ -35,6 +35,7 @@ import styles from './Map.module.css' import MapAnnotations from './overlays/annotations/Annotations' import MapAnnotationsDialog from './overlays/annotations/AnnotationsDialog' import useRulers from './overlays/rulers/rulers.hooks' +import MapInfo from './controls/MapInfo' // This avoids type checking to complain // https://github.com/visgl/deck.gl/issues/7304#issuecomment-1277850750 @@ -61,7 +62,7 @@ const MapWrapper = () => { (params: any) => { // add transitionDuration: 0 to avoid unresponsive zoom // https://github.com/visgl/deck.gl/issues/7158#issuecomment-1329722960 - setViewState({ ...(params.viewState as ViewState), transitionDuration: 0 }) + setViewState({ ...(params.viewState as MapCoordinates), transitionDuration: 0 }) }, [setViewState] ) @@ -315,6 +316,8 @@ const MapWrapper = () => { {isWorkspace && !reportLocation && ( )} + {/* TODO:deck pass hovered cursor coordinates */} + ) } diff --git a/apps/fishing-map/features/map/controls/MapControls.module.css b/apps/fishing-map/features/map/controls/MapControls.module.css index 17a3e0f358..962209483e 100644 --- a/apps/fishing-map/features/map/controls/MapControls.module.css +++ b/apps/fishing-map/features/map/controls/MapControls.module.css @@ -64,9 +64,7 @@ transform: scale(0); height: 0; pointer-events: none; - transition: - transform 0.3s 0.5s, - border 0.3s 0s; + transition: transform 0.3s 0.5s, border 0.3s 0s; margin-bottom: 0; border: none; } diff --git a/apps/fishing-map/features/map/controls/MapInfo.tsx b/apps/fishing-map/features/map/controls/MapInfo.tsx index 5e48cec04c..263b8d54a6 100644 --- a/apps/fishing-map/features/map/controls/MapInfo.tsx +++ b/apps/fishing-map/features/map/controls/MapInfo.tsx @@ -3,13 +3,13 @@ import { useSelector } from 'react-redux' import formatcoords from 'formatcoords' import cx from 'classnames' import { DateTime, DateTimeFormatOptions } from 'luxon' -import { ScaleControl } from 'react-map-gl' import { InteractionEvent } from '@globalfishingwatch/react-hooks' import { toFixed } from 'utils/shared' import { useTimerangeConnect } from 'features/timebar/timebar.hooks' import I18nDate from 'features/i18n/i18nDate' import { selectShowTimeComparison } from 'features/reports/reports.selectors' import styles from './MapInfo.module.css' +import MapScaleControl from './MapScaleControl' export const pickDateFormatByRange = (start: string, end: string): DateTimeFormatOptions => { const A_DAY = 1000 * 60 * 60 * 24 @@ -49,7 +49,7 @@ const MapInfo = ({ center }: { center: InteractionEvent | null }) => { return (
- + {center && (
{toFixed(center.latitude, 4)} {toFixed(center.longitude, 4)} diff --git a/apps/fishing-map/features/map/controls/MapScaleControl.module.css b/apps/fishing-map/features/map/controls/MapScaleControl.module.css new file mode 100644 index 0000000000..9380167d71 --- /dev/null +++ b/apps/fishing-map/features/map/controls/MapScaleControl.module.css @@ -0,0 +1,10 @@ +.scale { + position: absolute; + bottom: var(--space-M); + left: var(--space-S); + min-height: 1.5rem; + font: var(--font-XS); + background: none; + color: rgba(var(--white-rgb), 0.65); + border-bottom: 1px solid rgba(var(--white-rgb), 0.65); +} diff --git a/apps/fishing-map/features/map/controls/MapScaleControl.tsx b/apps/fishing-map/features/map/controls/MapScaleControl.tsx new file mode 100644 index 0000000000..c8d7bba4d3 --- /dev/null +++ b/apps/fishing-map/features/map/controls/MapScaleControl.tsx @@ -0,0 +1,52 @@ +import { useTranslation } from 'react-i18next' +import { distance as turfDistance } from '@turf/turf' +import { useMapViewport } from '../map-viewport.hooks' +import styles from './MapScaleControl.module.css' + +// code from maplibre-gl-js +// https://github.com/maplibre/maplibre-gl-js/blob/d76c0447f49ddf9ea238ebe458b2488b03c0b361/src/ui/control/scale_control.ts + +type ScaleControlProps = { + maxWidth?: number +} + +function getDecimalRoundNum(d: number) { + const multiplier = Math.pow(10, Math.ceil(-Math.log(d) / Math.LN10)) + return Math.round(d * multiplier) / multiplier +} + +function getRoundNum(num: number) { + const pow10 = Math.pow(10, `${Math.floor(num)}`.length - 1) + let d = num / pow10 + + d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : d >= 1 ? 1 : getDecimalRoundNum(d) + + return pow10 * d +} + +const NAUTICAL_MILE_UNIT = 1852 + +const MapScaleControl = ({ maxWidth = 100 }: ScaleControlProps) => { + const { t } = useTranslation() + const mapViewport = useMapViewport() + + if (!mapViewport) { + return null + } + + const y = mapViewport.height / 2 + const left = mapViewport?.unproject([0, y]) + const right = mapViewport?.unproject([maxWidth, y]) + const maxMeters = turfDistance(left, right) * 1000 + const maxDistance = maxMeters / NAUTICAL_MILE_UNIT + const distance = getRoundNum(maxDistance) + const ratio = distance / maxDistance + + return ( +
+ {distance} {t(`map.nauticalMilesAbbr`, 'nm')} +
+ ) +} + +export default MapScaleControl diff --git a/apps/fishing-map/features/map/map-layers.hooks.ts b/apps/fishing-map/features/map/map-layers.hooks.ts index 24d2fa3a06..b26419cf2f 100644 --- a/apps/fishing-map/features/map/map-layers.hooks.ts +++ b/apps/fishing-map/features/map/map-layers.hooks.ts @@ -1,30 +1,18 @@ import { useSelector } from 'react-redux' -import { useMemo } from 'react' import { DataviewInstance } from '@globalfishingwatch/api-types' import { useDeckLayerComposer, useDeckLayerLoadedState, } from '@globalfishingwatch/deck-layer-composer' import { useGlobalConfigConnect } from 'features/map/map.hooks' -import { selectHighlightedTime } from 'features/timebar/timebar.slice' -import { useHighlightedEventsConnect } from 'features/timebar/timebar.hooks' import { selectDataviewInstancesResolvedVisible } from 'features/dataviews/selectors/dataviews.selectors' export const useMapDeckLayers = () => { - const highlightedTime = useSelector(selectHighlightedTime) const dataviews = useSelector(selectDataviewInstancesResolvedVisible) const globalConfig = useGlobalConfigConnect() - const { highlightedEvents } = useHighlightedEventsConnect() - const params = useMemo(() => { - return { - highlightedTime, - highlightEventIds: highlightedEvents, - } - }, [highlightedEvents, highlightedTime]) const { layers } = useDeckLayerComposer({ dataviews: dataviews as DataviewInstance[], globalConfig, - // params, }) return layers diff --git a/apps/fishing-map/features/map/popups/PopupWrapper.tsx b/apps/fishing-map/features/map/popups/PopupWrapper.tsx index 05cc29e3a1..8d01bf392b 100644 --- a/apps/fishing-map/features/map/popups/PopupWrapper.tsx +++ b/apps/fishing-map/features/map/popups/PopupWrapper.tsx @@ -1,7 +1,6 @@ import { Fragment } from 'react' import cx from 'classnames' import { groupBy } from 'lodash' -import type { Anchor } from 'react-map-gl' import { useSelector } from 'react-redux' import { DataviewCategory } from '@globalfishingwatch/api-types' import { Spinner } from '@globalfishingwatch/ui-components' @@ -29,7 +28,6 @@ type PopupWrapperProps = { closeOnClick?: boolean className?: string onClose?: () => void - anchor?: Anchor type?: 'hover' | 'click' } function PopupWrapper({ @@ -39,7 +37,6 @@ function PopupWrapper({ type = 'hover', className = '', onClose, - anchor, }: PopupWrapperProps) { // Assuming only timeComparison heatmap is visible, so timerange description apply to all const timeCompareTimeDescription = useTimeCompareTimeDescription() diff --git a/apps/fishing-map/pages/index.tsx b/apps/fishing-map/pages/index.tsx index 272a4a175b..3b065303e5 100644 --- a/apps/fishing-map/pages/index.tsx +++ b/apps/fishing-map/pages/index.tsx @@ -1,19 +1,11 @@ import dynamic from 'next/dynamic' -const MapProvider = dynamic(() => import('react-map-gl').then((module) => module.MapProvider), { - ssr: false, -}) - const AppNoSSRComponent = dynamic(() => import('../features/app/App'), { ssr: false, }) const Index = () => { - return ( - - - - ) + return } export default Index diff --git a/apps/fishing-map/public/locales/source/translations.json b/apps/fishing-map/public/locales/source/translations.json index 140cef5b3b..9ed1eb7e37 100644 --- a/apps/fishing-map/public/locales/source/translations.json +++ b/apps/fishing-map/public/locales/source/translations.json @@ -609,6 +609,7 @@ "loading": "Loading", "lowRes": "See low resolution heatmaps", "mapLoadingWait": "Please wait until map loads", + "nauticalMilesAbbr": "nm", "rulers_add": "Add rulers", "rulersStop": "Stop measures", "rulersDelete": "Delete all measures",