Why is clearRect() not fully clearing fillRect() - javascript

Why is clearRect() not fully clearing fillRect() when they have the same values in this example?
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
setInterval(function(){
let rect = {x:Math.random()*c.width, y:Math.random()*c.height}
ctx.fillRect(rect.x, rect.y, 5, 5);
ctx.clearRect(rect.x, rect.y, 5,5);
},500)
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

Because of antialiasing.
You are drawing at non-integer coordinates, while you can't have half pixel rendered, so the pixels colors are shaded with some transparency to give this illusion of smaller pixels than a pixel.
However, clearRect() is also subject to this antialiasing, and thus will leave some translucent pixels.
To avoid this try to always draw at pixel integers when possible, and moreover, clear the whole canvas and redraw what needs to be at every frame.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
setInterval(function() {
// clear all
ctx.clearRect(0, 0, c.width, c.height);
// redraw what needs to be
let rect = {
x: Math.random() * c.width,
y: Math.random() * c.height
}
ctx.fillRect(rect.x, rect.y, 5, 5);
}, 500)
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

Related

HTML5, canvas: some linewidth too narrow and then disappear

A stupid simple canvas usage:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.scale(100000, 100000);
ctx.lineWidth = 0.00001;
ctx.moveTo(0, 0);
ctx.lineTo(200, 100);
ctx.stroke();
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
The current line segment is not displayed。
if I change to this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.scale(10000, 10000);
ctx.lineWidth = 0.0001;
ctx.moveTo(0, 0);
ctx.lineTo(200, 100);
ctx.stroke();
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
Line segments will be displayed?
Why does this happen. It’s annoying. Thanks for your help!
This is caused by a bug in the GPU renderer used by Chrome.
We can confirm it's only a bug in the GPU pipes by initializing your context with the willReadFrequently flag, but that's not a proper solution (because you want GPU acceleration when available).
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d", { willReadFrequently: true });
ctx.scale(100000, 100000);
ctx.lineWidth = 0.00001;
ctx.moveTo(0, 0);
ctx.lineTo(200, 100);
ctx.stroke();
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
So, it would be great to open an issue against Chromium, you can point to them that apparently this CL introduced the issue, and thus it is a regression.
While you're there, you can also open one against WebKit, which doesn't even pass the x10,000 scale test.
But to be honest, you are asking for trouble using such scales.
Such "rounding" bugs regularly come and go in various engines, and not only this obvious, sometimes only when doing a particular curve etc.
So the best is to stick to "standard" scales, if you really need to go that far, then do the scaling yourself from JS:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
const scale = 100_000;
ctx.moveTo(0, 0);
ctx.lineTo(200 * scale, 100 * scale);
ctx.stroke();
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>

Canvas HTML - Smoothness between lineTo and Bezier curve

Maybe this is more a math question but lets see:
I'm using HTML5 Canvas to draw a line chart.
The chart is basically Position X Time.
Each line represents a vehicle in a position (Y) in a given time (X).
I only have information about when a vehicle passed through determined points in the road. So if a vehicle stops between two points I don't have the information that it actually stoped, but when it passes through the next point I will be able to draw a line that will be almost horizontal, because the average speed, i.e. the line slope, will be really small.
In these scenarios we have defined that if a vehicle moved below 10Km/h I should consider that it made a stop and should draw a horizontal smooth line.
Basically I have to transform this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(0, 30);
ctx.lineTo(20, 50);
ctx.lineTo(220, 70);
ctx.lineTo(240, 110);
ctx.stroke();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
Into this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(0, 30);
ctx.lineTo(20, 50);
ctx.bezierCurveTo(
50, 70,
210, 50,
220, 70
)
ctx.lineTo(240, 110);
ctx.stroke();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
The problem is: how do I chose good values for the bezier points?
In the above example I have done it experimentally. I cannot find a way to programatically pick good point values so my lines don't look bad like these:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(0, 30);
ctx.lineTo(20, 50);
ctx.bezierCurveTo(
20, 70,
180, 50,
220, 70
)
ctx.lineTo(240, 110);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, 80);
ctx.lineTo(20, 100);
ctx.bezierCurveTo(
20, 120,
220, 100,
220, 120
)
ctx.lineTo(280, 150);
ctx.stroke();
<canvas id="myCanvas" width="300" height="170" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
I'm looking for a computationally simple solution because this is redrawn everytime with a lot of lines, so I don't want this melting down my performance.
Thanks for any tips!
I found a good solution for my problem: Using line interpolation.
Having the following segments and imagine I want to smooth things between B and C, how can I choose some bezier points that would garantee a smooth curve instead of broken one?
First I interpolate the segment AB and find the point B', which is the point the line AB would touch the Y coordinate for C. Then I use the same process to find C':
The points B' and C' make good points for the bezier in order to smooth things up to a horizontal line:
This is also being computationally simple enough since finding the a line equation is rather simple.

