JavaXT
|
|
Slider Classif(!javaxt) var javaxt={}; if(!javaxt.dhtml) javaxt.dhtml={}; //****************************************************************************** //** Slider //*****************************************************************************/ /** * Basic horizontal slide control. Can be used as a range slider, play * control, etc. Supports touch devices. Credit: * http://css3wizardry.com/2010/09/14/range-slider-with-css-and-javascript/ * ******************************************************************************/ javaxt.dhtml.Slider = function(parent, config) { var me = this; var defaultConfig = { /** Initial value for the slider */ value: 0, /** If true, the slider will be disabled when it is initialized. The * slider can be enabled and disabled using the enable() and disable() * methods. */ disabled: false, /** Style for individual elements within the component. Note that you can * provide CSS class names instead of individual style definitions. */ style: { groove: "sliderGrove", handle: "sliderHandle" } }; var handle, slider, mask; var value; //number - leave undefined initially var sliderHeight = 0; var handleWidth = 0; var handleHeight = 0; var xOffset = 0; var yOffset = 0; //************************************************************************** //** Constructor //************************************************************************** var init = function(){ if (typeof parent === "string"){ parent = document.getElementById(parent); } if (!parent) return; //Clone the config so we don't modify the original config object var clone = {}; merge(clone, config); //Merge clone with default config merge(clone, defaultConfig); config = clone; //Create slider div slider = createElement('div', parent, config.style.groove); slider.style.position = "relative"; slider.style.padding = "0px"; //padding inside the grove can throw off height calc slider.style.width = '100%'; me.el = slider; //Add slider control handle = createElement('div', slider, config.style.handle); handle.style.position = "absolute"; onRender(slider, function(){ var handleRect = javaxt.dhtml.utils.getRect(handle); var sliderRect = javaxt.dhtml.utils.getRect(slider); handleWidth = handleRect.width; handleHeight = handleRect.height; var sliderWidth = getWidth(slider); sliderHeight = sliderRect.height; xOffset = -(handleWidth/2); yOffset = -(handleHeight/2) + (sliderHeight/2); updateSlider(0, true); handle.style.left = xOffset + 'px'; handle.style.top = yOffset + 'px'; var top = yOffset; //-6; Drag.init(handle, null, 0, sliderWidth-handleWidth, top, top); handle.onDrag = function() { updateSlider(Drag.x); me.onDrag(me.getValue()); }; handle.onDragEnd = function() { }; //Bind to 'touchmove' events (touch devices only) handle.addEventListener('touchmove', function(event) { event.preventDefault(); var touch = event.touches[0]; var x = touch.pageX - this.parentNode.offsetLeft; if (x<0) x = 0; if (x>(sliderWidth-(handleWidth))) x = (sliderWidth-(handleWidth)); this.style.left = x + 'px'; updateSlider(x); me.onDrag(me.getValue()); }, false); if (config.disabled===true) me.disable(); me.setValue(config.value, true); me.onRender(); }); }; //************************************************************************** //** enable //************************************************************************** /** Used to enable the slider. */ this.enable = function(){ var outerDiv = me.el; outerDiv.style.opacity = ""; if (mask) mask.style.visibility = "hidden"; }; //************************************************************************** //** disable //************************************************************************** /** Used to disable the slider. */ this.disable = function(){ var outerDiv = me.el; outerDiv.style.opacity = "0.5"; if (mask){ mask.style.visibility = "visible"; } else{ mask = document.createElement('div'); mask.setAttribute("desc", "mask"); mask.style.position = "absolute"; mask.style.zIndex = 1; mask.style.width = "100%"; mask.style.height = handleHeight + "px"; mask.style.top = yOffset + "px"; mask.style.left = -(handleWidth/2) + "px"; var m2 = mask.cloneNode(); m2.style.top = ""; m2.style.left = ""; m2.style.right = -(handleWidth/2) + "px"; mask.appendChild(m2); outerDiv.insertBefore(mask, outerDiv.firstChild); } }; //************************************************************************** //** isEnabled //************************************************************************** /** Returns true if the slider is enabled. */ this.isEnabled = function(){ return !me.isDisabled(); }; //************************************************************************** //** isDisabled //************************************************************************** /** Returns true if the slider is disabled. */ this.isDisabled = function(){ if (mask){ if (mask.style.visibility !== "hidden") return true; } return false; }; //************************************************************************** //** onRender //************************************************************************** /** Called after the slider has been added to the DOM */ this.onRender = function(){}; //************************************************************************** //** onDrag //************************************************************************** /** Called whenever the slider handle is dragged by the user. */ this.onDrag = function(val){}; //************************************************************************** //** onChange //************************************************************************** /** Called whenever the position of the slider handle has changed. */ this.onChange = function(val){}; //************************************************************************** //** getValue //************************************************************************** /** Returns the value of the slider. * @param returnPercentage Optional. If true, returns a percentage value. * Otherwise, returns the current position of the slider in pixels. */ this.getValue = function(returnPercentage){ var w = me.getWidth(); var val = value; if (val>=(w-(handleWidth/2))) val = w; if (returnPercentage===true){ var p = Math.round((val/w) * 100) / 100; if (p>1) p = 1; if (p<0) p = 0; return p; } else{ return val; } }; //************************************************************************** //** getWidth //************************************************************************** /** Returns the width of the slider. This, together with the getValue() * method, can be used to compute a percentage value. */ this.getWidth = function(){ return getWidth(slider)-(handleWidth/2); }; //************************************************************************** //** setValue //************************************************************************** /** Used to set the position of the slider. * @param x Accepts a number representing pixels from the left or a string * representing a percentage value (e.g. '50%') * @param silent If true, will not fire the onChange event */ this.setValue = function(x, silent){ if (javaxt.dhtml.utils.isString(x)){ if (x.lastIndexOf("%")===x.length-1){ x = parseInt(x.substring(0,x.length-1)); if (isNaN(x) || x<0 || x>100) return; x = me.getWidth() * (x/100); } } if (javaxt.dhtml.utils.isNumber(x)){ x = parseFloat(x); } else { return; } handle.style.left = (x-(handleWidth/2)) + 'px'; updateSlider(x, silent); }; //************************************************************************** //** getStyle //************************************************************************** /** Returns the computed style for a given element. */ var getStyle = function(element){ return document.defaultView.getComputedStyle(element, null); }; //************************************************************************** //** getProperty //************************************************************************** var getProperty = function(style, property){ return style.getPropertyValue(property.toLowerCase()); }; //************************************************************************** //** updateSlider //************************************************************************** /** Updates the background of the slider and fires the onChange event. * @param silent If true, will not fire the onChange event */ var updateSlider = function(x, silent){ if (x===value) return; value = x; var sz = (x+(handleWidth/2)) + "px " + sliderHeight + "px, 100% " + sliderHeight + "px"; slider.style.MozBackgroundSize = sz; //-moz-background-size slider.style.backgroundSize = sz; //background-size if (silent!==true) me.onChange(value); }; //************************************************************************** //** getWidth //************************************************************************** var getWidth = function(slider){ var style = getStyle(slider); var sliderWidth = parseInt(getProperty(style, "width")); var padding = parseInt(getProperty(style, "padding-right")); var border = parseInt(getProperty(style, "border-right-width")); sliderWidth -= padding; sliderWidth -= border; return sliderWidth; }; //************************************************************************** //** Drag //************************************************************************** /** Class used to manage the slider. */ var Drag = { // The current element being dragged. obj: null, // The initalization function for the object to be dragged. // elem is an element to use as a handle while dragging (optional). // elemParent is the element to be dragged, if not specified, // the handle will be the element dragged. // minX, maxX, minY, maxY are the min and max coordinates // allowed for the element while dragging. // bSwapHorzRef will toggle the horizontal coordinate system from referencing // the left of the element to the right of the element. // bSwapVertRef will toggle the vertical coordinate system from referencing // the top of the element to the bottom of the element. init: function(elem, elemParent, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef) { // Watch for the drag event to start. elem.onmousedown = Drag.start; // Figure out which coordinate system is being used. elem.hmode = bSwapHorzRef ? false : true ; elem.vmode = bSwapVertRef ? false : true ; // Figure out which element is acting as the draggable "handle." elem.root = elemParent && elemParent != null ? elemParent : elem ; var style = getStyle(elem.root); // Initalize the specified coordinate system. // In order to keep track of the position of the dragged element, // we need to query the inline position values. // Therefore we query the element's style properties // to get those values and attach them inline on the element. if (elem.hmode && isNaN(parseInt(elem.root.style.left ))) { elem.root.style.left = getProperty(style, "left"); } if (elem.vmode && isNaN(parseInt(elem.root.style.top ))) { elem.root.style.top = getProperty(style, "top"); } if (!elem.hmode && isNaN(parseInt(elem.root.style.right ))) { elem.root.style.right = getProperty(style, "right"); } if (!elem.vmode && isNaN(parseInt(elem.root.style.bottom))) { elem.root.style.bottom = getProperty(style, "bottom"); } // Look to see if the user provided min/max x/y coordinates. elem.minX = typeof minX != 'undefined' ? minX : null; elem.minY = typeof minY != 'undefined' ? minY : null; elem.maxX = typeof maxX != 'undefined' ? maxX : null; elem.maxY = typeof maxY != 'undefined' ? maxY : null; // Add methods for user-defined functions. elem.root.onDragStart = new Function(); elem.root.onDragEnd = new Function(); // The following will fire continuously while the element // is being dragged. Useful if you want to create a slider that // can update some type of data as it is being dragged. elem.root.onDrag = new Function(); }, start: function(e) { // Figure out which object is being dragged. var elem = Drag.obj = this; // Normalize the event object. e = Drag.fixE(e); // Get the current x and y coordinates. Drag.y = parseInt(elem.vmode ? elem.root.style.top : elem.root.style.bottom); Drag.x = parseInt(elem.hmode ? elem.root.style.left : elem.root.style.right ); // Call the user's function with the current x and y coordinates. elem.root.onDragStart(Drag.x, Drag.y); // Remember the starting mouse position. elem.lastMouseX = e.clientX; elem.lastMouseY = e.clientY; // Do the following if the CSS coordinate system is being used. if (elem.hmode) { // Set the min and max coordiantes, where applicable. if (elem.minX != null) elem.minMouseX = e.clientX - Drag.x + elem.minX; if (elem.maxX != null) elem.maxMouseX = elem.minMouseX + elem.maxX - elem.minX; // Otherwise, use a traditional mathematical coordinate system. } else { if (elem.minX != null) elem.maxMouseX = -elem.minX + e.clientX + Drag.x; if (elem.maxX != null) elem.minMouseX = -elem.maxX + e.clientX + Drag.x; } // Do the following if the CSS coordinate system is being used. if (elem.vmode) { // Set the min and max coordiantes, where applicable. if (elem.minY != null) elem.minMouseY = e.clientY - Drag.y + elem.minY; if (elem.maxY != null) elem.maxMouseY = elem.minMouseY + elem.maxY - elem.minY; // Otherwise, we're using a traditional mathematical coordinate system. } else { if (elem.minY != null) elem.maxMouseY = -elem.minY + e.clientY + Drag.y; if (elem.maxY != null) elem.minMouseY = -elem.maxY + e.clientY + Drag.y; } // Watch for "drag" and "end" events. document.onmousemove = Drag.drag; document.onmouseup = Drag.end; return false; }, // A function to watch for all movements of the mouse during the drag event. drag: function(e) { // Normalize the event object. e = Drag.fixE(e); // Get our reference to the element being dragged. var elem = Drag.obj; // Get the position of the mouse within the window. var ey = e.clientY; var ex = e.clientX; // Get the current x and y coordinates. Drag.y = parseInt(elem.vmode ? elem.root.style.top : elem.root.style.bottom); Drag.x = parseInt(elem.hmode ? elem.root.style.left : elem.root.style.right ); var nx, ny; // If a minimum X position was set, make sure it doesn't go past that. if (elem.minX != null) ex = elem.hmode ? Math.max(ex, elem.minMouseX) : Math.min(ex, elem.maxMouseX); // If a maximum X position was set, make sure it doesn't go past that. if (elem.maxX != null) ex = elem.hmode ? Math.min(ex, elem.maxMouseX) : Math.max(ex, elem.minMouseX); // If a minimum Y position was set, make sure it doesn't go past that. if (elem.minY != null) ey = elem.vmode ? Math.max(ey, elem.minMouseY) : Math.min(ey, elem.maxMouseY); // If a maximum Y position was set, make sure it doesn't go past that. if (elem.maxY != null) ey = elem.vmode ? Math.min(ey, elem.maxMouseY) : Math.max(ey, elem.minMouseY); // Figure out the newly translated x and y coordinates. nx = Drag.x + ((ex - elem.lastMouseX) * (elem.hmode ? 1 : -1)); ny = Drag.y + ((ey - elem.lastMouseY) * (elem.vmode ? 1 : -1)); // Set the new x and y coordinates onto the element. Drag.obj.root.style[elem.hmode ? "left" : "right"] = nx + "px"; Drag.obj.root.style[elem.vmode ? "top" : "bottom"] = ny + "px"; // Remember the last position of the mouse. Drag.obj.lastMouseX = ex; Drag.obj.lastMouseY = ey; // Call the user's onDrag function with the current x and y coordinates. Drag.obj.root.onDrag(nx, ny); return false; }, // Function that handles the end of a drag event. end: function() { // No longer watch for mouse events (as the drag is done). document.onmousemove = null; document.onmouseup = null; // Call our special onDragEnd function with the x and y coordinates // of the element at the end of the drag event. Drag.obj.root.onDragEnd( parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"])); // No longer watch the object for drags. Drag.obj = null; }, // A function for normalizing the event object. fixE: function(e) { // If the element's properties aren't set, get the values from the equivalent offset properties. if (typeof e.elemX == 'undefined') e.elemX = e.offsetX; if (typeof e.elemY == 'undefined') e.elemY = e.offsetY; return e; } }; //************************************************************************** //** Utils //************************************************************************** var merge = javaxt.dhtml.utils.merge; var onRender = javaxt.dhtml.utils.onRender; var createElement = javaxt.dhtml.utils.createElement; init(); }; |