oxjs/source/Ox.UI/js/Form/Ox.Range.js

298 lines
10 KiB
JavaScript
Raw Normal View History

2011-11-05 16:46:53 +00:00
'use strict';
2011-12-21 13:42:47 +00:00
2011-05-16 08:24:46 +00:00
/*@
Ox.Range <f:Ox.Element> Range Object
() -> <f> Range Object
(options) -> <f> Range Object
(options, self) -> <f> Range Object
options <o> Options object
2011-12-21 13:42:47 +00:00
arrows <b> if true, show arrows
arrowStep <n> step when clicking arrows
arrowSymbols <[s]> arrow symbols, like ['minus', 'plus']
max <n> maximum value
min <n> minimum value
orientation <s> 'horizontal' or 'vertical'
step <n> step between values
size <n> width or height, in px
thumbSize <n> minimum width or height of thumb, in px
thumbStyle <s|'opaque'> Thumb style ('opaque' or 'transparent')
thumbValue <b> if true, display value on thumb
trackColors <[s]> CSS colors
trackGradient <b|false> if true, display track colors as gradient
trackImages <s|[s]> one or multiple track background image URLs
trackStep <n> 0 (scroll here) or step when clicking track
value <n> initial value
values <[s]> values to display on thumb
2011-05-16 10:49:48 +00:00
self <o> shared private variable
change <!> triggered on change of the range
2011-05-16 08:24:46 +00:00
@*/
2011-04-29 22:07:23 +00:00
2011-04-22 22:03:10 +00:00
Ox.Range = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
2011-12-21 13:42:47 +00:00
.defaults({
arrows: false,
arrowStep: 1,
arrowSymbols: ['left', 'right'],
changeOnDrag: false,
max: 100,
min: 0,
orientation: 'horizontal',
step: 1,
size: 128, // fixme: shouldn't this be width?
thumbSize: 16,
thumbStyle: 'default',
thumbValue: false,
trackColors: [],
trackGradient: false,
trackImages: [],
trackStep: 0,
value: 0,
values: [],
})
.options(options || {})
.addClass('OxRange')
.css({
width: self.options.size + 'px'
});
2011-04-22 22:03:10 +00:00
2011-12-21 13:42:47 +00:00
self.hasValues = !Ox.isEmpty(self.options.values);
if (self.hasValues) {
self.options.max = self.options.values.length - 1;
self.options.min = 0;
self.options.step = 1;
self.options.thumbValue = true;
self.options.value = Ox.isNumber(self.options.value)
? self.options.values[self.options.value] : self.options.value;
}
self.options.arrowStep = options.arrowStep || self.options.step;
2011-12-21 13:42:47 +00:00
self.options.trackImages = Ox.toArray(self.options.trackImages);
self.trackColors = self.options.trackColors.length;
self.trackImages = self.options.trackImages.length;
self.values = (
self.options.max - self.options.min + self.options.step
) / self.options.step;
2011-04-22 22:03:10 +00:00
setSizes();
if (self.options.arrows) {
self.$arrows = [];
Ox.range(0, 2).forEach(function(i) {
self.$arrows[i] = Ox.Button({
2011-04-22 22:03:10 +00:00
overlap: i == 0 ? 'right' : 'left',
title: self.options.arrowSymbols[i],
type: 'image'
})
.addClass('OxArrow')
.bindEvent({
2011-09-17 11:49:29 +00:00
mousedown: function(data) {
clickArrow(data, i, true);
2011-04-22 22:03:10 +00:00
},
2011-09-17 11:49:29 +00:00
mouserepeat: function(data) {
clickArrow(data, i, false);
2011-04-22 22:03:10 +00:00
}
})
.appendTo(that.$element);
});
}
self.$track = Ox.Element()
2011-04-22 22:03:10 +00:00
.addClass('OxTrack')
.css(Ox.extend({
2011-04-22 22:03:10 +00:00
width: (self.trackSize - 2) + 'px'
}, self.trackImages == 1 ? {
background: 'rgb(0, 0, 0)'
} : {}))
.bindEvent(Ox.extend({
2011-04-22 22:03:10 +00:00
mousedown: clickTrack,
drag: dragTrack
}, self.options.changeOnDrag ? {} : {
dragend: dragendTrack
}))
2011-04-22 22:03:10 +00:00
.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) {
$('<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',
width: self.thumbSize
})
2011-12-21 13:42:47 +00:00
.addClass('OxThumb' + (
self.options.thumbStyle == 'transparent' ? ' OxTransparent' : ''
))
2011-04-22 22:03:10 +00:00
.appendTo(self.$track);
setThumb();
2011-09-17 11:49:29 +00:00
function clickArrow(data, i, animate) {
2011-04-22 22:03:10 +00:00
// fixme: shift doesn't work, see menu scrolling
setValue(
self.options.value
+ self.options.arrowStep * (i == 0 ? -1 : 1) * (data.shiftKey ? 2 : 1),
2011-12-21 13:42:47 +00:00
animate,
true
);
2011-04-22 22:03:10 +00:00
}
2011-09-17 11:49:29 +00:00
function clickTrack(data) {
2011-04-22 22:03:10 +00:00
// fixme: thumb ends up a bit too far on the right
2011-09-19 13:17:35 +00:00
var isThumb = $(data.target).hasClass('OxThumb');
2011-04-22 22:03:10 +00:00
self.drag = {
left: self.$track.offset().left,
2011-09-17 11:49:29 +00:00
offset: isThumb ? data.clientX - self.$thumb.offset().left - 8 /*self.thumbSize / 2*/ : 0
2011-04-22 22:03:10 +00:00
};
2011-12-21 13:42:47 +00:00
setValue(getValue(data.clientX - self.drag.left - self.drag.offset), !isThumb, true);
2011-04-22 22:03:10 +00:00
}
2011-09-17 11:49:29 +00:00
function dragTrack(data) {
setValue(
2011-12-21 13:42:47 +00:00
getValue(data.clientX - self.drag.left - self.drag.offset),
false,
self.options.changeOnDrag
);
}
function dragendTrack(data) {
self.options.value = void 0;
2011-12-21 13:42:47 +00:00
setValue(getValue(data.clientX - self.drag.left - self.drag.offset), false, true);
2011-04-22 22:03:10 +00:00
}
2011-12-21 13:42:47 +00:00
function getPx(value) {
var pxPerValue = (self.trackSize - self.thumbSize)
/ (self.options.max - self.options.min);
value = self.hasValues ? self.options.values.indexOf(value) : value;
return Math.ceil((value - self.options.min) * pxPerValue);
2011-04-22 22:03:10 +00:00
}
/*
function getTime(oldValue, newValue) {
return self.animationTime * Math.abs(oldValue - newValue) / (self.options.max - self.options.min);
}
*/
2011-12-21 13:42:47 +00:00
function getValue(px) {
2011-04-22 22:03:10 +00:00
var px = self.trackSize / self.values >= 16 ? px : px - 8,
2011-12-21 13:42:47 +00:00
valuePerPx = (self.options.max - self.options.min)
/ (self.trackSize - self.thumbSize),
value = Ox.limit(
self.options.min
+ Math.floor(px * valuePerPx / self.options.step) * self.options.step,
self.options.min,
self.options.max
);
return self.hasValues ? self.options.values[value] : value;
2011-04-22 22:03:10 +00:00
}
function setSizes() {
self.trackSize = self.options.size - self.options.arrows * 32;
self.thumbSize = Math.max(self.trackSize / self.values, self.options.thumbSize);
2011-12-21 13:42:47 +00:00
self.trackImageWidths = self.trackImages == 1
? [self.trackSize - 16]
: Ox.divideInt(self.trackSize - 2, self.trackImages);
self.trackColorStart = self.options.trackGradient
? self.thumbSize / 2 / self.options.size : 0;
self.trackColorStep = self.options.trackGradient
? (self.options.size - self.thumbSize) / (self.trackColors - 1) / self.options.size
: 1 / self.trackColors;
that.css({
width: self.options.size + 'px'
});
2011-04-22 22:03:10 +00:00
self.$track && self.$track.css({
width: (self.trackSize - 2) + 'px'
});
if (self.$thumb) {
2011-12-21 13:42:47 +00:00
self.$thumb.options({width: self.thumbSize});
setThumb();
}
2011-04-22 22:03:10 +00:00
}
function setThumb(animate) {
self.$thumb.stop().animate({
2011-12-21 13:42:47 +00:00
marginLeft: getPx(self.options.value) - 1 + 'px',
2011-04-22 22:03:10 +00:00
//width: self.thumbSize + 'px'
}, animate ? 250 : 0, function() {
2011-12-21 13:42:47 +00:00
self.options.thumbValue && self.$thumb.options({
title: self.options.value
});
2011-04-22 22:03:10 +00:00
});
}
function setTrackColors() {
2011-12-21 13:42:47 +00:00
['moz', 'o', 'webkit'].forEach(function(browser) {
self.$track.css({
background: '-' + browser + '-linear-gradient(left, '
+ self.options.trackColors[0] + ' 0%, '
+ self.options.trackColors.map(function(v, i) {
var ret = v + ' ' + (
self.trackColorStart + self.trackColorStep * i
) * 100 + '%';
if (!self.options.trackGradient) {
ret += ', ' + v + ' ' + (
self.trackColorStart + self.trackColorStep * (i + 1)
) * 100 + '%';
}
return ret;
}).join(', ') + ', '
+ self.options.trackColors[self.trackColors - 1] + ' 100%)'
});
2011-04-22 22:03:10 +00:00
});
}
function setValue(value, animate, trigger) {
2011-11-10 22:47:38 +00:00
// fixme: toPrecision helps with imprecise results of divisions,
// but won't work for very large values. And is 10 a good value?
2011-12-21 13:42:47 +00:00
value = Ox.limit(
self.hasValues ? self.options.values.indexOf(value) : value.toPrecision(10),
self.options.min,
self.options.max
);
value = self.hasValues ? self.options.values[value] : value;
2011-04-22 22:03:10 +00:00
if (value != self.options.value) {
//time = getTime(self.options.value, value);
self.options.value = value;
setThumb(animate);
2011-12-21 13:42:47 +00:00
trigger && that.triggerEvent('change', {value: self.options.value});
2011-04-22 22:03:10 +00:00
}
}
2011-04-29 12:40:51 +00:00
self.setOption = function(key, value) {
2011-04-22 22:03:10 +00:00
if (key == 'size') {
setSizes();
} else if (key == 'trackColors') {
setTrackColors();
} else if (key == 'value') {
setThumb();
}
}
return that;
};