I made a circular progressbar for my office work time. It also shows a time interval for lunch time. On fridays our work time is shorter by 1 hour. And the problem is on fridays the lunch time interval is placed wrong on the progressbar. It's closer to the end of worktime than it should be. Here's the code:
var bar = document.getElementById('progressbar');
createProgressBar = function(bar) {
var options = {
start: 0,
width: bar.getAttribute('data-width'),
height: bar.getAttribute('data-height'),
percent: 100,
lineWidth: bar.getAttribute('data-linewidth')
},
canvas = document.createElement('canvas'),
paper = canvas.getContext('2d'),
span = document.createElement('span'),
radius = (options.width - options.lineWidth) / 2,
color = paper.createLinearGradient(0, 0, options.width, 0),
end = new Date(),
today = new Date(),
breakStart = new Date(),
breakEnd = new Date();
breakStart.setHours(12, 0, 0);
breakEnd.setHours(13, 0, 0);
if(today.getDay() == 5) {
var full = 480;
end.setHours(17, 00, 0);
}
else {
var full = 540;
end.setHours(18, 0, 0);
}
span.style.width = bar.style.width = options.width + 'px';
span.style.height = bar.style.height = options.height + 'px';
canvas.width = options.width;
canvas.height = options.height;
span.style.lineHeight = options.height + 'px';
span.style.color = 'white';
color.addColorStop(0, '#ff5349');
color.addColorStop(0.5, '#ff5349');
color.addColorStop(1.0, '#ff5349');
bar.appendChild(span);
bar.appendChild(canvas);
function updateTime() {
var now = new Date(),
remaining = end - now,
_second = 1000,
_minute = _second * 60,
_hour = _minute * 60,
_day = _hour * 24,
hours = Math.floor((remaining % _day) / _hour),
minutes = Math.floor((remaining % _hour) / _minute),
seconds = Math.floor((remaining % _minute) / _second),
current = (full - (hours * 60) - minutes) / full * 100,
step = 1.5 + (2 * current / 100),
startb = (breakStart.getHours() * 60 + breakStart.getMinutes()) / full * 100,
endb = (breakEnd.getHours() * 60 + breakEnd.getMinutes()) / full * 100,
startBr = 1.5 + (2 * startb / 100),
endBr = 1.5 + (2 * endb / 100);
createCircle(options, paper, radius, color, Math.PI * 1.5, Math.PI * step);
createBreak(options, paper, radius, color, Math.PI * startBr, Math.PI * endBr);
};
updateTime();
},
createCircle = function(options, paper, radius, color, start, end) {
paper.clearRect(
options.width / 2 - radius - options.lineWidth,
options.height / 2 - radius - options.lineWidth,
radius * 2 + (options.lineWidth * 2),
radius * 2 + (options.lineWidth * 2)
);
paper.beginPath();
paper.arc(options.width / 2, options.height / 2, radius, 0, Math.PI * 2, false);
paper.strokeStyle = 'white';
paper.lineCap = 'butt';
paper.lineWidth = options.lineWidth;
paper.stroke();
paper.closePath();
},
createBreak = function(options, paper, radius, color, start, end) {
paper.beginPath();
paper.arc(options.width / 2, options.height / 2, 171, start, end, false);
paper.strokeStyle = 'orange';
paper.lineCap = 'butt';
paper.lineWidth = 19;
paper.stroke();
paper.closePath();
};
createProgressBar(bar);
body {
background-color: #333;
padding: 0;
font-family: 'sans serif', Verdana, Tahoma, Helvetica;
}
canvas {
position: absolute;
display: block;
left: 0;
top: 0;
}
#progressbar {
position: fixed;
top: 50%;
left: 50%;
margin-top: -180px;
margin-left: -180px;
}
<div id="progressbar" data-width="360" data-height="360" data-linewidth="16"></div>
I can post some screenshots if necessary to make it clear what I mean
Related
I found this countdown timer that I would like to include in one of my modules. Unfortunately I can't figure out how to use the timer multiple times on one page (the classic one - only the last timer is running) - I also know that probably (?) the go function should be the reason - but currently I can't figure out how to instantiate the timer.
What I have so far (but it does not work):
Codepen Original: https://codepen.io/l422y/pen/cdwhm
I have in-depth JS basic knowledge but this is still beyond my horizon.
var ringer = {
//countdown_to: "10/31/2014",
//countdown_to: targetdaytime,
rings: {
'DAYS': {
s: 86400000, // mseconds in a day,
max: 365
},
'HOURS': {
s: 3600000, // mseconds per hour,
max: 24
},
'MINUTES': {
s: 60000, // mseconds per minute
max: 60
},
'SECONDS': {
s: 1000,
max: 60
},
'MICROSEC': {
s: 10,
max: 100
}
},
r_count: 5,
r_spacing: 10, // px
r_size: 100, // px
r_thickness: 2, // px
update_interval: 11, // ms
init: function(container, targetdaytime) {
$r = ringer;
$r.cvs = document.createElement('canvas');
$r.size = {
w: ($r.r_size + $r.r_thickness) * $r.r_count + ($r.r_spacing * ($r.r_count - 1)),
h: ($r.r_size + $r.r_thickness)
};
$r.cvs.setAttribute('width', $r.size.w);
$r.cvs.setAttribute('height', $r.size.h);
$r.ctx = $r.cvs.getContext('2d');
$(container).append($r.cvs);
$r.cvs = $($r.cvs);
$r.ctx.textAlign = 'center';
$r.actual_size = $r.r_size + $r.r_thickness;
$r.countdown_to_time = new Date(targetdaytime).getTime();
$r.cvs.css({
width: $r.size.w + "px",
height: $r.size.h + "px"
});
$r.go();
},
ctx: null,
go: function() {
var idx = 0;
$r.time = (new Date().getTime()) - $r.countdown_to_time;
for (var r_key in $r.rings) $r.unit(idx++, r_key, $r.rings[r_key]);
setTimeout($r.go, $r.update_interval);
},
unit: function(idx, label, ring) {
var x, y, value, ring_secs = ring.s;
value = parseFloat($r.time / ring_secs);
$r.time -= Math.round(parseInt(value)) * ring_secs;
value = Math.abs(value);
x = ($r.r_size * .5 + $r.r_thickness * .5);
x += +(idx * ($r.r_size + $r.r_spacing + $r.r_thickness));
y = $r.r_size * .5;
y += $r.r_thickness * .5;
// calculate arc end angle
var degrees = 360 - (value / ring.max) * 360.0;
var endAngle = degrees * (Math.PI / 180);
$r.ctx.save();
$r.ctx.translate(x, y);
$r.ctx.clearRect($r.actual_size * -0.5, $r.actual_size * -0.5, $r.actual_size, $r.actual_size);
// first circle
$r.ctx.strokeStyle = "rgba(128,128,128,0.2)";
$r.ctx.beginPath();
$r.ctx.arc(0, 0, $r.r_size / 2, 0, 2 * Math.PI, 2);
$r.ctx.lineWidth = $r.r_thickness;
$r.ctx.stroke();
// second circle
$r.ctx.strokeStyle = "rgba(253, 128, 1, 0.9)";
$r.ctx.beginPath();
$r.ctx.arc(0, 0, $r.r_size / 2, 0, endAngle, 1);
$r.ctx.lineWidth = $r.r_thickness;
$r.ctx.stroke();
// label
$r.ctx.fillStyle = "#ffffff";
$r.ctx.font = '12px Helvetica';
$r.ctx.fillText(label, 0, 23);
$r.ctx.fillText(label, 0, 23);
$r.ctx.font = 'bold 40px Helvetica';
$r.ctx.fillText(Math.floor(value), 0, 10);
$r.ctx.restore();
}
}
jQuery(document).ready(function($) {
new ringer.init('#cd-container-1', '12/24/2020');
new ringer.init('#cd-container-2', '10/31/2020');
});
body,
html {
width: 100%;
height: 100%;
margin: 0;
}
html {
display: table;
}
canvas {
width: 900px;
height: 200px;
display: block;
position: relative;
background: transparent;
margin: 40px auto;
}
body {
background: #000000;
background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/12399/free-pumpkin-wallpaper-25771-26455-hd-wallpapers.jpg");
background-position: top center;
background-size: cover;
color: #fff;
margin: 0;
padding: 0;
overflow: hidden;
display: table-cell;
vertical-align: middle;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="cd-container-1"></div>
<div id="cd-container-2"></div>
It is because your object is not a JS class, therefore it is not possible to create instances of it. Its basically a single instance of a class.
I transformed it to a class for you, so now you can initialize multiple instances of it:
class Ringer { // <-- make class from it
rings = { // <-- object properties to class fields
'DAYS': {
s: 86400000, // mseconds in a day,
max: 365
},
'HOURS': {
s: 3600000, // mseconds per hour,
max: 24
},
'MINUTES': {
s: 60000, // mseconds per minute
max: 60
},
'SECONDS': {
s: 1000,
max: 60
},
'MICROSEC': {
s: 10,
max: 100
}
};
r_count = 5;
r_spacing = 10; // px
r_size = 100; // px
r_thickness = 2; // px
update_interval = 11; // ms
ctx = null;
init (container, targetdaytime) { // <-- functions to class methods
this.cvs = document.createElement('canvas'); // <-- just access this instead of reference to the object
this.size = {
w: (this.r_size + this.r_thickness) * this.r_count + (this.r_spacing * (this.r_count - 1)),
h: (this.r_size + this.r_thickness)
};
this.cvs.setAttribute('width', this.size.w);
this.cvs.setAttribute('height', this.size.h);
this.ctx = this.cvs.getContext('2d');
$(container).append(this.cvs);
this.cvs = $(this.cvs);
this.ctx.textAlign = 'center';
this.actual_size = this.r_size + this.r_thickness;
this.countdown_to_time = new Date(targetdaytime).getTime();
this.cvs.css({
width: this.size.w + "px",
height: this.size.h + "px"
});
this.go();
}
go() {
var idx = 0;
this.time = (new Date().getTime()) - this.countdown_to_time;
for (var r_key in this.rings) this.unit(idx++, r_key, this.rings[r_key]);
setTimeout(() => this.go(), this.update_interval); // () => this.go() instead of $r.go
}
unit(idx, label, ring) {
var x, y, value, ring_secs = ring.s;
value = parseFloat(this.time / ring_secs);
this.time -= Math.round(parseInt(value)) * ring_secs;
value = Math.abs(value);
x = (this.r_size * .5 + this.r_thickness * .5);
x += +(idx * (this.r_size + this.r_spacing + this.r_thickness));
y = this.r_size * .5;
y += this.r_thickness * .5;
// calculate arc end angle
var degrees = 360 - (value / ring.max) * 360.0;
var endAngle = degrees * (Math.PI / 180);
this.ctx.save();
this.ctx.translate(x, y);
this.ctx.clearRect(this.actual_size * -0.5, this.actual_size * -0.5, this.actual_size, this.actual_size);
// first circle
this.ctx.strokeStyle = "rgba(128,128,128,0.2)";
this.ctx.beginPath();
this.ctx.arc(0, 0, this.r_size / 2, 0, 2 * Math.PI, 2);
this.ctx.lineWidth = this.r_thickness;
this.ctx.stroke();
// second circle
this.ctx.strokeStyle = "rgba(253, 128, 1, 0.9)";
this.ctx.beginPath();
this.ctx.arc(0, 0, this.r_size / 2, 0, endAngle, 1);
this.ctx.lineWidth = this.r_thickness;
this.ctx.stroke();
// label
this.ctx.fillStyle = "#ffffff";
this.ctx.font = '12px Helvetica';
this.ctx.fillText(label, 0, 23);
this.ctx.fillText(label, 0, 23);
this.ctx.font = 'bold 40px Helvetica';
this.ctx.fillText(Math.floor(value), 0, 10);
this.ctx.restore();
}
}
jQuery(document).ready(function($) {
(new Ringer()).init('#cd-container-1', '12/24/2020'); // <-- init new instance with new Ringer() and call init() on that instance
(new Ringer()).init('#cd-container-2', '10/31/2020');
});
body,
html {
width: 100%;
height: 100%;
margin: 0;
}
html {
display: table;
}
canvas {
width: 900px;
height: 200px;
display: block;
position: relative;
background: transparent;
margin: 40px auto;
}
body {
background: #000000;
background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/12399/free-pumpkin-wallpaper-25771-26455-hd-wallpapers.jpg");
background-position: top center;
background-size: cover;
color: #fff;
margin: 0;
padding: 0;
overflow: hidden;
display: table-cell;
vertical-align: middle;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="cd-container-1"></div>
<div id="cd-container-2"></div>
If you want to read more into classes and how they work, I found a cool little summary here: https://www.digitalocean.com/community/tutorials/js-objects-prototypes-classes
Simple: wrap it in a function.
function createRinger() {
const ringer = { ... }
return ringer
}
const ringer1 = createRinger()
const ringer2 = createRinger()
ringer1.init(target1, targetDateTime1)
ringer2.init(target2, targetDateTime2)
There are other ways that improve efficiency of memory use (eg use the prototype chain), but unless you have lots of timers on a page, these approaches are moot.
I am developing a game in ionic 4 'spin the wheel'. so far I am able to spin the wheel which stops randomly on any of the sections. Can anyone help me with setting probability to sections so that users will have fewer chances to win? I would like to pre-define each section with some percentage value. for eg section with 0 will have 50% 4 will have 10% etc, and the greatest value will have a 1% chance to win. below code, I have tried.
SpinWheel.ts
export class SpinWheel {
#ViewChild('myCanvas', { static: false }) myCanvas: ElementRef;
colors = ["#2a8251", "#dc0927", "#414243", "#dc0927", "#2E2C75",
"#dc0927", "#414243", "#dc0927", "#2E2C75",
"#dc0927"];
restaraunts = ["0", "32", "15", "19",
"4", "21", "2", "25",
"17", "34"];
startAngle = 0;
arc = 2 * Math.PI / 10;
spinTimeout = null;
spinArcStart = 10;
spinTime = 0;
spinTimeTotal = 0;
ctx;
spinAngleStart;
constructor() {
}
ngOnInit() {
}
ngAfterViewInit(): void {
this.draw();
}
draw() {
this.drawRouletteWheel();
}
drawRouletteWheel() {
var canvas = document.getElementById("wheelcanvas");
var outsideRadius = 140;
var textRadius = 120;
var insideRadius = 25;
this.ctx = (<HTMLCanvasElement>this.myCanvas.nativeElement).getContext('2d');
this.ctx.clearRect(0, 0, 500, 500);
this.ctx.strokeStyle = "black";
this.ctx.lineWidth = 2;
this.ctx.font = 'bold 12px sans-serif';
for (var i = 0; i < 10; i++) {
var angle = this.startAngle + i * this.arc;
this.ctx.fillStyle = this.colors[i];
this.ctx.beginPath();
this.ctx.arc(150, 150, outsideRadius, angle, angle + this.arc, false);
this.ctx.arc(150, 150, insideRadius, angle + this.arc, angle, true);
this.ctx.stroke();
this.ctx.fill();
this.ctx.save();
this.ctx.shadowOffsetX = -1;
this.ctx.shadowOffsetY = -1;
this.ctx.shadowBlur = 0;
//this.ctx.shadowColor = "rgb(220,220,220)";
this.ctx.fillStyle = "white";
this.ctx.translate(150 + Math.cos(angle + this.arc / 2) * textRadius, 150 + Math.sin(angle + this.arc / 2) * textRadius);
this.ctx.rotate(angle + this.arc / 2 + Math.PI / 2);
var text = this.restaraunts[i];
this.ctx.fillText(text, -this.ctx.measureText(text).width / 2, 0);
this.ctx.restore();
}
//Arrow
this.ctx.fillStyle = "black";
this.ctx.beginPath();
this.ctx.moveTo(150 - 4, 150 - (outsideRadius + 5));
this.ctx.lineTo(150 + 4, 150 - (outsideRadius + 5));
this.ctx.lineTo(150 + 4, 150 - (outsideRadius - 5));
this.ctx.lineTo(150 + 9, 150 - (outsideRadius - 5));
this.ctx.lineTo(150 + 0, 150 - (outsideRadius - 13));
this.ctx.lineTo(150 - 9, 150 - (outsideRadius - 5));
this.ctx.lineTo(150 - 4, 150 - (outsideRadius - 5));
this.ctx.lineTo(150 - 4, 150 - (outsideRadius + 5));
this.ctx.fill();
}
spin() {
this.spinAngleStart = Math.random() * 10 + 10;
this.spinTime = 0;
this.spinTimeTotal = Math.random() * 3 + 4 * 1000;
this.rotateWheel();
}
rotateWheel() {
this.spinTime += 30;
if (this.spinTime >= this.spinTimeTotal) {
this.stopRotateWheel();
return;
}
var spinAngle = this.spinAngleStart - this.easeOut(this.spinTime, 0, this.spinAngleStart, this.spinTimeTotal);
this.startAngle += (spinAngle * Math.PI / 180);
this.drawRouletteWheel();
this.spinTimeout = setTimeout(() => {
this.rotateWheel();
}, 30);
}
stopRotateWheel() {
clearTimeout(this.spinTimeout);
var degrees = this.startAngle * 180 / Math.PI + 90;
var arcd = this.arc * 180 / Math.PI;
var index = Math.floor((360 - degrees % 360) / arcd);
this.ctx.save();
this.ctx.font = 'bold 30px sans-serif';
var text = this.restaraunts[index]
//this.ctx.fillText(text, 150 - this.ctx.measureText(text).width / 2, 150 + 10);
alert("You got:\n" + text);
this.ctx.restore();
}
// t: current time
// b: start value
// c: change in value
// d: duration
easeOut(t, b, c, d) {
return c * Math.sin(t/d * (Math.PI/2)) + b;
}
}
spin_wheel.html
<div class="wheel">
<canvas #myCanvas width="auto" height="300"></canvas>
<div class="icon-center"><img class="app-logo" (click)="spin()" src="../../assets/icon/favicon.png"/></div>
</div>
See attached image spin wheel screen
Thanks in advance.
The question goes as simple as it can, the title pretty much describes what I'm trying to do.
I'm new to Three.js and WebGL, I more or less understand the basics of creating a Cube but when it comes to what I'm trying to do I'm at loss.
I'm basically using this pen as reference while I learn: https://codepen.io/jackrugile/pen/vOEKzw as it does what I want without it being relative to screen size
var tick = 0,
smallestDimension = Math.min(window.innerWidth, window.innerHeight),
viewportWidth = smallestDimension,
viewportHeight = smallestDimension,
worldWidth = 100,
worldHeight = 100,
rows = 30,
cols = 30,
tileWidth = worldWidth / cols,
tileHeight = worldHeight / rows,
FOV = 90,
scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(
FOV,
viewportWidth / viewportHeight,
0.1,
1000
),
renderer = new THREE.WebGLRenderer({
antialias: true
}),
plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(worldWidth, worldHeight, 1),
new THREE.MeshPhongMaterial({
color: 0x222222
})
),
cubes = new THREE.Object3D(),
spotLight = new THREE.SpotLight(0xffffff),
ambientLight = new THREE.AmbientLight(0x666666);
renderer.setSize(viewportWidth, viewportHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
scene.add(plane);
scene.add(cubes);
scene.add(spotLight);
scene.add(ambientLight);
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
var width = tileWidth,
height = tileHeight,
dx = (cols / 2 - x),
dy = (rows / 2 - y),
depth = 1 + (20 - Math.sqrt(dx * dx + dy * dy)) / 4,
xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
zBase = depth / 2,
cube = new THREE.Mesh(
new THREE.BoxGeometry(width, height, depth),
new THREE.MeshPhongMaterial({
color: 'rgb(' + ~~((y / rows) * 255) + ', ' + ~~((x / cols) * 255) + ', 255)',
shininess: 50
})
);
cube.position.set(
xBase,
yBase,
zBase
);
cube.castShadow = true;
cube.receiveShadow = true;
cube.zBase = zBase;
cube.zScaleTarget = 1;
cubes.add(cube);
}
}
plane.position.set(0, 0, 0);
plane.castShadow = false;
plane.receiveShadow = true;
camera.position.set(0, 0, 100);
spotLight.position.set(0, 0, 100);
spotLight.castShadow = true;
spotLight.shadowCameraNear = 0.1;
spotLight.shadowMapWidth = 2048;
spotLight.shadowMapHeight = 2048;
spotLight.shadowDarkness = 0.1;
function step() {
spotLight.position.x = Math.sin(tick / 100) * (worldWidth / 2);
spotLight.position.y = Math.cos(tick / 100) * (worldHeight / 2);
cubes.traverse(function(cube) {
if (cube instanceof THREE.Mesh) {
if (Math.abs(cube.scale.z - cube.zScaleTarget) > 0.001) {
cube.scale.z += (cube.zScaleTarget - cube.scale.z) * 0.05;
} else {
cube.zScaleTarget = 1 + Math.random() * 10;
}
cube.position.z = cube.geometry.parameters.depth / 2 * cube.scale.z;
}
});
tick++;
}
function render() {
renderer.render(scene, camera);
}
function loop() {
requestAnimationFrame(loop);
step();
render();
}
loop();
document.body.appendChild(renderer.domElement);
body {
background: #000;
overflow: hidden;
}
canvas {
bottom: 0;
display: block;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
worldWidth = 100,
worldHeight = 100,
rows = 30,
cols = 30,
tileWidth = worldWidth / cols,
tileHeight = worldHeight / rows,
I see it uses this to set the size of the tiles that he lates uses in the loop:
...
var width = tileWidth,
height = tileHeight,
dx = ( cols / 2 - x ),
dy = ( rows / 2 - y ),
depth = 1 + ( 20 - Math.sqrt( dx * dx + dy * dy ) ) / 4,
xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
...
How would I draw this tiles across the whole viewport so its similar to:
Thank you!
Rather then to take Math.min use this in line number 2 smallestDimension = Math.max( window.innerWidth, window.innerHeight )
It will automatically cover your screen size.
If you want you can change rows = 10 and col = 10
The hours will shift when the minute hand hits 56 minutes in the 112 minute clock.(the position on 56 will be 14th hour as per the following code.
We tried many solutions through many days and finally had a breakthrough with the help of Kaiido from Stackoverflow community. It has become a complete solution for the first part of our clock system for Moon.
We currently blocked in the step of assembling the digital values into the analog Canvas clock system. The purpose of this clocks work is to fulfill an ambition of helping & joining hands with the scientific community. Your contribution with our efforts is highly respected.
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.08 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (num = 1; num < 29; num++) {
ang = num * Math.PI / 14;
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);
}
<html>
<body>
<canvas id="canvas" width="400" height="400" style="background-color:#333">
</canvas>
</body>
</html>
The values are to be inserted from the following code base, where the
minutes seconds and hours run using the following format,
28 hours = 1 day
56 mins = 1 hour
56 seconds = 1 minute
// our constants
var ms_per_sec = 1000; // 1000
var sec_per_min = 56; // 55.54920598892;
var min_per_hr = 56; // 55.54920598892;
var hrs_per_day = 28;
// let's make our target date at some fixed distance in our own time system
var countDownDate = new Date().getTime() +
(1 * hrs_per_day * min_per_hr * sec_per_min * ms_per_sec) + // 1 day
(2 * min_per_hr * sec_per_min * ms_per_sec) + // two hours
(1 * sec_per_min * ms_per_sec) + // 1 minutes
(5 * ms_per_sec); // 5 seconds
// Update the count down every frame
function loop() {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now and the count down date
var total_ms = (countDownDate + now);
// from here our values are based on our own time system
var total_seconds = (total_ms / ms_per_sec);
var total_minutes = (total_seconds/ sec_per_min);
var total_hours = (total_minutes / min_per_hr);
var total_days = (total_hours / hrs_per_day);
var days = Math.floor(total_days);
var hours = Math.floor(total_hours % hrs_per_day);
var minutes = Math.floor(total_minutes % 112);
var seconds = Math.floor(total_seconds % sec_per_min);
// Output the result in an element with id="demo"
document.getElementById("demo").textContent = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ";
// If the count down is over, write some text
if (total_ms < 0) {
document.getElementById("demo").innerHTML = "EXPIRED";
return;
}
requestAnimationFrame(loop);
}
loop();
<html>
<body>
<div id="demo"></div>
</body>
</html>
The problem faced is that the analog clock has a settimeInterval that
makes the looped code execute at a faster rate, messing with the time of
the clock. Is there a way to execute the analog clock in a cleaner way.
We are happy to have arrived at the solution for the digital clock with
the help of the stackoverflow community. The hours assembled in the
digital clock are running perfectly as expected. We are looking forward
to the solution on the analog clock. Your help towards our Research work
with ourmoonlife is highly respected. We consider our work to be the
common property of this planet, we welcome you to join hands with us.
Thanks for the wonderful opportunity.
You already have the correct logic to get your time in Hour:Minutes:Seconds format.
To draw it as an analogous clock, you just have to convert these values to angle.
On 12h clocks, we do ((Math.PI * 2) / 12) * (hour % 12), or more literally, (full_circle / number_of_hours_per_circle) * (hour % number_of_hours_per_circle).
In your project, you have 28 hours per day, so you could try to make a 14hrs clock to keep AM/PM format, but you're not forced to.
Now, your rounded 56 minutes per hours maps pretty well with the 28 hours per day (4 minutes pet tick on a AM/PM clock, or 2 minutes per tick on a 28H clock), but beware that your original
55.54920598892 wouldn't map so well.
// our constants
var ms_per_sec = 1000; // 1000
var sec_per_min = 56; // 55.54920598892;
var min_per_hr = 56; // 55.54920598892;
var hrs_per_day = 28;
// let's make our target date at some fixed distance in our own time system
var countDownDate = new Date().getTime() +
(1 * hrs_per_day * min_per_hr * sec_per_min * ms_per_sec) + // 1 day
(2 * min_per_hr * sec_per_min * ms_per_sec) + // two hours
(1 * sec_per_min * ms_per_sec) + // 1 minutes
(5 * ms_per_sec); // 5 seconds
// Update the count down every frame
function loop() {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now and the count down date
var total_ms = (countDownDate + now);
// from here our values are based on our own time system
var total_seconds = (total_ms / ms_per_sec);
var total_minutes = (total_seconds/ sec_per_min);
var total_hours = (total_minutes / min_per_hr);
var total_days = (total_hours / hrs_per_day);
var days = Math.floor(total_days);
var hours = Math.floor(total_hours % hrs_per_day);
var minutes = Math.floor(total_minutes % 112);
var seconds = Math.floor(total_seconds % sec_per_min);
// Output the result in an element with id="demo"
draw(hours, minutes, seconds);
// If the count down is over, write some text
if (total_ms < 0) {
document.getElementById("demo").innerHTML = "EXPIRED";
return;
}
requestAnimationFrame(loop);
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
radius = radius * 0.90
function draw(hours, minutes, seconds) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(canvas.height / 2, canvas.height / 2);
drawFace(ctx, radius);
drawNumbers(ctx, radius);
drawTime(ctx, radius, hours, minutes, seconds);
}
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.08 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (num = 1; num < 29; num++) {
ang = num * Math.PI / 14;
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, hours, minutes, seconds) {
const angle_hours = getAngle(hours, hrs_per_day);
drawHand(ctx, angle_hours, radius * 0.5, radius * 0.07);
//minute
const angle_minutes = getAngle(minutes, min_per_hr);
drawHand(ctx, angle_minutes, radius * 0.8, radius * 0.07);
// second
const angle_seconds = getAngle(seconds, sec_per_min);
drawHand(ctx, angle_seconds, radius * 0.9, radius * 0.02);
}
function getAngle(value, max) {
return (Math.PI*2 / max) * value;
}
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);
}
loop();
<html>
<body>
<canvas id="canvas" width="400" height="400" style="background-color:#333">
</canvas>
</body>
</html>
And if you want the 14H AM/PM variant:
// our constants
var ms_per_sec = 1000; // 1000
var sec_per_min = 56; // 55.54920598892;
var min_per_hr = 56; // 55.54920598892;
var hrs_per_day = 28;
// let's make our target date at some fixed distance in our own time system
var countDownDate = new Date().getTime() +
(1 * hrs_per_day * min_per_hr * sec_per_min * ms_per_sec) + // 1 day
(2 * min_per_hr * sec_per_min * ms_per_sec) + // two hours
(1 * sec_per_min * ms_per_sec) + // 1 minutes
(5 * ms_per_sec); // 5 seconds
// Update the count down every frame
function loop() {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now and the count down date
var total_ms = (countDownDate + now);
// from here our values are based on our own time system
var total_seconds = (total_ms / ms_per_sec);
var total_minutes = (total_seconds/ sec_per_min);
var total_hours = (total_minutes / min_per_hr);
var total_days = (total_hours / hrs_per_day);
var days = Math.floor(total_days);
var hours = Math.floor(total_hours % hrs_per_day);
var minutes = Math.floor(total_minutes % 112);
var seconds = Math.floor(total_seconds % sec_per_min);
// Output the result in an element with id="demo"
draw(hours, minutes, seconds);
// If the count down is over, write some text
if (total_ms < 0) {
document.getElementById("demo").innerHTML = "EXPIRED";
return;
}
requestAnimationFrame(loop);
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
radius = radius * 0.90
function draw(hours, minutes, seconds) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(canvas.height / 2, canvas.height / 2);
drawFace(ctx, radius);
drawNumbers(ctx, radius);
drawTime(ctx, radius, hours, minutes, seconds);
}
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.08 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (num = 1; num < 15; num++) {
ang = num * Math.PI / (14/2);
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, hours, minutes, seconds) {
const angle_hours = getAngle(hours % hrs_per_day/2, hrs_per_day/2);
drawHand(ctx, angle_hours, radius * 0.5, radius * 0.07);
//minute
const angle_minutes = getAngle(minutes, min_per_hr);
drawHand(ctx, angle_minutes, radius * 0.8, radius * 0.07);
// second
const angle_seconds = getAngle(seconds, sec_per_min);
drawHand(ctx, angle_seconds, radius * 0.9, radius * 0.02);
}
function getAngle(value, max) {
return (Math.PI*2 / max) * value;
}
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);
}
loop();
<html>
<body>
<canvas id="canvas" width="400" height="400" style="background-color:#333">
</canvas>
</body>
</html>
Canvas script:
function clock_hand_hh(hh) {
var hh_canvas = document.getElementById('clock_hand_hh');
var hh_context = hh_canvas.getContext('2d');
hh_canvas.width = 500;
hh_canvas.height = 500;
var centerX = hh_canvas.width / 2;
var centerY = hh_canvas.height / 2;
var radius = 10;
hh_context.beginPath();
hh_context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 5;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
hh_context.beginPath();
hh_context.bezierCurveTo(centerX, centerY, centerX - 10, centerY - 50, centerX, centerY - 100);
hh_context.bezierCurveTo(centerX, centerY-100, centerX + 10, centerY - 50, centerX, centerY);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 2;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
if (hh > 12) {
hh = hh - 12;
}
//alert((hh / 12) * 2 * Math.PI);
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);
}
Note: The alert(which I commented) is showing the correct value of angle of rotation required (in radians) for canvas.
You just move it twice: you draw using center variables, and then move coordinates also...
function clock_hand_hh(hh) {
var hh_canvas = document.getElementById('clock_hand_hh');
var hh_context = hh_canvas.getContext('2d');
hh_canvas.width = 500;
hh_canvas.height = 500;
var centerX = hh_canvas.width / 2;
var centerY = hh_canvas.height / 2;
var radius = 10;
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);
hh_context.beginPath();
hh_context.arc(0, 0, radius, 0, 2 * Math.PI, false);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 5;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
hh_context.beginPath();
hh_context.bezierCurveTo(0, 0, -10, -50, 0, -100);
hh_context.bezierCurveTo(0, -100, 10, -50, 0, 0);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 2;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
if (hh > 12) {
hh = hh % 12 + 1;
}
//alert((hh / 12) * 2 * Math.PI);
}
clock_hand_hh(4);
<canvas id="clock_hand_hh" style="width: 200px; height: 200px;"></canvas>
When you translate or rotate context it means you move and rotate the coordinate system with which you want to work. It does not affect the image already drawn.
What you need to do, is to modify the coordinate system before you start drawing. So just move the following two lines before the first beginPath() statement.
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);