If I draw a rectangle to the canvas, and I enable the shadows, then there will be created inner, and outer shadows too, but I only want outer shadow.
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.shadowColor = 'black';
ctx.shadowBlur = 5;
ctx.strokeRect(20,30,150,75);
The only way I've found is ctx.clearRect(20,30,150,75);. But it's not really what I want, because there may be something under my rect, and I don't want to delete it.
Thanks in advance,
You could fetch the pixels inside the rectangle, do the painting and put those pixels back. That way, pixels inside the rectangle won't change: http://jsfiddle.net/dkAKE/.
var imgdata = ctx.getImageData(20, 30, 150, 75);
ctx.strokeRect(20, 30, 150, 75);
ctx.putImageData(imgdata, 20, 30);
To retain the border, use (21, 31, 148, 73) as the area (assuming a stroke width of 1px).
You can also use .fillRect() instead of .strokeRect(). This will create a solid rectangle that has an inner color you define as .fillStyle()
ctx.shadowColor = 'black';
ctx.fillStyle = 'white';
ctx.shadowBlur = 5;
ctx.fillRect(20,30,150,75);
You will still have the problem of it overwriting whatever was underneath the rectangle, so you would still need pimvdb's solution to solve that problem.
Related
I'm trying to place text over a background color. I think the issue is that the "fillStyle" is being applied to both the text and the background. I want the text to be black. What am I doing wrong here?
Below is my code:
var canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
var ctx = canvas.getContext("2d");
ctx.fillText("hello", 0, 0);
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
var img = document.createElement("img");
img.src = canvas.toDataURL("image/png");
document.body.appendChild(img);
Here's a link to the fiddle: https://jsfiddle.net/jessecookedesign/9rsy9gjn/36/
Unlike HTML where you define a list of what you want to appear, when working with a canvas it's like you're painting. So each "drawing" operation you do (like fillRect or fillText) will go on top of any existing content and cover it up.
Similarly since you're actually painting, rather than defining objects, you need to set the fill style before drawing. Using the analogy, you need to select the color of paint you'll use before you put paint to canvas.
Finally, the fillText method takes a position as the start of the baseline of the text. Since (0, 0) is the top left of the canvas, your text will get drawn above the bounds of the canvas an not be visible, so you need to move it down e.g. fillText("Hello World", 10, 100);
Correcting for those issues you get something like the following (and skipping the steps involved in converting to an img tag):
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Draw a black background
context.fillStyle = "black";
context.fillRect(0, 0, 200, 200);
// Draw the text
context.fillStyle = "#E7E0CA";
context.fillText("Hello world", 10, 100);
<canvas id="canvas" width="200" height="200"></canvas>
Wrong order - You're drawing the rectangle over the text.
The text has the same color as the rectangle
There's no font specified
The position (0,0) is out of bounds
Try it like this:
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText("hello",10,30);
There are several issues:
You need to first fill the background, then fill the text.
Your text is above the canvas area — try a lower position.
This code has the correct order, and a position for the text that isn’t outside the canvas bounds.
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = "#000000";
ctx.fillText("hello", 10, 10);
With the changed order, of course you need to choose a new color for the text, in this case "#000000".
Alternatively, you could save and restore your canvas state:
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.restore();
ctx.fillText("hello", 10, 10);
Whenever you access canvas of html page,
whatever you draw first, will display first.
so if you want to display your colored box first fill it first, then write your text by providing color ,font and position of text. for example,
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#E7E0CA";//your rect color
ctx.fillRect(0, 0, 200, 200);//your rect size
ctx.fillStyle = "#000000";//color for your text
ctx.font="30px Arial";//font style and size
ctx.fillText("hello world",25,50);//text and location
</script>
How do I create a transparent gradient stroke that using html5 canvas? I need it to go from one point to another and look like the below image.
At the moment I have got this:
const gradient = ctx.createLinearGradient(1, 0, 100, 0);
gradient.addColorStop(0, '#fff');
gradient.addColorStop(1, '#d29baf');
ctx.lineWidth = 30;
ctx.strokeStyle = gradient;
ctx.beginPath();
ctx.moveTo(fromXPos, fromYPos);
ctx.lineTo(toXPos, toYPos);
ctx.stroke();
This makes it look like a solid block though like:
Thanks.
Fill a shape
Use a shape and fill it with the gradient.
You can use CSS colour type rgba(red,green,blue,alpha) where red,green,blue are values from 0-255 and alpha is 0 transparent to 1 opaque.
To create a shape you start with ctx.beginPath() to create a new shape then use lineTo(x,y) to mark out each corner. If you want to add another shape using the same fill or stroke you use ctx.moveTo(x,y) to move to the first point.
Note many people use ctx.beginPath(); ctx.moveTo(x,y); but that works just the same as ctx.beginPath(); ctx.lineTo(x,y); As the first point after beginPath is always converted to a moveTo for any type of path object.
const ctx = canvas.getContext("2d");
// draw first box (left of canvas)
ctx.fillStyle = "#ab7383";
ctx.fillRect(20,100,50,50);
// draw second box (to right of first)
ctx.fillStyle = "#904860";
ctx.fillRect(100,20,50,130);
// gradient from top of second box to bottom of both boxes
const g = ctx.createLinearGradient(0, 20, 0, 150);
g.addColorStop(0, `rgba(${0xd2},${0xba},${0xaf},1`); // opaque
g.addColorStop(1, `rgba(${0xd2},${0xba},${0xaf},0`); // transparent
ctx.fillStyle = g;
ctx.beginPath();
ctx.lineTo(70, 100); // top right of first box
ctx.lineTo(100, 20); // top left of second box
ctx.lineTo(100, 150); // bottom left of second box
ctx.lineTo(70, 150); // bottom right of first box
ctx.fill(); // fill the shape
<canvas id="canvas" style="border:2px solid black"></canvas>
I'm trying to make a fade out effect with JavaScript on the Canvas element. I'm currently have two sollutions for this. In theory, both should work fine, but in practice, only one does, and I wonder why.
The not working code is the following:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = 1;
requestAnimationFrame(test);
function test(){
i-=0.01;
ctx.fillStyle = "white";
ctx.fillRect(20, 20, 75, 50);
ctx.globalAlpha = i;
ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
requestAnimationFrame(test);
}
What I wanted to achieve, is to gradually change the alpha value of the current context, in order to fade it to white. After a while, it should have full transparency, but it does not. It stops right before reaching that state. Here it is in JSFiddle: https://jsfiddle.net/bq75v1mm/
The working code is the following:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = 1;
requestAnimationFrame(test);
function test(){
i-=0.01;
ctx.fillStyle = "white";
ctx.fillRect(20, 20, 75, 50);
ctx.fillStyle = "rgba("+255+","+0+","+0+","+i+")";
ctx.fillRect(20, 20, 75, 50);
requestAnimationFrame(test);
}
With this code, I'm just simply changing the alpha value of the given fillStyle for the upcoming rectangle, and it works like a charm, and makes the square vanish into thin air. Here it is in JSFiddle: https://jsfiddle.net/mxtynwwd/
I would like to understand why doesn't the first sollution work? Why can't I lower the globalAlpha value after a given minimum? Or is the problem in the code?
In your second example, you reset fillStyle every time before drawing the white rectangle.
You're not doing the same with globalAlpha in your first example.
Not all values will be accepted by the globalAlpha property. Quoting MDN:
A number between 0.0 (fully transparent) and 1.0 (fully opaque). The default value is 1.0 Values outside the range, including Infinity and NaN will not be set and globalAlpha will retain its previous value.
Due to precision loss in floating pointer math, when i becomes negative, globalAlpha gets stuck on 0.009999999999999247 (may vary across machines).
To fix both of the above, reset globalAlpha before drawing the white rectangle:
ctx.globalAlpha = 1;
and before drawing the red one, make sure i is >= 0:
i = i < 0 ? 0 : i;
Your first example can accordingly be updated to behave exactly like your second one:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = 1;
requestAnimationFrame(test);
function test() {
i -= 0.01;
i = i < 0 ? 0 : i;
ctx.globalAlpha = 1;
ctx.fillStyle = "white";
ctx.fillRect(20, 20, 75, 50);
ctx.globalAlpha = i;
ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
requestAnimationFrame(test);
}
[ Updated fiddle ]
context.font = '20pt Calibri';
context.fillStyle = 'rgba(225,225,225,0.5)';
var width = context.measureText(message2).width;
context.fillRect(xIndent, yIndent+100, width, 60);
context.fillStyle = 'rgba(255,85,0,1.0)';
context.fillText(message3, xIndent, yIndent+100);
I want the context.fillText to have no transparency and the context.fillRect to have some transparency
For some reason, I can make both transparent or both opague
The result is both TEXT and Background color are of the same transparency
You need to reset everything after the first text is written. Because you can set fillStyle after you have drawn or written something, it will still fill it. So, if you want to have to things drawn or written after each other you need to reset everything, so that the next fillStyle doesn't change it's fillStyle too. You need to use context.beginPath() after you have wriite the first text. Here is your code corrected :
context.font = '20pt Calibri';
context.fillStyle = 'rgba(225,225,225,0.5)';
var width = context.measureText(message2).width;
context.fillRect(xIndent, yIndent+100, width, 60);
context.beginPath();
context.fillStyle = 'rgba(255,85,0,1.0)';
context.fillText(message3, xIndent, yIndent+100);
It is best to use context.beginPath() each time you want to draw or write something else.... I hope this helped.....
I'm drawing simple text in HTML5 canvas using this:
context.fillStyle = "#FF0000"
context.font = "italic 20pt Arial";
context.fillText("sfddsfs", 50, 50);
Now I want to animate fade out of this text. How can that be done?
Edit: I'm aware there's currently no ready to use way to do this (at least I can't find anything). I'm a noob in graphic programming but want to learn, so any hint about where to start is appreciated.
Maybe something like putting the text in an own canvas and changing globalAlpha of the canvas...? But the background of the canvas would have to be transparent. And don't know about performance, have a lot of small labels appearing and dissapearing everywhere which need to be faded out.
It's easier if you use rgba() notation to set the fillStyle rather than the hexadecimal notation. Here's a working example (demo):
// Create a canvas element and append it to <body>
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
document.body.appendChild(canvas);
function fadeOut(text) {
var alpha = 1.0, // full opacity
interval = setInterval(function () {
canvas.width = canvas.width; // Clears the canvas
context.fillStyle = "rgba(255, 0, 0, " + alpha + ")";
context.font = "italic 20pt Arial";
context.fillText(text, 50, 50);
alpha = alpha - 0.05; // decrease opacity (fade out)
if (alpha < 0) {
canvas.width = canvas.width;
clearInterval(interval);
}
}, 50);
}
fadeOut('sfddsfs');
I think I got it. Forgot to mention that I have already a render loop and text objects which draw themselves on the canvas each frame.
So the solution is to add alpha variable to the text objects:
this.alpha = 1;
and each x frames or time reduce this a bit.
and in the render loop:
context.globalAlpha = textObject.alpha;
//draw the text
context.globalAlpha = 1;
There is no built-in solution to this. You have to do the animation(fade) by drawing each frame individually:
Set up some timing function that calculates the gradient between #FF0000 and the background color and redraws the text over and over until the background color is reached.