Editing jquery-countdown to fit my HTML element - javascript

I've collected a nice jQuery countdown script from here. It needs no configuration but a great opensource project. But where I want to set is a smaller place like 50%. So, now I want to make it 50% on both width and height. First of all I opened digits.png with photoshop and made it 50%, then I opened jquery.countdown.js and the code is following:
jQuery.fn.countdown = function(userOptions)
{
// Default options
var options = {
stepTime: 60,
// startTime and format MUST follow the same format.
// also you cannot specify a format unordered (e.g. hh:ss:mm is wrong)
format: "dd:hh:mm:ss",
startTime: "01:12:32:55",
digitImages: 6,
digitWidth: 67,
digitHeight: 90,
timerEnd: function(){},
image: "digits.png",
continuous: false
};
var digits = [], intervals = [];
// Draw digits in given container
var createDigits = function(where)
{
var c = 0;
// Iterate each startTime digit, if it is not a digit
// we'll asume that it's a separator
for (var i = 0; i < options.startTime.length; i++)
{
if (parseInt(options.startTime[i]) >= 0)
{
elem = $('<div id="cnt_' + c + '" class="cntDigit" />').css({
height: options.digitHeight,
float: 'left',
background: 'url(\'' + options.image + '\')',
width: options.digitWidth
});
elem.current = parseInt(options.startTime[i]);
digits.push(elem);
margin(c, -elem.current * options.digitHeight * options.digitImages);
if (options.continuous === true)
{
digits[c]._max = function(){ return 9; };
}
else
{
// Add max digits, for example, first digit of minutes (mm) has
// a max of 5. Conditional max is used when the left digit has reach
// the max. For example second "hours" digit has a conditional max of 4
switch (options.format[i])
{
case 'h':
digits[c]._max = function(pos, isStart) {
if (pos % 2 == 0)
return 2;
else
return (isStart) ? 3: 9;
};
break;
case 'd':
digits[c]._max = function(){ return 9; };
break;
case 'm':
case 's':
digits[c]._max = function(pos){ return (pos % 2 == 0) ? 5: 9; };
}
}
++c;
}
else
{
elem = $('<div class="cntSeparator"/>').css({float: 'left'})
.text(options.startTime[i]);
}
where.append(elem)
}
};
// Set or get element margin
var margin = function(elem, val)
{
if (val !== undefined)
{
digits[elem].margin = val;
return digits[elem].css({'backgroundPosition': '0 ' + val + 'px'});
}
return digits[elem].margin || 0;
};
var makeMovement = function(elem, steps, isForward)
{
// Stop any other movement over the same digit.
if (intervals[elem])
window.clearInterval(intervals[elem]);
// Move to the initial position (We force that because in chrome
// there are some scenarios where digits lost sync)
var initialPos = -(options.digitHeight * options.digitImages *
digits[elem].current);
margin(elem, initialPos);
digits[elem].current = digits[elem].current + ((isForward) ? steps: -steps);
var x = 0;
intervals[elem] = setInterval(function(){
if (x++ === options.digitImages * steps)
{
window.clearInterval(intervals[elem]);
delete intervals[elem];
return;
}
var diff = isForward ? -options.digitHeight: options.digitHeight;
margin(elem, initialPos + (x * diff));
}, options.stepTime / steps);
};
// Makes the movement. This is done by "digitImages" steps.
var moveDigit = function(elem)
{
if (digits[elem].current == 0)
{
// Is there still time left?
if (elem > 0)
{
var isStart = (digits[elem - 1].current == 0);
makeMovement(elem, digits[elem]._max(elem, isStart), true);
moveDigit(elem - 1);
}
else // That condition means that we reach the end! 00:00.
{
for (var i = 0; i < digits.length; i++)
{
clearInterval(intervals[i]);
clearInterval(intervals.main);
margin(i, 0);
}
options.timerEnd();
}
return;
}
makeMovement(elem, 1);
};
$.extend(options, userOptions);
createDigits(this);
intervals.main = setInterval(function(){ moveDigit(digits.length - 1); },
1000);
};
I tried changing some variables, digitWidth: 67 to digitWidth: 34 then digitHeight: 90 to digitHeight: 45 with no success. I want to make the countdown timer just half than the original. Can you suggest any change anywhere in the code, please?
Update: This is digits.png, 50% than original!
I also changed associated div's like #holder with no success.
Following is the current situation of the timer. The red marked places are the problems I mean misplaced.

