Give view proper Matrix transformation functions, just like on Item.

Relates to #832
This commit is contained in:
Jürg Lehni 2016-01-16 15:10:19 +01:00
parent b3e81af9b6
commit 3a3d46692b
6 changed files with 158 additions and 59 deletions

View file

@ -220,8 +220,6 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform
*/
scale: function(/* scale, center */) {
// Do not modify scale, center, since that would arguments of which
// we're reading from!
var scale = Point.read(arguments),
center = Point.read(arguments, 0, { readNull: true });
if (center)
@ -761,10 +759,10 @@ var Matrix = Base.extend(/** @lends Matrix# */{
this._tx, this._ty);
}
}
}, Base.each(['a', 'c', 'b', 'd', 'tx', 'ty'], function(name) {
}, Base.each(['a', 'c', 'b', 'd', 'tx', 'ty'], function(key) {
// Create getters and setters for all internal attributes.
var part = Base.capitalize(name),
prop = '_' + name;
var part = Base.capitalize(key),
prop = '_' + key;
this['get' + part] = function() {
return this[prop];
};

View file

@ -947,10 +947,10 @@ var Point = Base.extend(/** @lends Point# */{
* /*#=*/Numerical.TRIGONOMETRIC_EPSILON;
}
}
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) {
// Inject round, ceil, floor, abs:
var op = Math[name];
this[name] = function() {
var op = Math[key];
this[key] = function() {
return new Point(op(this.x), op(this.y));
};
}, {}));

View file

@ -524,10 +524,10 @@ var Size = Base.extend(/** @lends Size# */{
return new Size(Math.random(), Math.random());
}
}
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) {
// Inject round, ceil, floor, abs:
var op = Math[name];
this[name] = function() {
var op = Math[key];
this[key] = function() {
return new Size(op(this.width), op(this.height));
};
}, {}));

View file

@ -35,7 +35,9 @@ var ChangeFlag = {
// Raster pixels
PIXELS: 0x200,
// Clipping in one of the child items
CLIPPING: 0x400
CLIPPING: 0x400,
// The view has been transformed
VIEW: 0x800
};
// Shortcuts to often used ChangeFlag values including APPEARANCE
@ -51,5 +53,6 @@ var Change = {
STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE,
ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE,
CONTENT: ChangeFlag.CONTENT | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE
PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE,
VIEW: ChangeFlag.VIEW | ChangeFlag.APPEARANCE
};

View file

