UNPKG

maplair

Version:

JavaScript library for mobile-friendly interactive maps

152 lines (151 loc) • 4.68 kB
import { setOptions } from "../../core/Util.js"; import { Point } from "../../geometry/Point.js"; import { Bounds } from "../../geometry/Bounds.js"; import { LatLngBounds } from "../../geo/LatLngBounds.js"; import { LatLng } from "../../geo/LatLng.js"; import { _sqClosestPointOnSegment, clipSegment, isFlat, pointToSegmentDistance, polylineCenter, simplify } from "../../geometry/LineUtil.js"; import { Path } from "./Path.js"; //#region src/layer/vector/Polyline.js var Polyline = class Polyline extends Path { static { this.setDefaultOptions({ smoothFactor: .5, noClip: false }); } constructor(latlngs, options) { super(); setOptions(this, options); this._setLatLngs(latlngs); this.callInitHooks(Polyline); } getLatLngs() { return this._latlngs; } setLatLngs(latlngs) { this._setLatLngs(latlngs); return this.redraw(); } isEmpty() { return !this._latlngs.length; } closestLayerPoint(p) { p = new Point(p); let minDistance = Infinity, minPoint = null, p1, p2; const closest = _sqClosestPointOnSegment; for (const points of this._parts) for (let i = 1, len = points.length; i < len; i++) { p1 = points[i - 1]; p2 = points[i]; const sqDist = closest(p, p1, p2, true); if (sqDist < minDistance) { minDistance = sqDist; minPoint = closest(p, p1, p2); } } if (minPoint) minPoint.distance = Math.sqrt(minDistance); return minPoint; } getCenter() { if (!this._map) throw new Error("Must add layer to map before using getCenter()"); return polylineCenter(this._defaultShape(), this._map.options.crs); } getBounds() { return this._bounds; } addLatLng(latlng, latlngs) { latlngs ??= this._defaultShape(); latlng = new LatLng(latlng); latlngs.push(latlng); this._bounds.extend(latlng); return this.redraw(); } _setLatLngs(latlngs) { this._bounds = new LatLngBounds(); this._latlngs = this._convertLatLngs(latlngs); } _defaultShape() { return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0]; } _convertLatLngs(latlngs) { const result = [], flat = isFlat(latlngs); for (let i = 0, len = latlngs.length; i < len; i++) if (flat) { result[i] = new LatLng(latlngs[i]); this._bounds.extend(result[i]); } else result[i] = this._convertLatLngs(latlngs[i]); return result; } _project() { const pxBounds = new Bounds(); this._rings = []; this._projectLatlngs(this._latlngs, this._rings, pxBounds); if (this._bounds.isValid() && pxBounds.isValid()) { this._rawPxBounds = pxBounds; this._updateBounds(); } } _updateBounds() { const w = this._clickTolerance(), p = new Point(w, w); if (!this._rawPxBounds) return; this._pxBounds = new Bounds([this._rawPxBounds.min.subtract(p), this._rawPxBounds.max.add(p)]); } _projectLatlngs(latlngs, result, projectedBounds) { if (latlngs[0] instanceof LatLng) { const ring = latlngs.map((latlng) => this._map.latLngToLayerPoint(latlng)); ring.forEach((r) => projectedBounds.extend(r)); result.push(ring); } else latlngs.forEach((latlng) => this._projectLatlngs(latlng, result, projectedBounds)); } _clipPoints() { const bounds = this._renderer._bounds; this._parts = []; if (!this._pxBounds || !this._pxBounds.intersects(bounds)) return; if (this.options.noClip) { this._parts = this._rings; return; } const parts = this._parts; let i, j, k, len, len2, segment, points; for (i = 0, k = 0, len = this._rings.length; i < len; i++) { points = this._rings[i]; for (j = 0, len2 = points.length; j < len2 - 1; j++) { segment = clipSegment(points[j], points[j + 1], bounds, j, true); if (!segment) continue; parts[k] ??= []; parts[k].push(segment[0]); if (segment[1] !== points[j + 1] || j === len2 - 2) { parts[k].push(segment[1]); k++; } } } } _simplifyPoints() { const parts = this._parts, tolerance = this.options.smoothFactor; for (let i = 0, len = parts.length; i < len; i++) parts[i] = simplify(parts[i], tolerance); } _update() { if (!this._map) return; this._clipPoints(); this._simplifyPoints(); this._updatePath(); } _updatePath() { this._renderer._updatePoly(this); } _containsPoint(p, closed) { let i, j, k, len, len2, part; const w = this._clickTolerance(); if (!this._pxBounds || !this._pxBounds.contains(p)) return false; for (i = 0, len = this._parts.length; i < len; i++) { part = this._parts[i]; for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { if (!closed && j === 0) continue; if (pointToSegmentDistance(p, part[k], part[j]) <= w) return true; } } return false; } }; //#endregion export { Polyline }; //# sourceMappingURL=Polyline.js.map