UNPKG

leaflet

Version:

JavaScript library for mobile-friendly interactive maps

152 lines (127 loc) 4 kB
/* * @class Polygon * @aka L.Polygon * @inherits Polyline * * A class for drawing polygon overlays on a map. Extends `Polyline`. * * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points. * * * @example * * ```js * // create a red polygon from an array of LatLng points * var latlngs = [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]]; * * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map); * * // zoom the map to the polygon * map.fitBounds(polygon.getBounds()); * ``` * * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape: * * ```js * var latlngs = [ * [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring * [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole * ]; * ``` * * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape. * * ```js * var latlngs = [ * [ // first polygon * [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring * [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole * ], * [ // second polygon * [[-109.05, 37],[-109.03, 41],[-102.05, 41],[-102.04, 37],[-109.05, 38]] * ] * ]; * ``` */ L.Polygon = L.Polyline.extend({ options: { fill: true }, isEmpty: function () { return !this._latlngs.length || !this._latlngs[0].length; }, getCenter: function () { // throws error when not yet added to map as this center calculation requires projected coordinates if (!this._map) { throw new Error('Must add layer to map before using getCenter()'); } var i, j, p1, p2, f, area, x, y, center, points = this._rings[0], len = points.length; if (!len) { return null; } // polygon centroid algorithm; only uses the first ring if there are multiple area = x = y = 0; for (i = 0, j = len - 1; i < len; j = i++) { p1 = points[i]; p2 = points[j]; f = p1.y * p2.x - p2.y * p1.x; x += (p1.x + p2.x) * f; y += (p1.y + p2.y) * f; area += f * 3; } if (area === 0) { // Polygon is so small that all points are on same pixel. center = points[0]; } else { center = [x / area, y / area]; } return this._map.layerPointToLatLng(center); }, _convertLatLngs: function (latlngs) { var result = L.Polyline.prototype._convertLatLngs.call(this, latlngs), len = result.length; // remove last point if it equals first one if (len >= 2 && result[0] instanceof L.LatLng && result[0].equals(result[len - 1])) { result.pop(); } return result; }, _setLatLngs: function (latlngs) { L.Polyline.prototype._setLatLngs.call(this, latlngs); if (L.Polyline._flat(this._latlngs)) { this._latlngs = [this._latlngs]; } }, _defaultShape: function () { return L.Polyline._flat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0]; }, _clipPoints: function () { // polygons need a different clipping algorithm so we redefine that var bounds = this._renderer._bounds, w = this.options.weight, p = new L.Point(w, w); // increase clip padding by stroke width to avoid stroke on clip edges bounds = new L.Bounds(bounds.min.subtract(p), bounds.max.add(p)); this._parts = []; if (!this._pxBounds || !this._pxBounds.intersects(bounds)) { return; } if (this.options.noClip) { this._parts = this._rings; return; } for (var i = 0, len = this._rings.length, clipped; i < len; i++) { clipped = L.PolyUtil.clipPolygon(this._rings[i], bounds, true); if (clipped.length) { this._parts.push(clipped); } } }, _updatePath: function () { this._renderer._updatePoly(this, true); } }); // @factory L.polygon(latlngs: LatLng[], options?: Polyline options) L.polygon = function (latlngs, options) { return new L.Polygon(latlngs, options); };