@ -2936,11 +2936,19 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* @property
* @type Color
*/
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
var rotate = key === 'rotate';
this[key] = function(/* value, center */) {
var value = (rotate ? Base : Point).read(arguments),
center = Point.read(arguments, 0, { readNull: true });
return this.transform(new Matrix()[key](value,
center || this.getPosition(true)));
};
}, /** @lends Item# */{
/**
* {@grouptitle Transform Functions}
*
* Translates (moves) the item by the given offset point.
* Translates (moves) the item by the given offset views.
*
* @param {Point} delta the offset to translate the item by
*/
@ -2950,13 +2958,15 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
},
/**
* Rotates the item by a given angle around the given point.
* Rotates the item by a given angle around the given center point.
*
* Angles are oriented clockwise and measured in degrees.
*
* @name Item#rotate
* @function
* @param {Number} angle the rotation angle
* @param {Point} [center={@link Item#position}]
* @see Matrix#rotate
* @see Matrix#rotate(angle[, center])
*
* @example {@paperscript}
* // Rotating an item:
@ -2993,20 +3003,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* path.rotate(3, view.center);
* }
*/
rotate: function(angle /*, center */) {
return this.transform(new Matrix().rotate(angle,
Point.read(arguments, 1, { readNull: true })
|| this.getPosition(true)));
}
}, Base.each(['scale', 'shear', 'skew'], function(name) {
this[name] = function() {
// See Matrix#scale for explanation of this:
var point = Point.read(arguments),
center = Point.read(arguments, 0, { readNull: true });
return this.transform(new Matrix()[name](point,
center || this.getPosition(true)));
};
}, /** @lends Item# */{
/**
* Scales the item by the given value from its center point, or optionally
* from a supplied point.
@ -3078,7 +3075,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* @function
* @param {Point} shear the horziontal and vertical shear factors as a point
* @param {Point} [center={@link Item#position}]
* @see Matrix#shear
* @see Matrix#shear(shear[, center])
*/
/**
* Shears the item by the given values from its center point, or optionally
@ -3089,7 +3086,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* @param {Number} hor the horizontal shear factor
* @param {Number} ver the vertical shear factor
* @param {Point} [center={@link Item#position}]
* @see Matrix#shear
* @see Matrix#shear(hor, ver[, center])
*/
/**
@ -3100,7 +3097,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* @function
* @param {Point} skew the horziontal and vertical skew angles in degrees
* @param {Point} [center={@link Item#position}]
* @see Matrix#shear
* @see Matrix#shear(skew[, center])
*/
/**
* Skews the item by the given angles from its center point, or optionally
@ -3111,9 +3108,9 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
* @param {Number} hor the horizontal skew angle in degrees
* @param {Number} ver the vertical sskew angle in degrees
* @param {Point} [center={@link Item#position}]
* @see Matrix#shear
* @see Matrix#shear(hor, ver[, center])
*/
}), /** @lends Item# */{
/**
* Transform the item.
*
@ -3331,7 +3328,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
*/
fitBounds: function(rectangle, fill) {
// TODO: Think about passing options with various ways of defining
// fitting.
// fitting. Compare with InDesign fitting to see possible options.
rectangle = Rectangle.read(arguments);
var bounds = this.getBounds(),
itemRatio = bounds.height / bounds.width,
@ -3343,8 +3340,8 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
new Size(bounds.width * scale, bounds.height * scale));
newBounds.setCenter(rectangle.getCenter());
this.setBounds(newBounds);
},
}
}), /** @lends Item# */{
/**
* {@grouptitle Event Handlers}
*
@ -4070,10 +4067,10 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
_canComposite: function() {
return false;
}
}, Base.each(['down', 'drag', 'up', 'move'], function(name) {
this['removeOn' + Base.capitalize(name)] = function() {
}, Base.each(['down', 'drag', 'up', 'move'], function(key) {
this['removeOn' + Base.capitalize(key)] = function() {
var hash = {};
hash[name] = true;
hash[key] = true;
return this.removeOn(hash);
};
}, /** @lends Item# */{

View file

@ -261,18 +261,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
/**
* Private notifier that is called whenever a change occurs in this view.
* Used only by Matrix for now.
*
* @param {ChangeFlag} flags describes what exactly has changed
*/
_changed: function(flags) {
this._project._changed(flags);
},
_transform: function(matrix) {
this._matrix.concatenate(matrix);
_changed: function() {
// The only one calling View._changed() is Matrix, so it can only mean
// one thing:
this._project._changed(/*#=*/Change.VIEW);
// Force recalculation of these values next time they are requested.
this._bounds = null;
this._update();
},
/**
@ -329,13 +324,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
return;
this._viewSize.set(size.width, size.height);
this._setViewSize(size);
this._bounds = null; // Force recalculation
// Call onResize handler on any size change
this.emit('resize', {
size: size,
delta: delta
});
this._update();
this._changed();
this.update();
},
/**
@ -382,7 +377,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
setCenter: function(/* center */) {
var center = Point.read(arguments);
this.scrollBy(center.subtract(this.getCenter()));
this.translate(this.getCenter().subtract(center));
},
/**
@ -396,8 +391,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
},
setZoom: function(zoom) {
// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
this._transform(new Matrix().scale(zoom / this._zoom,
this.transform(new Matrix().scale(zoom / this._zoom,
this.getCenter()));
this._zoom = zoom;
},
@ -438,17 +432,124 @@ var View = Base.extend(Emitter, /** @lends View# */{
*/
isInserted: function() {
return DomElement.isInserted(this._element);
}
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
var rotate = key === 'rotate';
this[key] = function(/* value, center */) {
var value = (rotate ? Base : Point).read(arguments),
center = Point.read(arguments, 0, { readNull: true });
return this.transform(new Matrix()[key](value,
center || this.getCenter(true)));
};
}, /** @lends View# */{
/**
* {@grouptitle Transform Functions}
*
* Translates (scrolls) the view by the given offset vector.
*
* @param {Point} delta the offset to translate the view by
*/
translate: function(/* delta */) {
var mx = new Matrix();
return this.transform(mx.translate.apply(mx, arguments));
},
/**
* Rotates the view by a given angle around the given center point.
*
* Angles are oriented clockwise and measured in degrees.
*
* @name View#rotate
* @function
* @param {Number} angle the rotation angle
* @param {Point} [center={@link View#getCenter()}]
* @see Matrix#rotate(angle[, center])
*/
/**
* Scales the view by the given value from its center point, or optionally
* from a supplied point.
*
* @name View#scale
* @function
* @param {Number} scale the scale factor
* @param {Point} [center={@link View#getCenter()}]
*/
/**
* Scales the view by the given values from its center point, or optionally
* from a supplied point.
*
* @name View#scale
* @function
* @param {Number} hor the horizontal scale factor
* @param {Number} ver the vertical scale factor
* @param {Point} [center={@link View#getCenter()}]
*/
/**
* Shears the view by the given value from its center point, or optionally
* by a supplied point.
*
* @name View#shear
* @function
* @param {Point} shear the horziontal and vertical shear factors as a point
* @param {Point} [center={@link View#getCenter()}]
* @see Matrix#shear(shear[, center])
*/
/**
* Shears the view by the given values from its center point, or optionally
* by a supplied point.
*
* @name View#shear
* @function
* @param {Number} hor the horizontal shear factor
* @param {Number} ver the vertical shear factor
* @param {Point} [center={@link View#getCenter()}]
* @see Matrix#shear(hor, ver[, center])
*/
/**
* Skews the view by the given angles from its center point, or optionally
* by a supplied point.
*
* @name View#skew
* @function
* @param {Point} skew the horziontal and vertical skew angles in degrees
* @param {Point} [center={@link View#getCenter()}]
* @see Matrix#shear(skew[, center])
*/
/**
* Skews the view by the given angles from its center point, or optionally
* by a supplied point.
*
* @name View#skew
* @function
* @param {Number} hor the horizontal skew angle in degrees
* @param {Number} ver the vertical sskew angle in degrees
* @param {Point} [center={@link View#getCenter()}]
* @see Matrix#shear(hor, ver[, center])
*/
/**
* Transform the view.
*
* @param {Matrix} matrix the matrix by which the view shall be transformed
*/
transform: function(matrix) {
this._matrix.concatenate(matrix);
},
/**
* Scrolls the view by the given vector.
*
* @param {Point} point
* @deprecated use {@link #translate(delta)} instead (using opposite
* direction).
*/
scrollBy: function(/* point */) {
this._transform(new Matrix().translate(Point.read(arguments).negate()));
},
this.translate(Point.read(arguments).negate());
}
}), /** @lends View# */{
/**
* Makes all animation play by adding the view to the request animation
* loop.