JavaScript if CSS animation ended - javascript

I am making a game in HTML/JavaScript and as part of this there is a "special ability" that can only be triggered every x seconds. I have created a GUI element that displays whether the ability is yet ready for use. Because I am using CSS animations, I want to check if, on a keypress, the element has finished animating (indicating that it is ready).
I want to do this in a simple if statement, rather than using addEventListener but I am not sure if this is possible.
My code so far is:
var keystate = {};
window.addEventListener("keydown", function(e) {
keystate[e.keycode || e.which] = true;
}, true);
window.addEventListener("keyup", function(e) {
keystate[e.keycode || e.which] = false;
}, true);
window.setInterval(function() {
if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well
//do stuff
document.getElementById("circle_flash_glow").classList.add("circle_flash_use");
}
}, 16.666666666666667);
#svg_circle_loader {
position: absolute;
right: 0;
bottom: 0;
background: none;
border: none;
margin: none;
padding: none;
}
#circle_flash_loader {
fill: none;
stroke: #F00;
stroke-width: 10px;
stroke-dashoffset: 80;
animation-fill-mode: forwards;
}
.circle_loader_load {
animation: circle_flash_loading linear;
animation-duration: 2.5s;
}
#keyframes circle_flash_loading {
0% {
stroke-dasharray: 0, 314;
}
100% {
stroke-dasharray: 314, 0;
}
}
#circle_flash_glow {
fill: none;
stroke: #F00;
stroke-width: 0px;
animation-fill-mode: forwards;
opacity: 1;
}
.circle_flash_use {
animation: circle_flash_pulse 0.6s ease-out;
}
#keyframes circle_flash_pulse {
0% {
opacity: 1;
stroke-width: 0px;
}
100% {
opacity: 0;
stroke-width: 70px;
}
}
<svg id="svg_circle_loader" width="200" height="200">
<defs>
<filter id="f1" x="-50" y="-50" width="200" height="200">
<feGaussianBlur stdDeviation="5"></feGaussianBlur>
</filter>
</defs>
<circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle>
<circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle>
</svg>

Add a variable to set the current state, and set it with setTimeout() for checking whether it is animating or not. also add window.onload to get its state by adding
window.onload=function(){
animating=true;
sts.value=animating;
window.setTimeout(function() {
animating=false;
sts.value=animating;
}, 2500);
};
where I am using 2500. because your css animation property has
2.5s=2500ms
var animating = false;
var keystate = {};
window.addEventListener("keydown", function(e) {
keystate[e.keycode || e.which] = true;
}, true);
window.addEventListener("keyup", function(e) {
keystate[e.keycode || e.which] = false;
}, true);
window.setInterval(function() {
if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well
//do stuff
if (!animating) {
alert("animation finished");
document.getElementById("circle_flash_glow").classList.add("circle_flash_use");
}
}
}, 16.666666666666667);
window.onload = function() {
animating = true;
sts.value = animating;
window.setTimeout(function() {
animating = false;
sts.value = animating;
}, 2500);
};
#svg_circle_loader {
position: absolute;
right: 0;
bottom: 0;
background: none;
border: none;
margin: none;
padding: none;
}
#circle_flash_loader {
fill: none;
stroke: #F00;
stroke-width: 10px;
stroke-dashoffset: 80;
animation-fill-mode: forwards;
}
.circle_loader_load {
animation: circle_flash_loading linear;
animation-duration: 2.5s;
}
#keyframes circle_flash_loading {
0% {
stroke-dasharray: 0, 314;
}
100% {
stroke-dasharray: 314, 0;
}
}
#circle_flash_glow {
fill: none;
stroke: #F00;
stroke-width: 0px;
animation-fill-mode: forwards;
opacity: 1;
}
.circle_flash_use {
animation: circle_flash_pulse 0.6s ease-out;
}
#keyframes circle_flash_pulse {
0% {
opacity: 1;
stroke-width: 0px;
}
100% {
opacity: 0;
stroke-width: 70px;
}
}
<svg id="svg_circle_loader" width="200" height="200">
<defs>
<filter id="f1" x="-50" y="-50" width="200" height="200">
<feGaussianBlur stdDeviation="5"></feGaussianBlur>
</filter>
</defs>
<circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle>
<circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle>
</svg>
<input id="sts" value="" />

