Symmetrical pi-based html canvas translating - javascript

In the W3 Schools HTML Canvas Clock drawing tutorial, the clock numbers are translated around the canvas using a static multiplier (.85, shown below).
ctx.translate(0, -radius*0.85);
If you didn't want to use the hardcoded/static .85 value to position the numeral, how would you find the correct position using Sin, or Cos, or other means?

I think here is the answer:
function drawNumerals() {
var numerals = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
angle = 0,
numeralWidth = 0;
numerals.forEach(function(numeral) {
angle = Math.PI/6 * (numeral-3);
numeralWidth = context.measureText(numeral).width;
context.fillText(numeral,
canvas.width/2 + Math.cos(angle)*(HAND_RADIUS) - numeralWidth/2,
canvas.height/2 + Math.sin(angle)*(HAND_RADIUS) + FONT_HEIGHT/3);
});
}
You just have to edit it to your needs.
I found it on Github Gist Draw circle with clock numbers

Seems to scale up correctly when i tried.
Are you removing or omitting the height attribute on the canvas element like this?
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas"
style="background-color:#333">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.15 + "px arial";
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*0.85);
ctx.rotate(-ang);
}
}
</script>
</body>
</html>
The code determines the height it should use for the clock from the elements actual dimensions. If you dont constrain the height and width it will look wrong.
If you see you can double the size of the clock by modifying the height and width attributes of the canvas
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" height="800px" width="800px"
style="background-color:#333">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.15 + "px arial";
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*0.85);
ctx.rotate(-ang);
}
}
</script>
</body>
</html>

Related

Creating circular time range selection using HTML5 canvas?

For one of my application i am creating circular time range selector widget.I have created the clock dial using html canvas.I need help to select time range by touch and drag on the dial as shown in the imageCircular clock dial. When clicked on the "Add" button, the previous selection should be cleared. Next time i should be able to set new range. this continues. The range value should be stored in a variable. It should work on the mobile device. Your help would be appreciated. http://codepen.io/harish_s/pen/ggpoBq
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = 180;
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.strokeStyle = "rgb(207,207,207)";
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.lineWidth = 60;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, 150, 0, 2*Math.PI);
ctx.fillStyle = "rgb(243,244,244)";
ctx.fill();
ctx.beginPath();
ctx.arc(0, 0, 50, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.font = '25pt Calibri';
ctx.fillStyle = 'white';
ctx.fillText('SET', -25, 10);
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.20 + "px arial";
ctx.fillStyle = '#000';
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*1);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*1);
ctx.rotate(-ang);
}
}
#canvas{
position: absolute;
width: 50%;
left: 35%;
top:5%;
}
<canvas id="canvas" width="1000" height="500">
</canvas>

building a clock with html canvas

I want to create a clock using HTML5, canvas and JavaScript.
However I don't understand why when I run the following code with Sublime I can't see anything. I tried to see something using both Internet Explorer and Google Chrome.
Maybe the error is in the code?
This is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Clock</title>
<!--<script src="clockJS.js" ></script>-->
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<img id="myImage" />
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
ctx.strokeStyle = '28d1fa';
ctx.linewidth = 17;
ctx.lineCap = "round";
ctx.shadowBlur = 15;
ctx.shadowColor = '28d1fa';
function degToRad(degree) {
var factor = Math.PI / 180;
return degree * factor;
}
function renderTime() {
var now = new Date();
var today = now.toDateString();
var time = today.toLocaleTimeString();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = now.getSeconds();
var milliseconds = now.getMilliseconds();
var newSeconds = seconds + (milliseconds/1000);
//Background
gradient = ctx.createRadioGradient(250, 250, 5, 250, 250, 300);
gradient.addColorStop(0, '09303a');
gradient.addColorStop(1, 'black');
ctx.fillStyle = gradient;
//ctx.fillStyle = '333333';
ctx.fillRect(0, 0, 500, 500);
//Hours
ctx.beginPath();
ctx.arc(250, 250, 200, degToRad(270), degToRad((hours*15)-90));
ctx.stroke();
//Minutes
ctx.beginPath();
ctx.arc(250, 250, 170, degToRad(270), degToRad((minutes*6)-90));
ctx.stroke();
//Seconds
ctx.beginPath();
ctx.arc(250, 250, 140, degToRad(270), degToRad((newSeconds*6)-90));
ctx.stroke();
//Date
ctx.font = "23px Arial bold";
ctx.fillStyle = '28d1fa';
ctx.fillText(today, 175, 250);
//Time
ctx.font = "23px Arial";
ctx.fillStyle = '28d1fa';
ctx.fillText(time, 175, 280);
var dataUrl = canvas.toDataUrl();
document.getElementById('myImage').src = dataUrl;
}
setInterval(renderTime, 40);
</script>
</body>
</html>
Can someone help me?
Change this lines:
var time = today.toLocaleTimeString();
gradient = ctx.createRadioGradient(250, 250, 5, 250, 250, 300);
var dataUrl = canvas.toDataUrl();
To this:
var time = now.toLocaleTimeString();
gradient = ctx.createRadialGradient(250, 250, 5, 250, 250, 300);
var dataUrl = canvas.toDataURL();
That should get you something into the screen. I recommend you using Chrome's developer console to see all the JavaScript errors.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
setInterval(drawClock, 1000);
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
drawTime(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.15 + "px arial";
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*0.85);
ctx.rotate(-ang);
}
}
function drawTime(ctx, radius){
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
//hour
hour=hour%12;
hour=(hour*Math.PI/6)+
(minute*Math.PI/(6*60))+
(second*Math.PI/(360*60));
drawHand(ctx, hour, radius*0.5, radius*0.07);
//minute
minute=(minute*Math.PI/30)+(second*Math.PI/(30*60));
drawHand(ctx, minute, radius*0.8, radius*0.07);
// second
second=(second*Math.PI/30);
drawHand(ctx, second, radius*0.9, radius*0.02);
}
function drawHand(ctx, pos, length, width) {
ctx.beginPath();
ctx.lineWidth = width;
ctx.lineCap = "round";
ctx.moveTo(0,0);
ctx.rotate(pos);
ctx.lineTo(0, -length);
ctx.stroke();
ctx.rotate(-pos);
}
<canvas id="canvas" width="400" height="400"
style="background-color:#333">
</canvas>

