@groupdocs.examples.jquery/signature
Version:
jQuery plugin that allows to display and sign documents supported by groupdocs libraries APIs
355 lines (301 loc) • 13.4 kB
JavaScript
/* globals define jQuery */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory)
} else {
// Browser globals
factory(jQuery)
}
}(function ($) {
$.widget('ui.rotatable', $.ui.mouse, {
widgetEventPrefix: 'rotate',
options: {
angle: false, // specify an angle in radians (for backward compatability)
degrees: false, // specify angle in degrees
handle: false, // an image to use for a handle
handleOffset: { // where the handle should appear
top: 0,
left: 0
},
radians: false, // specify angle in radians
rotate: null, // a callback for during rotation
rotationCenterOffset: { // offset the center of the element for rotation
top: 0,
left: 0
},
snap: false, // boolean flag, should the element snap to a certain rotation?
start: null, // callback when rotation starts
step: 22.5, // angle in degrees that the rotation should be snapped to
stop: null, // callback when rotation stops
transforms: null, // other transforms to performed on the element
wheelRotate: false // boolean flag, should the element rotate when the mousewheel is rotated?
},
// accessor for the angle in radians
angle: function (angle) {
if (angle === undefined) {
return this.options.angle
}
this.options.angle = angle
this.elementCurrentAngle = angle
this._performRotation(this.options.angle)
},
// calculates the element center if needed and returns it
getElementCenter: function () {
this.elementCenter = this._calculateElementCenter()
return this.elementCenter
},
// accessor for the handle
handle: function (handle) {
if (handle === undefined) {
return this.options.handle
}
this.options.handle = handle
},
plugins: {},
/* accessor for the center of rotation
* takes an object with keys of top and left
*/
rotationCenterOffset: function (offset) {
if (offset === undefined) {
return this.options.rotationCenterOffset
}
if (offset.top !== null) {
this.options.rotationCenterOffset.top = offset.top
}
if (offset.left !== null) {
this.options.rotationCenterOffset.left = offset.left
}
},
// listener for rotating the element
rotateElement: function (event) {
if (!this.element || this.element.disabled || this.options.disabled) {
return false
}
if (!event.which) {
this.stopRotate(event)
return false
}
var rotateAngle = this._calculateRotateAngle(event)
var previousRotateAngle = this.elementCurrentAngle
this.elementCurrentAngle = rotateAngle
// Plugins callbacks need to be called first.
this._propagate('rotate', event)
if (this._propagate('rotate', event) === false) {
this.elementCurrentAngle = previousRotateAngle
return false
}
var ui = this.ui()
if (this._trigger('rotate', event, ui) === false) {
this.elementCurrentAngle = previousRotateAngle
return false
} else if (ui.angle.current !== rotateAngle) {
rotateAngle = ui.angle.current
this.elementCurrentAngle = rotateAngle
}
this._performRotation(rotateAngle)
if (previousRotateAngle !== rotateAngle) {
this.hasRotated = true
}
return false
},
// listener for starting rotation
startRotate: function (event) {
var center = this.getElementCenter()
var startXFromCenter = event.pageX - center.x
var startYFromCenter = event.pageY - center.y
this.mouseStartAngle = Math.atan2(startYFromCenter, startXFromCenter)
this.elementStartAngle = this.elementCurrentAngle
this.hasRotated = false
this._propagate('start', event)
$(document).bind('mousemove', this.listeners.rotateElement)
$(document).bind('mouseup', this.listeners.stopRotate)
return false
},
// listener for stopping rotation
stopRotate: function (event) {
if (!this.element || this.element.disabled) {
return
}
$(document).unbind('mousemove', this.listeners.rotateElement)
$(document).unbind('mouseup', this.listeners.stopRotate)
this.elementStopAngle = this.elementCurrentAngle
this._propagate('stop', event)
setTimeout(function () { this.element = false }, 10)
return false
},
// listener for mousewheel rotation
wheelRotate: function (event) {
var angle = this._angleInRadians(Math.round(event.originalEvent.deltaY / 10))
if (this.options.snap || event.shiftKey) {
angle = this._calculateSnap(angle)
}
angle = this.elementCurrentAngle + angle
this.angle(angle)
this._trigger('rotate', event, this.ui())
},
// for callbacks
ui: function () {
return {
api: this,
element: this.element,
angle: {
start: this.elementStartAngle,
current: this.elementCurrentAngle,
degrees: Math.abs(this._angleInDegrees(this.elementCurrentAngle)),
stop: this.elementStopAngle
}
}
},
/* *********************** private functions ************************** */
// calculates the radians for a given angle in degrees
_angleInRadians: function (degrees) {
return degrees * Math.PI / 180
},
// calculates the degrees for a given angle in radians
_angleInDegrees: function (radians) {
return radians * 180 / Math.PI
},
// calculates the center of the element
_calculateElementCenter: function () {
var elementOffset = this._getElementOffset()
// Rotation center given via options
if (this._isRotationCenterSet()) {
return {
x: elementOffset.left + this.rotationCenterOffset().left,
y: elementOffset.top + this.rotationCenterOffset().top
}
}
// Deduce rotation center from transform-origin
if (this.element.css('transform-origin') !== undefined) {
var originPx = this.element.css('transform-origin').match(/([\d.]+)px +([\d.]+)px/)
if (originPx != null) {
return {
x: elementOffset.left + parseFloat(originPx[1]),
y: elementOffset.top + parseFloat(originPx[2])
}
}
}
// Default rotation center: middle of the element
return {
x: elementOffset.left + this.element.width() / 2,
y: elementOffset.top + this.element.height() / 2
}
},
// calculates the angle that the element should snap to and returns it in radians
_calculateSnap: function (radians) {
var degrees = this._angleInDegrees(radians)
degrees = Math.round(degrees / this.options.step) * this.options.step
return this._angleInRadians(degrees)
},
// calculates the angle to rotate the element to, based on input
_calculateRotateAngle: function (event) {
var center = this.getElementCenter()
var xFromCenter = event.pageX - center.x
var yFromCenter = event.pageY - center.y
var mouseAngle = Math.atan2(yFromCenter, xFromCenter)
var rotateAngle = mouseAngle - this.mouseStartAngle + this.elementStartAngle
if (this.options.snap || event.shiftKey) {
rotateAngle = this._calculateSnap(rotateAngle)
}
return rotateAngle
},
// constructor
_create: function () {
var handle
if (!this.options.handle) {
handle = $(document.createElement('div'))
handle.addClass('ui-rotatable-handle')
handle.append('<i class="fa fa-undo" aria-hidden="true"></i>');
if (this.options.handleOffset.top !== 0 || this.options.handleOffset.left !== 0) {
handle.css('position', 'relative')
handle.css('top', this.options.handleOffset.top + 'px')
handle.css('left', this.options.handleOffset.left + 'px')
}
} else {
handle = this.options.handle
}
this.listeners = {
rotateElement: $.proxy(this.rotateElement, this),
startRotate: $.proxy(this.startRotate, this),
stopRotate: $.proxy(this.stopRotate, this),
wheelRotate: $.proxy(this.wheelRotate, this)
}
if (this.options.wheelRotate) {
this.element.bind('wheel', this.listeners.wheelRotate)
}
handle.draggable({ helper: 'clone', start: this._dragStart, handle: handle })
handle.bind('mousedown', this.listeners.startRotate)
if (!handle.closest(this.element).length) {
handle.appendTo(this.element)
}
this.rotationCenterOffset(this.options.rotationCenterOffset)
if (this.options.degrees) {
this.elementCurrentAngle = this._angleInRadians(this.options.degrees)
}
else {
this.elementCurrentAngle = this.options.radians || this.options.angle || 0
}
this._performRotation(this.elementCurrentAngle)
},
// destructor
_destroy: function () {
this.element.removeClass('ui-rotatable')
this.element.find('.ui-rotatable-handle').remove()
if (this.options.wheelRotate) {
this.element.unbind('wheel', this.listeners.wheelRotate)
}
},
// used for the handle
_dragStart: function (event) {
if (this.element) {
return false
}
},
// retrieves the element offset
_getElementOffset: function () {
this._performRotation(0)
var offset = this.element.offset()
this._performRotation(this.elementCurrentAngle)
return offset
},
_getTransforms: function (angle) {
var transforms = 'rotate(' + angle + 'rad)'
if (this.options.transforms) {
transforms += ' ' + (function (transforms) {
var t = []
for (var i in transforms) {
if (transforms.hasOwnProperty(i) && transforms[i]) {
t.push(i + '(' + transforms[i] + ')')
}
}
return t.join(' ')
}(this.options.transforms))
}
return transforms
},
// checks to see if the element has a rotationCenterOffset set
_isRotationCenterSet: function () {
return (this.options.rotationCenterOffset.top !== 0 || this.options.rotationCenterOffset.left !== 0)
},
// performs the actual rotation on the element
_performRotation: function (angle) {
if (this._isRotationCenterSet()) {
this.element.css('transform-origin', this.options.rotationCenterOffset.left + 'px ' + this.options.rotationCenterOffset.top + 'px')
this.element.css('-ms-transform-origin', this.options.rotationCenterOffset.left + 'px ' + this.options.rotationCenterOffset.top + 'px') /* IE 9 */
this.element.css('-webkit-transform-origin', this.options.rotationCenterOffset.left + 'px ' + this.options.rotationCenterOffset + 'px') /* Chrome, Safari, Opera */
}
var transforms = this._getTransforms(angle)
this.element.css('transform', transforms)
this.element.css('-moz-transform', transforms)
this.element.css('-webkit-transform', transforms)
this.element.css('-o-transform', transforms)
},
// propagates events
_propagate: function (n, event) {
$.ui.plugin.call(this, n, [event, this.ui()]);
(n !== 'rotate' && this._trigger(n, event, this.ui()))
}
})
return $.ui.rotatable
}))