// ==UserScript== // @name WME Geometries // @version 1.3 // @description Import geometry files into Waze Map Editor. Supports GeoJSON, GML, WKT, KML and GPX. // @include https://www.waze.com/*/editor* // @include https://www.waze.com/editor* // @include https://beta.waze.com/* // @exclude https://www.waze.com/*user/*editor/* // @grant none // @author Timbones // @contributor wlodek76 // @namespace https://greasyfork.org/users/3339 // @downloadURL none // ==/UserScript== /* Blah Blah Blah */ var geometries = function() { // maximum number of features that will be shown with labels var maxlabels = 2500; // show labels using first attribute that starts or ends with 'name' (case insensitive regexp) var labelname = /^name|name$/; // each loaded file will be rendered with one of these colours in ascending order var colorlist = [ "deepskyblue", "magenta", "limegreen", "orange", "teal", "grey" ]; // ------------------------------------------------------------- var geolist; var formathelp = 'GeoJSON, WKT'; var formats = { 'GEOJSON':new OL.Format.GeoJSON(), 'WKT':new OL.Format.WKT() }; patchOpenLayers(); // patch adds KML, GPX and TXT formats var EPSG_4326 = new OL.Projection("EPSG:4326"); // lat,lon var EPSG_4269 = new OL.Projection("EPSG:4269"); // NAD 83 var EPSG_3857 = new OL.Projection("EPSG:3857"); // WGS 84 var layerindex = 0; // delayed initialisation setTimeout(init, 654); W.loginManager.events.register("login", null, init); // add interface to Settings tab function init() { var geobox = document.createElement('div'); geobox.style.paddingTop = '6px'; console.log("WME Geometries: Initialising for Editor"); $("#sidepanel-areas").append(geobox); var geotitle = document.createElement('h4'); geotitle.innerHTML = 'Import Geometry File'; geobox.appendChild(geotitle); geolist = document.createElement('ul'); geobox.appendChild(geolist); var geoform = document.createElement('form'); geobox.appendChild(geoform); var inputfile = document.createElement('input'); inputfile.type = 'file'; inputfile.id = 'GeometryFile'; inputfile.title = '.geojson, .gml or .wkt'; inputfile.addEventListener('change', addGeometryLayer, false); geoform.appendChild(inputfile); var notes = document.createElement('p'); notes.innerHTML = 'Formats: ' + formathelp + '
' + 'Coordinates: EPSG:4326, EPSG:3857'; geoform.appendChild(notes); var inputadd = document.createElement('input'); inputadd.type = 'button'; inputadd.value = 'Clear All'; inputadd.onclick = removeGeometryLayers; geoform.appendChild(inputadd); console.log("WME Geometries initialised"); } // import selected file as a vector layer function addGeometryLayer() { // get the selected file from user var fileList = document.getElementById('GeometryFile'); file = fileList.files[0]; fileList.value = ''; var fileext = file.name.split('.').pop(); var filename = file.name.replace('.' + fileext, ''); fileext = fileext.toUpperCase(); // add list item color = colorlist[(layerindex++) % colorlist.length]; var fileitem = document.createElement('li'); fileitem.id = file.name; fileitem.style.color = color; fileitem.innerHTML = 'Loading...'; geolist.appendChild(fileitem); // check if format is supported var parser = formats[fileext]; if (typeof parser == 'undefined') { fileitem.innerHTML = fileext.toUpperCase() + ' format not supported :('; fileitem.style.color = 'red'; return; } parser.internalProjection = W.map.getProjectionObject(); parser.externalProjection = EPSG_4326; // add a new layer for the geometry var layerid = 'wme_geometry_'+layerindex; var WME_Geometry = new OL.Layer.Vector("Geometry: " + filename, { rendererOptions: { zIndexing: true }, uniqueName: layerid, shortcutKey: "S+" + layerindex, layerGroup: 'wme_geometry' } ); var layerStyle = { strokeColor: color, strokeOpacity: 0.75, strokeWidth: 3, fillColor: color, fillOpacity: 0.1, pointRadius: 6, fontColor: 'white', labelOutlineColor: color, labelOutlineWidth: 4, labelAlign: 'left' }; WME_Geometry.setZIndex(-9999); WME_Geometry.displayInLayerSwitcher = true; // hack in translation: I18n.translations[I18n.locale].layers.name[layerid] = "WME Geometries: " + filename; // read the file into the new layer var reader = new FileReader(); reader.onload = (function(theFile) { return function(e) { if (/"EPSG:3857"|:EPSG::3857"/.test(e.target.result)) { parser.externalProjection = EPSG_3857; } else if (/"EPSG:4269"|:EPSG::4269"/.test(e.target.result)) { parser.externalProjection = EPSG_4269; } // load geometry files var features = parser.read(e.target.result); // detect bad data if (features.length === 0) { fileitem.innerHTML = 'No features loaded :('; fileitem.style.color = 'red'; WME_Geometry.destroy(); return; } // check which attribute can be used for labels var labelwith = '(no labels)'; if (features.length <= maxlabels) { for (var attrib in features[0].attributes) { if (labelname.test(attrib.toLowerCase()) === true) { if (typeof features[0].attributes[attrib] == 'string') { labelwith = 'Labels: ' + attrib; layerStyle.label = '${'+attrib+'}'; break; } } } } WME_Geometry.styleMap = new OL.StyleMap(layerStyle); // add data to the map WME_Geometry.addFeatures(features); W.map.addLayer(WME_Geometry); fileitem.innerHTML = filename; fileitem.title = fileext.toUpperCase() + " " + parser.externalProjection.projCode + ": " + features.length + " features loaded\n" + labelwith; console.log("WME Geometries: Loaded " + fileitem.title); }; })(file); reader.readAsText(file); } // clear all function removeGeometryLayers() { var layers = W.map.getLayersBy("layerGroup","wme_geometry"); for (i = 0; i < layers.length; i++) { layers[i].destroy(); } geolist.innerHTML = ''; layerindex = 0; return false; } // ------------------------------------------------------------------------------------ // replace missing functions in OpenLayers 2.12 function patchOpenLayers() { if (OL.VERSION_NUMBER != 'Release 2.12') { console.log("WME Geometries: OpenLayers version mismatch - cannot apply patch"); return; } OL.Format.KML=OL.Class(OL.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date,extractAttributes:!0,kvpAttributes:!1,extractStyles:!1,extractTracks:!1,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(a){this.regExes= {trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,kmlColor:/(\w{2})(\w{2})(\w{2})(\w{2})/,kmlIconPalette:/root:\/\/icons\/palette-(\d+)(\.\w+)/,straightBracket:/\$\[(.*?)\]/g};this.externalProjection=new OL.Projection("EPSG:4326");OL.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){this.features=[];this.styles={};this.fetched={};return this.parseData(a,{depth:0,styleBaseUrl:this.styleBaseUrl})},parseData:function(a,b){"string"==typeof a&& (a=OL.Format.XML.prototype.read.apply(this,[a]));for(var c=["Link","NetworkLink","Style","StyleMap","Placemark"],d=0,e=c.length;d=this.maxDepth)return!1;var c=OL.Util.extend({},b);c.depth++;for(var d=0,e=a.length;d=e.length)){switch(e.length){case 1:f=e[0];break;case 2:f=e[0];e=e[1];f=3==f.nodeType||4==f.nodeType?f:e;break;default:f=e[1]}if(3==f.nodeType||4==f.nodeType)if(d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,f=OL.Util.getXmlNodeValue(f))f=f.replace(this.regExes.trimSpace,""),b[d]=f}return b},parseExtendedData:function(a){var b={},c,d,e,f,g=a.getElementsByTagName("Data");c=0;for(d=g.length;c0){parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection)}}else{throw new TypeError("Unsupported geometry type: "+type);}break}}var bounds;var boxNodes=this.getElementsByTagNameNS(node,this.gmlns,"Box");for(i=0;i0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,""); coords=coordString.split(this.regExes.splitSpace)}if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",")}}if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coord");if(nodeList.length>0){var xList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"X");var yList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"Y"); if(xList.length>0&&yList.length>0){coords=[xList[0].firstChild.nodeValue,yList[0].firstChild.nodeValue]}}}if(coords.length==2){coords[2]=null}if(this.xy){return new OL.Geometry.Point(coords[0],coords[1],coords[2])}else{return new OL.Geometry.Point(coords[1],coords[0],coords[2])}},multipoint:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Point");var components=[];if(nodeList.length>0){var point;for(var i=0;i0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);var dim=parseInt(nodeList[0].getAttribute("dimension"));var j,x,y,z;for(var i=0;i0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);for (var i=0;i0){var line;for(var i=0;i0){var ring;for(var i=0;i0){var polygon;for(var i=0;i0){var coords=[];if(lpoint.length>0){coordString=lpoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace)}if(coords.length==2){coords[2]=null}if(this.xy){var lowerPoint=new OL.Geometry.Point(coords[0],coords[1],coords[2])}else{var lowerPoint=new OL.Geometry.Point(coords[1],coords[0],coords[2])}}var upoint=this.getElementsByTagNameNS(node,this.gmlns,"upperCorner");if(upoint.length>0){var coords=[];if(upoint.length>0) {coordString=upoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace)}if(coords.length==2){coords[2]=null}if(this.xy){var upperPoint=new OL.Geometry.Point(coords[0],coords[1],coords[2])}else{var upperPoint=new OL.Geometry.Point(coords[1],coords[0],coords[2])}}if(lowerPoint&&upperPoint){components.push(new OL.Geometry.Point(lowerPoint.x,lowerPoint.y));components.push(new OL.Geometry.Point(upperPoint.x,lowerPoint.y)); components.push(new OL.Geometry.Point(upperPoint.x,upperPoint.y));components.push(new OL.Geometry.Point(lowerPoint.x,upperPoint.y));components.push(new OL.Geometry.Point(lowerPoint.x,lowerPoint.y));var ring=new OL.Geometry.LinearRing(components);envelope=new OL.Geometry.Polygon([ring])}return envelope},box:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");var coordString;var coords,beginPoint=null,endPoint=null;if(nodeList.length>0){coordString= nodeList[0].firstChild.nodeValue;coords=coordString.split(" ");if(coords.length==2){beginPoint=coords[0].split(",");endPoint=coords[1].split(",")}}if(beginPoint!==null&&endPoint!==null){return new OL.Bounds(parseFloat(beginPoint[0]),parseFloat(beginPoint[1]),parseFloat(endPoint[0]),parseFloat(endPoint[1]))}}},parseAttributes:function(node){var attributes={};var childNode=node.firstChild;var children,i,child,grandchildren,grandchild,name,value;while(childNode){if(childNode.nodeType==1){children=childNode.childNodes; for(i=0;iTXT'; formats.KML = new OL.Format.KML(); formats.GPX = new OL.Format.GPX(); formats.GML = new OL.Format.GML(); //formats.TXT = new OL.Format.Text(); } }; // ------------------------------------------------------------------------------------ // https://cdnjs.com/libraries/openlayers/2.12 function loadOLScript(filename) { var openlayers = document.createElement('script'); openlayers.src = "https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.12/" + filename + ".js"; openlayers.type = "text/javascript"; //openlayers.onload = geometries; document.head.appendChild(openlayers); } window.onload = geometries; // ------------------------------------------------------------------------------------