<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<link rel="icon" src="/images/favicon.png" />
<title>graphing calculator thing, redux</title>
<style type="text/css">
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
line-height: 1.25em;
padding: 0; margin: 0; border: 0;
-webkit-tab-size: 4;
-moz-tab-size: 4;
-ms-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
background: #000; width: 100%; height: 100%;
text-align: center;
font-family: sans-serif;
}
body div * {
background: #888; margin: auto;
font-size: 2em; height: 1.5em;
}
div div { background: #000; color: #fff; }
body div canvas { width: 720px; height: 720px; display: block; }
input { width: 720px; }
button { width: 360px; border: 2px outset; }
input, button:active, button.active { border: 2px inset; }
</style>
<script type="text/javascript">
// evil global variables
var ele, scr, rsz, ctx, img, input, how = 0, stts, buttons;
async function draw () {
stts.innerHTML = "WORKING";
input.onkeydown = _ => true;
buttons.forEach(e => e.disabled = true);
input.disabled = true;
// deep sorcery...
await (async _ => new Promise(r => setTimeout(r, 0)))();
try {
if (!how) { // cartesian
for (var gy = 0; gy < rsz.height; gy++) {
for (var gx = 0; gx < rsz.width; gx++) {
addr = 4 * (gy * rsz.width + gx);
var y = 2 * (rsz.height / 2 - gy) / rsz.height;
var x = 2 * (gx - rsz.width / 2) / rsz.width;
var r = eval(input.value);
if (isNaN(r)) {
img.data[addr + 0] = 255;
img.data[addr + 1] = 0;
img.data[addr + 2] = 0;
img.data[addr + 3] = 255;
continue;
};
var red = 0;
var green = 0;
var blue = 0;
if (r > y) {
if (red || green || blue) {
red = (red + 255) / 2;
green = green / 2;
blue = blue / 2;
} else {
red = 255;
}
}
// TODO: replace this with a proper square root negation system
// see colors.html
if (-r > y) {
if (red || green || blue) {
red = red / 2;
green = (green + 255) / 2;
blue = (blue + 255) / 2;
} else {
green = 255;
blue = 255;
}
}
if (!x || !y) {
red = 255;
green = 255;
blue = 255;
}
img.data[addr + 0] = red;
img.data[addr + 1] = green;
img.data[addr + 2] = blue;
img.data[addr + 3] = 255;
}
/*
ctx.putImageData(img, 0, 0);
scr.drawImage(rsz, 0, 0, ele.width, ele.height);
await (async _ => new Promise(r => setTimeout(r, 0)))();
*/
}
} else { // polar
// radius = sqrt(x * x + y * y);
// theta = Math.acos(x / radius)
// x = Math.cos(theta) * radius;
// y = Math.sin(theta) * radius;
// x / radius = Math.cos(theta);
// y / radius = Math.sin(theta);
for (var gy = 0; gy < rsz.height; gy++) {
for (var gx = 0; gx < rsz.width; gx++) {
addr = 4 * (gy * rsz.width + gx);
var y = 2 * (rsz.height / 2 - gy) / rsz.height;
var x = 2 * (gx - rsz.width / 2) / rsz.width;
var red = 0;
var green = 0;
var blue = 0;
var flip = 1 - 2 * (y > 0);
y = Math.sqrt(x * x + y * y);
x = flip * Math.acos(x / y) / Math.PI; // should * 2?
y = y * 2 - 1;
if (isNaN(x)) {
img.data[addr + 0] = 255;
img.data[addr + 1] = 0;
img.data[addr + 2] = 0;
img.data[addr + 3] = 255;
continue;
};
var r = eval(input.value);
if (r > y) {
if (red || green || blue) {
red = (red + 255) / 2;
green = green / 2;
blue = blue / 2;
} else {
red = 255;
}
}
// TODO: replace this with a proper square root negation system
// see colors.html
if (-r > y) {
if (red || green || blue) {
red = red / 2;
green = (green + 255) / 2;
blue = (blue + 255) / 2;
} else {
red = 0;
green = 255;
blue = 255;
}
}
if (!isNaN(x) && 0 == x ||
Math.abs(y) < .0055) {
red = 255;
green = 255;
blue = 255;
}
img.data[addr + 0] = red;
img.data[addr + 1] = green;
img.data[addr + 2] = blue;
img.data[addr + 3] = 255;
}
/*
ctx.putImageData(img, 0, 0);
scr.drawImage(rsz, 0, 0, ele.width, ele.height);
await (async _ => new Promise(r => setTimeout(r, 0)))();
*/
}
}
ctx.putImageData(img, 0, 0);
scr.drawImage(rsz, 0, 0, ele.width, ele.height);
stts.innerHTML = "IDLE";
} catch (e) {
for (var i = 0; i < rsz.width * rsz.height * 4; i += 4) {
img.data[i + 0] = 127;
img.data[i + 1] = 127;
img.data[i + 2] = 127;
img.data[i + 3] = 255;
}
stts.innerHTML = e.toString();
}
input.onkeydown = e => 13 == e.keyCode && draw() || true;
input.disabled = false;
buttons.forEach(e => e.disabled = false);
input.focus();
}
onload = _ => {
// half-scale drawing context
rsz = document.createElement("canvas");
rsz.height = 720;
rsz.width = 720;
ctx = rsz.getContext("2d");
ctx.imageSmoothingEnabled = false;
img = ctx.createImageData(rsz.height, rsz.width);
// actual display canvas
ele = document.querySelector("canvas");
ele.height = rsz.height / 2;
ele.width = rsz.width / 2;
scr = ele.getContext("2d");
scr.imageSmoothingEnabled = false; // pixelate!
input = document.querySelector("input");
input.onkeydown = async e => 13 == e.keyCode && await draw() || true;
input.focus();
stts = document.querySelector("#status");
buttons = Array.from(document.querySelectorAll("button"));
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = (i => {
return async _ => {
buttons.forEach(e => e.classList.remove("active"));
buttons[i].classList.add("active");
how = i;
await draw();
};
})(i);
}
draw();
}
</script>
</head>
<body>
<div>
<input value="(Math.sqrt(1 - x * x) + Math.sin(Math.PI * x)) / 2" />
<canvas width="720px" height="720px">Y U no canvas?</canvas>
<button class="active">cartesian</button><button>polar</button>
<div id="status"></div>
</div>
</body>
</html>