X-Git-Url: https://git.toastfreeware.priv.at/philipp/winterrodeln/mediawiki_extensions/wrmap.git/blobdiff_plain/310084e4c888fed6a6a83815e28175adc1c5f010..1234fddc62ff7e34d1b5b7d2f5f613fc18e45ef1:/wrmap.js diff --git a/wrmap.js b/wrmap.js index 51ea34d..24d4b69 100644 --- a/wrmap.js +++ b/wrmap.js @@ -1,20 +1,36 @@ "use strict"; +/* +// "User defined" popup class to be able to specify a minimum size for the popup, +// so that Safari 7.0 displays it correctly (see ticket #89). +OpenLayers.Popup.WrInfo = OpenLayers.Class(OpenLayers.Popup.FramedCloud, { + minSize: new OpenLayers.Size(180, 260), + + initialize: function(id, lonlat, contentSize, contentHTML, anchor, closeBox, closeCallback) { + OpenLayers.Popup.FramedCloud.prototype.initialize.apply(this, arguments); + }, + + CLASS_NAME: "OpenLayers.Popup.WrInfo" +}); +*/ + function init_wrmap(i, jq_map) { // define constants - var EPSG4326 = new OpenLayers.Projection("EPSG:4326"); // lon/lat - var EPSG3857 = new OpenLayers.Projection("EPSG:3857"); // google + var EPSG4326 = ol.proj.get("EPSG:4326"); // lon/lat + var EPSG3857 = ol.proj.get("EPSG:3857"); // google // tool functions - function createElement(tagName, attributes={}) { + function createElement(tagName, attributes) { var element = $(document.createElement(tagName)); + if (attributes === undefined) return element; for (var attribute in attributes) { element.attr(attribute, attributes[attribute]); } return element; } - function appendElement(parentElement, tagName, attributes={}) { + function appendElement(parentElement, tagName, attributes) { + if (attributes === undefined) attributes = {}; var element = createElement(tagName, attributes); parentElement.append(element); return element; @@ -23,71 +39,184 @@ function init_wrmap(i, jq_map) { // extract geojson from map element and clear map element's content jq_map = $(jq_map); - OpenLayers.ImgPath = jq_map.attr('data-img-path'); // e.g. "/mediawiki/extensions/wrmap/openlayers/img/" + var ext_path = jq_map.attr('data-ext-path'); // e.g. '/mediawiki/extensions/wrmap' + var img_path = ext_path + '/img'; var json_string = jq_map.children().last().text(); jq_map.empty(); // once parsed, remove geojson string from the map element. - var format_json = new OpenLayers.Format.JSON(); - var json_js = format_json.read(json_string); - var format_geojson = new OpenLayers.Format.GeoJSON(); - var features_all = format_geojson.read(json_js); - - // extract, tranform and split features to layers - var features_path = new Array(); - var features_point = new Array(); - for (var i = 0; i != features_all.length; ++i) { - var feature = features_all[i]; - feature.geometry.transform(EPSG4326, EPSG3857); - if (feature.geometry instanceof OpenLayers.Geometry.Point) features_point.push(feature); - else features_path.push(feature); - } + var json_js = JSON.parse(json_string); + var format_geojson = new ol.format.GeoJSON(); + var features_all = format_geojson.readFeatures(json_js, {dataProjection: EPSG4326, featureProjection: EPSG3857}); // background layer // ---------------- - var layer_map = new OpenLayers.Layer.Google("Google Physical", { - type: google.maps.MapTypeId.TERRAIN + + // OSM map + var layer_map = new ol.layer.Tile({ + source: new ol.source.OSM() }); - // // Alternative: OSM map - // var layer_map = new OpenLayers.Layer.OSM(); - - // // Alternative: Microsoft Bing Maps + + /* + // Microsoft Bing Maps // var layer_map = new OpenLayers.Layer.Bing({ - // type: "Road", - // key: "AgPH3SlIXAwajrJKf0FORQyhTqsP8KIlvtN6RKfvxe6fOB6q6-HFmg8EOFm7LSOA"}); + // type: "Road", + // key: "AgPH3SlIXAwajrJKf0FORQyhTqsP8KIlvtN6RKfvxe6fOB6q6-HFmg8EOFm7LSOA", + // tileOptions: {crossOriginKeyword: null}}); + + // // Alternative: Base map + // // see: http://www.basemap.at + // // Alternative: OpenTopoMap + // // see: https://opentopomap.org/about + // // Alternative: Dummy base layer // var layer_map = new OpenLayers.Layer.Vector("Base Layer", { // isBaseLayer: true}); + */ + - // path layer // ---------- - var layer_path = new OpenLayers.Layer.Vector("Path", { - styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({ - strokeColor: '${getStrokeColor}', - strokeWidth: '${getStrokeWidth}' - }, { - context: { - getStrokeColor: function(feature) { - if (feature.attributes.strokeColor !== undefined) return feature.attributes.strokeColor; - if (feature.attributes.type == 'rodelbahn') return '#014e9a'; - if (feature.attributes.type == 'gehweg') return '#e98401'; - if (feature.attributes.type == 'alternative') return '#7f7fff'; - if (feature.attributes.type == 'lift') return '#000000'; - if (feature.attributes.type == 'anfahrt') return '#e1e100'; - return '#ee9900'; - }, - getStrokeWidth: function(feature) { - if (feature.attributes.strokeWidth !== undefined) return feature.attributes.strokeWidth; - if (feature.attributes.type == 'lift' || feature.attributes.type == 'anfahrt') return 3; - return 6; - } - } - })) - }); - + function get_feature_title(feature) { + var title = feature.get('type'); + if (title == 'sledrun') return feature.get('name'); + title = title.charAt(0).toUpperCase() + title.slice(1); // first letter uppercase + if (feature.get('name')) title += ': ' + feature.get('name'); + return title; + } + + // Returns 0 to 5 for features that represent sledruns as their condition + var get_sledrun_condition = function(feature) { + var condition = feature.get('condition'); + if (condition === undefined) return 0; + return condition; + } + + function style_point_function(feature, resolution) { + if (feature.get('type') == 'sledrun') { + let condition = get_sledrun_condition(feature); + let src = img_path + '/marker_c_sledrun_' + condition + 'nn.png'; + let marker_style = new ol.style.Style({ + image: new ol.style.Icon({ + src: src, + imgSize: [17, 17], + anchor: [0.5, 0.5] + }), + }); + let shadow_style = new ol.style.Style({ + image: new ol.style.Icon({ + src: img_path + '/marker_c_shadow.png', + imgSize: [23, 23], + anchor: [0.4, 0.4] + }), + }); + return [shadow_style, marker_style]; + + } else { + let src = img_path + '/marker_p_' + feature.get('type') + '.png'; + let marker_style = new ol.style.Style({ + image: new ol.style.Icon({ + src: src, + imgSize: [20, 34], + anchor: [0.5, 1.0] + }), + }); + return [marker_style]; + } + } + + function style_point_function_selected(feature, resolution) { + let style_array = style_point_function(feature, resolution); + style_array[0].setText(new ol.style.Text({ + text: get_feature_title(feature), + font: 'icon', + offsetY: 14, + stroke: new ol.style.Stroke({ + color: '#ddd', + width: 2, + }), + })); + return style_array; + } + + function style_path_function(feature, resolution) { + var line_color = { + 'rodelbahn': '#014e9a', + 'gehweg': '#e98401', + 'alternative': '#7f7fff', + 'lift': '#000000', + 'anfahrt': '#e1e100' + }; + var color = feature.get('strokeColor') || line_color[feature.get('type')] || '#e7525b'; + var width = (feature.get('type') in ['lift', 'anfahrt']) ? 3 : 6; + return new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: color, + width: width + }) + }); + } + + function style_function(feature, resolution) { + if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function(feature, resolution); + return style_path_function(feature, resolution); + }; + + function style_function_selected(feature, resolution) { + if (feature.getGeometry() instanceof ol.geom.Point) return style_point_function_selected(feature, resolution); + return style_path_function(feature, resolution); + }; + + + // popup overlay + // ------------- + var popup_container = document.getElementById('popup'); + var popup_content = document.getElementById('popup-content'); + var popup_closer = document.getElementById('popup-closer'); + var popup_overlay = new ol.Overlay({element: popup_container, autoPan: {animation: {duration: 250}}}); + popup_closer.onclick = function() {popup_overlay.setPosition(undefined); popup_closer.blur(); return false;}; + + function create_popup_dom(feature) { + var popup_div = createElement('div'); + + // name + if (feature.get('name') !== undefined && (feature.get('wiki') !== undefined || feature.get('thumb_url') !== undefined)) { + var h2 = appendElement(popup_div, 'h2'); + if (feature.get('wiki') === undefined) h2.text(feature.get('name')); + else appendElement(h2, 'a', {href: feature.get('wiki')}).text(feature.get('name')); + } + + // sledrun information + if (feature.get('type') == 'sledrun') { + var p = appendElement(popup_div, 'p').text('Rodelbahnzustand').append(createElement('br')); + if (feature.get('condition') !== undefined) { + var condition_text = {1: 'Sehr gut', 2: 'Gut', 3: 'MittelmäÃig', 4: 'Schlecht', 5: 'Geht nicht'}; + var year_month_day = feature.get('date_report').split('-'); + p.append(createElement('a', {href: feature.get('wiki') + '#Eintr.C3.A4ge'}).text(condition_text[feature.get('condition')]), ' '); + p.append(createElement('small').text(year_month_day[2] + '.' + year_month_day[1] + '.'), ' '); + p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Neu'))); + } else { + p.append(createElement('em').append(createElement('a', {href: feature.get('wiki') + '#Eintragen'}).text('Bitte eintragen'))); + } + } + + // wiki link + if (feature.get('wiki') !== undefined) { + var a = appendElement(appendElement(popup_div, 'p'), 'a', {href: feature.get('wiki')}); + var detail_text = 'Details'; + if (feature.get('type') == 'sledrun') detail_text += ' zur Rodelbahn'; + if (feature.get('type') == 'gasthaus') detail_text += ' zum Gasthaus'; + if (feature.get('thumb_url') === undefined) a.text(detail_text); + else a.append(createElement('img', {src: feature.get('thumb_url'), alt: detail_text, title: detail_text})); + } + + return popup_div; + } + + + /* // point layer // ----------- var filter_point_sledrun = new OpenLayers.Filter.Comparison({ @@ -96,6 +225,7 @@ function init_wrmap(i, jq_map) { value: 'sledrun' }); + var layer_point = new OpenLayers.Layer.Vector("Point", { styleMap: new OpenLayers.StyleMap({ 'default': new OpenLayers.Style({ @@ -105,10 +235,7 @@ function init_wrmap(i, jq_map) { context: { // the following context functions should only be available in the rule that uses them, // but the rule dependent contexts are ignored by OpenLayers (I think that's a bug) - getCondition: function(feature) { - if (feature.attributes.condition === undefined) return 0; - return feature.attributes.condition; - }, + getCondition: get_sledrun_condition, getSymbol: function(feature) { var name = feature.attributes.type; return name; @@ -118,12 +245,12 @@ function init_wrmap(i, jq_map) { new OpenLayers.Rule({ filter: filter_point_sledrun, symbolizer: { - externalGraphic: '/vorlagen/bahnzustand${getCondition}_0.png', + externalGraphic: img_path + '/marker_c_sledrun_${getCondition}nn.png', graphicWidth: 17, graphicHeight: 17, graphicXOffset: -8, graphicYOffset: -8, - backgroundGraphic: "/vorlagen/gmap_rodelbahn_c_s.png", + backgroundGraphic: img_path + '/marker_c_shadow.png', backgroundWidth: 23, backgroundHeight: 23, backgroundXOffset: -8, @@ -133,7 +260,7 @@ function init_wrmap(i, jq_map) { new OpenLayers.Rule({ elseFilter: true, symbolizer: { - externalGraphic: '/vorlagen/gmap_${getSymbol}.png', + externalGraphic: img_path + '/marker_p_${getSymbol}.png', graphicWidth: 20, graphicHeight: 34, graphicXOffset: -10, @@ -148,6 +275,7 @@ function init_wrmap(i, jq_map) { fontWeight: "bold" }, { context: { + getCondition: get_sledrun_condition, getTitle: function(feature) { var title = ''; if (feature.attributes.type != 'point') { @@ -164,7 +292,8 @@ function init_wrmap(i, jq_map) { filter: filter_point_sledrun, symbolizer: { label: "${name}", - labelYOffset: 14 + labelYOffset: 14, + externalGraphic: img_path + '/marker_c_sledrun_${getCondition}nh.png' } }), new OpenLayers.Rule({ @@ -174,12 +303,33 @@ function init_wrmap(i, jq_map) { } }) ] - }) + }), + select: new OpenLayers.Style({ + fillOpacity: 1. + }, { + context: { + getCondition: get_sledrun_condition, + }, + rules: [ + new OpenLayers.Rule({ + filter: filter_point_sledrun, + symbolizer: { + externalGraphic: img_path + '/marker_c_sledrun_${getCondition}nh.png', + backgroundGraphic: false, + graphicXOffset: -6, + graphicYOffset: -6 + } + }), + new OpenLayers.Rule({ + elseFilter: true + }) + ] + }) }), rendererOptions: {yOrdering: true} }); - +*/ // map itself // ---------- var lon = json_js.properties.lon; @@ -192,104 +342,58 @@ function init_wrmap(i, jq_map) { if (height === undefined) height = 450; // default: 450 pixel jq_map.width(width); jq_map.height(height); - var map = new OpenLayers.Map(jq_map.context, { - projection: EPSG3857, - displayProjection: EPSG4326, - units: "m", - theme: null, - layers: [layer_map, layer_path, layer_point], - center: new OpenLayers.LonLat(lon, lat).transform(EPSG4326, EPSG3857), - zoom: zoom + + var layer_sledrun_source = new ol.source.Vector({features: features_all}); + var layer_sledrun = new ol.layer.Vector({ + source: layer_sledrun_source, + style: style_function }); - - // add features - // if this would be done before the layer is added to the map, the features are not added - layer_path.addFeatures(features_path); - layer_point.addFeatures(features_point); - - // disable mouse wheel zoom - var navigation_control = map.getControlsByClass('OpenLayers.Control.Navigation')[0]; - navigation_control.disableZoomWheel(); - - // layer switcher - // map.addControl(new OpenLayers.Control.LayerSwitcher()); - - // print sledrun name when mouse moves over it - map.addControl(new OpenLayers.Control.SelectFeature(layer_point, { - hover: true, - highlightOnly: true, - autoActivate: true, - renderIntent: "highlight" - })); - - // show popup when user clicks on a sledrun icon - map.addControl(new OpenLayers.Control.SelectFeature(layer_point, { - autoActivate: true, - toggle: true, - onSelect: function(feature) { - var attr = feature.attributes; - var popup_div = createElement('div'); - - // name - if (attr.name !== undefined && (attr.wiki !== undefined || attr.thumb_url !== undefined)) { - var h2 = appendElement(popup_div, 'h2'); - if (attr.wiki === undefined) h2.text(attr.name); - else appendElement(h2, 'a', {href: attr.wiki}).text(attr.name); + var map = new ol.Map({ + target: jq_map[0], + layers: [ + layer_map, + layer_sledrun + ], + overlays: [popup_overlay], + view: new ol.View({ + center: ol.proj.fromLonLat([lon, lat]), + zoom: zoom + }), + controls: ol.control.defaults({ + attributionOptions: { + collapsible: false } + }), + interactions: ol.interaction.defaults({ + mouseWheelZoom: false + }) + }); - // sledrun information - if (attr.type == 'sledrun') { - var p = appendElement(popup_div, 'p').text('Rodelbahnzustand').append(createElement('br')); - if (attr.condition !== undefined) { - var condition_text = {1: 'Sehr gut', 2: 'Gut', 3: 'MittelmäÃig', 4: 'Schlecht', 5: 'Geht nicht'}; - var year_month_day = attr.date_report.split('-'); - p.append(createElement('a', {href: attr.wiki + '#Eintr.C3.A4ge'}).text(condition_text[attr.condition]), ' '); - p.append(createElement('small').text(year_month_day[2] + '.' + year_month_day[1] + '.'), ' '); - p.append(createElement('em').append(createElement('a', {href: attr.wiki + '#Eintragen'}).text('Neu'))); - } else { - p.append(createElement('em').append(createElement('a', {href: attr.wiki + '#Eintragen'}).text('Bitte eintragen'))); - } - } - // wiki link - if (attr.wiki !== undefined) { - var a = appendElement(appendElement(popup_div, 'p'), 'a', {href: attr.wiki}); - var detail_text = 'Details'; - if (attr.type == 'sledrun') detail_text += ' zur Rodelbahn'; - if (attr.type == 'gasthaus') detail_text += ' zum Gasthaus'; - if (attr.thumb_url === undefined) a.text(detail_text); - else a.append(createElement('img', {src: attr.thumb_url, alt: detail_text, title: detail_text})); - } + var select_hover = new ol.interaction.Select({ + condition: ol.events.condition.pointerMove, + style: style_function_selected, + }); + map.addInteraction(select_hover); - // no popup if we don't have anything to say - if (popup_div.children().length == 0) return; - - // Open popup - var selectFeatureControl = this; - var popup = new OpenLayers.Popup.FramedCloud('sledruninfopopup_' + attr.wiki, - feature.geometry.getBounds().getCenterLonLat(), - null, - popup_div.html(), - null, true, function(event) { - // onPopupClose - selectFeatureControl.unselectAll(); - }); - feature.popup = popup; - map.addPopup(popup); - }, - onUnselect: function(feature) { - if (feature.popup === null) return; - - // Close popup - map.removePopup(feature.popup); - feature.popup.destroy(); - feature.popup = null; + var select_click = new ol.interaction.Select({ + condition: ol.events.condition.click, + }); + map.addInteraction(select_click); + select_click.on('select', function(event) { + if (event.selected.length > 0) { + let feature = event.selected[0]; + let coordinates = feature.getGeometry().getCoordinates(); + let popup_dom = create_popup_dom(feature); + if (popup_dom.children().length > 0) { + $(popup_content).empty().append(popup_dom); + popup_overlay.setPosition(coordinates); + } } - })); + }); } - function init_wrmaps() { var jq_maps = $('.wrmap'); // all wrmap