//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 = $('
') .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; 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; };