mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Implement Matrix, Item#position, Item#bounds (setter too), Item#transform(), Item#scale(), Item#rotate(), Item#transalte() and Item#shear(). Some of it work in progress.
This commit is contained in:
parent
6ef5183731
commit
ee8c30b518
3 changed files with 651 additions and 2 deletions
493
src/basic/Matrix.js
Normal file
493
src/basic/Matrix.js
Normal file
|
@ -0,0 +1,493 @@
|
||||||
|
// Based on goog.graphics.AffineTransform, as part of the Closure Library.
|
||||||
|
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
var Matrix = Base.extend({
|
||||||
|
/**
|
||||||
|
* Creates a 2D affine transform. An affine transform performs a linear
|
||||||
|
* mapping from 2D coordinates to other 2D coordinates that preserves the
|
||||||
|
* "straightness" and "parallelness" of lines.
|
||||||
|
*
|
||||||
|
* Such a coordinate transformation can be represented by a 3 row by 3
|
||||||
|
* column matrix with an implied last row of [ 0 0 1 ]. This matrix
|
||||||
|
* transforms source coordinates (x,y) into destination coordinates (x',y')
|
||||||
|
* by considering them to be a column vector and multiplying the coordinate
|
||||||
|
* vector by the matrix according to the following process:
|
||||||
|
* <pre>
|
||||||
|
* [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
|
||||||
|
* [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
|
||||||
|
* [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* This class is optimized for speed and minimizes calculations based on its
|
||||||
|
* knowledge of the underlying matrix (as opposed to say simply performing
|
||||||
|
* matrix multiplication).
|
||||||
|
*
|
||||||
|
* @param {number} m00 The m00 coordinate of the transform.
|
||||||
|
* @param {number} m10 The m10 coordinate of the transform.
|
||||||
|
* @param {number} m01 The m01 coordinate of the transform.
|
||||||
|
* @param {number} m11 The m11 coordinate of the transform.
|
||||||
|
* @param {number} m02 The m02 coordinate of the transform.
|
||||||
|
* @param {number} m12 The m12 coordinate of the transform.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
initialize: function(m00, m10, m01, m11, m02, m12) {
|
||||||
|
if (arguments.length == 6) {
|
||||||
|
this.set(m00, m10, m01, m11, m02, m12);
|
||||||
|
} else if (arguments == 1) {
|
||||||
|
var mx = arguments[0];
|
||||||
|
// TODO: Check for array!
|
||||||
|
this.set(mx._m00, mx._m10, mx._m01, mx._m11, mx._m02, mx._m12);
|
||||||
|
} else if (arguments.length) {
|
||||||
|
throw Error('Insufficient matrix parameters');
|
||||||
|
} else {
|
||||||
|
this._m00 = this._m11 = 1;
|
||||||
|
this._m10 = this._m01 = this._m02 = this._m12 = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Matrix} A copy of this transform.
|
||||||
|
*/
|
||||||
|
clone: function() {
|
||||||
|
return new Matrix(this._m00, this._m10, this._m01,
|
||||||
|
this._m11, this._m02, this._m12);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this transform to the matrix specified by the 6 values.
|
||||||
|
*
|
||||||
|
* @param {number} m00 The m00 coordinate of the transform.
|
||||||
|
* @param {number} m10 The m10 coordinate of the transform.
|
||||||
|
* @param {number} m01 The m01 coordinate of the transform.
|
||||||
|
* @param {number} m11 The m11 coordinate of the transform.
|
||||||
|
* @param {number} m02 The m02 coordinate of the transform.
|
||||||
|
* @param {number} m12 The m12 coordinate of the transform.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
set: function(m00, m10, m01, m11, m02, m12) {
|
||||||
|
this._m00 = m00;
|
||||||
|
this._m10 = m10;
|
||||||
|
this._m01 = m01;
|
||||||
|
this._m11 = m11;
|
||||||
|
this._m02 = m02;
|
||||||
|
this._m12 = m12;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatentates this transform with a scaling transformation.
|
||||||
|
*
|
||||||
|
* @param {number} sx The x-axis scaling factor.
|
||||||
|
* @param {number} sy The y-axis scaling factor.
|
||||||
|
* @param {Point} center The optional center for the scaling transformation.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
scale: function(sx, sy /* | scale */, center) {
|
||||||
|
// TODO: Make single scale parameter work with center points!
|
||||||
|
// Check arguments.length and typeof arguments[1], if object, assume
|
||||||
|
// scale
|
||||||
|
center = Point.read(arguments, 2);
|
||||||
|
// TODO: Optimise calls to translate to not rely on point conversion
|
||||||
|
// use private translate function instead.
|
||||||
|
if (center)
|
||||||
|
this.translate(center.x, center.y);
|
||||||
|
this._m00 *= sx;
|
||||||
|
this._m10 *= sx;
|
||||||
|
this._m01 *= sy;
|
||||||
|
this._m11 *= sy;
|
||||||
|
if (center)
|
||||||
|
this.translate(-center.x, -center.y);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatentates this transform with a translate transformation.
|
||||||
|
*
|
||||||
|
* @param {number} dx The distance to translate in the x direction.
|
||||||
|
* @param {number} dy The distance to translate in the y direction.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
translate: function(point) {
|
||||||
|
point = Point.read(arguments);
|
||||||
|
if (point) {
|
||||||
|
var x = point.x, y = point.y;
|
||||||
|
this._m02 += x * this._m00 + y * this._m01;
|
||||||
|
this._m12 += x * this._m10 + y * this._m11;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatentates this transform with a rotation transformation around an
|
||||||
|
* anchor point.
|
||||||
|
*
|
||||||
|
* @param {number} angle The angle of rotation measured in degrees.
|
||||||
|
* @param {number} x The x coordinate of the anchor point.
|
||||||
|
* @param {number} y The y coordinate of the anchor point.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
rotate: function(angle, center) {
|
||||||
|
return this.concatenate(
|
||||||
|
Matrix.getRotateInstance.apply(Matrix, arguments));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatentates this transform with a shear transformation.
|
||||||
|
*
|
||||||
|
* @param {number} shx The x shear factor.
|
||||||
|
* @param {number} shy The y shear factor.
|
||||||
|
* @param {Point} center The optional center for the shear transformation.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
shear: function(shx, shy, center) {
|
||||||
|
center = Point.read(arguments, 2);
|
||||||
|
// TODO: Optimise calls to translate to not rely on point conversion
|
||||||
|
// use private translate function instead.
|
||||||
|
if (center)
|
||||||
|
this.translate(center.x, center.y);
|
||||||
|
var m00 = this._m00;
|
||||||
|
var m10 = this._m10;
|
||||||
|
this._m00 += shy * this._m01;
|
||||||
|
this._m10 += shy * this._m11;
|
||||||
|
this._m01 += shx * m00;
|
||||||
|
this._m11 += shx * m10;
|
||||||
|
if (center)
|
||||||
|
this.translate(-center.x, -center.y);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string} A string representation of this transform. The format of
|
||||||
|
* of the string is compatible with SVG matrix notation, i.e.
|
||||||
|
* "matrix(a,b,c,d,e,f)".
|
||||||
|
*/
|
||||||
|
toString: function() {
|
||||||
|
// TODO: Make behave the same as in Scriptographer
|
||||||
|
return 'matrix(' + [this._m00, this._m10, this._m01, this._m11,
|
||||||
|
this._m02, this._m12].join(',') + ')';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The scaling factor in the x-direction (m00).
|
||||||
|
*/
|
||||||
|
getScaleX: function() {
|
||||||
|
return this._m00;
|
||||||
|
},
|
||||||
|
|
||||||
|
setScaleX: function(scaleX) {
|
||||||
|
this._m00 = scaleX;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The scaling factor in the y-direction (m11).
|
||||||
|
*/
|
||||||
|
getScaleY: function() {
|
||||||
|
return this._m11;
|
||||||
|
},
|
||||||
|
|
||||||
|
setScaleY: function(scaleY) {
|
||||||
|
this._m11 = scaleY;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The translation in the x-direction (m02).
|
||||||
|
*/
|
||||||
|
getTranslateX: function() {
|
||||||
|
return this._m02;
|
||||||
|
},
|
||||||
|
|
||||||
|
setTranslateX: function(translateX) {
|
||||||
|
this._m02 = translateX;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The translation in the y-direction (m12).
|
||||||
|
*/
|
||||||
|
getTranslateY: function() {
|
||||||
|
return this._m12;
|
||||||
|
},
|
||||||
|
|
||||||
|
setTranslateY: function(translateY) {
|
||||||
|
this._m12 = translateY;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The shear factor in the x-direction (m01).
|
||||||
|
*/
|
||||||
|
getShearX: function() {
|
||||||
|
return this._m01;
|
||||||
|
},
|
||||||
|
|
||||||
|
setShearX: function(shearX) {
|
||||||
|
this._m01 = shearX;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The shear factor in the y-direction (m10).
|
||||||
|
*/
|
||||||
|
getShearY: function() {
|
||||||
|
return this._m10;
|
||||||
|
},
|
||||||
|
|
||||||
|
setShearY: function(shearY) {
|
||||||
|
this._m10 = shearY;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates an affine transform to this transform.
|
||||||
|
*
|
||||||
|
* @param {Matrix} mx The transform to concatenate.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
concatenate: function(mx) {
|
||||||
|
var m0 = this._m00;
|
||||||
|
var m1 = this._m01;
|
||||||
|
this._m00 = mx._m00 * m0 + mx._m10 * m1;
|
||||||
|
this._m01 = mx._m01 * m0 + mx._m11 * m1;
|
||||||
|
this._m02 += mx._m02 * m0 + mx._m12 * m1;
|
||||||
|
|
||||||
|
m0 = this._m10;
|
||||||
|
m1 = this._m11;
|
||||||
|
this._m10 = mx._m00 * m0 + mx._m10 * m1;
|
||||||
|
this._m11 = mx._m01 * m0 + mx._m11 * m1;
|
||||||
|
this._m12 += mx._m02 * m0 + mx._m12 * m1;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-concatenates an affine transform to this transform.
|
||||||
|
*
|
||||||
|
* @param {Matrix} mx The transform to preconcatenate.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
preConcatenate: function(mx) {
|
||||||
|
var m0 = this._m00;
|
||||||
|
var m1 = this._m10;
|
||||||
|
this._m00 = mx._m00 * m0 + mx._m01 * m1;
|
||||||
|
this._m10 = mx._m10 * m0 + mx._m11 * m1;
|
||||||
|
|
||||||
|
m0 = this._m01;
|
||||||
|
m1 = this._m11;
|
||||||
|
this._m01 = mx._m00 * m0 + mx._m01 * m1;
|
||||||
|
this._m11 = mx._m10 * m0 + mx._m11 * m1;
|
||||||
|
|
||||||
|
m0 = this._m02;
|
||||||
|
m1 = this._m12;
|
||||||
|
this._m02 = mx._m00 * m0 + mx._m01 * m1 + mx._m02;
|
||||||
|
this._m12 = mx._m10 * m0 + mx._m11 * m1 + mx._m12;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a point or an array of coordinates by this matrix and returns
|
||||||
|
* the result. If an array is transformed, the the result is stored into a
|
||||||
|
* destination array.
|
||||||
|
*
|
||||||
|
* @param {Point} point The point to be transformed.
|
||||||
|
*
|
||||||
|
* @param {Array} src The array containing the source points
|
||||||
|
* as x, y value pairs.
|
||||||
|
* @param {number} srcOff The offset to the first point to be transformed.
|
||||||
|
* @param {Array} dst The array into which to store the transformed
|
||||||
|
* point pairs.
|
||||||
|
* @param {number} dstOff The offset of the location of the first transformed
|
||||||
|
* point in the destination array.
|
||||||
|
* @param {number} numPts The number of points to tranform.
|
||||||
|
*/
|
||||||
|
transform: function(/* point | */ src, srcOff, dst, dstOff, numPts) {
|
||||||
|
if (arguments.length == 5) {
|
||||||
|
var i = srcOff;
|
||||||
|
var j = dstOff;
|
||||||
|
var srcEnd = srcOff + 2 * numPts;
|
||||||
|
while (i < srcEnd) {
|
||||||
|
var x = src[i++];
|
||||||
|
var y = src[i++];
|
||||||
|
dst[j++] = x * this._m00 + y * this._m01 + this._m02;
|
||||||
|
dst[j++] = x * this._m10 + y * this._m11 + this._m12;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
} else if (arguments.length > 0) {
|
||||||
|
var point = Point.read(arguments);
|
||||||
|
if (point) {
|
||||||
|
var x = point.x, y = point.y;
|
||||||
|
return new Point(
|
||||||
|
x * this._m00 + y * this._m01 + this._m02,
|
||||||
|
x * this._m10 + y * this._m11 + this._m12
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} The determinant of this transform.
|
||||||
|
*/
|
||||||
|
getDeterminant: function() {
|
||||||
|
return this._m00 * this._m11 - this._m01 * this._m10;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} Whether this transform is the identity transform.
|
||||||
|
*/
|
||||||
|
isIdentity: function() {
|
||||||
|
return this._m00 == 1 && this._m10 == 0 && this._m01 == 0 &&
|
||||||
|
this._m11 == 1 && this._m02 == 0 && this._m12 == 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the transform is invertible. A transform is not invertible
|
||||||
|
* if the determinant is 0 or any value is non-finite or NaN.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether the transform is invertible.
|
||||||
|
*/
|
||||||
|
isInvertible: function() {
|
||||||
|
var det = this.getDeterminant();
|
||||||
|
return isFinite(det) && det != 0 && isFinite(this._m02)
|
||||||
|
&& isFinite(this._m12);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the matrix is singular or not. Singular matrices cannot be
|
||||||
|
* inverted.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether the matrix is singular.
|
||||||
|
*/
|
||||||
|
isSingular: function() {
|
||||||
|
return !this.isInvertible();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Matrix} An Matrix object representing the inverse transformation.
|
||||||
|
*/
|
||||||
|
createInverse: function() {
|
||||||
|
var det = this.getDeterminant();
|
||||||
|
if (isFinite(det) && det != 0 && isFinite(this._m02)
|
||||||
|
&& isFinite(this._m12)) {
|
||||||
|
return new Matrix(
|
||||||
|
this._m11 / det,
|
||||||
|
-this._m10 / det,
|
||||||
|
-this._m01 / det,
|
||||||
|
this._m00 / det,
|
||||||
|
(this._m01 * this._m12 - this._m11 * this._m02) / det,
|
||||||
|
(this._m10 * this._m02 - this._m00 * this._m12) / det);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this transform to a scaling transformation.
|
||||||
|
*
|
||||||
|
* @param {number} sx The x-axis scaling factor.
|
||||||
|
* @param {number} sy The y-axis scaling factor.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
setToScale: function(sx, sy) {
|
||||||
|
return this.set(sx, 0, 0, sy, 0, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this transform to a translation transformation.
|
||||||
|
*
|
||||||
|
* @param {number} dx The distance to translate in the x direction.
|
||||||
|
* @param {number} dy The distance to translate in the y direction.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
setToTranslation: function(delta) {
|
||||||
|
delta = Point.read(arguments);
|
||||||
|
if (delta) {
|
||||||
|
return this.set(1, 0, 0, 1, delta.x, delta.y);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this transform to a shearing transformation.
|
||||||
|
*
|
||||||
|
* @param {number} shx The x-axis shear factor.
|
||||||
|
* @param {number} shy The y-axis shear factor.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
setToShear: function(shx, shy) {
|
||||||
|
return this.set(1, shy, shx, 1, 0, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this transform to a rotation transformation.
|
||||||
|
*
|
||||||
|
* @param {number} angle The angle of rotation measured in degrees.
|
||||||
|
* @param {number} x The x coordinate of the anchor point.
|
||||||
|
* @param {number} y The y coordinate of the anchor point.
|
||||||
|
* @return {Matrix} This affine transform.
|
||||||
|
*/
|
||||||
|
setToRotation: function(angle, center) {
|
||||||
|
center = Point.read(arguments, 1);
|
||||||
|
if (center) {
|
||||||
|
angle = angle * Math.PI / 180.0;
|
||||||
|
var x = center.x, y = center.y;
|
||||||
|
var cos = Math.cos(angle);
|
||||||
|
var sin = Math.sin(angle);
|
||||||
|
return this.set(cos, sin, -sin, cos,
|
||||||
|
x - x * cos + y * sin,
|
||||||
|
y - x * sin - y * cos);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
statics: {
|
||||||
|
/**
|
||||||
|
* Creates a transform representing a scaling transformation.
|
||||||
|
*
|
||||||
|
* @param {number} sx The x-axis scaling factor.
|
||||||
|
* @param {number} sy The y-axis scaling factor.
|
||||||
|
* @return {Matrix} A transform representing a scaling
|
||||||
|
* transformation.
|
||||||
|
*/
|
||||||
|
getScaleInstance: function(sx, sy) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
return mx.setToScale.apply(mx, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform representing a translation transformation.
|
||||||
|
*
|
||||||
|
* @param {number} dx The distance to translate in the x direction.
|
||||||
|
* @param {number} dy The distance to translate in the y direction.
|
||||||
|
* @return {Matrix} A transform representing a
|
||||||
|
* translation transformation.
|
||||||
|
*/
|
||||||
|
getTranslateInstance: function(delta) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
return mx.setToTranslation.apply(mx, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform representing a shearing transformation.
|
||||||
|
*
|
||||||
|
* @param {number} shx The x-axis shear factor.
|
||||||
|
* @param {number} shy The y-axis shear factor.
|
||||||
|
* @return {Matrix} A transform representing a shearing
|
||||||
|
* transformation.
|
||||||
|
*/
|
||||||
|
getShearInstance: function(shx, shy, center) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
return mx.setToShear.apply(mx, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform representing a rotation transformation.
|
||||||
|
*
|
||||||
|
* @param {number} angle The angle of rotation measured in degrees.
|
||||||
|
* @param {number} x The x coordinate of the anchor point.
|
||||||
|
* @param {number} y The y coordinate of the anchor point.
|
||||||
|
* @return {Matrix} A transform representing a rotation
|
||||||
|
* transformation.
|
||||||
|
*/
|
||||||
|
getRotateInstance: function(angle, center) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
return mx.setToRotation.apply(mx, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
147
src/item/Item.js
147
src/item/Item.js
|
@ -384,5 +384,152 @@ Item = Base.extend({
|
||||||
parent = parent.parent;
|
parent = parent.parent;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getBounds: function() {
|
||||||
|
// TODO: Implement
|
||||||
|
return new Rectangle();
|
||||||
|
},
|
||||||
|
|
||||||
|
setBounds: function(rect) {
|
||||||
|
var bounds = this.bounds;
|
||||||
|
rect = Rectangle.read(arguments);
|
||||||
|
var matrix = new Matrix();
|
||||||
|
// Read this from bottom to top:
|
||||||
|
// Translate to new center:
|
||||||
|
var center = rect.center;
|
||||||
|
matrix.translate(center);
|
||||||
|
// Scale to new Size, if size changes and avoid divisions by 0:
|
||||||
|
if (rect.width != bounds.width || rect.height != bounds.height) {
|
||||||
|
matrix.scale(
|
||||||
|
bounds.width != 0 ? rect.width / bounds.width : 1,
|
||||||
|
bounds.height != 0 ? rect.height / bounds.height : 1);
|
||||||
|
}
|
||||||
|
// Translate to center:
|
||||||
|
center = bounds.center;
|
||||||
|
matrix.translate(-center.x, -center.y);
|
||||||
|
// Now execute the transformation:
|
||||||
|
transform(matrix);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item's position within the art board. This is the
|
||||||
|
* {@link Rectangle#getCenter()} of the {@link Item#getBounds()} rectangle.
|
||||||
|
*
|
||||||
|
* Sample code:
|
||||||
|
* <code>
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
*
|
||||||
|
* // Move the circle to { x: 20, y: 20 }
|
||||||
|
* circle.position = new Point(20, 20);
|
||||||
|
*
|
||||||
|
* // Move the circle 10 points to the right
|
||||||
|
* circle.position += new Point(10, 0);
|
||||||
|
* print(circle.position); // { x: 30, y: 20 }
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
getPosition: function() {
|
||||||
|
return this.bounds.center;
|
||||||
|
},
|
||||||
|
|
||||||
|
setPosition: function(point) {
|
||||||
|
translate(point.subtract(this.position));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param flags: Array of any of the following: 'objects', 'children',
|
||||||
|
* 'fill-gradients', 'fill-patterns', 'stroke-patterns', 'lines'.
|
||||||
|
* Default: ['objects', 'children']
|
||||||
|
*/
|
||||||
|
transform: function(matrix, flags) {
|
||||||
|
// TODO: Walk DOM and call transform on chidren, depending on flags
|
||||||
|
// TODO: Handle flags, add TransformFlag class and convert to bit mask
|
||||||
|
// for quicker checking
|
||||||
|
if (this.transformContent)
|
||||||
|
this.transformContent(matrix, flags);
|
||||||
|
if (this.children) {
|
||||||
|
for (var i = 0, l = this.children.length; i < l; i++) {
|
||||||
|
var child = this.children[i];
|
||||||
|
child.transform(matrix, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
transformContent: function(matrix, flags) {
|
||||||
|
// The code that performs the actual transformation of content,
|
||||||
|
// if defined. Item itself does not define this.
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Translates (moves) the item by the given offset point.
|
||||||
|
*
|
||||||
|
* Sample code:
|
||||||
|
* <code>
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* circle.translate(new Point(5, 10));
|
||||||
|
* print(circle.position); // {x: 15, y: 20}
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* Alternatively you can also add to the {@link #getPosition()} of the item:
|
||||||
|
* <code>
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* circle.position += new Point(5, 10);
|
||||||
|
* print(circle.position); // {x: 15, y: 20}
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @param delta
|
||||||
|
*/
|
||||||
|
translate: function(delta) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
mx.translate.apply(mx, arguments);
|
||||||
|
this.transform(mx);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@grouptitle Transform Functions}
|
||||||
|
*
|
||||||
|
* Scales the item by the given values from its center point, or optionally
|
||||||
|
* by a supplied point.
|
||||||
|
*
|
||||||
|
* @param sx
|
||||||
|
* @param sy
|
||||||
|
* @param center {@default the center point of the item}
|
||||||
|
*
|
||||||
|
* @see Matrix#scale(double, double, Point center)
|
||||||
|
*/
|
||||||
|
scale: function(sx, sy /* | scale */, center) {
|
||||||
|
// TODO: Make single scale parameter work, and still pass center
|
||||||
|
// or position
|
||||||
|
this.transform(new Matrix().scale(sx, sy, center || this.position));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates the item by a given angle around the given point.
|
||||||
|
*
|
||||||
|
* Angles are oriented clockwise and measured in degrees by default. Read
|
||||||
|
* more about angle units and orientation in the description of the
|
||||||
|
* {@link com.scriptographer.ai.Point#getAngle()} property.
|
||||||
|
*
|
||||||
|
* @param angle the rotation angle
|
||||||
|
* @see Matrix#rotate(double, Point)
|
||||||
|
*/
|
||||||
|
rotate: function(angle, center) {
|
||||||
|
this.transform(new Matrix().rotate(angle, center || this.position));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shears the item with a given amount around its center point.
|
||||||
|
*
|
||||||
|
* @param shx
|
||||||
|
* @param shy
|
||||||
|
* @see Matrix#shear(double, double)
|
||||||
|
*/
|
||||||
|
shear: function(shx, shy, center) {
|
||||||
|
// TODO: Add support for center ack to Scriptographer too!
|
||||||
|
this.transform(new Matrix().shear(shx, shy, center || this.position));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -145,8 +145,17 @@ PathItem = Item.extend(new function() {
|
||||||
return new Rectangle(min.x, min.y, max.x - min.x , max.y - min.y);
|
return new Rectangle(min.x, min.y, max.x - min.x , max.y - min.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
setBounds: function(bounds) {
|
transformContent: function(matrix, flags) {
|
||||||
// TODO:
|
for (var i = 0, l = this._segments.length; i < l; i++) {
|
||||||
|
var segment = this._segments[i];
|
||||||
|
var point = segment.point;
|
||||||
|
var handleIn = segment.handleIn.add(point);
|
||||||
|
var handleOut = segment.handleOut.add(point);
|
||||||
|
point = matrix.transform(point);
|
||||||
|
segment.point = point;
|
||||||
|
segment.handleIn = matrix.transform(handleIn).subtract(point);
|
||||||
|
segment.handleOut = matrix.transform(handleOut).subtract(point);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addSegment: function(segment) {
|
addSegment: function(segment) {
|
||||||
|
|
Loading…
Reference in a new issue