oxjs/source/js/Ox.UI/Form/Ox.Range.js
2011-04-25 11:12:02 +02:00

249 lines
9 KiB
JavaScript

// vim: et:ts=4:sw=4:sts=4:ft=js
Ox.Range = function(options, self) {
/**
options
arrows boolean if true, show arrows
arrowStep number step when clicking arrows
arrowSymbols array arrow symbols, like ['minus', 'plus']
max number maximum value
min number minimum value
orientation string 'horizontal' or 'vertical'
step number step between values
size number width or height, in px
thumbSize number minimum width or height of thumb, in px
thumbValue boolean if true, display value on thumb
trackGradient array colors
trackImages string or array one or multiple track background image URLs
trackStep number 0 (scroll here) or step when clicking track
value number initial value
valueNames array value names to display on thumb
*/
var self = self || {},
that = new Ox.Element({}, self)
.defaults({
arrows: false,
arrowStep: 1,
arrowSymbols: ['left', 'right'],
max: 100,
min: 0,
orientation: 'horizontal',
step: 1,
size: 128,
thumbSize: 16,
thumbValue: false,
trackColors: [],
trackImages: [],
trackStep: 0,
value: 0,
valueNames: null,
})
.options($.extend(options, {
arrowStep: options.arrowStep ?
options.arrowStep : options.step,
trackImages: $.makeArray(options.trackImages || [])
}))
.addClass('OxRange')
.css({
width: self.options.size + 'px'
});
$.extend(self, {
trackColors: self.options.trackColors.length,
trackImages: self.options.trackImages.length,
values: (self.options.max - self.options.min + self.options.step) /
self.options.step
});
setSizes();
if (self.options.arrows) {
self.$arrows = [];
Ox.range(0, 2).forEach(function(i) {
self.$arrows[i] = new Ox.Button({
overlap: i == 0 ? 'right' : 'left',
title: self.options.arrowSymbols[i],
type: 'image'
})
.addClass('OxArrow')
.bindEvent({
mousedown: function(event, e) {
clickArrow(e, i, true);
},
mouserepeat: function(event, e) {
clickArrow(e, i, false);
}
})
.appendTo(that.$element);
});
}
self.$track = new Ox.Element()
.addClass('OxTrack')
.css($.extend({
width: (self.trackSize - 2) + 'px'
}, self.trackImages == 1 ? {
background: 'rgb(0, 0, 0)'
} : {}))
.bindEvent({
mousedown: clickTrack,
drag: dragTrack
})
.appendTo(that.$element);
self.trackColors && setTrackColors();
if (self.trackImages) {
self.$trackImages = $('<div>')
.css({
width: self.trackSize + 'px',
marginRight: (-self.trackSize - 1) + 'px'
})
.appendTo(self.$track.$element);
self.options.trackImages.forEach(function(v, i) {
//Ox.print(self.trackImageWidths[i])
$('<img>')
.attr({
src: v
})
.addClass(i == 0 ? 'OxFirstChild' : '')
.addClass(i == self.trackImages - 1 ? 'OxLastChild' : '')
.css({
width: self.trackImageWidths[i] + 'px'
})
.mousedown(function(e) {
e.preventDefault(); // prevent drag
})
.appendTo(self.$trackImages);
//left += self.trackImageWidths[i];
});
}
self.$thumb = Ox.Button({
id: self.options.id + 'Thumb',
title: self.options.thumbValue ? (self.options.valueNames ?
self.options.valueNames[self.options.value] :
self.options.value) : '',
width: self.thumbSize
})
.addClass('OxThumb')
/*
.css({
border: '1px solid rgb(255, 255, 255)',
background: 'rgba(0, 0, 0, 0)'
})
*/
.appendTo(self.$track);
setThumb();
function clickArrow(e, i, animate) {
// fixme: shift doesn't work, see menu scrolling
setValue(self.options.value + self.options.arrowStep * (i == 0 ? -1 : 1) * (e.shiftKey ? 2 : 1), animate);
}
function clickTrack(event, e) {
// fixme: thumb ends up a bit too far on the right
var isThumb = $(e.target).hasClass('OxThumb');
self.drag = {
left: self.$track.offset().left,
offset: isThumb ? e.clientX - self.$thumb.offset().left - 8 /*self.thumbSize / 2*/ : 0
};
setValue(getVal(e.clientX - self.drag.left - self.drag.offset), !isThumb);
}
function dragTrack(event, e) {
setValue(getVal(e.clientX - self.drag.left - self.drag.offset))
}
function getPx(val) {
var pxPerVal = (self.trackSize - self.thumbSize) /
(self.options.max - self.options.min);
return Math.ceil((val - self.options.min) * pxPerVal);
}
/*
function getTime(oldValue, newValue) {
return self.animationTime * Math.abs(oldValue - newValue) / (self.options.max - self.options.min);
}
*/
function getVal(px) {
var px = self.trackSize / self.values >= 16 ? px : px - 8,
valPerPx = (self.options.max - self.options.min) /
(self.trackSize - self.thumbSize);
return Ox.limit(self.options.min +
Math.floor(px * valPerPx / self.options.step) * self.options.step,
self.options.min, self.options.max);
}
function setSizes() {
self.trackSize = self.options.size - self.options.arrows * 32;
self.thumbSize = Math.max(self.trackSize / self.values, self.options.thumbSize);
self.trackImageWidths = self.trackImages == 1 ? [self.trackSize - 16] :
Ox.divideInt(self.trackSize - 2, self.trackImages);
self.trackColorsStart = self.thumbSize / 2 / self.options.size;
self.trackColorsStep = (self.options.size - self.thumbSize) /
(self.trackColors - 1) / self.options.size;
self.$track && self.$track.css({
width: (self.trackSize - 2) + 'px'
});
self.$thumb && self.$thumb.options({
width: self.thumbSize
});
}
function setThumb(animate) {
self.$thumb.stop().animate({
marginLeft: (getPx(self.options.value) - 1) + 'px',
//width: self.thumbSize + 'px'
}, animate ? 200 : 0, function() {
if (self.options.thumbValue) {
self.$thumb.options({
title: self.options.valueNames ?
self.options.valueNames[self.options.value] :
self.options.value
});
}
});
}
function setTrackColors() {
self.$track.css({
backgroundImage: $.browser.mozilla ?
('-moz-linear-gradient(left, ' +
self.options.trackColors[0] + ' 0%, ' + $.map(self.options.trackColors, function(v, i) {
return v + ' ' + ((self.trackColorsStart + self.trackColorsStep * i) * 100) + '%';
}).join(', ') + ', ' + self.options.trackColors[self.trackColors - 1] + ' 100%)') :
('-webkit-gradient(linear, left top, right top, color-stop(0, ' +
self.options.trackColors[0] + '), ' + $.map(self.options.trackColors, function(v, i) {
return 'color-stop(' + (self.trackColorsStart + self.trackColorsStep * i) + ', ' + v + ')';
}).join(', ') + ', color-stop(1, ' + self.options.trackColors[self.trackColors - 1] + '))')
});
}
function setValue(value, animate) {
var value = Ox.limit(value, self.options.min, self.options.max);
if (value != self.options.value) {
//time = getTime(self.options.value, value);
self.options.value = value;
setThumb(animate);
that.triggerEvent('change', {
value: value
});
}
}
self.onChange = function(key, value) {
if (key == 'size') {
setSizes();
} else if (key == 'trackColors') {
setTrackColors();
} else if (key == 'value') {
setThumb();
}
}
return that;
};