I really appreciate the non-antialiased, jagged style of digital imagery so my goal for this assignment was to create some sort of collaborative tool for exploring glitchy, abstract visuals taking advantage of this style.
The user draws horizontal or vertical lines (even numbered connection counts are assigned horizontal lines, odds are vertical) along the small 200px canvas by dragging the mouse button. So for users creating vertical lines, at each mouse position along the x-axis of the canvas, a for loop iterates through each pixel in the column and fills it with a 1px black rectangle. In order to keep the canvas from just being filled completely black I made it so that pixels that are already black are turned white.
The result is a lot of unexpected behavior, rendering each canvas image unique, even between users on the same canvas.
The algorithm for filling pixels is as follows:
canvas.addEventListener('mousemove', function(evt) {
//when mouse is pressed
if (isMouseDown) {
//draw pixel at current mousepos:
if (numUsers % 2 == 0) { //if even number of users
//set the user to horizontal
drawLineHor_(evt.clientY, context);
} else { //if odd number of users
//set the user to vertical
drawLineVer_(evt.clientX, context);
}
//send drawing
var objtosend = {
x: evt.clientX,
y: evt.clientY,
px: px,
py: py,
userNum: numUsers
};
socket.emit('drawing', objtosend);
}
//receive drawing
socket.on('drawing', function(receivedData) {
if (receivedData.userNum % 2 == 0) { //if this user is even
//set the user to horizontal
drawLineHor(receivedData.y, context);
} else { // if this user is odd
//set the user to vertical
drawLineVer(receivedData.x, context);
}
});
});
//these functions could probably all be consolidated somehow
function drawLineHor(y, ctx) {
for (var x = 0; x < canvas.width; x++) {
//get color
var p = ctx.getImageData(x, y, 1, 1).data;
//compare color
if (p == "0,0,0,255") { //if black
//set to clear
ctx.fillStyle = white;
} else { //if clear
ctx.fillStyle = black;
}
//fill this pixel
ctx.fillRect(x, y, 1, 1);
}
}
function drawLineVer(x, ctx) {
for (var y = 0; y < canvas.height; y++) {
//get color
var p = ctx.getImageData(x, y, 1, 1).data;
//compare color
if (p == "0,0,0,255") { //if black
//set to clear
ctx.fillStyle = white;
} else { //if clear
ctx.fillStyle = black;
}
//fill this pixel
ctx.fillRect(x, y, 1, 1);
}
}
function drawLineHor_(y, ctx) {
for (var x = 0; x < canvas.width; x++) {
ctx.fillStyle = black;
ctx.fillRect(x, y, 1, 1);
}
}
function drawLineVer_(x, ctx) {
for (var y = 0; y < canvas.height; y++) {
ctx.fillStyle = black;
ctx.fillRect(x, y, 1, 1);
}
}
I found that there is no way to get perfect, 1px non-antialiased lines in a canvas with the built-in drawing methods. One trick is to translate the entire canvas half a pixel (ctx.translate(0.5, 0.5)
) to offset the interpolation that causes 1px lines to fill 2px, but this still doesn’t keep lines 1px when drawn at angles. So what I did instead (which also allowed me individual pixel control) was make 1px sized rects with ctx.fillRect(x,y,1,1)
. The canvas thus is so small because this requires large for loops which is detrimental to performance.