210 lines
5.2 KiB
JavaScript
210 lines
5.2 KiB
JavaScript
// Cell size; the width/height of each pixel
|
|
var cs = 30;
|
|
// The zoom level
|
|
var zoom = 0;
|
|
// The list of pixels to shade
|
|
var pix = [];
|
|
// The x and y offsets
|
|
var xoff, yoff;
|
|
// If the canvas or circle need updating
|
|
var updateCanvas = true;
|
|
var updateCircle = true;
|
|
// The circle's radius
|
|
var rad = 5.1;
|
|
// The accuracy of the circle
|
|
var steps = 8000;
|
|
// The cell size below which the grid is not drawn
|
|
var gridShow = 10;
|
|
// Whether or not the center is even
|
|
var evenCenter = false;
|
|
|
|
// Theme colors
|
|
var BACKGR, FOREGR, COLOR;
|
|
|
|
//Create the canvas, initialize the input fields, and set the theme colors.
|
|
function setup() {
|
|
var canvas = createCanvas(900, 675);
|
|
canvas.parent('canvas-wrapper');
|
|
document.getElementById('radius-slider').value = rad;
|
|
document.getElementById('radius-text').value = rad;
|
|
document.getElementById('even-center').value = evenCenter;
|
|
document.getElementById('accuracy').value = steps;
|
|
xoff = width / 2 - cs / 2;
|
|
yoff = height / 2 - cs / 2;
|
|
resetPix();
|
|
BACKGR = color(220);
|
|
FOREGR = color(100);
|
|
COLOR = color(30, 160, 60);
|
|
document.getElementById("defaultCanvas0").onwheel = function (event) {
|
|
event.preventDefault();
|
|
};
|
|
document.getElementById("defaultCanvas0").onmousewheel = function (event) {
|
|
event.preventDefault();
|
|
};
|
|
}
|
|
|
|
//Delete the old circle and create the highlighted center
|
|
function resetPix() {
|
|
pix = [];
|
|
pix.push({ x: 0, y: 0, c: COLOR });
|
|
if (evenCenter) {
|
|
pix.push({ x: 0, y: 1, c: COLOR });
|
|
pix.push({ x: 1, y: 0, c: COLOR });
|
|
pix.push({ x: 1, y: 1, c: COLOR });
|
|
}
|
|
}
|
|
|
|
//When an update occurs, redraw the canvas on the next frame.
|
|
function draw() {
|
|
if (updateCanvas || updateCircle) {
|
|
background(BACKGR);
|
|
// If only the canvas is updated, the circle doesn't need to be retraced.
|
|
if (updateCircle) {
|
|
resetPix();
|
|
// Slightly decrease the radius in certian cases to prevent glitches.
|
|
var r = rad;
|
|
if (!evenCenter && abs(round(r) - r) == 0.5)
|
|
r -= 0.00000001;
|
|
else if (evenCenter && round(r) - r == 0)
|
|
r -= 0.00000001;
|
|
// Trace the circle to find which pixels are inside it.
|
|
traceCircle(r);
|
|
}
|
|
// Draw the colored pixels to the screen.
|
|
drawPix();
|
|
stroke(0);
|
|
strokeWeight(1);
|
|
// If not zoomed out too far, draw the grid.
|
|
if (cs > gridShow)
|
|
drawGrid(xoff, yoff, cs);
|
|
// Draw the highlighted circle path.
|
|
drawCirclePath()
|
|
// Do not update again immediately after this.
|
|
updateCircle = false;
|
|
updateCanvas = false;
|
|
}
|
|
}
|
|
|
|
//Draw the grid of horsizontal and veritcal lines.
|
|
function drawGrid(xoff, yoff, gap) {
|
|
for (var x = xoff % gap; x < width; x += gap) {
|
|
line(x, 0, x, height);
|
|
}
|
|
for (var y = yoff % gap; y < height; y += gap) {
|
|
line(0, y, width, y);
|
|
}
|
|
}
|
|
|
|
var lastX, lastY;
|
|
//Start the drag.
|
|
function mousePressed() {
|
|
lastX = mouseX;
|
|
lastY = mouseY;
|
|
}
|
|
|
|
//Move the image around when dragged.
|
|
function mouseDragged() {
|
|
if (mouseX > 0 && mouseY > 0) {
|
|
xoff += mouseX - lastX;
|
|
yoff += mouseY - lastY;
|
|
lastX = mouseX;
|
|
lastY = mouseY;
|
|
updateCanvas = true;
|
|
}
|
|
}
|
|
|
|
//Zoom in and out by scrolling.
|
|
function mouseWheel(event) {
|
|
if(mouseX >= 0 && mouseX < width && mouseY >= 0 && mouseY < height) {
|
|
var c = event.delta;
|
|
var f = (c > 0) ? 8 / 9 : (c < 0) ? 9 / 8 : 1;
|
|
cs *= f;
|
|
xoff = (xoff - mouseX) * f + mouseX;
|
|
yoff = (yoff - mouseY) * f + mouseY;
|
|
updateCanvas = true;
|
|
}
|
|
}
|
|
|
|
//Find which pixels are in the path of the circle by tracing it.
|
|
function traceCircle(r) {
|
|
var lx, ly;
|
|
var cx = 0, cy = 0;
|
|
if (evenCenter) { cx = 0.5; cy = 0.5; }
|
|
// Go around the circle in <steps> number of steps
|
|
for (var ang = 0; ang < 1; ang += 1 / steps) {
|
|
var x = round(r * cos(ang * TAU) + cx);
|
|
var y = round(r * sin(ang * TAU) + cy);
|
|
// If the location is different from the previous one...
|
|
if (x != lx || y != ly) {
|
|
// ...create a shaded pixel at the location
|
|
var obj = { x: x, y: y, c: color(FOREGR) };
|
|
pix.push(obj);
|
|
lx = x;
|
|
ly = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw the colored pixels to the screen
|
|
function drawPix() {
|
|
noStroke()
|
|
for (var i = 0; i < pix.length; i++) {
|
|
fill(pix[i].c);
|
|
rect(pix[i].x * cs + xoff, pix[i].y * cs + yoff, cs, cs);
|
|
}
|
|
}
|
|
|
|
// Draw the colored circle path
|
|
function drawCirclePath() {
|
|
noFill();
|
|
// Choose stroke weight based on zoom level
|
|
if (cs > 20) strokeWeight(2.5);
|
|
else if (cs > gridShow) strokeWeight(1.5);
|
|
else strokeWeight(1);
|
|
var cx = 0, cy = 0;
|
|
if (evenCenter) { cx = 0.5; cy = 0.5; }
|
|
stroke(COLOR);
|
|
ellipse(xoff + cx * cs + cs / 2, yoff + cy * cs + cs / 2, 2 * rad * cs, 2 * rad * cs);
|
|
}
|
|
|
|
// Change the radius of the circle
|
|
function updateRadius(value) {
|
|
// Make sure the slider and text field match.
|
|
document.getElementById('radius-slider').value = value;
|
|
document.getElementById('radius-text').value = value;
|
|
rad = value;
|
|
updateCircle = true;
|
|
}
|
|
|
|
|
|
// Change the accuracy.
|
|
function updateAccuracy(value) {
|
|
if (value != 0) {
|
|
steps = +value;
|
|
updateCircle = true;
|
|
}
|
|
}
|
|
|
|
// Change the center between odd (one pixel) and even (four pixels).
|
|
function updateCenter(value) {
|
|
old = evenCenter
|
|
if (old == true && value == false) {
|
|
xoff += 0.5 * cs;
|
|
yoff += 0.5 * cs;
|
|
} else if (old == false && value == true) {
|
|
xoff -= 0.5 * cs;
|
|
yoff -= 0.5 * cs;
|
|
}
|
|
evenCenter = value;
|
|
|
|
updateCircle = true;
|
|
}
|
|
|
|
// Reset drag and zoom.
|
|
function resetMotion() {
|
|
zoom = 0;
|
|
cs = 60;
|
|
xoff = width / 2 - cs / 2;
|
|
yoff = height / 2 - cs / 2;
|
|
updateCircle = true;
|
|
}
|