├── .gitattributes ├── LICENSE ├── README.md ├── examples ├── images │ ├── arrow.png │ ├── arrow3.png │ ├── arrow_ci.png │ ├── begin.png │ ├── end.png │ └── flag.png ├── marker-direction.html └── marker-direction.js └── src ├── marker-direction.js └── marker-direction.min.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 JackZouShao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | leaflet-marker-direction 2 | ============= 3 |
4 | Plugin for Leaflet to display the path and the direction of the marker
5 | 6 | Check out the [demo](https://thomas2077.github.io/leaflet-marker-direction/examples/marker-direction.html) 7 | 8 | Leaflet versions 9 | ----- 10 | The plugin is based on Leaflet 1.0.0 or above 11 | 12 | Usage 13 | ---- 14 | ````js 15 | // inite map 16 | var map = L.map('map').setView([30.201479, 120.155908], 13); 17 | L.tileLayer(...).addTo(map); 18 | 19 | // your data 20 | var list = [ 21 | {"lon":"120.15261","lat":"30.182835"}, 22 | {"lon":"120.152431666667","lat":"30.1828733333333"}, 23 | {"lon":"120.15239","lat":"30.182755"}, 24 | {"lon":"120.152303333333","lat":"30.1826566666667"} 25 | ]; 26 | // iterate your data 27 | for(var i in list){ 28 | var img = new Image(); 29 | img.src = './images/arrow3.png'; 30 | var options = { 31 |        label: 'your label', 32 | labelFlag: labelFlag, 33 | labelColor: 'black', 34 | img: img 35 | }; 36 | 37 | // use angeMaker plugin 38 | var angleMarker = L.angleMarker(latlng, options); 39 | var angle = 0; 40 | 41 | // get angele between A(previousPoint) and B(nextPoint) 42 | angle = angleMarker.getAngle(previousLatLng, nextLanLng); 43 | 44 | // set angele A -> B 45 | angleMarker.setHeading(angle); 46 | map.addLayer(angleMarker); 47 | } 48 | ```` 49 | ### Options 50 | *`label` Text near the your marker
51 | *`labelFlag` whethe to display the text
52 | *`labelColor` The color of the text
53 | *`img` Your custom maker
54 | ### update history 55 | -------------------------------------------------------------------------------- /examples/images/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/arrow.png -------------------------------------------------------------------------------- /examples/images/arrow3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/arrow3.png -------------------------------------------------------------------------------- /examples/images/arrow_ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/arrow_ci.png -------------------------------------------------------------------------------- /examples/images/begin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/begin.png -------------------------------------------------------------------------------- /examples/images/end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/end.png -------------------------------------------------------------------------------- /examples/images/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thomas2077/leaflet-marker-direction/448b1e7ff250d1dc5e96ce7836fb1c313a912208/examples/images/flag.png -------------------------------------------------------------------------------- /examples/marker-direction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | demo 6 | 46 | 49 | 50 | 51 |
52 |
53 | 54 |
55 |
56 | 57 | 58 | 61 | 62 | 949 | 950 | -------------------------------------------------------------------------------- /examples/marker-direction.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LEAFLET.MARKER_DRECTION 3 | * vesion 0.0.1 4 | * @author Thomas Zou 5 | * @date 10/1/2018 6 | */ 7 | 8 | /* Angle ICON */ 9 | L.AngleIcon = L.Icon.extend({ 10 | // default value 11 | options: { 12 | angle: 0, 13 | iconSize: new L.Point(80,60), // canvas size 14 | className: "leaflet-boat-icon", 15 | course: 0, // angle 16 | labelAnchor: [10, -10], // test loaction 17 | pointType:0, // pointType 18 | ciFlag :false, 19 | label:'', 20 | textColor:'red', 21 | img:null 22 | }, 23 | 24 | createIcon: function () { 25 | var e = document.createElement("canvas"); 26 | this._setIconStyles(e, "icon"); 27 | var s = this.options.iconSize; 28 | e.width = s.x; 29 | e.height = s.y; 30 | this.ctx = e.getContext("2d"); 31 | this.draw(e.getContext("2d"), s.x, s.y); 32 | return e; 33 | }, 34 | 35 | draw: function(ctx, w, h) { 36 | 37 | if(!ctx) 38 | return; 39 | var x = this.x; 40 | var y = this.y; 41 | 42 | var course = this.options.course; 43 | 44 | ctx.font="10px Courier New"; 45 | ctx.fillStyle = this.options.textColor; 46 | if(this.options.ciFlag){ 47 | var text = this.options.label; 48 | ctx.fillText(text, 0, 20); 49 | } 50 | 51 | this.drwaImage(ctx, this.options.img, course, 35, 20); 52 | }, 53 | 54 | /** 55 | * draw image by canvas 56 | * @param ctx canvas 57 | * @param img image 58 | * @param course angle 59 | * @param w width 60 | * @param h height 61 | */ 62 | drwaImage : function(ctx , img, course, w, h){ 63 | console.log(img.src) 64 | img.onload = function(){ 65 | //平移坐标原点 66 | ctx.translate(40,30); 67 | //旋转画布 68 | ctx.rotate(course); 69 | ctx.translate(-40,-30); 70 | //画图 71 | ctx.drawImage(img,w,h); 72 | console.log(img.src) 73 | } 74 | }, 75 | 76 | /** 77 | * 获得两点之间方向角 (Get the direction angle between two points) 78 | * 根据地球上两点之间的经纬度计算两点之间与正北方向的夹角 79 | * (According to the latitude and longitude between two points on earth, 80 | * calculate the angle between two points and the direction of the north) 81 | * 82 | * @param 点A(L.Latlng) PointA 83 | * @param 点B(L.Latlng) PointB 84 | * @return result: AB角度 (the angle of AB (calculated result degree)) 85 | * 86 | * @version 2016-08-19 87 | * 88 | * @see Math.atan2()用于返回从x轴到指定坐标点(x, y)的角度(以弧度为单位);y/x = tan# 89 | * Math.atan2 () returns the angle (in radians) from the x-axis to the specified coordinate point (x, y); y / x = tan # 90 | * @version 2016-08-19 91 | */ 92 | getAngle : function(A, B){ 93 | var angle = null; 94 | var latA = A.lat; 95 | var lonA = A.lon; 96 | var latB = B.lat; 97 | var lonB = B.lon; 98 | 99 | // 注意经度或者纬度相等 (when longitude or latitude is equal) 100 | if(lonA == lonB && latA>latB ){ 101 | angle = Math.PI; 102 | } 103 | else if(lonA == lonB && latA < latB ){ 104 | angle = 0 ; 105 | } 106 | else if(lonA > lonB && latA == latB ){ 107 | angle = -(Math.PI/2); 108 | } 109 | else if(lonA < lonB && latA == latB ){ 110 | angle = Math.PI/2 ; 111 | } 112 | 113 | // 注意经度或者纬度都不相等 (Longitude and latitude are not equal) 114 | else{ 115 | var x1 = A.lat*Math.pow(10,12); 116 | var x2 = B.lat*Math.pow(10,12); 117 | var y1 = A.lon*Math.pow(10,12); 118 | var y2 = B.lon*Math.pow(10,12); 119 | angle = Math.atan2(y2-y1,x2-x1) 120 | } 121 | options.angle = angle; 122 | return angle; 123 | }, 124 | 125 | /** 126 | * 设置maker 和正北方向 角度 127 | * Set the angle between the maker and the north 128 | * @param heading (Unit: radian) 129 | */ 130 | setHeading : function(heading) { 131 | 132 | if(!heading){ 133 | heading = options.angle; 134 | } 135 | this.options.course = (heading % 360); 136 | var s = this.options.iconSize; 137 | 138 | //我们不需要在这里显示的调用draw()方法,因为map.addLayer(layer)会调用这个方法 139 | //We do not need to call draw() as shown here 140 | //because map.addLayer (layer) will call this method 141 | //this.draw(this.ctx, s.x, s.y); 142 | } 143 | }); 144 | 145 | // AngleMarker继承Marker并添加setHeading 和 getAngle 方法 146 | // AngleMarker extends from Marker and adds the setHeading and getAngle methods 147 | L.AngleMarker = L.Marker.extend({ 148 | getAngle : function (A, B) { 149 | return this.options.icon.getAngle(A, B); 150 | }, 151 | setHeading: function(heading) { 152 | this.options.icon.setHeading(heading); 153 | } 154 | }); 155 | 156 | L.angleMarker = function(pos, options) { 157 | 158 | options.icon = new L.AngleIcon({ 159 | ciFlag:options.labelFlag, 160 | label:options.label, 161 | textColor:options.labelColor, 162 | img: options.img 163 | }); 164 | 165 | return new L.AngleMarker(pos,options); 166 | }; 167 | -------------------------------------------------------------------------------- /src/marker-direction.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LEAFLET.MARKER_DRECTION 3 | * vesion 0.0.1 4 | * @author Thomas Zou 5 | * @date 10/1/2018 6 | */ 7 | 8 | /* Angle ICON */ 9 | L.AngleIcon = L.Icon.extend({ 10 | // default value 11 | options: { 12 | angle: 0, 13 | iconSize: new L.Point(80,60), // canvas size 14 | className: "leaflet-boat-icon", 15 | course: 0, // angle 16 | labelAnchor: [10, -10], // test loaction 17 | pointType:0, // pointType 18 | ciFlag :false, 19 | label:'', 20 | textColor:'red', 21 | img:null 22 | }, 23 | 24 | createIcon: function () { 25 | var e = document.createElement("canvas"); 26 | this._setIconStyles(e, "icon"); 27 | var s = this.options.iconSize; 28 | e.width = s.x; 29 | e.height = s.y; 30 | this.ctx = e.getContext("2d"); 31 | this.draw(e.getContext("2d"), s.x, s.y); 32 | return e; 33 | }, 34 | 35 | draw: function(ctx, w, h) { 36 | 37 | if(!ctx) 38 | return; 39 | var x = this.x; 40 | var y = this.y; 41 | 42 | var course = this.options.course; 43 | 44 | ctx.font="10px Courier New"; 45 | ctx.fillStyle = this.options.textColor; 46 | if(this.options.ciFlag){ 47 | var text = this.options.label; 48 | ctx.fillText(text, 0, 20); 49 | } 50 | 51 | this.drwaImage(ctx, this.options.img, course, 35, 20); 52 | }, 53 | 54 | /** 55 | * draw image by canvas 56 | * @param ctx canvas 57 | * @param img image 58 | * @param course angle 59 | * @param w width 60 | * @param h height 61 | */ 62 | drwaImage : function(ctx , img, course, w, h){ 63 | console.log(img.src) 64 | img.onload = function(){ 65 | //平移坐标原点 66 | ctx.translate(40,30); 67 | //旋转画布 68 | ctx.rotate(course); 69 | ctx.translate(-40,-30); 70 | //画图 71 | ctx.drawImage(img,w,h); 72 | console.log(img.src) 73 | } 74 | }, 75 | 76 | /** 77 | * 获得两点之间方向角 (Get the direction angle between two points) 78 | * 根据地球上两点之间的经纬度计算两点之间与正北方向的夹角 79 | * (According to the latitude and longitude between two points on earth, 80 | * calculate the angle between two points and the direction of the north) 81 | * 82 | * @param 点A(L.Latlng) PointA 83 | * @param 点B(L.Latlng) PointB 84 | * @return result: AB角度 (the angle of AB (calculated result degree)) 85 | * 86 | * @version 2016-08-19 87 | * 88 | * @see Math.atan2()用于返回从x轴到指定坐标点(x, y)的角度(以弧度为单位);y/x = tan# 89 | * Math.atan2 () returns the angle (in radians) from the x-axis to the specified coordinate point (x, y); y / x = tan # 90 | * @version 2016-08-19 91 | */ 92 | getAngle : function(A, B){ 93 | var angle = null; 94 | var latA = A.lat; 95 | var lonA = A.lon; 96 | var latB = B.lat; 97 | var lonB = B.lon; 98 | 99 | // 注意经度或者纬度相等 (when longitude or latitude is equal) 100 | if(lonA == lonB && latA>latB ){ 101 | angle = Math.PI; 102 | } 103 | else if(lonA == lonB && latA < latB ){ 104 | angle = 0 ; 105 | } 106 | else if(lonA > lonB && latA == latB ){ 107 | angle = -(Math.PI/2); 108 | } 109 | else if(lonA < lonB && latA == latB ){ 110 | angle = Math.PI/2 ; 111 | } 112 | 113 | // 注意经度或者纬度都不相等 (Longitude and latitude are not equal) 114 | else{ 115 | var x1 = A.lat*Math.pow(10,12); 116 | var x2 = B.lat*Math.pow(10,12); 117 | var y1 = A.lon*Math.pow(10,12); 118 | var y2 = B.lon*Math.pow(10,12); 119 | angle = Math.atan2(y2-y1,x2-x1) 120 | } 121 | options.angle = angle; 122 | return angle; 123 | }, 124 | 125 | /** 126 | * 设置maker 和正北方向 角度 127 | * Set the angle between the maker and the north 128 | * @param heading (Unit: radian) 129 | */ 130 | setHeading : function(heading) { 131 | 132 | if(!heading){ 133 | heading = options.angle; 134 | } 135 | this.options.course = (heading % 360); 136 | var s = this.options.iconSize; 137 | 138 | //我们不需要在这里显示的调用draw()方法,因为map.addLayer(layer)会调用这个方法 139 | //We do not need to call draw() as shown here 140 | //because map.addLayer (layer) will call this method 141 | //this.draw(this.ctx, s.x, s.y); 142 | } 143 | }); 144 | 145 | // AngleMarker继承Marker并添加setHeading 和 getAngle 方法 146 | // AngleMarker extends from Marker and adds the setHeading and getAngle methods 147 | L.AngleMarker = L.Marker.extend({ 148 | getAngle : function (A, B) { 149 | return this.options.icon.getAngle(A, B); 150 | }, 151 | setHeading: function(heading) { 152 | this.options.icon.setHeading(heading); 153 | } 154 | }); 155 | 156 | L.angleMarker = function(pos, options) { 157 | 158 | options.icon = new L.AngleIcon({ 159 | ciFlag:options.labelFlag, 160 | label:options.label, 161 | textColor:options.labelColor, 162 | img: options.img 163 | }); 164 | 165 | return new L.AngleMarker(pos,options); 166 | }; 167 | -------------------------------------------------------------------------------- /src/marker-direction.min.js: -------------------------------------------------------------------------------- 1 | L.AngleIcon=L.Icon.extend({options:{angle:0,iconSize:new L.Point(80,60),className:"leaflet-boat-icon",course:0,labelAnchor:[10,-10],pointType:0,ciFlag:false,label:"",textColor:"red",img:null},createIcon:function(){var e=document.createElement("canvas");this._setIconStyles(e,"icon");var s=this.options.iconSize;e.width=s.x;e.height=s.y;this.ctx=e.getContext("2d");this.draw(e.getContext("2d"),s.x,s.y);return e},draw:function(ctx,w,h){if(!ctx){return}var x=this.x;var y=this.y;var course=this.options.course;ctx.font="10px Courier New";ctx.fillStyle=this.options.textColor;if(this.options.ciFlag){var text=this.options.label;ctx.fillText(text,0,20)}this.drwaImage(ctx,this.options.img,course,35,20)},drwaImage:function(ctx,img,course,w,h){console.log(img.src);img.onload=function(){ctx.translate(40,30);ctx.rotate(course);ctx.translate(-40,-30);ctx.drawImage(img,w,h);console.log(img.src)}},getAngle:function(A,B){var angle=null;var latA=A.lat;var lonA=A.lon;var latB=B.lat;var lonB=B.lon;if(lonA==lonB&&latA>latB){angle=Math.PI}else{if(lonA==lonB&&latAlonB&&latA==latB){angle=-(Math.PI/2)}else{if(lonA