@bitalltech-maplibre/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("maplibre-gl")):"function"==typeof define&&define.amd?define(["exports","maplibre-gl"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).BitAllTechMaplibreCore={},t.maplibregl)}(this,function(t,e){"use strict";const i={},a=()=>({...i}),n="https://tiles.openfreemap.org/styles",r=(t,e,i)=>({type:t,label:e,style:`${n}/${i}`}),o={"openfreemap-liberty":r("openfreemap-liberty","OpenFreeMap Liberty","liberty"),"openfreemap-bright":r("openfreemap-bright","OpenFreeMap Bright","bright"),"openfreemap-positron":r("openfreemap-positron","OpenFreeMap Positron","positron"),"openfreemap-dark":r("openfreemap-dark","OpenFreeMap Dark","dark"),"openfreemap-fiord":r("openfreemap-fiord","OpenFreeMap Fiord","fiord")},l=Object.keys(o),c=(t="openfreemap-liberty")=>o[t].style,s=["0","1","2","3","4","5","6","7"],p=(t,e)=>{const i=(t=>{const e=t||a().tdtToken;if(!e)throw new Error("Tianditu token is required. Pass token or call setMaplibreToolsConfig({ tdtToken }).");return e})(e);return s.map(e=>`https://t${e}.tianditu.gov.cn/DataServer?T=${t}&x={x}&y={y}&l={z}&tk=${i}`)},d=(t,e={})=>({type:"raster",tiles:p(t,e.token),tileSize:256,minzoom:0,maxzoom:18,attribution:"&copy; 天地图"}),h=(t={})=>{const e=!1!==t.label,i={"tdt-image":d("img_w",t)},a=[{id:"tdt-image",type:"raster",source:"tdt-image"}];return e&&(i["tdt-image-label"]=d("cia_w",t),a.push({id:"tdt-image-label",type:"raster",source:"tdt-image-label"})),{version:8,sources:i,layers:a}},f=[...Object.keys(o),"tdt-image","tdt-image-label"],y=t=>f.includes(t),u=(t="openfreemap-liberty",e={})=>"tdt-image"===t?h({...e,label:!1}):"tdt-image-label"===t?h({...e,label:!0}):c(t),m=t=>t*Math.PI/180,g=t=>180*t/Math.PI,M=t=>(t%360+360)%360,b=(t,e,i)=>{const a=e/6378137,n=m(i),r=m(t[1]),o=m(t[0]),l=Math.asin(Math.sin(r)*Math.cos(a)+Math.cos(r)*Math.sin(a)*Math.cos(n)),c=o+Math.atan2(Math.sin(n)*Math.sin(a)*Math.cos(r),Math.cos(a)-Math.sin(r)*Math.sin(l));return[(s=g(c),s>180?s-360:s<-180?s+360:s),g(l)];var s},k=(t,e,i=64)=>{const a=((t,e)=>{const i=M(e)-M(t);return i<=0?i+360:i})(t,e),n=Math.max(12,Math.ceil(i*a/360));return Array.from({length:n+1},(e,i)=>M(t+a*i/n))},v=(t,e,i=64)=>(t=>{if(0===t.length)return t;const[e,i]=t[0],a=t[t.length-1];return a[0]===e&&a[1]===i?t:[...t,[e,i]]})(Array.from({length:i},(a,n)=>b(t,e,360*n/i))),A=(t,e,i=64)=>({type:"Polygon",coordinates:[v(t,e,i)]}),$=(t,e,i=64)=>({type:"LineString",coordinates:v(t,e,i)}),w=(t,e,i,a,n=64)=>{const r=k(i,a,n).map(i=>b(t,e,i));return{type:"Polygon",coordinates:[[t,...r,t]]}},x=(t,e,i,a,n=64)=>({type:"LineString",coordinates:k(i,a,n).map(i=>b(t,e,i))}),F=(t,e,i)=>({type:"LineString",coordinates:[t,b(t,e,i)]}),O=(t,e)=>({type:"Feature",geometry:t,properties:e}),q=t=>({type:"FeatureCollection",features:t}),S=(t,e,i)=>{const a=i?"visible":"none";e.forEach(e=>{t.getLayer(e)&&t.setLayoutProperty(e,"visibility",a)})},D=(t,e,i)=>{const a=e.id,n=`${a}-source`;let r,o={...e},l=[],c=[n],s=!1,p=!1;const d=()=>{null==r||r(),r=void 0,[...l].reverse().forEach(e=>{((t,e)=>{t.getLayer(e)&&t.removeLayer(e)})(t,e)}),[...c].reverse().forEach(e=>{((t,e)=>{t.getSource(e)&&t.removeSource(e)})(t,e)}),l=[],c=[n]},h=e=>{const i=t.getSource(n);i&&i.setData(e)},f=()=>{var e,a;if(s)return;d();const p=i(o);t.addSource(n,{type:"geojson",data:p.data}),null==(e=p.canvasSources)||e.forEach(e=>{t.addSource(e.id,e.source)}),c=[n,...(null==(a=p.canvasSources)?void 0:a.map(t=>t.id))||[]],l=p.layers.map(t=>t.id),p.layers.forEach(e=>{var i;const a="raster"===e.type&&(null==(i=p.canvasSources)?void 0:i[0])?p.canvasSources[0].id:n;t.addLayer({...e,source:a},o.beforeId)}),S(t,l,!1!==o.visible),p.startAnimation&&(r=p.startAnimation({getOptions:()=>o,setData:h})||void 0)},y=()=>{p&&!s&&t.isStyleLoaded()&&(p=!1,t.off("styledata",y),f())},u=()=>{s||(t.isStyleLoaded()?(p&&(p=!1,t.off("styledata",y)),f()):p||(p=!0,t.on("styledata",y)))};return u(),{id:a,update(t){s||(o={...o,...t,id:a},u())},show(){s||(o={...o,visible:!0},S(t,l,!0))},hide(){s||(o={...o,visible:!1},S(t,l,!1))},remove(){s||(s=!0,p&&(p=!1,t.off("styledata",y)),d())}}},j=(t,e=0)=>{const i=Math.max(10,t.radius??70),a=Math.max(i,t.maxRadius??2.3*i),n=Math.max(1,t.pulseCount??2),r=Math.max(1,t.lineWidth??2),o=t.pulseOpacity??.9,l=[O(A(t.center,i),{kind:"core"})];for(let c=0;c<n;c+=1){const s=(e+c/n)%1,p=i+(a-i)*s;l.push(O($(t.center,p),{kind:"pulse",opacity:o*(1-s),width:r*(1-.35*s)}))}return q(l)},T=t=>{const e=t.color||"#ff3b30",i=t.fillColor||e;return{data:j(t),layers:[{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":i,"fill-opacity":t.fillOpacity??.28}},{id:`${t.id}-pulse`,type:"line",filter:["==",["get","kind"],"pulse"],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],t.pulseOpacity??.9],"line-width":["coalesce",["get","width"],t.lineWidth??2]}}],startAnimation({getOptions:t,setData:e}){const i=Math.max(400,t().duration??1800);let a=0;const n=performance.now(),r=o=>{const l=t();e(j(l,(o-n)%i/i)),a=requestAnimationFrame(r)};return a=requestAnimationFrame(r),()=>{cancelAnimationFrame(a)}}}},L=(t,e=0)=>{var i,a;const n=Math.max(16,t.radius??110),r=Math.max(0,t.pulseScale??.16),o=(1-Math.cos(e*Math.PI*2))/2,l=n*(1+r*o),c=1.28*l,s=Math.max(1,t.ringCount??(null==(i=t.radii)?void 0:i.length)??3),p=Math.max(2.2*l,t.maxRadius??((null==(a=t.radii)?void 0:a.length)?Math.max(...t.radii):n*(2.5*s))),d=p/s,h=[O(A(t.center,c),{kind:"halo",opacity:(t.haloOpacity??.16)*(.75+.65*o)}),O(A(t.center,l),{kind:"core",opacity:(t.fillOpacity??.28)*(.88+.2*o)}),O($(t.center,1.06*l),{kind:"core-ring",opacity:(t.lineOpacity??.95)*(.8+.2*o),width:Math.max(1,(t.lineWidth??3)*(.92+.12*o))})];for(let f=0;f<s;f+=1){const i=(f+e+1)*d%p||p,a=i/p;h.push(O($(t.center,i),{kind:"ring",opacity:Math.max(.18,(t.lineOpacity??.95)*(1-.42*a)),width:Math.max(1,(t.lineWidth??3)*(1-.18*a))}))}return q(h)},z=t=>{const e=t.color||"#ef4444",i=t.fillColor||e;return{data:L(t),layers:[{id:`${t.id}-halo`,type:"fill",filter:["==",["get","kind"],"halo"],paint:{"fill-color":i,"fill-opacity":["coalesce",["get","opacity"],t.haloOpacity??.16]}},{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":i,"fill-opacity":["coalesce",["get","opacity"],t.fillOpacity??.28]}},{id:`${t.id}-rings`,type:"line",filter:["any",["==",["get","kind"],"ring"]],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],t.lineOpacity??.95],"line-width":["coalesce",["get","width"],t.lineWidth??3]}}],startAnimation({getOptions:t,setData:e}){const i=Math.max(600,t().duration??2e3);let a=0;const n=performance.now(),r=o=>{const l=t();e(L(l,(o-n)%i/i)),a=requestAnimationFrame(r)};return a=requestAnimationFrame(r),()=>{cancelAnimationFrame(a)}}}},P=(t,e,i)=>Math.min(i,Math.max(e,t)),I=t=>(t%360+360)%360,N=(t,e)=>{const i=(t=>{const e=t.trim(),i=e.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);if(i){const t=i[1],e=3===t.length?t.split("").map(t=>t+t).join(""):t;return[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16)]}const a=e.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);if(a)return[P(Number(a[1]),0,255),P(Number(a[2]),0,255),P(Number(a[3]),0,255)]})(t);return i?`rgba(${i[0]}, ${i[1]}, ${i[2]}, ${P(e,0,1)})`:t},B=(t,e)=>{const i=b(t,e,0)[1],a=b(t,e,90)[0],n=b(t,e,180)[1],r=b(t,e,270)[0];return[[r,i],[a,i],[a,n],[r,n]]},C=t=>{var e;const i=null==(e=t.gradient)?void 0:e.colors;return Array.isArray(i)&&i.length>=2?i:void 0},_=(t,e,i=0)=>{const a=t.getContext("2d"),n=C(e);if(!a||!e.gradient||!n)return;const r=t.width,o=r/2,l=o-2,c=e.startAngle+i,s=((t,e)=>{const i=I(e)-I(t);return i<=0?i+360:i})(c,e.endAngle+i),p=(c-90)*Math.PI/180;const d=p+s*Math.PI/180,h=e.gradient.opacity??e.opacity??.28,f=e.gradient.centerOpacity??e.gradient.tailOpacity??.25*h,y=e.gradient.edgeOpacity??e.gradient.headOpacity??h,u=a.createRadialGradient(o,o,0,o,o,l);n.forEach((t,e)=>{const i=e/Math.max(1,n.length-1),a=f+(y-f)*i;u.addColorStop(i,N(t,a))}),a.clearRect(0,0,r,r),a.save(),a.beginPath(),a.moveTo(o,o),a.arc(o,o,l,p,d,!1),a.closePath(),a.clip(),a.fillStyle=u,a.fillRect(0,0,r,r),a.restore()},E=t=>{if(!C(t))return;const e=(()=>{const t=document.createElement("canvas");return t.width=768,t.height=768,t})();return _(e,t),e},G=(t,e,i)=>C(t)?[]:[O(w(t.center,t.radius,e,i),{kind:"sector",color:t.color||"#ff453a",opacity:t.opacity??.28})],H=(t,e=0)=>{const i=t.startAngle+e,a=t.endAngle+e,n=[...G(t,i,a),O(F(t.center,t.radius,i),{kind:"frame"}),O(F(t.center,t.radius,a),{kind:"frame"})];return q(n)},J=t=>{const e=E(t),i=e?{id:`${t.id}-sector-fill`,type:"raster",paint:{"raster-opacity":1,"raster-fade-duration":0}}:{id:`${t.id}-sector-fill`,type:"fill",filter:["==",["get","kind"],"sector"],paint:{"fill-color":["coalesce",["get","color"],t.color||"#ff453a"],"fill-opacity":["coalesce",["get","opacity"],t.opacity??.28],"fill-antialias":!1}};return{data:H(t),canvasSources:e?[{id:`${t.id}-canvas-source`,source:{type:"canvas",canvas:e,coordinates:B(t.center,t.radius),animate:Boolean(t.rotationSpeed&&0!==t.rotationSpeed)}}]:void 0,layers:[i,{id:`${t.id}-sector-frame`,type:"line",filter:["==",["get","kind"],"frame"],paint:{"line-color":t.outlineColor||t.color||"#ff453a","line-opacity":t.outlineOpacity??.95,"line-width":t.outlineWidth??2}}],startAnimation:t.rotationSpeed&&0!==t.rotationSpeed?({getOptions:t,setData:i})=>{const a=performance.now();let n=0;const r=o=>{const l=t(),c=(o-a)/1e3*(l.rotationSpeed||0);e&&_(e,l,c),i(H(l,c)),n=requestAnimationFrame(r)};return n=requestAnimationFrame(r),()=>{cancelAnimationFrame(n)}}:void 0}},K=(t,e)=>{const i=Math.max(40,t.radius),a=t.direction??270,n=Math.min(180,Math.max(8,t.spread??72)),r=Math.max(1,t.lineCount??7),o=Math.max(20,t.lineSpacing??Math.max(80,i/9)),l=e??0,c=Math.max(0,Math.min(.35*i,t.innerRadius??Math.min(.4*o,120))),s=a-n/2,p=a+n/2,d=[];for(let h=0;h<r;h+=1){const e=c+l+h*o;if(e>i)continue;const a=e/i,n=1-h/Math.max(1,r);d.push(O(x(t.center,e,s,p),{kind:"directional-pulse-line",opacity:Math.max(.08,(t.opacity??.92)*(.42+.58*n)*(1-.28*a)),width:Math.max(1,(t.lineWidth??2.8)*(.86+.24*n)*(1-.08*a))}))}return q(d)},Q=t=>({data:K(t),layers:[{id:`${t.id}-directional-pulse`,type:"line",filter:["==",["get","kind"],"directional-pulse-line"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":t.color||"#ef4444","line-opacity":["coalesce",["get","opacity"],t.opacity??.92],"line-width":["coalesce",["get","width"],t.lineWidth??2.8]}}],startAnimation:t.speed&&t.speed>0?({getOptions:t,setData:e})=>{const i=performance.now();let a=0;const n=r=>{const o=t(),l=Math.max(40,o.radius),c=Math.max(20,o.lineSpacing??Math.max(80,l/9)),s=(r-i)/1e3*(o.speed??0)%c;e(K(o,s)),a=requestAnimationFrame(n)};return a=requestAnimationFrame(n),()=>{cancelAnimationFrame(a)}}:void 0}),R=(t,e=0)=>{var i;const a=Math.max(0,t.ringCount??4),n=Math.max(1,t.trailCount??8),r=Math.max(12,t.sweepAngle??42),o=.22*r,l=t.tailOpacity??.04,c=t.headOpacity??Math.max(.24,t.opacity??.3),s=(t.sweepStartAngle??0)+e,p=!1!==t.showCrosshair,d=!1!==t.showDistanceLabels,h=Math.max(20,t.coreRadius??Math.min(160,.035*t.radius)),f=[];for(let y=a;y>=1;y-=1){const e=t.radius*y/a;if(f.push(O($(t.center,e),{kind:"ring"})),d){const a=(null==(i=t.distanceLabelFormatter)?void 0:i.call(t,e,y))??`${Math.round(e)}`;[{bearing:0,textAnchor:"bottom"},{bearing:90,textAnchor:"left"},{bearing:180,textAnchor:"top"},{bearing:270,textAnchor:"right"}].forEach(i=>{f.push(O({type:"Point",coordinates:b(t.center,e,i.bearing)},{kind:"distance-label",text:a,textAnchor:i.textAnchor}))})}}p&&f.push(O({type:"LineString",coordinates:[b(t.center,t.radius,180),b(t.center,t.radius,0)]},{kind:"crosshair"}),O({type:"LineString",coordinates:[b(t.center,t.radius,270),b(t.center,t.radius,90)]},{kind:"crosshair"})),f.push(O(A(t.center,h),{kind:"core"}));for(let y=n-1;y>=0;y-=1){const e=s-o*y,i=e+r,a=(n-y)/n,p=l+(c-l)*a*a;f.push(O(w(t.center,t.radius,e,i),{kind:"sweep",opacity:p}))}return f.push(O(w(t.center,t.radius,s+.42*r,s+r),{kind:"head",opacity:Math.min(1,c+.08)})),q(f)},U=t=>({data:R(t),layers:[{id:`${t.id}-radar-trail`,type:"fill",filter:["==",["get","kind"],"sweep"],paint:{"fill-color":t.color||"#22c55e","fill-opacity":["coalesce",["get","opacity"],t.opacity??.32]}},{id:`${t.id}-radar-rings`,type:"line",filter:["==",["get","kind"],"ring"],paint:{"line-color":t.ringColor||t.color||"#22c55e","line-opacity":t.ringOpacity??.95,"line-width":t.ringWidth??2}},{id:`${t.id}-radar-crosshair`,type:"line",filter:["==",["get","kind"],"crosshair"],paint:{"line-color":t.crosshairColor||t.ringColor||t.color||"#22c55e","line-opacity":t.crosshairOpacity??.5,"line-width":t.crosshairWidth??1.4}},{id:`${t.id}-radar-distance-labels`,type:"symbol",filter:["==",["get","kind"],"distance-label"],layout:{"text-field":["get","text"],"text-size":t.distanceLabelSize??12,"text-anchor":["get","textAnchor"],"text-allow-overlap":!0,"text-ignore-placement":!0},paint:{"text-color":t.distanceLabelColor||t.ringColor||t.color||"#22c55e","text-opacity":t.distanceLabelOpacity??.92,"text-halo-color":t.distanceLabelHaloColor||"rgba(15, 23, 42, 0.42)","text-halo-width":1}}],startAnimation({getOptions:t,setData:e}){const i=performance.now();let a=0;const n=r=>{const o=t(),l=(r-i)/1e3*(o.rotationSpeed??36);e(R(o,l)),a=requestAnimationFrame(n)};return a=requestAnimationFrame(n),()=>{cancelAnimationFrame(a)}}}),V=(t,e)=>t?"string"==typeof t&&y(t)?u(t,{token:e}):t:u("openfreemap-liberty");t.maplibregl=e,t.BASE_MAP_TYPES=f,t.OPENFREEMAP_STYLES=o,t.OPENFREEMAP_STYLE_BASE_URL=n,t.OPENFREEMAP_STYLE_TYPES=l,t.TDT_STYLE_TYPES=["tdt-image","tdt-image-label"],t.addDirectionalPulse=(t,e)=>D(t,e,Q),t.addPulseMarker=(t,e)=>D(t,e,T),t.addRadarSweep=(t,e)=>D(t,e,U),t.addRingPulseMarker=(t,e)=>D(t,e,z),t.addSectorScan=(t,e)=>D(t,e,J),t.createMap=t=>{const{style:i,tdtToken:a,...n}=t;return new e.Map({...n,style:V(i,a)})},t.createTiandituImageStyle=h,t.createTiandituRasterSource=d,t.getBaseMapStyle=u,t.getMaplibreToolsConfig=a,t.getOpenFreeMapStyle=c,t.isBaseMapType=y,t.setBaseMap=(t,e,i={})=>{const{diff:a=!1,...n}=i;t.setStyle(u(e,n),{diff:a})},t.setMaplibreToolsConfig=t=>{Object.assign(i,t)},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("maplibre-gl")):"function"==typeof define&&define.amd?define(["exports","maplibre-gl"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).BitAllTechMaplibreCore={},t.maplibregl)}(this,function(t,e){"use strict";const i={},o=()=>({...i}),n="https://tiles.openfreemap.org/styles",r=(t,e,i)=>({type:t,label:e,style:`${n}/${i}`}),a={"openfreemap-liberty":r("openfreemap-liberty","OpenFreeMap Liberty","liberty"),"openfreemap-bright":r("openfreemap-bright","OpenFreeMap Bright","bright"),"openfreemap-positron":r("openfreemap-positron","OpenFreeMap Positron","positron"),"openfreemap-dark":r("openfreemap-dark","OpenFreeMap Dark","dark"),"openfreemap-fiord":r("openfreemap-fiord","OpenFreeMap Fiord","fiord")},c=Object.keys(a),l=(t="openfreemap-liberty")=>a[t].style,s=["0","1","2","3","4","5","6","7"],d="&copy; 天地图",p=(t,e)=>{const i=(t=>{const e=t||o().tdtToken;if(!e)throw new Error("Tianditu token is required. Pass token or call setMaplibreToolsConfig({ tdtToken }).");return e})(e);return s.map(e=>`https://t${e}.tianditu.gov.cn/DataServer?T=${t}&x={x}&y={y}&l={z}&tk=${i}`)},f=(t,e={})=>({type:"raster",tiles:p(t,e.token),tileSize:256,minzoom:0,maxzoom:18,attribution:d}),u=(t={})=>({type:"raster",tiles:p("vec_w",t.token),tileSize:256,minzoom:0,maxzoom:18,attribution:d}),h=(t={})=>{const e=!1!==t.label,i={"tdt-image":f("img_w",t)},o=[{id:"tdt-image",type:"raster",source:"tdt-image"}];return e&&(i["tdt-image-label"]=f("cia_w",t),o.push({id:"tdt-image-label",type:"raster",source:"tdt-image-label"})),{version:8,sources:i,layers:o}},y=(t={})=>{const e=!1!==t.label,i={"tdt-mvt":u(t)},o=[{id:"tdt-mvt",type:"raster",source:"tdt-mvt"}];return e&&(i["tdt-mvt-label"]=f("cva_w",t),o.push({id:"tdt-mvt-label",type:"raster",source:"tdt-mvt-label"})),{version:8,sources:i,layers:o}},g=[...Object.keys(a),"tdt-image","tdt-image-label","tdt-mvt","tdt-mvt-label"],m=t=>g.includes(t),M=(t="openfreemap-liberty",e={})=>"tdt-image"===t?h({...e,label:!1}):"tdt-image-label"===t?h({...e,label:!0}):"tdt-mvt"===t?y({...e,label:!1}):"tdt-mvt-label"===t?y({...e,label:!0}):l(t),b=6378137,$=t=>t*Math.PI/180,k=t=>180*t/Math.PI,v=t=>(t%360+360)%360,w=(t,e,i)=>{const o=e/b,n=$(i),r=$(t[1]),a=$(t[0]),c=Math.asin(Math.sin(r)*Math.cos(o)+Math.cos(r)*Math.sin(o)*Math.cos(n)),l=a+Math.atan2(Math.sin(n)*Math.sin(o)*Math.cos(r),Math.cos(o)-Math.sin(r)*Math.sin(c));return[(s=k(l),s>180?s-360:s<-180?s+360:s),k(c)];var s},A=(t,e)=>{const i=$(e[1]-t[1]),o=$(e[0]-t[0]),n=$(t[1]),r=$(e[1]),a=Math.sin(i/2)*Math.sin(i/2)+Math.cos(n)*Math.cos(r)*Math.sin(o/2)*Math.sin(o/2);return 12756274*Math.atan2(Math.sqrt(a),Math.sqrt(1-a))},x=(t,e)=>{const i=$(t[1]),o=$(e[1]),n=$(e[0]-t[0]),r=Math.sin(n)*Math.cos(o),a=Math.cos(i)*Math.sin(o)-Math.sin(i)*Math.cos(o)*Math.cos(n);return v(k(Math.atan2(r,a)))},F=(t,e,i=64)=>{const o=((t,e)=>{const i=v(e)-v(t);return i<=0?i+360:i})(t,e),n=Math.max(12,Math.ceil(i*o/360));return Array.from({length:n+1},(e,i)=>v(t+o*i/n))},O=(t,e,i=64)=>(t=>{if(0===t.length)return t;const[e,i]=t[0],o=t[t.length-1];return o[0]===e&&o[1]===i?t:[...t,[e,i]]})(Array.from({length:i},(o,n)=>w(t,e,360*n/i))),q=(t,e,i=64)=>({type:"Polygon",coordinates:[O(t,e,i)]}),P=(t,e,i=64)=>({type:"LineString",coordinates:O(t,e,i)}),j=(t,e,i,o,n=64)=>{const r=F(i,o,n).map(i=>w(t,e,i));return{type:"Polygon",coordinates:[[t,...r,t]]}},S=(t,e,i,o,n=64)=>({type:"LineString",coordinates:F(i,o,n).map(i=>w(t,e,i))}),L=(t,e,i)=>({type:"LineString",coordinates:[t,w(t,e,i)]}),T=(t,e)=>({type:"Feature",geometry:t,properties:e}),D=t=>({type:"FeatureCollection",features:t}),z=(t,e)=>{t.getLayer(e)&&t.removeLayer(e)},I=(t,e)=>{t.getSource(e)&&t.removeSource(e)},B=(t,e,i)=>{const o=i?"visible":"none";e.forEach(e=>{t.getLayer(e)&&t.setLayoutProperty(e,"visibility",o)})},_=t=>t instanceof Error&&"Style is not done loading."===t.message,C=(t,e,i)=>{const o=e.id,n=`${o}-source`;let r,a={...e},c=[],l=[n],s=!1,d=!1;const p=()=>{null==r||r(),r=void 0,[...c].reverse().forEach(e=>{z(t,e)}),[...l].reverse().forEach(e=>{I(t,e)}),c=[],l=[n]},f=e=>{const i=t.getSource(n);i&&i.setData(e)},u=()=>{try{(()=>{var e,o,d;if(s)return;p();const u=i(a);t.addSource(n,{type:"geojson",data:u.data}),null==(e=u.canvasSources)||e.forEach(e=>{t.addSource(e.id,e.source)}),l=[n,...(null==(o=u.canvasSources)?void 0:o.map(t=>t.id))||[]],c=u.layers.map(t=>t.id),u.layers.forEach(e=>{var i;const o="raster"===e.type&&(null==(i=u.canvasSources)?void 0:i[0])?u.canvasSources[0].id:n;t.addLayer({...e,source:o},a.beforeId)}),B(t,c,!1!==a.visible),null==(d=u.canvasSources)||d.forEach(e=>{var i;const o=t.style,n=null==(i=null==o?void 0:o.tileManagers)?void 0:i[e.id];if(!n||!n.t)return;const r=n.used;n.used=!0;const a=t;n.update(a.transform,a.terrain),n.used=r}),u.startAnimation&&(r=u.startAnimation({getOptions:()=>a,setData:f})||void 0)})(),d&&(d=!1,t.off("styledata",h))}catch(e){if(!_(e))throw e;d||(d=!0,t.on("styledata",h))}},h=()=>{d&&!s&&u()},y=()=>{s||u()};return y(),{id:o,update(t){s||(a={...a,...t,id:o},y())},show(){s||(a={...a,visible:!0},B(t,c,!0))},hide(){s||(a={...a,visible:!1},B(t,c,!1))},remove(){s||(s=!0,d&&(d=!1,t.off("styledata",h)),p())}}},N=(t,e=0)=>{const i=Math.max(10,t.radius??70),o=Math.max(i,t.maxRadius??2.3*i),n=Math.max(1,t.pulseCount??2),r=Math.max(1,t.lineWidth??2),a=t.pulseOpacity??.9,c=[T(q(t.center,i),{kind:"core"})];for(let l=0;l<n;l+=1){const s=(e+l/n)%1,d=i+(o-i)*s;c.push(T(P(t.center,d),{kind:"pulse",opacity:a*(1-s),width:r*(1-.35*s)}))}return D(c)},E=t=>{const e=t.color||"#ff3b30",i=t.fillColor||e;return{data:N(t),layers:[{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":i,"fill-opacity":t.fillOpacity??.28}},{id:`${t.id}-pulse`,type:"line",filter:["==",["get","kind"],"pulse"],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],t.pulseOpacity??.9],"line-width":["coalesce",["get","width"],t.lineWidth??2]}}],startAnimation({getOptions:t,setData:e}){const i=Math.max(400,t().duration??1800);let o=0;const n=performance.now(),r=a=>{const c=t();e(N(c,(a-n)%i/i)),o=requestAnimationFrame(r)};return o=requestAnimationFrame(r),()=>{cancelAnimationFrame(o)}}}},R=(t,e=0)=>{const i=Math.max(16,t.radius??110),o=Math.max(0,t.pulseScale??.16),n=(1-Math.cos(e*Math.PI*2))/2,r=i*(1+o*n),a=Math.max(1,t.ringCount??3),c=Math.max(2.2*r,t.maxRadius??i*(2.5*a)),l=c/a,s=t.fillOpacity??.28,d=[T(q(t.center,r),{kind:"core",opacity:s*(.88+.2*n)}),T(P(t.center,1.06*r),{kind:"core-ring",opacity:(t.lineOpacity??.95)*(.8+.2*n),width:Math.max(1,(t.lineWidth??3)*(.92+.12*n))})];for(let p=0;p<a;p+=1){const i=(p+e+1)*l%c||c,o=i/c;d.push(T(P(t.center,i),{kind:"ring",opacity:Math.max(.18,(t.lineOpacity??.95)*(1-.42*o)),width:Math.max(1,(t.lineWidth??3)*(1-.18*o))}))}return D(d)},W=t=>{const e=t.color||"#ef4444",i=t.fillColor||e;return{data:R(t),layers:[{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":i,"fill-opacity":["coalesce",["get","opacity"],t.fillOpacity??.28]}},{id:`${t.id}-rings`,type:"line",filter:["any",["==",["get","kind"],"ring"]],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],t.lineOpacity??.95],"line-width":["coalesce",["get","width"],t.lineWidth??3]}}],startAnimation({getOptions:t,setData:e}){const i=Math.max(600,t().duration??2e3);let o=0;const n=performance.now(),r=a=>{const c=t();e(R(c,(a-n)%i/i)),o=requestAnimationFrame(r)};return o=requestAnimationFrame(r),()=>{cancelAnimationFrame(o)}}}},X=(t,e=0)=>{const i=Math.max(1,t.radius??90),o=Math.max(1,t.minRadius??.78*i),n=Math.max(o,t.maxRadius??1.22*i),r=(1-Math.cos(e*Math.PI*2))/2,a=o+(n-o)*r,c=t.fillOpacity??.28,l=t.minFillOpacity??.46*c,s=t.strokeOpacity??.82,d=t.minStrokeOpacity??.38*s,p=1-r,f=[T(q(t.center,a),{kind:"breathing-fill",opacity:l+(c-l)*p})];return(t.strokeWidth??2)>0&&f.push(T(P(t.center,a),{kind:"breathing-stroke",opacity:d+(s-d)*p})),D(f)},Y=t=>{const e=t.color||"#1677ff",i=t.fillColor||e,o=t.strokeColor||e,n=Math.max(0,t.strokeWidth??2);return{data:X(t),layers:[{id:`${t.id}-breathing-fill`,type:"fill",filter:["==",["get","kind"],"breathing-fill"],paint:{"fill-color":i,"fill-opacity":["coalesce",["get","opacity"],t.fillOpacity??.28]}},{id:`${t.id}-breathing-stroke`,type:"line",filter:["==",["get","kind"],"breathing-stroke"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":o,"line-opacity":["coalesce",["get","opacity"],t.strokeOpacity??.82],"line-width":n}}],startAnimation({getOptions:t,setData:e}){const i=Math.max(400,t().duration??1800),o=performance.now();let n=0;const r=a=>{const c=t();e(X(c,(a-o)%i/i)),n=requestAnimationFrame(r)};return n=requestAnimationFrame(r),()=>{cancelAnimationFrame(n)}}}},G=(t,e,i)=>Math.min(i,Math.max(e,t)),H=t=>{const e=t.trim(),i=e.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);if(i){const t=i[1],e=3===t.length?t.split("").map(t=>t+t).join(""):t;return[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16)]}const o=e.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);if(o)return[G(Number(o[1]),0,255),G(Number(o[2]),0,255),G(Number(o[3]),0,255)]},J=t=>(t%360+360)%360,K=t=>(t-90)*Math.PI/180,Q=(t,e)=>{const i=H(t);return i?`rgba(${i[0]}, ${i[1]}, ${i[2]}, ${G(e,0,1)})`:t},U=t=>t*(2-t),V=(t,e)=>{const i=t.length-1;if(e<=0)return t[0];if(e>=i)return t[i];const o=Math.floor(e),n=e-o,[r,a]=[H(t[o]),H(t[o+1])];if(!r||!a)return t[Math.round(e)];const[c,l,s]=((t,e,i)=>[Math.round(t[0]+(e[0]-t[0])*i),Math.round(t[1]+(e[1]-t[1])*i),Math.round(t[2]+(e[2]-t[2])*i)])(r,a,n);return`rgb(${c},${l},${s})`},Z=(t,e)=>{const i=w(t,e,0)[1],o=w(t,e,90)[0],n=w(t,e,180)[1],r=w(t,e,270)[0];return[[r,i],[o,i],[o,n],[r,n]]},tt=t=>{var e;const i=null==(e=t.gradient)?void 0:e.colors;return Array.isArray(i)&&i.length>=2?i:void 0},et=(t,e,i=0)=>{const o=t.getContext("2d"),n=tt(e);if(!o||!e.gradient||!n)return;const r=t.width,a=r/2,c=a-2,l=e.startAngle+i,s=((t,e)=>{const i=J(e)-J(t);return i<=0?i+360:i})(l,e.endAngle+i),d=K(l),p=d+s*Math.PI/180,f=e.gradient.opacity??e.opacity??.28,u=e.gradient.centerOpacity??.25*f,h=e.gradient.edgeOpacity??f,y=o.createRadialGradient(a,a,0,a,a,c);n.forEach((t,e)=>{const i=e/Math.max(1,n.length-1),o=u+(h-u)*i;y.addColorStop(i,Q(t,o))}),o.clearRect(0,0,r,r),o.save(),o.beginPath(),o.moveTo(a,a),o.arc(a,a,c,d,p,!1),o.closePath(),o.clip(),o.fillStyle=y,o.fillRect(0,0,r,r),o.restore()},it=t=>{if(!tt(t))return;const e=(()=>{const t=document.createElement("canvas");return t.width=768,t.height=768,t})();return et(e,t),e},ot=(t,e,i)=>tt(t)?[]:[T(j(t.center,t.radius,e,i),{kind:"sector",color:t.color||"#ff453a",opacity:t.opacity??.28})],nt=(t,e=0)=>{const i=t.startAngle+e,o=t.endAngle+e,n=[...ot(t,i,o),T(L(t.center,t.radius,i),{kind:"frame"}),T(L(t.center,t.radius,o),{kind:"frame"})];return D(n)},rt=t=>{const e=it(t),i=e?{id:`${t.id}-sector-fill`,type:"raster",paint:{"raster-opacity":1,"raster-fade-duration":0}}:{id:`${t.id}-sector-fill`,type:"fill",filter:["==",["get","kind"],"sector"],paint:{"fill-color":["coalesce",["get","color"],t.color||"#ff453a"],"fill-opacity":["coalesce",["get","opacity"],t.opacity??.28],"fill-antialias":!1}};return{data:nt(t),canvasSources:e?[{id:`${t.id}-canvas-source`,source:{type:"canvas",canvas:e,coordinates:Z(t.center,t.radius),animate:Boolean(t.rotationSpeed&&0!==t.rotationSpeed)}}]:void 0,layers:[i,{id:`${t.id}-sector-frame`,type:"line",filter:["==",["get","kind"],"frame"],paint:{"line-color":t.outlineColor||t.color||"#ff453a","line-opacity":t.outlineOpacity??.95,"line-width":t.outlineWidth??2}}],startAnimation:t.rotationSpeed&&0!==t.rotationSpeed?({getOptions:t,setData:i})=>{const o=performance.now();let n=0;const r=a=>{const c=t(),l=(a-o)/1e3*(c.rotationSpeed||0);e&&et(e,c,l),i(nt(c,l)),n=requestAnimationFrame(r)};return n=requestAnimationFrame(r),()=>{cancelAnimationFrame(n)}}:void 0}},at=(t,e)=>{const i=Math.max(40,t.radius),o=t.direction??270,n=Math.min(180,Math.max(8,t.spread??72)),r=Math.max(1,t.lineCount??7),a=Math.max(20,t.lineSpacing??Math.max(80,i/9)),c=e??0,l=Math.max(0,Math.min(.35*i,t.innerRadius??Math.min(.4*a,120))),s=o-n/2,d=o+n/2,p=[];for(let f=0;f<r;f+=1){const e=l+c+f*a;if(e>i)continue;const o=e/i,n=1-f/Math.max(1,r);p.push(T(S(t.center,e,s,d),{kind:"directional-pulse-line",opacity:Math.max(.08,(t.opacity??.92)*(.42+.58*n)*(1-.28*o)),width:Math.max(1,(t.lineWidth??2.8)*(.86+.24*n)*(1-.08*o))}))}return D(p)},ct=t=>({data:at(t),layers:[{id:`${t.id}-directional-pulse`,type:"line",filter:["==",["get","kind"],"directional-pulse-line"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":t.color||"#ef4444","line-opacity":["coalesce",["get","opacity"],t.opacity??.92],"line-width":["coalesce",["get","width"],t.lineWidth??2.8]}}],startAnimation:t.speed&&t.speed>0?({getOptions:t,setData:e})=>{const i=performance.now();let o=0;const n=r=>{const a=t(),c=Math.max(40,a.radius),l=Math.max(20,a.lineSpacing??Math.max(80,c/9)),s=(r-i)/1e3*(a.speed??0)%l;e(at(a,s)),o=requestAnimationFrame(n)};return o=requestAnimationFrame(n),()=>{cancelAnimationFrame(o)}}:void 0}),lt=t=>{var e;const i=null==(e=t.gradient)?void 0:e.colors;return Array.isArray(i)&&i.length>=2},st=(t,e)=>{const i=w(t,e,0)[1],o=w(t,e,90)[0],n=w(t,e,180)[1],r=w(t,e,270)[0];return[[r,i],[o,i],[o,n],[r,n]]},dt=(t,e,i=0)=>{const o=t.getContext("2d"),n=e.gradient,r=null==n?void 0:n.colors;if(!o||!n||!r||r.length<2)return;const a=t.width,c=a/2,l=c-2,s=Math.max(12,e.sweepAngle??42),d=e.tailOpacity??.04,p=Math.max(.24,e.opacity??.3),f=(e.sweepStartAngle??0)+i,u=f,h=f+s,y=s;o.clearRect(0,0,a,a);const g=o.createConicGradient(K(u),c,c),m=y/360,M=Math.min(1,p+.08);for(let b=0;b<=128;b++){const t=b/128,e=d+(M-d)*U(t),i=t*(r.length-1),o=V(r,i);g.addColorStop(t*m,Q(o,Math.max(0,e)))}o.save(),o.beginPath(),o.moveTo(c,c),o.arc(c,c,l,K(u),K(h),!1),o.closePath(),o.fillStyle=g,o.fill(),o.restore()},pt=(t,e=0)=>{var i;const o=Math.max(0,t.ringCount??4),n=Math.max(12,t.sweepAngle??42),r=t.headOpacity??Math.max(.24,t.opacity??.3),a=(t.sweepStartAngle??0)+e,c=!1!==t.showCrosshair,l=!1!==t.showDistanceLabels,s=Math.max(20,t.coreRadius??Math.min(160,.035*t.radius)),d=lt(t),p=[];for(let f=o;f>=1;f-=1){const e=t.radius*f/o;if(p.push(T(P(t.center,e),{kind:"ring"})),l){const o=(null==(i=t.distanceLabelFormatter)?void 0:i.call(t,e,f))??`${Math.round(e)}`;[{bearing:0,textAnchor:"bottom"},{bearing:90,textAnchor:"left"},{bearing:180,textAnchor:"top"},{bearing:270,textAnchor:"right"}].forEach(i=>{p.push(T({type:"Point",coordinates:w(t.center,e,i.bearing)},{kind:"distance-label",text:o,textAnchor:i.textAnchor}))})}}return c&&p.push(T({type:"LineString",coordinates:[w(t.center,t.radius,180),w(t.center,t.radius,0)]},{kind:"crosshair"}),T({type:"LineString",coordinates:[w(t.center,t.radius,270),w(t.center,t.radius,90)]},{kind:"crosshair"})),p.push(T(q(t.center,s),{kind:"core"})),d||p.push(T(j(t.center,t.radius,a,a+n),{kind:"sweep",opacity:r})),D(p)},ft=t=>{const e=lt(t)?(()=>{const t=document.createElement("canvas");return t.width=768,t.height=768,t})():void 0;e&&dt(e,t);const i=e?{id:`${t.id}-radar-trail`,type:"raster",paint:{"raster-opacity":1,"raster-fade-duration":0}}:{id:`${t.id}-radar-trail`,type:"fill",filter:["==",["get","kind"],"sweep"],paint:{"fill-color":t.color||"#22c55e","fill-opacity":["coalesce",["get","opacity"],t.opacity??.32]}};return{data:pt(t),canvasSources:e?[{id:`${t.id}-canvas-source`,source:{type:"canvas",canvas:e,coordinates:st(t.center,t.radius),animate:!0}}]:void 0,layers:[i,{id:`${t.id}-radar-rings`,type:"line",filter:["==",["get","kind"],"ring"],paint:{"line-color":t.ringColor||t.color||"#22c55e","line-opacity":t.ringOpacity??.95,"line-width":t.ringWidth??2}},{id:`${t.id}-radar-crosshair`,type:"line",filter:["==",["get","kind"],"crosshair"],paint:{"line-color":t.crosshairColor||t.ringColor||t.color||"#22c55e","line-opacity":t.crosshairOpacity??.5,"line-width":t.crosshairWidth??1.4}},{id:`${t.id}-radar-distance-labels`,type:"symbol",filter:["==",["get","kind"],"distance-label"],layout:{"text-field":["get","text"],"text-size":t.distanceLabelSize??12,"text-anchor":["get","textAnchor"],"text-allow-overlap":!0,"text-ignore-placement":!0},paint:{"text-color":t.distanceLabelColor||t.ringColor||t.color||"#22c55e","text-opacity":t.distanceLabelOpacity??.92,"text-halo-color":t.distanceLabelHaloColor||"rgba(15, 23, 42, 0.42)","text-halo-width":1}}],startAnimation({getOptions:t,setData:i}){const o=performance.now();let n=0;const r=a=>{const c=t(),l=(a-o)/1e3*(c.rotationSpeed??36);e&&dt(e,c,l),i(pt(c,l)),n=requestAnimationFrame(r)};return n=requestAnimationFrame(r),()=>{cancelAnimationFrame(n)}}}},ut=(t,e)=>{const i=w(t,e,0)[1],o=w(t,e,90)[0],n=w(t,e,180)[1],r=w(t,e,270)[0];return[[r,i],[o,i],[o,n],[r,n]]},ht=t=>{const e=(()=>{const t=document.createElement("canvas");return t.width=512,t.height=512,t})();((t,e)=>{const i=t.getContext("2d");if(!i)return;const o=t.width,n=o/2,r=n-1,a=e.color||"#06c536",c=e.fillColor||a,l=e.borderColor||a,s=e.fillOpacity??.06,d=e.borderOpacity??.92;i.clearRect(0,0,o,o),i.save(),i.beginPath(),i.arc(n,n,r,0,2*Math.PI),i.clip();const p=i.createRadialGradient(n,n,0,n,n,r),f=Math.min(.8,s+.85*(d-s));p.addColorStop(0,Q(c,s)),p.addColorStop(.85,Q(c,s)),p.addColorStop(.92,Q(l,s+.3*(f-s))),p.addColorStop(.96,Q(l,s+.7*(f-s))),p.addColorStop(1,Q(l,f)),i.fillStyle=p,i.fillRect(0,0,o,o),i.restore()})(e,t);const i=t.borderColor||t.color||"#06c536";return{data:D([T(P(t.center,t.radius),{kind:"defence-border"})]),canvasSources:[{id:`${t.id}-canvas-source`,source:{type:"canvas",canvas:e,coordinates:ut(t.center,t.radius),animate:!0}}],layers:[{id:`${t.id}-defence-circle`,type:"raster",paint:{"raster-opacity":1,"raster-fade-duration":0}},{id:`${t.id}-defence-border`,type:"line",filter:["==",["get","kind"],"defence-border"],paint:{"line-color":i,"line-opacity":t.borderOpacity??.92,"line-width":t.borderWidth??2}}]}},yt=(t,e=0)=>{const i=Math.max(1,t.sourceWidth??220),o=Math.max(1,t.targetWidth??45),n=(t=>{const e=t.target||w(t.center,t.distance||0,t.bearing||0),i=void 0!==t.target?x(t.center,t.target):v(t.bearing||0),o=w(t.center,t.startWidth/2,i-90),n=w(t.center,t.startWidth/2,i+90);return{polygon:{type:"Polygon",coordinates:[[o,w(e,t.endWidth/2,i-90),w(e,t.endWidth/2,i+90),n,o]]},centerLine:{type:"LineString",coordinates:[t.center,e]}}})({center:t.center,target:t.target,startWidth:i,endWidth:o}),r=[T(n.polygon,{kind:"countermeasure-channel"}),T(n.centerLine,{kind:"countermeasure-line"})],a=A(t.center,t.target),c=x(t.center,t.target),l=Math.max(0,Math.floor(t.particleCount??18)),s=Math.max(300,t.particleDuration??1200),d=e%s/s,p=Math.max(1,t.particleRadius??2.8);if(a>0)for(let f=0;f<l;f+=1){const e=(d+f/l)%1;r.push(T({type:"Point",coordinates:w(t.center,a*e,c)},{kind:"countermeasure-particle",opacity:.25+.75*e,radius:p*(.7+.3*e)}))}if(!1!==t.targetRipple){const i=Math.max(1,Math.floor(t.targetRippleCount??2)),o=Math.max(10,t.targetRippleRadius??120),n=Math.max(300,t.targetRippleDuration??900),a=e%n/n;for(let e=0;e<i;e+=1){const n=(a+e/i)%1,c="forcedLanding"===t.mode?1-n:n;r.push(T(P(t.target,Math.max(2,o*c)),{kind:"countermeasure-target-ripple",opacity:.9*Math.sin(Math.PI*n)}))}}return D(r)},gt=t=>{const e=t.color??"#a855f7",i=t.lineColor??"#f0abfc",o=Math.max(1,t.lineWidth??2.5);return{data:yt(t),layers:[{id:`${t.id}-countermeasure-channel`,type:"fill",filter:["==",["get","kind"],"countermeasure-channel"],paint:{"fill-color":t.channelColor??e,"fill-opacity":t.channelOpacity??.16}},{id:`${t.id}-countermeasure-glow`,type:"line",filter:["==",["get","kind"],"countermeasure-line"],layout:{"line-cap":"round"},paint:{"line-color":i,"line-opacity":.28*(t.lineOpacity??.92),"line-width":4*o,"line-blur":1.4*o}},{id:`${t.id}-countermeasure-line`,type:"line",filter:["==",["get","kind"],"countermeasure-line"],layout:{"line-cap":"round"},paint:{"line-color":i,"line-opacity":t.lineOpacity??.92,"line-width":o}},{id:`${t.id}-countermeasure-target-ripple`,type:"line",filter:["==",["get","kind"],"countermeasure-target-ripple"],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],.9],"line-width":Math.max(1,t.targetRippleWidth??2.5)}},{id:`${t.id}-countermeasure-particle`,type:"circle",filter:["==",["get","kind"],"countermeasure-particle"],paint:{"circle-color":t.particleColor??i,"circle-opacity":["coalesce",["get","opacity"],1],"circle-radius":["coalesce",["get","radius"],2.8],"circle-blur":.18,"circle-stroke-color":"#ffffff","circle-stroke-opacity":.45,"circle-stroke-width":.5}}],startAnimation:({getOptions:t,setData:e})=>{let i=0;const o=performance.now(),n=r=>{e(yt(t(),r-o)),i=requestAnimationFrame(n)};return i=requestAnimationFrame(n),()=>cancelAnimationFrame(i)}}},mt=(t,e=0)=>{const i=[],o=new Set,n=Math.max(0,Math.floor(t.particleCount??5)),r=Math.max(300,t.particleDuration??1600),a=e%r/r,c=Math.max(1,t.particleRadius??2.5);if(t.links.forEach((e,r)=>{const l=e.color??("detection"===(s=e.type)?"#38bdf8":"command"===s?"#22d3ee":"#f97316");var s;const d=A(e.from,e.to),p=x(e.from,e.to);if(i.push(T({type:"LineString",coordinates:[e.from,e.to]},{kind:"coordination-link",linkType:e.type,color:l})),!1!==t.showNodes&&[e.from,e.to].forEach(t=>{const e=`${t[0]},${t[1]}`;o.has(e)||(o.add(e),i.push(T({type:"Point",coordinates:t},{kind:"coordination-node",color:l})))}),!(d<=0))for(let o=0;o<n;o+=1){const s=(a+o/n+r/t.links.length)%1;i.push(T({type:"Point",coordinates:w(e.from,d*s,p)},{kind:"coordination-particle",color:l,opacity:.35+.65*s,radius:c}))}}),!1!==t.targetRipple){const o=Math.max(300,t.targetRippleDuration??1200),n=e%o/o,r=Math.max(10,t.targetRippleRadius??100)*n;i.push(T(P(t.center,Math.max(2,r)),{kind:"coordination-target-ripple",opacity:.9*(1-n)}))}return D(i)},Mt=t=>{const e=Math.max(1,t.lineWidth??2.2),i=t.lineOpacity??.9;return{data:mt(t),layers:[{id:`${t.id}-coordination-detection`,type:"line",filter:["==",["get","linkType"],"detection"],paint:{"line-color":["coalesce",["get","color"],"#38bdf8"],"line-opacity":i,"line-width":e,"line-dasharray":[2,2]}},{id:`${t.id}-coordination-command`,type:"line",filter:["==",["get","linkType"],"command"],paint:{"line-color":["coalesce",["get","color"],"#22d3ee"],"line-opacity":i,"line-width":e,"line-dasharray":[.5,1.8]}},{id:`${t.id}-coordination-countermeasure`,type:"line",filter:["==",["get","linkType"],"countermeasure"],paint:{"line-color":["coalesce",["get","color"],"#f97316"],"line-opacity":i,"line-width":e+.8}},{id:`${t.id}-coordination-target-ripple`,type:"line",filter:["==",["get","kind"],"coordination-target-ripple"],paint:{"line-color":"#ff3b30","line-opacity":["coalesce",["get","opacity"],.9],"line-width":2.5}},{id:`${t.id}-coordination-node`,type:"circle",filter:["==",["get","kind"],"coordination-node"],paint:{"circle-color":["coalesce",["get","color"],"#ffffff"],"circle-radius":Math.max(2,t.nodeRadius??5),"circle-stroke-color":"#ffffff","circle-stroke-width":1.5}},{id:`${t.id}-coordination-particle`,type:"circle",filter:["==",["get","kind"],"coordination-particle"],paint:{"circle-color":["coalesce",["get","color"],"#ffffff"],"circle-opacity":["coalesce",["get","opacity"],1],"circle-radius":["coalesce",["get","radius"],2.5],"circle-blur":.1}}],startAnimation:({getOptions:t,setData:e})=>{let i=0;const o=performance.now(),n=r=>{e(mt(t(),r-o)),i=requestAnimationFrame(n)};return i=requestAnimationFrame(n),()=>cancelAnimationFrame(i)}}},bt=(t,e=0)=>{const i=[T({type:"LineString",coordinates:[t.center,t.spoofedPosition]},{kind:"spoofing-offset"})],o=A(t.center,t.spoofedPosition),n=x(t.center,t.spoofedPosition),r=Math.max(0,Math.floor(t.particleCount??10)),a=Math.max(300,t.particleDuration??1800),c=e%a/a;if(!1!==t.showTruePosition&&i.push(T({type:"Point",coordinates:t.center},{kind:"spoofing-true-position"})),!1!==t.showSpoofedPosition&&i.push(T({type:"Point",coordinates:t.spoofedPosition},{kind:"spoofing-ghost"})),o>0)for(let l=0;l<r;l+=1){const e=(c+l/r)%1;i.push(T({type:"Point",coordinates:w(t.center,o*e,n)},{kind:"spoofing-particle",opacity:.25+.75*e}))}if(!1!==t.ripple){const o=Math.max(1,Math.floor(t.rippleCount??2)),n=Math.max(300,t.rippleDuration??1200),r=Math.max(10,t.rippleRadius??120),a=e%n/n;for(let e=0;e<o;e+=1){const n=(a+e/o)%1;i.push(T(P(t.spoofedPosition,Math.max(2,r*n)),{kind:"spoofing-ripple",opacity:.75*(1-n)}))}}return D(i)},$t=t=>{const e=t.color??"#8b5cf6";return{data:bt(t),layers:[{id:`${t.id}-spoofing-offset`,type:"line",filter:["==",["get","kind"],"spoofing-offset"],layout:{"line-cap":"round"},paint:{"line-color":t.lineColor??e,"line-opacity":t.lineOpacity??.82,"line-width":Math.max(1,t.lineWidth??2),"line-dasharray":[1.2,2]}},{id:`${t.id}-spoofing-ripple`,type:"line",filter:["==",["get","kind"],"spoofing-ripple"],paint:{"line-color":e,"line-opacity":["coalesce",["get","opacity"],.75],"line-width":2}},{id:`${t.id}-spoofing-true-position`,type:"circle",filter:["==",["get","kind"],"spoofing-true-position"],paint:{"circle-color":"#ffffff","circle-radius":5,"circle-stroke-color":e,"circle-stroke-width":2}},{id:`${t.id}-spoofing-ghost`,type:"circle",filter:["==",["get","kind"],"spoofing-ghost"],paint:{"circle-color":e,"circle-opacity":t.ghostOpacity??.42,"circle-radius":Math.max(2,t.ghostRadius??8),"circle-stroke-color":"#ffffff","circle-stroke-opacity":.8,"circle-stroke-width":1.5}},{id:`${t.id}-spoofing-particle`,type:"circle",filter:["==",["get","kind"],"spoofing-particle"],paint:{"circle-color":e,"circle-opacity":["coalesce",["get","opacity"],1],"circle-radius":Math.max(1,t.particleRadius??2.5),"circle-blur":.12}}],startAnimation:({getOptions:t,setData:e})=>{let i=0;const o=performance.now(),n=r=>{e(bt(t(),r-o)),i=requestAnimationFrame(n)};return i=requestAnimationFrame(n),()=>cancelAnimationFrame(i)}}},kt=(t,e)=>t?"string"==typeof t&&m(t)?M(t,{token:e}):t:M("openfreemap-liberty");t.maplibregl=e,t.BASE_MAP_TYPES=g,t.OPENFREEMAP_STYLES=a,t.OPENFREEMAP_STYLE_BASE_URL=n,t.OPENFREEMAP_STYLE_TYPES=c,t.TDT_STYLE_TYPES=["tdt-image","tdt-image-label","tdt-mvt","tdt-mvt-label"],t.addBreachAlert=(t,e)=>{const i=e.id,o=`${i}-fence-source`,n=`${i}-fence-fill`,r=`${i}-fence-line`,a=`${i}-ripple-source`,c=`${i}-ripple-line`;let l,s,d,p={...e},f=!1,u=!1,h=!1,y=!1,g=0;const m=()=>p.fenceColor??"#1677ff",M=()=>p.fenceFillColor??m(),b=()=>p.fenceFillOpacity??.1,$=()=>p.fenceBorderWidth??2,k=()=>p.fenceBorderOpacity??.9,v=()=>p.fenceAlertColor??"#ff3b30",w=()=>p.rippleColor??v(),A=e=>{const i=t.getSource(a);i&&i.setData(e)},x=t=>{const e=Math.max(20,p.rippleRadius??800),i=Math.max(1,p.rippleCount??3),o=Math.max(400,p.rippleDuration??1500),n=Math.max(1,p.rippleLineWidth??3),r=performance.now(),a=c=>{A(((t,e,i,o,n,r)=>{const a=[];for(let c=0;c<i;c+=1){const l=(r/o+c/i)%1,s=l*e;s<1||a.push(T(P(t,s),{kind:"ring",opacity:.95*(1-l),width:n*(1-.3*l)}))}return D(a)})(t,e,i,o,n,c-r)),g=requestAnimationFrame(a)};g=requestAnimationFrame(a)},F=()=>{if(!h)return;const e=m(),i=M();t.getLayer(n)&&(t.setPaintProperty(n,"fill-color",i),t.setPaintProperty(n,"fill-opacity",b())),t.getLayer(r)&&(t.setPaintProperty(r,"line-color",e),t.setPaintProperty(r,"line-width",$()),t.setPaintProperty(r,"line-opacity",k()))},O=()=>{const e=p.tacticalColor??v(),i=Math.max(1,p.tacticalBorderWidth??4),o="viewport"===p.tacticalScope?12:0,n=Math.max(60,p.fenceFlashInterval??200),r=t.getContainer(),a=document.createElement("div");a.style.position="absolute",a.style.inset=`${o}px`,a.style.border=`${i}px solid ${e}`,a.style.boxShadow=`inset 0 0 ${6*i}px ${e}`,a.style.pointerEvents="none",a.style.zIndex="5",a.style.opacity="1",r.appendChild(a),d=a;let c=!0;s=setInterval(()=>{c=!c,a.style.opacity=c?"1":"0.15"},n)},q=()=>{const e=(t=>{if(!t)return[];if(Array.isArray(t))return[{type:"Polygon",coordinates:t}];switch(t.type){case"Polygon":return[t];case"MultiPolygon":return t.coordinates.map(t=>({type:"Polygon",coordinates:t}));case"Feature":{const e=t.geometry;return"Polygon"===(null==e?void 0:e.type)?[e]:"MultiPolygon"===(null==e?void 0:e.type)?e.coordinates.map(t=>({type:"Polygon",coordinates:t})):[]}case"FeatureCollection":{const e=[];for(const i of t.features){const t=i.geometry;"Polygon"===(null==t?void 0:t.type)?e.push(t):"MultiPolygon"===(null==t?void 0:t.type)&&e.push(...t.coordinates.map(t=>({type:"Polygon",coordinates:t})))}return e}default:return[]}})(p.fence);if(0===e.length)return;const i=D(e.map(t=>T(t,{kind:"fence"})));if(h){const e=t.getSource(o);e&&e.setData(i),F()}else t.getSource(o)?t.getSource(o).setData(i):t.addSource(o,{type:"geojson",data:i}),t.getLayer(n)||t.addLayer({id:n,type:"fill",source:o,filter:["==",["get","kind"],"fence"],paint:{"fill-color":M(),"fill-opacity":b()}},p.beforeId),t.getLayer(r)||t.addLayer({id:r,type:"line",source:o,filter:["==",["get","kind"],"fence"],paint:{"line-color":m(),"line-width":$(),"line-opacity":k()}},p.beforeId),h=!0,B(t,[n,r],!1!==p.visible)},j=()=>{u&&!f&&S()},S=()=>{if(!f)try{q(),t.getSource(a)||t.addSource(a,{type:"geojson",data:D([])}),t.getLayer(c)?t.getLayer(c)&&t.setPaintProperty(c,"line-color",w()):(t.addLayer({id:c,type:"line",source:a,filter:["==",["get","kind"],"ring"],paint:{"line-color":w(),"line-opacity":["coalesce",["get","opacity"],.9],"line-width":["coalesce",["get","width"],3]}},p.beforeId),B(t,[c],!1!==p.visible)),u=!1,t.off("styledata",j)}catch(e){if(!_(e))throw e;u||(u=!0,t.on("styledata",j))}},L=()=>{l&&(clearInterval(l),l=void 0),g&&(cancelAnimationFrame(g),g=0),A(D([])),s&&(clearInterval(s),s=void 0),d&&(d.remove(),d=void 0),F()};return S(),{id:i,update(t){f||(p={...p,...t,id:i},S())},show(){f||(p={...p,visible:!0},B(t,[n,r,c],!0))},hide(){f||(p={...p,visible:!1},B(t,[n,r,c],!1))},remove(){f||(f=!0,u&&(u=!1,t.off("styledata",j)),L(),z(t,c),z(t,r),z(t,n),I(t,a),I(t,o),h=!1)},trigger(e){if(f)return;y&&L();const i=e??p.center;y=!0,!1!==p.fenceFlash&&(()=>{if(!h)return;const e=v(),i=Math.max(60,p.fenceFlashInterval??200);let o=!0;t.getLayer(n)&&(t.setPaintProperty(n,"fill-color",e),t.setPaintProperty(n,"fill-opacity",.42)),t.getLayer(r)&&(t.setPaintProperty(r,"line-color",e),t.setPaintProperty(r,"line-opacity",1)),l=setInterval(()=>{o=!o;const e=o?.42:.08,i=o?1:.4;t.getLayer(n)&&t.setPaintProperty(n,"fill-opacity",e),t.getLayer(r)&&t.setPaintProperty(r,"line-opacity",i)},i)})(),!1!==p.ripple&&x(i),p.tacticalFlash&&O()},reset(){f||(L(),y=!1)},isActive:()=>y}},t.addBreathingCircle=(t,e)=>C(t,e,Y),t.addCoordinatedCountermeasure=(t,e)=>C(t,e,Mt),t.addCountermeasureBeam=(t,e)=>C(t,e,gt),t.addDefenceCircle=(t,e)=>C(t,e,ht),t.addDirectionalPulse=(t,e)=>C(t,e,ct),t.addNavigationSpoofing=(t,e)=>C(t,e,$t),t.addPulseMarker=(t,e)=>C(t,e,E),t.addRadarSweep=(t,e)=>C(t,e,ft),t.addRingPulseMarker=(t,e)=>C(t,e,W),t.addSectorScan=(t,e)=>C(t,e,rt),t.addTargetLock=(t,i)=>{const o=i.id;let n,r={...i},a=!1;const c=document.createElement("div"),l=document.createElement("div"),s=Array.from({length:4},()=>document.createElement("div")),d=Array.from({length:4},()=>document.createElement("div"));c.dataset.effectId=o,c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.pointerEvents="none",l.style.position="absolute",l.style.inset="0",c.appendChild(l),s.forEach(t=>{t.style.position="absolute",t.style.boxSizing="border-box",l.appendChild(t)}),d.forEach(t=>{t.style.position="absolute",c.appendChild(t)});const p=new e.Marker({element:c,anchor:"center"}).setLngLat(r.center).addTo(t),f=()=>{const t=r.color??"#ff3b30",e=Math.max(24,r.size??72),i=Math.max(1,r.lineWidth??2),o=Math.min(e/2,Math.max(2*i,r.cornerLength??18)),a=Math.max(2,r.crosshairLength??10),f=Math.max(0,r.crosshairGap??5);p.setLngLat(r.center),c.style.width=`${e}px`,c.style.height=`${e}px`,c.style.display=!1===r.visible?"none":"block",c.style.opacity=`${Math.min(1,Math.max(0,r.opacity??1))}`,s.forEach(t=>{t.style.width=`${o}px`,t.style.height=`${o}px`,t.style.border="0"}),Object.assign(s[0].style,{left:"0",top:"0",borderLeft:`${i}px solid ${t}`,borderTop:`${i}px solid ${t}`}),Object.assign(s[1].style,{right:"0",top:"0",borderRight:`${i}px solid ${t}`,borderTop:`${i}px solid ${t}`}),Object.assign(s[2].style,{right:"0",bottom:"0",borderRight:`${i}px solid ${t}`,borderBottom:`${i}px solid ${t}`}),Object.assign(s[3].style,{left:"0",bottom:"0",borderLeft:`${i}px solid ${t}`,borderBottom:`${i}px solid ${t}`}),d.forEach(e=>{e.style.display=!1===r.showCrosshair?"none":"block",e.style.background=t}),Object.assign(d[0].style,{width:`${i}px`,height:`${a}px`,left:"50%",bottom:`calc(50% + ${f}px)`,transform:"translateX(-50%)"}),Object.assign(d[1].style,{width:`${i}px`,height:`${a}px`,left:"50%",top:`calc(50% + ${f}px)`,transform:"translateX(-50%)"}),Object.assign(d[2].style,{width:`${a}px`,height:`${i}px`,right:`calc(50% + ${f}px)`,top:"50%",transform:"translateY(-50%)"}),Object.assign(d[3].style,{width:`${a}px`,height:`${i}px`,left:`calc(50% + ${f}px)`,top:"50%",transform:"translateY(-50%)"}),null==n||n.cancel(),n=void 0,l.style.transform="rotate(0deg)",!1!==r.rotate&&(n=l.animate([{transform:"rotate(0deg)"},{transform:"rotate(360deg)"}],{duration:Math.max(300,r.rotationDuration??2400),iterations:1/0}))};return f(),{id:o,update(t){a||(r={...r,...t,id:o},f())},show(){a||(r={...r,visible:!0},c.style.display="block")},hide(){a||(r={...r,visible:!1},c.style.display="none")},remove(){a||(a=!0,null==n||n.cancel(),n=void 0,p.remove())}}},t.createFenceCircle=(t,e,i)=>q(t,e,i),t.createMap=t=>{const{style:i,tdtToken:o,...n}=t;return new e.Map({...n,style:kt(i,o)})},t.createTiandituImageStyle=h,t.createTiandituRasterSource=f,t.getBaseMapStyle=M,t.getMaplibreToolsConfig=o,t.getOpenFreeMapStyle=l,t.isBaseMapType=m,t.setBaseMap=(t,e,i={})=>{const{diff:o=!1,...n}=i;t.setStyle(M(e,n),{diff:o})},t.setMaplibreToolsConfig=t=>{Object.assign(i,t)},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
@@ -1,7 +1,7 @@
1
1
  import type { Map, StyleSpecification } from "maplibre-gl";
2
2
  import { type OpenFreeMapStyleType } from "./openfreemap";
3
3
  import { type TiandituStyleOptions } from "./tianditu";
4
- export type BaseMapType = OpenFreeMapStyleType | "tdt-image" | "tdt-image-label";
4
+ export type BaseMapType = OpenFreeMapStyleType | "tdt-image" | "tdt-image-label" | "tdt-mvt" | "tdt-mvt-label";
5
5
  export interface BaseMapOptions extends TiandituStyleOptions {
6
6
  /** 透传给 map.setStyle;false 会完整重载样式,true 会尝试差量更新。 */
7
7
  diff?: boolean;
@@ -11,6 +11,10 @@ export declare const BASE_MAP_TYPES: BaseMapType[];
11
11
  export declare const isBaseMapType: (type: string) => type is BaseMapType;
12
12
  /** 根据底图类型返回 MapLibre style。OpenFreeMap 返回 URL,天地图返回内联 style。 */
13
13
  export declare const getBaseMapStyle: (type?: BaseMapType, options?: TiandituStyleOptions) => string | StyleSpecification;
14
+ /**
15
+ * 切换内置底图。
16
+ * 注意:setStyle 会重建样式,业务图层/插件图层如需保留,应在 styledata/load 后自行恢复或使用对应控制器重建。
17
+ */
14
18
  export declare const setBaseMap: (map: Map, type: BaseMapType, options?: BaseMapOptions) => void;
15
19
  export * from "./openfreemap";
16
20
  export * from "./tianditu";
@@ -1,6 +1,6 @@
1
1
  import type { RasterSourceSpecification, StyleSpecification } from "maplibre-gl";
2
- /** 天地图图层类型:影像底图或影像注记。 */
3
- export type TiandituLayerType = "tdt-image" | "tdt-image-label";
2
+ /** 天地图图层类型:影像底图、影像注记、矢量底图、矢量注记。 */
3
+ export type TiandituLayerType = "tdt-image" | "tdt-image-label" | "tdt-mvt" | "tdt-mvt-label";
4
4
  export interface TiandituOptions {
5
5
  /** 天地图 token;不传时读取 setMaplibreToolsConfig 设置的全局 token。 */
6
6
  token?: string;
@@ -9,7 +9,10 @@ export interface TiandituStyleOptions extends TiandituOptions {
9
9
  /** 是否叠加注记图层,默认 true。 */
10
10
  label?: boolean;
11
11
  }
12
- export declare const TDT_STYLE_TYPES: readonly ["tdt-image", "tdt-image-label"];
13
- export declare const createTiandituRasterSource: (tileType: "img_w" | "cia_w", options?: TiandituOptions) => RasterSourceSpecification;
12
+ export declare const TDT_STYLE_TYPES: readonly ["tdt-image", "tdt-image-label", "tdt-mvt", "tdt-mvt-label"];
13
+ export declare const createTiandituRasterSource: (tileType: "img_w" | "cia_w" | "vec_w" | "cva_w", options?: TiandituOptions) => RasterSourceSpecification;
14
+ export declare const createTiandituMvtSource: (options?: TiandituOptions) => RasterSourceSpecification;
14
15
  /** 创建 MapLibre 可直接使用的天地图影像 style。 */
15
16
  export declare const createTiandituImageStyle: (options?: TiandituStyleOptions) => StyleSpecification;
17
+ /** 创建 MapLibre 可直接使用的天地图矢量 style。 */
18
+ export declare const createTiandituMvtStyle: (options?: TiandituStyleOptions) => StyleSpecification;
@@ -1,4 +1,5 @@
1
1
  export type LngLatTuple = [number, number];
2
+ /** 将任意角度规整到 0-360 度。 */
2
3
  export declare const normalizeAngle: (angle: number) => number;
3
4
  /** 从中心点按距离和方位角推算目标点,单位米/度。 */
4
5
  export declare const getDestination: (center: LngLatTuple, distance: number, bearing: number) => LngLatTuple;
@@ -9,6 +10,7 @@ export declare const getBearing: (start: LngLatTuple, end: LngLatTuple) => numbe
9
10
  /** 创建圆形外环坐标,圆在 GeoJSON 中用多边形近似。 */
10
11
  export declare const createCircleCoordinates: (center: LngLatTuple, radius: number, segmentCount?: number) => LngLatTuple[];
11
12
  export declare const createCirclePolygon: (center: LngLatTuple, radius: number, segmentCount?: number) => GeoJSON.Polygon;
13
+ /** 创建圆形线,适合脉冲环、雷达距离环。 */
12
14
  export declare const createCircleLine: (center: LngLatTuple, radius: number, segmentCount?: number) => GeoJSON.LineString;
13
15
  /** 创建扇形面:中心点 + 弧线点 + 中心点。 */
14
16
  export declare const createSectorPolygon: (center: LngLatTuple, radius: number, startAngle: number, endAngle: number, segmentCount?: number) => GeoJSON.Polygon;
@@ -1,2 +1,2 @@
1
- export { addDirectionalPulse, addPulseMarker, addRingPulseMarker, addRadarSweep, addSectorScan, } from "./low-altitude";
2
- export type { DirectionalPulseOptions, MapEffectController, PulseMarkerOptions, RingPulseMarkerOptions, RadarSweepOptions, SectorScanOptions, } from "./low-altitude";
1
+ export { addBreachAlert, addBreathingCircle, addCountermeasureBeam, addCoordinatedCountermeasure, addDefenceCircle, addDirectionalPulse, addNavigationSpoofing, addPulseMarker, addRingPulseMarker, addRadarSweep, addSectorScan, addTargetLock, createFenceCircle, } from "./low-altitude";
2
+ export type { BreachAlertController, BreachAlertOptions, BreathingCircleOptions, CountermeasureBeamOptions, CoordinatedCountermeasureOptions, CoordinationLink, CoordinationLinkType, DefenceCircleOptions, DirectionalPulseOptions, FenceGeometry, MapEffectController, NavigationSpoofingOptions, PulseMarkerOptions, RingPulseMarkerOptions, RadarSweepOptions, SectorScanOptions, TargetLockOptions, } from "./low-altitude";
@@ -1,4 +1,4 @@
1
- import type { Map } from "maplibre-gl";
1
+ import { type Map } from "maplibre-gl";
2
2
  import { type LngLatTuple } from "./geometry";
3
3
  interface BaseEffectOptions {
4
4
  /** 特效 id;会派生出 sourceId 和多个 layerId。 */
@@ -12,109 +12,352 @@ interface BaseEffectOptions {
12
12
  }
13
13
  /** addXxxEffect 返回的控制器,用于更新、显隐和移除特效。 */
14
14
  export interface MapEffectController<Options> {
15
+ /** 特效 id。 */
15
16
  id: string;
17
+ /** 更新特效配置。内部会重建 source/layer 或刷新动画数据。 */
16
18
  update: (options: Partial<Omit<Options, "id">>) => void;
19
+ /** 显示全部相关图层,不重新创建 source。 */
17
20
  show: () => void;
21
+ /** 隐藏全部相关图层,source 数据仍保留。 */
18
22
  hide: () => void;
23
+ /** 移除图层、source 和动画。调用后控制器不可再恢复。 */
19
24
  remove: () => void;
20
25
  }
21
26
  /** 单点扩散脉冲:适合告警点、事件点、目标点高亮。 */
22
27
  export interface PulseMarkerOptions extends BaseEffectOptions {
28
+ /** 中心实心区域半径,单位米。 */
23
29
  radius?: number;
30
+ /** 脉冲最大扩散半径,单位米。 */
24
31
  maxRadius?: number;
32
+ /** 主颜色。 */
25
33
  color?: string;
34
+ /** 中心填充色,默认跟随 color。 */
26
35
  fillColor?: string;
36
+ /** 中心填充透明度。 */
27
37
  fillOpacity?: number;
38
+ /** 脉冲环透明度。 */
28
39
  pulseOpacity?: number;
40
+ /** 脉冲环线宽。 */
29
41
  lineWidth?: number;
42
+ /** 同时存在的脉冲环数量。 */
30
43
  pulseCount?: number;
44
+ /** 一轮扩散动画时长,单位毫秒。 */
31
45
  duration?: number;
32
46
  }
33
47
  /** 多环脉冲:比普通脉冲更强调中心和外扩环。 */
34
48
  export interface RingPulseMarkerOptions extends BaseEffectOptions {
49
+ /** 核心半径,单位米。 */
35
50
  radius?: number;
36
- radii?: number[];
51
+ /** 外环最大半径,单位米。 */
37
52
  maxRadius?: number;
53
+ /** 外扩环数量。 */
38
54
  ringCount?: number;
55
+ /** 主颜色。 */
39
56
  color?: string;
57
+ /** 核心填充色。 */
40
58
  fillColor?: string;
59
+ /** 核心填充透明度。设为 0 可隐藏填充。 */
41
60
  fillOpacity?: number;
42
- haloOpacity?: number;
61
+ /** 核心描边线及外扩同心环的线透明度。 */
43
62
  lineOpacity?: number;
63
+ /** 环线宽度。 */
44
64
  lineWidth?: number;
65
+ /** 一轮动画时长,单位毫秒。 */
45
66
  duration?: number;
67
+ /** 核心呼吸缩放幅度。 */
46
68
  pulseScale?: number;
47
69
  }
48
- /** 扇形扫描渐变配置。colors 会从圆心沿半径方向过渡到外缘。 */
70
+ /** 呼吸圆:适合叠在图标、设备点或目标点后面做柔和背景高亮。 */
71
+ export interface BreathingCircleOptions extends BaseEffectOptions {
72
+ /** 基础半径,单位米。 */
73
+ radius?: number;
74
+ /** 呼吸最小半径,单位米;不传时根据 radius 自动计算。 */
75
+ minRadius?: number;
76
+ /** 呼吸最大半径,单位米;不传时根据 radius 自动计算。 */
77
+ maxRadius?: number;
78
+ /** 主颜色。 */
79
+ color?: string;
80
+ /** 填充色,默认跟随 color。 */
81
+ fillColor?: string;
82
+ /** 最亮时填充透明度。 */
83
+ fillOpacity?: number;
84
+ /** 最暗时填充透明度。 */
85
+ minFillOpacity?: number;
86
+ /** 描边颜色,默认跟随 color。 */
87
+ strokeColor?: string;
88
+ /** 最亮时描边透明度。 */
89
+ strokeOpacity?: number;
90
+ /** 最暗时描边透明度。 */
91
+ minStrokeOpacity?: number;
92
+ /** 描边宽度,单位像素。设为 0 可隐藏描边。 */
93
+ strokeWidth?: number;
94
+ /** 一轮呼吸动画时长,单位毫秒。 */
95
+ duration?: number;
96
+ }
97
+ /** 扇形扫描渐变配置。colors 在扇形扫描效果中会从圆心沿半径方向过渡到外缘。在雷达扫描中,centerOpacity 会从圆心开始,edgeOpacity 会从外缘开始。 */
49
98
  export interface SectorScanGradientOptions {
50
99
  colors?: string[];
51
- steps?: number;
52
100
  opacity?: number;
53
- /** 圆心附近透明度;不传时使用 tailOpacity 或基础透明度的 25%。 */
101
+ /** 圆心附近透明度;不传时使用基础透明度的 25%。 */
54
102
  centerOpacity?: number;
55
- /** 外缘透明度;不传时使用 headOpacity 或基础透明度。 */
103
+ /** 外缘透明度;不传时使用基础透明度。 */
56
104
  edgeOpacity?: number;
57
- /** 兼容旧配置:等同于 centerOpacity。 */
58
- tailOpacity?: number;
59
- /** 兼容旧配置:等同于 edgeOpacity。 */
60
- headOpacity?: number;
61
105
  }
62
106
  /** 扇形扫描:给定起止角度,可选旋转速度和分段渐变。 */
63
107
  export interface SectorScanOptions extends BaseEffectOptions {
108
+ /** 扇形半径,单位米。 */
64
109
  radius: number;
110
+ /** 起始方位角,0 表示正北,顺时针增加。 */
65
111
  startAngle: number;
112
+ /** 结束方位角,0 表示正北,顺时针增加。 */
66
113
  endAngle: number;
114
+ /** 纯色填充颜色;未传 gradient.colors 时使用。 */
67
115
  color?: string;
116
+ /** 纯色填充透明度,或渐变默认透明度。 */
68
117
  opacity?: number;
118
+ /** 径向渐变配置;colors 至少两个颜色时启用 Canvas 渐变。 */
69
119
  gradient?: SectorScanGradientOptions;
120
+ /** 扇形两条边线颜色。 */
70
121
  outlineColor?: string;
122
+ /** 扇形边线透明度。 */
71
123
  outlineOpacity?: number;
124
+ /** 扇形边线宽度。 */
72
125
  outlineWidth?: number;
126
+ /** 旋转速度,单位度/秒;不传或为 0 时静止。 */
73
127
  rotationSpeed?: number;
74
128
  }
75
129
  /** 定向脉冲:一组沿指定方向推进的弧线。 */
76
130
  export interface DirectionalPulseOptions extends BaseEffectOptions {
131
+ /** 最大脉冲半径,单位米。 */
77
132
  radius: number;
133
+ /** 中心方向角,0 表示正北。 */
78
134
  direction?: number;
135
+ /** 扇形展开角度。 */
79
136
  spread?: number;
137
+ /** 主颜色。 */
80
138
  color?: string;
139
+ /** 线透明度。 */
81
140
  opacity?: number;
141
+ /** 线宽。 */
82
142
  lineWidth?: number;
143
+ /** 同屏弧线数量。 */
83
144
  lineCount?: number;
145
+ /** 弧线间距,单位米。 */
84
146
  lineSpacing?: number;
147
+ /** 推进速度,单位米/秒;不传时静止。 */
85
148
  speed?: number;
149
+ /** 内侧起始半径,单位米。 */
86
150
  innerRadius?: number;
87
151
  }
88
152
  /** 雷达扫描:距离环、十字线、距离文字和旋转扫描尾迹。 */
89
153
  export interface RadarSweepOptions extends BaseEffectOptions {
154
+ /** 雷达半径,单位米。 */
90
155
  radius: number;
156
+ /** 扫描主色。 */
91
157
  color?: string;
158
+ /** 扫描面默认透明度。 */
92
159
  opacity?: number;
160
+ /** 单个扫描扇形角度。 */
93
161
  sweepAngle?: number;
162
+ /** 初始扫描起始角度。 */
94
163
  sweepStartAngle?: number;
164
+ /** 旋转速度,单位度/秒。 */
95
165
  rotationSpeed?: number;
166
+ /** 距离环数量。 */
96
167
  ringCount?: number;
168
+ /** 距离环颜色。 */
97
169
  ringColor?: string;
170
+ /** 距离环透明度。 */
98
171
  ringOpacity?: number;
172
+ /** 距离环线宽。 */
99
173
  ringWidth?: number;
100
- trailCount?: number;
174
+ /** 尾部透明度(渐变模式控制扫描起始边透明度)。 */
101
175
  tailOpacity?: number;
176
+ /** 头部透明度(渐变模式控制扫描结束边透明度)。 */
102
177
  headOpacity?: number;
178
+ /** 是否显示十字线。 */
103
179
  showCrosshair?: boolean;
180
+ /** 十字线颜色。 */
104
181
  crosshairColor?: string;
182
+ /** 十字线透明度。 */
105
183
  crosshairOpacity?: number;
184
+ /** 十字线宽度。 */
106
185
  crosshairWidth?: number;
186
+ /** 中心核心半径,单位米。 */
107
187
  coreRadius?: number;
188
+ /** 中心核心颜色。 */
108
189
  coreColor?: string;
190
+ /** 是否显示距离文字。 */
109
191
  showDistanceLabels?: boolean;
192
+ /** 距离文字颜色。 */
110
193
  distanceLabelColor?: string;
194
+ /** 距离文字 halo 颜色。 */
111
195
  distanceLabelHaloColor?: string;
196
+ /** 距离文字透明度。 */
112
197
  distanceLabelOpacity?: number;
198
+ /** 距离文字字号。 */
113
199
  distanceLabelSize?: number;
200
+ /** 自定义距离文字格式化。 */
114
201
  distanceLabelFormatter?: (distance: number, index: number) => string;
202
+ /** 径向渐变配置;colors 至少两个颜色时启用 Canvas 渐变渲染扫描区域。 */
203
+ gradient?: SectorScanGradientOptions;
204
+ }
205
+ /** 防御圆:静态地理圆,内部淡色填充经径向渐变过渡到边缘光晕,最外层叠加实心边框线,适合标识设备覆盖范围或防御区域。 */
206
+ export interface DefenceCircleOptions extends BaseEffectOptions {
207
+ /** 防御半径,单位米。 */
208
+ radius: number;
209
+ /** 主颜色。fillColor 和 borderColor 不传时默认跟随此值。 */
210
+ color?: string;
211
+ /** 内部填充色,不传时跟随 color。 */
212
+ fillColor?: string;
213
+ /** 内部填充透明度(渐变起始值)。 */
214
+ fillOpacity?: number;
215
+ /** 边框颜色,不传时跟随 color。 */
216
+ borderColor?: string;
217
+ /** 边框线宽,单位像素。 */
218
+ borderWidth?: number;
219
+ /** 边框线透明度(最外层实心边框)。 */
220
+ borderOpacity?: number;
221
+ }
222
+ /** 目标锁定:固定像素尺寸的四角锁定框和中心准星,适合跟随移动目标。 */
223
+ export interface TargetLockOptions extends BaseEffectOptions {
224
+ /** 锁定框颜色。 */
225
+ color?: string;
226
+ /** 锁定框尺寸,单位像素。 */
227
+ size?: number;
228
+ /** 线宽,单位像素。 */
229
+ lineWidth?: number;
230
+ /** 四角线段长度,单位像素。 */
231
+ cornerLength?: number;
232
+ /** 是否显示中心准星,默认 true。 */
233
+ showCrosshair?: boolean;
234
+ /** 中心准星单侧长度,单位像素。 */
235
+ crosshairLength?: number;
236
+ /** 准星与中心点之间的留白,单位像素。 */
237
+ crosshairGap?: number;
238
+ /** 是否旋转锁定框,默认 true。 */
239
+ rotate?: boolean;
240
+ /** 旋转一周时长,单位毫秒。 */
241
+ rotationDuration?: number;
242
+ /** 整体透明度。 */
243
+ opacity?: number;
244
+ }
245
+ /** 定向反制光束:由设备指向目标的收窄能量通道、粒子流和目标震荡环。 */
246
+ export interface CountermeasureBeamOptions extends BaseEffectOptions {
247
+ /** 反制目标经纬度。 */
248
+ target: LngLatTuple;
249
+ /** 反制模式。驱离时震荡环向外扩散,迫降时向目标收缩。 */
250
+ mode?: "expulsion" | "forcedLanding";
251
+ /** 主颜色。 */
252
+ color?: string;
253
+ /** 能量通道填充颜色,默认跟随 color。 */
254
+ channelColor?: string;
255
+ /** 能量通道透明度。 */
256
+ channelOpacity?: number;
257
+ /** 设备端通道宽度,单位米。 */
258
+ sourceWidth?: number;
259
+ /** 目标端通道宽度,单位米。 */
260
+ targetWidth?: number;
261
+ /** 中心束线颜色,默认使用偏亮的紫红色。 */
262
+ lineColor?: string;
263
+ /** 中心束线宽度,单位像素。 */
264
+ lineWidth?: number;
265
+ /** 中心束线透明度。 */
266
+ lineOpacity?: number;
267
+ /** 推进粒子颜色,默认跟随 lineColor。 */
268
+ particleColor?: string;
269
+ /** 同时显示的推进粒子数量;设为 0 可关闭。 */
270
+ particleCount?: number;
271
+ /** 粒子基础半径,单位像素。 */
272
+ particleRadius?: number;
273
+ /** 粒子从设备移动到目标所需时间,单位毫秒。 */
274
+ particleDuration?: number;
275
+ /** 是否显示目标端震荡环。 */
276
+ targetRipple?: boolean;
277
+ /** 目标端震荡环最大半径,单位米。 */
278
+ targetRippleRadius?: number;
279
+ /** 同时显示的震荡环数量。 */
280
+ targetRippleCount?: number;
281
+ /** 单轮震荡时长,单位毫秒。 */
282
+ targetRippleDuration?: number;
283
+ /** 震荡环线宽,单位像素。 */
284
+ targetRippleWidth?: number;
285
+ }
286
+ export type CoordinationLinkType = "detection" | "command" | "countermeasure";
287
+ export interface CoordinationLink {
288
+ /** 链路起点。 */
289
+ from: LngLatTuple;
290
+ /** 链路终点。 */
291
+ to: LngLatTuple;
292
+ /** 探测、指挥或反制链路。 */
293
+ type: CoordinationLinkType;
294
+ /** 覆盖该链路的默认颜色。 */
295
+ color?: string;
296
+ }
297
+ /** 多设备协同反制:展示探测、指挥和反制链路及其数据流向。 */
298
+ export interface CoordinatedCountermeasureOptions extends BaseEffectOptions {
299
+ /** 协同链路集合。center 表示当前处置目标位置。 */
300
+ links: CoordinationLink[];
301
+ /** 链路线宽,单位像素。 */
302
+ lineWidth?: number;
303
+ /** 链路透明度。 */
304
+ lineOpacity?: number;
305
+ /** 每条链路同时显示的流动粒子数量。 */
306
+ particleCount?: number;
307
+ /** 流动粒子半径,单位像素。 */
308
+ particleRadius?: number;
309
+ /** 粒子走完整条链路的时长,单位毫秒。 */
310
+ particleDuration?: number;
311
+ /** 是否显示链路端点。 */
312
+ showNodes?: boolean;
313
+ /** 链路端点半径,单位像素。 */
314
+ nodeRadius?: number;
315
+ /** 是否显示目标协同状态环。 */
316
+ targetRipple?: boolean;
317
+ /** 目标状态环最大半径,单位米。 */
318
+ targetRippleRadius?: number;
319
+ /** 目标状态环动画时长,单位毫秒。 */
320
+ targetRippleDuration?: number;
321
+ }
322
+ /** 导航诱骗:展示目标真实位置到诱导位置的偏移关系和诱导流向。 */
323
+ export interface NavigationSpoofingOptions extends BaseEffectOptions {
324
+ /** 后端或业务算法给出的诱导位置。center 表示目标真实位置。 */
325
+ spoofedPosition: LngLatTuple;
326
+ /** 主颜色。 */
327
+ color?: string;
328
+ /** 偏移虚线颜色,默认跟随 color。 */
329
+ lineColor?: string;
330
+ /** 偏移虚线宽度,单位像素。 */
331
+ lineWidth?: number;
332
+ /** 偏移虚线透明度。 */
333
+ lineOpacity?: number;
334
+ /** 诱导方向流动粒子数量。 */
335
+ particleCount?: number;
336
+ /** 粒子半径,单位像素。 */
337
+ particleRadius?: number;
338
+ /** 粒子从真实位置移动到诱导位置的时长,单位毫秒。 */
339
+ particleDuration?: number;
340
+ /** 是否显示真实位置点。 */
341
+ showTruePosition?: boolean;
342
+ /** 是否显示诱导位置虚影。 */
343
+ showSpoofedPosition?: boolean;
344
+ /** 诱导位置虚影半径,单位像素。 */
345
+ ghostRadius?: number;
346
+ /** 诱导位置虚影透明度。 */
347
+ ghostOpacity?: number;
348
+ /** 是否显示诱导位置脉冲环。 */
349
+ ripple?: boolean;
350
+ /** 诱导位置脉冲环最大半径,单位米。 */
351
+ rippleRadius?: number;
352
+ /** 同时显示的脉冲环数量。 */
353
+ rippleCount?: number;
354
+ /** 单轮脉冲动画时长,单位毫秒。 */
355
+ rippleDuration?: number;
115
356
  }
116
357
  /** 添加单点扩散脉冲特效。 */
117
358
  export declare const addPulseMarker: (map: Map, options: PulseMarkerOptions) => MapEffectController<PulseMarkerOptions>;
359
+ /** 添加呼吸圆特效。 */
360
+ export declare const addBreathingCircle: (map: Map, options: BreathingCircleOptions) => MapEffectController<BreathingCircleOptions>;
118
361
  /** 添加多环脉冲特效。 */
119
362
  export declare const addRingPulseMarker: (map: Map, options: RingPulseMarkerOptions) => MapEffectController<RingPulseMarkerOptions>;
120
363
  /** 添加扇形扫描特效。 */
@@ -123,4 +366,76 @@ export declare const addSectorScan: (map: Map, options: SectorScanOptions) => Ma
123
366
  export declare const addDirectionalPulse: (map: Map, options: DirectionalPulseOptions) => MapEffectController<DirectionalPulseOptions>;
124
367
  /** 添加雷达扫描特效。 */
125
368
  export declare const addRadarSweep: (map: Map, options: RadarSweepOptions) => MapEffectController<RadarSweepOptions>;
369
+ /** 添加防御圆特效。 */
370
+ export declare const addDefenceCircle: (map: Map, options: DefenceCircleOptions) => MapEffectController<DefenceCircleOptions>;
371
+ /** 添加定向反制光束。 */
372
+ export declare const addCountermeasureBeam: (map: Map, options: CountermeasureBeamOptions) => MapEffectController<CountermeasureBeamOptions>;
373
+ /** 添加多设备协同反制链路。 */
374
+ export declare const addCoordinatedCountermeasure: (map: Map, options: CoordinatedCountermeasureOptions) => MapEffectController<CoordinatedCountermeasureOptions>;
375
+ /** 添加导航诱骗位置偏移效果。 */
376
+ export declare const addNavigationSpoofing: (map: Map, options: NavigationSpoofingOptions) => MapEffectController<NavigationSpoofingOptions>;
377
+ /** 添加目标锁定框。锁定框使用 DOM Marker,缩放地图时保持固定像素尺寸。 */
378
+ export declare const addTargetLock: (map: Map, initialOptions: TargetLockOptions) => MapEffectController<TargetLockOptions>;
379
+ /** 围栏几何。
380
+ * 支持直接传入 edit 插件 getAll() 的 FeatureCollection(含多个围栏 feature),
381
+ * 也支持单个 Polygon / MultiPolygon / Feature,或多边形环坐标数组(外环在前)。
382
+ * 非 Polygon 几何(如 Point / LineString)会被忽略。 */
383
+ export type FenceGeometry = GeoJSON.Polygon | GeoJSON.MultiPolygon | GeoJSON.Feature<GeoJSON.Polygon | GeoJSON.MultiPolygon> | GeoJSON.FeatureCollection | LngLatTuple[][];
384
+ export interface BreachAlertOptions extends BaseEffectOptions {
385
+ /** 接触点经纬度,作为涟漪中心。trigger 时可传入覆盖。 */
386
+ center: LngLatTuple;
387
+ /** 围栏几何。围栏闪烁作用对象。 */
388
+ fence?: FenceGeometry;
389
+ /** 围栏正常态颜色(蓝/绿),默认 #1677ff。 */
390
+ fenceColor?: string;
391
+ /** 围栏填充色,默认跟随 fenceColor。 */
392
+ fenceFillColor?: string;
393
+ /** 围栏填充透明度,默认 0.1。 */
394
+ fenceFillOpacity?: number;
395
+ /** 围栏边框宽度,默认 2。 */
396
+ fenceBorderWidth?: number;
397
+ /** 围栏边框透明度,默认 0.9。 */
398
+ fenceBorderOpacity?: number;
399
+ /** 是否启用围栏高频闪烁警报,默认 true。 */
400
+ fenceFlash?: boolean;
401
+ /** 警报态颜色,默认 #ff3b30。 */
402
+ fenceAlertColor?: string;
403
+ /** 闪烁半周期 ms(亮→暗→亮),默认 200(高频)。 */
404
+ fenceFlashInterval?: number;
405
+ /** 是否启用接触点涟漪,默认 true。 */
406
+ ripple?: boolean;
407
+ /** 涟漪颜色,默认跟随 fenceAlertColor。 */
408
+ rippleColor?: string;
409
+ /** 涟漪最大扩散半径,单位米,默认 800。 */
410
+ rippleRadius?: number;
411
+ /** 同时扩散的环数,默认 3。 */
412
+ rippleCount?: number;
413
+ /** 单波扩散周期 ms(一个环从中心扩散到最大半径的时长),默认 1500。涟漪循环播放直到 reset。 */
414
+ rippleDuration?: number;
415
+ /** 涟漪线宽,默认 3。 */
416
+ rippleLineWidth?: number;
417
+ /** 是否启用战术框闪烁,默认 false。 */
418
+ tacticalFlash?: boolean;
419
+ /** 战术框范围,默认 'fullscreen'。'viewport' 表示内缩聚焦框。 */
420
+ tacticalScope?: "fullscreen" | "viewport";
421
+ /** 战术框颜色,默认跟随 fenceAlertColor。 */
422
+ tacticalColor?: string;
423
+ /** 边框粗细 px,默认 4。 */
424
+ tacticalBorderWidth?: number;
425
+ }
426
+ /** addBreachAlert 返回的控制器。在 MapEffectController 基础上扩展事件触发能力。 */
427
+ export interface BreachAlertController extends MapEffectController<BreachAlertOptions> {
428
+ /** 触发一次预警。传入接触点会覆盖 center;若已在警报中,先 reset 再触发。 */
429
+ trigger: (point?: LngLatTuple) => void;
430
+ /** 立即停止当前预警:围栏恢复原色、涟漪消散、战术框停止。 */
431
+ reset: () => void;
432
+ /** 当前是否处于警报中。 */
433
+ isActive: () => boolean;
434
+ }
435
+ /** 构造圆形围栏几何。
436
+ * GeoJSON 不支持 Circle 类型,这里用多边形近似(默认 64 段),
437
+ * 与 edit 插件画圆输出的格式一致,可直接作为 fence 传入。 */
438
+ export declare const createFenceCircle: (center: LngLatTuple, radius: number, segmentCount?: number) => GeoJSON.Polygon;
439
+ /** 添加围栏闯入预警特效。 */
440
+ export declare const addBreachAlert: (map: Map, initialOptions: BreachAlertOptions) => BreachAlertController;
126
441
  export {};