-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathDataVisualizer.js
More file actions
136 lines (109 loc) · 3.62 KB
/
DataVisualizer.js
File metadata and controls
136 lines (109 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class DataVisualizer {
constructor({
baseMapUrl,
dataMapUrl,
width,
height,
dataDepth,
}) {
this.baseMapUrl = baseMapUrl;
this.dataMapUrl = dataMapUrl;
this.width = width;
this.height = height;
this.dataDepth = dataDepth;
}
async init() {
this.scene = new THREE.Scene();
// camera
const aspect = window.innerWidth / window.innerHeight;
this.camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
this.camera.position.set(0, 50, 50);
const rendererOptions = {
antialias: true,
};
this.renderer = new THREE.WebGLRenderer(rendererOptions);
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
this.setupLights();
// array of rows of values
// const data = generateData(100, 100);
function treshold(value, tresholdValue = 0.2) {
return (value < tresholdValue) ? undefined : value;
}
const imageData = await getImageData(this.dataMapUrl, 0.1);
function f(x) {
return Math.max(0, Math.min(1, Math.exp(x * 2) / 2.2 - 1));
}
const data = imageData.map(row => row.map(
([r, g, b, a]) => treshold(f(1 - r / 255))
));
const dataWidth = data.length;
const dataHeight = data[0] ? data[0].length : 0;
const materials = DataVisualizer.createMaterialPalette(10);
const mergedGeometry = new THREE.Geometry();
for (let j = 0; j < data.length; j++) {
const row = data[j];
for (let i = 0; i < row.length; i++) {
const value = row[i];
if (value !== undefined){
const cubeGeometry = new THREE.CubeGeometry(1, 1, 1);
const cube = new THREE.Mesh(cubeGeometry);
cube.applyMatrix(new THREE.Matrix4().makeTranslation(
i - dataWidth / 2,
0.5,
j - dataHeight / 2
));
const y = value * this.dataDepth;
cube.applyMatrix(new THREE.Matrix4().makeScale(1, y, 1));
for (let k = 0; k < cubeGeometry.faces.length; k++) {
cubeGeometry.faces[k].materialIndex = Math.round(
(1 - value) * (materials.length - 1)
);
}
mergedGeometry.merge(cubeGeometry, cube.matrix);
}
}
}
const mergedMesh = new THREE.Mesh(mergedGeometry, materials);
const map = createMap({
width: this.width,
height: this.height,
url: this.baseMapUrl,
});
this.scene.add(map);
this.scene.add(mergedMesh);
this.control = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.animate();
}
static createMaterialPalette(count) {
const materials = [];
for (let i = 0; i < count; i++) {
const material = new THREE.MeshPhongMaterial();
const colorComponent = Math.round(i / count * 255);
material.color = new THREE.Color(`rgba(255, ${colorComponent}, 0)`);
materials.push(material);
material.transparent = true;
material.opacity = .5;
}
return materials;
}
setupLights() {
const lights = [];
const light1 = new THREE.PointLight(0xffffff, 0.5, 0);
const light2 = new THREE.PointLight(0xffffff, 0.5, 0);
const light3 = new THREE.PointLight(0xffffff, 0.5, 0);
light1.position.set(0, 200, 0);
light2.position.set(100, 200, 100);
light3.position.set(-100, -200, -100);
lights.push(light1);
lights.push(light2);
lights.push(light3);
for (let i = 0; i < lights.length; i++) {
this.scene.add(lights[i]);
}
}
animate() {
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(() => this.animate());
}
}