mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-09 14:22:08 -05:00
878be7962e
Conflicts: src/path/Curve.js src/path/PathItem.Boolean.js src/util/Numerical.js
639 lines
26 KiB
JavaScript
639 lines
26 KiB
JavaScript
/*
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
* http://paperjs.org/
|
|
*
|
|
* Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
|
|
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
|
*
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
*
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/**
|
|
* A function scope holding all the functionality needed to convert a SVG DOM
|
|
* to a Paper.js DOM.
|
|
*/
|
|
new function() {
|
|
// Define a couple of helper functions to easily read values from SVG
|
|
// objects, dealing with baseVal, and item lists.
|
|
// index is option, and if passed, causes a lookup in a list.
|
|
|
|
function getValue(node, name, isString, allowNull) {
|
|
var namespace = SVGNamespaces[name],
|
|
value = namespace
|
|
? node.getAttributeNS(namespace, name)
|
|
: node.getAttribute(name);
|
|
if (value === 'null')
|
|
value = null;
|
|
// Interpret value as number. Never return NaN, but 0 instead.
|
|
// If the value is a sequence of numbers, parseFloat will
|
|
// return the first occurring number, which is enough for now.
|
|
return value == null
|
|
? allowNull
|
|
? null
|
|
: isString
|
|
? ''
|
|
: 0
|
|
: isString
|
|
? value
|
|
: parseFloat(value);
|
|
}
|
|
|
|
function getPoint(node, x, y, allowNull) {
|
|
x = getValue(node, x, false, allowNull);
|
|
y = getValue(node, y, false, allowNull);
|
|
return allowNull && (x == null || y == null) ? null
|
|
: new Point(x, y);
|
|
}
|
|
|
|
function getSize(node, w, h, allowNull) {
|
|
w = getValue(node, w, false, allowNull);
|
|
h = getValue(node, h, false, allowNull);
|
|
return allowNull && (w == null || h == null) ? null
|
|
: new Size(w, h);
|
|
}
|
|
|
|
// Converts a string attribute value to the specified type
|
|
function convertValue(value, type, lookup) {
|
|
return value === 'none'
|
|
? null
|
|
: type === 'number'
|
|
? parseFloat(value)
|
|
: type === 'array'
|
|
? value ? value.split(/[\s,]+/g).map(parseFloat) : []
|
|
: type === 'color'
|
|
? getDefinition(value) || value
|
|
: type === 'lookup'
|
|
? lookup[value]
|
|
: value;
|
|
}
|
|
|
|
// Importer functions for various SVG node types
|
|
|
|
function importGroup(node, type, options, isRoot) {
|
|
var nodes = node.childNodes,
|
|
isClip = type === 'clippath',
|
|
item = new Group(),
|
|
project = item._project,
|
|
currentStyle = project._currentStyle,
|
|
children = [];
|
|
if (!isClip) {
|
|
item = applyAttributes(item, node, isRoot);
|
|
// Style on items needs to be handled differently than all other
|
|
// items: We first apply the style to the item, then use it as the
|
|
// project's currentStyle, so it is used as a default for the
|
|
// creation of all nested items. importSVG then needs to check for
|
|
// items and avoid calling applyAttributes() again.
|
|
project._currentStyle = item._style.clone();
|
|
}
|
|
// Collect the children in an array and apply them all at once.
|
|
for (var i = 0, l = nodes.length; i < l; i++) {
|
|
var childNode = nodes[i],
|
|
child;
|
|
if (childNode.nodeType === 1
|
|
&& (child = importSVG(childNode, options, false))
|
|
&& !(child instanceof Symbol))
|
|
children.push(child);
|
|
}
|
|
item.addChildren(children);
|
|
// Clip paths are reduced (unboxed) and their attributes applied at the
|
|
// end.
|
|
if (isClip)
|
|
item = applyAttributes(item.reduce(), node, isRoot);
|
|
// Restore currentStyle
|
|
project._currentStyle = currentStyle;
|
|
if (isClip || type === 'defs') {
|
|
// We don't want the defs in the DOM. But we might want to use
|
|
// Symbols for them to save memory?
|
|
item.remove();
|
|
item = null;
|
|
}
|
|
return item;
|
|
}
|
|
|
|
function importPoly(node, type) {
|
|
var coords = node.getAttribute('points').match(
|
|
/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g),
|
|
points = [];
|
|
for (var i = 0, l = coords.length; i < l; i += 2)
|
|
points.push(new Point(
|
|
parseFloat(coords[i]),
|
|
parseFloat(coords[i + 1])));
|
|
var path = new Path(points);
|
|
if (type === 'polygon')
|
|
path.closePath();
|
|
return path;
|
|
}
|
|
|
|
function importPath(node) {
|
|
// Get the path data, and determine whether it is a compound path or a
|
|
// normal path based on the amount of moveTo commands inside it.
|
|
var data = node.getAttribute('d'),
|
|
param = { pathData: data };
|
|
// If there are multiple moveTo commands or a closePath command followed
|
|
// by other commands, we have a CompoundPath:
|
|
return (data.match(/m/gi) || []).length > 1 || /z\S+/i.test(data)
|
|
? new CompoundPath(param)
|
|
: new Path(param);
|
|
}
|
|
|
|
function importGradient(node, type) {
|
|
var id = (getValue(node, 'href', true) || '').substring(1),
|
|
isRadial = type === 'radialgradient',
|
|
gradient;
|
|
if (id) {
|
|
// Gradients are always wrapped in a Color object, so get the
|
|
// gradient object from there.
|
|
// TODO: Handle exception if there is no definition for this id.
|
|
gradient = definitions[id].getGradient();
|
|
} else {
|
|
var nodes = node.childNodes,
|
|
stops = [];
|
|
for (var i = 0, l = nodes.length; i < l; i++) {
|
|
var child = nodes[i];
|
|
if (child.nodeType === 1)
|
|
stops.push(applyAttributes(new GradientStop(), child));
|
|
}
|
|
gradient = new Gradient(stops, isRadial);
|
|
}
|
|
var origin, destination, highlight;
|
|
if (isRadial) {
|
|
origin = getPoint(node, 'cx', 'cy');
|
|
destination = origin.add(getValue(node, 'r'), 0);
|
|
highlight = getPoint(node, 'fx', 'fy', true);
|
|
} else {
|
|
origin = getPoint(node, 'x1', 'y1');
|
|
destination = getPoint(node, 'x2', 'y2');
|
|
}
|
|
applyAttributes(
|
|
new Color(gradient, origin, destination, highlight), node);
|
|
// We don't return the gradient, since we only need a reference to it in
|
|
// definitions, which is created in applyAttributes()
|
|
return null;
|
|
}
|
|
|
|
// NOTE: All importers are lowercase, since jsdom is using uppercase
|
|
// nodeNames still.
|
|
var importers = {
|
|
'#document': function (node, type, options, isRoot) {
|
|
var nodes = node.childNodes;
|
|
for (var i = 0, l = nodes.length; i < l; i++) {
|
|
var child = nodes[i];
|
|
if (child.nodeType === 1) {
|
|
// NOTE: We need to move the svg node into our current
|
|
// document, so default styles apply!
|
|
var next = child.nextSibling;
|
|
document.body.appendChild(child);
|
|
var item = importSVG(child, options, isRoot);
|
|
// After import, we move it back to where it was:
|
|
if (next) {
|
|
node.insertBefore(child, next);
|
|
} else {
|
|
node.appendChild(child);
|
|
}
|
|
return item;
|
|
}
|
|
}
|
|
},
|
|
// http://www.w3.org/TR/SVG/struct.html#Groups
|
|
g: importGroup,
|
|
// http://www.w3.org/TR/SVG/struct.html#NewDocument
|
|
svg: importGroup,
|
|
clippath: importGroup,
|
|
// http://www.w3.org/TR/SVG/shapes.html#PolygonElement
|
|
polygon: importPoly,
|
|
// http://www.w3.org/TR/SVG/shapes.html#PolylineElement
|
|
polyline: importPoly,
|
|
// http://www.w3.org/TR/SVG/paths.html
|
|
path: importPath,
|
|
// http://www.w3.org/TR/SVG/pservers.html#LinearGradients
|
|
lineargradient: importGradient,
|
|
// http://www.w3.org/TR/SVG/pservers.html#RadialGradients
|
|
radialgradient: importGradient,
|
|
|
|
// http://www.w3.org/TR/SVG/struct.html#ImageElement
|
|
image: function (node) {
|
|
var raster = new Raster(getValue(node, 'href', true));
|
|
raster.on('load', function() {
|
|
var size = getSize(node, 'width', 'height');
|
|
this.setSize(size);
|
|
// Since x and y start from the top left of an image, add
|
|
// half of its size. We also need to take the raster's matrix
|
|
// into account, which will be defined by the time the load
|
|
// event is called.
|
|
var center = this._matrix._transformPoint(
|
|
getPoint(node, 'x', 'y').add(size.divide(2)));
|
|
this.translate(center);
|
|
});
|
|
return raster;
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/struct.html#SymbolElement
|
|
symbol: function(node, type, options, isRoot) {
|
|
// Pass true for dontCenter:
|
|
return new Symbol(importGroup(node, type, options, isRoot), true);
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/struct.html#DefsElement
|
|
defs: importGroup,
|
|
|
|
// http://www.w3.org/TR/SVG/struct.html#UseElement
|
|
use: function(node) {
|
|
// Note the namespaced xlink:href attribute is just called href
|
|
// as a property on node.
|
|
// TODO: Support overflow and width, height, in combination with
|
|
// overflow: hidden. Paper.js currently does not support
|
|
// PlacedSymbol clipping, but perhaps it should?
|
|
var id = (getValue(node, 'href', true) || '').substring(1),
|
|
definition = definitions[id],
|
|
point = getPoint(node, 'x', 'y');
|
|
// Use place if we're dealing with a symbol:
|
|
return definition
|
|
? definition instanceof Symbol
|
|
// When placing symbols, we nee to take both point and
|
|
// matrix into account. This just does the right thing:
|
|
? definition.place(point)
|
|
: definition.clone().translate(point)
|
|
: null;
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGCircleElement
|
|
circle: function(node) {
|
|
return new Shape.Circle(getPoint(node, 'cx', 'cy'),
|
|
getValue(node, 'r'));
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/shapes.html#InterfaceSVGEllipseElement
|
|
ellipse: function(node) {
|
|
// We only use object literal notation where the default one is not
|
|
// supported (e.g. center / radius fo Shape.Ellipse).
|
|
return new Shape.Ellipse({
|
|
center: getPoint(node, 'cx', 'cy'),
|
|
radius: getSize(node, 'rx', 'ry')
|
|
});
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/shapes.html#RectElement
|
|
rect: function(node) {
|
|
var point = getPoint(node, 'x', 'y'),
|
|
size = getSize(node, 'width', 'height'),
|
|
radius = getSize(node, 'rx', 'ry');
|
|
return new Shape.Rectangle(new Rectangle(point, size), radius);
|
|
},
|
|
|
|
// http://www.w3.org/TR/SVG/shapes.html#LineElement
|
|
line: function(node) {
|
|
return new Path.Line(getPoint(node, 'x1', 'y1'),
|
|
getPoint(node, 'x2', 'y2'));
|
|
},
|
|
|
|
text: function(node) {
|
|
// Not supported by Paper.js
|
|
// x: multiple values for x
|
|
// y: multiple values for y
|
|
// dx: multiple values for x
|
|
// dy: multiple values for y
|
|
// TODO: Support for these is missing in Paper.js right now
|
|
// rotate: character rotation
|
|
// lengthAdjust:
|
|
var text = new PointText(getPoint(node, 'x', 'y')
|
|
.add(getPoint(node, 'dx', 'dy')));
|
|
text.setContent(node.textContent.trim() || '');
|
|
return text;
|
|
}
|
|
};
|
|
|
|
// Attributes and Styles
|
|
|
|
// NOTE: Parameter sequence for all apply*() functions is:
|
|
// (item, value, name, node) rather than (item, node, name, value),
|
|
// so we can omit the less likely parameters from right to left.
|
|
|
|
function applyTransform(item, value, name, node) {
|
|
// http://www.w3.org/TR/SVG/types.html#DataTypeTransformList
|
|
// Parse SVG transform string. First we split at /)\s*/, to separate
|
|
// commands
|
|
var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
|
|
matrix = new Matrix();
|
|
for (var i = 0, l = transforms.length; i < l; i++) {
|
|
var transform = transforms[i];
|
|
if (!transform)
|
|
break;
|
|
// Command come before the '(', values after
|
|
var parts = transform.split(/\(\s*/),
|
|
command = parts[0],
|
|
v = parts[1].split(/[\s,]+/g);
|
|
// Convert values to floats
|
|
for (var j = 0, m = v.length; j < m; j++)
|
|
v[j] = parseFloat(v[j]);
|
|
switch (command) {
|
|
case 'matrix':
|
|
matrix.concatenate(
|
|
new Matrix(v[0], v[1], v[2], v[3], v[4], v[5]));
|
|
break;
|
|
case 'rotate':
|
|
matrix.rotate(v[0], v[1], v[2]);
|
|
break;
|
|
case 'translate':
|
|
matrix.translate(v[0], v[1]);
|
|
break;
|
|
case 'scale':
|
|
matrix.scale(v);
|
|
break;
|
|
case 'skewX':
|
|
matrix.skew(v[0], 0);
|
|
break;
|
|
case 'skewY':
|
|
matrix.skew(0, v[0]);
|
|
break;
|
|
}
|
|
}
|
|
item.transform(matrix);
|
|
}
|
|
|
|
function applyOpacity(item, value, name) {
|
|
// http://www.w3.org/TR/SVG/painting.html#FillOpacityProperty
|
|
// http://www.w3.org/TR/SVG/painting.html#StrokeOpacityProperty
|
|
var color = item[name === 'fill-opacity' ? 'getFillColor'
|
|
: 'getStrokeColor']();
|
|
if (color)
|
|
color.setAlpha(parseFloat(value));
|
|
}
|
|
|
|
// Create apply-functions for attributes, and merge in those for SVGStlyes.
|
|
// We need to define style attributes first, and merge in all others after,
|
|
// since transform needs to be applied after fill color, as transformations
|
|
// can affect gradient fills.
|
|
var attributes = Base.each(SVGStyles, function(entry) {
|
|
this[entry.attribute] = function(item, value) {
|
|
item[entry.set](convertValue(value, entry.type, entry.fromSVG));
|
|
// When applying gradient colors to shapes, we need to offset
|
|
// the shape's initial position to get the same results as SVG.
|
|
if (entry.type === 'color' && item instanceof Shape) {
|
|
// Do not use result of convertValue() above, since calling
|
|
// the setter will produce a new cloned color.
|
|
var color = item[entry.get]();
|
|
if (color)
|
|
color.transform(new Matrix().translate(
|
|
item.getPosition(true).negate()));
|
|
}
|
|
};
|
|
}, {
|
|
id: function(item, value) {
|
|
definitions[value] = item;
|
|
if (item.setName)
|
|
item.setName(value);
|
|
},
|
|
|
|
'clip-path': function(item, value) {
|
|
// http://www.w3.org/TR/SVG/masking.html#ClipPathProperty
|
|
var clip = getDefinition(value);
|
|
if (clip) {
|
|
clip = clip.clone();
|
|
clip.setClipMask(true);
|
|
// If item is already a group, move the clip-path inside
|
|
if (item instanceof Group) {
|
|
item.insertChild(0, clip);
|
|
} else {
|
|
return new Group(clip, item);
|
|
}
|
|
}
|
|
},
|
|
|
|
gradientTransform: applyTransform,
|
|
transform: applyTransform,
|
|
|
|
'fill-opacity': applyOpacity,
|
|
'stroke-opacity': applyOpacity,
|
|
|
|
visibility: function(item, value) {
|
|
item.setVisible(value === 'visible');
|
|
},
|
|
|
|
display: function(item, value) {
|
|
// NOTE: 'none' gets translated to null in getAttribute()
|
|
item.setVisible(value !== null);
|
|
},
|
|
|
|
'stop-color': function(item, value) {
|
|
// http://www.w3.org/TR/SVG/pservers.html#StopColorProperty
|
|
if (item.setColor)
|
|
item.setColor(value);
|
|
},
|
|
|
|
'stop-opacity': function(item, value) {
|
|
// http://www.w3.org/TR/SVG/pservers.html#StopOpacityProperty
|
|
// NOTE: It is important that this is applied after stop-color!
|
|
if (item._color)
|
|
item._color.setAlpha(parseFloat(value));
|
|
},
|
|
|
|
offset: function(item, value) {
|
|
// http://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute
|
|
var percentage = value.match(/(.*)%$/);
|
|
item.setRampPoint(percentage
|
|
? percentage[1] / 100
|
|
: parseFloat(value));
|
|
},
|
|
|
|
viewBox: function(item, value, name, node, styles) {
|
|
// http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
|
|
// TODO: implement preserveAspectRatio attribute
|
|
// viewBox will be applied both to the group that's created for the
|
|
// content in Symbol.definition, and the Symbol itself.
|
|
var rect = new Rectangle(convertValue(value, 'array')),
|
|
size = getSize(node, 'width', 'height', true);
|
|
if (item instanceof Group) {
|
|
// This is either a top-level svg node, or the container for a
|
|
// symbol.
|
|
var scale = size ? rect.getSize().divide(size) : 1,
|
|
matrix = new Matrix().translate(rect.getPoint()).scale(scale);
|
|
item.transform(matrix.inverted());
|
|
} else if (item instanceof Symbol) {
|
|
// The symbol is wrapping a group. Note that viewBox was already
|
|
// applied to the group, and above code was executed for it.
|
|
// All that is left to handle here on the Symbol level is
|
|
// clipping. We can't do it at group level because
|
|
// applyAttributes() gets called for groups before their
|
|
// children are added, for styling reasons. See importGroup()
|
|
if (size)
|
|
rect.setSize(size);
|
|
var clip = getAttribute(node, 'overflow', styles) != 'visible',
|
|
group = item._definition;
|
|
if (clip && !rect.contains(group.getBounds())) {
|
|
// Add a clip path at the top of this symbol's group
|
|
clip = new Shape.Rectangle(rect).transform(group._matrix);
|
|
clip.setClipMask(true);
|
|
group.addChild(clip);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
function getAttribute(node, name, styles) {
|
|
// First see if the given attribute is defined.
|
|
var attr = node.attributes[name],
|
|
value = attr && attr.value;
|
|
if (!value) {
|
|
// Fallback to using styles. See if there is a style, either set
|
|
// directly on the object or applied to it through CSS rules.
|
|
// We also need to filter out inheritance from their parents.
|
|
var style = Base.camelize(name);
|
|
value = node.style[style];
|
|
if (!value && styles.node[style] !== styles.parent[style])
|
|
value = styles.node[style];
|
|
}
|
|
// Return undefined if attribute is not defined, but null if it's
|
|
// defined as not set (e.g. fill / stroke).
|
|
return !value
|
|
? undefined
|
|
: value === 'none'
|
|
? null
|
|
: value;
|
|
}
|
|
|
|
/**
|
|
* Converts various SVG styles and attributes into Paper.js styles and
|
|
* attributes and applies them to the passed item.
|
|
*
|
|
* @param {SVGElement} node an SVG node to read style and attributes from.
|
|
* @param {Item} item the item to apply the style and attributes to.
|
|
*/
|
|
function applyAttributes(item, node, isRoot) {
|
|
// SVG attributes can be set both as styles and direct node attributes,
|
|
// so we need to handle both.
|
|
var styles = {
|
|
node: DomElement.getStyles(node) || {},
|
|
// Do not check for inheritance if this is the root, since we want
|
|
// the default SVG settings to stick.
|
|
parent: !isRoot && DomElement.getStyles(node.parentNode) || {}
|
|
};
|
|
Base.each(attributes, function(apply, name) {
|
|
var value = getAttribute(node, name, styles);
|
|
if (value !== undefined)
|
|
item = Base.pick(apply(item, value, name, node, styles), item);
|
|
});
|
|
return item;
|
|
}
|
|
|
|
var definitions = {};
|
|
function getDefinition(value) {
|
|
// When url() comes from a style property, '#'' seems to be missing on
|
|
// WebKit, so let's make it optional here:
|
|
var match = value && value.match(/\((?:#|)([^)']+)/);
|
|
return match && definitions[match[1]];
|
|
}
|
|
|
|
function importSVG(source, options, isRoot) {
|
|
if (!source)
|
|
return null;
|
|
if (!options) {
|
|
options = {};
|
|
} else if (typeof options === 'function') {
|
|
options = { onLoad: options };
|
|
}
|
|
|
|
var node = source,
|
|
// Remember current scope so we can restore it in onLoad.
|
|
scope = paper;
|
|
|
|
function onLoadCallback(svg) {
|
|
paper = scope;
|
|
var item = importSVG(svg, options, isRoot),
|
|
onLoad = options.onLoad,
|
|
view = scope.project && scope.getView();
|
|
if (onLoad)
|
|
onLoad.call(this, item);
|
|
view.update();
|
|
}
|
|
|
|
if (isRoot) {
|
|
// Have the group not pass on all transformations to its children,
|
|
// as this is how SVG works too.
|
|
// See if it's a string but handle markup separately
|
|
if (typeof source === 'string' && !/^.*</.test(source)) {
|
|
/*#*/ if (__options.environment == 'browser') {
|
|
// First see if we're meant to import an element with the given
|
|
// id.
|
|
node = document.getElementById(source);
|
|
// Check if the string does not represent SVG data, in which
|
|
// case it must be the URL of a SVG to be loaded.
|
|
if (node) {
|
|
source = null;
|
|
} else {
|
|
return Http.request('get', source, onLoadCallback);
|
|
}
|
|
/*#*/ } else if (__options.environment == 'node') {
|
|
// TODO: Implement!
|
|
/*#*/ } // __options.environment == 'node'
|
|
} else if (typeof File !== 'undefined' && source instanceof File) {
|
|
// Load local file through FileReader
|
|
var reader = new FileReader();
|
|
reader.onload = function() {
|
|
onLoadCallback(reader.result);
|
|
};
|
|
return reader.readAsText(source);
|
|
}
|
|
}
|
|
|
|
if (typeof source === 'string')
|
|
node = new DOMParser().parseFromString(source, 'image/svg+xml');
|
|
if (!node.nodeName)
|
|
throw new Error('Unsupported SVG source: ' + source);
|
|
// jsdom in Node.js uses uppercase values for nodeName...
|
|
var type = node.nodeName.toLowerCase(),
|
|
importer = importers[type],
|
|
item,
|
|
data = node.getAttribute && node.getAttribute('data-paper-data'),
|
|
settings = scope.settings,
|
|
applyMatrix = settings.applyMatrix;
|
|
// Have items imported from SVG not bake in all transformations to their
|
|
// content and children, as this is how SVG works too, but preserve the
|
|
// current setting so we can restore it after.
|
|
settings.applyMatrix = false;
|
|
item = importer && importer(node, type, options, isRoot) || null;
|
|
settings.applyMatrix = applyMatrix;
|
|
if (item) {
|
|
// Do not apply attributes if this is a #document node.
|
|
// See importGroup() for an explanation of filtering for Group:
|
|
if (type !== '#document' && !(item instanceof Group))
|
|
item = applyAttributes(item, node, isRoot);
|
|
// Support onImportItem callback, to provide mechanism to handle
|
|
// special attributes (e.g. inkscape:transform-center)
|
|
var onImport = options.onImport;
|
|
if (onImport)
|
|
item = onImport(node, item, options) || item;
|
|
if (options.expandShapes && item instanceof Shape) {
|
|
item.remove();
|
|
item = item.toPath();
|
|
}
|
|
if (data)
|
|
item._data = JSON.parse(data);
|
|
}
|
|
// Clear definitions at the end of import?
|
|
if (isRoot) {
|
|
definitions = {};
|
|
// Now if settings.applyMatrix was set, apply recursively and set
|
|
// #applyMatrix = true on the item and all children.
|
|
if (applyMatrix && item)
|
|
item.matrix.apply(true, true);
|
|
}
|
|
return item;
|
|
}
|
|
|
|
// NOTE: Documentation is in Item.js
|
|
Item.inject({
|
|
importSVG: function(node, options) {
|
|
return this.addChild(importSVG(node, options, true));
|
|
}
|
|
});
|
|
|
|
// NOTE: Documentation is in Project.js
|
|
Project.inject({
|
|
importSVG: function(node, options) {
|
|
this.activate();
|
|
return importSVG(node, options, true);
|
|
}
|
|
});
|
|
};
|