| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8" /> |
| | <title>3D Apartment Visualization</title> |
| | |
| | <meta |
| | http-equiv="Content-Security-Policy" |
| | content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline';" |
| | /> |
| | <style> |
| | body { |
| | margin: 0; |
| | overflow: hidden; |
| | background-color: #202020; |
| | } |
| | canvas { |
| | display: block; |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <script type="module"> |
| | |
| | import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.module.js'; |
| | import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.149.0/examples/jsm/controls/OrbitControls.js'; |
| | |
| | |
| | const scene = new THREE.Scene(); |
| | scene.background = new THREE.Color(0x202020); |
| | |
| | |
| | const camera = new THREE.PerspectiveCamera( |
| | 75, |
| | window.innerWidth / window.innerHeight, |
| | 0.1, |
| | 1000 |
| | ); |
| | camera.position.set(100, 100, 300); |
| | |
| | |
| | const renderer = new THREE.WebGLRenderer({ antialias: true }); |
| | renderer.setSize(window.innerWidth, window.innerHeight); |
| | document.body.appendChild(renderer.domElement); |
| | |
| | |
| | const controls = new OrbitControls(camera, renderer.domElement); |
| | controls.enableDamping = true; |
| | controls.dampingFactor = 0.05; |
| | |
| | |
| | const apartments = [ |
| | { rank: 1, pricePerSqm: 90788, block: 'D' }, |
| | { rank: 2, pricePerSqm: 95584, block: 'D' }, |
| | { rank: 3, pricePerSqm: 96545, block: 'C' }, |
| | { rank: 4, pricePerSqm: 100171, block: 'C' }, |
| | { rank: 5, pricePerSqm: 101833, block: 'C' }, |
| | { rank: 6, pricePerSqm: 102200, block: 'B' }, |
| | { rank: 7, pricePerSqm: 106238, block: 'D' }, |
| | { rank: 8, pricePerSqm: 106327, block: 'B' }, |
| | { rank: 9, pricePerSqm: 107423, block: 'B' }, |
| | { rank: 10, pricePerSqm: 109136, block: 'A' } |
| | ]; |
| | |
| | |
| | const apartmentGroup = new THREE.Group(); |
| | scene.add(apartmentGroup); |
| | |
| | |
| | const blockColors = { |
| | 'A': 0xff0000, |
| | 'B': 0x0000ff, |
| | 'C': 0x00ff00, |
| | 'D': 0xffff00 |
| | }; |
| | |
| | |
| | apartments.forEach(apartment => { |
| | |
| | const x = apartment.rank * 30; |
| | const y = -(apartment.pricePerSqm - 90000) / 50; |
| | let z; |
| | switch (apartment.block) { |
| | case 'A': |
| | z = 0; |
| | break; |
| | case 'B': |
| | z = 100; |
| | break; |
| | case 'C': |
| | z = 200; |
| | break; |
| | case 'D': |
| | z = 300; |
| | break; |
| | default: |
| | z = 0; |
| | } |
| | |
| | |
| | const geometry = new THREE.SphereGeometry(5, 16, 16); |
| | const material = new THREE.MeshPhongMaterial({ |
| | color: blockColors[apartment.block] || 0xffffff |
| | }); |
| | const sphere = new THREE.Mesh(geometry, material); |
| | sphere.position.set(x, y, z); |
| | apartmentGroup.add(sphere); |
| | }); |
| | |
| | |
| | const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); |
| | scene.add(ambientLight); |
| | const directionalLight = new THREE.DirectionalLight(0xffffff, 1); |
| | directionalLight.position.set(0, 1, 1); |
| | scene.add(directionalLight); |
| | |
| | |
| | window.addEventListener('resize', () => { |
| | camera.aspect = window.innerWidth / window.innerHeight; |
| | camera.updateProjectionMatrix(); |
| | renderer.setSize(window.innerWidth, window.innerHeight); |
| | }); |
| | |
| | |
| | function animate() { |
| | requestAnimationFrame(animate); |
| | controls.update(); |
| | renderer.render(scene, camera); |
| | } |
| | animate(); |
| | </script> |
| | </body> |
| | </html> |
| |
|