Related

custom progress semicircle with vue 3

I have a progress semicircle and try to work dynamically with vue 3. I want a help because I dont know why it doesnt work. I change the progress variable but nothing change. Need to calculate of stroke-dashoffset but the calculation is wrong?
<template>
<svg class="circle" viewBox="2 -2 28 36" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop class="stop1" offset="0%" />
<stop class="stop2" offset="100%" />
</linearGradient>
<circle class="circle-background" r="16" cx="16" cy="16" shape-rendering="geometricPrecision"></circle>
<circle class="circle-progress" style="stroke-dashoffset: 75;" r="16" cx="16" cy="16" shape-rendering="geometricPrecision"></circle>
</svg>
</template>
<script setup>
import { ref, computed } from 'vue'
const progress = ref(50);
const strokeDashoffset = computed(() => (100 - (100 - progress.value)));
const background = computed(() => {
const angle = 360 * progress.value;
return `
radial-gradient(white 50%, transparent 51%),
conic-gradient(transparent 0deg ${angle}deg, gainsboro ${angle}deg 360deg),
conic-gradient(orange 0deg, yellow 90deg, lightgreen 180deg, green)
`;
});
</script>
<style>
/* svg {
filter: drop-shadow(0 0 10px rgb(0 0 0 / 0.4));
} */
.circle {
width: 200px;
height: 200px;
transform: rotate(-225deg);
fill: none;
stroke: white;
stroke-dasharray: 75 100;
stroke-linecap: round;
}
.circle-background {
fill: none;
stroke: gainsboro;
stroke-width: 3px;
stroke-dasharray: 75 100;
stroke-linecap: round;
}
.circle-progress {
fill: none;
stroke-linecap: round;
stroke: url(#gradient);
stroke-dasharray: 75 100;
stroke-dashoffset: 20;
stroke-linecap: round;
stroke-width: 3px;
transition: stroke-dashoffset 1s ease-in-out;
}
.stop1 {
stop-color: #e66465;
}
.stop2 {
stop-color: #9198e5;
}
#progress-circle {
background: v-bind(background);
}
.circle-progress {
stroke-dashoffset: v-bind(strokeDashoffset);
}
</style>

lazy line painter as a pre-loader

