Grass Swing Algorithm
UPDATE
I did an abbreviated update to better fit what I consider your requirements. To use the mouse, you simply calculate the angle between the mouse point and the warp root and use this for the new angle in the update.
I have included a simple mouse-sensitive approach that makes the stamps βpointβ to the mouse, but you can add random angles like delta, etc. to this. All you need is as indicated in the code - adjust if necessary.
New violin (based on the previous one with a few changes):
http://jsfiddle.net/AbdiasSoftware/yEwGc/

Image depicting 150 strains simulated.
Demo version of Grass model:
http://jsfiddle.net/AbdiasSoftware/5z89V/
This will create a nice realistic grass field. The demo has 70 herbs (works best in Chrome or just reduces the amount for Firefox).
The code is pretty simple. It consists of the main object ( grassObj ), which contains its geometry, as well as functions for calculating angles, segments, movements, etc. I will show it in detail below.
First, some elements that are available globally by function:
var numOfGrass = 70, /// number of grass strains grass, /// get canvas context ctx = canvas.getContext('2d'), w = canvas.width, h = canvas.height, /// we use an animated image for the background /// The image also clears the canvas for each loop call /// I rendered the clouds in a 3D software. img = document.createElement('img'), ix = 0, /// background image position iw = -1; /// used for with and initial for flag /// load background image, use it whenever it ready img.onload = function() {iw = this.width} img.src = 'http://i.imgur.com/zzjtzG7.jpg';
Heart - grassObj
The main object mentioned above is grassObj :
function grassObj(x, y, seg1, seg2, maxAngle) { /// exposed properties we need for rendering this.x = x; /// bottom position of grass this.y = y; this.seg1 = seg1; /// segments of grass this.seg2 = seg2; this.gradient = getGradient(Math.random() * 50 + 50, 100 * Math.random() + 170); this.currentAngle; ///current angle that will be rendered /// internals used for calculating new angle, goal, difference and speed var counter, /// counter between 0-1 for ease-in/out delta, /// random steps in the direction goal rel. c.angle. angle, /// current angle, does not change until goal is reached diff, /// diff between goal and angle goal = getAngle(); /// internal: returns an angel between 0 and maxAngle function getAngle() { return maxAngle * Math.random(); } /// ease in-out function function easeInOut(t) { return t < 0.5 ? 4 * t * t * t : (t-1) * (2 * t - 2) * (2 * t - 2) + 1; } /// sets a new goal for grass to move to. Does the main calculations function newGoal() { angle = goal; /// set goal as new angle when reached this.currentAngle = angle; goal = getAngle(); /// get new goal diff = goal - angle; /// calc diff counter = 0; /// reset counter delta = (4 * Math.random() + 1) / 100; } /// creates a gradient for this grass to increase realism function getGradient(min, max) { var g = ctx.createLinearGradient(0, 0, 0, h); g.addColorStop(1, 'rgb(0,' + parseInt(min) + ', 0)'); g.addColorStop(0, 'rgb(0,' + parseInt(max) + ', 0)'); return g; } /// this is called from animation loop. Counts and keeps tracks of /// current position and calls new goal when current goal is reached this.update = function() { /// count from 0 to 1 with random delta value counter += delta; /// if counter passes 1 then goal is reached -> get new goal if (counter > 1) { newGoal(); return; } /// ease in/out function var t = easeInOut(counter); /// update current angle for render this.currentAngle = angle + t * diff; } /// init newGoal(); return this; }
Grass generator
We call makeGrass to generate grass in random positions, random heights and random segments. The function is called with the amount of grass to render, the width and height of the canvas to fill, and the variable change in percent (0 - 1 float).
The only grass consists of only four points. The two midpoints are distributed approximately 1/3 and 2/3 of the total height with a slight change in the gap. The points are smoother when rendering, using a cardinal spline with full tension to make the grass look smooth.
function makeGrass(numOfGrass, width, height, hVariation) { /// setup variables var x, y, seg1, seg2, angle, hf = height * hVariation, /// get variation i = 0, grass = []; /// array to hold the grass /// generate grass for(; i < numOfGrass; i++) { x = width * Math.random(); /// random x position y = height - hf * Math.random(); /// random height /// break grass into 3 segments with random variation seg1 = y / 3 + y * hVariation * Math.random() * 0.1; seg2 = (y / 3 * 2) + y * hVariation * Math.random() * 0.1; grass.push(new grassObj(x, y, seg1, seg2, 15 * Math.random() + 50)); } return grass; }
Render
The render function simply projects objects and updates the current geometry:
function renderGrass(ctx, grass) { /// local vars for animation var len = grass.length, i = 0, gr, pos, diff, pts, x, y; /// renders background when loaded if (iw > -1) { ctx.drawImage(img, ix--, 0); if (ix < -w) { ctx.drawImage(img, ix + iw, 0); } if (ix <= -iw) ix = 0; } else { ctx.clearRect(0, 0, w, h); } /// loops through the grass object and renders current state for(; gr = grass[i]; i++) { x = gr.x; y = gr.y; ctx.beginPath(); /// calculates the end-point based on length and angle /// Angle is limited [0, 60] which we add 225 deg. to get /// it upwards. Alter 225 to make grass lean more to a side. pos = lineToAngle(ctx, x, h, y, gr.currentAngle + 225); /// diff between end point and root point diff = (pos[0] - x) pts = []; /// starts at bottom, goes to top middle and then back /// down with a slight offset to make the grass pts.push(x); /// first couple at bottom pts.push(h); /// first segment 1/4 of the difference pts.push(x + (diff / 4)); pts.push(h - gr.seg1); /// second segment 2/3 of the difference pts.push(x + (diff / 3 * 2)); pts.push(h - gr.seg2); pts.push(pos[0]); /// top point pts.push(pos[1]); /// re-use previous data, but go backward down to root again /// with a slight offset pts.push(x + (diff / 3 * 2) + 10); pts.push(h - gr.seg2); pts.push(x + (diff / 4) + 12); pts.push(h - gr.seg1 + 10); pts.push(x + 15); /// end couple at bottom pts.push(h); /// smooth points (extended context function, see demo) ctx.curve(pts, 0.8, 5); ctx.closePath(); /// fill grass with its gradient ctx.fillStyle = gr.gradient; ctx.fill(); } }
Animate
The main loop where we animate everything:
function animate() {
And all this for this version.