Files
django-ram/ram/driver/static/wt/js/jquery.rotaryswitch.js

420 lines
12 KiB
JavaScript

/*
Version 1.0.1
Copyright 2014 Red White Silver GmbH
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
(function($, window, document, undefined) {
var pluginName = 'rotaryswitch',
defaults = {
minimum: 0, // Minimal value
maximum: 12, // Maximum value
step: 1, // Step size
snapInMotion: true, // Snap to steps in motion
beginDeg: 0, // Start point in deg
lengthDeg: 360, // Length in deg
minimumOverMaximum: true, // Which value will used, if the the start and the end point at the same deg.
showInput: false, // Show input element
showMarks: false, // Show deg marks
themeClass: 'defaultTheme' // Theme class
};
function Plugin(element, options) {
this.element = $(element);
this.domElements = {};
this.htmlStructure = {
wrap: '<div class="rotaryswitchPlugin"></div>',
switchButton: '<div class="switch"></div>',
overlay: '<div class="overlay"></div>',
marks: '<div class="marks"></div>',
mark: '<div class="mark"></div>'
};
this.mousePosition = {x: -1, y: -1};
this.switchDeg = 0;
this.valueInPercent = 0;
this.value = 0;
this.steps = 0;
this.totalDeg = 0;
this.degPerStep = 0;
this.lastTriggeredValue = -1;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.initialize();
}
Plugin.prototype = {
/**
* Initialze this plugin
* See inline comments for more details
*
* @param none
* @return none
*/
initialize: function() {
// Save the needed jquery DOM elements
this.domElements = {
// Wrap the input element and save the parent as main element and add theme class:
main: this.element.wrap(this.htmlStructure.wrap).parent().addClass(this.options.themeClass),
switchButton: $(this.htmlStructure.switchButton),
overlay: $(this.htmlStructure.overlay)
};
// Append addional dom elements:
this.domElements.main.append([this.domElements.switchButton, this.domElements.overlay]);
// Calculate the length (Maximum - minimum)
this.steps = Math.abs(this.options.maximum - this.options.minimum);
// Calculate the total deg length
this.totalDeg = this.options.lengthDeg;
// Calculate deg per step
this.degPerStep = this.totalDeg / this.steps;
// Listen to some necessary events
this.domElements.main.on('mousedown', $.proxy(this.onMouseDown, this));
this.domElements.main.on('touchstart', $.proxy(this.onTouchStart, this));
this.element.on('change', $.proxy(this.onChangeElementValue, this));
this.readValueFromInput(); // Get the value from the input element
this.rotateSwitch(); // Rotate the switch
// Show marks if wished
if (this.options.showMarks === true) {
this.renderMarks();
}
// Show the input element if wished
if (this.options.showInput === false) {
this.element.hide();
}
},
/**
* Adds marks for each step
*
* @param none
* @return none
*/
renderMarks: function() {
var i=0,
len = this.steps / this.options.step,
deg = this.options.beginDeg,
degPerStep = this.degPerStep * this.options.step,
marks = $(this.htmlStructure.marks);
for (; i < len; i += 1) {
deg += degPerStep;
var mark = $(this.htmlStructure.mark).css({'transform': 'rotate('+deg+'deg) translate(0, -'+ (this.domElements.main.width()/2 + (this.domElements.main.width()*0.1)) +'px)'});
marks.append(mark);
}
this.domElements.main.append(marks);
},
/**
* On mouse down event handler
* Save the mouse position (x, y) to the object this.mousePosition
* call the method this.startHandling
*
* @param event jquery mouse event
* @return none
*/
onMouseDown: function(event) {
event.preventDefault();
this.mousePosition.x = event.pageX;
this.mousePosition.y = event.pageY;
this.startHandling();
},
/**
* On mouse up event handler
* call the method this.stopHandling
*
* @param event jquery mouse event
* @return none
*/
onMouseUp: function(event) {
this.stopHandling();
},
/**
* On mouse move event handler
* Save the mouse position (x, y) to the object this.mousePosition
* call the method this.calculateSwitchDeg
* call the method this.calculateValueByDeg
* call the method this.rotateSwitch
* call the method this.setValueToInput
*
* @param event jquery mouse event
* @return none
*/
onMousemove: function(event) {
event.preventDefault();
this.mousePosition.x = event.pageX;
this.mousePosition.y = event.pageY;
this.calculateSwitchDeg();
this.calculateValueByDeg();
this.rotateSwitch();
this.setValueToInput();
},
/**
* On touch start event handler
* Identical width this.onMouseDown
*
* @param event jquery touch event
* @return none
* @see this.onMouseDown
*/
onTouchStart: function(event) {
event.preventDefault();
this.mousePosition.x = event.originalEvent.targetTouches[0].pageX;
this.mousePosition.y = event.originalEvent.targetTouches[0].pageY;
this.startHandling();
},
/**
* On touch end event handler
* Identical width this.onMouseUp
*
* @param event jquery touch event
* @return none
* @see this.onMouseUp
*/
onTouchEnd: function(event) {
this.stopHandling();
},
/**
* On touch move event handler
* Identical width this.onMousemove
*
* @param event jquery touch event
* @return none
* @see this.onMousemove
*/
onTouchMove: function(event) {
event.preventDefault();
this.mousePosition.x = event.originalEvent.targetTouches[0].pageX;
this.mousePosition.y = event.originalEvent.targetTouches[0].pageY;
this.calculateSwitchDeg();
this.calculateValueByDeg();
this.rotateSwitch();
this.setValueToInput();
},
/**
* On change input element event handler
* If event not triggered by plugin:
* Call the method this.readValueFromInput
* Call the method this.rotateSwitch
*
* @param event jquery event
* @return none
*/
onChangeElementValue: function(event) {
if (!event.plugin || event.plugin !== this) {
this.readValueFromInput();
this.rotateSwitch();
}
},
/**
* Triggered by mouse or touch begin event
* Calls some methods
* Listen to some events
* Add class 'active' to the main DOM element (this.domElements.main)
*
* @param none
* @return none
*/
startHandling: function() {
this.calculateSwitchDeg();
this.calculateValueByDeg();
this.rotateSwitch();
this.setValueToInput();
$(document).on('mouseup', $.proxy(this.onMouseUp, this));
$(document).on('mousemove', $.proxy(this.onMousemove, this));
$(document).on('touchend', $.proxy(this.onTouchEnd, this));
$(document).on('touchmove', $.proxy(this.onTouchMove, this));
this.domElements.main.addClass('active');
},
/**
* Triggered by mouseup or touchend event
* Stop listen to some events
* Call method this.rotateSwitch
* Remove class 'active' from the main DOM element (this.domElements.main)
*
* @param none
* @return none
*/
stopHandling: function() {
$(document).off('mouseup', $.proxy(this.onMouseUp, this))
.off('mousemove', $.proxy(this.onMousemove, this))
.off('touchend', $.proxy(this.onTouchEnd, this))
.off('touchmove', $.proxy(this.onTouchMove, this));
this.rotateSwitch(true);
this.domElements.main.removeClass('active');
},
/**
* Calculate the switch deg by the element position and the mouse position
* Stores the switch deg in this.switchDeg
* @param none
* @return none
*/
calculateSwitchDeg: function() {
var offset = this.domElements.main.offset(),
radians = Math.atan2(this.mousePosition.x - (offset.left + (this.domElements.main.width()/2)), this.mousePosition.y - (offset.top + (this.domElements.main.height()/2)));
if (this.mousePosition.x !== -1) {
this.switchDeg = (radians * (180 / Math.PI) * -1) + 180;
}
},
/**
* Calculate the value by deg
* Stores the in percent in this.valueInPercent
* Stores the value in this.value
* @param none
* @return none
*/
calculateValueByDeg: function() {
var range = this.options.maximum - this.options.minimum;
if (this.switchDeg - this.options.beginDeg > 0) {
this.valueInPercent = (this.switchDeg - this.options.beginDeg) / this.totalDeg;
} else {
this.valueInPercent = (this.switchDeg - this.options.beginDeg + 360) / this.totalDeg;
}
if (this.valueInPercent > 1) {
if (this.valueInPercent > (((360 / this.totalDeg)-1) / 2)+1 ) {
this.valueInPercent = 0;
} else {
this.valueInPercent = 1;
}
}
this.value = ~~ (((((range * this.valueInPercent) < 0) ? -0.5 : 0.5) + ((range * this.valueInPercent) / this.options.step))) * this.options.step;
this.value += this.options.minimum;
if (this.options.lengthDeg === 360 && (this.value === this.options.minimum || this.value === this.options.maximum)) {
if (this.options.minimumOverMaximum === true) {
this.value = this.options.minimum;
} else {
this.value = this.options.maximum;
}
}
},
/**
* Rotate the switch with css transform
* snap to the the next rounded value if the parameter snap is true
* @param snap boolean
* @return none
*/
rotateSwitch: function(snap) {
var deg = 0,
exactDeg = (this.valueInPercent * this.totalDeg),
roundedDeg = ((this.value / this.steps) * this.totalDeg) - (this.options.minimum * this.degPerStep),
difference = Math.abs(Math.abs(exactDeg) - Math.abs(roundedDeg)),
rotateString = '';
if (snap === true || (this.options.snapInMotion === true && difference < this.degPerStep / 6)) {
if (roundedDeg + this.options.beginDeg < 360) {
deg = (roundedDeg + this.options.beginDeg);
} else {
deg = roundedDeg + this.options.beginDeg - 360;
}
} else {
if (exactDeg + this.options.beginDeg < 360) {
deg = (exactDeg + this.options.beginDeg);
} else {
deg = exactDeg + this.options.beginDeg - 360;
}
}
rotateString = ['rotate(', deg, 'deg)'].join('');
this.domElements.switchButton.css({
'transform': rotateString,
'-webkit-transform': rotateString,
'-moz-transform': rotateString,
'-o-transform': rotateString,
'-ms-transform': rotateString
});
},
/**
* Read the valur from the input element
* If no value available, this.options.minimum is used
* @param snap boolean
* @return none
*/
readValueFromInput: function() {
var elementValue = parseInt(this.element.val(), 10);
if (isNaN(elementValue) === true) {
this.value = this.options.minimum;
} else {
this.value = Math.max(this.options.minimum, elementValue);
this.value = Math.min(this.options.maximum, this.value);
}
this.value -= this.options.minimum;
this.valueInPercent = this.value / (this.options.maximum - this.options.minimum);
},
/**
* Set the value to the input element
* and trigger the change event on the input element
* @param none
* @return none
*/
setValueToInput: function() {
if (this.value !== this.lastTriggeredValue) {
this.lastTriggeredValue = this.value;
this.element.val(this.value).trigger({type: 'change', plugin: this});
}
}
};
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)){
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
};
}(jQuery, window, document));