@@ -434,12 +434,43 @@ const chartColors = JSON.stringify(colors)
434434
435435 wrapper.querySelectorAll('.chart-btn').forEach((btn) => {
436436 btn.addEventListener('click', () => {
437+ const duration = 300
438+ const zoomFactor = 0.75
437439 if ((btn as HTMLElement).classList.contains('zoom-in')) {
438- controls.dollyIn(1.4)
440+ const targetPos = camera.position
441+ .clone()
442+ .sub(controls.target)
443+ .normalize()
444+ .multiplyScalar(camera.position.distanceTo(controls.target) * zoomFactor)
445+ .add(controls.target)
446+ const startPos = camera.position.clone()
447+ const zoomStart = performance.now()
448+ function zoomInAnim() {
449+ const p = Math.min((performance.now() - zoomStart) / duration, 1)
450+ const e = 1 - Math.pow(1 - p, 3)
451+ camera.position.lerpVectors(startPos, targetPos, e)
452+ controls.update()
453+ if (p < 1) requestAnimationFrame(zoomInAnim)
454+ }
455+ zoomInAnim()
439456 } else if ((btn as HTMLElement).classList.contains('zoom-out')) {
440- controls.dollyOut(1.4)
457+ const targetPos = camera.position
458+ .clone()
459+ .sub(controls.target)
460+ .normalize()
461+ .multiplyScalar(camera.position.distanceTo(controls.target) / zoomFactor)
462+ .add(controls.target)
463+ const startPos = camera.position.clone()
464+ const zoomStart = performance.now()
465+ function zoomOutAnim() {
466+ const p = Math.min((performance.now() - zoomStart) / duration, 1)
467+ const e = 1 - Math.pow(1 - p, 3)
468+ camera.position.lerpVectors(startPos, targetPos, e)
469+ controls.update()
470+ if (p < 1) requestAnimationFrame(zoomOutAnim)
471+ }
472+ zoomOutAnim()
441473 } else {
442- // Smooth reset
443474 const resetStart = performance.now()
444475 const fromPos = camera.position.clone()
445476 const toPos = DEFAULT_EYE.clone()
0 commit comments