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>
Related
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
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
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.
I have a bunch of canvas elements in my html file like so:
<canvas id="one"></canvas>
<canvas id="two"></canvas>
I'm using the arrow keys to move an object around #one, but I want to have that object "appear" in #two when it hits a point on #one, e.g. x=150 and y=55.
I tried using the jQuery focus() method when that coordinate was triggered, but the object stayed in #one. Any suggestions?
To make a canvas element focus-able, and therefor able to capture key-strokes, you simply add a tabIndex attribute to the element:
Now you can TAB between the elements and bind event-listeners to the canvas element directly.
Inside the handler you simply draw to the canvas you want based on whatever criteria you require.
Example
var canvases = document.querySelectorAll("canvas"),
i = 0;
while(canvas = canvases[i++]) {
canvas.width = 200;
canvas.tabIndex = 0;
canvas.addEventListener("keyup", process);
}
function process(e) {
var ctx = this.getContext("2d");
ctx.clearRect(0, 0, 200, 150);
ctx.fillText("KEY HERE: " + e.keyCode, 10, 10);
}
canvas {border:1px solid #999;margin:0 2px 2px 0; display:inline-block}
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
Rather than changing focus when that coordinate is hit, I think you need to change the <canvas> element (and associated context) you're drawing to, e.g.:
var theCanvas = document.getElementById("one");
var context = theCanvas.getContext("2d");
... your canvas drawing code here ...
if (posX < 150 && posY < 55) {
//clear the top canvas
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
// switch to the second canvas
theCanvas = document.getElementById("two");
context = theCanvas.getContext("2d");
}
Here's a fiddle that borrows code from rectangleworld.com. Drag the circle into the upper left corner of the top canvas, and it should appear in the lower canvas.
JSFiddle
There is no such thing as focus on a canvas for this purpose.
Your both canvases need to listen for keypresses, while your code needs to decide what to draw on which canvas.
var canvas1 = document.getElementById("one");
var context1 = canvas1.getContext("2d");
var canvas2 = document.getElementById("two");
var context2 = canvas2.getContext("2d");
canvas1.width = canvas1.height = canvas2.width = canvas2.height = 50;
var obj = {x: 5, y: 5, w: 5};
function draw() {
canvas1.width = canvas2.width = canvas2.width;
context1.beginPath();
context1.rect(obj.x, obj.y, obj.w, obj.w);
context1.fillStyle = 'green';
context1.fill();
context2.beginPath();
context2.rect(obj.x - canvas1.width, obj.y, obj.w, obj.w);
context2.fillStyle = 'blue';
context2.fill();
}
window.addEventListener('keydown', function() {
if(++obj.x > canvas1.width + canvas2.width) obj.x = 5;
draw();
});
draw();
canvas {border: 1px solid black; margin: 10px;}
<canvas id="one"></canvas>
<canvas id="two"></canvas>
<p>Click inside this window to get focus and then <br>press any key to move the object to the right</p>
Of course, this can be optimized not to redraw both canvases on each tick, but you get the idea.
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/