@ray-js/robot-map-sdk 0.0.17-beta.4 → 0.0.17-beta.6

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.
Files changed (48) hide show
  1. package/dist/index.rjs.js +1 -1
  2. package/dist-app/assets/index-DPMQ-Izq.js +1 -0
  3. package/dist-app/index.html +1 -1
  4. package/dist-docs/404.html +2 -2
  5. package/dist-docs/assets/{app.C5xCc25N.js → app.Cwwjhfv-.js} +1 -1
  6. package/dist-docs/assets/chunks/@localSearchIndexroot.DX09zKNQ.js +1 -0
  7. package/dist-docs/assets/chunks/{BitmapFont.CfNZJWQu.js → BitmapFont.B-IfRDQk.js} +1 -1
  8. package/dist-docs/assets/chunks/{BufferResource.U7KmcJEb.js → BufferResource.CSAKqlzf.js} +1 -1
  9. package/dist-docs/assets/chunks/{CanvasRenderer.V8PvjkXK.js → CanvasRenderer.MDV1Xxi4.js} +1 -1
  10. package/dist-docs/assets/chunks/{RenderTargetSystem.CIN4IDnj.js → RenderTargetSystem.g57-QZWo.js} +1 -1
  11. package/dist-docs/assets/chunks/{VPLocalSearchBox.BXtgZMz6.js → VPLocalSearchBox.Ddw3Wr6t.js} +1 -1
  12. package/dist-docs/assets/chunks/{WebGLRenderer.9sqpUvol.js → WebGLRenderer.BkDOpZPC.js} +1 -1
  13. package/dist-docs/assets/chunks/{WebGPURenderer.B8iy8W66.js → WebGPURenderer.BwHfcpIa.js} +1 -1
  14. package/dist-docs/assets/chunks/{browserAll.Curl4kc3.js → browserAll.Bwww-soc.js} +1 -1
  15. package/dist-docs/assets/chunks/{index.BPYuggut.js → index.ChgcAKwM.js} +20 -20
  16. package/dist-docs/assets/chunks/{theme.DdcAePki.js → theme.BLq0Vss6.js} +3 -3
  17. package/dist-docs/assets/chunks/{webworkerAll.9SOLh1Dq.js → webworkerAll.D7ZfSazD.js} +1 -1
  18. package/dist-docs/assets/{guide_advanced-usage.md.BsGRhEuG.js → guide_advanced-usage.md.BrP4iZb-.js} +141 -79
  19. package/dist-docs/assets/{guide_advanced-usage.md.BsGRhEuG.lean.js → guide_advanced-usage.md.BrP4iZb-.lean.js} +1 -1
  20. package/dist-docs/assets/{guide_getting-started.md.Ca_k5NRJ.js → guide_getting-started.md.DOtxbNfK.js} +1 -1
  21. package/dist-docs/guide/advanced-usage.html +144 -82
  22. package/dist-docs/guide/concepts.html +3 -3
  23. package/dist-docs/guide/getting-started.html +5 -5
  24. package/dist-docs/guide/mcp.html +3 -3
  25. package/dist-docs/guide/spot-room-binding.html +3 -3
  26. package/dist-docs/hashmap.json +1 -1
  27. package/dist-docs/index.html +3 -3
  28. package/dist-docs/plans/2026-03-04-detected-objects-visibility-design.html +3 -3
  29. package/dist-docs/plans/2026-03-04-show-detected-objects-implementation-plan.html +3 -3
  30. package/dist-docs/plans/2026-03-10-simulator-debug-design.html +3 -3
  31. package/dist-docs/plans/2026-03-10-simulator-events-console-design.html +3 -3
  32. package/dist-docs/plans/2026-03-10-simulator-events-console-implementation-plan.html +3 -3
  33. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-design.html +3 -3
  34. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-implementation-plan.html +3 -3
  35. package/dist-docs/plans/2026-03-10-testing-rollout-next-steps-plan.html +3 -3
  36. package/dist-docs/plans/2026-03-11-simulator-logger-dump-implementation-plan.html +3 -3
  37. package/dist-docs/reference/callbacks.html +3 -3
  38. package/dist-docs/reference/config.html +3 -3
  39. package/dist-docs/reference/data.html +3 -3
  40. package/dist-docs/reference/methods.html +3 -3
  41. package/dist-docs/reference/runtime.html +3 -3
  42. package/dist-docs/reference/types.html +3 -3
  43. package/dist-docs/reference/utils.html +3 -3
  44. package/dist-docs/simulator/index.html +3 -3
  45. package/package.json +1 -1
  46. package/dist-app/assets/index-Bju2ykDd.js +0 -1
  47. package/dist-docs/assets/chunks/@localSearchIndexroot.JKj3B6eW.js +0 -1
  48. /package/dist-docs/assets/{guide_getting-started.md.Ca_k5NRJ.lean.js → guide_getting-started.md.DOtxbNfK.lean.js} +0 -0
