// vim: et:ts=4:sw=4:sts=4:ft=js /*@ Ox.Range Range Object () -> Range Object (options) -> Range Object (options, self) -> Range Object options Options object arrows if true, show arrows arrowStep step when clicking arrows arrowSymbols arrow symbols, like ['minus', 'plus'] max maximum value min minimum value orientation 'horizontal' or 'vertical' step step between values size width or height, in px thumbSize minimum width or height of thumb, in px thumbValue if true, display value on thumb trackGradient colors trackImages or one or multiple track background image URLs trackStep 0 (scroll here) or step when clicking track value initial value valueNames value names to display on thumb self shared private variable change triggered on change of the range @*/ Ox.Range = function(options, self) { 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, // fixme: shouldn't this be width? 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 = $('
') .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]) $('') .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; that.css({ width: self.options.size + 'px' }); self.$track && self.$track.css({ width: (self.trackSize - 2) + 'px' }); if (self.$thumb) { self.$thumb.options({ width: self.thumbSize }); setThumb(); } } 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.setOption = function(key, value) { if (key == 'size') { setSizes(); } else if (key == 'trackColors') { setTrackColors(); } else if (key == 'value') { setThumb(); } } return that; };