How can I stop filling my circle at some point?

How can I stop filling my circle at some point?
Like only fill 50% of the circle or 25% of the circle and leave the left over. Just like progress bar.
below is the code Im using but it is filling entire circle.
Kindly please give me suggestions.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineCap = "round";
var y = ch - 10;
var drawingColor = "#0092f9";
animate();
function animate() {
if (y > 0) {
requestAnimationFrame(animate);
}
ctx.clearRect(0, 0, cw, ch);
ctx.save();
drawContainer(0, null, null);
drawContainer(15, drawingColor, null);
drawContainer(7, "white", "white");
ctx.save();
ctx.clip();
drawLiquid();
ctx.restore();
ctx.restore();
y--;
}
function drawLiquid() {
ctx.beginPath();
ctx.moveTo(0, y);
for (var x = 0; x < 300; x += 1) {
ctx.quadraticCurveTo(x + 5, y+5, x + 5, y);
}
ctx.lineTo(cw, ch);
ctx.lineTo(0, ch);
ctx.closePath();
ctx.fillStyle = drawingColor;
ctx.fill();
}
function drawContainer(linewidth, strokestyle, fillstyle) {
ctx.beginPath();
ctx.arc(cw/2, ch/2,cw/2-30,0,2*Math.PI);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokestyle;
ctx.stroke();
if (fillstyle) {
ctx.fillStyle = fillstyle;
ctx.fill();
}
}
<canvas id="canvas" width=200 height=200></canvas>
I know zit at javascript but: Just change the limit of y in animate. I put 100 instead of 0 and it fills half the circle.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineCap = "round";
var y = ch - 10;
var drawingColor = "#0092f9";
animate();
function animate() {
if (y > 100) {
requestAnimationFrame(animate);
}
ctx.clearRect(0, 0, cw, ch);
ctx.save();
drawContainer(0, null, null);
drawContainer(15, drawingColor, null);
drawContainer(7, "white", "white");
ctx.save();
ctx.clip();
drawLiquid();
ctx.restore();
ctx.restore();
y--;
}
function drawLiquid() {
ctx.beginPath();
ctx.moveTo(0, y);
for (var x = 0; x < 300; x += 1) {
ctx.quadraticCurveTo(x + 5, y+5, x + 5, y);
}
ctx.lineTo(cw, ch);
ctx.lineTo(0, ch);
ctx.closePath();
ctx.fillStyle = drawingColor;
ctx.fill();
}
function drawContainer(linewidth, strokestyle, fillstyle) {
ctx.beginPath();
ctx.arc(cw/2, ch/2,cw/2-30,0,2*Math.PI);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokestyle;
ctx.stroke();
if (fillstyle) {
ctx.fillStyle = fillstyle;
ctx.fill();
}
}
<canvas id="canvas" width=200 height=200></canvas>

Animating an emoticon to wink with animation in HTML5 canvas

