From 18253b5e5d997e30e3980ec1ca68aaef3a561a09 Mon Sep 17 00:00:00 2001 From: Jeff Schiller Date: Mon, 21 Sep 2009 22:16:44 +0000 Subject: [PATCH] Issue 73: A good deal of the plumbing is now down for layers. You can select the current layer in the layers panel and elements not on the current layer are not selectable. git-svn-id: http://svg-edit.googlecode.com/svn/trunk@669 eee81c28-f429-11dd-99c0-75d572ba1ddd --- editor/svg-editor.html | 4 +- editor/svg-editor.js | 19 ++++- editor/svgcanvas.js | 167 +++++++++++++++++++++++++++++++++++------ 3 files changed, 165 insertions(+), 25 deletions(-) diff --git a/editor/svg-editor.html b/editor/svg-editor.html index 7f854d8a..e3ba4899 100644 --- a/editor/svg-editor.html +++ b/editor/svg-editor.html @@ -45,7 +45,9 @@ diff --git a/editor/svg-editor.js b/editor/svg-editor.js index 0d68825a..67dd7b4c 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -742,6 +742,7 @@ function svg_edit_setup() { } svgCanvas.clearSelection(); hideSourceEditor(); + populateLayers(); }; var saveDocProperties = function(){ @@ -1068,6 +1069,22 @@ function svg_edit_setup() { $(this).removeClass('tool_flyout_button_current'); }); + var populateLayers = function(){ + var layerlen = svgCanvas.getNumLayers(); + $('#layerlist').empty(); + for (var layer = 0; layer < layerlen; ++layer) { + var name = svgCanvas.getLayer(layer); + $('#layerlist').append(""); + } + $('#layerlist option').mouseup(function(evt){ + $('#layerlist option').removeAttr("selected"); + var option = $(this); + option.attr("selected", "selected"); + svgCanvas.setCurrentLayer(option.attr("value")); + }); + }; + populateLayers(); + function changeResolution(x,y) { var new_res = x+'x'+y; var found = false; @@ -1134,7 +1151,7 @@ function svg_edit_setup() { svgCanvas.bind("saved", opts.save); } } - + return svgCanvas; }; diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js index 2124299d..afb78586 100644 --- a/editor/svgcanvas.js +++ b/editor/svgcanvas.js @@ -1,17 +1,14 @@ /* Issue 73 (Layers) TODO: -- when a layer option is selected, deselect all other layers -- when a layer option is double-clicked, pop up a 'rename' dialog? or provide a button? -- upon turning SVG text into a DOM, analyze all top-level elements that have a - and create layer options -- create a global variable for the currently selected layer, hold a reference to the <g> +- create API for SvgCanvas that allows the client to: + - change layer order + - create a layer + - delete a layer - when New/Delete are clicked, fire off a function - when creating a new layer, create a <g> with a <title>, set the current layer to the new one - when deleting a layer, delete all children of the <g> and then delete the <g> - ensure New/Delete are undo-able -- upon changing current layers, set pointer-events='none' on all elements in the old current layer - then pointer-events='all' on all elements in the newly selected layer - create a mouseover region on the sidepanels that is resizable and affects all children within - default the side panel to closed - add a button that opens the side panel? @@ -594,8 +591,8 @@ function BatchCommand(text) { svgroot.appendChild(svgzoom); var comment = svgdoc.createComment(" created with SVG-edit - http://svg-edit.googlecode.com/ "); svgzoom.appendChild(comment); - // associative array of layer names to <g> elements - var all_layers = {}; + // z-ordered array of tuples containing layer names and <g> elements + var all_layers = []; // pointer to the current layer <g> var current_layer = null; @@ -1466,7 +1463,8 @@ function BatchCommand(text) { "stroke-opacity": cur_shape.stroke_opacity, "stroke-linecap": "round", "stroke-linejoin": "round", - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); freehand_min_x = x; @@ -1486,7 +1484,8 @@ function BatchCommand(text) { "width": 0, "height": 0, "id": getNextId(), - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); newImage.setAttributeNS(xlinkns, "href", "images/logo.png"); @@ -1512,7 +1511,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "stroke-opacity": cur_shape.stroke_opacity, "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); break; @@ -1532,7 +1532,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "stroke-opacity": cur_shape.stroke_opacity, "fill": "none", - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); break; @@ -1551,7 +1552,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "stroke-opacity": cur_shape.stroke_opacity, "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); break; @@ -1571,7 +1573,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "stroke-opacity": cur_shape.stroke_opacity, "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); break; @@ -1593,7 +1596,8 @@ function BatchCommand(text) { "opacity": cur_shape.opacity, "font-size": cur_text.font_size, "font-family": cur_text.font_family, - "text-anchor": "middle" + "text-anchor": "middle", + "style": "pointer-events:all" } }); newText.textContent = "text"; @@ -2034,7 +2038,7 @@ function BatchCommand(text) { 'stroke': "#00F", 'stroke-width': 2, 'cursor': 'move', - "pointer-events": "all" + 'style': 'pointer-events:all' }); pointGrip = pointGripContainer.appendChild(pointGrip); @@ -2214,7 +2218,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "opacity": cur_shape.opacity, "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity + "fill-opacity": cur_shape.fill_opacity, + "style": "pointer-events:all" } }); call("changed",[element]); @@ -2238,7 +2243,8 @@ function BatchCommand(text) { "stroke-dasharray": cur_shape.stroke_style, "opacity": cur_shape.opacity, "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity + "fill-opacity": cur_shape.fill_opacity, + "style": "pointer-events:all" } }); call("changed",[element]); @@ -2282,7 +2288,8 @@ function BatchCommand(text) { "stroke-width": cur_shape.stroke_width, "stroke-dasharray": cur_shape.stroke_style, "stroke-opacity": cur_shape.stroke_opacity, - "opacity": cur_shape.opacity / 2 + "opacity": cur_shape.opacity / 2, + "style": "pointer-events:all" } }); // set stretchy line to first point @@ -2515,6 +2522,16 @@ function BatchCommand(text) { call("saved", str); }; + var walkTree = function(elem, cbFn){ + if (elem && elem.nodeType == 1) { + cbFn(elem); + var i = elem.childNodes.length; + while (i--) { + walkTree(elem.childNodes.item(i), cbFn); + } + } + }; + this.getSvgString = function() { return svgCanvasToString(); }; @@ -2568,7 +2585,25 @@ function BatchCommand(text) { current_zoom = 1; // identify layers - + all_layers = []; + var numchildren = svgzoom.childNodes.length; + // loop through all children of svgzoom + for (var i = 0; i < numchildren; ++i) { + var child = svgzoom.childNodes.item(i); + // for each g, find its layer name + if (child && child.tagName == "g") { + var name = getLayerName(child); + // store layer and name in global variable + if (name) { + all_layers.push( [name,child] ); + current_layer = child; + walkTree(child, function(e){e.setAttribute("style", "pointer-events:none");}); + } + } + } + console.dir(all_layers); + walkTree(current_layer, function(e){e.setAttribute("style","pointer-events:all");}); + selectorManager.update(); addCommandToHistory(batchCmd); @@ -2581,6 +2616,92 @@ function BatchCommand(text) { return true; }; + // Layer API Functions + // TODO: change layer order + // TODO: create a layer + // TODO: delete a layer + this.getNumLayers = function() { + return all_layers.length; + }; + this.getLayer = function(i) { + if (i >= 0 && i < canvas.getNumLayers()) { + return all_layers[i][0]; + } + return ""; + }; + this.getCurrentLayer = function() { + for (var i = 0; i < all_layers.length; ++i) { + if (all_layers[i][1] == current_layer) { + return all_layers[i][0]; + } + } + return ""; + }; + this.setCurrentLayer = function(name) { + for (var i = 0; i < all_layers.length; ++i) { + if (name == all_layers[i][0]) { + if (current_layer != all_layers[i][1]) { + walkTree(current_layer,function(e){e.setAttribute("style","pointer-events:none");}); + current_layer = all_layers[i][1]; + walkTree(current_layer,function(e){e.setAttribute("style","pointer-events:all");}); + } + return true; + } + } + return false; + }; + this.renameLayer = function(oldname, newname) { + var rememberCurrentLayer = current_layer; + if (canvas.setCurrentLayer(oldname)) { + var oldLayer = current_layer; + // setCurrentLayer will return false if the name doesn't already exists + if (!canvas.setCurrentLayer(newname)) { + // find the index of the layer + for (var i = 0; i < all_layers.length; ++i) { + if (all_layers[i][1] == oldLayer) break; + } + all_layers[i][0] = newname; + + // now change the underlying title element contents + var len = oldLayer.childNodes.length; + for (var i = 0; i < len; ++i) { + var child = oldLayer.childNodes.item(i); + // found the <title> element, now append all the + if (child && child.tagName == "title") { + // wipe out old name + // TODO: make this undo-able + while (child.firstChild) { child.removeChild(child.firstChild); } + child.appendChild( svgdoc.createTextNode(newname) ); + return true; + } + } + } + } + return false; + }; + // used internally + var getLayerName = function(g) { + var name = ""; + if (g && g.tagName == "g") { + var len = g.childNodes.length; + for (var i = 0; i < len; ++i) { + var child = g.childNodes.item(i); + // found the <title> element, now append all the + if (child && child.tagName == "title") { + var tlen = child.childNodes.length; + for (var j = 0; j < tlen; ++j) { + var textNode = child.childNodes.item(j); + if (textNode.nodeType == 3) { + name += textNode.nodeValue; + } + } + break; + } + } + } + return name; + }; + this.clear = function() { current_poly_pts = []; @@ -2602,8 +2723,8 @@ function BatchCommand(text) { layer_title.appendChild(svgdoc.createTextNode("Layer 1")); current_layer.appendChild(layer_title); current_layer = svgzoom.appendChild(current_layer); - all_layers = {}; - all_layers["Layer 1"] = current_layer; + all_layers = []; + all_layers[0] = ["Layer 1",current_layer]; // clear the undo stack resetUndoStack();