dumb by default


dir: Home / Applets / canvas api test
published-date: 17 May 2025 09:39 +0700

canvas api test


  1{
  2
  3const canvas = document.getElementById("viewport");
  4const ctx = canvas.getContext("2d", {"alpha":false});
  5const w = canvas.width;
  6const h = canvas.height;
  7const pbuf = [0,0,0,0];
  8var i=0, j=0, x=0, y=0, rx=0, ry=0;
  9
 10const _SIN_LK_RES = 128;
 11const _SIN_LK = Array.from({length:_SIN_LK_RES+1}, (_, i) => (Math.sin(Math.PI*2*i/_SIN_LK_RES) + 1) / 2);
 12const ftoi = (v) => ~~v;
 13const sin01 = (v) => _SIN_LK[ftoi((v%1)*_SIN_LK_RES)];
 14
 15
 16function cTimer () {
 17  this.f = 0;
 18  this.fps = 0;
 19  this.t = 0;
 20  this.pt = 0;
 21  this.dt = 0;
 22  this.update = () => {
 23    this.f += 1;
 24    this.t = Date.now();
 25    this.dt = this.t - this.pt;
 26    this.pt = this.t;
 27    this.fps = this.dt > 0 ? ftoi(1 / this.dt * 1000) : NaN;
 28  }
 29  this.progress = (n_loop) => this.f % n_loop / Math.max(n_loop-1, 1)
 30}
 31const timer = new cTimer();
 32
 33
 34function cInputElementValuesProxy () {
 35  this.values = {};
 36  this.target = {};
 37  this.display = {};
 38  this.register = (name, _default=null, cast=(v)=>v) => {
 39    this.values[name] = null;
 40    this.target[name] = document.getElementById(name);
 41    this.display[name] = this.target[name].parentElement.querySelector("#" + name + "_value");
 42
 43    this.target[name].addEventListener("input", (event) => {
 44      this.values[name] = cast(event.target.value);
 45      if (this.display[name] !== null) {
 46        this.display[name].innerHTML = "" + event.target.value;
 47      }
 48    });
 49
 50    if (_default !== null) {
 51      this.target[name].value = _default;
 52      this.values[name] = cast(_default);
 53      this.display[name].innerHTML = "" + _default;
 54    }
 55  };
 56}
 57const p_inputs = new cInputElementValuesProxy();
 58p_inputs.register("loop", 100, parseInt);
 59
 60
 61function evalData(x, y) {
 62  rx = x/w;
 63  ry = y/h/2;
 64  rf = timer.progress(p_inputs.values.loop);
 65  pbuf[0] = ftoi(255 * sin01((rx*1 + ry*.2 + rf+1)));
 66  pbuf[1] = ftoi(255 * sin01((rx*1 + ry*.6 + rf*3)));
 67  pbuf[2] = ftoi(255 * sin01((rx*1 + ry*2 + rf*2)));
 68  pbuf[3] = 255;
 69}
 70
 71
 72function init() {
 73  ctx.fillStyle = "black";
 74  timer.update();
 75  canvasClear();
 76  window.requestAnimationFrame(update);
 77}
 78
 79
 80function canvasClear() {
 81  ctx.save();
 82  ctx.clearRect(0,0,w,h);
 83  ctx.fillStyle = "white";
 84  ctx.fillRect(0,0,w,h);
 85  ctx.restore();
 86}
 87
 88
 89function canvasDraw() {
 90  const imd = ctx.getImageData(0,0,w,h);
 91  for (i=0; i<imd.data.length; i+=4) {
 92    x = i/4 % w;
 93    y = Math.floor(i/4/w);
 94    evalData(x, y);
 95    for (j=0; j<4;j+=1) {
 96      imd.data[i+j] = pbuf[j];
 97    }
 98  }
 99  ctx.putImageData(imd, 0, 0);
100}
101
102
103function canvasDrawInfo() {
104  const iw = 130;
105  ctx.save();
106  ctx.fillStyle = "black";
107  ctx.fillRect(w-iw, h-16, iw, 16);
108  ctx.fillStyle = "white";
109  ctx.font = "12px monospace";
110  ctx.textBaseline = "middle";
111  ctx.fillText(timer.dt + "ms", w-iw+4, h-7);
112  ctx.fillText("fps:" + timer.fps, w-iw+44, h-7);
113  ctx.fillText(timer.f % p_inputs.values.loop, w-iw+96, h-7);
114  ctx.restore();
115}
116
117
118function update() {
119  timer.update();
120  canvasDraw();
121  canvasDrawInfo();
122  window.requestAnimationFrame(update);
123}
124
125init();
126
127}




Built with Hugo | previoip (c) 2025