Made all imported SVGs be placed in the defs with corresponding use elements, added button to convert a use elem to its reference element. Also fixed some minor bugs.

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1649 eee81c28-f429-11dd-99c0-75d572ba1ddd
This commit is contained in:
Alexis Deveria
2010-07-29 15:09:49 +00:00
parent d3f14f2d6e
commit 35ac12a3c9
6 changed files with 190 additions and 131 deletions

View File

@@ -110,7 +110,7 @@ svgEditor.addExtension("imagelib", function() {
});
var back = $('<input type=button value="Show libraries">').appendTo(browser).click(function() {
frame.hide();
frame.attr('src', 'about:blank').hide();
lib_opts.show();
header.text(all_libs);
}).css({
@@ -122,7 +122,7 @@ svgEditor.addExtension("imagelib", function() {
$.each(img_libs, function(i, opts) {
$('<li>').appendTo(lib_opts).text(opts.name).click(function() {
frame.attr('src', opts.url).show();
header.text(name);
header.text(opts.name);
lib_opts.hide();
}).append('<span>' + opts.description + '</span>');
});
@@ -153,7 +153,7 @@ svgEditor.addExtension("imagelib", function() {
width: 100%;\
height: 100%;\
background-color: rgba(0, 0, 0, .5);\
z-index: 4;\
z-index: 5;\
}\
\
#imgbrowse {\

View File

@@ -1,7 +1,12 @@
<?xml version='1.0'?>
<svg width="137" height="137" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<path id="svg_1" d="m32.186821,97.716736q36.315895,24.940765 72.545845,0m-64.675407,-49.255753c0,-3.855408 3.125259,-6.980789 6.980682,-6.980789c3.854485,0 6.978722,3.125381 6.978722,6.980789c0,3.853455 -3.124237,6.978668 -6.978722,6.978668c-3.855423,0 -6.980682,-3.125214 -6.980682,-6.978668m42.930473,0c0,-3.855408 3.12529,-6.980789 6.97963,-6.980789c3.854401,0 6.979706,3.125381 6.979706,6.980789c0,3.853455 -3.125305,6.978668 -6.979706,6.978668c-3.85434,0 -6.97963,-3.125214 -6.97963,-6.978668m-81.485962,20.035995l0,0c0,-37.001968 29.996788,-66.998917 67.000946,-66.998917c37.003036,0 66.999985,29.996948 66.999985,66.998917c0,37.004089 -29.996948,67.001007 -66.999985,67.001007c-37.004158,0 -67.000946,-29.996918 -67.000946,-67.001007zm0,0l0,0c0,-37.001968 29.996788,-66.998917 67.000946,-66.998917c37.003036,0 66.999985,29.996948 66.999985,66.998917c0,37.004089 -29.996948,67.001007 -66.999985,67.001007c-37.004158,0 -67.000946,-29.996918 -67.000946,-67.001007z" stroke-width="3" stroke="#000000" fill="#ffff00"/>
</g>
<title>Cool smiley</title>
<path fill="url(#svg_4)" stroke="#000000" stroke-width="3" d="m32.18682,97.71674q36.3159,24.94076 72.54585,0m-64.67542,-49.25576c0,-3.8554 3.12526,-6.98079 6.98068,-6.98079c3.85449,0 6.97872,3.12539 6.97872,6.98079c0,3.85346 -3.12423,6.97867 -6.97872,6.97867c-3.85542,0 -6.98068,-3.12521 -6.98068,-6.97867m42.93047,0c0,-3.8554 3.12529,-6.98079 6.97963,-6.98079c3.8544,0 6.97971,3.12539 6.97971,6.98079c0,3.85346 -3.12531,6.97867 -6.97971,6.97867c-3.85434,0 -6.97963,-3.12521 -6.97963,-6.97867m-81.48596,20.036l0,0c0,-37.00197 29.99679,-66.99892 67.00095,-66.99892c37.00303,0 66.99998,29.99695 66.99998,66.99892c0,37.00409 -29.99695,67.00101 -66.99998,67.00101c-37.00416,0 -67.00095,-29.99692 -67.00095,-67.00101zm0,0l0,0c0,-37.00197 29.99679,-66.99892 67.00095,-66.99892c37.00303,0 66.99998,29.99695 66.99998,66.99892c0,37.00409 -29.99695,67.00101 -66.99998,67.00101c-37.00416,0 -67.00095,-29.99692 -67.00095,-67.00101z" id="svg_1"/>
<path id="svg_5" d="m23.84005,41.03445l17.57052,0l5.42937,-19.67914l5.42941,19.67914l17.5706,0l-14.21488,12.16242l5.42982,19.67939l-14.21495,-12.16281l-14.21489,12.16281l5.42991,-19.67939l-14.21491,-12.16242l0,0z" stroke-width="3" fill="#000000"/>
<path id="svg_6" d="m65.84005,41.03445l17.57052,0l5.42937,-19.67914l5.42941,19.67914l17.5706,0l-14.21487,12.16242l5.42982,19.67939l-14.21496,-12.1628l-14.2149,12.1628l5.42992,-19.67939l-14.21491,-12.16242l0,0z" stroke-width="3" fill="#000000"/>
<defs>
<linearGradient y2="0.25391" x2="0.46484" y1="0.94922" x1="0.44531" id="svg_4">
<stop stop-color="#ff0000" offset="0"/>
<stop stop-color="#ffff00" offset="1"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -664,6 +664,23 @@
</svg>
</g>
<g id="unlink_use">
<svg width="222" height="222" xmlns="http://www.w3.org/2000/svg">
<path id="svg_1" d="m93.75,118.44922c-4.5,13.58447 -14.66553,11.5 -28.25,11.5l-34,0c-13.58447,0 -24.5,-7.16553 -24.5,-21.5c0,-14.33447 10.91553,-20.5 24.5,-20.5l34,0c13.58447,0 19.75,-2.33447 26.5,10.75" stroke-width="13" stroke="#3f3f3f" fill="none"/>
<g id="svg_11">
<line id="svg_4" y2="65.94563" x2="83.07683" y1="28.27895" x1="45.41017" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none"/>
<line id="svg_5" y2="15.01293" x2="109.41467" y1="65.94638" x1="109.41467" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none"/>
<line id="svg_6" y2="29.31928" x2="177.58937" y1="65.94638" x1="140.96227" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none"/>
</g>
<g id="svg_12" transform="rotate(-180, 108, 172.111)">
<line y2="190.94563" x2="79.57683" y1="153.27895" x1="41.91017" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none" id="svg_13"/>
<line y2="140.01293" x2="105.91467" y1="190.94638" x1="105.91467" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none" id="svg_14"/>
<line y2="154.31928" x2="174.08937" y1="190.94638" x1="137.46227" stroke-linecap="round" stroke-width="8" stroke="#007fff" fill="none" id="svg_15"/>
</g>
<path transform="rotate(-180, 172.125, 108.926)" id="svg_2" d="m215.5,118.44901c-4.5,13.58499 -14.6655,11.5 -28.25,11.5l-34,0c-13.5845,0 -24.5,-7.16501 -24.5,-21.5c0,-14.3343 10.9155,-20.4998 24.5,-20.4998l34,0c13.5845,0 19.75,-2.3345 26.5,10.75" stroke-width="13" stroke="#3f3f3f" fill="none"/>
</svg>
</g>
<g id="width">
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<path id="svg_6" d="m19,42.5l-7.5,7.5l7.5,7.5l0,-15zm0,7.5l62,0l0,-7.5l7.5,7.5l-7.5,7.5l0,-7.5" stroke-width="8" stroke="#000000" fill="#000000"/>

View File

@@ -359,10 +359,18 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<input id="text" type="text" size="35"/>
</div>
<div id="gsvg_panel">
<!-- formerly gsvg_panel -->
<div id="container_panel">
<!-- Add viewBox field here? -->
</div>
<div id="use_panel">
<div class="tool_sep"></div>
<div class="push_button" id="tool_unlink_use" title="Break link to reference element (make unique)"></div>
</div>
<div id="path_node_panel">
<div class="tool_sep"></div>
<div class="tool_button" id="tool_node_link" title="Link Control Points"></div>

View File

@@ -332,6 +332,7 @@
'#tool_reorient':'reorient',
'#tool_group':'group',
'#tool_ungroup':'ungroup',
'#tool_unlink_use':'unlink_use',
'#tool_alignleft, #tool_posleft':'align_left',
'#tool_aligncenter, #tool_poscenter':'align_center',
@@ -1311,7 +1312,7 @@
}
var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false;
$('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,\
#ellipse_panel, #line_panel, #text_panel, #image_panel, #gsvg_panel').hide();
#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel').hide();
if (elem != null) {
var elname = elem.nodeName;
@@ -1401,13 +1402,14 @@
ellipse: ['cx','cy','rx','ry'],
line: ['x1','y1','x2','y2'],
text: [],
gsvg: []
'use': []
};
var el_name = elem.tagName;
if($(elem).data('gsvg')) {
$('#gsvg_panel').show();
$('#container_panel').show();
$('#g_panel').show();
}
if(panels[el_name]) {
@@ -1446,8 +1448,7 @@
var href = elem.getAttributeNS(xlinkNS, "href");
setImageURL(href);
} // image
else if(el_name == 'g') {
console.log('is group');
else if(el_name == 'g' || el_name == 'use') {
var title = svgCanvas.getTitle();
$('#g_title').val(title);
}
@@ -2343,7 +2344,7 @@
svgCanvas.groupSelectedElements();
}
// ungroup
else if(selectedElement && selectedElement.tagName == 'g'){
else if(selectedElement){
svgCanvas.ungroupSelectedElement();
}
};
@@ -3503,6 +3504,7 @@
{sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey+'C', true]},
{sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey+'G', true]},
{sel:'#tool_ungroup', fn: clickGroup, evt: 'click'},
{sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'},
{sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'},
// these two lines are required to make Opera work properly with the flyout mechanism
// {sel:'#tools_rect_show', fn: clickRect, evt: 'click'},
@@ -3985,7 +3987,6 @@
})();
// ?iconsize=s&bkgd_color=555
// svgEditor.setConfig({

View File

@@ -1253,9 +1253,11 @@ var SelectorManager;
// The bbox for a group does not include stroke vals, so we
// get the bbox based on its children.
var stroked_bbox = getStrokedBBox(selected.childNodes);
$.each(bbox, function(key, val) {
bbox[key] = stroked_bbox[key];
});
if(stroked_bbox) {
$.each(bbox, function(key, val) {
bbox[key] = stroked_bbox[key];
});
}
}
// loop and transform our bounding box until we reach our first rotation
@@ -2279,7 +2281,12 @@ var copyElem = function(el) {
if($(el).data('gsvg')) {
$(new_el).data('gsvg', new_el.firstChild);
} else if(new_el.tagName == 'image') {
} else if($(el).data('symbol')) {
var ref = $(el).data('symbol');
$(new_el).data('ref', ref).data('symbol', ref);
}
else if(new_el.tagName == 'image') {
preventClickDefault(new_el);
}
return new_el;
@@ -2884,10 +2891,10 @@ var remapElement = this.remapElement = function(selected,changes,m) {
changes["height"] = scaleh(changes["height"]);
break;
case "use":
var pt1 = remap(changes["x"],changes["y"]);
changes["x"] = pt1.x;
changes["y"] = pt1.y;
break;
// var pt1 = remap(changes["x"],changes["y"]);
// changes["x"] = pt1.x;
// changes["y"] = pt1.y;
// break;
case "g":
case "text":
// if it was a translate, then just update x,y
@@ -2998,9 +3005,6 @@ var remapElement = this.remapElement = function(selected,changes,m) {
changes.height = Math.abs(changes.height);
assignAttributes(selected, changes, 1000, true);
break;
case "use":
assignAttributes(selected, changes, 1000, true);
break;
case "ellipse":
changes.rx = Math.abs(changes.rx);
changes.ry = Math.abs(changes.ry);
@@ -3008,6 +3012,7 @@ var remapElement = this.remapElement = function(selected,changes,m) {
if(changes.r) changes.r = Math.abs(changes.r);
case "line":
case "text":
case "use":
assignAttributes(selected, changes, 1000, true);
break;
case "g":
@@ -3167,8 +3172,6 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
attrs = ["width", "height", "x", "y"];
break;
case "use":
attrs = ["x", "y"];
break;
case "text":
attrs = ["x", "y"];
break;
@@ -3612,8 +3615,11 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
// if we had [M][T][S][T] we want to extract the matrix equivalent of
// [T][S][T] and push it down to the element
if (N >= 3 && tlist.getItem(N-2).type == 3 &&
tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2 &&
selected.nodeName != "use")
tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2)
// Removed this so a <use> with a given [T][S][T] would convert to a matrix.
// Is that bad?
// && selected.nodeName != "use"
{
operation = 3; // scale
m = transformListToTransform(tlist,N-3,N-1).matrix;
@@ -5094,7 +5100,10 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
to: cur_shape.opacity,
dur: ani_dur
}).appendTo(element);
c_ani[0].beginElement();
try {
// Fails in FF4 on foreignObject
c_ani[0].beginElement();
} catch(e){}
} else {
ani_dur = 0;
}
@@ -7845,13 +7854,19 @@ var uniquifyElems = this.uniquifyElems = function(g) {
obj_num++;
}
// Function: svgToGroup
// Converts a child SVG element to a group
var svgToGroup = this.svgToGroup = function(elem) {
// Function: convertToGroup
// Converts selected/given <use> or child SVG element to a group
var convertToGroup = this.convertToGroup = function(elem) {
if(!elem) {
elem = selectedElements[0];
}
if(elem.tagName == 'g') {
var $elem = $(elem);
var batchCmd = new BatchCommand();
var ts;
if($elem.data('gsvg')) {
// Use the gsvg as the new group
var svg = elem.firstChild;
var pt = $(svg).attr(['x', 'y']);
@@ -7865,67 +7880,66 @@ var svgToGroup = this.svgToGroup = function(elem) {
tlist.appendItem(xform);
recalculateDimensions(elem);
call("selected", [elem]);
// addToSelection(elem]);
return;
// elem = $(elem).data('gsvg');
} else if($elem.data('symbol')) {
elem = $elem.data('symbol');
ts = $elem.attr('transform');
var pos = $elem.attr(['x','y']);
// Not ideal, but works
ts += "translate(" + pos.x + "," + pos.y + ")";
var prev = $elem.prev();
// Remove <use> element
batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].parentNode));
$elem.remove();
// See if other elements reference this symbol
var has_more = $(svgcontent).find('use:data(symbol)').length;
var g = svgdoc.createElementNS(svgns, "g");
var childs = elem.children;
for(var i = 0; i < childs.length; i++) {
g.appendChild(childs[i].cloneNode(true));
}
// while (elem.hasChildNodes())
// g.appendChild(elem.firstChild.cloneNode(true));
if (ts)
g.setAttribute("transform", ts);
var parent = elem.parentNode;
uniquifyElems(g);
// now give the g itself a new id
g.id = getNextId();
prev.after(g);
if(parent) {
if(!has_more) {
// remove symbol/svg element
parent.removeChild(elem);
batchCmd.addSubCommand(new RemoveElementCommand(elem, parent));
}
batchCmd.addSubCommand(new InsertElementCommand(g));
}
// recalculate dimensions on the top-level children so that unnecessary transforms
// are removed
walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}});
clearSelection();
addToSelection([g]);
addCommandToHistory(batchCmd);
} else {
console.log('Unexpected element to ungroup:', elem);
}
if(elem.tagName != 'svg') return;
var g = svgdoc.createElementNS(svgns, "g");
while (elem.hasChildNodes())
g.appendChild(elem.firstChild);
// if (ts)
// g.setAttribute("transform", ts);
var parent = elem.parentNode;
if(parent) parent.removeChild(elem);
uniquifyElems(g);
// now give the g itself a new id
g.id = getNextId();
current_layer.appendChild(g);
// change image href vals if possible
// $(svgcontent).find('image').each(function() {
// var image = this;
// preventClickDefault(image);
// var val = this.getAttributeNS(xlinkns, "href");
// if(val.indexOf('data:') === 0) {
// // Check if an SVG-edit data URI
// var m = val.match(/svgedit_url=(.*?);/);
// if(m) {
// var url = decodeURIComponent(m[1]);
// $(new Image()).load(function() {
// image.setAttributeNS(xlinkns,'xlink:href',url);
// }).attr('src',url);
// }
// }
// // Add to encodableImages if it loads
// canvas.embedImage(val);
// });
var batchCmd = new BatchCommand();
if(parent) {
batchCmd.addSubCommand(new RemoveElementCommand(elem, parent));
batchCmd.addSubCommand(new InsertElementCommand(g));
}
// recalculate dimensions on the top-level children so that unnecessary transforms
// are removed
walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}});
// batchCmd.addSubCommand(new InsertElementCommand(svgcontent));
// reset transform lists
// svgTransformLists = {};
clearSelection();
addToSelection([g]);
addCommandToHistory(batchCmd);
}
//
@@ -7996,6 +8010,16 @@ this.setSvgString = function(xmlString) {
}
});
// Set ref element for <use> elements
$(svgcontent).find('use').each(function() {
var id = this.getAttributeNS(xlinkns,"href").substr(1);
var ref_elem = getElem(id);
$(this).data('ref', ref_elem);
if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') {
$(this).data('symbol', ref_elem);
}
});
// convert gradients with userSpaceOnUse to objectBoundingBox
$(svgcontent).find('linearGradient, radialGradient').each(function() {
var grad = this;
@@ -8118,12 +8142,11 @@ this.setSvgString = function(xmlString) {
};
// Function: importSvgString
// This function imports the input SVG XML into the current layer in the drawing
// This function imports the input SVG XML as a <symbol> in the <defs>, then adds a
// <use> to the current layer.
//
// Parameters:
// xmlString - The SVG as XML text.
// toElements - Boolean indicating whether or not to convert the SVG to a group
// with children
//
// Returns:
// This function returns false if the import was unsuccessful, true otherwise.
@@ -8134,8 +8157,7 @@ this.setSvgString = function(xmlString) {
// arbitrary transform lists, but makes some assumptions about how the transform list
// was obtained
// * import should happen in top-left of current zoomed viewport
// * create a new layer for the imported SVG
this.importSvgString = function(xmlString, toElements) {
this.importSvgString = function(xmlString) {
try {
// convert string into XML document
var newDoc = Utils.text2xml(xmlString);
@@ -8145,11 +8167,11 @@ this.importSvgString = function(xmlString, toElements) {
var batchCmd = new BatchCommand("Change Source");
// import new svg document into our document
var importedNode = svgdoc.importNode(newDoc.documentElement, true);
var svg = svgdoc.importNode(newDoc.documentElement, true);
var innerw = convertToNum('width', importedNode.getAttribute("width")),
innerh = convertToNum('height', importedNode.getAttribute("height")),
innervb = importedNode.getAttribute("viewBox"),
var innerw = convertToNum('width', svg.getAttribute("width")),
innerh = convertToNum('height', svg.getAttribute("height")),
innervb = svg.getAttribute("viewBox"),
// if no explicit viewbox, create one out of the width and height
vb = innervb ? innervb.split(" ") : [0,0,innerw,innerh];
for (var j = 0; j < 4; ++j)
@@ -8169,32 +8191,39 @@ this.importSvgString = function(xmlString, toElements) {
// Hack to make recalculateDimensions understand how to scale
ts = "translate(0) " + ts + " translate(0)";
if(!toElements) {
var elem = $(importedNode).appendTo(current_layer)[0];
groupSvgElem(elem);
clearSelection();
var g = elem.parentNode;
g.setAttribute("transform", ts);
recalculateDimensions(g);
addToSelection([g]);
return;
}
var g = svgToGroup(importedNode);
// Uncomment this once Firefox has fixed their symbol bug:
// https://bugzilla.mozilla.org/show_bug.cgi?id=353575
// var symbol = svgdoc.createElementNS(svgns, "symbol");
// while (svg.firstChild) {
// symbol.appendChild(svg.firstChild);
// }
// var attrs = svg.attributes;
// for(var i=0; i < attrs.length; i++) {
// var attr = attrs[i];
// symbol.setAttribute(attr.nodeName, attr.nodeValue);
// }
var symbol = svg;
symbol.id = getNextId();
var use_el = svgdoc.createElementNS(svgns, "use");
use_el.setAttributeNS(xlinkns, "xlink:href", "#" + symbol.id);
findDefs().appendChild(symbol);
current_layer.appendChild(use_el);
clearSelection();
use_el.setAttribute("transform", ts);
recalculateDimensions(use_el);
$(use_el).data('symbol', symbol);
addToSelection([use_el]);
return true;
// TODO: Find way to add this in a recalculateDimensions-parsable way
// if (vb[0] != 0 || vb[1] != 0)
// ts = "translate(" + (-vb[0]) + "," + (-vb[1]) + ") " + ts;
// add all children of the imported <svg> to the <g> we create
call("changed", [svgcontent]);
} catch(e) {
console.log(e);
return false;
@@ -8698,8 +8727,7 @@ this.setConfig = function(opts) {
this.getTitle = function(elem) {
elem = elem || selectedElements[0];
if(!elem) return;
elem = $(elem).data('gsvg') || elem;
elem = $(elem).data('gsvg') || $(elem).data('symbol') || elem;
var childs = elem.childNodes;
for (var i=0; i<childs.length; i++) {
if(childs[i].nodeName == 'title') {
@@ -10009,16 +10037,16 @@ this.groupSelectedElements = function() {
// significant recalculations to apply group's transforms, etc to its children
this.ungroupSelectedElement = function() {
var g = selectedElements[0];
if($(g).data('gsvg') || $(g).data('symbol')) {
// Is svg, so actually convert to group
convertToGroup(g);
return;
}
if (g.tagName == "g") {
if($(g).data('gsvg')) {
// Is gsvg, so actually convert to group
svgToGroup(g);
return;
}
var batchCmd = new BatchCommand("Ungroup Elements");
var parent = g.parentNode;
var anchor = g.previousSibling;
var anchor = g.nextSibling;
var children = new Array(g.childNodes.length);
var xform = g.getAttribute("transform");
// get consolidated matrix