@@ -9,11 +9,11 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.C5xCc25N.js"></script>
12
+ <script type="module" src="/assets/app.Cwwjhfv-.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.DdcAePki.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.BLq0Vss6.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
- <link rel="modulepreload" href="/assets/guide_advanced-usage.md.BsGRhEuG.lean.js">
16
+ <link rel="modulepreload" href="/assets/guide_advanced-usage.md.BrP4iZb-.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
18
18
  <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
19
19
  </head>
@@ -304,82 +304,7 @@
304
304
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClickVirtualWall</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleClickVirtualWall}</span></span>
305
305
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
306
306
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
307
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="门槛" tabindex="-1">门槛 <a class="header-anchor" href="#门槛" aria-label="Permalink to &quot;门槛&quot;">​</a></h3><p>门槛分为可通行(<code>passable</code>)与不可通行(<code>impassable</code>)两种类型,数据由四个角点(<code>points</code>,顺时针 左上→右上→右下→左下,与禁区同序)与类型(<code>type</code>)构成。编辑交互通过 <code>editingThresholdIds</code> 门控,列入的门槛显示删除 / 旋转 / 缩放 / 移动控件。</p><div class="warning custom-block"><p class="custom-block-title">数据格式变更</p><p>0.0.18 起门槛数据由「中心线两点 + <code>height</code>」改为四角坐标(与主流厂商协议对齐)。传入两个点的旧数据会被丢弃并打一条 warn 日志,不再渲染;<code>controls.threshold.defaultHeight</code> 同时被移除。</p></div><p>新建门槛不用自己算四个角:<a href="/reference/methods.html#getthresholdpointsbyviewportcenter"><code>getThresholdPointsByViewportCenter()</code></a> 在当前视口中心生成一条门槛的角点,缺省 1m × 0.15m(长 × 厚),可传 <code>width</code> / <code>height</code> 覆盖。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 例:用户点「添加门槛」时在视口中心放一条默认尺寸的门槛</span></span>
308
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> points</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> mapApi.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getThresholdPointsByViewportCenter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
309
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">thresholds, { id: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">nextId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), points, type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;passable&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }])</span></span></code></pre></div><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React, { useState } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
310
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { RobotMap, ThresholdParam } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;@ray-js/robot-map&#39;</span></span>
311
- <span class="line"></span>
312
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MapPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
313
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 将设备上报的门槛数据绘制到地图上</span></span>
314
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">thresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([</span></span>
315
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
316
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;threshold1&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
317
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 四角坐标:顶点 0→1 为长度方向,0→3 为厚度方向</span></span>
318
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> points: [</span></span>
319
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
320
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">20</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
321
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">20</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
322
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
323
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
324
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;impassable&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 可选,缺省 &#39;passable&#39;</span></span>
325
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
326
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ])</span></span>
327
- <span class="line"></span>
328
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">editingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setEditingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([])</span></span>
329
- <span class="line"></span>
330
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击门槛删除按钮时触发(宿主收窄数据后重绘)</span></span>
331
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleRemoveThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
332
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">filter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id))</span></span>
333
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
334
- <span class="line"></span>
335
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 手势操作门槛(旋转 / 缩放 / 移动)结束后触发</span></span>
336
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleUpdateThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">threshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
337
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 强烈建议在 onUpdate 回调中更新业务侧的数据</span></span>
338
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
339
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item)),</span></span>
340
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
341
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
342
- <span class="line"></span>
343
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击门槛时触发</span></span>
344
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleClickThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">threshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
345
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">editingThresholdIds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">includes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(threshold.id)) {</span></span>
346
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 非编辑态点击 → 进入编辑态</span></span>
347
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setEditingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([threshold.id])</span></span>
348
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span></span>
349
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
350
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 编辑态点击 → 翻转 type 后重绘,同一门槛原地换肤</span></span>
351
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> nextType</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.type </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;passable&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;impassable&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;passable&#39;</span></span>
352
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
353
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span></span>
354
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">item, type: nextType } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item,</span></span>
355
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ),</span></span>
356
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
357
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
358
- <span class="line"></span>
359
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span></span>
360
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">RobotMap</span></span>
361
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> config</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
362
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> controls: {</span></span>
363
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold: {</span></span>
364
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 长度与厚度的米区间(缩放到临界值即停)</span></span>
365
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minLength: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
366
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxLength: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
367
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
368
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
369
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ... 其他配置见 config 参考</span></span>
370
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
371
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
372
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
373
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> runtime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
374
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> editingThresholdIds,</span></span>
375
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
376
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> thresholds</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{thresholds}</span></span>
377
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onRemoveThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleRemoveThreshold}</span></span>
378
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUpdateThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleUpdateThreshold}</span></span>
379
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClickThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleClickThreshold}</span></span>
380
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
381
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
382
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">只读展示</p><p>只读展示设备识别的门槛时,不把它们的 id 放进 <code>editingThresholdIds</code> 即可。</p></div><h3 id="禁扫区域-禁拖区域-清扫划区" tabindex="-1">禁扫区域/禁拖区域/清扫划区 <a class="header-anchor" href="#禁扫区域-禁拖区域-清扫划区" aria-label="Permalink to &quot;禁扫区域/禁拖区域/清扫划区&quot;">​</a></h3><p>禁扫区域、禁拖区域和清扫划区都是由四个顶点坐标构成的矩形区域,各自具有独立的配置、参数和方法。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 以禁扫区域为例</span></span>
307
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="禁扫区域-禁拖区域-清扫划区" tabindex="-1">禁扫区域/禁拖区域/清扫划区 <a class="header-anchor" href="#禁扫区域-禁拖区域-清扫划区" aria-label="Permalink to &quot;禁扫区域/禁拖区域/清扫划区&quot;">​</a></h3><p>禁扫区域、禁拖区域和清扫划区都是由四个顶点坐标构成的矩形区域,各自具有独立的配置、参数和方法。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 以禁扫区域为例</span></span>
383
308
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
384
309
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { RobotMap, ZoneParam } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;@ray-js/robot-map&#39;</span></span>
385
310
  <span class="line"></span>
