I recently wanted to make a She Loves Me, She Loves Me Not Game using JavaScript and SVG. My requirements were: 1) Support a random number of petals. 2) The petals should be clickable. Turns out these two requirements make for some fun JavaScript and Geometry.

Here is an image of what I was going for.

The first thing I tackled was the basic infrastructure of the flower. The following Flower function handles generating a random number of petals and the state of the game messages.

// by Jason Rowe - jasonrowe.com @jsonrow function Flower(thee, numberOfPetals) { var petals = numberOfPetals; if(!petals && petals !== 0){ petals = Math.floor(Math.random()* 5) + 5; } var originalTotalNumberOfPetals = petals; this.totalPetals = function () { return originalTotalNumberOfPetals; } this.removePetal = function(){ if(petals > 0){ petals = petals - 1; } return petals; }; this.petals = function(){ return petals; }; var love = false; this.toggleLove = function(){ love = !love; return love; }; this.isItLove = function(){ return love; }; this.result = function(){ var message; if(this.toggleLove()){ message = thee + " loves me"; } else{ message = thee + " loves me not"; } return message; }; }

The next thing was to get the actual drawing of the flower. The first challenge I ran into was creating a random number of petals equally distributed around the center of the flower. To do this I used the polar coordinate system.

var totalPetals = flowerData.petals(); for(var i = 0; i < totalPetals; i++){ log("creating petal"); // Creates Circle Polar Coordinate System var radius = 83; var centerX = 170; var centerY = 160; // get x, y position of the petals var xPosition = radius * Math.cos(2 * Math.PI * i / totalPetals) + centerX; var yPosition = radius * Math.sin(2 * Math.PI * i / totalPetals) + centerY; ....

It quickly became apparent that I needed more Geometry to point the petals in the right direction.

So to help find the correct rotation, I created a TrianglePointsToDegrees function which would solve the angles I needed.

//by Jason Rowe - jasonrowe.com @jsonrow 2013 //Given a triangle with points (x1, y1, x2, y2, x3, y3), // calculates angles A,B,C and edges a,b,c // // // lower case a,b,c are the edges // upper case A,B,C are angles // (x1, y1) // /\ // b / C\ a // / \ // / \ // (x2,y2)/A______B\(x3, y3) // c function TrianglePointsToDegrees(x1, y1, x2, y2, x3, y3){ //distance formula to find lengths between points function lineDistance( point1, point2 ){ var xs = 0; var ys = 0; xs = point2.x - point1.x; xs = xs * xs; ys = point2.y - point1.y; ys = ys * ys; return Math.sqrt( xs + ys ); }; log("create points"); var point1 = {"x": x1, "y": y1}; var point2 = {"x": x2, "y": y2}; var point3 = {"x": x3, "y": y3}; log("create triangle edges"); var edgeA = {}; edgeA.points = [point3, point1]; edgeA.distance = lineDistance(point3, point1); this.edgeA = function(){ return edgeA; }; var edgeB = {}; edgeB.points = [point1, point2]; edgeB.distance = lineDistance(point1, point2); this.edgeB = function(){ return edgeB; }; var edgeC = {}; edgeC.points = [point2, point3]; edgeC.distance = lineDistance(point2, point3); this.edgeC = function(){ return edgeC; }; var sidea = edgeA.distance; var sideb = edgeB.distance; var sidec = edgeC.distance; log("calc angles"); var anga = Math.acos((-sidea*sidea+sideb*sideb+sidec*sidec)/(2*sideb*sidec)); var angb = Math.acos((-sideb*sideb+sidea*sidea+sidec*sidec)/(2*sidea*sidec)); var angc = Math.acos((-sidec*sidec+sidea*sidea+sideb*sideb)/(2*sidea*sideb)); this.aDegree = function(){ return anga*180/Math.PI; }; this.bDegree = function(){ return angb*180/Math.PI; }; this.cDegree = function(){ return angc*180/Math.PI; }; }

Then after creating my x, y coordinates, I found the angle I needed, and completed the ellipse rotation

var totalPetals = flowerData.petals(); for(var i = 0; i < totalPetals; i++){ log("creating petal"); // Creates Circle Polar Coordinate System var radius = 83; var centerX = 170; var centerY = 160; // get x, y position of the petals var xPosition = radius * Math.cos(2 * Math.PI * i / totalPetals) + centerX; var yPosition = radius * Math.sin(2 * Math.PI * i / totalPetals) + centerY; var ellipseHeight = 70; var petalEllipse = this.paper.ellipse(xPosition, yPosition, 30, ellipseHeight); var angle = null; if(xPosition !== centerX){ var triangle = new TrianglePointsToDegrees(xPosition, yPosition, centerX, centerY, xPosition, yPosition + ellipseHeight) if(xPosition > centerX){ angle = triangle.cDegree(); } else{ angle = -triangle.cDegree(); } } //rotate ellipse around center if(angle){ petalEllipse.transform("r" + angle); }

The final fun Geometry was the stem which is a quadratic Bézier curve. I mostly just used trial and error to get the intermediate points Q “M 150 150, **Q 210 227** 150 300 **Q 70 400** 150 450″. The other points are just the start, middle, and end of the line.

var stem = this.paper.path("M 150 150, Q 210 227 150 300 Q 70 400 150 450") stem.attr({stroke:'#47D147',"stroke-width":5}); stem.attr("width", 5);

I recently made a similar flower but since I’m not good at maths found a much easier way to angle them correctly around the flower using save and restore and simply rotating the canvas by Math.PI*2/numberofpetals each time I draw one within a for loop(Which is inside the save and restore). Hope you understand xD Much less time was spent.

Very nice, that sounds like the right way to do it if using canvas. I’m using SVG which doesn’t seem to have the same concept. The method would work in SVG but might take a bit more work. The library I’m using Raphael doesn’t have a way to create parent child relationships. If I could get around that, I could add the petals to the a common element and rotate it as you suggested. It seems like I would be fighting a bit with SVG library I’m using but yes it could be done.