Search

Rss Posts

Rss Comments

Login

 

Posts in ‘javascript’

dateSlider jQuery plugin

Feb 18

This is actually the third version, as the first two didn’t quite hit the mark on the requirements… This jQuery dateslider is based on the slick and cool Ajaxorized version, originally written for Prototype.js. What I didn’t like was that it’s zoom in/out feature didn’t really scale very well (what unit I am looking at? and why don’t these lines line up?), and made it hard to pick a date and time.

I used jQueryUI because it handily had all the things I need: draggable, resizable things. The hardest part was, of course, the actual date-times (as anyone who has to work with Javascript dates knows). I used the super handy date.js like the original as well.

To use it, include jquery, jqueryui, date.js, and the plugin:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script>
<script src="date.js"></script>
<script src="jquery.dateRanger.js" type="text/javascript"></script>

Then, initalize the plugin:


<script type="text/javascript">
$(function(){
$("#my-date-slider").dateRanger({
"dateFormat": "MMM dd yyyy HH:mm:ss",
"timeStart": Date.today().set({
day: 1,
month: 0,
year: 2011
}),"timeEnd": Date.today().set({
day: 30,
month: 11,
year: 2012
}),
"startDate": Date.parse("1/17/2011"),
"endDate": Date.parse("4/2/2011"),
"zoomLevel": "month",
"unitwidth": 20
})
});
</script>
The options:

  • dateFormat : a string or date.js format specified (check it!) (i.e. “MMM dd”, “u”, “yyyy-MM-d ht”)
  • timeStart: the first available date; You can pass in anything recognized by date.js (i.e. “today”, “yesterday”, “+2weeks”, “-18years”, etc.)
  • timeEnd: the last available date
  • startDate: beginning of the selected range
  • endDate: the end of the selected range
  • zoomLevel: what time unit you see on load: accepts “year”,”month”,”day”, or “hour”
  • unitwidth: how wide is a unit? If you change this, be sure to change the css for .day to match

