Skip to content

Commit

Permalink
Merge pull request #2578 from GlobalFishingWatch:deck-migration/inter…
Browse files Browse the repository at this point in the history
…actions

show tooltip on hovered features
  • Loading branch information
j8seangel authored Mar 27, 2024
2 parents 0427ce9 + 8cec5db commit 0306a3e
Show file tree
Hide file tree
Showing 59 changed files with 1,105 additions and 868 deletions.
55 changes: 0 additions & 55 deletions apps/fishing-map/features/dataviews/dataviews.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
EndpointId,
} from '@globalfishingwatch/api-types'
import { UrlDataviewInstance } from '@globalfishingwatch/dataviews-client'
import { ContextLayerType } from '@globalfishingwatch/layer-composer'
import { AggregationOperation } from '@globalfishingwatch/fourwings-aggregate'
import { getDatasetConfigurationProperty } from '@globalfishingwatch/datasets-client'
import {
Expand All @@ -24,7 +23,6 @@ import {
TEMPLATE_CLUSTERS_DATAVIEW_SLUG,
} from 'data/workspaces'
import { VesselInstanceDatasets, isPrivateDataset } from 'features/datasets/datasets.utils'
import { Area } from 'features/areas/areas.slice'

// used in workspaces with encounter events layers
export const ENCOUNTER_EVENTS_SOURCE_ID = 'encounter-events'
Expand Down Expand Up @@ -301,59 +299,6 @@ export const getVesselInWorkspace = (vessels: UrlDataviewInstance[], vesselId: s
return vesselInWorkspace
}

const RFMO_LINKS: Record<string, string> = {
'CCSBT Primary Area': 'https://www.ccsbt.org/',
AIDCP: 'https://www.iattc.org/en-US/AIDCP/About-AIDCP',
CCAMLR: 'https://www.ccamlr.org/',
CCBSP: 'https://www.fao.org/fishery/en/organization/rfb/ccbsp',
CCSBT: 'https://www.ccsbt.org/',
CPPS: 'http://www.cpps-int.org/',
FFA: 'https://www.ffa.int/',
GFCM: 'https://www.fao.org/gfcm/en/',
IATTC: 'https://www.iattc.org/',
ICCAT: 'https://www.iccat.int/en/',
ICES: 'https://www.ices.dk/',
IOTC: 'https://www.iotc.org/',
NAFO: 'https://www.nafo.int/',
NAMMCO: 'https://nammco.no/',
NASCO: 'https://www.nasco.int/',
NEAFC: 'https://www.neafc.org/',
NPAFC: 'https://npafc.org/',
NPFC: 'https://www.npfc.int/',
PICES: 'https://meetings.pices.int/',
SEAFDEC: 'https://www.seafdec.org/',
SEAFO: 'https://www.seafo.org/',
SIOFA: 'https://www.apsoi.org/',
SPC: 'https://www.spc.int/',
SPRFMO: 'https://www.sprfmo.int/',
WCPFC: 'https://www.wcpfc.int/',
}

export const getContextAreaLink = (
generatorContextLayer: ContextLayerType,
area: Area | string | number
) => {
const areaIsObject = typeof area === 'object'
switch (generatorContextLayer) {
case ContextLayerType.MPA:
case ContextLayerType.MPANoTake:
case ContextLayerType.MPARestricted:
return `https://www.protectedplanet.net/${areaIsObject ? area?.id : area}`
case ContextLayerType.TunaRfmo:
return RFMO_LINKS[areaIsObject ? area?.id : area]
case ContextLayerType.EEZ:
return `https://www.marineregions.org/eezdetails.php?mrgid=${areaIsObject ? area?.id : area}`
case ContextLayerType.ProtectedSeas:
return `https://map.navigatormap.org/site-detail?site_id=${areaIsObject ? area?.id : area}`
case ContextLayerType.FAO:
return `https://www.fao.org/fishery/en/area/${
areaIsObject ? area?.properties?.F_CODE : area
}/en`
default:
return undefined
}
}

export const isBathymetryDataview = (dataview: UrlDataviewInstance) => {
return dataview.id.includes('bathymetry')
}
3 changes: 2 additions & 1 deletion apps/fishing-map/features/map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import { RulersLayer } from '@globalfishingwatch/deck-layers'
import {
useIsDeckLayersLoading,
useSetDeckLayerComposer,
useSetDeckLayerInteraction,
useSetDeckLayerLoadedState,
} from '@globalfishingwatch/deck-layer-composer'
import useMapInstance, { useSetMapInstance } from 'features/map/map-context.hooks'
Expand Down Expand Up @@ -62,6 +61,7 @@ import { selectCurrentDataviewInstancesResolved } from 'features/dataviews/selec
import { useMapDeckLayers, useMapLayersLoaded } from 'features/map/map-layers.hooks'
import { MapCoordinates } from 'types'
import { DEFAULT_VIEWPORT } from 'data/config'
import MapPopups from 'features/map/popups/MapPopups'
import {
MAP_VIEW,
useViewStateAtom,
Expand Down Expand Up @@ -330,6 +330,7 @@ const MapWrapper = () => {
/>
)}
</DeckGL>
<MapPopups />
{/* {style && (
<Map
id="map"
Expand Down
13 changes: 5 additions & 8 deletions apps/fishing-map/features/map/map-bounds.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useCallback, useEffect } from 'react'
import { fitBounds } from '@math.gl/web-mercator'
import { atom, useAtom } from 'jotai'
import { Deck } from '@deck.gl/core'
import { MiniglobeBounds } from '@globalfishingwatch/ui-components'
import { LngLatBounds, Map } from '@globalfishingwatch/maplibre-gl'
import { LngLatBounds } from '@globalfishingwatch/maplibre-gl'
import { Bbox } from 'types'
import { FOOTER_HEIGHT } from 'features/footer/Footer'
import { TIMEBAR_HEIGHT } from 'features/timebar/timebar.config'
Expand Down Expand Up @@ -61,17 +62,14 @@ type FitBoundsParams = {
}

export const getMapCoordinatesFromBounds = (
map: Map,
map: Deck,
bounds: Bbox,
params: FitBoundsParams = {}
) => {
const { mapWidth, mapHeight, padding = 60 } = params
const width = mapWidth || (map ? parseInt(map.getCanvas().style.width) : window.innerWidth / 2)
const width = mapWidth || (map ? map.width : window.innerWidth / 2)
const height =
mapHeight ||
(map
? parseInt(map.getCanvas().style.height)
: window.innerHeight - TIMEBAR_HEIGHT - FOOTER_HEIGHT)
mapHeight || (map ? map.height : window.innerHeight - TIMEBAR_HEIGHT - FOOTER_HEIGHT)
const { latitude, longitude, zoom } = fitBounds({
bounds: [
[bounds[0], bounds[1]],
Expand Down Expand Up @@ -102,7 +100,6 @@ export function useMapFitBounds() {
const setViewState = useSetViewState()
const fitBounds = useCallback(
(bounds: Bbox, params: FitBoundsParams = {}) => {
console.log('fitBounds')
if (viewport) {
const newViewport = viewport.fitBounds(convertToTupleBoundingBox(bounds), params)
setViewState({
Expand Down
87 changes: 55 additions & 32 deletions apps/fishing-map/features/map/map-interactions.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import { ExtendedStyle, ExtendedStyleMeta } from '@globalfishingwatch/layer-comp
import { DataviewCategory, DataviewType } from '@globalfishingwatch/api-types'
import { MapLayerMouseEvent } from '@globalfishingwatch/maplibre-gl'
import {
useDeckLayerInteraction,
useSetDeckLayerInteraction,
useMapHoverInteraction,
useSetMapHoverInteraction,
useMapClickInteraction,
useSetMapClickInteraction,
} from '@globalfishingwatch/deck-layer-composer'
import { useMapDrawConnect } from 'features/map/map-draw.hooks'
import { useMapAnnotation } from 'features/map/overlays/annotations/annotations.hooks'
Expand Down Expand Up @@ -43,9 +45,10 @@ import { SliceInteractionEvent } from './map.slice'
import { isRulerLayerPoint } from './map-interaction.utils'
import { useMapRulersDrag } from './overlays/rulers/rulers-drag.hooks'

const defaultEmptyFeatures = [] as PickingInfo[]
export const useMapMouseHover = (style?: ExtendedStyle) => {
const map = useDeckMap()
const setDeckLayerInteraction = useSetDeckLayerInteraction()
const setMapHoverFeatures = useSetMapHoverInteraction()
const { isMapDrawing } = useMapDrawConnect()
const { isMapAnnotating } = useMapAnnotation()
const { onRulerMapHover, rulersEditing } = useRulers()
Expand All @@ -67,22 +70,31 @@ export const useMapMouseHover = (style?: ExtendedStyle) => {

const onMouseMove: DeckProps['onHover'] = useCallback(
(info: PickingInfo, event: any) => {
if (!info.coordinate) return
const features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
if (!map || !info.coordinate) return

if (features) {
setDeckLayerInteraction(features)
// onRulerDrag(features)
let features = defaultEmptyFeatures
try {
features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
} catch (e) {
console.warn(e)
}

setMapHoverFeatures({
longitude: info.coordinate[0],
latitude: info.coordinate[1],
features,
})
// onRulerDrag(features)

if (rulersEditing) {
onRulerMapHover(info)
}
},
[map, onRulerMapHover, rulersEditing, setDeckLayerInteraction]
[map, onRulerMapHover, rulersEditing, setMapHoverFeatures]
)

const hoveredTooltipEvent = parseMapTooltipEvent(hoveredEvent, dataviews, temporalgridDataviews)
Expand All @@ -107,6 +119,7 @@ export const useMapMouseClick = (style?: ExtendedStyle) => {
// const map = useMapInstance()
const map = useDeckMap()
const { isMapDrawing } = useMapDrawConnect()
const setMapClickFeatures = useSetMapClickInteraction()
const { isMapAnnotating, addMapAnnotation } = useMapAnnotation()
const { isErrorNotificationEditing, addErrorNotification } = useMapErrorNotification()
const isMarineManagerLocation = useSelector(selectIsMarineManagerLocation)
Expand All @@ -132,18 +145,18 @@ export const useMapMouseClick = (style?: ExtendedStyle) => {
...prev,
[current.category]: [...(prev[current.category] ?? []), current],
}),
{}
{} as Record<string, TooltipEventFeature[]>
)

return Object.entries(layersByCategory).map(
([featureCategory, features]) =>
`${featureCategory}: ${features.map((f) => f.layerId).join(',')}`
`${featureCategory}: ${(features as any[]).map((f) => f.layerId).join(',')}`
)
}, [clickedEvent, clickedTooltipEvent])

const onMapClick: DeckProps['onClick'] = useCallback(
(info: PickingInfo, event: any) => {
if (!info.coordinate) return
if (!map || !info.coordinate) return
if (event.srcEvent.defaultPrevented) {
// this is needed to allow interacting with overlay elements content
return true
Expand All @@ -170,12 +183,17 @@ export const useMapMouseClick = (style?: ExtendedStyle) => {
// if (rulersEditing && !hasRulerFeature) {
// return onRulerMapClick(event)
// }

const features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
let features = defaultEmptyFeatures
try {
features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
} catch (e) {
console.warn(e)
}
setMapClickFeatures({ longitude: info.coordinate[0], latitude: info.coordinate[1], features })
const fourWingsValues = features?.map(
(f: PickingInfo) =>
f.sourceLayer?.getPickingInfo({ info, mode: 'click', sourceLayer: f.sourceLayer }).object
Expand Down Expand Up @@ -204,6 +222,7 @@ export const useMapMouseClick = (style?: ExtendedStyle) => {
rulersEditing,
addMapAnnotation,
addErrorNotification,
setMapClickFeatures,
onRulerMapClick,
]
)
Expand Down Expand Up @@ -299,11 +318,11 @@ export const useMapCursor = () => {
const { isMapAnnotating } = useMapAnnotation()
const { isErrorNotificationEditing } = useMapErrorNotification()
const { rulersEditing } = useRulers()
const deckInteractions = useDeckLayerInteraction()
const hoverFeatures = useMapHoverInteraction()?.features
const getCursor = useCallback(
({ isDragging }: { isDragging: boolean }) => {
if (isMapAnnotating || isErrorNotificationEditing || rulersEditing) {
if (rulersEditing && deckInteractions.some(isRulerLayerPoint)) {
if (rulersEditing && hoverFeatures.some(isRulerLayerPoint)) {
return 'move'
}
return 'crosshair'
Expand All @@ -312,7 +331,7 @@ export const useMapCursor = () => {
}
return 'grab'
},
[deckInteractions, isErrorNotificationEditing, isMapAnnotating, rulersEditing]
[hoverFeatures, isErrorNotificationEditing, isMapAnnotating, rulersEditing]
)
return { getCursor }
}
Expand All @@ -324,14 +343,18 @@ export const useMapDrag = () => {

const onMapDragStart = useCallback(
(info: PickingInfo, event: any) => {
if (!info.coordinate) return
if (!map || !info.coordinate) return
if (rulersEditing) {
const features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
onRulerDragStart(info, features)
try {
const features = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
onRulerDragStart(info, features)
} catch (e) {
console.warn(e)
}
}
},
[map, onRulerDragStart, rulersEditing]
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map/features/map/map-sources.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export type DataviewFeature = LayerFeature & {

export const areDataviewsFeatureLoaded = (dataviews: DataviewFeature | DataviewFeature[]) => {
const dataviewsArray = toArray(dataviews as DataviewFeature)
return dataviewsArray.length ? dataviewsArray.every(({ state }) => state?.loaded) : false
return dataviewsArray.length ? dataviewsArray.every(({ state } = {}) => state?.loaded) : false
}

export const hasDataviewsFeatureError = (dataviews: DataviewFeature | DataviewFeature[]) => {
Expand Down
Loading

0 comments on commit 0306a3e

Please sign in to comment.