@@ -568,7 +493,144 @@
568
493
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClickSpot</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleClickSpot}</span></span>
569
494
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
570
495
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
571
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p><ul><li><p>虽然在设计上是纯受控的,但地图控制元素在手势操作时会先在内部实时进行更新,并在手势结束后通过 <code>onUpdate</code> 回调抛出最新的数据。</p></li><li><p>为保证一致性,我们强烈建议始终在 <code>onUpdate</code> 回调更新业务侧的数据。这个更新不会产生额外的渲染,你无需担心。</p></li></ul></div><h2 id="新增地图控制元素" tabindex="-1">新增地图控制元素 <a class="header-anchor" href="#新增地图控制元素" aria-label="Permalink to &quot;新增地图控制元素&quot;">​</a></h2><p>借助受控的设计,新增一个地图控制元素非常简单,以虚拟墙为例:</p><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>新增其他地图控制元素的方式也是类似的,重点在于如何维护好数据和运行时状态。</p></div><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
496
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="门槛" tabindex="-1">门槛 <a class="header-anchor" href="#门槛" aria-label="Permalink to &quot;门槛&quot;">​</a></h3><p>门槛分为可通行(<code>passable</code>)与不可通行(<code>impassable</code>)两种类型,数据由四个角点(<code>points</code>,顺时针 左上→右上→右下→左下,与禁区同序)与类型(<code>type</code>)构成。编辑交互通过 <code>editingThresholdIds</code> 门控,列入的门槛显示删除 / 旋转 / 缩放 / 移动控件。</p><div class="warning custom-block"><p class="custom-block-title">数据格式变更</p><p>0.0.18 起门槛数据由「中心线两点 + <code>height</code>」改为四角坐标(与主流厂商协议对齐)。传入两个点的旧数据会被丢弃并打一条 warn 日志,不再渲染;<code>controls.threshold.defaultHeight</code> 同时被移除。</p></div><p>新建门槛不用自己算四个角:<a href="/reference/methods.html#getthresholdpointsbyviewportcenter"><code>getThresholdPointsByViewportCenter()</code></a> 在当前视口中心生成一条门槛的角点,缺省 1m × 0.15m(长 × 厚),可传 <code>width</code> / <code>height</code> 覆盖。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 例:用户点「添加门槛」时在视口中心放一条默认尺寸的门槛</span></span>
497
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> points</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> mapApi.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getThresholdPointsByViewportCenter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
498
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">thresholds, { id: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">nextId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), points, type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;passable&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }])</span></span></code></pre></div><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React, { useState } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
499
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { RobotMap, ThresholdParam } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;@ray-js/robot-map&#39;</span></span>
500
+ <span class="line"></span>
501
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MapPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
502
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 将设备上报的门槛数据绘制到地图上</span></span>
503
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">thresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([</span></span>
504
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
505
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;threshold1&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
506
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 四角坐标:顶点 0→1 为长度方向,0→3 为厚度方向</span></span>
507
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> points: [</span></span>
508
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
509
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">20</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
510
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">20</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
511
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
512
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
513
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;impassable&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 可选,缺省 &#39;passable&#39;</span></span>
514
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
515
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ])</span></span>
516
+ <span class="line"></span>
517
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">editingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setEditingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([])</span></span>
518
+ <span class="line"></span>
519
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击门槛删除按钮时触发(宿主收窄数据后重绘)</span></span>
520
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleRemoveThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
521
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">filter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id))</span></span>
522
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
523
+ <span class="line"></span>
524
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 手势操作门槛(旋转 / 缩放 / 移动)结束后触发</span></span>
525
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleUpdateThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">threshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
526
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 强烈建议在 onUpdate 回调中更新业务侧的数据</span></span>
527
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
528
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item)),</span></span>
529
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
530
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
531
+ <span class="line"></span>
532
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击门槛时触发</span></span>
533
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleClickThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">threshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ThresholdParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
534
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">editingThresholdIds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">includes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(threshold.id)) {</span></span>
535
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 非编辑态点击 → 进入编辑态</span></span>
536
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setEditingThresholdIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([threshold.id])</span></span>
537
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span></span>
538
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
539
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 编辑态点击 → 翻转 type 后重绘,同一门槛原地换肤</span></span>
540
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> nextType</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.type </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;passable&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;impassable&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;passable&#39;</span></span>
541
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setThresholds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
542
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thresholds.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span></span>
543
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">item, type: nextType } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item,</span></span>
544
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ),</span></span>
545
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
546
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
547
+ <span class="line"></span>
548
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span></span>
549
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">RobotMap</span></span>
550
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> config</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
551
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> controls: {</span></span>
552
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> threshold: {</span></span>
553
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 长度与厚度的米区间(缩放到临界值即停)</span></span>
554
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minLength: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
555
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxLength: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
556
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
557
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
558
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ... 其他配置见 config 参考</span></span>
559
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
560
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
561
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
562
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> runtime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
563
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> editingThresholdIds,</span></span>
564
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
565
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> thresholds</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{thresholds}</span></span>
566
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onRemoveThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleRemoveThreshold}</span></span>
567
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUpdateThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleUpdateThreshold}</span></span>
568
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClickThreshold</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleClickThreshold}</span></span>
569
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
570
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
571
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">只读展示</p><p>只读展示设备识别的门槛时,不把它们的 id 放进 <code>editingThresholdIds</code> 即可。</p></div><h3 id="坡道" tabindex="-1">坡道 <a class="header-anchor" href="#坡道" aria-label="Permalink to &quot;坡道&quot;">​</a></h3><p>坡道表示机器人可以爬上的一段斜面,数据由四个角点(<code>points</code>,顺时针 左上→右上→右下→左下,与门槛 / 禁区同序)构成,纹样是一列朝上的浅角箭头,用来指示上坡方向。编辑交互通过 <code>editingRampIds</code> 门控,列入的坡道显示删除 / 旋转 / 缩放 / 移动控件。</p><div class="tip custom-block"><p class="custom-block-title">坡向由点序自带,没有 direction 字段</p><p>坡向垂直于 0→1(宽)边、从 3→2 边指向 0→1 边 —— 未旋转时即「朝上」。旋转坡道时点集整体旋转,箭头随之旋转,所以你只需要维护 <code>points</code>。</p></div><p>新建坡道不用自己算四个角:<a href="/reference/methods.html#getramppointsbyviewportcenter"><code>getRampPointsByViewportCenter()</code></a> 在当前视口中心生成一片坡道的角点,缺省 0.8m × 0.4m(宽 × 高,高方向即坡向),可传 <code>width</code> / <code>height</code> 覆盖。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 例:用户点「添加坡道」时在视口中心放一片默认尺寸的坡道</span></span>
572
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> points</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> mapApi.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getRampPointsByViewportCenter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
573
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setRamps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">ramps, { id: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">nextId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), points }])</span></span></code></pre></div><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React, { useState } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
574
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { RobotMap, RampParam } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;@ray-js/robot-map&#39;</span></span>
575
+ <span class="line"></span>
576
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MapPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
577
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 将设备上报的坡道数据绘制到地图上</span></span>
578
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ramps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setRamps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">RampParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([</span></span>
579
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
580
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;ramp1&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
581
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 四角坐标:顶点 0→1 为宽方向,0→3 为高方向(即坡向)</span></span>
582
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> points: [</span></span>
583
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">8</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
584
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">16</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">8</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
585
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">16</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
586
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { x: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, y: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
587
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
588
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
589
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ])</span></span>
590
+ <span class="line"></span>
591
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">editingRampIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setEditingRampIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([])</span></span>
592
+ <span class="line"></span>
593
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击坡道删除按钮时触发(宿主收窄数据后重绘)</span></span>
594
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleRemoveRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
595
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setRamps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(ramps.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">filter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id))</span></span>
596
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
597
+ <span class="line"></span>
598
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 手势操作坡道(旋转 / 缩放 / 移动)结束后触发</span></span>
599
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleUpdateRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">ramp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> RampParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
600
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 强烈建议在 onUpdate 回调中更新业务侧的数据</span></span>
601
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setRamps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(ramps.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">item</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (item.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ramp.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ramp </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> item)))</span></span>
602
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
603
+ <span class="line"></span>
604
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 点击坡道时触发</span></span>
605
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handleClickRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">ramp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> RampParam</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
606
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 切换到编辑状态</span></span>
607
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setEditingRampIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">([ramp.id])</span></span>
608
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
609
+ <span class="line"></span>
610
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span></span>
611
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">RobotMap</span></span>
612
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> config</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
613
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> controls: {</span></span>
614
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ramp: {</span></span>
615
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 宽与高的米区间(缩放到临界值即停)</span></span>
616
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minWidth: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
617
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxWidth: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
618
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> minHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
619
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxHeight: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">4</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
620
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ... 其他配置见 config 参考</span></span>
621
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
622
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
623
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
624
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> runtime</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
625
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> editingRampIds,</span></span>
626
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
627
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ramps</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{ramps}</span></span>
628
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onRemoveRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleRemoveRamp}</span></span>
629
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onUpdateRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleUpdateRamp}</span></span>
630
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onClickRamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{handleClickRamp}</span></span>
631
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
632
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
633
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">只读展示</p><p>只读展示设备识别的坡道时,不把它们的 id 放进 <code>editingRampIds</code> 即可。</p></div><div class="warning custom-block"><p class="custom-block-title">点集会被归一化</p><p>绘制时绕向纠正为顺时针、宽与高分别钳制到 <a href="/reference/config.html#controls-ramp"><code>controls.ramp</code></a> 的 <code>minWidth</code>/<code>maxWidth</code> 与 <code>minHeight</code>/<code>maxHeight</code>(米)区间,再拉直成标准矩形。与门槛不同,<strong>不做</strong>长边规范(那会翻转坡向)。因此 <code>getRamps()</code> 与 <code>onUpdateRamp</code> 回吐的点集是归一化后的结果,不一定与传入的原始点逐字相同。</p></div><div class="tip custom-block"><p class="custom-block-title">小坡道上箭头会偏平</p><p>箭头折角默认只有 9°(取自 UED 矢量稿)。0.5m 的坡道在默认缩放下只有 10px 宽,折角外凸不到 1px,方向几乎看不出来。如果场景里小坡道很常见,把 <a href="/reference/config.html#controls-ramp-arrowangle"><code>controls.ramp.arrowAngle</code></a> 调陡(例如 <code>20</code>)会明显好读;整体纹样疏密由 <a href="/reference/config.html#controls-ramp-arrowdensity"><code>arrowDensity</code></a> 控制。</p></div><div class="warning custom-block"><p class="custom-block-title">组件库透传待发布</p><p><code>ramps</code> prop 的 <code>@ray-js/robot-map</code> 组件库透传尚未发布;SDK 侧 <code>drawRamps</code> / <code>getRamps</code> 等接口已可用。</p></div><div class="tip custom-block"><p class="custom-block-title">TIP</p><ul><li><p>虽然在设计上是纯受控的,但地图控制元素在手势操作时会先在内部实时进行更新,并在手势结束后通过 <code>onUpdate</code> 回调抛出最新的数据。</p></li><li><p>为保证一致性,我们强烈建议始终在 <code>onUpdate</code> 回调更新业务侧的数据。这个更新不会产生额外的渲染,你无需担心。</p></li></ul></div><h2 id="新增地图控制元素" tabindex="-1">新增地图控制元素 <a class="header-anchor" href="#新增地图控制元素" aria-label="Permalink to &quot;新增地图控制元素&quot;">​</a></h2><p>借助受控的设计,新增一个地图控制元素非常简单,以虚拟墙为例:</p><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>新增其他地图控制元素的方式也是类似的,重点在于如何维护好数据和运行时状态。</p></div><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> React </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;react&#39;</span></span>
572
634
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { RobotMap } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;@ray-js/robot-map&#39;</span></span>
573
635
  <span class="line"></span>
574
636
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MapPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
@@ -1288,8 +1350,8 @@
1288
1350
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (mapApi) {</span></span>
1289
1351
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> mapApi.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">forceEndGesture</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
1290
1352
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
1291
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">提示</p><p>地图 SDK 内部已针对双指缩放时的快速松手做了防抖缓冲处理,搭配上述方案可获得最佳手势体验。</p></div></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-08-03T08:52:07.000Z" data-v-e98dd255></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-e257564d><span class="visually-hidden" id="doc-footer-aria-label" data-v-e257564d>Pager</span><div class="pager" data-v-e257564d><a class="VPLink link pager-link prev" href="/guide/getting-started.html" data-v-e257564d><!--[--><span class="desc" data-v-e257564d>Previous page</span><span class="title" data-v-e257564d>快速开始</span><!--]--></a></div><div class="pager" data-v-e257564d><!----></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
1292
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"BsGRhEuG\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"Ca_k5NRJ\",\"guide_mcp.md\":\"BYlNOxMG\",\"guide_spot-room-binding.md\":\"CZGLnxCe\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"reference_callbacks.md\":\"BP78Z1wN\",\"reference_config.md\":\"DHyraAQF\",\"reference_data.md\":\"f7vBtzcn\",\"reference_methods.md\":\"D2L6f98h\",\"reference_runtime.md\":\"g-NWJXS6\",\"reference_types.md\":\"B2PPyukT\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
1353
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">提示</p><p>地图 SDK 内部已针对双指缩放时的快速松手做了防抖缓冲处理,搭配上述方案可获得最佳手势体验。</p></div></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-08-07T11:30:19.000Z" data-v-e98dd255></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-e257564d><span class="visually-hidden" id="doc-footer-aria-label" data-v-e257564d>Pager</span><div class="pager" data-v-e257564d><a class="VPLink link pager-link prev" href="/guide/getting-started.html" data-v-e257564d><!--[--><span class="desc" data-v-e257564d>Previous page</span><span class="title" data-v-e257564d>快速开始</span><!--]--></a></div><div class="pager" data-v-e257564d><!----></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
1354
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"BrP4iZb-\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"DOtxbNfK\",\"guide_mcp.md\":\"BYlNOxMG\",\"guide_spot-room-binding.md\":\"CZGLnxCe\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"reference_callbacks.md\":\"BP78Z1wN\",\"reference_config.md\":\"DHyraAQF\",\"reference_data.md\":\"f7vBtzcn\",\"reference_methods.md\":\"D2L6f98h\",\"reference_runtime.md\":\"g-NWJXS6\",\"reference_types.md\":\"B2PPyukT\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
1293
1355
 
1294
1356
  </body>
1295
1357
  </html>
@@ -9,9 +9,9 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.C5xCc25N.js"></script>
12
+ <script type="module" src="/assets/app.Cwwjhfv-.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.DdcAePki.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.BLq0Vss6.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
16
  <link rel="modulepreload" href="/assets/guide_concepts.md.CJ87tk-r.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
@@ -21,7 +21,7 @@
21
21
  <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle has-sidebar" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/" data-v-1168a8e4><!--[--><!--]--><!----><span data-v-1168a8e4>Tuya Robot Map</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/guide/concepts.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/reference/data.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>参考</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/simulator/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>模拟调试</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-a6f0e41e><span class="vpi-align-left menu-icon" data-v-a6f0e41e></span><span class="menu-text" data-v-a6f0e41e>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-5d98c3a5 data-v-319d5ca6><div class="curtain" data-v-319d5ca6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-319d5ca6><span class="visually-hidden" id="sidebar-aria-label" data-v-319d5ca6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-c40bc020><section class="VPSidebarItem level-0 has-active" data-v-c40bc020 data-v-b3fd67f8><div class="item" role="button" tabindex="0" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><h2 class="text" data-v-b3fd67f8>指南</h2><!----></div><div class="items" data-v-b3fd67f8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/guide/concepts.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>基本概念</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/guide/getting-started.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>快速开始</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/guide/advanced-usage.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>进阶使用</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-sidebar has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>页面导航</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _guide_concepts" data-v-39a288b8><div><h1 id="基本概念" tabindex="-1">基本概念 <a class="header-anchor" href="#基本概念" aria-label="Permalink to &quot;基本概念&quot;">​</a></h1><p>了解 Tuya Robot Map 的核心概念。</p><h2 id="核心组件" tabindex="-1">核心组件 <a class="header-anchor" href="#核心组件" aria-label="Permalink to &quot;核心组件&quot;">​</a></h2><p>后续文档中,我们会使用 <code>RobotMap</code> 组件作为示例,你可以根据实际需求选择使用 <code>RobotMap</code> 或 <code>RjsRobotMap</code> 组件。</p><h3 id="robotmap-组件" tabindex="-1">RobotMap 组件 <a class="header-anchor" href="#robotmap-组件" aria-label="Permalink to &quot;RobotMap 组件&quot;">​</a></h3><p>React 地图组件,提供完整的地图渲染和交互功能:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">RobotMap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p><ul><li><p><code>RobotMap</code> 组件是基于 <a href="https://developer.tuya.com/cn/miniapp/develop/ray/component/open/web-view" target="_blank" rel="noreferrer">WebView</a> 开发的,开发前请详细阅读<a href="https://developer.tuya.com/cn/miniapp/develop/miniapp/component/native-component/native-component" target="_blank" rel="noreferrer">原生组件说明</a>。</p></li><li><p><code>RobotMap</code> 默认铺满全屏,适用于<strong>首页实时地图</strong>等场景,一个页面只能有一个 <code>RobotMap</code> 组件。</p></li><li><p>需要在小程序<code>global.config.ts</code>中配置<code>webviewRoot</code>让小程序能够正确加载<code>RobotMap</code>的资源。</p></li></ul><div class="language-json vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
22
22
  <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;webviewRoot&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;node_modules/@ray-js/robot-map-sdk/dist-app&quot;</span></span>
23
23
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div></div><h3 id="rjsrobotmap-组件" tabindex="-1">RjsRobotMap 组件 <a class="header-anchor" href="#rjsrobotmap-组件" aria-label="Permalink to &quot;RjsRobotMap 组件&quot;">​</a></h3><p>基于Rjs开发的地图组件,它拥有和 <code>RobotMap</code> 组件相同的Props。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">RjsRobotMap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p><p><code>RjsRobotMap</code> 基于 <a href="https://developer.tuya.com/cn/miniapp/develop/ray/framework/render" target="_blank" rel="noreferrer">Rjs</a> 开发,它没有原生组件的限制,一个页面可以有多个 <code>RjsRobotMap</code> 组件。适用于<strong>多地图</strong>、<strong>弹窗里的地图</strong> 等场景。</p></div><div class="warning custom-block"><p class="custom-block-title">WARNING</p><p>引入 <code>RjsRobotMap</code> 对页面加载速度有一定影响。如无必要场景,我们建议始终使用 <code>RobotMap</code> 组件。</p></div><h2 id="坐标系统" tabindex="-1">坐标系统 <a class="header-anchor" href="#坐标系统" aria-label="Permalink to &quot;坐标系统&quot;">​</a></h2><h3 id="地图原点坐标" tabindex="-1">地图原点坐标 <a class="header-anchor" href="#地图原点坐标" aria-label="Permalink to &quot;地图原点坐标&quot;">​</a></h3><p>地图原点是扫地机器人运行过程中确定的参考点,地图上的元素都是基于这个原点计算的相对位置。</p><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>地图原点本身是相对于地图左上角来定位的。例如在一张100 x 100(宽 x 高)的 地图中,如果原点坐标是(20, 80),表示原点位于相对于地图左上角(20, 80)的位置。</p></div><h3 id="地图坐标系" tabindex="-1">地图坐标系 <a class="header-anchor" href="#地图坐标系" aria-label="Permalink to &quot;地图坐标系&quot;">​</a></h3><p>地图坐标系是本 SDK 实际使用的坐标系,用于在地图上渲染和显示各种元素。地图坐标系以地图原点为中心(0, 0):</p><ul><li>X轴:向右为正方向</li><li>Y轴:向下为正方向</li></ul><h4 id="与机器坐标系的不同" tabindex="-1">与机器坐标系的不同 <a class="header-anchor" href="#与机器坐标系的不同" aria-label="Permalink to &quot;与机器坐标系的不同&quot;">​</a></h4><p>需要注意的是,本 SDK 使用的地图坐标系与扫地机器人设备本身使用的机器坐标系在 Y 轴方向上相反:</p><ul><li><p><strong>机器坐标系</strong>(设备使用的坐标系):</p><ul><li>X轴:向右为正方向</li><li>Y轴:向上为正方向</li></ul></li><li><p><strong>地图坐标系</strong>(本 SDK 使用的坐标系):</p><ul><li>X轴:向右为正方向(与机器坐标系一致)</li><li>Y轴:向下为正方向(与机器坐标系相反)</li></ul></li></ul><p>SDK 采用标准的屏幕坐标系(Screen Coordinate System)进行渲染,因此 Y 轴方向与机器坐标系相反。在 SDK 中,如果原点在(0, 0),坐标为(1, 1)的点会渲染在原点的右下方。</p><p>例如,以下元素的坐标均使用地图坐标系:</p><ul><li>充电桩</li><li>清扫路径 (含机器人位置)</li><li>虚拟墙</li><li>禁区</li><li>清扫区域</li><li>分割线</li><li>其他自定义元素</li><li>...</li></ul><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>本文档中,如果未特别说明,涉及到的坐标均指地图坐标系(X向右,Y向下)。</p></div></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2025-12-30T11:04:05.000Z" data-v-e98dd255></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-e257564d><span class="visually-hidden" id="doc-footer-aria-label" data-v-e257564d>Pager</span><div class="pager" data-v-e257564d><!----></div><div class="pager" data-v-e257564d><a class="VPLink link pager-link next" href="/guide/getting-started.html" data-v-e257564d><!--[--><span class="desc" data-v-e257564d>Next page</span><span class="title" data-v-e257564d>快速开始</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
24
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"BsGRhEuG\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"Ca_k5NRJ\",\"guide_mcp.md\":\"BYlNOxMG\",\"guide_spot-room-binding.md\":\"CZGLnxCe\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"reference_callbacks.md\":\"BP78Z1wN\",\"reference_config.md\":\"DHyraAQF\",\"reference_data.md\":\"f7vBtzcn\",\"reference_methods.md\":\"D2L6f98h\",\"reference_runtime.md\":\"g-NWJXS6\",\"reference_types.md\":\"B2PPyukT\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
24
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"BrP4iZb-\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"DOtxbNfK\",\"guide_mcp.md\":\"BYlNOxMG\",\"guide_spot-room-binding.md\":\"CZGLnxCe\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"reference_callbacks.md\":\"BP78Z1wN\",\"reference_config.md\":\"DHyraAQF\",\"reference_data.md\":\"f7vBtzcn\",\"reference_methods.md\":\"D2L6f98h\",\"reference_runtime.md\":\"g-NWJXS6\",\"reference_types.md\":\"B2PPyukT\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
25
25
 
26
26
  </body>
27
27
  </html>