Xmin Ymin
Xmax Ymax
Xmin Ymin
Xmax Ymax
<body>
<script>
var width = 500;
var height = 500;
var lastvalue = 0;
canvas = new Canvas(width,height);
function DoDisplay(value) {
if (value == undefined) {
value = lastvalue;
}
lastvalue = value;
canvas.Clear();
switch (value) {
case '0':
LineTest(canvas);
break;
case '1':
DrawIt(canvas);
break;
case '2':
Circle(canvas);
break;
case '3':
Dragon(canvas);
break;
default:
}
canvas.Redisplay();
return;
}
canvas.Clear();
DoDisplay('0');
canvas.Redisplay();
</script>
<p>
<select onchange="DoDisplay(this.value)">
<option value="0">Line Test</option>
<option value="1">Data Test</option>
<option value="2">Circle</option>
<option value="3">Dragon</option>
</select>
<hr>
Window :
<p>
X<sub>min</sub> <input type="text" id="wxn" length = "4" size="4">
Y<sub>min</sub> <input type="text" id="wyn" length = "4" size="4">
<p>
X<sub>max</sub> <input type="text" id="wxx" length = "4" size="4">
Y<sub>max</sub> <input type="text" id="wyx" length = "4" size="4">
<p>
<button type="button" id="Redraw"
onclick="canvas.SetWindow();DoDisplay()">
Set
</button>
<hr>
Viewport :
<p>
X<sub>min</sub> <input type="text" id="vxn" length = "4" size="4">
Y<sub>min</sub> <input type="text" id="vyn" length = "4" size="4">
<p>
X<sub>max</sub> <input type="text" id="vxx" length = "4" size="4">
Y<sub>max</sub> <input type="text" id="vyx" length = "4" size="4">
<p>
<button type="button" id="Redraw"
onclick="canvas.SetViewport();DoDisplay()">
Set
</button>
<script>
canvas.FixInput();
</script>
<hr>
<hr>
function Canvas(width, height, locID) {
if (width == undefined || width < 0) {
width = 300;
}
if (height == undefined || height < 0) {
height = 300;
}
var canvas = document.createElement('canvas')
canvas.height = height;
canvas.width = width;
canvas.style = "border:1px solid #000000;";
if(locID == undefined) {
document.body.appendChild(canvas);
} else {
div = document.getElementById(locID);
if (null == div) {
document.body.appendChild(canvas);
} else {
div.appendChild(canvas);
}
}
document.body.appendChild(canvas);
this.width = width;
this.height = height;
this.clearColor = {"R":255, "G": 255, "B": 255}
this.ctx = canvas.getContext("2d");
this.fastLines = true;
this.frameBuffer = new Array(this.width);
for(var x = 0; x < this.width; x++) {
this.frameBuffer[x] = new Array(this.height);
for(var y=0; y < this.height; y++) {
this.frameBuffer[x][y] = {"R": this.clearColor.R,
"G": this.clearColor.G, "B": this.clearColor.B};
}
}
this.windowXMin = 0;
this.windowXMax = Math.round(this.width);
this.windowYMin = 0;
this.windowYMax = Math.round(this.height);
this.viewportXMin = 0;
this.viewportXMax = this.width;
this.viewportYMin = 0;
this.viewportYMax = this.height;
return this;
}
Canvas.prototype = {
// ui elements.
SetClearColor: function(r,g,b) {
this.clearColor.R = r;
this.clearColor.G = g;
this.clearColor.B = b;
return;
},
SetViewport: function() {
node = document.getElementById("vxn");
vxn = parseInt(node.value);
node = document.getElementById("vxx");
vxx = parseInt(node.value);
if (vxn == vxx) {
this.FixInput();
} else if (vxn > vxx) {
tmp = vxx;
vxx = vxn;
vxn = tmp;
}
node = document.getElementById("vyn");
vyn = parseInt(node.value);
node = document.getElementById("vyx");
vyx = parseInt(node.value);
if (vyn == vyx) {
this.FixInput();
} else if (vyn > vyx) {
tmp = vyx;
vyx = vyn;
vyn = tmp;
}
this.viewportXMin = vxn;
this.viewportXMax = vxx;
this.viewportYMin = vyn;
this.viewportYMax = vyx;
return;
},
SetWindow: function() {
node = document.getElementById("wxn");
wxn = parseInt(node.value);
node = document.getElementById("wxx");
wxx = parseInt(node.value);
if (wxn == wxx) {
this.FixInput();
} else if (wxn > wxx) {
tmp = wxx;
wxx = wxn;
wxn = tmp;
}
node = document.getElementById("wyn");
wyn = parseInt(node.value);
node = document.getElementById("wyx");
wyx = parseInt(node.value);
if (wyn == wyx) {
this.FixInput();
} else if (wyn > wyx) {
tmp = wyx;
wyx = wyn;
wyn = tmp;
}
this.windowXMin = wxn;
this.windowXMax = wxx;
this.windowYMin = wyn;
this.windowYMax = wyx;
return;
},
FixInput: function() {
document.getElementById("wxn").value = this.windowXMin;
document.getElementById("wxx").value = this.windowXMax;
document.getElementById("wyn").value = this.windowYMin;
document.getElementById("wyx").value = this.windowYMax;
document.getElementById("vxn").value = this.viewportXMin;
document.getElementById("vxx").value = this.viewportXMax;
document.getElementById("vyn").value = this.viewportYMin;
document.getElementById("vyx").value = this.viewportYMax;
return;
},
Width: function() {
return this.width;
},
Height: function() {
return this.height;
},
Clear: function() {
for(var x = 0; x < this.width; x++) {
for(var y=0; y < this.height; y++) {
this.frameBuffer[x][y].R = this.clearColor.R;
this.frameBuffer[x][y].G = this.clearColor.G;
this.frameBuffer[x][y].B = this.clearColor.B;
}
}
return;
},
Redisplay: function() {
for(var x = 0; x < this.width; x++) {
for(var y=0; y < this.height; y++) {
color = "rgb(" + this.frameBuffer[x][y].R
+ ", " + this.frameBuffer[x][y].G
+ ", " + this.frameBuffer[x][y].B +")";
this.ctx.fillStyle = color;
this.ctx.fillRect(x,y,1,1);
}
}
return;
},
SetPoint: function(x,y,r,g,b) {
if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
// this if is a very bad form of clipping
if (x >= this.viewportXMin && x <= this.viewportXMax
&& y>=this.viewportYMin && y <= this.viewportYMax) {
this.frameBuffer[x][y].R = Clamp(0,255,r);
this.frameBuffer[x][y].G = Clamp(0,255,g);
this.frameBuffer[x][y].B = Clamp(0,255,b);
}
}
return;
},
TransformX: function (x) {
var xNDC
var xDC
xNDC = (x-this.windowXMin)* 2/(this.windowXMax-this.windowXMin) -1;
// note this SHOULD be simplified
xDC = (xNDC+1) * (this.viewportXMax-this.viewportXMin)/2
+ this.viewportXMin;
return Math.round(xDC);
},
TransformY: function(y) {
var yNDC,
yDC;
// note this SHOULD be simplified
yNDC = (y-this.windowYMin) * 2 / (this.windowYMax-this.windowYMin)-1;
yDC = (-1* yNDC +1) *(this.viewportYMax-this.viewportYMin)/2
+ this.viewportYMin;
return Math.round(yDC);
},
Point: function(x,y, r,g,b) {
xs = this.TransformX(x);
ys = this.TransformY(y);
this.SetPoint(xs,ys,r,g,b);
},
Line: function(x1, y1, r1, g1, b1, x2, y2, r2, g2, b2) {
console.log("orig", x1, y1, x2, y2);
var xs = this.TransformX(x1)
var xe = this.TransformX(x2);
var ys = this.TransformY(y1);
var ye = this.TransformY(y2);
console.log('transformed ' , xs,xe, ys, ye);
this.BruteLine(xs, ys, r1, g1, b1, xe, ye, r2, g2, b2);
},
BruteLine: function(x1, y1, r1, g1, b1, x2, y2, r2, g2, b2) {
var dx = x2-x1;
var dy = y2-y1;
var m = dy/dx; // may be NAN but will not be used.
var x,y,dir;
if (dx == 0 && dy == 0) {
// attempt to draw a degenerate line (a point)
this.SetPoint(x1, y1, r1, g1,b1)
} else if (dx == 0) {
// no change in x, so it is a vertical line
var sy = Math.min(y1,y2);
var ey = Math.max(y1, y2);
for(y=sy; y <= ey; y++) {
this.SetPoint(x1,y,r1,g1,b1);
}
} else if (dy == 0) {
// no change in y so it is a horizontal line.
var sx = Math.min(x1,x2);
var ex = Math.max(x1, x2);
for(x=sx; x <= ex; x++) {
this.SetPoint(x,y1,r1,g1,b1);
}
} else if (Math.abs(dx) > Math.abs(dy) ) {
if (dx < 0) {
dir = -1;
} else {
dir = 1;
}
for(x=x1; x!= x2; x+= dir) {
y = Math.round(y1+m*(x-x1));
this.SetPoint(x,y,r1,g1,b1);
}
} else {
if (dy < 0) {
dir = -1;
} else {
dir = 1;
}
for(y=y1; y != y2; y+= dir) {
x = Math.round(x1 + 1/m*(y-y1));
this.SetPoint(x,y,r1,g1,b1);
}
}
return;
},
};
function Clamp(min, max, v) {
return Math.max(min, Math.min(v,max));
}
var X=0,
Y = 1,
R = 2,
G = 3,
B = 4;
data = [
[ "line", [ 10,10,255,0,0], [20,20,0,0,255], [30,30,0,255,0]],
[ "polygon", [100,100,0,255,255], [110,100,0,255,255],
[110,110,0,255,255], [100,110,0,255,255]],
];
function DrawPolyLine(canvas, ary) {
for(var p =1; p < ary.length-1; p++) {
canvas.Line(
ary[p][X],ary[p][Y], ary[p][R],ary[p][G],ary[p][B],
ary[p+1][X],ary[p+1][Y], ary[p+1][R],ary[p+1][G],ary[p+1][B]) ;
}
return;
}
function DrawPolygon(canvas, ary) {
DrawPolyLine(canvas, ary);
var a = 1, b = ary.length-1;
canvas.Line(
ary[b][X],ary[b][Y], ary[b][R],ary[b][G],ary[b][B],
ary[a][X],ary[a][Y], ary[a][R],ary[a][G],ary[a][B]) ;
return;
}
function DrawIt(canvas) {
var shape,point;
for(shape=0; shape < data.length; shape ++) {
console.log("drawing a ", data[shape][0]);
if (data[shape][0] == "line") {
DrawPolyLine(canvas, data[shape]);
} else if (data[shape][0] == "polygon") {
DrawPolygon(canvas, data[shape]);
}
}
return;
}
function Dragon(canvas) {
DrawPolyLine(canvas, dragon[0]);
return;
}
function Circle(canvas) {
var t;
var x1,y1;
var x2,y2;
var r = Math.min(canvas.Width()/2, canvas.Height()/2)*.9;
var xc, yc;
var step = 30;
xc = 0;
yc = 0;
t = 0;
for (var R = 20; R <= r ; R+= 10) {
x1 = xc + Math.round(R * Math.cos(t*Math.PI/180));
y1 = yc + Math.round(R * Math.sin(t*Math.PI/180));
for(t=step;t<360; t+= step) {
x2 = xc + Math.round(R * Math.cos(t*Math.PI/180));
y2 = yc + Math.round(R * Math.sin(t*Math.PI/180));
canvas.Line(x1, y1, 0,0,0, x2, y2 , 255, 0,0);
x1 = x2;
y1 = y2;
}
t = 360;
x2 = xc + Math.round(R * Math.cos(t*Math.PI/180));
y2 = yc + Math.round(R * Math.sin(t*Math.PI/180));
canvas.Line(x1, y1, 255,0,0, x2, y2 , 255, 0,0);
}
canvas.Point(xc, yc, 255,0,0);
}
function LineTest(canvas) {
var xm = -200;
var ym = -200;
var xx = -100;
var yx = -100;
// draw a horizontal line left to right.
canvas.Line(xm,ym, 0,0,0, xx,ym , 0, 0, 0 );
// draw a horizontal line right to left
canvas.Line(xx,yx, 0,0,0, xm, yx, 0, 0, 0 );
// draw a vertical line top to bottom
canvas.Line (xm, yx, 0, 0, 0, xm, ym, 0,0,0);
// draw a vertical line bottom to top.
canvas.Line (xx, ym, 0, 0, 0, xx, yx, 0,0,0);
// four diagionals.
canvas.Line(xm,ym,0,0,0, xx,yx,0,0,0);
canvas.Line(xx,yx,0,0,0, xm,ym,0,0,0);
canvas.Line(xx,ym,0,0,0, xm,yx,0,0,0);
canvas.Line(xm,yx,0,0,0, xx,ym,0,0,0);
var xc = Math.round((xx+xm)/2);
var yc = Math.round((yx+ym)/2);;
var r = Math.min(Math.abs(xx-xm),Math.abs(yx,ym))*.7;
var x,y;
var t;
for(t=0;t<360;t+=10) {
x = xc + Math.round(r*Math.cos(t*Math.PI/180));
y = yc + Math.round(r*Math.sin(t*Math.PI/180));
canvas.Line(xc, yc,255,0,0, x,y,155,42,0);
}
}