Repository for Ideas & Research
Open Source GIS, Hydrologic Modeling, Optimization

HTML5

1   Canvas animation

http://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/

Uniqki code
#regex /^/#html /
<!--
A simulation model of an elastic collision

Author:    Huidae Cho
Copyright: (C) 2017, 2019, Huidae Cho <https://idea.isnew.info>
License:   GNU Affero General Public License v3
-->
<table style="border:0px;">
<tr><td>ax:</td><td><input id="ax" oninput="ball.x.acc=parseFloat(this.value)*0.1; reanimate()" /></td><td>ay:</td><td><input id="ay" oninput="ball.y.acc=parseFloat(this.value)*0.1; reanimate()" /></td></tr>
<tr><td>vx:</td><td><input id="vx" readonly="readonly" /></td><td>vy:</td><td><input id="vy" readonly="readonly" /></td></tr>
<tr><td style="text-align:right;">x:</td><td><input id="x" readonly="readonly" /></td><td style="text-align:right;">y:</td><td><input id="y" readonly="readonly" /></td></tr>
</table>
<canvas id="canvas-bouncing-ball" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas-bouncing-ball');
var context = canvas.getContext('2d');
var wall = {
  mass: 100000
};
var ball = {
  radius: 0,
  density: 1,
  mass: 0,
  x: {
    pos: 0,
    vel: 0,
    acc: 0.0*9.81,
    loss: 1, // loss from impact
    loss2: 0.01, // loss in x from y impact
  },
  y: {
    pos: 0,
    vel: 0,
    acc: 0.1*9.81,
    loss: 1, // loss from impact
    loss2: 0.01, // loss in y from x impact
  }
};
var Draw = {
  rectangle: function (x, y, w, h) {
    context.beginPath();
    context.rect(x, y, w, h);
    context.fillStyle = '#8ED6FF';
    context.fill();
    context.lineWidth = 2;
    context.strokeStyle = 'black';
    context.stroke();
  },
  circle: function(x, y, r) {
    context.beginPath();
    context.arc(x, y, r, 0, 2 * Math.PI, false);
    context.fillStyle = 'green';
    context.fill();
    context.lineWidth = 2;
    context.strokeStyle = '#003300';
    context.stroke();
  }
};

function move(coor1, coor2, min, max) {
  var vel1 = coor1.vel + coor1.acc;
  if (coor1.pos + vel1 >= min && coor1.pos + vel1 <= max) {
    coor1.vel = vel1;
    coor1.pos += coor1.vel;
  } else {
    var wallPos = coor1.pos + vel1 < min ? min : max;
    var t = (wallPos - coor1.pos) / vel1; // fraction of time before impact
    vel1 = coor1.vel + coor1.acc * t; // partially accelerated

    // conservations of momentum and kinetic energy
    coor1.vel = (ball.mass - wall.mass) / (ball.mass + wall.mass) * vel1;

    // other losses in coor1 from coor1 impact
    if (Math.abs(coor1.vel) > coor1.loss)
      coor1.vel = Math.sign(coor1.vel) * (Math.abs(coor1.vel) - coor1.loss);
    else
      coor1.vel = 0;

    coor1.pos = wallPos + coor1.vel;

    // other losses in coor2 from coor1 impact
    if (Math.abs(coor2.vel) > coor2.loss2)
      coor2.vel = Math.sign(coor2.vel) * (Math.abs(coor2.vel) - coor2.loss2);
    else
      coor2.vel = 0;
  }
}

