1/** 2 * Semicircle extension for L.Circle. 3 * Jan Pieter Waagmeester <[email protected]> 4 * 5 * This version is tested with leaflet 1.0.2 6 */ 7(function (factory) { 8 if (typeof define === 'function' && define.amd) { 9 // AMD 10 define(['leaflet'], factory); 11 } else if (typeof module !== 'undefined' && typeof require !== 'undefined') { 12 // Node/CommonJS 13 module.exports = factory(require('leaflet')); 14 } else { 15 // Browser globals 16 if (typeof window.L === 'undefined') { 17 throw 'Leaflet must be loaded first'; 18 } 19 factory(window.L); 20 } 21})(function (L) { 22 var DEG_TO_RAD = Math.PI / 180; 23 24 // make sure 0 degrees is up (North) and convert to radians. 25 function fixAngle (angle) { 26 return (angle - 90) * DEG_TO_RAD; 27 } 28 29 // rotate point [x + r, y+r] around [x, y] by `angle` radians. 30 function rotated (p, angle, r) { 31 return p.add( 32 L.point(Math.cos(angle), Math.sin(angle)).multiplyBy(r) 33 ); 34 } 35 36 L.Point.prototype.rotated = function (angle, r) { 37 return rotated(this, angle, r); 38 }; 39 40 var semicircle = { 41 options: { 42 startAngle: 0, 43 stopAngle: 359.9999 44 }, 45 46 startAngle: function () { 47 if (this.options.startAngle < this.options.stopAngle) { 48 return fixAngle(this.options.startAngle); 49 } else { 50 return fixAngle(this.options.stopAngle); 51 } 52 }, 53 54 stopAngle: function () { 55 if (this.options.startAngle < this.options.stopAngle) { 56 return fixAngle(this.options.stopAngle); 57 } else { 58 return fixAngle(this.options.startAngle); 59 } 60 }, 61 62 setStartAngle: function (angle) { 63 this.options.startAngle = angle; 64 return this.redraw(); 65 }, 66 67 setStopAngle: function (angle) { 68 this.options.stopAngle = angle; 69 return this.redraw(); 70 }, 71 72 setDirection: function (direction, degrees) { 73 if (degrees === undefined) { 74 degrees = 10; 75 } 76 this.options.startAngle = direction - (degrees / 2); 77 this.options.stopAngle = direction + (degrees / 2); 78 79 return this.redraw(); 80 }, 81 getDirection: function () { 82 return this.stopAngle() - (this.stopAngle() - this.startAngle()) / 2; 83 }, 84 85 isSemicircle: function () { 86 var startAngle = this.options.startAngle, 87 stopAngle = this.options.stopAngle; 88 89 return ( 90 !(startAngle === 0 && stopAngle > 359) && 91 !(startAngle === stopAngle) 92 ); 93 }, 94 _containsPoint: function (p) { 95 function normalize (angle) { 96 while (angle <= -Math.PI) { 97 angle += 2.0 * Math.PI; 98 } 99 while (angle > Math.PI) { 100 angle -= 2.0 * Math.PI; 101 } 102 return angle; 103 } 104 var angle = Math.atan2(p.y - this._point.y, p.x - this._point.x); 105 var nStart = normalize(this.startAngle()); 106 var nStop = normalize(this.stopAngle()); 107 if (nStop <= nStart) { 108 nStop += 2.0 * Math.PI; 109 } 110 if (angle <= nStart) { 111 angle += 2.0 * Math.PI; 112 } 113 return ( 114 nStart < angle && angle <= nStop && 115 p.distanceTo(this._point) <= this._radius + this._clickTolerance() 116 ); 117 } 118 }; 119 120 L.SemiCircle = L.Circle.extend(semicircle); 121 L.SemiCircleMarker = L.CircleMarker.extend(semicircle); 122 123 L.semiCircle = function (latlng, options) { 124 return new L.SemiCircle(latlng, options); 125 }; 126 L.semiCircleMarker = function (latlng, options) { 127 return new L.SemiCircleMarker(latlng, options); 128 }; 129 130 var _updateCircleSVG = L.SVG.prototype._updateCircle; 131 var _updateCircleCanvas = L.Canvas.prototype._updateCircle; 132 133 L.SVG.include({ 134 _updateCircle: function (layer) { 135 // If we want a circle, we use the original function 136 if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) || 137 !layer.isSemicircle()) { 138 return _updateCircleSVG.call(this, layer); 139 } 140 if (layer._empty()) { 141 return this._setPath(layer, 'M0 0'); 142 } 143 144 var p = layer._map.latLngToLayerPoint(layer._latlng), 145 r = layer._radius, 146 r2 = Math.round(layer._radiusY || r), 147 start = p.rotated(layer.startAngle(), r), 148 end = p.rotated(layer.stopAngle(), r); 149 150 var largeArc = (layer.options.stopAngle - layer.options.startAngle >= 180) ? '1' : '0'; 151 152 var d = 'M' + p.x + ',' + p.y + 153 // line to first start point 154 'L' + start.x + ',' + start.y + 155 'A ' + r + ',' + r2 + ',0,' + largeArc + ',1,' + end.x + ',' + end.y + 156 ' z'; 157 158 this._setPath(layer, d); 159 } 160 }); 161 162 L.Canvas.include({ 163 _updateCircle: function (layer) { 164 // If we want a circle, we use the original function 165 if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) || 166 !layer.isSemicircle()) { 167 return _updateCircleCanvas.call(this, layer); 168 } 169 170 if (!this._drawing || layer._empty()) { return; } 171 172 var p = layer._point, 173 ctx = this._ctx, 174 r = layer._radius, 175 s = (layer._radiusY || r) / r, 176 start = p.rotated(layer.startAngle(), r); 177 178 if (s !== 1) { 179 ctx.save(); 180 ctx.scale(1, s); 181 } 182 183 ctx.beginPath(); 184 ctx.moveTo(p.x, p.y); 185 ctx.lineTo(start.x, start.y); 186 ctx.arc(p.x, p.y, r, layer.startAngle(), layer.stopAngle()); 187 ctx.lineTo(p.x, p.y); 188 189 if (s !== 1) {
190 ctx.restore(); 191 } 192 193 this._fillStroke(ctx, layer); 194 } 195 }); 196});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.