HTML5, canvas: some linewidth too narrow and then disappear - javascript

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>

Related

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.

Why is clearRect() not fully clearing fillRect()

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>

HTML5 Canvas clearRect isn't working

So I'm trying to have an 'X' appear on the screen and go across every second, but the previous 'X's don't go away when I draw the new ones, a whole path of 'X's stays behind and I want it to just be one that moves across in 60px increments. Obviously there must be something having to do with paths and such that I don't know about, here's my code:
//ctx is already defined as the canvas context and works fine
var bx = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
setInterval(function(){
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
ctx.moveTo(bx*60 ,0);
ctx.lineTo(bx*60+60,60);
ctx.moveTo(bx*60+60,0);
ctx.lineTo(bx*60 ,60);
ctx.stroke();
bx++;
},1000);
<canvas id="myCanvas" width="200" height="100"></canvas>
You forget to begin and close path. Your canvas go to clear but all your lines will be every iteration rerendered.
//ctx is already defined as the canvas context and works fine
var bx = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
setInterval(function(){
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
ctx.beginPath(); // begin
ctx.moveTo(bx*60 ,0);
ctx.lineTo(bx*60+60,60);
ctx.moveTo(bx*60+60,0);
ctx.lineTo(bx*60 ,60);
ctx.closePath(); // close
ctx.stroke();
bx++;
},1000);
Try this:
//ctx is already defined as the canvas context and works fine
var bx = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
setInterval(function() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
ctx.moveTo(bx * 60, 0);
ctx.lineTo(bx * 60 + 60, 60);
ctx.moveTo(bx * 60 + 60, 0);
ctx.lineTo(bx * 60, 60);
ctx.closePath();
ctx.stroke();
bx++;
}, 1000);
<canvas id="myCanvas" width="200" height="100"></canvas>

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/

Categories

Resources