{"_id":"@bitalltech-maplibre/measure","_rev":"5-3f3105fc658e96c1f6dc571a81cc314f","name":"@bitalltech-maplibre/measure","dist-tags":{"latest":"2.1.0"},"versions":{"1.0.0":{"name":"@bitalltech-maplibre/measure","version":"1.0.0","keywords":["bitalltech","maplibre","measure","distance"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/measure@1.0.0","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"52bcbd0896faf981b92aa57a763f062f7ed1f4e7","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/measure/-/measure-1.0.0.tgz","fileCount":12,"integrity":"sha512-Y4ic0wVNzMGmkeqSU8KhLvv4HcvFYaYkauAl4nNj0XFGHxQVWH8iSieOMRxsgHjQERSzvJJYIFVCy6qOyEPsOA==","signatures":[{"sig":"MEUCIQCaKYlH8Kouj1dVwm/Ge4y71K+iQ5XKs7HZZ6dvBCWYhQIge8I0OvSHRXtrYrVmufO9irN+T4Lk37zm6FLKLA8qAAQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44896},"main":"dist/index.cjs.js","style":"dist/style.css","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"},"./style.css":"./dist/style.css"},"gitHead":"d8091f95b99d6cd6c94c139294005a261e682dc9","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":{},"sideEffects":["*.css","src/style.css","dist/style.css"],"_nodeVersion":"20.12.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/measure_1.0.0_1783507038201_0.37706048593216246","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@bitalltech-maplibre/measure","version":"1.0.2","keywords":["bitalltech","maplibre","measure","distance"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/measure@1.0.2","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"086623c6ff61f7fe471a4d81156c85bab173d9a2","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/measure/-/measure-1.0.2.tgz","fileCount":13,"integrity":"sha512-J5SNviE8l7Y0OLURuyUsMZ6ziAYAdUGSwu8QOyTCb7/uYjJJvYYtUoeFzTb3c5v0rFMEKc4+SP1wmMg0i+hkMQ==","signatures":[{"sig":"MEUCICSg6UwiCwlVtR7MWE0P0B8JG1kN4v/LFSt6ULgp6w9dAiEA9nyxWvFd/MvpkFUtIVdmLrGX4HfwfnNaXOxGhAgBXC8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":67831},"main":"dist/index.cjs.js","style":"dist/style.css","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"},"./style.css":"./dist/style.css"},"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":{},"sideEffects":["*.css","src/style.css","dist/style.css"],"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/measure_1.0.2_1787044198463_0.8562112169908227","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@bitalltech-maplibre/measure","version":"1.0.3","keywords":["bitalltech","maplibre","measure","distance"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/measure@1.0.3","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"a6c7f2c1c75ee9b18dd7637da654eb0c5c023e60","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/measure/-/measure-1.0.3.tgz","fileCount":13,"integrity":"sha512-DRiXbNiTTosd9bHBijhWBUdOhJhW1m3hKvHb3lX8S+b43By8HJ7wSDG8alWwMWMZtisBB0zvSw7ar7Z9ROZ5yg==","signatures":[{"sig":"MEYCIQCN0XHryFIyly0Gcqq3DyalGyBTC6u2BD1CCCBlXoU73QIhAL1r7EDavEUbpHeR4yaEZLTggpVvhaVkL/SNKcN+N+5P","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69128},"main":"dist/index.cjs.js","style":"dist/style.css","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"},"./style.css":"./dist/style.css"},"gitHead":"5d62fff7e64418e5a3e3cf325e4c855352f1f36a","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":{},"sideEffects":["*.css","src/style.css","dist/style.css"],"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/measure_1.0.3_1787549845524_0.8114361487191999","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@bitalltech-maplibre/measure","version":"2.0.0","keywords":["bitalltech","maplibre","measure","distance"],"license":"UNLICENSED","_id":"@bitalltech-maplibre/measure@2.0.0","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"dist":{"shasum":"541295278fc2ab7cb1f80b3aa27eebcbe97eecea","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/measure/-/measure-2.0.0.tgz","fileCount":15,"integrity":"sha512-HHd2CzF83SVkA7dX7Gn9G793UghJZkJlsr/gUdKDG/WBN205Uan8hyhKqAgofVynCnKDo86ePl8buwNkmKrvBA==","signatures":[{"sig":"MEUCIHPR5miCtAS8fDZpraYEEfCNf4Tj3L1HSz0pvEJxq9U8AiEAppwXDsiVKe6UgeRzP8b541l6oeZUbDnGZDhz/1YKCEM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":128519},"main":"dist/index.cjs.js","style":"dist/style.css","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"},"./style.css":"./dist/style.css"},"gitHead":"5d62fff7e64418e5a3e3cf325e4c855352f1f36a","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":{},"sideEffects":["*.css","src/style.css","dist/style.css"],"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"maplibre-gl":"^5.24.0"},"_npmOperationalInternal":{"tmp":"tmp/measure_2.0.0_1787627178411_0.5260680186333901","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@bitalltech-maplibre/measure","version":"2.1.0","description":"BitAllTech MapLibre 测量控件包","main":"dist/index.cjs.js","module":"dist/index.esm.js","unpkg":"dist/index.umd.js","jsdelivr":"dist/index.umd.js","types":"dist/types/index.d.ts","style":"dist/style.css","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"},"./style.css":"./dist/style.css"},"scripts":{"build":"vite build && tsc --project tsconfig.json --emitDeclarationOnly","prepublishOnly":"npm run build"},"keywords":["bitalltech","maplibre","measure","distance"],"license":"UNLICENSED","sideEffects":["*.css","src/style.css","dist/style.css"],"publishConfig":{"access":"public"},"peerDependencies":{"maplibre-gl":"^5.24.0"},"_id":"@bitalltech-maplibre/measure@2.1.0","gitHead":"5d62fff7e64418e5a3e3cf325e4c855352f1f36a","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-EWDupPbmBTeKF6shndpOciAg9T8SG/PzBhJeGoJw5/uTuJu4KHNMOxoC7d5HpP4h/e1CMihW09faukXNT39eHg==","shasum":"a49e74445b91d547418e7c1242944f530654ccef","tarball":"https://registry.npmjs.org/@bitalltech-maplibre/measure/-/measure-2.1.0.tgz","fileCount":15,"unpackedSize":131059,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC4HWTLeUqch80EGaC+QCUohRTT0svNiC4XqnQ4WyFuYQIgO9sQby9aGLt6GIgDqdHPjGVp6taGp7VHp5TEVneLMoQ="}]},"_npmUser":{"name":"hanyue1218","email":"1584503074@qq.com"},"directories":{},"maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/measure_2.1.0_1787643051114_0.751096191540751"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-08T10:37:18.046Z","modified":"2026-08-25T07:30:51.438Z","1.0.0":"2026-07-08T10:37:18.343Z","1.0.2":"2026-08-18T09:09:58.606Z","1.0.3":"2026-08-24T05:37:25.662Z","2.0.0":"2026-08-25T03:06:18.570Z","2.1.0":"2026-08-25T07:30:51.261Z"},"license":"UNLICENSED","keywords":["bitalltech","maplibre","measure","distance"],"description":"BitAllTech MapLibre 测量控件包","maintainers":[{"name":"hanyue1218","email":"1584503074@qq.com"}],"readme":"# @bitalltech-maplibre/measure\n\n基于 MapLibre GL JS 的测量控件。**三个模式 + 一个开关**：\n\n- `mode: 'distance' | 'area' | 'height'` —— 测距 / 测面 / 两点量高（DVH）\n- `adaptTerrain: boolean` —— 贴地不是独立模式，而是一个开关\n\n一次测量把所有可得的量都算出来（水平 / 空间(斜距) / 贴地长度，平面 / 贴地面积，高差），\nUI 自己挑要显示哪个 —— 用户不必先决定「测平面还是测贴地」再重画一遍。\n\n## 安装\n\n```bash\nnpm install @bitalltech-maplibre/measure maplibre-gl\n```\n\n## 使用\n\n```ts\nimport \"@bitalltech-maplibre/measure/style.css\";\nimport { MaplibreMeasureControl } from \"@bitalltech-maplibre/measure\";\n\nconst measure = new MaplibreMeasureControl({\n  mode: \"distance\",\n  defaultActive: false,\n  unit: \"metric\",\n  showSegmentLabels: true,\n  showTotalLabel: true,\n  showEndClear: true,\n  styles: {\n    activeLineColor: \"#ff0000\",\n    fillColor: \"#ff0000\",\n    fillOpacity: 0.18,\n    pointColor: \"#ff0000\",\n    lineWidth: 4,\n  },\n});\n\nmap.addControl(measure, \"top-left\");\n\nmap.on(\"measure.finish\", (event) => {\n  console.log(event.formatted.primary); // 当前配置下的主数值文案\n  console.log(event.horizontal, event.spatial, event.surface);\n  console.log(event.measurements);\n});\n```\n\n## 结束当前一轮\n\n四条路径**默认全开**，任意一条可用就不会出现「怎么双击都结束不了」：\n\n| 方式 | 说明 |\n| --- | --- |\n| 双击 | 控件自管判定（间隔 ≤300ms + CSS 像素距离 ≤8px），原生 `dblclick` 作为快速路径 |\n| 右键 | `contextmenu` |\n| 回车 | `Enter` |\n| 单击末点 | 点最后一个已落点，不会多落重复点 |\n\n```ts\nnew MaplibreMeasureControl({\n  // 例：把右键留给业务菜单\n  finish: { dblclick: true, contextmenu: false, enter: true, clickLastPoint: true },\n});\n```\n\n**为什么不只用原生 `dblclick`**：原生事件要求两次点击落在同一 DOM 节点、且间距在平台阈值内。\n在高分屏、页面缩放、或光标恰好压住测量标注时都可能不派发，只认它就会让用户陷入死局。\n自管判定与原生事件之间用 400ms 时间窗去重，不会重复结束。\n\n其他：`Escape` 先丢弃当前草稿，没有草稿时才退出会话；落点与上一点像素距离过近时视为重复点丢弃；\n结束瞬间临时禁用地图双击缩放，避免结束动作顺带把地图放大一级；`height` 模式落满两点自动结束。\n\n## 高程与贴地\n\n水平 / 空间 / 贴地是**三个不同的量**，恒有 `贴地 ≥ 空间 ≥ 水平`：\n\n| 量 | 定义 |\n| --- | --- |\n| `horizontal` | 忽略高程的地表投影长度（Haversine 累加） |\n| `spatial` | 只用两端高程的斜距 `hypot(水平, 高差)` |\n| `surface` | 沿地表重采样后逐段累加的贴地长度 |\n\n高程来源统一走 `elevationProvider`，签名一致，来源可换：\n\n```ts\n// 地形 DEM —— 不传 elevationProvider 时的默认实现\nelevationProvider: (p) => map.queryTerrainElevation(p)\n// 业务目标高度 —— 低空场景测目标斜距不需要 DEM\nelevationProvider: (p) => pickTargetAltitude(p)\n// 用户手输\nelevationProvider: () => manualAltitude\n```\n\n> **没有任何高程来源时，空间距离在数学上就等于水平距离、高差恒为 0。**\n> 这不是精度差异，而是完全相同的数字。此时结果里 `terrainApplied` 为 `false`，\n> UI 应据此隐藏或标注，不要把平面距离当成「空间距离」展示。\n\n贴地需要沿线重采样查高程，而 `render` 每次 `mousemove` 都会触发，所以采样量必须有预算：\n\n```ts\nterrain: {\n  sampleInterval: 30,        // 采样间隔（米）\n  maxSamplesPerSegment: 32,  // 单段上限\n  maxSamplesTotal: 512,      // 整线预算，超出按段长比例缩减\n}\n```\n\n## API\n\n- `start()` / `stop()` / `clear()`：开始新会话 / 退出但保留结果 / 清空全部。\n- `clearMeasurement(id)`：按 id 清除一条已完成测量，`id` 来自 `getResult().measurements[].id`，不受数组顺序变化影响。\n- `getResult(): MeasureResult`：当前草稿优先，无草稿时返回最后一条完成结果，并附带 `measurements` 全部历史。\n- `isActive()`。\n- `setMode(mode)` / `getMode()`：运行时切模式。不同模式几何语义不同，切换会丢弃草稿并清空已完成结果。\n- `setUnit(unit)`。\n- `setAdaptTerrain(on)` / `isAdaptTerrain()`。\n- `setElevationProvider(provider?)`：传 `undefined` 回落到地图地形高程。\n- `setStyles(partial)`：局部更新样式，已存在图层立即生效。\n\n## MeasureRecord\n\n```ts\n{\n  id?: string\n  mode: MeasureMode\n  coordinates: LngLat[]\n  elevations: (number | undefined)[]\n  terrainApplied: boolean      // 是否真的取到了高程\n  horizontal: number           // distance=总长, area=周长(含闭合段), height=两点水平距离\n  spatial: number              // 斜距\n  surface: number              // 贴地；未开 adaptTerrain 时等于 horizontal\n  planarArea: number           // 非 area 模式为 0\n  surfaceArea: number          // 未开 adaptTerrain 时等于 planarArea\n  verticalHeight: number       // 首末两点高差绝对值\n  segments: MeasureSegment[]   // 逐段 { from, to, horizontal, spatial, surface }\n  formatted: MeasureFormatted  // 各量的文案 + primary\n}\n```\n\n`MeasureResult` = `MeasureRecord` + `measurements: MeasureRecord[]`。\n\n`primaryValue` 决定标注和 `formatted.primary` 取哪个量，默认 `'auto'`：\n开了 `adaptTerrain` 且拿到高程时取 `surface`，否则取 `horizontal`；`height` 模式恒取高差。\n\n## 配置\n\n- `mode`：`'distance'`（默认）/ `'area'` / `'height'`。\n- `adaptTerrain`：是否计算贴地量，默认 `false`。\n- `elevationProvider` / `terrain`：见上文。\n- `primaryValue`：`'auto'`（默认）/ `'horizontal'` / `'spatial'` / `'surface'`。\n- `finish`：结束方式开关，默认四种全开。\n- `showEndClear`：是否在结束标注中显示「清除」按钮，默认 `true`。该按钮只清除当前这一条。\n- `styles.labelBackgroundColor` / `styles.labelBorderColor`：标注背景色、边框色。\n- `styles.fillColor` / `styles.fillOpacity`：测面填充色和透明度。\n\n## 交互\n\n- 单击地图添加测量点（延迟 220ms 落点，给双击判定留窗口）。\n- 鼠标移动时显示预览线和跟随提示，提示里带当前实时数值。\n- 结束当前一轮后控件保持激活，可继续单击开始下一轮。\n- 点击激活状态下的测量按钮会结束会话并移除当前全部测量结果。\n- 工具栏清空按钮清除当前控件的全部测量结果。\n- 完成后最后一个点旁显示带清除按钮的总量标注，点击只删除该条。\n- 标注是 `pointer-events: none` 的 DOM Marker，不参与命中测试，不会抢走地图点击。\n\n## 事件\n\n- `measure.start`\n- `measure.update`\n- `measure.finish`\n- `measure.modechange`：`setMode` 切换模式时触发，payload `{ mode }`。\n- `measure.clear`：`scope: \"measurement\"` 表示清除单条并携带 `id`；`scope: \"all\"` 表示清除全部。\n","readmeFilename":"README.md"}