I'm working in this long press time counter
PROBLEM
It works well, but now instead of displaying time differences (end - start), I want it to display count numbers like working with count++ (1,2,3,4....)
I tried using delta = end.getSeconds() - start.getSeconds() ; or delta = end.getMilliseconds() - start.getMilliseconds();but sometimes it shows negative numbers https://jsfiddle.net/7h65ufLq/18/
(function(window, document, undefined){
'use strict';
var start;
var end;
var delta;
var button = document.getElementById('myCanvas');
function getDate(){
start = new Date();
}
function retrieveDate() {
end = new Date();
delta = end - start;
document.getElementById("demo").innerHTML = delta;
}
button.addEventListener("mousedown", getDate);
button.addEventListener("mouseup",retrieveDate );
button.addEventListener("touchstart", getDate);
button.addEventListener("touchend",retrieveDate );
document.addEventListener('contextmenu', event => event.preventDefault())
})(window, document)
#myCanvas{
height:100px;
width:100px;
border:1px solid red;
-webkit-user-select: auto;
-webkit-touch-callout: inherit;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
<canvas id="myCanvas">click</canvas>
<span id="demo">0</span>
Rather than display a delta time, you could just start an interval that increases the count at specific times. Then on mouse up, clear the interval.
For example:
(function(window, document, undefined) {
'use strict';
var button = document.getElementById('myCanvas');
var interval;
var count;
function startCount() {
count = 0
document.getElementById("demo").innerHTML = count
interval = setInterval(function() {
count++;
document.getElementById("demo").innerHTML = count
}, 1000) // increase count every second
}
function endCount() {
clearInterval(interval)
}
button.addEventListener("mousedown", startCount);
button.addEventListener("mouseup", endCount);
button.addEventListener("touchstart", startCount);
button.addEventListener("touchend", endCount);
document.addEventListener('contextmenu', event => event.preventDefault())
})(window, document)
#myCanvas {
height: 100px;
width: 100px;
border: 1px solid red;
-webkit-user-select: auto;
-webkit-touch-callout: inherit;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
<canvas id="myCanvas">click</canvas>
<span id="demo">0</span>
Related
I want to add a timer which decrease Automatically (like 10 seconds, 9 seconds... till 0 seconds) but the progress bar will increase. And I am new to javascript, and the below code also copied from another site , so please help me in adding timer inside the progress bar
Till now I did this code
I want to make like this
Demo
<div class="progress"></div>
<style>
.progress-bar {
height: 20px;
background: #1da1f2;
box-shadow: 2px 14px 15px -7px rgba(30, 166, 250, 0.36);
border-radius: 50px;
transition: all 0.5s;
}
.progress {
width: 100%;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: start;
background: #e6e9ff;
border-radius: 20px;
box-shadow: 0px 10px 50px #abb7e9;
}
</style>
<script>
/*
* (class)Progress<nowValue, minValue, maxValue>
*/
//helper function-> return <DOMelement>
function elt(type, prop, ...childrens) {
let elem = document.createElement(type);
if (prop) Object.assign(elem, prop);
for (let child of childrens) {
if (typeof child == "string") elem.appendChild(document.createTextNode(child));
else elem.appendChild(elem);
}
return elem;
}
//Progress class
class Progress {
constructor(now, min, max, options) {
this.dom = elt("div", {
className: "progress-bar"
});
this.min = min;
this.max = max;
this.intervalCode = 0;
this.now = now;
this.syncState();
if(options.parent){
document.querySelector(options.parent).appendChild(this.dom);
}
else document.body.appendChild(this.dom)
}
syncState() {
this.dom.style.width = this.now + "%";
}
startTo(step, time) {
if (this.intervalCode !== 0) return;
this.intervalCode = setInterval(() => {
console.log("sss")
if (this.now + step > this.max) {
this.now = this.max;
this.syncState();
clearInterval(this.interval);
this.intervalCode = 0;
return;
}
this.now += step;
this.syncState()
}, time)
}
end() {
this.now = this.max;
clearInterval(this.intervalCode);
this.intervalCode = 0;
this.syncState();
}
}
let pb = new Progress(15, 0, 100, {parent : ".progress"});
//arg1 -> step length
//arg2 -> time(ms)
pb.startTo(5, 500);
//end to progress after 5s
setTimeout( () => {
pb.end()
}, 10000)
</script>
I think the core problem is that the code you copied is overly complicated especially for beginners. What I would recommend is to start from what you know and build up.
Here is the functionality you want written using only core principles of JavaScript and CSS.
let initialTime = 10; //All time in seconds
let timeLeft = initialTime;
let interval;
let progressBarTextElement = document.getElementById('progress-bar-text');
let progressBarElement = document.getElementById('progress-bar');
function render() {
let progressPercentage = (1 - (timeLeft / initialTime) ) * 100;
progressBarElement.style.width = progressPercentage + '%';
progressBarTextElement.innerHTML = timeLeft + 's';
}
function tick() {
timeLeft = timeLeft - 1;
if(timeLeft <= 0) {
clearInterval(interval); //Stops interval
}
render(); //Updates html
}
function startProgressBar() {
interval = setInterval(tick, 1000); //Will call tick every second
render();
}
startProgressBar();
html {font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;}
.progress-bar-continer {
height: 80px;
width: 100%;
position: relative;
display: flex;
justify-content: center;
align-items: center;
background-color: #406086;
}
.progress-bar {
background-color: #1b3e80;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0%;
transition: width 1s; /* Makes progressBar smooth */
transition-timing-function: linear; /* Try to remove this line for more tick tock feel */
}
.progress-bar-text {
color: white;
font-size: 24px;
font-weight: 700;
position: relative;
z-index: 1;
}
<div class="progress-bar-continer">
<div class="progress-bar" id="progress-bar"></div>
<div class="progress-bar-text" id="progress-bar-text"></div>
<div>
Try to understand the code best you can and you will have no problems adding any features you want on top of it. All the fancy stuff will come later with experience.
I am trying to make an infinite scroll in my chat. I'm using the scroll event to check if scrolltop < clientHeight and call a function loadMore if it is. This works pretty well as long as you never scroll to the very top. I made a gif to show this (hopefully it makes sense):
If you still have more room to scroll when the older messages get loaded, you keep your place and the scroll bar gets pushed down.
But if you are scrolled all the way to the top when the older messages get loaded, the scroll bar stays pinned to the top and you lose your place (also the scroll event stops being fired, so you stop loading messages unless you scroll down a little)
Has anyone else experienced this? And what did you do to fix it? Any advice appreciated. Thanks!
updated the answer to support 2 directions (up or down) and loading paddings. Please run the snippet in expanded mode, inline preview frame is too small for the scrollable list.
var isLoadingAlready = false;
var upDirection = true; // to load records on top of the list; false to load them to the end of the list
var loadThreshold = 100; // distance to the edge (in pixels) to start loading
var howManyDataLoadsAvailable = 5;
if (upDirection){
$('.scroll')[0].scrollTop = 100000; // scrolling all the way down
$('.scroll').css('paddingTop', loadThreshold);
} else {
$('.scroll').css('paddingBottom', loadThreshold);
}
$('.scroll').on('scroll', function () {
var s = this; // picking DOM element
if (s) { // just to be sure/safe
var scrollableHeight = s.scrollHeight - s.clientHeight;
if (scrollableHeight > 0) {
var scrollTop = s.scrollTop;
var distToTheEdge = upDirection?scrollTop:scrollableHeight - scrollTop;
if (distToTheEdge < loadThreshold && !isLoadingAlready) {
isLoadingAlready = true;
loadMoreRecords(function () { // assuming you have a callback to allow next loading
isLoadingAlready = false;
});
}
}
}
});
loadMoreRecords();
function loadMoreRecords(doneCallback){
$('.scroll').addClass('loading');
// simulating the actual loading process with setTimeout
setTimeout(function(){
// simulated items to insert:
var items = [];
if (howManyDataLoadsAvailable-- > 0){
for (var i = 0; i < 10; i++){
items.push($('<li>').text('msg: '+(i+1)+', parts left: '+howManyDataLoadsAvailable));
}
}
var $se = $('.scroll'); // scrollable DOM element
var $ul = $('.scroll ul');
var se = $se[0];
if (upDirection) {
var hBefore = $ul.height();
$ul.prepend(items);
var hDiff = $ul.height() - hBefore;
se.scrollTop = Math.max(hDiff, loadThreshold);
} else {
$ul.append(items);
se.scrollTop = se.scrollHeight - se.clientHeight - Math.max(se.scrollHeight - se.clientHeight - se.scrollTop, loadThreshold);
}
$se.removeClass('loading');
if (typeof(doneCallback) === 'function'){
doneCallback();
}
}, 500);
}
.scroll{
overflow-y: auto;
max-height: 200px;
border: 2px dashed #aaa;
padding: 0.5em;
margin: 1em;
}
.scroll.loading{
background-color: #f5f5f5;
}
ul{
list-style: none;
padding: 0;
}
li{
padding: 0.5em;
border: 1px solid #eee;
border-radius: 0.5em;
margin: 0.2em;
animation: colorchange 1200ms;
background: white;
box-shadow: 1px 1px 5px 0px rgba(0,0,0,0.05);
}
#keyframes colorchange
{
0% {background: #def;}
100% {background: white;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="scroll">
<ul></ul>
</div>
I'm trying to visualize a countdown via a div's width. This could be used for something like a banner system showing when the next banner will slide in, or for a notification system showing how long the notification will be visible.
So in my example below, I have the .outer div emptied after 5 seconds, but the .timer div's width is not reaching width: 0%; at the same time as the setTimeout() kicks in.
The variable len would represent how long the banner or notification would be shown for.
The calculation in the variable offset is what is throwing me off (I think), I cannot seem to get the calculation correct. I would like it to be dynamic, meaning, no matter what len is and what the width of the outer/parent div is, it will always take len time to reach width: 0%;.
I hope my explanation makes sense. Any help would be greatly appreciated.
const len = 5000;
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let timerWidth = timer.offsetWidth;
let offset = len / timerWidth;
let init = 100;
let interval = setInterval(() => {
init = init - offset;
timer.style.width = init + '%';
}, 1000);
setTimeout(() => {
outer.innerHTML = '';
clearInterval(interval);
}, len);
* {
box-sizing:border-box;
}
body {
padding: 100px 10px 10px;
}
.outer {
width: 100%;
border: 1px solid slategray;
padding: 10px;
}
.timer {
width: 100%;
height: 10px;
background: red;
transition: all 1000ms linear;
}
<div class="outer">
<div class="timer"></div>
<p>Some Message Here!</p>
</div>
Two problems with the code:
interval doesn't start as soon as the page is loaded so the CSS is late in transition.
offset was wrong indeed.
Here's how I fixed it:
let toElapse = 3000; // modify as you like
let tick = 1000; //if you modify this don't forget to replicate
//in CSS transition prop
let countDownEl = document.querySelector('#countdown');
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let init = 100;
// we calculate the offset based on the tick and time to elapse
let offset = init / (toElapse/tick);
countDownEl.innerHTML = init;
setTimeout(()=>{
// we need to start the first CSS transition ASAP so it is not late.
init = init - offset;
timer.style.width = init.toFixed(2) + '%';
},0)
let interval = setInterval(() => {
// the same interval.
countDownEl.innerHTML = init;
init = init - offset;
timer.style.width = init.toFixed(2) + '%';
}, tick);
setTimeout(() => {
// the same clearance timeout
outer.innerHTML = '';
clearInterval(interval);
}, toElapse);
* {
box-sizing:border-box;
}
body {
padding: 100px 10px 10px;
}
.outer {
width: 100%;
border: 1px solid slategray;
padding: 10px;
}
.timer {
width: 100%;
height: 10px;
background: red;
transition: width 1s linear;
}
<div class="outer">
<div class="timer"></div><span id="countdown"></span>
<p>Some Message Here!</p>
</div>
If you use percentage in width you don't need to know the width of your box.
you just need to substract and add on offset to timeout.
const len = 5000;
let outer = document.querySelector('.outer');
let timer = document.querySelector('.timer');
let timerWidth = timer.offsetWidth;
let offset = 100 * 1000 / 5000;
let interval = setInterval(() => {
init = init - 20;
timer.style.width = init + '%';
}, 1000);
setTimeout(() => {
outer.innerHTML = '';
clearInterval(interval);
}, len + 1000);
I am rotating an element when I click on a button using setInterval along with clearInterval to stop rotation when a certain value is reached by clearing the interval time t.It works well but when I click on the same button over and over again before the current animation completes , the animation no longer stop rotating.clearInterval does not work in this case.
The code below illustrates it :
var t; // interval
var x = 0 ; // counter
var cal ; // element to be rotate
function prepareRotatesX(){
x=x+5;
cal =document.getElementById("myCalendar");
cal.style.transform="rotateX("+x+"deg)";
if(x>360){ clearInterval(t); x=0;}
}
function rotate(){
t = setInterval(function(){
prepareRotatesX();
}, 10);
}
#myCalendar{
position: absolute;
top:45px;
left:20px;
border: 2px solid blue;
width: 210px;
height:170px;
background-color:blue;
}
<div id="myCalendar">
<!---HERE COME CALENDAR -->
</div>
<!-- make rotation-->
<button id='bnext' onclick='rotate();'>Rotation</button>
So how to stop rotation in this case ?
The option you are probably after is if it is still running than do not run it again. So see if t is defined, if it is exit. And when the loop is done, than you can reset the interval.
var t; // interval
var x = 0; // counter
var cal; // element to be rotate
function prepareRotatesX() {
x = x + 5;
cal = document.getElementById("myCalendar");
cal.style.transform = "rotateX(" + x + "deg)";
if (x > 360) {
clearInterval(t);
x = 0;
t = null
}
}
function rotate() {
if (t) return; // if t is defined, than it is running so exit
t = setInterval(function() {
prepareRotatesX();
}, 10);
}
#myCalendar {
position: absolute;
top: 45px;
left: 20px;
border: 2px solid blue;
width: 210px;
height: 170px;
background-color: blue;
}
<div id="myCalendar">
<!---HERE COME CALENDAR -->
</div>
<!-- make rotation-->
<button id='bnext' onclick='rotate();'>Rotation</button>
other option is to just clear the interval and restart it
function rotate() {
if (t) clearInterval(t)
t = setInterval(function() {
prepareRotatesX();
}, 10);
}
Variable t declared globally is creating problem, if you move t to local scope in your code. It should fix your problem (Assuming that previous clicks rotation should continue)
In case if you want to abort the previous click, you can follow solution given by #epascarello
var x = 0 ; // counter
var cal ; // element to be rotate
function prepareRotatesX(t){
x=x+5;
cal =document.getElementById("myCalendar");
cal.style.transform="rotateX("+x+"deg)";
if(x>360){ clearInterval(t); x=0;}
}
function rotate(){
var t; // interval
t = setInterval(function(){
prepareRotatesX(t);
}, 10);
}
#myCalendar{
position: absolute;
top:45px;
left:20px;
border: 2px solid blue;
width: 210px;
height:170px;
background-color:blue;
}
<div id="myCalendar">
<!---HERE COME CALENDAR -->
</div>
<!-- make rotation-->
<button id='bnext' onclick='rotate();'>Rotation</button>
In your rotate method, which is called on click you need to make a change to see if the interval is defined and clear it if it is. See below code update.
var t; // interval
var x = 0 ; // counter
var cal ; // element to be rotate
function prepareRotatesX(){
x=x+5;
cal =document.getElementById("myCalendar");
cal.style.transform="rotateX("+x+"deg)";
if(x>360){ clearInterval(t); x=0;}
}
function rotate(){
if(t !== undefined) {
clearInterval(t);
}
t = setInterval(function(){
prepareRotatesX();
}, 10);
}
#myCalendar{
position: absolute;
top:45px;
left:20px;
border: 2px solid blue;
width: 210px;
height:170px;
background-color:blue;
}
<div id="myCalendar">
<!---HERE COME CALENDAR -->
</div>
<!-- make rotation-->
<button id='bnext' onclick='rotate();'>Rotation</button>
For teaching myself javascript (and for getting/giving more insight in the field of astronomy :) ), I am setting up a page that displays relative positions of sun and moon.
Right now, the speed of the sun and moon movement is still fixed, but I would really like to make this dynamically user-definable via an input field. So, the initial speed is '30', and a user can speed this up or slow this down. Obviously, the ratio between sun and moon must stay fixed. I tried a lot of things (see some relics in the code, but I can't get it to work.
Anyone with more experience with javascript can assist me in doing this? Also, I notice CPU usage gets very high during this animation. Are there simple steps in making this script more efficient?
var dagen = 0;
function speed($this){
var speedSetting = $this.value;
//alert(speedSetting);
//return per;
}
function periode(bolletje, multiplier=30){
if (bolletje == 'zon'){var per = (multiplier*24/2);}
if (bolletje == 'maan'){var per = (multiplier*24*29.5/2);}
return per;
}
function step(delta) {
elem.style.height = 100*delta + '%'
}
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
function terugweg(element, delta, duration) {
var to = -300;
var bolletje = element.getAttribute('id');
per = periode(bolletje);
document.getElementById(bolletje).style.background='transparent';
animate({
delay: 0,
duration: duration || per,
//1 sec by default
delta: delta,
step: function(delta) {
element.style.left = ((to*delta)+300) + "px"
}
});
if(bolletje == 'zon'){
dagen ++;
}
bolletje = element;
document.getElementById('dagen').innerHTML = dagen;
//setInterval(function (element) {
setTimeout(function (element) {
move(bolletje, function(p) {return p})
}, per);
}
function move(element, delta, duration) {
var to = 300;
var bolletje = element.getAttribute('id');
per = periode(bolletje);
document.getElementById(bolletje).style.background='yellow';
animate({
delay: 0,
duration: duration || per,
//1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
}
});
bolletje = element;
//setInterval(function (element) {
setTimeout(function (element) {
terugweg(bolletje, function(p) {return p})
}, per);
}
hr{clear: both;}
form{display: block;}
form label{width: 300px; float: left; clear: both;}
form input{float: right;}
.aarde{width: 300px; height: 300px; border-radius: 150px; background: url('https://domain.com/img/aarde.png');}
#zon{width: 40px; height: 40px; background: yellow; border: 2px solid yellow; border-radius: 20px; position: relative; margin-left: -20px; top: 120px;}
#maan{width: 30px; height: 30px; background: yellow; border: 2px solid yellow; border-radius: 16px; position: relative; margin-left: -15px; top: 115px;}
<form>
<div onclick="move(this.children[0], function(p) {return p}), move(this.children[1], function(p) {return p})" class="aarde">
<div id="zon"></div>
<div id="maan"></div>
</div>
Dagen: <span id="dagen">0</span>
</form>
<form>
<label><input id="snelheid" type="range" min="10" max="300" value="30" oninput="speed(this)">Snelheid: <span id="snelheidDisplay">30</span></label>
</form>
First, change onlick to oninput in speed input tag.
<input id="snelheid" type="number" value="30" oninput="speed(this)">
And in your speed() function set multiplier = $this.value. multiplier should be global:
var multiplier = 30;
function speed($this){
console.log($this.value);
multiplier = $this.value;
//alert(speedSetting);
//return per;
}
function periode(bolletje){
if (bolletje == 'zon'){var per = (multiplier*24/2);}
if (bolletje == 'maan'){var per = (multiplier*24*29.5/2);}
return per;
}
Here is an example:
https://jsfiddle.net/do4n9L03/2/
Note: multiplier is not speed, it is delay. If you increase it it become slower