You didn't resize digits.png correctly - it's too high, so digitHeight doesn't match your image.
See demo with an image that has 50% height (plugin code unchanged):
http://jsfiddle.net/lhoeppner/RGyPQ/
See the section with the image param:
$('#counter').countdown({
stepTime: 60,
digitWidth: 34,
digitHeight: 45,
format: 'hh:mm:ss',
startTime: "12:32:55",
timerEnd: function () {
alert('end!!');
},
image: "http://s21.postimg.org/nfgjv6b7r/digits2.png"
});

Related

JavaScript method to determine correct path is confusing

I'm learning algorithms and doing JavaScript exercise questions, and I don't understand how one reaches the correct answer for a particular algorithm.
The question provided in the exercise is:
Have the function CorrectPath(str) read the str parameter being
passed, which will represent the movements made in a 5x5 grid of cells
starting from the top left position. The characters in the input
string will be entirely composed of: r, l, u, d, ?. Each of the
characters stand for the direction to take within the grid, for
example: r = right, l = left, u = up, d = down. Your goal is to
determine what characters the question marks should be in order for a
path to be created to go from the top left of the grid all the way to
the bottom right without touching previously travelled on cells in the
grid.
For example, the input drdr??rrddd? should ouptut drdruurrdddd
I've not found a solution on my own. I'm taking a look at a solution provided, and I'm bothered because:
A. pure functions are not used to manipulate values within the CorrectPath function (note the addX() and addY() methods contained within). I'm not convinced the solution provided is using best practices, especially coming from a functional programming background.
B. I don't understand how the steps taken, specifically in the while block and the succeeding for block, are taken to reach the correct answer and why sometimes the missingLetters array has letters remaining and other times not
The working solution provided is below
function CorrectPath(str) {
let x = 0, //start x coord
y = 0, //start y coord
missingLetters = []
const unknowns = str.match(/\W/g)
function addX() {
while(x !== 4) {
if (x > 4) {
x--;
missingLetters.push('l');
} else {
x++;
missingLetters.push('r');
}
}
}
function addY() {
while (y !== 4) {
if (y > 4) {
y--;
missingLetters.push('u');
} else {
y++;
missingLetters.push('d');
}
}
}
//tallies current number of x and y movements
for (let i=0; i<str.length; i++) {
switch (str[i]) {
case 'd':
y += 1;
break;
case 'u':
y -= 1;
break;
case 'l':
x -= 1;
break;
case 'r':
x += 1;
break;
}
}
if (x > y) { addX(); addY(); }
if (y >= x) { addY(); addX(); }
while (missingLetters.length < unknowns.length) {
var pos = missingLetters.length - 1;
if (missingLetters[pos] === 'r') {x += 1; missingLetters.push('r'); addX()}
if (missingLetters[pos] === 'l') {x -= 1; missingLetters.push('l'); addX()}
if (missingLetters[pos] === 'd') {y += 1; missingLetters.push('d'); addY()}
if (missingLetters[pos] === 'u') {y -= 1; missingLetters.push('u'); addY()}
}
var newStr = str.split('');
for (var j=0; j<str.length; j++) {
if (newStr[j] === '?') {
newStr[j] = missingLetters.shift()
}
}
return newStr.join('');
}
CorrectPath(readline());
Here's a solution I found
const dirMap = {
u: { x: 0, y: -1 },
r: { x: 1, y: 0 },
d: { x: 0, y: 1 },
l: { x: -1, y: 0 }
}
function CorrectPath(pathString) {
const map = Array(5*5)
return trace(pathString, map)
}
function trace(path, [...map], x = 0, y = 0, newPath = "") {
const steps = path.split(""),
nextMove = steps.shift()
if (nextMove === undefined) {
if (5 * y + x === (5*5-1)) return newPath
return "Bad move"
}
if (nextMove === "?") {
const moves = availableMoves(x,y,map)
if (!moves.length) return "Bad move"
for(let i = 0; i<moves.length; i++) {
let move = moves[i],
trySteps = [move,...steps].join("")
res = trace(trySteps,map,x,y,newPath)
if (!res || res === "Bad move") continue
else return res
}
return "Bad move"
} else {
if (!canMove(nextMove, x, y, map)) return "Bad move"
const pos = dirMap[nextMove],
newX = pos.x + x,
newY = pos.y + y
newPath += nextMove
map[5*newY+newX] = nextMove
return trace(steps.join(""),map,newX,newY,newPath)
}
}
function availableMoves(x,y,map) {
const steps = []
Object.keys(dirMap).forEach(z => {
if (canMove(z,x,y,map)) steps.push(z)
})
return steps
}
function canMove(dir, xPath, yPath, map) {
const pos = dirMap[dir],
x = pos.x + xPath,
y = pos.y + yPath
if (x > 4 || x < 0 || y > 4 || y < 0) return false
if (map[5*y+x] !== undefined) return false
return true
}
CorrectPath(readline());

