From 7d2ccc1b2fc63811a940a50300ac0a527c0a7326 Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Thu, 26 Sep 2024 08:59:17 +0200 Subject: [PATCH 1/4] keep clustering if too many positions are on screen --- libs/api-types/src/dataviews.ts | 1 + .../clusters/FourwingsClustersLayer.ts | 110 ++++++++---------- .../clusters/fourwings-clusters.types.ts | 2 +- .../fourwings/lib/parse-fourwings-clusters.ts | 2 +- libs/deck-loaders/src/fourwings/lib/types.ts | 2 +- 5 files changed, 55 insertions(+), 62 deletions(-) diff --git a/libs/api-types/src/dataviews.ts b/libs/api-types/src/dataviews.ts index 986bce2a38..47851fbfa9 100644 --- a/libs/api-types/src/dataviews.ts +++ b/libs/api-types/src/dataviews.ts @@ -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> export interface DataviewConfig { diff --git a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts index b6707141bf..228b900e0d 100644 --- a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts +++ b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts @@ -79,6 +79,7 @@ const ICON_MAPPING: Record = { const CLUSTER_LAYER_ID = 'clusters' const POINTS_LAYER_ID = 'points' +const MAX_INDIVIDUAL_POINTS = 1000 export class FourwingsClustersLayer extends CompositeLayer< FourwingsClustersLayerProps & TileLayerProps @@ -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: 12, reduce: (accumulated, props) => { - accumulated.count += props.count + return (accumulated.value += props.value) }, }), } @@ -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 ( @@ -326,25 +317,26 @@ 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` + if (d.properties.value > 1000) { + return `>${Math.floor(d.properties.value / 1000)}k` } - return d.properties.count.toString() + return d.properties.value.toString() } filterSubLayer({ layer }: FilterContext) { - if (this.clusterMode === 'positions') { - return !layer.id.includes(CLUSTER_LAYER_ID) - } else { - return true - } + return true + // if (this.clusterMode === 'positions') { + // return !layer.id.includes(CLUSTER_LAYER_ID) + // } else { + // return true + // } } renderLayers(): Layer<{}> | LayersList | null { @@ -405,8 +397,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', }), ] } diff --git a/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts b/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts index e9d2424f4c..3b6a55bcb9 100644 --- a/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts +++ b/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts @@ -23,7 +23,7 @@ export type FourwingsClustersLayerProps = DeckLayerProps<{ export type FourwingsClusterProperties = { id: string - count: number + value: number col: number row: number tile: Tile2DHeader['index'] diff --git a/libs/deck-loaders/src/fourwings/lib/parse-fourwings-clusters.ts b/libs/deck-loaders/src/fourwings/lib/parse-fourwings-clusters.ts index b80e61cbf3..0852c99576 100644 --- a/libs/deck-loaders/src/fourwings/lib/parse-fourwings-clusters.ts +++ b/libs/deck-loaders/src/fourwings/lib/parse-fourwings-clusters.ts @@ -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, diff --git a/libs/deck-loaders/src/fourwings/lib/types.ts b/libs/deck-loaders/src/fourwings/lib/types.ts index 62ce77a1b3..e7559b4f16 100644 --- a/libs/deck-loaders/src/fourwings/lib/types.ts +++ b/libs/deck-loaders/src/fourwings/lib/types.ts @@ -71,7 +71,7 @@ export type FourwingsPositionFeatureProperties = { export type FourwingsPointFeatureProperties = { id: number - count: number + value: number [key: string]: any } From f6ffa9944dc0a87da44b9c0a8e07b33e43f7d6ba Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Thu, 26 Sep 2024 09:10:17 +0200 Subject: [PATCH 2/4] add port visits dataset to translations --- libs/i18n-labels/source/datasets.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/i18n-labels/source/datasets.json b/libs/i18n-labels/source/datasets.json index da95aa2d30..91b6a808be 100644 --- a/libs/i18n-labels/source/datasets.json +++ b/libs/i18n-labels/source/datasets.json @@ -1213,6 +1213,10 @@ "name": "Phosphate concentration (PO4)", "description": "

Overview

\n
    \n
  • 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.
  • \n
      \n

      Source

      \n
        \n Generated using E.U. Copernicus Marine Service Information; https://doi.org/10.48670/moi-00015." }, + "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", @@ -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." } -} \ No newline at end of file +} From 48de01410bfc18f5a488e78a9e42dc650e749a19 Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Thu, 26 Sep 2024 09:20:06 +0200 Subject: [PATCH 3/4] make sure individual points are visible at least at the last zoom level --- libs/deck-layer-composer/src/resolvers/clusters.ts | 2 ++ .../src/layers/fourwings/clusters/FourwingsClustersLayer.ts | 2 +- .../src/layers/fourwings/clusters/fourwings-clusters.types.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/deck-layer-composer/src/resolvers/clusters.ts b/libs/deck-layer-composer/src/resolvers/clusters.ts index 06070cfa04..3fb5fef53b 100644 --- a/libs/deck-layer-composer/src/resolvers/clusters.ts +++ b/libs/deck-layer-composer/src/resolvers/clusters.ts @@ -5,6 +5,7 @@ import { UrlDataviewInstance, } from '@globalfishingwatch/dataviews-client' import { + FOURWINGS_MAX_ZOOM, FourwingsClusterEventType, FourwingsClustersLayerProps, getUTCDateTime, @@ -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, } } diff --git a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts index 228b900e0d..b57272ca8f 100644 --- a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts +++ b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts @@ -118,7 +118,7 @@ export class FourwingsClustersLayer extends CompositeLayer< viewportLoaded: false, clusterIndex: new Supercluster({ radius: 70, - maxZoom: 12, + maxZoom: this.props.maxZoom - 1, reduce: (accumulated, props) => { return (accumulated.value += props.value) }, diff --git a/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts b/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts index 3b6a55bcb9..abb5e6078b 100644 --- a/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts +++ b/libs/deck-layers/src/layers/fourwings/clusters/fourwings-clusters.types.ts @@ -19,6 +19,7 @@ export type FourwingsClustersLayerProps = DeckLayerProps<{ tilesUrl: string visible: boolean clusterMaxZoomLevels?: ClusterMaxZoomLevelConfig + maxZoom: number }> export type FourwingsClusterProperties = { From 9800eac42174a6add6cc2d9f1b97d52c718379af Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Thu, 26 Sep 2024 10:04:34 +0200 Subject: [PATCH 4/4] remove unnecesary function --- .../layers/fourwings/clusters/FourwingsClustersLayer.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts index b57272ca8f..3f1c2a4b0f 100644 --- a/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts +++ b/libs/deck-layers/src/layers/fourwings/clusters/FourwingsClustersLayer.ts @@ -330,15 +330,6 @@ export class FourwingsClustersLayer extends CompositeLayer< return d.properties.value.toString() } - filterSubLayer({ layer }: FilterContext) { - return true - // if (this.clusterMode === 'positions') { - // return !layer.id.includes(CLUSTER_LAYER_ID) - // } else { - // return true - // } - } - renderLayers(): Layer<{}> | LayersList | null { const { color, tilesUrl, eventType = 'encounter' } = this.props const { clusters, points, radiusScale } = this.state