"use strict"; (() => { // src/leaflet-ais-tracksymbol.ts (function() { const leaflet = globalThis.L; if (!leaflet) return; function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } function finiteAngle(value) { if (value === null || !Number.isFinite(value)) return null; const normalized = (value % 360 + 360) % 360; return normalized; } function svgColor(value, fallback) { const text = value || fallback || ""; return text.replace(/"/g, """); } function buildSymbolHtml(options, zoom) { const heading = finiteAngle(options.heading); const course = finiteAngle(options.course); const angle = heading != null ? heading : course; const speed = Number.isFinite(options.speed) ? Math.max(0, Number(options.speed)) : 0; const sizeBase = Number.isFinite(options.size) ? options.size : 22; const zoomBoost = zoom >= 12 ? 4 : zoom >= 9 ? 2 : 0; const size = clamp(sizeBase + zoomBoost, 16, 32); const courseLen = course != null ? clamp(size * (0.55 + Math.min(speed, 30) / 30), size * 0.55, size * 1.2) : 0; const color = svgColor(options.color, "#ff7559"); const outline = svgColor(options.outline, "#6b2118"); const body = angle != null ? `` : ``; const courseLine = course != null ? `` : ""; return ``; } leaflet.TrxAisTrackSymbol = leaflet.Marker.extend({ options: { heading: null, course: null, speed: null, color: "#ff7559", outline: "#6b2118", size: 22, interactive: true, keyboard: true, riseOnHover: true }, initialize: function(latlng, options) { const merged = leaflet.Util.extend({}, this.options, options || {}); merged.icon = leaflet.divIcon({ className: "trx-ais-track-symbol-icon", html: "", iconSize: [merged.size, merged.size], iconAnchor: [merged.size / 2, merged.size / 2] }); leaflet.Marker.prototype.initialize.call(this, latlng, merged); }, onAdd: function(map) { leaflet.Marker.prototype.onAdd.call(this, map); this._refreshIcon(); this._boundZoomRefresh = this._refreshIcon.bind(this); map.on("zoomend", this._boundZoomRefresh); }, onRemove: function(map) { if (this._boundZoomRefresh) { map.off("zoomend", this._boundZoomRefresh); this._boundZoomRefresh = null; } leaflet.Marker.prototype.onRemove.call(this, map); }, setAisState: function(next) { if ("heading" in next) this.options.heading = next.heading; if ("course" in next) this.options.course = next.course; if ("speed" in next) this.options.speed = next.speed; if ("color" in next) this.options.color = next.color; if ("outline" in next) this.options.outline = next.outline; this._refreshIcon(); return this; }, _refreshIcon: function() { if (!this._icon) return; const zoom = this._map && typeof this._map.getZoom === "function" ? this._map.getZoom() : 0; const html = buildSymbolHtml(this.options, zoom); this._icon.innerHTML = html; const sizeBase = Number.isFinite(this.options.size) ? this.options.size : 22; const zoomBoost = zoom >= 12 ? 4 : zoom >= 9 ? 2 : 0; const size = clamp(sizeBase + zoomBoost, 16, 32); this._icon.style.width = `${size}px`; this._icon.style.height = `${size}px`; this._icon.style.marginLeft = `${-size / 2}px`; this._icon.style.marginTop = `${-size / 2}px`; } }); leaflet.trxAisTrackSymbol = function(latlng, options) { const Constructor = leaflet.TrxAisTrackSymbol; if (!Constructor) throw new Error("AIS track symbol constructor is unavailable"); return new Constructor(latlng, options); }; })(); })();