I have a image of a circle (png) and I'd like to use clip to mask a portion of it. Is there such a type of radial clip? (Say I wanted to convert the circle to a pie chart e.g 32% only) with the clip mask
Edit: Perhaps tips on a SVG overlay would be nice if this isnt possible?
Using canvas (and a very small bit of jquery to get node references):
var ctx = $( '#canvasTag' )[0].getContext( '2d' );
// draw your image
ctx.drawImage( $( '#imgTag' )[0], x, y );
// change composite operation so that only the image below the arc below shows
ctx.globalCompositeOperation = 'destination-in';
// draw part of a circle
ctx.beginPath();
ctx.arc( x, y, radius, startAngle, endAngle, false ); // draw outer arc
ctx.lineTo( x, y ); // draw to center
ctx.closePath();
ctx.fill();
Related
I want to have html5 canvas text slide in behind nothing, its an effect where text appears like coming out behind some obstacle, but the obstacle is invisible.
Here is some youtube video showing how to do it in after effect:
https://www.youtube.com/watch?v=KIYMy7vLLRo
I know how to slide a text along canvas, and one idea I got is having two canvases on top of each other, and top canvas is smaller and contains the text that is initially out of canvas and slides in. But if there is a way to do it with just one canvas that would be great.
You can using a clipping path to mask out part of the text.
Save the existing clipping path using the save() method. Create a shape/path and make it the new clipping path using the clip() method. Draw your text. Store the previous clipping path using the restore() method.
For example, suppose your canvas is 100 pixels by 100 pixels. The following will draw text on only the left side of the canvas.
context.save();
context.rect(0, 0, 50, 100);
context.clip();
context.fillText("Draw some text.", 30, 50);
context.restore();
jsFiddle : https://jsfiddle.net/CanvasCode/vgpov2yk/3
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
// Positions for the text startint off
var xText = -100;
var yText = 150;
// This will update the canvas as fast as possible (not good)
setInterval(function () {
// Clear the canvas
ctx.fillStyle = "#F0F";
ctx.fillRect(0, 0, c.width, c.height);
ctx.save()
// We create a clip rect
ctx.rect(200,0,400,400);
ctx.clip();
// Draw text
ctx.fillStyle = "#FFF";
ctx.font = "30px Arial";
ctx.fillText("Hello World", xText, yText);
ctx.restore();
// Increase the text x position
if (xText < 200) {
xText += 0.5;
}
}, 15);
All you have to do is use a clip rect which is like a mask in image editing.
I need a function in HTML5 that with given context, x1, y1, x2, y2 would draw me a circle (at beginning of this vector) with arrow that represents the vector itself, that would have gradient background. Left image is what I got - I am not pleased with the result... right image is visualisation of what I would like to make.
Could anybody help me with that please?
This is my arrow function (circle is obvious):
function arrow(context, fromx, fromy, tox, toy){
var headlen = 10;
var angle = Math.atan2(toy-fromy,tox-fromx);
context.moveTo(fromx, fromy);
context.lineTo(tox, toy);
context.lineTo(tox-headlen*Math.cos(angle-Math.PI/6),toy-headlen*Math.sin(angle-Math.PI/6));
context.moveTo(tox, toy);
context.lineTo(tox-headlen*Math.cos(angle+Math.PI/6),toy-headlen*Math.sin(angle+Math.PI/6));
}
Ok, I'll bite...
If your arrow function is working fine now, you can also draw a circle in that function.
This modified arrow() will draw both the circle and arrow in gray.
Since you want to change the context state ( change fill/stroke to gray ) you should wrap the path drawing commands in context.save and context.restore.
You should (must!) begin all atomic path drawings with context.beginPath. This prevents path drawings from being inadvertently repeated.
This refactoring of your arrow uses context transforms to set the rotation point at x1,y1 and then draws the circle and then draws the arrow to x2,y2.
A Demo: http://jsfiddle.net/m1erickson/87T8d/
Example arrow function:
function arrow(x1,y1,x2,y2){
var dx=x2-x1;
var dy=y2-y1;
var radians=Math.atan2(dy,dx);
var length=Math.sqrt(dx*dx+dy*dy);
// save the unrotated context state
ctx.save();
// set the rotation point as x1,y1
ctx.translate(x1,y1);
// rotate the canvas by the angle of the vector
ctx.rotate(radians);
// draw the circle
ctx.beginPath();
ctx.arc(0,0,8,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="gray"; // or gradient if you prefer
ctx.fill();
// draw the arrow
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(length,0);
ctx.lineTo(length-7,-4);
ctx.lineTo(length-7,4);
ctx.lineTo(length,0);
ctx.closePath();
ctx.fillStyle="gray";
ctx.fill();
ctx.strokeStyle="gray";
ctx.stroke();
// restore the context to its unrotated state
ctx.restore();
}
I'm developing a simple chart using html5 Canvas. The idea is to draw two lines - one for min values and another one for max values, which I managed to do AND fill the space between those two line with some colour. Wonder how do I do the last part?
to fill the space you have to:
//get the context of the canvas
var context = canvas.getContext("2d");
//begin to draw
context.beginPath();
//draw all the lines you need to do the path....
context.moveTo(x, y);
context.lineTo(x1,y1);
context.lineTo(x2,y2);
//end of draw
context.closePath();
//to fill the space in the shape
context.fillStyle = "#FF00FF";
context.fill();
//to draw a border
context.lineWidth = 5;
context.strokeStyle = "#FF0000";
context.stroke();
UPDATE: to fill the space between 2 lines, is drawing a square:
I asume the lines are defined as:
line1: from (x1,y1) to (x2,y2)
line2: from (x3,y3) to (x4,y4)
then the square to draw to fill the space:
from (x1,y1) -> (x2,y2) -> (x3,y3) -> (x4,y4) and closepath();
then:
context.beginPath();
context.moveTo(x1,y1); //go to first point
context.lineTo(x2,y2); //draw to second point
context.lineTo(x3,y3); //draw to third point
context.lineTo(x4,y4); //draw to last point
context.closePath(); //draw to first point
context.fill(); //fill the area
I have created 2 shapes, circle and rectangle, one on top of the other to resemble a key lock. I then try to apply a stroke but its stroking both shapes. What I want it to do is just stroke the merged pattern and not any of the intersections.
context.beginPath();
context.fillStyle = "#ccc";
context.arc(115, 550, 12, 0, 2 * Math.PI, false);
context.moveTo(105, 555);
context.fillStyle = "#999";
context.rect(105, 555, 20, 30);
context.fill();
context.stroke();
context.closePath();
If I try to draw the rect first, then the arc on top there are extra line paths when you stroke, its like I have to close Path and then draw it again.
You can't use a rect and a whole circle if you want the path to do without the intersecting part.
Instead you have to draw only part of the circle and only part of the rectangle. This should do it for you:
context.beginPath();
context.fillStyle = "#ccc";
context.arc(115, 550, 12, 2.5, 2.2 * Math.PI, false);
context.moveTo(105+20, 555);
context.fillStyle = "#999";
// instead of a rect, we really want three lines
context.lineTo(105+20,555+30);
context.lineTo(105,555+30);
context.lineTo(105,555);
context.fill();
context.stroke();
context.closePath();
While working on my own irregular shape answer, I discovered a lab project by Professor Cloud that solved my problem.
This page, SVG-to-Canvas, parses an SVG graphic to Canvas code. So if you have an application like Illustrator with which you can draw and save the graphic as SVG, then you can parse the usable canvas codes and just plug them in.
You can use compositing and temporary canvas. Something like that:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var tempCanvas = document.getElementById('tempCanvas');
var tempContext = tempCanvas.getContext('2d');
tempContext.save();
// clear temp context
tempContext.clearRect(0, 0, canvas.width, canvas.height);
// draw all rects with strokes
tempContext.beginPath();
tempContext.strokeStyle='red';
tempContext.lineWidth=3;
tempContext.arc(100, 100, 60, 0, 2 * Math.PI, false);
tempContext.rect(20,150,100,200);
tempContext.stroke();
// set compositing to erase existing drawings
// where the new drawings are drawn
tempContext.globalCompositeOperation='destination-out';
// fill all rects
// This "erases" all but the outline stroke
tempContext.beginPath();
tempContext.fillStyle='blue';
tempContext.arc(100, 100, 60, 0, 2 * Math.PI, false);
tempContext.rect(20,150,100,200);
tempContext.fill();
// draw outlines from tempcanvas into canvas
ctx.drawImage(tempCanvas, 0, 0);
// draw into canvas
ctx.beginPath();
ctx.fillStyle='green';
ctx.globalAlpha = 0.2;
ctx.rect(20,150,100,200);
ctx.arc(100, 100, 60, 0, 2 * Math.PI, false);
ctx.fill();
tempContext.restore();
And a jsfiddle: https://jsfiddle.net/EvaF/8to68dtd/2/
Using the HTML5 <canvas> element, I would like to load an image file (PNG, JPEG, etc.), draw it to the canvas completely transparently, and then fade it in. I have figured out how to load the image and draw it to the canvas, but I don't know how to change its opacity.
Here's the code I have so far:
var canvas = document.getElementById('myCanvas');
if (canvas.getContext)
{
var c = canvas.getContext('2d');
c.globalAlpha = 0;
var img = new Image();
img.onload = function() {
c.drawImage(img, 0, 0);
}
img.src = 'image.jpg';
}
Will somebody please point me in the right direction like a property to set or a function to call that will change the opacity?
I am also looking for an answer to this question, (to clarify, I want to be able to draw an image with user defined opacity such as how you can draw shapes with opacity) if you draw with primitive shapes you can set fill and stroke color with alpha to define the transparency. As far as I have concluded right now, this does not seem to affect image drawing.
//works with shapes but not with images
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
I have concluded that setting the globalCompositeOperation works with images.
//works with images
ctx.globalCompositeOperation = "lighter";
I wonder if there is some kind third way of setting color so that we can tint images and make them transparent easily.
EDIT:
After further digging I have concluded that you can set the transparency of an image by setting the globalAlpha parameter BEFORE you draw the image:
//works with images
ctx.globalAlpha = 0.5
If you want to achieve a fading effect over time you need some kind of loop that changes the alpha value, this is fairly easy, one way to achieve it is the setTimeout function, look that up to create a loop from which you alter the alpha over time.
Some simpler example code for using globalAlpha:
ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore();
If you need img to be loaded:
var img = new Image();
img.onload = function() {
ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore()
};
img.src = "http://...";
Notes:
Set the 'src' last, to guarantee that your onload handler is called on all platforms, even if the image is already in the cache.
Wrap changes to stuff like globalAlpha between a save and restore (in fact use them lots), to make sure you don't clobber settings from elsewhere, particularly when bits of drawing code are going to be called from events.
Edit: The answer marked as "correct" is not correct.
It's easy to do. Try this code, swapping out "ie.jpg" with whatever picture you have handy:
<!DOCTYPE HTML>
<html>
<head>
<script>
var canvas;
var context;
var ga = 0.0;
var timerId = 0;
function init()
{
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
timerId = setInterval("fadeIn()", 100);
}
function fadeIn()
{
context.clearRect(0,0, canvas.width,canvas.height);
context.globalAlpha = ga;
var ie = new Image();
ie.onload = function()
{
context.drawImage(ie, 0, 0, 100, 100);
};
ie.src = "ie.jpg";
ga = ga + 0.1;
if (ga > 1.0)
{
goingUp = false;
clearInterval(timerId);
}
}
</script>
</head>
<body onload="init()">
<canvas height="200" width="300" id="myCanvas"></canvas>
</body>
</html>
The key is the globalAlpha property.
Tested with IE 9, FF 5, Safari 5, and Chrome 12 on Win7.
This suggestion is based on pixel manipulation in canvas 2d context.
From MDN:
You can directly manipulate pixel data in canvases at the byte level
To manipulate pixels we'll use two functions here - getImageData and putImageData.
getImageData usage:
var myImageData = context.getImageData(left, top, width, height);
The putImageData syntax:
context.putImageData(myImageData, x, y);
Where context is your canvas 2d context, and x and y are the position on the canvas.
So to get red green blue and alpha values, we'll do the following:
var r = imageData.data[((x*(imageData.width*4)) + (y*4))];
var g = imageData.data[((x*(imageData.width*4)) + (y*4)) + 1];
var b = imageData.data[((x*(imageData.width*4)) + (y*4)) + 2];
var a = imageData.data[((x*(imageData.width*4)) + (y*4)) + 3];
Where x is the horizontal offset, y is the vertical offset.
The code making image half-transparent:
var canvas = document.getElementById('myCanvas');
var c = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
c.drawImage(img, 0, 0);
var ImageData = c.getImageData(0,0,img.width,img.height);
for(var i=0;i<img.height;i++)
for(var j=0;j<img.width;j++)
ImageData.data[((i*(img.width*4)) + (j*4) + 3)] = 127;//opacity = 0.5 [0-255]
c.putImageData(ImageData,0,0);//put image data back
}
img.src = 'image.jpg';
You can make you own "shaders" - see full MDN article here
You can. Transparent canvas can be quickly faded by using destination-out global composite operation. It's not 100% perfect, sometimes it leaves some traces but it could be tweaked, depending what's needed (i.e. use 'source-over' and fill it with white color with alpha at 0.13, then fade to prepare the canvas).
// Fill canvas using 'destination-out' and alpha at 0.05
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.beginPath();
ctx.fillRect(0, 0, width, height);
ctx.fill();
// Set the default mode.
ctx.globalCompositeOperation = 'source-over';
I think this answers the question best, it actually changes the alpha value of something that has been drawn already. Maybe this wasn't part of the api when this question was asked.
Given 2d context c.
function reduceAlpha(x, y, w, h, dA) {
let screenData = c.getImageData(x, y, w, h);
for(let i = 3; i < screenData.data.length; i+=4){
screenData.data[i] -= dA; //delta-Alpha
}
c.putImageData(screenData, x, y );
}
Set global Alpha draw the object that has opacity then set back to normal.
//////////////////////// circle ///////////////////////
ctx.globalAlpha = 0.75;
ctx.beginPath();
ctx.arc(x1, y1, r1, 0, Math.PI*2);
ctx.fillStyle = colour;
ctx.fill();
ctx.closePath();
ctx.globalAlpha = 1;
How i made it..on canvas i first draw rect in a selfrun function 0,0,canvas.width,canvas.height as a background of canvas and i set globalAlpha to 1 .then i draw other shapes in ather own functions and set their globalAlpha to 0.whatever number they dont affect each other even images.
Like Ian said, use c.globalAlpha = 0.5 to set the opacity, type up the rest of the settings for the square, then follow up with c.save();. This will save the settings for the square then you can c.rect and c.fillStyle the square how you want it. I chose not to wrap it with c.restore afterwards and it worked well
If you use jCanvas library you can use opacity property when drawing. If you need fade effect on top of that, simply redraw with different values.
You can't. It's immediate mode graphics. But you can sort of simulate it by drawing a rectangle over it in the background color with an opacity.
If the image is over something other than a constant color, then it gets quite a bit trickier. You should be able to use the pixel manipulation methods in this case. Just save the area before drawing the image, and then blend that back on top with an opacity afterwards.