Drawing anti-aliased round-capped line with canvas - javascript

I'm trying to create a stylised timeline for an audio player. I would like to draw a nice thick line with round caps at the ends. I thought it would be relatively trivial to do this with canvas. However, I'm finding that at least in Chrome on Mac OS, the lines are not anti-aliased; and also (possibly as a consequence) the line caps are elongated, rather than perfect half-circles.
What perplexes me is that when I view the W3 Schools example the line is anti-aliased, with the expected caps. This makes me wonder if something in my code is triggering a non-anti-aliased mode in the browser...
Here is my full code:
<html>
<head>
<style>
body {
background-color: #212b69;
}
.centering {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#timeline {
width: 60%;
height: 50px;
}
</style>
</head>
<body>
<div class="centering">
<canvas id="timeline" />
</div>
<script type="text/javascript">
var timeline = document.getElementById('timeline');
var ctx = timeline.getContext('2d');
var centrline = timeline.height/2;
// ctx.translate(0.5, 0.5); // I have tried the half-pixel trick
// line settings
ctx.lineCap = "round";
ctx.lineWidth = 30;
ctx.strokeStyle = "white";
// draw test stroke
ctx.beginPath();
ctx.moveTo(20, centrline);
ctx.lineTo(60, centrline+10); // offset to show aliasing of edges
ctx.stroke();
</script>
</body>
</html>
My result:
Compared with W3Schools result:
I understand from these posts that vector anti-aliasing is determined by the browser. Note also that I've tried the trick of translating the canvas by a half-pixel to kick it into anti-aliasing mode. If there is no way to get canvas to get what I want it to do, is there some other method? Given that I only want to create a relatively simple shape...

