This repository has been archived by the owner on Feb 6, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
389 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,247 @@ | |||
/* | |||
Drawing polygons using slanted borders technique | |||
by Andrey Kuzmin unsoundscapes@gmail.com MIT licensed | |||
*/ | |||
|
|||
(function() { | |||
|
|||
function getInternetExplorerVersion() | |||
// Returns the version of Internet Explorer or a -1 | |||
// (indicating the use of another browser). | |||
{ | |||
var rv = -1; // Return value assumes failure. | |||
if (navigator.appName == 'Microsoft Internet Explorer') | |||
{ | |||
var ua = navigator.userAgent; | |||
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); | |||
if (re.exec(ua) != null) | |||
rv = parseFloat( RegExp.$1 ); | |||
} | |||
return rv; | |||
} | |||
|
|||
function DivCanvas(element) { | |||
this.element = element; | |||
this.cache = ""; | |||
this.opacity = 1; | |||
this.transparent = 'transparent'; | |||
this.filter = ''; | |||
|
|||
this.ie = getInternetExplorerVersion(); | |||
if (this.ie > 5 && this.ie < 8) { | |||
this.transparent = this.ieHackColor; | |||
this.filter = ";filter: chroma(color=" + this.ieHackColor + ")"; | |||
} | |||
} | |||
|
|||
DivCanvas.prototype = { | |||
roundMethod: Math.round, // could be parseInt, but looks uglier | |||
ieHackColor: 'cyan', | |||
setOpacity: function(opacity) { | |||
this.opacity = opacity; | |||
if(this.ie>5 && this.ie<8) | |||
this.filter = ";filter:chroma(color=" + this.ieHackColor + ")" + | |||
(opacity==1 ? "" : " alpha(opacity=" + parseInt(opacity*100) + ")"); | |||
else if (this.ie>5 && this.ie<9) | |||
this.filter = (opacity==1 ? "" : ";filter:alpha(opacity=" + parseInt(opacity*100) + ")"); | |||
else | |||
this.filter = opacity==1 ? "" : ";opacity:" + opacity; | |||
return this; | |||
}, | |||
triangle: function(x, y, color) { | |||
this._tri(x, y, color); | |||
return this; | |||
}, | |||
polygon: function(x, y, color) { | |||
var n = x.length; | |||
if (n < 3) return false; | |||
var V = new Array(n); | |||
/* we want a counter-clockwise polygon in V */ | |||
if ( 0.0 < this._area(x,y) ) | |||
for (var v=0; v<n; v++) V[v] = v; | |||
else | |||
for (var v=0; v<n; v++) V[v] = (n-1)-v; | |||
var nv = n; | |||
/* remove nv-2 Vertices, creating 1 triangle every time */ | |||
var count = 2 * nv; /* error detection */ | |||
for(var m=0, v=nv-1; nv>2; ) | |||
{ | |||
/* if we loop, it is probably a non-simple polygon */ | |||
if (0 >= (count--)) return false; //** Triangulate: ERROR - probable bad polygon! | |||
/* three consecutive vertices in current polygon, <u,v,w> */ | |||
var u = v ; if (nv <= u) u = 0; /* previous */ | |||
v = u+1; if (nv <= v) v = 0; /* new v */ | |||
var w = v+1; if (nv <= w) w = 0; /* next */ | |||
if ( this._snip(x,y,u,v,w,nv,V) ) | |||
{ | |||
var a,b,c,s,t; | |||
/* true names of the vertices */ | |||
a = V[u]; b = V[v]; c = V[w]; | |||
this._tri([x[c],x[a],x[b]], [y[c],y[a],y[b]], color ) | |||
m++; | |||
/* remove v from remaining polygon */ | |||
for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--; | |||
/* resest error detection counter */ | |||
count = 2*nv; | |||
} | |||
} | |||
return this; | |||
}, | |||
circle: function(x, y, r, color) { | |||
var dx1=r, dx2, dy1=0, dy2, da = 10; | |||
for(var a = da; a <= 90; a+= da){ | |||
dx2 = this.roundMethod(r*Math.cos((a) * Math.PI / 180)) | |||
dy2 = this.roundMethod(-r*Math.sin((a) * Math.PI / 180)) | |||
this._trapezoid(x - dx1, y - dy1, dx1 - dx2, dx1 - dx2, dy1 - dy2, dx2 * 2, color) | |||
this._trapezoid(x - dx1, y + dy1, dx1 - dx2, dx1 - dx2, dy2 - dy1, dx2 * 2, color) | |||
dx1 = dx2 | |||
dy1 = dy2 | |||
} | |||
return this; | |||
}, | |||
textCircle: function(x, y, r, color) { | |||
var x = parseInt(x - 1.379*r), | |||
y = parseInt(y-2.61*r), | |||
size = parseInt(r*4.61) | |||
this.cache += "<span class='p' style='left:"+ | |||
x + "px;top:" + y + "px;font-family:Arial;font-size:" + | |||
size + "px; color:" + color + "'>●</span>" | |||
return this | |||
}, | |||
flush: function() { | |||
this.element.innerHTML += this.cache; | |||
this.cache = ""; | |||
return this; | |||
}, | |||
empty: function() { | |||
this.element.innerHTML = ""; | |||
return this; | |||
}, | |||
_area: function(x, y) { | |||
var n = x.length, A = 0.0; | |||
for(var p=n-1,q=0; q<n; p=q++) | |||
A+= x[p] * y[q] - x[q] * y[p]; | |||
return A * 0.5; | |||
}, | |||
_isInsideTriangle: function(Ax, Ay, Bx, By, Cx, Cy, Px, Py) { | |||
return (Cx - Bx) * (Py - By) - (Cy - By) * (Px - Bx) >= 0 && | |||
(Bx - Ax) * (Py - Ay) - (By - Ay) * (Px - Ax) >= 0 && | |||
(Ax - Cx) * (Py - Cy) - (Ay - Cy) * (Px - Cx) >= 0; | |||
}, | |||
_snip: function(x, y, u, v, w, n, V) { | |||
var Ax, Ay, Bx, By, Cx, Cy; | |||
Ax = x[V[u]]; Ay = y[V[u]]; | |||
Bx = x[V[v]]; By = y[V[v]]; | |||
Cx = x[V[w]]; Cy = y[V[w]]; | |||
if ( 0.0000000001 > (Bx-Ax)*(Cy-Ay) - (By-Ay)*(Cx-Ax) ) return false; | |||
for (var p=0;p<n;p++){ | |||
if( p == u || p == v || p == w ) continue; | |||
if (this._isInsideTriangle(Ax,Ay,Bx,By,Cx,Cy,x[V[p]],y[V[p]])) return false; | |||
} | |||
return true; | |||
}, | |||
_tri: function(x, y, color) { | |||
if(x[2]==x[1] || x[2]==x[0] || x[1]==x[0]) | |||
if(y[2]==y[1] || y[2]==y[0] || y[1]==y[0]) | |||
this._rightTri(x, y, color); | |||
else | |||
this._splitV(x, y, color); | |||
else | |||
this._splitH(x, y, color); | |||
}, | |||
_sortOrder: function(a) { | |||
if(a[0] > a[1]) | |||
if(a[1] > a[2]) | |||
return [0, 1, 2]; | |||
else | |||
return a[0] > a[2] ? [0, 2, 1] : [2, 0, 1]; | |||
else | |||
if(a[0] > a[2]) | |||
return [1, 0, 2]; | |||
else | |||
return a[1] > a[2] ? [1, 2, 0] : [2, 1, 0]; | |||
}, | |||
_splitH: function(x, y, color) { | |||
var p = this._sortOrder(x); | |||
if(y[p[0]]==y[p[2]] && x[p[2]] < x[p[1]] < x[p[0]]) { | |||
this._trapezoid(x[p[2]], y[p[2]], x[p[1]]-x[p[2]],x[p[0]]-x[p[1]], | |||
y[p[1]]-y[p[0]], 0, color); | |||
return | |||
} | |||
var y0 = this.roundMethod((y[p[2]] - y[p[0]]) * | |||
(x[p[1]] - x[p[0]]) / (x[p[2]] - x[p[0]]) + y[p[0]]); | |||
this._tri([x[p[0]], x[p[1]], x[p[1]]], [y[p[0]], y[p[1]], y0], color); | |||
this._tri([x[p[2]], x[p[1]], x[p[1]]], [y[p[2]], y[p[1]], y0], color); | |||
}, | |||
_splitV: function(x, y, color) { | |||
var p = this._sortOrder(y); | |||
if(x[p[0]]==x[p[2]] && y[p[2]] < y[p[1]] < y[p[0]]) { | |||
this._trapezoidH(x[p[2]], y[p[2]], y[p[0]]-y[p[1]], | |||
y[p[1]]-y[p[2]], x[p[1]]-x[p[0]], 0, color); | |||
return | |||
} | |||
var x0 = this.roundMethod((x[p[2]] - x[p[0]]) * | |||
(y[p[1]] - y[p[0]]) / (y[p[2]] - y[p[0]]) + x[p[0]]); | |||
this._tri([x[p[0]], x[p[1]], x0], [y[p[0]], y[p[1]], y[p[1]]], color); | |||
this._tri([x[p[2]], x[p[1]], x0], [y[p[2]], y[p[1]], y[p[1]]], color); | |||
}, | |||
_rightTri: function(x, y, color) | |||
/* | |||
Iterates through all combinations to find | |||
the position of the right corner | |||
*/ | |||
{ | |||
for(var i=0, c; i<6; i++) { | |||
c = [[0, 1, 2], [1, 2, 0], [2, 0, 1], [1, 0, 2], [0, 2, 1], [2, 1, 0]][i]; | |||
if(x[c[0]]==x[c[1]] && y[c[0]]==y[c[2]]) | |||
return this._rightTriangle(x[c[0]], y[c[0]], x[c[2]]-x[c[0]], y[c[1]]-y[c[0]], color); | |||
} | |||
}, | |||
_rightTriangle: function(x, y, dx, dy, color) | |||
/* | |||
Draws right triangle based on right angle, | |||
endpoint coordinates, and catheti | |||
|\ | |||
| \ | |||
dy | \ | |||
| \ | |||
| \ | |||
(x,y) o_____\ | |||
dx | |||
*/ | |||
{ | |||
this.cache += "<div class='p' style='left:" + | |||
(x + (dx<0 ? dx : 0)) + "px;top:" + | |||
(y + (dy<0 ? dy : 0)) + "px;border-" + | |||
(dx>0 ? "left" : "right") + ":" + Math.abs(dx) + "px solid " + color + | |||
";border-" + (dy>0 ? "bottom:" : "top:") + Math.abs(dy) + "px solid " + | |||
this.transparent + this.filter + | |||
"'></div>"; | |||
}, | |||
_trapezoid: function(x, y, dx1, dx2, dy, w, color) { | |||
this.cache += "<div class='p' style='left:" + | |||
x + "px; top: " + | |||
(y + (dy < 0 ? dy : 0)) + "px; width: " + w + "px; border-left:" + | |||
Math.abs(dx1) + "px solid " + this.transparent + "; border-right:" + | |||
Math.abs(dx2) + "px solid " + this.transparent + "; border-" + | |||
(dy < 0 ? "bottom:" : "top:") + Math.abs(dy) + "px solid " + color + this.filter + | |||
"'></div>"; | |||
}, | |||
_trapezoidH: function(x, y, dy1, dy2, dx, h, color) { | |||
this.cache += "<div class='p' style='left:" + | |||
(x + (dx < 0 ? dx : 0)) + "px; top: " + | |||
y + "px; height: " + h + "px; border-top:" + | |||
Math.abs(dy2) + "px solid " + this.transparent + "; border-bottom:" + | |||
Math.abs(dy1) + "px solid " + this.transparent + "; border-" + | |||
(dx<0 ? "right:" : "left:") + Math.abs(dx) + "px solid " + color + this.filter + | |||
"'></div>"; | |||
} | |||
}; | |||
|
|||
this.DivCanvas = DivCanvas; | |||
|
|||
}).call(this) | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,34 @@ | |||
|
|||
body { | |||
background: gray; | |||
} | |||
|
|||
|
|||
/* | |||
Canvas styles | |||
should at least have | |||
position: relative | |||
*/ | |||
#divcanvas { | |||
background: white; | |||
width: 640px; | |||
height: 480px; | |||
margin: auto; | |||
margin-top: 100px; | |||
position: relative; | |||
} | |||
|
|||
|
|||
/* Basic css for generated elements */ | |||
div.p { | |||
position: absolute; | |||
overflow: hidden; | |||
width: 0px; | |||
height: 0px; | |||
} | |||
/* Used in textCircle */ | |||
span.p { | |||
position: absolute; | |||
cursor: default; | |||
line-height: 1; | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,108 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<title>DivCanvas</title> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |||
<link rel="stylesheet" href="style.css" type="text/css" media="screen"> | |||
<script src="divcanvas.js" type="text/javascript"></script> | |||
</head> | |||
<body> | |||
<div id="divcanvas"></div> | |||
<script> | |||
// Init canvas | |||
var canvas = new DivCanvas(document.getElementById("divcanvas")); | |||
|
|||
// Draw triangles | |||
// canvas.triangle([470, 100, 300], [70, 400, 60], "red") | |||
// canvas.triangle([70, 400, 30], [270, 200, 100], "blue") | |||
// canvas.triangle([620, 200, 100], [170, 400, 360], "green") | |||
|
|||
// Test different circle methods | |||
//canvas.setOpacity(.5) | |||
//canvas.textCircle(460, 160, 100, "#b00") | |||
canvas.circle(460, 160, 100, "#b00") | |||
|
|||
// Draw crane shape | |||
var k = 2, dx = 100, dy = 380, // coefficients to scale and translate shape | |||
crane = [ | |||
{ | |||
x: [48, 49, -19, -32, -6], | |||
y: [-44, -17, -11, -33, -103], | |||
c: "#c7d7e5" | |||
}, | |||
{ | |||
x: [-25, -26, -32, 55, 55, 54, 54, 57, 50, 22, 13, 5, 0, -10, -19, -75], | |||
y: [-14, 11, 28, 33, 27, 22, 19, 19, -18, -21, -21, -15, -16, -18, -18, -101], | |||
c: "#394e4d" | |||
}, | |||
{ | |||
x: [-78, -27, -22, -22, -76], | |||
y: [-100, 13, 0, -14, -103], | |||
c: "#628183" | |||
}, | |||
{ | |||
x: [-79, -26, -33, -77], | |||
y: [-97, 12, -13, -102], | |||
c: "#aac7db" | |||
}, | |||
{ | |||
x: [31, 24, 21, 44, 45, 34, 87, 93], | |||
y: [-57, -29, -8, 10, 7, -52, -51, -55], | |||
c: "#668082" | |||
}, | |||
{ | |||
x: [46, 48, 38, 34 ], | |||
y: [10, 2, -51, -53], | |||
c: "#344747" | |||
}, | |||
{ | |||
x: [28, 32, 92, 94], | |||
y: [-57, -66, -60, -55], | |||
c: "#879aa3" | |||
}, | |||
{ | |||
x: [35, 29, 32, 27, 25, 23, 30, 34, 93], | |||
y: [-61, -59, -66, -63, -54, -22, -54, -57, -55], | |||
c: "#fbfbfb" | |||
}, | |||
{ | |||
x: [-24, -16, -2, 13, 42, 39, -67, -70, -54, -32], | |||
y: [10, -5, -11, -10, 20, 35, 106, 103, 46, 31], | |||
c: "#e1e9ee" | |||
}, | |||
{ | |||
x: [-20, -11, 3, 16, 29, 34, 25, 5, -10, -30], | |||
y: [10, 0, -8, -6, 9, 22, 28, 34, 33, 30], | |||
c: "#b0c7d2" | |||
}, | |||
{ | |||
x: [30, 41, 38, -64, -67, -70, -66, 42, 43], | |||
y: [7, 22, 34, 104, 105, 105, 108, 35, 20], | |||
c: "#567e7c" | |||
}, | |||
{ | |||
x: [16, 0, -6], | |||
y: [-77, -55, -102], | |||
c: "#acbdca" | |||
}, | |||
{ | |||
x: [-57, -66, -27, -28], | |||
y: [68, 103, 77, 52], | |||
c: "#f7f9fa" | |||
} | |||
] | |||
|
|||
for (var i=0, x, y, j, n, l=crane.length; i<l; i++) { | |||
x = [], y = [] | |||
for (j=0, n=crane[i].x.length; j<n; j++) { | |||
x[j] = crane[i].x[j] * k + dx | |||
y[j] = crane[i].y[j] * k + dy | |||
} | |||
canvas.polygon(x, y, crane[i].c) | |||
} | |||
|
|||
// Show the drawing | |||
canvas.flush() | |||
</script> | |||
</body> | |||
</html> |