官术网_书友最值得收藏!

Creating complex shapes

It's time to take everything we learned and integrate it into the most complex shape we have seen so far, the Star of David. This star is part of the flag of Israel (one of my favorite flags in the world ;)). We need to take a roundabout before we can create it by visiting the magical world of sine and cosine.

Creating complex shapes

You got to love it, right? I know many people fear cosines and sines but actually they are really easy and fun to work with. Let's break them down here in a more programming-for-drawing type of way. The most basic idea is that you have a triangle that has a 90 degree angle. You have some information about this triangle, and that's all you need to be able to start working with sine and cosine. Once you know that you have a 90 degree angle and know the sine/cosine, you have all the information you need and with it you can discover any missing information. In our case we know all the angles and we know the length of the hypotenuse (it's our radius; take a look at the image with the circle to see it in action). In JavaScript, the methods Math.cos() and Math.sin() are both representing a circle with a radius of one located on the (0,0) point on the screen. If we input the angle we are looking for into the sin function, it would return the x value (in this case the length of the adjacent) and the cos function would return the length of the opposite, in our case the required value y.

I've made a nice video which goes deeper into the logic. You can check it out at http://02geek.com/courses/video/58/467/Using-Cos-and-Sin-to-animate.html.

Getting ready

The easiest way to understand how sine/cosine work is by a live example, and in our case we will use it to help us figure out how to create the Star of David in the flag of Israel. We will take a step back and learn how we figured out the points on the screen to create the shapes. Again we will be skipping the creation of the HTML file and will go right into the JavaScript code. For an overview of how to get your HTML set, please review the Graphics with 2D canvas recipe.

Getting ready

How to do it...

After creating the JavaScript file add the following code in your init function.

  1. Create our basic canvas variables:
    var canvas = document.getElementById("israel");
    var wid = canvas.width;
    var hei = canvas.height;
    var context = canvas.getContext("2d");
  2. Define one degree in radians. We do that since Math.cos and Math.sin expect a radian value and not a degree value (radian is one degree measured in radians):
    var radian = Math.PI/180;
  3. Create a tilt variable. This variable will define the tilt of the triangle that will be created. Imagine the triangle is in a circle and we are rotating the circle with this tilt variable:
    var tilt = radian*180;
  4. Define the center point of the canvas:
    var baseX = wid / 2;
    var baseY = hei / 2;
  5. Set the radius of the invisible bounding circle of the Star of David:
    var radius = 24;
  6. Define the height of the strips in the flag:
    var stripHeight = 14;
  7. Define a line width:
    context.lineWidth=5;
  8. Create two triangles (one tilted and one not):
    createTrinagle(context,
      baseX+ Math.sin(0) * radius, baseY + Math.cos(0) * radius,
      baseX+ Math.sin(radian*120) * radius, baseY + Math.cos(radian*120) * radius,
      baseX+ Math.sin(radian*240) * radius, baseY + Math.cos(radian*240) * radius, 
      null,"#0040C0");
    
    createTrinagle(context,
      baseX+ Math.sin(tilt) * radius, baseY + Math.cos(tilt) * radius,
      baseX+ Math.sin(radian*120+tilt) * radius, baseY + Math.cos(radian*120+tilt) * radius,
      baseX+ Math.sin(radian*240+tilt) * radius, baseY + Math.cos(radian*240+tilt) * radius, 
      null,"#0040C0");
  9. Draw flag strips:
    context.lineWidth=stripHeight;
    context.beginPath();
    context.moveTo(0,stripHeight);
    context.lineTo(wid,stripHeight);
    context.moveTo(0,hei- stripHeight);
    context.lineTo(wid,hei- stripHeight);
    context.closePath();
    context.stroke();
  10. Create the createTriangle function:
    function createTriangle(context,x1,y1,x2,y2,x3,y3,fillColor,strokeColor){
      context.beginPath();
      context.moveTo(x1,y1);
      context.lineTo(x2,y2);
      context.lineTo(x3,y3);
      context.lineTo(x1,y1);
      context.closePath();
      if(fillColor) {
        context.fillStyle = fillColor;
        context.fill();     
      }
      if(strokeColor){
      context.strokeStyle = strokeColor;
      context.stroke();
      
      }
    }

You are done. Run your application and you will find the flag of Israel with the Star of David in the center of the flag.

How it works...

Before we dig into the creation of the flag and how it was done, we need to understand how we locate points in a circle. To do so let's look at a simpler example:

var rad = Math.PI/180;        
context.fillStyle = "#FFDE00";
context.arc(wid / 2, hei / 2, 30, 0, 2 * Math.PI, false);
context.fill();
context.beginPath();
context.strokeStyle = "#ff0000";
context.lineWidth=6;
context.moveTo(Math.sin(0) * 30 + wid / 2, Math.cos(0) * 30 + hei/2);
context.lineTo(Math.sin(rad*120) * 30 + wid / 2, Math.cos(rad*120) * 30 + hei/2);
context.stroke();

The following is the output the code will generate:

How it works...

Although a circle, in our human-friendly head, is a shape that has 360 degrees, it's actually best represented in most programming languages in radians.

Radians are just like degrees, only instead of being human-friendly numbers between 0 and 360 these are numbers between 0 and two times Pi. You might be wondering what Pi is, so a bit more on Pi. Pi is in essence the value that is created when you take the circumference of any circle and divide it by the diameter of the same circle. The result that would come back would be Pi or about 3.14159. It is a magical number and the good news is you don't need to know much more about it if you don't want to. All you need to know is that 3.142 is equal to half of a circle. With that fact we can now divide Pi by 180 to get a value in radian that equals one degree:

var rad = Math.PI/180;

We then create a circle with a radius of 30 in the center of the screen, to help us visualize this, and move on to start creating a line that will start at angle 0 of our circle and end at angle 120 (as we want to create a triangle 360/3).

context.strokeStyle = "#ff0000";
context.lineWidth=6;
context.moveTo(Math.sin(0) * 30 + wid / 2, Math.cos(0) * 30 + hei/2);
context.lineTo(Math.sin(rad*120) * 30 + wid / 2, Math.cos(rad*120) * 30 + hei/2);
context.stroke();

Let's break down the most complex line:

context.lineTo(Math.sin(rad*120) * 30 + wid / 2, Math.cos(rad*120) * 30 + hei/2);

As Math.sin and Math.cos return a value for a radius of 1, we will multiply any value returned by the radius of our circle (in this case 30). In the parameters of Math.sin and Math.cos, we will provide the exact same values; in this example 120 radians. As our circle would be centered at the top left-hand side of the canvas we want to shift the circle to start from the center of the screen by adding to our values wid/2 and hei/2.

At this stage, you should know how to find points on a circle, and with that how to draw lines between two points. Let's go back to our flag of Israel and take a deeper look into the new function createTriangle. It was based on the function fillTriangle created in the Creating shapes using paths recipe.

function createTriangle(context,x1,y1,x2,y2,x3,y3,fillColor,strokeColor){

...

 if(fillColor) {
 context.fillStyle = fillColor;
 context.fill(); 
 }

if(stokeColor){
 context.strokeStyle = fillColor;
 context.stroke(); 

 }

}

I've highlighted the new components of this function compared to the function fillTriangle. The two new parameters fillColor and strokeColor define if we should fill or stroke the triangle. Notice that we moved the strokeStyle and fillStyle methods to the bottom of our function to reduce our code footprint. Great! We now have a modern triangle creator that could deal with the Star of David.

There's more...

OK, time to connect the dots (literally speaking) and create the flag of Israel. Looking back at our original code we find ourselves using the createTriangle function twice to create the full Star of David shape. Let's take a deeper look at the logic here by looking at the second triangle (the one that is turned upside down):

createTriangle(context,
  baseX+ Math.sin(tilt) * radius, 
  baseY + Math.cos(tilt) * radius,
 baseX+ Math.sin(radian*120+tilt) * radius, 
 baseY + Math.cos(radian*120+tilt) * radius,
baseX+ Math.sin(radian*240+tilt) * radius,
  baseY + Math.cos(radian*240+tilt) * radius, null,"#0040C0");

We are sending in three points on the virtual circle to create a triangle. We split our virtual circle to three equal parts and find the point values at the 0, 120, and 240 degrees. This way if we drew a line between these points we would get a perfect triangle in which all of the sides were equal.

Let's take a deeper look at one of the points sent to the createTriangle function:

baseX + Math.sin(radian*120+tilt) * radius,   
baseY + Math.cos(radian*120+tilt) * radius

We start from baseX and baseY (the center of the screen) as the center point of our circle before we figure out the actual point gap from that base starting point. We then add to it the value that we get from Math.sin and Math.cos respectively. In this example, we are trying to get 120 degrees plus the tilt value. In other words, 120 degrees plus 180 degrees (or 300 degrees).

To make it easier to comprehend, in pseudocode it would look similar to the following code snippet:

 startingPositionX + Math.sin(wantedDegree) * Radius 
 startingPositionY + Math.cin(wantedDegree) * Radius 

Not much more to say besides congrats. We just finished creating another flag and in the process, learned how to create complex shapes, use math to help us figure out points on the screen, and mix together different shapes to create more advanced shapes.

主站蜘蛛池模板: 高尔夫| 唐海县| 织金县| 荥阳市| 万山特区| 突泉县| 基隆市| 凤庆县| 板桥市| 钟山县| 同江市| 栾城县| 汉寿县| 克山县| 达日县| 岑溪市| 新龙县| 衡阳县| 天气| 宁陵县| 措勤县| 上高县| 怀安县| 淳安县| 游戏| 突泉县| 南靖县| 重庆市| 静乐县| 石城县| 吉隆县| 湟中县| 海晏县| 靖远县| 临洮县| 安新县| 疏附县| 来安县| 广丰县| 绥滨县| 沙雅县|