HTML Canvas - bizzarre results [duplicate] - javascript

This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 4 years ago.
function Start() {
DrawViewDist();
DrawFoV();
}
function DrawFoV() {
var c = document.getElementById("roomCanvas1");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#f0f";
ctx.lineWidth=1;
ctx.beginPath();
ctx.moveTo(150, 113);
ctx.lineTo(123,16);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(150, 113);
ctx.lineTo(175,16);
ctx.stroke();
}
function DrawViewDist() {
var c = document.getElementById("roomCanvas1");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#ff0";
ctx.lineWidth=1;
ctx.beginPath();
ctx.moveTo(150, 113);
ctx.lineTo(150,16);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(1, 1);
ctx.lineTo(299,149);
ctx.stroke();
}
body {
background-color: #802828;
color: #fff;
}
#roomCanvas1 {
height: 600px;
width: 800px;
padding: 0;
border: 1px solid #0f0;
}
<!DOCTYPE html>
<html>
<head>
<title>Canvas Test</title>
</head>
<body onload="Start()">
<div id="main">
<canvas id="roomCanvas1">Your browser does not support HTML5 canvas drawings.</canvas>
</div>
</body>
</html>
I'm trying to draw lines using a canvas. The canvas is set to 800x600 and I have a 1 px border around it so I can see that it really IS 800x600 - but when I try to draw the lines, I have to pretend that the canvas is 300x150 in order to have the lines start/end in the right places. On top of that, the lines are much thicker than they should be - and they're blurry! I started with the code from W3Schools and just modified it. Everything works fine (using the same browser) in their TryIt editor so I can't imagine what the problem is.

This is a common problem that I have had in the past. Just set the canvas.width = 800 and canvas.height = 600. The canvas's height and width are naturally 150 and 300. When you change the canvas's height and width in html/css, it doesn't change js. you have to specify in the js that there was a change. Hope this helps

Related

Removing text in HTML5 Canvas?

