The question title may be vague. Basically, imagine a racing game built in canvas. The track takes up 10,000 x 10,000 pixels of screen space. However the browser window is 500 x 500 pixels. The car should stay centered in the browser and the 'viewable' area of the 10,000 x 10,000 canvas will change. Otherwise the car would just drive off the edge at disappear.
Does this technique have a name?
What are the basic principles to make this happen?
If the car should stay at the same position (relative to the canvas' position), then you should not move the car. Instead, move the background picture/track/map to the other side.
Causing your eyes to think the car moves right can be done by either moving the car to the right, or by moving the map to the left. The second option seems to be what you want, since the car won't move whereas the viewable area (i.e. the map) will.
This is a quick demo from scratch: http://jsfiddle.net/vXsqM/.
It comes down to altering the map's position the other way round:
$("body").on("keydown", function(e) {
if(e.which === 37) pos.x += speed; // left key, so move map to the right
if(e.which === 38) pos.y += speed;
if(e.which === 39) pos.x -= speed;
if(e.which === 40) pos.y -= speed;
// make sure you can't move the map too far.
// clamp does: if x < -250 return -250
// if x > 0 return 0
// else it's allowed, so just return x
pos.x = clamp(pos.x, -250, 0);
pos.y = clamp(pos.y, -250, 0);
draw();
});
You can then draw the map with the position saved:
ctx.drawImage(img, pos.x, pos.y);
If you're looking for a way to actually move the car when the map cannot be moved any further (because you're driving the car close to a side of the map), then you'd have to extend the clamping and also keep track of when the car should be moved and how far: http://jsfiddle.net/vXsqM/1/.
// for x coordinate:
function clamp2(x, y, a, b) { // x = car x, y = map x, a = min map x, b = max map x
return y > b ? -y : y < a ? a - y : x;
}
The position clamping then becomes a little more complex:
// calculate how much car should be moved
posCar.x = clamp2(posCar.x, posMap.x, -250, 0);
posCar.y = clamp2(posCar.y, posMap.y, -250, 0);
// also don't allow the car to be moved off the map
posCar.x = clamp(posCar.x, -100, 100);
posCar.y = clamp(posCar.y, -100, 100);
// calculate where the map should be drawn
posMapReal.x = clamp(posMap.x, -250, 0);
posMapReal.y = clamp(posMap.y, -250, 0);
// keep track of where the map virtually is, to calculate car position
posMap.x = clamp(posMap.x, -250 - 100, 0 + 100);
posMap.y = clamp(posMap.y, -250 - 100, 0 + 100);
// the 100 is because the car (circle in demo) has a radius of 25 and can
// be moved max 100 pixels to the left and right (it then hits the side)
Two things:
Canvas transformation methods
First, the canvas transformation methods (along with context.save() and context.restore() are your friends and will greatly simplify the math needed to view a portion of a large 'world`. If you use this approach, you can get the desired behavior just by specifying the portion of the world that is visible and the world-coordinates of everything you want to draw.
This is not the only way of doing things* but the transformation methods are meant for exactly this kind of problem. You can use them or you can reinvent them by manually keeping track of where your background should be drawn, etc., etc.
Here's an example of how to use them, adapted from a project of mine:
function(outer, inner, ctx, drawFunction) {
//Save state so we can return to a clean transform matrix.
ctx.save();
//Clip so that we cannot draw outside of rectangle defined by `outer`
ctx.beginPath();
ctx.moveTo(outer.left, outer.top);
ctx.lineTo(outer.right, outer.top);
ctx.lineTo(outer.right, outer.bottom);
ctx.lineTo(outer.left, outer.bottom);
ctx.closePath();
//draw a border before clipping so we can see our viewport
ctx.stroke();
ctx.clip();
//transform the canvas so that the rectangle defined by `inner` fills the
//rectangle defined by `outer`.
var ratioWidth = (outer.right - outer.left) / (inner.right - inner.left);
var ratioHeight = (outer.bottom - outer.top) / (inner.bottom - inner.top);
ctx.translate(outer.left, outer.top);
ctx.scale(ratioWidth, ratioHeight);
ctx.translate(-inner.left, -inner.top);
//here I assume that your drawing code is a function that takes the context
//and draws your world into it. For performance reasons, you should
//probably pass `inner` as an argument too; if your draw function knows what
//portion of the world it is drawing, it can ignore things outside of that
//region.
drawFunction(ctx);
//go back to the previous canvas state.
ctx.restore();
};
If you are clever, you can use this to create multiple viewports, picture-in-pictures, etc. of different sizes and zoom in and out on stuff.
Performance
Second, as I commented in the code, you should make sure your drawing code knows what portion of your larger 'world' will be visible so that you don't do a lot of work trying to draw things that will not be visible.
The canvas transformation methods are meant for solving exactly this kind of problem. Use 'em!
*You will likely have problems if your world is so large that its coordinates cannot fit in an appropriate integer. You'll hit that problem roughly when your world exceeds billion (10^9) or a long trillion (10^18) pixels in any dimension, depending on whether the integers are 32- or 64-bit. If your world isn't measured in pixels but in 'world units', you'll run into problems when your world's total size and smallest feature scale lead to floating point inaccuracies. In that case, you will need to do extra work to keep track of things... but you'll probably still want to use the canvas transformation methods!
My very first game was a racing game where I moved the background instead of the car and although I want to think now that I had my reasons to make it so... I just didn't know better.
There are a few techniques that you need to know to achieve this well.
Tiled background. You need to make your track out of smaller pieces that tiled. To To draw 10,000 x 10,000 pixels is 100MPix image usually such image will have 32bit depth (4 bytes) this will end up being 400MB in memory. Compressions like PNG, JPEG won't help you since these are made to store and transfer images. They cant be rendered to a canvas without decompressing.
Move the car along your track. There is nothing worst then moving the BG under the car. If you need to add more features to your game like AI cars... now they will have to move along the map and to implement car collisions you need to make some not hard but strange spacial transformations.
Add camera entity. The camera needs to have position and viewport size (this is the size of your canvas). The camera will make or break your game. This is the entity that will give you the sense of speed in the game... You can have a camera shake for collisions, if you have drifts if your game the camera can slide pass the desired position and center back to the car, etc. Of course the most important thing will be tracking the car. Some simple suggestions I can give you are to not put the car in dead center of the camera. put the car a little behind so you can see a bit more what's in front of your. The faster the car moves the more you should offset the camera. Also you can't just compute the position of the camera instead compute desired position and slowly per frame move the current camera position to the desired position.
Now when you have camera and a large tiled map, when you draw the tiles you have to subtrack the camera position. You can also compute which tiles are not visible and skip them. This technique will allow you do extend your game with even larger maps or you can stream your map where you don't have all the tiles loaded and load in advance on background (AJAX) what will be visible soon.
Related
I would like draw 3D points represented in image to 3D rectangle. Any idea how could I represent these in x,y and z axis
Here projection type is orthographic.
Thanks
Okay. Let's look at a simple example of what you are trying to accomplish it, and why this is such a complicated problem.
First, lets look a some projection functions. You need a way to mathematically describe how to transform a 3D (or higher dimensional) point into a 2D space (your monitor), or a projection.
The simpiest to understand is a very simple dimetric projection. Something like:
x' = x + z/2;
y' = y + z/4;
What does this mean? Well, x' is you x coordinate 2D projection: for every unit you move backwards in space, the projection will move that point half that many units to the right. And y' represents that same projection for your y coordinate: for every unit you move backwards in space, the projection will move that point a quarter unit up.
So a point at [0,0,0] will get projected to a 2d point of [0,0]. A point at [0,0,4] will get projected to a 2d point of [2,1].
Implemented in JavaScript, it would look something like this:
// Dimetric projection functions
var dimetricTx = function(x,y,z) { return x + z/2; };
var dimetricTy = function(x,y,z) { return y + z/4; };
Once you have these projection functions -- or ways to translate from 3D space into 2D space -- you can use them to start draw your image. A simple example of that using js canvas. First, some context stuff:
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
Now, lets make a little helper to draw a 3D point:
var drawPoint = (function(ctx,tx,ty, size) {
return function(p) {
size = size || 3;
// Draw "point"
ctx.save();
ctx.fillStyle="#f00";
ctx.translate(tx.apply(undefined, p), ty.apply(undefined,p));
ctx.beginPath();
ctx.arc(0,0,size,0,Math.PI*2);
ctx.fill();
ctx.restore();
};
})(ctx,dimetricTx,dimetricTy);
This is pretty simple function, we are injecting the canvas context as ctx, as well as our tx and ty functions, which in this case our the dimetric functions we saw earlier.
And now a polygon drawer:
var drawPoly = (function(ctx,tx,ty) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
// Begin the path
ctx.beginPath();
// Move to the first point
var p = args.pop();
if(p) {
ctx.moveTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
// Draw to the next point
while((p = args.pop()) !== undefined) {
ctx.lineTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
ctx.closePath();
ctx.stroke();
};
})(ctx, dimetricTx, dimetricTy);
With those two functions, you could effectively draw the kind of graph you are looking for. For example:
// The array of points
var points = [
// [x,y,z]
[20,30,40],
[100,70,110],
[30,30,75]
];
(function(width, height, depth, points) {
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
// Set some context
ctx.save();
ctx.scale(1,-1);
ctx.translate(0,-c.height);
ctx.save();
// Move our graph
ctx.translate(100,20);
// Draw the "container"
ctx.strokeStyle="#999";
drawPoly([0,0,depth],[0,height,depth],[width,height,depth],[width,0,depth]);
drawPoly([0,0,0],[0,0,depth],[0,height,depth],[0,height,0]);
drawPoly([width,0,0],[width,0,depth],[width,height,depth],[width,height,0]);
drawPoly([0,0,0],[0,height,0],[width,height,0],[width,0,0]);
ctx.stroke();
// Draw the points
for(var i=0;i<points.length;i++) {
drawPoint(points[i]);
}
})(150,100,150,points);
However, you should now be able to start to see some of the complexity of your actual question emerge. Namely, you asked about rotation, in this example we are using an extremely simple projection (our dimetric projection) which doesn't take much other than an oversimplified relationship between depth and its influences on x,y position. As the projections become more complex, you need to know more about your relationship/orientation in 3D space in order to create a reasonable 2D projection.
A working example of the above code can be found here. The example also includes isometric projection functions that can be swapped out for the dimetric ones to see how that changes the way the graph looks. It also does some different visualization stuff that I didn't include here, like drawing "shadows" to help "visualize" the actual orientation -- the limitations of 3D to 2D projections.
It's complicated, and even a superficial discussion is kind of beyond the scope of this stackoverflow. I recommend you read more into the mathematics behind 3D, there are plenty of resources, both online and in print form. Once you have a more solid understanding of the basics of how the math works then return here if you have a specific implementation question about it.
What you want to do is impossible to do using the method you've stated - this is because a box - when rotated in 3 dimensions won't look anything like that diagram of yours. It will also vary based on the type of projection you need. You can, however get started using three.js which is a 3D drawing library for Javascript.
Hope this helps.
How to Draw 3D Rectangle?
posted in: Parallelogram | updated on: 14 Sep, 2012
To sketch 3 - Dimensional Rectangle means we are dealing with the figures which are different from 2 – D figures, which would need 3 axes to represent them. So, how to draw 3D rectangle?
To start with, first make two lines, one vertical and another horizontal in the middle of the paper such that they represent a “t” letter of English. This is what we need to draw for temporary use and will be removed later after the construction of the 3 – D rectangle is complete. Next we draw a Square whose measure of each side is 1 inch. Square must be perfect in Geometry so that 90 degree angles that are formed at respective corners are exact in measure. Now starting from upper right corner of the square we draw a line segment that will be stretched to a measure of 2 inches in the direction at an angle of 45 degrees. Similarly, we repeat the procedure by drawing another Line Segment from the upper left corner of the square and stretching it to 2 inches length in the direction at an angle of 45 degrees. These 2 line segments are considered to be the diagonals with respect to the horizontal line that we drew temporarily in starting. Also these lines will be parallel to each other. Next we draw a line that joins the end Point of these two diagonals.
Next starting from the very right of the 2 inch diagonal end point, draw a line of measure 1 inch that is supposed to be perpendicular to the temporary horizontal line. Next we need to join the lower left corner of the square with end point of the last 1’’ line we drew in 4th step and finally we get our 3 - D rectangular. Now we can erase our initial “t”. This 3- D rectangle resembles a Cuboid.
EDIT: I dug into the extremely well-documented source code in Decker's link (vector movement demo) and I'm fairly confident I can figure this out working off some of the code there. Thank you all for your help :D
I'm working on movement for a game in javascript. Left and right arrow keys rotate an image of a spaceship while up arrow causes it to accelerate. Using the degree of rotation and the speed, I can calculate movement in terms of x and y with Math.sin() and Math.cos(), but this means that the ship handles like a car. Seeing as it's supposed to be in space, I'd like to make the rotation of the ship only affect its path while accelerating and to take into account the ship's current movement.
I messed around with it a lot and tried dividing the movement into two separate forces, the current direction and speed and the desired direction, but nothing seems even close to how it should feel.
Sorry if that was confusing, here's the simplified code for the original movement:
function main()
{
if(keyStates[39]) // Right arrow pressed?
ship.deg+=8;
if(keyStates[37]) // Left arrow pressed?
ship.deg-=8;
if(keyStates[38]) // Up arrow pressed?
{
if(ship.speed<16)
ship.speed+=1;
}
var shift=getXYshift(ship.deg,ship.speed);
function getXYshift(deg,speed)
{
return {x:Math.round(Math.cos((90-deg)*Math.PI/180)*speed*-1), y:Math.round(Math.sin((90-deg)*Math.PI/180)*speed)};
}
setTimeout(function(){ main() }, 50);
}
You can use one Vector to keep track of the ships speed and direction and alter the direction of that vector when the up arrow is pressed by checking the angle of a second Vector used to keep track of the ships current angle.
I recommend getting this book Supercharged Javascript Graphics which explains in detail the use of vectors and much more.
You can also view the source code for one of the books examples here at the authors website which has a vector handling object that could prove useful to you.
Based on my low physical knowledge:
The ship has a speed with a direction. This can be expressed as a vector from your space, like x pixels on the X-axis, y pixels on the Y-axis (and maybe more dimensions) per second.
Then it has a rotation speed, like α degrees counterclockwise per second.
To compute the travel of your ship for a second, just add the speed vector to the coordinates. And add the rotation to the current orientation.
To change the speed vector based on rotation and acceleration, you would build a vector with a length relating to the acceleration, in the direction of the current orientation. Then add the acceleration vector to the speed vector.
Pseudo code:
ship = {
coordinates: [0, 0], // space units
orientation: 0, // radiant
speed: [0, 0], // space units / time frame
rotation: 0 // radiant / time fram
}
function animatestep {
coordinates[0] += speed[0];
coordinates[1] += speed[1];
orientation += rotation;
}
onaccelerate = function {
speed[0] += cos(orientation) * acceleration;
speed[1] += sin(orientation) * acceleration;
}
onleft = function {
rotation++;
}
onright = function {
rotation--;
}
Note that this makes the space ship really behave like a space ship, because rotation might be difficult to stop. Instead of using a rotation speed, you might need to allow to set the orientation of the ship step-by-step :-) You might also set limits on rotation and acceleration (otherwise the ship bursts) and use a maximum velocity (like the speed of light, including different speed addition).
You should be using a mathematical concept known as a "vector" for your movement. A vector is simply a force and a direction. This vector will be applied to the X,Y coordinate of your ship (ignoring its direction) every frame when determining where to draw the ship. When you accelerate you will use the direction the ship is facing and a constant value assigned to acceleration to form a vector that can be applied to your movement vector for calculating its effect on velocity.
Here is a quick introduction to vectors: http://www.khanacademy.org/science/physics/v/introduction-to-vectors-and-scalars , after watching the video you should have a good idea about what need to be looking for. From there Google should be your friend.
EDIT: Above when I said: "you will use the direction the ship is facing and a constant value assigned to acceleration to form a vector that can be applied to your movement vector for calculating its effect on velocity" I was referring to vector algebra. If you decide to use vectors to solve your problem, you will need to use the concept of vector addition to accelerate. When you press the arrow key, you will generate a vector of magnitude m (where m can be any real number indicating how fast you want to accelerate) and a direction d (more than likely this value will correspond with the direction the ship is facing). You will then add this new vector to the ships current vector to get the ships new vector after the acceleration for the current frame is applied. You can read more here: http://emweb.unl.edu/Math/mathweb/vectors/vectors.html
Cheers and happy Coding
Do you use getXYshift after a right/left arrow press? You should only use it when the up arrow is pressed. This way your ship will rotate without accelerating in any direction. Only change your velocity when the up arrow key is pressed and decelerate when it isn't. Don't change the velocity with the right/left keys, use them to change the rotation of your ship.
It seems certain tiles will not get drawn. I have a tileset split-up into 32x32 squares and uses a 2D 100x100 array to draw the map onto the canvas.
Then it sets the "viewport" for the player. Since it's one big map, the player is always centered on the edge, unless they run near the edge.
However, this has caused problems drawing the map. Red block is "player"
Somethings I found out was that, a higher viewport (15x10) will give the ability to draw SOME previously not-drawn tiles.
Here's the code. You can download the tileset to test on localhost or below on jsFiddle http://mystikrpg.com/images/all_tiles.png
Everything below is well commented.
Even if change viewport I do see some tiles get drawn, not all.
http://pastebin.com/cBTum1aQ
Here is jsFiddle: http://jsfiddle.net/weHXU/
Working Demo
Basically I took a different approach to drawing the tiles. Using putImageData and getImageData can cause performance issues, also by pre-allocating all the image data in the beginning you are incurring a memory penalty to start out with. You already have the data in the form of the image you might as well just reference it directly instead, and it should actually be faster.
Heres the method I use
for (y = 0; y <= vHeight; y++) {
for (x = 0; x <= vWidth; x++) {
theX = x * 32;
theY = y * 32;
var tile = (board[y+vY][x+vX]-1),
tileY = Math.floor(tile/tilesX),
tileX = Math.floor(tile%tilesX);
context.drawImage(imageObj, tileX*tileWidth, tileY*tileHeight, tileWidth, tileHeight, theX, theY, tileWidth, tileHeight);
}
}
Its almost the same, but instead of looking at an array of the pre saved data, I just reference the area of the already loaded image.
Explanation on getting the referenced tile
Say I have a grid thats 4x4, and I need to get tile number 7, to get the y I would do 7/4, then to get the x I would use the remainder of 7/4 (7 mod 4).
As for the original issue.. I really have no idea what was causing the missing tiles, I just changed it to my method so I could test from there but it worked right away for me.
Friends, i'm finding rotating a text canvas object a bit tricky. The thing is, I'm drawing a graphic, but sometimes the width of each bar is smaller than the 'value' of that bar. So I have to ratate the 'value' 90 degrees. It will work in most cases.
I am doing the following
a function(x, y, text, maxWidth...)
var context = this.element.getContext('2d');
var metric = context.measureText(text); //metric will receive the measures of the text
if(maxWidth != null){
if(metric.width > maxWidth) context.rotate(Math.PI / 2);
}
context.fillText(text, x, y);
Ok, but it doesn't really work. Problems that I have seen: The text duplicates in different angles. The angles are not what I want (perhaps just a matter of trigonometry).
Well I just don't know what to do. I read something about methods like 'save' and 'restore' but I don't what to do with them. I've made some attempts but no one worked.
Would you help me with this, guys?
This is a bit tricky to answer simply because there are a lot of concepts going on, so I've made you an example of what I think you'd like to do here:
http://jsfiddle.net/5UKE3/
The main part of it is this. I've put in a lot of comments to explain whats going on:
function drawSomeText(x, y, text, maxWidth) {
//metric will receive the measures of the text
var metric = ctx.measureText(text);
console.log(metric.width);
ctx.save(); // this will "save" the normal canvas to return to
if(maxWidth != null && metric.width > maxWidth) {
// These two methods will change EVERYTHING
// drawn on the canvas from this point forward
// Since we only want them to apply to this one fillText,
// we use save and restore before and after
// We want to find the center of the text (or whatever point you want) and rotate about it
var tx = x + (metric.width/2);
var ty = y + 5;
// Translate to near the center to rotate about the center
ctx.translate(tx,ty);
// Then rotate...
ctx.rotate(Math.PI / 2);
// Then translate back to draw in the right place!
ctx.translate(-tx,-ty);
}
ctx.fillText(text, x, y);
ctx.restore(); // This will un-translate and un-rotate the canvas
}
To rotate around the right spot you have to translate to that spot, then rotate, then translate back.
Once you rotate the canvas the context is rotated forever, so in order to stop all your new drawing operations from rotating when you dont want them to, you have to use save and restore to "remember" the normal, unrotated context.
If anything else doesn't make sense let me know. Have a good time making canvas apps!
I want to check a collision between two Sprites in HTML5 canvas. So for the sake of the discussion, let's assume that both sprites are IMG objects and a collision means that the alpha channel is not 0. Now both of these sprites can have a rotation around the object's center but no other transformation in case this makes this any easier.
Now the obvious solution I came up with would be this:
calculate the transformation matrix for both
figure out a rough estimation of the area where the code should test (like offset of both + calculated extra space for the rotation)
for all the pixels in the intersecting rectangle, transform the coordinate and test the image at the calculated position (rounded to nearest neighbor) for the alpha channel. Then abort on first hit.
The problem I see with that is that a) there are no matrix classes in JavaScript which means I have to do that in JavaScript which could be quite slow, I have to test for collisions every frame which makes this pretty expensive. Furthermore I have to replicate something I already have to do on drawing (or what canvas does for me, setting up the matrices).
I wonder if I'm missing anything here and if there is an easier solution for collision detection.
I'm not a javascript coder but I'd imagine the same optimisation tricks work just as well for Javascript as they do for C++.
Just rotate the corners of the sprite instead of every pixel. Effectively you would be doing something like software texture mapping. You could work out the x,y position of a given pixel using various gradient information. Look up software texture mapping for more info.
If you quadtree decomposed the sprite into "hit" and "non-hit" areas then you could effectively check to see if a given quad tree decomposition is all "non-hit", "all hit" or "possible hit" (ie contains hits and non-hit pixels. The first 2 are trivial to pass through. In the last case you then go down to the next decomposition level and repeat the test. This way you only check the pixels you need too and for large areas of "non-hit" and "hit" you don't have to do such a complex set of checks.
Anyway thats just a couple of thoughts.
I have to replicate something I already have to do on drawing
Well, you could make a new rendering context, plot one rotated white-background mask to it, set the compositing operation to lighter and plot the other rotated mask on top at the given offset.
Now if there's a non-white pixel left, there's a hit. You'd still have to getImageData and sift through the pixels to find that out. You might be able to reduce that workload a bit by scaling the resultant image downwards (relying on anti-aliasing to keep some pixels non-white), but I'm thinking it's probably still going to be quite slow.
I have to test for collisions every frame which makes this pretty expensive.
Yeah, I think realistically you're going to be using precalculated collision tables. If you've got space for it, you could store one hit/no hit bit for every combination of sprite a, sprite b, relative rotation, relative-x-normalised-to-rotation and relative-y-normalised-to-rotation. Depending on how many sprites you have and how many steps of rotation or movement, this could get rather large.
A compromise would be to store the pre-rotated masks of each sprite in a JavaScript array (of Number, giving you 32 bits/pixels of easily &&-able data, or as a character in a Sring, giving you 16 bits) and && each line of intersecting sprite masks together.
Or, give up on pixels and start looking at eg. paths.
Same problem, an alternative solution. First I use getImageData data to find a polygon that surrounds the sprite. Careful here because the implementation works with images with transparent background that have a single solid object. Like a ship. The next step is Ramer Douglas Peucker Algorithm to reduce the number of vertices in the polygon. I finally get a polygon of very few vertices easy and cheap to rotate and check collisions with the other polygons for each sprite.
http://jsfiddle.net/rnrlabs/9dxSg/
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var img = document.getElementById("img");
context.drawImage(img, 0,0);
var dat = context.getImageData(0,0,img.width, img.height);
// see jsfiddle
var startPixel = findStartPixel(dat, 0);
var path = followPath(startPixel, dat, 0);
// 4 is RDP epsilon
map1 = properRDP(path.map, 4, path.startpixel.x, path.startpixel.y);
// draw
context.beginPath();
context.moveTo(path.startpixel.x, path.startpixel.x);
for(var i = 0; i < map.length; i++) {
var p = map[i];
context.lineTo(p.x, p.y);
}
context.strokeStyle = 'red';
context.closePath();
context.stroke();