Modularización
parent
448db3ae31
commit
c617962fd2
@ -0,0 +1,47 @@
|
|||||||
|
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET
|
||||||
|
Based on https://codepen.io/okada-web/pen/OJydGzy?editors=0010
|
||||||
|
*/
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
class ArgentinianFlag extends THREE.Group {
|
||||||
|
constructor(height) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
var geometry = new THREE.PlaneGeometry(3,2,30,20);
|
||||||
|
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
|
||||||
|
geometry.setAttribute('color', colors);
|
||||||
|
for(var i = 0; i < colors.count; i++)
|
||||||
|
if(i < 31 * 7 || i >= 31 * 14)
|
||||||
|
colors.setXYZ(i, 117/255, 170/255, 219/255);
|
||||||
|
else
|
||||||
|
colors.setXYZ(i, 1, 1, 1);
|
||||||
|
var material = new THREE.MeshBasicMaterial({side:THREE.DoubleSide, vertexColors: true});
|
||||||
|
this.mesh = new THREE.Mesh(geometry,material);
|
||||||
|
this.mesh.rotateX(Math.PI/2);
|
||||||
|
|
||||||
|
var scale = height / 3;
|
||||||
|
this.mesh.position.x = 1.5 * scale;
|
||||||
|
this.mesh.position.z = 1 * scale;
|
||||||
|
this.mesh.scale.setScalar(scale);
|
||||||
|
this.add(this.mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
animate() {
|
||||||
|
var hor = 0.3;
|
||||||
|
var speed = 0.1;
|
||||||
|
var ver = 0.1;
|
||||||
|
var swing = 0.5;
|
||||||
|
var pos = this.mesh.geometry.attributes.position;
|
||||||
|
const time = Date.now() * speed / 50;
|
||||||
|
for (let y=0; y<20+1; y++) {
|
||||||
|
for (let x=0; x<30+1; x++) {
|
||||||
|
const index = x + y * (30+1);
|
||||||
|
const vertex = pos[index];
|
||||||
|
pos.setZ(index, Math.sin(hor * x + ver * y - time) * swing * x / 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos.needsUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ArgentinianFlag };
|
@ -0,0 +1,25 @@
|
|||||||
|
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
function checkBoard(width, height) {
|
||||||
|
var geometry = new THREE.PlaneGeometry(width, height, width, height);
|
||||||
|
geometry = geometry.toNonIndexed();
|
||||||
|
const colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
|
||||||
|
for(var i = 0; i < colors.count; i++) {
|
||||||
|
var col = Math.trunc(i / 6) % width;
|
||||||
|
var row = Math.trunc(i / 6 / width);
|
||||||
|
if((col + row % 2) % 2)
|
||||||
|
colors.setXYZ(i, 0x44 / 0xff, 0xaa / 0xff, 0);
|
||||||
|
else
|
||||||
|
colors.setXYZ(i, 0x55 / 0xff, 0xd4 / 0xff, 0);
|
||||||
|
}
|
||||||
|
geometry.setAttribute('color', colors);
|
||||||
|
const material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors});
|
||||||
|
var mesh = new THREE.Mesh(geometry, material);
|
||||||
|
|
||||||
|
mesh.position.x = width / 2;
|
||||||
|
mesh.position.y = height / 2;
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { checkBoard };
|
@ -0,0 +1,185 @@
|
|||||||
|
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
|
||||||
|
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.136.0/examples/jsm/loaders/STLLoader.js';
|
||||||
|
import { WindMill } from './windmill.js';
|
||||||
|
import { Screen } from './screen.js';
|
||||||
|
import { ArgentinianFlag } from './argentinianflag.js';
|
||||||
|
import { checkBoard } from './checkboard.js';
|
||||||
|
|
||||||
|
window.three = THREE;
|
||||||
|
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
|
||||||
|
const renderer = new THREE.WebGLRenderer({antialias: true});
|
||||||
|
document.body.appendChild(renderer.domElement);
|
||||||
|
//renderer.setPixelRatio( window.devicePixelRatio );
|
||||||
|
|
||||||
|
function log(s) {
|
||||||
|
document.getElementById("text").innerHTML = s;
|
||||||
|
document.getElementById("popup").style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindSimulation {
|
||||||
|
constructor(width, height, mills) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.mills = mills;
|
||||||
|
|
||||||
|
this.wms = [];
|
||||||
|
this.init_windmills();
|
||||||
|
|
||||||
|
this.wm = null;
|
||||||
|
this.simulation = null;
|
||||||
|
this.xhr = null;
|
||||||
|
|
||||||
|
this.checkBoard = checkBoard(width, height);
|
||||||
|
scene.add(this.checkBoard);
|
||||||
|
|
||||||
|
const loader = new STLLoader();
|
||||||
|
loader.load('./MonumentoBandera.stl', (geometry) => {
|
||||||
|
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
|
||||||
|
var mesh = new THREE.Mesh(geometry, material);
|
||||||
|
var scale = 0.0093;
|
||||||
|
mesh.scale.setScalar(scale);
|
||||||
|
mesh.rotation.z = -Math.PI / 2;
|
||||||
|
mesh.position.x = 9.5;
|
||||||
|
mesh.position.y = 0.3;
|
||||||
|
scene.add(mesh);
|
||||||
|
this.monument = mesh;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.flag = new ArgentinianFlag(0.3);
|
||||||
|
this.flag.position.set(9.5, 0.3, 0.3);
|
||||||
|
this.flag.rotation.z = Math.PI;
|
||||||
|
scene.add(this.flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
init_windmills() {
|
||||||
|
if(!WindMill.isReady()) {
|
||||||
|
setTimeout(() => { this.init_windmills() }, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(var i = 0; i < this.mills; i++) {
|
||||||
|
var wm = new WindMill();
|
||||||
|
wm.position.set(i + 0.5, i + 0.5, 0);
|
||||||
|
wm.rotation.z = Math.PI;
|
||||||
|
scene.add(wm);
|
||||||
|
this.wms.push(wm);
|
||||||
|
}
|
||||||
|
this.wm = this.wms[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
move(pos, ended=false) {
|
||||||
|
if(this.simulation) {
|
||||||
|
scene.remove(this.simulation);
|
||||||
|
this.simulation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var wm = this.wm;
|
||||||
|
|
||||||
|
if(ended) {
|
||||||
|
if(this.wm != null) this.wm.select(false);
|
||||||
|
this.wm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wm == null) return false;
|
||||||
|
if(pos.x > this.width - 0.5 || pos.x < 0.5 || pos.y > this.height - 0.5 || pos.y < 0.5) return false;
|
||||||
|
for(var i = 0; i < this.wms.length; i++) {
|
||||||
|
if(this.wms[i] == wm) continue;
|
||||||
|
if(pos.clone().sub(this.wms[i].position).length() < 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wm.position.x = pos.x;
|
||||||
|
wm.position.y = pos.y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
animate() {
|
||||||
|
requestAnimationFrame(() => { this.animate(); });
|
||||||
|
|
||||||
|
if(!Screen.isMobile || (Screen.isMobile && screen.clicked)) {
|
||||||
|
const intersects = screen.raycaster.intersectObjects(this.wms);
|
||||||
|
var wm = null;
|
||||||
|
for(var i = 0; i < intersects.length; i++) {
|
||||||
|
if(intersects[i].object.geometry.constructor.name != "CylinderGeometry") {
|
||||||
|
wm = intersects[i].object.parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!screen.clicked || Screen.isMobile) {
|
||||||
|
if(this.wm != wm) {
|
||||||
|
if(this.wm != null) this.wm.select(false);
|
||||||
|
if(wm != null) wm.select(true);
|
||||||
|
}
|
||||||
|
this.wm = wm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 0; i < this.wms.length; i++) {
|
||||||
|
this.wms[i].animate();
|
||||||
|
//this.wms[i].rotation.z += 0.01;
|
||||||
|
}
|
||||||
|
//this.flag.rotation.z += 0.01;
|
||||||
|
|
||||||
|
this.flag.animate();
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulate() {
|
||||||
|
if(this.xhr != null)
|
||||||
|
this.xhr.abort();
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
this.xhr = xhr;
|
||||||
|
xhr.open("POST", "/solver/", true);
|
||||||
|
xhr.setRequestHeader("Content-Type", "application/json");
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if(this.xhr != xhr) return;
|
||||||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||||
|
var json = JSON.parse(xhr.responseText);
|
||||||
|
this.add_simulation(json.ws);
|
||||||
|
this.xhr = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var pos = [];
|
||||||
|
for(var i = 0; i < this.wms.length; i++)
|
||||||
|
pos.push([this.wms[i].position.y, this.wms[i].position.x]);
|
||||||
|
var data = JSON.stringify({"pos": pos});
|
||||||
|
xhr.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_simulation(ws) {
|
||||||
|
var geometry = new THREE.PlaneGeometry(this.width, this.height, 10 * this.width, 10 * this.height);
|
||||||
|
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.count * 4), 4);
|
||||||
|
geometry.setAttribute('color', colors);
|
||||||
|
const material = new THREE.MeshBasicMaterial({vertexColors: true, transparent: true,});
|
||||||
|
var mesh = new THREE.Mesh(geometry, material);
|
||||||
|
mesh.position.set(this.width / 2, this.height / 2, 90/126);
|
||||||
|
|
||||||
|
for(var i = 0; i < colors.count; i++) {
|
||||||
|
var j = Math.trunc(i / 101);
|
||||||
|
colors.setXYZW(i, 1 - ws[i % 101][100 - j] / 8, 0, 0, 1 - ws[i % 101][100 - j] / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.simulation)
|
||||||
|
scene.remove(this.simulation);
|
||||||
|
this.simulation = mesh;
|
||||||
|
scene.add(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var width = 10;
|
||||||
|
var height = 10;
|
||||||
|
var ws = new WindSimulation(width, height, 5);
|
||||||
|
|
||||||
|
var screen = new Screen(camera, renderer, new THREE.Vector3(width / 2 + 0.5, height / 2, -0.95));
|
||||||
|
screen.setMoveCallBack((pos, end) => { ws.move(pos, end); });
|
||||||
|
screen.onResize();
|
||||||
|
|
||||||
|
window.ws = ws;
|
||||||
|
window.screen = screen;
|
||||||
|
window.scene = scene;
|
||||||
|
ws.animate();
|
@ -0,0 +1,117 @@
|
|||||||
|
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
static isMobile = 'ontouchstart' in document.documentElement;
|
||||||
|
|
||||||
|
constructor(camera, renderer, center) {
|
||||||
|
this.camera = camera;
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.center = center;
|
||||||
|
this.cbmove = null;
|
||||||
|
|
||||||
|
this.raycaster = new THREE.Raycaster();
|
||||||
|
this.pointerScreen = new THREE.Vector2();
|
||||||
|
this.pointerWorld = new THREE.Vector3();
|
||||||
|
|
||||||
|
this.radius = 23;
|
||||||
|
this.phi = -0.5;
|
||||||
|
this.theta = 0.45;
|
||||||
|
this.z = 15;
|
||||||
|
this.aspect = 2.24;
|
||||||
|
|
||||||
|
this.clicked = false;
|
||||||
|
|
||||||
|
this.camera.setFocalLength(60);
|
||||||
|
|
||||||
|
if(Screen.isMobile) {
|
||||||
|
window.addEventListener('touchstart', (event) => { this.onClick(event); });
|
||||||
|
window.addEventListener('touchend', (event) => { this.onMouseUp(event); });
|
||||||
|
window.addEventListener('touchmove', (event) => { this.onPointerMove(event); });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.addEventListener('mouseup', (event) => { this.onMouseUp(event); });
|
||||||
|
window.addEventListener('mousedown', (event) => { this.onClick(event); });
|
||||||
|
window.addEventListener('pointermove', (event) => { this.onPointerMove(event); });
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', () => { this.onResize(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
setMoveCallBack(cbmove) {
|
||||||
|
this.cbmove = cbmove;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePointers(event) {
|
||||||
|
if(Screen.isMobile) {
|
||||||
|
var touch = event.touches[0] || event.changedTouches[0];
|
||||||
|
var x = touch.pageX;
|
||||||
|
var y = touch.pageY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var x = event.clientX
|
||||||
|
var y = event.clientY;
|
||||||
|
}
|
||||||
|
this.pointerScreen.x = (x / window.innerWidth) * 2 - 1;
|
||||||
|
this.pointerScreen.y = -(y / window.innerHeight) * 2 + 1;
|
||||||
|
this.raycaster.setFromCamera(this.pointerScreen, this.camera);
|
||||||
|
|
||||||
|
var point = new THREE.Vector3(this.pointerScreen.x, this.pointerScreen.y, 0.5);
|
||||||
|
point.unproject(this.camera);
|
||||||
|
point.sub(this.camera.position).normalize();
|
||||||
|
var distance = -this.camera.position.z / point.z;
|
||||||
|
this.pointerWorld.copy(this.camera.position).add(point.multiplyScalar(distance));
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick(event) {
|
||||||
|
this.clicked = true;
|
||||||
|
this.updatePointers(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseUp(event) {
|
||||||
|
this.clicked = false;
|
||||||
|
this.updatePointers(event);
|
||||||
|
ws.move(this.pointerWorld, true);
|
||||||
|
if(this.cbmove)
|
||||||
|
this.cbmove(this.pointerWorld, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPointerMove(event) {
|
||||||
|
this.updatePointers(event);
|
||||||
|
if(this.clicked) {
|
||||||
|
if(this.cbmove)
|
||||||
|
this.cbmove(this.pointerWorld, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize() {
|
||||||
|
this.camera.aspect = window.innerWidth / window.innerHeight;
|
||||||
|
this.camera.fov = 15;
|
||||||
|
this.camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
var r;
|
||||||
|
if(this.camera.aspect > this.aspect)
|
||||||
|
r = this.radius;
|
||||||
|
else {
|
||||||
|
r = this.radius * this.aspect / this.camera.aspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
document.getElementById("container").style.height = window.innerHeight;
|
||||||
|
document.getElementById("container").style.width = window.innerWidth;
|
||||||
|
document.getElementById("rotate").style.display = this.camera.aspect > 1 ? "none" : "block";
|
||||||
|
|
||||||
|
var theta = Math.PI / 2 - this.theta;
|
||||||
|
var phi = this.phi - Math.PI / 2;
|
||||||
|
var x = r * Math.sin(theta) * Math.cos(phi) + this.center.x;
|
||||||
|
var y = r * Math.sin(theta) * Math.sin(phi) + this.center.y;
|
||||||
|
var z = r * Math.cos(theta) + this.center.z;
|
||||||
|
|
||||||
|
this.camera.position.set(x, y, z);
|
||||||
|
this.camera.up = new THREE.Vector3(0,0,1);
|
||||||
|
this.camera.lookAt(this.center);
|
||||||
|
|
||||||
|
this.raycaster.setFromCamera(this.pointerScreen, this.camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Screen };
|
@ -0,0 +1,23 @@
|
|||||||
|
var geometry = new THREE.CylinderGeometry(0.09, 0.03, 0.5, 10, 5, true);
|
||||||
|
geometry = geometry.toNonIndexed();
|
||||||
|
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
|
||||||
|
geometry.setAttribute('color', colors);
|
||||||
|
for(var i = 0; i < colors.count; i++) {
|
||||||
|
if((Math.trunc(i / 6) + Math.trunc(i / 30) % 2) % 2)
|
||||||
|
colors.setXYZ(i, 1, 1, 1);
|
||||||
|
else
|
||||||
|
colors.setXYZ(i, 1, 0.3, 0);
|
||||||
|
}
|
||||||
|
var material = new THREE.MeshBasicMaterial({vertexColors: true, side: THREE.DoubleSide});
|
||||||
|
var mesh = new THREE.Mesh(geometry, material);
|
||||||
|
mesh.position.z = 1;
|
||||||
|
mesh.position.x = 9.5;
|
||||||
|
mesh.position.y = 0.5;
|
||||||
|
mesh.rotation.z = -Math.PI / 2;
|
||||||
|
var cone = mesh;
|
||||||
|
scene.add(mesh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
cone.rotation.y = 0.1 * Math.sin(Date.now() / 1000);
|
||||||
|
cone.rotation.x = 0.08 * Math.sin(Date.now() / 5000);
|
||||||
|
*/
|
@ -0,0 +1,98 @@
|
|||||||
|
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.136.0/examples/jsm/loaders/STLLoader.js';
|
||||||
|
import { Spring } from './spring.js';
|
||||||
|
|
||||||
|
class WindMill extends THREE.Group {
|
||||||
|
static geometryBody = null;
|
||||||
|
static geometryBlades = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
const loader = new STLLoader();
|
||||||
|
loader.load('./aspas_126m_85.stl', function(geometry) {
|
||||||
|
WindMill.geometryBlades = geometry;
|
||||||
|
});
|
||||||
|
loader.load('./cuerpo_126m_50.stl', function(geometry) {
|
||||||
|
WindMill.geometryBody = geometry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static isReady() {
|
||||||
|
return WindMill.geometryBody != null && WindMill.geometryBlades != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.material = new THREE.MeshBasicMaterial({color: 0xffffff});
|
||||||
|
this.materialCircle = new THREE.MeshBasicMaterial({color: 0xaa0000});
|
||||||
|
//this.materialCircle.transparent = true;
|
||||||
|
//this.materialCircle.opacity = 0.5;
|
||||||
|
|
||||||
|
this.meshBlades = new THREE.Mesh(WindMill.geometryBlades, this.material);
|
||||||
|
this.meshBlades.scale.set(0.0075, 0.0075, 0.0075);
|
||||||
|
this.meshBlades.position.z = 90/126;
|
||||||
|
|
||||||
|
this.meshBody = new THREE.Mesh(WindMill.geometryBody, this.material);
|
||||||
|
this.meshBody.scale.set(0.0075, 0.0075, 0.0075);
|
||||||
|
this.meshBody.position.z = 90/126;
|
||||||
|
|
||||||
|
var geometry = new THREE.CircleGeometry(0.5, 20);
|
||||||
|
this.meshCircle = new THREE.Mesh(geometry, this.materialCircle);
|
||||||
|
this.meshCircle.position.z = 0.01;
|
||||||
|
this.meshCircle.visible = false;
|
||||||
|
|
||||||
|
this.add(this.meshBlades);
|
||||||
|
this.add(this.meshBody);
|
||||||
|
this.add(this.meshCircle);
|
||||||
|
|
||||||
|
this.spring1 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||||
|
this.spring1.position.z = 90/126;
|
||||||
|
this.spring1.rotation.z = -Math.PI/2;
|
||||||
|
this.spring1.rotation.x = -Math.PI;
|
||||||
|
this.spring1.update();
|
||||||
|
this.add(this.spring1);
|
||||||
|
|
||||||
|
this.spring2 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||||
|
this.spring2.position.z = 90/126;
|
||||||
|
this.spring2.rotation.z = -Math.PI/2;
|
||||||
|
this.spring2.rotation.x = -Math.PI * 1 / 3;
|
||||||
|
this.spring2.update();
|
||||||
|
this.add(this.spring2);
|
||||||
|
|
||||||
|
this.spring3 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||||
|
this.spring3.position.z = 90/126;
|
||||||
|
this.spring3.rotation.z = -Math.PI/2;
|
||||||
|
this.spring3.rotation.x = Math.PI * 1 / 3;
|
||||||
|
this.spring3.update();
|
||||||
|
this.add(this.spring3);
|
||||||
|
|
||||||
|
this.spring1.visible = this.spring2.visible = this.spring3.visible = false;
|
||||||
|
|
||||||
|
this.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
animate() {
|
||||||
|
this.meshBlades.rotation.x += 0.1;
|
||||||
|
this.spring1.rotation.x += 0.1;
|
||||||
|
this.spring2.rotation.x += 0.1;
|
||||||
|
this.spring3.rotation.x += 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
select(selected) {
|
||||||
|
if(selected == this.selected) return;
|
||||||
|
this.selected = selected;
|
||||||
|
this.meshCircle.visible = selected;
|
||||||
|
|
||||||
|
if(selected)
|
||||||
|
this.material.color.set(0xff0000);
|
||||||
|
else
|
||||||
|
this.material.color.set(0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_springs(value) {
|
||||||
|
this.spring1.visible = this.spring2.visible = this.spring3.visible = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { WindMill };
|
@ -0,0 +1,102 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Encode Sans", sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 4vh;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#popup {
|
||||||
|
z-index: 1000;
|
||||||
|
max-width: 70vw;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: auto;
|
||||||
|
border: solid #fff 5px;
|
||||||
|
height: auto;
|
||||||
|
background: #00000088;
|
||||||
|
padding: 4vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#popup p + p {
|
||||||
|
margin-top: -3vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close {
|
||||||
|
font-weight: 900;
|
||||||
|
float: right;
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin-top: -5vh;
|
||||||
|
margin-right: -3.5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
position: absolute;
|
||||||
|
right: 4vh;
|
||||||
|
top: 4vh;
|
||||||
|
padding: 4vh;
|
||||||
|
background: darkblue;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button:hover {
|
||||||
|
background: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#copyright {
|
||||||
|
z-index: 2;
|
||||||
|
font-size: 0.4em;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rotate {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: 1vh;
|
||||||
|
font-size: 0.5em;
|
||||||
|
width: 20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rotate img {
|
||||||
|
width: 7vh;
|
||||||
|
float: left;
|
||||||
|
padding-right: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
z-index: 1;
|
||||||
|
position: absolute;
|
||||||
|
right: 1vh;
|
||||||
|
bottom: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo img {
|
||||||
|
width: 15vh;
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo img:hover {
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
Loading…
Reference in New Issue