Download plugin: jquery.dateRanger.js:
(function($){
$.fn.dateRanger = function(options){
var settings = {
"startDate": Date.parse('-7days'),
"endDate": Date.parse('-1days'),
"dateFormat": 'MMM dd yyyy HH:mm:ss',
"timeStart": Date.today().set({
day: 1,
month: 0,
year: 2011
}).clearTime(),
"timeEnd": Date.today().set({
day: 31,
month: 11,
year: 2012
}).clearTime(),
"zoomLevel": "day",
"unitwidth": 20
};
var config = $.extend(settings, options);
var zoom = config.zoomLevel, rangeStart = config.startDate, rangeStop = config.endDate, timeStart = config.timeStart, timeEnd = config.timeEnd, f = config.dateFormat, w = config.unitwidth, one = new Array();
one["second"] = 1000;
one["minute"] = 1000 * 60;
one["hour"] = 1000 * 60 * 60;
one["day"] = 1000 * 60 * 60 * 24;
one["month"] = 1000 * 60 * 60 * 24 * 30;
one["year"] = 1000 * 60 * 60 * 24 * 365;
function mapDates(ui){
var range = ui.width() / w;
var s = ui.position().left / w;
var e = s + range - 1;
var startDate = $j(".day").eq(s).attr("data-date");
var endDate = $j(".day").eq(e).attr("data-date");
$j("#datestart").val(startDate.toString(f))
$j("#dateend").val(inclusiveRange(endDate, zoom).toString(f))
centerSelection();
}
function centerSelection(){
$j("#dragger").css('left', -1 * ($j("#resizer").position().left - .5 * ($j("#mask").width() - $j("#resizer").width())))
}
function difference(a, b, z){
A = a.getTime() / one[z];
B = b.getTime() / one[z];
return Math.floor(B - A);
}
function unitsbetween(a, b, z){
A = a.getTime() / one[z];
B = b.getTime() / one[z];
return (B - A);
}
function inclusiveRange(d, zoom){
var $fullrange = (Date.parse(d)) ? Date.parse(d) : Date.parse(d.substring(0, d.length - 1));
var compare = $fullrange.clone();
switch (zoom) {
case "year":
return compare.set({
month: 0,
day: 1
}).clearTime().add(1).years().add(-1).seconds();
break;
case "month":
return compare.moveToLastDayOfMonth().add(1).days().add(-1).seconds();
break;
case "day":
return compare.add(1).days().add(-1).seconds();
break;
case "hour":
return compare.add(1).hours().add(-1).seconds();
break;
case "minute":
return compare.add(1).minute().add(-1).seconds();
break;
case "second":
return compare.add(1).seconds().add(-1).milliseconds();
break;
default:
return $fullrange;
break;
}
}
function buildDates(zoom){
$j("#dragger").css('left', '0')
$j("#dragger .day").remove();
$j("#resizer").css({
left: 0,
width: w + "px"
})
var visibleArea, format1, format2, tempDate;
switch (zoom) {
case "hour":
var tempDateHS = Date.parse($j("#datestart").val()).clone().add(-1).days();
var tempDateHE = Date.parse($j("#dateend").val()).clone().clearTime().add(2).days();
visibleArea = difference(tempDateHS, tempDateHE, zoom);
format1 = "MMM dd yy ht";
format2 = "ht";
tempDate = tempDateHS.clone()
break;
case "day":
visibleArea = difference(config.timeStart, timeEnd, zoom);
format1 = "MMM dd yy";
format2 = " dd";
tempDate = timeStart.clone()
break;
case "month":
visibleArea = difference(config.timeStart, timeEnd, zoom);
format1 = "MMM 'yy";
format2 = "MMM 'yy";
tempDate = timeStart.clone()
break;
case "year":
visibleArea = Math.max(timeEnd.getFullYear() - config.timeStart.getFullYear(), 1);
format1 = "yyyy";
tempDate = timeStart.clone()
break;
}
$j("#dragger").css('width', visibleArea * w)
for (i = 0; i < visibleArea; i++) {
if ((zoom == "day" && tempDate.getDate() == 1) || (zoom == "hour" && tempDate.getHours() == 0)) {
format = format1;
cl = " fdotm"
}
else
if (zoom == "month" && tempDate.getMonth() == 0) {
format = format1;
cl = " fmoty"
}
else
if (zoom == "year") {
format = format1;
cl = " yrot"
}
else {
format = format2;
cl = "";
}
$j("#dragger").append('<div data-date="' + tempDate.toString(f) + '">' + tempDate.toString(format) + '</div>')
tempDate.add(1)[zoom]()
}
}
function setScroller(s, r){
if (r > 1)
r = Math.ceil(r);
else
r = Math.round(r);
$j("#resizer").css({
left: $j(".day[data-date='" + s + "']").position().left,
width: r * w + "px"
})
}
function u2Date(u){
if (u.indexOf("Z") != -1)
return Date.parse(u.substring(0, u.length - 1));
else
return Date.parse(u);
}
$j("#datestart").live("change", function(e){
if (Date.parse($j(this).val())) {
var inpS = Date.parse($j(this).val());
var inpE = u2Date($j("#dateend").val())
if (inpS.compareTo(inpE) == 1) {
inpE = inpS;
}
$j("#datestart").val(inpS.toString(f));
setScroller($j("#datestart").val(), Math.max(difference(inpS, inpE, zoom), 1))
mapDates($j("#resizer"));
}
else {
$j(this).addClass("error").effect("pulsate", {
times: 2
}, 500, function(){
$j(this).removeClass("error").focus()
});
}
});
$j("#dateend").live("change", function(e){
if (Date.parse($j(this).val())) {
var inpE = Date.parse($j(this).val());
var inpS = u2Date($j("#datestart").val())
if (inpS.compareTo(inpE) == 1) {
inpE = inpS;
}
$j("#dateend").val(inpE.toString(f));
setScroller($j("#datestart").val(), Math.max(difference(inpS, inpE, zoom), 1))
mapDates($j("#resizer"));
}
else {
$j(this).addClass("error").effect("pulsate", {
times: 2
}, 500, function(){
$j(this).removeClass("error").focus()
});
}
});
$j("div.zoomMenu div").live("click", function(){
$t = $j(this);
zoom = $t.html();
$j("div.zoomMenu div").removeClass("selectedZoom")
$t.addClass("selectedZoom");
buildDates(zoom)
inpS = u2Date($j("#datestart").val());
inpE = u2Date($j("#dateend").val());
switch (zoom) {
case "hour":
inpS.set({
"hour": 0
});
inpE = inclusiveRange(inpE, zoom);
break;
case "day":
inpS.set({
"hour": 0
});
inpE = inclusiveRange(inpE, zoom);
break;
case "month":
inpS.moveToFirstDayOfMonth();
inpE.moveToLastDayOfMonth();
break;
case "year":
inpS.set({
month: 0,
day: 1
});
inpE.set({
month: 0,
day: 1
}).add(1).years().add(-1).seconds();
break;
}
$j("#datestart").val(inpS.toString(f));
$j("#dateend").val(inpE.toString(f));
setScroller($j("#datestart").val(), difference(inpS, inpE, zoom))
mapDates($j("#resizer"));
});
return this.each(function(){
var zooms = {
"year": "yyyy",
"month": "MMM",
"day": "dd",
"hour": "HH"
};
var structure = '<div id="range">';
structure += '<div id="dragDate">';
structure += '<label for="datestart">Start</label><input id="datestart" name="datestart" type="text" /> ';
structure += '<label for="dateend">Stop</label><input id="dateend" type="text" name="dateend"/>';
structure += '</div>';
structure += '<div id="mask"><div id="dragger"><div id="resizer"></div></div>';
structure += '</div>';
structure += '<div>';
var cla = '';
for (b in zooms) {
cla = (b == zoom) ? '' : '';
structure += '<div' + cla + '>' + b + '</div>';
}
structure += '</div></div>';
$j(this).append(structure);
buildDates(zoom);
$j("#dragger").draggable({
grid: [w, 0],
axis: 'x',
addClasses: false
});
$j("#resizer").resizable({
handles: 'e, w',
grid: [w, 0],
containment: '#dragger',
stop: function(event, ui){
if (ui.position.left < 0) {
$j("#resizer").css('left', '0px')
}
mapDates($j(this))
},
addClasses: false
}).draggable({
grid: [w, 0],
axis: 'x',
containment: '#dragger',
stop: function(event, ui){
mapDates($j(this))
},
addClasses: false
}).css({
left: $j(".day[data-date='" + rangeStart.toString(f) + "']").position().left,
width: difference(rangeStart, rangeStop, zoom) * w + "px"
});
mapDates($j("#resizer"));
centerSelection();
});
};
})(jQuery);

