Home Reference Source

scripts/widgets/ui_progress.js

import {UIBase} from '../core/ui_base.js';
import * as util from '../path-controller/util/util.js';
import {keymap} from '../path-controller/util/simple_events.js';

export class ProgressCircle extends UIBase {
  constructor() {
    super();

    this.canvas = document.createElement("canvas");
    this.g = this.canvas.getContext("2d");

    this.shadow.appendChild(this.canvas);
    this.size = 150;
    this.animreq = undefined;
    this._value = 0.0;
    this.startTime = util.time_ms();
  }

  init() {
    super.init();
    this.flagRedraw();
    this.update();

    //enable keyboard focus
    this.tabIndex = 0;
    this.setAttribute("tab-index", 0);
    this.setAttribute("tabindex", 0);

    let onkey = (e) => {
      switch (e.keyCode) {
        case keymap["Escape"]:
          if (this.oncancel) {
            this.oncancel(this);
          }
          break;
      }
    }

    this.addEventListener("keydown", onkey);
    this.canvas.addEventListener("keydown", onkey);
  }

  flagRedraw() {
    if (this.animreq !== undefined) {
      return;
    }

    this.animreq = requestAnimationFrame(() => {
      this.animreq = undefined;
      this.draw();
    })
  }

  draw() {
    let c = this.canvas, g = this.g;

    let clr1 = "rgb(68,69,83)";
    let clr2 = "rgb(141,154,196)";
    let clr3 = "rgb(214,110,54)";

    let t = (util.time_ms() - this.startTime) / 1000.0;

    g.save();
    g.clearRect(0, 0, c.width, c.height);

    g.lineWidth /= c.width*0.5;
    g.scale(c.width, c.height);
    g.translate(0.5, 0.5);

    g.fillStyle = clr2;
    g.strokeStyle = clr1;

    g.beginPath();
    g.moveTo(0, 0);
    g.arc(0, 0, 0.45, Math.PI, -Math.PI);
    //g.closePath()

    g.moveTo(0, 0);
    g.arc(0, 0, 0.2, Math.PI, -Math.PI);
    //g.closePath()

    g.clip("evenodd");

    g.beginPath();
    g.arc(0, 0, 0.45, -Math.PI, Math.PI);
    g.fill();
    g.stroke();

    g.beginPath();
    g.arc(0, 0, 0.2, Math.PI, -Math.PI);
    g.stroke();

    g.beginPath();

    let th = this._value*Math.PI*2.0;

    let steps = 12;
    let dth = (Math.PI*2.0) / steps;
    let lwid = g.lineWidth;
    g.lineWidth *= 3;

    for (let i=0; i<steps; i++) {
      let th1 = i * dth;
      th1 += t;

      let r1 = 0.2;
      let r2 = 0.45;
      let th2 = th1 + dth*0.5;

      g.beginPath();
      g.moveTo(Math.cos(th1)*r1, Math.sin(th1)*r1);
      g.lineTo(Math.cos(th2)*r2, Math.sin(th2)*r2);
      g.strokeStyle = "rgba(255,255,255,0.5)";
      g.stroke();
    }

    g.lineWidth = lwid;

    g.beginPath();
    g.moveTo(0, 0);
    g.arc(0, 0, 0.4, Math.PI, -Math.PI);
    //g.closePath()

    g.clip("evenodd");

    g.beginPath();
    g.fillStyle = clr3;
    g.moveTo(0, 0);
    g.arc(0, 0, 0.45, 0, th);
    g.lineTo(0, 0);
    g.fill();

    g.strokeStyle = "rgb(141,154,196)";
    g.stroke();

    g.restore();
  }

  set value(percent) {
    this._value = percent;
    this.flagRedraw();
  }

  get value() {
    return this._value;
  }

  startTimer() {
    if (this.timer !== undefined) {
      return;
    }

    this.focus();

    window.setInterval(() => {
      if (!this.isConnected) {
        this.endTimer();
        return;
      }

      this.flagRedraw();
    }, 50);
  }

  endTimer() {
    if (this.timer !== undefined) {
      window.clearInterval(this.timer);
    }
    this.timer = undefined;
  }

  update() {
    if (!this.isConnected && this.timer) {
      this.endTimer();
    }

    let size = ~~(this.size*UIBase.getDPI());

    if (size !== this.canvas.width) {
      this.setCSS();
    }
  }

  setCSS() {
    let c = this.canvas;

    let size = ~~(this.size*UIBase.getDPI());

    if (c.width !== size) {
      c.width = c.height = size;

      size /= UIBase.getDPI();
      c.style["width"] = size + "px";
      c.style["height"] = size + "px";

      c.style["display"] = "flex";

      this.style["width"] = size + "px";
      this.style["height"] = size + "px";

      //forcibly redraw in this case, do not queue with flagRedraw
      this.draw();
    }

    this.style["display"] = "flex";
    this.style["align-items"] = "center";
    this.style["justify-content"] = "center";
    this.style["width"] = "100%";
    this.style["height"] = "100%";
  }

  static define() {
    return {
      tagname : "progress-circle-x"
    }
  }
}
UIBase.register(ProgressCircle);