/ magnetic.html
magnetic.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> 6 7 <title>Magnetic — Space.js</title> 8 9 <link rel="preconnect" href="https://fonts.gstatic.com"> 10 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono"> 11 <link rel="stylesheet" href="assets/css/style.css"> 12 13 <script type="module"> 14 import { Interface, Magnetic, clearTween, ticker, tween } from './src/index.js'; 15 16 class Progress extends Interface { 17 constructor() { 18 super(null, 'svg'); 19 20 const size = 90; 21 22 this.width = size; 23 this.height = size; 24 this.x = size / 2; 25 this.y = size / 2; 26 this.radius = size * 0.4; 27 this.progress = 0; 28 this.needsUpdate = false; 29 30 this.initSVG(); 31 32 this.addListeners(); 33 } 34 35 initSVG() { 36 this.attr({ 37 width: this.width, 38 height: this.height 39 }); 40 41 this.circle = new Interface(null, 'svg', 'circle'); 42 this.circle.attr({ 43 cx: this.x, 44 cy: this.y, 45 r: this.radius 46 }); 47 this.circle.css({ 48 fill: 'none', 49 stroke: 'var(--ui-color)', 50 strokeWidth: 1.5 51 }); 52 this.circle.start = 0; 53 this.circle.offset = -0.25; 54 this.add(this.circle); 55 } 56 57 addListeners() { 58 ticker.add(this.onUpdate); 59 } 60 61 removeListeners() { 62 ticker.remove(this.onUpdate); 63 } 64 65 // Event handlers 66 67 onUpdate = () => { 68 if (this.needsUpdate) { 69 this.update(); 70 } 71 }; 72 73 onProgress = ({ progress }) => { 74 clearTween(this); 75 76 this.needsUpdate = true; 77 78 tween(this, { progress }, 500, 'easeOutCubic', () => { 79 this.needsUpdate = false; 80 81 if (this.progress >= 1) { 82 this.onComplete(); 83 } 84 }); 85 }; 86 87 onComplete = () => { 88 this.removeListeners(); 89 90 this.events.emit('complete'); 91 }; 92 93 // Public methods 94 95 update = () => { 96 this.circle.drawLine(this.progress); 97 }; 98 99 animateOut = callback => { 100 this.tween({ scale: 0.9, opacity: 0 }, 400, 'easeInCubic', callback); 101 }; 102 103 destroy = () => { 104 this.removeListeners(); 105 106 clearTween(this); 107 108 return super.destroy(); 109 }; 110 } 111 112 class App { 113 static async init() { 114 this.initView(); 115 116 this.addListeners(); 117 } 118 119 static initView() { 120 this.view = new Progress(); 121 this.view.css({ 122 position: 'absolute', 123 left: '50%', 124 top: '50%', 125 marginLeft: -this.view.width / 2, 126 marginTop: -this.view.height / 2, 127 cursor: 'pointer' 128 }); 129 document.body.appendChild(this.view.element); 130 131 this.magnet = new Magnetic(this.view); 132 this.view.add(this.magnet); 133 134 this.view.onProgress({ progress: 1 }); 135 } 136 137 static addListeners() { 138 this.view.element.addEventListener('click', this.onClick); 139 ticker.start(); 140 } 141 142 // Event handlers 143 144 static onClick = () => { 145 this.view.element.removeEventListener('click', this.onClick); 146 147 this.magnet.disable(); 148 149 this.view.animateOut(() => { 150 this.view = this.view.destroy(); 151 }); 152 }; 153 } 154 155 App.init(); 156 </script> 157 </head> 158 <body> 159 </body> 160 </html>