I have the following problem:
I need to transform text on a HTML canvas, e.g. give it a trapezoid shape.
Here's what I tried:
context.beginPath();
context.moveTo(0, 0);
context.lineTo(200, 0);
context.lineTo(100, -100);
context.lineTo(0, -100);
context.closePath();
context.clip();
context.fillText("Hello World", this.x, this.y);
As you might have guessed, the text gets cut off instead of transformed to fit the shape. Below are images of what I am trying to do and what I managed to do.
Any help is appreciated :)
What I managed to do:
What I want to do:
What you can do is get a dummy canvas element in which you put your normal text, then you can apply your own maths to the pixel color values in textCtx.getImageData onto another imageData array that you create, so you can then put that into another canvas with the correct transform with transformedTextCtx.putImageData, and finally draw its canvas onto the original context with ctx.drawImage.
I'm going to assume you know the kind of maths that you want to apply, and if not I suggest you look into skewing and scaling, and find out how you can combine the two.
The mdn resources for the imageData methods are in the "Pixel Manipulation" subsection of the canvas rendering context page: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#Pixel_manipulation
General Answer: How to transform text
You can transform your text (or anything else) by using canvasContext.setTransform before drawing. You don't need any second canvas.
Examples:
canvasContext.setTransform(1, 0, 0, 1, 0, 0); is the default
canvasContext.setTransform(0.5, 0, 0, 1, 0, 0); reduces width to 50%
canvasContext.setTransform(1, 0, 0, 0.5, 0, 0); reduces height to 50%
Specific Answer:
I couldn't figure this out quickly. I'll leave it up to the next user to figure it out.
Related
I'm trying to create my first game to HTML5. And I search for hours like leaving a text persperctiva (for canvas).
See attached what I need. Are two "points" in text that needs to be modified to the effect that I need.
Image: https://pbs.twimg.com/media/BVbuU1PCUAA7d8a.png
PS: I managed to leave with only the text "rotation" (basic) and that is not right for my purpose.
All topics that I found say in response is not possible.
Canvas's 2d context can't do the non-parallel transforming that is shown in your link.
To do perspective-like warping, you will need to use the canvas 3d context (webGL).
Alternatively, here is a post on how to interpolate pixels from an original triangle into a distorted triangle:
http://codeslashslashcomment.com/2012/12/12/dynamic-image-distortion-html5-canvas/
This will allow you to "manually" do perspective distortions in 2d context.
It doesn't look like there's much perspective involved, so you might get away with a simple skew:
var angle = -0.2;
context.setTransform(1, 0, angle, 1, 0, 0);
context.drawImage(img, 100, 0, 350, 100);
http://jsfiddle.net/fTQcn/
I am creating an animation in Canvas. Initially, the Canvas will have a set of images drawn on it. After certain time, say 5 seconds, an image has to be cleared from its original place and drawn at a separate place.
To clear the image, I tried using context.clearRect() to clear the portion, but no luck. Is there any other way to do this?
clearRect is the right way. Note that if you have a transformation applied, it may be clearing a different rectangle in the canvas. You can always remedy this by using:
// I have lots of transforms right now
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Will always clear the right space
ctx.clearRect(x, y, width, height);
ctx.restore();
// Still have my old transforms
As I understand it, gradient fills must be specified relative to the canvas element itself (i.e. 0, 0) rather than relative to the shape you're actually filling.
Question: am I right in this assertion, and is there a suggested way around it?
For example (JSFiddle here):
ctx.beginPath();
ctx.rect(40, 50, 100, 70);
var grd = ctx.createLinearGradient(0, 50, 0, 120);
grd.addColorStop(0, "red");
grd.addColorStop(1, "blue");
ctx.fillStyle = grd;
ctx.fill();
There, I make a rectangle. I expected that, to fill it with a gradient starting from the top left of the shape, I would pass 0, 0 as the first two params. It seems I must pass instead the X/Y coordinates of the rectangle relative to the canvas.
This becomes an issue if, say, you have an arc built with a quadratic curve, since, without being a Maths genius, you don't know the top position of the curve - only the control point.
If you don't know the bounds of the shapes that you're drawing, you're going to have a bad time.
If you're using gradients, especially re-using gradients, it's best to always make your gradients and shapes from the origin and translate them to the locations they are going to be.
Setting up that sort of system will make it so that defining gradients is more or less relative to the size of your objects, but you'll still have to do the bounds calculations yourself.
Here's an example of translating a gradient and shape to make it "relative" to the canvas:
http://jsfiddle.net/simonsarris/RFgcs/
I was wondering if there is a way to draw an image but give it a colourized effect.
If you consider games, when you want to place a sprite but theres an object in the way, often the object you try to place get a red tint to it to indicate it cannot be placed which is what im trying to achieve.
I currently draw it with an opacity here:
ctx.globalAlpha = 0.5
ctx.drawImage(image,abposx,abposy);
Is this possible to achieve without a library?
You can draw a semitransparent rectangle over top of it. For example:
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // 1/2 opacity red
ctx.fillRect(0, 0, 30, 30); // Draw this over top of your image
Here's a demo.
For isometric images, all you have to do is create the appropriate path. Here's an example of that:
You can clip the overlay to your image by setting the globalCompositeOperation to source-atop:
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // 1/2 opacity red
ctx.fillRect(0, 0, 30, 30); // Draw this over top of your image
ctx.globalCompositeOperation = 'source-over';
Here's a demo. You may also have to use a shadow canvas if the areas you're trying to draw on also have content, though.
I am using an HTML canvas and javascript and I need to clear all of the pixels underneath a shape created by closing a path (for example, I am using flot, and I want to make rounded corners, and to do this, I first need to remove the square corners by drawing a curve on top of the corner to remove the desired pixels).
Right now, I am doing this by just filling the shape with the same color as the background, which can imitate what I want to do, but, it is not ideal as it makes it impossible to place the chart on top of non-solid backgrounds without seeing the square corners. I know that there is a clearRect method that would do what I want to do, but with only rectangles, I need to do it with any closed shape. Is it possible, and if so, how would I do it?
brainjam's code was heading in the right direction, but didn't fully solve the problem. Here's the solution:
context.save();
context.globalCompositeOperation = 'copy';
context.fillStyle = 'rgba(0,0,0,0)';
//draw shape to cover up stuff underneath
context.fill();
context.restore();
Here's an example of a function that will clear a circle from a canvas:
var clearCircle = function(x, y, radius)
{
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
I think what you want is a clipping region, defined by the clip() function. The latter takes a bunch of paths. Here's an example.
This is a little different from what you are specifically asking (which is to remove pixels after drawing them), but actually not drawing the pixels in the first place is probably better, if I understand your requirements correctly.
Edit: I now think I understand that what you want to do is clear pixels to transparent black. To do that, after having defined your paths, do something like this:
context.fillStyle = 'rgba(0,0,0,0)';
context.fill();
The first statement sets the fill color to transparent black.
Use globalCompositeOperation = 'destination-out' instead of 'copy', it will erase all pixels of the shape in the canvas.
See all kinds of composition here
very usefull !