Related
let's say we want to animate a count up from 10 to 100, using CountUp.js we should do something like this:
The question is how can I resolve a promise after the counting has finished.
createMainCountUp(); // initiate once
function createMainCountUp(){
const div = document.createElement("div");
div.id = "percentCounterTarget";
document.body.appendChild(div);
}
promisedFunc(); // this is a function I want
async function promisedFunc() {
console.log('counting has started...');
await Counting(); // I want to resolve this function when counting has finished
console.log('counting has finished!');
}
// here is the main function to start counting
function Counting(){
dial = new CountUp('percentCounterTarget', 10, 100, 4, 5);
dial.start();
//easing dial function
function CountUp(target, startVal, endVal, decimals, duration, options) {
var self = this;
// default options
self.options = {
useEasing: true, // toggle easing
useGrouping: true, // 1,000,000 vs 1000000
separator: ',', // character to use as a separator
decimal: '.', // character to use as a decimal
easingFn: fastEase, //normalEase, //slowEase, // optional custom easing function
formattingFn: formatNumber, // optional custom formatting function, default is formatNumber above
prefix: '', // optional text before the result
suffix: '', // optional text after the result
numerals: [] // optionally pass an array of custom numerals for 0-9
};
// extend default options with passed options object
if (options && typeof options === 'object') {
for (var key in self.options) {
if (options.hasOwnProperty(key) && options[key] !== null) {
self.options[key] = options[key];
}
}
}
if (self.options.separator === '') {
self.options.useGrouping = false;
} else {
// ensure the separator is a string (formatNumber assumes this)
self.options.separator = '' + self.options.separator;
}
// make sure requestAnimationFrame and cancelAnimationFrame are defined
// polyfill for browsers without native support
// by Opera engineer Erik Möller
var lastTime = 0;
var vendors = ['webkit', 'moz', 'ms', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
function formatNumber(num) {
var neg = (num < 0),
x, x1, x2, x3, i, len;
num = Math.abs(num).toFixed(self.decimals);
num += '';
x = num.split('.');
x1 = x[0];
x2 = x.length > 1 ? self.options.decimal + x[1] : '';
if (self.options.useGrouping) {
x3 = '';
for (i = 0, len = x1.length; i < len; ++i) {
if (i !== 0 && ((i % 3) === 0)) {
x3 = self.options.separator + x3;
}
x3 = x1[len - i - 1] + x3;
}
x1 = x3;
}
// optional numeral substitution
if (self.options.numerals.length) {
x1 = x1.replace(/[0-9]/g, function(w) {
return self.options.numerals[+w];
})
x2 = x2.replace(/[0-9]/g, function(w) {
return self.options.numerals[+w];
})
}
return (neg ? '-' : '') + self.options.prefix + x1 + x2 + self.options.suffix;
}
//Ease functions
function fastEase(t, b, c, d) {
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
}
function normalEase(t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc * ts + -5 * ts * ts + 10 * tc + -10 * ts + 5 * t);
}
function slowEase(t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc + -3 * ts + 3 * t);
}
function ensureNumber(n) {
return (typeof n === 'number' && !isNaN(n));
}
self.initialize = function() {
if (self.initialized) return true;
self.error = '';
self.d = (typeof target === 'string') ? document.getElementById(target) : target;
if (!self.d) {
self.error = '[CountUp] target is null or undefined'
return false;
}
self.startVal = Number(startVal);
self.endVal = Number(endVal);
// error checks
if (ensureNumber(self.startVal) && ensureNumber(self.endVal)) {
self.decimals = Math.max(0, decimals || 0);
self.dec = Math.pow(10, self.decimals);
self.duration = Number(duration) * 1000 || 2000;
self.countDown = (self.startVal > self.endVal);
self.frameVal = self.startVal;
self.initialized = true;
return true;
} else {
self.error = '[CountUp] startVal (' + startVal + ') or endVal (' + endVal + ') is not a number';
return false;
}
};
// Print value to target
self.printValue = function(value) {
var result = self.options.formattingFn(value);
console.log(value);
};
self.count = function(timestamp) {
if (!self.startTime) {
self.startTime = timestamp;
}
self.timestamp = timestamp;
var progress = timestamp - self.startTime;
self.remaining = self.duration - progress;
// to ease or not to ease
if (self.options.useEasing) {
if (self.countDown) {
self.frameVal = self.startVal - self.options.easingFn(progress, 0, self.startVal - self.endVal, self.duration);
} else {
self.frameVal = self.options.easingFn(progress, self.startVal, self.endVal - self.startVal, self.duration);
}
} else {
if (self.countDown) {
self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));
} else {
self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
}
}
// don't go past endVal since progress can exceed duration in the last frame
if (self.countDown) {
self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal;
} else {
self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal;
}
// decimal
self.frameVal = Math.round(self.frameVal * self.dec) / self.dec;
// format and print value
self.printValue(self.frameVal);
// whether to continue
if (progress < self.duration) {
self.rAF = requestAnimationFrame(self.count);
} else {
if (self.callback) self.callback();
}
};
// start your animation
self.start = function(callback) {
if (!self.initialize()) return;
self.callback = callback;
self.rAF = requestAnimationFrame(self.count);
};
// pass a new endVal and start animation
self.update = function(newEndVal) {
if (!self.initialize()) return;
newEndVal = Number(newEndVal);
if (!ensureNumber(newEndVal)) {
self.error = '[CountUp] update() - new endVal is not a number: ' + newEndVal;
return;
}
self.error = '';
if (newEndVal === self.frameVal) return;
cancelAnimationFrame(self.rAF);
self.paused = false;
delete self.startTime;
self.startVal = self.frameVal;
self.endVal = newEndVal;
self.countDown = (self.startVal > self.endVal);
self.rAF = requestAnimationFrame(self.count);
};
// format startVal on initialization
if (self.initialize()) self.printValue(self.startVal);
}
}
Note: the StackOverflow snippet not showing the logs correctly. the code works fine.
Since CountUp.start() can take a callback function, you could create and return a Promise that calls the resolve function once the countdown is finished.
function counting() {
return new Promise((resolve, reject) => {
const dial = new CountUp(...);
dial.start(resolve);
});
}
Edit: Once the countdown is finished CountUp will call the callback function that you pass into .start(). You can see this in the copy of CountUp.js you posted in your snippet - at the comment "whether to continue" in self.count, it calls the callback function once the countdown is finished progressing. We can utilize this in a promise by calling resolve once the countdown is complete.
I have a function which creates values for time as I am trying to calculate them, however when I try and change a drop down times I the values don't change as they just stay at 7. The function only loads the default values (time) which is 7 as it is 7 am.
As you can see from the screenshot when the form is loaded it has a time of 7am with the value of 7, but when I change the time to 8:00 it does not show the proper value of 8 and stays at a value of 7
Here is my code:
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
var timeStringToValue = function timeStringToValue(timeStr) {
var _timeStr$match = timeStr.match(/(\d+):(\d+) ([ap]m)/),
_timeStr$match2 = _slicedToArray(_timeStr$match, 4),
hours = _timeStr$match2[1],
minutes = _timeStr$match2[2],
ampm = _timeStr$match2[3];
var ampmHourModifier = ampm === 'pm' ? 12 : 0;
return Number(hours) + ampmHourModifier + minutes / 60;
};
var startMonTimeStr = $('.start-time-monday option:selected').text();
var FinishtMonTimeStr = $('.finish-time-monday option:selected').text();
var startMonValue = timeStringToValue(startMonTimeStr);
console.log(timeStringToValue(startMonTimeStr));
console.log(timeStringToValue(FinishtMonTimeStr));
I have written this code to get the value of the Timer in a div :
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = document.createElement("div");
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container.innerHTML = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
};
var boundTimeUpdate = timeUpdate.bind(time);
window.setInterval(boundTimeUpdate,10);
console.log(container);
return container;
})();
This code works when I link the var timerGenartor with a div. But, now I would like to return the var container into a string. So I changed my code to this : (I just changed the initialization of container and this value)
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = "";
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
};
var boundTimeUpdate = timeUpdate.bind(time);
window.setInterval(boundTimeUpdate,10);
console.log(container);
return container;
})();
With this modification nothing is returned or display in the console and I don't understand why. However, the comment "console.log" gives me good the timer. So, why the first console.log displays the good result and not the second one ?
The working code as you expected with two JS functions
// JS 1
var timerGenerator = (function() {
var time = {
centiSec: 0,
secondes: 0,
minutes: 0,
hours: 0
};
var container = "";
var timeDisplay = function() {
function smoothDisplay(value) {
return (value < 10 ? '0' : '') + value;
}
return "" + smoothDisplay(this.hours) + ":" + smoothDisplay(this.minutes) + ":" + smoothDisplay(this.secondes) + "." + smoothDisplay(this.centiSec);
};
var boundTimeDisplay = timeDisplay.bind(time);
var timeUpdate = function() {
container = boundTimeDisplay();
//console.log(container);
this.centiSec++;
if(this.centiSec === 100) {
this.centiSec = 0;
this.secondes++;
}
if(this.secondes === 60) {
this.secondes = 0;
this.minutes++;
}
if(this.minutes === 60) {
this.minutes = 0;
this.hours++;
}
return container;
};
var boundTimeUpdate = timeUpdate.bind(time);
return boundTimeUpdate;
})();
// JS 2
var spanGenerator = (function() {
var container = document.createElement('span');
window.setInterval(function(){
container.innerHTML = timerGenerator();
}, 10);
return container;
})();
document.getElementById('timer').appendChild(spanGenerator);
<div id="timer"></div>
It can be because your container is empty as it is initialized in timeUpdate function which is eventually called 10ms later(for the first time) because of the setInterval. U will have to call the timeUpdate function before putting it in setInterval.
hello all i am using the following js code to convert the input type date into three different text boxes for day,month and year.
js
(function () {
var sign = function(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
};
// TODO Calcular año bisiesto
var bisiesto = function(year)
{
return true;
// return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? 1 : 0;
};
$.fn.insertAt = $.fn.insertAt || function(index, $parent) {
return this.each(function() {
if (index === 0) {
$parent.prepend(this);
} else {
$parent.children().eq(index - 1).after(this);
}
});
};
var Crossdp = function(e, o) {
if (e.data("cross-datepicker")) {
return this;
}
e.attr("type", "text");
o = $.extend({}, $.fn.cdp.defaults, o);
if(o.hideInput)
e.hide();
var cnt = $("<div>").addClass(o.classes.container || "").data("input", e).insertBefore(e);
// Data
var days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// Read format
var d = $("<select>").addClass(o.classes.controls || "").addClass(o.classes.days || ""),
m = $("<select>").addClass(o.classes.controls || "").addClass(o.classes.months || ""),
y = $("<select>").addClass(o.classes.controls || "").addClass(o.classes.year || "");
/**
* Gets the format metadata.
*/
var getFormat = function(format) {
var f = {},
last = "",
order = 0,
elements = {
"d": d,
"m": m,
"y": y
};
for(var i = 0, of=format; i < of.length; i++) {
var c = of[i];
if(last == c) {
f[c].count ++;
}
else if(c == "d" || c == "y" || c == "m") {
f[c] = {
"count": 1,
"order": order++,
"e": elements[c]
};
elements[c].data("order", f[c].order);
last = c;
}
if(order > 3) {
throw "Invalid date format";
}
}
return f;
};
var iF = getFormat(o.inputFormat),
f = getFormat(o.format);
for(var i in f) {
f[i].e.appendTo(cnt);
}
cnt.sort(function(a, b) {
if(a.data("order") > b.data("order")) {
return 1;
}
else if(a.data("order") < b.data("order")) {
return -1;
}
else {
return 0;
}
});
// Helpers
/**
* Format a numeric day to string.
*/
var formatDay = function(day, format) {
var text = String(day),
c = format || f.d.count;
while(c > text.length) {
text = "0" + text;
}
return text;
};
/**
* Format a numeric month to string.
*/
var formatMonth = function(month, format) {
if(month > 12) {
throw "Invalid month: "+month;
}
var c = format || f.m.count,
text = String(month);
if(c == 2) {
if(text.length == 1) {
text = "0" + text;
}
}
else if(c == 3) {
text = o.months[i-1].substr(0, 3);
}
else if(c == 4) {
text = o.months[i-1];
}
else {
throw "Invalid month format";
}
return text;
};
/**
* Format a numeric month to string.
*/
var formatYear = function(year, format) {
var text = String(year),
c = format || f.y.count;
if(c == 2) {
text = text.substr(text.length-2, 2);
}
else if(c != 4) {
throw "Invalid year format";
}
return text;
};
var parseYear = function(date, format) {
// TODO
};
// Update input function
var formatDate = function(resultFormat, readFormat, years, months, days) {
var a = ["d", "m", "y"],
result = resultFormat;
if(typeof days === 'string')
days = parseInt(days);
if(typeof months === 'string')
months = parseInt(months);
if(typeof years === 'string')
years = parseInt(years);
for(var i = 0; i < a.length; i++) {
var ch = a[i], /* Example: a[0]='d' */
format = readFormat[ch], /* Example: uF['d']='dd' */
word = "",
formatted = "";
for(var j = 0; j < format.count; j++) {
word += ch;
}
if(ch == "d") {
formatted = formatDay(days, format.count);
}
else if(ch == "m") {
formatted = formatMonth(months, format.count);
}
else {
formatted = formatYear(years, format.count);
}
result = result.replace(word, formatted);
}
return result;
};
var updateInput = function() {
e.val(formatDate(o.inputFormat, iF, y.val(), m.val(), d.val()));
};
this.updateInput = function() {
updateInput();
};
var updateFromInput = function() {
// TODO
};
// Generate 3 selects
/* Days */
d.data("days", 0);
/**
* Days of determinated month.
*/
var generateDays = function(month) {
if(d.data("days") == days[month-1]) {
return;
}
var selected = parseInt(d.val() || "1");
d.html("");
if(month == 0) {
return;
}
if(o.addNullOption) {
d.append("<option value=''>"+o.nullOptionText+"</option>");
}
for(var i = 1; i <= days[month-1]; i++) {
$("<option>").attr("value", i).text(formatDay(i)).appendTo(d);
}
d.val(selected);
};
d.change(function() {
updateInput();
});
generateDays(1);
/* Months */
m.change(function() {
// Regenerate days
generateDays(parseInt($(this).val()));
updateInput();
});
if(o.addNullOption) {
m.append("<option value='0'>"+o.nullOptionText+"</option>");
}
for(var i = 1; i <= 12; i++) {
m.append("<option value='"+i+"'>"+formatMonth(i)+"</option>");
}
/* Years */
var from,
to;
if(typeof o.years[0] == 'string') {
var current = new Date().getFullYear(),
count;
if(o.years.length == 3) {
current += o.years[1];
count = o.years[2];
}
else {
count = o.years[1];
}
for(var i = current; i != current + count; i += sign(count)) {
y.append("<option value='"+i+"'>"+formatYear(i)+"</option>");
}
}
else {
for(var i = o.years[0]; i != o.years[1]; i += sign(o.years[1]-o.years[0])) {
y.append("<option value='"+i+"'>"+formatYear(i)+"</option>");
}
}
y.change(function() {
updateInput();
});
// Save
this.inputs = {
d: d,
y: y,
m: m
};
// Finish
if(e.data("initial-day")) {
$(function() {
$.fn.cdp.statics.fns.set(e, [
e.data("initial-year"),
e.data("initial-month"),
e.data("initial-day")]);
});
}
updateInput();
e.data("cross-datepicker", this);
};
$.fn.cdp = function (o, arg) {
var e = $(this);
if (e.length == 0) {
return this;
}
else if (e.length > 1) {
e.each(function () {
$(this).cdp(o);
});
return this;
}
if(!e.is("input")) {
throw "You can apply Cross-DatePicker only on an 'input' element";
}
if(typeof o === 'string') {
var st = $.fn.cdp.statics;
if(!st.fns[o]) {
console.error("Unknown function "+o);
}
st.fns[o](e, arg);
return this;
}
var cdp = new Crossdp(e, o);
return this;
}
$.fn.cdp.defaults = {
hideInput: true,
format: "d/mmm/yyyy",
inputFormat: "yyyy-mm-dd",
years: ["now", -100], // [initial year, final year] or ["now", relative years count] or ["now", relative years from, relative years count]
months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
addNullOption: false,
nullOptionText: "Select",
classes: {
container: "cdp-container",
controls: "cdp-select",
days: "cdp-d",
months: "cdp-m",
years: "cdp-y"
}
};
$.fn.cdp.statics = {
fns: {
set: function(e, arg) {
var st = $.fn.cdp.statics,
obj = e.data("cross-datepicker"),
y,m,d;
if($.isArray(arg)) {
y = arg[0];
m = arg[1];
d = arg[2];
}
else if(typeof arg === 'string') {
var array = arg.split("-");
y = parseInt(array[0]);
m = parseInt(array[1]);
d = parseInt(array[2]);
}
else {
y = arg.year || arg.y;
m = arg.month || arg.m;
d = arg.day || arg.d;
}
obj.inputs.y.val(String(y));
obj.inputs.m.val(String(m));
obj.inputs.d.val(String(d));
obj.updateInput();
}
}
};
})();
how to implement
html
<input type="date" data-initial-day="20" data-initial-year="2010" data-initial-month="64" />
<!-- Required scripts -->
<script src='https://code.jquery.com/jquery-2.1.0.min.js'></script>
<script src='../src/cross-datepicker.js'></script>
<script>
$(function() {
$("input[type='date']").cdp();
});
</script>
the problem is that the code works great when defined data-initial-year for month and day also but when i want to show the default none selected date like select day select month and select year it shows blank or 0 .
i dont know how to solve this i have tried to solve the problem by adding some text into the js file but no help .
if you can suggest me something it would be great.
The plugin code needs to check if an entry is valid before setting it.
First off, set the addNullOption to true so that a "Select" text is visible.
$(function() {
$("input[type='date']").cdp({
addNullOption : true,
nullOptionText: "Select"
});
});
Then modify the last function $.fn.cdp.statics with the "check valid" code included below (demo):
$.fn.cdp.statics = {
fns: {
set: function(e, arg) {
var st = $.fn.cdp.statics,
obj = e.data("cross-datepicker"),
y,m,d;
if($.isArray(arg)) {
y = arg[0];
m = arg[1];
d = arg[2];
}
else if(typeof arg === 'string') {
var array = arg.split("-");
y = parseInt(array[0]);
m = parseInt(array[1]);
d = parseInt(array[2]);
}
else {
y = arg.year || arg.y;
m = arg.month || arg.m;
d = arg.day || arg.d;
}
// check valid
if ( obj.inputs.y.find('option[value="' + y + '"]').length ) {
obj.inputs.y.val(String(y));
}
if ( obj.inputs.m.find('option[value="' + m + '"]').length ) {
obj.inputs.m.val(String(m));
}
if ( obj.inputs.d.find('option[value="' + d + '"]').length ) {
obj.inputs.d.val(String(d));
}
obj.updateInput();
}
}
};
To show "Select" in the other selects, I ended up adding the following code because the year select didn't have a null option:
if (o.addNullOption) {
y.append("<option value='0'>"+o.nullOptionText+"</option>");
}
and changing the "check valid" code to:
// check valid
y = obj.inputs.y.find('option[value="' + y + '"]').length ? y : 0;
obj.inputs.y.val(String(y));
m = obj.inputs.m.find('option[value="' + m + '"]').length ? m : 0;
obj.inputs.m.val(String(m));
d = obj.inputs.d.find('option[value="' + d + '"]').length ? d : 0;
obj.inputs.d.val(String(d));
Get the full code from this updated demo.
I have problem with removing a timer while it not being used anymore in javascript ?
let say we have a variable tm for the timer and set it with window.setInterval, while it still running we replace it by a new setInterval, how possible to get rid of the first setInterval ?
example code
var tm = setInterval(function(){
console.log('tm1')
}, 10);
tm = setInterval(function(){
console.log('tm2')
}, 10)
this is the real problem
motion:function(ele,cssStart,cssEnd,duration,tangent, easing,loop, complete){
if(ele==null||typeof cssEnd !== 'string') throw new TypeError();
if(!$hd.isElement(ele) || !$hd(ele).isExists()) throw new TypeError();
var validRules = /(left|top|width|color|height|background-color|margin-left|margin-right|margin-top|margin-botom|border-color|padding-left|padding-right|padding-top|border-bottom-width|border-top-width|border-left-width|border-right-width|border-bottom-color|border-top-color|border-left-color|border-right-color|padding-bottom|border-width|opacity|font-size)\s?(?=:).[^;]*(?=;?)/gim;
// filtering css input
cssEnd = cssEnd.replace(/\s{2,}|\n|\t/gim,'').replace(/\s?(:)\s?/gi,'$1').match(validRules);
cssStart = !cssStart?[]:cssStart.replace(/\s{2,}|\n|\t/gim,'').replace(/\s(:)\s/gi,'$1').match(validRules);
if(!cssEnd) throw new Error('invalid css rules, please refer to the documentation about the valid css rules for animation');
// creating properties
var _cssEnd = [],
_paused = false,
_cssStart = [],
_tm = null,
_step,
_complete = typeof complete ==='function'?complete:null,
_loop = 0,
_easing = typeof easing ==='string'?easing.match(/^easein|easeout|easeinout$/)?easing:'easein':'easein',
_tangent = typeof tangent ==='string'?tangent in hd.classes.motionTangents ? tangent:'linear':'linear';
this.ele = $hd(ele),
this.duration = isNaN(duration)?1:parseFloat(duration),
this.loop = isNaN(loop)?0:parseInt(loop),
this.isPlaying = false;
this.complete = false;
// verifying the css rules of the end point
var verify = function(cssStart, cssEnd){
for (var i = 0; i < cssEnd.length; i++) {
var colorPattern = /#[a-z0-9]+|rgba?\s?\(([0-9]{1,3}\s?,\s?)+((([0-9]+)?(\.)?([0-9]+))+)?\)/gi,
name = cssEnd[i].replace(/^([a-z0-9-]+)\s?(?=:).*/gi,'$1'),
value = cssEnd[i].replace(/^[a-z0-9-]+\s?:(.*)/gi,'$1'),
startIndex = $hd(cssStart).inspectData(name+':',false),
startValue = !startIndex.length?this.ele.getcss(name):cssStart[startIndex].replace(/^[a-z0-9-]+:(.*)/gi,'$1');
if(value=='') continue;
// parsing values
if(name.match(/color/i)){
//if color
// validate the color
if(!value.match(colorPattern)) continue;
if(value.match(/#[a-z0-9]+/ig)){
// if hex then convert to rgb
var rgb = $hd(value).hex2rgb(),
value = !rgb?null:rgb;
if(!value) continue;
}
// verifying cssStart's value
startValue = !startValue.match(colorPattern)?this.ele.getcss(name):startValue;
if(!startValue.match(colorPattern)) continue;
if(startValue.match(/#[a-z0-9]+/ig)){
// if hex then convert to rgb
var rgb = $hd(startValue).hex2rgb(),
startValue = rgb==null?null:rgb;
}
// if browser doesn't support rgba then convert the value to rgb
value = !$hd.supports.rgba && value.match(/rgba/i)?value.replace(/(.*)a\s?(\((\d{1,3},)(\d{1,3},)(\d{1,3})).*/i,'$1$2)'):value;
startValue = !$hd.supports.rgba && startValue.match(/rgba/i)?startValue.replace(/(.*)a\s?(\((\d{1,3},)(\d{1,3},)(\d{1,3})).*/i,'$1$2)'):startValue;
// compare and convert the value of both to object
var colora = value.match(/[0-9]{1,3}/g),
colorb = startValue.match(/[0-9]{1,3}/g);
if(colora.length > colorb.length){
colorb.push(this.ele.getcss('opacity'))
}else if(colorb.length>colora.length){
colora.push(colorb[colorb.length-1])
}
_cssEnd.push({
type:'color',
name:name,
value:{
r:parseInt(colora[0]),
g:parseInt(colora[1]),
b:parseInt(colora[2]),
a:colora[3]?parseFloat(colora[3]):null
}
});
_cssStart.push({
type:'color',
name:name,
value:{
r:parseInt(colorb[0]),
g:parseInt(colorb[1]),
b:parseInt(colorb[2]),
a:colorb[3]?parseFloat(colorb[3]):null
}
});
}else{
value = parseFloat(value),
startValue = parseFloat((isNaN(parseFloat(startValue))?parseFloat(this.ele.getcss(name)):startValue));
if(isNaN(value)) continue;
if(isNaN(startValue)) startValue = 0;
_cssEnd.push({
type:'unit',
name:name,
value:parseFloat(value)
});
_cssStart.push({
type:'unit',
name:name,
value:parseFloat(startValue)
});
}
}
};
verify.apply(this,[cssStart,cssEnd]);
// clearing the arguments
cssStart = complete = cssEnd = duration = tangent = loop = ele = verify = null;
if($hd(_cssEnd).isEmpty()) throw new Error('MotionClass::invalid css rules');// raise error if cssEnd is empty
var _pauseTime = 0;
this.play = function(){
if(this.isPlaying) return;
if(!this.ele.isExists() || !this.ele.visible()) {
this.stop();
return;
}
this.isPlaying = true;
_paused = false;
if( $hd(_cssEnd).inspectData('left',true,true).length||
$hd(_cssEnd).inspectData('top',true, true).length)
this.ele.css('position:absolute');
var st = new Date() - _pauseTime;
_tm = window.setInterval(function(){
if(!this.ele.isExists() || !this.ele.visible()) {
this.stop();
return;
}
var pg, delta,
timePassed = new Date() - st;
pg = timePassed / (this.duration*1000);
if (pg > 1) pg = 1;
if(_easing === 'easeout'){
delta = 1 - hd.classes.motionTangents[_tangent](1 - pg);
}else if(_easing==='easeinout'){
if (pg <= 0.5) {
// the first half of animation will easing in
delta= hd.classes.motionTangents[_tangent](2 * pg) / 2
} else {
// the rest of animation will easing out
delta= (2 - hd.classes.motionTangents[_tangent](2 * (1 - pg))) / 2
}
}else{
delta = hd.classes.motionTangents[_tangent](pg);
}
// the movement
_step.call(this,delta);
if(_paused){
window.clearInterval(_tm);
_tm=null;
_pauseTime = timePassed;
this.isPlaying = false;
return;
}
if (pg == 1) {
_pauseTime =0;
if(_loop>=this.loop){
this.complete = true;
this.stop();
if(_complete)_complete.call(null,this);
}else{
_loop++;
st = new Date(),
timePassed = new Date() - st,
pg = 0;
}
}
}.bind(this),15);
};
_step = function(delta){
var styles = '';
for(var i=0;i<_cssEnd.length;i++){
var name = _cssEnd[i].name,
svalue =_cssStart[i].value,
value = _cssEnd[i].value;
if(_cssEnd[i].type == 'color'){
styles += name+':'+(value.a !=null?'rgba(':'rgb(')
+ Math.max(Math.min(parseInt((delta * (value.r-svalue.r)) + svalue.r, 10), 255), 0) + ','
+ Math.max(Math.min(parseInt((delta * (value.g-svalue.g)) + svalue.g, 10), 255), 0) + ','
+ Math.max(Math.min(parseInt((delta * (value.b-svalue.b)) + svalue.b, 10), 255), 0)
+ (value.a ==null?'':',' + $hd(parseFloat((value.a-svalue.a)*delta+svalue.a)).round(1)) +') !important;';
}else{
styles += name+':'+ $hd(parseFloat((value-svalue)*delta+svalue)).round(2) + (name.match(/opacity/i)?'':'px')+ '!important;';
}
this.ele.css(styles);
}
};
this.stop = function(){
this.isPlaying = false;
window.clearInterval(_tm);
_tm=null;
_loop = 0;
};
this.pause = function(){
_paused = true;
};
}
this how the problems came up;
var color = 'rgba('+($(1).randomize(0,255)+',')+
($(1).randomize(0,255)+',')+
($(1).randomize(0,255)+',')+
'1)';
var bcolor = 'rgb('+($(1).randomize(0,255)+',')+
($(1).randomize(0,255)+',')+
($(1).randomize(0,255)+',')+
')';
var motion = new hd.classes.motion(box,'',('height:'+($(1).randomize(10,50))+
'px;border-color:'+bcolor+
';background-color:'+color+
';left :'+((e.x || e.clientX)-(box.rectangle().width/2))+
';top : '+((e.y || e.clientY)-(box.rectangle().height/2))+
';border-top-width:'+($(1).randomize(0,50))),
2,'circle','easeinout',1, function(e){
status.html('Idle');
});
motion.play();
while variable motion has been referenced with an motion class (animation), how possible to stop the first motion's timer if it being replaced with new motion class(animation)
Really easy! clearInterval(tm). If you call them different names, you will be able to differentiate between them.