HTML5 - Canvas: Draw text over gradient

I want to write some text over a gradient (to make a scale):
I have this so far:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Create gradient
var grd = ctx.createLinearGradient(0,0,500,0);
grd.addColorStop(0,"red");
grd.addColorStop(0.5,"yellow");
grd.addColorStop(1,"green");
// Fill with gradient
ctx.font = "30px Arial";
ctx.fillText("Hello World",10,50);
ctx.fillStyle = grd;
ctx.fillRect(0,0,500,100);
<canvas id="myCanvas" width="500" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
I can't see the text. How can I fix this?
I want to create this:
Where the circle is generated from some score that I give.
There are two issues:
You're drawing the background overtop of the text
You're drawing the background and text in the same gradient, so the text will be invisible on top of the background
Move the text-drawing after the rectangle, and change its color:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Create gradient
var grd = ctx.createLinearGradient(0,0,500,0);
grd.addColorStop(0,"red");
grd.addColorStop(0.5,"yellow");
grd.addColorStop(1,"green");
// Fill with gradient
ctx.font = "30px Arial";
ctx.fillStyle = grd;
ctx.fillRect(0,0,500,100);
ctx.fillStyle = "#000";
ctx.fillText("Hello World",10,50);
<canvas id="myCanvas" width="500" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
You may want to set the text last. I can see you are drawing the filled rectangle over the text you have already drawn. Try doing this instead:
<canvas id="myCanvas" width="500" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Create gradient
var grd = ctx.createLinearGradient(0,0,500,0);
grd.addColorStop(0,"red");
grd.addColorStop(0.5,"yellow");
grd.addColorStop(1,"green");
// Fill with gradient
ctx.fillStyle = grd;
ctx.fillRect(0,0,500,100);
//write text with canvas methods
c.fillStyle = '#000000';
c.font = "30px Arial";
c.fillText("Hello World",10,50);
</script>
You may also want to consider looking up canvas.textAlign and canvas.textBaseline properties for positioning the text;

Draw Shape in JQuery

I am working in Jquery.
I have 4 Cordinates , Width, Height, x Position and Y position.
How can i create a Square shape Using This
$('#box').drawRect(20,20,2,30,{color:'red'})
I tried this and Not Working. Looking for a Good Hand
Here is My Demo. http://fiddle.jshell.net/vbm2vhu4/
try using canvas tag in JavaScript..
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(20, 20, 150, 100);
ctx.stroke();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
JSFIDDLE
JAVASCRIPT
Draw a circle
$(document).ready(function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
});
Drawing a rectangle requires canvas. You really do not need to use jquery for it. It can be well done with Javascript. I am attaching my example here.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150">
Browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Blue rectangle
ctx.beginPath();
ctx.lineWidth = "10";
ctx.strokeStyle = "blue";
ctx.rect(50, 50, 50, 50);
ctx.stroke();
</script>
</body>
</html>
Paste this into a notepad and save as .html and load it in your browser
or jsfiddle http://jsfiddle.net/ssbiswal1987/vsbak0mq/

