gis-view-webgl2 0.1.13 → 0.1.15
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/dist/index.cjs +1 -1
- package/dist/index.d.ts +140 -60
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +73 -5
- package/docs/GisView.md +49 -49
- 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 +87 -16
- package/docs/demos/ApiCoverageDemo.vue +1 -5
- package/docs/demos/BackendSyncDemo.vue +1 -2
- package/docs/demos/BackgroundDemo.vue +68 -1
- package/docs/demos/BasicDemo.vue +76 -76
- package/docs/demos/BatchAddDemo.vue +2 -1
- package/docs/demos/ChannelDemo.vue +1 -3
- package/docs/demos/ClusterDemo.vue +48 -1
- package/docs/demos/CopyMergeDemo.vue +899 -904
- package/docs/demos/DemoShell.vue +336 -336
- package/docs/demos/EventDemo.vue +300 -300
- package/docs/demos/ExtensionDemo.vue +200 -200
- package/docs/demos/GisViewDemo.vue +64 -64
- package/docs/demos/LabelDemo.vue +489 -489
- package/docs/demos/StyleDemo.vue +67 -67
- package/docs/demos/api-index.js +24 -29
- package/docs/demos/demos.js +92 -92
- package/docs/demos/gis-view-demo/useGisViewDemo.js +19 -14
- package/docs/demos/shared/demoData.js +107 -107
- package/docs/demos/shared/demoStyle.css +249 -249
- package/docs/format/02-/350/212/202/347/202/271/344/270/216/347/272/277/350/267/257.md +3 -3
- package/docs/format/03-/346/213/220/347/202/271/350/243/205/351/245/260/344/270/216/346/240/267/345/274/217.md +3 -0
- package/docs/from0/01-/345/205/210/346/212/212/345/234/260/345/233/276/346/203/263/346/270/205/346/245/232.md +8 -7
- package/docs/index.html +3 -3
- package/docs/internals/04-/347/233/270/346/234/272/345/235/220/346/240/207/344/270/216/345/203/217/347/264/240.md +6 -4
- package/docs/internals/14-/350/203/214/346/231/257/345/261/202.md +2 -2
- package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +36 -16
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +38 -84
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +36 -19
- 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 +1 -1
- 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 +7 -7
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +15 -15
- 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 +1 -1
- package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +6 -0
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +1 -1
- package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +2 -0
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +10 -8
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +11 -7
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +27 -8
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +27 -4
- 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 +3 -3
- package/docs/playground/index.html +1 -1
- package/docs/sample-document/345/255/227/346/256/265/350/257/246/350/247/243.md +2 -2
- package/docs/steps/check-doc-truth.mjs +1 -1
- package/docs/steps/selftest-actions.html +4 -4
- package/docs/steps/selftest-data.html +5 -5
- package/docs/steps/selftest-demos.html +1683 -1619
- package/docs/steps/selftest-docs.html +4 -4
- package/docs/steps/selftest-effects.html +1 -1
- package/docs/steps/selftest-features.html +548 -47
- package/docs/steps/selftest-full.html +566 -566
- package/docs/steps/selftest-labels.html +647 -647
- package/docs/steps/selftest-perf.html +2282 -2237
- package/docs/steps/selftest-select.html +53 -14
- package/docs/steps/step-10-full.js +1 -4
- package/docs/steps/step-12-events.js +1 -4
- package/package.json +43 -43
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 几个功能演示共用的外观:浅色卡片 + 深色画布 + 右侧读数栏。
|
|
3
|
-
* 类名统一 dv- 前缀,和 GisViewDemo.vue 里那套 demo-* 互不干扰
|
|
4
|
-
* (综合示例保持原样,功能演示各自短小,共用这一份样式不必各写一遍)。
|
|
5
|
-
*/
|
|
6
|
-
.dv-demo {
|
|
7
|
-
display: grid;
|
|
8
|
-
grid-template-columns: minmax(0, 1fr) clamp(272px, 23vw, 380px);
|
|
9
|
-
gap: 14px;
|
|
10
|
-
align-items: start;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.dv-stage {
|
|
14
|
-
position: relative;
|
|
15
|
-
height: clamp(460px, calc(100vh - 320px), 860px);
|
|
16
|
-
border: 1px solid #e2e9f2;
|
|
17
|
-
border-radius: 10px;
|
|
18
|
-
overflow: hidden;
|
|
19
|
-
background: #f7fafd;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.dv-canvas {
|
|
23
|
-
height: 100%;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* 画布右上角的悬浮工具条:全屏 / 适合全部这类「不动数据」的操作 */
|
|
27
|
-
.dv-toolbar {
|
|
28
|
-
position: absolute;
|
|
29
|
-
top: 10px;
|
|
30
|
-
right: 10px;
|
|
31
|
-
z-index: 3;
|
|
32
|
-
display: flex;
|
|
33
|
-
gap: 6px;
|
|
34
|
-
padding: 5px;
|
|
35
|
-
border-radius: 8px;
|
|
36
|
-
background: rgba(255, 255, 255, 0.86);
|
|
37
|
-
box-shadow: 0 4px 16px rgba(31, 62, 105, 0.14);
|
|
38
|
-
backdrop-filter: blur(6px);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.dv-toolbar button {
|
|
42
|
-
padding: 5px 10px;
|
|
43
|
-
font-size: 12px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.dv-panel {
|
|
47
|
-
display: flex;
|
|
48
|
-
flex-direction: column;
|
|
49
|
-
gap: 10px;
|
|
50
|
-
max-height: clamp(460px, calc(100vh - 320px), 860px);
|
|
51
|
-
overflow: auto;
|
|
52
|
-
padding-right: 4px;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.dv-group {
|
|
56
|
-
padding: 12px;
|
|
57
|
-
border: 1px solid #e2e9f2;
|
|
58
|
-
border-radius: 10px;
|
|
59
|
-
background: #fff;
|
|
60
|
-
box-shadow: 0 8px 24px rgba(31, 62, 105, 0.05);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.dv-group > h3 {
|
|
64
|
-
display: flex;
|
|
65
|
-
align-items: center;
|
|
66
|
-
justify-content: space-between;
|
|
67
|
-
gap: 8px;
|
|
68
|
-
margin: 0 0 10px;
|
|
69
|
-
color: #17233d;
|
|
70
|
-
font-size: 14px;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.dv-row {
|
|
74
|
-
display: flex;
|
|
75
|
-
align-items: center;
|
|
76
|
-
flex-wrap: wrap;
|
|
77
|
-
gap: 8px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.dv-row + .dv-row {
|
|
81
|
-
margin-top: 8px;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.dv-row label {
|
|
85
|
-
display: inline-flex;
|
|
86
|
-
align-items: center;
|
|
87
|
-
gap: 5px;
|
|
88
|
-
color: #526b8d;
|
|
89
|
-
font-size: 12px;
|
|
90
|
-
cursor: pointer;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.dv-row select {
|
|
94
|
-
padding: 4px 6px;
|
|
95
|
-
border: 1px solid #d6e0ec;
|
|
96
|
-
border-radius: 6px;
|
|
97
|
-
background: #fff;
|
|
98
|
-
color: #1f2a44;
|
|
99
|
-
font-size: 12px;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.dv-row input[type='range'] {
|
|
103
|
-
width: 118px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.dv-button {
|
|
107
|
-
padding: 6px 10px;
|
|
108
|
-
border: 1px solid #cfdcec;
|
|
109
|
-
border-radius: 6px;
|
|
110
|
-
background: #f6f9fd;
|
|
111
|
-
color: #2f5e94;
|
|
112
|
-
font-size: 12px;
|
|
113
|
-
cursor: pointer;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.dv-button:hover {
|
|
117
|
-
background: #e9f1fb;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.dv-button--primary {
|
|
121
|
-
border-color: #3678bf;
|
|
122
|
-
background: #3678bf;
|
|
123
|
-
color: #fff;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.dv-button--primary:hover {
|
|
127
|
-
background: #28629e;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.dv-button--danger {
|
|
131
|
-
border-color: #e7bcbc;
|
|
132
|
-
background: #fdf4f4;
|
|
133
|
-
color: #b93b3b;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.dv-button:disabled {
|
|
137
|
-
opacity: 0.55;
|
|
138
|
-
cursor: not-allowed;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.dv-readout {
|
|
142
|
-
margin: 0;
|
|
143
|
-
padding: 8px 10px;
|
|
144
|
-
border-radius: 8px;
|
|
145
|
-
background: #f3f6fa;
|
|
146
|
-
color: #526b8d;
|
|
147
|
-
font-size: 12px;
|
|
148
|
-
line-height: 1.6;
|
|
149
|
-
word-break: break-all;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.dv-hint {
|
|
153
|
-
margin: 6px 0 0;
|
|
154
|
-
color: #8191a8;
|
|
155
|
-
font-size: 11px;
|
|
156
|
-
line-height: 1.6;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.dv-log {
|
|
160
|
-
max-height: 220px;
|
|
161
|
-
margin: 0;
|
|
162
|
-
padding: 0;
|
|
163
|
-
overflow: auto;
|
|
164
|
-
list-style: none;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.dv-log li {
|
|
168
|
-
padding: 5px 8px;
|
|
169
|
-
border-bottom: 1px dashed #e6edf6;
|
|
170
|
-
color: #526b8d;
|
|
171
|
-
font-size: 12px;
|
|
172
|
-
line-height: 1.5;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.dv-log li:last-child {
|
|
176
|
-
border-bottom: 0;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
.dv-log strong {
|
|
180
|
-
color: #2f5e94;
|
|
181
|
-
font-weight: 600;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.dv-chips {
|
|
185
|
-
display: flex;
|
|
186
|
-
flex-wrap: wrap;
|
|
187
|
-
gap: 5px;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.dv-chip {
|
|
191
|
-
padding: 3px 8px;
|
|
192
|
-
border: 1px solid #d6e0ec;
|
|
193
|
-
border-radius: 999px;
|
|
194
|
-
background: #fff;
|
|
195
|
-
color: #526b8d;
|
|
196
|
-
font-size: 11px;
|
|
197
|
-
cursor: pointer;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.dv-chip--active {
|
|
201
|
-
border-color: #3678bf;
|
|
202
|
-
background: #eaf2fc;
|
|
203
|
-
color: #2f5e94;
|
|
204
|
-
font-weight: 600;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/* 标签右键菜单:贴在指针位置的自绘菜单(演示 labelContextMenu 的用法) */
|
|
208
|
-
.dv-menu {
|
|
209
|
-
position: fixed;
|
|
210
|
-
z-index: 60;
|
|
211
|
-
min-width: 168px;
|
|
212
|
-
padding: 5px;
|
|
213
|
-
border: 1px solid #d6e0ec;
|
|
214
|
-
border-radius: 8px;
|
|
215
|
-
background: #fff;
|
|
216
|
-
box-shadow: 0 12px 32px rgba(31, 62, 105, 0.18);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.dv-menu button {
|
|
220
|
-
display: block;
|
|
221
|
-
width: 100%;
|
|
222
|
-
padding: 7px 10px;
|
|
223
|
-
border: 0;
|
|
224
|
-
border-radius: 6px;
|
|
225
|
-
background: transparent;
|
|
226
|
-
color: #1f2a44;
|
|
227
|
-
font-size: 12px;
|
|
228
|
-
text-align: left;
|
|
229
|
-
cursor: pointer;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.dv-menu button:hover {
|
|
233
|
-
background: #eef4fc;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
.dv-menu__title {
|
|
237
|
-
padding: 6px 10px 4px;
|
|
238
|
-
color: #8191a8;
|
|
239
|
-
font-size: 11px;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
@media (max-width: 1080px) {
|
|
243
|
-
.dv-demo {
|
|
244
|
-
grid-template-columns: minmax(0, 1fr);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.dv-panel {
|
|
248
|
-
max-height: none;
|
|
249
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 几个功能演示共用的外观:浅色卡片 + 深色画布 + 右侧读数栏。
|
|
3
|
+
* 类名统一 dv- 前缀,和 GisViewDemo.vue 里那套 demo-* 互不干扰
|
|
4
|
+
* (综合示例保持原样,功能演示各自短小,共用这一份样式不必各写一遍)。
|
|
5
|
+
*/
|
|
6
|
+
.dv-demo {
|
|
7
|
+
display: grid;
|
|
8
|
+
grid-template-columns: minmax(0, 1fr) clamp(272px, 23vw, 380px);
|
|
9
|
+
gap: 14px;
|
|
10
|
+
align-items: start;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.dv-stage {
|
|
14
|
+
position: relative;
|
|
15
|
+
height: clamp(460px, calc(100vh - 320px), 860px);
|
|
16
|
+
border: 1px solid #e2e9f2;
|
|
17
|
+
border-radius: 10px;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
background: #f7fafd;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.dv-canvas {
|
|
23
|
+
height: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* 画布右上角的悬浮工具条:全屏 / 适合全部这类「不动数据」的操作 */
|
|
27
|
+
.dv-toolbar {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 10px;
|
|
30
|
+
right: 10px;
|
|
31
|
+
z-index: 3;
|
|
32
|
+
display: flex;
|
|
33
|
+
gap: 6px;
|
|
34
|
+
padding: 5px;
|
|
35
|
+
border-radius: 8px;
|
|
36
|
+
background: rgba(255, 255, 255, 0.86);
|
|
37
|
+
box-shadow: 0 4px 16px rgba(31, 62, 105, 0.14);
|
|
38
|
+
backdrop-filter: blur(6px);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.dv-toolbar button {
|
|
42
|
+
padding: 5px 10px;
|
|
43
|
+
font-size: 12px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.dv-panel {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 10px;
|
|
50
|
+
max-height: clamp(460px, calc(100vh - 320px), 860px);
|
|
51
|
+
overflow: auto;
|
|
52
|
+
padding-right: 4px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.dv-group {
|
|
56
|
+
padding: 12px;
|
|
57
|
+
border: 1px solid #e2e9f2;
|
|
58
|
+
border-radius: 10px;
|
|
59
|
+
background: #fff;
|
|
60
|
+
box-shadow: 0 8px 24px rgba(31, 62, 105, 0.05);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.dv-group > h3 {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: space-between;
|
|
67
|
+
gap: 8px;
|
|
68
|
+
margin: 0 0 10px;
|
|
69
|
+
color: #17233d;
|
|
70
|
+
font-size: 14px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.dv-row {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
gap: 8px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.dv-row + .dv-row {
|
|
81
|
+
margin-top: 8px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.dv-row label {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 5px;
|
|
88
|
+
color: #526b8d;
|
|
89
|
+
font-size: 12px;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.dv-row select {
|
|
94
|
+
padding: 4px 6px;
|
|
95
|
+
border: 1px solid #d6e0ec;
|
|
96
|
+
border-radius: 6px;
|
|
97
|
+
background: #fff;
|
|
98
|
+
color: #1f2a44;
|
|
99
|
+
font-size: 12px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.dv-row input[type='range'] {
|
|
103
|
+
width: 118px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.dv-button {
|
|
107
|
+
padding: 6px 10px;
|
|
108
|
+
border: 1px solid #cfdcec;
|
|
109
|
+
border-radius: 6px;
|
|
110
|
+
background: #f6f9fd;
|
|
111
|
+
color: #2f5e94;
|
|
112
|
+
font-size: 12px;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.dv-button:hover {
|
|
117
|
+
background: #e9f1fb;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.dv-button--primary {
|
|
121
|
+
border-color: #3678bf;
|
|
122
|
+
background: #3678bf;
|
|
123
|
+
color: #fff;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.dv-button--primary:hover {
|
|
127
|
+
background: #28629e;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.dv-button--danger {
|
|
131
|
+
border-color: #e7bcbc;
|
|
132
|
+
background: #fdf4f4;
|
|
133
|
+
color: #b93b3b;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.dv-button:disabled {
|
|
137
|
+
opacity: 0.55;
|
|
138
|
+
cursor: not-allowed;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.dv-readout {
|
|
142
|
+
margin: 0;
|
|
143
|
+
padding: 8px 10px;
|
|
144
|
+
border-radius: 8px;
|
|
145
|
+
background: #f3f6fa;
|
|
146
|
+
color: #526b8d;
|
|
147
|
+
font-size: 12px;
|
|
148
|
+
line-height: 1.6;
|
|
149
|
+
word-break: break-all;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.dv-hint {
|
|
153
|
+
margin: 6px 0 0;
|
|
154
|
+
color: #8191a8;
|
|
155
|
+
font-size: 11px;
|
|
156
|
+
line-height: 1.6;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.dv-log {
|
|
160
|
+
max-height: 220px;
|
|
161
|
+
margin: 0;
|
|
162
|
+
padding: 0;
|
|
163
|
+
overflow: auto;
|
|
164
|
+
list-style: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.dv-log li {
|
|
168
|
+
padding: 5px 8px;
|
|
169
|
+
border-bottom: 1px dashed #e6edf6;
|
|
170
|
+
color: #526b8d;
|
|
171
|
+
font-size: 12px;
|
|
172
|
+
line-height: 1.5;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.dv-log li:last-child {
|
|
176
|
+
border-bottom: 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.dv-log strong {
|
|
180
|
+
color: #2f5e94;
|
|
181
|
+
font-weight: 600;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.dv-chips {
|
|
185
|
+
display: flex;
|
|
186
|
+
flex-wrap: wrap;
|
|
187
|
+
gap: 5px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.dv-chip {
|
|
191
|
+
padding: 3px 8px;
|
|
192
|
+
border: 1px solid #d6e0ec;
|
|
193
|
+
border-radius: 999px;
|
|
194
|
+
background: #fff;
|
|
195
|
+
color: #526b8d;
|
|
196
|
+
font-size: 11px;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.dv-chip--active {
|
|
201
|
+
border-color: #3678bf;
|
|
202
|
+
background: #eaf2fc;
|
|
203
|
+
color: #2f5e94;
|
|
204
|
+
font-weight: 600;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* 标签右键菜单:贴在指针位置的自绘菜单(演示 labelContextMenu 的用法) */
|
|
208
|
+
.dv-menu {
|
|
209
|
+
position: fixed;
|
|
210
|
+
z-index: 60;
|
|
211
|
+
min-width: 168px;
|
|
212
|
+
padding: 5px;
|
|
213
|
+
border: 1px solid #d6e0ec;
|
|
214
|
+
border-radius: 8px;
|
|
215
|
+
background: #fff;
|
|
216
|
+
box-shadow: 0 12px 32px rgba(31, 62, 105, 0.18);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.dv-menu button {
|
|
220
|
+
display: block;
|
|
221
|
+
width: 100%;
|
|
222
|
+
padding: 7px 10px;
|
|
223
|
+
border: 0;
|
|
224
|
+
border-radius: 6px;
|
|
225
|
+
background: transparent;
|
|
226
|
+
color: #1f2a44;
|
|
227
|
+
font-size: 12px;
|
|
228
|
+
text-align: left;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.dv-menu button:hover {
|
|
233
|
+
background: #eef4fc;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.dv-menu__title {
|
|
237
|
+
padding: 6px 10px 4px;
|
|
238
|
+
color: #8191a8;
|
|
239
|
+
font-size: 11px;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@media (max-width: 1080px) {
|
|
243
|
+
.dv-demo {
|
|
244
|
+
grid-template-columns: minmax(0, 1fr);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.dv-panel {
|
|
248
|
+
max-height: none;
|
|
249
|
+
}
|
|
250
250
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| `zIndex` | `number` | `0` | 绘制层级:大的盖在上面,同一个值算一层;不参与状态样式,悬停 / 选中不会把它抬层 |
|
|
15
15
|
| `shadow` | `GisViewShadow` | 无(不画阴影) | 阴影:`{ color, blur, offsetX, offsetY }`,偏移与模糊都是 CSS 像素 |
|
|
16
16
|
| `visible` | `boolean` | `true` | `false` 时这个节点不画(等价于被筛选隐藏,但数据还在);被它锚定的通道与回线一起消失 |
|
|
17
|
-
| `clickable` / `draggable` / `copyable` / `mergeable` | `boolean` |
|
|
17
|
+
| `clickable` / `draggable` / `copyable` / `mergeable` | `boolean` | `clickable` 缺省 `true`,实际悬停 / 选中仍要打开 `features.hover` / `features.select`;`draggable` 跟随 `features.drag`(**缺省关**,逐个节点的 `draggable: true` 也要先打开这个总开关);`copyable` / `mergeable` 缺省 `true` | 逐条覆盖对应的权限(节点的 `draggable` 只影响该节点) |
|
|
18
18
|
| `mergeInfo` | `GisViewMergeInfo \| null` | 无 | `mergePoints` / `mergeSelectedPoints` 写入的合并追溯(版本 `1`):保留节点保存 `targetPoint`、`sourceIds`、来源 `points` 快照与受影响 `lines` / `channels` 快照;`splitPoint(source)` 省略 `parts` 时据此自动解除合并。可 JSON 序列化,随数据导出;保留字段,业务数据不要占用。字段详解见 [manual 07 的「合并追溯」](../manual/07-%E6%8C%87%E9%92%88%E4%B8%8E%E8%A6%81%E7%B4%A0%E7%BC%96%E8%BE%91.md#%E5%90%88%E5%B9%B6%E8%BF%BD%E6%BA%AFmergeinfo) |
|
|
19
19
|
| `cursor` / `ctrlCursor` | `GisViewCursorValue` | 跟随 `options.cursorStyle.point` / `cursorStyle.ctrl.point` | 悬停这个点时的光标(按住 Ctrl / ⌘ 时用后者),写法见 GisView.md 的「光标」 |
|
|
20
20
|
| `hoverStyle` / `selectStyle` / `multiSelectStyle` / `boxSelectStyle` | `GisViewPointStyle` | 分别跟随 `options.pointHoverStyle` / `pointSelectStyle` / `pointMultiSelectStyle` / `pointBoxSelectStyle`(后两个缺省回落到选中样式) | 逐条覆盖悬停 / 选中 / Ctrl 多选 / 框选样式,按字段覆盖自身样式 |
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
| `color` / `width` / `opacity` / `join` | `string` / `number` | 无 / 无 / `1` / `'round'`(前三个回落到 `lineStyle` → `lineRules` → 内置默认) | 逐条外观:`join` 是拐角样式 `round`(默认,拐角与端点补圆点接头)/ `butt` |
|
|
36
36
|
| `lineType` / `dash` / `dashOffset` | `string` / `GisViewLineDash` / `number` | `'solid'` / 无 / `0` | 线型:`solid` / `dashed` / `dotted` / `dashdot`(与别名),或自定义图案;`dashOffset` 是虚线相位(CSS 像素,可以为负);认不出的字符串按实线画,`dash` 与 `lineType` 都写时以 `dash` 为准 |
|
|
37
37
|
| `shadow` | `GisViewShadow` | 无(不画阴影) | 阴影 |
|
|
38
|
-
| `visible` / `clickable` / `waypointEditable` | `boolean` | `true` /
|
|
38
|
+
| `visible` / `clickable` / `waypointEditable` | `boolean` | `true` / `true`(实际命中仍要 `features.hover` / `features.select`)/ `true`(实际拐点编辑仍要 `features.waypoint`,**缺省关**) | 逐条覆盖权限:`visible: false` 不画;线路自身 `waypointEditable: false` 时这条线不出拐点(全局仍要打开 `features: { waypoint: true }`) |
|
|
39
39
|
| `cursor` / `ctrlCursor` / `hoverStyle` / `selectStyle` / `multiSelectStyle` | 同节点 | 跟随对应的 `options`(`cursorStyle` / `lineHoverStyle` / `lineSelectStyle` / `lineMultiSelectStyle`) | 逐条覆盖光标与状态样式;通道回线的 `cursor` 以回线自身的为准 |
|
|
40
40
|
| `labels` / `lineLabel` / `lineLabelPosition` / `lineLabelParallel` / `lineLabelOffset` / `lineLabelVisibility` | `GisViewItemLabel[]` / `GisViewLineLabelContent` / 位置 / `boolean` / `[number, number]` / 显隐 | `labels` / `lineLabel*` 都不写时跟随 `options.lineLabel`;`lineLabel: false` = 这条线不显示标签 | 线路标签:`labels` 是逐条清单(推荐,可多条),其余是旧式单条写法;`position` 认 0 ~ 1 比例、`'50%'`、`{ distance }`(世界单位) |
|
|
41
|
-
| `decorations` | `GisViewLineDecoration[]` | 无(空数组 = 不画) | 沿线摆的图片 / SVG
|
|
41
|
+
| `decorations` | `GisViewLineDecoration[]` | 无(空数组 = 不画) | 沿线摆的图片 / SVG 标记(位置、锚点、平行、大小、颜色;可选 `followSelectColor` 跟随线路选中色,SVG path 写描边,并随选中抬层),见「标记 / 装饰」 |
|
|
42
42
|
| `tooltip` / `heatmap` | 同节点 | 跟随 `options.tooltip` / 不配 `options.heatmap` 就不参与 | 悬浮提示 / 热力图覆盖 |
|
|
43
43
|
| `effect` | `GisViewLineEffectInput` | 跟随 `options.effects.line` | 这条线上的跑动图标:写法同节点,认 `symbol` / `size` / `color` / `strokeColor` / `strokeWidth` / `count` / `spaced` / `period` / `speed` / `offset` / `reverse` / `opacity` / `parallel` / `delay` / `shadow`;位置按**弧长**算(折线拐点连续、不抄近道),见 GisView.md 的「动画效果(effects)」 |
|
|
44
44
|
| `direction` | `GisViewLineDirectionInput` | 跟随 `options.lineDirection` | 这条线上的静态方向箭头(不跑动):写法同上面的 `effect`(`true` 用全局那一份、对象逐字段覆盖、`false` / `null` 关掉),位置按弧长摆、朝向跟着线路切向(起点 → 终点,`reverse` 指回上游),见 GisView.md 的「线路方向箭头(lineDirection)」 |
|
|
@@ -65,8 +65,11 @@ view.exportData({ format: 'test', parts: ['waypoint'] })
|
|
|
65
65
|
| `parallel` | `boolean` | `false` | 符号是否跟着线路方向转(按锚点处的路径切向) |
|
|
66
66
|
| `size` | `number` | `18` | 屏幕尺寸(CSS 像素);跟着 `pointSizeScale` 与缩放档位走 |
|
|
67
67
|
| `color` / `strokeColor` / `strokeWidth` | `string` / `string` / `number` | `'#ffffff'` / 透明 / `0` | 填充 / 描边色 / 描边宽(只在形状与 SVG 符号上有意义,位图不受影响) |
|
|
68
|
+
| `followSelectColor` | `boolean` | `false` | 所属线路 / 节点被选中时是否改用其最终选中色:`symbol` 为 `{ type: 'svg', path }` 时写 `strokeColor`,其他符号写 `color`;取消选中后恢复装饰自身颜色 |
|
|
68
69
|
| `opacity` / `shadow` | `number` / `GisViewShadow` | `1` / 无 | 透明度与阴影,与节点同一套 |
|
|
69
70
|
|
|
71
|
+
装饰会随所属要素一起抬层:选中线路 / 通道回线的装饰排在抬层线路之后,选中节点与选中线路端点节点的装饰排在抬层节点之前;普通装饰留在普通层。`followSelectColor` 在 SVG path 上改描边、其他符号改填充 / 色调;`selectionOnTop: false` 只取消抬层、不改变变色规则。
|
|
72
|
+
|
|
70
73
|
运行时读写:`getLineDecorations(id)`(副本)/ `setLineDecorations(id, list)`(整份换,空数组 = 全摘掉)/
|
|
71
74
|
`addLineDecoration(id, decoration)`(追加,返回加进去的那一条)/ `updateLineDecoration(id, index, patch)`(只合并第 `index` 条)/
|
|
72
75
|
`removeLineDecoration(id, index)`(摘掉某一条)。
|
|
@@ -60,10 +60,10 @@ const unprojectPoint = (x, y) => [
|
|
|
60
60
|
(绕整体范围中心压一压,纬度不动),否则按「1 度经度 = 1 度纬度」画出来的地图会被拉长。
|
|
61
61
|
于是解析结果里有两份范围:
|
|
62
62
|
|
|
63
|
-
- `rawBounds`:缩放前的真实经纬度范围 ——
|
|
64
|
-
- `bounds
|
|
63
|
+
- `rawBounds`:缩放前的真实经纬度范围 —— 相机落位与 `fitView` 的基准;
|
|
64
|
+
- `bounds`:应用 `aspectScale`、`geoJsonStyle.bounds` 与 `rotation` 之后真正画出来的轴对齐范围 —— 判断「数据在不在视野里」用它。
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
解析结果另外用 `drawTransform` 记录最终的缩放、平移、中心与旋转角。这两层换算都在 `projection.js`(纯函数),`create.js` 把最终投影挂成实例方法:
|
|
67
67
|
|
|
68
68
|
```js
|
|
69
69
|
const projection = view.getGeoProjection() // 没有 GeoJSON 底图时是 null
|
|
@@ -79,7 +79,7 @@ view.getPointer() // { inside, screen, world, lngLat
|
|
|
79
79
|
|
|
80
80
|
```js
|
|
81
81
|
const mapper = view.createGeoMapper({
|
|
82
|
-
mode: 'fit', // 'lngLat'
|
|
82
|
+
mode: 'fit', // 'lngLat' / 'scale' 以最终底图为基准 | 'fit' 任意坐标等比铺进底图
|
|
83
83
|
scale: 1, // 节点与 geojson 的大小比例:1 是各模式的基准,越大数据铺得越开
|
|
84
84
|
padding: 0.08, // fit 模式四周留白(占底图短边比例)
|
|
85
85
|
data: view.getData()
|
|
@@ -88,9 +88,10 @@ const data = view.getData()
|
|
|
88
88
|
view.updateData(data.points.map(mapper.mapPoint), data.lines.map(mapper.mapLine))
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
`mapPoint` / `mapLine` / `mapChannel` / `mapData`
|
|
92
|
-
|
|
93
|
-
`pointZoomScale`
|
|
91
|
+
`mapPoint` / `mapLine` / `mapChannel` / `mapData` 都是「复制一份再换坐标」,原数据不动;坐标写成
|
|
92
|
+
`[x, y]` 或 `{ x, y }` 都认,通道分组路径与固定坐标装饰也会一起换。通道两端锚的是节点 id,
|
|
93
|
+
映射之后依旧对得上。节点尺寸与线宽仍然是 CSS 像素(`pointSizeScale` / `pointZoomScale` 照旧
|
|
94
|
+
生效),所以「数据铺多大」与「节点画多大」是两件事,可以分开调。
|
|
94
95
|
|
|
95
96
|
### 0.4 文件职责
|
|
96
97
|
|
package/docs/index.html
CHANGED
|
@@ -1421,7 +1421,7 @@
|
|
|
1421
1421
|
{ file: 'manual/14-视图与筛选.md', title: '手册 14 · 视图与筛选', blurb: '筛选 / 搜索 / 视图与背景', parent: 'GisView.md' },
|
|
1422
1422
|
{ file: 'manual/15-导出与集成.md', title: '手册 15 · 导出与集成', blurb: '导出 / 插件 / 自建界面', parent: 'GisView.md' },
|
|
1423
1423
|
{ file: 'manual/16-实例方法总表.md', title: '手册 16 · 实例方法总表', blurb: '实例方法主表', parent: 'GisView.md' },
|
|
1424
|
-
{ file: 'manual/17-参数速查.md', title: '手册 17 · 参数速查', blurb: '
|
|
1424
|
+
{ file: 'manual/17-参数速查.md', title: '手册 17 · 参数速查', blurb: '285 个成员逐个列全', parent: 'GisView.md' },
|
|
1425
1425
|
{ file: 'manual/18-逐方法示例.md', title: '手册 18 · 逐方法示例', blurb: '每个成员一段示例', parent: 'GisView.md' },
|
|
1426
1426
|
{ file: 'manual/19-读数与拖拽预览.md', title: '手册 19 · 读数与拖拽预览', blurb: '读数 / 定位 / 落点预览', parent: 'GisView.md' },
|
|
1427
1427
|
{ file: 'manual/20-性能与大数据.md', title: '手册 20 · 性能与大数据', blurb: '大数据开关与实测', parent: 'GisView.md' },
|
|
@@ -1492,7 +1492,7 @@
|
|
|
1492
1492
|
{ file: '../src/gis-view/README.md', title: 'src/gis-view/README.md', blurb: '源码导读与逐轮实现记录' }
|
|
1493
1493
|
]
|
|
1494
1494
|
const PAGES = [
|
|
1495
|
-
{ href: 'api/index.html', title: 'API 速查(方法 + 示例)', blurb: '
|
|
1495
|
+
{ href: 'api/index.html', title: 'API 速查(方法 + 示例)', blurb: '285 个实例成员 / 100 个 options,逐个带示例与复制' },
|
|
1496
1496
|
{ href: 'playground/index.html', title: '调试演示页(粘代码就跑)', blurb: '左侧编辑、右侧真实实例 + GeoJSON 底图:内置示例与「这一份文档」的示例同在一个下拉,粘代码直接跑' },
|
|
1497
1497
|
{ href: 'guide/sample-document.html', title: 'sample-document.json 图解', blurb: '点数据看端点 / 拐点 / 分组骨架' },
|
|
1498
1498
|
{ href: 'steps/index.html', title: '从 0 手写分步 demo', blurb: '13 步,每步一个文件' },
|
|
@@ -2074,7 +2074,7 @@
|
|
|
2074
2074
|
{ badge: 'START', title: '第一次使用', desc: '引入、最小数据与首屏配置,先把图画出来。', meta: '01 快速开始 · 约 10 分钟', file: 'manual/01-快速开始.md' },
|
|
2075
2075
|
{ badge: 'BACKEND', title: '接后端与导出', desc: '编辑接口、导出回灌、插件与自建界面。', meta: '15 导出与集成', file: 'manual/15-导出与集成.md' },
|
|
2076
2076
|
{ badge: 'PERF', title: '十万级性能', desc: 'Worker 筛选 / 异步搜索、批量更新与质量档。', meta: '20 性能与大数据', file: 'manual/20-性能与大数据.md' },
|
|
2077
|
-
{ badge: 'API', title: '查方法与参数', desc: '实例方法、options 与可复制示例集中检索。', meta: 'API 速查 ·
|
|
2077
|
+
{ badge: 'API', title: '查方法与参数', desc: '实例方法、options 与可复制示例集中检索。', meta: 'API 速查 · 285 个成员', href: 'api/index.html', external: true }
|
|
2078
2078
|
]
|
|
2079
2079
|
const renderReadingPaths = () => `<section class='doc-paths' aria-label='推荐阅读路径'>` +
|
|
2080
2080
|
`<div class='doc-paths__head'><strong>按任务选一条阅读路径</strong><span>第一次进来先看快速开始;带着明确目标时直接跳到对应章节。</span></div>` +
|
|
@@ -42,12 +42,14 @@ pixelRatio = clamp(min((配置的 pixelRatio ?? devicePixelRatio) * displaySca
|
|
|
42
42
|
经纬度与 GeoJSON 的换算在 `projection.js`(纯函数,不依赖 DOM 与 WebGL):
|
|
43
43
|
|
|
44
44
|
```js
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
// 第一步:只压经度、绕整体 bbox 中心,与 ECharts 的 geo.aspectScale 同义
|
|
46
|
+
base = [centerX + (lng - centerX) * aspectScale, lat]
|
|
47
|
+
// 第二步:geoJsonStyle.bounds / rotation 的缩放、平移和绕目标中心旋转
|
|
48
|
+
project(lng, lat) = rotate(base * drawScale + drawOffset)
|
|
49
|
+
unproject(x, y) = inverseAspect(inverseRotate((x, y) - drawOffset) / drawScale)
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
`createGeoProjection(source)` 吃 `buildGeoJsonShapes` / `resolveGeoJson` 的结果(带 `rawBounds`
|
|
52
|
+
`createGeoProjection(source)` 吃 `buildGeoJsonShapes` / `resolveGeoJson` 的结果(带 `rawBounds`、`aspectScale` 与可选的 `drawTransform`):`rawBounds` 是缩放前的真实范围,相机与 `fitView` 用它,`bounds` 是最终画出来的轴对齐范围。`resolveGeoJson()` 记录 `geoJsonStyle.bounds / rotation` 实际使用的缩放、平移、中心与角度,所以 `project` / `unproject` 不会再只算 `aspectScale`。`createGeoMapper(source, options)` 在这之上给出三种数据搬运方式:`'lngLat'` / `'scale'` 复用同一份最终投影(数据本身就是经纬度时与底图严丝合缝,后者再叠比例与偏移)、`'fit'` 把任意坐标系的数据等比铺进底图范围(contain + `padding`,长宽比不变)。映射坐标同时认 `[x, y]` 与 `{ x, y }`:`mapLine` / `mapChannel` 换 `path`、`start`、`end`,节点 / 线路的固定坐标装饰换 `at` 与坐标型 `position`,`mapChannel` 还换 `groups[].path`;`waypointOffsets` 是相对向量,用 `map(offset) - map([0, 0])` 换,不能套带平移的点映射。`boundsOfData` 从节点、线路几何、通道 / 分组路径与固定坐标装饰一起算 fit 范围。指针侧 `create.js` 缓存一份投影(按解析出来的 GeoJSON 引用比对,指针事件这种高频路径不重复解析),`lngLatToWorld` / `worldToLngLat` / `lngLatToScreen` / `screenToLngLat` / `getPointer()` 与 `onPointer` 都走它。
|
|
51
53
|
|
|
52
54
|
---
|
|
53
55
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
- **图片来源**:`background.js` 先把 `src` 归一成能解码的东西 —— URL / dataURL 交给 `Image`;传进来的 `<img>` / `<canvas>` / `<svg>` 元素直接用(SVG 元素走 `XMLSerializer` → dataURL);只给 SVG 路径的 `d` 字符串时用 `getBBox()` 量外框、按 `pathStyle` 上色后包成一份 SVG。资产按 key 缓存,纹理与「原图元素」一起存:鹰眼图用 Canvas2D 直接 `drawImage`,不需要 WebGL 贴图。
|
|
6
6
|
- **摆放**:`buildCornersQuad` 把四个角(左上 / 右上 / 右下 / 左下)变成 `[x, y, u, v] × 4`;`buildBackgroundQuad` 按 `bounds`(缺省用数据范围)与 `fit` 算 quad —— `contain` / `cover` / `stretch` / `center`(`center` 用 `size` 给世界单位下的原尺寸)。四边形直接喂 `imageProgram`。
|
|
7
|
-
- **GeoJSON**:`geojson.js` 的 `buildGeoJsonShapes` 按 Feature
|
|
8
|
-
- **aspectScale
|
|
7
|
+
- **GeoJSON**:`geojson.js` 的 `buildGeoJsonShapes` 按 Feature 分组解析(每个区域保留原始环、包围盒与重心,区域中心取最大外环的面积重心),多边形走三角剖分(带洞时先桥接再三角化),线进线路批次,点位要素按 `symbol` 走符号管线。环会先去掉闭合尾点、非法点与相邻重复点,避免重复铺描边和退化耳朵;凸环走 O(n) 扇形剖分,其余环用 prev / next 双链表做耳切并先用三角形包围盒剔除候选点,不再每个耳朵 `splice` 一次活动数组。`resolveGeoJson` 再把样式叠上去:整体色 → `regions`(按名字精确覆盖)→ `itemStyle(params)`(最后生效),输出三份形态 —— `regions`(小图与区域文字用)、`fillBuckets` / `strokeGroups` / `pointGroups`(WebGL 按颜色 / 线宽 / 半径成批画)、合并后的 `fills` / `strokes` / `points`(老调用方不用改)。
|
|
8
|
+
- **aspectScale 与最终摆放**:与 ECharts 的 `geo.aspectScale` 一致 —— 解析时坐标原样保留,解析完再围绕整体范围的 x 中心把经度乘一遍(只压经度、纬度不动)。`rawBounds` 存缩放前的真实范围;`geoJsonStyle.bounds / rotation` 再把整份底图缩放到目标矩形并旋转,`bounds` 是最终画面的轴对齐范围,`drawTransform` 记录实际缩放 / 平移 / 中心 / 角度。`projection.js` 会把这层也合成进 `project` / `unproject`,所以经纬度、事件 `lngLat` 与数据映射都以屏幕上最终底图为准。
|
|
9
9
|
- **区域文字**:解析出的世界坐标 + 字号 / 颜色交给覆盖层的背景标签层(`.gis-view__label-layer--geo`),`labelBoxes()` 把它算进导出图片,所以背景文字也进导出的图。
|
|
10
10
|
- 图片与 GeoJSON 都在**世界坐标**里画,跟随相机平移缩放;背景重新解析(图片解码完成、GeoJSON 变化)会触发一次 `buildScene()`:背景里的线也进线路批次,因此要整份重排,`onBackgroundChange` 让鹰眼图跟着重画。
|
|
11
11
|
- **内置编辑器**:`background-editor.js` 是可选的表现层,不在普通渲染路径里。第一次 `beginBackgroundEdit()` 才创建 DOM 覆盖层,从 `background.image.corners` 或 `geoJsonStyle.bounds + rotation` 反推中心 / 宽高 / 角度;拖动统一投影到背景局部坐标后计算,图片写回四角,GeoJSON 写回目标矩形与角度,其余背景字段保留。指针手势合并到动画帧,帧内用 `updateBackground()` 提交并以 `refresh({ reflow: false })` 重绘,覆盖层与 WebGL 底图同帧移动。`endBackgroundEdit()` 移除覆盖层并恢复进入前的 `backgroundEditing`,`destroy()` 同样清理。
|