Remove Item#applyMatrix boolean, go back to previous way of directly applying transformations to children in Group and Layer, and introduce new Clip class for non-transformed nested matrices.

This commit is contained in:
Jürg Lehni 2013-05-13 18:57:17 -07:00
parent c70b985911
commit 7c2e57e105
17 changed files with 83 additions and 64 deletions

View file

@ -125,7 +125,6 @@
path.closed = true;
var thrust = new Path([-8, -4], [-14, 0], [-8, 4]);
var group = new Group(path, thrust);
group.applyMatrix = true;
group.position = view.bounds.center;
return {
item: group,

View file

@ -27,21 +27,21 @@
var radius = this.radius = 50 * Math.random() + 30;
// Wrap CompoundPath in a Group, since CompoundPaths directly
// applies the transformations to the content, just like Path.
this.item = new Group({
var ball = new CompoundPath({
children: [
new CompoundPath({
children: [
new Path.Circle({
radius: radius
}),
new Path.Circle({
center: radius / 8,
radius: radius / 3
})
],
fillColor: new Color(gradient, 0, radius, radius / 8),
new Path.Circle({
radius: radius
}),
new Path.Circle({
center: radius / 8,
radius: radius / 3
})
],
fillColor: new Color(gradient, 0, radius, radius / 8),
});
this.item = new Clip({
children: [ball],
position: this.point
});
}

View file

@ -9,7 +9,6 @@
project.importSVG(document.getElementById('svg'));
// Resize the tiger to fit within the window:
project.activeLayer.applyMatrix = true;
project.activeLayer.fitBounds(view.bounds);
var items = project.activeLayer.firstChild.children;

View file

@ -123,7 +123,6 @@
var count = 30;
var group = new Group(paths);
group.applyMatrix = true;
var headGroup;
var eyePosition = new Point();
var eyeFollow = (Point.random() - 0.5);

View file

@ -12,10 +12,6 @@
var yesGroup = words.children.yes;
var noGroup = words.children.no;
project.activeLayer.applyMatrix = true;
noGroup.applyMatrix = true;
yesGroup.applyMatrix = true;
// Resize the words to fit snugly inside the view:
project.activeLayer.fitBounds(view.bounds);
project.activeLayer.scale(0.8);

View file

@ -69,7 +69,6 @@
// Transform the raster, so it fills the view:
raster.fitBounds(view.bounds, true);
group = new Group();
group.applyMatrix = true;
for (var y = 0; y < values.amount; y++) {
for (var x = 0; x < values.amount; x++) {
var copy = piece.clone();

View file

@ -28,7 +28,6 @@
// Create the group of circle shaped paths and scale it up a bit:
var group = createPhyllotaxis(values.amount);
group.applyMatrix = true;
group.scale(3);
function createPhyllotaxis(amount) {

26
src/item/Clip.js Normal file
View file

@ -0,0 +1,26 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
/**
* @name Clip
*
* @class A Clip is a collection of items, similar to a Group. But instead of
* automatically passing on transformations to its children by calling
* {@link Item#applyMatrix()}, the transformations are stored in the internal
* matrix.
*
* @extends Group
*/
var Clip = this.Clip = Group.extend(/** @lends Clip# */{
_class: 'Clip',
_applyMatrix: false
});

View file

@ -37,6 +37,9 @@ var Item = this.Item = Base.extend(Callback, {
}
}
}, /** @lends Item# */{
// All items apply their matrix by default.
// Exceptions are Raster, PlacedSymbol, Clip and Shape.
_applyMatrix: true,
_boundsSelected: false,
// Provide information about fields to be serialized, with their defaults
// that can be ommited.
@ -508,16 +511,6 @@ var Item = this.Item = Base.extend(Callback, {
*/
_guide: false,
/**
* Specifies whether the item directly transforms its contents when
* transformations are applied to it, or wether it simply stores them in
* {@link Item#matrix}.
*
* @type Boolean
* @default false
*/
applyMatrix: false,
/**
* Specifies whether an item is selected and will also return {@code true}
* if the item is partially selected (groups with some selected or partially
@ -1203,7 +1196,7 @@ var Item = this.Item = Base.extend(Callback, {
// TODO: Consider moving this to Base once it's useful in more than one
// place
var keys = ['_locked', '_visible', '_blendMode', '_opacity',
'_clipMask', '_guide', 'applyMatrix'];
'_clipMask', '_guide'];
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
if (this.hasOwnProperty(key))
@ -2193,26 +2186,10 @@ var Item = this.Item = Base.extend(Callback, {
position = this._position;
// Simply preconcatenate the internal matrix with the passed one:
this._matrix.preConcatenate(matrix);
if (this._transform)
this._transform(matrix);
// If we need to directly apply the accumulated transformations, call
// #_applyMatrix() with the internal _matrix, and set it to the identity
// transformation if it was possible to apply it. Application is not
// possible on Raster, PointText, PlacedSymbol, since the matrix is
// storing the actual location / transformation state.
if ((this.applyMatrix || arguments[1])
&& this._applyMatrix(this._matrix)) {
// When the matrix could be applied, we also need to transform
// color styles with matrices (only gradients so far):
var style = this._style,
fillColor = style.getFillColor(),
strokeColor = style.getStrokeColor();
if (fillColor)
fillColor.transform(this._matrix);
if (strokeColor)
strokeColor.transform(this._matrix);
this._matrix.reset();
}
// Call applyMatrix if we need to directly apply the accumulated
// transformations to the item's content.
if (this._applyMatrix || arguments[1])
this.applyMatrix(false);
// We always need to call _changed since we're caching bounds on all
// items, including Group.
this._changed(/*#=*/ Change.GEOMETRY);
@ -2242,16 +2219,39 @@ var Item = this.Item = Base.extend(Callback, {
return this;
},
_applyMatrix: function(matrix) {
// Pass on the transformation to the children, and apply it there too,
// by passing true for the 2nd hidden parameter.
_transformContent: function(matrix, applyMatrix) {
if (this._children) {
for (var i = 0, l = this._children.length; i < l; i++)
this._children[i].transform(matrix, true);
this._children[i].transform(matrix, applyMatrix);
return true;
}
},
applyMatrix: function(_dontNotify) {
// Call #_transformContent() with the internal _matrix and pass true for
// applyMatrix. Application is not possible on Raster, PointText,
// PlacedSymbol, since the matrix is where the actual location /
// transformation state is stored.
// Pass on the transformation to the content, and apply it there too,
// by passing true for the 2nd hidden parameter.
if (this._transformContent(this._matrix, true)) {
// When the matrix could be applied, we also need to transform
// color styles with matrices (only gradients so far):
var style = this._style,
fillColor = style.getFillColor(true),
strokeColor = style.getStrokeColor(true);
if (fillColor)
fillColor.transform(this._matrix);
if (strokeColor)
strokeColor.transform(this._matrix);
// Reset the internal matrix to the identity transformation if it
// was possible to apply it.
this._matrix.reset();
}
if (!_dontNotify)
this._changed(/*#=*/ Change.GEOMETRY);
},
/**
* Transform the item so that its {@link #bounds} fit within the specified
* rectangle, without changing its aspect ratio.

View file

@ -20,6 +20,7 @@
*/
var PlacedSymbol = this.PlacedSymbol = Item.extend(/** @lends PlacedSymbol# */{
_class: 'PlacedSymbol',
_applyMatrix: false,
// PlacedSymbol uses strokeBounds for bounds
_boundsGetter: { getBounds: 'getStrokeBounds' },
_boundsSelected: true,

View file

@ -19,6 +19,7 @@
*/
var Raster = this.Raster = Item.extend(/** @lends Raster# */{
_class: 'Raster',
_applyMatrix: false,
// Raster doesn't make the distinction between the different bounds,
// so use the same name for all of them
_boundsGetter: 'getBounds',

View file

@ -19,6 +19,7 @@
*/
var Shape = this.Shape = Item.extend(/** @lends Shape# */{
_class: 'Shape',
_applyMatrix: false,
initialize: function(type, point, size) {
this.base(point);

View file

@ -67,6 +67,7 @@ var paper = new function() {
/*#*/ include('item/Item.js');
/*#*/ include('item/Group.js');
/*#*/ include('item/Layer.js');
/*#*/ include('item/Clip.js');
/*#*/ include('item/Shape.js');
/*#*/ include('item/Raster.js');
/*#*/ include('item/PlacedSymbol.js');

View file

@ -300,7 +300,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
return true;
},
_applyMatrix: function(matrix) {
_transformContent: function(matrix) {
var coords = new Array(6);
for (var i = 0, l = this._segments.length; i < l; i++)
this._segments[i]._transformCoordinates(matrix, coords, true);
@ -1539,7 +1539,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
* the specified point
*/
getNearestLocation: function(point) {
point = this._matrix.inverseTransform(Point.read(arguments));
point = Point.read(arguments);
var curves = this.getCurves(),
minDist = Infinity,
minLoc = null;

View file

@ -20,9 +20,6 @@
* @extends Item
*/
var PathItem = this.PathItem = Item.extend(/** @lends PathItem# */{
// All PathItems directly apply transformations by default.
applyMatrix: true,
/**
* Returns all intersections between two {@link PathItem} items as an array
* of {@link CurveLocation} objects. {@link CompoundPath} items are also

View file

@ -151,12 +151,13 @@ var Style = this.Style = Base.extend(new function() {
}
};
fields[get] = function() {
fields[get] = function(/* dontMerge */) {
var value,
children = this._item && this._item._children;
// If this item has children, walk through all of them and see if
// they all have the same style.
if (!children || children.length === 0
// If true is passed for dontMerge, don't merge children styles
if (!children || children.length === 0 || arguments[0]
|| this._item._type === 'compound-path') {
var value = this._values[key];
if (value === undefined) {

View file

@ -53,7 +53,7 @@ test('path.bounds when contained in a transformed group', function() {
var group = new Group([path]);
compareRectangles(path.bounds, { x: 10, y: 10, width: 50, height: 50 }, 'path.bounds before group translation');
group.translate(100, 100);
compareRectangles(path.bounds, { x: 10, y: 10, width: 50, height: 50 }, 'path.bounds after group translation');
compareRectangles(path.bounds, { x: 110, y: 110, width: 50, height: 50 }, 'path.bounds after group translation');
});
test('text.bounds', function() {