├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── debug └── map.html ├── dist ├── Leaflet.Coordinates-0.1.5.css ├── Leaflet.Coordinates-0.1.5.ie.css ├── Leaflet.Coordinates-0.1.5.min.js └── Leaflet.Coordinates-0.1.5.src.js ├── examples └── demo.html ├── package.json ├── spec ├── Grunt.Helper.js ├── Number.Formatter.Spec.js └── SpecRunner.html └── src ├── Control.Coordinates.css ├── Control.Coordinates.ie.css ├── Control.Coordinates.js └── util └── NumberFormatter.js /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | build/ 196 | eggs/ 197 | parts/ 198 | var/ 199 | sdist/ 200 | develop-eggs/ 201 | .installed.cfg 202 | 203 | # Installer logs 204 | pip-log.txt 205 | 206 | # Unit test / coverage reports 207 | .coverage 208 | .tox 209 | 210 | #Translations 211 | *.mo 212 | 213 | #Mr Developer 214 | .mr.developer.cfg 215 | 216 | #Node 217 | node_modules 218 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | pkg: grunt.file.readJSON('package.json'), 8 | clean: { 9 | all: { 10 | src: ['dist/**/*'] 11 | } 12 | }, 13 | concat: { 14 | options: { 15 | separator: '' 16 | }, 17 | dist: { 18 | src: ['src/**/*.js'], 19 | dest: 'dist/<%= pkg.name%>-<%= pkg.version%>.src.js' 20 | } 21 | }, 22 | uglify: { 23 | options: { 24 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' 25 | }, 26 | dist: { 27 | files: { 28 | 'dist/<%= pkg.name %>-<%= pkg.version%>.min.js': ['<%= concat.dist.dest %>'] 29 | } 30 | } 31 | }, 32 | cssmin: { 33 | combine: { 34 | files: { 35 | 'dist/<%= pkg.name %>-<%= pkg.version%>.css': ['src/Control.Coordinates.css'], 36 | 'dist/<%= pkg.name %>-<%= pkg.version%>.ie.css': ['src/Control.Coordinates.ie.css'] 37 | } 38 | }, 39 | minify: { 40 | expand: true, 41 | cwd: 'dist/', 42 | src: ['*.css', '!*.min.css'], 43 | dest: 'dist/' 44 | } 45 | }, 46 | csslint: { 47 | strict: { 48 | options: { 49 | import: 2, 50 | 'adjoining-classes': false 51 | }, 52 | src: ['src/**/*.css'] 53 | } 54 | }, 55 | jasmine: { 56 | pivotal: { 57 | src: [ 58 | 'src/**/*.js' 59 | ], 60 | options: { 61 | specs: 'spec/*Spec.js', 62 | helpers: 'spec/*Helper.js', 63 | vendor: [ 64 | 'http://cdn.leafletjs.com/leaflet-0.5.1/leaflet-src.js' 65 | ], 66 | '--local-to-remote-url-access': true 67 | } 68 | } 69 | }, 70 | jshint: { 71 | // define the files to lint 72 | files: ['src/**/*.js'], 73 | // configure JSHint (documented at http://www.jshint.com/docs/) 74 | options: { 75 | // more options here if you want to override JSHint defaults 76 | globals: { 77 | console: true, 78 | module: true 79 | } 80 | } 81 | }, 82 | connect: { 83 | server: { 84 | options: { 85 | port: 9001, 86 | base: 'spec' 87 | } 88 | } 89 | } 90 | 91 | }); 92 | 93 | grunt.loadNpmTasks('grunt-contrib-uglify'); 94 | grunt.loadNpmTasks('grunt-contrib-concat'); 95 | grunt.loadNpmTasks('grunt-contrib-clean'); 96 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 97 | grunt.loadNpmTasks('grunt-contrib-jshint'); 98 | grunt.loadNpmTasks('grunt-contrib-csslint'); 99 | grunt.loadNpmTasks('grunt-contrib-jasmine'); 100 | grunt.loadNpmTasks('grunt-contrib-connect'); 101 | 102 | // Default task(s). 103 | grunt.registerTask('default', ['clean', 'jshint', 'connect', 'jasmine', 'csslint', 'concat', 'uglify', 'cssmin']); 104 | 105 | grunt.registerTask('test', ['connect', 'jasmine']); 106 | 107 | }; 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This work is licensed under a Creative Commons Attribution 3.0 Unported License. 2 | http://creativecommons.org/licenses/by/3.0 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Leaflet.Coordinates 2 | =================== 3 | 4 | ### What is this? 5 | A [Leaflet](https://github.com/Leaflet/Leaflet) plugin to view mouse coordinates. Also the user can change the coordinates and get a marker on that position viewing the coordinates. 6 | 7 | *Tested with Leaflet 0.5+* 8 | 9 | 10 | 11 | 12 | 13 | ### Demo anyone? 14 | [Have a look](http://mrmufflon.github.io/Leaflet.Coordinates/examples/demo.html) 15 | 16 | ### How to use? 17 | ```javascript 18 | L.control.coordinates({ 19 | position:"bottomleft", //optional default "bootomright" 20 | decimals:2, //optional default 4 21 | decimalSeperator:".", //optional default "." 22 | labelTemplateLat:"Latitude: {y}", //optional default "Lat: {y}" 23 | labelTemplateLng:"Longitude: {x}", //optional default "Lng: {x}" 24 | enableUserInput:true, //optional default true 25 | useDMS:false, //optional default false 26 | useLatLngOrder: true, //ordering of labels, default false-> lng-lat 27 | markerType: L.marker, //optional default L.marker 28 | markerProps: {}, //optional default {}, 29 | labelFormatterLng : function(lng){return lng+" lng"}, //optional default none, 30 | labelFormatterLat : function(lat){return lat+" lat"}, //optional default none 31 | customLabelFcn: function(latLonObj, opts) { "Geohash: " + encodeGeoHash(latLonObj.lat, latLonObj.lng)} //optional default none 32 | }).addTo(map); 33 | ``` 34 | 35 | ### Releases 36 | - [0.1.3](https://github.com/MrMufflon/Leaflet.Coordinates/tree/0.1.3) 37 | - [0.1.2](https://github.com/MrMufflon/Leaflet.Coordinates/tree/0.1.2) 38 | - [0.1.1](https://github.com/MrMufflon/Leaflet.Coordinates/tree/0.1.1) 39 | - [0.1.0](https://github.com/MrMufflon/Leaflet.Coordinates/tree/0.1.0) 40 | 41 | ### License 42 | Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License. 43 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Leaflet.Coordinates", 3 | "version": "0.1.5", 4 | "homepage": "https://github.com/MrMufflon/Leaflet.Coordinates", 5 | "authors": [ 6 | "MrMufflon" 7 | ], 8 | "description": "A Leaflet plugin to view coordinates", 9 | "main": [ 10 | "dist/Leaflet.Coordinates-0.1.5.min.js", 11 | "dist/Leaflet.Coordinates-0.1.5.css" 12 | ], 13 | "keywords": [ 14 | "Leaflet", 15 | "Coorniates", 16 | "map" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ], 26 | "dependencies": { 27 | "leaflet": "0.7.x" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /debug/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Coordinate viewing test page 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /dist/Leaflet.Coordinates-0.1.5.css: -------------------------------------------------------------------------------- 1 | .leaflet-control-coordinates{background-color:#D8D8D8;background-color:rgba(255,255,255,.8);cursor:pointer}.leaflet-control-coordinates,.leaflet-control-coordinates .uiElement input{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.leaflet-control-coordinates .uiElement{margin:4px}.leaflet-control-coordinates .uiElement .labelFirst{margin-right:4px}.leaflet-control-coordinates .uiHidden{display:none}.leaflet-control-coordinates .uiElement.label{color:inherit;font-weight:inherit;font-size:inherit;padding:0;display:inherit} -------------------------------------------------------------------------------- /dist/Leaflet.Coordinates-0.1.5.ie.css: -------------------------------------------------------------------------------- 1 | .leaflet-control-coordinates{background-color:#D8D8D8} -------------------------------------------------------------------------------- /dist/Leaflet.Coordinates-0.1.5.min.js: -------------------------------------------------------------------------------- 1 | /*! leaflet.coordinates 07-12-2016 */ 2 | L.Control.Coordinates=L.Control.extend({options:{position:"bottomright",decimals:4,decimalSeperator:".",labelTemplateLat:"Lat: {y}",labelTemplateLng:"Lng: {x}",labelFormatterLat:void 0,labelFormatterLng:void 0,enableUserInput:!0,useDMS:!1,useLatLngOrder:!1,centerUserCoordinates:!1,markerType:L.marker,markerProps:{}},onAdd:function(a){this._map=a;var b="leaflet-control-coordinates",c=this._container=L.DomUtil.create("div",b),d=this.options;this._labelcontainer=L.DomUtil.create("div","uiElement label",c),this._label=L.DomUtil.create("span","labelFirst",this._labelcontainer),this._inputcontainer=L.DomUtil.create("div","uiElement input uiHidden",c);var e,f;return d.useLatLngOrder?(f=L.DomUtil.create("span","",this._inputcontainer),this._inputY=this._createInput("inputY",this._inputcontainer),e=L.DomUtil.create("span","",this._inputcontainer),this._inputX=this._createInput("inputX",this._inputcontainer)):(e=L.DomUtil.create("span","",this._inputcontainer),this._inputX=this._createInput("inputX",this._inputcontainer),f=L.DomUtil.create("span","",this._inputcontainer),this._inputY=this._createInput("inputY",this._inputcontainer)),e.innerHTML=d.labelTemplateLng.replace("{x}",""),f.innerHTML=d.labelTemplateLat.replace("{y}",""),L.DomEvent.on(this._inputX,"keyup",this._handleKeypress,this),L.DomEvent.on(this._inputY,"keyup",this._handleKeypress,this),a.on("mousemove",this._update,this),a.on("dragstart",this.collapse,this),a.whenReady(this._update,this),this._showsCoordinates=!0,d.enableUserInput&&L.DomEvent.addListener(this._container,"click",this._switchUI,this),c},_createInput:function(a,b){var c=L.DomUtil.create("input",a,b);return c.type="text",L.DomEvent.disableClickPropagation(c),c},_clearMarker:function(){this._map.removeLayer(this._marker)},_handleKeypress:function(a){switch(a.keyCode){case 27:this.collapse();break;case 13:this._handleSubmit(),this.collapse();break;default:this._handleSubmit()}},_handleSubmit:function(){var a=L.NumberFormatter.createValidNumber(this._inputX.value,this.options.decimalSeperator),b=L.NumberFormatter.createValidNumber(this._inputY.value,this.options.decimalSeperator);if(void 0!==a&&void 0!==b){var c=this._marker;c||(c=this._marker=this._createNewMarker(),c.on("click",this._clearMarker,this));var d=new L.LatLng(b,a);c.setLatLng(d),c.addTo(this._map),this.options.centerUserCoordinates&&this._map.setView(d,this._map.getZoom())}},expand:function(){this._showsCoordinates=!1,this._map.off("mousemove",this._update,this),L.DomEvent.addListener(this._container,"mousemove",L.DomEvent.stop),L.DomEvent.removeListener(this._container,"click",this._switchUI,this),L.DomUtil.addClass(this._labelcontainer,"uiHidden"),L.DomUtil.removeClass(this._inputcontainer,"uiHidden")},_createCoordinateLabel:function(a){var b,c,d=this.options;return d.customLabelFcn?d.customLabelFcn(a,d):(b=d.labelFormatterLng?d.labelFormatterLng(a.lng):L.Util.template(d.labelTemplateLng,{x:this._getNumber(a.lng,d)}),c=d.labelFormatterLat?d.labelFormatterLat(a.lat):L.Util.template(d.labelTemplateLat,{y:this._getNumber(a.lat,d)}),d.useLatLngOrder?c+" "+b:b+" "+c)},_getNumber:function(a,b){var c;return c=b.useDMS?L.NumberFormatter.toDMS(a):L.NumberFormatter.round(a,b.decimals,b.decimalSeperator)},collapse:function(){if(!this._showsCoordinates){this._map.on("mousemove",this._update,this),this._showsCoordinates=!0;this.options;if(L.DomEvent.addListener(this._container,"click",this._switchUI,this),L.DomEvent.removeListener(this._container,"mousemove",L.DomEvent.stop),L.DomUtil.addClass(this._inputcontainer,"uiHidden"),L.DomUtil.removeClass(this._labelcontainer,"uiHidden"),this._marker){var a=this._createNewMarker(),b=this._marker.getLatLng();a.setLatLng(b);var c=L.DomUtil.create("div",""),d=L.DomUtil.create("div","",c);d.innerHTML=this._ordinateLabel(b);var e=L.DomUtil.create("a","",c);e.innerHTML="Remove",e.href="#";var f=L.DomEvent.stopPropagation;L.DomEvent.on(e,"click",f).on(e,"mousedown",f).on(e,"dblclick",f).on(e,"click",L.DomEvent.preventDefault).on(e,"click",function(){this._map.removeLayer(a)},this),a.bindPopup(c),a.addTo(this._map),this._map.removeLayer(this._marker),this._marker=null}}},_switchUI:function(a){L.DomEvent.stop(a),L.DomEvent.stopPropagation(a),L.DomEvent.preventDefault(a),this._showsCoordinates?this.expand():this.collapse()},onRemove:function(a){a.off("mousemove",this._update,this)},_update:function(a){var b=a.latlng,c=this.options;b&&(b=b.wrap(),this._currentPos=b,this._inputY.value=L.NumberFormatter.round(b.lat,c.decimals,c.decimalSeperator),this._inputX.value=L.NumberFormatter.round(b.lng,c.decimals,c.decimalSeperator),this._label.innerHTML=this._createCoordinateLabel(b))},_createNewMarker:function(){return this.options.markerType(null,this.options.markerProps)}}),L.control.coordinates=function(a){return new L.Control.Coordinates(a)},L.Map.mergeOptions({coordinateControl:!1}),L.Map.addInitHook(function(){this.options.coordinateControl&&(this.coordinateControl=new L.Control.Coordinates,this.addControl(this.coordinateControl))}),L.NumberFormatter={round:function(a,b,c){var d=L.Util.formatNum(a,b)+"",e=d.split(".");if(e[1]){for(var f=b-e[1].length;f>0;f--)e[1]+="0";d=e.join(c||".")}return d},toDMS:function(a){var b=Math.floor(Math.abs(a)),c=60*(Math.abs(a)-b),d=Math.floor(c),e=60*(c-d),f=Math.round(e);60==f&&(d++,f="00"),60==d&&(b++,d="00"),10>f&&(f="0"+f),10>d&&(d="0"+d);var g="";return 0>a&&(g="-"),""+g+b+"° "+d+"' "+f+"''"},createValidNumber:function(a,b){if(a&&a.length>0){var c=a.split(b||".");try{var d=Number(c.join("."));return isNaN(d)?void 0:d}catch(e){return void 0}}return void 0}}; -------------------------------------------------------------------------------- /dist/Leaflet.Coordinates-0.1.5.src.js: -------------------------------------------------------------------------------- 1 | /* 2 | * L.Control.Coordinates is used for displaying current mouse coordinates on the map. 3 | */ 4 | 5 | L.Control.Coordinates = L.Control.extend({ 6 | options: { 7 | position: 'bottomright', 8 | //decimals used if not using DMS or labelFormatter functions 9 | decimals: 4, 10 | //decimalseperator used if not using DMS or labelFormatter functions 11 | decimalSeperator: ".", 12 | //label templates for usage if no labelFormatter function is defined 13 | labelTemplateLat: "Lat: {y}", 14 | labelTemplateLng: "Lng: {x}", 15 | //label formatter functions 16 | labelFormatterLat: undefined, 17 | labelFormatterLng: undefined, 18 | //switch on/off input fields on click 19 | enableUserInput: true, 20 | //use Degree-Minute-Second 21 | useDMS: false, 22 | //if true lat-lng instead of lng-lat label ordering is used 23 | useLatLngOrder: false, 24 | //if true user given coordinates are centered directly 25 | centerUserCoordinates: false, 26 | //leaflet marker type 27 | markerType: L.marker, 28 | //leaflet marker properties 29 | markerProps: {} 30 | }, 31 | 32 | onAdd: function(map) { 33 | this._map = map; 34 | 35 | var className = 'leaflet-control-coordinates', 36 | container = this._container = L.DomUtil.create('div', className), 37 | options = this.options; 38 | 39 | //label containers 40 | this._labelcontainer = L.DomUtil.create("div", "uiElement label", container); 41 | this._label = L.DomUtil.create("span", "labelFirst", this._labelcontainer); 42 | 43 | 44 | //input containers 45 | this._inputcontainer = L.DomUtil.create("div", "uiElement input uiHidden", container); 46 | var xSpan, ySpan; 47 | if (options.useLatLngOrder) { 48 | ySpan = L.DomUtil.create("span", "", this._inputcontainer); 49 | this._inputY = this._createInput("inputY", this._inputcontainer); 50 | xSpan = L.DomUtil.create("span", "", this._inputcontainer); 51 | this._inputX = this._createInput("inputX", this._inputcontainer); 52 | } else { 53 | xSpan = L.DomUtil.create("span", "", this._inputcontainer); 54 | this._inputX = this._createInput("inputX", this._inputcontainer); 55 | ySpan = L.DomUtil.create("span", "", this._inputcontainer); 56 | this._inputY = this._createInput("inputY", this._inputcontainer); 57 | } 58 | xSpan.innerHTML = options.labelTemplateLng.replace("{x}", ""); 59 | ySpan.innerHTML = options.labelTemplateLat.replace("{y}", ""); 60 | 61 | L.DomEvent.on(this._inputX, 'keyup', this._handleKeypress, this); 62 | L.DomEvent.on(this._inputY, 'keyup', this._handleKeypress, this); 63 | 64 | //connect to mouseevents 65 | map.on("mousemove", this._update, this); 66 | map.on('dragstart', this.collapse, this); 67 | 68 | map.whenReady(this._update, this); 69 | 70 | this._showsCoordinates = true; 71 | //wether or not to show inputs on click 72 | if (options.enableUserInput) { 73 | L.DomEvent.addListener(this._container, "click", this._switchUI, this); 74 | } 75 | 76 | return container; 77 | }, 78 | 79 | /** 80 | * Creates an input HTML element in given container with given classname 81 | */ 82 | _createInput: function(classname, container) { 83 | var input = L.DomUtil.create("input", classname, container); 84 | input.type = "text"; 85 | L.DomEvent.disableClickPropagation(input); 86 | return input; 87 | }, 88 | 89 | _clearMarker: function() { 90 | this._map.removeLayer(this._marker); 91 | }, 92 | 93 | /** 94 | * Called onkeyup of input fields 95 | */ 96 | _handleKeypress: function(e) { 97 | switch (e.keyCode) { 98 | case 27: //Esc 99 | this.collapse(); 100 | break; 101 | case 13: //Enter 102 | this._handleSubmit(); 103 | this.collapse(); 104 | break; 105 | default: //All keys 106 | this._handleSubmit(); 107 | break; 108 | } 109 | }, 110 | 111 | /** 112 | * Called on each keyup except ESC 113 | */ 114 | _handleSubmit: function() { 115 | var x = L.NumberFormatter.createValidNumber(this._inputX.value, this.options.decimalSeperator); 116 | var y = L.NumberFormatter.createValidNumber(this._inputY.value, this.options.decimalSeperator); 117 | if (x !== undefined && y !== undefined) { 118 | var marker = this._marker; 119 | if (!marker) { 120 | marker = this._marker = this._createNewMarker(); 121 | marker.on("click", this._clearMarker, this); 122 | } 123 | var ll = new L.LatLng(y, x); 124 | marker.setLatLng(ll); 125 | marker.addTo(this._map); 126 | if (this.options.centerUserCoordinates) { 127 | this._map.setView(ll, this._map.getZoom()); 128 | } 129 | } 130 | }, 131 | 132 | /** 133 | * Shows inputs fields 134 | */ 135 | expand: function() { 136 | this._showsCoordinates = false; 137 | 138 | this._map.off("mousemove", this._update, this); 139 | 140 | L.DomEvent.addListener(this._container, "mousemove", L.DomEvent.stop); 141 | L.DomEvent.removeListener(this._container, "click", this._switchUI, this); 142 | 143 | L.DomUtil.addClass(this._labelcontainer, "uiHidden"); 144 | L.DomUtil.removeClass(this._inputcontainer, "uiHidden"); 145 | }, 146 | 147 | /** 148 | * Creates the label according to given options and formatters 149 | */ 150 | _createCoordinateLabel: function(ll) { 151 | var opts = this.options, 152 | x, y; 153 | if (opts.customLabelFcn) { 154 | return opts.customLabelFcn(ll, opts); 155 | } 156 | if (opts.labelFormatterLng) { 157 | x = opts.labelFormatterLng(ll.lng); 158 | } else { 159 | x = L.Util.template(opts.labelTemplateLng, { 160 | x: this._getNumber(ll.lng, opts) 161 | }); 162 | } 163 | if (opts.labelFormatterLat) { 164 | y = opts.labelFormatterLat(ll.lat); 165 | } else { 166 | y = L.Util.template(opts.labelTemplateLat, { 167 | y: this._getNumber(ll.lat, opts) 168 | }); 169 | } 170 | if (opts.useLatLngOrder) { 171 | return y + " " + x; 172 | } 173 | return x + " " + y; 174 | }, 175 | 176 | /** 177 | * Returns a Number according to options (DMS or decimal) 178 | */ 179 | _getNumber: function(n, opts) { 180 | var res; 181 | if (opts.useDMS) { 182 | res = L.NumberFormatter.toDMS(n); 183 | } else { 184 | res = L.NumberFormatter.round(n, opts.decimals, opts.decimalSeperator); 185 | } 186 | return res; 187 | }, 188 | 189 | /** 190 | * Shows coordinate labels after user input has ended. Also 191 | * displays a marker with popup at the last input position. 192 | */ 193 | collapse: function() { 194 | if (!this._showsCoordinates) { 195 | this._map.on("mousemove", this._update, this); 196 | this._showsCoordinates = true; 197 | var opts = this.options; 198 | L.DomEvent.addListener(this._container, "click", this._switchUI, this); 199 | L.DomEvent.removeListener(this._container, "mousemove", L.DomEvent.stop); 200 | 201 | L.DomUtil.addClass(this._inputcontainer, "uiHidden"); 202 | L.DomUtil.removeClass(this._labelcontainer, "uiHidden"); 203 | 204 | if (this._marker) { 205 | var m = this._createNewMarker(), 206 | ll = this._marker.getLatLng(); 207 | m.setLatLng(ll); 208 | 209 | var container = L.DomUtil.create("div", ""); 210 | var label = L.DomUtil.create("div", "", container); 211 | label.innerHTML = this._ordinateLabel(ll); 212 | 213 | var close = L.DomUtil.create("a", "", container); 214 | close.innerHTML = "Remove"; 215 | close.href = "#"; 216 | var stop = L.DomEvent.stopPropagation; 217 | 218 | L.DomEvent 219 | .on(close, 'click', stop) 220 | .on(close, 'mousedown', stop) 221 | .on(close, 'dblclick', stop) 222 | .on(close, 'click', L.DomEvent.preventDefault) 223 | .on(close, 'click', function() { 224 | this._map.removeLayer(m); 225 | }, this); 226 | 227 | m.bindPopup(container); 228 | m.addTo(this._map); 229 | this._map.removeLayer(this._marker); 230 | this._marker = null; 231 | } 232 | } 233 | }, 234 | 235 | /** 236 | * Click callback for UI 237 | */ 238 | _switchUI: function(evt) { 239 | L.DomEvent.stop(evt); 240 | L.DomEvent.stopPropagation(evt); 241 | L.DomEvent.preventDefault(evt); 242 | if (this._showsCoordinates) { 243 | //show textfields 244 | this.expand(); 245 | } else { 246 | //show coordinates 247 | this.collapse(); 248 | } 249 | }, 250 | 251 | onRemove: function(map) { 252 | map.off("mousemove", this._update, this); 253 | }, 254 | 255 | /** 256 | * Mousemove callback function updating labels and input elements 257 | */ 258 | _update: function(evt) { 259 | var pos = evt.latlng, 260 | opts = this.options; 261 | if (pos) { 262 | pos = pos.wrap(); 263 | this._currentPos = pos; 264 | this._inputY.value = L.NumberFormatter.round(pos.lat, opts.decimals, opts.decimalSeperator); 265 | this._inputX.value = L.NumberFormatter.round(pos.lng, opts.decimals, opts.decimalSeperator); 266 | this._label.innerHTML = this._createCoordinateLabel(pos); 267 | } 268 | }, 269 | 270 | _createNewMarker: function() { 271 | return this.options.markerType(null, this.options.markerProps); 272 | } 273 | 274 | }); 275 | 276 | //constructor registration 277 | L.control.coordinates = function(options) { 278 | return new L.Control.Coordinates(options); 279 | }; 280 | 281 | //map init hook 282 | L.Map.mergeOptions({ 283 | coordinateControl: false 284 | }); 285 | 286 | L.Map.addInitHook(function() { 287 | if (this.options.coordinateControl) { 288 | this.coordinateControl = new L.Control.Coordinates(); 289 | this.addControl(this.coordinateControl); 290 | } 291 | }); 292 | L.NumberFormatter = { 293 | round: function(num, dec, sep) { 294 | var res = L.Util.formatNum(num, dec) + "", 295 | numbers = res.split("."); 296 | if (numbers[1]) { 297 | var d = dec - numbers[1].length; 298 | for (; d > 0; d--) { 299 | numbers[1] += "0"; 300 | } 301 | res = numbers.join(sep || "."); 302 | } 303 | return res; 304 | }, 305 | 306 | toDMS: function(deg) { 307 | var d = Math.floor(Math.abs(deg)); 308 | var minfloat = (Math.abs(deg) - d) * 60; 309 | var m = Math.floor(minfloat); 310 | var secfloat = (minfloat - m) * 60; 311 | var s = Math.round(secfloat); 312 | if (s == 60) { 313 | m++; 314 | s = "00"; 315 | } 316 | if (m == 60) { 317 | d++; 318 | m = "00"; 319 | } 320 | if (s < 10) { 321 | s = "0" + s; 322 | } 323 | if (m < 10) { 324 | m = "0" + m; 325 | } 326 | var dir = ""; 327 | if (deg < 0) { 328 | dir = "-"; 329 | } 330 | return ("" + dir + d + "° " + m + "' " + s + "''"); 331 | }, 332 | 333 | createValidNumber: function(num, sep) { 334 | if (num && num.length > 0) { 335 | var numbers = num.split(sep || "."); 336 | try { 337 | var numRes = Number(numbers.join(".")); 338 | if (isNaN(numRes)) { 339 | return undefined; 340 | } 341 | return numRes; 342 | } catch (e) { 343 | return undefined; 344 | } 345 | } 346 | return undefined; 347 | } 348 | }; -------------------------------------------------------------------------------- /examples/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Leaflet.Coordinates Demo Page 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaflet.coordinates", 3 | "version": "0.1.5", 4 | "description": "A Leaflet plugin to view coordinates", 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-uglify": "~0.2.2", 8 | "grunt-contrib-concat": "~0.3.0", 9 | "grunt-contrib-clean": "~0.4.1", 10 | "grunt-contrib-cssmin": "~0.6.1", 11 | "grunt-contrib-csslint": "~0.1.2", 12 | "grunt-contrib-jshint": "~0.11.1", 13 | "grunt-contrib-connect": "~0.10", 14 | "grunt-contrib-jasmine": "~0.8", 15 | "jasmine": "~2.0" 16 | }, 17 | "dependencies": {}, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/MrMufflon/Leaflet.Coordinates.git" 21 | }, 22 | "main": "dist/Leaflet.Coordinates-0.1.5.src.js", 23 | "keywords": [ 24 | "gis", 25 | "coordinates", 26 | "leaflet", 27 | "map", 28 | "sdi" 29 | ], 30 | "author": "Felix Bache", 31 | "licenses": [{ 32 | "type": "CC BY 3", 33 | "url": "http://creativecommons.org/licenses/by/3.0/" 34 | }], 35 | "readmeFilename": "README.md", 36 | "gitHead": "3b5c7d7af4f735c9bb2a925aa0c4a839f61bb470", 37 | "bugs": { 38 | "url": "https://github.com/MrMufflon/Leaflet.Coordinates/issues" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spec/Grunt.Helper.js: -------------------------------------------------------------------------------- 1 | window.baseUrl = "http://localhost:9001"; -------------------------------------------------------------------------------- /spec/Number.Formatter.Spec.js: -------------------------------------------------------------------------------- 1 | describe('Number.Formatter', function() { 2 | var nf = L.NumberFormatter; 3 | it("formatts 9.27 correctly to DMS 9° 16' 12''", function() { 4 | expect(nf.toDMS(9.27)).toEqual("9° 16' 12''"); 5 | }); 6 | it("formatts -9.27 correctly to DMS -9° 16' 12''", function() { 7 | expect(nf.toDMS(-9.27)).toEqual("-9° 16' 12''"); 8 | }); 9 | it("formatts -9.1461 correctly to DMS -9° 08' 46''", function() { 10 | expect(nf.toDMS(-9.1461)).toEqual("-9° 08' 46''"); 11 | }); 12 | it("rounds -9.27334 correctly on 2 decimals with , seperator to -9,27", function() { 13 | expect(nf.round(-9.27334, 2, ",")).toEqual("-9,27"); 14 | }); 15 | it("rounds 9.27334 correctly on 4 decimals with , seperator to 9,2733", function() { 16 | expect(nf.round(9.27334, 4, ",")).toEqual("9,2733"); 17 | }); 18 | it("rounds 9.27394 correctly on 3 decimals with . seperator to 9.274", function() { 19 | expect(nf.round(9.27394, 3, ".")).toEqual("9.274"); 20 | }); 21 | it("rounds -9.27394 correctly on 3 decimals with . seperator to -9.274", function() { 22 | expect(nf.round(-9.27394, 3, ".")).toEqual("-9.274"); 23 | }); 24 | }); -------------------------------------------------------------------------------- /spec/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | Jasmine Spec Runner v2.0.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Control.Coordinates.css: -------------------------------------------------------------------------------- 1 | 2 | .leaflet-control-coordinates { 3 | background-color:#D8D8D8; 4 | background-color:rgba(255, 255, 255, 0.8); 5 | cursor:pointer; 6 | } 7 | .leaflet-control-coordinates, 8 | .leaflet-control-coordinates .uiElement input { 9 | -webkit-border-radius:5px; 10 | -moz-border-radius:5px; 11 | border-radius:5px; 12 | } 13 | 14 | .leaflet-control-coordinates .uiElement { 15 | margin:4px; 16 | } 17 | 18 | .leaflet-control-coordinates .uiElement .labelFirst { 19 | margin-right:4px; 20 | } 21 | 22 | .leaflet-control-coordinates .uiHidden{ 23 | display:none; 24 | } 25 | 26 | .leaflet-control-coordinates .uiElement.label { 27 | color:inherit; 28 | font-weight: inherit; 29 | font-size: inherit; 30 | padding: 0; 31 | display: inherit; 32 | } 33 | -------------------------------------------------------------------------------- /src/Control.Coordinates.ie.css: -------------------------------------------------------------------------------- 1 | 2 | .leaflet-control-coordinates { 3 | background-color:#D8D8D8; 4 | } -------------------------------------------------------------------------------- /src/Control.Coordinates.js: -------------------------------------------------------------------------------- 1 | /* 2 | * L.Control.Coordinates is used for displaying current mouse coordinates on the map. 3 | */ 4 | 5 | L.Control.Coordinates = L.Control.extend({ 6 | options: { 7 | position: 'bottomright', 8 | //decimals used if not using DMS or labelFormatter functions 9 | decimals: 4, 10 | //decimalseperator used if not using DMS or labelFormatter functions 11 | decimalSeperator: ".", 12 | //label templates for usage if no labelFormatter function is defined 13 | labelTemplateLat: "Lat: {y}", 14 | labelTemplateLng: "Lng: {x}", 15 | //label formatter functions 16 | labelFormatterLat: undefined, 17 | labelFormatterLng: undefined, 18 | //switch on/off input fields on click 19 | enableUserInput: true, 20 | //use Degree-Minute-Second 21 | useDMS: false, 22 | //if true lat-lng instead of lng-lat label ordering is used 23 | useLatLngOrder: false, 24 | //if true user given coordinates are centered directly 25 | centerUserCoordinates: false, 26 | //leaflet marker type 27 | markerType: L.marker, 28 | //leaflet marker properties 29 | markerProps: {} 30 | }, 31 | 32 | onAdd: function(map) { 33 | this._map = map; 34 | 35 | var className = 'leaflet-control-coordinates', 36 | container = this._container = L.DomUtil.create('div', className), 37 | options = this.options; 38 | 39 | //label containers 40 | this._labelcontainer = L.DomUtil.create("div", "uiElement label", container); 41 | this._label = L.DomUtil.create("span", "labelFirst", this._labelcontainer); 42 | 43 | 44 | //input containers 45 | this._inputcontainer = L.DomUtil.create("div", "uiElement input uiHidden", container); 46 | var xSpan, ySpan; 47 | if (options.useLatLngOrder) { 48 | ySpan = L.DomUtil.create("span", "", this._inputcontainer); 49 | this._inputY = this._createInput("inputY", this._inputcontainer); 50 | xSpan = L.DomUtil.create("span", "", this._inputcontainer); 51 | this._inputX = this._createInput("inputX", this._inputcontainer); 52 | } else { 53 | xSpan = L.DomUtil.create("span", "", this._inputcontainer); 54 | this._inputX = this._createInput("inputX", this._inputcontainer); 55 | ySpan = L.DomUtil.create("span", "", this._inputcontainer); 56 | this._inputY = this._createInput("inputY", this._inputcontainer); 57 | } 58 | xSpan.innerHTML = options.labelTemplateLng.replace("{x}", ""); 59 | ySpan.innerHTML = options.labelTemplateLat.replace("{y}", ""); 60 | 61 | L.DomEvent.on(this._inputX, 'keyup', this._handleKeypress, this); 62 | L.DomEvent.on(this._inputY, 'keyup', this._handleKeypress, this); 63 | 64 | //connect to mouseevents 65 | map.on("mousemove", this._update, this); 66 | map.on('dragstart', this.collapse, this); 67 | 68 | map.whenReady(this._update, this); 69 | 70 | this._showsCoordinates = true; 71 | //wether or not to show inputs on click 72 | if (options.enableUserInput) { 73 | L.DomEvent.addListener(this._container, "click", this._switchUI, this); 74 | } 75 | 76 | return container; 77 | }, 78 | 79 | /** 80 | * Creates an input HTML element in given container with given classname 81 | */ 82 | _createInput: function(classname, container) { 83 | var input = L.DomUtil.create("input", classname, container); 84 | input.type = "text"; 85 | L.DomEvent.disableClickPropagation(input); 86 | return input; 87 | }, 88 | 89 | _clearMarker: function() { 90 | this._map.removeLayer(this._marker); 91 | }, 92 | 93 | /** 94 | * Called onkeyup of input fields 95 | */ 96 | _handleKeypress: function(e) { 97 | switch (e.keyCode) { 98 | case 27: //Esc 99 | this.collapse(); 100 | break; 101 | case 13: //Enter 102 | this._handleSubmit(); 103 | this.collapse(); 104 | break; 105 | default: //All keys 106 | this._handleSubmit(); 107 | break; 108 | } 109 | }, 110 | 111 | /** 112 | * Called on each keyup except ESC 113 | */ 114 | _handleSubmit: function() { 115 | var x = L.NumberFormatter.createValidNumber(this._inputX.value, this.options.decimalSeperator); 116 | var y = L.NumberFormatter.createValidNumber(this._inputY.value, this.options.decimalSeperator); 117 | if (x !== undefined && y !== undefined) { 118 | var marker = this._marker; 119 | if (!marker) { 120 | marker = this._marker = this._createNewMarker(); 121 | marker.on("click", this._clearMarker, this); 122 | } 123 | var ll = new L.LatLng(y, x); 124 | marker.setLatLng(ll); 125 | marker.addTo(this._map); 126 | if (this.options.centerUserCoordinates) { 127 | this._map.setView(ll, this._map.getZoom()); 128 | } 129 | } 130 | }, 131 | 132 | /** 133 | * Shows inputs fields 134 | */ 135 | expand: function() { 136 | this._showsCoordinates = false; 137 | 138 | this._map.off("mousemove", this._update, this); 139 | 140 | L.DomEvent.addListener(this._container, "mousemove", L.DomEvent.stop); 141 | L.DomEvent.removeListener(this._container, "click", this._switchUI, this); 142 | 143 | L.DomUtil.addClass(this._labelcontainer, "uiHidden"); 144 | L.DomUtil.removeClass(this._inputcontainer, "uiHidden"); 145 | }, 146 | 147 | /** 148 | * Creates the label according to given options and formatters 149 | */ 150 | _createCoordinateLabel: function(ll) { 151 | var opts = this.options, 152 | x, y; 153 | if (opts.customLabelFcn) { 154 | return opts.customLabelFcn(ll, opts); 155 | } 156 | if (opts.labelFormatterLng) { 157 | x = opts.labelFormatterLng(ll.lng); 158 | } else { 159 | x = L.Util.template(opts.labelTemplateLng, { 160 | x: this._getNumber(ll.lng, opts) 161 | }); 162 | } 163 | if (opts.labelFormatterLat) { 164 | y = opts.labelFormatterLat(ll.lat); 165 | } else { 166 | y = L.Util.template(opts.labelTemplateLat, { 167 | y: this._getNumber(ll.lat, opts) 168 | }); 169 | } 170 | if (opts.useLatLngOrder) { 171 | return y + " " + x; 172 | } 173 | return x + " " + y; 174 | }, 175 | 176 | /** 177 | * Returns a Number according to options (DMS or decimal) 178 | */ 179 | _getNumber: function(n, opts) { 180 | var res; 181 | if (opts.useDMS) { 182 | res = L.NumberFormatter.toDMS(n); 183 | } else { 184 | res = L.NumberFormatter.round(n, opts.decimals, opts.decimalSeperator); 185 | } 186 | return res; 187 | }, 188 | 189 | /** 190 | * Shows coordinate labels after user input has ended. Also 191 | * displays a marker with popup at the last input position. 192 | */ 193 | collapse: function() { 194 | if (!this._showsCoordinates) { 195 | this._map.on("mousemove", this._update, this); 196 | this._showsCoordinates = true; 197 | var opts = this.options; 198 | L.DomEvent.addListener(this._container, "click", this._switchUI, this); 199 | L.DomEvent.removeListener(this._container, "mousemove", L.DomEvent.stop); 200 | 201 | L.DomUtil.addClass(this._inputcontainer, "uiHidden"); 202 | L.DomUtil.removeClass(this._labelcontainer, "uiHidden"); 203 | 204 | if (this._marker) { 205 | var m = this._createNewMarker(), 206 | ll = this._marker.getLatLng(); 207 | m.setLatLng(ll); 208 | 209 | var container = L.DomUtil.create("div", ""); 210 | var label = L.DomUtil.create("div", "", container); 211 | label.innerHTML = this._ordinateLabel(ll); 212 | 213 | var close = L.DomUtil.create("a", "", container); 214 | close.innerHTML = "Remove"; 215 | close.href = "#"; 216 | var stop = L.DomEvent.stopPropagation; 217 | 218 | L.DomEvent 219 | .on(close, 'click', stop) 220 | .on(close, 'mousedown', stop) 221 | .on(close, 'dblclick', stop) 222 | .on(close, 'click', L.DomEvent.preventDefault) 223 | .on(close, 'click', function() { 224 | this._map.removeLayer(m); 225 | }, this); 226 | 227 | m.bindPopup(container); 228 | m.addTo(this._map); 229 | this._map.removeLayer(this._marker); 230 | this._marker = null; 231 | } 232 | } 233 | }, 234 | 235 | /** 236 | * Click callback for UI 237 | */ 238 | _switchUI: function(evt) { 239 | L.DomEvent.stop(evt); 240 | L.DomEvent.stopPropagation(evt); 241 | L.DomEvent.preventDefault(evt); 242 | if (this._showsCoordinates) { 243 | //show textfields 244 | this.expand(); 245 | } else { 246 | //show coordinates 247 | this.collapse(); 248 | } 249 | }, 250 | 251 | onRemove: function(map) { 252 | map.off("mousemove", this._update, this); 253 | }, 254 | 255 | /** 256 | * Mousemove callback function updating labels and input elements 257 | */ 258 | _update: function(evt) { 259 | var pos = evt.latlng, 260 | opts = this.options; 261 | if (pos) { 262 | pos = pos.wrap(); 263 | this._currentPos = pos; 264 | this._inputY.value = L.NumberFormatter.round(pos.lat, opts.decimals, opts.decimalSeperator); 265 | this._inputX.value = L.NumberFormatter.round(pos.lng, opts.decimals, opts.decimalSeperator); 266 | this._label.innerHTML = this._createCoordinateLabel(pos); 267 | } 268 | }, 269 | 270 | _createNewMarker: function() { 271 | return this.options.markerType(null, this.options.markerProps); 272 | } 273 | 274 | }); 275 | 276 | //constructor registration 277 | L.control.coordinates = function(options) { 278 | return new L.Control.Coordinates(options); 279 | }; 280 | 281 | //map init hook 282 | L.Map.mergeOptions({ 283 | coordinateControl: false 284 | }); 285 | 286 | L.Map.addInitHook(function() { 287 | if (this.options.coordinateControl) { 288 | this.coordinateControl = new L.Control.Coordinates(); 289 | this.addControl(this.coordinateControl); 290 | } 291 | }); 292 | -------------------------------------------------------------------------------- /src/util/NumberFormatter.js: -------------------------------------------------------------------------------- 1 | L.NumberFormatter = { 2 | round: function(num, dec, sep) { 3 | var res = L.Util.formatNum(num, dec) + "", 4 | numbers = res.split("."); 5 | if (numbers[1]) { 6 | var d = dec - numbers[1].length; 7 | for (; d > 0; d--) { 8 | numbers[1] += "0"; 9 | } 10 | res = numbers.join(sep || "."); 11 | } 12 | return res; 13 | }, 14 | 15 | toDMS: function(deg) { 16 | var d = Math.floor(Math.abs(deg)); 17 | var minfloat = (Math.abs(deg) - d) * 60; 18 | var m = Math.floor(minfloat); 19 | var secfloat = (minfloat - m) * 60; 20 | var s = Math.round(secfloat); 21 | if (s == 60) { 22 | m++; 23 | s = "00"; 24 | } 25 | if (m == 60) { 26 | d++; 27 | m = "00"; 28 | } 29 | if (s < 10) { 30 | s = "0" + s; 31 | } 32 | if (m < 10) { 33 | m = "0" + m; 34 | } 35 | var dir = ""; 36 | if (deg < 0) { 37 | dir = "-"; 38 | } 39 | return ("" + dir + d + "° " + m + "' " + s + "''"); 40 | }, 41 | 42 | createValidNumber: function(num, sep) { 43 | if (num && num.length > 0) { 44 | var numbers = num.split(sep || "."); 45 | try { 46 | var numRes = Number(numbers.join(".")); 47 | if (isNaN(numRes)) { 48 | return undefined; 49 | } 50 | return numRes; 51 | } catch (e) { 52 | return undefined; 53 | } 54 | } 55 | return undefined; 56 | } 57 | }; --------------------------------------------------------------------------------