From f12e405fcafa1c1771f9e4b434a1257101e692b6 Mon Sep 17 00:00:00 2001 From: Isaac Bowen Date: Mon, 4 Mar 2024 17:05:32 +1100 Subject: [PATCH] adjusting sparkline canvas size ratio --- dist/bundle.js | 2 +- src/main.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index 13f6201..d78623c 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -16,7 +16,7 @@ \*********************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { -eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst THREE = __webpack_require__(/*! three */ \"./node_modules/three/build/three.cjs\");\nclass SphereWithRods {\n constructor() {\n this.rods = [];\n this.lastTime = 0; // To track the last animation frame time\n this.totalDuration = 60; // seconds\n this.baselineOrbitSpeed = 0.25; // Original baseline speed\n this.currentOrbitSpeed = this.baselineOrbitSpeed; // Starts at the baseline speed\n this.accumulatedAngle = 0; // To accumulate the orbit angle\n this.x = 0; // Our progress along the x axis of the sparkline, ranging from 0 to 1\n this.y = 0; // The height of the sparkline curve as we progress, ranging from 0 to 1\n this.reverse = false; // Indicates whether we're going forward or backward\n this.animate = () => {\n requestAnimationFrame(this.animate);\n // Directly correlate orbit speed with this.y, increasing it around the peak\n const speedMultiplier = 1 + 3 * this.y; // Ranges from 1 (at y=0) to 4 (at y=1)\n this.currentOrbitSpeed = this.baselineOrbitSpeed * speedMultiplier;\n // Calculate the change in angle based on the current orbit speed\n const deltaTime = this.getDeltaTime(); // Get the time difference since the last frame\n const angleIncrement = this.currentOrbitSpeed * deltaTime; // Calculate the angle increment for this frame\n this.accumulatedAngle += angleIncrement; // Accumulate the angle\n this.camera.position.x = 5 * Math.sin(this.accumulatedAngle);\n this.camera.position.y = 0;\n this.camera.position.z = 5 * Math.cos(this.accumulatedAngle);\n this.camera.lookAt(new THREE.Vector3(0, 0, 0));\n this.renderer.render(this.scene, this.camera);\n };\n // Helper method to calculate the time difference since the last frame\n this.lastFrameTime = performance.now();\n this.lastTime = Date.now();\n this.constructSphere();\n this.constructSparkline();\n this.addEventListeners();\n this.updateXY(); // Initialize the time and direction update loop\n }\n addEventListeners() {\n window.addEventListener('resize', this.onWindowResize.bind(this), false);\n // Add click event listener for toggling fullscreen\n window.addEventListener('click', this.toggleFullScreen.bind(this), false);\n }\n toggleFullScreen() {\n if (!document.fullscreenElement) {\n if (document.body.requestFullscreen) {\n document.body.requestFullscreen();\n }\n }\n else {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n }\n }\n }\n onWindowResize() {\n this.camera.aspect = window.innerWidth / window.innerHeight;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n this.sparklineCanvas.width = Math.min(window.innerWidth, window.innerHeight) * 0.5;\n this.sparklineCanvas.height = this.sparklineCanvas.width * 0.3;\n }\n constructSphere() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x0a0a0a);\n this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 100);\n this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n document.body.appendChild(this.renderer.domElement);\n this.camera.position.set(5, 5, 5);\n this.camera.lookAt(this.scene.position);\n this.rodMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });\n this.startPlacingRods();\n this.animate();\n }\n constructSparkline() {\n this.sparklineCanvas = document.getElementById('sparkline-canvas');\n this.sparklineContext = this.sparklineCanvas.getContext('2d');\n this.sparklineCanvas.width = Math.min(window.innerWidth, window.innerHeight) * 0.5;\n this.sparklineCanvas.height = this.sparklineCanvas.width * 0.3;\n this.startTime = Date.now();\n this.drawSparkline();\n }\n updateXY() {\n const currentTime = Date.now();\n const elapsedTime = (currentTime - this.startTime) / 1000; // in seconds\n const cycle = Math.floor(elapsedTime / this.totalDuration);\n this.x = (elapsedTime % this.totalDuration) / this.totalDuration; // Normalized time for current cycle\n this.y = this.calculateY(this.x); // Calculate the corresponding y value\n this.reverse = cycle % 2 !== 0; // Reverse direction every other cycle\n requestAnimationFrame(this.updateXY.bind(this));\n }\n drawSparkline() {\n this.sparklineContext.clearRect(0, 0, this.sparklineCanvas.width, this.sparklineCanvas.height);\n this.sparklineContext.strokeStyle = 'white';\n this.sparklineContext.lineWidth = Math.ceil(Math.sqrt(Math.min(window.innerWidth, window.innerHeight)) / 1000) * 3;\n this.sparklineContext.beginPath();\n for (let x = 10; x <= this.sparklineCanvas.width - 10; x++) {\n const t = (x - 10) / (this.sparklineCanvas.width - 20); // Adjust to ensure t starts from 0\n const y = this.calculateY(t) * (this.sparklineCanvas.height - 20);\n this.sparklineContext.lineTo(x, this.sparklineCanvas.height - 10 - y); // Invert y when plotting\n }\n this.sparklineContext.stroke();\n // Adjust the cursor position for back-and-forth movement\n const cursorProgress = this.reverse ? 1 - this.x : this.x; // If reverse is true, move the cursor backwards\n const lineX = cursorProgress * (this.sparklineCanvas.width - 20) + 10;\n this.sparklineContext.beginPath();\n this.sparklineContext.moveTo(lineX, 0);\n this.sparklineContext.lineTo(lineX, this.sparklineCanvas.height);\n this.sparklineContext.stroke();\n requestAnimationFrame(this.drawSparkline.bind(this));\n }\n calculateY(t) {\n // Ensure t is in the range [0, 1]\n t = Math.max(0, Math.min(1, t));\n // Calculate the sine wave, mapped to go from 0 at t=0, to 1 at t=0.5, back to 0 at t=1\n const sineWave = Math.sin(Math.PI * t);\n // Raise the sine wave to a power to sharpen the peak\n const power = 20;\n const y = Math.pow(sineWave, power);\n // Return the y value, which should now start and end at 0, with a peak in the middle\n return y;\n }\n placeRod() {\n const baseLength = 1;\n const maxLength = 4;\n const biasFactor = 3;\n const rodLength = baseLength + Math.pow(Math.random(), biasFactor) * (maxLength - baseLength);\n const rodGeometry = new THREE.CylinderGeometry(0.01, 0.01, rodLength, 32);\n const rod = new THREE.Mesh(rodGeometry, this.rodMaterial);\n const phi = Math.random() * 2 * Math.PI;\n const theta = Math.acos(2 * Math.random() - 1);\n const jitter = 0.9 + Math.random() * 0.2;\n const x = jitter * Math.sin(theta) * Math.cos(phi);\n const y = jitter * Math.sin(theta) * Math.sin(phi);\n const z = jitter * Math.cos(theta);\n rod.position.set(x, y, z);\n const rodPosition = new THREE.Vector3(x, y, z);\n const radialDirection = rodPosition.clone().normalize();\n const upDirection = Math.abs(radialDirection.y) < 0.99 ? new THREE.Vector3(0, 1, 0) : new THREE.Vector3(0, 0, 1);\n const tangentDirection = new THREE.Vector3().crossVectors(radialDirection, upDirection).normalize();\n rod.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangentDirection);\n const randomAngle = Math.random() * 2 * Math.PI;\n rod.rotateOnWorldAxis(radialDirection, randomAngle);\n this.scene.add(rod);\n this.rods.push(rod);\n }\n startPlacingRods() {\n const placeOrRemoveRod = () => {\n // Keep the maximum delay the same to maintain the bottom speed\n const maxDelay = 1000; // Maximum delay in milliseconds\n // Decrease the minimum delay to increase the top speed of rod addition/removal\n const minDelay = 40; // Minimum delay in milliseconds, reduced to increase top speed\n // Use a sharper curve to decrease the delay as this.y increases\n // The exponent can be adjusted to control how quickly the delay decreases\n const delayFactor = Math.pow(1 - this.y, 10); // Using a square to make the decrease more pronounced\n // Calculate the actual delay using the delayFactor to interpolate between minDelay and maxDelay\n const delay = minDelay + (maxDelay - minDelay) * delayFactor;\n if (!this.reverse) {\n this.placeRod();\n }\n else if (this.rods.length > 0) {\n const removeIndex = Math.floor(Math.random() * this.rods.length);\n const [removedRod] = this.rods.splice(removeIndex, 1);\n this.scene.remove(removedRod);\n }\n setTimeout(placeOrRemoveRod, delay);\n };\n placeOrRemoveRod();\n }\n getDeltaTime() {\n const now = performance.now();\n const deltaTime = (now - this.lastFrameTime) / 1000; // Convert to seconds\n this.lastFrameTime = now;\n return deltaTime;\n }\n}\nnew SphereWithRods();\n\n\n//# sourceURL=webpack://flow/./src/main.ts?"); +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst THREE = __webpack_require__(/*! three */ \"./node_modules/three/build/three.cjs\");\nclass SphereWithRods {\n constructor() {\n this.rods = [];\n this.lastTime = 0; // To track the last animation frame time\n this.totalDuration = 60; // seconds\n this.baselineOrbitSpeed = 0.25; // Original baseline speed\n this.currentOrbitSpeed = this.baselineOrbitSpeed; // Starts at the baseline speed\n this.accumulatedAngle = 0; // To accumulate the orbit angle\n this.x = 0; // Our progress along the x axis of the sparkline, ranging from 0 to 1\n this.y = 0; // The height of the sparkline curve as we progress, ranging from 0 to 1\n this.reverse = false; // Indicates whether we're going forward or backward\n this.animate = () => {\n requestAnimationFrame(this.animate);\n // Directly correlate orbit speed with this.y, increasing it around the peak\n const speedMultiplier = 1 + 3 * this.y; // Ranges from 1 (at y=0) to 4 (at y=1)\n this.currentOrbitSpeed = this.baselineOrbitSpeed * speedMultiplier;\n // Calculate the change in angle based on the current orbit speed\n const deltaTime = this.getDeltaTime(); // Get the time difference since the last frame\n const angleIncrement = this.currentOrbitSpeed * deltaTime; // Calculate the angle increment for this frame\n this.accumulatedAngle += angleIncrement; // Accumulate the angle\n this.camera.position.x = 5 * Math.sin(this.accumulatedAngle);\n this.camera.position.y = 0;\n this.camera.position.z = 5 * Math.cos(this.accumulatedAngle);\n this.camera.lookAt(new THREE.Vector3(0, 0, 0));\n this.renderer.render(this.scene, this.camera);\n };\n // Helper method to calculate the time difference since the last frame\n this.lastFrameTime = performance.now();\n this.lastTime = Date.now();\n this.constructSphere();\n this.constructSparkline();\n this.addEventListeners();\n this.updateXY(); // Initialize the time and direction update loop\n }\n addEventListeners() {\n window.addEventListener('resize', this.onWindowResize.bind(this), false);\n // Add click event listener for toggling fullscreen\n window.addEventListener('click', this.toggleFullScreen.bind(this), false);\n }\n toggleFullScreen() {\n if (!document.fullscreenElement) {\n if (document.body.requestFullscreen) {\n document.body.requestFullscreen();\n }\n }\n else {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n }\n }\n }\n onWindowResize() {\n this.camera.aspect = window.innerWidth / window.innerHeight;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n }\n constructSphere() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x0a0a0a);\n this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 100);\n this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n document.body.appendChild(this.renderer.domElement);\n this.camera.position.set(5, 5, 5);\n this.camera.lookAt(this.scene.position);\n this.rodMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });\n this.startPlacingRods();\n this.animate();\n }\n constructSparkline() {\n this.sparklineCanvas = document.getElementById('sparkline-canvas');\n this.sparklineContext = this.sparklineCanvas.getContext('2d');\n this.sparklineCanvas.width = Math.min(window.innerWidth, window.innerHeight) * 0.5;\n this.sparklineCanvas.height = this.sparklineCanvas.width * 0.35;\n this.startTime = Date.now();\n this.drawSparkline();\n }\n updateXY() {\n const currentTime = Date.now();\n const elapsedTime = (currentTime - this.startTime) / 1000; // in seconds\n const cycle = Math.floor(elapsedTime / this.totalDuration);\n this.x = (elapsedTime % this.totalDuration) / this.totalDuration; // Normalized time for current cycle\n this.y = this.calculateY(this.x); // Calculate the corresponding y value\n this.reverse = cycle % 2 !== 0; // Reverse direction every other cycle\n requestAnimationFrame(this.updateXY.bind(this));\n }\n drawSparkline() {\n this.sparklineContext.clearRect(0, 0, this.sparklineCanvas.width, this.sparklineCanvas.height);\n this.sparklineContext.strokeStyle = 'white';\n this.sparklineContext.lineWidth = Math.ceil(Math.sqrt(Math.min(window.innerWidth, window.innerHeight)) / 1000) * 3;\n this.sparklineContext.beginPath();\n for (let x = 10; x <= this.sparklineCanvas.width - 10; x++) {\n const t = (x - 10) / (this.sparklineCanvas.width - 20); // Adjust to ensure t starts from 0\n const y = this.calculateY(t) * (this.sparklineCanvas.height - 20);\n this.sparklineContext.lineTo(x, this.sparklineCanvas.height - 10 - y); // Invert y when plotting\n }\n this.sparklineContext.stroke();\n // Adjust the cursor position for back-and-forth movement\n const cursorProgress = this.reverse ? 1 - this.x : this.x; // If reverse is true, move the cursor backwards\n const lineX = cursorProgress * (this.sparklineCanvas.width - 20) + 10;\n this.sparklineContext.beginPath();\n this.sparklineContext.moveTo(lineX, 0);\n this.sparklineContext.lineTo(lineX, this.sparklineCanvas.height);\n this.sparklineContext.stroke();\n requestAnimationFrame(this.drawSparkline.bind(this));\n }\n calculateY(t) {\n // Ensure t is in the range [0, 1]\n t = Math.max(0, Math.min(1, t));\n // Calculate the sine wave, mapped to go from 0 at t=0, to 1 at t=0.5, back to 0 at t=1\n const sineWave = Math.sin(Math.PI * t);\n // Raise the sine wave to a power to sharpen the peak\n const power = 20;\n const y = Math.pow(sineWave, power);\n // Return the y value, which should now start and end at 0, with a peak in the middle\n return y;\n }\n placeRod() {\n const baseLength = 1;\n const maxLength = 4;\n const biasFactor = 3;\n const rodLength = baseLength + Math.pow(Math.random(), biasFactor) * (maxLength - baseLength);\n const rodGeometry = new THREE.CylinderGeometry(0.01, 0.01, rodLength, 32);\n const rod = new THREE.Mesh(rodGeometry, this.rodMaterial);\n const phi = Math.random() * 2 * Math.PI;\n const theta = Math.acos(2 * Math.random() - 1);\n const jitter = 0.9 + Math.random() * 0.2;\n const x = jitter * Math.sin(theta) * Math.cos(phi);\n const y = jitter * Math.sin(theta) * Math.sin(phi);\n const z = jitter * Math.cos(theta);\n rod.position.set(x, y, z);\n const rodPosition = new THREE.Vector3(x, y, z);\n const radialDirection = rodPosition.clone().normalize();\n const upDirection = Math.abs(radialDirection.y) < 0.99 ? new THREE.Vector3(0, 1, 0) : new THREE.Vector3(0, 0, 1);\n const tangentDirection = new THREE.Vector3().crossVectors(radialDirection, upDirection).normalize();\n rod.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangentDirection);\n const randomAngle = Math.random() * 2 * Math.PI;\n rod.rotateOnWorldAxis(radialDirection, randomAngle);\n this.scene.add(rod);\n this.rods.push(rod);\n }\n startPlacingRods() {\n const placeOrRemoveRod = () => {\n // Keep the maximum delay the same to maintain the bottom speed\n const maxDelay = 1000; // Maximum delay in milliseconds\n // Decrease the minimum delay to increase the top speed of rod addition/removal\n const minDelay = 40; // Minimum delay in milliseconds, reduced to increase top speed\n // Use a sharper curve to decrease the delay as this.y increases\n // The exponent can be adjusted to control how quickly the delay decreases\n const delayFactor = Math.pow(1 - this.y, 10); // Using a square to make the decrease more pronounced\n // Calculate the actual delay using the delayFactor to interpolate between minDelay and maxDelay\n const delay = minDelay + (maxDelay - minDelay) * delayFactor;\n if (!this.reverse) {\n this.placeRod();\n }\n else if (this.rods.length > 0) {\n const removeIndex = Math.floor(Math.random() * this.rods.length);\n const [removedRod] = this.rods.splice(removeIndex, 1);\n this.scene.remove(removedRod);\n }\n setTimeout(placeOrRemoveRod, delay);\n };\n placeOrRemoveRod();\n }\n getDeltaTime() {\n const now = performance.now();\n const deltaTime = (now - this.lastFrameTime) / 1000; // Convert to seconds\n this.lastFrameTime = now;\n return deltaTime;\n }\n}\nnew SphereWithRods();\n\n\n//# sourceURL=webpack://flow/./src/main.ts?"); /***/ }), diff --git a/src/main.ts b/src/main.ts index a187432..a452623 100644 --- a/src/main.ts +++ b/src/main.ts @@ -49,8 +49,6 @@ class SphereWithRods { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); - this.sparklineCanvas.width = Math.min(window.innerWidth, window.innerHeight) * 0.5; - this.sparklineCanvas.height = this.sparklineCanvas.width * 0.3; } constructSphere(): void { @@ -71,7 +69,7 @@ class SphereWithRods { this.sparklineCanvas = document.getElementById('sparkline-canvas') as HTMLCanvasElement; this.sparklineContext = this.sparklineCanvas.getContext('2d')!; this.sparklineCanvas.width = Math.min(window.innerWidth, window.innerHeight) * 0.5; - this.sparklineCanvas.height = this.sparklineCanvas.width * 0.3; + this.sparklineCanvas.height = this.sparklineCanvas.width * 0.35; this.startTime = Date.now(); this.drawSparkline(); }