mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Implement exporting of Symbols to SVG.
This commit is contained in:
parent
565fb86430
commit
f06701055d
3 changed files with 117 additions and 25 deletions
26
examples/SVG Export/Symbols.html
Normal file
26
examples/SVG Export/Symbols.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>Symbols</title>
|
||||||
|
<link rel="stylesheet" href="../css/style.css">
|
||||||
|
<script type="text/javascript" src="../../dist/paper.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" width="500" height="500"></canvas>
|
||||||
|
<script type="text/paperscript" canvas="canvas">
|
||||||
|
var ellipse = new Path.Ellipse({
|
||||||
|
from: [0, 0],
|
||||||
|
to: [200, 100],
|
||||||
|
fillColor: 'red'
|
||||||
|
});
|
||||||
|
var symbol = new Symbol(ellipse);
|
||||||
|
var p1 = symbol.place([100, 100]);
|
||||||
|
p1.rotate(45);
|
||||||
|
var p2 = symbol.place([300, 200]);
|
||||||
|
p2.rotate(-30);
|
||||||
|
document.getElementById('svg').appendChild(project.exportSvg());
|
||||||
|
</script>
|
||||||
|
<svg id="svg" style="width: 500px; height: 500px"></svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -22,12 +22,20 @@ new function() {
|
||||||
return formatFloat(point.x) + ',' + formatFloat(point.y);
|
return formatFloat(point.x) + ',' + formatFloat(point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatRectangle(rect) {
|
||||||
|
return formatFloat(rect.x) + ',' + formatFloat(rect.y)
|
||||||
|
+ ',' + formatFloat(rect.width) + ',' + formatFloat(rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
function setAttributes(svg, attrs) {
|
function setAttributes(svg, attrs) {
|
||||||
for (var key in attrs) {
|
for (var key in attrs) {
|
||||||
var val = attrs[key];
|
var val = attrs[key];
|
||||||
if (typeof val === 'number')
|
if (typeof val === 'number')
|
||||||
val = formatFloat(val);
|
val = formatFloat(val);
|
||||||
svg.setAttribute(key, val);
|
if (key === 'href')
|
||||||
|
svg.setAttributeNS('http://www.w3.org/1999/xlink','href', val);
|
||||||
|
else
|
||||||
|
svg.setAttribute(key, val);
|
||||||
}
|
}
|
||||||
return svg;
|
return svg;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +216,7 @@ new function() {
|
||||||
attrs.fill = 'none';
|
attrs.fill = 'none';
|
||||||
var svg = createElement('g', attrs);
|
var svg = createElement('g', attrs);
|
||||||
for (var i = 0, l = children.length; i < l; i++) {
|
for (var i = 0, l = children.length; i < l; i++) {
|
||||||
var child = children[i].exportSvg();
|
var child = exportSvg(children[i]);
|
||||||
if (child)
|
if (child)
|
||||||
svg.appendChild(child);
|
svg.appendChild(child);
|
||||||
}
|
}
|
||||||
|
@ -218,13 +226,12 @@ new function() {
|
||||||
function exportRaster(item) {
|
function exportRaster(item) {
|
||||||
var attrs = getTransform(item, true),
|
var attrs = getTransform(item, true),
|
||||||
size = item.getSize();
|
size = item.getSize();
|
||||||
attrs.width = size.width;
|
|
||||||
attrs.height = size.height;
|
|
||||||
attrs.x -= size.width / 2;
|
attrs.x -= size.width / 2;
|
||||||
attrs.y -= size.height / 2;
|
attrs.y -= size.height / 2;
|
||||||
var svg = createElement('image', attrs);
|
attrs.width = size.width;
|
||||||
svg.setAttributeNS('http://www.w3.org/1999/xlink','href', item.toDataURL());
|
attrs.height = size.height;
|
||||||
return svg;
|
attrs.href = item.toDataURL();
|
||||||
|
return createElement('image', attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportText(item) {
|
function exportText(item) {
|
||||||
|
@ -336,14 +343,35 @@ new function() {
|
||||||
return createElement(type, attrs);
|
return createElement(type, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportCompoundPath(path) {
|
function exportCompoundPath(item) {
|
||||||
var children = path._children,
|
var attrs = getTransform(item, true),
|
||||||
|
children = item._children,
|
||||||
paths = [];
|
paths = [];
|
||||||
for (var i = 0, l = children.length; i < l; i++)
|
for (var i = 0, l = children.length; i < l; i++)
|
||||||
paths.push(getPath(children[i]));
|
paths.push(getPath(children[i]));
|
||||||
return createElement('path', {
|
attrs.d = paths.join(' ');
|
||||||
d: paths.join(' ')
|
return createElement('path', attrs);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function exportPlacedSymbol(item) {
|
||||||
|
var attrs = getTransform(item, true),
|
||||||
|
symbol = item.getSymbol(),
|
||||||
|
symbolSvg = getDefinition(symbol);
|
||||||
|
definition = symbol.getDefinition(),
|
||||||
|
bounds = definition.getBounds();
|
||||||
|
if (!symbolSvg) {
|
||||||
|
symbolSvg = createElement('symbol', {
|
||||||
|
viewBox: formatRectangle(bounds)
|
||||||
|
});
|
||||||
|
symbolSvg.appendChild(exportSvg(definition));
|
||||||
|
setDefinition(symbol, symbolSvg, 'symbol');
|
||||||
|
}
|
||||||
|
attrs.href = '#' + symbolSvg.id;
|
||||||
|
attrs.x += bounds.x;
|
||||||
|
attrs.y += bounds.y;
|
||||||
|
attrs.width = formatFloat(bounds.width);
|
||||||
|
attrs.height = formatFloat(bounds.height);
|
||||||
|
return createElement('use', attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
var exporters = {
|
var exporters = {
|
||||||
|
@ -352,9 +380,9 @@ new function() {
|
||||||
raster: exportRaster,
|
raster: exportRaster,
|
||||||
pointtext: exportText,
|
pointtext: exportText,
|
||||||
path: exportPath,
|
path: exportPath,
|
||||||
compoundpath: exportCompoundPath
|
compoundpath: exportCompoundPath,
|
||||||
|
placedsymbol: exportPlacedSymbol
|
||||||
// TODO:
|
// TODO:
|
||||||
// placedsymbol:
|
|
||||||
// gradients
|
// gradients
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -398,6 +426,45 @@ new function() {
|
||||||
return setAttributes(svg, attrs);
|
return setAttributes(svg, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var definitions;
|
||||||
|
function getDefinition(item) {
|
||||||
|
if (!definitions)
|
||||||
|
definitions = { ids: {}, svgs: {} };
|
||||||
|
return definitions.svgs[item._id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefinition(item, svg, type) {
|
||||||
|
var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
|
||||||
|
svg.id = type + '-' + id;
|
||||||
|
definitions.svgs[item._id] = svg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportDefinitions(svg) {
|
||||||
|
if (!definitions)
|
||||||
|
return svg;
|
||||||
|
// We can only use svg nodes as defintion containers. Have the loop
|
||||||
|
// produce one if it's a single item of another type (when calling
|
||||||
|
// #exportSvg() on an item rather than a whole project)
|
||||||
|
var container = svg.nodeName.toLowerCase() == 'svg' && svg,
|
||||||
|
firstChild = container ? container.firstChild : svg;
|
||||||
|
for (var i in definitions.svgs) {
|
||||||
|
if (!container) {
|
||||||
|
container = createElement('svg');
|
||||||
|
container.appendChild(svg);
|
||||||
|
}
|
||||||
|
container.insertBefore(definitions.svgs[i], firstChild);
|
||||||
|
}
|
||||||
|
// Clear definitions at the end of export
|
||||||
|
definitions = null;
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportSvg(item) {
|
||||||
|
var exporter = exporters[item._type],
|
||||||
|
svg = exporter && exporter(item, item._type);
|
||||||
|
return svg && applyStyle(item, svg);
|
||||||
|
}
|
||||||
|
|
||||||
Item.inject(/** @lends Item# */{
|
Item.inject(/** @lends Item# */{
|
||||||
/**
|
/**
|
||||||
* {@grouptitle SVG Conversion}
|
* {@grouptitle SVG Conversion}
|
||||||
|
@ -408,9 +475,8 @@ new function() {
|
||||||
* @return {SVGSVGElement} the item converted to an SVG node
|
* @return {SVGSVGElement} the item converted to an SVG node
|
||||||
*/
|
*/
|
||||||
exportSvg: function() {
|
exportSvg: function() {
|
||||||
var exporter = exporters[this._type],
|
var svg = exportSvg(this);
|
||||||
svg = exporter && exporter(this, this._type);
|
return exportDefinitions(svg);
|
||||||
return svg && applyStyle(this, svg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -427,8 +493,8 @@ new function() {
|
||||||
var svg = createElement('svg'),
|
var svg = createElement('svg'),
|
||||||
layers = this.layers;
|
layers = this.layers;
|
||||||
for (var i = 0, l = layers.length; i < l; i++)
|
for (var i = 0, l = layers.length; i < l; i++)
|
||||||
svg.appendChild(layers[i].exportSvg());
|
svg.appendChild(exportSvg(layers[i]));
|
||||||
return svg;
|
return exportDefinitions(svg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -240,12 +240,6 @@ new function() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var definitions = {};
|
|
||||||
function getDefinition(value) {
|
|
||||||
var match = value.match(/\(#([^)']+)/);
|
|
||||||
return match && definitions[match[1]];
|
|
||||||
}
|
|
||||||
|
|
||||||
var importers = {
|
var importers = {
|
||||||
// http://www.w3.org/TR/SVG/struct.html#Groups
|
// http://www.w3.org/TR/SVG/struct.html#Groups
|
||||||
g: importGroup,
|
g: importGroup,
|
||||||
|
@ -502,6 +496,12 @@ new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var definitions = {};
|
||||||
|
function getDefinition(value) {
|
||||||
|
var match = value.match(/\(#([^)']+)/);
|
||||||
|
return match && definitions[match[1]];
|
||||||
|
}
|
||||||
|
|
||||||
function importSvg(svg, clearDefs) {
|
function importSvg(svg, clearDefs) {
|
||||||
var type = svg.nodeName.toLowerCase(),
|
var type = svg.nodeName.toLowerCase(),
|
||||||
importer = importers[type],
|
importer = importers[type],
|
||||||
|
|
Loading…
Reference in a new issue