I have an animated SVG using lazy line painter that I would like to use as a pre-loader. How can I review the page content (with a transition or a simple fade-in) after the line animation is completed?
So the concept is this: on landing LOAD SVG animation when COMPLETE transition into page content.
<!-- Include lazylinepainter -->
<script src="https://cdn.jsdelivr.net/npm/ lazy-line-painter#1.9.4/lib/lazy-line-painter-1.9.4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/d3js/5.15.0/d3.min.js"></script>
<script type="text/javascript">
(function(){
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
let el = document.querySelector('#markin2');
let myAnimation = new LazyLinePainter(el, {"ease":"easeLinear","strokeWidth":2.2,"strokeOpacity":1,"strokeColor":"#fff"});
myAnimation.paint();
}
}
})();
</script>
<svg version="1.1" id="markin2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="314.094px" height="314.765px" viewBox="0 0 314.094 314.765" enable-background="new 0 0 314.094 314.765" xml:space="preserve" data-llp-composed="true" class="lazy-line-painter">
<circle fill="none" stroke-miterlimit="10" cx="157.828" cy="157.404" r="150.813" data-llp-id="markin2-0" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
<path id="#markin2" class=".markin2" fill="none" values="#000" stroke-miterlimit="10" d="M18.482,132.273
c1.019-4.147,1.774-8.38,3.099-12.427c7.988-24.405,24.611-39.774,49.798-44.317c26.582-4.795,47.878,5.064,64.031,26.525
c2.094,2.782,2.112,4.714-0.499,7.183c-3.496,3.306-6.592,7.035-10.095,10.837c-2.364-3.506-4.425-7.039-6.94-10.211
C104.843,93.427,81.91,88.297,62.884,97.426c-18.967,9.102-29.097,30.539-24.289,51.399c4.649,20.172,22.977,34.573,43.973,34.571
c13.572-0.002,24.751-5.104,33.906-15.18c22.505-24.771,44.815-49.735,67.885-73.971c17.361-18.239,39.164-24.295,63.441-17.369
c24.221,6.91,39.282,23.516,45.102,48.006c3.184,13.398,1.887,26.967-2.008,39.987c-1.322,4.422-5.715,7.985-8.899,11.78
c-10.94,13.035-24.349,21.988-41.47,24.67c-19.018,2.979-35.86-2.006-50.829-13.86c-1.162-0.92-2.304-1.863-4.361-3.533
c0,2.48-0.004,4.178,0,5.873c0.045,22.324,0.009,44.646,0.213,66.967c0.037,3.956-0.771,7.102-3.877,9.674
c-1.653,1.37-3.243,2.961-4.409,4.748c-2.552,3.912-5.974,4.865-10.668,3.637c0-6.688,0.01-13.473-0.003-20.258
c-0.041-22.488,0.024-44.979-0.227-67.465c-0.056-4.814,1.073-8.443,4.622-11.914c6.039-5.908,11.509-12.398,17.593-19.056
c4.06,8.205,9.36,14.85,16.678,19.736c15.507,10.355,35.698,10.172,51.128-0.49c15.202-10.506,22.338-29.406,18.086-47.903
c-3.979-17.298-19.188-31.573-37.106-33.975c-15.415-2.066-29.11,2.093-39.841,13.781c-21.17,23.057-42.371,46.092-63.192,69.461
c-14.497,16.271-31.743,25.988-53.992,25.404c-30.517-0.799-56.945-24.744-60.94-55.143c-0.123-0.934-0.602-1.821-0.915-2.73
C18.482,140.272,18.482,136.272,18.482,132.273z" data-llp-id="markin2-1" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
</svg>
CSS
body, html {
background: #000;
position: absolute;
width: 100%;
height: 100%;
top:0;
left:0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
#markin2 {
width: 40vw;
height: 40vh;
position: relative;
overflow: visible;
}
.markin2 {
animation: stroke_fill 4s linear forwards, changeColor 2s, forwards;
stroke-dasharray: 1538.2169189453125px;
stroke-dashoffset: 0;
}
#keyframes stroke_fill {
0% {
fill: white;
}
50% {
fill: white;
stroke-dashoffset: 0;
}
100% {
fill: black;
stroke-dashoffset: 0;
}
}
#keyframes changeColor {
from{ fill: rgba(0,0,0,0);}
to{ fill: rgba(0,0,0,1)}
}
Here is the SVG animation example:
https://codepen.io/cpawl/pen/zYvEqYq
The Lazy Line Painter library has some custom events built in to which you can listen. Such as the complete event whenever you animation has been completed. Whenever that event is called, hide the SVG.
In the example below I've added this event listener but also wrapped your animation in a Promise. This way you can wait for it to finish and then do something. And also another Promise which listens for the load event on the document. So that this is an actual page loader and the SVG would not disappear before the page would be loaded.
In your HTML first load the SVG and then the JS you see below here. Inside the then callback function either delete your SVG, or set a class to the body which hides the class. Anyway you see fit.
body,
html {
background: #000;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
#markin2 {
width: 20vw;
height: 20vh;
position: relative;
overflow: visible;
}
.markin2 {
animation: stroke_fill 4s linear forwards, changeColor 2s, forwards;
stroke-dasharray: 1538.2169189453125px;
stroke-dashoffset: 0;
}
#keyframes stroke_fill {
0% {
fill: white;
}
50% {
fill: white;
stroke-dashoffset: 0;
}
100% {
fill: black;
stroke-dashoffset: 0;
}
}
#keyframes changeColor {
from {
fill: rgba(0, 0, 0, 0);
}
to {
fill: rgba(0, 0, 0, 1);
}
}
.hsvg {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 100%;
height: 100%;
background: #000000;
z-index: 999;
transition: 2000ms ease-in-out;
transition-property: opacity, visibility;
}
body.is-loaded .hsvg {
opacity: 0;
visibility: hidden;
}
.main-content {
color: #fff;
}
<script src="https://cdn.jsdelivr.net/npm/lazy-line-painter#1.9.6/lib/lazy-line-painter-1.9.6.min.js"></script>
<!-- Include lazylinepainter -->
<div class="hsvg">
<svg version="1.1" id="markin2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="314.094px" height="314.765px" viewBox="0 0 314.094 314.765" enable-background="new 0 0 314.094 314.765" xml:space="preserve"
data-llp-composed="true" class="lazy-line-painter">
<circle fill="none" stroke-miterlimit="10" cx="157.828" cy="157.404" r="150.813" data-llp-id="markin2-0" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
<path id="#markin2" class=".markin2" fill="none" values="#000" stroke-miterlimit="10" d="M18.482,132.273
c1.019-4.147,1.774-8.38,3.099-12.427c7.988-24.405,24.611-39.774,49.798-44.317c26.582-4.795,47.878,5.064,64.031,26.525
c2.094,2.782,2.112,4.714-0.499,7.183c-3.496,3.306-6.592,7.035-10.095,10.837c-2.364-3.506-4.425-7.039-6.94-10.211
C104.843,93.427,81.91,88.297,62.884,97.426c-18.967,9.102-29.097,30.539-24.289,51.399c4.649,20.172,22.977,34.573,43.973,34.571
c13.572-0.002,24.751-5.104,33.906-15.18c22.505-24.771,44.815-49.735,67.885-73.971c17.361-18.239,39.164-24.295,63.441-17.369
c24.221,6.91,39.282,23.516,45.102,48.006c3.184,13.398,1.887,26.967-2.008,39.987c-1.322,4.422-5.715,7.985-8.899,11.78
c-10.94,13.035-24.349,21.988-41.47,24.67c-19.018,2.979-35.86-2.006-50.829-13.86c-1.162-0.92-2.304-1.863-4.361-3.533
c0,2.48-0.004,4.178,0,5.873c0.045,22.324,0.009,44.646,0.213,66.967c0.037,3.956-0.771,7.102-3.877,9.674
c-1.653,1.37-3.243,2.961-4.409,4.748c-2.552,3.912-5.974,4.865-10.668,3.637c0-6.688,0.01-13.473-0.003-20.258
c-0.041-22.488,0.024-44.979-0.227-67.465c-0.056-4.814,1.073-8.443,4.622-11.914c6.039-5.908,11.509-12.398,17.593-19.056
c4.06,8.205,9.36,14.85,16.678,19.736c15.507,10.355,35.698,10.172,51.128-0.49c15.202-10.506,22.338-29.406,18.086-47.903
c-3.979-17.298-19.188-31.573-37.106-33.975c-15.415-2.066-29.11,2.093-39.841,13.781c-21.17,23.057-42.371,46.092-63.192,69.461
c-14.497,16.271-31.743,25.988-53.992,25.404c-30.517-0.799-56.945-24.744-60.94-55.143c-0.123-0.934-0.602-1.821-0.915-2.73
C18.482,140.272,18.482,136.272,18.482,132.273z" data-llp-id="markin2-1" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
</svg>
</div>
<script>
const pageLoad = new Promise(resolve => {
window.addEventListener('load', resolve);
});
const animationLoad = new Promise(resolve => {
let el = document.querySelector('#markin2');
let myAnimation = new LazyLinePainter(el, {
"ease": "easeLinear",
"strokeWidth": 2.2,
"strokeOpacity": 1,
"strokeColor": "#fff"
});
myAnimation.paint();
myAnimation.on('complete', resolve);
});
Promise.all([pageLoad, animationLoad]).then(function() {
document.body.classList.add('is-loaded');
console.log('Load event fired and animation done');
});
</script>
<div class="main-content">
<h1>IS THIS THING ON?</h1>
</div>