And some useful CSS to finish up with:

#range {
position: relative;
}
.day {
color: #8997a5;
padding: 10px 0 0;
font-size: 9px;
width: 19px;
float: left;
height: 25px;
border-left: 1px solid #eee;
text-align: center;
}
.fdotm {
padding: 1px 0 0 0;
border-left: 1px solid #bbb;
height: 35px;
}
.fmoty {
padding: 10px 0 0 0;
border-left: 1px solid #888;
height: 25px;
}
.yrot {
font-size: 8px
}
#mask {
width: 100%;
overflow: hidden;
height: 80px;
position: absolute;
left: 0;
top: 50px;
}
#dragger{
width: 10000em;
position: absolute;
left: 0;
top: 10px;
z-index: 2;
height: 75px;
cursor: move;
padding: 10px 0 0 0;
background: none;
border: none;
color: #000;
}
#dragger #resizer{
background: rgba(0, 137, 206, 0.2);
width: 200px;
position: absolute;
top: 10px;
z-index: 6;
height: 40px;
cursor: move;
padding: 0;
margin: 0;
}
.error {
background: #ff0013;
}
.zoomMenu {
padding: 10px 0 0 0;
text-align: center;
}
.zoomMenu div {
display: inline;
color: #0089ce;
text-align: center;
cursor: pointer;
margin-right: 5px;
padding: 2px 6px;
position: relative;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.zoomMenu div:hover {
background: #e5f3fb;
color: #333;
}
.zoomMenu div.selectedZoom {
background: #0089ce;
color: #fff;
}

jQuery quick slideshow

Aug 04

Ok, so I’ve been playing more and more with jQuery. Here’s my take on showing off my portfolio, where I give a brief on each project and include a screen-shot.  This also uses the cool reflection.js for the images, and provides a simple progress stepper.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">// <![CDATA[
$(function() {
$('#mainContent img').addClass("reflect rheight10");
$('#mainContent img').css("float","right"); //reflect messes up floats, so add back in here
$(".H").append('<span>&laquo; Prev</span> | <span>Next &raquo;</span>');
var g=1;
$(".H").each(function(){
perc = (g/$(".H").length)*100;
$(this).append('
<div>
<div style="width:'+perc+'%"></div>
</div>
')
g++;
});
$(".next").css('cursor','pointer').click(function(){    slideShow();    })
$(".prev").css('cursor','pointer').click(function(){    slideShowPrev();})
$(".H").filter(':not(:last)').hide();
$(".H").filter(':last').addClass('show'); //'show' the last slide because when we call slideshow(), it will loop around to the first slide
$('#port a').attr('target','_blank');
slideShow();
});

function slideShow() {
var current = $('#port .show');
var next = current.next().length ? current.next() : current.parent().children(':first');
current.fadeOut('slow').removeClass('show');
next.fadeIn('slow').addClass('show');
}
function slideShowPrev() {
var current = $('#port .show');
var prev = current.prev().length ? current.prev() : current.parent().children(':first');
current.fadeOut('slow').removeClass('show');
prev.fadeIn('slow').addClass('show');
}
// ]]></script>
<script src="scripts/reflection/reflection.js" type="text/javascript"></script>

This works with the structure I already had–classed div’s holding each project.

Mootools Noobslide Hover/mouseover/mouseenter good times

Sep 08

I’ve had the Noobslide (slideshow “class” for Mootools (great tutorial here) for awhile, but I needed to added some basic functionality: when you hover (or mouseover) a slide, it stops the show so you can read it. When you rollout (mouseleave or mouseout), the show starts up again. Great!

Note that this assumes you have your slides in generic <span> tags inside something with an id of ‘box1′.


window.addEvent('domready',function(){
var nS1 = new noobSlide({
box: $('box1'),
items: [0,1,2,3,4],
size: 400,
autoPlay: true,
interval: 8000,
fxOptions: {
duration: 1000,
transition: Fx.Transitions.Expo.easeInOut,
wait: false
}
});
//add mousein/out behaviors for all slides
$$('#box1 span').addEvents({
'mouseover':function(){
nS1.stop();
},
'mouseleave':function(){
//make sure the first argument matches your 'interval' value above
//this will set the delay,go to the next slide, without waiting for the delay (rolloff, immediately transitions to next slide)
nS1.play(8000,"next",false);
}
});
//end domready
});

Cool. Another thing I wanted was some text links to jump around the slide show. I’ve got my slides in a container with an id of’slidefloater.’ Here it is: (this would be inserted before the last ‘});’, inside the domready function )

var clinker=new Element('div',{'id':'clinker','styles':{'width':400}});
clinker.inject($('slidefloater'));
var labels = Array("label 0","label 1","label 2","label 3","label 4");
var i=0;
labels.each(function(el){
var linkto=new Element('a',{'html':el,'href':'#','styles':{'margin-right':4}});
linkto.j = i; //localize
linkto.addEvent('click', function(){
nS1.stop();
nS1.walk(this.j);
nS1.play(8000,"next",true); //go to next slide after normal interval (wait to go)
} );
i++;
linkto.inject($('clinker'));
});

Good times!