@pirireis/webglobeplugins 0.6.49-a → 0.7.1
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/Math/angle-calculation.js +4 -2
- package/Math/methods.js +196 -0
- package/index.js +2 -1
- package/package.json +1 -1
- package/point-heat-map/adaptors/timetracksplugin-format-to-this.js +78 -0
- package/point-heat-map/index.js +3 -0
- package/point-heat-map/plugin-webworker.js +166 -0
- package/point-heat-map/plugin.js +134 -0
- package/point-heat-map/point-to-heat-map-flow.js +155 -0
- package/point-heat-map/readme.md +15 -0
- package/programs/data2legend/density-to-legend.js +115 -0
- package/programs/data2legend/point-to-density-texture.js +114 -0
- package/programs/line-on-globe/degree-padding-around-circle-3d.js +4 -4
- package/timetracks/adaptors-line-strip.js +1 -1
- package/timetracks/program-line-strip.js +1 -1
- package/timetracks/program.js +1 -1
- package/timetracks/programpoint-line-strip.js +1 -1
- package/timetracks/programpoint.js +1 -1
- package/timetracks/readme.md +1 -0
- package/util/algorithms/index.js +0 -0
- package/util/algorithms/search-binary.js +26 -0
- package/util/interpolation/index.js +0 -0
- package/util/interpolation/timetrack/index.js +9 -0
- package/util/interpolation/timetrack/timetrack-interpolator.js +89 -0
- package/util/interpolation/timetrack/web-worker-str.js +176 -0
- package/util/interpolation/timetrack/web-worker.js +46 -0
- package/util/programs/draw-texture-on-canvas.js +103 -0
- package/util/programs/texturetoglobe.js +1 -1
- package/util/webglobe/gldefaultstates.js +2 -1
- package/waveparticles/plugin.js +0 -2
- package/wind/index.js +0 -2
- package/wind/plugin.js +1 -1
- package/write-text/context-text3.js +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
function bearingRealAngle(long, lat, endLong, endLat) {
|
|
2
2
|
const rLong = Radians * long;
|
|
3
3
|
const rLat = Radians * lat;
|
|
4
4
|
const rEndLong = Radians * endLong;
|
|
@@ -9,4 +9,6 @@ export function bearingRealAngle(long, lat, endLong, endLat) {
|
|
|
9
9
|
let initialBearing = Math.atan2(x, y) / Radians;
|
|
10
10
|
initialBearing = (initialBearing + 360) % 360;
|
|
11
11
|
return initialBearing;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { bearingRealAngle };
|
package/Math/methods.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
|
|
2
|
+
const WORLD_RADIUS_3D = 6378.137;
|
|
3
|
+
const WORLD_RADIUS_MERCATOR = 6378136.99911;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Array<number>} vec3 [x, y, z]
|
|
7
|
+
* @typedef {Array<number>} vec2 [x, y]
|
|
8
|
+
* @typedef {Array<number>} vec4 [x, y, z, w]
|
|
9
|
+
* @typedef {number} fraction a number between 0 and 1
|
|
10
|
+
* @typedef {Array<number>} wgs84 [long, lat]
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// *********************************************************
|
|
14
|
+
// **************** VECTOR OPERATIONS **********************
|
|
15
|
+
// *********************************************************
|
|
16
|
+
const RADIANS = Math.PI / 180;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {vec3} a
|
|
21
|
+
* @returns {vec3}
|
|
22
|
+
*/
|
|
23
|
+
const normalize3 = (a) => {
|
|
24
|
+
const len = length3(a);
|
|
25
|
+
return [a[0] / len, a[1] / len, a[2] / len];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {vec3} a
|
|
31
|
+
* @param {vec3} b
|
|
32
|
+
* @returns {number}
|
|
33
|
+
*/
|
|
34
|
+
const dot3 = (a, b) => {
|
|
35
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {vec3} a
|
|
41
|
+
* @returns {number}
|
|
42
|
+
*/
|
|
43
|
+
const length3 = (a) => {
|
|
44
|
+
return Math.sqrt(dot3(a, a));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
// *********************************************************
|
|
49
|
+
// **************** TRANSFORMATIONS ************************
|
|
50
|
+
// *********************************************************
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {vec3} cartesian
|
|
54
|
+
* @returns {vec2} long lat in radians
|
|
55
|
+
*/
|
|
56
|
+
const cartesian3dToRadian = (cartesian) => {
|
|
57
|
+
const x = cartesian[0];
|
|
58
|
+
const y = cartesian[1];
|
|
59
|
+
const z = cartesian[2];
|
|
60
|
+
// const length = Math.sqrt(x * x + y * y + z * z);
|
|
61
|
+
const long = Math.atan2(y, x);
|
|
62
|
+
const lat = Math.asin(z)// length);
|
|
63
|
+
return [long, lat];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {vec2} xy long lat in radians
|
|
69
|
+
* @returns {vec2} long lat in mercator meters
|
|
70
|
+
*/
|
|
71
|
+
const radianToMercator = (xy) => {
|
|
72
|
+
return [WORLD_RADIUS_MERCATOR * xy[0], WORLD_RADIUS_MERCATOR * Math.log(Math.tan(Math.PI / 4 + xy[1] / 2))];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {vec2} xy long lat radians
|
|
77
|
+
* @returns {vec3} cartesian
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
const radianToCartesian3d = (xy) => {
|
|
81
|
+
const x = Math.cos(xy[1]) * Math.cos(xy[0]);
|
|
82
|
+
const y = Math.cos(xy[1]) * Math.sin(xy[0]);
|
|
83
|
+
const z = -Math.sin(xy[1]);
|
|
84
|
+
return [x, y, z];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
// *********************************************************
|
|
89
|
+
// ***************** INTERPOLATIONS ************************
|
|
90
|
+
// *********************************************************
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {vec3} normalizedA
|
|
94
|
+
* @param {vec3} normalizedB
|
|
95
|
+
* @param {fraction} ratio
|
|
96
|
+
* @returns {vec3}
|
|
97
|
+
*/
|
|
98
|
+
const sphericalLinearInterpolation_UnitVector = (normalizedA, normalizedB, ratio) => {
|
|
99
|
+
const theta = Math.acos(dot3(normalizedA, normalizedB));
|
|
100
|
+
if (theta < 0.000001) return normalizedA; // CALIBRATE?
|
|
101
|
+
const sinTheta = Math.sin(theta);
|
|
102
|
+
const result = [
|
|
103
|
+
(Math.sin((1.0 - ratio) * theta) * normalizedA[0] + Math.sin(ratio * theta) * normalizedB[0]) / sinTheta,
|
|
104
|
+
(Math.sin((1.0 - ratio) * theta) * normalizedA[1] + Math.sin(ratio * theta) * normalizedB[1]) / sinTheta,
|
|
105
|
+
(Math.sin((1.0 - ratio) * theta) * normalizedA[2] + Math.sin(ratio * theta) * normalizedB[2]) / sinTheta
|
|
106
|
+
];
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {vec3} normalizedA
|
|
113
|
+
* @param {vec3} normalizedB
|
|
114
|
+
* @param {fraction} ratio
|
|
115
|
+
* @returns
|
|
116
|
+
*/
|
|
117
|
+
const sphericalLinearInterpolation_Mercator = (normalizedA, normalizedB, ratio) => {
|
|
118
|
+
const unitVector = sphericalLinearInterpolation_UnitVector(normalizedA, normalizedB, ratio);
|
|
119
|
+
const angles = cartesian3dToRadian(unitVector);
|
|
120
|
+
return radianToMercator(angles);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {vec4} a vec3 unit vector and length
|
|
125
|
+
* @param {vec4} b vec3 unit vector and length
|
|
126
|
+
* @param {fraction} ratio
|
|
127
|
+
*/
|
|
128
|
+
const sphericalLinearInterpolation_Cartesian3d = (a, b, ratio) => {
|
|
129
|
+
const unitVector = sphericalLinearInterpolation_UnitVector(a, b, ratio);
|
|
130
|
+
const height = a[3] + (b[3] - a[3]) * ratio;
|
|
131
|
+
return [unitVector[0] * height, unitVector[1] * height, unitVector[2] * height];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
*
|
|
137
|
+
* @param {wgs84} coordinates
|
|
138
|
+
* @returns {vec3}
|
|
139
|
+
*/
|
|
140
|
+
const wgs84ToUnitVector = (coordinates) => {
|
|
141
|
+
const long = coordinates[0] * RADIANS;
|
|
142
|
+
const lat = coordinates[1] * RADIANS;
|
|
143
|
+
|
|
144
|
+
const x = Math.cos(lat) * Math.cos(long);
|
|
145
|
+
const y = Math.cos(lat) * Math.sin(long);
|
|
146
|
+
const z = Math.sin(lat);
|
|
147
|
+
return [x, y, z];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {vec3} cartesian
|
|
153
|
+
* @returns {vec4} unit vector and length
|
|
154
|
+
*/
|
|
155
|
+
const cartesian3dToUnitVectorWithHeight = (cartesian) => {
|
|
156
|
+
const x = cartesian[0];
|
|
157
|
+
const y = cartesian[1];
|
|
158
|
+
const z = cartesian[2];
|
|
159
|
+
const height = Math.sqrt(x * x + y * y + z * z);
|
|
160
|
+
return [x / height, y / height, z / height, height];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {vec2} pixelXY
|
|
165
|
+
* @returns {vec2} long lat in radians
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
const pixelXYToRadians = (pixelXY) => {
|
|
169
|
+
const long = (2.0 * pixelXY[0] - 1.0) * Math.PI;
|
|
170
|
+
const lat = (2.0 * pixelXY[1] - 1.0) * Math.PI / 2.0;
|
|
171
|
+
return [long, lat]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const pixelXYLenghtToUnitVectorWithHeight = (pixelXYHeight) => {
|
|
175
|
+
const [long, lat] = pixelXYToRadians(pixelXYHeight);
|
|
176
|
+
const radius = WORLD_RADIUS_3D + pixelXYHeight[2];
|
|
177
|
+
return radianToCartesian3d([long, lat]).concat(radius);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
RADIANS,
|
|
182
|
+
WORLD_RADIUS_3D,
|
|
183
|
+
normalize3,
|
|
184
|
+
dot3,
|
|
185
|
+
length3,
|
|
186
|
+
cartesian3dToRadian,
|
|
187
|
+
radianToMercator,
|
|
188
|
+
radianToCartesian3d,
|
|
189
|
+
sphericalLinearInterpolation_UnitVector,
|
|
190
|
+
sphericalLinearInterpolation_Mercator,
|
|
191
|
+
sphericalLinearInterpolation_Cartesian3d,
|
|
192
|
+
wgs84ToUnitVector,
|
|
193
|
+
cartesian3dToUnitVectorWithHeight,
|
|
194
|
+
pixelXYLenghtToUnitVectorWithHeight
|
|
195
|
+
}
|
|
196
|
+
|
package/index.js
CHANGED
|
@@ -8,4 +8,5 @@ import * as compassrose from "./compassrose";
|
|
|
8
8
|
import * as heatwave from "./heatwave";
|
|
9
9
|
import * as util from "./util";
|
|
10
10
|
import * as programs from "./programs";
|
|
11
|
-
|
|
11
|
+
import * as pointheatmap from "./point-heat-map";
|
|
12
|
+
export { wind, waveparticles, timetracks, rangerings, compassrose, heatwave, util, programs, arrowfield, partialring, pointheatmap };
|
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Float32Array} TimeTrackMultiColorData | A linestring is representation, let A{a1, a2, a3}, B{b1, b2} be the points of the line.
|
|
3
|
+
* TimeTrackMultiColorData is [
|
|
4
|
+
* a1x, a1y, a1z, a1time, a1r, a1g, a1b, a1time, a3time,
|
|
5
|
+
* a2x, a2y, a2z, a2time, a2r, a2g, a2b, a1time, a3time,
|
|
6
|
+
* a3x, a3y, a3z, a3time, a3r, a3g, a3b, a1time, a3time,
|
|
7
|
+
* 0, 0, 0, 0, -1, -1, -1, 0, 0,
|
|
8
|
+
* b1x, b1y, b1z, b1time, b1r, b1g, b1b, b1time, b2time,
|
|
9
|
+
* b2x, b2y, b2z, b2time, b2r, b2g, b2b, BstartTime, BendTime
|
|
10
|
+
* ]
|
|
11
|
+
* there is a cutting point between A and B
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* ABOVE
|
|
17
|
+
* TO
|
|
18
|
+
* BELOW
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Array<number>} vec3 [x, y, z]
|
|
22
|
+
* @typedef {Array<number>} vec2 [x, y]
|
|
23
|
+
* @typedef {Array<number>} vec4 [x, y, z, w]
|
|
24
|
+
* @typedef {number} fraction a number between 0 and 1
|
|
25
|
+
* @typedef {Array<number>} wgs84 [long, lat]
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef Timetrack
|
|
31
|
+
* @property {Array<vec4>}} coordinates [x,y,z, length]
|
|
32
|
+
* @property {Array<Number>} times
|
|
33
|
+
* @param {Array<Timetrack>} timeTracks
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
import { pixelXYLenghtToUnitVectorWithHeight } from "../../Math/methods";
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const processACut = (array, offset) => {
|
|
43
|
+
// first 3 values of array
|
|
44
|
+
const v3 = array.slice(offset, offset + 3);
|
|
45
|
+
const v4 = pixelXYLenghtToUnitVectorWithHeight(v3);
|
|
46
|
+
const time = array[offset + 3];
|
|
47
|
+
return [v4, time];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const timeTrackPluginDataToPointHeatInterpolatorAdapter = (timeTrackPluginData) => {
|
|
52
|
+
const timeTracks = []
|
|
53
|
+
|
|
54
|
+
let offset = 0;
|
|
55
|
+
|
|
56
|
+
let timeTrack = {
|
|
57
|
+
coordinates: [],
|
|
58
|
+
times: []
|
|
59
|
+
}
|
|
60
|
+
while (offset < timeTrackPluginData.length) {
|
|
61
|
+
if (!timeTrackPluginData[offset]) {
|
|
62
|
+
timeTracks.push(timeTrack);
|
|
63
|
+
timeTrack = {
|
|
64
|
+
coordinates: [],
|
|
65
|
+
times: []
|
|
66
|
+
}
|
|
67
|
+
offset += 9;
|
|
68
|
+
}
|
|
69
|
+
const point = processACut(timeTrackPluginData, offset);
|
|
70
|
+
offset += 9;
|
|
71
|
+
timeTrack.coordinates.push(point[0]);
|
|
72
|
+
timeTrack.times.push(point[1]);
|
|
73
|
+
}
|
|
74
|
+
return timeTracks;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export { timeTrackPluginDataToPointHeatInterpolatorAdapter };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { PointHeatmapFlow } from "./point-to-heat-map-flow";
|
|
2
|
+
import { webworkerStr } from "../util/interpolation/timetrack/web-worker-str";
|
|
3
|
+
import { createTexture, getColorRampModed } from "../util";
|
|
4
|
+
|
|
5
|
+
class PointHeatmapPlugin {
|
|
6
|
+
|
|
7
|
+
constructor(id, { opacity = 1.0, pointSize = 5.0, onInterpolationComplete = () => { } } = {}) {
|
|
8
|
+
this.id = id;
|
|
9
|
+
this.globe = null;
|
|
10
|
+
this.gl = null;
|
|
11
|
+
this.densityToLegendProgram = null;
|
|
12
|
+
this._time = null;
|
|
13
|
+
|
|
14
|
+
this._opacity = opacity;
|
|
15
|
+
this._pointSize = pointSize;
|
|
16
|
+
this._legendTexture = null;
|
|
17
|
+
|
|
18
|
+
this._throttleListener = null;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
|
|
22
|
+
this.timeTrackInterpolationWorker = new Worker(
|
|
23
|
+
new URL(
|
|
24
|
+
'../util/interpolation/timetrack/web-worker.js',
|
|
25
|
+
import.meta.url
|
|
26
|
+
), { type: 'module' }
|
|
27
|
+
);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
console.log(e);
|
|
30
|
+
const blob = new Blob([webworkerStr], { type: 'application/javascript' });
|
|
31
|
+
this.timeTrackInterpolationWorker = new Worker(URL.createObjectURL(blob), { type: 'module' });
|
|
32
|
+
}
|
|
33
|
+
this.timeTrackInterpolationWorker.onmessage = (e) => {
|
|
34
|
+
if (e.data.error) {
|
|
35
|
+
throw new Error(e.data.error);
|
|
36
|
+
}
|
|
37
|
+
if (e.data === true) {
|
|
38
|
+
onInterpolationComplete()
|
|
39
|
+
}
|
|
40
|
+
if (e.data instanceof Float32Array) {
|
|
41
|
+
this.flow.setData(e.data);
|
|
42
|
+
this._throttleListener = null;
|
|
43
|
+
onInterpolationComplete();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// globe interaction
|
|
49
|
+
|
|
50
|
+
init(globe, gl) {
|
|
51
|
+
this.globe = globe;
|
|
52
|
+
this.gl = gl;
|
|
53
|
+
this.flow = new PointHeatmapFlow(globe);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
setPointSize(pointSize) {
|
|
59
|
+
if (typeof pointSize !== 'number' || pointSize <= 0) {
|
|
60
|
+
throw new Error('Invalid pointSize');
|
|
61
|
+
}
|
|
62
|
+
this._pointSize = pointSize;
|
|
63
|
+
this.globe.DrawRender();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Array<string>}
|
|
69
|
+
* @param {string} mode "interpolated" | "discrete"
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
setColorRamp(values, thresholds, mode = "interpolated") {
|
|
73
|
+
const gl = this.gl
|
|
74
|
+
if (this.gl === null) {
|
|
75
|
+
throw new Error('Plugin not initialized');
|
|
76
|
+
};
|
|
77
|
+
console.log(values, thresholds, mode);
|
|
78
|
+
const rampData = getColorRampModed(values, thresholds, mode);
|
|
79
|
+
console.log(rampData);
|
|
80
|
+
const texture = createTexture(gl, gl.LINEAR, rampData, 256, 1);
|
|
81
|
+
console.log(texture);
|
|
82
|
+
if (this._legendTexture) {
|
|
83
|
+
this.gl.deleteTexture(this._legendTexture);
|
|
84
|
+
}
|
|
85
|
+
this._legendTexture = texture;
|
|
86
|
+
this.globe.DrawRender();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
setTime(time) {
|
|
91
|
+
// TODO: WORK ON THIS
|
|
92
|
+
this._time = time;
|
|
93
|
+
if (this._throttleListener === null) {
|
|
94
|
+
this._throttleListener = setTimeout(() => {
|
|
95
|
+
this.timeTrackInterpolationWorker.postMessage({ time: this._time });
|
|
96
|
+
}, 0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
setTimetracks(timeTracks) {
|
|
102
|
+
this.timeTrackInterpolationWorker.postMessage({ timeTracks });
|
|
103
|
+
if (this._time !== null) {
|
|
104
|
+
this.setTime(this._time);
|
|
105
|
+
}
|
|
106
|
+
this.globe.DrawRender();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
setOpacity(opacity) {
|
|
111
|
+
if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {
|
|
112
|
+
throw new Error('Invalid opacity');
|
|
113
|
+
}
|
|
114
|
+
this._opacity = opacity;
|
|
115
|
+
this.globe.DrawRender();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
setGeometry() {
|
|
121
|
+
const geometry = this.globe.api_GetCurrentGeometry();
|
|
122
|
+
this.timeTrackInterpolationWorker.postMessage({ geometry });
|
|
123
|
+
if (this._time !== null) {
|
|
124
|
+
this.setTime(this._time);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
draw3D() {
|
|
130
|
+
if (this.isReady()) {
|
|
131
|
+
this.flow.draw(this._legendTexture, this._pointSize, this._opacity);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
resize() {
|
|
137
|
+
this.flow.resize();
|
|
138
|
+
if (this._time !== null) {
|
|
139
|
+
this.setTime(this._time);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
isReady() {
|
|
145
|
+
return (this.gl !== null && this._legendTexture !== null);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
free() {
|
|
149
|
+
if (this._isFreed) return;
|
|
150
|
+
this.gl.deleteTexture(this._legendTexture);
|
|
151
|
+
this.flow.free();
|
|
152
|
+
this.flow = null;
|
|
153
|
+
this.gl = null;
|
|
154
|
+
this._isFreed = true;
|
|
155
|
+
this.timeTrackInterpolator = null;
|
|
156
|
+
this._legendTexture = null;
|
|
157
|
+
this.timeTrackInterpolationWorker.terminate();
|
|
158
|
+
this.timeTrackInterpolationWorker = null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
export { PointHeatmapPlugin };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { PointHeatmapFlow } from "./point-to-heat-map-flow";
|
|
2
|
+
import { TimeTrackInterpolator } from "../util/interpolation/timetrack/timetrack-interpolator";
|
|
3
|
+
import { createTexture, getColorRampModed } from "../util";
|
|
4
|
+
|
|
5
|
+
class PointHeatmapPlugin {
|
|
6
|
+
|
|
7
|
+
constructor(id, { opacity = 1.0, pointSize = 5.0 } = {}) {
|
|
8
|
+
this.id = id;
|
|
9
|
+
this.globe = null;
|
|
10
|
+
this.gl = null;
|
|
11
|
+
this.densityToLegendProgram = null;
|
|
12
|
+
this._time = null;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
this._opacity = opacity;
|
|
16
|
+
this._pointSize = pointSize;
|
|
17
|
+
this._legendTexture = null;
|
|
18
|
+
this.timeTrackInterpolator = new TimeTrackInterpolator();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// globe interaction
|
|
22
|
+
|
|
23
|
+
init(globe, gl) {
|
|
24
|
+
this.globe = globe;
|
|
25
|
+
this.gl = gl;
|
|
26
|
+
this.flow = new PointHeatmapFlow(globe);
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
setPointSize(pointSize) {
|
|
32
|
+
if (typeof pointSize !== 'number' || pointSize <= 0) {
|
|
33
|
+
throw new Error('Invalid pointSize');
|
|
34
|
+
}
|
|
35
|
+
this._pointSize = pointSize;
|
|
36
|
+
this.globe.DrawRender();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {Array<string>}
|
|
42
|
+
* @param {string} mode "interpolated" | "discrete"
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
setColorRamp(values, thresholds, mode = "interpolated") {
|
|
46
|
+
const gl = this.gl
|
|
47
|
+
if (this.gl === null) {
|
|
48
|
+
throw new Error('Plugin not initialized');
|
|
49
|
+
};
|
|
50
|
+
console.log(values, thresholds, mode);
|
|
51
|
+
const rampData = getColorRampModed(values, thresholds, mode);
|
|
52
|
+
console.log(rampData);
|
|
53
|
+
const texture = createTexture(gl, gl.LINEAR, rampData, 256, 1);
|
|
54
|
+
console.log(texture);
|
|
55
|
+
if (this._legendTexture) {
|
|
56
|
+
this.gl.deleteTexture(this._legendTexture);
|
|
57
|
+
}
|
|
58
|
+
this._legendTexture = texture;
|
|
59
|
+
this.globe.DrawRender();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
setTime(time) {
|
|
64
|
+
this._time = time;
|
|
65
|
+
const data = this.timeTrackInterpolator.interpolate(time);
|
|
66
|
+
if (data === null) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.flow.setData(data);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
setTimetracks(timeTracks) {
|
|
74
|
+
this.timeTrackInterpolator.setTimetracks(timeTracks);
|
|
75
|
+
if (this._time !== null) {
|
|
76
|
+
this.setTime(this._time);
|
|
77
|
+
}
|
|
78
|
+
this.globe.DrawRender();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
setOpacity(opacity) {
|
|
83
|
+
if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {
|
|
84
|
+
throw new Error('Invalid opacity');
|
|
85
|
+
}
|
|
86
|
+
this._opacity = opacity;
|
|
87
|
+
this.globe.DrawRender();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
setGeometry() {
|
|
93
|
+
const geometry = this.globe.api_GetCurrentGeometry();
|
|
94
|
+
this.timeTrackInterpolator.setGeometry(geometry);
|
|
95
|
+
if (this._time !== null) {
|
|
96
|
+
this.setTime(this._time);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
draw3D() {
|
|
102
|
+
if (this.isReady()) {
|
|
103
|
+
this.flow.draw(this._legendTexture, this._pointSize, this._opacity);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
resize() {
|
|
109
|
+
this.timeTrackInterpolator.setGeometry(this.globe.api_GetCurrentGeometry());
|
|
110
|
+
this.flow.resize();
|
|
111
|
+
if (this._time !== null) {
|
|
112
|
+
this.setTime(this._time);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
isReady() {
|
|
118
|
+
return (this.gl !== null && this._legendTexture !== null);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
free() {
|
|
122
|
+
if (this._isFreed) return;
|
|
123
|
+
this.gl.deleteTexture(this._legendTexture);
|
|
124
|
+
this.flow.free();
|
|
125
|
+
this.flow = null;
|
|
126
|
+
this.gl = null;
|
|
127
|
+
this._isFreed = true;
|
|
128
|
+
this.timeTrackInterpolator = null;
|
|
129
|
+
this._legendTexture = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
export { PointHeatmapPlugin };
|