Attempting to replace shapes with images - javascript

I am very new to js as a whole, and have decided that a good way to get to know and javascript as a whole would be to follow a tutorial for building a simple block-breaking game.
The game itself runs just fine, however, I would like to find a way to replace the js-drawn circle with an image of a ball, and the blocks with any other rectangular images.
I know (I think) that I need to implement var img = new Image()
in some way, but I'm not entirely sure how to go about doing this without managing to make my circle disappear altogether.
I believe the offending area of my code may be this part:
function drawBall(){
ctx.beginPath();
ctx.arc(x, y, ballSize, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
However, given that I am new, I may have completely missed it , and so I also provide a codepen of the project thus far. Codepen

The code that draws the circle is the following:
ctx.arc(x, y, ballSize, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
So instead of drawing a circle (which is done with the .arc), you can draw an image instead using the .drawImage method. See docs. It would look something like this:
ctx.drawImage(image, x, y);
The image argument is an "image source", which could be just a plain <img> element in your HTML. See examples of how to its done in the docs that I linked.

Related

Javascript canvas gap after fill of shapes with common border

I would like to understand & learn a solution for the issue I am experiencing when I am filling two shapes/paths with a shared border, i.e. after the fill is called for all the shapes there is still a tiny gap present between them.
The snippet presents the code doing the drawing of the involved shapes/paths:
ctx.beginPath();
ctx.moveTo(pBottom.x, pBottom.y);
ctx.lineTo(0, 0);
ctx.lineTo(pTop.x, pTop.y);
ctx.lineTo(pTopFront.x, pTopFront.y);
ctx.lineTo(pBottomFront.x, pBottomFront.y);
ctx.fillStyle = gradientTopSide;
ctx.fill();
ctx.fillStyle = gradientBottomSide;
ctx.fill();
ctx.beginPath();
ctx.moveTo(pBottom.x, pBottom.y);
ctx.arc(0, 0, radiusBackArc, (angleBottomBack) * Math.PI / 180, (angleTopBack) * Math.PI / 180);
ctx.lineTo(0, 0);
ctx.fillStyle = gradientBackArc;
ctx.fill();
The gaps are visible to the left (by the blue circle), to the top of it and to the bottom. They are where the fills of radial and linear gradients meet.
I wanted play a bit with canvas to create a simple light/torch effect and these lines are ruining my fun. Certainly cause I do not know how to fill them in a nice way without ruining the gradient effect.
Please find the JSFiddle presenting the issue.
When you deal with gradients involving transparency you'll run into overlaps where alpha channel values will multiply as well as sub-pixeling, and rounding errors for the points and possibly also for gradient calculations.
Chances are that the calculations you do in the code has to be rounded off properly. If they aren't you will have canvas do sub-pixeling of those pixels and it's hard to maintain a concise result, in particular when alpha is involved. It's the quirks of canvas and this way of drawing gradient lines. Canvas does not properly "bend" (join) in the corners either so you get overlapping drawings - not much we can do about that part.
I see two ways to solve this is a simple manner:
Use an image which you draw in instead of building a shape - this is fast and the result just as good unless you need different sizes (if animated, that doesn't matter so much though). I would personally go with this option (and you'll get more artistic freedom as well).
Draw the shape with a different technique:
I'll demonstrate the latter here, and as a bonus you can drop a lot of code. If you need transparency than you should go with option 1. Also, it ain't perfect either as we still have to rely on canvas' way of doing this, but it could be perhaps an improved replacement when it comes to the overlapping issues:
Use a single closed path of the shape
Modify current shape by removing the last lineTo() and replace it with closePath()
Important: change lineJoin to round
We create a loop where we draw the shape overlapping, a and for each iteration:
Change solid color based on iteration
Scale slightly
Move slightly
I made a simple version of this here but I'll leave it to you to figure out the more satisfying details of values if you choose to use it.
var d2r = Math.PI / 180, i = 0, iterations = 14;
ctx.lineJoin = "round";
ctx.lineWidth = 3;
for(; i < iterations; i++) {
ctx.beginPath();
ctx.moveTo(pBottom.x, pBottom.y);
ctx.arc(0, 0, radiusBackArc, angleBottomBack * d2r, angleTopBack * d2r);
ctx.lineTo(pTopFront.x, pTopFront.y);
ctx.arc(0, 0, radiusFrontArc, angleTopFront * d2r, angleBottomFront * d2r);
// don't set endpoint=startpoint, instead just close the shape
ctx.closePath();
// using HSL will allow us to easily set a gradient ligthness:
ctx.strokeStyle = "hsl(0, 0%, " + (i/iterations*100) + "%)";
ctx.stroke();
ctx.translate(i*0.1,-i*0.02);
ctx.scale(0.99, 0.98);
}
Modified fiddle here

Draw a Play button on canvas in javascript - triangle in a circle

So I'm creating a simple userscript for me - I want to draw a play button over shaded version of any GIF image on the site to have them only played when I want to.
I have inspired myself here. To make the whole thing nice, I'm drawing a green circle over the animation. This is my intended effect (I really wonder if once can make some shapes in GIMP):
And this is what I currently have:
The Cleese ironic face animation comes from this GIF portal
I made a fiddle of my current GIF pauser userscript.
The critical code for printing the circle:
//Assume these variables
var ctx = canvas context (2d)
var w = canvas width
var h = canvas height
//The code:
ctx.beginPath();
//I'm making sure the circle will always fit - therefore Math.min
ctx.arc(w/2, h/2, Math.min(60, w/2-20, h/2-20), 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(0,180,0,0.5)';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
I hope it's clear that the triangle must always fit into the circle (size of which may vary). It must have the vertical line a little bit shorter then the other two, which must be of equal length.
I'm totally not interested in any existing GIF pausing libraries. Keep in mind that the question is about the triangle, not the GIFs.
Like this? http://jsfiddle.net/32ECU/
//Draw a triangle in it
ctx.strokeStyle = 'white';
ctx.beginPath();
ctx.moveTo(w/3, h/3);
ctx.lineTo(w/3, h-h/3);
ctx.lineTo(w-w/4, h/2);
ctx.lineTo(w/3, h/3);
ctx.fillStyle = 'white';
ctx.fill();

Drawing a circle inside another circle canvas

I am trying to draw a gear in Canvas but running into issues from the start. I want to have a filled circle with a hallowed out middle. Instead, I am getting what looks to be an outline of a single circle.
Here is my code:
var ctx = document.getElementById("canvas").getContext("2d"),
i = 0;
function drawGear(){
ctx.fillStyle = "#000";
ctx.translate(50,50);
ctx.arc(0,0,20,0,Math.PI*2);
ctx.fill();
ctx.fillStyle = "#FFF";;
ctx.arc(0,0,5,0,Math.PI*2);
ctx.fill();
}
drawGear();
http://jsfiddle.net/te3jn/
I believe that the issue is something related to the globalCompositeOperation, but I tried several of them (source-over, source-atop, destination-over) and none seem to work the way I want.
You should begin a new path when drawing the second circle, like this:
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
// ...
JS Fiddle.
Without this, you'll essentially redraw both circles - the inner and the outer one - with the second fill call (check this fiddle for demonstration)

Image not showing up on canvas element

So, I've been trying to make a scrolling shooter example with my game engine and I've come across something odd. A certain image I try to draw doesn't show up. It shows up in Chrome's resources, so it's not a path issue. Also all other images I try to display show up as well. If anyone can help me, it would be appreciated. =)
Link for reference:
http://pandamochi.x10.bz/scrollingshooter.html
Code for Drawing:
ctx.save();
if (this.sprite != ""){
ctx.translate(Math.round(this.x-ds_view.x), Math.round(this.y-ds_view.y));
ctx.scale(this.scaleX,this.scaleY);
ctx.rotate(this.rotateZ);
ctx.translate(-this.width/2,-this.height/2);
ctx.drawImage(this.sprite, this.width*this.sprite_index, 0, this.width, this.height, 0, 0, this.width, this.height);
}
ctx.restore();
Code I used to Set:
enemy.setSprite("images/ship.png",1,4,10);
Edit
So yeah I was way off.
ctx.drawImage(this.sprite, this.width*this.sprite_index, 0, this.width, this.height);
The translations are causing your issue. I changed the line above and can actually see the ship drawing. This isn't the most complete answer, but hopefully it gets you on the right track.
Live Demo

Mask an image using image map or canvas?

Okay, my issue is better explained visually:
I need to make those 5 images easily replaceable without the client having to manually cut angles out of images, etc. So I'm picturing it this way:
I created PNG masks for the blue bar and blue space above them. But the images still overlap at the bottom because they are all square (see last image for an example). Is there any way, using an image map (or even javascript) to cut/mask pieces out of a square image on page load?
Thanks,
Chris
I think your best option would be to use canvas unless I'm forgetting something with css3
<canvas id="image1" width="___" height="____">
</canvas>
var people = [___];
var canvas = document.getElementById("image1");
var context = canvas.getContext("2d");
context.drawImage(people[0], x, y, width, height);
context.beginPath();
context.moveTo(x, y);
context.lineTo(x1, y1);
context.lineTo(x2, y1);
context.arcTo(x, y);
context.clip();
context.closePath();
I may have messed up but I'm going for something like this
(x, y)\__
/ \__
/ \__
(x2, y1)(_________________\(x1, y1)
Which is my best way of drawing the leftmost pizza slice with ascii
Doing this will require multiple canvas elements. where each one represents one slice. The reason is because clipping will erase everything but what's in the path.
Resources:
MDN:clipping

Categories