@bitalltech-maplibre/core 1.0.0

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/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # bitalltech-maplibre-core
2
+
3
+ BitAllTech MapLibre 核心工具包,封装地图初始化、内置底图和低空可视化特效。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install bitalltech-maplibre-core maplibre-gl
9
+ ```
10
+
11
+ ## 基础使用
12
+
13
+ ```ts
14
+ import {
15
+ createMap,
16
+ maplibregl,
17
+ setMaplibreToolsConfig,
18
+ } from "bitalltech-maplibre-core";
19
+ import "maplibre-gl/dist/maplibre-gl.css";
20
+
21
+ setMaplibreToolsConfig({
22
+ tdtToken: "你的天地图 token",
23
+ });
24
+
25
+ const map = createMap({
26
+ container: "map",
27
+ center: [116.39, 39.91],
28
+ zoom: 10.5,
29
+ style: "openfreemap-liberty",
30
+ attributionControl: false,
31
+ });
32
+
33
+ map.addControl(new maplibregl.NavigationControl(), "top-right");
34
+ ```
35
+
36
+ ## 地图初始化
37
+
38
+ `createMap(options)` 是 `new maplibregl.Map()` 的轻量封装,额外支持内置底图类型:
39
+
40
+ - `openfreemap-liberty`
41
+ - `openfreemap-bright`
42
+ - `openfreemap-positron`
43
+ - `openfreemap-dark`
44
+ - `openfreemap-fiord`
45
+ - `tdt-image`
46
+ - `tdt-image-label`
47
+
48
+ 如果 `style` 传入普通 URL 或完整 `StyleSpecification`,会原样交给 MapLibre。
49
+
50
+ ## 底图
51
+
52
+ ```ts
53
+ import { setBaseMap } from "bitalltech-maplibre-core";
54
+
55
+ setBaseMap(map, "tdt-image-label", {
56
+ token: "你的天地图 token",
57
+ diff: false,
58
+ });
59
+ ```
60
+
61
+ 天地图 token 可以通过单次调用传入,也可以通过 `setMaplibreToolsConfig({ tdtToken })` 设置全局默认值。
62
+
63
+ ## 低空特效
64
+
65
+ ```ts
66
+ import { addRadarSweep, addPulseMarker } from "bitalltech-maplibre-core";
67
+
68
+ const radar = addRadarSweep(map, {
69
+ id: "radar",
70
+ center: [116.39, 39.91],
71
+ radius: 3000,
72
+ color: "#22c55e",
73
+ });
74
+
75
+ const pulse = addPulseMarker(map, {
76
+ id: "event-pulse",
77
+ center: [116.41, 39.92],
78
+ color: "#ef4444",
79
+ });
80
+
81
+ radar.update({ radius: 5000 });
82
+ pulse.hide();
83
+ radar.remove();
84
+ ```
85
+
86
+ 扇形扫描支持从圆心到外缘的径向渐变:
87
+
88
+ ```ts
89
+ addSectorScan(map, {
90
+ id: "sector",
91
+ center: [116.39, 39.91],
92
+ radius: 1600,
93
+ startAngle: 215,
94
+ endAngle: 282,
95
+ outlineColor: "#22c55e",
96
+ gradient: {
97
+ colors: ["#f97316", "#facc15", "#22c55e"],
98
+ steps: 64,
99
+ centerOpacity: 0.08,
100
+ edgeOpacity: 0.34,
101
+ },
102
+ });
103
+ ```
104
+
105
+ 当前提供:
106
+
107
+ - `addPulseMarker`
108
+ - `addRingPulseMarker`
109
+ - `addSectorScan`
110
+ - `addDirectionalPulse`
111
+ - `addRadarSweep`
112
+
113
+ 这些方法都会返回控制器,支持 `update()`、`show()`、`hide()` 和 `remove()`。
114
+
115
+ ## 常用导出
116
+
117
+ - `createMap`、`maplibregl`
118
+ - `setMaplibreToolsConfig`、`getMaplibreToolsConfig`
119
+ - `getBaseMapStyle`、`setBaseMap`
120
+ - 低空特效方法和对应类型
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("maplibre-gl"),e={},a=()=>({...e}),r="https://tiles.openfreemap.org/styles",i=(t,e,a)=>({type:t,label:e,style:`${r}/${a}`}),n={"openfreemap-liberty":i("openfreemap-liberty","OpenFreeMap Liberty","liberty"),"openfreemap-bright":i("openfreemap-bright","OpenFreeMap Bright","bright"),"openfreemap-positron":i("openfreemap-positron","OpenFreeMap Positron","positron"),"openfreemap-dark":i("openfreemap-dark","OpenFreeMap Dark","dark"),"openfreemap-fiord":i("openfreemap-fiord","OpenFreeMap Fiord","fiord")},o=Object.keys(n),s=(t="openfreemap-liberty")=>n[t].style,l=["0","1","2","3","4","5","6","7"],c=(t,e)=>{const r=(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 l.map(e=>`https://t${e}.tianditu.gov.cn/DataServer?T=${t}&x={x}&y={y}&l={z}&tk=${r}`)},p=(t,e={})=>({type:"raster",tiles:c(t,e.token),tileSize:256,minzoom:0,maxzoom:18,attribution:"&copy; 天地图"}),d=(t={})=>{const e=!1!==t.label,a={"tdt-image":p("img_w",t)},r=[{id:"tdt-image",type:"raster",source:"tdt-image"}];return e&&(a["tdt-image-label"]=p("cia_w",t),r.push({id:"tdt-image-label",type:"raster",source:"tdt-image-label"})),{version:8,sources:a,layers:r}},h=[...Object.keys(n),"tdt-image","tdt-image-label"],y=t=>h.includes(t),f=(t="openfreemap-liberty",e={})=>"tdt-image"===t?d({...e,label:!1}):"tdt-image-label"===t?d({...e,label:!0}):s(t),u=t=>t*Math.PI/180,m=t=>180*t/Math.PI,g=t=>(t%360+360)%360,M=(t,e,a)=>{const r=e/6378137,i=u(a),n=u(t[1]),o=u(t[0]),s=Math.asin(Math.sin(n)*Math.cos(r)+Math.cos(n)*Math.sin(r)*Math.cos(i)),l=o+Math.atan2(Math.sin(i)*Math.sin(r)*Math.cos(n),Math.cos(r)-Math.sin(n)*Math.sin(s));return[(c=m(l),c>180?c-360:c<-180?c+360:c),m(s)];var c},b=(t,e,a=64)=>{const r=((t,e)=>{const a=g(e)-g(t);return a<=0?a+360:a})(t,e),i=Math.max(12,Math.ceil(a*r/360));return Array.from({length:i+1},(e,a)=>g(t+r*a/i))},x=(t,e,a=64)=>(t=>{if(0===t.length)return t;const[e,a]=t[0],r=t[t.length-1];return r[0]===e&&r[1]===a?t:[...t,[e,a]]})(Array.from({length:a},(r,i)=>M(t,e,360*i/a))),k=(t,e,a=64)=>({type:"Polygon",coordinates:[x(t,e,a)]}),v=(t,e,a=64)=>({type:"LineString",coordinates:x(t,e,a)}),A=(t,e,a,r,i=64)=>{const n=b(a,r,i).map(a=>M(t,e,a));return{type:"Polygon",coordinates:[[t,...n,t]]}},$=(t,e,a,r,i=64)=>({type:"LineString",coordinates:b(a,r,i).map(a=>M(t,e,a))}),w=(t,e,a)=>({type:"LineString",coordinates:[t,M(t,e,a)]}),F=(t,e)=>({type:"Feature",geometry:t,properties:e}),O=t=>({type:"FeatureCollection",features:t}),q=(t,e,a)=>{const r=a?"visible":"none";e.forEach(e=>{t.getLayer(e)&&t.setLayoutProperty(e,"visibility",r)})},S=(t,e,a)=>{const r=e.id,i=`${r}-source`;let n,o={...e},s=[],l=[i],c=!1,p=!1;const d=()=>{null==n||n(),n=void 0,[...s].reverse().forEach(e=>{((t,e)=>{t.getLayer(e)&&t.removeLayer(e)})(t,e)}),[...l].reverse().forEach(e=>{((t,e)=>{t.getSource(e)&&t.removeSource(e)})(t,e)}),s=[],l=[i]},h=e=>{const a=t.getSource(i);a&&a.setData(e)},y=()=>{var e,r;if(c)return;d();const p=a(o);t.addSource(i,{type:"geojson",data:p.data}),null==(e=p.canvasSources)||e.forEach(e=>{t.addSource(e.id,e.source)}),l=[i,...(null==(r=p.canvasSources)?void 0:r.map(t=>t.id))||[]],s=p.layers.map(t=>t.id),p.layers.forEach(e=>{var a;const r="raster"===e.type&&(null==(a=p.canvasSources)?void 0:a[0])?p.canvasSources[0].id:i;t.addLayer({...e,source:r},o.beforeId)}),q(t,s,!1!==o.visible),p.startAnimation&&(n=p.startAnimation({getOptions:()=>o,setData:h})||void 0)},f=()=>{p&&!c&&t.isStyleLoaded()&&(p=!1,t.off("styledata",f),y())},u=()=>{c||(t.isStyleLoaded()?(p&&(p=!1,t.off("styledata",f)),y()):p||(p=!0,t.on("styledata",f)))};return u(),{id:r,update(t){c||(o={...o,...t,id:r},u())},show(){c||(o={...o,visible:!0},q(t,s,!0))},hide(){c||(o={...o,visible:!1},q(t,s,!1))},remove(){c||(c=!0,p&&(p=!1,t.off("styledata",f)),d())}}},D=(t,e=0)=>{const a=Math.max(10,t.radius??70),r=Math.max(a,t.maxRadius??2.3*a),i=Math.max(1,t.pulseCount??2),n=Math.max(1,t.lineWidth??2),o=t.pulseOpacity??.9,s=[F(k(t.center,a),{kind:"core"})];for(let l=0;l<i;l+=1){const c=(e+l/i)%1,p=a+(r-a)*c;s.push(F(v(t.center,p),{kind:"pulse",opacity:o*(1-c),width:n*(1-.35*c)}))}return O(s)},j=t=>{const e=t.color||"#ff3b30",a=t.fillColor||e;return{data:D(t),layers:[{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":a,"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 a=Math.max(400,t().duration??1800);let r=0;const i=performance.now(),n=o=>{const s=t();e(D(s,(o-i)%a/a)),r=requestAnimationFrame(n)};return r=requestAnimationFrame(n),()=>{cancelAnimationFrame(r)}}}},L=(t,e=0)=>{var a,r;const i=Math.max(16,t.radius??110),n=Math.max(0,t.pulseScale??.16),o=(1-Math.cos(e*Math.PI*2))/2,s=i*(1+n*o),l=1.28*s,c=Math.max(1,t.ringCount??(null==(a=t.radii)?void 0:a.length)??3),p=Math.max(2.2*s,t.maxRadius??((null==(r=t.radii)?void 0:r.length)?Math.max(...t.radii):i*(2.5*c))),d=p/c,h=[F(k(t.center,l),{kind:"halo",opacity:(t.haloOpacity??.16)*(.75+.65*o)}),F(k(t.center,s),{kind:"core",opacity:(t.fillOpacity??.28)*(.88+.2*o)}),F(v(t.center,1.06*s),{kind:"core-ring",opacity:(t.lineOpacity??.95)*(.8+.2*o),width:Math.max(1,(t.lineWidth??3)*(.92+.12*o))})];for(let y=0;y<c;y+=1){const a=(y+e+1)*d%p||p,r=a/p;h.push(F(v(t.center,a),{kind:"ring",opacity:Math.max(.18,(t.lineOpacity??.95)*(1-.42*r)),width:Math.max(1,(t.lineWidth??3)*(1-.18*r))}))}return O(h)},z=t=>{const e=t.color||"#ef4444",a=t.fillColor||e;return{data:L(t),layers:[{id:`${t.id}-halo`,type:"fill",filter:["==",["get","kind"],"halo"],paint:{"fill-color":a,"fill-opacity":["coalesce",["get","opacity"],t.haloOpacity??.16]}},{id:`${t.id}-core`,type:"fill",filter:["==",["get","kind"],"core"],paint:{"fill-color":a,"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 a=Math.max(600,t().duration??2e3);let r=0;const i=performance.now(),n=o=>{const s=t();e(L(s,(o-i)%a/a)),r=requestAnimationFrame(n)};return r=requestAnimationFrame(n),()=>{cancelAnimationFrame(r)}}}},P=(t,e,a)=>Math.min(a,Math.max(e,t)),T=t=>(t%360+360)%360,I=(t,e)=>{const a=(t=>{const e=t.trim(),a=e.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);if(a){const t=a[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 r=e.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);if(r)return[P(Number(r[1]),0,255),P(Number(r[2]),0,255),P(Number(r[3]),0,255)]})(t);return a?`rgba(${a[0]}, ${a[1]}, ${a[2]}, ${P(e,0,1)})`:t},N=(t,e)=>{const a=M(t,e,0)[1],r=M(t,e,90)[0],i=M(t,e,180)[1],n=M(t,e,270)[0];return[[n,a],[r,a],[r,i],[n,i]]},B=t=>{var e;const a=null==(e=t.gradient)?void 0:e.colors;return Array.isArray(a)&&a.length>=2?a:void 0},C=(t,e,a=0)=>{const r=t.getContext("2d"),i=B(e);if(!r||!e.gradient||!i)return;const n=t.width,o=n/2,s=o-2,l=e.startAngle+a,c=((t,e)=>{const a=T(e)-T(t);return a<=0?a+360:a})(l,e.endAngle+a),p=(l-90)*Math.PI/180;const d=p+c*Math.PI/180,h=e.gradient.opacity??e.opacity??.28,y=e.gradient.centerOpacity??e.gradient.tailOpacity??.25*h,f=e.gradient.edgeOpacity??e.gradient.headOpacity??h,u=r.createRadialGradient(o,o,0,o,o,s);i.forEach((t,e)=>{const a=e/Math.max(1,i.length-1),r=y+(f-y)*a;u.addColorStop(a,I(t,r))}),r.clearRect(0,0,n,n),r.save(),r.beginPath(),r.moveTo(o,o),r.arc(o,o,s,p,d,!1),r.closePath(),r.clip(),r.fillStyle=u,r.fillRect(0,0,n,n),r.restore()},_=t=>{if(!B(t))return;const e=(()=>{const t=document.createElement("canvas");return t.width=768,t.height=768,t})();return C(e,t),e},E=(t,e,a)=>B(t)?[]:[F(A(t.center,t.radius,e,a),{kind:"sector",color:t.color||"#ff453a",opacity:t.opacity??.28})],G=(t,e=0)=>{const a=t.startAngle+e,r=t.endAngle+e,i=[...E(t,a,r),F(w(t.center,t.radius,a),{kind:"frame"}),F(w(t.center,t.radius,r),{kind:"frame"})];return O(i)},H=t=>{const e=_(t),a=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:G(t),canvasSources:e?[{id:`${t.id}-canvas-source`,source:{type:"canvas",canvas:e,coordinates:N(t.center,t.radius),animate:Boolean(t.rotationSpeed&&0!==t.rotationSpeed)}}]:void 0,layers:[a,{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:a})=>{const r=performance.now();let i=0;const n=o=>{const s=t(),l=(o-r)/1e3*(s.rotationSpeed||0);e&&C(e,s,l),a(G(s,l)),i=requestAnimationFrame(n)};return i=requestAnimationFrame(n),()=>{cancelAnimationFrame(i)}}:void 0}},J=(t,e)=>{const a=Math.max(40,t.radius),r=t.direction??270,i=Math.min(180,Math.max(8,t.spread??72)),n=Math.max(1,t.lineCount??7),o=Math.max(20,t.lineSpacing??Math.max(80,a/9)),s=e??0,l=Math.max(0,Math.min(.35*a,t.innerRadius??Math.min(.4*o,120))),c=r-i/2,p=r+i/2,d=[];for(let h=0;h<n;h+=1){const e=l+s+h*o;if(e>a)continue;const r=e/a,i=1-h/Math.max(1,n);d.push(F($(t.center,e,c,p),{kind:"directional-pulse-line",opacity:Math.max(.08,(t.opacity??.92)*(.42+.58*i)*(1-.28*r)),width:Math.max(1,(t.lineWidth??2.8)*(.86+.24*i)*(1-.08*r))}))}return O(d)},K=t=>({data:J(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 a=performance.now();let r=0;const i=n=>{const o=t(),s=Math.max(40,o.radius),l=Math.max(20,o.lineSpacing??Math.max(80,s/9)),c=(n-a)/1e3*(o.speed??0)%l;e(J(o,c)),r=requestAnimationFrame(i)};return r=requestAnimationFrame(i),()=>{cancelAnimationFrame(r)}}:void 0}),Q=(t,e=0)=>{var a;const r=Math.max(0,t.ringCount??4),i=Math.max(1,t.trailCount??8),n=Math.max(12,t.sweepAngle??42),o=.22*n,s=t.tailOpacity??.04,l=t.headOpacity??Math.max(.24,t.opacity??.3),c=(t.sweepStartAngle??0)+e,p=!1!==t.showCrosshair,d=!1!==t.showDistanceLabels,h=Math.max(20,t.coreRadius??Math.min(160,.035*t.radius)),y=[];for(let f=r;f>=1;f-=1){const e=t.radius*f/r;if(y.push(F(v(t.center,e),{kind:"ring"})),d){const r=(null==(a=t.distanceLabelFormatter)?void 0:a.call(t,e,f))??`${Math.round(e)}`;[{bearing:0,textAnchor:"bottom"},{bearing:90,textAnchor:"left"},{bearing:180,textAnchor:"top"},{bearing:270,textAnchor:"right"}].forEach(a=>{y.push(F({type:"Point",coordinates:M(t.center,e,a.bearing)},{kind:"distance-label",text:r,textAnchor:a.textAnchor}))})}}p&&y.push(F({type:"LineString",coordinates:[M(t.center,t.radius,180),M(t.center,t.radius,0)]},{kind:"crosshair"}),F({type:"LineString",coordinates:[M(t.center,t.radius,270),M(t.center,t.radius,90)]},{kind:"crosshair"})),y.push(F(k(t.center,h),{kind:"core"}));for(let f=i-1;f>=0;f-=1){const e=c-o*f,a=e+n,r=(i-f)/i,p=s+(l-s)*r*r;y.push(F(A(t.center,t.radius,e,a),{kind:"sweep",opacity:p}))}return y.push(F(A(t.center,t.radius,c+.42*n,c+n),{kind:"head",opacity:Math.min(1,l+.08)})),O(y)},R=t=>({data:Q(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 a=performance.now();let r=0;const i=n=>{const o=t(),s=(n-a)/1e3*(o.rotationSpeed??36);e(Q(o,s)),r=requestAnimationFrame(i)};return r=requestAnimationFrame(i),()=>{cancelAnimationFrame(r)}}}),U=(t,e)=>t?"string"==typeof t&&y(t)?f(t,{token:e}):t:f("openfreemap-liberty");exports.maplibregl=t,exports.BASE_MAP_TYPES=h,exports.OPENFREEMAP_STYLES=n,exports.OPENFREEMAP_STYLE_BASE_URL=r,exports.OPENFREEMAP_STYLE_TYPES=o,exports.TDT_STYLE_TYPES=["tdt-image","tdt-image-label"],exports.addDirectionalPulse=(t,e)=>S(t,e,K),exports.addPulseMarker=(t,e)=>S(t,e,j),exports.addRadarSweep=(t,e)=>S(t,e,R),exports.addRingPulseMarker=(t,e)=>S(t,e,z),exports.addSectorScan=(t,e)=>S(t,e,H),exports.createMap=e=>{const{style:a,tdtToken:r,...i}=e;return new t.Map({...i,style:U(a,r)})},exports.createTiandituImageStyle=d,exports.createTiandituRasterSource=p,exports.getBaseMapStyle=f,exports.getMaplibreToolsConfig=a,exports.getOpenFreeMapStyle=s,exports.isBaseMapType=y,exports.setBaseMap=(t,e,a={})=>{const{diff:r=!1,...i}=a;t.setStyle(f(e,i),{diff:r})},exports.setMaplibreToolsConfig=t=>{Object.assign(e,t)};