why my javascript is showing value not founded?

I am trying to do a binary search in an array but my javascript is showing no value founded even when I entered a number that in the array in the prompt input
var array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100, 102, 105, 200, 250, 300, 320, 350];
var search = parseInt(prompt("enter what you search for"));
var first = 0,
last = array.length - 1,
position = 0,
middle, flag = false;
while ((flag == false) && (first <= last)) {
middle = ((first + last) / 2);
if (array[middle] == search) {
flag = true;
position = middle;
} else
if (array[middle] > search)
last = middle - 1;
else
first = middle + 1;
}
if (flag)
document.write("</br>value founded in position " + position);
else
document.write("</br>value not founded ");
middle value calculation.
middle = Math.round(first + ((last - first) / 2));
// Your code..
var array =[10,20,30,40,50,60,70,80,90,95,100,102,105,200,250,300,320,350] ;
var search= 20; //parseInt(prompt ("enter what you search for"));
var first=0, last=array.length-1,
position=0,
middle ,
flag=false;
while((flag==false) && (first <=last)) {
middle = Math.round(first + ((last - first) / 2)); //((first+last)/2); low + (last - low)/2
if (array[middle]==search){
flag=true;
position=middle ;
}else if(array[middle]>search) {
last=middle-1 ;
}
else {
first= middle+1;
}
}
if (flag)
document.write ("</br>value founded in position "+position);
else
document.write("</br>value not founded ");
For now when you do middle = ((first + last) / 2); it puts the number with floating point to the middle. However, you need to have integer number here. In order to make it you should wrap your calculation with Math.round() or Math.floor().
So you will get:
middle = Math.round((first + last) / 2);

Which part is responsible on the animation in this script?

this code is from a jquery countdown counter , I am trying to eliminate the animation (flip) as you can see in the demo, I succeed to remove the main one, but if you notice at the end when a digit is at 0 you see a quick animation back to 9, and I could not figure which part is responsible for that, this is the code again here.
/*
* jquery-countdown plugin
*
* Copyright (c) 2009 Martin Conte Mac Donell <Reflejo#gmail.com>
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
*/
// Draw digits in given container
var createDigits = function(where, options) {
var counter = 0;
// Iterate each startTime digit, if it is not a digit
// we'll asume that it's a separator
var mFirstPos, sFirstPos;
// reset digits and intervals array.
digits = [];
intervals = [];
for (var i = 0; i < options.startTime.length; i++) {
if (parseInt(options.startTime[i]) >= 0) {
elem = $('<div id="cnt_' + counter + '" class="cntDigit" />').css({
height: options.digitHeight,
float: 'left',
background: 'url(\'' + options.image + '\')',
width: options.digitWidth
});
elem.current = parseInt(options.startTime[i]);
digits.push(elem);
margin(counter, -elem.current * options.digitHeight * options.digitImages);
if (options.continuous === true) {
digits[counter]._max = function() { return 9; };
} else {
// Add max digits, for example, first digit of minutes (mm) has
// a max of 5. Conditional max is used when the left digit has reach
// the max. For example second "hours" digit has a conditional max of 4
switch (options.format[i]) {
case 'h':
digits[counter]._max = function(pos, isStart) {
if (pos % 2 == 0)
return 2;
else
return (isStart) ? 3: 9;
};
break;
case 'd':
digits[counter]._max = function() { return 9; };
break;
case 'm':
digits[counter]._max = function(pos) {
if(!mFirstPos) { mFirstPos = pos; }
return pos == mFirstPos ? 9 : 5;
};
break;
case 's':
digits[counter]._max = function(pos) {
if(!sFirstPos) { sFirstPos = pos; }
return pos == sFirstPos ? 9 : 5;
};
}
}
counter += 1;
} else {
elem = $('<div class="cntSeparator"/>').css({float: 'left'})
.text(options.startTime[i]);
}
where.append(elem)
}
};
var makeMovement = function(elem, steps, isForward, options) {
// Stop any other movement over the same digit.
if (intervals[elem])
window.clearInterval(intervals[elem]);
// Move to the initial position (We force that because in chrome
// there are some scenarios where digits lost sync)
var initialPos = -(options.digitHeight * options.digitImages *
digits[elem].current);
margin(elem, initialPos);
digits[elem].current = digits[elem].current + ((isForward) ? steps: -steps);
var x = 0;
intervals[elem] = setInterval(function() {
if (x++ === options.digitImages * steps) {
window.clearInterval(intervals[elem]);
delete intervals[elem];
return;
}
var diff = isForward ? -options.digitHeight: options.digitHeight;
margin(elem, initialPos + (x * diff));
}, options.stepTime / steps);
};
// Set or get element margin
var margin = function(elem, val) {
if (val !== undefined) {
digits[elem].margin = val;
return digits[elem].css({'backgroundPosition': '0 ' + val + 'px'});
}
return digits[elem].margin || 0;
};
// Makes the movement. This is done by "digitImages" steps.
var moveDigit = function(elem, options) {
if (digits[elem].current == 0) {
// Is there still time left?
if (elem > 0) {
var isStart = (digits[elem - 1].current == 0);
makeMovement(elem, digits[elem]._max(elem, isStart), true, options);
moveDigit(elem - 1, options);
} else { // That condition means that we reach the end! 00:00.
for (var i = 0; i < digits.length; i++) {
clearInterval(intervals[i]);
clearInterval(intervals.main);
margin(i, 0);
}
options.timerEnd();
}
return;
}
makeMovement(elem, 1, false, options);
};
// parses a date of the form hh:mm:ss, for example, where
// ... precision is the same as the format.
var parseRelativeDate = function(form, options) {
// give the date the values of now by default
var now = new Date();
var d = now.getDate();
var m = now.getMonth() + 1;
var y = now.getFullYear();
var h = now.getHours(), mm, s;
// read in components and render based on format
var format = options.format;
var parts = form.split(':');
if( format.indexOf('dd') == 0 ) {
d = parts[0];
parts = parts.slice(1);
format = format.substr(3);
}
if( format.indexOf('hh') == 0 ) {
h = parts[0];
parts = parts.slice(1);
format = format.substr(3);
}
if( format.indexOf('mm') == 0 ) {
mm = parts[0];
parts = parts.slice(1);
format = format.substr(3);
}
if( format.indexOf('ss') == 0 ) {
s = parts[0];
parts = parts.slice(1);
format = format.substr(3);
}
// return our constructed date object
return new Date([m, d, y].join('/') + ' ' + [h, mm, s].map(pad).join(':') + ' GMT-0900');
};
// convert a date object to the format specified
var formatCompute = function(d, options) {
var format = options.format;
var parse = {
d: d.getUTCDate() - 1,
h: d.getUTCHours(),
m: d.getUTCMinutes(),
s: d.getUTCSeconds()
};
return format.replace(/(dd|hh|mm|ss)/g, function($0, form) {
return pad(parse[form[0]]);
});
};
// add leading zeros
var pad = function(x){return (1e15+""+x).slice(-2)};
var digits = [];
var intervals = [];
jQuery.fn.countdown = function(userOptions) {
// Default options
var options = {
stepTime: 60,
// startTime and format MUST follow the same format.
// also you cannot specify a format unordered (e.g. hh:ss:mm is wrong)
format: "dd:hh:mm:ss",
startTime: "01:12:32:55",
digitImages: 6,
digitWidth: 67,
digitHeight: 90,
timerEnd: function(){},
image: "digits.png",
continuous: false
};
$.extend(options, userOptions);
// if an endTime is provided...
if( userOptions.endTime ) {
// calculate the difference between endTime and present time
var endDate = userOptions.endTime instanceof Date ? userOptions.endTime : parseRelativeDate(userOptions.endTime, options);
var diff = endDate.getTime() - (new Date()).getTime();
// and set that as the startTime
userOptions.startTime = formatCompute(new Date(diff), options);
delete userOptions.endTime;
}
$.extend(options, userOptions);
if (this.length) {
clearInterval(intervals.main);
createDigits(this, options);
intervals.main = setInterval(function(){ moveDigit(digits.length - 1, options); },
1000);
}
};
Is this:
setInterval(function(){ moveDigit(digits.length - 1, options); },
1000);
your animation has a duration of one second and this runs the function moveDigit()

jQuery Counter, animating to a total, but how do I include a comma?

I have a found a number of solutions on here for a counter, animating from one total to another.
Here's my what I'm using now:
jQuery.fn.extend({
ts : function (from, to, time) {
var steps = 1,
self = this,
counter;
if (from - to > 0) {
steps = -1;
};
from -= steps;
function step() {
self.text(from += steps);
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
var total = $('.total').ts(56000,56941);
It works well. However, I would like to add a comma to the total, something like 56,941. Is this possible?
I guess this will do it:
jQuery.fn.extend({
ts: function(from, to, time) {
var steps = 1, self = this, counter;
if (from - to > 0) steps = -1;
from -= steps;
function step() {
var x = (from += steps).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
self.text(x);
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
FIDDLE
From somewhere on the web...
function formatComma(x){
return (x+'').replace( /\B(?=(\d{3})+(?!\d))/g, ',');
}
I like my own solution of reversing the string better as it is easier to understand the logic...
function formatComma(x){
// prepare the input as a string ready for manipulating and returning
return (x+'')
// reverse the string (by converting to array)
.split("").reverse().join("")
// replace 3 digits in a row, with themselves and a comma
// so long as the digits are followed by a non-word boundary
.replace(/(\d{3})\B/g,'$1,')
// reverse it all again
.split("").reverse().join("")
}
This will work. The function is taken from http://ntt.cc/2008/04/25/6-very-basic-but-very-useful-javascript-number-format-functions-for-web-developers.html. Very handy
jQuery.fn.extend({
ts : function (from, to, time) {
var steps = 1,
self = this,
counter;
if (from - to > 0) {
steps = -1;
};
from -= steps;
function step() {
self.text(addCommas(from += steps));
if ((steps < 0 && to >= from) || (steps > 0 && from >= to)) {
clearInterval(counter);
};
};
counter = setInterval(step, time || 5);
}
});
var total = $('.total').ts(56000,56941);
function addCommas(nStr)
{
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
​
Sure it is! You can check this plugin (http://code.google.com/p/jquery-numberformatter/) and implement it in yours :-)

Math.ceil to nearest five at position 1

Okay....
I have a lot of uncontrolled numbers i want to round:
51255 -> 55000
25 -> 25
9214 -> 9500
13135 -> 15000
25123 -> 30000
I have tried modifying the numbers as string and counting length....
But is there a simple way using some Math function maybe?
Here's my late answer. Uses no Math methods.
function toN5( x ) {
var i = 5;
while( x >= 100 ) {x/=10; i*=10;}
return ((~~(x/5))+(x%5?1:0)) * i;
}
DEMO: http://jsbin.com/ujamoj/edit#javascript,live
[51255, 24, 25, 26, 9214, 13135, 25123, 1, 9, 0].map( toN5 );
// [55000, 25, 25, 30, 9500, 15000, 30000, 5, 10, 0]
Or this is perhaps a bit cleaner:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {x/=10; i*=10;}
return (x + (5-((x%5)||5))) * i;
}
DEMO: http://jsbin.com/idowan/edit#javascript,live
To break it down:
function toN5( x ) {
// v---we're going to reduce x to the tens place, and for each place
// v reduction, we'll multiply i * 10 to restore x later.
var i = 1;
// as long as x >= 100, divide x by 10, and multiply i by 10.
while( x >= 100 ) {x/=10; i*=10;}
// Now round up to the next 5 by adding to x the difference between 5 and
// the remainder of x/5 (or if the remainder was 0, we substitute 5
// for the remainder, so it is (x + (5 - 5)), which of course equals x).
// So then since we are now in either the tens or ones place, and we've
// rounded to the next 5 (or stayed the same), we multiply by i to restore
// x to its original place.
return (x + (5-((x%5)||5))) * i;
}
Or to avoid logical operators, and just use arithmetic operators, we could do:
return (x + ((5-(x%5))%5)) * i;
And to spread it out a bit:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {
x/=10;
i*=10;
}
var remainder = x % 5;
var distance_to_5 = (5 - remainder) % 5;
return (x + distance_to_5) * i;
}
var numbers = [51255, 25, 9214, 13135, 25123, 3, 6];
function weird_round(a) {
var len = a.toString().length;
var div = len == 1 ? 1 : Math.pow(10, len - 2);
return Math.ceil(a / 5 / div) * div * 5;
}
alert(numbers.map(weird_round));
Also updated for numbers below 10. Won't work properly for negative numbers either, just mention if you need this.
DEMO
I'm not sure why, but I thought it would be fun with regular expressions:
var result = +(number.toString().replace(/([1-9])([0-9])(.+)/, function() {
return Math.ceil(+(arguments[1] + '.' + arguments[2])) * 10 - (+arguments[2] < 5?5:0) + arguments[3].replace(/./g, '0');
}));
Working Demo
with(Math) {
var exp = floor(log(number)/log(10)) - 1;
exp = max(exp,0);
var n = number/pow(10,exp);
var n2 = ceil(n/5) * 5;
var result = n2 * pow(10,exp);
}
http://jsfiddle.net/NvvGf/4/
Caveat: only works for the natural numbers.
function round(number) {
var numberStr = number + "",
max,
i;
if (numberStr[1] > '4') {
numberStr[0] = parseInt(numberStr[0]) + 1;
numberStr[1] = '0';
} else {
numberStr[1] = '5';
}
for (i = 2; max = numberStr.length; i < max; i += 1) {
numberStr += '0';
}
return parseInt(numberStr);
}
Strange coincidence, I wrote something really similar not so long ago!
function iSuckAtNames(n) {
var n = n.toString(), len = n.length, res;
//Check the second number. if it's less than a 5, round down,
//If it's more/equal, round up
//Either way, we'll need to use this:
var res = parseFloat(n[0]) * Math.pow(10, len - 1); //e.g. 5 * 10^4 = 50000
if (n[1] <= 5) {
//we need to add a 5 right before the end!
res += 5 * Math.pow(10, len - 2);
}
else {
//We need another number of that size
res += Math.pow(10, len - 1);
}
return res;
}

Categories

Resources