/**
* @fileoverview A class implementing a rotation model for
* a drawing view-box.
*/
goog.provide('xrx.viewbox.ViewboxRotate');
goog.require('goog.object');
goog.require('xrx.drawing.Orientation');
goog.require('xrx.viewbox.ViewboxGeometry');
/**
* A class implementing the rotation model for a drawing view-box.
* @constructor
* @extends {xrx.viewbox.ViewboxGeometry}
* @private
*/
xrx.viewbox.ViewboxRotate = function() {
goog.base(this);
};
goog.inherits(xrx.viewbox.ViewboxRotate, xrx.viewbox.ViewboxGeometry);
/**
* Returns the current rotation in degrees.
* @return {number} The current rotation in degrees.
*/
xrx.viewbox.ViewboxRotate.prototype.getRotation = function() {
return this.ctm_.getRotation();
};
/**
* Checks whether the rotation value is valid.
* @param {number} rotation The rotation in degrees.
* @return {boolean} Whether the rotation is valid.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.isValidRotation = function(rotation) {
var abs = Math.abs(rotation);
return abs === 0 || abs === 90 || abs === 180 || abs === 270;
};
/**
* Whether the view-box currently is in vertical orientation.
* @return {boolean} Whether the view-box is oriented vertically.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.isVertical = function() {
var rotation = this.ctm_.getRotation();
return rotation === 0 || rotation === 180;
};
/**
* Whether the view-box currently is in horizontal orientation.
* @return {boolean} Whether the view-box is oriented horizontally.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.isHorizontal = function() {
var rotation = this.ctm_.getRotation();
return rotation === 90 || rotation === 270;
};
/**
* Utility enumeration for view-box orientations.
* @enum {number}
* @private
*/
xrx.viewbox.ViewboxRotate.Direction_ = {
'0': 0,
'90': 1,
'180': 2,
'270': 3
};
/**
* Returns a positional utility number representing the current orientation
* of the view-box.
* @return {number} The orientation.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.direction_ = function() {
var rotation = this.ctm_.getRotation();
return xrx.viewbox.ViewboxRotate.Direction_[parseInt(rotation)];
};
/**
* Rotates the view-box by an angle, respecting a fix-point or an orientation.
* @param {?number} angle The angle of rotation in degrees, e.g. 90 or 180.
* @param {?(Array<number>|string)} opt_fixPoint A fix-point or an orientation.
* Defaults to the center of the view-box.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.rotateBy = function(angle, opt_fixPoint) {
if (opt_fixPoint === undefined) {
this.rotateBy_(angle, undefined, undefined);
} else if (this.isFixPoint_(opt_fixPoint)) {
this.rotateBy_(angle, undefined, opt_fixPoint);
} else if (this.isOrientation_(opt_fixPoint)) {
this.rotateBy_(angle, opt_fixPoint, undefined);
} else {
throw Error('Invalid fix-point. Array[2] or xrx.drawing.Orientation.* expected.');
}
this.drawing_.draw();
};
/**
* Rotates the view-box by 90° in left direction, optionally respecting
* a fix-point or an orientation.
* @param {?(Array<number>|string)} opt_fixPoint The fix-point.
*/
xrx.viewbox.ViewboxRotate.prototype.rotateLeft = function(opt_fixPoint) {
this.rotateBy(-90, opt_fixPoint);
};
/**
* Rotates the view-box by 90° in right direction, optionally respecting
* a fix-point or an orientation.
* @param {?(Array<number>|string)} opt_fixPoint The fix-point.
*/
xrx.viewbox.ViewboxRotate.prototype.rotateRight = function(opt_fixPoint) {
this.rotateBy(90, opt_fixPoint);
};
/**
* Whether the fix-point is a point, that is an Array of length 2.
* @param {?} fixPoint The fix-point.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.isFixPoint_ = function(fixPoint) {
return (fixPoint instanceof Array && fixPoint.length === 2);
};
/**
* Whether the fix-point is an orientation, that is one of
* xrx.drawing.Orientation.*.
* @param {?} fixPoint The fix-point.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.isOrientation_ = function(fixPoint) {
return (typeof fixPoint === 'string' && goog.object.containsValue(
xrx.drawing.Orientation, fixPoint));
};
/**
* Rotates the view-box by an angle, respecting a fix-point or an
* orientation.
* @param {?number} angle The angle of rotation in degrees, e.g. 90 or 180.
* @param {?string} opt_orientation An orientation, defaults to
* xrx.drawing.Orientation.C.
* @param {?Array<number>} opt_fixPoint A fix-point, defaults to the center
* of the view-box.
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.rotateBy_ = function(angle, opt_orientation,
opt_fixPoint) {
if (angle === 0) return;
if (!this.isValidRotation(angle))
throw Error('Invalid rotation. 0, 90, 180 or 270 expected.');
var fixPoint;
var reverse = angle > 0 ? false : true;
if (opt_orientation !== undefined)
fixPoint = this.getPivotPoint_(opt_orientation, reverse, true);
if (opt_fixPoint !== undefined) {
if (this.containsPoint(opt_fixPoint)) {
fixPoint = this.ctm_.transformPoint(opt_fixPoint);
} else {
fixPoint = this.getPivotPoint_(xrx.drawing.Orientation.C, reverse, true);
}
}
if (fixPoint === undefined)
fixPoint = this.getPivotPoint_(xrx.drawing.Orientation.C, reverse, true);
this.ctm_.rotate(goog.math.toRadians(angle), fixPoint[0], fixPoint[1]);
this.dispatchExternal(xrx.drawing.EventType.VIEWBOX_CHANGE, this.drawing_);
};
/**
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.getPivotPoint_ = function(orientation,
reverse, opt_transformed) {
var pivotPoints = this.getPivotPoints_(reverse);
var point_ = {
'C': function(pp, vb) {
return vb.getCenterPoint_();
},
'NE': function(pp, vb, reverse) {
var order = [0, 1, 2, 3];
console.log(vb.direction_());
return pp[order[vb.direction_()]];
},
'SE': function(pp, vb, reverse) {
var order = [3, 0, 1, 2];
return pp[order[vb.direction_()]];
},
'SW': function(pp, vb, reverse) {
var order = [2, 3, 0, 1];
return pp[order[vb.direction_()]];
},
'NW': function(pp, vb, reverse) {
var order = [1, 2, 3, 0];
return pp[order[vb.direction_()]];
}
};
var point = point_[orientation](pivotPoints, this, reverse);
if (opt_transformed === true) this.ctm_.transformPoint(point);
return point;
};
/**
* Returns the four pivot points of this view-box.
* @param {boolean} reverse If we rotate in right or left direction.
* If reverse is true we assume left direction otherwise right direction.
* @return {Array<number>}
* @private
*/
xrx.viewbox.ViewboxRotate.prototype.getPivotPoints_ = function(reverse) {
var width = this.getWidth();
var height = this.getHeight();
return !reverse ? [
[width / 2, width / 2], // north
[height / 2, height / 2], // east
[width / 2, width / 2 + height / 2], // south
[-height / 2 + width, height / 2] // west
] : [
[-height / 2 + width, height / 2], // west
[width / 2, width / 2], // north
[height / 2, height / 2], // east
[width / 2, width / 2 + height / 2] // south
];
};
/**
* Disposes this view-box.
*/
xrx.viewbox.ViewboxRotate.prototype.disposeInternal = function() {
goog.base(this, 'disposeInternal');
};