Include Countdown Timer multiple times - javascript

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.

Related

Resizing font on a canvas

I use the wheel of fortune by Roko C. Buljan from here: how to draw a wheel of fortune?
This is my first experience with JS and canvas.
I want to put long sentences in labels, but they go out of bounds.
I've tried using a flexible font, but that doesn't really work and isn't exactly what I need. I need the text inside each block to move to a new line and reduce the font if it goes out of bounds.
Can this be implemented in this code, or would I need to write everything from scratch?
const sectors = [
{color:"#f82", label:"parallellogram into parallellogram"},
{color:"#0bf", label:"10"},
{color:"#fb0", label:"StackStack StackStack"},
{color:"#0fb", label:"50"},
{color:"#b0f", label:"StackStackStackStackStackStack"},
{color:"#f0b", label:"Stack Stack"},
{color:"#bf0", label:"Stack"},
];
const rand = (m, M) => Math.random() * (M - m) + m;
const tot = sectors.length;
const EL_spin = document.querySelector("#spin");
const ctx = document.querySelector("#wheel").getContext('2d');
const dia = ctx.canvas.width;
const rad = dia / 2;
const PI = Math.PI;
const TAU = 2 * PI;
const arc = TAU / sectors.length;
const friction = 0.991; // 0.995=soft, 0.99=mid, 0.98=hard
let angVel = 0; // Angular velocity
let ang = 0; // Angle in radians
const getIndex = () => Math.floor(tot - ang / TAU * tot) % tot;
function drawSector(sector, i) {
const ang = arc * i;
ctx.save();
// COLOR
ctx.beginPath();
ctx.fillStyle = sector.color;
ctx.moveTo(rad, rad);
ctx.arc(rad, rad, rad, ang, ang + arc);
ctx.lineTo(rad, rad);
ctx.fill();
// TEXT
ctx.translate(rad, rad);
ctx.rotate(ang + arc / 2);
ctx.textAlign = "right";
ctx.fillStyle = "#fff";
ctx.font = "bold 14px sans-serif";
ctx.fillText(sector.label, rad - 10, 10);
//
ctx.restore();
};
function rotate() {
const sector = sectors[getIndex()];
ctx.canvas.style.transform = `rotate(${ang - PI / 2}rad)`;
EL_spin.textContent = !angVel ? "SPIN" : sector.label;
EL_spin.style.background = sector.color;
}
function finishedSpinning() { // Called when the wheel stops spinning
const sector = sectors[getIndex()];
alert(sector.label);
}
function frame() {
if (!angVel) return;
const isSpinning = angVel > 0; // Check if the wheel is currently spinning
angVel *= friction; // Decrement velocity by friction
if (angVel < 0.002) angVel = 0; // Bring to stop
ang += angVel; // Update angle
ang %= TAU; // Normalize angle
rotate();
if (isSpinning && angVel === 0) { // If the wheel was spinning, but isn't anymore, it has just stopped
finishedSpinning();
}
}
function engine() {
frame();
requestAnimationFrame(engine)
}
// INIT
sectors.forEach(drawSector);
rotate(); // Initial rotation
engine(); // Start engine
EL_spin.addEventListener("click", () => {
if (!angVel) angVel = rand(0.25, 0.35);
});
#wheelOfFortune {
display: inline-block;
position: relative;
overflow: hidden;
}
#wheel {
display: block;
}
#spin {
font: 1.5em/0 sans-serif;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
width: 30%;
height: 30%;
margin: -15%;
background: #fff;
color: #fff;
box-shadow: 0 0 0 8px currentColor, 0 0px 15px 5px rgba(0, 0, 0, 0.6);
border-radius: 50%;
transition: 0.8s;
}
#spin::after {
content: "";
position: absolute;
top: -17px;
border: 10px solid transparent;
border-bottom-color: currentColor;
border-top: none;
}
<div id="wheelOfFortune">
<canvas id="wheel" width="300" height="300"></canvas>
<div id="spin">SPIN</div>
</div>
That's what I'm trying to do
Solution: HTML5 canvas ctx.fillText won't do line breaks?
New problem - long words as in the first label
Here's what I got, ready for any suggestions for improvement
(mainly the part with text centering - line 89)
It would also be nice to add a shadow to the text to stand out against the background of bright colors
New problem - long words as in the first label
const sectors = [
{ color: "#0fb", label: "Параллелограмм в паралеллограмме" },
{ color: "#0bf", label: "Бесплатная настройка виджета" },
{ color: "#fb0", label: "Два пресета цветов по цене одного" },
{ color: "#0fb", label: "1строчка" },
{ color: "#b0f", label: "Год премиум поддержки в подарок в подарок" },
{ color: "#f0b", label: "Скидка 10% на любой пакет" },
{ color: "#bf0", label: "Виджет 'Juice Contact' в подарок" },
{ color: "#f82", label: "Скидка 5% на любой пакет" },
{ color: "#bf0", label: "" },
];
function printAtWordWrap(context, text, x, y, lineHeight, fitWidth) {
fitWidth = fitWidth || 0;
if (fitWidth <= 0) {
context.fillText(text, x, y);
return;
}
let words = text.split(" ");
let currentLine = 0;
let idx = 1;
while (words.length > 0 && idx <= words.length) {
const str = words.slice(0, idx).join(" ");
const w = context.measureText(str).width;
if (w > fitWidth) {
if (idx == 1) {
idx = 2;
}
context.fillText(
words.slice(0, idx - 1).join(" "),
x,
y + lineHeight * currentLine
);
currentLine++;
words = words.splice(idx - 1);
idx = 1;
} else {
idx++;
}
}
if (idx > 0)
context.fillText(words.join(" "), x, y + lineHeight * currentLine);
}
const rand = (m, M) => Math.random() * (M - m) + m;
const tot = sectors.length;
const EL_spin = document.querySelector("#spin");
const ctx = document.querySelector("#wheel").getContext("2d");
const dia = ctx.canvas.width;
const rad = dia / 2;
const PI = Math.PI;
const TAU = 2 * PI;
const arc = TAU / sectors.length;
const friction = 0.991; // 0.995=soft, 0.99=mid, 0.98=hard
let angVel = 0; // Angular velocity
let ang = 0; // Angle in radians
const getIndex = () => Math.floor(tot - (ang / TAU) * tot) % tot;
// calcFontSize not used
const calcFontSize = () => {
const maxChars = Math.max(...sectors.map((ob) => ob.label.length));
const width = rad * 0.9 - 15;
const w = (width / maxChars) * 1.3;
const h = ((TAU * rad) / tot) * 0.5;
return Math.min(w, h);
};
function drawSector(sector, i) {
const ang = arc * i;
ctx.save();
// COLOR
ctx.beginPath();
ctx.fillStyle = sector.color;
ctx.moveTo(rad, rad);
ctx.arc(rad, rad, rad, ang, ang + arc);
ctx.lineTo(rad, rad);
ctx.fill();
// TEXT
ctx.translate(rad, rad);
ctx.rotate(ang + arc / 2);
ctx.textAlign = "center";
ctx.fillStyle = "#fff";
const fontSize = 15;
ctx.font = `bold ${fontSize}px sans-serif`;
// values for centering text - not ideal for now (need tuning)
const w = ctx.measureText(sector.label).width;
console.log(sector.label, w);
let y;
const lineWidth = 130; // width before line break
switch (true) {
case w < lineWidth:
y = fontSize / 3;
break;
case w >= lineWidth && w < 2 * lineWidth:
y = fontSize / 3 - 10;
break;
case w >= 2 * lineWidth && w < 3 * lineWidth:
y = fontSize / 3 - 20;
break;
case w >= 3 * lineWidth && w < 4 * lineWidth:
y = fontSize / 3 - 30;
break;
case w >= 4 * lineWidth:
y = fontSize / 3 - 40;
break;
default:
y = fontSize / 3;
}
printAtWordWrap(ctx, sector.label, rad * 0.7, y, 21, lineWidth);
ctx.restore();
}
function rotate() {
const sector = sectors[getIndex()];
ctx.canvas.style.transform = `rotate(${ang - PI / 2}rad)`;
EL_spin.textContent = !angVel
? "SPIN"
: ""; /* sector.label instead "" - if u want to display text inside spin element */
EL_spin.style.background = sector.color;
}
function finishedSpinning() {
// Called when the wheel stops spinning
const sector = sectors[getIndex()];
alert(sector.label);
}
function frame() {
if (!angVel) return;
const isSpinning = angVel > 0; // Check if the wheel is currently spinning
angVel *= friction; // Decrement velocity by friction
if (angVel < 0.002) angVel = 0; // Bring to stop
ang += angVel; // Update angle
ang %= TAU; // Normalize angle
rotate();
if (isSpinning && angVel === 0) {
// If the wheel was spinning, but isn't anymore, it has just stopped
finishedSpinning();
}
}
function engine() {
frame();
requestAnimationFrame(engine);
}
// INIT
sectors.forEach(drawSector);
rotate(); // Initial rotation
engine(); // Start engine
EL_spin.addEventListener("click", () => {
if (!angVel) angVel = rand(0.25, 0.35);
});
#wheelOfFortune {
display: inline-block;
position: relative;
overflow: hidden;
}
#wheel {
display: block;
}
#spin {
font: 1.5em/0 sans-serif;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
width: 30%;
height: 30%;
margin: -15%;
background: #fff;
color: #fff;
box-shadow: 0 0 0 8px currentColor, 0 0px 15px 5px rgba(0, 0, 0, 0.6);
border-radius: 50%;
transition: 0.8s;
}
#spin::after {
content: "";
position: absolute;
top: -17px;
border: 10px solid transparent;
border-bottom-color: currentColor;
border-top: none;
}
<body style="background-color: darkcyan">
<div id="wheelOfFortune">
<canvas id="wheel" width="480" height="480"></canvas>
<div id="spin">SPIN</div>
</div>
</body>

