Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here is the answer you wanted about growing hair.</p> <p>This also has the info you wanted about how to create a hair "object".</p> <p>Code and a Fiddle: <a href="http://jsfiddle.net/m1erickson/8K825/" rel="nofollow">http://jsfiddle.net/m1erickson/8K825/</a></p> <pre><code>&lt;!doctype html&gt; &lt;html&gt; &lt;head&gt; &lt;link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /&gt; &lt;!-- reset css --&gt; &lt;script type="text/javascript" src="http://code.jquery.com/jquery.min.js"&gt;&lt;/script&gt; &lt;style&gt; body{ background-color: ivory; } canvas{border:1px solid red;} &lt;/style&gt; &lt;script&gt; $(function(){ window.requestAnimationFrame = (function(callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var canvasOffset=$("#canvas").offset(); var offsetX=canvasOffset.left; var offsetY=canvasOffset.top; // the Hair "object" // Hair is a containing object that hosts a user-specified # of hairs var Hair = (function () { // constructor function Hair(x,y,width,height,haircount) { this.x=x; this.y=y; this.width=width; this.height=height; this.right=this.x+this.width; this.bottom=this.y+this.height; this.hairCount=haircount; this.startX=x+20; this.startY=y+height-3; //235; this.hairHeight=25; this.hairGrowth=0; this.lastEndX=[]; for(var i=0;i&lt;haircount;i++){ this.lastEndX[i]= x+20+(i*15); } } // grows the hair // works by changing the Y value of the end &amp; control points Hair.prototype.grow = function(increment){ this.hairGrowth+=increment; return(this.hairGrowth); } // draw all the hairs Hair.prototype.draw = function(mouseX){ // clear this object's space on the canvas // and set its styles ctx.clearRect(this.x,this.y,this.width,this.height); ctx.beginPath(); ctx.strokeStyle="grey"; ctx.lineWidth=7; ctx.lineCap = 'round'; ctx.beginPath(); for(var i=0;i&lt;this.hairCount;i++){ // straight hair var sx=cp1x=cp2x= this.startX+(i*15); var sy= this.startY; var cp1y = cp2y = (this.startY-(this.hairHeight+this.hairGrowth)/2); var endy = this.startY-this.hairHeight-this.hairGrowth; var endx = this.lastEndX[i]; // create bend, if any if(Math.abs(mouseX-sx)&lt;=10){ endx = sx+(mouseX-sx)*1.1; this.lastEndX[i]=endx; }; // draw this curve ctx.moveTo(sx,sy); ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,endx,endy); } // stroke ctx.stroke(); // temp outline ctx.lineWidth=1; ctx.beginPath(); ctx.rect(this.x,this.y,this.width,this.height); ctx.stroke(); } // return Hair; })(); var direction=1; var fps = 3; function animate() { setTimeout(function() { // change hair length var hairLength=hair.grow(direction); if(hairLength&lt;1 || hairLength&gt;10){ direction=(-direction); } // draw hair.draw(); // request next frame requestAnimationFrame(animate); }, 1000 / fps); } function handleMouseMove(e){ mouseX=parseInt(e.clientX-offsetX); mouseY=parseInt(e.clientY-offsetY); $("#movelog").html("Move: "+ mouseX + " / " + mouseY); // Put your mousemove stuff here if(mouseX&gt;=hair.x &amp;&amp; mouseX&lt;=hair.right &amp;&amp; mouseY&gt;=hair.y &amp;&amp; mouseY&lt;=hair.bottom){ hair.draw(mouseX); } } $("#canvas").mousemove(function(e){handleMouseMove(e);}); $("#grow").click(function(e){ animate(); }); // create a new patch of hair var hair=new Hair(25,50,150,50,8); hair.draw(225); }); // end $(function(){}); &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;p id="movelog"&gt;Move&lt;/p&gt; &lt;canvas id="canvas" width=300 height=200&gt;&lt;/canvas&gt;&lt;br&gt; &lt;button id="grow"&gt;Grow Hair&lt;/button&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <p><strong>[ Added: explanation of “Class” and instantiating an object from a class ]</strong></p> <p><code>var Hair=(function(){ …; return Hair; })()</code> creates a Hair “class”.</p> <p><code>var hair = new Hair(…)</code> creates an actual, usable Hair “object”. </p> <p>Think of the Hair-class as a template (or blueprint or cookie-cutter). All the code inside Hair-class only defines the properties and methods of the class. You don’t actually call any of the code in the Hair class. You just use it as a template to create actual hair objects. </p> <p>You can use the Hair class to create as many actual hair objects as you need—it’s reusable. The act of creating a hair object is known as “instantiating the Hair-class”.</p> <p>BTW, javascript does not actually have classes, so this is just a pseudo-class. But that’s a whole other explanation!</p> <p><em>You ask: What’s the use of direction=0.25?</em></p> <p>The direction variable is used to incrementally increase the height of hair when hair is “growing” during animation. The .25 tells the control/end points of the hair to go up by .25 pixels per animation frame.</p> <p><em>You ask: What’s the significance of callback function and that settimeout?</em></p> <p><code>setTimeout</code> is wrapping <code>requestAnimationFrame</code> so that the animation occurs at a fixed frame-per-second. </p> <p>RequestAnimationFrame (RAF) does a great job of optimizing performance, but you can’t control the frames-per-second with RAF alone. If you wrap RAF inside setTimeout, you can control the frames-per-second. For example, setTimeout(anyFunction,1000/fps) will trigger anyFunction about 3 times a second when fps==3. See this nice article on RAF+setTimeout: <a href="http://creativejs.com/resources/requestanimationframe/" rel="nofollow">http://creativejs.com/resources/requestanimationframe/</a></p> <p>As you discovered, RAF without setTimeout will still work, but RAF will try to grow your hair as quickly as possible, rather than with a fps interval.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload