forked from MapComplete/MapComplete
UX: center summary tiles, small style tweaks
This commit is contained in:
parent
020a1f8c3b
commit
38191309ca
4 changed files with 32 additions and 21 deletions
|
|
@ -29,8 +29,8 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"labelCss": "background: #ffffffbb",
|
"labelCss": "background: #ffffffcc; min-width: 2rem",
|
||||||
"labelCssClasses": "w-12 text-lg rounded-xl p-1 px-2"
|
"labelCssClasses": "text-lg rounded p-1 px-2 border-2 border-gray font-bold"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Feature, Point } from "geojson"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
||||||
import { GeoOperations } from "../../GeoOperations"
|
import { GeoOperations } from "../../GeoOperations"
|
||||||
import { Tiles } from "../../../Models/TileRange"
|
import { Tiles } from "../../../Models/TileRange"
|
||||||
|
import { Lists } from "../../../Utils/Lists"
|
||||||
|
|
||||||
export interface ClusteringOptions {
|
export interface ClusteringOptions {
|
||||||
/**
|
/**
|
||||||
|
|
@ -86,11 +87,10 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
|
||||||
features: Feature<Point>[],
|
features: Feature<Point>[],
|
||||||
tileId: number
|
tileId: number
|
||||||
): Feature<Point, SummaryProperties> {
|
): Feature<Point, SummaryProperties> {
|
||||||
let lon: number
|
let coordinates: [number, number]
|
||||||
let lat: number
|
|
||||||
const [z, x, y] = Tiles.tile_from_index(tileId)
|
|
||||||
if (this.showSummaryAt === "tilecenter") {
|
if (this.showSummaryAt === "tilecenter") {
|
||||||
;[lon, lat] = Tiles.centerPointOf(z, x, y)
|
const [z, x, y] = Tiles.tile_from_index(tileId)
|
||||||
|
coordinates = Tiles.centerPointOf(z, x, y)
|
||||||
} else {
|
} else {
|
||||||
let lonSum = 0
|
let lonSum = 0
|
||||||
let latSum = 0
|
let latSum = 0
|
||||||
|
|
@ -99,14 +99,15 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
|
||||||
lonSum += lon
|
lonSum += lon
|
||||||
latSum += lat
|
latSum += lat
|
||||||
}
|
}
|
||||||
lon = lonSum / features.length
|
const lon = lonSum / features.length
|
||||||
lat = latSum / features.length
|
const lat = latSum / features.length
|
||||||
|
coordinates = [lon, lat]
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Point",
|
type: "Point",
|
||||||
coordinates: [lon, lat],
|
coordinates
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
id: "summary_" + this.id + "_" + tileId,
|
id: "summary_" + this.id + "_" + tileId,
|
||||||
|
|
@ -120,10 +121,10 @@ export class ClusteringFeatureSource<T extends Feature<Point> = Feature<Point>>
|
||||||
/**
|
/**
|
||||||
* Groups multiple summaries together
|
* Groups multiple summaries together
|
||||||
*/
|
*/
|
||||||
export class ClusterGrouping implements FeatureSource<Feature<Point, { total_metric: string }>> {
|
export class ClusterGrouping implements FeatureSource<Feature<Point, { total_metric: string, id: string }>> {
|
||||||
private readonly _features: UIEventSource<Feature<Point, { total_metric: string }>[]> =
|
private readonly _features: UIEventSource<Feature<Point, { total_metric: string, id: string }>[]> =
|
||||||
new UIEventSource([])
|
new UIEventSource([])
|
||||||
public readonly features: Store<Feature<Point, { total_metric: string }>[]> = this._features
|
public readonly features: Store<Feature<Point, { total_metric: string, id: string }>[]> = this._features
|
||||||
|
|
||||||
public static readonly singleton = new ClusterGrouping()
|
public static readonly singleton = new ClusterGrouping()
|
||||||
|
|
||||||
|
|
@ -140,27 +141,34 @@ export class ClusterGrouping implements FeatureSource<Feature<Point, { total_met
|
||||||
private allSource: Store<Feature<Point, { total: number; tile_id: number }>[]>[] = []
|
private allSource: Store<Feature<Point, { total: number; tile_id: number }>[]>[] = []
|
||||||
|
|
||||||
private update() {
|
private update() {
|
||||||
const countPerTile = new Map<number, number>()
|
const countPerTile = new Map<number, { lon: number, lat: number, count: number }[]>()
|
||||||
for (const source of this.allSource) {
|
for (const source of this.allSource) {
|
||||||
for (const f of source.data) {
|
for (const f of source.data) {
|
||||||
const id = f.properties.tile_id
|
const id = f.properties.tile_id
|
||||||
const count = f.properties.total + (countPerTile.get(id) ?? 0)
|
if (!countPerTile.has(id)) {
|
||||||
countPerTile.set(id, count)
|
countPerTile.set(id, [])
|
||||||
|
}
|
||||||
|
const ls = countPerTile.get(id)
|
||||||
|
ls.push({ lon: f.geometry.coordinates[0], lat: f.geometry.coordinates[1], count: f.properties.total })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const features: Feature<Point, { total_metric: string; id: string }>[] = []
|
const features: Feature<Point, { total_metric: string; id: string }>[] = []
|
||||||
const now = new Date().getTime() + ""
|
const now = new Date().getTime() + ""
|
||||||
for (const tileId of countPerTile.keys()) {
|
for (const tileId of countPerTile.keys()) {
|
||||||
const coordinates = Tiles.centerPointOf(tileId)
|
const data = countPerTile.get(tileId)
|
||||||
|
const total = Lists.sum(data.map(d => d.count))
|
||||||
|
const lon = Lists.sum(data.map(d => d.lon * d.count)) / total
|
||||||
|
const lat = Lists.sum(data.map(d => d.lat * d.count)) / total
|
||||||
|
|
||||||
features.push({
|
features.push({
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
properties: {
|
properties: {
|
||||||
total_metric: "" + countPerTile.get(tileId),
|
total_metric: "" + total,
|
||||||
id: "clustered_all_" + tileId + "_" + now, // We add the date to force a fresh ID every time, this makes sure values are updated
|
id: "clustered_all_" + tileId + "_" + now, // We add the date to force a fresh ID every time, this makes sure values are updated
|
||||||
},
|
},
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Point",
|
type: "Point",
|
||||||
coordinates,
|
coordinates: [lon, lat]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -169,6 +177,10 @@ export class ClusterGrouping implements FeatureSource<Feature<Point, { total_met
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerSource(features: Store<Feature<Point, SummaryProperties>[]>) {
|
public registerSource(features: Store<Feature<Point, SummaryProperties>[]>) {
|
||||||
|
if (this.allSource.indexOf(features) >= 0) {
|
||||||
|
console.error("This source has already been registered")
|
||||||
|
return
|
||||||
|
}
|
||||||
this.allSource.push(features)
|
this.allSource.push(features)
|
||||||
features.addCallbackAndRun(() => {
|
features.addCallbackAndRun(() => {
|
||||||
//this.isDirty.set(true)
|
//this.isDirty.set(true)
|
||||||
|
|
|
||||||
|
|
@ -407,8 +407,7 @@ export default class ShowDataLayer {
|
||||||
state.mapProperties.zoom.map((z) => z + 2),
|
state.mapProperties.zoom.map((z) => z + 2),
|
||||||
options.layer.id,
|
options.layer.id,
|
||||||
{
|
{
|
||||||
cutoff: 7,
|
cutoff: 7
|
||||||
showSummaryAt: "tilecenter",
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
new ShowDataLayer(mlmap, options)
|
new ShowDataLayer(mlmap, options)
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,7 @@
|
||||||
<InsetSpacer height={AndroidPolyfill.getInsetSizes().top} />
|
<InsetSpacer height={AndroidPolyfill.getInsetSizes().top} />
|
||||||
</div>
|
</div>
|
||||||
<!-- Top bar with tools -->
|
<!-- Top bar with tools -->
|
||||||
<div class="flex items-center">
|
<div class="flex items-center" style="z-index: 10">
|
||||||
<MapControlButton
|
<MapControlButton
|
||||||
cls="m-0.5 p-0.5 sm:p-1"
|
cls="m-0.5 p-0.5 sm:p-1"
|
||||||
arialabel={Translations.t.general.labels.menu}
|
arialabel={Translations.t.general.labels.menu}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue