{"_id":"@bitalltech-maplibre/track","_rev":"8-1590751646802b4b290ece6c4861ba56","name":"@bitalltech-maplibre/track","dist-tags":{"latest":"1.2.1"},"versions":{"1.0.1":{"name":"@bitalltech-maplibre/track","version":"1.0.1","keywords":["bitalltech","maplibre","track","trajectory","realtime"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/track@1.0.1","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"59e1fc303c03d4215d770ac84fddf9659ed1b251","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/track/-/track-1.0.1.tgz","fileCount":10,"integrity":"sha512-3JeeLp5UooIn6lerulWEDp6PcL3khV8imH7/t/38fWH5beu4yuqaQogZd92xZ7X4vz99gIPtMkgW5MvrvboSFg==","signatures":[{"sig":"MEYCIQCcvljIg2QpQ3deLO2rMzw6FGjs42RbX3MLlWKmPbQ5lAIhAPVkHSbU1p0B718w9QiojhLbxtCY4Gx4CongoMm8ld0E","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82156},"main":"dist/index.cjs.js","types":"dist/types/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"195afa8e5c8710969c82c678cc5694eca09a6f59","scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"_npmVersion":"10.5.0","description":"BitAllTech MapLibre 实时目标轨迹渲染包","directories":{},"_nodeVersion":"20.12.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/track_1.0.1_1784103192646_0.4806100445593109","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@bitalltech-maplibre/track","version":"1.0.2","keywords":["bitalltech","maplibre","track","trajectory","realtime","cluster","svg"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/track@1.0.2","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"58937833121890b53c7ce913e989a6c59da42f69","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/track/-/track-1.0.2.tgz","fileCount":12,"integrity":"sha512-bICd3Xeo6zXm3PULI8XMCT5auQ9EWW9Qa4B+InFZjnpvVEOEtyl13wpXIrwt52ui08strPNibZCLZeYMd9kPlQ==","signatures":[{"sig":"MEYCIQD2CBgIKGLUwzkUXX7v+kVq1bwXW/KcLFLs4O+t0+sfagIhAOegWhF55X3j2uBA+7cCYVRObYsjOy7LMhc187NcbmyT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":136204},"main":"dist/index.cjs.js","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.js","module":"dist/index.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"2c25cb28ec5522380181bba6304e021a6f08a9ca","scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"jsdelivr":"dist/index.umd.js","_npmVersion":"10.5.0","description":"BitAllTech MapLibre 实时目标轨迹渲染包","directories":{},"_nodeVersion":"20.12.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/track_1.0.2_1785983529812_0.49996609535546765","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@bitalltech-maplibre/track","version":"1.0.3","keywords":["bitalltech","maplibre","track","trajectory","realtime"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/track@1.0.3","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"aa38d3c73530a96893bc5f1a5e53e8a42c68dfa1","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/track/-/track-1.0.3.tgz","fileCount":11,"integrity":"sha512-jErpKb16yPksqkvOKOU1ZCqcS04Pz27qrUDb0X0dYJVprw+3NqpNYpL3NbOdHl2JSWg+iGWl/gXQJP+hOnjUmw==","signatures":[{"sig":"MEUCIQCwXaKrc2eZj+2b6z+066bJLFX9OFqfRrx5ivLU2yKhOAIgMwpU0YxaaSbQp1xIQWvw4uv8FUSJK6HwPcNnoC3NuqU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101578},"main":"dist/index.cjs.js","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.js","module":"dist/index.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"2c25cb28ec5522380181bba6304e021a6f08a9ca","scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"jsdelivr":"dist/index.umd.js","_npmVersion":"10.9.8","description":"BitAllTech MapLibre 实时目标轨迹渲染包","directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/track_1.0.3_1786610188321_0.4408204310412933","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@bitalltech-maplibre/track","version":"1.1.0","keywords":["bitalltech","maplibre","track","trajectory","realtime"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/track@1.1.0","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"2d3daab20a99241378e96c10db14f5027cf5330f","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/track/-/track-1.1.0.tgz","fileCount":11,"integrity":"sha512-CqFpDpqQ7RQHgHsroWNVBMGU1BVCI2qrefMnTRH8LS0QI2DcxylxgViWCA7GVbTwXh2DXSAOoYlXemOuat6rpg==","signatures":[{"sig":"MEUCIQCHBMHPiUZcFsnxuXGotfRJk8GMMdVnKNI0djG/XCnokAIgDwEsONaTu1JwQR8pHCei07xewmLfrP1towI6BheC0ng=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":107316},"main":"dist/index.cjs.js","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.js","module":"dist/index.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"fc753ae830695f5670423a6cc5159c3a3ed44b4d","scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"jsdelivr":"dist/index.umd.js","_npmVersion":"10.9.8","description":"BitAllTech MapLibre 实时目标轨迹渲染包","directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/track_1.1.0_1787722114493_0.7992421006611741","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"_id":"@bitalltech-maplibre/track@1.2.1","dist":{"shasum":"ec9c16a9924fcecc6987fd309b59298599c375b8","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/track/-/track-1.2.1.tgz","fileCount":11,"integrity":"sha512-W5mDXeWftAsP+tOBZgoYRnHA7gA44Dkn0SagbM+w6T54eLAQZ4QRhThpWb5dwx4rrIMcPKoLeKl7Ek6r/ITNwQ==","signatures":[{"sig":"MEQCICEgcWtbTgJcA7rYKWXsJErthhreuzgdDaE8TpnOqVXHAiAROnlg8CGJQ8a7JjtCuKyOTp2a2sEAfF5L30Z2SZL8BQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDd0RbKKiN1J7cxImcGnnmXi2OF1cvGL3sqU8//oZCZAAiEAz6EH7WC1XjGxXNHtwhAHljoChfPc/bv9DLZ9ow/2Vk4="}],"unpackedSize":116449},"main":"dist/index.cjs.js","name":"@bitalltech-maplibre/track","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.js","module":"dist/index.esm.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"37345b86d342401647d7a957fcef9c5c1c15bbca","license":"UNLICENSED","scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"version":"1.2.1","_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"jsdelivr":"dist/index.umd.js","keywords":["bitalltech","maplibre","track","trajectory","realtime"],"_npmVersion":"10.9.8","description":"BitAllTech MapLibre 实时目标轨迹渲染包","directories":{},"maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/track_1.2.1_1789528753471_0.3461567171816138"}}},"time":{"created":"2026-07-15T08:13:12.506Z","modified":"2026-09-16T03:19:14.322Z","1.0.0":"2026-07-10T09:31:07.416Z","1.0.1":"2026-07-15T08:13:12.799Z","1.0.2":"2026-08-06T02:32:09.966Z","1.0.3":"2026-08-13T08:36:28.473Z","1.1.0":"2026-08-26T05:28:34.644Z","1.2.1":"2026-09-16T03:19:13.561Z"},"license":"UNLICENSED","keywords":["bitalltech","maplibre","track","trajectory","realtime"],"description":"BitAllTech MapLibre 实时目标轨迹渲染包","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"readme":"# @bitalltech-maplibre/track\r\n\r\nMapLibre 实时目标轨迹渲染包。它只处理通用目标、轨迹点、主题、显隐和交互事件，不绑定无人机、任务、后端接口或 IndexedDB。\r\n\r\n插件内部使用统一 GeoJSON source 承载目标图标、轨迹线和轨迹点，并通过三类 layer 分别渲染，避免大量实时数据下多个 source 异步更新造成图标、线、点不同步。\r\n\r\n## 安装\r\n\r\n```bash\r\nnpm install @bitalltech-maplibre/track maplibre-gl\r\n```\r\n\r\n## 基础使用\r\n\r\n```ts\r\nimport \"maplibre-gl/dist/maplibre-gl.css\";\r\nimport { createMap, maplibregl } from \"@bitalltech-maplibre/core\";\r\nimport { MaplibreTrackLayer } from \"@bitalltech-maplibre/track\";\r\n\r\nconst map = createMap({\r\n  container: \"map\",\r\n  center: [116.39, 39.91],\r\n  zoom: 12,\r\n  style: \"openfreemap-liberty\",\r\n});\r\n\r\nmap.addControl(new maplibregl.NavigationControl(), \"bottom-right\");\r\n\r\nconst track = new MaplibreTrackLayer({\r\n  themeAssign: \"sequence\",\r\n  showIcon: true,\r\n  showTrack: true,\r\n  showPoint: true,\r\n  segmentSize: 500,\r\n  renderInterval: 100,\r\n});\r\n\r\nmap.on(\"load\", () => {\r\n  track.addTo(map);\r\n\r\n  track.setTargets([\r\n    {\r\n      id: \"target-001\",\r\n      lng: 116.39,\r\n      lat: 39.91,\r\n      heading: 120,\r\n    },\r\n  ]);\r\n\r\n  track.appendPoint({\r\n    targetId: \"target-001\",\r\n    lng: 116.391,\r\n    lat: 39.912,\r\n    seq: 1,\r\n    // 示例中用前端时间模拟；真实接入建议传服务端点位产生时间。\r\n    timestamp: Date.now(),\r\n  });\r\n});\r\n```\r\n\r\n## 主题\r\n\r\n默认内置 10 套主题。图标、轨迹线和轨迹点会使用同一个主题序号，保证颜色一致。\r\n\r\n```ts\r\nconst track = new MaplibreTrackLayer({\r\n  themes: [\r\n    { key: \"red\", color: \"#ff4d4f\", iconUrl: \"/images/red-air.png\" },\r\n    { key: \"blue\", color: \"#1677ff\", iconUrl: \"/images/blue-air.png\" },\r\n  ],\r\n  themeAssign: \"hash\",\r\n});\r\n```\r\n\r\n`iconUrl` 会由插件自动加载并注册到 MapLibre；如果你已经手动 `map.addImage`，也可以传 `iconImage`。`iconImage` 传的是 MapLibre image id，不是图片 URL，并且需要在 `track.addTo(map)` 前完成注册。\r\n\r\n```ts\r\nmap.loadImage(\"/images/uav-default.png\", (error, image) => {\r\n  if (error || !image) return;\r\n\r\n  if (!map.hasImage(\"uav-default\")) {\r\n    map.addImage(\"uav-default\", image);\r\n  }\r\n\r\n  const track = new MaplibreTrackLayer({\r\n    themes: [\r\n      {\r\n        key: \"default\",\r\n        color: \"#1677ff\",\r\n        iconImage: \"uav-default\",\r\n      },\r\n    ],\r\n  });\r\n\r\n  track.addTo(map);\r\n});\r\n```\r\n\r\n`themeAssign` 支持：\r\n\r\n- `sequence`：按目标进入顺序轮转主题。\r\n- `hash`：按目标 id 稳定映射主题。\r\n- `(target, index) => number`：自定义主题序号。\r\n\r\n## 轨迹线描边\r\n\r\n轨迹线支持描边（halo）效果：插件会在轨迹线下方垫一层同数据的描边层，宽度方向上每侧各外扩 `lineStrokeWidth` 像素，视觉上只露出主线两侧的描边。默认 `lineStrokeWidth: 0`（关闭），颜色默认黑色、透明度 0.35。\r\n\r\n```ts\r\nconst track = new MaplibreTrackLayer({\r\n  styles: {\r\n    lineStrokeWidth: 2,        // 每侧各外扩 2px，默认 0 关闭\r\n    lineStrokeColor: \"#000000\", // 描边色，默认黑色\r\n    lineStrokeOpacity: 0.35,    // 描边透明度，不传时跟随 lineOpacity\r\n    // 选中态描边宽度；不传时保持 lineStrokeWidth\r\n    selectedLineStrokeWidth: 3,\r\n  },\r\n});\r\n```\r\n\r\n描边层与轨迹线层共用 source 和 feature，实时追点、选中态切换、`setTargetStyle` 覆盖都会同步生效，不需要业务层额外处理。描边层不参与点击/悬浮命中，事件仍由主线、点和图标层触发。\r\n\r\n描边也可以按主题或按目标配置：\r\n\r\n```ts\r\nconst track = new MaplibreTrackLayer({\r\n  themes: [\r\n    // 主题级描边色；未传时回退到全局 styles 或内置黑色\r\n    { key: \"red\", color: \"#ff4d4f\", lineStrokeColor: \"#7a1020\" },\r\n  ],\r\n});\r\n\r\ntrack.setTargetStyle(\"target-001\", {\r\n  lineStrokeColor: \"#ffffff\",\r\n  lineStrokeWidth: 3,\r\n});\r\n// 撤销描边覆盖，恢复主题/全局样式\r\ntrack.clearTargetStyle(\"target-001\");\r\n```\r\n\r\n描边层同样支持 layout/paint 透传，会合并到插件默认值之上；透传 paint 会覆盖插件生成的颜色/宽度表达式：\r\n\r\n```ts\r\nconst track = new MaplibreTrackLayer({\r\n  lineStrokeLayout: { \"line-cap\": \"butt\" },\r\n  lineStrokePaint: { \"line-blur\": 1 },\r\n});\r\n```\r\n\r\n已知现象：`lineOpacity` 小于 1 时主线是半透明的，会微微透出下方的描边色，属正常现象；需要纯净主线时把 `lineOpacity` 设为 1。\r\n\r\n## 性能参数\r\n\r\n`segmentSize` 用来控制轨迹线分片大小，默认 `500`。当某个目标的轨迹线达到该数量后，旧线段会被冻结成稳定的 GeoJSON feature，后续实时点只更新最后一个活跃线段。\r\n\r\n这不是轨迹抽稀：插件仍会完整保存并渲染每个轨迹点，`getTrackPoints(targetId)` 返回的也是完整点列。相邻线段之间会复用上一段末点，用于保证线段视觉连续。\r\n\r\n```ts\r\nconst track = new MaplibreTrackLayer({\r\n  // 目标多、轨迹长时建议保持默认值或按设备性能调整。\r\n  segmentSize: 500,\r\n  // 多个实时点会按刷新间隔合并提交，减少 MapLibre source 更新次数。\r\n  renderInterval: 100,\r\n});\r\n```\r\n\r\n大量 GeoJSON 实时更新时，也建议在创建地图前适当提高 MapLibre worker 数，并关闭 symbol 淡入淡出：\r\n\r\n```ts\r\nmaplibregl.setWorkerCount(Math.min(4, navigator.hardwareConcurrency || 2));\r\n\r\nconst map = createMap({\r\n  container: \"map\",\r\n  fadeDuration: 0,\r\n});\r\n```\r\n\r\n## 轨迹点元信息\r\n\r\n`appendPoint` 和 `appendPoints` 的 `TrackPoint` 只要求 `targetId`、`lng`、`lat`。`seq`、`timestamp`、`heading`、`properties` 都是可选字段。\r\n\r\n```ts\r\ntrack.appendPoint({\r\n  targetId: data.id,\r\n  lng: data.lng,\r\n  lat: data.lat,\r\n  heading: data.heading,\r\n  // 建议使用服务端序号，方便业务层在进入插件前做乱序过滤和去重。\r\n  seq: data.seq,\r\n  // 建议使用服务端记录的点位产生时间，而不是前端收到消息时的 Date.now()。\r\n  timestamp: data.timestamp,\r\n  properties: data,\r\n});\r\n```\r\n\r\n插件不会根据 `seq` 或 `timestamp` 自动排序、去重、回放或控制动画。它会按你调用 `appendPoint/appendPoints` 的顺序追加渲染，并原样保留这些字段，后续可通过 `getTrackPoints(targetId)` 或点击轨迹点事件取回。\r\n\r\n如果后端推送的是字符串时间，建议在业务层统一转成毫秒时间戳后再传入：\r\n\r\n```ts\r\ntrack.appendPoint({\r\n  targetId: data.id,\r\n  lng: data.lng,\r\n  lat: data.lat,\r\n  timestamp: new Date(data.eventTime).getTime(),\r\n});\r\n```\r\n\r\n## 常用方法\r\n\r\n```ts\r\ntrack.setTargets(targets);          // 全量替换当前目标快照，适合初始化或重置\r\n\r\ntrack.setTrackPoints(id, points);   // 替换某个目标的完整轨迹点\r\ntrack.appendPoint(point);           // 追加单个轨迹点\r\ntrack.appendPoints(points);         // 批量追加轨迹点\r\n\r\ntrack.setIconVisible(true);\r\ntrack.setTrackVisible(true);\r\ntrack.setPointVisible(false);\r\n\r\ntrack.setTargetStyle(\"target-001\", {\r\n  lineColor: \"#ff4d4f\",\r\n  lineWidth: 5,\r\n  lineStrokeColor: \"#7a1020\",\r\n  lineStrokeWidth: 2,\r\n  pointColor: \"#ff4d4f\",\r\n  pointRadius: 6,\r\n  iconImage: \"warning-aircraft\",\r\n  iconSize: 0.9,\r\n});\r\ntrack.clearTargetStyle(\"target-001\");\r\n\r\ntrack.selectTarget(\"target-001\");\r\ntrack.focusTarget(\"target-001\");\r\ntrack.removeTarget(\"target-001\");\r\ntrack.clear();\r\n```\r\n\r\n## 目标级样式\r\n\r\n`setTargetStyle(targetId, style)` 用于按目标覆盖图标、轨迹线和轨迹点样式。它只刷新该目标相关的 icon feature、线分片和点 feature，不会把全部目标重新 `setData`。\r\n\r\n```ts\r\ntrack.setTargetStyle(\"target-001\", {\r\n  lineColor: \"#ff4d4f\",\r\n  lineWidth: 5,\r\n  lineOpacity: 1,\r\n  pointColor: \"#ff4d4f\",\r\n  pointStrokeColor: \"#ffffff\",\r\n  pointRadius: 6,\r\n  pointStrokeWidth: 2,\r\n  iconImage: \"target-warning\",\r\n  iconSize: 0.9,\r\n  iconOpacity: 1,\r\n});\r\n\r\ntrack.clearTargetStyle(\"target-001\");\r\n```\r\n\r\n`iconImage` 需要传 MapLibre 已注册的 image id。插件不会在 `setTargetStyle` 中加载图片 URL，图片加载和业务状态切换建议放在业务层处理。\r\n\r\n## 事件\r\n\r\n```ts\r\ntrack.on(\"click\", (event) => {\r\n  console.log(event.targetId, event.target, event.point);\r\n});\r\n\r\ntrack.on(\"select\", (event) => {\r\n  console.log(event.targetId);\r\n});\r\n```\r\n","readmeFilename":"README.md"}