forked from MapComplete/MapComplete
Add theme introspecting mapcomplete changes
This commit is contained in:
parent
ccb548816f
commit
2e2a6965e7
8 changed files with 275 additions and 47 deletions
|
@ -83,7 +83,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
if (self.layer.layerDef.source.mercatorCrs) {
|
||||
json = GeoOperations.GeoJsonToWGS84(json)
|
||||
}
|
||||
|
||||
|
||||
const time = new Date();
|
||||
const newFeatures: { feature: any, freshness: Date } [] = []
|
||||
let i = 0;
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Utils} from "../Utils";
|
|||
|
||||
export default class Constants {
|
||||
|
||||
public static vNumber = "0.14.0-alpha-5";
|
||||
public static vNumber = "0.14.0-rc-1";
|
||||
public static ImgurApiKey = '7070e7167f0a25a'
|
||||
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import Combine from "../Base/Combine";
|
|||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import {Utils} from "../../Utils";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Svg from "../../Svg";
|
||||
|
||||
export default class Histogram<T> extends VariableUiElement {
|
||||
|
||||
|
@ -13,9 +13,9 @@ export default class Histogram<T> extends VariableUiElement {
|
|||
"#ff5858",
|
||||
"#ffad48",
|
||||
"#ffff59",
|
||||
"#9d62d9",
|
||||
"#56bd56",
|
||||
"#63a9ff",
|
||||
"#9d62d9",
|
||||
"#fa61fa"
|
||||
]
|
||||
|
||||
|
@ -24,6 +24,51 @@ export default class Histogram<T> extends VariableUiElement {
|
|||
countTitle: string | BaseUIElement,
|
||||
assignColor?: (t0: string) => string
|
||||
) {
|
||||
const sortMode = new UIEventSource<"name" | "name-rev" | "count" | "count-rev">("name")
|
||||
const sortName = new VariableUiElement(sortMode.map(m => {
|
||||
switch (m) {
|
||||
case "name":
|
||||
return Svg.up_svg()
|
||||
case "name-rev":
|
||||
return Svg.up_svg().SetStyle("transform: rotate(180deg)")
|
||||
default:
|
||||
return Svg.circle_svg()
|
||||
}
|
||||
}))
|
||||
const titleHeader = new Combine([sortName.SetClass("w-4 mr-2"), title]).SetClass("flex")
|
||||
.onClick(() => {
|
||||
if (sortMode.data === "name") {
|
||||
sortMode.setData("name-rev")
|
||||
} else {
|
||||
sortMode.setData("name")
|
||||
}
|
||||
})
|
||||
|
||||
const sortCount = new VariableUiElement(sortMode.map(m => {
|
||||
switch (m) {
|
||||
case "count":
|
||||
return Svg.up_svg()
|
||||
case "count-rev":
|
||||
return Svg.up_svg().SetStyle("transform: rotate(180deg)")
|
||||
default:
|
||||
return Svg.circle_svg()
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
const countHeader = new Combine([sortCount.SetClass("w-4 mr-2"), countTitle]).SetClass("flex").onClick(() => {
|
||||
if (sortMode.data === "count-rev") {
|
||||
sortMode.setData("count")
|
||||
} else {
|
||||
sortMode.setData("count-rev")
|
||||
}
|
||||
})
|
||||
|
||||
const header = [
|
||||
titleHeader,
|
||||
countHeader
|
||||
]
|
||||
|
||||
super(values.map(values => {
|
||||
|
||||
if (values === undefined) {
|
||||
|
@ -39,7 +84,21 @@ export default class Histogram<T> extends VariableUiElement {
|
|||
}
|
||||
|
||||
const keys = Array.from(counts.keys());
|
||||
keys.sort()
|
||||
|
||||
switch (sortMode.data) {
|
||||
case "name":
|
||||
keys.sort()
|
||||
break;
|
||||
case "name-rev":
|
||||
keys.sort().reverse()
|
||||
break;
|
||||
case "count":
|
||||
keys.sort((k0, k1) => counts.get(k0) - counts.get(k1))
|
||||
break;
|
||||
case "count-rev":
|
||||
keys.sort((k0, k1) => counts.get(k1) - counts.get(k0))
|
||||
break;
|
||||
}
|
||||
|
||||
const max = Math.max(...Array.from(counts.values()))
|
||||
|
||||
|
@ -57,7 +116,7 @@ export default class Histogram<T> extends VariableUiElement {
|
|||
}
|
||||
|
||||
return new Table(
|
||||
[Translations.W(title), countTitle],
|
||||
header,
|
||||
keys.map(key => [
|
||||
key,
|
||||
new Combine([
|
||||
|
@ -69,6 +128,6 @@ export default class Histogram<T> extends VariableUiElement {
|
|||
]),
|
||||
keys.map(_ => ["width: 20%"])
|
||||
).SetClass("w-full");
|
||||
}));
|
||||
}, [sortMode]));
|
||||
}
|
||||
}
|
|
@ -399,12 +399,12 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
{
|
||||
name: "title",
|
||||
doc: "The text to put above the given values column",
|
||||
doc: "This text will be placed above the texts (in the first column of the visulasition)",
|
||||
defaultValue: ""
|
||||
},
|
||||
{
|
||||
name: "countHeader",
|
||||
doc: "The text to put above the counts",
|
||||
doc: "This text will be placed above the bars",
|
||||
defaultValue: ""
|
||||
},
|
||||
{
|
||||
|
|
9
Utils.ts
9
Utils.ts
|
@ -137,14 +137,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
|
||||
public static NoNull<T>(array: T[]): T[] {
|
||||
const ls: T[] = [];
|
||||
for (const t of array) {
|
||||
if (t === undefined || t === null) {
|
||||
continue;
|
||||
}
|
||||
ls.push(t);
|
||||
}
|
||||
return ls;
|
||||
return array.filter(o => o !== undefined && o !== null)
|
||||
}
|
||||
|
||||
public static Hist(array: string[]): Map<string, number> {
|
||||
|
|
|
@ -1,3 +1,170 @@
|
|||
{
|
||||
"id": "mapcomplete-changes",
|
||||
"title": {
|
||||
"en": "Changes made with MapComplete"
|
||||
},
|
||||
"shortDescription": {
|
||||
"en": "Shows changes made by MapComplete"
|
||||
},
|
||||
"description": {
|
||||
"en": "This maps shows all the changes made with MapComplete"
|
||||
},
|
||||
"language": [
|
||||
"en"
|
||||
],
|
||||
"maintainer": "",
|
||||
"icon": "./assets/svg/logo.svg",
|
||||
"hideFromOverview": true,
|
||||
"version": "0",
|
||||
"startLat": 0,
|
||||
"startLon": 0,
|
||||
"startZoom": 1,
|
||||
"widenFactor": 0.05,
|
||||
"clustering": false,
|
||||
"layers": [
|
||||
{
|
||||
"id": "mapcomplete-changes",
|
||||
"name": {
|
||||
"en": "Changeset centers"
|
||||
},
|
||||
"minzoom": 0,
|
||||
"source": {
|
||||
"osmTags": "editor~*",
|
||||
"geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/mapcomplete-changes/tile_{z}_{x}_{y}.geojson",
|
||||
"geoJsonZoomLevel": 8,
|
||||
"maxCacheAge": 0
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_last_edit:contributor:lc:=feat.properties['_last_edit:contributor'].toLowerCase()"
|
||||
],
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "Changeset for {theme}"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"en": "Shows all MapComplete changes"
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "contributor",
|
||||
"render": {
|
||||
"en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "theme",
|
||||
"render": {
|
||||
"en": "Change with theme <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "theme~http.*",
|
||||
"then": {
|
||||
"en": "Change with <b>unofficial</b> theme <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
],
|
||||
"icon": {"render":"teardrop:#00cc00",
|
||||
"mappings": [{"if":"theme=aed","then":"./assets/themes/aed/logo.svg"},{"if":"theme=aed_brugge","then":"./assets/themes/aed/logo.svg"},{"if":"theme=artwork","then":"./assets/themes/artwork/artwork.svg"},{"if":"theme=benches","then":"./assets/themes/benches/bench_poi.svg"},{"if":"theme=bicyclelib","then":"./assets/themes/bicyclelib/logo.svg"},{"if":"theme=binoculars","then":"./assets/layers/binocular/telescope.svg"},{"if":"theme=bookcases","then":"./assets/themes/bookcases/bookcase.svg"},{"if":"theme=buurtnatuur","then":"./assets/themes/buurtnatuur/groen_logo.svg"},{"if":"theme=cafes_and_pubs","then":"./assets/layers/cafe_pub/pub.svg"},{"if":"theme=campersite","then":"./assets/themes/campersite/caravan.svg"},{"if":"theme=charging_stations","then":"./assets/themes/charging_stations/logo.svg"},{"if":"theme=climbing","then":"./assets/themes/climbing/climbing_icon.svg"},{"if":"theme=cycle_highways","then":"./assets/themes/cycle_highways/fietssnelwegen-logo.svg"},{"if":"theme=cycle_infra","then":"./assets/themes/cycle_infra/cycle-infra.svg"},{"if":"theme=cyclenodes","then":"./assets/themes/cyclenodes/logo.svg"},{"if":"theme=cyclestreets","then":"./assets/themes/cyclestreets/F111.svg"},{"if":"theme=cyclofix","then":"./assets/themes/cyclofix/logo.svg"},{"if":"theme=drinking_water","then":"./assets/themes/drinking_water/logo.svg"},{"if":"theme=entrances","then":"./assets/layers/entrance/door.svg"},{"if":"theme=etymology","then":"./assets/layers/etymology/logo.svg"},{"if":"theme=facadegardens","then":"./assets/themes/facadegardens/geveltuin.svg"},{"if":"theme=food","then":"./assets/layers/food/restaurant.svg"},{"if":"theme=fritures","then":"./assets/themes/fritures/logo.svg"},{"if":"theme=fruit_trees","then":"./assets/themes/fruit_trees/fruit_tree.svg"},{"if":"theme=ghostbikes","then":"./assets/themes/ghostbikes/logo.svg"},{"if":"theme=grb","then":"./assets/themes/grb_import/housenumber_blank.svg"},{"if":"theme=grb_fixme","then":"./assets/svg/bug.svg"},{"if":"theme=missing_streets","then":"./assets/svg/robot.svg"},{"if":"theme=hackerspaces","then":"./assets/themes/hackerspaces/glider.svg"},{"if":"theme=hailhydrant","then":"./assets/themes/hailhydrant/logo.svg"},{"if":"theme=mapcomplete-changes","then":"./assets/svg/logo.svg"},{"if":"theme=maps","then":"./assets/themes/maps/logo.svg"},{"if":"theme=nature","then":"./assets/themes/nature/logo.svg"},{"if":"theme=natuurpunt","then":"./assets/themes/natuurpunt/natuurpunt.png"},{"if":"theme=notes","then":"./assets/svg/resolved.svg"},{"if":"theme=observation_towers","then":"./assets/layers/observation_tower/Tower_observation.svg"},{"if":"theme=openwindpowermap","then":"./assets/themes/openwindpowermap/wind_turbine.svg"},{"if":"theme=parkings","then":"./assets/themes/parkings/parkings.svg"},{"if":"theme=personal","then":"./assets/svg/addSmall.svg"},{"if":"theme=play_forests","then":"./assets/layers/play_forest/icon.svg"},{"if":"theme=playgrounds","then":"./assets/themes/playgrounds/playground.svg"},{"if":"theme=postal_codes","then":"./assets/themes/postal_codes/townhall.svg"},{"if":"theme=postboxes","then":"./assets/themes/postboxes/postbox.svg"},{"if":"theme=shops","then":"./assets/themes/shops/shop.svg"},{"if":"theme=sidewalks","then":"./assets/svg/bug.svg"},{"if":"theme=speelplekken","then":"./assets/themes/speelplekken/logo.svg"},{"if":"theme=sport_pitches","then":"./assets/layers/sport_pitch/table_tennis.svg"},{"if":"theme=street_lighting","then":"./assets/layers/street_lamps/street_lamp.svg"},{"if":"theme=street_lighting_assen","then":"./assets/layers/street_lamps/street_lamp.svg"},{"if":"theme=surveillance","then":"./assets/themes/surveillance/logo.svg"},{"if":"theme=toerisme_vlaanderen","then":"./assets/svg/teardrop_with_hole_green.svg"},{"if":"theme=toilets","then":"./assets/themes/toilets/toilets.svg"},{"if":"theme=trees","then":"./assets/themes/trees/logo.svg"},{"if":"theme=uk_addresses","then":"./assets/themes/uk_addresses/housenumber_unknown.svg"},{"if":"theme=waste_basket","then":"./assets/themes/waste_basket/waste_basket.svg"}]
|
||||
|
||||
}
|
||||
},
|
||||
"iconSize": "30,30,bottom"
|
||||
}
|
||||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "theme-search",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "theme~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Themename contains {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "created_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_edit:contributor:lc~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Made by contributor {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not_created_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_edit:contributor:lc!~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "<b>Not</b> made by contributor {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"builtin": "current_view",
|
||||
"override": {
|
||||
"title": "Statistics on changesets in the current view",
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "link_to_more",
|
||||
"render": {
|
||||
"en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hist_themes",
|
||||
"render": "{histogram(_embedded_cs:themes, Themename, Number of changesets)}"
|
||||
},
|
||||
{
|
||||
"id": "hist_themes",
|
||||
"render": "{histogram(_embedded_cs:users, Contributor, Number of changesets)}"
|
||||
}
|
||||
],
|
||||
"calculatedTags": [
|
||||
"_embedded_cs=feat.overlapWith('mapcomplete-changes').map(f => f.feat.properties)",
|
||||
"_embedded_cs:themes=feat.get('_embedded_cs').map(cs => cs.theme)",
|
||||
"_embedded_cs:users=feat.get('_embedded_cs').map(cs => cs['_last_edit:contributor'])"
|
||||
],
|
||||
"+mapRendering": [{
|
||||
"location": [
|
||||
"point"
|
||||
],
|
||||
"icon":"statistics:black",
|
||||
"iconSize": "30,30,center"
|
||||
}]
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -748,14 +748,14 @@ video {
|
|||
right: 0.75rem;
|
||||
}
|
||||
|
||||
.top-4 {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.bottom-0 {
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.top-4 {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.right-1\/3 {
|
||||
right: 33.333333%;
|
||||
}
|
||||
|
@ -1096,6 +1096,10 @@ video {
|
|||
width: 6rem;
|
||||
}
|
||||
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.w-10 {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
@ -1120,8 +1124,8 @@ video {
|
|||
width: 2.75rem;
|
||||
}
|
||||
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
.w-4 {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
|
@ -1182,23 +1186,6 @@ video {
|
|||
transform: var(--tw-transform);
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
-webkit-animation: spin 1s linear infinite;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes pulse {
|
||||
50% {
|
||||
opacity: .5;
|
||||
|
@ -1216,6 +1203,23 @@ video {
|
|||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
-webkit-animation: spin 1s linear infinite;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -1339,6 +1343,10 @@ video {
|
|||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.rounded-sm {
|
||||
border-radius: 0.125rem;
|
||||
}
|
||||
|
||||
.rounded-l {
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
|
@ -1564,16 +1572,16 @@ video {
|
|||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-4xl {
|
||||
font-size: 2.25rem;
|
||||
line-height: 2.5rem;
|
||||
|
|
|
@ -112,12 +112,13 @@ class LayerOverviewUtils {
|
|||
|
||||
writeFileSync("./assets/generated/known_layers.json", JSON.stringify(Array.from(sharedLayers.values())))
|
||||
|
||||
/*
|
||||
writeFileSync('./assets/themes/mapcomplete-changes/icons-mapping.txt', JSON.stringify(
|
||||
Array.from(sharedThemes.values()).map(th => ({
|
||||
if: "theme=" + th.id,
|
||||
then: th.icon
|
||||
}))
|
||||
))
|
||||
)) //*/
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue