Webgl Three Js Draw Text Box on Screen
Drawing graphics
Graphics on the Spider web
As nosotros talked about in our HTML Multimedia and embedding module, the Web was originally merely text, which was very tiresome, and so images were introduced — get-go via the <img>
chemical element and subsequently via CSS properties such equally background-image
, and SVG.
This however was however not enough. While you could utilize CSS and JavaScript to animate (and otherwise manipulate) SVG vector images — every bit they are represented by markup — in that location was still no way to do the aforementioned for bitmap images, and the tools bachelor were rather express. The Web still had no way 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 amend when browsers began to support the <canvas>
element and associated Canvas API — Apple invented it in around 2004, and other browsers followed past implementing it in the years that followed. As you lot'll encounter below, sail provides many useful tools for creating 2D animations, games, data visualizations, and other types of app, especially when combined with some of the other APIs the web platform provides.
The beneath case shows a simple 2nd canvas-based bouncing balls blitheness that nosotros originally met in our Introducing JavaScript objects module:
Around 2006–2007, Mozilla started work on an experimental 3D sheet implementation. This became WebGL, which gained traction amid browser vendors, and was standardized around 2009–2010. WebGL allows yous to create real 3D graphics inside your web browser; the below example shows a simple rotating WebGL cube:
This article volition focus mainly on 2D sail, as raw WebGL lawmaking is very complex. We volition however testify how to use a WebGL library to create a 3D scene more hands, and you can find a tutorial covering raw WebGL elsewhere — see Getting started with WebGL.
Notation: Basic canvas functionality is supported well beyond browsers, with the exception of IE 8 and below for 2d canvass, and IE xi and below for WebGL.
Active learning: Getting started with a <canvas>
If you lot want to create a 2D or 3D scene on a web page, you demand to offset with an HTML <canvas>
element. This element is used to define the area on the folio into which the image volition be drawn. This is as simple equally including the chemical element on the folio:
<canvas width = "320" height = "240" > </sail >
This volition create a sail on the page with a size of 320 by 240 pixels.
Inside the canvas tags, you can put some fallback content, which is shown if the user's browser doesn't back up canvass.
<canvas width = "320" superlative = "240" > <p > Your browser doesn't support canvas. Boo hoo! </p > </canvas >
Of course, the in a higher place message is really unhelpful! In a real example you lot'd desire to relate the fallback content to the canvas content. For example, if you were rendering a constantly updating graph of stock prices, the fallback content could be a static image of the latest stock graph, with alt text proverb what the prices are in text.
Creating and sizing our canvas
Let'south start by creating our own sheet that we draw future experiments on to.
- Starting time brand a local copy of the 0_canvas_start directory. It contains 3 files:
- "index.html"
- "script.js"
- "style.css"
- Open "alphabetize.html", and add together the post-obit code into it, simply beneath the opening
<trunk>
tag:<canvas class = "myCanvas" > <p > Add suitable fallback here. </p > </canvass >
grade
to the<canvas>
element so it volition be easier to select if we take multiple canvases on the page, but we accept removed thewidth
andacme
attributes for now (you lot could add together them back in if yous wanted, but we will prepare them using JavaScript in a below section). Canvases with no explicit width and meridian default to 300 pixels wide by 150 pixels high. - Now open up "script.js" and add the following lines of JavaScript:
const canvas = document. querySelector ( '.myCanvas' ) ; const width = sheet.width = window.innerWidth; const height = canvas.height = window.innerHeight;
canvas
constant. In the 2d line we set both a new constantwidth
and the canvas'width
property equal toWindow.innerWidth
(which gives us the viewport width). In the 3rd line we set both a new abidingsummit
and the canvas'height
property equal toWindow.innerHeight
(which gives united states of america the viewport height). And then at present nosotros have a canvas that fills the entire width and height of the browser window! You lot'll also see that we are chaining assignments together with multiple equals signs — this is allowed in JavaScript, and it is a expert technique if you want to make multiple variables all equal to the same value. We wanted to make the canvas width and height easily accessible in the width/height variables, as they are useful values to have available for later (for example, if you want to draw something exactly halfway beyond the width of the canvas).
Note: Y'all should generally set the size of the epitome using HTML attributes or DOM properties, as explained higher up. You lot could utilise CSS, but the trouble then is that the sizing is done after the canvas has rendered, and only like whatsoever other image (the rendered canvass is simply an prototype), the image could become pixelated/distorted.
Getting the canvas context and concluding setup
We need to do one final thing before we tin consider our canvas template finished. To draw onto the sail we need to go a special reference to the drawing area called a context. This is washed using the HTMLCanvasElement.getContext()
method, which for basic usage takes a single string as a parameter representing the type of context you lot want to retrieve.
In this example we want a 2nd canvas, and then add together the following JavaScript line below the others in "script.js":
const ctx = sheet. getContext ( '2nd' ) ;
Note: other context values you could cull include webgl
for WebGL, webgl2
for WebGL 2, etc., only we won't need those in this commodity.
Then that'south it — our canvas is at present primed and ready for cartoon on! The ctx
variable at present contains a CanvasRenderingContext2D
object, and all drawing operations on the canvas will involve manipulating this object.
Let's exercise one concluding thing before nosotros movement on. Nosotros'll colour the sail background black to give you a first taste of the canvas API. Add together the following lines at the bottom of your JavaScript:
ctx.fillStyle = 'rgb(0, 0, 0)' ; ctx. fillRect ( 0 , 0 , width, height) ;
Here nosotros are setting a make full color using the sail' fillStyle
property (this takes color values just like CSS properties do), then cartoon a rectangle that covers the unabridged area of the canvas with thefillRect
method (the outset two parameters are the coordinates of the rectangle's top left mitt corner; the concluding ii are the width and height you lot want the rectangle fatigued at — we told y'all those width
and peak
variables would be useful)!
OK, our template is done and it'south time to move on.
2nd canvas nuts
As nosotros said above, all drawing operations are washed by manipulating a CanvasRenderingContext2D
object (in our instance, ctx
). Many operations demand to be 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 tiptop to bottom.
Drawing shapes tends to be done using the rectangle shape primitive, or by tracing a line along a sure path and so filling in the shape. Below we'll show how to practise both.
Uncomplicated rectangles
Permit's start with some unproblematic rectangles.
- First of all, take a copy of your newly coded sheet template (or brand a local copy of the 1_canvas_template directory if you didn't follow the above steps).
- Next, add together the following lines to the bottom of your JavaScript:
ctx.fillStyle = 'rgb(255, 0, 0)' ; ctx. fillRect ( 50 , 50 , 100 , 150 ) ;
- Let's add another rectangle into the mix — a light-green one this fourth dimension. Add the following at the bottom of your JavaScript:
ctx.fillStyle = 'rgb(0, 255, 0)' ; ctx. fillRect ( 75 , 75 , 100 , 100 ) ;
- Note that yous can depict semi-transparent graphics by specifying a semi-transparent color, for example by using
rgba()
. Thea
value defines what'southward called the "alpha channel, " or the corporeality of transparency the color has. The college its value, the more information technology will obscure whatsoever's behind it. Add the following to your lawmaking:ctx.fillStyle = 'rgba(255, 0, 255, 0.75)' ; ctx. fillRect ( 25 , 100 , 175 , 50 ) ;
- Now try drawing some more than rectangles of your ain; 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 blueprint). To set the color you want for your stroke, you employ the strokeStyle
holding; drawing a stroke rectangle is done using strokeRect
.
- Add together the following to the previous example, again below the previous JavaScript lines:
ctx.strokeStyle = 'rgb(255, 255, 255)' ; ctx. strokeRect ( 25 , 25 , 175 , 200 ) ;
- The default width of strokes is 1 pixel; you can adjust the
lineWidth
holding value to modify this (information technology takes a number representing the number of pixels wide the stroke is). Add the post-obit line in between the previous two lines:
Now you should see that your white outline has get much thicker! That'south it for now. At this point your example should wait similar this:
Drawing paths
If y'all want to draw anything more complex than a rectangle, you need to draw a path. Basically, this involves writing code to specify exactly what path the pen should movement along on your sheet to trace the shape yous want to describe. Sheet includes functions for cartoon straight lines, circles, Bézier curves, and more.
Permit's start the section off by making a fresh re-create of our canvas template (1_canvas_template), in which to draw the new example.
We'll be using some mutual methods and properties beyond all of the beneath sections:
-
beginPath()
— start cartoon a path at the point where the pen currently is on the canvass. On a new canvas, the pen starts out at (0, 0). -
moveTo()
— motility the pen to a different signal on the canvas, without recording or tracing the line; the pen "jumps" to the new position. -
fill()
— draw a filled shape by filling in the path you've traced so far. -
stroke()
— depict an outline shape by drawing a stroke along the path you've drawn then far. - You tin can too use features like
lineWidth
andfillStyle
/strokeStyle
with paths too as rectangles.
A typical, unproblematic path-drawing operation would look something like so:
ctx.fillStyle = 'rgb(255, 0, 0)' ; ctx. beginPath ( ) ; ctx. moveTo ( 50 , 50 ) ; // draw your path ctx. fill ( ) ;
Drawing lines
Allow's draw an equilateral triangle on the canvas.
- Outset of all, add together the post-obit helper function to the bottom of your code. This converts caste values to radians, which is useful because whenever y'all need to provide an angle value in JavaScript, information technology will nearly always be in radians, but humans usually think in degrees.
role degToRad ( degrees ) { render degrees * Math. PI / 180 ; }
- Next, beginning off your path by adding the following below your previous improver; hither nosotros prepare a color for our triangle, beginning drawing a path, and so move the pen to (50, 50) without drawing annihilation. That'due south where we'll start drawing our triangle.
ctx.fillStyle = 'rgb(255, 0, 0)' ; ctx. beginPath ( ) ; ctx. moveTo ( 50 , 50 ) ;
- Now add together the following lines at the bottom of your script:
ctx. lineTo ( 150 , 50 ) ; const triHeight = 50 * Math. tan ( degToRad ( 60 ) ) ; ctx. lineTo ( 100 , 50 + triHeight) ; ctx. lineTo ( 50 , fifty ) ; ctx. fill ( ) ;
- The longest side is called the hypotenuse
- The side next to the threescore degree bending is called the next — which nosotros know is fifty pixels, equally it is one-half of the line we simply drew.
- The side opposite the 60 degree bending is chosen the opposite, which is the summit of the triangle nosotros desire to calculate.
50 * Math.tan(degToRad(60))
. We utilize ourdegToRad()
function to convert lx degrees to radians, every bitMath.tan()
expects an input value in radians. - With the top calculated, we draw another line to
(100, fifty + triHeight)
. The Ten coordinate is unproblematic; information technology must be halfway between the previous two X values we set. The Y value on the other hand must exist fifty plus the triangle height, equally we know the top of the triangle is 50 pixels from the superlative of the sail. - The next line draws a line back to the starting signal of the triangle.
- Terminal of all, nosotros run
ctx.make full()
to end the path and make full in the shape.
Drawing circles
Now let's look at how to depict a circle in canvas. This is accomplished using the arc()
method, which draws all or part of a circle at a specified point.
- Permit's add an arc to our canvas — add the following to the lesser of your code:
ctx.fillStyle = 'rgb(0, 0, 255)' ; ctx. beginPath ( ) ; ctx. arc ( 150 , 106 , 50 , degToRad ( 0 ) , degToRad ( 360 ) , imitation ) ; ctx. fill up ( ) ;
arc()
takes six parameters. The first ii specify the position of the arc'south center (Ten and Y, respectively). The tertiary is the circle's radius, the fourth and fifth are the start and end angles at which to draw the circle (and so specifying 0 and 360 degrees gives us a full circle), and the 6th parameter defines whether the circumvolve should be fatigued counterclockwise (anticlockwise) or clockwise (false
is clockwise).Notation: 0 degrees is horizontally to the correct.
- Let's try adding another arc:
ctx.fillStyle = 'yellow' ; ctx. beginPath ( ) ; ctx. arc ( 200 , 106 , 50 , degToRad ( - 45 ) , degToRad ( 45 ) , truthful ) ; ctx. lineTo ( 200 , 106 ) ; ctx. fill ( ) ;
- We accept ready the last parameter of
arc()
totrue
, significant that the arc is drawn counterclockwise, which means that even though the arc is specified as starting at -45 degrees and ending at 45 degrees, we draw the arc effectually the 270 degrees not inside this portion. If you were to changetrue
tofalse
so re-run the code, only the 90 caste slice of the circle would be drawn. - Earlier calling
make full()
, nosotros draw a line to the middle of the circle. This ways that we become the rather nice Pac-Man-way cutout rendered. If you removed this line (try information technology!) so re-ran the code, you'd get just an border of the circle chopped off betwixt the start and end betoken of the arc. This illustrates some other important point of the canvas — if you try to fill an incomplete path (i.e. 1 that is not airtight), the browser fills in a straight line between the start and terminate point then fills it in.
- We accept ready the last parameter of
That's it for now; your concluding example should wait like this:
Notation: The finished code is available on GitHub equally 3_canvas_paths.
Note: To observe out more virtually advanced path drawing features such as Bézier curves, cheque out our Drawing shapes with sail tutorial.
Text
Canvas besides has features for drawing text. Allow's explore these briefly. Start past making another fresh copy of our sheet template (1_canvas_template) in which to draw the new instance.
Text is drawn using ii methods:
-
fillText()
— draws filled text. -
strokeText()
— draws outline (stroke) text.
Both of these have 3 properties in their bones usage: the text string to draw and the X and Y coordinates of the point to start cartoon the text at. This works out as the bottom left corner of the text box (literally, the box surrounding the text you draw), which might confuse you as other drawing operations tend to start from the acme left corner — bear this in mind.
There are also a number of properties to assist command text rendering such as font
, which lets y'all specify font family, size, etc. It takes as its value the aforementioned syntax as the CSS font
property.
Try adding the post-obit block to the bottom of your JavaScript:
ctx.strokeStyle = 'white' ; ctx.lineWidth = 1 ; ctx.font = '36px arial' ; ctx. strokeText ( 'Canvas text' , 50 , fifty ) ; ctx.fillStyle = 'ruddy' ; ctx.font = '48px georgia' ; ctx. fillText ( 'Canvas text' , fifty , 150 ) ;
Here we draw 2 lines of text, i outline and the other stroke. The final instance 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 upwards with! Y'all can find more than data on the options available for canvas text at Drawing text.
Drawing images onto canvas
It is possible to render external images onto your canvass. These can be unproblematic images, frames from videos, or the content of other canvases. For the moment we'll simply wait at the case of using some unproblematic images on our canvas.
- As earlier, brand another fresh copy of our canvas template (1_canvas_template) in which to draw the new example. Images are drawn onto sail using the
drawImage()
method. The simplest version takes three parameters — a reference to the epitome you want to render, and the X and Y coordinates of the image's elevation left corner. - Allow'southward get-go by getting an image source to embed in our sheet. Add the following lines to the bottom of your JavaScript:
const image = new Image ( ) ; epitome.src = 'firefox.png' ;
HTMLImageElement
object using theImage()
constructor. The returned object is the same type as that which is returned when you grab a reference to an existing<img>
element). We then set itssrc
attribute to equal our Firefox logo paradigm. At this betoken, the browser starts loading the image. - Nosotros could now attempt to embed the paradigm using
drawImage()
, but nosotros demand to make sure the image file has been loaded start, otherwise the code will fail. We can attain this using theload
event, which volition only be fired when the image has finished loading. Add the post-obit block below the previous ane:image. addEventListener ( 'load' , ( ) => ctx. drawImage (prototype, 20 , 20 , 185 , 175 , 50 , 50 , 185 , 175 ) ) ;
- Just at that place'southward more! What if nosotros want to display only a part of the prototype, or to resize it? We can do both with the more complex version of
drawImage()
. Update yourctx.drawImage()
line like so:ctx. drawImage (epitome, 20 , 20 , 185 , 175 , 50 , 50 , 185 , 175 ) ;
- The first parameter is the paradigm reference, as before.
- Parameters 2 and 3 ascertain the coordinates of the peak left corner of the area you want to cutting out of the loaded image, relative to the peak-left corner of the prototype itself. Nil to the left of the showtime parameter or to a higher place the 2d will be fatigued.
- Parameters 4 and 5 ascertain the width and height of the area we want to cut out from the original image nosotros loaded.
- Parameters half-dozen and 7 define the coordinates at which you want to draw the top-left corner of the cutting-out portion of the image, relative to the meridian-left corner of the canvas.
- Parameters 8 and nine define the width and acme to draw the cut-out area of the paradigm. In this instance, we accept specified the aforementioned dimensions as the original slice, just you lot could resize it past specifying unlike values.
The last example should expect like and so:
Note: The finished code is available on GitHub as 5_canvas_images.
Loops and animations
We have so far covered some very basic uses of 2d canvas, but really you won't feel the full ability of sail unless you update or animate it in some way. After all, sheet does provide scriptable images! If you aren't going to modify anything, and so you might too merely utilize static images and save yourself all the work.
Creating a loop
Playing with loops in canvas is rather fun — yous can run canvas commands within a for
(or other type of) loop merely like any other JavaScript code.
Permit's build a simple example.
- Brand another fresh re-create of our sail template (1_canvas_template) and open it in your code editor.
- Add the following line to the bottom of your JavaScript. This contains a new method,
translate()
, which moves the origin point of the canvass:ctx. translate (width/ 2 , height/ 2 ) ;
- Now add the following lawmaking to the lesser of the JavaScript:
function degToRad ( degrees ) { return degrees * Math. PI / 180 ; } role rand ( min, max ) { render Math. flooring (Math. random ( ) * (max-min+ one ) ) + (min) ; } allow length = 250 ; let moveOffset = 20 ; for ( let i = 0 ; i < length; i++ ) { }
degToRad()
office we saw in the triangle example above, arand()
part that returns a random number between given lower and upper bounds,length
andmoveOffset
variables (which we'll find out more than about afterward), and an emptyfor
loop. - The idea here is that we'll draw something on the canvas within the
for
loop, and iterate on information technology each time so we can create something interesting. Add the post-obit code within yourfor
loop:ctx.fillStyle = ` rgba( ${ 255 -length} ,0, ${ 255 -length} ,0.nine) ` ; ctx. beginPath ( ) ; ctx. moveTo (moveOffset,moveOffset) ; ctx. lineTo (moveOffset+length,moveOffset) ; const triHeight = length/ two * Math. tan ( degToRad ( lx ) ) ; ctx. lineTo (moveOffset+ (length/ 2 ) ,moveOffset+triHeight) ; ctx. lineTo (moveOffset,moveOffset) ; ctx. fill ( ) ; length-- ; moveOffset += 0.7 ; ctx. rotate ( degToRad ( 5 ) ) ;
- Set the
fillStyle
to be a shade of slightly transparent purple, which changes each time based on the value oflength
. As you'll see later the length gets smaller each fourth dimension the loop runs, so the effect hither is that the color gets brighter with each successive triangle drawn. - Brainstorm the path.
- Motility the pen to a coordinate of
(moveOffset, moveOffset)
; This variable defines how far we want to move each fourth dimension we draw a new triangle. - Describe a line to a coordinate of
(moveOffset+length, moveOffset)
. This draws a line of lengthlength
parallel to the 10 axis. - Summate the triangle's acme, equally before.
- Draw a line to the downward-pointing corner of the triangle, and then describe a line back to the outset of the triangle.
- Telephone call
fill()
to make full in the triangle. - Update the variables that describe the sequence of triangles, so we can be ready to describe the adjacent 1. We decrease the
length
value past one, so the triangles get smaller each time; incrementmoveOffset
by a small corporeality then each successive triangle is slightly further away, and use another new function,rotate()
, which allows united states of america to rotate the entire canvas! We rotate information technology past 5 degrees before cartoon the next triangle.
- Set the
That'due south it! The final case should expect like so:
At this indicate, we'd similar to encourage you lot to play with the example and make information technology your own! For example:
- Depict rectangles or arcs instead of triangles, or even embed images.
- Play with the
length
andmoveOffset
values. - Introduce some random numbers using that
rand()
office we included above but didn't use.
Animations
The loop example nosotros built in a higher place was fun, merely really yous need a constant loop that keeps going and going for any serious canvas applications (such as games and real time visualizations). If you lot call back of your canvas every bit being like a picture show, you really desire the display to update on each frame to evidence the updated view, with an ideal refresh rate of 60 frames per 2nd then that motility appears nice and smooth to the human centre.
There are a few JavaScript functions that volition permit you to run functions repeatedly, several times a 2nd, the best ane for our purposes here existence window.requestAnimationFrame()
. It takes one parameter — the proper noun of the part you desire to run for each frame. The next time the browser is set up to update the screen, your function volition get chosen. If that function draws the new update to your animation, then calls requestAnimationFrame()
once again just before the stop of the function, the animation loop will keep to run. The loop ends when you stop calling requestAnimationFrame()
or if you call window.cancelAnimationFrame()
after calling requestAnimationFrame()
only earlier the frame is called.
Note: It'south good exercise to call cancelAnimationFrame()
from your master 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 exist seen.
To see how it works, let'due south apace look over again at our Bouncing Balls case (see it live, and also run across 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 balls) { ball. draw ( ) ; ball. update ( ) ; ball. collisionDetect ( ) ; } requestAnimationFrame (loop) ; } loop ( ) ;
We run the loop()
office in one case at the lesser of the code to start the bicycle, cartoon the get-go animation frame; the loop()
office and so takes accuse of calling requestAnimationFrame(loop)
to run the adjacent frame of the animation, once more and over again.
Annotation that on each frame we are completely clearing the sail and redrawing everything. For every brawl present we draw it, update its position, and check to see if it is colliding with any other balls. Once you lot've drawn a graphic to a canvas, there's no way to manipulate that graphic individually like y'all tin can with DOM elements. Yous tin can't motility each ball around on the canvas, because one time information technology's drawn, it'southward part of the canvas, and is not an individual attainable chemical element or object. Instead, you lot have to erase and redraw, either past erasing the entire frame and redrawing everything, or by having code that knows exactly what parts need to be erased and only erases and redraws the minimum area of the canvass necessary.
Optimizing animation of graphics is an entire specialty of programming, with lots of clever techniques available. Those are beyond what we demand for our case, though!
In general, the procedure of doing a sheet blitheness involves the following steps:
- Articulate the canvass contents (e.thousand. with
fillRect()
orclearRect()
). - Save state (if necessary) using
save()
— this is needed when you want to save settings you lot've updated on the canvas before standing, which is useful for more advanced applications. - Describe the graphics you are animating.
- Restore the settings yous saved in step 2, using
restore()
- Call
requestAnimationFrame()
to schedule drawing of the next frame of the animation.
Notation: We won't cover save()
and restore()
here, simply they are explained nicely in our Transformations tutorial (and the ones that follow it).
A uncomplicated character animation
Now allow'due south create our own simple animation — nosotros'll go a grapheme from a certain rather crawly retro reckoner game to walk across the screen.
- Brand another fresh copy of our canvas template (1_canvas_template) and open information technology in your code editor.
- At the bottom of the JavaScript, add the following line to in one case once again brand the coordinate origin sit in the heart of the canvas:
ctx. translate (width/ two , height/ 2 ) ;
- At present let'southward create a new
HTMLImageElement
object, set itssrc
to the image nosotros desire to load, and add anonload
event handler that will cause thedescribe()
role to burn when the image is loaded:const image = new Image ( ) ; image.src = 'walk-right.png' ; image.onload = depict;
- At present nosotros'll add some variables to proceed track of the position the sprite is to be fatigued on the screen, and the sprite number we want to display.
let sprite = 0 ; let posX = 0 ;
drawImage()
to chop out a single sprite image from the spritesheet and display just that role, like 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 will always exist 0. The piece size will e'er be 102 by 148 pixels. - Now let's insert an empty
draw()
part at the bottom of the code, ready for filling up with some code: - The remainder of the code in this section goes inside
describe()
. First, add the following line, which clears the sheet to set for drawing each frame. Detect that nosotros take to specify the acme-left corner of the rectangle equally-(width/2), -(height/2)
because we specified the origin position aswidth/2, summit/two
earlier on.ctx. fillRect ( - (width/ ii ) , - (superlative/ 2 ) , width, height) ;
- Next, we'll draw our image using drawImage — the 9-parameter version. Add together the following:
ctx. drawImage (image, (sprite* 102 ) , 0 , 102 , 148 , 0 +posX, - 74 , 102 , 148 ) ;
- We specify
image
every bit the image to embed. - Parameters 2 and 3 specify the acme-left corner of the slice to cut out of the source paradigm, with the Ten value every bit
sprite
multiplied by 102 (wheresprite
is the sprite number between 0 and 5) and the Y value always 0. - Parameters iv and 5 specify the size of the slice to cutting out — 102 pixels past 148 pixels.
- Parameters 6 and 7 specify the acme-left corner of the box into which to draw the slice on the sheet — the X position is 0 +
posX
, pregnant that we tin can alter the drawing position by altering theposX
value. - Parameters viii and ix specify the size of the image on the canvas. We only desire to keep its original size, so we specify 102 and 148 every bit the width and height.
- We specify
- Now we'll alter the
sprite
value later on each describe — well, after some of them anyhow. Add the following block to the bottom of thedraw()
function:if (posX % 13 === 0 ) { if (sprite === five ) { sprite = 0 ; } else { sprite++ ; } }
if (posX % 13 === 0) { ... }
. Nosotros apply the modulo (%
) operator (also known every bit the remainder operator) to check whether theposX
value can exist exactly divided by 13 with no residue. If then, we move on to the next sprite past incrementingsprite
(wrapping to 0 after we're done with sprite #v). This effectively means that we are simply updating the sprite on every 13th frame, or roughly virtually 5 frames a 2d (requestAnimationFrame()
calls us at upwards to 60 frames per second if possible). We are deliberately slowing downwardly the frame charge per unit because we only accept vi sprites to work with, and if we display one every 60th of a second, our character volition move manner likewise fast! Inside the outer block we utilize anif ... else
statement to cheque whether thesprite
value is at 5 (the last sprite, given that the sprite numbers run from 0 to five). If we are showing the concluding sprite already, we resetsprite
back to 0; if not we just increment information technology past 1. - Next we demand to work out how to change the
posX
value on each frame — add the post-obit lawmaking block but below your final i.if (posX > width/ 2 ) { let newStartPos = - ( (width/ two ) + 102 ) ; posX = Math. ceil (newStartPos) ; console. log (posX) ; } else { posX += two ; }
if ... else
statement to see if the value ofposX
has become greater thanwidth/ii
, which means our character has walked off the correct edge of the screen. If so, we calculate a position that would put the graphic symbol just to the left of the left side of the screen. If our grapheme hasn't yet walked off the border of the screen, nosotros increaseposX
by ii. This will make him move a picayune bit to the right the next time we describe him. - Finally, nosotros demand to make the animation loop past calling
requestAnimationFrame()
at the bottom of thedepict()
function:window. requestAnimationFrame (draw) ;
That'due south it! The final example should look like and then:
A simple cartoon application
As a concluding animation case, we'd like to bear witness you a very uncomplicated drawing application, to illustrate how the animation loop can be combined with user input (like mouse movement, in this case). We won't get you lot to walk through and build this 1; we'll just explore the most interesting parts of the code.
The example can be institute on GitHub every bit 8_canvas_drawing_app, and yous can play with it live below:
Let's await at the about interesting parts. Kickoff of all, we keep rail of the mouse'south X and Y coordinates and whether it is beingness clicked or not with iii variables: curX
, curY
, and pressed
. When the mouse moves, nosotros burn a part set as the onmousemove
event handler, which captures the electric current 10 and Y values. We also use onmousedown
and onmouseup
effect handlers to modify the value of pressed
to true
when the mouse button is pressed, and back to false
again when it is released.
let curX; let curY; allow pressed = false ; // update mouse pointer coordinates document. addEventListener ( 'mousemove' , east => { curX = (window.Event) ? e.pageX : e.clientX + (document.documentElement.scrollLeft ? certificate.documentElement.scrollLeft : document.torso.scrollLeft) ; curY = (window.Event) ? e.pageY : e.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : certificate.body.scrollTop) ; } ) ; sheet. addEventListener ( 'mousedown' , ( ) => pressed = true ) ; sail. addEventListener ( 'mouseup' , ( ) => pressed = false ) ;
When the "Clear canvass" button is pressed, we run a elementary function that clears the whole canvas back to black, the same mode nosotros've seen before:
clearBtn. addEventListener ( 'click' , ( ) => { ctx.fillStyle = 'rgb(0,0,0)' ; ctx. fillRect ( 0 , 0 ,width,height) ; } ) ;
The drawing loop is pretty uncomplicated this time around — if pressed is true
, we depict a circle with a fill style equal to the value in the color picker, and a radius equal to the value set in the range input. We have to depict the circle 85 pixels above where we measured information technology from, because the vertical measurement is taken from the height of the viewport, but we are drawing the circle relative to the superlative of the canvass, which starts below the 85 pixel-high toolbar. If we drew information technology with simply curY
as 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. make full ( ) ; } requestAnimationFrame (describe) ; } draw ( ) ;
Note: The <input>
range
and color
types are supported fairly well across browsers, with the exception of Internet Explorer versions less than ten; too Safari doesn't yet support color
. If your browser doesn't support these inputs, they will fall back to unproblematic text fields and you'll merely have to enter valid color/number values yourself.
WebGL
It'due south now time to get out 2D behind, and take a quick look at 3D sail. 3D canvas content is specified using the WebGL API, which is a completely separate API from the 2d sail API, even though they both render onto <sheet>
elements.
WebGL is based on OpenGL (Open Graphics Library), and allows you to communicate directly with the reckoner'southward GPU. Every bit such, writing raw WebGL is closer to low level languages such as C++ than regular JavaScript; it is quite circuitous just incredibly powerful.
Using a library
Because of its complication, about people write 3D graphics code using a third political party JavaScript library such as Three.js, PlayCanvas, or Babylon.js. Near of these piece of work in a similar way, providing functionality to create archaic and custom shapes, position viewing cameras and lighting, covering surfaces with textures, and more than. They handle the WebGL for y'all, letting y'all work on a higher level.
Yes, using one of these means learning some other new API (a 3rd party one, in this example), only they are a lot simpler than coding raw WebGL.
Recreating our cube
Let'south expect at a simple example of how to create something with a WebGL library. We'll choose Three.js, equally it is 1 of the almost popular ones. In this tutorial nosotros'll create the 3D spinning cube we saw earlier.
- To start with, make a local re-create of threejs-cube/index.html in a new binder, then salvage a copy of metal003.png in the same folder. This is the image we'll utilize as a surface texture for the cube afterwards.
- Next, create a new file called
script.js
, over again in the aforementioned folder as before. - Next, you need to download the 3.min.js library and save information technology in the same directory every bit before.
- Now we've got
three.js
attached to our page, we tin start to write JavaScript that makes employ of information technology intoscript.js
. Let's starting time by creating a new scene — add together the following into your chief.js file:const scene = new THREE.Scene ( ) ;
Scene()
constructor creates a new scene, which represents the whole 3D earth we are trying to display. - Next, nosotros need a camera so we tin can run across the scene. In 3D imagery terms, the camera represents a viewer's position in the world. To create a photographic camera, add together the following lines adjacent:
const camera = new Iii.PerspectiveCamera ( 75 , window.innerWidth / window.innerHeight, 0.one , thou ) ; photographic camera.position.z = 5 ;
PerspectiveCamera()
constructor takes four arguments:- The field of view: How wide the expanse in front of the photographic camera is that should be visible onscreen, in degrees.
- The attribute ratio: Usually, this is the ratio of the scene's width divided by the scene's height. Using another value will distort the scene (which might exist what you want, but usually isn't).
- The most aeroplane: How close to the camera objects can be earlier we cease rendering them to the screen. Call up about how when you lot move your fingertip closer and closer to the space between your eyes, eventually you tin't run into it anymore.
- The far plane: How far away things are from the camera before they are no longer rendered.
- 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 now using the
WebGLRenderer()
constructor, but we'll non utilize it till later. Add the following lines next:const renderer = new THREE.WebGLRenderer ( ) ; renderer. setSize (window.innerWidth, window.innerHeight) ; document.body. appendChild (renderer.domElement) ;
<canvass>
element created by the renderer to the certificate's<trunk>
. Now anything the renderer draws will be displayed in our window. - Next, we want to create the cube we'll display on the sheet. Add the following clamper of lawmaking at the lesser of your JavaScript:
let cube; const loader = new THREE.TextureLoader ( ) ; loader. load ( 'metal003.png' , texture => { texture.wrapS = THREE .RepeatWrapping; texture.wrapT = 3 .RepeatWrapping; texture.repeat. set ( ii , 2 ) ; const geometry = new THREE.BoxGeometry ( 2.4 , 2.4 , ii.4 ) ; const material = new Iii.MeshLambertMaterial ( { map : texture } ) ; cube = new Iii.Mesh (geometry, material) ; scene. add (cube) ; draw ( ) ; } ) ;
- We first create a
cube
global variable so nosotros can access our cube from anywhere in the code. - Next, nosotros create a new
TextureLoader
object, then callload()
on it.load()
takes two parameters in this case (although it can accept more): the texture we want to load (our PNG), and a part that will run when the texture has loaded. - Inside this role we use backdrop of the
texture
object to specify that nosotros want a 2 x 2 repeat of the epitome wrapped effectually all sides of the cube. Adjacent, nosotros create a newBoxGeometry
object and a newMeshLambertMaterial
object, and bring them together in aMesh
to create our cube. An object typically requires a geometry (what shape it is) and a cloth (what its surface looks like). - Last of all, we add our cube to the scene, then call our
draw()
function to start off the animation.
- We first create a
- Before we become to defining
describe()
, we'll add together a couple of lights to the scene, to liven things upwards a chip; add together the following blocks next:const lite = new THREE.AmbientLight ( 'rgb(255,255,255)' ) ; // soft white light scene. add together (light) ; const spotLight = new THREE.SpotLight ( 'rgb(255,255,255)' ) ; spotLight.position. prepare ( 100 , thou , one thousand ) ; spotLight.castShadow = true ; scene. add together (spotLight) ;
AmbientLight
object is a kind of soft light that lightens the whole scene a bit, similar the sun when y'all are exterior. TheSpotLight
object, on the other mitt, is a directional beam of light, more than like a flashlight/torch (or a spotlight, in fact). - Last of all, permit'south add our
describe()
office to the bottom of the code:function draw ( ) { cube.rotation.10 += 0.01 ; cube.rotation.y += 0.01 ; renderer. render (scene, camera) ; requestAnimationFrame (draw) ; }
requestAnimationFrame()
to schedule drawing our adjacent frame.
Let's accept some other quick expect at what the finished product should look like:
You can discover the finished code on GitHub.
Annotation: In our GitHub repo yous can as well find another interesting 3D cube instance — Three.js Video Cube (see information technology live also). This uses getUserMedia()
to accept a video stream from a estimator spider web cam and project it onto the side of the cube as a texture!
Summary
At this signal, y'all should accept a useful idea of the basics of graphics programming using Sail and WebGL and what you can do with these APIs, as well as a good idea of where to go for farther information. Accept fun!
Meet too
Hither nosotros accept covered just the real basics of canvass — there is and then much more to learn! The beneath articles will have you farther.
- Canvas tutorial — A very detailed tutorial series explaining what y'all should know about 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 upwardly a bones demo with Three.js — basic Three.js tutorial. Nosotros too take equivalent guides for PlayCanvas or Babylon.js.
- Game development — the landing page for spider web games development on MDN. There are some really useful tutorials and techniques available here related to 2d and 3D canvas — see 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
- Customer-side storage
slagleungazintonat.blogspot.com
Source: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics
0 Response to "Webgl Three Js Draw Text Box on Screen"
Post a Comment