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