How to rotate the existing content of HTML5 canvas?

Is there a way to rotate the existing content of HTML5 canvas by Javascript? I know it's possible to rotate an image that will be drawn on to canvas, but I want to rotate the content that has been drawn on to canvas, for example, a 200x200 corner of a 400x400 canvas, or any specific region of an existing canvas.
Same question to scale the existing canvas content...
I know getImageData/putImageData provide a potential to transform the pixel array, but it's just too slow and inefficient.
It's pretty easy to do with a temp canvas.
Live Demo
Live Demo Animated (just for the heck of it)
The above example draws 2 boxes, then rotates and scales from 0,0 to 200,200
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = canvas.height = 400;
// fill the canvas black, and draw 2 boxes
ctx.fillStyle = "#000";
ctx.fillRect(0,0,400,400);
ctx.fillStyle = "rgb(255,0,0)";
ctx.fillRect(10,10,190,190);
ctx.fillStyle = "rgb(255,255,0)";
ctx.fillRect(250,250,90,90);
// Create a temp canvas to store our data (because we need to clear the other box after rotation.
var tempCanvas = document.createElement("canvas"),
tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
// put our data onto the temp canvas
tempCtx.drawImage(canvas,0,0,canvas.width,canvas.height);
// Append for debugging purposes, just to show what the canvas did look like before the transforms.
document.body.appendChild(tempCanvas);
// Now clear the portion to rotate.
ctx.fillStyle = "#000";
ctx.fillRect(0,0,200,200);
ctx.save();
// Translate (190/2 is half of the box we drew)
ctx.translate(190/2, 0);
// Scale
ctx.scale(0.5,0.5);
// Rotate it
ctx.rotate(45*Math.PI/180);
// Finally draw the image data from the temp canvas.
ctx.drawImage(tempCanvas,0,0,200,200,10,10,190,190);
ctx.restore();
If you first want to draw on a canvas and then rotate it for use on e.g. corners, you can to that when you "clone" the canvas or by using CSS.
Examples
Get the first canvas element:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
draw on it:
ctx.fillStyle = 'blue';
ctx.fillRect(0,0, 25, 5);
ctx.fill();
ctx.fillStyle = 'red';
ctx.fillRect(25, 0, 25, 5);
ctx.fill();
clone it to another canvas (that is rotated by CSS):
var ctx2 = document.getElementById("canvas2").getContext("2d");
ctx2.drawImage(canvas, 0,0);
or rotate the canvas while you "clone" it:
var ctx3 = document.getElementById("canvas3").getContext("2d");
ctx3.rotate(Math.PI/2);
ctx3.translate(0,-50);
ctx3.drawImage(canvas, 0,0);
here is the CSS for rotating it:
#canvas2 {
-webkit-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-o-transform:rotate(90deg);
-ms-transform:rotate(90deg);
}
Here is the full example:
<!DOCTYPE html>
<html>
<head>
<script>
window.onload = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = 'blue';
ctx.fillRect(0,0, 25, 5);
ctx.fill();
ctx.fillStyle = 'red';
ctx.fillRect(25, 0, 25, 5);
ctx.fill();
var ctx2 = document.getElementById("canvas2").getContext("2d");
ctx2.drawImage(canvas, 0,0);
var ctx3 = document.getElementById("canvas3").getContext("2d");
ctx3.rotate(Math.PI/2);
ctx3.translate(0,-50);
ctx3.drawImage(canvas, 0,0);
}
</script>
<style>
#canvas2 {
-webkit-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-o-transform:rotate(90deg);
-ms-transform:rotate(90deg);
}
</style>
</head>
<body>
<canvas id="canvas" width="50" height="50"></canvas>
<canvas id="canvas2" width="50" height="50"></canvas>
<canvas id="canvas3" width="50" height="50"></canvas>
</body>
</html>

Categories

Resources