seconds in a circle corner (like a clock)

I'm trying to create a circle that has small pins around (like seconds in a clock) to be like 60 of them (to count a minute)
here is a picture to describe what I mean
https://www.123rf.com/photo_91759207_stock-vector-close-up-of-digital-timer-showing-time-that-is-running-out-only-25-seconds-left-clock-on-vector-illu.html
I'm using React, javascript, css,
how can I make a loop that each pin would be stack to the circle 'corner' to fit his place ?
I'm having really hard time to find a way how to arrange them to look like it.
my final goal is to create a component that will receive a fill as prop that will represent the number of pins that needs to be in a different color, so I need a way to be able to control the background-color of each pin.
any advice would be awesome. thanks!
Do you mean something like the following? The code will create 60 "pins" for all tags with the class clock.
window.onload = function() {
var clocks = document.getElementsByClassName('clock'),
r = 0, i, j, d, clock;
for(j=0;j<clocks.length;j++) {
clock = clocks[j]
for(i=0;i<60;i++) {
d = document.createElement('div');
d.style.transform = "rotate("+ r +"deg)";
clock.appendChild(d);
r += 6;
}
}
}
.clock {
position:relative;
width:180px;
height:180px;
background:#eee;
}
.clock > div {
position:absolute;
margin-left:87px;
width:6px;
height:160px;
bottom:10px;
background: linear-gradient(to bottom, #491 16px, transparent 16px);
}
<div class="clock"></div>
Drawing the 'clock face' itself is easily done with SVG and stroke-dasharray.
Animating the clock can be done with an SVG mask, and some javascript to change the stroke-dashoffset.
An explanation of the maths for coming up with the values for the stroke-dasharray can be found in this answer.
const maskCircle = document.querySelector(".mask");
const clockText = document.querySelector(".clock-text");
const r = 50;
const c = 2 * r * Math.PI;
let secondsLeft = 60;
window.setInterval(function() {
if (secondsLeft > 0) {
secondsLeft--;
clockText.innerText = secondsLeft;
maskCircle.style.strokeDashoffset =
maskCircle.style.strokeDashoffset - c / 60 * -1;
} else {
clearInterval();
}
}, 1000);
body {
background: black;
}
.clock {
margin: 0 auto;
position: relative;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
}
.clock-face {
stroke-width: 15;
stroke-linecap: butt;
fill: transparent;
stroke-dasharray: 2.236 3;
}
.grey {
stroke: #333;
}
.white {
stroke: white;
}
.mask {
stroke-dasharray: 314.15 314.15;
stroke-dashoffset: 0;
}
.clock-text {
width: 100%;
margin: 0 auto;
color: white;
text-align: center;
position: absolute;
top: 50%;
font-size: 6em;
transform: translateY(-50%);
}
<div class="clock">
<svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="mask">
<circle class="clock-face white mask" cx="50" cy="50" r="50" transform="rotate(-90.5 50 50)" />
</mask>
</defs>
<circle class="clock-face grey" cx="50" cy="50" r="50" />
<circle class="clock-face white" cx="50" cy="50" r="50" mask="url(#mask)" />
</svg>
<div class="clock-text">60</div>
</div>

Polymer 3.0 Custom Element - How to Use javascript to interact with SVG

I am new on Polymer, so I'm learning while developing. Right now I'm using the latest version, Polymer 3.0. I already had a working frontpage on this site I'm working on. While I was trying to make everything work on polymer, I got stuck with making the javascript work.
On the original site, I was using this code
index.html
<div class="year-overview">
<div class="ano-lectivo">
<svg class="progress-ring" width="50%" height="50%" opacity="0" viewBox="0 0 42 42">
<circle class="progress-ring__circle" stroke="white" fill="transparent" r="15.91549430918954" cx="21" cy="21"></circle>
<text x="50%" y="53%" class="circle-text" text-anchor="middle">
<tspan class="currentDay">35</tspan>
<tspan class="daysLeft">/ 300</tspan>
<tspan x="50%" y="60%">Días Lectivos</tspan>
</text>
</svg>
</div>
And this is the javascript file:
function circleCircus(ringClass, circleClass, ringProgress) {
var circle = document.querySelector(circleClass);
var radius = circle.r.baseVal.value;
var circumference = radius * 2 * Math.PI;
var circleSVG = document.querySelector(ringClass); //For changing the opacity and not showing the circle before it loads
circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = `${circumference}`;
function setProgress(percent) {
const offset = circumference - percent / 100 * circumference;
circle.style.strokeDashoffset = offset;
}
setTimeout(function() {circleSVG.setAttribute("opacity", "100%");}, 1000); //Changing the circle opacity
setTimeout(function() { setProgress(ringProgress); }, 2000); //Changin the value in order to animate
}
//----------------------Progress Bar 1------------------------------------
circleCircus('.progress-ring', '.progress-ring__circle', 50);
Now that I'm working on Polymer I was creating a custom element for the donut chart, but I don't how to use or where to put the function that makes the strokeDasharray and the strokeDashoffset work correctly:
import { PolymerElement, html } from '#polymer/polymer/polymer-element.js';
class DonutChart extends PolymerElement {
static get template() {
return html`
<style>
.progress-ring__circle {
stroke-width: 3;
stroke: #000;
position: relative;
transition: stroke-dashoffset 0.35s, stroke-width 500ms ease-out, stroke 500ms ease-out;
-webkit-transition: stroke-dashoffset 0.35s, stroke-width 500ms ease-out, stroke 500ms ease-out; /* For Safari 3.1 to 6.0 */
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.currentDay {
font-size: 40%;
overflow: visible;
-webkit-transition: font-size 500ms ease-out; /* For Safari 3.1 to 6.0 */
transition: font-size 500ms ease-out;
}
.daysLeft {
font-size: 40%;
-webkit-transition: font-size 500ms, color 500ms; /* For Safari 3.1 to 6.0 */
transition: font-size 500ms, color 500ms;
}
.description {
font-size: 20%;
}
.circle-text {
fill: #000;
}
.progress-ring {
display: block;
position: relative;
margin-left: auto;
margin-right: auto;
}
svg:hover .currentDay {
font-size: 60%;
}
svg:hover .daysLeft {
font-size: 10%;
}
svg:hover .progress-ring__circle {
stroke-width: 1;
stroke: #5a64ed;
}
</style>
<svg class="progress-ring" width="100%" height="100%" viewBox="0 0 42 42">
<circle class="progress-ring__circle" stroke="white" fill="transparent" r="15.91549430918954" cx="21" cy="21"></circle>
<text x="50%" y="53%" class="circle-text" text-anchor="middle">
<tspan class="numbers" x="54%" y="50%"><tspan class="currentDay">35</tspan><tspan class="daysLeft">/300</tspan></tspan>
<tspan x="50%" y="60%" class="description">Días Lectivos</tspan>
</text>
</svg>
`;
}
constructor() {
super();
}
var circle = this.shadowRoot.querySelector('.progress-ring__circle');
var radius = circle.r.baseVal.value;
var circumference = radiius * 2 * Math.PI;
var circleSVG = this.shadowRoot.querySelector('.progress-ring');
circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = `${circumference}`;
function setProgress(percent) {
const offset = circumference - percent / 100 * circumference;
circle.style.strokeDashoffset = offset;
}
setProgress(79);
}
customElements.define('donut-chart', DonutChart);
Here is my original code and what I'm trying to accomplish in the custom element: https://codepen.io/maganalexis/pen/ePOxYX
Thank you for helping out.
After reading a lot of documents I found out the solution, I had to call the ready method and put my code under it:
import { PolymerElement, html } from '#polymer/polymer/polymer-element.js';
class DonutChart extends PolymerElement {
static get template() {
return html`
<style>
.progress-ring__circle {
stroke-width: 3;
stroke: #000;
position: relative;
transition: stroke-dashoffset 0.35s, stroke-width 500ms ease-out, stroke 500ms ease-out;
-webkit-transition: stroke-dashoffset 0.35s, stroke-width 500ms ease-out, stroke 500ms ease-out; /* For Safari 3.1 to 6.0 */
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.currentDay {
font-size: 40%;
overflow: visible;
-webkit-transition: font-size 500ms ease-out; /* For Safari 3.1 to 6.0 */
transition: font-size 500ms ease-out;
}
.daysLeft {
font-size: 40%;
-webkit-transition: font-size 500ms, color 500ms; /* For Safari 3.1 to 6.0 */
transition: font-size 500ms, color 500ms;
}
.description {
font-size: 20%;
}
.circle-text {
fill: #000;
}
.progress-ring {
display: block;
position: relative;
margin-left: auto;
margin-right: auto;
}
svg:hover .currentDay {
font-size: 60%;
}
svg:hover .daysLeft {
font-size: 10%;
}
svg:hover .progress-ring__circle {
stroke-width: 1;
stroke: #5a64ed;
}
</style>
<svg class="progress-ring" on-load="circleCircus" width="100%" height="100%" viewBox="0 0 42 42">
<circle class="progress-ring__circle" stroke="white" fill="transparent" r="15.91549430918954" cx="21" cy="21"></circle>
<text x="50%" y="53%" class="circle-text" text-anchor="middle">
<tspan class="numbers" x="54%" y="50%"><tspan class="currentDay">[[progressNum]]</tspan><tspan class="daysLeft">[[totalNum]]</tspan></tspan>
<tspan x="50%" y="60%" class="description">[[lowDescription]]</tspan>
</text>
</svg>
`;
}
static get properties() {
return {
progressNum: {
type: Number
},
totalNum: {
type: String
},
lowDescription: {
type: String
}
};
}
constructor() {
super();
}
ready(){
super.ready();
var circle = this.shadowRoot.querySelector('.progress-ring__circle');
var radius = circle.r.baseVal.value;
var circumference = radius * 2 * Math.PI;
var circleSVG = this.shadowRoot.querySelector('.progress-ring'); //For changing the opacity and not showing the circle before it loads
var proNum = `${this.progressNum}`;
circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = `${circumference}`;
function setProgress(percent) {
const offset = circumference - percent / 100 * circumference;
circle.style.strokeDashoffset = offset;
}
setTimeout(function() {circleSVG.setAttribute("opacity", "100%");}, 1000); //Changing the circle opacity
setTimeout(function() { setProgress(proNum); }, 2000); //Changin the value in order to animate
}
}
customElements.define('donut-chart', DonutChart);

Converting seconds in mm:ss in running JavaScript Timer

I'm just trying to update a friend's timer, which we did for an event a while ago. The timer works perfectly and already does everything it should (see and run Snippet). However, now I would like to display the format mm:ss instead of only seconds (eg. 180 -> 3:00). This must of course be able to count down further. Different approaches I googled have failed. Has anyone an idea how to solve my problem elegantly?
Edit: You can start and stop the timer by pressing 'Space'
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
body {
background-color: #333;
font-family: sans-serif;
}
.item {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%) scale(3.0);
}
.item h1 {
text-align: center;
position: absolute;
width: 100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 3em;
}
.item h2 {
text-align: center;
position: absolute;
width: 50%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 1.5em;
line-height: 0.9;
}
svg {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440;
/* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
</style>
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
<script type="text/javascript">
var running = false;
var time = 180;
var initialOffset = '440';
var runtime = 0;
$(document).keydown(function(e) {
switch (e.which) {
case 32:
setTimeout(function() {
if (running === false) {
running = true;
} else {
running = false;
};
}, 1);
break;
}
});
$(document).ready(function() {
console.log("ready!");
$('#start').click(function() {
running = true;
});
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset - (runtime * (initialOffset / (time + 10.5))));
$('h1').text(time - runtime);
if (runtime == 420) {
audioElement1.play();
}
if (runtime == time) {
clearInterval(interval);
$('.circle_animation').css('stroke-dashoffset', 880);
$('h1').text('');
$('h2').text('Time is up!');
}
if (running) {
runtime++;
};
}, 1000);
});
</script>
</head>
<body>
<div class="item html">
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<circle id="circle" r="65.85699" cy="81" cx="81" stroke-width="15" stroke="#ffffff" fill="none"/>
<circle id="circle" class="circle_animation" r="65.85699" cy="81" cx="81" stroke-width="16" stroke="#333" fill="none"/>
</g>
</svg>
<h1>180</h1>
<h2></h2>
</div>
</body>
</html>
Use modulus math:
function sec2human(seconds) {
sec = seconds % 60;
min = parseInt(seconds / 60);
if(sec.toString().length == 1) { // padding
sec = "0" + sec;
}
return min + ":" + sec;
}
Full working example:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
body {
background-color: #333;
font-family: sans-serif;
}
.item {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%) scale(3.0);
}
.item h1 {
text-align: center;
position: absolute;
width: 100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 3em;
}
.item h2 {
text-align: center;
position: absolute;
width: 50%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 1.5em;
line-height: 0.9;
}
svg {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440;
/* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
</style>
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
<script type="text/javascript">
var running = false;
var time = 180;
var initialOffset = '440';
var runtime = 0;
$(document).keydown(function(e) {
switch (e.which) {
case 32:
setTimeout(function() {
if (running === false) {
running = true;
} else {
running = false;
};
}, 1);
break;
}
});
$(document).ready(function() {
console.log("ready!");
$('#start').click(function() {
running = true;
});
$('h1').text(sec2human(time)); // added for initial display
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset - (runtime * (initialOffset / (time + 10.5))));
$('h1').text(sec2human(time - runtime)); // added function call
if (runtime == 420) {
audioElement1.play();
}
if (runtime == time) {
clearInterval(interval);
$('.circle_animation').css('stroke-dashoffset', 880);
$('h1').text('');
$('h2').text('Time is up!');
}
if (running) {
runtime++;
};
}, 1000);
});
function sec2human(seconds) {
sec = seconds % 60;
min = parseInt(seconds / 60);
if(sec.toString().length == 1) { // padding
sec = "0" + sec;
}
return min + ":" + sec;
}
</script>
</head>
<body>
<div class="item html">
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<circle id="circle" r="65.85699" cy="81" cx="81" stroke-width="15" stroke="#ffffff" fill="none"/>
<circle id="circle" class="circle_animation" r="65.85699" cy="81" cx="81" stroke-width="16" stroke="#333" fill="none"/>
</g>
</svg>
<h1>180</h1>
<h2></h2>
</div>
</body>
</html>
Here is the important part:
var seconds = time - runtime,
mins = ("0" + Math.floor(seconds / 60)).substr(-2),
secs = ("0" + (seconds % 60)).substr(-2);
$('h1').text(mins + ":" + secs);
Basically split up each part by minutes and seconds and concatenate them. The substring is to enforce double digit padding (ie: 02:03 instead of 2:3)
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
body {
background-color: #333;
font-family: sans-serif;
}
.item {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%) scale(3.0);
}
.item h1 {
text-align: center;
position: absolute;
width: 100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 3em;
}
.item h2 {
text-align: center;
position: absolute;
width: 50%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-110%);
color: #ffffff;
font-size: 1.5em;
line-height: 0.9;
}
svg {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440;
/* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
</style>
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
<script type="text/javascript">
var running = false;
var time = 180;
var initialOffset = '440';
var runtime = 0;
$(document).keydown(function(e) {
switch (e.which) {
case 32:
setTimeout(function() {
if (running === false) {
running = true;
} else {
running = false;
};
}, 1);
break;
}
});
$(document).ready(function() {
console.log("ready!");
$('#start').click(function() {
running = true;
});
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset - (runtime * (initialOffset / (time + 10.5))));
var seconds = time - runtime,
mins = ("0" + Math.floor(seconds / 60)).substr(-2),
secs = ("0" + (seconds % 60)).substr(-2);
$('h1').text(mins + ":" + secs);
if (runtime == 420) {
audioElement1.play();
}
if (runtime == time) {
clearInterval(interval);
$('.circle_animation').css('stroke-dashoffset', 880);
$('h1').text('');
$('h2').text('Time is up!');
}
if (running) {
runtime++;
};
}, 1000);
});
</script>
</head>
<body>
<div class="item html">
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<circle id="circle" r="65.85699" cy="81" cx="81" stroke-width="15" stroke="#ffffff" fill="none"/>
<circle id="circle" class="circle_animation" r="65.85699" cy="81" cx="81" stroke-width="16" stroke="#333" fill="none"/>
</g>
</svg>
<h1>180</h1>
<h2></h2>
</div>
</body>
</html>
Cool animation btw.

Categories

Resources