I want to implement a function as follows
There is a function such as
const FloatRed = (startDate, endDate, imgUrl) => {}
StartDate is the start date. When the start date arrives, insert an img element into the body
EndDate is the end date. When the end date arrives, destroy the img element
How to realize it? Thank you
For example,
FloatRed ("2023-02-06 14:00", "2023-02-06 14:05", "xxx. com/xxx/xxx. jpg")
I wrote a simple version
But I think it's always strange. Although it can basically meet the needs, I hope to give some suggestions and help improve it. thank you
let Is = false
let t = null;
const FloatingRed = (startDate, endDate, Imgurl) => {
let nowDate = new Date().getTime()
let startDate_s = new Date(startDate).getTime()
let endDate_s = new Date(endDate).getTime()
let ImageObj = new Image();
let Dom;
ImageObj.onload = (e) => {
Dom = `<div id="FloatRedImg"><img src="${Imgurl}" width=${ImageObj.width} height="${ImageObj.height}"></div>`
let Dom_old = $("#FloatRedImg").html()
if (nowDate >= endDate_s) {
$("#FloatRedImg").remove()
clearInterval(t)
}
if (Dom_old) {
return
}
if (nowDate > startDate_s) {
$("body").prepend(Dom)
}
}
ImageObj.src = Imgurl;
}
t = setInterval(() => {
FloatingRed("2023-02-06 16:49", "2023-02-06 16:50", "2022102201.jpg")
}, 1000)
If you put new Date().getTime() in a variable, it will make the time value constant. I prefer you call new Date().getTime() in setInterval, so that time will be updated continuously. Try this with change the startDate and endDate value :
let Is=false
let t;
const FloatingRed = (startDate, endDate, Imgurl) => {
let startDate_s = new Date(startDate).getTime()
let endDate_s = new Date(endDate).getTime()
let ImageObj = new Image();
let Dom;
ImageObj.onload=(e) => {
Dom = `<div id="FloatRedImg"><img src="${Imgurl}" width=${ImageObj.width} height="${ImageObj.height}"></div>`;
if (new Date().getTime() > startDate_s && new Date().getTime() <= endDate_s) {
$("body").prepend(Dom)
}
t = setInterval(() => {
if(new Date().getTime() > endDate_s) {
$("#FloatRedImg").remove();
clearInterval(t);
}
}, 1000);
}
ImageObj.src=Imgurl;
}
FloatingRed("2023-02-07 08:45", "2023-02-07 09:00", "https://picsum.photos/200");
setInterval(()=>{
$('#now').html(new Date().toLocaleString());
},1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="now"></div>
Related
I have stopwatch function that can run the stopwatch like below :
Stopwatch.vue
<script>
export default {
data() {
return {
time: "00:00.000",
timeBegan: null,
timeStopped: null,
stoppedDuration: 0,
started: null,
running: false,
};
}
methods: {
start() {
if (this.running) return;
if (this.timeBegan === null) {
this.timeBegan = new Date();
}
if (this.timeStopped !== null) {
this.stoppedDuration += new Date() - this.timeStopped;
}
this.started = setInterval(this.clockRunning, 10);
this.running = true;
},
clockRunning() {
let currentTime = new Date();
let timeElapsed = new Date(
currentTime - this.timeBegan - this.stoppedDuration
);
let min = timeElapsed.getUTCMinutes();
let sec = timeElapsed.getUTCSeconds();
let ms = timeElapsed.getUTCMilliseconds();
this.time =
this.zeroPrefix(min, 2) +
":" +
this.zeroPrefix(sec, 2) +
"." +
this.zeroPrefix(ms, 3);
},
zeroPrefix(num, digit) {
let zero = "";
for (let i = 0; i < digit; i++) {
zero += "0";
}
return (zero + num).slice(-digit);
},
},
mounted() {
this.start();
}
};
</script>
With the above function the stopwatch works well, but I want to move the function of the stopwatch using vuex so that it can make it easier for me to call the stopwatch function from any component.
index.js <-- In Vuex/store/stopwatch
export default {
state: {
time: "00:00.000",
timeBegan: null,
timeStopped: null,
stoppedDuration: 0,
started: null,
running: false,
},
actions: {
start(context) {
if (context.state.running) return;
if (context.state.timeBegan === null) {
context.state.timeBegan = new Date();
}
if (context.state.timeStopped !== null) {
context.state.stoppedDuration += new Date() - context.state.timeStopped;
}
context.state.started = setInterval(context.dispatch('clockRunning'), 10);
context.state.running = true;
},
clockRunning(context) {
let currentTime = new Date();
let timeElapsed = new Date(
currentTime - context.state.timeBegan - context.state.stoppedDuration
);
let min = timeElapsed.getUTCMinutes();
let sec = timeElapsed.getUTCSeconds();
let ms = timeElapsed.getUTCMilliseconds();
context.state.time =
context.dispatch('zeroPrefix')(min, 2) +
":" +
context.dispatch('zeroPrefix')(sec, 2) +
"." +
context.dispatch('zeroPrefix')(ms, 3);
},
zeroPrefix(num, digit) {
let zero = "";
for (let i = 0; i < digit; i++) {
zero += "0";
}
return (zero + num).slice(-digit);
}
},
mutations: {},
getters: {}
}
If I run the code above, I get an error :
I think the error occurs in the following line :
context.state.started = setInterval(context.dispatch('clockRunning'), 10);
But I didn't find any error in the line above.
This is the same line that works before move to vuex :
this.started = setInterval(this.clockRunning, 10);
How to solve the error above?
Update :
I made a demo code on codesandbox
I've tried changing it as #Estus Flask suggested but the error still appears,
I tried to change like the code below :
setInterval(() => context.dispatch('clockRunning'), 10)
But displays an error page that continues to grow every second until it becomes hundreds in a short time, with the appearance of the error makes my PC slow down and consumes all CPU performance to 100%.
Error appears as shown below :
Can anyone help to solve this error?
I put a stopper when the time reached 90 secs = 1min 30sec, but you can remove that. Just call a commit on 'stop'.
export default {
state: {
time: "00:00.000",
timeStarted: null,
timeBegan: null,
timeStopped: null,
stoppedDuration: 0,
started: null,
running: false,
maxSeconds: 90,
temp:{
min: "0",
sec: "0",
ms: "0",
secondsPassed: 0
}
},
actions: {
start({state, commit, dispatch}) {
if (state.running) return;
if (state.timeBegan === null) {
state.timeBegan = new Date();
}
if (state.timeStopped !== null) {
state.stoppedDuration += new Date() - state.timeStopped;
}
commit("start", {
callback:()=>{
dispatch("stopIfReachedMaximumSeconds");
dispatch("clockRunning");
}
});
},
async clockRunning({state, commit, dispatch}) {
let currentTime = new Date();
let timeElapsed = new Date(
currentTime - state.timeBegan - state.stoppedDuration
);
let min = timeElapsed.getUTCMinutes();
let sec = timeElapsed.getUTCSeconds();
let ms = timeElapsed.getUTCMilliseconds();
commit("newTemp", {
key: 'secondsPassed',
value: parseInt(Math.abs((state.timeStarted - new Date() )/ 1000))
});
if (state.running) {
await dispatch("zeroPrefix",{num: min, digit:2}).then(zeroPrefixResponse => {
commit("newTemp", {
key: 'min',
value: zeroPrefixResponse
})
});
await dispatch("zeroPrefix",{num: sec, digit:2}).then(zeroPrefixResponse => {
commit("newTemp", {
key: 'sec',
value: zeroPrefixResponse
})
});
await dispatch("zeroPrefix",{num: ms, digit:3}).then(zeroPrefixResponse => {
commit("newTemp", {
key: 'ms',
value: zeroPrefixResponse
})
});
state.time = state.temp.min + ":" + state.temp.sec + "." + state.temp.ms;
}
},
zeroPrefix(context, payload) {
return new Promise(resolve => {
let zero = "";
for (let i = 0; i < payload.digit; i++) {
zero += "0";
}
resolve((zero + payload.num).slice(-payload.digit));
});
},
stopIfReachedMaximumSeconds({state, commit}){
if(state.temp.secondsPassed >= state.maxSeconds){
console.log("REACHED MAXIMUM SECONDS");
commit("stop");
}
}
},
mutations: {
newTemp(state, payload){
state.temp[payload.key] = payload.value;
},
addSecondPassed(state, second){
state.temp.secondsPassed += second;
},
resetSecondPassed(state){
state.temp.secondsPassed = 0;
},
start(state, payload){
state.timeStarted = new Date();
state.started = setInterval(()=>{
payload.callback();
}, 10);
state.running = true;
},
stop(state){
clearInterval(state.started);
state.timeStarted = null;
state.started = null;
state.running = false;
state.temp.secondsPassed = 0;
}
},
getters: {}
};
The error means what it says, context.dispatch('clockRunning') expression is a promise while it's supposed to be a function, because the first argument of setInterval should be a function.
The first argument of setInterval should be a function. In case the intention is to dispatch an action on time interval, it should be:
setInterval(() => context.dispatch('clockRunning'), 10)
dispatch returns a promise, not a function. Action parameters should be passed as dispatch arguments:
context.dispatch('zeroPrefix', min, 2)
It's incorrect to use the result of zeroPrefix action in an expression. An action acts on the store and is supposed to returns a promise of asynchronous operation, not result. The result needs to be written and read from the state. In this case zeroPrefix doesn't operate on the state and shouldn't be a part of the store at all, it has be extracted to helper function.
I want to create a 3 hours countdown that runs in the background and repeats when it reaches 00:00:00. How can I do it using HTML and javascript? Thank you!
You can use Web Worker:
Run in background
No throttled ( settimeout-setinterval-on-inactive-tab )
// index.html
<div id="box">60</div>
<script>
let box = document.getElementById('box');
let worker = new Worker('countdown.js');
worker.postMessage(60);
worker.onmessage = function (event) {
box.innerHTML = event.data;
}
</script>
// countdown.js
onmessage = function (e) {
let num = e.data;
let count = setInterval(function () {
postMessage(--num);
if (num <= 0) {
clearInterval(count);
close();
}
}, 1000);
}
For background countdown. I think the big issue that you need to face is when you are leave the page or open a new tabs. right?
Do you want to make the countdown work even the tab is not active?
maybe requestAnimationFrame is helpful for you.
function showTime() {
remainingTime = getRemainingTime(endTime);
var seconds = pad((remainingTime / 1000));
console.log('remain time is: ', seconds + " sec")
if (remainingTime >= 1000) {
window.requestAnimationFrame(showTime);
} else {
console.log('Time up!!!')
}
}
function getRemainingTime(deadline) {
var currentTime = new Date().getTime();
return deadline - currentTime;
}
function pad(value) {
var sl = (""+Math.floor(value)).length;
if(sl > 2){
return ('0' + Math.floor(value)).slice(-sl);
}
return ('0' + Math.floor(value)).slice(-2);
}
endTime = new Date().getTime() + 1000*60;
window.requestAnimationFrame(showTime);
Demo here: https://codepen.io/quanhv/pen/oNZWxvB
As I understood from MDN, I am supposed to make variable and assign setInterval function to it, so that I could use that variable and call clearInterval for it, but for some reason, my code is now working. It is properly fetching data with buttonStart, but will not stop fetching data with buttonStop.
Thank you for your time.
const buttonStart = document.querySelector('#start')
const buttonStop = document.querySelector('#stop')
const list = document.querySelector('#list')
class Price {
constructor(time, price) {
this.time = time
this.price = price
}
}
const fetchBitcoin = async () => {
try {
const res = await fetch('https://api.cryptonator.com/api/ticker/btc-usd');
const data = await res.json();
const newPrice = new Price(data.timestamp, data.ticker.price)
return newPrice
} catch (e) {
console.log("Something went wrong in downloading price", e)
}
}
const addNewPrice = async () => {
const newLI = document.createElement('LI')
const newElement = await fetchBitcoin()
const newTime = convertTime(newElement.time)
newLI.append(newTime, ' ', newElement.price.slice(0, 8))
list.append(newLI)
}
function convertTime(time) {
let unix_timestamp = time
var date = new Date(unix_timestamp * 1000);
var hours = date.getHours();
var minutes = "0" + date.getMinutes();
var seconds = "0" + date.getSeconds();
var formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
return formattedTime
}
let interval = buttonStart.addEventListener('click', () => {
setInterval(addNewPrice, 2000)
})
buttonStop.addEventListener('click', () => clearInterval(interval));
You need to create interval variable and assign the return value of the setInterval method rather than addEventListener because addEventListener does not return anything,
let interval;
buttonStart.addEventListener('click', () => {
interval = setInterval(addNewPrice, 2000)
})
You need to adjust the example below to your use case but this is what you need in general:
var timerEl = document.querySelector('.js-timer');
var startBtn = document.querySelector('.js-start');
var stopBtn = document.querySelector('.js-stop');
var intervalId;
var timer = 0;
startBtn.addEventListener('click', function() {
stopTimer();
console.log('start timer');
intervalId = setInterval(execTimer, 100);
});
stopBtn.addEventListener('click', stopTimer);
function stopTimer() {
timer = 0;
console.log('stop timer');
clearInterval(intervalId);
renderTimer();
}
function execTimer() {
timer++;
renderTimer();
console.log('timer score', timer);
}
function renderTimer() {
timerEl.textContent = timer;
}
<span class="js-timer"></span><br />
<button class="js-start">Start</button>
<button class="js-stop">Stop</button>
I want to create a clock using java script. For this i'm using classes.
const htmlMarkup = (hours = 0, minutes = 0, seconds = 0) => {
console.log('render html')
return (
`<div class="clock">
<h2>clock: ${hours} ${minutes} ${seconds}</h2>
</div>`
)
};
class Clock {
constructor() {
this.time = new Date();
setInterval(() => {
this.getSeconds()
}, 1000)
}
renderHTML() {
return htmlMarkup(this.hours, this.minutes, this.getSeconds())
}
getSeconds() {
return this.seconds = this.time.getSeconds()
}
}
const runClock = new Clock();
document.querySelector(".app").innerHTML = runClock.renderHTML();
<div class="app"></div>
Even if i set:
setInterval(() => {
this.getSeconds()
}, 1000)
...the seconds are not changing. So, why the seconds still the same after first render of the application and how to ssolve the issue?
There are a couple of problems:
Your timer just calls getSeconds. getSeconds doesn't do anything to update the HTML. For that, you need to repeat the document.querySelector(".app").innerHTML = runClock.renderHTML(); part. (In fact, the Clock#getSectonds method doesn't do anything useful and you can just get rid of it.)
Your code does this.time = new Date() and then just uses this.time throughout. That Date object is unchanging, it doesn't continually update itself. You don't need this.time at all, just use new Date() in renderHTML.
Your code never sets the hours or minutes, so it just shows 0s for those.
Here's an example that modifies the constructor so it accepts the element to update, and then calls renderHTML in the timer callback, using new Date in renderHTML to get the current date/time. (I've also added various missing semicolons. You should either use them, nor not use them and rely on ASI instead, but not use them sporatically.)
const htmlMarkup = (hours = 0, minutes = 0, seconds = 0) => {
console.log('render html');
return (
`<div class="clock">
<h2>clock: ${hours} ${minutes} ${seconds}</h2>
</div>`
);
};
class Clock {
constructor(element) {
this.element = element;
setInterval(()=> {
this.element.innerHTML = this.renderHTML();
},1000);
}
renderHTML() {
const dt = new Date();
return htmlMarkup(dt.getHours(), dt.getMinutes(), dt.getSeconds());
}
}
const runClock = new Clock(document.querySelector(".app"));
<div class="app"></div>
ur not calling the new Date() again. check this.
const htmlMarkup = (hours = 0, minutes = 0, seconds = 0) => {
console.log("render html");
return `<div class="clock">
<h2>clock: ${hours} ${minutes} ${seconds}</h2>
</div>`;
};
class Clock {
constructor() {
setInterval(() => {
this.getSeconds();
}, 1000);
}
renderHTML() {
return htmlMarkup(this.hours, this.minutes, this.getSeconds());
}
getSeconds() {
this.time = new Date();
this.seconds = this.time.getSeconds();
console.log(this.time);
}
}
const runClock = new Clock();
document.querySelector(".app").innerHTML = runClock.renderHTML();
I did the following changes:
setInterval(()=> {
document.querySelector(".app").innerHTML = runClock.renderHTML();
},1000)
And
getSeconds() {
return (new Date()).getSeconds()
}
Now only the seconds are changing. You'll have to handle for minutes and hours.
I am trying to implement debounce function in vanilla JavaScript. I am not sure why clearTimeout does not clear the timeout object. In each event trigger, callback function setTimeout and if it is not more than 5 seconds from the last call, it clears the timeout that just created. But I don't see the timeout being cleared.
HTML:
<html>
<head>
</head>
<body>
<div id='move'>
</div>
<div id='result'>
</div>
</body>
JS:
var area;
var result;
function init() {
area = document.querySelector('#move');
area.addEventListener('mousemove', debouce1);
result = document.querySelector('#result');
}
function updateResult(event) {
let xCordinate = event.clientX;
let yCordinate = event.clientY;
result.textContent = `${xCordinate} , ${yCordinate}`;
}
function debounce1(fn, time) {
let firstTime = true;
let start;
return function() {
if (firstTime) {
fn.apply(null, arguments);
firstTime = false;
start = new Date();
} else {
let now = new Date();
let timer = setTimeout(() => {
fn.apply(null, arguments);
start = new Date();
}, time)
if (now - start < 4000) {
console.log('too fast');
clearTimeout(timer);
console.log(now - start);
console.log(timer);
start = new Date();
}
}
}
init();
There are quite a few issues with the code posted.
area.addEventListener('mousemove', debouce1);
It's debounce1 not debouce1
And it should be something like
area.addEventListener('mousemove', debounce1(updateResult, 1000));
Calling fn.apply with null means the code loses the fact that event handlers are called with this set to the element that the listener was bound to
The code is calling init inside debounce1
Another minor comment, you can call Date.now() or performance.now() to get number that represents time as a number which is arguably more appropriate than creating Date objects.
Also not sure what the point of even having a clearTimeout call is.
Here's a another implementation of debounce1. It passes on the last set of arguments and the last this. Made updateResult show this.id so we can check that this is correct for the callback.
'use strict';
const result = document.querySelector('#result');
function init() {
const area = document.querySelector('#move');
area.addEventListener('mousemove', debounce1(updateResult, 1000));
}
function updateResult(event) {
const xCordinate = event.clientX;
const yCordinate = event.clientY;
result.textContent = `${this.id}: ${xCordinate} , ${yCordinate}`;
}
function debounce1(fn, time) {
let lastArgs;
let lastThis;
let timeoutQueued;
let debounceTime = 0;
return function(...args) {
lastThis = this;
lastArgs = [...args];
if (!timeoutQueued) {
timeoutQueued = true;
setTimeout(function() {
timeoutQueued = false;
fn.apply(lastThis, lastArgs);
}, debounceTime);
debounceTime = time;
}
};
};
init();
#move {
background: red;
height: 50px;
}
<div id='move'></div>
<div id='result'>