b41c6ef476f68c72a19c741a1c93b48dab1890d2
[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         // OSM map
41         let layer_map = new ol.layer.Tile({
42                 source: new ol.source.OSM()
43         });
44
45
46         /*
47         // Microsoft Bing Maps
48         // let layer_map = new OpenLayers.Layer.Bing({
49         //      type: "Road",
50         //      key: "AgPH3SlIXAwajrJKf0FORQyhTqsP8KIlvtN6RKfvxe6fOB6q6-HFmg8EOFm7LSOA",
51         //      tileOptions: {crossOriginKeyword: null}});
52
53         // // Alternative: Base map
54         // // see: http://www.basemap.at
55         
56         // // Alternative: OpenTopoMap
57         // // see: https://opentopomap.org/about
58
59         // // Alternative: Dummy base layer
60         // let layer_map = new OpenLayers.Layer.Vector("Base Layer", {
61         //     isBaseLayer: true});
62         */
63
64
65         // path layer
66         // ----------
67
68         function get_feature_title(feature) {
69                 let title = feature.get('type');
70                 if (title == 'sledrun') return feature.get('name');
71                 title = title.charAt(0).toUpperCase() + title.slice(1); // first letter uppercase
72                 if (feature.get('name')) title += ': ' + feature.get('name');
73                 return title;
74         }
75
76         // Returns 0 to 5 for features that represent sledruns as their condition
77         let get_sledrun_condition = function(feature) {
78                 let condition = feature.get('condition');
79                 if (condition === undefined) return 0;
80                 return condition;
81         }
82
83         function style_point_function(feature, resolution) {
84                 if (feature.get('type') == 'sledrun') {
85                         let condition = get_sledrun_condition(feature);
86                         let src = img_path + '/marker_c_sledrun_' + condition + 'nn.png';
87                         let marker_style = new ol.style.Style({
88                                 image: new ol.style.Icon({
89                                         src: src,
90                                         imgSize: [17, 17],
91                                         anchor: [0.5, 0.5]
92                                 }),
93                         });
94                         let shadow_style = new ol.style.Style({
95                                 image: new ol.style.Icon({
96                                         src: img_path + '/marker_c_shadow.png',
97                                         imgSize: [23, 23],
98                                         anchor: [0.4, 0.4]
99                                 }),
100                         });
101                         return [shadow_style, marker_style];
102
103                 } else {
104                         let src = img_path + '/marker_p_' + feature.get('type') + '.png';
105                         let marker_style = new ol.style.Style({
106                                 image: new ol.style.Icon({
107                                         src: src,
108                                         imgSize: [20, 34],
109                                         anchor: [0.5, 1.0]
110                                 }),
111                         });
112                         return [marker_style];
113                 }
114         }
115
116         function style_point_function_highlight(feature, resolution) {
117                 let style_array = style_point_function(feature, resolution);
118                 style_array[0].setText(new ol.style.Text({
119                         text: get_feature_title(feature),
120                         font: 'icon',
121                         offsetY: 14,
122                         stroke: new ol.style.Stroke({
123                                 color: '#ddd',
124                                 width: 2,
125                         }),
126                 }));
127                 return style_array;
128         }
129
130         function style_path_function(feature, resolution) {
131                 let line_color = {
132                         'rodelbahn': '#014e9a',
133                         'gehweg': '#e98401',
134                         'alternative': '#7f7fff',
135                         'lift': '#000000',
136                         'anfahrt': '#e1e100'
137                 };
138                 let color = feature.get('strokeColor') || line_color[feature.get('type')] || '#e7525b';
139                 let width = (feature.get('type') in ['lift', 'anfahrt']) ? 3 : 6;
140                 return new ol.style.Style({
141                         stroke: new ol.style.Stroke({
142                                 color: color,
143                                 width: width
144                         })
145                 });
146         }
147
148         function style_function(feature, resolution) {
149                 if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function(feature, resolution);
150                 return style_path_function(feature, resolution);
151         };
152
153         function style_function_highlight(feature, resolution) {
154                 if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function_highlight(feature, resolution);
155                 return style_path_function(feature, resolution);
156         };
157
158
159         // popup overlay
160         // -------------
161         let popup_container = document.getElementById('popup');
162         let popup_content = document.getElementById('popup-content');
163         let popup_closer = document.getElementById('popup-closer');
164         let popup_overlay = new ol.Overlay({element: popup_container, autoPan: {animation: {duration: 250}}});
165         popup_closer.onclick = function() {popup_overlay.setPosition(undefined); popup_closer.blur(); return false;};
166
167         function create_popup_dom(feature) {
168                 let popup_div = createElement('div');
169
170                 // name
171                 if (feature.get('name') !== undefined && (feature.get('wiki') !== undefined || feature.get('thumb_url') !== undefined)) {
172                         let h2 = appendElement(popup_div, 'h2');
173                         if (feature.get('wiki') === undefined) h2.text(feature.get('name'));
174                         else appendElement(h2, 'a', {href: feature.get('wiki')}).text(feature.get('name'));
175                 }
176
177                 // sledrun information
178                 if (feature.get('type') == 'sledrun') {
179                         let p = appendElement(popup_div, 'p').text('Rodelbahnzustand').append(createElement('br'));
180                         if (feature.get('condition') !== undefined) {
181                                 let condition_text = {1: 'Sehr gut', 2: 'Gut', 3: 'Mittelmäßig', 4: 'Schlecht', 5: 'Geht nicht'};
182                                 let year_month_day = feature.get('date_report').split('-');
183                                 p.append(createElement('a', {href: feature.get('wiki') + '#Eintr.C3.A4ge'}).text(condition_text[feature.get('condition')]), ' ');
184                                 p.append(createElement('small').text(year_month_day[2] + '.' + year_month_day[1] + '.'), ' ');
185                                 p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Neu')));
186                         } else {
187                                 p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Bitte eintragen')));
188                         }
189                 }
190
191                 // wiki link
192                 if (feature.get('wiki') !== undefined) {
193                         let a = appendElement(appendElement(popup_div, 'p'), 'a', {href: feature.get('wiki')});
194                         let detail_text = 'Details';
195                         if (feature.get('type') == 'sledrun') detail_text += ' zur Rodelbahn';
196                         if (feature.get('type') == 'gasthaus') detail_text += ' zum Gasthaus';
197                         if (feature.get('thumb_url') === undefined) a.text(detail_text);
198                         else a.append(createElement('img', {src: feature.get('thumb_url'), alt: detail_text, title: detail_text}));
199                 }
200
201                 return popup_div;
202         }
203
204
205         // map itself
206         // ----------
207         let lon = json_js.properties.lon;
208         let lat = json_js.properties.lat;
209         let zoom = json_js.properties.zoom;
210         let width = json_js.properties.width;
211         let height = json_js.properties.height;
212         if (zoom === undefined) zoom = 10; // default zoom
213         if (width === undefined) width = '100%'; // default width
214         if (height === undefined) height = 450;  // default: 450 pixel
215         jq_map.width(width);
216         jq_map.height(height);
217
218         let layer_sledrun_source = new ol.source.Vector({features: features_all});
219         let layer_sledrun = new ol.layer.Vector({
220                 source: layer_sledrun_source,
221                 style: style_function
222         });
223
224         let map = new ol.Map({
225                 target: jq_map[0],
226                 layers: [
227                         layer_map,
228                         layer_sledrun
229                 ],
230                 overlays: [popup_overlay],
231                 view: new ol.View({
232                         center: ol.proj.fromLonLat([lon, lat]),
233                         zoom: zoom
234                 }),
235                 controls: ol.control.defaults({
236                         attributionOptions: {
237                                 collapsible: false
238                         }
239                 }),
240                 interactions: ol.interaction.defaults({
241                         mouseWheelZoom: false
242                 })
243         });
244
245
246         let select_hover = new ol.interaction.Select({
247                 condition: ol.events.condition.pointerMove,
248                 style: style_function_highlight,
249         });
250         map.addInteraction(select_hover);
251
252         let select_click = new ol.interaction.Select({
253                 condition: ol.events.condition.click,
254                 style: false,
255         });
256         map.addInteraction(select_click);
257         select_click.on('select', function(event) {
258                 if (event.selected.length > 0) {
259                         let feature = event.selected[0];
260                         let coordinates = feature.getGeometry().getCoordinates();
261                         let popup_dom = create_popup_dom(feature);
262                         if (popup_dom.children().length > 0) {
263                                 $(popup_content).empty().append(popup_dom);
264                                 popup_overlay.setPosition(coordinates);
265                         }
266                 }
267         });
268 }
269
270 function init_wrmaps() {
271         let jq_maps = $('.wrmap'); // all wrmap <div> elements
272         jq_maps.each(init_wrmap);
273 }
274
275
276 $(document).ready(init_wrmaps);
277