@pirireis/webglobeplugins 0.3.7 → 0.3.9
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/bearing-line/plugin.js +24 -8
- package/circle-lines/chain-api.md +336 -0
- package/circle-lines/chain-list-map.js +203 -0
- package/circle-lines/chain-map.js +0 -0
- package/circle-lines/plugin.js +318 -4
- package/circle-lines/util.js +1 -0
- package/package.json +1 -1
- package/programs/line-on-globe/circle.js +9 -15
- package/programs/line-on-globe/naive.js +16 -2
- package/write-text/context-text.js +25 -6
package/bearing-line/plugin.js
CHANGED
|
@@ -160,7 +160,7 @@ export default class Plugin {
|
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
this.lineVao = this.lineProgram.createVAO(
|
|
163
|
-
...['centerCoords', 'targetCoords', 'dashRatio', 'rgba'].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
163
|
+
...['centerCoords', 'targetCoords', 'dashRatio', 'dashOpacity', 'rgba'].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
164
164
|
this.ringVao = this.ringProgram.createVAO(
|
|
165
165
|
...['centerCoords', 'startAngle', 'tailAngle', 'rgba', 'radius', 'rgbaMode'].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
166
166
|
{
|
|
@@ -174,7 +174,7 @@ export default class Plugin {
|
|
|
174
174
|
}
|
|
175
175
|
// centerObj, startAngleObj, radiusObj, colorObj, dashRatioObj, dashOpacityObj
|
|
176
176
|
this.circleVao = this.circleProgram.createVAO(
|
|
177
|
-
...["centerCoords", "
|
|
177
|
+
...["centerCoords", "bigRadius", "rgba", "circleDashAngle", "dashOpacity"].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
|
|
@@ -216,17 +216,21 @@ export default class Plugin {
|
|
|
216
216
|
* @property {number} dashOpacity 0-1
|
|
217
217
|
* @property {number} circleDashAngle 0-360
|
|
218
218
|
* @param {Array<item>} items
|
|
219
|
-
* @param {Array<string>}
|
|
219
|
+
* @param {Array<string>} textWriterInjectionSubSetIDs | textContextInjectionMap keys to be used for writing text.
|
|
220
220
|
*/
|
|
221
|
-
insertBulk(items,
|
|
221
|
+
insertBulk(items, textWriterInjectionSubSetIDs = []) {
|
|
222
222
|
const { globe, bufferOrchestrator, bufferManagersCompMap } = this;// angleTextContext, distanceTextContext,
|
|
223
|
-
const
|
|
223
|
+
const textWriterInjectionSubSets = textWriterInjectionSubSetIDs.map((id) => this._textContextInjectionMap.get(id));
|
|
224
224
|
const data = []
|
|
225
225
|
for (let item of items) {
|
|
226
|
-
this._insertTexts(item,
|
|
226
|
+
this._insertTexts(item, textWriterInjectionSubSets);
|
|
227
227
|
data.push(this.__insertAdaptor(item));
|
|
228
228
|
}
|
|
229
229
|
bufferOrchestrator.insertBulk(data, bufferManagersCompMap);
|
|
230
|
+
this._textContextInjectionMap.forEach((v) => {
|
|
231
|
+
const { writer } = v;
|
|
232
|
+
writer.updateOpacityBulk(items, (e) => e.key, (e) => e.rgba[3]);
|
|
233
|
+
})
|
|
230
234
|
globe.DrawRender();
|
|
231
235
|
}
|
|
232
236
|
|
|
@@ -251,7 +255,7 @@ export default class Plugin {
|
|
|
251
255
|
*/
|
|
252
256
|
updateCoordinatesBulk(items, textWriterInjectionSubSetIDs = []) { //TODO
|
|
253
257
|
const injectionsSubSet = textWriterInjectionSubSetIDs.map((id) => this._textContextInjectionMap.get(id));
|
|
254
|
-
const { globe, bufferOrchestrator, bufferManagersCompMap,
|
|
258
|
+
const { globe, bufferOrchestrator, bufferManagersCompMap, } = this;
|
|
255
259
|
const data = []
|
|
256
260
|
for (let item of items) {
|
|
257
261
|
this._insertTexts(item, injectionsSubSet);
|
|
@@ -270,12 +274,22 @@ export default class Plugin {
|
|
|
270
274
|
* @param {*} textWriterInjectionSubSetIDs
|
|
271
275
|
* Do NOT send empty data if property ID of this data is entered or NaN is loaded to the buffer, resulting in an unwanted behaviour.
|
|
272
276
|
*/
|
|
273
|
-
updatePartial(items, propertyIDs = [], textWriterInjectionSubSetIDs = []) {
|
|
277
|
+
updatePartial(items, propertyIDs = [], textWriterInjectionSubSetIDs = []) { // textWriterInjectionSubSetIDs = []
|
|
274
278
|
if (propertyIDs.length === 0) console.warn("updatePartial is called with no target propertyIDs");
|
|
275
279
|
const { _textContextInjectionMap, bufferOrchestrator, bufferManagersCompMap } = this;
|
|
276
280
|
const writers = textWriterInjectionSubSetIDs.map((x) => _textContextInjectionMap.get(x));
|
|
277
281
|
for (let item of items) { this._insertTexts(item, writers) }
|
|
278
282
|
bufferOrchestrator.updateBulk(items, bufferManagersCompMap, propertyIDs);
|
|
283
|
+
// patch to update text opacity
|
|
284
|
+
for (const property of propertyIDs) {
|
|
285
|
+
if (property === "rgba") {
|
|
286
|
+
this._textContextInjectionMap.forEach((v) => {
|
|
287
|
+
const { writer } = v;
|
|
288
|
+
writer.updateOpacityBulk(items, (e) => e.key, (e) => e.rgba[3]);
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
}
|
|
292
|
+
}
|
|
279
293
|
}
|
|
280
294
|
|
|
281
295
|
|
|
@@ -359,6 +373,7 @@ export default class Plugin {
|
|
|
359
373
|
|
|
360
374
|
|
|
361
375
|
|
|
376
|
+
|
|
362
377
|
_insertTexts(item, textWriterInjectionSubSet) {
|
|
363
378
|
//TODO This method can be more performant if it works horizontally, tabular
|
|
364
379
|
textWriterInjectionSubSet.forEach((v) => {
|
|
@@ -369,6 +384,7 @@ export default class Plugin {
|
|
|
369
384
|
});
|
|
370
385
|
}
|
|
371
386
|
|
|
387
|
+
|
|
372
388
|
_deleteTexts(keys) {
|
|
373
389
|
this._textContextInjectionMap.forEach((e) => {
|
|
374
390
|
e.writer.deleteTextBulk(keys);
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
|
|
2
|
+
## insertBulk
|
|
3
|
+
```json
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"chainID": "Mağrib",
|
|
7
|
+
"points": [
|
|
8
|
+
{
|
|
9
|
+
"id": "Fas",
|
|
10
|
+
"long": 0,
|
|
11
|
+
"lat": 0,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id":"Cezayir",
|
|
15
|
+
"long": 10,
|
|
16
|
+
"lat": 20,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id":"Tunus",
|
|
20
|
+
"long": 10,
|
|
21
|
+
"lat": 15
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"rgba": [1,0,0,1],
|
|
25
|
+
"dashRatio": 0.1,
|
|
26
|
+
"dashOpacity": 0.5,
|
|
27
|
+
"circleDashAngle": 15,
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// ["distance"]
|
|
34
|
+
updateCoordinatesBulk( items, contextTextWriterIDs=[]) {
|
|
35
|
+
for ( const item of items){
|
|
36
|
+
this._updateCoordsChain(item.chainID, item.points);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_updateCoordsChain(chainID, nodes){
|
|
41
|
+
const chain = this._chainMap(chainID); // chain is a `list`
|
|
42
|
+
const updateIDs = [];
|
|
43
|
+
for ( let i = 0; i< chain.length; i++){
|
|
44
|
+
if ( )
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
// text
|
|
52
|
+
const textContextMap = new Map(
|
|
53
|
+
[
|
|
54
|
+
[
|
|
55
|
+
"distance",
|
|
56
|
+
{
|
|
57
|
+
writer: new ContextTextWriter(globe,),
|
|
58
|
+
coordsAdaptor: (item, index, array) => { //
|
|
59
|
+
const { long, lat } = globe.Math.GetMidPoint(item.long, item.lat, item.endLong, item.endLat);
|
|
60
|
+
return {
|
|
61
|
+
long,
|
|
62
|
+
lat,
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
textAdaptor: (item) => {
|
|
66
|
+
const distance = globe.Math.GetDist2D(item.long, item.lat, item.endLong, item.endLat);
|
|
67
|
+
return distance.toFixed(2) + "m";
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
// ["distance"]
|
|
76
|
+
updateCoordinatesBulk(items, textWriterInjectionSubSetIDs = []) {
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_updateChainCoords(chainID, points){
|
|
81
|
+
this._updateCoordsBuffer();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
const connectNaive = (p1, p2) => {p1.set("to",p2);p2.set("from":p1)};
|
|
91
|
+
const Tanca = new Map([["long", 0],[ "lat",0], ["from", null], ["to":null]]);
|
|
92
|
+
const Cebelitarik = new Map([["long", 0],[ "lat",0], ["from", null], ["to":null]]);
|
|
93
|
+
const Cezayir = new Map([["long", 0],[ "lat",0], ["from", null], ["to":null]]);
|
|
94
|
+
const Tunus = new Map([["long", 0],[ "lat",0], ["from", null], ["to":null]]);
|
|
95
|
+
const Tanca = {id, long,lat, toID}
|
|
96
|
+
|
|
97
|
+
plugin.insertBulk([
|
|
98
|
+
{
|
|
99
|
+
chainID: "Mağrib",
|
|
100
|
+
points: [
|
|
101
|
+
{Tanca, to: Cebelitarik}
|
|
102
|
+
{Cebelitarik, to:"Cezayir"},
|
|
103
|
+
{Cezayir, to: "Tunus"}, // implicitly connects to Tunus
|
|
104
|
+
{Tunus, to:null}
|
|
105
|
+
]),
|
|
106
|
+
rgba: [1.0, 0.0, 0.0, 1.0],
|
|
107
|
+
dashRatio: 0.1,
|
|
108
|
+
dashOpacity: 0.5,
|
|
109
|
+
circleDashAngle: 15,
|
|
110
|
+
}
|
|
111
|
+
]);
|
|
112
|
+
```
|
|
113
|
+
Advantage: User knows patterns of position data.
|
|
114
|
+
Disadventage: Not json.
|
|
115
|
+
Bug: How to insert into middle?
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
coordinateAdaptor => (v, i, array) => {
|
|
119
|
+
return {
|
|
120
|
+
(v.long + array[i+1].long) / 2.0,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
const connect = (chainMap, chainID, node) => {
|
|
126
|
+
const chain = chainMap.get(chainID);
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## updateCoordinatesBulk
|
|
134
|
+
|
|
135
|
+
updates pointMap;
|
|
136
|
+
then updates buffers from updated version of pointMap;
|
|
137
|
+
|
|
138
|
+
imparatively open next or prev
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
[
|
|
142
|
+
{
|
|
143
|
+
"chainID": "Mağrib",
|
|
144
|
+
"points": [
|
|
145
|
+
{
|
|
146
|
+
""Fas"": {
|
|
147
|
+
" "l"ong": 100,
|
|
148
|
+
"lat": 30
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
## deleteBulk
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
[
|
|
161
|
+
{
|
|
162
|
+
"chainID": "Mağrib",
|
|
163
|
+
"all": false,
|
|
164
|
+
"points": [
|
|
165
|
+
"Fas"
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
## ContextTextWriter
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
{
|
|
176
|
+
|
|
177
|
+
writer: new ContextTextWriter(globe),
|
|
178
|
+
coordsAdaptor: (item) =>
|
|
179
|
+
if (item.get("next") === null) return false;
|
|
180
|
+
const goe = {
|
|
181
|
+
long: point.get("long"),
|
|
182
|
+
lat: point.get("lat"),
|
|
183
|
+
endLong: point.get("next")?.get("long"),
|
|
184
|
+
endLat: point.get("next")?.get("lat")
|
|
185
|
+
}
|
|
186
|
+
return globe.getMidPoint(geo.long,geo.lat, geo.endLong, geo.endLat)
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
textAdaptor: (item) => {
|
|
190
|
+
const angle = item.long, item.lat, item.endLong, item.endLat
|
|
191
|
+
);
|
|
192
|
+
if (angle < 0) {
|
|
193
|
+
return (angle + 360).toFixed(2) + "°";
|
|
194
|
+
}
|
|
195
|
+
return angle.toFixed(2) + "°";
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
class Chain{
|
|
204
|
+
constractor(id, {rgba = [1,0,0,1], dashOpacity = 1, dashRatio = 0.1, circleDashAngle = 30 } = []){
|
|
205
|
+
this.id = 0;
|
|
206
|
+
this.idMap = new Map();
|
|
207
|
+
this.list = [];
|
|
208
|
+
this._rgba = rgba;
|
|
209
|
+
this._dashOpacity = dashOpacity;
|
|
210
|
+
this._dashRatio = dashRatio;
|
|
211
|
+
this._circleDashAngle = this.circleDashAngle;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
add(item, fromID = null){
|
|
215
|
+
this.idMap.set(item.id, item);
|
|
216
|
+
let drawIndex;
|
|
217
|
+
if (from === null) {
|
|
218
|
+
this.list.push(item);
|
|
219
|
+
drawIndex = this.list.length - 1;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
for ( let i = 0 ; i < this.list.length ; i++){
|
|
223
|
+
if ( fromID === this.list[i].id) {
|
|
224
|
+
drawIndex = i;
|
|
225
|
+
this.list.splice(i, 0, item);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this._update( [i, i-1]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
nextID(id){
|
|
233
|
+
// for loop if data source is a list. not performand.
|
|
234
|
+
// pointer if data rouce is a node. Clunky
|
|
235
|
+
// reconstract the map on (!append) operation.
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
## Design Priorities
|
|
243
|
+
|
|
244
|
+
user interaction. insert, update, get data
|
|
245
|
+
some processies are callback. callbacks uses the pattern user insert the data
|
|
246
|
+
|
|
247
|
+
ContextTextWriter Plugin interaction I provided was imparative. I fit to that context because item had required data.
|
|
248
|
+
Current context has uses next objects data in the chain.
|
|
249
|
+
|
|
250
|
+
What is the imparative way to get next data?
|
|
251
|
+
A `function` - A `pointer`
|
|
252
|
+
If I go with a `pointer` I need to get the data with a `pointer`
|
|
253
|
+
How to I provide a `function` to get the next data?
|
|
254
|
+
```js
|
|
255
|
+
getNodeData(chainID, id){
|
|
256
|
+
return this.chainMap.get(chainID).get(id)
|
|
257
|
+
}
|
|
258
|
+
// Problem to use this function the object of getNodeData must be created before creating contextTextWriterMap.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
how minimally hold the data
|
|
262
|
+
|
|
263
|
+
how to render
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
Edit mod. user asks chain data and bind placeholders.
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
## API
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
getChain(chainID) => {pointID, long, lat}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
## explore pattern
|
|
280
|
+
|
|
281
|
+
(x, index, array ) doesnt fit.
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
## insertBulk
|
|
287
|
+
```json
|
|
288
|
+
[
|
|
289
|
+
{
|
|
290
|
+
"chainID": "Mağrib",
|
|
291
|
+
"points": [
|
|
292
|
+
{
|
|
293
|
+
"id": "Fas",
|
|
294
|
+
"long": 0,
|
|
295
|
+
"lat": 0,
|
|
296
|
+
"to": "Cezayir"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"id":"Cezayir",
|
|
300
|
+
"long": 10,
|
|
301
|
+
"lat": 20,
|
|
302
|
+
"to": "Tunus"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"id":"Tunus",
|
|
306
|
+
"long": 10,
|
|
307
|
+
"lat": 15
|
|
308
|
+
}
|
|
309
|
+
],
|
|
310
|
+
"rgba": [1,0,0,1],
|
|
311
|
+
"dashRatio": 0.1,
|
|
312
|
+
"dashOpacity": 0.5,
|
|
313
|
+
"circleDashAngle": 15,
|
|
314
|
+
},
|
|
315
|
+
]
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
```js
|
|
319
|
+
// ["distance"]
|
|
320
|
+
updateCoordinatesBulk( items, contextTextWriterIDs=[]) {
|
|
321
|
+
for ( const item of items){
|
|
322
|
+
this._updateCoordsChain(item.chainID, item.points);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
_updateCoordsChain(chainID, nodes){
|
|
327
|
+
const chain = this._chainMap(chainID); // chain is a `list`
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
##
|
|
335
|
+
Get data from user with `to` keyword. implicitly add from keyword
|
|
336
|
+
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { keyMethod } from "./util";
|
|
2
|
+
/**
|
|
3
|
+
* set and get node data
|
|
4
|
+
* node indexes;
|
|
5
|
+
*/
|
|
6
|
+
export class ChainListMap {
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this._chainMap = new Map();
|
|
10
|
+
this._chainSideProperties = new Map();
|
|
11
|
+
this._indexMap = new Map(); // hold list index of lastly updated nodes. on add delete goes empty
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getChain(chainKey) {
|
|
15
|
+
if (!this._chainMap.has(chainKey)) this._chainMap.set(chainKey, []);
|
|
16
|
+
return this._chainMap.get(chainKey);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param {*} node
|
|
22
|
+
* @param {*} chainKey
|
|
23
|
+
* @param {string|null} theNodeKeyFront
|
|
24
|
+
*/
|
|
25
|
+
addNode(node, chainKey, theNodeKeyFront = null) {
|
|
26
|
+
const chain = this.getChain(chainKey);
|
|
27
|
+
|
|
28
|
+
if (theNodeKeyFront == null) {
|
|
29
|
+
chain.push(node);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < chain.length; i++) {
|
|
34
|
+
const n_ode = chain[i];
|
|
35
|
+
if (n_ode == theNodeKeyFront) {
|
|
36
|
+
chain.splice(i, 0, node);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this._resetIndexChain(chainKey);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
deleteNode(chainKey, nodeKey) {
|
|
44
|
+
const index = this.getIndexOfNode(chainKey, nodeKey);
|
|
45
|
+
const chain = this._chainMap.get(chainKey);
|
|
46
|
+
chain.splice(index, 1);
|
|
47
|
+
this._resetIndexChain(chainKey);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deleteNodesBelongToAChain(chainKey, nodeKeys) {
|
|
51
|
+
const chain = this._chainMap.get(chainKey);
|
|
52
|
+
const compKeys = [];
|
|
53
|
+
const removeSet = new Set(nodeKeys);
|
|
54
|
+
const newChain = []
|
|
55
|
+
for (const node of chain) {
|
|
56
|
+
const dKey = keyMethod(chainKey, node.key);
|
|
57
|
+
this._indexMap.delete(dKey);
|
|
58
|
+
if (removeSet.has(node.key)) {
|
|
59
|
+
compKeys.push(dKey);
|
|
60
|
+
} else {
|
|
61
|
+
newChain.push(node);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this._chainMap.set(chainKey, newChain);
|
|
65
|
+
return compKeys;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
deleteChainAndReturnChainKeys(chainKey) {
|
|
69
|
+
const keys = this.getNodeKeysOfChain(chainKey);
|
|
70
|
+
this._chainMap.delete(chainKey);
|
|
71
|
+
for (const key of keys) this._indexMap.delete(key);
|
|
72
|
+
return keys;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
updateNode(node, chainKey) {
|
|
76
|
+
const index = this.getIndexOfNode(chainKey, node.key)
|
|
77
|
+
const chain = this._chainMap.getChain(chainKey);
|
|
78
|
+
chain[index] = node;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
setChain(chainKey, list) {
|
|
83
|
+
if (this._chainMap.has(chain)) this._flushIndexMap();
|
|
84
|
+
this._chainMap.set(chainKey, list);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
setChainProperties(chainKey, properties) {
|
|
89
|
+
this._chainSideProperties.set(chainKey, properties);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
*
|
|
95
|
+
* @param {string} chainKey
|
|
96
|
+
* @param {Map} properties
|
|
97
|
+
* // after this method update text and buffer data of the chain
|
|
98
|
+
*/
|
|
99
|
+
updateChainProperties(chainKey, properties) {
|
|
100
|
+
|
|
101
|
+
const memoryProperties = this._chainSideProperties.get(chainKey);
|
|
102
|
+
properties.forEach((value, key, m) => {
|
|
103
|
+
memoryProperties[key] = value;
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getChainProperties(chainKey) {
|
|
109
|
+
this._chainSideProperties.get(chainKey);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
*
|
|
114
|
+
* @param {*} chainKey
|
|
115
|
+
* @param {*} callback | (value, index, array) => expexted output
|
|
116
|
+
*/
|
|
117
|
+
calculateBufferPropertiesChain(chainKey, callback, result, nodeIndexes = null) {
|
|
118
|
+
const nodes = this._chainMap(chainKey);
|
|
119
|
+
const props = this._chainSideProperties(chainKey);
|
|
120
|
+
const iterator = nodeIndexes !== null ? nodeIndexes : nodes.keys();
|
|
121
|
+
for (const i of iterator) {
|
|
122
|
+
|
|
123
|
+
result.push(callback(chain[i], i, chain, probs));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
*
|
|
130
|
+
* @param {*} chainKey
|
|
131
|
+
* @param {*} textWriterObjs
|
|
132
|
+
* @param {*} nodeKeys use nodeKeys on updateCoordinatesOnly
|
|
133
|
+
*/
|
|
134
|
+
textUpdate(chainKey, textWriterObjs, nodeIndexes = null) {
|
|
135
|
+
const chain = this.getChain(chainKey);
|
|
136
|
+
|
|
137
|
+
if (nodeKeys) {
|
|
138
|
+
textWriterObjs.forEach((v) => {
|
|
139
|
+
const { coordsAdaptor, textAdaptor, writer } = v;
|
|
140
|
+
for (const i in nodeIndexes) {
|
|
141
|
+
const value = chain[i];
|
|
142
|
+
const { long, lat } = coordsAdaptor(value, i, chain);
|
|
143
|
+
const text = textAdaptor(value, i, chain);
|
|
144
|
+
const opacity = opacityAdaptor(value, i, array);
|
|
145
|
+
|
|
146
|
+
writer.insertText(
|
|
147
|
+
keyMethod(chainKey, value.key),
|
|
148
|
+
lat,
|
|
149
|
+
long,
|
|
150
|
+
text,
|
|
151
|
+
opacity
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
textWriterObjs.forEach((v) => {
|
|
159
|
+
const { coordsAdaptor, textAdaptor, opacityAdaptor, writer } = v;
|
|
160
|
+
chain.forEach((value, i, array) => {
|
|
161
|
+
const { lat, long } = coordsAdaptor(value, i, array);
|
|
162
|
+
const text = textAdaptor(value, i, array);
|
|
163
|
+
const opacity = opacityAdaptor(value, i, array);
|
|
164
|
+
writer.insertText(item.key, lat, long, text);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
getIndexOfNode(chainKey, nodeKey) {
|
|
172
|
+
const key = keyMethod(chainKey, nodeKey);
|
|
173
|
+
if (this._indexMap.has(key)) return this._indexMap.get(key);
|
|
174
|
+
|
|
175
|
+
const chain = this._chainMap.get(chainKey);
|
|
176
|
+
for (let i = 0; i < chain.length; i++) {
|
|
177
|
+
const node = chain[i];
|
|
178
|
+
this._indexMap.set(key, i);
|
|
179
|
+
if (node.key === nodeKey) {
|
|
180
|
+
return i
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
_flushIndexMap() {
|
|
186
|
+
this._indexMap.clear();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_resetIndexChain(chainKey) {
|
|
190
|
+
const chain = this._chainMap.get(chain);
|
|
191
|
+
for (let i = 0; i < chain.length; i++) {
|
|
192
|
+
const node = chain[i]
|
|
193
|
+
this._indexMap.set(keyMethod(chainKey, node.key), i);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getNodeKeysOfChain(chainKey) {
|
|
198
|
+
const chain = this._chainMap(chainKey);
|
|
199
|
+
return chain.map((v) => keyMethod(chainKey, v.key));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
}
|
|
File without changes
|
package/circle-lines/plugin.js
CHANGED
|
@@ -10,8 +10,322 @@
|
|
|
10
10
|
* - line
|
|
11
11
|
*
|
|
12
12
|
* Chain
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
user data
|
|
14
|
+
[ {
|
|
15
|
+
chainKey: "Magrib",
|
|
16
|
+
nodes: new Map([
|
|
17
|
+
[ "Tanca", {long, lat, to:"Cebelitarik"}],
|
|
18
|
+
[ "Cebelitarik", {long, lat, to: null}]
|
|
19
|
+
])
|
|
20
|
+
}]
|
|
21
|
+
implicitly add from keyword for simplicity;
|
|
16
22
|
* # Mouse interations
|
|
17
|
-
*/
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { LineOnGlobeCache } from '../programs/line-on-globe/naive';
|
|
26
|
+
import { CircleCache } from '../programs/line-on-globe/circle';
|
|
27
|
+
import { BufferOrchestrator } from "../util/account";
|
|
28
|
+
import { ChainListMap } from "./chain-list-map";
|
|
29
|
+
import { keyMethod } from "./util";
|
|
30
|
+
import { buffer } from 'three/tsl';
|
|
31
|
+
|
|
32
|
+
// TODO: Add update buffer and update text mehods on add, delete, update methods
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Insert info to chain list map (nodes and properties)
|
|
37
|
+
*
|
|
38
|
+
* ask chain list map for text data
|
|
39
|
+
* ask chain list map for buffer data
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
const radian = Math.PI / 180;
|
|
44
|
+
|
|
45
|
+
export class CircleLineChainPlugin {
|
|
46
|
+
|
|
47
|
+
constructor(id, { textContextInjectionMap = new Map() } = {}) {
|
|
48
|
+
this.id = id;
|
|
49
|
+
this._textContextInjectionMap = textContextInjectionMap;
|
|
50
|
+
this._opacity = 1;
|
|
51
|
+
this._chainListMap = new ChainListMap();
|
|
52
|
+
this.bufferOrchestrator = new BufferOrchestrator({ capacity: 10 });
|
|
53
|
+
this._chainListMap
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// init
|
|
57
|
+
|
|
58
|
+
init(globe, gl) {
|
|
59
|
+
this.gl = gl;
|
|
60
|
+
this.globe = globe
|
|
61
|
+
this._initOrchestrations()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
_initOrchestrations() {
|
|
66
|
+
this.lineProgram = LineOnGlobeCache.get(globe);
|
|
67
|
+
this.circleProgram = CircleCache.get(globe);
|
|
68
|
+
{
|
|
69
|
+
// createBuffers
|
|
70
|
+
const bufferType = "DYNAMIC_DRAW";
|
|
71
|
+
const initialCapacity = this.bufferOrchestrator.capacity;
|
|
72
|
+
this.bufferManagersCompMap = new Map(
|
|
73
|
+
[
|
|
74
|
+
["centerCoords", {
|
|
75
|
+
'bufferManager': new BufferManager(gl, 2, { bufferType, initialCapacity }),
|
|
76
|
+
'adaptor': (item) => new Float32Array([radian * item.long, radian * item.lat]),
|
|
77
|
+
}],
|
|
78
|
+
["targetCoords", {
|
|
79
|
+
'bufferManager': new BufferManager(gl, 2, { bufferType, initialCapacity }),
|
|
80
|
+
'adaptor': (item) => new Float32Array([radian * item.targetLong, radian * item.targetLat])
|
|
81
|
+
}],
|
|
82
|
+
["rgba", {
|
|
83
|
+
'bufferManager': new BufferManager(gl, 4, { bufferType, initialCapacity }),
|
|
84
|
+
'adaptor': (item) => new Float32Array(item.rgba)
|
|
85
|
+
}],
|
|
86
|
+
["bigRadius", {
|
|
87
|
+
'bufferManager': new BufferManager(gl, 1, { bufferType, initialCapacity }),
|
|
88
|
+
'adaptor': (item) => new Float32Array([item.bigRadius])
|
|
89
|
+
}],
|
|
90
|
+
["rgbaMode", {
|
|
91
|
+
'bufferManager': new BufferManager(gl, 1, { bufferType, initialCapacity }),
|
|
92
|
+
'adaptor': (item) => new Float32Array([item.rgbaMode])
|
|
93
|
+
}],
|
|
94
|
+
["dashRatio", {
|
|
95
|
+
'bufferManager': new BufferManager(gl, 1, { bufferType, initialCapacity }),
|
|
96
|
+
'adaptor': (item) => new Float32Array([item.dashRatio])
|
|
97
|
+
}],
|
|
98
|
+
|
|
99
|
+
["dashOpacity", {
|
|
100
|
+
'bufferManager': new BufferManager(gl, 1, { bufferType, initialCapacity }),
|
|
101
|
+
'adaptor': (item) => new Float32Array([item.dashOpacity])
|
|
102
|
+
}],
|
|
103
|
+
["circleDashAngle", {
|
|
104
|
+
'bufferManager': new BufferManager(gl, 1, { bufferType, initialCapacity }),
|
|
105
|
+
'adaptor': (item) => new Float32Array([item.circleDashAngle / 360])
|
|
106
|
+
}]
|
|
107
|
+
]
|
|
108
|
+
);
|
|
109
|
+
// (startPotisionBufferObj, endPositionBufferObj, dashRatioBufferObj, colorBufferObj)
|
|
110
|
+
this.lineVao = this.lineProgram.createVAO(
|
|
111
|
+
...['centerCoords', 'targetCoords', 'dashRatio', 'dashOpacity', 'rgba'].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
112
|
+
this.circleVao = this.circleProgram.createVAO(
|
|
113
|
+
...["centerCoords", "bigRadius", "rgba", "circleDashAngle", "dashOpacity"].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
// API
|
|
120
|
+
|
|
121
|
+
// -- update bulk family
|
|
122
|
+
/**
|
|
123
|
+
*
|
|
124
|
+
* @param {Array<chain>} data
|
|
125
|
+
* @typedef chain
|
|
126
|
+
* @property {string} chainKey
|
|
127
|
+
* @property {Array<node>} nodes
|
|
128
|
+
*
|
|
129
|
+
* @typedef {Object} node
|
|
130
|
+
* @property {string} key
|
|
131
|
+
* @property {number} long
|
|
132
|
+
* @property {number} lat
|
|
133
|
+
*/
|
|
134
|
+
updateCoordinatesBulk(data, textWriterInjectionSubSetIDs = []) {
|
|
135
|
+
// update implicit data structure
|
|
136
|
+
// find keys to update.. (inserted data and the radius of "from")
|
|
137
|
+
// updateBuffers
|
|
138
|
+
// update text
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
// ---- insertBulk family
|
|
144
|
+
/**
|
|
145
|
+
*
|
|
146
|
+
* @param {Array<chain>} data
|
|
147
|
+
* @typedef chain
|
|
148
|
+
* @property {string} chainKey
|
|
149
|
+
* @property {[0-1,0-1,0-1,0-1]} rgba
|
|
150
|
+
* @property { 0-1 } dashOpacity
|
|
151
|
+
* @property { 0-1 } dashRatio
|
|
152
|
+
* @property {0-360} circleDashAngle
|
|
153
|
+
* @property {Array<node>} nodes
|
|
154
|
+
*
|
|
155
|
+
* @typedef {Object} node
|
|
156
|
+
* @property {string} key
|
|
157
|
+
* @property {number} long
|
|
158
|
+
* @property {number} lat
|
|
159
|
+
*/
|
|
160
|
+
insertBulk(data) {
|
|
161
|
+
// first insert everything to implicit structure,
|
|
162
|
+
// then iterate over data again to update text
|
|
163
|
+
// let _reconstractChainBufferData method interact with data and bufferOrchestrator.
|
|
164
|
+
const chainKeysToConstruct = [];
|
|
165
|
+
|
|
166
|
+
for (const { chainKey, rgba, dashOpacity, dashRatio, circleDashAngle, nodes } of data) {
|
|
167
|
+
this._chainListMap.setChain(chainKey, nodes);
|
|
168
|
+
this._chainListMap.setChainInfo(chainKey, {
|
|
169
|
+
rgba, dashOpacity, dashRatio, circleDashAngle
|
|
170
|
+
});
|
|
171
|
+
chainKeysToConstruct.push(chainKey);
|
|
172
|
+
}
|
|
173
|
+
this._reconstructChains(chainKeysToConstruct);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
* @param {*} chainKey
|
|
179
|
+
* @param {*} key // node key
|
|
180
|
+
* @param {*} long
|
|
181
|
+
* @param {*} lat
|
|
182
|
+
* @param {*} theNodeKeyFront | node key of the next node, null places to the last
|
|
183
|
+
*/
|
|
184
|
+
addNode(chainKey, key, long, lat, theNodeKeyFront = null) {
|
|
185
|
+
// TODO: if before object is null update the last two elements of the chain only.
|
|
186
|
+
this._chainListMap.addNode({ lat, long, key }, chainKey, theNodeKeyFront);
|
|
187
|
+
this._reconstructChains([chainKey]);
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
updateNodeCoordinates(node, chainKey, textContextIDs) {
|
|
194
|
+
this._chainListMap.updateNode(node, chainKey);
|
|
195
|
+
|
|
196
|
+
{
|
|
197
|
+
const textContexts = textContextIDs.map(v => this._textContextInjectionMap.get(v));
|
|
198
|
+
this._chainListMap.textUpdate(chainKey, textContextIDs,)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
setOpacity(opacity) {
|
|
206
|
+
this._opacity = opacity;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
getChain(chainKey) {
|
|
212
|
+
this._chainListMap.getChain(chainKey);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
*
|
|
217
|
+
* @param {*} chainKey
|
|
218
|
+
* @param {*} nodeKeys
|
|
219
|
+
*/
|
|
220
|
+
deleteChain(chainKey) {
|
|
221
|
+
const keys = this._chainListMap.deleteChainAndReturnChainKeys(chainKey)
|
|
222
|
+
this.bufferOrchestrator.deleteBulk(keys, this.bufferManagersCompMap)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* @param {Map<keys, [nodeKeys]} keysAndNodes
|
|
229
|
+
*/
|
|
230
|
+
deleteNodes(keysAndNodes) {
|
|
231
|
+
const bufferKeys = [];
|
|
232
|
+
const chainKeysToReconstuct = [];
|
|
233
|
+
keysAndNodes.forEach((nodeList, chainKey, m) => {
|
|
234
|
+
bufferKeys.push(...this._chainListMap.deleteChainAndReturnChainKeys(chainKey, nodeList));
|
|
235
|
+
chainKeysToReconstuct.push(chainKey);
|
|
236
|
+
})
|
|
237
|
+
this._reconstructChains(chainKeysToReconstuct);
|
|
238
|
+
this.bufferOrchestrator.deleteBulk(bufferKeys, this.bufferManagersCompMap);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
deleteNode(chainKey, nodeKey) {
|
|
243
|
+
this._chainListMap.deleteNode(chainKey, nodeKey);
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// implicit
|
|
248
|
+
|
|
249
|
+
_updateTextOpacityAll(items) {
|
|
250
|
+
this._textContextInjectionMap.forEach((v) => {
|
|
251
|
+
const { writer } = v
|
|
252
|
+
for (const item of items) {
|
|
253
|
+
if (item.rgba) {
|
|
254
|
+
writer.updateOpacityOfItem(item.key, item.rgba[3])
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
_insertTexts(item, textWriterInjectionSubSet) {
|
|
262
|
+
//TODO This method can be more performant if it works horizontally, tabular
|
|
263
|
+
textWriterInjectionSubSet.forEach((v) => {
|
|
264
|
+
const { coordsAdaptor, textAdaptor, writer } = v
|
|
265
|
+
const { lat, long } = coordsAdaptor(item);
|
|
266
|
+
const text = textAdaptor(item);
|
|
267
|
+
writer.insertText(item.key, lat, long, text);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
_reconstructChains(chainKeys) {
|
|
274
|
+
const { globe } = globe;
|
|
275
|
+
// this.lineVao = this.lineProgram.createVAO(
|
|
276
|
+
// ...['centerCoords', 'targetCoords', 'dashRatio', 'dashOpacity', 'rgba'].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
277
|
+
// this.circleVao = this.circleProgram.createVAO(
|
|
278
|
+
// ...["centerCoords", "bigRadius", "rgba", "circleDashAngle", "dashOpacity"].map(key => obj(this.bufferManagersCompMap.get(key))));
|
|
279
|
+
// }
|
|
280
|
+
const radiusM = radiusMethod(globe);
|
|
281
|
+
const callback = (v, i, array, probs) => {
|
|
282
|
+
return {
|
|
283
|
+
rgba: probs.rgba,
|
|
284
|
+
bigRadius: radiusM(v, i, array),
|
|
285
|
+
circleDashAngle: probs.circleDashAngle,
|
|
286
|
+
dashOpacity: probs.dashOpacity,
|
|
287
|
+
dashRatio: probs.dashRatio,
|
|
288
|
+
long: v.long,
|
|
289
|
+
lat: v.lat,
|
|
290
|
+
targetLong: array[i + 1].long,
|
|
291
|
+
targetLat: array[i + 1].lat,
|
|
292
|
+
key: keyMethod(probs.chainKey, v.key)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const bulkData = [];
|
|
296
|
+
chainKeys.forEach((k) => {
|
|
297
|
+
this._chainListMap.calculateBufferPropertiesChain(k, callback, bulkData);
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
this._insertBulk(bulkData);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
_insertBulk(bulkData) {
|
|
305
|
+
this.bufferOrchestrator.insertBulk(bulkData, this.bufferManagersCompMap);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
// GLOBE API
|
|
310
|
+
//TODO:
|
|
311
|
+
free() {
|
|
312
|
+
if (this.isFreed) return;
|
|
313
|
+
this.bufferManagersCompMap.forEach(({ bufferManager }) => {
|
|
314
|
+
bufferManager.free();
|
|
315
|
+
})
|
|
316
|
+
LineOnGlobeCache.release(this.globe);
|
|
317
|
+
CircleCache.release(this.globe);
|
|
318
|
+
this.isFreed = true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
draw3D() {
|
|
322
|
+
const { gl } = this;
|
|
323
|
+
this.lineProgram.draw(this.lineVao, this.bufferOrchestrator.length, this._opacity);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
const radiusMethod = (globe) => (v, i, array) => {
|
|
330
|
+
return globe.Math.GetDist2D(v.long, v.lat, array[i + 1].endLong, array[i + 1].endLat)
|
|
331
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const keyMethod = (chainKey, nodeKey) => `${chainKey}_${nodeKey}`;
|
package/package.json
CHANGED
|
@@ -36,7 +36,6 @@ ${circleLimpFromLongLatRadCenterMercatorRealDistance}
|
|
|
36
36
|
uniform float edge_count;
|
|
37
37
|
|
|
38
38
|
in vec2 center_position;
|
|
39
|
-
in float start_angle;
|
|
40
39
|
in float radius;
|
|
41
40
|
in vec4 color;
|
|
42
41
|
in float dash_ratio;
|
|
@@ -112,11 +111,10 @@ class Logic {
|
|
|
112
111
|
|
|
113
112
|
{ // assign attribute locations
|
|
114
113
|
gl.bindAttribLocation(program, 0, "center_position");
|
|
115
|
-
gl.bindAttribLocation(program, 1, "
|
|
116
|
-
gl.bindAttribLocation(program, 2, "
|
|
117
|
-
gl.bindAttribLocation(program, 3, "
|
|
118
|
-
gl.bindAttribLocation(program, 4, "
|
|
119
|
-
gl.bindAttribLocation(program, 5, "dash_opacity");
|
|
114
|
+
gl.bindAttribLocation(program, 1, "radius");
|
|
115
|
+
gl.bindAttribLocation(program, 2, "color");
|
|
116
|
+
gl.bindAttribLocation(program, 3, "dash_ratio");
|
|
117
|
+
gl.bindAttribLocation(program, 4, "dash_opacity");
|
|
120
118
|
}
|
|
121
119
|
|
|
122
120
|
this.cameraBindingPoint = 0;
|
|
@@ -125,7 +123,7 @@ class Logic {
|
|
|
125
123
|
gl.uniformBlockBinding(program, cameraBlockLocation, this.cameraBindingPoint);
|
|
126
124
|
}
|
|
127
125
|
|
|
128
|
-
createVAO(centerObj,
|
|
126
|
+
createVAO(centerObj, radiusObj, colorObj, dashRatioObj, dashOpacityObj) {
|
|
129
127
|
const { gl } = this;
|
|
130
128
|
const vao = gl.createVertexArray();
|
|
131
129
|
const divisor = 1;
|
|
@@ -134,25 +132,21 @@ class Logic {
|
|
|
134
132
|
const { buffer, stride = 0, offset = 0 } = centerObj;
|
|
135
133
|
vaoAttributeLoader(gl, buffer, 0, 2, stride, offset, divisor);
|
|
136
134
|
}
|
|
137
|
-
{
|
|
138
|
-
const { buffer, stride = 0, offset = 0 } = startAngleObj;
|
|
139
|
-
vaoAttributeLoader(gl, buffer, 1, 1, stride, offset, divisor);
|
|
140
|
-
}
|
|
141
135
|
{
|
|
142
136
|
const { buffer, stride = 0, offset = 0 } = radiusObj;
|
|
143
|
-
vaoAttributeLoader(gl, buffer,
|
|
137
|
+
vaoAttributeLoader(gl, buffer, 1, 1, stride, offset, divisor);
|
|
144
138
|
}
|
|
145
139
|
{
|
|
146
140
|
const { buffer, stride = 0, offset = 0 } = colorObj;
|
|
147
|
-
vaoAttributeLoader(gl, buffer,
|
|
141
|
+
vaoAttributeLoader(gl, buffer, 2, 4, stride, offset, divisor);
|
|
148
142
|
}
|
|
149
143
|
{
|
|
150
144
|
const { buffer, stride = 0, offset = 0 } = dashRatioObj;
|
|
151
|
-
vaoAttributeLoader(gl, buffer,
|
|
145
|
+
vaoAttributeLoader(gl, buffer, 3, 1, stride, offset, divisor);
|
|
152
146
|
}
|
|
153
147
|
{
|
|
154
148
|
const { buffer, stride = 0, offset = 0 } = dashOpacityObj;
|
|
155
|
-
vaoAttributeLoader(gl, buffer,
|
|
149
|
+
vaoAttributeLoader(gl, buffer, 4, 1, stride, offset, divisor);
|
|
156
150
|
}
|
|
157
151
|
gl.bindVertexArray(null);
|
|
158
152
|
gl.bindVertexArray(null);
|
|
@@ -21,10 +21,12 @@ in vec2 start_position;
|
|
|
21
21
|
in vec2 end_position;
|
|
22
22
|
in float dash_ratio;
|
|
23
23
|
in vec4 color;
|
|
24
|
+
in float dash_opacity;
|
|
24
25
|
out vec4 v_color;
|
|
25
26
|
out vec2 v_limp;
|
|
26
27
|
out float interpolation;
|
|
27
28
|
out float v_dash_ratio;
|
|
29
|
+
out float v_dash_opacity;
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
void main() {
|
|
@@ -50,6 +52,7 @@ void main() {
|
|
|
50
52
|
// else {v_color = vec4(0.0, 0.0, 0.0, 0.0);}
|
|
51
53
|
v_color = color;
|
|
52
54
|
v_dash_ratio = dash_ratio;
|
|
55
|
+
v_dash_opacity = dash_opacity;
|
|
53
56
|
}
|
|
54
57
|
`;
|
|
55
58
|
|
|
@@ -62,13 +65,14 @@ out vec4 color;
|
|
|
62
65
|
in float interpolation;
|
|
63
66
|
in float v_dash_ratio;
|
|
64
67
|
in vec2 v_limp;
|
|
68
|
+
in float v_dash_opacity;
|
|
65
69
|
void main() {
|
|
66
70
|
if (v_limp.x < -POLE || v_limp.x > POLE || v_limp.y < -POLE || v_limp.y > POLE) { discard; }
|
|
67
71
|
color = v_color;
|
|
68
72
|
color.a *= opacity;
|
|
69
73
|
if ( v_dash_ratio >= 1.0 ) { return; }
|
|
70
74
|
if (interpolation > 0.95) { return; }
|
|
71
|
-
if (fract(interpolation / (2.0 * v_dash_ratio)) < 0.5) { color.a
|
|
75
|
+
if (fract(interpolation / (2.0 * v_dash_ratio)) < 0.5) { color.a *= v_dash_opacity; }
|
|
72
76
|
|
|
73
77
|
}
|
|
74
78
|
`;
|
|
@@ -88,6 +92,7 @@ class Logic {
|
|
|
88
92
|
gl.bindAttribLocation(program, 1, "end_position");
|
|
89
93
|
gl.bindAttribLocation(program, 2, "dash_ratio");
|
|
90
94
|
gl.bindAttribLocation(program, 3, "color");
|
|
95
|
+
gl.bindAttribLocation(program, 4, "dash_opacity");
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
{
|
|
@@ -133,7 +138,7 @@ class Logic {
|
|
|
133
138
|
|
|
134
139
|
|
|
135
140
|
//
|
|
136
|
-
createVAO(startPotisionBufferObj, endPositionBufferObj, dashRatioBufferObj, colorBufferObj) {
|
|
141
|
+
createVAO(startPotisionBufferObj, endPositionBufferObj, dashRatioBufferObj, dashOpacityBufferObj, colorBufferObj) {
|
|
137
142
|
const { gl } = this;
|
|
138
143
|
const vao = gl.createVertexArray();
|
|
139
144
|
gl.bindVertexArray(vao);
|
|
@@ -168,6 +173,15 @@ class Logic {
|
|
|
168
173
|
gl.vertexAttribPointer(3, 4, gl.FLOAT, false, stride, offset);
|
|
169
174
|
gl.vertexAttribDivisor(3, 1);
|
|
170
175
|
}
|
|
176
|
+
|
|
177
|
+
{
|
|
178
|
+
const { buffer, stride = 0, offset = 0 } = dashOpacityBufferObj;
|
|
179
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
180
|
+
gl.enableVertexAttribArray(4);
|
|
181
|
+
gl.vertexAttribPointer(4, 1, gl.FLOAT, false, stride, offset);
|
|
182
|
+
gl.vertexAttribDivisor(4, 1);
|
|
183
|
+
}
|
|
184
|
+
|
|
171
185
|
gl.bindVertexArray(null);
|
|
172
186
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
173
187
|
return vao;
|
|
@@ -22,6 +22,7 @@ export class ContextTextWriter {
|
|
|
22
22
|
this.doDraw = doDraw;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
setDoDraw(bool) {
|
|
26
27
|
this.doDraw = bool;
|
|
27
28
|
}
|
|
@@ -42,8 +43,9 @@ export class ContextTextWriter {
|
|
|
42
43
|
draw() {
|
|
43
44
|
if (!this.doDraw) return;
|
|
44
45
|
const { globe, style, itemMap } = this;
|
|
45
|
-
const { textFont, opacity } = style;
|
|
46
|
-
|
|
46
|
+
const { textFont, opacity: opacity_ } = style;
|
|
47
|
+
|
|
48
|
+
for (const [key, { lat, long, text, opacity = null }] of itemMap) {
|
|
47
49
|
const { x, y } = globe.api_GetScreenPointFromGeo(
|
|
48
50
|
{
|
|
49
51
|
long: long,
|
|
@@ -52,17 +54,30 @@ export class ContextTextWriter {
|
|
|
52
54
|
},
|
|
53
55
|
style.zMode === CSZMode.Z_MSL,
|
|
54
56
|
);
|
|
55
|
-
|
|
56
|
-
globe.api_DrawContextTextMultiLine(text, textFont,
|
|
57
|
+
const o = opacity === null ? opacity_ : opacity * opacity_;
|
|
58
|
+
if (x !== null && y !== null) globe.api_DrawContextTextMultiLine(text, textFont, o, { x, y });
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
|
|
61
|
-
insertText(key, lat, long, text) {
|
|
63
|
+
insertText(key, lat, long, text,) { // TODO: Make it more generic
|
|
62
64
|
this.itemMap.set(key, { lat, long, text });
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
|
|
68
|
+
updateOpacityOfItem(key, opacity) {
|
|
69
|
+
this.itemMap.get(key).opacity = opacity;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
updateOpacityBulk(items, keyAdaptor, valueAdaptor) {
|
|
73
|
+
for (const item of items) {
|
|
74
|
+
const key = keyAdaptor(item);
|
|
75
|
+
const opacity = valueAdaptor(item);
|
|
76
|
+
const data = this.itemMap.get(key)
|
|
77
|
+
data.opacity = opacity;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
66
81
|
updateText(key, text) {
|
|
67
82
|
const item = this.itemMap.get(key);
|
|
68
83
|
item.text = text;
|
|
@@ -94,7 +109,11 @@ export class ContextTextWriter {
|
|
|
94
109
|
}
|
|
95
110
|
}
|
|
96
111
|
|
|
112
|
+
|
|
113
|
+
|
|
97
114
|
clear() {
|
|
98
115
|
this.itemMap.clear();
|
|
99
116
|
}
|
|
100
|
-
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|