forked from MapComplete/MapComplete
		
	More work on GRB theme, add 'apply_action' button
This commit is contained in:
		
							parent
							
								
									a456842773
								
							
						
					
					
						commit
						6c39f563b6
					
				
					 6 changed files with 275 additions and 66 deletions
				
			
		|  | @ -183,7 +183,7 @@ Some advanced functions are available on **feat** as well: | |||
| ### overlapWith  | ||||
| 
 | ||||
|  Gives a list of features from the specified layer which this feature (partly) overlaps with. If the current feature is a point, all features that embed the point are given. The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point. | ||||
| 
 | ||||
| The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list | ||||
| For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`  | ||||
| 
 | ||||
|   0. ...layerIds - one or more layer ids  of the layer from which every feature is checked for overlap) | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_nam | |||
|   - [canonical](#canonical) | ||||
|   - [import_button](#import_button) | ||||
|   - [multi_apply](#multi_apply) | ||||
|   - [tag_apply](#tag_apply) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -191,6 +192,8 @@ key | _undefined_ | The key of the tag to give the canonical text for | |||
| 
 | ||||
|  This button will copy the data from an external dataset into OpenStreetMap. It is only functional in official themes but can be tested in unofficial themes. | ||||
| 
 | ||||
| #### Importing a dataset into OpenStreetMap: requirements | ||||
| 
 | ||||
| If you want to import a dataset, make sure that: | ||||
| 
 | ||||
| 1. The dataset to import has a suitable license | ||||
|  | @ -199,17 +202,42 @@ If you want to import a dataset, make sure that: | |||
| 
 | ||||
| There are also some technicalities in your theme to keep in mind: | ||||
| 
 | ||||
| 1. The new point will be added and will flow through the program as any other new point as if it came from OSM. | ||||
| 1. The new feature will be added and will flow through the program as any other new point as if it came from OSM. | ||||
|     This means that there should be a layer which will match the new tags and which will display it. | ||||
| 2. The original point from your geojson layer will gain the tag '_imported=yes'. | ||||
| 2. The original feature from your geojson layer will gain the tag '_imported=yes'. | ||||
|     This should be used to change the appearance or even to hide it (eg by changing the icon size to zero) | ||||
| 3. There should be a way for the theme to detect previously imported points, even after reloading. | ||||
|     A reference number to the original dataset is an excellen way to do this     | ||||
|     A reference number to the original dataset is an excellent way to do this | ||||
| 4. When importing ways, the theme creator is also responsible of avoiding overlapping ways.  | ||||
|      | ||||
| #### Disabled in unofficial themes | ||||
| 
 | ||||
| The import button can be tested in an unofficial theme by adding `test=true` or `backend=osm-test` as [URL-paramter](URL_Parameters.md).  | ||||
| The import button will show up then. If in testmode, you can read the changeset-XML directly in the web console. | ||||
| In the case that MapComplete is pointed to the testing grounds, the edit will be made on https://master.apis.dev.openstreetmap.org | ||||
| 
 | ||||
| 
 | ||||
| #### Specifying which tags to copy or add | ||||
| 
 | ||||
| The first argument of the import button takes a `;`-seperated list of tags to add. | ||||
| 
 | ||||
| These can either be a tag to add, such as `amenity=fast_food` or can use a substitution, e.g. `addr:housenumber=$number`.  | ||||
| This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature.  | ||||
| 
 | ||||
| If a value to substitute is undefined, empty string will be used instead. | ||||
| 
 | ||||
| This supports multiple values, e.g. `ref=$source:geometry:type/$source:geometry:ref` | ||||
| 
 | ||||
| Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with `[a-zA-Z0-9_:]*`). Sadly, delimiting with `{}` as these already mark the boundaries of the special rendering... | ||||
| 
 | ||||
| Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript) | ||||
|   | ||||
|    | ||||
|   | ||||
| 
 | ||||
| name | default | description | ||||
| ------ | --------- | ------------- | ||||
| tags | _undefined_ | Tags to copy-specification. This contains one or more pairs (seperated by a `;`), e.g. `amenity=fast_food; addr:housenumber=$number`. This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature. (Hint: prepare these values, e.g. with calculatedTags) | ||||
| tags | _undefined_ | The tags to add onto the new object - see specification above | ||||
| text | Import this data into OpenStreetMap | The text to show on the button | ||||
| icon | ./assets/svg/addSmall.svg | A nice icon to show in the button | ||||
| minzoom | 18 | How far the contributor must zoom in before being able to import the point | ||||
|  | @ -233,4 +261,33 @@ overwrite | _undefined_ | If set to 'true', the tags on the other objects will a | |||
|   | ||||
| #### Example usage  | ||||
| 
 | ||||
|  {multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)} Generated from UI/SpecialVisualisations.ts | ||||
|  {multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)} | ||||
| 
 | ||||
| 
 | ||||
| ### tag_apply  | ||||
| 
 | ||||
|  Shows a big button; clicking this button will apply certain tags onto the feature. | ||||
| 
 | ||||
| The first argument takes a specification of which tags to add. | ||||
| These can either be a tag to add, such as `amenity=fast_food` or can use a substitution, e.g. `addr:housenumber=$number`.  | ||||
| This new point will then have the tags `amenity=fast_food` and `addr:housenumber` with the value that was saved in `number` in the original feature.  | ||||
| 
 | ||||
| If a value to substitute is undefined, empty string will be used instead. | ||||
| 
 | ||||
| This supports multiple values, e.g. `ref=$source:geometry:type/$source:geometry:ref` | ||||
| 
 | ||||
| Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with `[a-zA-Z0-9_:]*`). Sadly, delimiting with `{}` as these already mark the boundaries of the special rendering... | ||||
| 
 | ||||
| Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript) | ||||
|    | ||||
| 
 | ||||
| name | default | description | ||||
| ------ | --------- | ------------- | ||||
| tags_to_apply | _undefined_ | A specification of the tags to apply | ||||
| message | _undefined_ | The text to show to the contributor | ||||
| image | _undefined_ | An image to show to the contributor on the button | ||||
| id_of_object_to_apply_this_one | _undefined_ | If specified, applies the the tags onto _another_ object. The id will be read from properties[id_of_object_to_apply_this_one] of the selected object. The tags are still calculated based on the tags of the _selected_ element | ||||
|   | ||||
| #### Example usage  | ||||
| 
 | ||||
|  `{tag_apply(survey_date:=$_now:date, Surveyed today!)}` Generated from UI/SpecialVisualisations.ts | ||||
|  | @ -34,6 +34,10 @@ import ShowDataLayer from "./ShowDataLayer/ShowDataLayer"; | |||
| import Link from "./Base/Link"; | ||||
| import List from "./Base/List"; | ||||
| import {OsmConnection} from "../Logic/Osm/OsmConnection"; | ||||
| import {SubtleButton} from "./Base/SubtleButton"; | ||||
| import ChangeTagAction from "../Logic/Osm/Actions/ChangeTagAction"; | ||||
| import {And} from "../Logic/Tags/And"; | ||||
| import Toggle from "./Input/Toggle"; | ||||
| 
 | ||||
| export interface SpecialVisualization { | ||||
|     funcName: string, | ||||
|  | @ -45,6 +49,17 @@ export interface SpecialVisualization { | |||
| 
 | ||||
| export default class SpecialVisualizations { | ||||
| 
 | ||||
|     private static tagsToApplyHelpText = `These can either be a tag to add, such as \`amenity=fast_food\` or can use a substitution, e.g. \`addr:housenumber=$number\`. 
 | ||||
| This new point will then have the tags \`amenity=fast_food\` and \`addr:housenumber\` with the value that was saved in \`number\` in the original feature. 
 | ||||
| 
 | ||||
| If a value to substitute is undefined, empty string will be used instead. | ||||
| 
 | ||||
| This supports multiple values, e.g. \`ref=$source:geometry:type/$source:geometry:ref\` | ||||
| 
 | ||||
| Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with \`[a-zA-Z0-9_:]*\`). Sadly, delimiting with \`{}\` as these already mark the boundaries of the special rendering...
 | ||||
| 
 | ||||
| Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript) | ||||
|  ` | ||||
|     public static specialVisualizations: SpecialVisualization[] = | ||||
|         [ | ||||
|             { | ||||
|  | @ -222,7 +237,6 @@ export default class SpecialVisualizations { | |||
|                     return minimap; | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             { | ||||
|                 funcName: "sided_minimap", | ||||
|                 docs: "A small map showing _only one side_ the selected feature. *This features requires to have linerenderings with offset* as only linerenderings with a postive or negative offset will be shown. Note: in most cases, this map will be automatically introduced", | ||||
|  | @ -305,14 +319,14 @@ export default class SpecialVisualizations { | |||
|                     name: "key", | ||||
|                     defaultValue: "opening_hours", | ||||
|                     doc: "The tagkey from which the table is constructed." | ||||
|                 },{ | ||||
|                 }, { | ||||
|                     name: "prefix", | ||||
|                     defaultValue: "", | ||||
|                     doc:"Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__" | ||||
|                 },{ | ||||
|                     doc: "Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__" | ||||
|                 }, { | ||||
|                     name: "postfix", | ||||
|                     defaultValue: "", | ||||
|                     doc:"Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__" | ||||
|                     doc: "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__" | ||||
|                 }], | ||||
|                 example: "A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`", | ||||
|                 constr: (state: State, tagSource: UIEventSource<any>, args) => { | ||||
|  | @ -529,57 +543,21 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be | |||
| 
 | ||||
| The first argument of the import button takes a \`;\`-seperated list of tags to add.
 | ||||
| 
 | ||||
| These can either be a tag to add, such as \`amenity=fast_food\` or can use a substitution, e.g. \`addr:housenumber=$number\`. 
 | ||||
| This new point will then have the tags \`amenity=fast_food\` and \`addr:housenumber\` with the value that was saved in \`number\` in the original feature. 
 | ||||
| 
 | ||||
| If a value to substitute is undefined, empty string will be used instead. | ||||
| 
 | ||||
| This supports multiple values, e.g. \`ref=$source:geometry:type/$source:geometry:ref\` | ||||
| 
 | ||||
| Remark that the syntax is slightly different then expected; it uses '$' to note a value to copy, followed by a name (matched with \`[a-zA-Z0-9_:]*\`). Sadly, delimiting with \`{}\` as these already mark the boundaries of the special rendering...
 | ||||
| 
 | ||||
| Note that these values can be prepare with javascript in the theme by using a [calculatedTag](calculatedTags.md#calculating-tags-with-javascript) | ||||
|     | ||||
| ${SpecialVisualizations.tagsToApplyHelpText} | ||||
|    | ||||
| `,
 | ||||
|                 constr: (state, tagSource, args) => { | ||||
|                     if (!state.layoutToUse.official && !(state.featureSwitchIsTesting.data || state.osmConnection._oauth_config.url === OsmConnection.oauth_configs["osm-test"].url)) { | ||||
|                         return new Combine([new FixedUiElement("The import button is disabled for unofficial themes to prevent accidents.").SetClass("alert"), | ||||
|                             new FixedUiElement("To test, add <b>test=true</b> or <b>backend=osm-test</b> to the URL. The changeset will be printed in the console. Please open a PR to officialize this theme to actually enable the import button.")]) | ||||
|                     } | ||||
|                     const tgsSpec = args[0].split(";").map(spec => { | ||||
|                         const kv = spec.split("=").map(s => s.trim()); | ||||
|                         if (kv.length != 2) { | ||||
|                             throw "Invalid key spec: multiple '=' found in " + spec | ||||
|                         } | ||||
|                         return kv | ||||
|                     }) | ||||
|                     const rewrittenTags: UIEventSource<Tag[]> = tagSource.map(tags => { | ||||
|                         const newTags: Tag [] = [] | ||||
|                         for (const [key, value] of tgsSpec) { | ||||
|                             if (value.indexOf('$') >= 0) { | ||||
|                                  | ||||
|                                 let parts = value.split("$") | ||||
|                                 // THe first of the split won't start with a '$', so no substitution needed
 | ||||
|                                 let actualValue = parts[0] | ||||
|                                 parts.shift() | ||||
| 
 | ||||
|                                 for (const part of parts) { | ||||
|                                     const [_, varName, leftOver] = part.match(/([a-zA-Z0-9_:]*)(.*)/) | ||||
|                                     actualValue += (tags[varName] ?? "") + leftOver | ||||
|                                 } | ||||
|                                 newTags.push(new Tag(key, actualValue)) | ||||
|                             } else { | ||||
|                                 newTags.push(new Tag(key, value)) | ||||
|                             } | ||||
|                         } | ||||
|                         return newTags | ||||
|                     }) | ||||
|                     const rewrittenTags = SpecialVisualizations.generateTagsToApply(args[0], tagSource) | ||||
|                     const id = tagSource.data.id; | ||||
|                     const feature = state.allElements.ContainingFeatures.get(id) | ||||
|                     const minzoom = Number(args[3]) | ||||
|                     const message =  args[1] | ||||
|                     const message = args[1] | ||||
|                     const image = args[2] | ||||
|                      | ||||
| 
 | ||||
|                     return new ImportButton( | ||||
|                         image, message, tagSource, rewrittenTags, feature, minzoom, state | ||||
|                     ) | ||||
|  | @ -636,12 +614,113 @@ Note that these values can be prepare with javascript in the theme by using a [c | |||
|                     ); | ||||
| 
 | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 funcName: "tag_apply", | ||||
|                 docs: "Shows a big button; clicking this button will apply certain tags onto the feature.\n\nThe first argument takes a specification of which tags to add.\n" + SpecialVisualizations.tagsToApplyHelpText, | ||||
|                 args: [ | ||||
|                     { | ||||
|                         name: "tags_to_apply", | ||||
|                         doc: "A specification of the tags to apply" | ||||
|                     }, | ||||
|                     { | ||||
|                         name: "message", | ||||
|                         doc: "The text to show to the contributor" | ||||
|                     }, | ||||
|                     { | ||||
|                         name: "image", | ||||
|                         doc: "An image to show to the contributor on the button" | ||||
|                     }, | ||||
|                     { | ||||
|                         name: "id_of_object_to_apply_this_one", | ||||
|                         defaultValue: undefined, | ||||
|                         doc: "If specified, applies the the tags onto _another_ object. The id will be read from properties[id_of_object_to_apply_this_one] of the selected object. The tags are still calculated based on the tags of the _selected_ element" | ||||
|                     } | ||||
|                 ], | ||||
|                 example: "`{tag_apply(survey_date:=$_now:date, Surveyed today!)}`", | ||||
|                 constr: (state, tags, args) => { | ||||
|                     const tagsToApply = SpecialVisualizations.generateTagsToApply(args[0], tags) | ||||
|                     const msg = args[1] | ||||
|                     let image = args[2]?.trim() | ||||
|                     if (image === "" || image === "undefined") { | ||||
|                         image = undefined | ||||
|                     } | ||||
|                     const targetIdKey = args[3] | ||||
|                     const t = Translations.t.general.apply_button | ||||
|                      | ||||
|                     const tagsExplanation = new VariableUiElement(tagsToApply.map(tagsToApply => { | ||||
|                             const tagsStr = tagsToApply.map(t => t.asHumanString(false, true)).join("&"); | ||||
|                             let el: BaseUIElement = new FixedUiElement(tagsStr) | ||||
|                             if(targetIdKey !== undefined){ | ||||
|                                  const targetId = tags.data[targetIdKey] ?? tags.data.id | ||||
|                                 el = t.appliedOnAnotherObject.Subs({tags: tagsStr , id: targetId }) | ||||
|                             } | ||||
|                             return el; | ||||
|                         } | ||||
|                     )).SetClass("subtle") | ||||
|                      | ||||
|                     const applied = new UIEventSource(false) | ||||
|                     const applyButton = new SubtleButton(image, new Combine([msg, tagsExplanation]).SetClass("flex flex-col")) | ||||
|                         .onClick(() => { | ||||
|                             const targetId = tags.data[ targetIdKey] ?? tags.data.id | ||||
|                             const changeAction = new ChangeTagAction(targetId, | ||||
|                                 new And(tagsToApply.data), | ||||
|                                 tags.data, // We pass in the tags of the selected element, not the tags of the target element!
 | ||||
|                                 { | ||||
|                                     theme: state.layoutToUse.id, | ||||
|                                     changeType: "answer" | ||||
|                                 } | ||||
|                             ) | ||||
|                             state.changes.applyAction(changeAction) | ||||
|                             applied.setData(true) | ||||
|                         }) | ||||
| 
 | ||||
|                      | ||||
|                     return new Toggle( | ||||
|                         new Toggle( | ||||
|                          t.isApplied.SetClass("thanks"),    | ||||
|                         applyButton, | ||||
|                             applied | ||||
|                         ) | ||||
|                         , undefined, state.osmConnection.isLoggedIn) | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
| 
 | ||||
|     static HelpMessage: BaseUIElement = SpecialVisualizations.GenHelpMessage(); | ||||
|     private static generateTagsToApply(spec: string, tagSource: UIEventSource<any>): UIEventSource<Tag[]> { | ||||
| 
 | ||||
|     private static GenHelpMessage() { | ||||
|         const tgsSpec = spec.split(";").map(spec => { | ||||
|             const kv = spec.split("=").map(s => s.trim()); | ||||
|             if (kv.length != 2) { | ||||
|                 throw "Invalid key spec: multiple '=' found in " + spec | ||||
|             } | ||||
|             return kv | ||||
|         }) | ||||
|         return tagSource.map(tags => { | ||||
|             const newTags: Tag [] = [] | ||||
|             for (const [key, value] of tgsSpec) { | ||||
|                 if (value.indexOf('$') >= 0) { | ||||
| 
 | ||||
|                     let parts = value.split("$") | ||||
|                     // THe first of the split won't start with a '$', so no substitution needed
 | ||||
|                     let actualValue = parts[0] | ||||
|                     parts.shift() | ||||
| 
 | ||||
|                     for (const part of parts) { | ||||
|                         const [_, varName, leftOver] = part.match(/([a-zA-Z0-9_:]*)(.*)/) | ||||
|                         actualValue += (tags[varName] ?? "") + leftOver | ||||
|                     } | ||||
|                     newTags.push(new Tag(key, actualValue)) | ||||
|                 } else { | ||||
|                     newTags.push(new Tag(key, value)) | ||||
|                 } | ||||
|             } | ||||
|             return newTags | ||||
|         }) | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static HelpMessage() { | ||||
| 
 | ||||
|         const helpTexts = | ||||
|             SpecialVisualizations.specialVisualizations.map(viz => new Combine( | ||||
|  | @ -651,7 +730,7 @@ Note that these values can be prepare with javascript in the theme by using a [c | |||
|                     viz.args.length > 0 ? new Table(["name", "default", "description"], | ||||
|                         viz.args.map(arg => { | ||||
|                             let defaultArg = arg.defaultValue ?? "_undefined_" | ||||
|                             if(defaultArg == ""){ | ||||
|                             if (defaultArg == "") { | ||||
|                                 defaultArg = "_empty string_" | ||||
|                             } | ||||
|                             return [arg.name, defaultArg, arg.doc]; | ||||
|  | @ -665,9 +744,9 @@ Note that these values can be prepare with javascript in the theme by using a [c | |||
|                 ] | ||||
|             )); | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
|         const toc = new List( | ||||
|             SpecialVisualizations.specialVisualizations.map(viz => new Link(viz.funcName, "#"+viz.funcName)) | ||||
|             SpecialVisualizations.specialVisualizations.map(viz => new Link(viz.funcName, "#" + viz.funcName)) | ||||
|         ) | ||||
| 
 | ||||
|         return new Combine([ | ||||
|  | @ -679,4 +758,5 @@ Note that these values can be prepare with javascript in the theme by using a [c | |||
|             ] | ||||
|         ).SetClass("flex flex-col"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -7,7 +7,8 @@ | |||
|     "nl": "Grb Fixup" | ||||
|   }, | ||||
|   "description": { | ||||
|     "nl": "GRB Fixup" | ||||
|     "nl": "GRB Fixup", | ||||
|     "en": "This theme is an attempt to help automating the GRB import.<br/>Note that this is very hacky and 'steals' the GRB data from an external site; in order to do this, you need to install and activate <a href='https://addons.mozilla.org/en-US/firefox/addon/cors-everywhere/'>this firefox extension</a> for it to work." | ||||
|   }, | ||||
|   "language": [ | ||||
|     "nl" | ||||
|  | @ -23,6 +24,9 @@ | |||
|   "clustering": { | ||||
|     "maxZoom": 15 | ||||
|   }, | ||||
|   "overrideAll": { | ||||
|     "minzoom": 18 | ||||
|   }, | ||||
|   "layers": [ | ||||
|     { | ||||
|       "id": "OSM-buildings", | ||||
|  | @ -31,7 +35,6 @@ | |||
|         "osmTags": "building~*", | ||||
|         "maxCacheAge": 0 | ||||
|       }, | ||||
|       "minzoom": 16, | ||||
|       "mapRendering": [ | ||||
|         { | ||||
|           "width": { | ||||
|  | @ -67,6 +70,55 @@ | |||
|       ], | ||||
|       "title": "OSM-gebouw", | ||||
|       "tagRenderings": [ | ||||
|         { | ||||
|           "id": "building type", | ||||
|           "freeform": { | ||||
|             "key": "building" | ||||
|           }, | ||||
|           "render": "The building type is <b>{building}</b>", | ||||
|           "mappings": [ | ||||
|             { | ||||
|               "if": "building=house", | ||||
|               "then": "A normal house" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=detached", | ||||
|               "then": "A house detached from other building" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=semidetached_house", | ||||
|               "then": "A house sharing only one wall with another house" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=apartments", | ||||
|               "then": "An apartment building - highrise for living" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=office", | ||||
|               "then": "An office building - highrise for work" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=apartments", | ||||
|               "then": "An apartment building" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=shed", | ||||
|               "then": "A small shed, e.g. in a garden" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=garage", | ||||
|               "then": "A single garage to park a car" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=garages", | ||||
|               "then": "A building containing only garages; typically they are all identical" | ||||
|             }, | ||||
|             { | ||||
|               "if": "building=yes", | ||||
|               "then": "A building - no specification" | ||||
|             } | ||||
|           ] | ||||
|         }, | ||||
|         "all_tags" | ||||
|       ] | ||||
|     }, | ||||
|  | @ -99,7 +151,6 @@ | |||
|         }, | ||||
|         "maxCacheAge": 0 | ||||
|       }, | ||||
|       "minzoom": 18, | ||||
|       "mapRendering": [ | ||||
|         { | ||||
|           "color": { | ||||
|  | @ -124,7 +175,6 @@ | |||
|       "name": { | ||||
|         "nl": "Fixmes op gebouwen" | ||||
|       }, | ||||
|       "minzoom": 21, | ||||
|       "source": { | ||||
|         "maxCacheAge": 0, | ||||
|         "osmTags": { | ||||
|  | @ -314,7 +364,6 @@ | |||
|         "geoJsonZoomLevel": 18, | ||||
|         "maxCacheAge": 0 | ||||
|       }, | ||||
|       "minzoom": 16, | ||||
|       "name": "CRAB-addressen", | ||||
|       "title": "CRAB-adres", | ||||
|       "mapRendering": [ | ||||
|  | @ -372,7 +421,6 @@ | |||
|       "name": { | ||||
|         "nl": "Fixmes op gebouwen" | ||||
|       }, | ||||
|       "minzoom": 16, | ||||
|       "source": { | ||||
|         "maxCacheAge": 0, | ||||
|         "osmTags": { | ||||
|  | @ -563,7 +611,6 @@ | |||
|       }, | ||||
|       "name": "GRB geometries", | ||||
|       "title": "GRB outline", | ||||
|       "minzoom": 16, | ||||
|       "calculatedTags": [ | ||||
|         "_overlaps_with=feat.overlapWith('OSM-buildings').filter(f => f.overlap > 1 &&  (feat.get('_surface') < 20 || f.overlap / feat.get('_surface')) > 0.9)[0] ?? null", | ||||
|         "_overlap_absolute=feat.get('_overlaps_with')?.overlap", | ||||
|  | @ -587,6 +634,26 @@ | |||
|           "render": "<div>The overlapping openstreetmap-building is a <b>{_osm_obj:building}</b> and covers <b>{_overlap_percentage}%</b> of the GRB building<div><h3>GRB geometry:</h3>{minimap(21, id):height:10rem;border-radius:1rem;overflow:hidden}<h3>OSM geometry:</h3>{minimap(21,_osm_obj:id):height:10rem;border-radius:1rem;overflow:hidden}", | ||||
|           "condition": "_overlaps_with!=null" | ||||
|         }, | ||||
|         { | ||||
|           "id": "apply-id", | ||||
|           "render": "{tag_apply(source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref,Mark the OSM-building as imported,,_osm_obj:id)}", | ||||
|           "condition": { | ||||
|             "and": [ | ||||
|               "_overlaps_with!=null" | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": "apply-building-type", | ||||
|           "render": "{tag_apply(building=$building,Use the building type from GRB,,_osm_obj:id)}", | ||||
|           "condition": { | ||||
|             "and": [ | ||||
|               "_overlaps_with!=null", | ||||
|               "_osm_obj:building=yes", | ||||
|               "building!=yes" | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": "Import-button", | ||||
|           "render": "{import_button(building=$building; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref, Upload this building to OpenStreetMap)}", | ||||
|  | @ -594,7 +661,8 @@ | |||
|             { | ||||
|               "if": "_overlaps_with!=null", | ||||
|               "then": "Cannot be imported directly, there is a nearly identical building geometry in OpenStreetMap" | ||||
|             }] | ||||
|             } | ||||
|           ] | ||||
|         }, | ||||
|         "all_tags" | ||||
|       ], | ||||
|  |  | |||
|  | @ -131,6 +131,10 @@ | |||
|             "previouslyHiddenTitle": "Previously visited hidden themes", | ||||
|             "hiddenExplanation": "These themes are only visible if you know the link. You have discovered {hidden_discovered} out of {total_hidden} hidden themes" | ||||
|         }, | ||||
|         "apply_button": { | ||||
|             "isApplied": "The changes are applied", | ||||
|             "appliedOnAnotherObject": "The object {id} will receive {tags}" | ||||
|         }, | ||||
|         "sharescreen": { | ||||
|             "intro": "<h3>Share this map</h3> Share this map by copying the link below and sending it to friends and family:", | ||||
|             "addToHomeScreen": "<h3>Add to your home screen</h3>You can easily add this website to your smartphone home screen for a native feel. Click the 'add to home screen' button in the URL bar to do this.", | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ function WriteFile(filename, html: string | BaseUIElement, autogenSource: string | |||
|     ]).AsMarkdown()); | ||||
| } | ||||
| 
 | ||||
| WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage, ["UI/SpecialVisualisations.ts"]) | ||||
| WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage(), ["UI/SpecialVisualisations.ts"]) | ||||
| WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"), | ||||
|     ["SimpleMetaTagger", "ExtraFunction"]) | ||||
| WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(), ["ValidatedTextField.ts"]); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue