diff --git a/editor/extensions/ext-imagelib.js b/editor/extensions/ext-imagelib.js index d289f3a2..563b2631 100644 --- a/editor/extensions/ext-imagelib.js +++ b/editor/extensions/ext-imagelib.js @@ -110,7 +110,7 @@ svgEditor.addExtension("imagelib", function() { }); var back = $('').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) { $('
  • ').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('' + opts.description + ''); }); @@ -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 {\ diff --git a/editor/extensions/imagelib/smiley.svg b/editor/extensions/imagelib/smiley.svg index 36a7fef0..21a798d6 100644 --- a/editor/extensions/imagelib/smiley.svg +++ b/editor/extensions/imagelib/smiley.svg @@ -1,7 +1,12 @@ - - - Layer 1 - - + Cool smiley + + + + + + + + + \ No newline at end of file diff --git a/editor/images/svg_edit_icons.svg b/editor/images/svg_edit_icons.svg index 2255ba5e..26959c20 100644 --- a/editor/images/svg_edit_icons.svg +++ b/editor/images/svg_edit_icons.svg @@ -664,6 +664,23 @@ + + + + + + + + + + + + + + + + + diff --git a/editor/svg-editor.html b/editor/svg-editor.html index 44d607ed..cd69b312 100644 --- a/editor/svg-editor.html +++ b/editor/svg-editor.html @@ -359,10 +359,18 @@ script type="text/javascript" src="locale/locale.min.js"> -
    + +
    +
    +
    + + +
    + +
    diff --git a/editor/svg-editor.js b/editor/svg-editor.js index ad75d87d..c09127fd 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -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({ diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js index 197277ca..bb3079c0 100644 --- a/editor/svgcanvas.js +++ b/editor/svgcanvas.js @@ -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 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 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 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 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 in the , then adds a +// 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 to the 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