@pirireis/webglobeplugins 0.3.7 → 0.3.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.
@@ -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", "startAngle", "bigRadius", "rgba", "circleDashAngle", "dashOpacity"].map(key => obj(this.bufferManagersCompMap.get(key))));
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>} injectionsSubSetIDs | textContextInjectionMap keys to be used for writing text.
219
+ * @param {Array<string>} textWriterInjectionSubSetIDs | textContextInjectionMap keys to be used for writing text.
220
220
  */
221
- insertBulk(items, injectionsSubSetIDs = []) {
221
+ insertBulk(items, textWriterInjectionSubSetIDs = []) {
222
222
  const { globe, bufferOrchestrator, bufferManagersCompMap } = this;// angleTextContext, distanceTextContext,
223
- const injectionsSubSet = injectionsSubSetIDs.map((id) => this._textContextInjectionMap.get(id));
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, injectionsSubSet);
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, angleTextContext, distanceTextContext } = this;
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
@@ -10,8 +10,322 @@
10
10
  * - line
11
11
  *
12
12
  * Chain
13
- * - multiple circlelines connected
14
- * - a wrapper around buffer orchester to hold one to many relationship
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT"
@@ -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, "start_angle");
116
- gl.bindAttribLocation(program, 2, "radius");
117
- gl.bindAttribLocation(program, 3, "color");
118
- gl.bindAttribLocation(program, 4, "dash_ratio");
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, startAngleObj, radiusObj, colorObj, dashRatioObj, dashOpacityObj) {
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, 2, 1, stride, offset, divisor);
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, 3, 4, stride, offset, divisor);
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, 4, 1, stride, offset, divisor);
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, 5, 1, stride, offset, divisor);
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 /= 4.0; }
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
- for (const [key, { lat, long, text }] of itemMap) {
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, opacity, { x, y });
57
+ const o = opacity === null ? opacity_ : opacity * opacity_;
58
+ 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
+