First off, sorry about the bad title, I couldn't think of a better way to describe what I was trying to do. I have an HTML canvas, which, for argument's sake, is x pixels wide and y pixels tall. I have been trying to write a code that takes the location in the array of the canvas' image data of two pixels that are on lines z and z + 1 and fill in all the pixels in the higher row between the two pixels a certain color. I'm afraid I may not have made much sense, so here's a diagram:
Sorry about the poor graphics, but assume each rectangle is a pixel. The program should take in the first value for each of the black pixels (each is stored as r,g,b,a, the program gets the location of the r in the array representing the canvas' image data), and stores the r value for the lower pixel as bottomPixel
and the higher one as topPixel
. In this case, bottomPixel = 124
and topPixel = 112
It should use this to fill all pixels between the two base pixels a certain color. For example, using the previous pixel locations, the red pixels in the following picture should be colored in, but the blue one should not.
Here is the code I have: (Assume that the canvas has an Id "Canvas" and is 6px wide by 10px tall)
var cnvs = document.getElementById("Canvas");
cnvs.height = 10; //This height and width is here as an example.
cnvs.width = 6;
var cont = cnvs.getContext("2d");
var environment = cont.getImageData(0,0,6,10);
var bottomPixel = 124;//Not neccesarily 124 or 112, just example values
var topPixel = 112;
if ( bottomPixel - topPixel > 6*4 ) //If bottomPixel is to the right of topPixel
{
for ( var i = 0 ; i < ((bottomPixel-6*4)-topPixel)/4 ; i++ )
{
var index = topPixel + i * 4;
environment.data[index] = 0;
environment.data[index + 1 ] = 255;
environment.data[index + 2 ] = 0;
environment.data[index + 3 ] = 255;
}
}
if ( bottomPixel - topPixel > 6*4 ) //If bottomPixel is to the left of topPixel
{
for ( var i = 0 ; i < (topPixel-(bottomPixel-6*4))/4; i++ )
{
var index = topPixel - i * 4;
environment.data[index] = 0;
environment.data[index + 1 ] = 255;
environment.data[index + 2 ] = 0;
environment.data[index + 3 ] = 255;
}
}
I'd like to know why my code isn't doing what I previously described. If anything here needs clarification, please leave a comment. Thanks!
This is a method that works on the point coordinates and uses a the setPixel function to modify imageData. I'm using blue for start and black for end. You'll need to adjust for your exact condition but you can use setPixel to allow for direct x and y edits on the imageData.
update
I've included an alternate line method and your line method. There is also an animation that will help you find errors.
function ptIndex(p, w) {
return ((p.x|0) + ((p.y|0) * w)) * 4;
}
function setPixel(p, w, d, rgba) {
var i = ptIndex(p, w);
d[i] = rgba.r;
d[i + 1] = rgba.g;
d[i + 2] = rgba.b;
d[i + 3] = rgba.a;
}
function yourLine(p1, p2, w, d, rgba) {
var cnvs = document.getElementById("Canvas");
var bottomPixel = ptIndex(p1, w);
var topPixel = ptIndex(p2, w)
if (bottomPixel - topPixel > w * 4) //If bottomPixel is to the right of topPixel
{
for (var i = 0; i < ((bottomPixel - w * 4) - topPixel) / 4; i++) {
var index = topPixel + i * 4;
d[index] = rgba.r;
d[index + 1] = rgba.g;
d[index + 2] = rgba.b;
d[index + 3] = rgba.a
}
}
if (bottomPixel - topPixel > w * 4) //If bottomPixel is to the left of topPixel
{
for (var i = 0; i < (topPixel - (bottomPixel - w * 4)) / 4; i++) {
var index = topPixel - i * 4;
d[index] = rgba.r;
d[index + 1] = rgba.g;
d[index + 2] = rgba.b;
d[index + 3] = rgba.a
}
}
}
function drawRandPoints() {
var cnvs = document.getElementById("Canvas");
var cont = cnvs.getContext("2d");
// ghost last draw
cont.fillStyle = "white";
cont.fillRect(0, 0, cnvs.width, cnvs.height);
// get image data
var environment = cont.getImageData(0, 0, cnvs.width, cnvs.height);
var d = environment.data, w = cnvs.width;
// create colors
var black = {
r: 0,
g: 0,
b: 0,
a: 255
};
var red = {
r: 255,
g: 0,
b: 0,
a: 255
};
var blue = {
r: 0,
g: 0,
b: 255,
a: 255
};
var frames = 0;
var p1 = {x: ((cnvs.width / 2|0)), y: 0, sx: 1, sy:0};
var p2 = {x: cnvs.width, y: ((cnvs.height / 2)|0), sx: -1, sy: 0};
function step(p) {
if (p.x > cnvs.width) {
p.x = cnvs.width;
p.sx = 0;
p.sy = 1;
}
if (p.y > cnvs.height) {
p.y = cnvs.height;
p.sy = 0;
p.sx = -1;
}
if (p.x < 0) {
p.x = 0;
p.sx = 0;
p.sy = -1;
}
if (p.y < 0) {
p.y = 0;
p.sy = 0;
p.sx = 1;
}
}
function ani() {
cont.fillStyle = "white";
cont.fillRect(0, 0, cnvs.width, cnvs.height);
environment = cont.getImageData(0, 0, cnvs.width, cnvs.height);
d = environment.data;
step(p1);
step(p2);
var p3 = {
x: cnvs.width - p1.x,
y: cnvs.height - p2.y
};
var p4 = {
x: cnvs.width - p2.x,
y: cnvs.height - p1.y
};
yourLine(p1, p2, w, d, {r:0,g:255,b:0,a:255});
myDrawLine(p1, p2, w, d, red);
drawLineNoAliasing(p3, p4, w, d, blue);
setPixel(p1, w, d, black);
setPixel(p2, w, d, black);
frames %= 12;
p1.x += p1.sx;
p1.y += p1.sy;
p2.x += p2.sx;
p2.y += p2.sy;
// Put the pixel data on the canvas.
cont.putImageData(environment, 0, 0);
requestAnimationFrame(ani);
}
ani();
}
function myDrawLine(p1, p2, w, d, rgba) {
// Get the max length between x or y
var lenX = Math.abs(p1.x - p2.x);
var lenY = Math.abs(p1.y - p2.y);
var len = Math.sqrt(Math.pow(lenX,2) + Math.pow(lenY,2));
// Calculate the step increment between points
var stepX = lenX / len;
var stepY = lenY / len;
// If the first x or y is greater then make step negetive.
if (p2.x < p1.x) stepX *= -1;
if (p2.y < p1.y) stepY *= -1;
// Start at the first point
var x = p1.x;
var y = p1.y;
for (var i = 0; i < len; i++) {
x += stepX;
y += stepY;
// Make a point from new x and y
var p = {
x: x,
y: y
};
// Draw pixel on data
setPixel(p, w, d, rgba);
// reached goal (removes extra pixel)
if (Math.abs(p.x - p2.x) <= 1 && Math.abs(p.y - p2.y) <= 1) {
break;
}
}
// Draw start and end pixels. (might draw over line start and end)
setPixel(p1, w, d, rgba);
setPixel(p2, w, d, rgba);
}
// alternate from http://stackoverflow.com/questions/4261090/html5-canvas-and-anti-aliasing answer
// some helper functions
// finds the distance between points
function DBP(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
// finds the angle of (x,y) on a plane from the origin
function getAngle(x, y) {
return Math.atan(y / (x == 0 ? 0.01 : x)) + (x < 0 ? Math.PI : 0);
}
// the function
function drawLineNoAliasing(p1, p2, w, d, rgba) {
var dist = DBP(p1.x, p1.y, p2.x, p2.y); // length of line
var ang = getAngle(p2.x - p1.x, p2.y - p1.y); // angle of line
var cos = Math.cos(ang);
var sin = Math.sin(ang);
for (var i = 0; i < dist; i++) {
// for each point along the line
var pt = {
x: p1.x + cos * i,
y: p1.y + sin * i
};
setPixel(pt, w, d, rgba);
}
}
// end alt
drawRandPoints();
#Canvas {
border: 1px solid red image-rendering: optimizeSpeed;
/* Older versions of FF */
image-rendering: -moz-crisp-edges;
/* FF 6.0+ */
image-rendering: -webkit-optimize-contrast;
/* Safari */
image-rendering: -o-crisp-edges;
/* OS X & Windows Opera (12.02+) */
image-rendering: pixelated;
/* Awesome future-browsers */
image-rendering: optimize-contrast;
/* CSS3 Proposed */
-ms-interpolation-mode: nearest-neighbor;
/* IE */
}
<canvas id="Canvas" width="128" height="64" style="width:320px"></canvas>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With