Error: <tspan> attribute dy: Expected length, "NaN" - Raphael.js

I've got a lot of errors when hiding/showing object made in raphael.
I have a house made with raphael - when button clicked a gauge is shown and animating, if you click again the house is showing and animating again (function running over and over again when clicking)
This function is showing on phone, on normal desktop the function isn't used. So therefor I can't just put the function on the button.
BUT! I got a lot of errors when doing it.
Made a fiddle showing it. See it here.
Full js code here:
pv = 80;
pointerv = Math.round(pv);
onload = function() {
$(function dogauge() {
var Needle, arc, arcEndRad, arcStartRad, barWidth, chart, chartInset, degToRad, el, endPadRad, height, i, margin, needle, numSections, padRad, percToDeg, percToRad, percent, radius, ref, sectionIndx, sectionPerc, startPadRad, svg, totalPercent, width;
percent = pointerv/100;
barWidth = 40;
numSections = 3;
// / 2 for HALF circle
sectionPerc = 1 / numSections / 2;
padRad = 0.05;
chartInset = 10;
// start at 270deg
totalPercent = .75;
el = d3.select('.chart-gauge');
margin = {
top: 20,
right: 20,
bottom: 30,
left: 20
};
width = el[0][0].offsetWidth - margin.left - margin.right;
height = width;
radius = Math.min(width, height) / 2;
percToDeg = function(perc) {
return perc * 360;
};
percToRad = function(perc) {
return degToRad(percToDeg(perc));
};
degToRad = function(deg) {
return deg * Math.PI / 180;
};
svg = el.append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom);
chart = svg.append('g').attr('transform', `translate(${(width + margin.left) / 2}, ${(height + margin.top) / 2})`);
// build gauge bg
for (sectionIndx = i = 1, ref = numSections; (1 <= ref ? i <= ref : i >= ref); sectionIndx = 1 <= ref ? ++i : --i) {
arcStartRad = percToRad(totalPercent);
arcEndRad = arcStartRad + percToRad(sectionPerc);
totalPercent += sectionPerc;
startPadRad = sectionIndx === 0 ? 0 : padRad / 2;
endPadRad = sectionIndx === numSections ? 0 : padRad / 2;
arc = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth).startAngle(arcStartRad + startPadRad).endAngle(arcEndRad - endPadRad);
chart.append('path').attr('class', `arc chart-color${sectionIndx}`).attr('d', arc);
}
Needle = class Needle {
constructor(len, radius1) {
this.len = len;
this.radius = radius1;
}
drawOn(el, perc) {
el.append('circle').attr('class', 'needle-center').attr('cx', 0).attr('cy', 0).attr('r', this.radius);
return el.append('path').attr('class', 'needle').attr('d', this.mkCmd(perc));
}
animateOn(el, perc) {
var self;
self = this;
return el.transition().delay(500).ease('elastic').duration(3000).selectAll('.needle').tween('progress', function() {
return function(percentOfPercent) {
var progress;
progress = percentOfPercent * perc;
return d3.select(this).attr('d', self.mkCmd(progress));
};
});
}
mkCmd(perc) {
var centerX, centerY, leftX, leftY, rightX, rightY, thetaRad, topX, topY;
thetaRad = percToRad(perc / 2); // half circle
centerX = 0;
centerY = 0;
topX = centerX - this.len * Math.cos(thetaRad);
topY = centerY - this.len * Math.sin(thetaRad);
leftX = centerX - this.radius * Math.cos(thetaRad - Math.PI / 2);
leftY = centerY - this.radius * Math.sin(thetaRad - Math.PI / 2);
rightX = centerX - this.radius * Math.cos(thetaRad + Math.PI / 2);
rightY = centerY - this.radius * Math.sin(thetaRad + Math.PI / 2);
return `M ${leftX} ${leftY} L ${topX} ${topY} L ${rightX} ${rightY}`;
}
};
needle = new Needle(90, 15);
needle.drawOn(chart, 0);
needle.animateOn(chart, percent);
});
$(function dohouse() {
var paper = Raphael("frivardihouse", 250, 260);
paper.customAttributes.step = function (s) {
var len = this.orbit.getTotalLength();
var point = this.orbit.getPointAtLength(s * len);
return {
transform: "t" + [point.x, point.y] + "r" + point.alpha
};
};
var bghouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z").attr({fill: "#cccccc", stroke: "none"});
bghouse.glow({
width:10,
fill:true,
offsetx :0,
offsety:3,
color:'#bfbfbf'
}
);
function formatNumber(num) {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.')
}
function round(value, precision) {
var multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
let ltv = (100 - 80)/100;
/*let vardi = <?=$graph->CurrentPropValue?>;
let boligvardi = "Boligværdi " + formatNumber(vardi);
let boligvardilink = boligvardi.link("https://realkreditkonsulenten.dk/kundeportal/?page=property");*/
let equity = 20;
let h = 144*ltv;
let y = 86+((1-ltv)*144);
let EqText = formatNumber (equity);
let ltvtxt = round(ltv * 100);
var green = "#59ba41";
var darkgreen = "#1a7266";
var yellow = "#fbb732";
var red = "#c80000";
var finalfillcolor = green;
if (ltv > 0.6) {
finalfillcolor = darkgreen;
}
if (ltv > 0.82) {
finalfillcolor = yellow;
}
if (ltv > 0.95) {
finalfillcolor = red;
}
if (ltv > 1) {
h = 144;
y= 88;
}
var fillhouse = paper.rect(40.5,230,172.3,0).attr({fill: green, stroke: "none"});
/*skal hides hvis function mus kører*/
var sAnimation = Raphael.animation({ 'width': 172.3, 'height': h, 'x': 40.5, 'y': y, fill: finalfillcolor}, 2000, "backOut")
fillhouse.animate(sAnimation);
var thehouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z").attr({fill: "#ffffff", stroke: "none"});
var txtbelaning = paper.text(126.8,198, "BELÅNING").attr({"font-family": "Open sans", "font-weight":"700", "font-size": 20, "transform": "matrix(1 0 0 1 79.455 216.7752)", "fill":"#ffffff"});
/*var housevalue = paper.text(126.8,210, boligvardi).attr({"font-family": "Open sans", "font-weight":"400", "font-size": 13, "fill":"#ffffff"});*/
paper.customAttributes.txtprc = function (txtprc) {
return {
txtprc: [txtprc],
text: Math.floor(txtprc) +"%" + '\n'
}
}
var txtprc = paper
.text(126.1,158.2)
.attr({
"font-size": 48,
"fill": "#ffffff",
"font-family":"Open sans",
"font-weight":"700",
txtprc: [0,1000]
})
txtprc.animate({
txtprc: [ltvtxt, 1000]
}, 2000, "easeInOut")
var txtfrivardi = paper.text(126.8,42.1, "FRIVÆRDI").attr({"font-family": "Open sans", "font-weight":"600", "font-size": 12, "transform": "matrix(1 0 0 1 98.6264 51.0823)", "fill":"#585857"});
paper.customAttributes.txtfrivardival = function (txtfrivardival) {
return {
txtfrivardival: [txtfrivardival],
text: formatNumber(Math.floor(txtfrivardival)) + '\n'
}
}
var txtfrivardival = paper
.text(126.2,61.3)
.attr({
"font-size": 20,
"fill": "#585857",
"font-family":"Open sans",
"font-weight":"700",
txtfrivardival: [0,1000]
})
txtfrivardival.animate({
txtfrivardival: [equity, 1000]
}, 2000, "easeInOut")
});
};
$("#segaugeknap").click(function() {
if($(this).text()=== "OVERVÅGNINGSBAROMETER"){
$(this).text("TILBAGE");
document.getElementById('chart-gauge').innerHTML = '';
onload();
}
else{
$(this).text("OVERVÅGNINGSBAROMETER");
}
$('#frivardihouse, #housevalue_f, #gaugebox').slideToggle('slow');
document.getElementById('frivardihouse').innerHTML = '';
onload();
});
to get rid of the multiple houses and visible multiple gauges
$("#segaugeknap").click(function() {
if($(this).text()=== "OVERVÅGNINGSBAROMETER"){
$(this).text("TILBAGE");
document.getElementById('chart-gauge').innerHTML = '';
onload();
} else{
$(this).text("OVERVÅGNINGSBAROMETER");
document.getElementById('frivardihouse').innerHTML = '';
onload();
}
$('#frivardihouse, #housevalue_f, #gaugebox').slideToggle('slow');
});
You still have multiple gauges when house is shown.
tspan errors only happen when animation is still going. With above modification it only happens when gauge is still animating.
You shouldn't start drawing the 2 svg each time you click the bottun
So first step is to seperate the 2 drawing function and remove the onload wrapper function.
Then when you click on the guage button is to wait until the slide animation complete so we can calculate the width and height for the guage container Div after that is to draw the gauge and same for the house.
Please check the following jsfiddle i've forked yours and do the changes hope it's clear for you.
Check the fiddle https://jsfiddle.net/tb1k5sgc/
pv = 80;
pointerv = Math.round(pv);
function dogauge() {
var Needle, arc, arcEndRad, arcStartRad, barWidth, chart, chartInset, degToRad, el, endPadRad, height, i, margin, needle, numSections, padRad, percToDeg, percToRad, percent, radius, ref, sectionIndx, sectionPerc, startPadRad, svg, totalPercent, width;
percent = pointerv/100;
barWidth = 40;
numSections = 3;
// / 2 for HALF circle
sectionPerc = 1 / numSections / 2;
padRad = 0.05;
chartInset = 10;
// start at 270deg
totalPercent = .75;
el = d3.select('.chart-gauge');
margin = {
top: 20,
right: 20,
bottom: 30,
left: 20
};
width = el[0][0].offsetWidth - margin.left - margin.right;
height = width;
radius = Math.min(width, height) / 2;
percToDeg = function(perc) {
return perc * 360;
};
percToRad = function(perc) {
return degToRad(percToDeg(perc));
};
degToRad = function(deg) {
return deg * Math.PI / 180;
};
svg = el.append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom);
chart = svg.append('g').attr('transform', `translate(${(width + margin.left) / 2}, ${(height + margin.top) / 2})`);
// build gauge bg
for (sectionIndx = i = 1, ref = numSections; (1 <= ref ? i <= ref : i >= ref); sectionIndx = 1 <= ref ? ++i : --i) {
arcStartRad = percToRad(totalPercent);
arcEndRad = arcStartRad + percToRad(sectionPerc);
totalPercent += sectionPerc;
startPadRad = sectionIndx === 0 ? 0 : padRad / 2;
endPadRad = sectionIndx === numSections ? 0 : padRad / 2;
arc = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth).startAngle(arcStartRad + startPadRad).endAngle(arcEndRad - endPadRad);
chart.append('path').attr('class', `arc chart-color${sectionIndx}`).attr('d', arc);
}
Needle = class Needle {
constructor(len, radius1) {
this.len = len;
this.radius = radius1;
}
drawOn(el, perc) {
el.append('circle').attr('class', 'needle-center').attr('cx', 0).attr('cy', 0).attr('r', this.radius);
return el.append('path').attr('class', 'needle').attr('d', this.mkCmd(perc));
}
animateOn(el, perc) {
var self;
self = this;
return el.transition().delay(500).ease('elastic').duration(3000).selectAll('.needle').tween('progress', function() {
return function(percentOfPercent) {
var progress;
progress = percentOfPercent * perc;
return d3.select(this).attr('d', self.mkCmd(progress));
};
});
}
mkCmd(perc) {
var centerX, centerY, leftX, leftY, rightX, rightY, thetaRad, topX, topY;
thetaRad = percToRad(perc / 2); // half circle
centerX = 0;
centerY = 0;
topX = centerX - this.len * Math.cos(thetaRad);
topY = centerY - this.len * Math.sin(thetaRad);
leftX = centerX - this.radius * Math.cos(thetaRad - Math.PI / 2);
leftY = centerY - this.radius * Math.sin(thetaRad - Math.PI / 2);
rightX = centerX - this.radius * Math.cos(thetaRad + Math.PI / 2);
rightY = centerY - this.radius * Math.sin(thetaRad + Math.PI / 2);
return `M ${leftX} ${leftY} L ${topX} ${topY} L ${rightX} ${rightY}`;
}
};
needle = new Needle(90, 15);
needle.drawOn(chart, 0);
needle.animateOn(chart, percent);
};
function dohouse() {
var paper = Raphael("frivardihouse", 250, 260);
paper.customAttributes.step = function (s) {
var len = this.orbit.getTotalLength();
var point = this.orbit.getPointAtLength(s * len);
return {
transform: "t" + [point.x, point.y] + "r" + point.alpha
};
};
var bghouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z").attr({fill: "#cccccc", stroke: "none"});
bghouse.glow({
width:10,
fill:true,
offsetx :0,
offsety:3,
color:'#bfbfbf'
}
);
function formatNumber(num) {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.')
}
function round(value, precision) {
var multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
let ltv = (100 - 80)/100;
/*let vardi = <?=$graph->CurrentPropValue?>;
let boligvardi = "Boligværdi " + formatNumber(vardi);
let boligvardilink = boligvardi.link("https://realkreditkonsulenten.dk/kundeportal/?page=property");*/
let equity = 20;
let h = 144*ltv;
let y = 86+((1-ltv)*144);
let EqText = formatNumber (equity);
let ltvtxt = round(ltv * 100);
var green = "#59ba41";
var darkgreen = "#1a7266";
var yellow = "#fbb732";
var red = "#c80000";
var finalfillcolor = green;
if (ltv > 0.6) {
finalfillcolor = darkgreen;
}
if (ltv > 0.82) {
finalfillcolor = yellow;
}
if (ltv > 0.95) {
finalfillcolor = red;
}
if (ltv > 1) {
h = 144;
y= 88;
}
var fillhouse = paper.rect(40.5,230,172.3,0).attr({fill: green, stroke: "none"});
/*skal hides hvis function mus kører*/
var sAnimation = Raphael.animation({ 'width': 172.3, 'height': h, 'x': 40.5, 'y': y, fill: finalfillcolor}, 2000, "backOut")
fillhouse.animate(sAnimation);
var thehouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z").attr({fill: "#ffffff", stroke: "none"});
var txtbelaning = paper.text(126.8,198, "BELÅNING").attr({"font-family": "Open sans", "font-weight":"700", "font-size": 20, "transform": "matrix(1 0 0 1 79.455 216.7752)", "fill":"#ffffff"});
/*var housevalue = paper.text(126.8,210, boligvardi).attr({"font-family": "Open sans", "font-weight":"400", "font-size": 13, "fill":"#ffffff"});*/
paper.customAttributes.txtprc = function (txtprc) {
return {
txtprc: [txtprc],
text: Math.floor(txtprc) +"%" + '\n'
}
}
var txtprc = paper
.text(126.1,158.2)
.attr({
"font-size": 48,
"fill": "#ffffff",
"font-family":"Open sans",
"font-weight":"700",
txtprc: [0,1000]
})
txtprc.animate({
txtprc: [ltvtxt, 1000]
}, 2000, "easeInOut")
var txtfrivardi = paper.text(126.8,42.1, "FRIVÆRDI").attr({"font-family": "Open sans", "font-weight":"600", "font-size": 12, "transform": "matrix(1 0 0 1 98.6264 51.0823)", "fill":"#585857"});
paper.customAttributes.txtfrivardival = function (txtfrivardival) {
return {
txtfrivardival: [txtfrivardival],
text: formatNumber(Math.floor(txtfrivardival)) + '\n'
}
}
var txtfrivardival = paper
.text(126.2,61.3)
.attr({
"font-size": 20,
"fill": "#585857",
"font-family":"Open sans",
"font-weight":"700",
txtfrivardival: [0,1000]
})
txtfrivardival.animate({
txtfrivardival: [equity, 1000]
}, 2000, "easeInOut")
};
$("#segaugeknap").click(function() {
$('#frivardihouse, #gaugebox').slideToggle(400);
if($(this).text()=== "OVERVÅGNINGSBAROMETER"){
$(this).text("TILBAGE");
document.getElementById('chart-gauge').innerHTML = '';
setTimeout(dogauge, 401);
}
else{
$(this).text("OVERVÅGNINGSBAROMETER");
document.getElementById('frivardihouse').innerHTML = '';
setTimeout(dohouse, 401);
}
});
$(document).ready(function(){
dohouse();
})
.chart-gauge {
width: 100%;
height: 180px;
margin-left: 10px;
}
.chart-color1 {
fill: rgb(200,0,0);
}
.chart-color2 {
fill: rgb(251, 183, 50);
}
.chart-color3 {
fill: rgb(89, 186, 65);;
}
.needle,
.needle-center {
fill: #464A4F;
}
.prose {
text-align: center;
font-family: sans-serif;
color: #ababab;
}
.gaugebox {display: none; border-radius: 0px 0px 5px 5px !important;margin-top: -10px !important;padding: 0px 10px 20px 10px !important;}
#segauge {background-color:#000;color:#fff;width:300px;margin: 0 auto;text-align:center;padding:10px;}
.gaugebox h4 {text-align: center;font-weight: 700;margin-bottom: 0px;}
.gaugebox .gaugetxt span:first-child(){float: left;}
.gaugebox .gaugetxt span:nth-child(2){float: right;}
.gaugetxt {width: 360px; margin: 0 auto;}
.gaugefullwrapper {
background: #fff;
border-radius: 10px;
width: 380px;
margin: 0 auto;
padding-bottom: 10px;
box-shadow: 0px 4px 15px rgba(0,0,0,0.2);
}
.gaugewrapper {margin: 0 auto; width: 350px }
div#gauge {
width: 80%;height: 180px;margin: 0 auto;
}
/*hus*/
div#frivardihouse svg {
margin: 0 auto;
display: block;
padding-top: 10px;
transition: all 0.6s cubic-bezier(.87,-.41,.19,1.44)
}
div#frivardihouse svg:hover {transform: scale(1.04);
}
div#frivardihouse {
margin-top: -20px;
}
.housevalue_f {text-align: center;padding-bottom: 10px;}
.housevalue_f a span {color: #17aec6;}
.housevalue_f a {color: #666666;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js"></script>
<div class="housegauge">
<div class="graphs house">
<div id="frivardihouse"></div>
<div class="w-btn-wrapper align_center" id="segauge"><span id="segaugeknap" class="w-btn style_solid size_medium color_primary icon_none">OVERVÅGNINGSBAROMETER</span></div>
</div>
<div class="gaugebox" id="gaugebox">
<div class="gaugefullwrapper">
<div class="gaugewrapper">
<div id="chart-gauge" class="chart-gauge"></div>
</div>
<div class="gaugetxt">
<span>Langt fra omlægning</span><span>Tæt på omlægning</span>
</div>
</div>
</div>
</div>

Javascript - Point object towards mouse

I'm trying to get this player character to point towards the mouse pointer, but it doesn't move at all. I have no idea where to start, can somebody please help me?
Here is the full code:
The part which I need help with is in the updatevalues() function in the player object (javascript)
var canvas = document.getElementById("tanks-canvas");
var game = canvas.getContext("2d");
canvas.height = screen.height / 1.175;
canvas.width = screen.width / 1.05;
game.translate(canvas.width / 2, canvas.height / 2);
clear();
txt(0, 0, "Loading...", "100px georgia", "rgb(0, 0, 0)");
var mousex = 0;
var mousey = 0;
var angle;
var mode = "menu";
var key = [];
var scale = 1;
for (i = 0; i <= 255; i += 1) {
key[i] = false;
}
/*
Class Definition:
*/
// Bodies:
var circle_body = {
x: 0,
y: 0,
radius: 100,
draw: function() {
this.setvals();
circ(this.x, this.y, this.radius, "rgb(0, 150, 255)");
},
setvals: function() {
this.radius = 25 * scale;
}
};
// Turrents:
var rect_turrent = {
x: 0,
y: 0,
width: 0,
height: 0,
offset: 0,
draw: function() {
this.setvals();
rect(this.x + this.offset, this.y, this.width, this.height, "rgb(150, 150, 150)");
},
setvals: function() {
this.offset = 35 * scale;
this.width = 30 * scale;
this.height = 15 * scale;
}
};
// Classes:
var base = {
draw: function() {
rect_turrent.draw();
circle_body.draw();
}
};
/*
Functions & Objects
*/
function txt(x, y, content, font, color) {
game.fillStyle = color;
game.textAlign = "center";
game.font = font;
game.fillText(content, x, y);
}
function rect(x, y, width, height, color) {
x -= width / 2;
y -= height / 2;
game.fillStyle = color;
game.strokeStyle = color.black;
game.fillRect(x, y, width, height);
game.strokeRect(x, y, width, height);
}
function img(x, y, img) {
x -= img.width / 2;
y -= img.height / 2;
game.drawImage(img, x, y);
}
function circ(x, y, radius, color) {
game.fillStyle = color;
game.strokeStyle = color.black;
game.beginPath();
game.arc(x, y, radius, 0, Math.PI * 2);
game.fill();
game.stroke();
}
function clear() {
rect(0, 0, canvas.width + 10, canvas.height + 10, "rgb(200, 200, 200)");
}
/*
IMPORTANT: Player Character:
*/
var player = {
// Variables
x: 0,
y: 0,
type: "base",
angle: 0,
autorotate: false,
// Functions
update: function() {
this.updatevalues();
game.save();
game.rotate(this.angle);
this.draw();
game.restore();
txt(0, -100, "Mouse x: " + mousex + " | Mouse y: " + mousey + " | Angle: " + this.angle, "20px georgia", "rgb(0, 0, 0)");
},
draw: function() {
if (this.type == "base") {
base.draw();
}
},
updatevalues: function() {
this.offsetY = mousex - this.x;
this.offsetX = mousey - this.y;
this.angle = Math.atan(mousex / mousey);
}
};
function menu() {
player.update();
}
function update() {
if (mode == "menu") {
menu();
}
clear();
player.update();
}
/*
Intervals:
*/
game.interval = setInterval(update, 50);
/*
Event Listeners
*/
document.addEventListener("keydown", function(event) {
for (i = 0; i <= 255; i++) {
if (event.keyCode == i) {
key[i] = true;
}
}
});
document.addEventListener("keyup", function(event) {
for (i = 0; i <= 255; i++) {
key[i] = false;
}
});
document.addEventListener("mousemove", function(event) {
mousex = event.offsetX - (canvas.width / 2);
mousey = (canvas.height / 2) - event.offsetY;
});
/* Everything */
* {
transition: 1s;
}
body {
background-color: rgb(100, 100, 100);
}
/* Flexbox: */
.flex-container {
display: flex;
flex-direction: column;
padding: 5vw;
}
#header {
flex-direction: row;
background-color: rgb(200, 0, 0);
}
#main {
background-color: rgb(200, 150, 50);
}
#navbar {
z-index: 1;
overflow: hidden;
background-color: rgb(200, 200, 200);
position: fixed;
top: 0;
width: 100%
}
/* Images */
img {
display: block;
margin-left: auto;
margin-right: auto;
}
.imgcontainer {
position: relative;
width: 50%
}
.imgoverlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 100, 200, 0.75);
overflow: hidden;
width: 100%;
height: 0;
}
.imgtext {
text-align: center;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: rgba(200, 200, 200, 0.75);
}
.imgcontainer:hover .imgoverlay {
height: 100%;
}
.image {
width: 100%;
height: auto;
}
/* Navigation Menu */
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.75);
overflow-x: hidden;
padding-top: 5vw;
}
/* The navigation menu links */
.sidenav a {
padding: 1vw 1vw 1vw 4vw;
text-decoration: none;
overflow-x: hidden;
font-size: 2vw;
color: rgba(150, 150, 150, 0.75);
display: block;
}
/* When you mouse over the navigation links, change their color */
.sidenav a:hover {
color: rgb(255, 255, 255);
}
/* Position and style the close button (top right corner) */
.sidenav .closebtn {
position: absolute;
top: 0;
right: 1vw;
font-size: 5vw;
margin-left: 50px;
}
/* Styles: */
h1 {
font: 10vw courier;
color: rgb(0, 0, 200);
text-align: center;
padding: none;
}
h2 {
font: 9vw courier;
color: rgb(0, 0, 150);
text-align: center;
padding: none;
}
h3 {
font: 8vw courier;
color: rgb(0, 0, 150);
text-align: center;
padding: none;
}
h4 {
font: 7vw courier;
color: rgb(0, 0, 150);
text-align: center;
padding: none;
}
h5 {
font: 6vw courier;
color: rgb(0, 0, 150);
text-align: center;
padding: none;
}
h6 {
font: 5vw courier;
color: rgb(0, 0, 150);
text-align: center;
padding: none;
}
p {
font: 2vw georgia;
color: rgb(0, 100, 0);
text-align: justify;
}
/* Other */
.link {
color: rgb(150, 150, 150);
}
.link:hover {
color: rgb(255, 255, 255);
}
code {
font-family: courier;
}
canvas {
padding: none;
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
display: block;
background-color: rgb(255, 255, 255);
border: 5px solid rgb(0, 0, 0);
}
<!DOCTYPE html>
<html>
<head>
<title>Game Goods</title>
<link rel="stylesheet" href="style.css">
<script src="functions.js"></script>
</head>
<body>
<!-- Game -->
<canvas id="tanks-canvas"></canvas>
<script src="tanks-script.js"></script>
</body>
</html>
(If you run it, hit "full page", or it won't work.)
Edit 10-30-18: I've changed the code according to Helder's answer. At least the mousex works now...
Edit 10-31-18: I changed mousex and mousey to also be at coordinates 0, 0 when the mouse is at the middle. The canvas works like a coordinate plane now. I also added debugging text (you can see it if you run the snippet).
Your calculations for the angle are incorrect, take a look at this sample...
This is by no means the exact solution but should get you moving on the right direction, I'm only using mousex in my calculation.
var canvas = document.getElementById("tanks-canvas");
var game = canvas.getContext("2d");
canvas.height = canvas.width = 170;
game.translate(canvas.width / 2, canvas.height / 2);
clear();
var mousex = 0;
var mousey = 0;
var angle;
var mode = "menu";
var key = [];
var scale = 1;
for (i = 0; i <= 255; i += 1) {
key[i] = false;
}
var player = {
x: 0, y: 0,
type: "base",
angle: 0,
autorotate: false,
update: function() {
this.updatevalues();
game.save()
game.rotate(this.angle);
this.draw();
game.restore();
},
updatevalues: function() {
this.offsetY = mousex - this.x;
this.offsetX = mousey - this.y;
this.angle = 360 * Math.sin(mousex/30000);
},
draw: function() {
if (this.type == "base") {
base.draw();
}
}
};
/*
Class Definition:
*/
// Bodies:
var circle_body = {
x: 0,
y: 0,
radius: 100,
draw: function() {
this.setvals();
circ(this.x, this.y, this.radius, "rgb(0, 150, 255)");
},
setvals: function() {
this.radius = 25 * scale;
}
};
// Turrents:
var rect_turrent = {
x: 0,
y: 0,
width: 0,
height: 0,
offset: 0,
draw: function() {
this.setvals();
rect(this.x + this.offset, this.y, this.width, this.height, "rgb(150, 150, 150)");
},
setvals: function() {
this.offset = 35 * scale;
this.width = 30 * scale;
this.height = 15 * scale;
}
};
// Classes:
var base = {
draw: function() {
rect_turrent.draw();
circle_body.draw();
}
};
/*
Functions & Objects
*/
function rect(x, y, width, height, color) {
x -= width / 2;
y -= height / 2;
game.fillStyle = color;
game.strokeStyle = color.black;
game.fillRect(x, y, width, height);
game.strokeRect(x, y, width, height);
}
function circ(x, y, radius, color) {
game.fillStyle = color;
game.strokeStyle = color.black;
game.beginPath();
game.arc(x, y, radius, 0, Math.PI * 2);
game.fill();
game.stroke();
}
function clear() {
rect(0, 0, canvas.width + 10, canvas.height + 10, "rgb(200, 200, 200)");
}
function update() {
clear();
player.update();
}
game.interval = setInterval(update, 50);
document.addEventListener("mousemove", function(event) {
mousex = event.offsetX;
mousey = event.offsetY;
});
<canvas id="tanks-canvas"></canvas>
I found out the formula with help from my math teacher & a different question.
The formula is
Math.atan2(-y, x);

progressbar doesn't work correctly

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

circle progressbar doesn't start from the middle

I have a circular progress bar that must start from 0 degree - middle of a top part of the circle. But I've noticed that it starts not in the middle, but a little to the left. How do I fix that?
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: 90,
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),
step = 1.5;
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';
color.addColorStop(0, "red");
color.addColorStop(0.5, "red");
color.addColorStop(1.0, "red");
bar.appendChild(span);
bar.appendChild(canvas);
(function animat() {
span.textContent = options.start + '%';
createCircle(options, paper, radius, color, Math.PI * 1.5, Math.PI * step);
console.log(step);
options.start++;
step += 0.02;
if (options.start <= options.percent) {
setTimeout(animat, 10);
}
})();
},
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 = '#dbd7d2';
paper.lineCap = 'round';
paper.lineWidth = options.lineWidth;
paper.stroke();
paper.closePath();
paper.beginPath();
paper.arc(options.width / 2, options.height / 2, radius, start, end, false);
paper.strokeStyle = color;
paper.lineCap = 'square';
paper.lineWidth = options.lineWidth;
paper.stroke();
paper.closePath();
};
createProgressBar(bar);
#progressbar {
position: fixed;
top: 50%;
left: 50%;
margin-top: -150px;
margin-left: -150px;
}
canvas {
position: absolute;
display: block;
left: 0;
top: 0
}
span {
display: block;
color: #222;
text-align: center;
font-family: "sans serif", tahoma, Verdana, helvetica;
font-size: 30px
}
<div id="progressbar" data-width="320" data-height="320" data-linewidth="16"></div>
That's what the progress bar looks like: https://jsfiddle.net/ue20b8bd/
P.S. I've modified the code from github: https://github.com/su-ning/html5-circle-progressbar
The problem was with the lineCap property. Using 'butt' as a lineCap fixed the problem!

Categories

Resources