forked from MapComplete/MapComplete
		
	Feature: second iteration of clustering
This commit is contained in:
		
							parent
							
								
									8360ab9a8b
								
							
						
					
					
						commit
						5bc8f11d24
					
				
					 3 changed files with 25 additions and 5 deletions
				
			
		| 
						 | 
					@ -8,7 +8,8 @@ import { Utils } from "../../../Utils"
 | 
				
			||||||
import { TagsFilter } from "../../Tags/TagsFilter"
 | 
					import { TagsFilter } from "../../Tags/TagsFilter"
 | 
				
			||||||
import { BBox } from "../../BBox"
 | 
					import { BBox } from "../../BBox"
 | 
				
			||||||
import { OsmTags } from "../../../Models/OsmFeature"
 | 
					import { OsmTags } from "../../../Models/OsmFeature"
 | 
				
			||||||
;("use strict")
 | 
					
 | 
				
			||||||
 | 
					("use strict")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A wrapper around the 'Overpass'-object.
 | 
					 * A wrapper around the 'Overpass'-object.
 | 
				
			||||||
| 
						 | 
					@ -138,7 +139,6 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
 | 
				
			||||||
                    return undefined
 | 
					                    return undefined
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                this.runningQuery.setData(true)
 | 
					                this.runningQuery.setData(true)
 | 
				
			||||||
                console.trace("Overpass feature source: querying geojson")
 | 
					 | 
				
			||||||
                data = (await overpass.queryGeoJson(bounds))[0]
 | 
					                data = (await overpass.queryGeoJson(bounds))[0]
 | 
				
			||||||
            } catch (e) {
 | 
					            } catch (e) {
 | 
				
			||||||
                this.retries.data++
 | 
					                this.retries.data++
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,12 +15,15 @@ export interface ClusteringOptions {
 | 
				
			||||||
     * drop those features and emit a summary tile instead
 | 
					     * drop those features and emit a summary tile instead
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    cutoff?: 20 | number
 | 
					    cutoff?: 20 | number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    showSummaryAt?: "tilecenter" | "average"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>> implements FeatureSource<T> {
 | 
					export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>> implements FeatureSource<T> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public readonly summaryPoints: FeatureSource
 | 
					    public readonly summaryPoints: FeatureSource
 | 
				
			||||||
    private readonly id: string
 | 
					    private readonly id: string
 | 
				
			||||||
 | 
					    private readonly showSummaryAt: "tilecenter" | "average"
 | 
				
			||||||
    features: Store<T[]>
 | 
					    features: Store<T[]>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -35,6 +38,7 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
 | 
				
			||||||
                id: string,
 | 
					                id: string,
 | 
				
			||||||
                options?: ClusteringOptions) {
 | 
					                options?: ClusteringOptions) {
 | 
				
			||||||
        this.id = id
 | 
					        this.id = id
 | 
				
			||||||
 | 
					        this.showSummaryAt = options?.showSummaryAt ?? "average"
 | 
				
			||||||
        const clusterCutoff = options?.dontClusterAboveZoom ?? 17
 | 
					        const clusterCutoff = options?.dontClusterAboveZoom ?? 17
 | 
				
			||||||
        const doCluster = options?.dontClusterAboveZoom === undefined ? new ImmutableStore(true) : currentZoomlevel.map(zoom => zoom <= clusterCutoff)
 | 
					        const doCluster = options?.dontClusterAboveZoom === undefined ? new ImmutableStore(true) : currentZoomlevel.map(zoom => zoom <= clusterCutoff)
 | 
				
			||||||
        const cutoff = options?.cutoff ?? 20
 | 
					        const cutoff = options?.cutoff ?? 20
 | 
				
			||||||
| 
						 | 
					@ -42,6 +46,7 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
 | 
				
			||||||
        currentZoomlevel = currentZoomlevel.stabilized(500)
 | 
					        currentZoomlevel = currentZoomlevel.stabilized(500)
 | 
				
			||||||
        this.summaryPoints = new StaticFeatureSource(summaryPoints)
 | 
					        this.summaryPoints = new StaticFeatureSource(summaryPoints)
 | 
				
			||||||
        this.features = (upstream.features.map(features => {
 | 
					        this.features = (upstream.features.map(features => {
 | 
				
			||||||
 | 
					            console.log(">>> Updating features in clusters ", this.id, ":", features)
 | 
				
			||||||
            if (!doCluster.data) {
 | 
					            if (!doCluster.data) {
 | 
				
			||||||
                summaryPoints.set([])
 | 
					                summaryPoints.set([])
 | 
				
			||||||
                return features
 | 
					                return features
 | 
				
			||||||
| 
						 | 
					@ -69,8 +74,23 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private createSummaryFeature(features: Feature<Point>[], tileId: number): Feature<Point> {
 | 
					    private createSummaryFeature(features: Feature<Point>[], tileId: number): Feature<Point> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let lon: number
 | 
				
			||||||
 | 
					        let lat: number
 | 
				
			||||||
        const [z, x, y] = Tiles.tile_from_index(tileId)
 | 
					        const [z, x, y] = Tiles.tile_from_index(tileId)
 | 
				
			||||||
        const [lon, lat] = Tiles.centerPointOf(z, x, y)
 | 
					        if (this.showSummaryAt === "tilecenter") {
 | 
				
			||||||
 | 
					            [lon, lat] = Tiles.centerPointOf(z, x, y)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let lonSum = 0
 | 
				
			||||||
 | 
					            let latSum = 0
 | 
				
			||||||
 | 
					            for (const feature of features) {
 | 
				
			||||||
 | 
					                const [lon, lat] = feature.geometry.coordinates
 | 
				
			||||||
 | 
					                lonSum += lon
 | 
				
			||||||
 | 
					                latSum += lat
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            lon = lonSum / features.length
 | 
				
			||||||
 | 
					            lat = latSum / features.length
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return <Feature<Point>>{
 | 
					        return <Feature<Point>>{
 | 
				
			||||||
            type: "Feature",
 | 
					            type: "Feature",
 | 
				
			||||||
            geometry: {
 | 
					            geometry: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -351,7 +351,6 @@ export default class ShowDataLayer {
 | 
				
			||||||
            drawLines?: true | boolean
 | 
					            drawLines?: true | boolean
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        console.trace("Creating a data layer for", options.layer.id)
 | 
					 | 
				
			||||||
        this._options = options
 | 
					        this._options = options
 | 
				
			||||||
        this.onDestroy.push(map.addCallbackAndRunD((map) => this.initDrawFeatures(map)))
 | 
					        this.onDestroy.push(map.addCallbackAndRunD((map) => this.initDrawFeatures(map)))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -397,7 +396,8 @@ export default class ShowDataLayer {
 | 
				
			||||||
            const clustering = new ClusteringFeatureSource(feats, state.mapProperties.zoom.map(z => z + 2),
 | 
					            const clustering = new ClusteringFeatureSource(feats, state.mapProperties.zoom.map(z => z + 2),
 | 
				
			||||||
                options.layer.id,
 | 
					                options.layer.id,
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    cutoff: 5
 | 
					                    cutoff: 2,
 | 
				
			||||||
 | 
					                    showSummaryAt: "tilecenter"
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            new ShowDataLayer(mlmap, {
 | 
					            new ShowDataLayer(mlmap, {
 | 
				
			||||||
                features: clustering.summaryPoints,
 | 
					                features: clustering.summaryPoints,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue