(function ($, OC) { 'use strict'; var gpxedit = { map: {}, baseLayers: null, id: 0, // indexed by gpxedit_id layersData: {} }; function load_map() { var layer = getUrlParameter('layer'); console.log('layer '+layer); var default_layer = 'OpenStreetMap'; if (typeof layer !== 'undefined'){ default_layer = decodeURI(layer); } // get url from key and layer type function geopUrl (key, layer, format) { return 'http://wxs.ign.fr/'+ key + '/wmts?LAYER=' + layer +'&EXCEPTIONS=text/xml&FORMAT='+(format?format:'image/jpeg') +'&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal' +'&TILEMATRIXSET=PM&TILEMATRIX={z}&TILECOL={x}&TILEROW={y}' ; } // change it if you deploy GPXEDIT var API_KEY = 'ljthe66m795pr2v2g8p7faxt'; var ign = new L.tileLayer ( geopUrl(API_KEY,'GEOGRAPHICALGRIDSYSTEMS.MAPS'), { attribution:'© IGN-France', maxZoom:18 }); var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; var osmAttribution = 'Map data © 2013 OpenStreetMap contributors'; var osm = new L.TileLayer(osmUrl, {maxZoom: 18, attribution: osmAttribution}); var osmfrUrl = 'http://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png'; var osmfr = new L.TileLayer(osmfrUrl, {maxZoom: 20, attribution: osmAttribution}); var osmfr2 = new L.TileLayer(osmfrUrl, {minZoom: 0, maxZoom: 13, attribution: osmAttribution}); var openmapsurferUrl = 'http://openmapsurfer.uni-hd.de/tiles/roads/'+ 'x={x}&y={y}&z={z}'; var openmapsurferAttribution = 'Imagery from GIScience Research Group @ University of Heidelberg — '+ 'Map data © '+ 'OpenStreetMap'; var openmapsurfer = new L.TileLayer(openmapsurferUrl, {maxZoom: 18, attribution: openmapsurferAttribution}); var transportUrl = 'http://a.tile2.opencyclemap.org/transport/{z}/{x}/{y}.'+ 'png'; var transport = new L.TileLayer(transportUrl, {maxZoom: 18, attribution: osmAttribution}); var pisteUrl = 'http://tiles.openpistemap.org/nocontours/{z}/{x}/{y}.png'; var piste = new L.TileLayer(pisteUrl, {maxZoom: 18, attribution: osmAttribution}); var hikebikeUrl = 'http://toolserver.org/tiles/hikebike/{z}/{x}/{y}.png'; var hikebike = new L.TileLayer(hikebikeUrl, {maxZoom: 18, attribution: osmAttribution}); var osmCycleUrl = 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png'; var osmCycleAttrib = '© '+ 'OpenCycleMap, © '+ 'OpenStreetMap'; var osmCycle = new L.TileLayer(osmCycleUrl, {maxZoom: 18, attribution: osmCycleAttrib}); var darkUrl = 'http://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png'; var darkAttrib = '© Map tiles by CartoDB, under CC BY 3.0. Data by'+ ' OpenStreetMap, under ODbL.'; var dark = new L.TileLayer(darkUrl, {maxZoom: 18, attribution: darkAttrib}); var esriTopoUrl = 'https://server.arcgisonline.com/ArcGIS/rest/services/World'+ '_Topo_Map/MapServer/tile/{z}/{y}/{x}'; var esriTopoAttrib = 'Tiles © Esri — Esri, DeLorme, NAVTEQ, '+ 'TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ord'+ 'nance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User'+ ' Community'; var esriTopo = new L.TileLayer(esriTopoUrl, {maxZoom: 18, attribution: esriTopoAttrib}); var esriAerialUrl = 'https://server.arcgisonline.com/ArcGIS/rest/services'+ '/World_Imagery/MapServer/tile/{z}/{y}/{x}'; var esriAerialAttrib = 'Tiles © Esri — Source: Esri, i-cubed, '+ 'USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the'+ ' GIS User Community'; var esriAerial = new L.TileLayer(esriAerialUrl, {maxZoom: 18, attribution: esriAerialAttrib}); var tonerUrl = 'http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.jpg'; var stamenAttribution = 'Leaflet | © Map tiles by Stamen Design, under CC BY 3.0, Data by OpenSt'+ 'reetMap, under CC BY SA.'; var toner = new L.TileLayer(tonerUrl, {maxZoom: 18, attribution: stamenAttribution}); var watercolorUrl = 'http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg'; var watercolor = new L.TileLayer(watercolorUrl, {maxZoom: 18, attribution: stamenAttribution}); var routeUrl = 'http://{s}.tile.openstreetmap.fr/route500/{z}/{x}/{y}.png'; var routeAttrib = '©, Tiles © O'+ 'penStreetMap France'; var route = new L.TileLayer(routeUrl, {minZoom: 1, maxZoom: 20, attribution: routeAttrib}); var baseLayers = { 'OpenStreetMap': osm, 'OpenCycleMap': osmCycle, 'IGN France': ign, 'OpenMapSurfer Roads': openmapsurfer, 'Hike & bike': hikebike, 'OSM Transport': transport, 'ESRI Aerial': esriAerial, 'ESRI Topo with relief': esriTopo, 'Dark' : dark, 'Toner' : toner, 'Watercolor' : watercolor, 'OpenStreetMap France': osmfr }; gpxedit.baseLayers = baseLayers; var baseOverlays = { 'OsmFr Route500': route, 'OpenPisteMap Relief': L.tileLayer('http://tiles2.openpistemap.org/landshaded/{z}/{x}/{y}.png', { attribution: '©, Tiles © OpenStreetMap France', minZoom: 1, maxZoom: 15 } ), 'OpenPisteMap pistes' : piste }; var layerlist = []; gpxedit.map = new L.Map('map', { zoomControl: true, layers: layerlist, }); L.control.scale({metric: true, imperial: true, position:'topleft'}) .addTo(gpxedit.map); L.control.mousePosition().addTo(gpxedit.map); gpxedit.searchControl = L.Control.geocoder({position:'topleft'}); gpxedit.searchControl.addTo(gpxedit.map); gpxedit.locateControl = L.control.locate({follow:true}); gpxedit.locateControl.addTo(gpxedit.map); L.Control.measureControl().addTo(gpxedit.map); L.control.sidebar('sidebar').addTo(gpxedit.map); gpxedit.map.setView(new L.LatLng(27, 5), 3); if (! baseLayers.hasOwnProperty(default_layer)){ default_layer = 'OpenStreetMap'; } gpxedit.map.addLayer(baseLayers[default_layer]); gpxedit.activeLayers = L.control.activeLayers(baseLayers, baseOverlays); gpxedit.activeLayers.addTo(gpxedit.map); gpxedit.minimapControl = new L.Control.MiniMap( osmfr2, { toggleDisplay: true, position:'bottomright' } ).addTo(gpxedit.map); gpxedit.minimapControl._toggleDisplayButtonClicked(); //gpxedit.map.on('moveend',updateTrackListFromBounds); //gpxedit.map.on('zoomend',updateTrackListFromBounds); //gpxedit.map.on('baselayerchange',updateTrackListFromBounds); gpxedit.editableLayers = new L.FeatureGroup(); gpxedit.map.addLayer(gpxedit.editableLayers); var options = { position: 'bottomleft', draw: { polyline: { shapeOptions: { color: '#f357a1', weight: 7 } }, polygon:false, circle: false, rectangle:false, marker: { icon: L.divIcon({ className: 'leaflet-div-icon2', iconAnchor: [5, 30] }) } }, edit: { featureGroup: gpxedit.editableLayers, //REQUIRED!! } }; var drawControl = new L.Control.Draw(options); gpxedit.map.addControl(drawControl); // when something is created, we generate popup content // and initialize layer data gpxedit.map.on(L.Draw.Event.CREATED, function (e) { onCreated(e.layerType, e.layer); }); // not used for the moment gpxedit.map.on('draw:edited', function (e) { var layers = e.layers; layers.eachLayer(function (layer) { }); }); // remove data associated with the deleted layer gpxedit.map.on('draw:deleted', function (e) { var layers = e.layers; layers.eachLayer(function (layer) { delete gpxedit.layersData[layer.gpxedit_id]; }); }); // load data into popup when it opens // this is needed because popup content is created each time we open one // so, the content is lost when it's closed gpxedit.map.on('popupopen', function(e){ var id = parseInt(e.popup.getContent().match(/layerid="(\d+)"/)[1]); var buttonParent = $('button.popupOkButton[layerid='+id+']').parent(); buttonParent.find('input.layerName').val(gpxedit.layersData[id].name); buttonParent.find('textarea.layerDesc').val(gpxedit.layersData[id].description); buttonParent.find('textarea.layerCmt').val(gpxedit.layersData[id].comment); }); } // called when something is drawn by hand or when a gpx is loaded // it generates the popup content and initializes the layer's data // it returns the layer in case we want to set the layer's data manually (when loading a gpx) function onCreated(type, layer){ var popupTitle = 'Track'; if (type === 'marker') { popupTitle = 'Waypoint'; } layer.bindPopup('

'+popupTitle+'

'+ ''+ ''+ '
Name
Description
Comment
'+ ''); layer.gpxedit_id = gpxedit.id; layer.type = type; gpxedit.layersData[gpxedit.id] = {name:'', description:'', comment:'', layer: layer}; gpxedit.editableLayers.addLayer(layer); gpxedit.id++; return layer; } function getUrlParameter(sParam) { var sPageURL = window.location.search.substring(1); var sURLVariables = sPageURL.split('&'); for (var i = 0; i < sURLVariables.length; i++) { var sParameterName = sURLVariables[i].split('='); if (sParameterName[0] === sParam) { return sParameterName[1]; } } } // generate gpx text from current map elements function generateGpx(){ var gpxText = '\n'; var now = new Date(); var now_utc_str = now.getUTCFullYear()+'-'+ ("0" + now.getUTCMonth()).slice(-2)+'-'+ ("0" + now.getUTCDate()).slice(-2)+'T'+ ("0" + now.getUTCHours()).slice(-2)+':'+ ("0" + now.getUTCMinutes()).slice(-2)+':'+ ("0" + now.getUTCSeconds()).slice(-2)+'Z'; gpxText = gpxText + '\n'; gpxText = gpxText + '\n\n\n'; gpxedit.editableLayers.eachLayer(function(layer){ var id = layer.gpxedit_id; var name = gpxedit.layersData[id].name; var comment = gpxedit.layersData[id].comment; var description = gpxedit.layersData[id].description; if (layer.type === 'marker'){ var lat = layer._latlng.lat; var lng = layer._latlng.lng; gpxText = gpxText + ' \n'; if (name){ gpxText = gpxText + ' '+name+'\n'; } else{ gpxText = gpxText + ' unnamed\n'; } if (comment){ gpxText = gpxText + ' '+comment+'\n'; } if (description){ gpxText = gpxText + ' '+description+'\n'; } gpxText = gpxText + ' \n'; } else{ gpxText = gpxText + ' \n'; if (name){ gpxText = gpxText + ' '+name+'\n'; } else{ gpxText = gpxText + ' unnamed\n'; } if (comment){ gpxText = gpxText + ' '+comment+'\n'; } if (description){ gpxText = gpxText + ' '+description+'\n'; } gpxText = gpxText + ' \n'; for (var i=0; i\n'+ ' \n'; } gpxText = gpxText + ' \n \n'; } }); gpxText = gpxText + ' \n'; return gpxText; } // adds a marker and initialize its data function drawMarker(latlng, name, desc, cmt){ // to add a marker var m = L.marker(latlng, { icon: L.divIcon({ className: 'leaflet-div-icon2', iconAnchor: [5, 30] }) }); var layer = onCreated('marker', m); m.bindTooltip(name, {sticky:true}); gpxedit.layersData[layer.gpxedit_id].name = name; gpxedit.layersData[layer.gpxedit_id].comment = cmt; gpxedit.layersData[layer.gpxedit_id].description = desc; } // adds a polyline and initialize its data function drawLine(latlngs, name, desc, cmt){ var p = L.polyline(latlngs, { color: '#f357a1', weight: 7 }); var layer = onCreated('polyline', p); p.bindTooltip(name, {sticky:true}); gpxedit.layersData[layer.gpxedit_id].name = name; gpxedit.layersData[layer.gpxedit_id].comment = cmt; gpxedit.layersData[layer.gpxedit_id].description = desc; } // parse gpx xml text to draw it on the map function parseGpx(xml){ var dom = $.parseXML(xml); $(dom).find('wpt').each(function(){ var lat = $(this).attr('lat'); var lon = $(this).attr('lon'); var name = $(this).find('name').text(); var cmt = $(this).find('cmt').text(); var desc = $(this).find('desc').text(); drawMarker([lat, lon], name, desc, cmt); }); $(dom).find('trk').each(function(){ var latlngs = []; var name = $(this).find('name').text(); var cmt = $(this).find('cmt').text(); var desc = $(this).find('desc').text(); $(this).find('trkseg').each(function(){ $(this).find('trkpt').each(function(){ var lat = $(this).attr('lat'); var lon = $(this).attr('lon'); latlngs.push([lat,lon]); }); }); drawLine(latlngs, name, desc, cmt); }); } // remove layers from map and delete all layers data function clear(){ var layersToRemove = []; gpxedit.editableLayers.eachLayer(function (layer) { delete gpxedit.layersData[layer.gpxedit_id]; layersToRemove.push(layer); }); for(var i=0; i'+message); $('#failed').fadeIn(); setTimeout(hideFailedSuccessAnimation, 4000); } function hideFailedSuccessAnimation(){ $('#failed').fadeOut(); } function showSaveSuccessAnimation(path){ $('#saved').find('b#content').html('File successfully saved as
'+path); //$('#saved').show(); $('#saved').fadeIn(); setTimeout(hideSaveSuccessAnimation, 4000); } function hideSaveSuccessAnimation(){ $('#saved').fadeOut(); } function loadFile(file){ var req = { path : file } var url = OC.generateUrl('/apps/gpxedit/getgpx'); $.post(url, req).done(function (response) { clear(); if (response.gpx === ''){ alert('The file does not exist or it is not a gpx'); } else{ parseGpx(response.gpx); var bounds = gpxedit.editableLayers.getBounds(); gpxedit.map.fitBounds(bounds, {animate:true, paddingTopLeft: [parseInt($('#sidebar').css('width')), 0]} ); } }); } $(document).ready(function(){ gpxedit.username = $('p#username').html(); load_map(); document.onkeydown = checkKey; $('body').on('click','button.popupOkButton', function(e) { var id = parseInt($(this).attr('layerid')); var name = $(this).parent().find('.layerName').val(); var description = $(this).parent().find('.layerDesc').val(); var comment = $(this).parent().find('.layerCmt').val(); gpxedit.layersData[id].name = name; gpxedit.layersData[id].description = description; gpxedit.layersData[id].comment = comment; gpxedit.layersData[id].layer.bindTooltip(name, {sticky:true}); gpxedit.map.closePopup(); }); $('button#clearButton').click(function(e){ clear(); }); $('button#saveButton').click(function(e){ var gpxText = generateGpx(); var nbExpanded = $('#savetree li.expanded').length; if (nbExpanded == 0){ var saveFilePath = '/'+$('input#saveName').val(); } else{ var saveFilePath = gpxedit.savePath+'/'+$('input#saveName').val(); } var req = { path: saveFilePath, content: gpxText } var url = OC.generateUrl('/apps/gpxedit/savegpx'); $.post(url, req).done(function (response) { if (response.status === 'fiw'){ showFailedSuccessAnimation(saveFilePath, 'Impossible to write file : write access denied'); } else if (response.status === 'fu'){ showFailedSuccessAnimation(saveFilePath, 'Impossible to write file : folder does not exist'); } else if (response.status === 'fw'){ showFailedSuccessAnimation(saveFilePath, 'Impossible to write file : folder write access denied'); } else if (response.status === 'bfn'){ showFailedSuccessAnimation(saveFilePath, 'Bad file name, must end with ".gpx"'); } else{ showSaveSuccessAnimation(saveFilePath); } }); }); var treeurl = OC.generateUrl('/apps/gpxedit/getdircontent'); $('#loadtree').fileTree({root: '/', script: treeurl, multiFolder: false }, function(file) { gpxedit.fileToLoad = file; loadFile(file); // set save name var spl = file.split('/'); var basename = spl[spl.length-1]; $('input#saveName').val(basename); }); var savetreeurl = OC.generateUrl('/apps/gpxedit/getdircontentdir'); $('#savetree').fileTree({root: '/', script: savetreeurl, multiFolder: false, onlyFolders: true }, function(file) { }); $('#savetree').on('filetreeexpand', function(e, data){ gpxedit.savePath = data.rel; $('#savetree a').removeClass('selectedFolder'); data.li.find('>a').addClass('selectedFolder'); }); $('#savetree').on('filetreecollapse', function(e, data){ gpxedit.savePath = data.li.parent().parent().find('>a').attr('rel'); data.li.find('li.expanded').removeClass('expanded'); data.li.find('>a').removeClass('selectedFolder'); data.li.parent().parent().find('>a').addClass('selectedFolder'); }); $('body').on('click','h2#loadtitle', function(e) { if ($('#loaddiv').is(':visible')){ $('#loaddiv').slideUp(); $('#loadoptiontoggle').html(''); } else{ $('#loaddiv').slideDown(); $('#loadoptiontoggle').html(''); } }); $('body').on('click','h2#savetitle', function(e) { if ($('#savediv').is(':visible')){ $('#savediv').slideUp(); $('#saveoptiontoggle').html(''); } else{ $('#savediv').slideDown(); $('#saveoptiontoggle').html(''); } }); }); })(jQuery, OC);