Merge branch 'develop'

This commit is contained in:
Pieter Vander Vennet 2023-02-12 23:05:06 +01:00
commit a6102aa3e0
6 changed files with 159 additions and 16 deletions

View file

@ -0,0 +1,129 @@
# Integrating MapRoulette
[MapRoulette](https://www.maproulette.org/) is a website which has challenges. A challenge is a collection of _microtasks_, i.e. mapping
tasks which can be solved in a few minutes.
A perfect example of this is to setup such a challenge to e.g. import new points. [Important: always follow the import guidelines if you want to import data.](https://wiki.openstreetmap.org/wiki/Import/Guidelines)
(Another approach to set up a guided import is to create a map note for every point with the [import helper](https://mapcomplete.osm.be/import_helper). This however litters the map and will upset mappers if used with to much points.)
## The API
**Most of the heavy lifting is done in layer `maproulette`. Extend this layer with your needs**
The API is shortly discussed here for future reference only.
There is an API-endpoint at `https://maproulette.org/api/v2/tasks/box/{x_min}/{y_min}/{x_max}/{y_max}` which can be used
to query _all_ tasks in a bbox and returns this as geojson. Hint:
use [the maproulette theme in debug mode](https://mapcomplete.osm.be/maproulette?debug=true) to inspect all properties.
To view the overview a single challenge, visit `https://maproulette.org/browse/challenges/<challenge-id>` with your
browser.
The API endpoint for a single challenge is `https://maproulette.org/api/v2/challenge/view/<challenge-id>` which returns a
geojson.
## Displaying MapRoulette data in MapComplete
As you'll probably want to link MapComplete to your challenge, reuse [maproulette_challenge](Docs/Layers/maproulette_challenge.md).
It has a basic framework already to load the tags.
Of course, interacting with the tasks is the next step.
### Detecting nearby features
You can use [`calculatedTags`](./Docs/CalculatedTags.md) to add a small piece of code to e.g. detect nearby entities.
The following example is to match hotels:
```
"calculatedTags": [
"_closest_osm_hotel=feat.closest('hotel')?.properties?.id",
"_closest_osm_hotel_distance=feat.distanceTo(feat.properties._closest_osm_hotel)",
"_has_closeby_feature=Number(feat.properties._closest_osm_hotel_distance) < 50 ? 'yes' : 'no'"
],
```
This can be used to decide if tags should be applied on an existing object or a new point should be created.
### Creating a new point based on a maproulette challenge (Guided import)
**Requirement**: the MapRoulette task should have `tags` added.
One can add `import`-button in the featureInfoBox ([documentation here](./Docs/SpecialRenderings.md#importbutton)).
Note that the import button has support for MapRoulette and is able to close the task if the property containing the maproulette-id is given:
```json
{
"id": "import-button",
"render": {
"special": {
"type": "import_button",
"targetLayer": "<the layer in which the point should appear afterwards>",
"tags": "tags", -- should stay 'tags'
"maproulette_id": "mr_taskId", -- important to get the task closed
"text": {
"en": "Import this point" -- or a nice message
},
"icon": "./assets/svg/addSmall.svg", -- optional, feel free to change
"location_picker": "photo", -- optional, background layer to pinpoint the hotel
}
}
}
```
### Applying tags to already existing features
For this, [the `tag_apply`-button can be used](./Docs/SpecialRenderings.md#tagapply).
The following example uses the calculated tags `_has_closeby_feature` and `_closest_osm_hotel`. These were added by a small extra script using `calculatedTagss`.
```json
{
"id": "tag-apply-button",
"condition": "_has_closeby_feature=yes", -- don't show if no feature to add to
"render": {
"special": {
"type": "tag_apply",
"tags_to_apply": "$tags", -- note the '$', property containing the tags
"id_of_object_to_apply_this_one": "_closest_osm_hotel" -- id of the feature to add those tags to
"message": {
"en": "Add all the suggested tags"
},
"image": "./assets/svg/addSmall.svg",
}
}
}
```
## Creating a maproulette challenge
A challenge can be created on https://maproulette.org/admin/projects
This can be done with a geojson-file (or by other means).
To create an import dataset, make a geojson file where every feature has a `tags`-field with ';'-seperated tags to add.
Furthermore, setting the property `blurb` can be useful.
(The following example is not tested and might be wrong.)
```
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {"type": "Point", "coordinates": [1.234, 5.678]},
"properties": {
"tags": "foo=bar;name=xyz",
"blurb": "Please review this item and add it..."
}
}
]
}
```

View file

@ -14,6 +14,9 @@ export class FixedUiElement extends BaseUIElement {
AsMarkdown(): string {
if (this.HasClass("code")) {
if (this.content.indexOf("\n") > 0 || this.HasClass("block")) {
return "\n```\n" + this.content + "\n```\n"
}
return "`" + this.content + "`"
}
if (this.HasClass("font-bold")) {

View file

@ -644,7 +644,7 @@ export class ImportPointButton extends AbstractImportButton {
},
{
name: "maproulette_id",
doc: "If given, the maproulette challenge will be marked as fixed",
doc: "The property name of the maproulette_id - this is probably `mr_taskId`. If given, the maproulette challenge will be marked as fixed. Only use this if part of a maproulette-layer.",
},
],
{ showRemovedTags: false }

View file

@ -30,7 +30,6 @@ import WikipediaBox from "./Wikipedia/WikipediaBox"
import Wikidata, { WikidataResponse } from "../Logic/Web/Wikidata"
import { Translation } from "./i18n/Translation"
import Translations from "./i18n/Translations"
import MangroveReviews from "../Logic/Web/MangroveReviews"
import ReviewForm from "./Reviews/ReviewForm"
import ReviewElement from "./Reviews/ReviewElement"
import OpeningHoursVisualization from "./OpeningHours/OpeningHoursVisualization"
@ -480,6 +479,10 @@ export default class SpecialVisualizations {
args: [],
constr(state, tagSource, argument, guistate) {
let parentId = tagSource.data.mr_challengeId
if (parentId === undefined) {
console.warn("Element ", tagSource.data.id, " has no mr_challengeId")
return undefined
}
let challenge = Stores.FromPromise(
Utils.downloadJsonCached(
`https://maproulette.org/api/v2/challenge/${parentId}`,
@ -512,7 +515,7 @@ export default class SpecialVisualizations {
})
)
},
docs: "Show details of a MapRoulette task",
docs: "Fetches the metadata of MapRoulette campaign that this task is part of and shows those details (namely `title`, `description` and `instruction`).\n\nThis reads the property `mr_challengeId` to detect the parent campaign.",
},
{
funcName: "statistics",
@ -725,13 +728,6 @@ export default class SpecialVisualizations {
render: {
special: {
type: "some_special_visualisation",
before: {
en: "Some text to prefix before the special element (e.g. a title)",
nl: "Een tekst om voor het element te zetten (bv. een titel)",
},
after: {
en: "Some text to put after the element, e.g. a footer",
},
argname: "some_arg",
message: {
en: "some other really long message",
@ -739,12 +735,20 @@ export default class SpecialVisualizations {
},
other_arg_name: "more args",
},
before: {
en: "Some text to prefix before the special element (e.g. a title)",
nl: "Een tekst om voor het element te zetten (bv. een titel)",
},
after: {
en: "Some text to put after the element, e.g. a footer",
},
},
},
null,
" "
)
).SetClass("code"),
'In other words: use `{ "before": ..., "after": ..., "special": {"type": ..., "argname": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)',
]).SetClass("flex flex-col"),
...helpTexts,
]).SetClass("flex flex-col")

View file

@ -5,6 +5,11 @@
"geoJsonZoomLevel": 16,
"osmTags": "title~*"
},
"description": {
"en": "Layer showing all tasks in MapRoulette",
"de": "Ebene, die alle MapRoulette-Aufgaben zeigt",
"nl": "Laag met alle taken uit MapRoulette"
},
"mapRendering": [
{
"location": [
@ -128,11 +133,6 @@
"render": "{blurb}"
}
],
"description": {
"en": "Layer showing all tasks in MapRoulette",
"de": "Ebene, die alle MapRoulette-Aufgaben zeigt",
"nl": "Laag met alle taken uit MapRoulette"
},
"minzoom": 15,
"name": {
"en": "MapRoulette Tasks",

View file

@ -64,7 +64,14 @@ function WriteFile(
md.replace(/\n\n\n+/g, "\n\n")
writeFileSync(filename, md)
if (!md.endsWith("\n")) {
md += "\n"
}
const warnAutomated =
"[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)"
writeFileSync(filename, warnAutomated + md)
}
/**