I'm working on a HTML5 Canvas project and have some text drawn on the screen. Right now, it appears and just stay there, but what I need is for it to disappear after a few seconds so that every time it's called it's not just new text being drawn on top of the old text.
I tried clearRect() but that completely clears the entire rectangle and removes some of my background too, which I don't want.
Is there a way to do this?
I'm drawing the text with this basic function:
function drawText() {
ctx.font = "30px Arial";
ctx.fillText("Please wait...", 575, 130);
}
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<button onclick="showTheText()">Click to show text</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function showTheText() {
var myText = {
text: 'Hello World',
x: 0,
y: 75,
fill: 1
};
drawText(myText, context);
// wait one second before starting animation
setTimeout(function() {
animate(myText, canvas, context);
}, 1000);
}
function drawText(myText, context) {
context.font="30px Arial";
context.fillStyle="rgb(0, 0, 0, " + myText.fill + ")";
context.fillText(myText.text, myText.x, myText.y);
}
function animate(myText, canvas, context) {
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// !!!!!!!! redraw your background !!!!!!!!
// then redraw your text with new opacity
myText.fill -= .1;
drawText(myText, context);
// request new frame
if (myText.fill > -.1) {
setTimeout(function() {
animate(myText, canvas, context);
}, 2000 / 60);
}
}
</script>
</body>
</html>
Hope this can help you. What it does it immediately draws the text (and the rest of your background, you didn't provide it), then sets up a recursive timeout that will clear the rect, redraw your background, decrement the amount of opacity to apply to the text's fill, and redraw the text as well. You can slow it down by changing the time of the last setTimeout.
I adapted it from this example: https://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/
you can create a simple function to delete ,
you will need some values. For example, font height. width of character ... etc ,
for example in this case , you can use the following function , With few modifications :
function removeText(x,y,txt_length,font_height,char_width,ctx) {
ctx.clearRect(x, y-font_height ,char_width*txt_length,font_height);
}
and this function for write your string :
function drawText(x,y,text,ctx) {
ctx.font = "30px Arial";
ctx.fillText(text,x,y);
}
The same parameters x and y are passed to the functions and txt_length = text.length;
Once you've drawn text to canvas, it's no longer text - it's just a bunch of pixels! Since those pixels overwrite what is already there, there's no way to delete just the text.
Generally what you can do is re-draw the entire scene without the text, if you want to get rid of it.
You could also try re-drawing the text in the same position using the background color, which would remove the text, but this only works if the text is on a solid background.
To achieve expected use below option of fillStyle in clearText function
Create another function clearText with fillStyle white color with same text and x , y coordinates
Call clearText function from the drawText
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
function drawText() {
clearText()
ctx.font = "30px Arial";
ctx.fillStyle = "black";
ctx.fillText("Please wait...", 575, 130);
}
function clearText() {
ctx.font = "30px Arial";
ctx.fillStyle = "white";
ctx.fillText("Please wait...", 575, 130);
}
<button onclick="drawText()">draw text</button><br>
<canvas id="myCanvas" width="800" height="800"
style="border:1px solid #d3d3d3;">
Your browser does not support the canvas element.
</canvas>
code sample - https://codepen.io/nagasai/pen/oqOXxz

Lines outside of canvas

I define a canvas as <canvas id="maincanvas" class="canvas"></canvas> with the style
.canvas {
width: 1000px;
height: 750px;
border: 1px dotted;
}
Then I try to draw a line from the upper-left to the lower-right with:
function GenerateSym() {
var c = document.getElementById("maincanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(5, 5);
ctx.lineTo(995, 745);
ctx.stroke();
Unfortunately, the line seems to start just a few px too low. While it leaves the canvas entirely on the bottom-center instead of ending just before the bottom-right corner. Additionally, the line seems to be at least 3px wide with terrible anti-aliasing.
I'm running Mint 18 with Firefox 58. Thanks!
You cannot use CSS style for resizing of the canvas element, or you will run into this issue. The canvas DOM element has properties width and height which equel to attributes "width=.." and "height=.." . As said here: Canvas width and height in HTML5 .
So the correct thing to do would be:
.canvas{ style: 1px dotted;}
and
<script>
var c = document.getElementById("maincanvas");
var ctx = c.getContext("2d");
c.width= 1000;
c.height= 750;
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo(5, 5);
ctx.lineTo(995, 745);
ctx.stroke();</script>

Text position on canvas is different in FireFox and Chrome

I need to draw a text string at a precise position on HTML5 canvas.
Here's my test code:
<!DOCTYPE html>
<html>
<body>
<canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
window.onload = function() {
var canvas = document.getElementById("mainCanvas");
var ctx = canvas.getContext("2d");
ctx.textBaseline = "top";
ctx.font = '100px Arial';
ctx.textAlign = 'left';
ctx.fillStyle = 'rgba(0, 0, 0, 255)';
ctx.fillText('Test', 0, 0);
}
</script>
</body>
</html>
The margin at the top is different in Chrome and Firefox:
I'm going to draw other elements (e.g. images, shapes) on the canvas, and I need to make sure the text appears at the same position in all browsers. Is it possible?
Cause
As #iftah says: This mis-alignment is caused by a Firefox bug.
Please add your voice to the Firefox's bug page so they fix it soon.
Workaround
(Unfortunately), The workaround is to draw the text on a second canvas and scan that pixel data to find the topmost & leftmost pixel of the text.
Then draw the text on the main canvas but pulled upward and leftward by the calculated pixel offsets.
Here is annotated code and a Demo:
// canvas vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// test vars
var text='Test';
var fontsize=100;
var fontface='arial';
drawTextAtXY(0,0,text,fontsize,fontface,'black');
function drawTextAtXY(x,y,text,fontsize,fontface,fill){
// find the leftmost & topmost pixel of the text
var minXY=getTextTop(text,fontsize,fontface);
// set the font styles
ctx.textBaseline='top';
ctx.font=fontsize+'px '+fontface;
ctx.fillStyle=fill;
// draw the text
// Pull the text leftward and topward by minX & minY
ctx.fillText(text,x-minXY.x,y-minXY.y);
}
function getTextTop(text,fontsize,fontface){
// create temp working canvas
var c=document.createElement('canvas');
var w=canvas.width;
var h=fontsize*2;
c.width=w;
c.height=h;
var cctx=c.getContext('2d');
// set font styles
cctx.textBaseline='top';
cctx.font=fontsize+'px '+fontface;
cctx.fillStyle='red';
// draw the text
cctx.fillText(text,0,0);
// get pixel data
var imgdata=cctx.getImageData(0,0,w,h);
var d=imgdata.data;
// scan pixel data for minX,minY
var minX=10000000;
var minY=minX;
for(var y=0;y<h;y++){
for(var x=0;x<w;x++){
var n=(y*w+x)*4
if(d[n+3]>0){
if(y<minY){minY=y;}
if(x<minX){minX=x;}
}
}}
// return the leftmost & topmost pixel of the text
return({x:minX,y:minY});
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Text drawn exactly at specified X,Y</h4>
<canvas id="canvas" width=300 height=200></canvas>
You can fix it easily.
you can use textBaseline = "middle";
and must use transform to 50px of top
means:
<canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
window.onload = function() {
var canvas = document.getElementById("mainCanvas");
var ctx = canvas.getContext("2d");
ctx.textBaseline = "middle";
ctx.font = '100px Arial';
ctx.textAlign = 'left';
ctx.fillStyle = 'rgba(0, 0, 0, 1)';
ctx.save();
ctx.transform(1, 0, 0, 1, 0, 50);
ctx.fillText('Test', 0, 0);
ctx.restore();
}
</script>
A another bug is in your code: rgba(0, 0, 0, 255)
fourth number in rgba must be between 0-1 for example 0.75.
why I write .save() and .restore() ?
for reset transform and clear after use it.
Of course you can use
ctx.fillText('Test', 0, 50);
Instead
ctx.save();
ctx.transform(1, 0, 0, 1, 0, 50);
ctx.fillText('Test', 0, 0);
ctx.restore();
This appears to be a bug in Firefox dating back to 2012 and still not fixed!
See https://bugzilla.mozilla.org/show_bug.cgi?id=737852
Edit:
Setting the baseLine to "alphabetic" (the default) results in both Chrome and Firefox having the same vertical location for the text.
Edit:
Unfortunately, the vertical location isn't the only difference between Firefox and Chrome. Changing the string to "Testing" shows clearly that not only is the vertical location different, but also the space between the letters is slightly different - resulting in different width of the text.
If you really must have pixel perfect location AND size of the text maybe you should use Bitmap fonts
As stated in other answer it's some king of bug (or maybe just a different implementation). textBaseline bottom and Y position to 100 can fix it.
<canvas id="mainCanvas" width="320" height="240" style = "border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
window.onload = function() {
var canvas = document.getElementById("mainCanvas");
var ctx = canvas.getContext("2d");
ctx.textBaseline = "bottom";
ctx.font = '100px Arial';
ctx.textAlign = 'left';
ctx.fillStyle = 'rgba(150, 50, 0, 1)';
ctx.fillText('Test', 0, 100);
}
</script>
In general: Use baseline bottom and increase Y position the font size amount

Draw a rotating circle over previous canvas

I'm trying to draw a rotating circle over another canvas.
I've managed to draw the circle, but once it rotates it fills everything inside the rotating radius white and the circle becomes a big continuous circle.
I just want a small circle rotating around the canvas center like a planet around the sun.
This is just example code in my real code the red rectangle is a roulette wheel that rotates in the opposite direction this is the reason why I have two canvas.
I need the (ball) to be white this is why I tried to use .fillstyle and fill() but it doesn't works how I want.
Here is my code:
<html>
<head>
</head>
<body>
<style>
#container { position: relative; }
.canvas { position: absolute; top: 0; left: 0; }
</style>
<div id = 'container'>
<canvas class = "canvas" id= "rectangleCanvas" width = "500" height= "500" style = "z-index : 1" ></canvas>
<canvas class = "canvas" id= "ballCanvas" width = "500" height= "500" style = "z-index : 2"></canvas>
</div>
<script type="text/javascript">
function drawRectangle(){
var canvas = document.getElementById("rectangleCanvas")
ctx = canvas.getContext("2d");
ctx.fillStyle = 'red';
ctx.fillRect(0,0,500,500);
};
drawRectangle();
function drawBall(){
var canvas = document.getElementById("ballCanvas");
if(canvas.getContext){
ctx2 = canvas.getContext("2d");
ctx2.strokeStyle = 'black';
ctx2.fillStyle = 'white';
ctx2.clearRect(0, 0, 500, 500);
ctx2.translate(250,250);
ctx2.rotate(Math.PI / -180);
ctx2.translate(-250, -250);
ctx2.arc(250,65,10,0,2*Math.PI);
ctx2.stroke();
ctx2.fill();
}
}
setInterval(drawBall,5);
</script>
</body>
Can somebody help please?
insert
ctx2.beginPath();
before the ctx2.clearRect(0, 0, 500, 500);
All you need is to redraw the recrangle each step of the timer. This is how canvas works.

html canvas shadow/blur won't go away

There is a shadow on the bottom and right sides of a rectangle I've drawn in the canvas on the upper-left hand corner of my window here:
http://thomasshouler.com/datavis/gugg/ratio.html
I haven't set any positive values to the relevant context attributes (shadowBlur, shadowOffsetY, etc.), so what gives?
Canvas code snippet:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.shadowBlur=0;
ctx.shadowOffsetY=0;
var width = 50;
var height = 4;
var grd=ctx.createLinearGradient(0,0,width,0);
grd.addColorStop(0,'#008000');
grd.addColorStop(0.5,'#CCCCCC');
grd.addColorStop(1,'#FF0000');
ctx.fillStyle=grd;
ctx.fillRect(0,0,width,height);
Any wisdom would be greatly appreciated.
It's related to scaling as the canvas is displayed. Your original fragment with a very small gradient and scaled up http://jsfiddle.net/CBzu4/ clearly shows the blurred outline.
Drawing larger (making sure there is no css scaling) it looks fine: http://jsfiddle.net/CBzu4/1/ and the code is the same as yours, just rearranged:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var width = 50 * 8;
var height = 4 * 8;
var grd=ctx.createLinearGradient(0,0,width,0);
grd.addColorStop(0,'#008000');
grd.addColorStop(0.5,'#FFFF00');
grd.addColorStop(1,'#FF0000');
ctx.fillStyle = grd;
ctx.fillRect(5,5,width,height);
Same code, but this time the canvas scaled up with the embedded style: http://jsfiddle.net/CBzu4/2/
<canvas id="myCanvas" style="border: 1px solid red; width: 120%; height: 120%;" width="600" height="80">
The final version is again the same as yours, no css scaling at all and no blurred outline: http://jsfiddle.net/CBzu4/3/

Categories