I want to use an image like this on canvas:
The user will "paint and fill" the image, but not on top of the outline.
The problem is:
If I put behind the canvas, the paint will cover the outline.
If I put over the canvas the image block canvas interaction.
Can you help me guys?
Use compositing mode "destination-over" to draw behind existing content (from image, vectors etc.). It's necessary that the existing content provide an alpha channel or composition won't work. If there is no alpha-channel you can convert inverse luma / matte (the white) to alpha channel.
// a quick-n-dirty demo
var ctx = c.getContext("2d");
ctx.lineWidth = 10;
ctx.moveTo(100, 0); ctx.lineTo(150, 150); ctx.stroke();
ctx.fillStyle = "#09f";
// KEY: composite mode -
ctx.globalCompositeOperation = "destination-over";
// draw behind the line
c.onmousemove = function(e) {
ctx.fillRect(e.clientX - 10, e.clientY - 10, 20, 20);
};
body {margin:0}
canvas {border:#777 solid 1px}
<canvas id="c"></canvas>
Here is the example of drawImage function. You can draw any preloaded image onto canvas. You can also try to place the <img> overlay in front of the canvas and disable mouse events for it using pointer-events: none CSS property.
Related
I'm trying to place text on sqlare rotated 45 degrees. The problem is my text is under the rectangle shape. Can I change position of text?
my code is like
var c = document.getElementById("myCanvas");
var square= c.getContext("2d");
var text= c.getContext("2d");
text.fillStyle = "red";
text.fillText("1", 40, 50);
text.fillStyle = "#000000";
square.rotate(Math.PI / 4);
square.fillRect(50, 0, 50, 50);
jsfiddle
You're drawing the text first, then the rectangle, and then wondering why the text is behind the rectangle?
Firstly, you only need to getContext once, not twice.
Second, draw things in the right order: background first, then foreground.
It appears you may have a misconception about how the canvas context works.
You see, you only need one instance of the context, which you can then use to create all your shapes, paths and even write text on the canvas.
Also, you are drawing the text before the rectangle, which would cover it up.
With that in mind, I've created a new JSFiddle where you can check out a correct approach to do this.
HTML
<canvas id="myCanvas" width="300" height="150">
Your browser does not support the HTML5 canvas tag.
</canvas>
JavaScript
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //we get the canvas context
ctx.save(); //save context properties
ctx.rotate(Math.PI / 4);
ctx.fillRect(50, 0, 50, 50);
ctx.restore(); //restore saved properties
ctx.fillStyle = "red";
ctx.fillText("1", 40, 50);
As you can see, we only take one instance of the context, and we draw from there.
The context save() and restore() functions help prevent the rotation from affecting the text. You could also rotate the same amount in the opposite direction.
Hope it helps!
I am trying to make a 2d top-down game in Javascript at the moment. I've currently got a day/night system working where a black rectangle gradually becomes more opaque (as the day goes on) before it finally is fully opaque, simulating the peak of the night where the player can not see.
I want to implement an artificial light system, where the player could use a torch that will illuminate a small area in-front of them. However, my problem is that I don't seem to be able to find a way to 'cut out' a shape from my opaque rectangle. By cutting out a shape, it would look like the player has a torch.
Please find an example mock-up image I made below to show what I mean.
http://i.imgur.com/VqnTwoR.png
Obviously the shape shouldn't be as roughly drawn as that :)
Thanks for your time,
Cam
EDIT: The code used to draw the rectangle is as follows:
context.fillStyle = "#000033";
context.globalAlpha = checkLight(gameData.worldData.time);
context.fillRect(0, 0, 512, 480);
//This is where you have to add the cut out triangles for light!
context.stroke();
Instead of drawing a rectangle over the scene to darken it when the "light" is on, instead draw an image with the "lit" area completely transparent and the rest of the "dark" area more opaque.
One way is to use declare a triangular clipping area and draw your revealed scene. The scene would display only inside the defined clipping area.
Example code and a Demo:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var offset = 50;
var img = new Image();
img.onload = function() {
knockoutAndRefill(50,100,300,50,75,350);
};
img.src = 'http://guideimg.alibaba.com/images/trip/1/03/18/7/landscape-arch_68367.jpg';
function knockoutAndRefill(x0,y0,x1,y1,x2,y2){
context.save();
context.fillStyle='black';
context.fillRect(0,0,canvas.width,canvas.height);
context.beginPath();
context.moveTo(x0,y0);
context.lineTo(x1,y1);
context.lineTo(x2,y2);
context.closePath();
context.clip();
context.drawImage(img,0,0);
context.restore();
}
<canvas id=myCanvas width=500 height=400>
I'm just started working with Leap Motion (it is so much fun). The Leap works mainly with vectors. And now I want to create a program where I can visualise where is a vector pointing. The only way I can imagine doing this is by using a small image which appears when this fuction is on and positioning by using the img.style.left , img.style.top instructions. Any other ideas?
If your goal is to represent 2D Vectors,
You can use canvas to draw lines.
A canvas is like a div but you can draw whatever you want in it, I don't know anything about Leap Motion but if you want to draw lines and circles at precise coordinates, it may be a good solution instead of working with the DOM itself.
The JS part looks like this :
var canvas = document.getElementById('my-canvas');
var ctx = canvas.getContext('2d');
//For exemple here is how to draw a rectangle
//fillStyle support all valid css color
ctx.fillStyle = "rgba(50, 255, 24, 0.7)";
//Create the rectangle, with (startX, startY, height, width)
ctx.fillRect(20, 15, 50, 50);
ctx.beginPath(); //Tells canvas we want to draw
ctx.moveTo(250,250); //Moves the cursor to the coordinates (250, 250);
ctx.lineTo(75, 84); //Draws a line from the cursor (250, 250) to (75, 84);
ctx.closePath(); //Tells canvas to 'close' the drawing
ctx.strokeStyle = "red";
ctx.stroke(); //Draws the line stroke
And the HTML is simply :
<canvas id="my-canvas" height="500px" width="500px">
Here is the text displayed when the browser doesnt support canvas.
</canvas>
I made a jsfiddle to show you what simple things we can do with canvas.
http://jsfiddle.net/pq8g0bf0/1/
A nice website to learn canvas : http://www.html5canvastutorials.com/tutorials/html5-canvas-element/
Since it's javascript, you are free to do calculations for your vectors coordinates, addding eventListeners etc ...
Is it possible to give a glow effect to an image automatically, say using canvas?
jsfiddle
The canvas tag would have to omit the transparent
and make it have an outter glow?
<canvas id="canvas" width=960 height=960></canvas>
Make a canvas path glow by applying a series of overlapping shadows with increasing blur
A Demo: http://jsfiddle.net/m1erickson/Z3Lx2/
You can change the styling of the glow by varying the number of overlays and the blur size.
Example code for a glow effect:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// glow
var glowColor="blue";
ctx.save();
ctx.strokeStyle = glowColor;
ctx.shadowColor = glowColor;
ctx.shadowOffsetX=300;
for (var i = 0; i < 10; i++) {
ctx.shadowBlur = i * 2;
ctx.strokeRect(-270, 30, 75, 150);
}
ctx.restore();
To get the outline path of your phone image, you can use the "marching ants" algorithm.
This algorithm will create a path that outlines an image.
In your case you would define the image as all pixels that are not transparent.
Here's a very good implementation of "marching ants" that is used in the excellent d3 library:
https://github.com/d3/d3-plugins/blob/master/geom/contour/contour.js
It's used like this:
DrawImage your phone on the canvas.
// draw the image
// (this time to grab the image's pixel data
ctx.drawImage(img,0,0);
Get the pixel color array from the canvas using ctx.getImageData
// grab the image's pixel data
imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
data=imgData.data;
Define a function that checks the pixel array for non-transparent pixels at any x,y on the canvas.
// This is used by the marching ants algorithm
// to determine the outline of the non-transparent
// pixels on the image
var defineNonTransparent=function(x,y){
var a=data[(y*cw+x)*4+3];
return(a>20);
}
Call the contour function:
// call the marching ants algorithm
// to get the outline path of the image
// (outline=outside path of transparent pixels
var points=geom.contour(defineNonTransparent);
Here's an example result:
the glow is automatically generated using overlapping shadows
the outline path of the phone is calculated using the marching ants algorithm
i want to set transparency for part of canvas
can I use globalAlpha like for all canvas except rectangle i create in the canvas ?
If you mean how to make a rectangle transparent after you have a bunch of things drawn to the canvas you can do the following:
/// clear a rectangle to make canvas transparent
ctx.globalCompositeOperation = 'destination-out';
/// set alpha using a fill color with transparency
ctx.fillStyle = 'rgba(0,0,0,0.5)';
/// fill rectangle which now will become partly transparent all the way
ctx.fillRect(40, 40, 320, 320);
/// reset composite mode
ctx.globalCompositeOperation = 'source-over';
Live demo here
If this is not what you mean then you need to plan your drawings. As mentioned elsewhere you can set globalAlpha before you draw something, draw it, then set globalAlpha back before you draw the next. Each draw after setting globalAlpha will be drawn with that alpha value (if the fill-style, stroke-style of image alpha uses transparency as well that will be a result of the two alpha values as they are multiplied).
globalCompositeOperation decides how it will be drawn, for example on top of existing content, instead of and so forth (see an overview here).
As I've said in the comments twice, you just have to set the global alpha to what you want, draw what you want with that alpha, then change the global alpha to a new value, then draw what you want in that alpha. That can be done as follows
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(255, 0, 0,1)';
ctx.fillRect(0, 0, 150, 50);
ctx.globalAlpha = 0.2;
ctx.fillRect(150,50,150,50);
Demo