mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-04 03:45:58 -05:00
Give view proper Matrix transformation functions, just like on Item.
Relates to #832
This commit is contained in:
parent
b3e81af9b6
commit
3a3d46692b
6 changed files with 158 additions and 59 deletions
|
@ -220,8 +220,6 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
* @return {Matrix} this affine transform
|
* @return {Matrix} this affine transform
|
||||||
*/
|
*/
|
||||||
scale: function(/* scale, center */) {
|
scale: function(/* scale, center */) {
|
||||||
// Do not modify scale, center, since that would arguments of which
|
|
||||||
// we're reading from!
|
|
||||||
var scale = Point.read(arguments),
|
var scale = Point.read(arguments),
|
||||||
center = Point.read(arguments, 0, { readNull: true });
|
center = Point.read(arguments, 0, { readNull: true });
|
||||||
if (center)
|
if (center)
|
||||||
|
@ -761,10 +759,10 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
this._tx, this._ty);
|
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.
|
// Create getters and setters for all internal attributes.
|
||||||
var part = Base.capitalize(name),
|
var part = Base.capitalize(key),
|
||||||
prop = '_' + name;
|
prop = '_' + key;
|
||||||
this['get' + part] = function() {
|
this['get' + part] = function() {
|
||||||
return this[prop];
|
return this[prop];
|
||||||
};
|
};
|
||||||
|
|
|
@ -947,10 +947,10 @@ var Point = Base.extend(/** @lends Point# */{
|
||||||
* /*#=*/Numerical.TRIGONOMETRIC_EPSILON;
|
* /*#=*/Numerical.TRIGONOMETRIC_EPSILON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
|
}, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) {
|
||||||
// Inject round, ceil, floor, abs:
|
// Inject round, ceil, floor, abs:
|
||||||
var op = Math[name];
|
var op = Math[key];
|
||||||
this[name] = function() {
|
this[key] = function() {
|
||||||
return new Point(op(this.x), op(this.y));
|
return new Point(op(this.x), op(this.y));
|
||||||
};
|
};
|
||||||
}, {}));
|
}, {}));
|
||||||
|
|
|
@ -524,10 +524,10 @@ var Size = Base.extend(/** @lends Size# */{
|
||||||
return new Size(Math.random(), Math.random());
|
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:
|
// Inject round, ceil, floor, abs:
|
||||||
var op = Math[name];
|
var op = Math[key];
|
||||||
this[name] = function() {
|
this[key] = function() {
|
||||||
return new Size(op(this.width), op(this.height));
|
return new Size(op(this.width), op(this.height));
|
||||||
};
|
};
|
||||||
}, {}));
|
}, {}));
|
||||||
|
|
|
@ -35,7 +35,9 @@ var ChangeFlag = {
|
||||||
// Raster pixels
|
// Raster pixels
|
||||||
PIXELS: 0x200,
|
PIXELS: 0x200,
|
||||||
// Clipping in one of the child items
|
// 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
|
// Shortcuts to often used ChangeFlag values including APPEARANCE
|
||||||
|
@ -51,5 +53,6 @@ var Change = {
|
||||||
STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE,
|
STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE,
|
||||||
ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE,
|
ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE,
|
||||||
CONTENT: ChangeFlag.CONTENT | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
|
CONTENT: ChangeFlag.CONTENT | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
|
||||||
PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE
|
PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE,
|
||||||
|
VIEW: ChangeFlag.VIEW | ChangeFlag.APPEARANCE
|
||||||
};
|
};
|
||||||
|
|
|
@ -2936,11 +2936,19 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
* @property
|
* @property
|
||||||
* @type Color
|
* @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}
|
* {@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
|
* @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.
|
* Angles are oriented clockwise and measured in degrees.
|
||||||
*
|
*
|
||||||
|
* @name Item#rotate
|
||||||
|
* @function
|
||||||
* @param {Number} angle the rotation angle
|
* @param {Number} angle the rotation angle
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
* @see Matrix#rotate
|
* @see Matrix#rotate(angle[, center])
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Rotating an item:
|
* // Rotating an item:
|
||||||
|
@ -2993,20 +3003,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
* path.rotate(3, view.center);
|
* 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
|
* Scales the item by the given value from its center point, or optionally
|
||||||
* from a supplied point.
|
* from a supplied point.
|
||||||
|
@ -3078,7 +3075,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
* @function
|
* @function
|
||||||
* @param {Point} shear the horziontal and vertical shear factors as a point
|
* @param {Point} shear the horziontal and vertical shear factors as a point
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @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
|
* 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} hor the horizontal shear factor
|
||||||
* @param {Number} ver the vertical shear factor
|
* @param {Number} ver the vertical shear factor
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @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
|
* @function
|
||||||
* @param {Point} skew the horziontal and vertical skew angles in degrees
|
* @param {Point} skew the horziontal and vertical skew angles in degrees
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @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
|
* 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} hor the horizontal skew angle in degrees
|
||||||
* @param {Number} ver the vertical sskew angle in degrees
|
* @param {Number} ver the vertical sskew angle in degrees
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
* @see Matrix#shear
|
* @see Matrix#shear(hor, ver[, center])
|
||||||
*/
|
*/
|
||||||
}), /** @lends Item# */{
|
|
||||||
/**
|
/**
|
||||||
* Transform the item.
|
* Transform the item.
|
||||||
*
|
*
|
||||||
|
@ -3331,7 +3328,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
*/
|
*/
|
||||||
fitBounds: function(rectangle, fill) {
|
fitBounds: function(rectangle, fill) {
|
||||||
// TODO: Think about passing options with various ways of defining
|
// TODO: Think about passing options with various ways of defining
|
||||||
// fitting.
|
// fitting. Compare with InDesign fitting to see possible options.
|
||||||
rectangle = Rectangle.read(arguments);
|
rectangle = Rectangle.read(arguments);
|
||||||
var bounds = this.getBounds(),
|
var bounds = this.getBounds(),
|
||||||
itemRatio = bounds.height / bounds.width,
|
itemRatio = bounds.height / bounds.width,
|
||||||
|
@ -3343,8 +3340,8 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
new Size(bounds.width * scale, bounds.height * scale));
|
new Size(bounds.width * scale, bounds.height * scale));
|
||||||
newBounds.setCenter(rectangle.getCenter());
|
newBounds.setCenter(rectangle.getCenter());
|
||||||
this.setBounds(newBounds);
|
this.setBounds(newBounds);
|
||||||
},
|
}
|
||||||
|
}), /** @lends Item# */{
|
||||||
/**
|
/**
|
||||||
* {@grouptitle Event Handlers}
|
* {@grouptitle Event Handlers}
|
||||||
*
|
*
|
||||||
|
@ -4070,10 +4067,10 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
_canComposite: function() {
|
_canComposite: function() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, Base.each(['down', 'drag', 'up', 'move'], function(name) {
|
}, Base.each(['down', 'drag', 'up', 'move'], function(key) {
|
||||||
this['removeOn' + Base.capitalize(name)] = function() {
|
this['removeOn' + Base.capitalize(key)] = function() {
|
||||||
var hash = {};
|
var hash = {};
|
||||||
hash[name] = true;
|
hash[key] = true;
|
||||||
return this.removeOn(hash);
|
return this.removeOn(hash);
|
||||||
};
|
};
|
||||||
}, /** @lends Item# */{
|
}, /** @lends Item# */{
|
||||||
|
|
135
src/view/View.js
135
src/view/View.js
|
@ -261,18 +261,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
/**
|
/**
|
||||||
* Private notifier that is called whenever a change occurs in this view.
|
* Private notifier that is called whenever a change occurs in this view.
|
||||||
* Used only by Matrix for now.
|
* Used only by Matrix for now.
|
||||||
*
|
|
||||||
* @param {ChangeFlag} flags describes what exactly has changed
|
|
||||||
*/
|
*/
|
||||||
_changed: function(flags) {
|
_changed: function() {
|
||||||
this._project._changed(flags);
|
// The only one calling View._changed() is Matrix, so it can only mean
|
||||||
},
|
// one thing:
|
||||||
|
this._project._changed(/*#=*/Change.VIEW);
|
||||||
_transform: function(matrix) {
|
|
||||||
this._matrix.concatenate(matrix);
|
|
||||||
// Force recalculation of these values next time they are requested.
|
// Force recalculation of these values next time they are requested.
|
||||||
this._bounds = null;
|
this._bounds = null;
|
||||||
this._update();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,13 +324,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
return;
|
return;
|
||||||
this._viewSize.set(size.width, size.height);
|
this._viewSize.set(size.width, size.height);
|
||||||
this._setViewSize(size);
|
this._setViewSize(size);
|
||||||
this._bounds = null; // Force recalculation
|
|
||||||
// Call onResize handler on any size change
|
// Call onResize handler on any size change
|
||||||
this.emit('resize', {
|
this.emit('resize', {
|
||||||
size: size,
|
size: size,
|
||||||
delta: delta
|
delta: delta
|
||||||
});
|
});
|
||||||
this._update();
|
this._changed();
|
||||||
|
this.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -382,7 +377,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
|
|
||||||
setCenter: function(/* center */) {
|
setCenter: function(/* center */) {
|
||||||
var center = Point.read(arguments);
|
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) {
|
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.getCenter()));
|
||||||
this._zoom = zoom;
|
this._zoom = zoom;
|
||||||
},
|
},
|
||||||
|
@ -438,17 +432,124 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
*/
|
*/
|
||||||
isInserted: function() {
|
isInserted: function() {
|
||||||
return DomElement.isInserted(this._element);
|
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.
|
* Scrolls the view by the given vector.
|
||||||
*
|
*
|
||||||
* @param {Point} point
|
* @param {Point} point
|
||||||
|
* @deprecated use {@link #translate(delta)} instead (using opposite
|
||||||
|
* direction).
|
||||||
*/
|
*/
|
||||||
scrollBy: function(/* point */) {
|
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
|
* Makes all animation play by adding the view to the request animation
|
||||||
* loop.
|
* loop.
|
||||||
|
|
Loading…
Reference in a new issue