Reputation: 3434
I'm trying to practice with HTML5 canvas drawing so I came up with this. I should result in a yellow star that is overlapped by a green silhouette of a bust (the head and shoulders of a person).
However if the drawStar() line is un-commented, the green silhouette is not drawn. Is this Working code is not as important as an explanation of what is happening.
http://jsfiddle.net/xiondark2008/LYfHJ/2/
HTML:
<!DOCTYPE html>
<html>
<head>
<style>
h6{
-webkit-margin-before: .5em;
-webkit-margin-after: 0;
}
label{
margin-left: 1em;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="19" height="19"
style="border:1px solid d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
</html>
javascript:
function drawProfile(ctx,x,y,width,height) {
this.flp = false;
this.x = function(r){ return Math.floor(width*(this.flp?1-r:r)); }
this.y = function(r){ return Math.floor(height*r); }
ctx.save();
ctx.translate( x, y );
ctx.fillStyle="#40FF00";
ctx.beginPath();
ctx.moveTo( this.x(0), this.y(1) );
ctx.bezierCurveTo(
this.x(0), this.y(125/190),
this.x(70/190), this.y(170/190),
this.x(75/190), this.y(120/190)
);
ctx.lineTo( this.x(95/190), this.y(130/190) );
ctx.bezierCurveTo(
this.x(40/190), this.y(130/190),
this.x(30/190), this.y(0),
this.x(95/190), this.y(0)
);
this.flp = true;
ctx.bezierCurveTo(
this.x(30/190), this.y(0),
this.x(40/190), this.y(130/190),
this.x(95/190), this.y(130/190)
);
ctx.lineTo( this.x(75/190), this.y(120/190) );
ctx.bezierCurveTo(
this.x(70/190), this.y(170/190),
this.x(0), this.y(125/190),
this.x(0), this.y(1)
);
ctx.fill();
this.flp = false;
ctx.restore();
}
function drawStar(ctx,x,y,height) {
var pnts = 5,
rad = height/(1-Math.cos(0.8*Math.PI));
this.x = function(p,dst){
return dst * Math.sin( (p/pnts)*2*Math.PI );
}
this.y = function(p,dst){
return dst * Math.cos( (p/pnts)*2*Math.PI ) * -1;
}
this.movePct = function(a,b,pct){
var f = (function(x){
var m = (b.y-a.y)/(b.x-a.x);
return m*x+(a.y-(a.x*m));
}).bind(),
r = b.x - a.x,
point = {};
point.x = a.x+(r*pct);
point.y = f(point.x);
return point;
}
this.transPoints = function(s,p,e,pct){
var sp = this.movePct(s,p,pct),
ep = this.movePct(e,p,pct);
return [sp,ep];
}
ctx.save();
ctx.translate( x+rad, y+rad );
ctx.fillStyle = "#ffff00";
ctx.beginPath();
for(var i=0;i<pnts;i++){
var dst = rad/2,
s = { x: this.x( i+0.5, dst ),
y: this.y( i+0.5, dst ) },
p = { x: this.x( i+1, rad ),
y: this.y( i+1, rad ) },
e = { x: this.x( i+1.5, dst ),
y: this.y( i+1.5, dst ) },
t = this.transPoints(s,p,e,.75);
if(i==0){ ctx.moveTo( s.x, s.y ); }
ctx.lineTo(t[0].x, t[0].y);
ctx.quadraticCurveTo(p.x, p.y, t[1].x, t[1].y);
ctx.lineTo(e.x, e.y);
}
ctx.fill();
ctx.restore();
}
function draw(c) {
var ctx = c.getContext("2d");
this.x = function(r){ return c.width*r; }
this.y = function(r){ return c.height*r; }
ctx.shadowBlur=this.y(1/19);
ctx.shadowColor="black";
//drawStar( ctx, this.x(-3/19), this.y(-1/19), this.y(20/19) );
drawProfile( ctx, this.x(6/19), this.y(1/19), this.x(18/19), this.y(18/19) );
if(0){
ctx.clearRect( this.x(1), this.y(0), this.x(1), this.y(1) );
ctx.clearRect( this.x(0), this.y(1), this.x(1), this.y(1) );
}
}
draw( document.getElementById("myCanvas") );
Upvotes: 1
Views: 190
Reputation: 125
Joe is right. You are overwriting the this.x and this.y functions. I don't know why you are doing this. I made a workaround by resetting the this.x and this.y functions to their old value at the end of the functions drawProfile and drawStar:
function drawProfile(ctx,x,y,width,height) {
var oldX = this.x, //storing the old values for this.x ...
oldY = this.y; // ... and this.y
this.flp = false;
this.x = function(r){ return Math.floor(width*(this.flp?1-r:r)); }
this.y = function(r){ return Math.floor(height*r); }
ctx.save();
ctx.translate( x, y );
ctx.fillStyle="#40FF00";
ctx.beginPath();
ctx.moveTo( this.x(0), this.y(1) );
ctx.bezierCurveTo( this.x(0), this.y(125/190),
this.x(70/190), this.y(170/190),
this.x(75/190), this.y(120/190)
);
ctx.lineTo( this.x(95/190), this.y(130/190) );
ctx.bezierCurveTo( this.x(40/190), this.y(130/190),
this.x(30/190), this.y(0),
this.x(95/190), this.y(0)
);
this.flp = true;
ctx.bezierCurveTo( this.x(30/190), this.y(0),
this.x(40/190), this.y(130/190),
this.x(95/190), this.y(130/190)
);
ctx.lineTo( this.x(75/190), this.y(120/190) );
ctx.bezierCurveTo( this.x(70/190), this.y(170/190),
this.x(0), this.y(125/190),
this.x(0), this.y(1)
);
ctx.fill();
this.flp = false;
ctx.restore();
this.x = oldX; //Restoring old values
this.y = oldY;
}
function drawStar(ctx,x,y,height)
{
var pnts = 5,
rad = height/(1-Math.cos(0.8*Math.PI)),
oldX = this.x, //storing the old values for this.x ...
oldY = this.y; // ... and this.y
this.x = function(p,dst){
return dst * Math.sin( (p/pnts)*2*Math.PI );
}
this.y = function(p,dst){
return dst * Math.cos( (p/pnts)*2*Math.PI ) * -1;
}
this.movePct = function(a,b,pct){
var f = (function(x){
var m = (b.y-a.y)/(b.x-a.x);
return m*x+(a.y-(a.x*m));
}).bind(),
r = b.x - a.x,
point = {};
point.x = a.x+(r*pct);
point.y = f(point.x);
return point;
}
this.transPoints = function(s,p,e,pct){
var sp = this.movePct(s,p,pct),
ep = this.movePct(e,p,pct);
return [sp,ep];
}
ctx.save();
ctx.translate( x+rad, y+rad );
ctx.fillStyle = "#ffff00";
ctx.beginPath();
for(var i=0;i<pnts;i++){
var dst = rad/2,
s = { x: this.x( i+0.5, dst ),
y: this.y( i+0.5, dst ) },
p = { x: this.x( i+1, rad ),
y: this.y( i+1, rad ) },
e = { x: this.x( i+1.5, dst ),
y: this.y( i+1.5, dst ) },
t = this.transPoints(s,p,e,.75);
if(i==0){ ctx.moveTo( s.x, s.y ); }
ctx.lineTo(t[0].x, t[0].y);
ctx.quadraticCurveTo(p.x, p.y, t[1].x, t[1].y);
ctx.lineTo(e.x, e.y);
}
ctx.fill();
ctx.restore();
this.x = oldX; //Resetting the old values
this.y = oldY;
}
function draw(c)
{
var ctx = c.getContext("2d");
this.x = function(r){ return c.width*r; }
this.y = function(r){ return c.height*r; }
ctx.shadowBlur=this.y(1/19);
ctx.shadowColor="black";
drawStar( ctx, this.x(-3/19), this.y(-1/19), this.y(20/19) );
drawProfile( ctx, this.x(6/19), this.y(1/19), this.x(18/19), this.y(18/19) );
if(0){
ctx.clearRect( this.x(1), this.y(0), this.x(1), this.y(1) );
ctx.clearRect( this.x(0), this.y(1), this.x(1), this.y(1) );
}
}
draw( document.getElementById("myCanvas") );
Upvotes: 0
Reputation: 47609
You're using this
in your functions. In the context here, this
is bound to window
(there are lots of resources out there about how to use this
, and you're doing it incorrectly).
In each function that you use this
, is is bound to the same thing (window
) so they over-write each other's variables. (This is because of the way you're using the functions. If you new
ed them it would be a different story).
So
draw()
method sets this.x
, which is actually window.x
,drawStar()
as an argumentdrawStar()
function method changes the value of this.x
(which is window.x
) and returns back to draw()
draw()
calls drawProfile()
with this.x
(which is window.x
), except this time its value is a function rather than the float value you wanted it to be.(for x
read x
and y
)
You can do this all with closures and variables. Remove the this
es and your program will work. Probably.
Upvotes: 2