forked from MapComplete/MapComplete
		
	Add loading of live data
This commit is contained in:
		
							parent
							
								
									feab5a19b3
								
							
						
					
					
						commit
						0d6412f824
					
				
					 14 changed files with 291 additions and 35 deletions
				
			
		|  | @ -17,6 +17,7 @@ import * as bike_repair_station from "../../assets/layers/bike_repair_station/bi | |||
| import * as birdhides from "../../assets/layers/bird_hide/birdhides.json" | ||||
| import * as nature_reserve from "../../assets/layers/nature_reserve/nature_reserve.json" | ||||
| import * as bike_cafes from "../../assets/layers/bike_cafe/bike_cafes.json" | ||||
| import * as bike_monitoring_station from "../../assets/layers/bike_monitoring_station/bike_monitoring_station.json" | ||||
| import * as cycling_themed_objects from "../../assets/layers/cycling_themed_object/cycling_themed_objects.json" | ||||
| import * as bike_shops from "../../assets/layers/bike_shop/bike_shop.json" | ||||
| import * as maps from "../../assets/layers/maps/maps.json" | ||||
|  | @ -43,6 +44,7 @@ export class FromJSON { | |||
|             FromJSON.Layer(viewpoint), | ||||
|             FromJSON.Layer(bike_parking), | ||||
|             FromJSON.Layer(bike_repair_station), | ||||
|             FromJSON.Layer(bike_monitoring_station), | ||||
|             FromJSON.Layer(birdhides), | ||||
|             FromJSON.Layer(nature_reserve), | ||||
|             FromJSON.Layer(bike_cafes), | ||||
|  |  | |||
|  | @ -117,7 +117,7 @@ export class FilteredLayer { | |||
|                 feature.properties["_lon"] = "" + lat; // We expect a string here for lat/lon
 | ||||
|                 feature.properties["_lat"] = "" + lon; | ||||
|                 // But the codegrid SHOULD be a number!
 | ||||
|                 CodeGrid.grid.getCode(lat, lon, (error, code) => { | ||||
|                 CodeGrid.getCode(lat, lon, (error, code) => { | ||||
|                     if (error === null) { | ||||
|                         feature.properties["_country"] = code; | ||||
|                     } else { | ||||
|  |  | |||
|  | @ -91,6 +91,14 @@ export class LayerUpdater { | |||
| 
 | ||||
|         self.retries.setData(0); | ||||
|          | ||||
|         let newIds = 1; | ||||
|         for (const feature of geojson.features) { | ||||
|             if(feature.properties.id === undefined){ | ||||
|                 feature.properties.id = "ext/"+newIds; | ||||
|                 newIds++; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         function renderLayers(layers: FilteredLayer[]) { | ||||
|             if (layers.length === 0) { | ||||
|                 self.runningQuery.setData(false); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import {Bounds} from "../Bounds"; | ||||
| import {TagsFilter} from "../Tags"; | ||||
| import $ from "jquery" | ||||
| import * as $ from "jquery" | ||||
| import * as OsmToGeoJson from "osmtogeojson"; | ||||
| 
 | ||||
| /** | ||||
|  | @ -28,13 +28,12 @@ export class Overpass { | |||
|      | ||||
|     queryGeoJson(bounds: Bounds, continuation: ((any) => void), onFail: ((reason) => void)): void { | ||||
| 
 | ||||
|         let query = this.buildQuery( "[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]") | ||||
|         let query = this.buildQuery("[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]") | ||||
| 
 | ||||
|         if(Overpass.testUrl !== null){ | ||||
|         if (Overpass.testUrl !== null) { | ||||
|             console.log("Using testing URL") | ||||
|             query = Overpass.testUrl; | ||||
|         } | ||||
| 
 | ||||
|         $.getJSON(query, | ||||
|             function (json, status) { | ||||
|                 if (status !== "success") { | ||||
|  | @ -42,7 +41,7 @@ export class Overpass { | |||
|                     onFail(status); | ||||
|                 } | ||||
| 
 | ||||
|                 if(json.elements === [] && json.remarks.indexOf("runtime error") > 0){ | ||||
|                 if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) { | ||||
|                     console.log("Timeout or other runtime error"); | ||||
|                     onFail("Runtime error (timeout)") | ||||
|                     return; | ||||
|  |  | |||
|  | @ -1,7 +1,12 @@ | |||
| import codegrid from "codegrid-js"; | ||||
| 
 | ||||
| export default class CodeGrid { | ||||
|     public static readonly grid = CodeGrid.InitGrid(); | ||||
|     private static readonly grid = CodeGrid.InitGrid(); | ||||
|      | ||||
| 
 | ||||
|     public static getCode(lat: any, lon: any, handle: (error, code) => void) { | ||||
|         CodeGrid.grid.getCode(lat, lon, handle); | ||||
|     } | ||||
| 
 | ||||
|     private static InitGrid(): any { | ||||
|         const grid = codegrid.CodeGrid("./tiles/"); | ||||
|  | @ -15,4 +20,6 @@ export default class CodeGrid { | |||
|         }); | ||||
|         return grid; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										53
									
								
								Logic/Web/LiveQueryHandler.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Logic/Web/LiveQueryHandler.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| /** | ||||
|  * Fetches data from random data sources | ||||
|  */ | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import * as $ from "jquery" | ||||
| 
 | ||||
| export default class LiveQueryHandler { | ||||
| 
 | ||||
| 
 | ||||
|     private static cache = {} // url --> UIEventSource<actual data>
 | ||||
|     private static neededShorthands = {} // url -> (shorthand:paths)[]
 | ||||
| 
 | ||||
|     public static FetchLiveData(url: string, shorthands: string[]): UIEventSource<any /* string -> string */> { | ||||
| 
 | ||||
|         const shorthandsSet: string[] = LiveQueryHandler.neededShorthands[url] ?? [] | ||||
| 
 | ||||
|         for (const shorthand of shorthands) { | ||||
|             if (shorthandsSet.indexOf(shorthand) < 0) { | ||||
|                 shorthandsSet.push(shorthand); | ||||
|             } | ||||
|         } | ||||
|         LiveQueryHandler.neededShorthands[url] = shorthandsSet; | ||||
| 
 | ||||
| 
 | ||||
|         if (LiveQueryHandler[url] === undefined) { | ||||
|             const source = new UIEventSource({}); | ||||
|             LiveQueryHandler[url] = source; | ||||
| 
 | ||||
|                 console.log("Fetching live data from a third-party (unknown) API:",url) | ||||
|             $.getJSON(url, function (data) { | ||||
|                 for (const shorthandDescription of shorthandsSet) { | ||||
| 
 | ||||
|                     const descr = shorthandDescription.trim().split(":"); | ||||
|                     const shorthand = descr[0]; | ||||
|                     const path = descr[1]; | ||||
|                     const parts = path.split("."); | ||||
|                     let trail = data; | ||||
|                     for (const part of parts) { | ||||
|                         if (trail !== undefined) { | ||||
|                             trail = trail[part]; | ||||
|                         } | ||||
|                     } | ||||
|                     source.data[shorthand] = trail; | ||||
|                 } | ||||
|                 source.ping(); | ||||
| 
 | ||||
|             }) | ||||
| 
 | ||||
|         } | ||||
|         return LiveQueryHandler[url]; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -184,3 +184,6 @@ Park icon via http://www.onlinewebfonts.com/icon/425974, CC BY 3.0 (@sterankofra | |||
| Forest icon via https://www.onlinewebfonts.com/icon/498112, CC BY | ||||
| 
 | ||||
| Statistics icon via https://www.onlinewebfonts.com/icon/197818 | ||||
| 
 | ||||
| Chronometer (on monitoring_station.svg): ANTU chronometer | ||||
| https://commons.wikimedia.org/w/index.php?title=Antu_chronometer&action=edit&redlink=1 | ||||
|  | @ -1,6 +1,8 @@ | |||
| import {UIElement} from "./UIElement"; | ||||
| import OpeningHoursVisualization from "./OhVisualization"; | ||||
| import {UIEventSource} from "../Logic/UIEventSource"; | ||||
| import {VariableUiElement} from "./Base/VariableUIElement"; | ||||
| import LiveQueryHandler from "../Logic/Web/LiveQueryHandler"; | ||||
| 
 | ||||
| export default class SpecialVisualizations { | ||||
| 
 | ||||
|  | @ -8,13 +10,13 @@ export default class SpecialVisualizations { | |||
|         funcName: string, | ||||
|         constr: ((tagSource: UIEventSource<any>, argument: string[]) => UIElement), | ||||
|         docs: string, | ||||
|         args: {name: string, defaultValue: string, doc: string}[] | ||||
|         args: { name: string, defaultValue?: string, doc: string }[] | ||||
|     }[] = | ||||
| 
 | ||||
|         [{ | ||||
|             funcName: "opening_hours_table", | ||||
|             docs: "Creates an opening-hours table. Usage: {opening_hours_table(opening_hours)} to create a table of the tag 'opening_hours'.", | ||||
|             args:[{name:"key", defaultValue: "opening_hours", doc: "The tag from which the table is constructed"}], | ||||
|             args: [{name: "key", defaultValue: "opening_hours", doc: "The tag from which the table is constructed"}], | ||||
|             constr: (tagSource: UIEventSource<any>, args) => { | ||||
|                 let keyname = args[0]; | ||||
|                 if (keyname === undefined || keyname === "") { | ||||
|  | @ -24,6 +26,26 @@ export default class SpecialVisualizations { | |||
|             } | ||||
|         }, | ||||
| 
 | ||||
|             { | ||||
|                 funcName: "live", | ||||
|                 docs: "Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)}", | ||||
|                 args: [{ | ||||
|                     name: "Url", doc: "The URL to load" | ||||
|                 }, { | ||||
|                     name: "Shorthands", | ||||
|                     doc: "A list of shorthands, of the format 'shorthandname:path.path.path'. Seperated by ;" | ||||
|                 }, { | ||||
|                     name: "path", doc: "The path (or shorthand) that should be returned" | ||||
|                 }], | ||||
|                 constr: (tagSource: UIEventSource<any>, args) => { | ||||
|                     const url = args[0]; | ||||
|                     const shorthands = args[1]; | ||||
|                     const neededValue = args[2]; | ||||
|                     const source = LiveQueryHandler.FetchLiveData(url, shorthands.split(";")); | ||||
|                     return new VariableUiElement(source.map(data => data[neededValue] ?? "Loading...")); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         ] | ||||
| 
 | ||||
| } | ||||
|  | @ -47,10 +47,10 @@ export default class Translation extends UIElement { | |||
| 
 | ||||
|             for (const knownSpecial of knownSpecials) { | ||||
| 
 | ||||
| 
 | ||||
|                 do { | ||||
|                     const matched = template.match(`(.*){${knownSpecial.funcName}\\((.*)\\)}(.*)`); | ||||
|                     if (matched === null) { | ||||
|                     continue; | ||||
|                         break; | ||||
|                     } | ||||
|                     const partBefore = matched[1]; | ||||
|                     const argument = matched[2]; | ||||
|  | @ -64,6 +64,10 @@ export default class Translation extends UIElement { | |||
|                         console.error(e); | ||||
|                         template = partBefore + partAfter; | ||||
|                     } | ||||
| 
 | ||||
|                 } while (true); | ||||
| 
 | ||||
| 
 | ||||
|             } | ||||
|             newTranslations[lang] = template; | ||||
|         } | ||||
|  |  | |||
|  | @ -103,10 +103,10 @@ export default class Translations { | |||
|             }), | ||||
| 
 | ||||
|             respectPrivacy: new T({ | ||||
|                 en: "Please respect privacy. Do not photograph people nor license plates.<br/>Respect copyright. Only upload images you made yourself. Do not upload Google Streetview Images - these will be removed.", | ||||
|                 en: "Do not photograph people nor license plates. Do not upload Google Maps, Google Streetview or other copyrighted sources.", | ||||
|                 ca: "Respecta la privacitat. No fotografiïs gent o matrícules", | ||||
|                 es: "Respeta la privacidad. No fotografíes gente o matrículas", | ||||
|                 nl: "Respecteer privacy. Fotografeer geen mensen of nummerplaten.<br/>Repecteer auteursrechten. Voeg enkel foto's toe die je zelf maakte. Screenshots van andere services (zoals Google Streetview) worden verwijderd", | ||||
|                 nl: "Fotografeer geen mensen of nummerplaten. Voeg geen Google Maps, Google Streetview of foto's met auteursrechten toe.", | ||||
|                 fr: "Merci de respecter la vie privée. Ne publiez pas les plaques d\'immatriculation", | ||||
|                 gl: "Respecta a privacidade. Non fotografes xente ou matrículas", | ||||
|                 de: "Bitte respektieren Sie die Privatsphäre. Fotografieren Sie weder Personen noch Nummernschilder" | ||||
|  | @ -969,6 +969,9 @@ export default class Translations { | |||
|     } | ||||
| 
 | ||||
|     public static WT(s: string | Translation): Translation { | ||||
|         if(s === undefined){ | ||||
|             return undefined; | ||||
|         } | ||||
|         if (typeof (s) === "string") { | ||||
|             return new Translation({en: s}); | ||||
|         } | ||||
|  |  | |||
|  | @ -0,0 +1,58 @@ | |||
| { | ||||
|   "id": "bike_monitoring_station", | ||||
|   "name": { | ||||
|     "en": "Monitoring stations" | ||||
|   }, | ||||
|   "minzoom": 12, | ||||
|   "overpassTags": { | ||||
|     "and": [ | ||||
|       "man_made=monitoring_station", | ||||
|       "monitoring:bicycle=yes" | ||||
|     ] | ||||
|   }, | ||||
|   "title": { | ||||
|     "render": { | ||||
|       "nl": "Fietstelstation", | ||||
|       "en": "Bicycle counting station" | ||||
|     }, | ||||
|     "mappings": [ | ||||
|       { | ||||
|         "if": "name~*", | ||||
|         "then": { | ||||
|           "en": "Bicycle counting station {name}", | ||||
|           "nl": "Fietstelstation {name}" | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
|         "if": "ref~*", | ||||
|         "then": { | ||||
|           "en": "Bicycle counting station {ref}", | ||||
|           "nl": "Fietstelstation {ref}" | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   "description": {}, | ||||
|   "tagRenderings": [ | ||||
|     { | ||||
|       "render": "<b>{live({url},{url:format},hour)}</b> cyclists last hour<br/><b>{live({url},{url:format},day)}</b> cyclists today<br/><b>{live({url},{url:format},year)}</b> cyclists this year<br/>", | ||||
|       "condition": { | ||||
|         "and": ["url~*","url:format~*"] | ||||
|       } | ||||
|     } | ||||
|   ], | ||||
|   "hideUnderlayingFeaturesMinPercentage": 0, | ||||
|   "icon": { | ||||
|     "render": "./assets/layers/bike_monitoring_station/monitoring_station.svg" | ||||
|   }, | ||||
|   "width": { | ||||
|     "render": "8" | ||||
|   }, | ||||
|   "iconSize": { | ||||
|     "render": "40,40,center" | ||||
|   }, | ||||
|   "color": { | ||||
|     "render": "#00f" | ||||
|   }, | ||||
|   "presets": [] | ||||
| } | ||||
							
								
								
									
										96
									
								
								assets/layers/bike_monitoring_station/monitoring_station.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								assets/layers/bike_monitoring_station/monitoring_station.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    id="svg27" | ||||
|    version="1.1" | ||||
|    fill="none" | ||||
|    viewBox="0 0 97 123" | ||||
|    height="123" | ||||
|    width="97"> | ||||
|   <metadata | ||||
|      id="metadata31"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <path | ||||
|      style="fill:#ffd42a" | ||||
|      id="path2" | ||||
|      fill="#5675DF" | ||||
|      d="M52.1412 111.419C50.4633 115.605 44.5366 115.605 42.8588 111.419L24.7014 66.1099C23.385 62.8252 25.8039 59.25 29.3426 59.25L65.6574 59.25C69.1962 59.25 71.615 62.8252 70.2986 66.11L52.1412 111.419Z" /> | ||||
|   <ellipse | ||||
|      style="fill:#ffd42a" | ||||
|      id="ellipse4" | ||||
|      fill="#5675DF" | ||||
|      ry="47.5" | ||||
|      rx="48.5" | ||||
|      cy="47.5" | ||||
|      cx="48.5" /> | ||||
|   <defs | ||||
|      id="defs25"> | ||||
|     <filter | ||||
|        color-interpolation-filters="sRGB" | ||||
|        filterUnits="userSpaceOnUse" | ||||
|        height="53.5" | ||||
|        width="40.7188" | ||||
|        y="25.5" | ||||
|        x="32.2812" | ||||
|        id="filter0_d"> | ||||
|       <feFlood | ||||
|          id="feFlood10" | ||||
|          result="BackgroundImageFix" | ||||
|          flood-opacity="0" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix12" | ||||
|          values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" | ||||
|          type="matrix" | ||||
|          in="SourceAlpha" /> | ||||
|       <feOffset | ||||
|          id="feOffset14" | ||||
|          dy="4" /> | ||||
|       <feGaussianBlur | ||||
|          id="feGaussianBlur16" | ||||
|          stdDeviation="2" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix18" | ||||
|          values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" | ||||
|          type="matrix" /> | ||||
|       <feBlend | ||||
|          id="feBlend20" | ||||
|          result="effect1_dropShadow" | ||||
|          in2="BackgroundImageFix" | ||||
|          mode="normal" /> | ||||
|       <feBlend | ||||
|          id="feBlend22" | ||||
|          result="shape" | ||||
|          in2="effect1_dropShadow" | ||||
|          in="SourceGraphic" | ||||
|          mode="normal" /> | ||||
|     </filter> | ||||
|   </defs> | ||||
|   <g | ||||
|      style="fill:#ffffff" | ||||
|      transform="matrix(0.1210062,0,0,0.1210062,13.583344,11.282657)" | ||||
|      id="g844"> | ||||
|     <path | ||||
|        d="m 464.99,141.27 c 0,0 8.996,9.05 15.346,0.017 l 12.1,-17.349 c 4.225,-6.103 -1.231,-10.327 -1.796,-10.744 l -73.41,-51.29 h -0.017 c -4.52,-3.145 -7.521,-1.236 -9.1,0.533 l -1.311,1.891 -11.181,16.01 c -0.053,0.061 -6.315,9.937 3.695,15.16 v 0.013 c 14.295,7.03 40.526,21.868 65.66,45.814 l 0.018,-0.051" | ||||
|        id="path838" /> | ||||
|     <path | ||||
|        d="M 341.45,0 H 225.76 c -8.978,0 -16.334,7.213 -16.334,16.338 v 13.484 c 0,9.112 7.356,16.468 16.334,16.468 h 5.725 v 9.521 c 0.009,13.688 8.648,14.825 12.985,14.534 0.737,-0.109 1.501,-0.226 2.308,-0.33 0.009,0 0.122,-0.026 0.122,-0.026 h -0.009 c 15.397,-2.108 40.9,-4.125 70.15,-0.403 l 0.017,-0.026 c 0,0 18.737,3.474 18.686,-13.758 v -9.52 h 5.725 c 8.987,0 16.325,-7.348 16.325,-16.473 V 16.338 C 357.7939,7.221 350.437,0 341.45,0" | ||||
|        id="path840" /> | ||||
|     <path | ||||
|        d="m 11,5.563 c -3.71,0 -6.719,3.01 -6.719,6.719 0,3.71 3.01,6.719 6.719,6.719 3.71,0 6.719,-3.01 6.719,-6.719 0,-3.711 -3.01,-6.719 -6.719,-6.719 m 0.1,2.938 c 0.542,0 1.06,0.107 1.553,0.318 0.493,0.212 0.918,0.496 1.275,0.854 0.358,0.358 0.644,0.782 0.855,1.275 0.212,0.493 0.316,1.011 0.316,1.553 0,0.542 -0.105,1.06 -0.316,1.553 -0.212,0.493 -0.498,0.918 -0.855,1.275 -0.358,0.358 -0.782,0.642 -1.275,0.854 -0.493,0.212 -1.011,0.318 -1.553,0.318 -0.597,0 -1.165,-0.125 -1.703,-0.377 C 8.859,15.872 8.401,15.516 8.022,15.058 7.998,15.023 7.987,14.984 7.989,14.941 7.991,14.898 8.006,14.863 8.034,14.836 l 0.713,-0.719 c 0.035,-0.031 0.079,-0.047 0.131,-0.047 0.056,0.007 0.095,0.028 0.119,0.063 0.253,0.33 0.564,0.585 0.932,0.766 0.368,0.181 0.759,0.27 1.172,0.27 0.361,0 0.707,-0.07 1.035,-0.211 0.328,-0.141 0.612,-0.331 0.852,-0.57 0.24,-0.24 0.43,-0.523 0.57,-0.852 0.141,-0.328 0.211,-0.672 0.211,-1.033 0,-0.361 -0.07,-0.705 -0.211,-1.033 -0.141,-0.328 -0.331,-0.612 -0.57,-0.852 -0.24,-0.24 -0.523,-0.43 -0.852,-0.57 -0.328,-0.141 -0.674,-0.211 -1.035,-0.211 -0.34,0 -0.666,0.06 -0.979,0.184 -0.312,0.123 -0.591,0.3 -0.834,0.529 l 0.715,0.719 c 0.108,0.104 0.131,0.224 0.072,0.359 -0.059,0.139 -0.161,0.209 -0.307,0.209 H 7.434 c -0.09,0 -0.168,-0.034 -0.234,-0.1 C 7.134,11.671 7.1,11.593 7.1,11.503 V 9.169 C 7.1,9.023 7.17,8.921 7.309,8.862 7.444,8.803 7.564,8.827 7.668,8.934 L 8.346,9.606 C 8.718,9.255 9.142,8.984 9.619,8.792 c 0.477,-0.193 0.97,-0.289 1.48,-0.289" | ||||
|        transform="matrix(35.45144,0,0,35.45144,-106.35,-106.35)" | ||||
|        id="path842" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.6 KiB | 
|  | @ -20,11 +20,11 @@ | |||
|   "icon": "./assets/themes/cyclofix/logo.svg", | ||||
|   "version": "0", | ||||
|   "startLat": 50.8465573, | ||||
|   | ||||
|   "defaultBackgroundId": "CartoDB.Voyager", | ||||
|   "startLon":  4.3516970, | ||||
|   "startZoom": 16, | ||||
|   "widenFactor": 0.05, | ||||
|   "socialImage": "./assets/themes/cyclofix/logo.svg", | ||||
|   "layers": ["bike_repair_station", "bike_cafes", "bike_shops", "drinking_water", "bike_parking","bike_themed_object"], | ||||
|   "layers": ["bike_repair_station", "bike_cafes", "bike_shops", "drinking_water", "bike_parking","bike_themed_object","bike_monitoring_station"], | ||||
|   "roamingRenderings": [] | ||||
| } | ||||
							
								
								
									
										15
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								test.ts
									
										
									
									
									
								
							|  | @ -1,15 +1,16 @@ | |||
| //*
 | ||||
| 
 | ||||
| 
 | ||||
| import {UIEventSource} from "./Logic/UIEventSource"; | ||||
| import OpeningHoursVisualization from "./UI/OhVisualization"; | ||||
| import LiveQueryHandler from "./Logic/Web/LiveQueryHandler"; | ||||
| import {VariableUiElement} from "./UI/Base/VariableUIElement"; | ||||
| 
 | ||||
| const oh = "Tu-Fr 09:00-17:00 'as usual'; mo off 'yyy'; su off 'xxx'" | ||||
| const tags = new UIEventSource<any>({opening_hours:oh}); | ||||
| new OpeningHoursVisualization(tags, 'opening_hours').AttachTo('maindiv') | ||||
| const source = LiveQueryHandler.FetchLiveData("https://data.mobility.brussels/bike/api/counts/?request=live&featureID=CJM90", | ||||
|     "hour:data.hour_cnt;day:data.day_cnt;year:data.year_cnt".split(";")) | ||||
| source.addCallback((data) => {console.log(data)}) | ||||
| new VariableUiElement(source.map(data => { | ||||
|     return ["Data is:", data.hour, "last hour;", data.day, "last day; ", data.year, "last year;"].join(" ") | ||||
| })).AttachTo('maindiv') | ||||
| 
 | ||||
| 
 | ||||
| window.setTimeout(() => {tags.data._country = "be"; }, 5000) | ||||
| /*/ | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue