Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deck migration/draw layer #2629

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ee24bab
Update save function with current features
weberjavi Apr 17, 2024
4df2644
Tentative coordinates edit overlay
weberjavi Apr 22, 2024
5317b72
Merge branch 'deck-migration/base-branch' into deck-migration/draw-la…
weberjavi Apr 22, 2024
11ef64c
Handle click through interaction hook
weberjavi Apr 24, 2024
1a98792
Update selection on feature hover
weberjavi Apr 24, 2024
3c637fb
Add draw hover to interaction hooks
weberjavi Apr 24, 2024
d97565d
render draw layer onTop of other layers
j8seangel Apr 25, 2024
ff01704
Wip
weberjavi Apr 25, 2024
f5f4a44
Merge branch 'deck-migration/base-branch' into deck-migration/draw-la…
weberjavi Apr 25, 2024
631c6ef
Handle overlapping features and features removal
weberjavi Apr 30, 2024
6a61d48
Avoid selection on hover
weberjavi Apr 30, 2024
51509f5
🤖
weberjavi Apr 30, 2024
e1adb45
Update styles
weberjavi Apr 30, 2024
90ae879
Merge branch 'deck-migration/base-branch' into deck-migration/draw-la…
weberjavi May 2, 2024
c90cb4a
Avoid default popup to be displayed on map tools interaction
weberjavi May 2, 2024
0ba3201
Handle overlays cursor from hooks
weberjavi May 2, 2024
251247b
Add getPickingInfo to rulers layer
weberjavi May 2, 2024
aa77c45
Handle dragstart through useGetPickingInteraction
weberjavi May 2, 2024
53ac627
Add default cursor
weberjavi May 2, 2024
1286ed5
Move dragpan logic to interaction hook
weberjavi May 2, 2024
103be8f
Avoid cursor setting on errornotification
weberjavi May 2, 2024
773b49c
Double click zoom temporary comment
weberjavi May 2, 2024
3a9e9c1
Merge branch 'deck-migration/base-branch' into deck-migration/draw-la…
j8seangel May 6, 2024
3ac497e
Merge branch 'deck-migration/base-branch' into deck-migration/draw-la…
j8seangel Jun 6, 2024
a792b8a
wip: test moving logic to the draw class layer
j8seangel May 6, 2024
27bb154
wip: try custom draw mode
j8seangel May 6, 2024
c055361
fix rulers layer
j8seangel Jun 6, 2024
ff80b9c
fix rulers remove
j8seangel Jun 6, 2024
398ef3c
fix rulers tooltip remove
j8seangel Jun 6, 2024
07bc282
fix drag rulers
j8seangel Jun 7, 2024
817740a
clean up rulers instance
j8seangel Jun 7, 2024
597fdfc
basic draw feature
j8seangel Jun 7, 2024
a4be0f8
add and remove draw features
j8seangel Jun 7, 2024
3f2a835
draw points mode
j8seangel Jun 7, 2024
84196d9
polish draw interactions
j8seangel Jun 10, 2024
8392a7b
Merge pull request #2666 from GlobalFishingWatch/deck-migration/draw-…
j8seangel Jun 10, 2024
ed5698d
fix line color in tentative feature
j8seangel Jun 10, 2024
d8aca28
points icons
j8seangel Jun 10, 2024
7e361bd
support static user radius sizes
j8seangel Jun 10, 2024
181640c
polish points draw
j8seangel Jun 10, 2024
41933d0
fix points draw icons
j8seangel Jun 10, 2024
fbc7480
stop propagation on draw layers click
j8seangel Jun 10, 2024
f727ac4
fix feature selection when other already selected
j8seangel Jun 10, 2024
e34d436
customize draw tooltips
j8seangel Jun 10, 2024
6886b29
fix build
j8seangel Jun 10, 2024
4c514f6
disable draw edit for now
j8seangel Jun 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/fishing-map/features/datasets/datasets.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { UrlDataviewInstance } from '@globalfishingwatch/dataviews-client'
import { IconType, MultiSelectOption } from '@globalfishingwatch/ui-components'
import {
getDatasetConfigurationProperty,
getDatasetGeometryType,
getEnvironmentalDatasetRange,
} from '@globalfishingwatch/datasets-client'
Expand Down Expand Up @@ -151,6 +152,10 @@ export const getDatasetTypeIcon = (dataset: Dataset): IconType | null => {
if (dataset.type === DatasetTypes.Fourwings) return 'heatmap'
if (dataset.type === DatasetTypes.Events) return 'clusters'
const geometryType = getDatasetGeometryType(dataset)
if (geometryType === 'draw') {
const geometryType = getDatasetConfigurationProperty({ dataset, property: 'geometryType' })
return geometryType === 'points' ? 'dots' : 'polygons'
}
if (geometryType === 'points') {
return 'dots'
}
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map/features/dataviews/dataviews.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const getUserPolygonsDataviewInstance = (
config: {
colorCyclingType: 'fill' as ColorCyclingType,
},
dataviewId: TEMPLATE_ENVIRONMENT_DATAVIEW_SLUG,
dataviewId: TEMPLATE_CONTEXT_DATAVIEW_SLUG,
datasetsConfig: [
{
datasetId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const LayerLibraryUserPanel = ({ searchQuery }: { searchQuery: string }) => {
}, [datasets.length, onAddNewClick, dispatch])

const onDrawClick = useCallback(() => {
dispatchSetMapDrawing(true)
dispatchSetMapDrawing('polygons')
dispatch(setModalOpen({ id: 'layerLibrary', open: false }))
trackEvent({
category: TrackCategory.ReferenceLayer,
Expand Down
47 changes: 6 additions & 41 deletions apps/fishing-map/features/map/Map.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useCallback, useEffect, useRef } from 'react'
import { useSelector } from 'react-redux'
import { DeckGL, DeckGLRef } from '@deck.gl/react'
import { LayersList } from '@deck.gl/core'
import dynamic from 'next/dynamic'
// import { atom, useAtom } from 'jotai'
import { RulersLayer, DrawLayer } from '@globalfishingwatch/deck-layers'
import { RulersLayer } from '@globalfishingwatch/deck-layers'
import {
useIsDeckLayersLoading,
useSetDeckLayerComposer,
Expand All @@ -20,32 +19,22 @@ import {
useMapMouseClick,
useMapMouseHover,
} from 'features/map/map-interactions.hooks'
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 { useMapLayers } from 'features/map/map-layers.hooks'
import MapPopups from 'features/map/popups/MapPopups'
import { MapCoordinates } from 'types'
import { MAP_VIEW, useViewStateAtom, useUpdateViewStateUrlParams } from './map-viewport.hooks'
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 { useDrawLayer } from './overlays/draw/draw.hooks'
import { useMapDrawConnect } from './map-draw.hooks'
import MapInfo from './controls/MapInfo'
import { MAP_CANVAS_ID } from './map.config'
import TimeComparisonLegend from './TimeComparisonLegend'

// This avoids type checking to complain
// https://github.com/visgl/deck.gl/issues/7304#issuecomment-1277850750
const RulersLayerComponent = RulersLayer as any
const DrawLayerComponent = DrawLayer as any
const DrawDialog = dynamic(
() => import(/* webpackChunkName: "DrawDialog" */ './overlays/draw/DrawDialog')
)
const PopupWrapper = dynamic(
() => import(/* webpackChunkName: "PopupWrapper" */ './popups/PopupWrapper')
)
const Hint = dynamic(() => import(/* webpackChunkName: "Hint" */ 'features/help/Hint'))

const mapStyles = {
Expand All @@ -55,8 +44,6 @@ const mapStyles = {
}

const MapWrapper = () => {
///////////////////////////////////////
// DECK related code
const deckRef = useRef<DeckGLRef>(null)
useSetMapInstance(deckRef)
const { viewState, setViewState } = useViewStateAtom()
Expand All @@ -71,14 +58,11 @@ const MapWrapper = () => {
useUpdateViewStateUrlParams()
const onMapClick = useMapMouseClick()
const { onMouseMove, hoveredCoordinates } = useMapMouseHover()
const { getCursor } = useMapCursor()
const getCursor = useMapCursor()
const { onMapDrag, onMapDragStart, onMapDragEnd } = useMapDrag()
////////////////////////////////////////
// Used it only once here to attach the listener only once
useMapRulersDrag()
const { rulers, editingRuler, rulersVisible } = useRulers()
const { isMapDrawing } = useMapDrawConnect()
const layers = useMapDeckLayers()
const layers = useMapLayers()

const setDeckLayers = useSetDeckLayerComposer()
useEffect(() => {
return () => {
Expand All @@ -98,18 +82,14 @@ const MapWrapper = () => {
const mapLoading = useIsDeckLayersLoading()

const setDeckLayerLoadedState = useSetDeckLayerLoadedState()
const { onDrawEdit, onDrawClick, drawLayerMode, drawFeaturesIndexes, drawFeatures } =
useDrawLayer()

const currentRuler = editingRuler ? [editingRuler] : []

return (
<div className={styles.container}>
<DeckGL
id={MAP_CANVAS_ID}
ref={deckRef}
views={MAP_VIEW}
layers={deckRef ? (layers as LayersList) : []}
layers={deckRef ? layers : []}
onAfterRender={() => {
setDeckLayerLoadedState(layers)
}}
Expand All @@ -136,21 +116,6 @@ const MapWrapper = () => {
<MapAnnotations />
<MapAnnotationsDialog />
<ErrorNotification />
{(editingRuler || rulers) && (
<RulersLayerComponent
rulers={[...(rulers || []), ...currentRuler]}
visible={rulersVisible}
/>
)}
{isMapDrawing && (
<DrawLayerComponent
data={drawFeatures}
onEdit={onDrawEdit}
onClick={onDrawClick}
selectedFeatureIndexes={drawFeaturesIndexes}
mode={drawLayerMode}
/>
)}
</DeckGL>
{isMapDrawing && <DrawDialog />}
<MapPopups />
Expand Down
7 changes: 5 additions & 2 deletions apps/fishing-map/features/map/map-draw.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { useCallback } from 'react'
import { useSelector } from 'react-redux'
import { selectIsMapDrawing } from 'routes/routes.selectors'
import { DrawFeatureType } from '@globalfishingwatch/deck-layers'
import { selectIsMapDrawing, selectMapDrawingMode } from 'routes/routes.selectors'
import { useLocationConnect } from 'routes/routes.hook'

export const useMapDrawConnect = () => {
const isMapDrawing = useSelector(selectIsMapDrawing)
const mapDrawingMode = useSelector(selectMapDrawingMode)
const { dispatchQueryParams } = useLocationConnect()

const dispatchSetMapDrawing = useCallback(
(mapDrawing: boolean) => {
(mapDrawing: DrawFeatureType | false) => {
dispatchQueryParams({ mapDrawing })
},
[dispatchQueryParams]
Expand All @@ -27,6 +29,7 @@ export const useMapDrawConnect = () => {

return {
isMapDrawing,
mapDrawingMode,
dispatchResetMapDraw,
dispatchSetMapDrawing,
dispatchSetMapDrawEditDataset,
Expand Down
10 changes: 6 additions & 4 deletions apps/fishing-map/features/map/map-interaction.utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { DeckLayerPickingObject } from '@globalfishingwatch/deck-layers'
import { RulerPickingObject } from '@globalfishingwatch/deck-layers'
import { DeckLayerPickingObject, DrawPickingObject } from '@globalfishingwatch/deck-layers'

export const isRulerLayerPoint = (feature: DeckLayerPickingObject) =>
feature.category === 'rulers' && (feature as RulerPickingObject).geometry?.type === 'Point'
export const isRulerLayerPoint = (pickingObject: DeckLayerPickingObject) =>
pickingObject.category === 'rulers'

export const isDrawFeature = (feature: DeckLayerPickingObject) =>
feature.category === 'draw' && (feature as DrawPickingObject).geometry?.type === 'Polygon'
j8seangel marked this conversation as resolved.
Show resolved Hide resolved
65 changes: 33 additions & 32 deletions apps/fishing-map/features/map/map-interactions.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useRef, useState } from 'react'
import { useSelector } from 'react-redux'
import { DeckProps, PickingInfo, Position } from '@deck.gl/core'
import { DeckProps, PickingInfo } from '@deck.gl/core'
import type { MjolnirPointerEvent } from 'mjolnir.js'
import { DataviewCategory, DataviewType } from '@globalfishingwatch/api-types'
import {
Expand All @@ -12,17 +12,15 @@ import {
import {
ClusterPickingObject,
DeckLayerInteractionPickingInfo,
DeckLayerPickingObject,
FourwingsHeatmapPickingObject,
} from '@globalfishingwatch/deck-layers'
import { useMapDrawConnect } from 'features/map/map-draw.hooks'
import { useMapAnnotation } from 'features/map/overlays/annotations/annotations.hooks'
import { SUBLAYER_INTERACTION_TYPES_WITH_VESSEL_INTERACTION } from 'features/map/map.hooks'
import useRulers from 'features/map/overlays/rulers/rulers.hooks'
import { useDeckMap } from 'features/map/map-context.hooks'
import { selectActiveTemporalgridDataviews } from 'features/dataviews/selectors/dataviews.selectors'
import { selectIsMarineManagerLocation } from 'routes/routes.selectors'
import { useMapErrorNotification } from 'features/map/overlays/error-notification/error-notification.hooks'
import { selectCurrentDataviewInstancesResolved } from 'features/dataviews/selectors/dataviews.instances.selectors'
import { useAppDispatch } from 'features/app/app.hooks'
import { setHintDismissed } from 'features/help/hints.slice'
import { ENCOUNTER_EVENTS_SOURCE_ID } from 'features/dataviews/dataviews.utils'
Expand All @@ -40,6 +38,7 @@ import {
setClickedEvent,
} from './map.slice'
import { useSetViewState } from './map-viewport.hooks'
import { useDrawLayerInstance } from './overlays/draw/draw.hooks'

export const useClickedEventConnect = () => {
const dispatch = useAppDispatch()
Expand Down Expand Up @@ -205,6 +204,7 @@ export const useGetPickingInteraction = () => {
return f.object || []
})
return {
...info,
type,
longitude: info.coordinate[0],
latitude: info.coordinate[1],
Expand All @@ -226,9 +226,9 @@ export const useMapMouseHover = () => {
const { onRulerMapHover, rulersEditing } = useRulers()

const [hoveredCoordinates, setHoveredCoordinates] = useState<number[]>()
const [hoveredDebouncedEvent, setHoveredDebouncedEvent] = useState<SliceInteractionEvent | null>(
null
)
// const [hoveredDebouncedEvent, setHoveredDebouncedEvent] = useState<SliceInteractionEvent | null>(
// null
// )

// const onSimpleMapHover = useSimpleMapHover(setHoveredEvent as InteractionEventCallback)
// const onMapHover = useMapHover(
Expand Down Expand Up @@ -284,7 +284,7 @@ export const useMapMouseHover = () => {
onMouseMove,
// resetHoverState,
hoveredCoordinates,
hoveredDebouncedEvent,
// hoveredDebouncedEvent,
// hoveredTooltipEvent,
}
}
Expand Down Expand Up @@ -312,16 +312,19 @@ export const useMapMouseClick = () => {
}

export const useMapCursor = () => {
const { isMapDrawing } = useMapDrawConnect()
// const { getDrawCursor } = useDrawLayer()
const { isMapAnnotating } = useMapAnnotation()
const { isErrorNotificationEditing } = useMapErrorNotification()
const { rulersEditing } = useRulers()
const hoverFeatures = useMapHoverInteraction()?.features

const getCursor = useCallback(
({ isDragging }: { isDragging: boolean }) => {
if (hoverFeatures?.some(isRulerLayerPoint)) {
return 'move'
}
if (isMapAnnotating || isErrorNotificationEditing || rulersEditing) {
if (rulersEditing && hoverFeatures?.some(isRulerLayerPoint)) {
return 'move'
}
return 'crosshair'
}
if (isDragging) {
Expand All @@ -332,50 +335,48 @@ export const useMapCursor = () => {
}
return 'grab'
},
[hoverFeatures, isErrorNotificationEditing, isMapAnnotating, rulersEditing]
[rulersEditing, isMapAnnotating, isErrorNotificationEditing, hoverFeatures]
)
return { getCursor }

return getCursor
}

export const useMapDrag = () => {
const map = useDeckMap()
const { rulersEditing } = useRulers()
const { onRulerDrag, onRulerDragStart, onRulerDragEnd } = useMapRulersDrag()

const onMapDragStart = useCallback(
(info: PickingInfo, event: any) => {
if (!map || !info.coordinate) return
if (rulersEditing) {
const pickedInfo = map?.pickMultipleObjects({
x: info.x,
y: info.y,
radius: 0,
})
const features = pickedInfo.flatMap((p) => p.object || [])
onRulerDragStart(info, features)
if (!info.coordinate || !info.object) return
const isRulerPoint = isRulerLayerPoint(info.object)
if (isRulerPoint) {
onRulerDragStart(info)
event.stopPropagation()
}
},
[map, onRulerDragStart, rulersEditing]
[onRulerDragStart]
)

const onMapDrag = useCallback(
(info: PickingInfo, event: any) => {
if (!info.coordinate) return
if (rulersEditing) {
(info: PickingInfo<DeckLayerPickingObject>, event: any) => {
if (!info.coordinate || !info.object) return
const isRulerPoint = isRulerLayerPoint(info.object)
if (isRulerPoint) {
onRulerDrag(info)
event.stopPropagation()
}
},
[onRulerDrag, rulersEditing]
[onRulerDrag]
)

const onMapDragEnd = useCallback(
(info: PickingInfo, event: any) => {
if (!info.coordinate) return
if (rulersEditing) {
if (!info.coordinate || !info.object) return
const isRulerPoint = isRulerLayerPoint(info.object)
if (isRulerPoint) {
onRulerDragEnd()
}
},
[onRulerDragEnd, rulersEditing]
[onRulerDragEnd]
)
return { onMapDrag, onMapDragStart, onMapDragEnd }
}
19 changes: 18 additions & 1 deletion apps/fishing-map/features/map/map-layers.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ import {
useDeckLayerComposer,
useDeckLayerLoadedState,
} from '@globalfishingwatch/deck-layer-composer'
import { RulersLayer } from '@globalfishingwatch/deck-layers'
import { useGlobalConfigConnect } from 'features/map/map.hooks'
import { selectDataviewInstancesResolvedVisible } from 'features/dataviews/selectors/dataviews.selectors'
import { selectIsWorkspaceIndexLocation, selectIsUserLocation } from 'routes/routes.selectors'
import { DEFAULT_BASEMAP_DATAVIEW_INSTANCE } from 'data/workspaces'
import { selectWorkspaceStatus } from 'features/workspace/workspace.selectors'
import { AsyncReducerStatus } from 'utils/async-slice'
import { useDrawLayerInstance } from './overlays/draw/draw.hooks'
import {
selectMapReportBufferDataviews,
selectShowWorkspaceDetail,
selectWorkspacesListDataview,
} from './map.selectors'
import useRulers, { useMapRulerInstance } from './overlays/rulers/rulers.hooks'

export const useMapDeckLayers = () => {
export const useMapDataviewsLayers = () => {
const workspaceStatus = useSelector(selectWorkspaceStatus)
const workspaceDataviews = useSelector(selectDataviewInstancesResolvedVisible)
const bufferDataviews = useSelector(selectMapReportBufferDataviews)
Expand Down Expand Up @@ -59,6 +62,20 @@ export const useMapDeckLayers = () => {
return layers
}

export const useMapOverlayLayers = () => {
const drawLayerInstance = useDrawLayerInstance()
const rulerLayerInstance = useMapRulerInstance()
return useMemo(() => {
return [drawLayerInstance!, rulerLayerInstance!].filter(Boolean)
}, [drawLayerInstance, rulerLayerInstance])
}

export const useMapLayers = () => {
const dataviewsLayers = useMapDataviewsLayers()
const overlays = useMapOverlayLayers()
return useMemo(() => [...dataviewsLayers, ...overlays], [dataviewsLayers, overlays])
}

export const useMapLayersLoaded = () => {
const layerStatus = useDeckLayerLoadedState()
return Object.values(layerStatus).every((l) => l.loaded)
Expand Down
Loading
Loading