From 2e2a6965e7dc47579f2d2a0fd8a1e25543214aeb Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 16 Jan 2022 02:00:55 +0100 Subject: [PATCH] Add theme introspecting mapcomplete changes --- Logic/FeatureSource/Sources/GeoJsonSource.ts | 2 +- Models/Constants.ts | 2 +- UI/BigComponents/Histogram.ts | 69 ++++++- UI/SpecialVisualizations.ts | 4 +- Utils.ts | 9 +- .../mapcomplete-changes.json | 169 +++++++++++++++++- css/index-tailwind-output.css | 64 ++++--- scripts/generateLayerOverview.ts | 3 +- 8 files changed, 275 insertions(+), 47 deletions(-) diff --git a/Logic/FeatureSource/Sources/GeoJsonSource.ts b/Logic/FeatureSource/Sources/GeoJsonSource.ts index 4ff718ebe5..8de41dd33c 100644 --- a/Logic/FeatureSource/Sources/GeoJsonSource.ts +++ b/Logic/FeatureSource/Sources/GeoJsonSource.ts @@ -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; diff --git a/Models/Constants.ts b/Models/Constants.ts index 67b06f13e0..d02d9ec552 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -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" diff --git a/UI/BigComponents/Histogram.ts b/UI/BigComponents/Histogram.ts index 994a1ebe84..015fdbe302 100644 --- a/UI/BigComponents/Histogram.ts +++ b/UI/BigComponents/Histogram.ts @@ -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 extends VariableUiElement { @@ -13,9 +13,9 @@ export default class Histogram extends VariableUiElement { "#ff5858", "#ffad48", "#ffff59", - "#9d62d9", "#56bd56", "#63a9ff", + "#9d62d9", "#fa61fa" ] @@ -24,6 +24,51 @@ export default class Histogram 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 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 extends VariableUiElement { } return new Table( - [Translations.W(title), countTitle], + header, keys.map(key => [ key, new Combine([ @@ -69,6 +128,6 @@ export default class Histogram extends VariableUiElement { ]), keys.map(_ => ["width: 20%"]) ).SetClass("w-full"); - })); + }, [sortMode])); } } \ No newline at end of file diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index 28611fcb55..b15d58b8e2 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -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: "" }, { diff --git a/Utils.ts b/Utils.ts index 3c1abd1dc6..9192367004 100644 --- a/Utils.ts +++ b/Utils.ts @@ -137,14 +137,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } public static NoNull(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 { diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json index 0e0dcd235c..2274fc3f6f 100644 --- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json +++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json @@ -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 {_last_edit:contributor}" + } + }, + { + "id": "theme", + "render": { + "en": "Change with theme {theme}" + }, + "mappings": [ + { + "if": "theme~http.*", + "then": { + "en": "Change with unofficial theme {theme}" + } + } + ] + } + ], + "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"}] -} \ No newline at end of file + }, + "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": "Not 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 here" + } + }, + { + "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" + }] + + } + } + ] +} diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index e49ef5ff35..1191b9bcba 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -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; diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 1ddea2e7e2..1be2cb556f 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -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 })) - )) + )) //*/ }