@pirireis/webglobeplugins 0.6.19 → 0.6.21
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 +30 -29
- package/circle-line-chain/plugin.js +16 -15
- package/package.json +1 -1
- package/programs/line-on-globe/circle-accurate-3d.js +0 -1
- package/programs/line-on-globe/circle-accurate-flat.js +20 -10
- package/programs/rings/distancering/paddyflatprogram2d.js +151 -0
- package/programs/rings/distancering/paddyflatprogram3d.js +151 -0
- package/rangerings/rangerings copy.js +219 -0
- package/rangerings-2/plugin.js +42 -0
- package/rangerings-2/ring-account.js +0 -0
- package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +5 -76
- package/circle-line-chain/chain-api.md +0 -336
package/bearing-line/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { pieceOfPieProgramCache } from '../programs/rings/partial-ring/piece-of-pie';
|
|
2
2
|
import { LineOnGlobeCache } from '../programs/line-on-globe/naive-accurate';
|
|
3
3
|
import { CircleCache as Circle3DCache } from '../programs/line-on-globe/circle-accurate-3d';
|
|
4
|
-
import { CircleCache, EDGE_COUNT as flatCircleEdgeCount } from '../programs/line-on-globe/circle-accurate-flat';
|
|
4
|
+
import { CircleCache, EDGE_COUNT as flatCircleEdgeCount, centerCoords2dflatDataCreator } from '../programs/line-on-globe/circle-accurate-flat';
|
|
5
5
|
import { BufferOrchestrator, BufferManager } from '../util/account';
|
|
6
6
|
import { AngledLineProgramCache } from '../programs/line-on-globe/angled-line'; // TODO calculate the bearing target for 2d and 3d and use lineOnGlobeProgram
|
|
7
7
|
import { mapGetOrThrow } from "../util/check/get";
|
|
@@ -41,10 +41,19 @@ export default class Plugin {
|
|
|
41
41
|
*
|
|
42
42
|
* @param {*} id
|
|
43
43
|
* @param {Map<[K ,{writer:ContextTextWriter, coordsAdaptor, textAdaptor}]} textContextInjectionMap import { ContextTextWriter } from '@pirireis/webglobeplugins/write-text/context-text';
|
|
44
|
-
*
|
|
44
|
+
*
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
-
constructor(id,
|
|
47
|
+
constructor(id,
|
|
48
|
+
{
|
|
49
|
+
opacity = 1,
|
|
50
|
+
textContextInjectionMap = new Map(),
|
|
51
|
+
drawVRM = true,
|
|
52
|
+
drawBearingLine = true,
|
|
53
|
+
drawAngleRing = true,
|
|
54
|
+
drawText = true,
|
|
55
|
+
circleFlatEdgeCount = flatCircleEdgeCount - 2
|
|
56
|
+
} = {}) {
|
|
48
57
|
this.id = id;
|
|
49
58
|
this._opacity = opacity;
|
|
50
59
|
this.bufferOrchestrator = new BufferOrchestrator({ capacity: 10 });
|
|
@@ -53,7 +62,11 @@ export default class Plugin {
|
|
|
53
62
|
this.drawVRM = drawVRM;
|
|
54
63
|
this.drawBearingLine = drawBearingLine;
|
|
55
64
|
this.drawAngleRing = drawAngleRing;
|
|
65
|
+
|
|
66
|
+
|
|
56
67
|
this.drawText = drawText;
|
|
68
|
+
|
|
69
|
+
this.circleFlatEdgeCount = circleFlatEdgeCount + 2;//circleFlatEdgeCount;
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
setDoDrawVRM(bool) {
|
|
@@ -122,6 +135,7 @@ export default class Plugin {
|
|
|
122
135
|
this.circle3DProgram = Circle3DCache.get(globe);
|
|
123
136
|
// this.angleTextContext = new ContextTextWriter(globe);
|
|
124
137
|
// this.distanceTextContext = new ContextTextWriter(globe);
|
|
138
|
+
const circleFlatEdgeCount = this.circleFlatEdgeCount
|
|
125
139
|
{
|
|
126
140
|
// createBuffers
|
|
127
141
|
const bufferType = "DYNAMIC_DRAW";
|
|
@@ -134,7 +148,7 @@ export default class Plugin {
|
|
|
134
148
|
'adaptor': (item) => new Float32Array(globe.api_GetMercator2DPoint(item.long, item.lat)),
|
|
135
149
|
}],
|
|
136
150
|
["centerCoords2dflat", {
|
|
137
|
-
'bufferManager': new BufferManager(gl,
|
|
151
|
+
'bufferManager': new BufferManager(gl, circleFlatEdgeCount * 2, { bufferType, initialCapacity }),
|
|
138
152
|
'adaptor': (item) => item.centerCoords2dflat,
|
|
139
153
|
}],
|
|
140
154
|
["centerCoords3d", {
|
|
@@ -216,21 +230,21 @@ export default class Plugin {
|
|
|
216
230
|
|
|
217
231
|
// normal circle
|
|
218
232
|
["circleDashAngle", {
|
|
219
|
-
'bufferManager': new BufferManager(gl,
|
|
233
|
+
'bufferManager': new BufferManager(gl, circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
220
234
|
'adaptor': (item) => new Float32Array(item.rgba),
|
|
221
235
|
}],
|
|
222
236
|
// CIRCLE Mercator
|
|
223
237
|
["rgbaMercator", {
|
|
224
|
-
'bufferManager': new BufferManager(gl, 4 *
|
|
225
|
-
'adaptor': (item) => populateFloat32Array.fillWithListData(
|
|
238
|
+
'bufferManager': new BufferManager(gl, 4 * circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
239
|
+
'adaptor': (item) => populateFloat32Array.fillWithListData(circleFlatEdgeCount, item.rgba),
|
|
226
240
|
}],
|
|
227
241
|
["circleDashAngleMercator", {
|
|
228
|
-
'bufferManager': new BufferManager(gl,
|
|
229
|
-
'adaptor': (item) => populateFloat32Array.fillFloat32Array(
|
|
242
|
+
'bufferManager': new BufferManager(gl, circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
243
|
+
'adaptor': (item) => populateFloat32Array.fillFloat32Array(circleFlatEdgeCount, item.circleDashAngle / 360),
|
|
230
244
|
}],
|
|
231
245
|
["dashOpacityMercator", {
|
|
232
|
-
'bufferManager': new BufferManager(gl,
|
|
233
|
-
'adaptor': (item) => populateFloat32Array.fillFloat32Array(
|
|
246
|
+
'bufferManager': new BufferManager(gl, circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
247
|
+
'adaptor': (item) => populateFloat32Array.fillFloat32Array(circleFlatEdgeCount, item.dashOpacity),
|
|
234
248
|
}],
|
|
235
249
|
|
|
236
250
|
]
|
|
@@ -286,7 +300,7 @@ export default class Plugin {
|
|
|
286
300
|
if (is3D) {
|
|
287
301
|
this.circle3DProgram.draw(this.circle3DVao, this.bufferOrchestrator.length, this._opacity);
|
|
288
302
|
} else {
|
|
289
|
-
this.circleProgram.draw(this.circleVao, this.bufferOrchestrator.length, this._opacity);
|
|
303
|
+
this.circleProgram.draw(this.circleVao, this.bufferOrchestrator.length, this.circleFlatEdgeCount, this._opacity);
|
|
290
304
|
}
|
|
291
305
|
}
|
|
292
306
|
if (this.drawText) {
|
|
@@ -436,22 +450,7 @@ export default class Plugin {
|
|
|
436
450
|
tailAngle3d -= Math.PI * 2;
|
|
437
451
|
}
|
|
438
452
|
|
|
439
|
-
const centerCoords2dflat =
|
|
440
|
-
const radius2d = globe.Math.GetDist2D(item.long, item.lat, item.endLong, item.endLat);
|
|
441
|
-
const pointsLongLat = globe.Math.GetEllipseGeo(
|
|
442
|
-
item.long,
|
|
443
|
-
item.lat,
|
|
444
|
-
radius2d,
|
|
445
|
-
radius2d,
|
|
446
|
-
startAngleOfCircle,
|
|
447
|
-
360 / (flatCircleEdgeCount - 2), // 1 for return to start point, 1 for cutting circles
|
|
448
|
-
);
|
|
449
|
-
|
|
450
|
-
for (let i = 1; i < flatCircleEdgeCount; i++) {
|
|
451
|
-
const { long: lg, lat: lt } = pointsLongLat[i - 1];
|
|
452
|
-
centerCoords2dflat.set(globe.api_GetMercator2DPoint(lg, lt), i * 2);
|
|
453
|
-
}
|
|
454
|
-
|
|
453
|
+
const centerCoords2dflat = centerCoords2dflatDataCreator(globe, item.long, item.lat, item.endLong, item.endLat, { startAngleOfCircle, edgeCount: this.circleFlatEdgeCount });
|
|
455
454
|
return {
|
|
456
455
|
key: item.key,
|
|
457
456
|
lat: item.lat,
|
|
@@ -473,11 +472,13 @@ export default class Plugin {
|
|
|
473
472
|
|
|
474
473
|
|
|
475
474
|
__fixPartialProperties(propertyIDs) {
|
|
476
|
-
const s = new Set("rgba", "dashOpacity", "circleDashAngle");
|
|
475
|
+
const s = new Set(["rgba", "dashOpacity", "circleDashAngle"]);
|
|
477
476
|
const result = []
|
|
478
477
|
for (const item of propertyIDs) {
|
|
479
478
|
result.push(item);
|
|
479
|
+
console.log(item + " is processing")
|
|
480
480
|
if (s.has(item)) {
|
|
481
|
+
console.log(item + "Mercator is added")
|
|
481
482
|
result.push(item + "Mercator");
|
|
482
483
|
}
|
|
483
484
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LineOnGlobeCache } from '../programs/line-on-globe/naive-accurate';
|
|
2
|
-
import { CircleCache, EDGE_COUNT as
|
|
2
|
+
import { CircleCache, EDGE_COUNT as flatCircleEdgeCount, centerCoords2dflatDataCreator } from '../programs/line-on-globe/circle-accurate-flat';
|
|
3
3
|
import { CircleCache as Circle3DCache } from '../programs/line-on-globe/circle-accurate-3d';
|
|
4
4
|
import { LineToTheOriginCache } from "../programs/line-on-globe/to-the-origin"
|
|
5
5
|
import { BufferOrchestrator, BufferManager } from "../util/account";
|
|
@@ -47,7 +47,8 @@ export class CircleLineChainPlugin {
|
|
|
47
47
|
constructor(id, {
|
|
48
48
|
drawCircleOn = true,
|
|
49
49
|
textContextWriterInjectionMap = new Map(),
|
|
50
|
-
textDataPreAdaptor = null
|
|
50
|
+
textDataPreAdaptor = null,
|
|
51
|
+
circleFlatEdgeCount = flatCircleEdgeCount - 2
|
|
51
52
|
} = {}) {
|
|
52
53
|
this.id = id;
|
|
53
54
|
this._checkTextContextWriterInjectionMap(textContextWriterInjectionMap);
|
|
@@ -58,6 +59,7 @@ export class CircleLineChainPlugin {
|
|
|
58
59
|
this.bufferOrchestrator = new BufferOrchestrator({ capacity: 10 });
|
|
59
60
|
this._drawCircleOn = drawCircleOn;
|
|
60
61
|
this._textDataPreAdaptor = textDataPreAdaptor;
|
|
62
|
+
this._circleFlatEdgeCount = circleFlatEdgeCount + 2;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
// init
|
|
@@ -82,6 +84,7 @@ export class CircleLineChainPlugin {
|
|
|
82
84
|
this.circle3DProgram = Circle3DCache.get(globe);
|
|
83
85
|
|
|
84
86
|
this.lineToTheOriginProgram = LineToTheOriginCache.get(globe);
|
|
87
|
+
const _circleFlatEdgeCount = this._circleFlatEdgeCount;
|
|
85
88
|
{
|
|
86
89
|
// createBuffers
|
|
87
90
|
const bufferType = "DYNAMIC_DRAW";
|
|
@@ -138,29 +141,27 @@ export class CircleLineChainPlugin {
|
|
|
138
141
|
return new Float32Array(item.chainProperties.rgba);
|
|
139
142
|
}
|
|
140
143
|
}],
|
|
141
|
-
|
|
142
|
-
|
|
143
144
|
// Mercator buffers
|
|
144
145
|
["circleDashAngleMercator", {
|
|
145
|
-
'bufferManager': new BufferManager(gl, 1 *
|
|
146
|
+
'bufferManager': new BufferManager(gl, 1 * _circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
146
147
|
'adaptor': (item) => {
|
|
147
148
|
if (item.circleProperties?.circleDashAngle) return new Float32Array([item.circleProperties.circleDashAngle / 360]);
|
|
148
|
-
return new populateFloat32Array.fillFloat32Array(
|
|
149
|
+
return new populateFloat32Array.fillFloat32Array(_circleFlatEdgeCount, item.chainProperties.circleDashAngle / 360);
|
|
149
150
|
}
|
|
150
151
|
}],
|
|
151
|
-
["rgbaCircleMercator", {
|
|
152
|
-
"bufferManager": new BufferManager(gl, 4 *
|
|
152
|
+
["rgbaCircleMercator", { // 62
|
|
153
|
+
"bufferManager": new BufferManager(gl, 4 * _circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
153
154
|
"adaptor": (item) => {
|
|
154
|
-
if (item.circleProperties?.rgba) return populateFloat32Array.fillWithListData(
|
|
155
|
-
return populateFloat32Array.fillWithListData(
|
|
155
|
+
if (item.circleProperties?.rgba) return populateFloat32Array.fillWithListData(_circleFlatEdgeCount, item.circleProperties.rgba);
|
|
156
|
+
return populateFloat32Array.fillWithListData(_circleFlatEdgeCount, item.chainProperties.rgba);
|
|
156
157
|
}
|
|
157
158
|
}],
|
|
158
159
|
["dashOpacityMercator", {
|
|
159
|
-
'bufferManager': new BufferManager(gl, 1 *
|
|
160
|
-
'adaptor': (item) => populateFloat32Array.fillFloat32Array(
|
|
160
|
+
'bufferManager': new BufferManager(gl, 1 * _circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
161
|
+
'adaptor': (item) => populateFloat32Array.fillFloat32Array(_circleFlatEdgeCount, item.chainProperties.dashOpacity)
|
|
161
162
|
}],
|
|
162
163
|
["centerCoords2dMercator", {
|
|
163
|
-
'bufferManager': new BufferManager(gl, 2 *
|
|
164
|
+
'bufferManager': new BufferManager(gl, 2 * _circleFlatEdgeCount, { bufferType, initialCapacity }),
|
|
164
165
|
'adaptor': (item) => item.centerCoords2dflat,
|
|
165
166
|
}],
|
|
166
167
|
]
|
|
@@ -379,7 +380,7 @@ export class CircleLineChainPlugin {
|
|
|
379
380
|
const callback = (v, i, array, chainProperties) => {
|
|
380
381
|
if (i == array.length - 1) return null;
|
|
381
382
|
|
|
382
|
-
const centerCoords2dflat = centerCoords2dflatDataCreator(globe, v.long, v.lat, array[i + 1].long, array[i + 1].lat);
|
|
383
|
+
const centerCoords2dflat = centerCoords2dflatDataCreator(globe, v.long, v.lat, array[i + 1].long, array[i + 1].lat, { edgeCount: this._circleFlatEdgeCount });
|
|
383
384
|
|
|
384
385
|
return {
|
|
385
386
|
chainProperties: chainProperties,
|
|
@@ -442,7 +443,7 @@ export class CircleLineChainPlugin {
|
|
|
442
443
|
if (is3D) {
|
|
443
444
|
this.circle3DProgram.draw(this.circle3DVao, this.bufferOrchestrator.length, this._opacity);
|
|
444
445
|
} else {
|
|
445
|
-
this.circleProgram2d.draw(this.circleVao2d, this.bufferOrchestrator.length, this._opacity);
|
|
446
|
+
this.circleProgram2d.draw(this.circleVao2d, this.bufferOrchestrator.length, this._circleFlatEdgeCount, this._opacity);
|
|
446
447
|
}
|
|
447
448
|
}
|
|
448
449
|
gl.enable(gl.DEPTH_TEST);
|
package/package.json
CHANGED
|
@@ -11,14 +11,17 @@ import {
|
|
|
11
11
|
* Insert the points from the second index and skip 1 point as you placed 361 points
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Plus 1 for returning to the start point. 1 for cutting the circle into pieces.
|
|
16
|
+
*/
|
|
17
|
+
const EDGE_COUNT = 62;
|
|
15
18
|
|
|
16
19
|
const vertexShaderSource = `#version 300 es
|
|
17
20
|
precision highp float;
|
|
18
21
|
${CameraUniformBlockString}
|
|
19
22
|
${mercatorXYToGLPosition}
|
|
20
23
|
|
|
21
|
-
uniform
|
|
24
|
+
uniform int edge_count;
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
in vec2 position2d;
|
|
@@ -32,8 +35,8 @@ out float v_dash_ratio;
|
|
|
32
35
|
out float v_dash_opacity;
|
|
33
36
|
out vec2 v_limp;
|
|
34
37
|
void main() {
|
|
35
|
-
interpolation = float( gl_VertexID %
|
|
36
|
-
if ( gl_VertexID %
|
|
38
|
+
interpolation = float( gl_VertexID % edge_count ) / float(edge_count);
|
|
39
|
+
if ( gl_VertexID % edge_count == 0 ) { return; } // cut on the first point.
|
|
37
40
|
if ( is3D ) {
|
|
38
41
|
return;
|
|
39
42
|
v_limp = vec2(0.0, 0.0);
|
|
@@ -79,11 +82,13 @@ class Logic {
|
|
|
79
82
|
this.gl = globe.gl;
|
|
80
83
|
this._lastOpacity = 1.0;
|
|
81
84
|
this._lastMercatorMode = 0;
|
|
85
|
+
this._lastEdgeCount = EDGE_COUNT;
|
|
82
86
|
this.program = createProgram(this.gl, vertexShaderSource, fragmentShaderSource);
|
|
83
87
|
|
|
84
88
|
const { gl, program } = this;
|
|
85
89
|
this.program.uniforms = {
|
|
86
90
|
opacity: gl.getUniformLocation(program, "opacity"),
|
|
91
|
+
edgeCount: gl.getUniformLocation(program, "edge_count"),
|
|
87
92
|
mercator_calculation_mode: gl.getUniformLocation(program, "mercator_calculation_mode")
|
|
88
93
|
};
|
|
89
94
|
|
|
@@ -91,6 +96,7 @@ class Logic {
|
|
|
91
96
|
const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
|
|
92
97
|
gl.useProgram(program);
|
|
93
98
|
gl.uniform1f(program.uniforms.opacity, 1.0);
|
|
99
|
+
gl.uniform1i(program.uniforms.edgeCount, EDGE_COUNT);
|
|
94
100
|
gl.uniform1i(program.uniforms.mercator_calculation_mode, 0);
|
|
95
101
|
gl.useProgram(currentProgram);
|
|
96
102
|
|
|
@@ -138,16 +144,20 @@ class Logic {
|
|
|
138
144
|
}
|
|
139
145
|
|
|
140
146
|
|
|
141
|
-
draw(vao, length, opacity) {
|
|
147
|
+
draw(vao, length, edgeCount, opacity) {
|
|
142
148
|
const { gl, program, cameraBlockTotem, cameraBindingPoint } = this;
|
|
143
149
|
gl.useProgram(program);
|
|
144
150
|
if (this._lastOpacity !== opacity) {
|
|
145
151
|
gl.uniform1f(program.uniforms.opacity, opacity);
|
|
146
152
|
this._lastOpacity = opacity;
|
|
147
153
|
}
|
|
154
|
+
if (this._lastEdgeCount !== edgeCount) {
|
|
155
|
+
gl.uniform1i(program.uniforms.edgeCount, edgeCount);
|
|
156
|
+
this._lastEdgeCount = edgeCount;
|
|
157
|
+
}
|
|
148
158
|
gl.bindVertexArray(vao);
|
|
149
159
|
cameraBlockTotem.bind(cameraBindingPoint);
|
|
150
|
-
gl.drawArrays(gl.LINE_STRIP, 0, length *
|
|
160
|
+
gl.drawArrays(gl.LINE_STRIP, 0, length * edgeCount)
|
|
151
161
|
// gl.drawArrays(gl.POINTS, 0, length * EDGE_COUNT)
|
|
152
162
|
cameraBlockTotem.unbind(cameraBindingPoint);
|
|
153
163
|
gl.bindVertexArray(null);
|
|
@@ -170,8 +180,8 @@ const CircleCache = Object.freeze({
|
|
|
170
180
|
});
|
|
171
181
|
|
|
172
182
|
|
|
173
|
-
function centerCoords2dflatDataCreator(globe, centerLong, centerLat, targetLong, targetLat, { startAngleOfCircle = null } = {}) {
|
|
174
|
-
const centerCoords2dflat = new Float32Array(
|
|
183
|
+
function centerCoords2dflatDataCreator(globe, centerLong, centerLat, targetLong, targetLat, { startAngleOfCircle = null, edgeCount = EDGE_COUNT } = {}) {
|
|
184
|
+
const centerCoords2dflat = new Float32Array(edgeCount * 2);
|
|
175
185
|
const radius2d = globe.Math.GetDist2D(centerLong, centerLat, targetLong, targetLat);
|
|
176
186
|
let angle;
|
|
177
187
|
if (startAngleOfCircle === null) {
|
|
@@ -185,10 +195,10 @@ function centerCoords2dflatDataCreator(globe, centerLong, centerLat, targetLong,
|
|
|
185
195
|
radius2d,
|
|
186
196
|
radius2d,
|
|
187
197
|
angle,
|
|
188
|
-
360 / (
|
|
198
|
+
360 / (edgeCount - 2), // 1 for return to start point, 1 for cutting circles
|
|
189
199
|
);
|
|
190
200
|
|
|
191
|
-
for (let i = 1; i <
|
|
201
|
+
for (let i = 1; i < edgeCount; i++) {
|
|
192
202
|
const { long: lg, lat: lt } = pointsLongLat[i - 1];
|
|
193
203
|
centerCoords2dflat.set(globe.api_GetMercator2DPoint(lg, lt), i * 2);
|
|
194
204
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createProgram, shaderfunctions } from "../../../util";
|
|
2
|
+
import {
|
|
3
|
+
circleLimpFromLongLatRadCenterMercatorRealDistanceNew_accurate,
|
|
4
|
+
circleLimpFromLongLatRadCenterCartesian3D_accurate_accurate
|
|
5
|
+
} from "../../../util/shaderfunctions/geometrytransformations";
|
|
6
|
+
import CameraUniformBlockTotem, { CameraUniformBlockString } from "../../totems/camerauniformblock";
|
|
7
|
+
import { globeProgramCache, noRegisterGlobeProgramCache } from "../../programcache";
|
|
8
|
+
|
|
9
|
+
const vertexShader = `#version 300 es ` +
|
|
10
|
+
shaderfunctions.PI +
|
|
11
|
+
shaderfunctions.R +
|
|
12
|
+
shaderfunctions.POLE +
|
|
13
|
+
CameraUniformBlockString +
|
|
14
|
+
shaderfunctions.mercatorXYToGLPosition +
|
|
15
|
+
shaderfunctions.longLatRadToMercator +
|
|
16
|
+
shaderfunctions.longLatRadToCartesian3D +
|
|
17
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorCompass +
|
|
18
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorRealDistancePadding +
|
|
19
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorRealDistance + `
|
|
20
|
+
|
|
21
|
+
${circleLimpFromLongLatRadCenterCartesian3D_accurate_accurate}
|
|
22
|
+
|
|
23
|
+
in vec2 center;
|
|
24
|
+
in float radius;
|
|
25
|
+
in float pad_range;
|
|
26
|
+
in vec4 color;
|
|
27
|
+
in float flag;
|
|
28
|
+
|
|
29
|
+
uniform int compass;
|
|
30
|
+
uniform float pad_count;
|
|
31
|
+
|
|
32
|
+
uniform float opacity;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
out vec2 v_limp;
|
|
36
|
+
out vec4 v_color;
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
void main() {
|
|
40
|
+
|
|
41
|
+
float alpha_padding = z_level * z_level / (pad_range/ 100.0 );
|
|
42
|
+
if( flag == 2.0 || flag == 1.0 || radius == 0.0 || alpha_padding < 0.1 || z_level < 3.0 ) return; // 1.0 is hide
|
|
43
|
+
v_color = vec4(color.rgb, color.a * alpha_padding * opacity);
|
|
44
|
+
|
|
45
|
+
gl_PointSize = 2.0;
|
|
46
|
+
|
|
47
|
+
float odd = mod(float(gl_VertexID), 2.0);
|
|
48
|
+
float index = (float(gl_VertexID)- odd ) / 2.0;
|
|
49
|
+
float angle = 3.1415926535897932384626433832795 * 2.0 * (index / pad_count );
|
|
50
|
+
float radius_ = radius - (pad_range * odd);
|
|
51
|
+
|
|
52
|
+
if ( is3D){
|
|
53
|
+
gl_Position = projection * view * vec4(
|
|
54
|
+
circleLimpFromLongLatRadCenterCartesian3D_accurate( center, radius_, angle) - translate, 1.0);
|
|
55
|
+
v_limp = vec2(0.0, 0.0);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
vec2 limp;
|
|
59
|
+
if ( compass == 1 ){
|
|
60
|
+
limp = circleLimpFromLongLatRadCenterMercatorCompass(center , radius_, angle);
|
|
61
|
+
} else {
|
|
62
|
+
// limp = circleLimpFromLongLatRadCenterMercatorRealDistancePadding(center, radius_, angle);
|
|
63
|
+
limp = circleLimpFromLongLatRadCenterMercatorRealDistance(center, radius_, angle);
|
|
64
|
+
}
|
|
65
|
+
v_limp = limp;
|
|
66
|
+
gl_Position = mercatorXYToGLPosition(limp);
|
|
67
|
+
}`;
|
|
68
|
+
|
|
69
|
+
const fragmentShader = `#version 300 es
|
|
70
|
+
precision highp float; `+
|
|
71
|
+
shaderfunctions.POLE + `
|
|
72
|
+
in vec4 v_color;
|
|
73
|
+
in vec2 v_limp;
|
|
74
|
+
out vec4 outColor;
|
|
75
|
+
void main() {
|
|
76
|
+
if ( v_limp.x < -POLE || v_limp.x > POLE || v_limp.y < -POLE || v_limp.y > POLE ){ discard; }
|
|
77
|
+
outColor = v_color;
|
|
78
|
+
}`;
|
|
79
|
+
|
|
80
|
+
class Logic {
|
|
81
|
+
constructor(globe) {
|
|
82
|
+
this.globe = globe;
|
|
83
|
+
this.gl = globe.gl;
|
|
84
|
+
this.program = createProgram(this.gl, vertexShader, fragmentShader);
|
|
85
|
+
{ // bind positions so bufferManager can use them
|
|
86
|
+
this.gl.bindAttribLocation(this.program, 0, "center");
|
|
87
|
+
this.gl.bindAttribLocation(this.program, 1, "radius");
|
|
88
|
+
this.gl.bindAttribLocation(this.program, 2, "pad_range");
|
|
89
|
+
this.gl.bindAttribLocation(this.program, 3, "color");
|
|
90
|
+
this.gl.bindAttribLocation(this.program, 4, "flag");
|
|
91
|
+
}
|
|
92
|
+
this.cameraBlockBindingPoint = 0;
|
|
93
|
+
const cameraBlockIndex = this.gl.getUniformBlockIndex(this.program, "CameraUniformBlock");
|
|
94
|
+
this.gl.uniformBlockBinding(this.program, cameraBlockIndex, this.cameraBlockBindingPoint);
|
|
95
|
+
this.cameraBlockTotem = globeProgramCache.getProgram(globe, CameraUniformBlockTotem);
|
|
96
|
+
this._padCountLocation = this.gl.getUniformLocation(this.program, "pad_count");
|
|
97
|
+
this._opacityLocation = this.gl.getUniformLocation(this.program, "opacity");
|
|
98
|
+
this._compassLocation = this.gl.getUniformLocation(this.program, "compass");
|
|
99
|
+
this._compassMode = 1;
|
|
100
|
+
this._opacity = 1.0;
|
|
101
|
+
this._padCount = 360;
|
|
102
|
+
{
|
|
103
|
+
const currentProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM);
|
|
104
|
+
this.gl.useProgram(this.program);
|
|
105
|
+
this.gl.uniform1i(this._compassLocation, 1);
|
|
106
|
+
this.gl.uniform1f(this._opacityLocation, 1.0);
|
|
107
|
+
this.gl.uniform1f(this._padCountLocation, 360)
|
|
108
|
+
this.gl.useProgram(currentProgram);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
draw(attrBufferManager, padCount, compass, opacity) {
|
|
115
|
+
const { gl, program, _padCountLocation, cameraBlockBindingPoint, cameraBlockTotem, _compassLocation } = this;
|
|
116
|
+
gl.useProgram(program);
|
|
117
|
+
attrBufferManager.bindPaddingVAO();
|
|
118
|
+
cameraBlockTotem.bind(cameraBlockBindingPoint);
|
|
119
|
+
// draw instanced
|
|
120
|
+
if (padCount !== this._padCount) {
|
|
121
|
+
this._padCount = padCount;
|
|
122
|
+
// console.log("padCount", padCount);
|
|
123
|
+
gl.uniform1f(_padCountLocation, padCount);
|
|
124
|
+
}
|
|
125
|
+
if (compass !== this._compassMode) {
|
|
126
|
+
// console.log("compass", compass);
|
|
127
|
+
gl.uniform1i(_compassLocation, compass);
|
|
128
|
+
this._compassMode = compass;
|
|
129
|
+
}
|
|
130
|
+
if (opacity !== this._opacity) {
|
|
131
|
+
// console.log("opacity", opacity);
|
|
132
|
+
this._opacity = opacity;
|
|
133
|
+
gl.uniform1f(this._opacityLocation, opacity);
|
|
134
|
+
}
|
|
135
|
+
gl.drawArraysInstanced(gl.LINES, 0, padCount * 2, attrBufferManager.length);
|
|
136
|
+
gl.bindVertexArray(null);
|
|
137
|
+
cameraBlockTotem.unbind(cameraBlockBindingPoint);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
free() {
|
|
141
|
+
this.gl.deleteProgram(this.program);
|
|
142
|
+
globeProgramCache.releaseProgram(this.globe, CameraUniformBlockTotem);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
export const PaddingProgramCache = Object.freeze({
|
|
149
|
+
getProgram: (globe) => { return noRegisterGlobeProgramCache.getProgram(globe, Logic) },
|
|
150
|
+
releaseProgram: (globe) => { noRegisterGlobeProgramCache.releaseProgram(globe, Logic) }
|
|
151
|
+
})
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createProgram, shaderfunctions } from "../../../util";
|
|
2
|
+
import {
|
|
3
|
+
circleLimpFromLongLatRadCenterMercatorRealDistanceNew_accurate,
|
|
4
|
+
circleLimpFromLongLatRadCenterCartesian3D_accurate_accurate
|
|
5
|
+
} from "../../../util/shaderfunctions/geometrytransformations";
|
|
6
|
+
import CameraUniformBlockTotem, { CameraUniformBlockString } from "../../totems/camerauniformblock";
|
|
7
|
+
import { globeProgramCache, noRegisterGlobeProgramCache } from "../../programcache";
|
|
8
|
+
|
|
9
|
+
const vertexShader = `#version 300 es ` +
|
|
10
|
+
shaderfunctions.PI +
|
|
11
|
+
shaderfunctions.R +
|
|
12
|
+
shaderfunctions.POLE +
|
|
13
|
+
CameraUniformBlockString +
|
|
14
|
+
shaderfunctions.mercatorXYToGLPosition +
|
|
15
|
+
shaderfunctions.longLatRadToMercator +
|
|
16
|
+
shaderfunctions.longLatRadToCartesian3D +
|
|
17
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorCompass +
|
|
18
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorRealDistancePadding +
|
|
19
|
+
shaderfunctions.circleLimpFromLongLatRadCenterMercatorRealDistance + `
|
|
20
|
+
|
|
21
|
+
${circleLimpFromLongLatRadCenterCartesian3D_accurate_accurate}
|
|
22
|
+
|
|
23
|
+
in vec2 center;
|
|
24
|
+
in float radius;
|
|
25
|
+
in float pad_range;
|
|
26
|
+
in vec4 color;
|
|
27
|
+
in float flag;
|
|
28
|
+
|
|
29
|
+
uniform int compass;
|
|
30
|
+
uniform float pad_count;
|
|
31
|
+
|
|
32
|
+
uniform float opacity;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
out vec2 v_limp;
|
|
36
|
+
out vec4 v_color;
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
void main() {
|
|
40
|
+
|
|
41
|
+
float alpha_padding = z_level * z_level / (pad_range/ 100.0 );
|
|
42
|
+
if( flag == 2.0 || flag == 1.0 || radius == 0.0 || alpha_padding < 0.1 || z_level < 3.0 ) return; // 1.0 is hide
|
|
43
|
+
v_color = vec4(color.rgb, color.a * alpha_padding * opacity);
|
|
44
|
+
|
|
45
|
+
gl_PointSize = 2.0;
|
|
46
|
+
|
|
47
|
+
float odd = mod(float(gl_VertexID), 2.0);
|
|
48
|
+
float index = (float(gl_VertexID)- odd ) / 2.0;
|
|
49
|
+
float angle = 3.1415926535897932384626433832795 * 2.0 * (index / pad_count );
|
|
50
|
+
float radius_ = radius - (pad_range * odd);
|
|
51
|
+
|
|
52
|
+
if ( is3D){
|
|
53
|
+
gl_Position = projection * view * vec4(
|
|
54
|
+
circleLimpFromLongLatRadCenterCartesian3D_accurate( center, radius_, angle) - translate, 1.0);
|
|
55
|
+
v_limp = vec2(0.0, 0.0);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
vec2 limp;
|
|
59
|
+
if ( compass == 1 ){
|
|
60
|
+
limp = circleLimpFromLongLatRadCenterMercatorCompass(center , radius_, angle);
|
|
61
|
+
} else {
|
|
62
|
+
// limp = circleLimpFromLongLatRadCenterMercatorRealDistancePadding(center, radius_, angle);
|
|
63
|
+
limp = circleLimpFromLongLatRadCenterMercatorRealDistance(center, radius_, angle);
|
|
64
|
+
}
|
|
65
|
+
v_limp = limp;
|
|
66
|
+
gl_Position = mercatorXYToGLPosition(limp);
|
|
67
|
+
}`;
|
|
68
|
+
|
|
69
|
+
const fragmentShader = `#version 300 es
|
|
70
|
+
precision highp float; `+
|
|
71
|
+
shaderfunctions.POLE + `
|
|
72
|
+
in vec4 v_color;
|
|
73
|
+
in vec2 v_limp;
|
|
74
|
+
out vec4 outColor;
|
|
75
|
+
void main() {
|
|
76
|
+
if ( v_limp.x < -POLE || v_limp.x > POLE || v_limp.y < -POLE || v_limp.y > POLE ){ discard; }
|
|
77
|
+
outColor = v_color;
|
|
78
|
+
}`;
|
|
79
|
+
|
|
80
|
+
class Logic {
|
|
81
|
+
constructor(globe) {
|
|
82
|
+
this.globe = globe;
|
|
83
|
+
this.gl = globe.gl;
|
|
84
|
+
this.program = createProgram(this.gl, vertexShader, fragmentShader);
|
|
85
|
+
{ // bind positions so bufferManager can use them
|
|
86
|
+
this.gl.bindAttribLocation(this.program, 0, "center");
|
|
87
|
+
this.gl.bindAttribLocation(this.program, 1, "radius");
|
|
88
|
+
this.gl.bindAttribLocation(this.program, 2, "pad_range");
|
|
89
|
+
this.gl.bindAttribLocation(this.program, 3, "color");
|
|
90
|
+
this.gl.bindAttribLocation(this.program, 4, "flag");
|
|
91
|
+
}
|
|
92
|
+
this.cameraBlockBindingPoint = 0;
|
|
93
|
+
const cameraBlockIndex = this.gl.getUniformBlockIndex(this.program, "CameraUniformBlock");
|
|
94
|
+
this.gl.uniformBlockBinding(this.program, cameraBlockIndex, this.cameraBlockBindingPoint);
|
|
95
|
+
this.cameraBlockTotem = globeProgramCache.getProgram(globe, CameraUniformBlockTotem);
|
|
96
|
+
this._padCountLocation = this.gl.getUniformLocation(this.program, "pad_count");
|
|
97
|
+
this._opacityLocation = this.gl.getUniformLocation(this.program, "opacity");
|
|
98
|
+
this._compassLocation = this.gl.getUniformLocation(this.program, "compass");
|
|
99
|
+
this._compassMode = 1;
|
|
100
|
+
this._opacity = 1.0;
|
|
101
|
+
this._padCount = 360;
|
|
102
|
+
{
|
|
103
|
+
const currentProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM);
|
|
104
|
+
this.gl.useProgram(this.program);
|
|
105
|
+
this.gl.uniform1i(this._compassLocation, 1);
|
|
106
|
+
this.gl.uniform1f(this._opacityLocation, 1.0);
|
|
107
|
+
this.gl.uniform1f(this._padCountLocation, 360)
|
|
108
|
+
this.gl.useProgram(currentProgram);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
draw(attrBufferManager, padCount, compass, opacity) {
|
|
115
|
+
const { gl, program, _padCountLocation, cameraBlockBindingPoint, cameraBlockTotem, _compassLocation } = this;
|
|
116
|
+
gl.useProgram(program);
|
|
117
|
+
attrBufferManager.bindPaddingVAO();
|
|
118
|
+
cameraBlockTotem.bind(cameraBlockBindingPoint);
|
|
119
|
+
// draw instanced
|
|
120
|
+
if (padCount !== this._padCount) {
|
|
121
|
+
this._padCount = padCount;
|
|
122
|
+
// console.log("padCount", padCount);
|
|
123
|
+
gl.uniform1f(_padCountLocation, padCount);
|
|
124
|
+
}
|
|
125
|
+
if (compass !== this._compassMode) {
|
|
126
|
+
// console.log("compass", compass);
|
|
127
|
+
gl.uniform1i(_compassLocation, compass);
|
|
128
|
+
this._compassMode = compass;
|
|
129
|
+
}
|
|
130
|
+
if (opacity !== this._opacity) {
|
|
131
|
+
// console.log("opacity", opacity);
|
|
132
|
+
this._opacity = opacity;
|
|
133
|
+
gl.uniform1f(this._opacityLocation, opacity);
|
|
134
|
+
}
|
|
135
|
+
gl.drawArraysInstanced(gl.LINES, 0, padCount * 2, attrBufferManager.length);
|
|
136
|
+
gl.bindVertexArray(null);
|
|
137
|
+
cameraBlockTotem.unbind(cameraBlockBindingPoint);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
free() {
|
|
141
|
+
this.gl.deleteProgram(this.program);
|
|
142
|
+
globeProgramCache.releaseProgram(this.globe, CameraUniformBlockTotem);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
export const PaddingProgramCache = Object.freeze({
|
|
149
|
+
getProgram: (globe) => { return noRegisterGlobeProgramCache.getProgram(globe, Logic) },
|
|
150
|
+
releaseProgram: (globe) => { noRegisterGlobeProgramCache.releaseProgram(globe, Logic) }
|
|
151
|
+
})
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { rings } from "../programs";
|
|
2
|
+
import { COMPASS_MODES } from "./enum";
|
|
3
|
+
import { PaddingFreeAngleCache } from "../programs/rings/distancering";
|
|
4
|
+
|
|
5
|
+
import RangeRingAngleText from "./rangeringangletext";
|
|
6
|
+
const { circleProgramCache, PaddingProgramCache, CirclePaddySharedBuffer } = rings;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef RangeRingData
|
|
10
|
+
* @property {number} centerX
|
|
11
|
+
* @property {number} centerY
|
|
12
|
+
* @property {Array<Ring>} rings
|
|
13
|
+
*
|
|
14
|
+
* @typedef Ring
|
|
15
|
+
* @property {number} radius
|
|
16
|
+
* @property {number} padding
|
|
17
|
+
* @property {[number, number, number]} color
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export default class {
|
|
24
|
+
|
|
25
|
+
constructor(id, { oneDegreePadding = true, compass = COMPASS_MODES.REAL, showNumbers = true, numbersStyle = null, opacity = 1 } = {}) {
|
|
26
|
+
this.id = id;
|
|
27
|
+
this.compass = compass;
|
|
28
|
+
this._showNumbers = showNumbers;
|
|
29
|
+
this._numbersStyle = numbersStyle;
|
|
30
|
+
this._opacity = opacity;
|
|
31
|
+
this.circleEdgeCount = 360;
|
|
32
|
+
this._onedegreepaddingOn = oneDegreePadding;
|
|
33
|
+
this.bufferManager = null;
|
|
34
|
+
|
|
35
|
+
this._deleteCounter = 0;
|
|
36
|
+
this._deleteThreshold = 10;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
setOneDegreePaddingOn(oneDegreePadding) {
|
|
41
|
+
this._onedegreepaddingOn = oneDegreePadding;
|
|
42
|
+
this.globe.DrawRender();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
init(globe, gl) {
|
|
46
|
+
this.gl = gl;
|
|
47
|
+
this.globe = globe;
|
|
48
|
+
this.circleFlatProgram = circleProgramCache.getProgram(globe);
|
|
49
|
+
this.paddyFlatProgram = PaddingProgramCache.getProgram(globe);
|
|
50
|
+
this.paddingFreeAngleProgram = PaddingFreeAngleCache.getProgram(globe);
|
|
51
|
+
if (this._showNumbers) {
|
|
52
|
+
this.textPlugin = new RangeRingAngleText(globe, this.id + "text", { flatCompassMode: this.compass, style: this._numbersStyle, opacity: this._opacity });
|
|
53
|
+
delete this._numbersStyle;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// TODO: Add text free
|
|
58
|
+
free() {
|
|
59
|
+
|
|
60
|
+
this.circleProgramCache?.releaseProgram(this.globe);
|
|
61
|
+
this.PaddingProgramCache?.releaseProgram(this.globe);
|
|
62
|
+
this.PaddingFreeAngleCache?.releaseProgram(this.globe);
|
|
63
|
+
this.gl.deleteVertexArray(this.bufferManager?.vao);
|
|
64
|
+
this.gl.deleteVertexArray(this.paddingBufferManager?.vao);
|
|
65
|
+
this.paddingBufferManager?.free();
|
|
66
|
+
this.bufferManager?.free();
|
|
67
|
+
this.textPlugin?.free();
|
|
68
|
+
this.circleFlatProgram = null;
|
|
69
|
+
this.paddyFlatProgram = null;
|
|
70
|
+
this.bufferManager = null;
|
|
71
|
+
this.paddingBufferManager = null;
|
|
72
|
+
this.textPlugin = null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
setOpacity(opacity) {
|
|
77
|
+
this._opacity = opacity;
|
|
78
|
+
this.textPlugin?.setOpacity(opacity); // TODO impolement this
|
|
79
|
+
this.globe.DrawRender();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setGeometry() {
|
|
83
|
+
this.textPlugin?.setGeometry();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
draw3D() {
|
|
88
|
+
const { circleFlatProgram, paddyFlatProgram, paddingFreeAngleProgram, bufferManager, compass, gl, circleEdgeCount, paddingBufferManager, _opacity } = this;
|
|
89
|
+
if (this.bufferManager !== null && bufferManager.length > 0) {
|
|
90
|
+
gl.disable(gl.DEPTH_TEST);
|
|
91
|
+
circleFlatProgram.draw(bufferManager, compass, circleEdgeCount, _opacity);
|
|
92
|
+
if (this._onedegreepaddingOn) paddyFlatProgram.draw(bufferManager, 360, compass, _opacity);
|
|
93
|
+
paddingFreeAngleProgram.draw(paddingBufferManager, compass, _opacity);
|
|
94
|
+
gl.enable(gl.DEPTH_TEST);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {RangeRingData} rangeRingData
|
|
102
|
+
* 0 compass limps
|
|
103
|
+
* other real distance limp
|
|
104
|
+
*/
|
|
105
|
+
setCampass(compass) {
|
|
106
|
+
this.compass = compass;
|
|
107
|
+
this.textPlugin?.setCompass(compass);
|
|
108
|
+
this.globe.DrawRender();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
initilizeBufferManager(initialRingCapacity, bufferDrawType) {
|
|
112
|
+
const { gl, globe } = this
|
|
113
|
+
this.bufferDrawType = bufferDrawType;
|
|
114
|
+
this.bufferManager = new CirclePaddySharedBuffer(gl, globe, { bufferType: bufferDrawType, initialRingCapacity: initialRingCapacity });
|
|
115
|
+
this.paddingBufferManager = this.paddingFreeAngleProgram.createBuffer({ bufferType: bufferDrawType, initialRingCapacity });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @typedef {Array<{ringID, radius, paddingRange}>} rings
|
|
121
|
+
* @param {Array<centerID:string, x:number, y:number, stepAngle:number, rgba:[4 numbers], rings:rings} items
|
|
122
|
+
*/
|
|
123
|
+
insertBulk(items) {
|
|
124
|
+
const insertData = ringItemsToCircleBufferInsertDataAdaptor(items);
|
|
125
|
+
|
|
126
|
+
this.bufferManager.insertBulk(insertData);
|
|
127
|
+
for (const item of items) {
|
|
128
|
+
item.paddingAngles = angleToPaddingAngles(item.stepAngle, 0);
|
|
129
|
+
}
|
|
130
|
+
this.paddingBufferManager.insertBulk(items);
|
|
131
|
+
this.textPlugin?.insertBulk(items);
|
|
132
|
+
this.globe.DrawRender();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
*
|
|
138
|
+
* @param {Array<{centerID, x, y}>} items
|
|
139
|
+
*/
|
|
140
|
+
updateCentersXY(items) {
|
|
141
|
+
this.bufferManager.updateCentersXY(items);
|
|
142
|
+
this.paddingBufferManager.updateCentersXY(items);
|
|
143
|
+
this.textPlugin?.updateCentersXY(items);
|
|
144
|
+
this.globe.DrawRender();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @param {Array<{centerID, rgba:[4 numbers]}>} centerColors
|
|
150
|
+
*/
|
|
151
|
+
updateCentersColor(centerColors) {
|
|
152
|
+
this.bufferManager.updateCentersColor(centerColors);
|
|
153
|
+
this.paddingBufferManager.updateCentersColor(centerColors);
|
|
154
|
+
this.globe.DrawRender();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {Array<{centerID}>} centerIds
|
|
160
|
+
*/
|
|
161
|
+
removeCenters(centerIds) {
|
|
162
|
+
this.bufferManager.removeCenters(centerIds);
|
|
163
|
+
this.paddingBufferManager.removeCenters(centerIds);
|
|
164
|
+
this.textPlugin?.removeCenters(centerIds);
|
|
165
|
+
this._deleteCounter += centerIds.length;
|
|
166
|
+
if (this._deleteCounter > this._deleteThreshold) {
|
|
167
|
+
// this is naive since we are not checking the actual deletion
|
|
168
|
+
// but it works
|
|
169
|
+
this._deleteCounter = 0;
|
|
170
|
+
this.bufferManager.defrag();
|
|
171
|
+
this.paddingBufferManager.defrag();
|
|
172
|
+
}
|
|
173
|
+
this.globe.DrawRender();
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
* @param {Array<{centerID, hide, textHide}>} centerHides
|
|
180
|
+
*/
|
|
181
|
+
updateCentersHide(centerHides) {
|
|
182
|
+
this.bufferManager.updateCentersHide(centerHides);
|
|
183
|
+
this.paddingBufferManager.updateCentersHide(centerHides);
|
|
184
|
+
this.textPlugin?.updateCentersHide(centerHides);
|
|
185
|
+
this.globe.DrawRender();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
const ringItemsToCircleBufferInsertDataAdaptor = (ringItems) => {
|
|
193
|
+
|
|
194
|
+
const result = [];
|
|
195
|
+
for (const { centerID, x, y, rgba, rings, hide = 0, textHide = 0 } of ringItems) {
|
|
196
|
+
const resultRings = [];
|
|
197
|
+
for (const { ringID, radius, padding } of rings) {
|
|
198
|
+
resultRings.push({
|
|
199
|
+
ringID,
|
|
200
|
+
radius,
|
|
201
|
+
padding: padding / 5,
|
|
202
|
+
rgba,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
result.push({
|
|
207
|
+
centerID,
|
|
208
|
+
x,
|
|
209
|
+
y,
|
|
210
|
+
rings: resultRings,
|
|
211
|
+
hide,
|
|
212
|
+
textHide
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const angleToPaddingAngles = (gapDegree, offsetDegree = 0) => Array.from({ length: Math.ceil(360 / gapDegree) }, (_, i) => (i * gapDegree + offsetDegree) * Math.PI / 180);
|
|
219
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re implementation of rangering plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Circlelari cizen programlar
|
|
8
|
+
* Circlelari cizen bufferlarin muhasevesi.
|
|
9
|
+
*
|
|
10
|
+
* 1 derecelikler çok masraflı.
|
|
11
|
+
* bir dereceklikler için ayrı buffer orchastrator oluşturulmalı.
|
|
12
|
+
*
|
|
13
|
+
*
|
|
14
|
+
* A Range Ring {
|
|
15
|
+
* rings: [ ring, ]
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef RangeRingData
|
|
22
|
+
* @property {number} centerX
|
|
23
|
+
* @property {number} centerY
|
|
24
|
+
* @property {Array<Ring>} rings
|
|
25
|
+
*
|
|
26
|
+
* @typedef Ring
|
|
27
|
+
* @property {number} radius
|
|
28
|
+
* @property {number} padding
|
|
29
|
+
* @property {[number, number, number]} color
|
|
30
|
+
*
|
|
31
|
+
*
|
|
32
|
+
* @method setOpacity
|
|
33
|
+
* @method insertBulk
|
|
34
|
+
* @method updateCentersXY
|
|
35
|
+
* @method updateCentersColor
|
|
36
|
+
* @method removeCenters
|
|
37
|
+
* @method updateCentersHide
|
|
38
|
+
*
|
|
39
|
+
* @method setOneDegreePaddingOn // performance consuming, might be removed
|
|
40
|
+
* @method setCompass // removed
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
File without changes
|
|
@@ -29,79 +29,6 @@
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* Scratchpad
|
|
34
|
-
*
|
|
35
|
-
* plugin insertBulk(items){
|
|
36
|
-
* this.offsetManager.autoExtendBuffers(items.length);
|
|
37
|
-
* this.offsetManager.assignOffsets(items); // read item.keys and assign offsets to them.
|
|
38
|
-
* this.attrib1BufferManager.insertBulk(items.map(item => this.attrib1Block(item)), );
|
|
39
|
-
* this.attrib2BufferManager.insertBulk();
|
|
40
|
-
* if (this.attrib3isInNeed) this.attrib3BufferManager.insertBulk(items);
|
|
41
|
-
* this.globe.DrawRender();
|
|
42
|
-
* }
|
|
43
|
-
*
|
|
44
|
-
* useTheCaseThatRequiresAttrib3(){
|
|
45
|
-
* // generate items from other buffers if possible.
|
|
46
|
-
* }
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* assignOffsets(items){
|
|
50
|
-
* for (const item of items){
|
|
51
|
-
* const offset = this.offsetManager.getOffset(item.key) || this.offsetManager.nextOffset();
|
|
52
|
-
* item.__offset__ = offset;
|
|
53
|
-
*
|
|
54
|
-
* allBuffers = [attrib1BufferManager, attrib2BufferManager, attrib3BufferManager]
|
|
55
|
-
* // // not single responsibility ..
|
|
56
|
-
* defrag(allBuffers){
|
|
57
|
-
* for (const bufferManager of allBuffers){
|
|
58
|
-
* bufferManager.defrag(this.offsetManager.offsetMap);
|
|
59
|
-
* }
|
|
60
|
-
* this.offsetManager._defrag();
|
|
61
|
-
* }
|
|
62
|
-
*
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
*
|
|
68
|
-
* attrib1BufferManager.insertBulk( items) {
|
|
69
|
-
* gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
70
|
-
* for (const item of items) {
|
|
71
|
-
* const block = this.itemToBlock(item); // this changes based on inserted data structure and expected block structure.
|
|
72
|
-
* gl.bufferSubData(gl.ARRAY_BUFFER, item.__offset__, block);
|
|
73
|
-
* }
|
|
74
|
-
* gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
75
|
-
* }
|
|
76
|
-
*
|
|
77
|
-
* deleteBulk(offsets){
|
|
78
|
-
* gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
79
|
-
* for (const offset of offsets) {
|
|
80
|
-
* gl.bufferSubData(gl.ARRAY_BUFFER, offset, emptyBlock);
|
|
81
|
-
* }
|
|
82
|
-
* gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
83
|
-
* }
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* //
|
|
87
|
-
* defrag(offsetMap){
|
|
88
|
-
* const newArray = new Float32Array(itemCount * itemSize);
|
|
89
|
-
* const bufferData = this._getBufferData();
|
|
90
|
-
* let newOffSet = 0;
|
|
91
|
-
* for (const [key, offSet] of offsetMap) {
|
|
92
|
-
* const bufferOffset = offset;
|
|
93
|
-
* newArray.set(bufferData.slice(bufferOffset, bufferOffset + itemSize), newOffSet);
|
|
94
|
-
newOffset += itemSize * 4;
|
|
95
|
-
}
|
|
96
|
-
*
|
|
97
|
-
* gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
98
|
-
*
|
|
99
|
-
* }
|
|
100
|
-
*
|
|
101
|
-
* ----------------
|
|
102
|
-
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
32
|
const EXTRA_SIZE = 10;
|
|
106
33
|
|
|
107
34
|
export class BufferOrchestrator {
|
|
@@ -137,7 +64,6 @@ export class BufferOrchestrator {
|
|
|
137
64
|
for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
|
|
138
65
|
bufferManager.insertBulk(items.map(adaptor), offsets);
|
|
139
66
|
}
|
|
140
|
-
|
|
141
67
|
}
|
|
142
68
|
|
|
143
69
|
|
|
@@ -155,7 +81,9 @@ export class BufferOrchestrator {
|
|
|
155
81
|
}
|
|
156
82
|
if (bufferKeys) {
|
|
157
83
|
for (const key of bufferKeys) {
|
|
158
|
-
const
|
|
84
|
+
const bufferManagerComp = bufferManagersMap.get(key);
|
|
85
|
+
if (bufferManagerComp === undefined) throw new Error("updateBulk bufferKey does not exist");
|
|
86
|
+
const { bufferManager, adaptor } = bufferManagerComp;
|
|
159
87
|
bufferManager.insertBulk(items.map(adaptor), offsets);
|
|
160
88
|
}
|
|
161
89
|
} else {
|
|
@@ -228,7 +156,8 @@ export class BufferOrchestrator {
|
|
|
228
156
|
}
|
|
229
157
|
}
|
|
230
158
|
this._defrag();
|
|
231
|
-
this._length =
|
|
159
|
+
this._length = offsetMap.size;
|
|
160
|
+
this._capacity = newCapacity;
|
|
232
161
|
this.tombstoneOffsets = [];
|
|
233
162
|
}
|
|
234
163
|
|
|
@@ -1,336 +0,0 @@
|
|
|
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
|
-
|