📜 ⬆️ ⬇️

Another Canvas Guide [4]: ​​The end

In this part


[Transformations,
Compositions
Animations
Pixel Manipulation]

Transformations


Recall some methods


First, we will need to recall the two methods that were mentioned in the last chapter.
save - saves the current state at the top of the stack
restore - sets the state from the top of the stack
The state should be understood: transformation matrix, drawing area, and the following properties: strokeStyle, fillStyle globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline.

Displace


translate(float x, float y) 
- let's shift the current position of the origin of coordinates by x and y from the previous position.
Consider the following example:
 ctx.save() //  ctx.translate(100,100) //   ctx.textBaseline = 'top' ctx.font = "bold italic 30px sans-serif" ctx.strokeText(" ",0,0) //     (0;0),        ctx.restore() // ,     ,    

Turn



 rotate(float angle) 
- rotates the x-axis and ordinate angle angle, also do not forget that the angle is measured in radians, to convert the angle to radians from degrees, multiply degrees by Pi and divide by 180, that is: rad = deg * Math.PI // 180
For example, add a line after ctx.translate (100,100): ctx.rotate (45 * Math.PI / 180)

Reduce / increase



 scale(float x, float y) 
- will apply the new scale to the x and y axes.
For example, replace ctx.rotate (45 * Math.PI / 180) with ctx.scale (0.65,1.5)

Multiply the matrix


 transform(float m11, float m12, float m21, float m22, float dx , float dy) 
- multiply the old matrix to the new matrix.

Apply the matrix



 setTransform(float m11, float m12, float m21, float m22, float dx , float dy) 
- Apply a new matrix, for example, look at the following code.
 var img = new Image(); img.onload = function(){ ctx.save() ctx.setTransform(1,0.5,0,1,1,1) ctx.drawImage(img,0,0,78,50) ctx.restore() } img.src = 'brick.jpg'; 

I used a brick wall picture and a shearing transformation .
In addition, the transformations can be read in more detail in the topic from Nutochka
')

Compositions


Types of composition operations



The globalCompositeOperation property is responsible for the type of composition operation, we could paint all its possible values, but there is a Canvas Cheat Sheet and it is better to show a part of the picture, a blue rectangle was drawn first, and a red circle second and depending on the value of globalCompositeOperation we will get different results .














GlobalAlpha property



The globalAlpha property is actually a multiplier by which the transparency of each image is multiplied, while only if 0 <= globalAlpha <= 1. For example, consider the code:
 ctx.globalAlpha = 0.6; ctx.fillRect(0,0,100,100) ctx.fillRect(50,50,100,100) 


Animation


requestAnimationFrame


If earlier timers were used for animation, now a special function called requestAnimationFrame has appeared, the topic is already covered so it is better to read the translation from azproduction .

The basic principle of animation


The basic principle of animation is to erase the old frame and draw a new one. To erase the old frame is the easiest to use the clearRect function. For example, consider the following code. First, add the requestAnimationFrame definition to your code:
 var x = 400, y = 300; (function loop(){ ctx.clearRect(0,0,800,600); ctx.beginPath(); ctx.arc(x++,y++,50,0,Math.PI*2,false); ctx.fill() requestAnimFrame(loop); })(); 

Also about animation can be read in the topic from trickii

1 game! = 1 canvas


I saw this rule in the canvas acceleration presentation and realized that this is the simplest rule.
Instead of drawing complex images with each frame, you can save this image into a virtual canvas and then draw it with each frame, but however it is worth noting that you don’t have to shove everything into a virtual canvas, you only have to push shapes that are really difficult to draw (for example, text or gradient ). For example, I did a small test on jsperf.com , not ideal, but I think the meaning is clear.

Manipulate pixels


Apart from high-level methods, canvas also has full access to pixels, using it you can create wonderful things (I mean filters and the like), and also draw simple things very quickly. There is a special type of ImageData for working with pixels, it has three properties, width, height (I think it doesn’t need to be explained) and data is an array of r, g, b, a values ​​for each pixel.

How pixel data is stored



Data about the pixels as previously stated is stored in an array, while the number of elements in the array is equal to the number of pixels multiplied by 4. All elements take values ​​in the range 0..255.
Including the alpha channel stored in values ​​from 0..255. The picture shows that the four values ​​of r, g, b, a form a segment, the segment in turn is a single indivisible cell storing the parameters of one pixel.

Creating an empty ImageData


 ImageData = context.createImageData(int w, int h) 
- creates an empty ImageData with width and height w and h, respectively.
 ImageData = context.createImageData(imageData) 
- create an empty ImageData with the width and height of the transferred imageData, note: the data is not copied.

Application ImageData


 context.putImageData(imageData imgd, int x, int y) 
- will change the array of pixels of the canvas in the area from the point xy with the width and height of imageData.

Simple example


But enough of the theory, let's get down to business, let's try to draw a graph of the function y = x * x, without smoothing:
 var imgd = ctx.createImageData(800, 600); var x,y,segment,xround,yround; for (x=-40 ; x<=40 ; x+=0.01) { y = x*x; xround = ~~(x+0.5); yround = ~~(y+0.5); segment = ((-yround+400)*imgd.width + xround + 40)*4; imgd.data[segment+3] = 255; } ctx.putImageData(imgd, 0, 0); 

To compare performance, I wrote similar code using fillRect, again on jsperf , however, to draw one point, it is better to use fillRect since creating imageData also takes resources.

Manipulation of image pixels


 ImageData = context.createImageData(int x, int y, int w, int h) 
- returns an imageData object with data from canvas in a rectangular area with a left top vertex at (x; y) and a width, height w and h, respectively. For example, let's try to highlight white areas in a photo:
 var img = new Image(); img.src = 'test.jpg'; //     img.onload = function(){ //netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); --      FireFox   ctx.drawImage(img, 0, 0, 160, 120); var imgd = ctx.getImageData(0, 0, 160, 120); // imageData for (var i=0 ; i<imgd.data.length ; i+=4) { imgd.data[i] = imgd.data[i+1] = imgd.data[i+2] = imgd.data[i] < 200 && imgd.data[i+1] < 200 && imgd.data[i+2] < 200 ? 0 : 255; //     } ctx.putImageData(imgd, 0, 0); //, ,     } 

Source: https://habr.com/ru/post/119621/


All Articles