/ 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>