Draw Little Circles in Angular

Drawing graphics

Graphics on the Spider web

As we talked virtually in our HTML Multimedia and embedding module, the Web was originally merely text, which was very boring, so images were introduced — offset via the <img> element and later via CSS properties such as background-image, and SVG.

This notwithstanding was still non enough. While you could use CSS and JavaScript to animate (and otherwise dispense) SVG vector images — as they are represented past markup — in that location was still no way to practise the same for bitmap images, and the tools bachelor were rather express. The Web still had no manner to effectively create animations, games, 3D scenes, and other requirements commonly handled by lower level languages such as C++ or Java.

The situation started to improve when browsers began to support the <sheet> element and associated Sail API — Apple tree invented it in around 2004, and other browsers followed by implementing it in the years that followed. As you'll come across below, canvas provides many useful tools for creating 2D animations, games, data visualizations, and other types of app, particularly when combined with some of the other APIs the spider web platform provides.

The below example shows a simple 2d canvas-based bouncing assurance blitheness that nosotros originally met in our Introducing JavaScript objects module:

Effectually 2006–2007, Mozilla started piece of work on an experimental 3D canvass implementation. This became WebGL, which gained traction among browser vendors, and was standardized around 2009–2010. WebGL allows y'all to create real 3D graphics inside your web browser; the below example shows a elementary rotating WebGL cube:

This article will focus mainly on 2D canvas, as raw WebGL code is very complex. We will however show how to employ a WebGL library to create a 3D scene more easily, and you tin can find a tutorial covering raw WebGL elsewhere — run into Getting started with WebGL.

Note: Bones canvass functionality is supported well across browsers, with the exception of IE viii and below for 2nd sail, and IE 11 and below for WebGL.

Active learning: Getting started with a <sheet>

If you want to create a 2D or 3D scene on a web page, you need to kickoff with an HTML <canvass> element. This element is used to ascertain the area on the folio into which the prototype will be drawn. This is as simple as including the element on the page:

                                                                            <sheet                    width                                          =                      "320"                                        meridian                                          =                      "240"                                        >                                                                              </canvas                    >                                                

This volition create a canvas on the page with a size of 320 by 240 pixels.

Inside the canvas tags, you tin can put some fallback content, which is shown if the user'southward browser doesn't support canvass.

                                                                            <canvass                    width                                          =                      "320"                                        height                                          =                      "240"                                        >                                                                              <p                    >                  Your browser doesn't support canvas. Boo hoo!                                          </p                    >                                                                              </canvas                    >                                                

Of grade, the in a higher place message is actually unhelpful! In a real case yous'd want to chronicle the fallback content to the canvas content. For example, if you were rendering a constantly updating graph of stock prices, the fallback content could exist a static epitome of the latest stock graph, with alt text saying what the prices are in text.

Creating and sizing our canvass

Let'due south offset past creating our own canvas that we draw hereafter experiments on to.

  1. First make a local copy of the 0_canvas_start directory. It contains three files:
    • "alphabetize.html"
    • "script.js"
    • "way.css"
  2. Open "index.html", and add the following lawmaking into it, only beneath the opening <body> tag:
                                                                                                <sheet                        course                                                  =                          "myCanvas"                                                >                                                                                              <p                        >                      Add suitable fallback here.                                                  </p                        >                                                                                              </sheet                        >                                                            
    We have added a class to the <canvas> chemical element and then it will be easier to select if we take multiple canvases on the folio, only we take removed the width and height attributes for now (you could add them back in if you wanted, but we will ready them using JavaScript in a below section). Canvases with no explicit width and superlative default to 300 pixels broad by 150 pixels high.
  3. At present open "script.js" and add the following lines of JavaScript:
                                              const                      canvas                      =                      document.                      querySelector                      (                      '.myCanvas'                      )                      ;                      const                      width                      =                      canvas.width                      =                      window.innerWidth;                      const                      height                      =                      canvas.height                      =                      window.innerHeight;                                      
    Hither nosotros have stored a reference to the sheet in the canvas constant. In the second line we set both a new constant width and the canvas' width holding equal to Window.innerWidth (which gives u.s. the viewport width). In the tertiary line we set both a new constant height and the sheet' height property equal to Window.innerHeight (which gives usa the viewport meridian). So now we have a canvas that fills the entire width and height of the browser window! You'll besides see that we are chaining assignments together with multiple equals signs — this is allowed in JavaScript, and it is a good technique if you want to make multiple variables all equal to the aforementioned value. We wanted to make the sheet width and acme easily accessible in the width/height variables, as they are useful values to have available for later (for example, if you desire to draw something exactly halfway across the width of the canvas).

Note: You should generally set up the size of the image using HTML attributes or DOM properties, equally explained above. You could use CSS, just the trouble then is that the sizing is done afterward the canvas has rendered, and just like whatever other image (the rendered sail is just an image), the prototype could become pixelated/distorted.

Getting the canvas context and terminal setup

Nosotros demand to do one final thing earlier we tin can consider our canvas template finished. To draw onto the canvas we need to get a special reference to the drawing area called a context. This is done using the HTMLCanvasElement.getContext() method, which for bones usage takes a single cord as a parameter representing the type of context you want to retrieve.

In this instance we want a 2d sail, so add the following JavaScript line beneath the others in "script.js":

                                  const                  ctx                  =                  sheet.                  getContext                  (                  '2d'                  )                  ;                              

Annotation: other context values you lot could choose include webgl for WebGL, webgl2 for WebGL two, etc., only we won't need those in this article.

So that's it — our canvas is now primed and gear up for drawing on! The ctx variable now contains a CanvasRenderingContext2D object, and all cartoon operations on the canvas will involve manipulating this object.

