-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcategories.html
175 lines (151 loc) · 8.35 KB
/
categories.html
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Visualization of Appropriate Technology Solutions</title>
<style>
body { margin: 0; }
canvas { display: block; }
#info {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display: block;
color: white;
}
</style>
</head>
<body>
<div id="info">Appropriate Technology Solutions<br>
<span style="font-size: 14px;">X: Cost/Effort vs. Benefit, Y: DIY-ability, Z: Scalability & Adaptability</span>
</div>
<script type="module">
import * as THREE from 'https://unpkg.com/[email protected]/build/three.module.js';
import { OrbitControls } from 'https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js';
// Our data
const subjectsRankingMatrix = [
{ id: "1", name: "Water Filtration and Purification", "C/E:B": 8, DIY: 7, "S&A": 8 },
{ id: "2", name: "Sustainable Energy Solutions", "C/E:B": 7, DIY: 5, "S&A": 7 },
{ id: "3", name: "Composting Systems", "C/E:B": 9, DIY: 9, "S&A": 9 },
{ id: "4", name: "Rainwater Harvesting", "C/E:B": 8, DIY: 8, "S&A": 8 },
{ id: "5", name: "Natural Building Techniques", "C/E:B": 7, DIY: 6, "S&A": 6 },
{ id: "6", name: "Greywater Systems", "C/E:B": 7, DIY: 6, "S&A": 7 },
{ id: "7", name: "Small-scale Aquaponics", "C/E:B": 6, DIY: 5, "S&A": 6 },
{ id: "8", name: "Biogas Digesters", "C/E:B": 6, DIY: 4, "S&A": 5 },
{ id: "9", name: "Solar Cookers", "C/E:B": 9, DIY: 9, "S&A": 8 },
{ id: "10", name: "Micro-hydro Power", "C/E:B": 5, DIY: 3, "S&A": 4 },
{ id: "11", name: "Improved Cookstoves", "C/E:B": 8, DIY: 7, "S&A": 9 },
{ id: "12", name: "Passive Solar Design", "C/E:B": 8, DIY: 6, "S&A": 7 },
{ id: "13", name: "Bamboo Construction", "C/E:B": 7, DIY: 6, "S&A": 6 },
{ id: "14", name: "Pedal-powered Machines", "C/E:B": 7, DIY: 5, "S&A": 6 },
{ id: "15", name: "Plastic Bottle Construction", "C/E:B": 8, DIY: 9, "S&A": 7 },
{ id: "16", name: "Solar-Powered Water Purification", "C/E:B": 7, DIY: 4, "S&A": 6 },
{ id: "17", name: "Biogas-Powered Cooking and Lighting", "C/E:B": 6, DIY: 3, "S&A": 5 },
{ id: "18", name: "Aquaponics with Solar Power", "C/E:B": 5, DIY: 4, "S&A": 5 },
{ id: "19", name: "Rainwater Harvesting for Hydroponics", "C/E:B": 7, DIY: 6, "S&A": 7 },
{ id: "20", name: "Waste-to-Energy Composting Toilets", "C/E:B": 7, DIY: 5, "S&A": 6 },
{ id: "21", name: "Bamboo Rainwater Harvesting Structures", "C/E:B": 8, DIY: 7, "S&A": 7 },
{ id: "22", name: "Pedal-Powered Water Filtration", "C/E:B": 8, DIY: 6, "S&A": 7 },
{ id: "23", name: "Solar Food Dehydrators", "C/E:B": 9, DIY: 8, "S&A": 8 },
{ id: "24", name: "Upcycled Plastic Bottle Greenhouse", "C/E:B": 8, DIY: 9, "S&A": 7 },
{ id: "25", name: "Biomass-Powered Water Pumps", "C/E:B": 6, DIY: 4, "S&A": 5 },
{ id: "26", name: "Vertical Hydroponic Gardens with Greywater Recycling", "C/E:B": 6, DIY: 5, "S&A": 6 },
{ id: "27", name: "Wind-Powered Desalination Units", "C/E:B": 5, DIY: 2, "S&A": 4 },
{ id: "28", name: "Biochar Production from Agricultural Waste", "C/E:B": 7, DIY: 6, "S&A": 7 },
{ id: "29", name: "Solar-Powered Vaccine Refrigerators", "C/E:B": 8, DIY: 3, "S&A": 7 },
{ id: "30", name: "Micro-hydro and Fish Ladder Combinations", "C/E:B": 5, DIY: 2, "S&A": 3 },
{ id: "31", name: "Mycelium-Based Building Insulation", "C/E:B": 7, DIY: 5, "S&A": 6 },
{ id: "32", name: "Pedal-Powered Washing Machines", "C/E:B": 8, DIY: 7, "S&A": 8 },
{ id: "33", name: "Solar Balloon Water Heaters", "C/E:B": 9, DIY: 8, "S&A": 7 },
{ id: "34", name: "Algae-Powered Streetlights", "C/E:B": 5, DIY: 2, "S&A": 4 },
{ id: "35", name: "Waste Plastic Road Construction", "C/E:B": 6, DIY: 3, "S&A": 5 },
{ id: "36", name: "Solar-Powered Atmospheric Water Generators", "C/E:B": 6, DIY: 3, "S&A": 5 },
{ id: "37", name: "Bamboo Bicycle Frames with Water Storage", "C/E:B": 7, DIY: 5, "S&A": 6 },
{ id: "38", name: "Floating Photovoltaic and Aquaculture Systems", "C/E:B": 5, DIY: 2, "S&A": 4 },
{ id: "39", name: "Passive Cooling Earth Tubes", "C/E:B": 8, DIY: 6, "S&A": 7 },
{ id: "40", name: "Piezoelectric Energy Harvesting Floors", "C/E:B": 4, DIY: 2, "S&A": 5 }
];
// Set up the scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Add lights
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Create axes
const axesHelper = new THREE.AxesHelper(10);
scene.add(axesHelper);
// Create data points
const geometry = new THREE.SphereGeometry(0.1, 32, 32);
const materials = subjectsRankingMatrix.map(() =>
new THREE.MeshPhongMaterial({ color: Math.random() * 0xffffff })
);
const dataPoints = subjectsRankingMatrix.map((subject, index) => {
const mesh = new THREE.Mesh(geometry, materials[index]);
mesh.position.set(subject['C/E:B'], subject.DIY, subject['S&A']);
mesh.userData = { name: subject.name };
scene.add(mesh);
return mesh;
});
// Set up camera position
camera.position.set(15, 15, 15);
camera.lookAt(5, 5, 5);
// Add orbit controls
const controls = new OrbitControls(camera, renderer.domElement);
// Raycaster for mouse interaction
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// Event listener for mouse movement
document.addEventListener('mousemove', onMouseMove, false);
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
// Update the picking ray with the camera and mouse position
raycaster.setFromCamera(mouse, camera);
// Calculate objects intersecting the picking ray
const intersects = raycaster.intersectObjects(dataPoints);
// Reset all point sizes
dataPoints.forEach(point => point.scale.set(1, 1, 1));
// Highlight intersected point
if (intersects.length > 0) {
const intersectedPoint = intersects[0].object;
intersectedPoint.scale.set(1.5, 1.5, 1.5);
// Update info div
document.getElementById('info').innerHTML = `
Appropriate Technology Solutions<br>
<span style="font-size: 14px;">X: Cost/Effort vs. Benefit, Y: DIY-ability, Z: Scalability & Adaptability</span><br>
<span style="font-size: 16px; color: yellow;">${intersectedPoint.userData.name}</span>
`;
} else {
// Reset info div
document.getElementById('info').innerHTML = `
Appropriate Technology Solutions<br>
<span style="font-size: 14px;">X: Cost/Effort vs. Benefit, Y: DIY-ability, Z: Scalability & Adaptability</span>
`;
}
controls.update();
renderer.render(scene, camera);
}
animate();
// Handle window resizing
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>