Just remove the following css rule and the shape will stop skewing.
#timeline {
width: 60%;
height: 50px;
}
Here's a working example without skew: enter link description here
var timeline = document.getElementById('timeline');
var ctx = timeline.getContext('2d');
var centrline = timeline.height/2;
// ctx.translate(0.5, 0.5); // I have tried the half-pixel trick
// line settings
ctx.lineCap = "round";
ctx.lineWidth = 30;
ctx.strokeStyle = "white";
// draw test stroke
ctx.beginPath();
ctx.moveTo(20, centrline);
ctx.lineTo(60, centrline+10); // offset to show aliasing of edges
ctx.stroke();
body {
background-color: #212b69;
}
.centering {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
<div class="centering">
<canvas id="timeline" />
</div>

Related

How to center the "fillRect" -methode relative to canvas element

I want to center the blue rectangle made with fillrec relative to the size of the canvas (aqua). I didnt find a solution yet, due to my newbie knowledge working with JS. And my little research and trying things out didn't help either. I was hoping for a little guidance regarding that matter.
canvas {
padding: 0;
margin: auto;
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: aqua;
}
<html>
<link rel="stylesheet" href="canvas.css">
<body>
<canvas width="800", height="800", id="1" > </canvas>
<script>
let canvas = document.querySelector('canvas');
let context = canvas.getContext('2d');
context.fillStyle = "Blue"
context.fillRect(15, 15, 400, 400);
</script>
</body>
</html>
Uhhh if you canvas is always 800 and that square always 400 you can do
context.fillRect(200, 200, 400, 400);
It just plus and minus
Or you can check this out
How do I center a rectangle on a canvas

how can I make balls resize automatically using .arc

I'm trying to make a ball made by .arc function grow with time, and i want to be able to specify the duration. this is where I'm stuck:
function start(){
var ball1,ball2,ball3,ball4;
var ball=document.getElementById("MyCanvas");
ball1=ball.getContext("2d");
ball1.fillStyle="yellow";
ball1.beginPath();
ball1.arc(95,50,40,0,2*Math.PI);
ball1.fill();
scaling(ball1);
}
function scaling(ball){
ball.beginPath();
ball.arc(95,50,100,0,2*Math.PI);
}
window.addEventListener("load",start,false);
body{background-color:white;}
<canvas id="MyCanvas" width="1000" height="500" style="border:black 1px solid"></canvas>
so is there a way to do it with .arc? and if not, any other way to do it? (like border-radius:50%).
Really, ball should contain all the data for... a ball. Instead you set it equal to the canvas:
var ball = document.getElementById("MyCanvas");
...and use ball1 for the context
ball1 = ball.getContext("2d");
Firstly, you should rename those variables to something else.
var canvas, context;
var ball;
function start(){
canvas = document.getElementById("MyCanvas");
context = canvas.getContext("2d");
}
window.addEventListener("load",start,false);
and then you need to think about an animation loop and all sorts of other things...
Perhaps instead you should think about something much simpler like using pure CSS.
.circle{
width: 50px;
height: 50px;
transition: all 1s;
background: yellow;
border-radius: 50%;
cursor: pointer;
}
.circle:hover{
width: 100px;
height: 100px;
}
<div class="circle"></div>

How do I add editable text fields on an image?

I am trying to figure out a way to duplicate what they have here:
https://realsteelcenter.com/collections/monograms/products/family-name-circle-monogram
I know they're using Canvas but I am still very new to JS so I am having a hard time figuring this out.
There are a lot of websites using something like this and I am surprised that I have not found anything on this. I was really hoping to have found YouTube video that explains how to do this, but no luck.
Any advice that would push me in the right direction is appreciated.
Start off with an input type="text" field in which you can enter the name and a canvas to render everything in. In JavaScript listen for the input event on the input so you can update the current text every time the value of the input has been changed.
Now in your canvas you'll want to output the text value that has been set by your input. You could do this in the event handler of your input event. So everytime the user changes the input clear the canvas (otherwise it will draw over the previous word) with the clearRect method of the context and then draw the word in the canvas with the fillText method. You'll have to do some extra math to calculate the correct position of the text and can do that with the measureText method.
I've added an example below which will hopefully get you started in the right direction.
const text = document.getElementById('name');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const fontSize = 32;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
ctx.font = `${fontSize}px sans-serif`;
text.addEventListener('input', function(event) {
const textValue = event.target.value;
const { width } = ctx.measureText(textValue);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillText(textValue, (canvas.width / 2) - (width / 2), (canvas.height / 2) + (fontSize / 2));
});
#canvas {
display: block;
width: 400px;
height: 250px;
border: 1px solid black;
margin-bottom: 30px;
}
<canvas id="canvas"></canvas>
<label for="name">Enter a name</label>
<input type="text" id="name">
Well using jQuery that's easy to do ! You can start with something like following :
<input id='myText' type='text'/>
<div class="container">
<img src="img_snow_wide.jpg" alt="Snow" style="width:100%;">
<div class="centered">Centered</div>
</div>
CSS:
.container {
position: relative;
text-align: center;
color: white;
}
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
jQuery:
$('#myText').on('input', function() {
$('.centered').empty().html($(this).val);
}

Button to go from page to page

So I've looked around at page to page functions and have seen mixed techniques.
I have a full canvas animation with clicking and keyboard functionality and all, but I want to have a screen prior that is blank and just has a button that says Start.
Would I have to make a new html file? Or a function that clears the canvas and has the button on it that transitions to the animation? And how does the general set up for that look like?
Same Page Solution
Create a div container. Make everything in the container have display none except for the start button. When the start button is pressed, a JS function is run which sets everything in the container to the proper display property and makes the start button invisible. Not that manipulating the DOM is a costly operation and should be done sparingly. http://jsfiddle.net/qrj3Lxb5/1/
HTML
<body>
<div>
<canvas id="myCanvas"></canvas>
<button id="btn" onclick="start(this.id)">Start</button>
</div>
</body>
CSS
#myCanvas {
display: none
}
#btn {
margin: 0 auto;
}
div {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center
}
html {
height: 100%
}
body {
height: 100%
}
JS
var start = function(id) {
var c = document.getElementById("myCanvas");
c.style.display = "inline-block";
var btn = document.getElementById(id);
btn.style.display = "none";
}
document.addEventListener("DOMContentLoaded", function(event) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(95, 50, 40, 0, 2 * Math.PI);
ctx.stroke();
});
You can alternatively have a new html page for the canvas. Up to you.

Canvas element lines aren't straight?

I am trying to draw an element on a canvas but whenever I draw the canvas, the lines turn out faded and not bold. I don't understand why this happening with my code.. whenever I try it with code from W3schools it turns out fine. Here is my code and an image below.
<!DOCTYPE html>
<html>
<head>
<title>Talk Walk</title>
<style type="text/css">
#canvas {
position: absolute;
top: 0px;
left: 0px;
height: 500px;
width: 750px;
background-color: blue;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0,150,75);
</script>
</body>
</html>
The problem here is that there's some aliasing going on when you're drawing the rectangles.
This is happening because the "edge" of the green rectangle isn't drawn exactly on a pixel. Normally, you wouldn't really see it, but since you're stretching out the canvas by using css to set it's width and height, you get this result:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0,150,75);
#canvas {
height: 500px;
width: 750px;
background-color: blue;
}
<canvas id="canvas"></canvas>
To fix that, use the width and height HTML attributes, instead of css:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0,150,75);
#canvas {
background-color: blue;
}
<canvas id="canvas" height="500" width="750"></canvas>
This properly scales the canvas, so the aliasing (while still there if you zoom in) doesn't scale up.

Categories