4e11557ca72379d99493664709c41f7fc815461d
[philipp/winterrodeln/mediawiki_extensions/wrmap.git] / wrmap.js
1 "use strict";
2
3 function init_wrmap(i, jq_map) {
4         // define constants
5         let EPSG4326 = ol.proj.get("EPSG:4326"); // lon/lat
6         let EPSG3857 = ol.proj.get("EPSG:3857"); // google
7
8         // tool functions
9         function createElement(tagName, attributes) {
10                 let element = $(document.createElement(tagName));
11                 if (attributes === undefined) return element;
12                 for (let attribute in attributes) {
13                         element.attr(attribute, attributes[attribute]);
14                 }
15                 return element;
16         }
17
18         function appendElement(parentElement, tagName, attributes) {
19                 if (attributes === undefined) attributes = {};
20                 let element = createElement(tagName, attributes);
21                 parentElement.append(element);
22                 return element;
23         }
24
25
26         // extract geojson from map element and clear map element's content
27         jq_map = $(jq_map);
28         let ext_path = jq_map.attr('data-ext-path'); // e.g. '/mediawiki/extensions/wrmap'
29         let img_path = ext_path + '/img';
30         let json_string = jq_map.children().last().text();
31         jq_map.empty(); // once parsed, remove geojson string from the map element.
32         let json_js = JSON.parse(json_string);
33         let format_geojson = new ol.format.GeoJSON();
34         let features_all = format_geojson.readFeatures(json_js, {dataProjection: EPSG4326, featureProjection: EPSG3857});
35
36
37         // background layer
38         // ----------------
39
40         let layer_map;
41
42         // OSM layer
43         layer_map = new ol.layer.Tile({
44                 source: new ol.source.OSM()
45         });
46
47         // basemap.at layer  // TODO: Currently this is a race condition
48         let capabilitiesUrl = 'https://www.basemap.at/wmts/1.0.0/WMTSCapabilities.xml';
49         fetch(capabilitiesUrl).then(function(response) {
50                 return response.text();
51         }).then(function(text) {
52                 let result = new ol.format.WMTSCapabilities().read(text);
53                 let options = ol.source.WMTS.optionsFromCapabilities(result, {
54                         layer: 'geolandbasemap',
55                         matrixSet: 'google3857',
56                         style: 'normal',
57                 });
58                 layer_map = new ol.layer.Tile({
59                         source: new ol.source.WMTS(options),
60                 });
61         });
62
63         /*
64         // Microsoft Bing Maps
65         // let layer_map = new OpenLayers.Layer.Bing({
66         //      type: "Road",
67         //      key: "AgPH3SlIXAwajrJKf0FORQyhTqsP8KIlvtN6RKfvxe6fOB6q6-HFmg8EOFm7LSOA",
68         //      tileOptions: {crossOriginKeyword: null}});
69
70         // // Alternative: Base map
71         // // see: https://www.basemap.at
72         
73         // // Alternative: OpenTopoMap
74         // // see: https://opentopomap.org/about
75
76         // // Alternative: Dummy base layer
77         // let layer_map = new OpenLayers.Layer.Vector("Base Layer", {
78         //     isBaseLayer: true});
79         */
80
81
82         // path layer
83         // ----------
84
85         function get_feature_title(feature) {
86                 let title = feature.get('type');
87                 if (title == 'sledrun') return feature.get('name');
88                 title = title.charAt(0).toUpperCase() + title.slice(1); // first letter uppercase
89                 if (feature.get('name')) title += ': ' + feature.get('name');
90                 return title;
91         }
92
93         // Returns 0 to 5 for features that represent sledruns as their condition
94         let get_sledrun_condition = function(feature) {
95                 let condition = feature.get('condition');
96                 if (condition === undefined) return 0;
97                 return condition;
98         }
99
100         function sledrun_icon_style(condition, highlight) {
101                 let hl = highlight ? 'h' : 'n';
102                 let src = img_path + '/marker_c_sledrun_' + condition + 'n' + hl + '.png';
103                 return new ol.style.Style({
104                         image: new ol.style.Icon({
105                                 src: src,
106                                 imgSize: [17, 17],
107                                 anchor: [0.5, 0.5]
108                         }),
109                 });
110
111         }
112
113         function sledrun_icon_shadow_style() {
114                 return new ol.style.Style({
115                         image: new ol.style.Icon({
116                                 src: img_path + '/marker_c_shadow.png',
117                                 imgSize: [23, 23],
118                                 anchor: [0.4, 0.4]
119                         }),
120                 });
121         }
122
123         function marker_icon_style(feature) {
124                 let src = img_path + '/marker_p_' + feature.get('type') + '.png';
125                 return new ol.style.Style({
126                         image: new ol.style.Icon({
127                                 src: src,
128                                 imgSize: [20, 34],
129                                 anchor: [0.5, 1.0]
130                         }),
131                 });
132         }
133
134         function point_style(feature, highlight) {
135                 let sledrun = feature.get('type') == 'sledrun';
136                 let icon_style;
137                 if (sledrun) {
138                         let condition = get_sledrun_condition(feature);
139                         icon_style = sledrun_icon_style(condition, highlight);
140                 } else icon_style = marker_icon_style(feature);
141                 if (highlight) {
142                         icon_style.setText(new ol.style.Text({
143                                 text: get_feature_title(feature),
144                                 font: 'icon',
145                                 offsetY: 14,
146                                 stroke: new ol.style.Stroke({
147                                         color: '#ddd',
148                                         width: 2,
149                                 }),
150                         }));
151                 }
152                 if (sledrun) {
153                         let shadow_style = sledrun_icon_shadow_style();
154                         return [shadow_style, icon_style];
155                 }
156                 return [icon_style];
157         }
158
159         function style_point_function(feature, resolution) {
160                 return point_style(feature, false);
161         }
162
163         function style_point_function_highlight(feature, resolution) {
164                 return point_style(feature, true);
165         }
166
167         function style_path_function(feature, resolution) {
168                 let line_color = {
169                         'rodelbahn': '#014e9a',
170                         'gehweg': '#e98401',
171                         'alternative': '#7f7fff',
172                         'lift': '#000000',
173                         'anfahrt': '#e1e100'
174                 };
175                 let color = feature.get('strokeColor') || line_color[feature.get('type')] || '#e7525b';
176                 let width = (feature.get('type') in ['lift', 'anfahrt']) ? 3 : 6;
177                 return new ol.style.Style({
178                         stroke: new ol.style.Stroke({
179                                 color: color,
180                                 width: width
181                         })
182                 });
183         }
184
185         function style_function(feature, resolution) {
186                 if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function(feature, resolution);
187                 return style_path_function(feature, resolution);
188         };
189
190         function style_function_highlight(feature, resolution) {
191                 if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function_highlight(feature, resolution);
192                 return style_path_function(feature, resolution);
193         };
194
195
196         // popup overlay
197         // -------------
198         let popup_container = document.getElementById('popup');
199         let popup_content = document.getElementById('popup-content');
200         let popup_closer = document.getElementById('popup-closer');
201         let popup_overlay = new ol.Overlay({element: popup_container, autoPan: {animation: {duration: 250}}});
202         popup_closer.onclick = function() {popup_overlay.setPosition(undefined); popup_closer.blur(); return false;};
203
204         function create_popup_dom(feature) {
205                 let popup_div = createElement('div');
206
207                 // name
208                 if (feature.get('name') !== undefined && (feature.get('wiki') !== undefined || feature.get('thumb_url') !== undefined)) {
209                         let h2 = appendElement(popup_div, 'h2');
210                         if (feature.get('wiki') === undefined) h2.text(feature.get('name'));
211                         else appendElement(h2, 'a', {href: feature.get('wiki')}).text(feature.get('name'));
212                 }
213
214                 // sledrun information
215                 if (feature.get('type') == 'sledrun') {
216                         let p = appendElement(popup_div, 'p').text('Rodelbahnzustand').append(createElement('br'));
217                         if (feature.get('condition') !== undefined) {
218                                 let condition_text = {1: 'Sehr gut', 2: 'Gut', 3: 'Mittelmäßig', 4: 'Schlecht', 5: 'Geht nicht'};
219                                 let year_month_day = feature.get('date_report').split('-');
220                                 p.append(createElement('a', {href: feature.get('wiki') + '#Eintr.C3.A4ge'}).text(condition_text[feature.get('condition')]), ' ');
221                                 p.append(createElement('small').text(year_month_day[2] + '.' + year_month_day[1] + '.'), ' ');
222                                 p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Neu')));
223                         } else {
224                                 p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Bitte eintragen')));
225                         }
226                 }
227
228                 // wiki link
229                 if (feature.get('wiki') !== undefined) {
230                         let a = appendElement(appendElement(popup_div, 'p'), 'a', {href: feature.get('wiki')});
231                         let detail_text = 'Details';
232                         if (feature.get('type') == 'sledrun') detail_text += ' zur Rodelbahn';
233                         if (feature.get('type') == 'gasthaus') detail_text += ' zum Gasthaus';
234                         if (feature.get('thumb_url') === undefined) a.text(detail_text);
235                         else a.append(createElement('img', {src: feature.get('thumb_url'), alt: detail_text, title: detail_text}));
236                 }
237
238                 return popup_div;
239         }
240
241
242         // map itself
243         // ----------
244         let lon = json_js.properties.lon;
245         let lat = json_js.properties.lat;
246         let zoom = json_js.properties.zoom;
247         let width = json_js.properties.width;
248         let height = json_js.properties.height;
249         if (zoom === undefined) zoom = 10; // default zoom
250         if (width === undefined) width = '100%'; // default width
251         if (height === undefined) height = 450;  // default: 450 pixel
252         jq_map.width(width);
253         jq_map.height(height);
254
255         let layer_sledrun_source = new ol.source.Vector({features: features_all});
256         let layer_sledrun = new ol.layer.Vector({
257                 source: layer_sledrun_source,
258                 style: style_function
259         });
260
261         let map = new ol.Map({
262                 target: jq_map[0],
263                 layers: [
264                         layer_map,
265                         layer_sledrun
266                 ],
267                 overlays: [popup_overlay],
268                 view: new ol.View({
269                         center: ol.proj.fromLonLat([lon, lat]),
270                         zoom: zoom
271                 }),
272                 controls: ol.control.defaults({
273                         attributionOptions: {
274                                 collapsible: false
275                         }
276                 }),
277                 interactions: ol.interaction.defaults({
278                         mouseWheelZoom: false
279                 })
280         });
281
282
283         let select_hover = new ol.interaction.Select({
284                 condition: ol.events.condition.pointerMove,
285                 style: style_function_highlight,
286         });
287         map.addInteraction(select_hover);
288
289         let select_click = new ol.interaction.Select({
290                 condition: ol.events.condition.click,
291                 style: false,
292         });
293         map.addInteraction(select_click);
294         select_click.on('select', function(event) {
295                 if (event.selected.length > 0) {
296                         let feature = event.selected[0];
297                         let coordinates = feature.getGeometry().getCoordinates();
298                         let popup_dom = create_popup_dom(feature);
299                         if (popup_dom.children().length > 0) {
300                                 $(popup_content).empty().append(popup_dom);
301                                 popup_overlay.setPosition(coordinates);
302                         }
303                 }
304         });
305 }
306
307 function init_wrmaps() {
308         let jq_maps = $('.wrmap'); // all wrmap <div> elements
309         jq_maps.each(init_wrmap);
310 }
311
312
313 $(document).ready(init_wrmaps);
314