I am attempting to animate an emoticon that was previously drawn in canvas. I am attempting to do a draw and clear using frames following a tutorial but am not getting results. I have 6 frames of the emoticon coded and am unsure how to include this within the code. This is what I have so far:
<!DOCTYPE html>
<html>
<head>
<title>Adding Animation</title>
<style>
canvas {
border: 3px #CCC solid;
}
</style>
</head>
<body>
<div id="container">
<canvas id="myCanvas" height="1200" width="900"></canvas>
</div>
<script>
var mainCanvas = document.querySelector("#myCanvas");
var mainContext = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
function drawCircle() {
mainContext.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
mainContext.fillStyle = "#EEEEEE";
mainContext.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
ctx.closePath();
//The eyes
//Left
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(850, 405, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
drawCircle();
</script>
</body>
</html>
I am unsure if I am even on the right track as I have a difficult time with animation. Does anyone have any suggestions they can give me guidance on?
You have 2 names for the context: mainContext & ctx.
Change it to a single name and your face is "smiley" ! :-)
...
To animate:
Use a requestAnimationFrame loop to change the scaleY value in scale(scaleX,scaleY) over time.
Here's annotated code and a Demo:
var mainCanvas = document.querySelector("#myCanvas");
var ctx = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
ctx.translate(-425,-275);
drawCircle(1);
// global var to hold pct the left eye is open
// 1==fully open, 0==fully closed
var scaley=1;
var direction=-1;
// request 1 animate() loop
requestAnimationFrame(animate);
function animate(time){
// draw smiley with the specified eye openness
drawCircle(scaley);
scaley+=.02*direction;
if(scaley<0){
scaley=0;
direction=1;
}
if(scaley>1){
scaley=1;
direction=-1;
}
requestAnimationFrame(animate);
}
function drawCircle(scaleY) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
ctx.fillStyle = "#EEEEEE";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
//The eyes
//Left
ctx.save();
// move the [0,0] origin to the left eye's centerpoint
ctx.translate(550,405);
// close the left eye by the specified scaleY
ctx.scale(0.65, scaleY);
ctx.beginPath();
// draw the left eye (arc) at 0,0 because
// we translated the origin to [550,405] earlier
ctx.arc(0, 0, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
<canvas id="myCanvas" height="1200" width="900"></canvas>
You never declared a ctx variable.
Change all your mainContext by ctx and it should be working fine.

Troubles with craftyjs png sprite and custom drawed figure?

i have following code with newest craftyjs:
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin:0;
}
</style>
<script type="text/javascript" src="crafty.js"></script>
<script>
Crafty.c("Planet", {
Planet: function(radius, map) {
this.radius = radius;
this.map = map;
return this;
},
draw: function() {
var ctx = Crafty.canvas.context;
var x = 100;
var y = 100;
var offsetX = 0;
var map = this.map;
ctx.save();
ctx.beginPath();
ctx.arc(x, y, this.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.clip();
var scale = (this.radius * 2) / map.height;
ctx.drawImage(map, 0, 0, map.width, map.height, x - this.radius - offsetX * scale, y - this.radius, map.width * scale, map.height * scale);
ctx.beginPath();
ctx.arc(x, y, this.radius * 1.04, Math.PI * 0.70, Math.PI * 1.30, false);
ctx.shadowColor = "black";
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 5;
ctx.stroke();
ctx.beginPath();
ctx.arc(x, y, this.radius * 1.04, -Math.PI * 0.30, Math.PI * 0.30, false);
ctx.shadowColor = "black";
ctx.shadowBlur = 5;
ctx.shadowOffsetX = -5;
ctx.stroke();
ctx.restore();
console.log('drawing');
}
});
Game = {
// Initialize and start our game
start: function() {
// Start crafty and set a background color so that we can see it's working
Crafty.init(500,500);
Crafty.scene('Game', function() {
Crafty.load(["1.jpg", "ship.png"],
function() {
Crafty.sprite("ship.png", {player_spr:[0,0, 48,48]});
Crafty.background("url('space.jpg')");
Crafty.e("2D, Canvas, Planet")
.Planet(40, Crafty.asset('1.jpg'));
var b2d = Crafty.e("2D, Canvas, player_spr, Actor, Fourway")
.multiway({W: -90, S: 90, D: 0, A: 180})
.attr({z: 4});
Crafty.viewport.clampToEntities = false;
Crafty.viewport.follow(b2d,0,0);
});
});
Crafty.scene('Game');
}
}
window.onload = Game.start;
</script>
</head>
<body>
</body>
</html>
Textures is:
File: 1.jpg
File: ship.png
The result canvas rendered image:
This is a strange bug! What i can to do with it?
Crafty sprite conflict with custom drawings... (it shows sprite transparency)
CraftyJS Github version fix this issue!
Just compile that with grunt.
Thank you for your answers!

Categories