gis-view-webgl2 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +232 -228
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +49 -0
- package/docs/GisView.md +1 -1
- package/docs/ai/06-/344/274/232/350/257/235/347/264/242/345/274/225/344/270/216/345/244/215/346/237/245/346/226/271/346/263/225.md +48 -0
- package/docs/demos/BasicDemo.vue +2 -2
- package/docs/demos/BatchAddDemo.vue +6 -6
- package/docs/demos/ConnectDemo.vue +164 -33
- package/docs/demos/CopyMergeDemo.vue +27 -14
- package/docs/demos/EventDemo.vue +17 -20
- package/docs/demos/LabelDemo.vue +5 -5
- package/docs/demos/api-index.js +31 -29
- package/docs/demos/gis-view-demo/GisViewDemoCardHeader.vue +1 -1
- package/docs/demos/gis-view-demo/GisViewDemoStage.vue +1 -1
- package/docs/demos/gis-view-demo/panels/DataPanels.vue +1 -1
- package/docs/demos/gis-view-demo/useGisViewDemo.js +31 -33
- package/docs/format/07-/344/272/213/344/273/266/350/275/275/350/215/267/344/270/216/347/244/272/344/276/213/346/225/260/346/215/256.md +8 -7
- package/docs/from0/05-/347/233/270/346/234/272/344/270/216/344/272/244/344/272/222.md +1 -1
- package/docs/from0/07-/351/200/232/351/201/223/345/210/206/347/273/204/344/270/216/345/244/232/345/233/236/347/272/277.md +26 -10
- package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +1 -1
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +21 -16
- package/docs/manual/06-/346/225/260/346/215/256/344/270/216/345/234/272/346/231/257/346/233/264/346/226/260.md +9 -10
- package/docs/manual/07-/346/214/207/351/222/210/344/270/216/350/246/201/347/264/240/347/274/226/350/276/221.md +54 -31
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +3 -3
- package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +9 -6
- package/docs/manual/10-/351/200/232/351/201/223/347/274/226/350/276/221/344/270/216/346/226/260/345/242/236.md +226 -493
- package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +2 -2
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +12 -13
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +23 -21
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +19 -17
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +125 -78
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +1 -1
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +2 -2
- package/docs/manual/21-/350/257/264/346/230/216/344/270/216/345/270/270/350/247/201/351/227/256/351/242/230.md +4 -4
- package/docs/steps/README.md +9 -7
- package/docs/steps/bench-scale.html +1 -1
- package/docs/steps/index.html +6 -6
- package/docs/steps/selftest-actions.html +26 -25
- package/docs/steps/selftest-data.html +1 -1
- package/docs/steps/selftest-demos.html +102 -6
- package/docs/steps/selftest-docs.html +3 -3
- package/docs/steps/selftest-features.html +283 -51
- package/docs/steps/selftest-full.html +3 -3
- package/docs/steps/selftest-labels.html +1 -1
- package/docs/steps/selftest-perf.html +31 -4
- package/docs/steps/selftest-select.html +20 -5
- package/docs/steps/step-05-pick.js +4 -8
- package/docs/steps/step-07-channels.js +3 -5
- package/docs/steps/step-08-labels.js +3 -3
- package/docs/steps/step-10-full.js +3 -3
- package/docs/steps/step-12-events.js +41 -24
- package/package.json +1 -1
|
@@ -69,21 +69,41 @@ view.updateOptions({ cascadeHighlight: false }) // 关掉并收掉当前高亮
|
|
|
69
69
|
|
|
70
70
|
### action:一次操作的判读
|
|
71
71
|
|
|
72
|
-
指针事件、拐点、标签与选中集事件都带一份 `action
|
|
72
|
+
指针事件、拐点、标签与选中集事件都带一份 `action`,回答两个问题:**这是什么操作**(`action.type`)、**点在了什么上面**(`action.target`)。命中的数据不重复打包,直接在载荷顶层读:
|
|
73
73
|
|
|
74
74
|
| 字段 | 取值 | 说明 |
|
|
75
75
|
| --- | --- | --- |
|
|
76
76
|
| `action.type` | 动作名 | 按下时是**意图**(`dragPoint` 拖节点 / `dragWaypoint` 拖拐点 / `boxSelect` 框选 / `pan` 平移 / `copy` 复制 / `channelDraft` 点两次加通道 / `decorationDraft` 动态装饰器草稿 / `contextMenu` 右键 / `click` 普通左键),松开时是**刚做完的那件事**(没拖就是 `click`),点击时是**真正发生的那一件**(`select` 选中 / `clearSelection` 点空白 / `click` 没开选中时的点击);拐点是 `addWaypoint` / `removeWaypoint` / `selectWaypoint` / `dragWaypoint`,标签是 `selectLabel` / `dragLabel` / `contextMenu` / `dblClick`,选中集是 `select` / `toggleSelect` / `boxSelect` / `clearSelection`,悬停固定是 `hover` |
|
|
77
77
|
| `action.target` | `point` / `line` / `channel` / `waypoint` / `label` / `selection` / `empty` | 点在了什么上面:通道回线的 `type` 也是 `line`,但要按通道处理,所以 `target` 单独给 `channel`;点空白是 `empty`;拐点与标签各有自己的 `waypoint` / `label` |
|
|
78
|
-
|
|
|
79
|
-
| `
|
|
80
|
-
| `action.modifiers` | `{ ctrl, meta, shift, alt }` | 修饰键,与原生事件一一对应 —— 「按住 Shift 是另一套菜单」这类判断不用再读 `originalEvent` |
|
|
81
|
-
| `action.left` / `action.right` | 布尔 | 左键 / 右键的一眼判定(与 `action.button` 同一份:`left` 就是 `button === 'left'`),比比对字符串少写一点;中键两边都是 `false` |
|
|
78
|
+
| 命中数据 | 载荷顶层 | 点 / 线读 `item`(与数据里同一份对象);通道回线读 `channel` / `channelContext`;选中集变更读 `items`;拐点读 `lineIndex` / `pathIndex` / `coordinate` / `line`;标签读 `label` / `parent`;聚合读 `id` / `count` / `pointIds` / `bounds` |
|
|
79
|
+
| 原始输入 | `originalEvent` | 鼠标键(`button` / `buttons`)、修饰键(`ctrlKey` / `metaKey` / `shiftKey` / `altKey`)与 `clientX` / `clientY` 都从原始事件读;程序化 `hoverAt()` 没有这一份 |
|
|
82
80
|
| `action.moved` | 布尔 | 这一次按下之后有没有真的拖动过:按下恒为 `false`,松开时说明是「拖」还是「点」,拐点拖动是 `start` 为 `false`、`move` / `end` 为 `true` |
|
|
83
81
|
| `action.double` | 布尔 | 只在点击载荷里出现:`true` 说明这一下是双击里的第二下(单双击要做两件事的界面按它推迟一下) |
|
|
84
82
|
| `action.press` | 动作名 / `null` | 只在松开 / 点击载荷里出现:**按下时的意图**(与那一刻 `onPointerDown` 的 `action.type` 同一份)——「按下想拖、松开成了点」这类对照看它;没有配对的按下事件时是 `null` |
|
|
85
83
|
| `action.duration` | 毫秒 | 只在松开 / 点击载荷里出现:这一次按下按了多久(四舍五入),没有配对的按下事件时是 `0` |
|
|
86
|
-
| `action.longPress` | 布尔 | 只在松开 / 点击载荷里出现:这一次算不算长按(超过 500 ms 且中间没拖动过 —— 触摸 /
|
|
84
|
+
| `action.longPress` | 布尔 | 只在松开 / 点击载荷里出现:这一次算不算长按(超过 500 ms 且中间没拖动过 —— 触摸 / 触控笔按它出菜单;鼠标键仍看 `originalEvent.button`) |
|
|
85
|
+
|
|
86
|
+
### 载荷迁移:旧字段 → 新入口
|
|
87
|
+
|
|
88
|
+
这一版把能从别处取得的字段从回调载荷里删掉了。旧代码按下表改一行即可;`selected` / `wasSelected` 是事件发生时的状态快照,保留:
|
|
89
|
+
|
|
90
|
+
| 旧字段 / 写法 | 现在从哪取 |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `payload.selection` | `view.getSelectionInfo()`(`{ ids, count, points, lines, channels }`,结果按选中集引用缓存) |
|
|
93
|
+
| `action.data`(点 / 线) | `payload.item` |
|
|
94
|
+
| `action.data`(通道回线) | `payload.channel` / `payload.channelContext` |
|
|
95
|
+
| `action.data`(选中集) | `payload.items` |
|
|
96
|
+
| `action.data`(拐点) | `payload.lineIndex` / `pathIndex` / `coordinate` / `line` |
|
|
97
|
+
| `action.data`(标签) | `payload.label` / `payload.parent` |
|
|
98
|
+
| `action.data`(聚合) | 载荷顶层 `id` / `count` / `pointIndexes` / `pointIds` / `bounds` / `radius` |
|
|
99
|
+
| `action.button` / `action.modifiers` / `action.left` / `action.right` | `payload.originalEvent.button` / `buttons` / `ctrlKey` / `metaKey` / `shiftKey` / `altKey` |
|
|
100
|
+
| `payload.button` / `payload.buttons` | `payload.originalEvent.button` / `buttons` |
|
|
101
|
+
| `payload.clientX` / `payload.clientY` | `payload.originalEvent.clientX` / `clientY` |
|
|
102
|
+
| `payload.lineIndex` / `payload.lineId`(右键线路) | `payload.index` / `payload.item.id`;通道归属用 `view.getLineChannel(payload.index)` |
|
|
103
|
+
| 复制载荷 `payload.point` | `payload.item`;批量看 `payload.items[0]` |
|
|
104
|
+
| 复制载荷 `payload.coordinate` | `payload.item.x` / `payload.item.y`;批量看 `payload.items[0].x` / `y` |
|
|
105
|
+
| 复制载荷 `payload.setItem(patch)` | `payload.update(patch)` |
|
|
106
|
+
| 回调 `(payload, event)` 两个参数 | 回调只收 `(payload)`,DOM 事件在 `payload.originalEvent`;事件总线载荷也不再包成 `{ payload, event }` |
|
|
87
107
|
|
|
88
108
|
```js
|
|
89
109
|
createGisView(container, {
|
|
@@ -91,19 +111,19 @@ createGisView(container, {
|
|
|
91
111
|
// 一套分支处理全部指针操作:先看是什么操作,再看点在什么上面,最后直接取数据
|
|
92
112
|
onPointerUp: payload => {
|
|
93
113
|
if (payload.action.moved) return // 拖过的不当点击处理
|
|
94
|
-
if (payload.action.type === 'click' && payload.action.target === 'point') openPoint(payload.
|
|
95
|
-
if (payload.action.type === 'click' && payload.action.target === 'channel') openChannel(payload.
|
|
114
|
+
if (payload.action.type === 'click' && payload.action.target === 'point') openPoint(payload.item)
|
|
115
|
+
if (payload.action.type === 'click' && payload.action.target === 'channel') openChannel(payload.channel)
|
|
96
116
|
if (payload.action.target === 'empty') closePanel()
|
|
97
117
|
},
|
|
98
118
|
onClick: payload => {
|
|
99
119
|
if (!payload) return // 空白处的点击载荷是 null(选中已经清空)
|
|
100
120
|
if (payload.action.double) return // 双击的第二下:单双击要做不同的事时按它推迟
|
|
101
|
-
openDetail(payload.item, payload.action.type, payload.
|
|
121
|
+
openDetail(payload.item, payload.action.type, payload.originalEvent)
|
|
102
122
|
},
|
|
103
|
-
onContextMenu:
|
|
104
|
-
|
|
123
|
+
onContextMenu: payload => {
|
|
124
|
+
payload.originalEvent.preventDefault()
|
|
105
125
|
// 右键只有一条意思:action.type 恒为 contextMenu,action.target 说明点的是什么
|
|
106
|
-
openMenu(payload.action.target, payload
|
|
126
|
+
openMenu(payload.action.target, payload, payload.world)
|
|
107
127
|
}
|
|
108
128
|
})
|
|
109
129
|
```
|
|
@@ -112,16 +132,16 @@ createGisView(container, {
|
|
|
112
132
|
createGisView(container, {
|
|
113
133
|
points, lines, channels,
|
|
114
134
|
// 左键按下:按下那一刻光标下的要素
|
|
115
|
-
onPointerDown:
|
|
116
|
-
console.log(payload.button, payload.buttons) // 0 左键、1 中键、2 右键
|
|
135
|
+
onPointerDown: payload => {
|
|
136
|
+
console.log(payload.originalEvent.button, payload.originalEvent.buttons) // 0 左键、1 中键、2 右键
|
|
117
137
|
console.log(payload.hit, payload.type, payload.item) // 空白处 hit 为 false、type 为 null
|
|
118
138
|
console.log(payload.world, payload.x, payload.y) // 光标处的世界坐标与画布 CSS 像素
|
|
119
139
|
},
|
|
120
140
|
onPointerUp: payload => console.log('抬起', payload.type, payload.item),
|
|
121
141
|
// 右键:点 / 线 / 空白都发,命中通道回线时载荷里还有 channelId / groupId / channelIndex / group / groups
|
|
122
|
-
onContextMenu:
|
|
142
|
+
onContextMenu: payload => {
|
|
123
143
|
if (!payload.hit) return // 空白处也可以在这里收掉自己的菜单
|
|
124
|
-
|
|
144
|
+
payload.originalEvent.preventDefault() // 想自己弹菜单就拦住浏览器默认菜单
|
|
125
145
|
openMenu(payload.item, payload.world, payload.type)
|
|
126
146
|
},
|
|
127
147
|
onHover: payload => console.log('悬停', payload?.item ?? '空白处')
|
|
@@ -133,12 +153,12 @@ createGisView(container, {
|
|
|
133
153
|
- 配了 GeoJSON 背景时,以上载荷都多一个 `lngLat`:按光标的世界坐标(要素命中用 `coordinate`,悬停用最近一次光标位置)反算出来的真实经纬度,点 / 线 / 通道都一样;想自己换算就用 `worldToLngLat` / `screenToLngLat`,光标级别的屏幕坐标 + 世界坐标 + 经纬度看 `onPointer` 与 `getPointer()`。
|
|
134
154
|
- `onPointerDown` / `onPointerUp` 不改变组件行为:选中、拖拽、框选、拐点编辑照旧。左键的一次「点」(没有拖动)仍然走 `onClick` / `onDblClick`,两者是并列的,不会互相吞掉 —— 载荷里的 `action.type` 各说各话:按下是**意图**、松开是**刚做完的那件事**(`action.moved` 说明是拖还是点)、点击是**真正发生的那一件**。这一下如果同时改了选中,顺序固定是 `onClick → onSelect → onSelectChange`;`selectTrigger: 'dblClick'` 的第二下再在最后补 `onDblClick`。
|
|
135
155
|
- 点空白处照发:`onPointerDown` / `onPointerUp` 的 `action.target` 是 `empty`(开了平移时按下是 `pan` 的意图),`onClick` / `onDblClick` 的载荷是 `null`(选中在那一刻已经清空)——「点了空白」这件事也可以看 `onSelectChange` 的 `action.type: 'clearSelection'`。
|
|
136
|
-
- **中键按住就是临时平移**(`pan` 开关开着时):`onPointerDown` 的 `action.type` 是 `pan`、`
|
|
156
|
+
- **中键按住就是临时平移**(`pan` 开关开着时):`onPointerDown` 的 `action.type` 是 `pan`、`originalEvent.button === 1`,按住拖动平移画布、松开结束(`onPointerUp` 的 `action.type` 也是 `pan`);这一路**不经过** `onClick`,中键也不会改选中 —— 想自己接中键(中键菜单 / 快捷操作)就按 `originalEvent.button` 认它。长按(触摸 / 触控笔)与中键一样有明确的读数:看松开 / 点击载荷的 `action.longPress` 与 `action.press` / `action.duration`。
|
|
137
157
|
- `onContextMenu` 每次都只发这一条;命中通道回线时,分组读数在同一份载荷的 `group` / `groups` 上,可执行动作挂在 `channelContext` 上(见「通道右键交互框」),不再额外发第二个回调。**右键缺省整个不接**(`contextMenu` 开关没开时系统菜单照弹、回调也不发);接住之后一律 `preventDefault()` 收掉系统菜单(点 / 线 / 空白 / 通道都一样),回调照常发。想自己弹菜单就写 `interactive: true` / `contextMenu: true` / `features: 'view'`,想让系统菜单自己弹出来就写 `preventContextMenu: false`。
|
|
138
158
|
- 命中的层级是**点 → 线 → 通道**:右键落在节点上时载荷是 `type: 'point'`,没有 `channelContext` —— 节点压在通道回线上(端点最常见)不会被当成通道右键;点空白处同样没有 `channelContext`,可以直接用它收框。
|
|
139
159
|
- 悬停是高频率回调:大数据量下建议只做节流的读数或轻量样式切换(demo 里的读数就是这么做的)。
|
|
140
160
|
|
|
141
|
-
-
|
|
161
|
+
- 命中的要素**在不在选中集里**用载荷里的 `selected`(这一刻)/ `wasSelected`(`onClick` 给的是「点之前」的那一份,双击同理;右键与按下 / 松开都是「当下」,此时与 `selected` 相同)。整份选中集有多少改用 `view.getSelectionInfo()`:`{ ids, count, points, lines, channels }`,通道回线按通道算一个。左键 / 右键要自己接一套操作(按命中分支、弹自己的面板、决定要不要保留多选)时,这一快照加一次读数就够:
|
|
142
162
|
|
|
143
163
|
```js
|
|
144
164
|
createGisView(container, {
|
|
@@ -147,23 +167,24 @@ createGisView(container, {
|
|
|
147
167
|
if (!payload) return // 空白处:选中已经清空
|
|
148
168
|
// payload.selected:「点完之后」在不在选中集里;payload.wasSelected:「点之前」的那一份
|
|
149
169
|
if (payload.selected && payload.wasSelected) openDetail(payload.item)
|
|
150
|
-
|
|
170
|
+
const info = view.getSelectionInfo()
|
|
171
|
+
console.log(info.count, info.channels)
|
|
151
172
|
},
|
|
152
|
-
onContextMenu:
|
|
153
|
-
|
|
173
|
+
onContextMenu: payload => {
|
|
174
|
+
payload.originalEvent.preventDefault() // 自己弹菜单
|
|
154
175
|
if (payload.type === 'point' && !payload.wasSelected) {
|
|
155
176
|
// 右键落在没选中的节点上:先把它选上,再按「选中集」弹面板(落在已选中的节点上就保留整份多选)
|
|
156
177
|
view.selectFeatures(payload.item.id)
|
|
157
178
|
}
|
|
158
|
-
openMenu({ target: payload.item, selection:
|
|
179
|
+
openMenu({ target: payload.item, selection: view.getSelectionInfo(), coordinate: payload.world })
|
|
159
180
|
}
|
|
160
181
|
})
|
|
161
182
|
```
|
|
162
183
|
|
|
163
|
-
- Ctrl + 点击(多选取反)与 Shift + 拖动(默认框选键,可用 `shortcuts.boxSelect` 改)**不经过** `onClick`:顺序是 `onSelect → onSelectChange`。取反的 `action.type` 是 `toggleSelect`(取反取没了也是它,此时 `action.target` 是 `empty`)、框选是 `boxSelect`(没框到东西也是它)、点空白清空是 `clearSelection`;载荷里的 `items` 是操作之后的选中集、`count` 是新的条数。想在这条路里知道「点下去的那一刻它是不是已选中的」,看 `onPointerDown` / `onPointerUp` 载荷的 `selected`,或者在回调里读一次 `getSelectionData()`。选中事件里通道回线的 `group` / `groups`
|
|
184
|
+
- Ctrl + 点击(多选取反)与 Shift + 拖动(默认框选键,可用 `shortcuts.boxSelect` 改)**不经过** `onClick`:顺序是 `onSelect → onSelectChange`。取反的 `action.type` 是 `toggleSelect`(取反取没了也是它,此时 `action.target` 是 `empty`)、框选是 `boxSelect`(没框到东西也是它)、点空白清空是 `clearSelection`;载荷里的 `items` 是操作之后的选中集、`count` 是新的条数。想在这条路里知道「点下去的那一刻它是不是已选中的」,看 `onPointerDown` / `onPointerUp` 载荷的 `selected`,或者在回调里读一次 `getSelectionData()`。选中事件里通道回线的 `group` / `groups` 与本次选中的 `lineIndexes` / `lineIds` 看单通道载荷顶层;多通道一起选中时看 `channelContexts`。`items[]` 里的回线不重复挂任何通道字段,需要单条归属时用外层 `lineIndexes` / `lineIds` 映射或调 `getLineChannel(index)`。
|
|
164
185
|
- 不订阅事件、只想知道「这儿是什么」时用 `pickAt(clientX, clientY)`:按鼠标事件里的客户端坐标拾取,返回与指针载荷同一份结果(另加 `target` 与 `lngLat`),空白处返回 `null`;只读 —— 不改选中、不动光标,自建浮层 / 自定义菜单 / 拖拽放下时用它。框内有什么(自建框选界面、框内统计)用 `getFeaturesInRect(rect)`、当前画面里有哪几条通道用 `getChannelsInView()`,三个方法都在「实例方法」里。
|
|
165
186
|
- 悬停也可以**程序化驱动**:`hoverAt(clientX, clientY)` 让指针「停」到某个位置(悬停高亮、光标与 `onHover` 一起更新,返回与 `onHover` 同一份读数),`clearHover()` 撤掉并补发一条 `onHover(null)`,`getHover()` 随时读当前这一份 —— 外部列表 / 表格 hover 到某一行时联动高亮图上的要素用它,不必自己派发指针事件;不需要了就不用订阅 `onHover`。
|
|
166
|
-
- 选中集整个拿走用 `getSelectionData()`,一份就够:读数(`ids` / `count` / `pointCount` / `lineCount` / `channelCount`)加**要素本身**(`points` / `lines` / `channels`(按通道去重))与 `items`(与 `getSelections()`
|
|
187
|
+
- 选中集整个拿走用 `getSelectionData()`,一份就够:读数(`ids` / `count` / `pointCount` / `lineCount` / `channelCount`)加**要素本身**(`points` / `lines` / `channels`(按通道去重))与 `items`(与 `getSelections()` 同一份,通道回线不带通道字段)、`pointIndexes` / `lineIndexes`、`bounds`(世界包围盒,空选中时 `null`):
|
|
167
188
|
|
|
168
189
|
```js
|
|
169
190
|
const data = view.getSelectionData()
|
|
@@ -344,13 +365,13 @@ if (!copied.ok) console.warn(copied.reason)
|
|
|
344
365
|
|
|
345
366
|
| phase | 什么时候 | 能做什么 |
|
|
346
367
|
| --- | --- | --- |
|
|
347
|
-
| `start` | 预览刚出现 | `payload.update({...})`
|
|
368
|
+
| `start` | 预览刚出现 | `payload.update({...})` 改复制品,`payload.cancel()` 直接取消 |
|
|
348
369
|
| `move` | 预览跟着鼠标动(`follow: true`) | 同 `start` |
|
|
349
370
|
| `commit` | 落地之前(`commitPointCopy()` 里发) | `payload.cancel()` 可以拦住这一次复制,改数据也在这里生效 |
|
|
350
371
|
| `end` | 已经落地 | 读 `payload.index` / `payload.item` 同步业务数据 |
|
|
351
372
|
| `cancel` | 复制被取消 | 清理自建预览 |
|
|
352
373
|
| `clipboard` | 复制到剪贴板(Ctrl+C) | `payload.cancel()` 表示不要这次剪贴板 |
|
|
353
|
-
| `batch` | 批量复制 / 整组粘贴落地 | 读 `payload.sources`(来源快照)、`payload.items` / `indexes`(新节点)、`payload.lines` / `channels`(一起复制出来的内部线路 / 通道);要撤掉整批用 `payload.revert()` / `cancel()`,要改落地后的节点用 `view.updatePoint(payload.item.id, patch)`(批量载荷不提供预览期的 `update`
|
|
374
|
+
| `batch` | 批量复制 / 整组粘贴落地 | 读 `payload.sources`(来源快照)、`payload.items` / `indexes`(新节点)、`payload.lines` / `channels`(一起复制出来的内部线路 / 通道);要撤掉整批用 `payload.revert()` / `cancel()`,要改落地后的节点用 `view.updatePoint(payload.item.id, patch)`(批量载荷不提供预览期的 `update` 改写) |
|
|
354
375
|
|
|
355
376
|
```js
|
|
356
377
|
createGisView(container, {
|
|
@@ -638,14 +659,16 @@ const split = view.splitPoint('hub', [
|
|
|
638
659
|
{ name: '枢纽(主)' }, // 第一份:沿用原下标与 id
|
|
639
660
|
{ x: 116.42, y: 39.91, name: '枢纽(东)', lines: ['line-east'] },
|
|
640
661
|
{ x: 116.38, y: 39.89, name: '枢纽(西)', lines: ['line-west'], channelTo: ['corridor-1'] }
|
|
641
|
-
], { label: '
|
|
662
|
+
], { autoLines: 'alternate', label: '解除合并' })
|
|
642
663
|
|
|
643
664
|
if (split.ok) {
|
|
644
|
-
console.log(split.pointIds, split.
|
|
665
|
+
console.log(split.pointIds, split.autoAssignedLines, split.lineAssignments)
|
|
645
666
|
api.post('/gis/points/split', split.changes) // 拆分后的节点、受影响的线路与通道端点,以及删除项
|
|
646
667
|
}
|
|
647
668
|
```
|
|
648
669
|
|
|
670
|
+
`options.autoLines` 决定**没写进 `lines` 的线路**怎么分:缺省 `'first'` 全跟第一份(兼容旧行为);`'alternate'` 按「同一条通道的成员成一组、独立线路各算一条」为单位,轮流分给当前负载最少的一份。显式写进 `lines` 的线路不参与自动分配,但会计入负载;同一条通道的成员因此不会被拆到两份上。解除合并时推荐 `'alternate'`,可以让四回线的通道整体去 A、两条独立线路分别去 A / B,而不是把通道回线拆散。
|
|
671
|
+
|
|
649
672
|
每份节点定义可以直接写节点字段(`id` / `x` / `y` / `name` / 样式 / 业务字段),也可以放进 `item`;另外三项是从节点字段里摘出来的分配指令,不会写进节点数据:
|
|
650
673
|
|
|
651
674
|
| 字段 | 作用 |
|
|
@@ -658,14 +681,14 @@ if (split.ok) {
|
|
|
658
681
|
|
|
659
682
|
- **第一份接在原下标上**,缺省沿用来源节点的 id;其余几份追加到 `points` 末尾。`options.keepSourceId: false` 时第一份也生成 `${来源 id}-split-1`。没写 id 的其余份依次生成 `${来源 id}-split-2` / `-3`…,撞上现有 id 时自动加序号;显式写了重复 id 会整次失败。
|
|
660
683
|
- **节点字段从来源继承,再按这一份的字段覆盖**;坐标缺省继承来源。至少给两份,坐标必须是有效数字,否则 `ok: false` 且 `reason` 说明原因。
|
|
661
|
-
- **线路默认跟第一份**:没写进任何一份 `lines
|
|
684
|
+
- **线路默认跟第一份**:没写进任何一份 `lines`、但连在来源节点上的线路,`autoLines: 'first'`(缺省)时全部改挂到第一份;写 `autoLines: 'alternate'` 时按上面的「通道成组 / 独立线路单条」轮流分配。同一条线路显式分给两份会整次失败。认不出 / 没连在来源上的引用进 `skipped.lines`,不影响其余条目。
|
|
662
685
|
- **通道端点默认跟第一条被分配过的成员回线**:例如通道里唯一一条回线分给了第二份,通道的 `from` 会自动改到第二份节点,而不是留在第一份;成员都没显式分配时才回落到第一份。显式写了 `channels` / `channelFrom` / `channelTo` 的按显式分配来。
|
|
663
686
|
- **几何一起改**:线路的 `from` / `to` 改到对应新节点;没有 id 绑定、但 `start` / `end` / `path` 顶点与来源坐标重合的端点 / 顶点也改到新坐标。通道端点按新声明重新锚定,成员回线由通道骨架推导,不用逐条改。
|
|
664
687
|
- **拆完清理退化数据**:两端落到同一份、变自环或零长度的线路删掉;两端因此相同的通道删掉;成员回线全被删空的通道也删掉。删除项分别进 `removedLineIds` / `removedLineIndexes` 与 `removedChannelIds`。
|
|
665
|
-
- **返回的 `channelsChanged` 只数端点被改写的通道**;被删掉的通道单列在 `removedChannels` / `removedChannelIds`。`changes` 给 `{ removedPoint, points, lines, removedLines, channels, removedChannels }`:`points` 是拆分后的全部节点,`lines` / `channels` 是仍存在且端点被改写的线路 / 通道,删除项单列;可直接作为后端事务输入。`skipped` 说明哪些线路 / 通道引用没认出来。
|
|
688
|
+
- **返回的 `channelsChanged` 只数端点被改写的通道**;被删掉的通道单列在 `removedChannels` / `removedChannelIds`。`autoLines` 是本次采用的口径,`autoAssignedLines` 只数自动分配(没在 `parts[].lines` 里显式写)的线路,`lineAssignments` 按份给出 `{ index, pointId, lineIds, lineCount }`,含显式与自动分配后的最终结果。`changes` 给 `{ removedPoint, points, lines, removedLines, channels, removedChannels }`:`points` 是拆分后的全部节点,`lines` / `channels` 是仍存在且端点被改写的线路 / 通道,删除项单列;可直接作为后端事务输入。`skipped` 说明哪些线路 / 通道引用没认出来。
|
|
666
689
|
- **撤销**:不用逐条回滚,`view.undo()` 一步回到拆分前;重做一步恢复拆分结果。
|
|
667
690
|
|
|
668
|
-
`CopyMergeDemo.vue`
|
|
691
|
+
`CopyMergeDemo.vue` 的「解除合并」一节可以直接点按钮看效果:选中一个节点,按两份拆开,调用 `splitPoint(source.id, [A, B], { autoLines: 'alternate', label: '解除合并' })`;读数会列出新节点 id、自动分线数、每份接到多少条线路、通道成员是否仍成组,以及改绑 / 删除的线路与通道。
|
|
669
692
|
|
|
670
693
|
## 删除(remove)
|
|
671
694
|
|
|
@@ -27,7 +27,7 @@ view.deselect() // 取消全部
|
|
|
27
27
|
|
|
28
28
|
`refs` 可以是节点 / 线路 id、`{ type, index }`、通道 / 分组写法、拾取载荷或搜索命中。公开实例没有 `select()`,旧代码统一改用 `selectFeatures()`;`deselect([])` 是「没有目标」,不会改选中集。上面按缺省 `selectTrigger: 'click'` 写;改成 `'dblClick'` 后,选中与点空白清空都由第二下完成,接口调用不受影响。
|
|
29
29
|
|
|
30
|
-
**选中状态只有一份**:`selectFeatures()` / `deselect()` 与单击、Ctrl 多选、框选改的是同一份选中 state,样式、`isSelected()` 与 `getSelectionData()` 都立即更新。选中集实际变化时,它们与点击一样会按 `onSelect → onSelectChange` 发回调(接口来源 `cause: 'api'`);区别只在入口和通知口径,不在“算不算选中”。`onSelect` 是**本次操作**回调(真实点击 / 框选 / `selectAt` 每次成功操作都发),`onSelectChange`
|
|
30
|
+
**选中状态只有一份**:`selectFeatures()` / `deselect()` 与单击、Ctrl 多选、框选改的是同一份选中 state,样式、`isSelected()` 与 `getSelectionData()` 都立即更新。选中集实际变化时,它们与点击一样会按 `onSelect → onSelectChange` 发回调(接口来源 `cause: 'api'`);区别只在入口和通知口径,不在“算不算选中”。`onSelect` 是**本次操作**回调(真实点击 / 框选 / `selectAt` 每次成功操作都发),`onSelectChange` 是**集合状态**回调(只在集合真的变了时发,适合同步面板)。选中通道回线时两条回调都在外层带 `channelId` / `group` / `groups` / 本次选中的 `lineIndexes` / `lineIds`;多通道看 `channelContexts`,`items[]` 不再逐条挂通道字段,见 [04 事件与回调](04-事件与回调.md#回调)。
|
|
31
31
|
|
|
32
32
|
## 选中 / 拖动的层级(selectionOnTop)
|
|
33
33
|
|
|
@@ -143,7 +143,7 @@ view.selectFeatures({ type: 'channel', channelId: 'channel-a' }, { mode: 'remove
|
|
|
143
143
|
|
|
144
144
|
如果手上只有鼠标坐标、又希望组件像用户单击一样选中,用 `selectAt(clientX, clientY)`:命中顺序、通道回线摊开(`channelSelectMode`)与真实点击一致,但不需要先自己拆拾取载荷。命中空白或聚合圆时返回 `null`,不改原选中集。
|
|
145
145
|
|
|
146
|
-
它立即生效,不受 `selectTrigger: 'dblClick'` 等待影响,也不派发 `onClick` / `onDblClick`;每次成功命中都发 `onSelect`(模拟一次单击),`onSelectChange` 只在选中集实际变化时发,`cause` 都是 `'api'
|
|
146
|
+
它立即生效,不受 `selectTrigger: 'dblClick'` 等待影响,也不派发 `onClick` / `onDblClick`;每次成功命中都发 `onSelect`(模拟一次单击),`onSelectChange` 只在选中集实际变化时发,`cause` 都是 `'api'`。选中通道回线时两条回调都在外层带当前命中的 `group`、整条通道的 `groups`、顶层 `channelId` 与本次选中的 `lineIndexes` / `lineIds`;多通道看 `channelContexts`。要取消指定项或全部,继续用 `deselect()`。
|
|
147
147
|
|
|
148
148
|
`selectAt()` 与 `selectFeatures()` 最终落在同一份选中 state,选中样式和读回结果没有区别;区别在入口、是否经过坐标命中与返回值:
|
|
149
149
|
|
|
@@ -189,7 +189,7 @@ selection.channelCount // 这些回线涉及的通道数(按通道去重)
|
|
|
189
189
|
selection.points // 选中的节点数据(引用,与 getData() 同一份)
|
|
190
190
|
selection.lines // 选中的线路数据(通道回线也算一条)
|
|
191
191
|
selection.channels // 选中回线所属的通道(按通道去重,同一条通道的几回线算一条)
|
|
192
|
-
selection.items // 与 getSelections()
|
|
192
|
+
selection.items // 与 getSelections() 同一份:带下标与屏幕坐标;通道回线不带通道字段
|
|
193
193
|
selection.bounds // 世界包围盒(空选中时 null),直接交给 zoomToBounds / focusOn
|
|
194
194
|
view.focusOn(selection.items) // 把视角中心挪到这一批(比例不动)
|
|
195
195
|
view.focusOn(selection.items, { zoom: true }) // 按这一批的整体范围适配
|
package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md
CHANGED
|
@@ -47,12 +47,15 @@ Ctrl / ⌘ + 点击在 `'group'` / `'channel'` 下是**整批取反**:这一
|
|
|
47
47
|
骨架与 `path`)。点击一条回线时不必先扫一遍 `getChannelGroups()` 再自己判断是哪组;`groups.length` 就是组数。
|
|
48
48
|
|
|
49
49
|
选中回调(`onSelect` / `onSelectChange`)带同一份通道上下文:选中集只涉及一条通道时,载荷顶层平铺
|
|
50
|
-
`channelId` / `channelIndex` / `channel` / `groupId` / `groupIndex` / `group` / `groups
|
|
51
|
-
`selectAt()` 的 `group` 是命中的那一组;框选、`selectFeatures()`
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
`channelId` / `channelIndex` / `channel` / `groupId` / `groupIndex` / `group` / `groups` 与本次选中的
|
|
51
|
+
`lineIndexes` / `lineIds`。真实单击与 `selectAt()` 的 `group` 是命中的那一组;框选、`selectFeatures()`
|
|
52
|
+
这类没有单次命中组的入口,取选中集里第一条通道回线所在的组。`groups` 始终是整条通道的全部分组,不是只含
|
|
53
|
+
选中的组。一次选中多条通道时顶层不再摊平,改看 `channelContexts`(每项带同样的字段与本次选中的
|
|
54
|
+
`lineIndexes` / `lineIds`);单通道不会额外创建 `channelContexts`。
|
|
55
|
+
|
|
56
|
+
`items[]` 里每条回线**不再挂任何通道字段**,避免十万级选中时为每条线路重复写同一份归属。要用 `items`
|
|
57
|
+
反查时看外层的 `lineIndexes` / `lineIds`(本次选中子集),再对应顶层上下文或 `channelContexts`;只问一条
|
|
58
|
+
线路时调 `getLineChannel(index)`。`groups[].lineIds` 是整组成员,与本次选中的 `lineIds` 不是同一份数据。
|
|
56
59
|
`onSelect` 与 `onSelectChange` 共用同一批对象引用,两条都订阅时不会各拷一份。
|
|
57
60
|
|
|
58
61
|
### 分组拐点拖动模式(channelWaypointDragMode)
|