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 stopAngle: function () { 54 if (this.options.startAngle < this.options.stopAngle) { 55 return fixAngle(this.options.stopAngle); 56 } else { 57 return fixAngle(this.options.startAngle); 58 } 59 }, 60 61 setStartAngle: function (angle) { 62 this.options.startAngle = angle; 63 return this.redraw(); 64 }, 65 66 setStopAngle: function (angle) { 67 this.options.stopAngle = angle; 68 return this.redraw(); 69 }, 70 71 setDirection: function (direction, degrees) { 72 if (degrees === undefined) { 73 degrees = 10; 74 } 75 this.options.startAngle = direction - (degrees / 2); 76 this.options.stopAngle = direction + (degrees / 2); 77 78 return this.redraw(); 79 }, 80 getDirection: function () { 81 return this.stopAngle() - (this.stopAngle() - this.startAngle()) / 2; 82 }, 83 84 isSemicircle: function () { 85 var startAngle = this.options.startAngle, 86 stopAngle = this.options.stopAngle; 87 88 return ( 89 !(startAngle === 0 && stopAngle > 359) && 90 !(startAngle == stopAngle) 91 ); 92 }, 93 _containsPoint: function (p) { 94 function normalize (angle) { 95 while (angle <= -Math.PI) { 96 angle += 2.0 * Math.PI; 97 } 98 while (angle > Math.PI) { 99 angle -= 2.0 * Math.PI; 100 } 101 return angle; 102 } 103 var angle = Math.atan2(p.y - this._point.y, p.x - this._point.x); 104 var nStart = normalize(this.startAngle()); 105 var nStop = normalize(this.stopAngle()); 106 if (nStop <= nStart) { 107 nStop += 2.0 * Math.PI; 108 } 109 if (angle <= nStart) { 110 angle += 2.0 * Math.PI; 111 } 112 return ( 113 nStart < angle && angle <= nStop && 114 p.distanceTo(this._point) <= this._radius + this._clickTolerance() 115 ); 116 } 117 }; 118 119 L.SemiCircle = L.Circle.extend(semicircle); 120 L.SemiCircleMarker = L.CircleMarker.extend(semicircle); 121 122 L.semiCircle = function (latlng, options) { 123 return new L.SemiCircle(latlng, options); 124 }; 125 L.semiCircleMarker = function (latlng, options) { 126 return new L.SemiCircleMarker(latlng, options); 127 }; 128 129 var _updateCircleSVG = L.SVG.prototype._updateCircle; 130 var _updateCircleCanvas = L.Canvas.prototype._updateCircle; 131 132 L.SVG.include({ 133 _updateCircle: function (layer) { 134 // If we want a circle, we use the original function 135 if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) || 136 !layer.isSemicircle()) { 137 return _updateCircleSVG.call(this, layer); 138 } 139 if (layer._empty()) { 140 return this._setPath(layer, 'M0 0'); 141 } 142 143 var p = layer._map.latLngToLayerPoint(layer._latlng), 144 r = layer._radius, 145 r2 = Math.round(layer._radiusY || r), 146 start = p.rotated(layer.startAngle(), r), 147 end = p.rotated(layer.stopAngle(), r); 148 149 var largeArc = (layer.options.stopAngle - layer.options.startAngle >= 180) ? '1' : '0'; 150 151 var d = 'M' + p.x + ',' + p.y + 152 // line to first start point 153 'L' + start.x + ',' + start.y + 154 'A ' + r + ',' + r2 + ',0,' + largeArc + ',1,' + end.x + ',' + end.y + 155 ' z'; 156 157 this._setPath(layer, d); 158 } 159 }); 160 161 L.Canvas.include({ 162 _updateCircle: function (layer) { 163 // If we want a circle, we use the original function 164 if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) || 165 !layer.isSemicircle()) { 166 return _updateCircleCanvas.call(this, layer); 167 } 168 169 var p = layer._point, 170 ctx = this._ctx, 171 r = layer._radius, 172 s = (layer._radiusY || r) / r, 173 start = p.rotated(layer.startAngle(), r); 174 175 this._drawnLayers[layer._leaflet_id] = layer; 176 177 if (s !== 1) { 178 ctx.save(); 179 ctx.scale(1, s); 180 } 181 182 ctx.beginPath(); 183 ctx.moveTo(p.x, p.y); 184 ctx.lineTo(start.x, start.y); 185 ctx.arc(p.x, p.y, r, layer.startAngle(), layer.stopAngle()); 186 ctx.lineTo(p.x, p.y); 187 188 if (s !== 1) {
189 ctx.restore(); 190 } 191 192 this._fillStroke(ctx, layer); 193 } 194 }); 195});
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.