Permit's practise i final matter before we move on. We'll color the canvas background black to give yous a first taste of the canvas API. Add the following lines at the lesser of your JavaScript:

                ctx.fillStyle                  =                  'rgb(0, 0, 0)'                  ;                  ctx.                  fillRect                  (                  0                  ,                  0                  ,                  width,                  height)                  ;                              

Hither we are setting a fill color using the sail' fillStyle property (this takes color values simply similar CSS properties do), then drawing a rectangle that covers the entire expanse of the canvas with thefillRect method (the showtime two parameters are the coordinates of the rectangle'south height left manus corner; the last two are the width and height you desire the rectangle drawn at — we told yous those width and elevation variables would be useful)!

OK, our template is done and it's fourth dimension to move on.

2D canvas basics

As we said above, all drawing operations are washed by manipulating a CanvasRenderingContext2D object (in our case, ctx). Many operations demand to exist given coordinates to pinpoint exactly where to draw something — the top left of the canvass is point (0, 0), the horizontal (x) centrality runs from left to right, and the vertical (y) axis runs from top to bottom.

Drawing shapes tends to be washed using the rectangle shape primitive, or by tracing a line along a certain path and then filling in the shape. Below we'll show how to do both.

Unproblematic rectangles

Let's start with some uncomplicated rectangles.

  1. Offset of all, accept a copy of your newly coded canvas template (or make a local re-create of the 1_canvas_template directory if yous didn't follow the above steps).
  2. Next, add together the following lines to the bottom of your JavaScript:
                        ctx.fillStyle                      =                      'rgb(255, 0, 0)'                      ;                      ctx.                      fillRect                      (                      fifty                      ,                      50                      ,                      100                      ,                      150                      )                      ;                                      
    If you salvage and refresh, you should see a red rectangle has appeared on your canvas. Its top left corner is 50 pixels abroad from the top and left of the canvass edge (equally defined by the commencement ii parameters), and information technology is 100 pixels broad and 150 pixels tall (equally divers by the tertiary and 4th parameters).
  3. Let'southward add another rectangle into the mix — a green one this time. Add the following at the bottom of your JavaScript:
                        ctx.fillStyle                      =                      'rgb(0, 255, 0)'                      ;                      ctx.                      fillRect                      (                      75                      ,                      75                      ,                      100                      ,                      100                      )                      ;                                      
    Save and refresh, and you'll encounter your new rectangle. This raises an important indicate: graphics operations like drawing rectangles, lines, and and then forth are performed in the order in which they occur. Think of it like painting a wall, where each coat of paint overlaps and may fifty-fifty hide what's underneath. You lot can't do anything to modify this, and so you lot have to think advisedly about the society in which you describe the graphics.
  4. Note that you can depict semi-transparent graphics past specifying a semi-transparent colour, for example by using rgba(). The a value defines what'south called the "alpha channel, " or the corporeality of transparency the color has. The college its value, the more it volition obscure whatever's behind it. Add together the post-obit to your code:
                        ctx.fillStyle                      =                      'rgba(255, 0, 255, 0.75)'                      ;                      ctx.                      fillRect                      (                      25                      ,                      100                      ,                      175                      ,                      50                      )                      ;                                      
  5. At present attempt drawing some more than rectangles of your own; have fun!

Strokes and line widths

And so far nosotros've looked at drawing filled rectangles, but you lot can also draw rectangles that are just outlines (chosen strokes in graphic pattern). To set the color you want for your stroke, y'all employ the strokeStyle property; cartoon a stroke rectangle is done using strokeRect.

  1. Add the following to the previous example, again below the previous JavaScript lines:
                        ctx.strokeStyle                      =                      'rgb(255, 255, 255)'                      ;                      ctx.                      strokeRect                      (                      25                      ,                      25                      ,                      175                      ,                      200                      )                      ;                                      
  2. The default width of strokes is i pixel; yous can arrange the lineWidth belongings value to change this (it takes a number representing the number of pixels broad the stroke is). Add together the following line in betwixt the previous two lines:

At present you lot should run into that your white outline has become much thicker! That's it for at present. At this point your example should await like this:

Drawing paths

If yous desire to depict anything more than complex than a rectangle, you need to draw a path. Basically, this involves writing code to specify exactly what path the pen should move along on your sail to trace the shape you desire to draw. Canvas includes functions for drawing straight lines, circles, Bézier curves, and more.

Permit'south start the section off by making a fresh re-create of our sheet template (1_canvas_template), in which to draw the new example.

We'll be using some common methods and properties across all of the beneath sections:

  • beginPath() — beginning drawing a path at the signal where the pen currently is on the canvass. On a new canvas, the pen starts out at (0, 0).
  • moveTo() — move the pen to a dissimilar bespeak on the canvas, without recording or tracing the line; the pen "jumps" to the new position.
  • fill() — describe a filled shape past filling in the path you've traced so far.
  • stroke() — draw an outline shape by drawing a stroke along the path y'all've fatigued and then far.
  • You can also use features like lineWidth and fillStyle/strokeStyle with paths as well every bit rectangles.

A typical, simple path-drawing operation would look something like then:

                ctx.fillStyle                  =                  'rgb(255, 0, 0)'                  ;                  ctx.                  beginPath                  (                  )                  ;                  ctx.                  moveTo                  (                  l                  ,                  fifty                  )                  ;                  // draw your path                  ctx.                  fill                  (                  )                  ;                              

Drawing lines

Let'due south draw an equilateral triangle on the canvas.

  1. Beginning of all, add the following helper function to the bottom of your lawmaking. This converts degree values to radians, which is useful because whenever you need to provide an angle value in JavaScript, it volition nearly ever exist in radians, just humans usually think in degrees.
                                              function                      degToRad                      (                      degrees                      )                      {                      return                      degrees                      *                      Math.                      PI                      /                      180                      ;                      }                                      
  2. Next, kickoff off your path by adding the following beneath your previous add-on; here we set a color for our triangle, start drawing a path, and then move the pen to (50, l) without drawing annihilation. That's where nosotros'll start cartoon our triangle.
                        ctx.fillStyle                      =                      'rgb(255, 0, 0)'                      ;                      ctx.                      beginPath                      (                      )                      ;                      ctx.                      moveTo                      (                      l                      ,                      50                      )                      ;                                      
  3. Now add the post-obit lines at the bottom of your script:
                        ctx.                      lineTo                      (                      150                      ,                      50                      )                      ;                      const                      triHeight                      =                      50                      *                      Math.                      tan                      (                      degToRad                      (                      60                      )                      )                      ;                      ctx.                      lineTo                      (                      100                      ,                      l                      +                      triHeight)                      ;                      ctx.                      lineTo                      (                      50                      ,                      50                      )                      ;                      ctx.                      fill up                      (                      )                      ;                                      
    Let's run through this in society: First nosotros draw a line across to (150, 50) — our path at present goes 100 pixels to the right along the x axis. 2d, we work out the height of our equilateral triangle, using a bit of simple trigonometry. Basically, nosotros are drawing the triangle pointing down. The angles in an equilateral triangle are e'er threescore degrees; to piece of work out the height we can split up it downward the middle into two right-angled triangles, which will each have angles of 90 degrees, 60 degrees, and 30 degrees. In terms of the sides:
    • The longest side is called the hypotenuse
    • The side adjacent to the lx degree angle is called the adjacent — which nosotros know is 50 pixels, as it is half of the line we simply drew.
    • The side opposite the 60 degree angle is chosen the contrary, which is the elevation of the triangle we want to summate.
    One of the basic trigonometric formulae states that the length of the adjacent multiplied by the tangent of the angle is equal to the opposite, hence we come up with 50 * Math.tan(degToRad(60)). We use our degToRad() office to convert lx degrees to radians, equally Math.tan() expects an input value in radians.
  4. With the height calculated, nosotros describe another line to (100, 50 + triHeight). The 10 coordinate is elementary; it must be halfway between the previous two X values we set. The Y value on the other hand must be l plus the triangle acme, every bit nosotros know the top of the triangle is 50 pixels from the summit of the canvas.
  5. The next line draws a line back to the starting point of the triangle.
  6. Last of all, we run ctx.make full() to end the path and fill in the shape.

Drawing circles

At present permit's look at how to draw a circumvolve in sheet. This is accomplished using the arc() method, which draws all or role of a circle at a specified bespeak.

  1. Let'south add an arc to our canvas — add together the following to the bottom of your code:
                        ctx.fillStyle                      =                      'rgb(0, 0, 255)'                      ;                      ctx.                      beginPath                      (                      )                      ;                      ctx.                      arc                      (                      150                      ,                      106                      ,                      fifty                      ,                      degToRad                      (                      0                      )                      ,                      degToRad                      (                      360                      )                      ,                      false                      )                      ;                      ctx.                      fill                      (                      )                      ;                                      
    arc() takes six parameters. The kickoff two specify the position of the arc's center (Ten and Y, respectively). The 3rd is the circle's radius, the 4th and fifth are the start and end angles at which to draw the circle (so specifying 0 and 360 degrees gives us a total circle), and the sixth parameter defines whether the circle should be drawn counterclockwise (anticlockwise) or clockwise (imitation is clockwise).

    Note: 0 degrees is horizontally to the right.

  2. Permit'southward try adding another arc:
                        ctx.fillStyle                      =                      'yellow'                      ;                      ctx.                      beginPath                      (                      )                      ;                      ctx.                      arc                      (                      200                      ,                      106                      ,                      fifty                      ,                      degToRad                      (                      -                      45                      )                      ,                      degToRad                      (                      45                      )                      ,                      true                      )                      ;                      ctx.                      lineTo                      (                      200                      ,                      106                      )                      ;                      ctx.                      fill                      (                      )                      ;                                      
    The pattern hither is very similar, just with ii differences:
    • We have set the last parameter of arc() to truthful, meaning that the arc is drawn counterclockwise, which means that even though the arc is specified equally starting at -45 degrees and catastrophe at 45 degrees, we draw the arc around the 270 degrees not inside this portion. If you were to change true to faux and then re-run the code, only the xc degree slice of the circle would be drawn.
    • Before calling fill(), we draw a line to the center of the circumvolve. This means that nosotros get the rather nice Pac-Human-style cutout rendered. If you removed this line (effort it!) and so re-ran the code, you'd get only an edge of the circumvolve chopped off betwixt the start and terminate betoken of the arc. This illustrates some other of import point of the canvas — if you lot effort to fill up an incomplete path (i.e. i that is not airtight), the browser fills in a straight line between the start and end point and and so fills information technology in.

That'southward information technology for now; your last case should look similar this:

Notation: The finished lawmaking is available on GitHub as 3_canvas_paths.

Note: To find out more about avant-garde path cartoon features such every bit Bézier curves, check out our Drawing shapes with canvas tutorial.

Text

Sheet too has features for drawing text. Let'south explore these briefly. Start past making some other fresh re-create of our canvas template (1_canvas_template) in which to draw the new case.

Text is drawn using two methods:

  • fillText() — draws filled text.
  • strokeText() — draws outline (stroke) text.

Both of these take three properties in their basic usage: the text string to draw and the 10 and Y coordinates of the point to commencement drawing the text at. This works out as the lesser left corner of the text box (literally, the box surrounding the text you depict), which might confuse y'all equally other drawing operations tend to kickoff from the top left corner — acquit this in heed.

There are also a number of properties to help control text rendering such every bit font, which lets you lot specify font family, size, etc. It takes equally its value the same syntax as the CSS font property.

Endeavour adding the following block to the bottom of your JavaScript:

                ctx.strokeStyle                  =                  'white'                  ;                  ctx.lineWidth                  =                  1                  ;                  ctx.font                  =                  '36px arial'                  ;                  ctx.                  strokeText                  (                  'Sail text'                  ,                  50                  ,                  50                  )                  ;                  ctx.fillStyle                  =                  'cherry'                  ;                  ctx.font                  =                  '48px georgia'                  ;                  ctx.                  fillText                  (                  'Canvas text'                  ,                  50                  ,                  150                  )                  ;                              

Here we depict two lines of text, ane outline and the other stroke. The final example should look like so:

Note: The finished code is available on GitHub as 4_canvas_text.

Have a play and see what you can come up with! You lot can find more information on the options available for canvas text at Drawing text.

Drawing images onto sheet

It is possible to render external images onto your canvas. These tin can be uncomplicated images, frames from videos, or the content of other canvases. For the moment we'll merely look at the case of using some elementary images on our canvas.

  1. As earlier, make another fresh re-create of our sail template (1_canvas_template) in which to describe the new example. Images are drawn onto sail using the drawImage() method. The simplest version takes three parameters — a reference to the image y'all want to render, and the X and Y coordinates of the image's top left corner.
  2. Let's start by getting an epitome source to embed in our canvas. Add the post-obit lines to the bottom of your JavaScript:
                                              const                      image                      =                      new                      Paradigm                      (                      )                      ;                      image.src                      =                      'firefox.png'                      ;                                      
    Here we create a new HTMLImageElement object using the Image() constructor. The returned object is the same type every bit that which is returned when you lot grab a reference to an existing <img> element). Nosotros then set its src attribute to equal our Firefox logo image. At this point, the browser starts loading the image.
  3. We could at present try to embed the image using drawImage(), simply we need to make sure the paradigm file has been loaded first, otherwise the lawmaking will fail. We can achieve this using the load upshot, which will only be fired when the image has finished loading. Add together the following block below the previous one:
                        paradigm.                      addEventListener                      (                      'load'                      ,                      (                      )                      =>                      ctx.                      drawImage                      (image,                      20                      ,                      20                      ,                      185                      ,                      175                      ,                      50                      ,                      50                      ,                      185                      ,                      175                      )                      )                      ;                                      
    If you load your example in the browser now, you lot should see the image embedded in the sail.
  4. Merely there's more! What if we want to display but a function of the prototype, or to resize it? We can do both with the more complex version of drawImage(). Update your ctx.drawImage() line like so:
                        ctx.                      drawImage                      (image,                      20                      ,                      20                      ,                      185                      ,                      175                      ,                      50                      ,                      fifty                      ,                      185                      ,                      175                      )                      ;                                      
    • The first parameter is the image reference, every bit before.
    • Parameters 2 and iii define the coordinates of the top left corner of the area you desire to cut out of the loaded image, relative to the top-left corner of the image itself. Zip to the left of the commencement parameter or in a higher place the second will be drawn.
    • Parameters 4 and v define the width and top of the area we want to cut out from the original image we loaded.
    • Parameters 6 and 7 define the coordinates at which you desire to draw the superlative-left corner of the cut-out portion of the image, relative to the pinnacle-left corner of the canvas.
    • Parameters 8 and 9 define the width and height to describe the cutting-out area of the image. In this case, we accept specified the same dimensions as the original slice, but you could resize information technology past specifying different values.

