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

Fishing map/cluster layer tweaks #2847

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions libs/api-types/src/dataviews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export type DataviewSublayerConfig = {

export type FourwingsGeolocation = 'country' | 'port' | 'default'

/** Used to define the max zoom level for each geolocation (all levels must be below 12) */
export type ClusterMaxZoomLevelConfig = Partial<Record<FourwingsGeolocation, number>>

export interface DataviewConfig<Type = DataviewType> {
Expand Down
2 changes: 2 additions & 0 deletions libs/deck-layer-composer/src/resolvers/clusters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
UrlDataviewInstance,
} from '@globalfishingwatch/dataviews-client'
import {
FOURWINGS_MAX_ZOOM,
FourwingsClusterEventType,
FourwingsClustersLayerProps,
getUTCDateTime,
Expand Down Expand Up @@ -95,6 +96,7 @@ export const resolveDeckFourwingsClustersLayerProps: DeckResolverFunction<
visible: dataview.config?.visible ?? true,
tilesUrl: resolveEndpoint(dataset, datasetConfig, { absolute: true }) || '',
clusterMaxZoomLevels: dataview.config?.clusterMaxZoomLevels,
maxZoom: FOURWINGS_MAX_ZOOM,
eventType: dataset.subcategory as FourwingsClusterEventType,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const ICON_MAPPING: Record<FourwingsClusterEventType, any> = {

const CLUSTER_LAYER_ID = 'clusters'
const POINTS_LAYER_ID = 'points'
const MAX_INDIVIDUAL_POINTS = 1000

export class FourwingsClustersLayer extends CompositeLayer<
FourwingsClustersLayerProps & TileLayerProps
Expand Down Expand Up @@ -117,9 +118,9 @@ export class FourwingsClustersLayer extends CompositeLayer<
viewportLoaded: false,
clusterIndex: new Supercluster({
radius: 70,
maxZoom: Math.floor(this.props.clusterMaxZoomLevels?.default || MAX_ZOOM_TO_CLUSTER_POINTS),
maxZoom: this.props.maxZoom - 1,
reduce: (accumulated, props) => {
accumulated.count += props.count
return (accumulated.value += props.value)
},
}),
}
Expand Down Expand Up @@ -166,59 +167,49 @@ export class FourwingsClustersLayer extends CompositeLayer<

_onViewportLoad = (tiles: Tile2DHeader[]) => {
const { zoom } = this.context.viewport
if (this.clusterMode === 'positions') {
const points = tiles.flatMap((tile) => {
return tile.content
? tile.content.map((feature: any) =>
transformTileCoordsToWGS84(
feature,
tile.bbox as GeoBoundingBox,
this.context.viewport
)
)
: []
}) as FourwingsPointFeature[]
const data: FourwingsPointFeature[] = tiles.flatMap((tile) => {
return this.clusterMode === 'positions'
? (tile.content || []).map((feature: FourwingsPointFeature) =>
transformTileCoordsToWGS84(feature, tile.bbox as GeoBoundingBox, this.context.viewport)
)
: tile.content || []
})
if (this.clusterMode === 'positions' && data.length < MAX_INDIVIDUAL_POINTS) {
requestAnimationFrame(() => {
this.setState({
viewportLoaded: true,
points,
points: data,
clusters: undefined,
radiusScale: undefined,
} as FourwingsClustersTileLayerState)
})
} else {
const data = tiles.flatMap((tile) => {
return tile.content || []
}) as FourwingsPointFeature[]

this.state.clusterIndex.load(data)
const allClusters = this.state.clusterIndex.getClusters(
[-180, -85, 180, 85],
Math.round(zoom)
)
let clusters: FourwingsClusterFeature[] = []
let points: FourwingsPointFeature[] = []
if (allClusters.length) {
allClusters.forEach((f) => {
f.properties.count > 1
? clusters.push(f as FourwingsClusterFeature)
: points.push(f as FourwingsPointFeature)
})
}
})
return
}
this.state.clusterIndex.load(data)
const allClusters = this.state.clusterIndex.getClusters([-180, -85, 180, 85], Math.round(zoom))
let clusters: FourwingsClusterFeature[] = []
let points: FourwingsPointFeature[] = []

const counts = clusters.map((cluster) => cluster.properties.count)
const radiusScale = scaleSqrt()
.domain([1, counts.length ? max(counts) : 1])
.range([MIN_CLUSTER_RADIUS, MAX_CLUSTER_RADIUS])
requestAnimationFrame(() => {
this.setState({
viewportLoaded: true,
clusters,
points,
radiusScale,
} as FourwingsClustersTileLayerState)
if (allClusters.length) {
allClusters.forEach((f) => {
f.properties.value > 1
? clusters.push(f as FourwingsClusterFeature)
: points.push(f as FourwingsPointFeature)
})
}

const counts = clusters.map((cluster) => cluster.properties.value)
const radiusScale = scaleSqrt()
.domain([1, counts.length ? max(counts) : 1])
.range([MIN_CLUSTER_RADIUS, MAX_CLUSTER_RADIUS])
requestAnimationFrame(() => {
this.setState({
viewportLoaded: true,
clusters,
points,
radiusScale,
})
})
}

_fetchClusters = async (
Expand Down Expand Up @@ -326,25 +317,17 @@ export class FourwingsClustersLayer extends CompositeLayer<
}

_getRadius = (d: FourwingsClusterFeature) => {
return this.state.radiusScale?.(d.properties.count) || MIN_CLUSTER_RADIUS
return this.state.radiusScale?.(d.properties.value) || MIN_CLUSTER_RADIUS
}

_getClusterLabel = (d: FourwingsClusterFeature) => {
if (d.properties.count > 1000000) {
return `>${Math.floor(d.properties.count / 1000000)}M`
if (d.properties.value > 1000000) {
return `>${Math.floor(d.properties.value / 1000000)}M`
}
if (d.properties.count > 1000) {
return `>${Math.floor(d.properties.count / 1000)}k`
}
return d.properties.count.toString()
}

filterSubLayer({ layer }: FilterContext) {
if (this.clusterMode === 'positions') {
return !layer.id.includes(CLUSTER_LAYER_ID)
} else {
return true
if (d.properties.value > 1000) {
return `>${Math.floor(d.properties.value / 1000)}k`
}
return d.properties.value.toString()
}

renderLayers(): Layer<{}> | LayersList | null {
Expand Down Expand Up @@ -405,8 +388,8 @@ export class FourwingsClustersLayer extends CompositeLayer<
getAlignmentBaseline: 'center',
// extensions: [new CollisionFilterExtension()],
// collisionTestProps: { sizeScale: 1 },
// getCollisionPriority: (d: any) => parseInt(d.properties.count || 1),
collisionGroup: 'text',
// getCollisionPriority: (d: any) => parseInt(d.properties.value || 1),
// collisionGroup: 'text',
}),
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ export type FourwingsClustersLayerProps = DeckLayerProps<{
tilesUrl: string
visible: boolean
clusterMaxZoomLevels?: ClusterMaxZoomLevelConfig
maxZoom: number
}>

export type FourwingsClusterProperties = {
id: string
count: number
value: number
col: number
row: number
tile: Tile2DHeader['index']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const getPoints = (
},
properties: {
// TODO:deck remove the round as won't be needed with real data
count: Math.round(offset + value * scale),
value: Math.round(offset + value * scale),
id: generateUniqueId(tile!.index.x, tile!.index.y, cellNum),
tile: tile?.index,
col,
Expand Down
2 changes: 1 addition & 1 deletion libs/deck-loaders/src/fourwings/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export type FourwingsPositionFeatureProperties = {

export type FourwingsPointFeatureProperties = {
id: number
count: number
value: number
[key: string]: any
}

Expand Down
6 changes: 5 additions & 1 deletion libs/i18n-labels/source/datasets.json
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,10 @@
"name": "Phosphate concentration (PO4)",
"description": "<h2>Overview</h2>\n<ul>\n<li>Phosphate is a major nutrient for marine foodwebs and ocean productivity, but high concentrations can also be an indicator of pollution. This dataset is comprised of biogeochemical parameters, including phosphate, over the global ocean displayed with a 1/4 degree horizontal resolution.</li>\n<ul>\n<h2>Source</h2>\n<ul>\n <a href='https://doi.org/10.48670/moi-00015'>Generated using E.U. Copernicus Marine Service Information; https://doi.org/10.48670/moi-00015.</a></li>"
},
"public-global-port-visits-events": {
"name": "Port Visits (AIS)",
"description": "The dataset contains port visits for AIS"
},
"public-global-presence-tracks": {
"name": "Tracks",
"description": "The dataset contains the tracks from all vessels (AIS) - Version 20201001",
Expand Down Expand Up @@ -1911,4 +1915,4 @@
"name": "WPP NRI",
"description": "The WPP-NRI (Wilayah Pengelolaan Perikanan Negara Republik Indonesia) are fisheries management areas for fishing, conservation, research and fisheries development which cover inland waters, archipelagic waters, and territorial seas within and outside the exclusive economic zone of Indonesia."
}
}
}
Loading