function animate() {
  if (ball.x.vel == 0 && ball.y.vel == 0) {
    ball.radius = Math.random() * ((canvas.width - 6) * 0.1 - 1) + 10;
    ball.mass = ball.density * Math.PI * Math.pow(ball.radius, 2);
    ball.x.pos = Math.random() * (canvas.width - 2 * ball.radius - 4) + ball.radius + 2;
    ball.y.pos = Math.random() * (canvas.height - 2 * ball.radius - 4) + ball.radius + 2;
    ball.x.vel = Math.random() * 100 - 50;
    ball.y.vel = Math.random() * 100 - 50;
  }

  move(ball.x, ball.y, ball.radius + 2, canvas.width - ball.radius - 2);
  move(ball.y, ball.x, ball.radius + 2, canvas.height - ball.radius - 2);

  context.clearRect(0, 0, canvas.width, canvas.height);
  Draw.rectangle(1, 1, canvas.width - 2, canvas.height - 2);
  Draw.circle(ball.x.pos, ball.y.pos, ball.radius);

  reqID = requestAnimationFrame(animate);

  document.getElementById('x').value = ball.x.pos.toFixed(3);
  document.getElementById('y').value = ball.y.pos.toFixed(3);
  document.getElementById('vx').value = ball.x.vel.toFixed(3);
  document.getElementById('vy').value = ball.y.vel.toFixed(3);
}

function reanimate() {
  cancelAnimationFrame(reqID);
  ball.x.vel = ball.y.vel = 0;
  animate();
}

var reqID;
document.getElementById('ax').value = ball.x.acc.toFixed(3)*10;
document.getElementById('ay').value = ball.y.acc.toFixed(3)*10;
animate();
</script>
#noregex /^/
Uniqki output
ax:ay:
vx:vy:
x:y:

2   Web socket

2.1   Web socket screencasting

This .NET program takes the screen shot of a small window of the desktop and outputs pixel information every 1 second.

using System;
using System.Drawing;
using System.Threading;

namespace WebSocketScreencast
{
    class Program
    {
        static void Main(string[] args)
        {
            // https://stackoverflow.com/a/5049138
            using (Bitmap bmp = new Bitmap(100, 100))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    while (true)
                    {
                        g.CopyFromScreen(0, 0, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
                        for (int x = 0; x < 100; x++)
                        {
                            for (int y = 0; y < 100; y++)
                            {
                                Color color;

                                color = bmp.GetPixel(x, y);
                                Console.WriteLine("{0} {1} {2} {3} {4} {5}", x, y, color.R, color.G, color.B, color.A);
                            }
                        }
                        Console.WriteLine("draw");
                        Thread.Sleep(1000);
                    }
                }
            }
        }
    }
}

This comandline starts the web socket daemon to serve screencasting using the above .NET program.

websocketd.exe --staticdir=. --port 8000 cmd /c WebSocketScreencast.exe

The following HTML5 code receives the pixel information that the web socket daemon sends and draws it on the canvas.

<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var imageData = context.createImageData(100, 100);

function setPixel(imageData, x, y, r, g, b, a) {
  var index = (x + y * imageData.width) * 4;
  imageData.data[index+0] = r;
  imageData.data[index+1] = g;
  imageData.data[index+2] = b;
  imageData.data[index+3] = a;
}

function drawImage(imageData, x, y) {
  context.putImageData(imageData, x, y);
}

var ws = new WebSocket('ws://localhost:8000/');
ws.onmessage = function(event) {
  var data = event.data;
  if (data == "draw") {
    drawImage(imageData, 0, 0);
  } else {
    var d = data.split(" ");
    x = parseInt(d[0]);
    y = parseInt(d[1]);
    r = parseInt(d[2]);
    g = parseInt(d[3]);
    b = parseInt(d[4]);
    a = parseInt(d[5]);
    setPixel(imageData, x, y, r, g, b, a);
  }
};
</script>

3   SVG.js demo

Uniqki code
#regex /^/#html /
<input type="text" value="Dragon----- - - - ->" placeholder="Type text here...">
<div id="drawing"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.7.1/svg.min.js"></script>
<script>
var input = document.querySelector('input[type=text]')
var draw = SVG('drawing').viewbox(0, 0, 300, 140)
var text = draw.text(function(add) {
	add.tspan( input.value )
})

text
	.path('M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80')
	.animate(1000, '<>')
	.plot('M10 80 C 40 150, 65 150, 95 80 S 150 10, 180 80')
	.loop(true, true)

input.addEventListener('keyup', updateText(text))

function updateText(textPath) {
	return function() {
		textPath.tspan(this.value)
	}				
}
</script>
#noregex /^/
Uniqki output