The terminal case should look like so:

Note: The finished code is available on GitHub equally 5_canvas_images.

Loops and animations

Nosotros have so far covered some very basic uses of second sheet, simply really you won't experience the full power of canvas unless you update or animate it in some manner. After all, sail does provide scriptable images! If you aren't going to modify annihilation, then you might as well just use static images and salve yourself all the work.

Creating a loop

Playing with loops in canvas is rather fun — you can run canvas commands within a for (or other type of) loop just similar any other JavaScript code.

Let's build a simple example.

  1. Make another fresh copy of our sheet template (1_canvas_template) and open it in your code editor.
  2. Add the following line to the lesser of your JavaScript. This contains a new method, translate(), which moves the origin point of the canvas:
                        ctx.                      translate                      (width/                      2                      ,                      elevation/                      2                      )                      ;                                      
    This causes the coordinate origin (0, 0) to be moved to the center of the sail, rather than being at the meridian left corner. This is very useful in many situations, like this i, where we want our pattern to exist drawn relative to the middle of the canvass.
  3. At present add the following code to the lesser of the JavaScript:
                                              office                      degToRad                      (                      degrees                      )                      {                      render                      degrees                      *                      Math.                      PI                      /                      180                      ;                      }                      function                      rand                      (                      min,                        max                      )                      {                      return                      Math.                      floor                      (Math.                      random                      (                      )                      *                      (max-min+                      i                      )                      )                      +                      (min)                      ;                      }                      allow                      length                      =                      250                      ;                      let                      moveOffset                      =                      20                      ;                      for                      (                      let                      i                      =                      0                      ;                      i                      <                      length;                      i++                      )                      {                      }                                      
    Hither we are implementing the same degToRad() function we saw in the triangle example to a higher place, a rand() office that returns a random number between given lower and upper bounds, length and moveOffset variables (which we'll find out more most later), and an empty for loop.
  4. The idea here is that we'll describe something on the canvas inside the for loop, and iterate on it each fourth dimension so we can create something interesting. Add together the following lawmaking inside your for loop:
                        ctx.fillStyle                      =                                              `                        rgba(                                                  ${                          255                          -length}                                                ,0,                                                  ${                          255                          -length}                                                ,0.9)                        `                                            ;                      ctx.                      beginPath                      (                      )                      ;                      ctx.                      moveTo                      (moveOffset,moveOffset)                      ;                      ctx.                      lineTo                      (moveOffset+length,moveOffset)                      ;                      const                      triHeight                      =                      length/                      two                      *                      Math.                      tan                      (                      degToRad                      (                      60                      )                      )                      ;                      ctx.                      lineTo                      (moveOffset+                      (length/                      2                      )                      ,moveOffset+triHeight)                      ;                      ctx.                      lineTo                      (moveOffset,moveOffset)                      ;                      ctx.                      make full                      (                      )                      ;                      length--                      ;                      moveOffset                      +=                      0.7                      ;                      ctx.                      rotate                      (                      degToRad                      (                      5                      )                      )                      ;                                      
    So on each iteration, we:
    • Fix the fillStyle to be a shade of slightly transparent imperial, which changes each time based on the value of length. As you'll see later the length gets smaller each time the loop runs, so the effect here is that the color gets brighter with each successive triangle fatigued.
    • Begin the path.
    • Motility the pen to a coordinate of (moveOffset, moveOffset); This variable defines how far we want to movement each time nosotros draw a new triangle.
    • Draw a line to a coordinate of (moveOffset+length, moveOffset). This draws a line of length length parallel to the X axis.
    • Calculate the triangle'south height, equally before.
    • Draw a line to the downwardly-pointing corner of the triangle, then describe a line back to the offset of the triangle.
    • Call fill() to fill in the triangle.
    • Update the variables that draw the sequence of triangles, so we can be ready to draw the next one. We decrease the length value by 1, then the triangles go smaller each time; increase moveOffset by a small amount so each successive triangle is slightly further away, and use another new function, rotate(), which allows us to rotate the entire canvas! Nosotros rotate information technology by 5 degrees before drawing the adjacent triangle.

That'due south it! The concluding example should look like so:

At this point, we'd similar to encourage you to play with the instance and get in your own! For example:

  • Describe rectangles or arcs instead of triangles, or even embed images.
  • Play with the length and moveOffset values.
  • Introduce some random numbers using that rand() function we included in a higher place but didn't utilise.

Animations

The loop example we congenital to a higher place was fun, but really you demand a abiding loop that keeps going and going for whatsoever serious canvas applications (such as games and real time visualizations). If yous think of your canvas every bit being like a motion picture, yous really want the display to update on each frame to show the updated view, with an platonic refresh rate of 60 frames per second so that movement appears dainty and smooth to the human being eye.

At that place are a few JavaScript functions that volition allow you lot to run functions repeatedly, several times a second, the best ane for our purposes here being window.requestAnimationFrame(). It takes one parameter — the name of the function you want to run for each frame. The next fourth dimension the browser is ready to update the screen, your function will get called. If that office draws the new update to your animation, and then calls requestAnimationFrame() again only before the end of the function, the animation loop will continue to run. The loop ends when y'all stop calling requestAnimationFrame() or if you call window.cancelAnimationFrame() after calling requestAnimationFrame() but before the frame is called.

Note: It'due south good practice to call cancelAnimationFrame() from your principal code when you're done using the animation, to ensure that no updates are still waiting to exist run.

The browser works out complex details such as making the animation run at a consistent speed, and not wasting resources animating things that can't be seen.

To see how it works, let's quickly look again at our Bouncing Balls example (see it live, and also meet the source code). The code for the loop that keeps everything moving looks like this:

                                  function                  loop                  (                  )                  {                  ctx.fillStyle                  =                  'rgba(0, 0, 0, 0.25)'                  ;                  ctx.                  fillRect                  (                  0                  ,                  0                  ,                  width,                  height)                  ;                  for                  (                  const                  ball                  of                  assurance)                  {                  ball.                  draw                  (                  )                  ;                  ball.                  update                  (                  )                  ;                  ball.                  collisionDetect                  (                  )                  ;                  }                  requestAnimationFrame                  (loop)                  ;                  }                  loop                  (                  )                  ;                              

We run the loop() function once at the bottom of the lawmaking to start the bike, drawing the start animation frame; the loop() function then takes accuse of calling requestAnimationFrame(loop) to run the adjacent frame of the animation, again and again.

Note that on each frame we are completely clearing the canvass and redrawing everything. For every ball nowadays nosotros depict information technology, update its position, and check to see if information technology is colliding with any other assurance. Once you've fatigued a graphic to a sheet, there's no way to manipulate that graphic individually like yous can with DOM elements. Y'all can't move each ball around on the canvas, because once information technology'south drawn, it's part of the sail, and is non an individual attainable element or object. Instead, you have to erase and redraw, either by erasing the entire frame and redrawing everything, or by having code that knows exactly what parts demand to be erased and only erases and redraws the minimum area of the sail necessary.

Optimizing blitheness of graphics is an entire specialty of programming, with lots of clever techniques available. Those are beyond what we need for our case, though!

In general, the process of doing a canvas animation involves the post-obit steps:

  1. Clear the canvas contents (e.chiliad. with fillRect() or clearRect()).
  2. Save state (if necessary) using relieve() — this is needed when you want to save settings you've updated on the canvass before standing, which is useful for more advanced applications.
  3. Depict the graphics y'all are animating.
  4. Restore the settings yous saved in step 2, using restore()
  5. Call requestAnimationFrame() to schedule drawing of the next frame of the blitheness.

Note: We won't cover save() and restore() here, but they are explained nicely in our Transformations tutorial (and the ones that follow it).

A simple graphic symbol animation

Now let'south create our own simple animation — we'll go a character from a certain rather crawly retro computer game to walk across the screen.

  1. Make some other fresh copy of our sheet template (1_canvas_template) and open it in your lawmaking editor.
  2. At the bottom of the JavaScript, add together the following line to over again make the coordinate origin sit in the middle of the canvas:
                        ctx.                      translate                      (width/                      2                      ,                      height/                      ii                      )                      ;                                      
  3. Now let'southward create a new HTMLImageElement object, set its src to the image we want to load, and add an onload upshot handler that will crusade the draw() function to fire when the epitome is loaded:
                                              const                      epitome                      =                      new                      Image                      (                      )                      ;                      image.src                      =                      'walk-right.png'                      ;                      image.onload                      =                      depict;                                      
  4. At present we'll add some variables to keep rails of the position the sprite is to be drawn on the screen, and the sprite number nosotros desire to brandish.
                                              let                      sprite                      =                      0                      ;                      permit                      posX                      =                      0                      ;                                      
    Let'south explain the spritesheet image (which we have respectfully borrowed from Mike Thomas' Create a sprite sheet walk bike using CSS blitheness). The image looks like this: Information technology contains six sprites that make up the whole walking sequence — each 1 is 102 pixels wide and 148 pixels high. To brandish each sprite cleanly we volition accept to utilize drawImage() to chop out a single sprite epitome from the spritesheet and display only that office, similar nosotros did above with the Firefox logo. The 10 coordinate of the slice will have to be a multiple of 102, and the Y coordinate volition always be 0. The slice size volition always exist 102 past 148 pixels.
  5. Now let's insert an empty draw() function at the bottom of the code, ready for filling upwardly with some code:
  6. The residual of the code in this section goes inside draw(). First, add the following line, which clears the canvas to set for drawing each frame. Observe that we have to specify the peak-left corner of the rectangle equally -(width/ii), -(superlative/2) considering we specified the origin position as width/2, height/2 earlier on.
                        ctx.                      fillRect                      (                      -                      (width/                      2                      )                      ,                      -                      (height/                      2                      )                      ,                      width,                      height)                      ;                                      
  7. Next, nosotros'll draw our prototype using drawImage — the ix-parameter version. Add the post-obit:
                        ctx.                      drawImage                      (image,                      (sprite*                      102                      )                      ,                      0                      ,                      102                      ,                      148                      ,                      0                      +posX,                      -                      74                      ,                      102                      ,                      148                      )                      ;                                      
    As y'all tin encounter:
    • We specify paradigm equally the prototype to embed.
    • Parameters 2 and 3 specify the top-left corner of the slice to cut out of the source epitome, with the X value as sprite multiplied past 102 (where sprite is the sprite number between 0 and five) and the Y value ever 0.
    • Parameters 4 and 5 specify the size of the slice to cutting out — 102 pixels past 148 pixels.
    • Parameters half dozen and vii specify the top-left corner of the box into which to draw the slice on the canvas — the X position is 0 + posX, pregnant that we can alter the drawing position by altering the posX value.
    • Parameters 8 and 9 specify the size of the paradigm on the canvas. We just desire to keep its original size, so we specify 102 and 148 equally the width and pinnacle.
  8. Now we'll alter the sprite value after each draw — well, after some of them anyway. Add the following block to the bottom of the describe() office:
                                              if                      (posX                      %                      13                      ===                      0                      )                      {                      if                      (sprite                      ===                      five                      )                      {                      sprite                      =                      0                      ;                      }                      else                      {                      sprite++                      ;                      }                      }                                      
    Nosotros are wrapping the whole block in if (posX % xiii === 0) { ... }. We apply the modulo (%) operator (likewise known as the remainder operator) to check whether the posX value can be exactly divided by 13 with no remainder. If so, nosotros motion on to the next sprite by incrementing sprite (wrapping to 0 after nosotros're done with sprite #5). This effectively ways that we are merely updating the sprite on every 13th frame, or roughly most five frames a second (requestAnimationFrame() calls us at upward to sixty frames per second if possible). We are deliberately slowing downwards the frame charge per unit because nosotros only have six sprites to work with, and if nosotros brandish one every 60th of a second, our character will motion way too fast! Inside the outer block we use an if ... else statement to check whether the sprite value is at 5 (the last sprite, given that the sprite numbers run from 0 to 5). If we are showing the concluding sprite already, we reset sprite back to 0; if not nosotros just increment it past 1.
  9. Side by side we need to work out how to change the posX value on each frame — add together the following code block just below your last i.
                                              if                      (posX                      >                      width/                      2                      )                      {                      let                      newStartPos                      =                      -                      (                      (width/                      2                      )                      +                      102                      )                      ;                      posX                      =                      Math.                      ceil                      (newStartPos)                      ;                      console.                      log                      (posX)                      ;                      }                      else                      {                      posX                      +=                      ii                      ;                      }                                      
    We are using another if ... else statement to see if the value of posX has get greater than width/2, which means our character has walked off the right edge of the screen. If so, we calculate a position that would put the character but to the left of the left side of the screen. If our character hasn't notwithstanding walked off the edge of the screen, we increase posX by 2. This will make him motion a little chip to the correct the next time we draw him.
  10. Finally, nosotros need to brand the animation loop by calling requestAnimationFrame() at the bottom of the depict() office:
                        window.                      requestAnimationFrame                      (draw)                      ;                                      

That's it! The terminal example should look like so:

A unproblematic drawing awarding

As a final animation example, nosotros'd similar to show you a very simple cartoon application, to illustrate how the animation loop can be combined with user input (like mouse motion, in this case). Nosotros won't become you to walk through and build this one; nosotros'll merely explore the most interesting parts of the code.

The example can be establish on GitHub as 8_canvas_drawing_app, and you can play with information technology live below:

Permit's look at the virtually interesting parts. First of all, we keep track of the mouse's 10 and Y coordinates and whether information technology is being clicked or not with three variables: curX, curY, and pressed. When the mouse moves, we fire a function set every bit the onmousemove event handler, which captures the current X and Y values. We besides use onmousedown and onmouseup event handlers to change the value of pressed to truthful when the mouse push is pressed, and back to fake again when information technology is released.

                                  let                  curX;                  let                  curY;                  let                  pressed                  =                  faux                  ;                  // update mouse pointer coordinates                  document.                  addEventListener                  (                  'mousemove'                  ,                  due east                  =>                  {                  curX                  =                  (window.Consequence)                  ?                  east.pageX                  :                  e.clientX                  +                  (certificate.documentElement.scrollLeft                  ?                  document.documentElement.scrollLeft                  :                  document.body.scrollLeft)                  ;                  curY                  =                  (window.Issue)                  ?                  e.pageY                  :                  e.clientY                  +                  (document.documentElement.scrollTop                  ?                  document.documentElement.scrollTop                  :                  document.body.scrollTop)                  ;                  }                  )                  ;                  canvas.                  addEventListener                  (                  'mousedown'                  ,                  (                  )                  =>                  pressed                  =                  true                  )                  ;                  canvas.                  addEventListener                  (                  'mouseup'                  ,                  (                  )                  =>                  pressed                  =                  false                  )                  ;                              

When the "Clear sail" push is pressed, nosotros run a simple role that clears the whole canvas dorsum to blackness, the aforementioned way nosotros've seen earlier:

                clearBtn.                  addEventListener                  (                  'click'                  ,                  (                  )                  =>                  {                  ctx.fillStyle                  =                  'rgb(0,0,0)'                  ;                  ctx.                  fillRect                  (                  0                  ,                  0                  ,width,height)                  ;                  }                  )                  ;                              

The drawing loop is pretty elementary this time effectually — if pressed is truthful, we depict a circumvolve with a fill style equal to the value in the colour picker, and a radius equal to the value set in the range input. We accept to draw the circumvolve 85 pixels in a higher place where we measured it from, because the vertical measurement is taken from the top of the viewport, but we are drawing the circle relative to the top of the canvas, which starts below the 85 pixel-high toolbar. If we drew it with just curY equally the y coordinate, it would appear 85 pixels lower than the mouse position.

                                  function                  draw                  (                  )                  {                  if                  (pressed)                  {                  ctx.fillStyle                  =                  colorPicker.value;                  ctx.                  beginPath                  (                  )                  ;                  ctx.                  arc                  (curX,                  curY-                  85                  ,                  sizePicker.value,                  degToRad                  (                  0                  )                  ,                  degToRad                  (                  360                  )                  ,                  false                  )                  ;                  ctx.                  fill up                  (                  )                  ;                  }                  requestAnimationFrame                  (depict)                  ;                  }                  depict                  (                  )                  ;                              

Notation: The <input> range and colour types are supported fairly well across browsers, with the exception of Internet Explorer versions less than ten; also Safari doesn't yet support color. If your browser doesn't back up these inputs, they will autumn back to elementary text fields and you'll just have to enter valid color/number values yourself.

WebGL

Information technology'south now time to leave 2nd backside, and take a quick await at 3D canvas. 3D canvass content is specified using the WebGL API, which is a completely separate API from the 2d sail API, even though they both return onto <canvas> elements.

WebGL is based on OpenGL (Open Graphics Library), and allows y'all to communicate straight with the reckoner's GPU. Equally such, writing raw WebGL is closer to depression level languages such equally C++ than regular JavaScript; it is quite complex but incredibly powerful.

Using a library

Because of its complexity, most people write 3D graphics code using a third party JavaScript library such every bit Three.js, PlayCanvas, or Babylon.js. Almost of these work in a similar way, providing functionality to create primitive and custom shapes, position viewing cameras and lighting, covering surfaces with textures, and more. They handle the WebGL for you, letting you work on a higher level.

Yes, using one of these ways learning some other new API (a third political party i, in this case), but they are a lot simpler than coding raw WebGL.

Recreating our cube

Let's look at a elementary instance of how to create something with a WebGL library. Nosotros'll choose 3.js, as it is one of the most popular ones. In this tutorial we'll create the 3D spinning cube nosotros saw before.

  1. To start with, brand a local copy of threejs-cube/index.html in a new binder, so relieve a re-create of metal003.png in the same folder. This is the paradigm we'll employ as a surface texture for the cube later on.
  2. Next, create a new file called script.js, once more in the same binder every bit earlier.
  3. Adjacent, y'all need to download the three.min.js library and save it in the same directory as before.
  4. Now we've got three.js attached to our folio, we can start to write JavaScript that makes utilise of it into script.js. Let's get-go by creating a new scene — add the following into your principal.js file:
                                              const                      scene                      =                      new                      THREE.Scene                      (                      )                      ;                                      
    The Scene() constructor creates a new scene, which represents the whole 3D earth we are trying to display.
  5. Next, we need a photographic camera so we tin can see the scene. In 3D imagery terms, the camera represents a viewer's position in the world. To create a camera, add the following lines next:
                                              const                      camera                      =                      new                      THREE.PerspectiveCamera                      (                      75                      ,                      window.innerWidth                      /                      window.innerHeight,                      0.ane                      ,                      1000                      )                      ;                      camera.position.z                      =                      5                      ;                                      
    The PerspectiveCamera() constructor takes four arguments:
    • The field of view: How wide the area in front end of the photographic camera is that should be visible onscreen, in degrees.
    • The attribute ratio: Normally, this is the ratio of the scene's width divided by the scene's height. Using another value will distort the scene (which might be what you want, only ordinarily isn't).
    • The well-nigh aeroplane: How close to the camera objects can be earlier nosotros stop rendering them to the screen. Think about how when you move your fingertip closer and closer to the space between your eyes, somewhen you can't see it anymore.
    • The far airplane: How far away things are from the camera earlier they are no longer rendered.
    We also set the camera'southward position to be v distance units out of the Z centrality, which, like in CSS, is out of the screen towards you, the viewer.
  6. The third vital ingredient is a renderer. This is an object that renders a given scene, as viewed through a given camera. We'll create one for at present using the WebGLRenderer() constructor, but we'll not use information technology till later. Add together the following lines adjacent:
                                              const                      renderer                      =                      new                      Three.WebGLRenderer                      (                      )                      ;                      renderer.                      setSize                      (window.innerWidth,                      window.innerHeight)                      ;                      document.body.                      appendChild                      (renderer.domElement)                      ;                                      
    The start line creates a new renderer, the second line sets the size at which the renderer will draw the photographic camera's view, and the third line appends the <canvas> element created by the renderer to the document's <trunk>. Now anything the renderer draws volition be displayed in our window.
  7. Next, nosotros want to create the cube nosotros'll brandish on the canvass. Add the following chunk of code at the bottom of your JavaScript:
                                              allow                      cube;                      const                      loader                      =                      new                      Three.TextureLoader                      (                      )                      ;                      loader.                      load                      (                      'metal003.png'                      ,                      texture                      =>                      {                      texture.wrapS                      =                      THREE                      .RepeatWrapping;                      texture.wrapT                      =                      Three                      .RepeatWrapping;                      texture.repeat.                      set                      (                      two                      ,                      2                      )                      ;                      const                      geometry                      =                      new                      THREE.BoxGeometry                      (                      2.4                      ,                      2.4                      ,                      2.4                      )                      ;                      const                      material                      =                      new                      3.MeshLambertMaterial                      (                      {                      map                      :                      texture                      }                      )                      ;                      cube                      =                      new                      Iii.Mesh                      (geometry,                      material)                      ;                      scene.                      add                      (cube)                      ;                      depict                      (                      )                      ;                      }                      )                      ;                                      
    There's a bit more to have in hither, so let's become through it in stages:
    • We first create a cube global variable and so nosotros can access our cube from anywhere in the lawmaking.
    • Adjacent, nosotros create a new TextureLoader object, then phone call load() on it. load() takes ii parameters in this case (although information technology tin can accept more): the texture nosotros want to load (our PNG), and a function that will run when the texture has loaded.
    • Inside this function nosotros apply properties of the texture object to specify that we want a 2 x 2 repeat of the image wrapped around all sides of the cube. Next, nosotros create a new BoxGeometry object and a new MeshLambertMaterial object, and bring them together in a Mesh to create our cube. An object typically requires a geometry (what shape it is) and a material (what its surface looks like).
    • Last of all, we add together our cube to the scene, then call our depict() function to start off the blitheness.
  8. Before we get to defining draw(), nosotros'll add a couple of lights to the scene, to liven things up a bit; add the following blocks next:
                                              const                      light                      =                      new                      THREE.AmbientLight                      (                      'rgb(255,255,255)'                      )                      ;                      // soft white low-cal                      scene.                      add                      (light)                      ;                      const                      spotLight                      =                      new                      3.SpotLight                      (                      'rgb(255,255,255)'                      )                      ;                      spotLight.position.                      set                      (                      100                      ,                      1000                      ,                      chiliad                      )                      ;                      spotLight.castShadow                      =                      true                      ;                      scene.                      add                      (spotLight)                      ;                                      
    An AmbientLight object is a kind of soft light that lightens the whole scene a bit, like the sunday when you are outside. The SpotLight object, on the other hand, is a directional axle of light, more like a flashlight/torch (or a spotlight, in fact).
  9. Last of all, let'southward add our depict() function to the bottom of the code:
                                              part                      depict                      (                      )                      {                      cube.rotation.ten                      +=                      0.01                      ;                      cube.rotation.y                      +=                      0.01                      ;                      renderer.                      render                      (scene,                      camera)                      ;                      requestAnimationFrame                      (describe)                      ;                      }                                      
    This is fairly intuitive; on each frame, nosotros rotate our cube slightly on its 10 and Y axes, then render the scene as viewed past our camera, then finally phone call requestAnimationFrame() to schedule drawing our next frame.

Let'southward have another quick await at what the finished production should await similar:

You tin can find the finished lawmaking on GitHub.

Note: In our GitHub repo you can also observe another interesting 3D cube example — Three.js Video Cube (see it live also). This uses getUserMedia() to take a video stream from a computer web cam and projection it onto the side of the cube every bit a texture!

Summary

At this betoken, y'all should take a useful thought of the nuts of graphics programming using Canvass and WebGL and what you can do with these APIs, too as a good idea of where to go for farther information. Take fun!

Come across also

Here we have covered merely the real basics of canvas — there is so much more than to larn! The below articles will take y'all farther.

  • Canvas tutorial — A very detailed tutorial series explaining what you should know most 2d canvas in much more detail than was covered here. Essential reading.
  • WebGL tutorial — A series that teaches the basics of raw WebGL programming.
  • Building up a basic demo with Three.js — bones Three.js tutorial. We also take equivalent guides for PlayCanvas or Babylon.js.
  • Game development — the landing page for web games development on MDN. In that location are some really useful tutorials and techniques available here related to 2D and 3D sail — run across the Techniques and Tutorials menu options.

Examples

In this module

  • Introduction to spider web APIs
  • Manipulating documents
  • Fetching data from the server
  • Third party APIs
  • Drawing graphics
  • Video and audio APIs
  • Client-side storage

baxtergrately.blogspot.com

Source: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics

0 Response to "Draw Little Circles in Angular"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel