Made various code optimizations, removing several global and SvgCanvas variables. Also made all keyboard shortcuts preventDefault

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1126 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Alexis Deveria 2009-12-29 21:20:45 +00:00
parent 9086e13901
commit 4ba0d002f0
2 changed files with 99 additions and 88 deletions

View File

@ -2111,7 +2111,11 @@ function svg_edit_setup() {
$.each(keyval.split('/'), function(i, key) { $.each(keyval.split('/'), function(i, key) {
$(document).bind('keydown', {combi: key, disableInInput: disInInp}, function(e) { $(document).bind('keydown', {combi: key, disableInInput: disInInp}, function(e) {
fn(); fn();
if(pd) e.preventDefault(); if(pd) {
e.preventDefault();
}
// Prevent default on ALL keys?
return false;
}); });
}); });

View File

@ -16,16 +16,21 @@
* ensure undo/redo works perfectly * ensure undo/redo works perfectly
*/ */
var isOpera = !!window.opera;
var isWebkit = navigator.userAgent.indexOf("AppleWebKit") != -1;
if(!window.console) { if(!window.console) {
window.console = {}; window.console = {};
window.console.log = function(str) {}; window.console.log = function(str) {};
window.console.dir = function(str) {}; window.console.dir = function(str) {};
if(window.opera) {
window.console.log = function(str) {opera.postError(str);}
}
} }
if( isOpera ) {
window.console.log = function(str) {opera.postError(str);} function SvgCanvas(container)
} {
var isOpera = !!window.opera;
var isWebkit = navigator.userAgent.indexOf("AppleWebKit") != -1;
var uiStrings = { var uiStrings = {
"pathNodeTooltip":"Drag node to move it. Double-click node to change segment type", "pathNodeTooltip":"Drag node to move it. Double-click node to change segment type",
@ -58,11 +63,9 @@ var svgWhiteList = {
"switch": ["id", "requiredFeatures", "systemLanguage"], "switch": ["id", "requiredFeatures", "systemLanguage"],
"svg": ["id", "height", "requiredFeatures", "systemLanguage", "transform", "viewBox", "width", "xmlns", "xmlns:xlink"], "svg": ["id", "height", "requiredFeatures", "systemLanguage", "transform", "viewBox", "width", "xmlns", "xmlns:xlink"],
"text": ["fill", "fill-opacity", "fill-rule", "font-family", "font-size", "font-style", "font-weight", "id", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "transform", "text-anchor", "x", "xml:space", "y"], "text": ["fill", "fill-opacity", "fill-rule", "font-family", "font-size", "font-style", "font-weight", "id", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "transform", "text-anchor", "x", "xml:space", "y"],
"title": [], "title": []
}; };
function SvgCanvas(c)
{
// console.log('Start profiling') // console.log('Start profiling')
// setTimeout(function() { // setTimeout(function() {
@ -83,9 +86,11 @@ var fromXml = function(str) {
return $('<p/>').html(str).text(); return $('<p/>').html(str).text();
}; };
var pathFuncsStrs = ['Moveto','Lineto','CurvetoCubic','CurvetoQuadratic','Arc','LinetoHorizontal','LinetoVertical','CurvetoCubicSmooth','CurvetoQuadraticSmooth']
var pathFuncs = [0,'ClosePath']; var pathFuncs = [0,'ClosePath'];
$.each(pathFuncsStrs,function(i,s){pathFuncs.push(s+'Abs');pathFuncs.push(s+'Rel');}); (function() {
var pathFuncsStrs = ['Moveto','Lineto','CurvetoCubic','CurvetoQuadratic','Arc','LinetoHorizontal','LinetoVertical','CurvetoCubicSmooth','CurvetoQuadraticSmooth'];
$.each(pathFuncsStrs,function(i,s){pathFuncs.push(s+'Abs');pathFuncs.push(s+'Rel');});
}());
// These command objects are used for the Undo/Redo stack // These command objects are used for the Undo/Redo stack
// attrs contains the values that the attributes had before the change // attrs contains the values that the attributes had before the change
@ -94,14 +99,14 @@ function ChangeElementCommand(elem, attrs, text) {
this.text = text ? ("Change " + elem.tagName + " " + text) : ("Change " + elem.tagName); this.text = text ? ("Change " + elem.tagName + " " + text) : ("Change " + elem.tagName);
this.newValues = {}; this.newValues = {};
this.oldValues = attrs; this.oldValues = attrs;
for (attr in attrs) { for (var attr in attrs) {
if (attr == "#text") this.newValues[attr] = elem.textContent; if (attr == "#text") this.newValues[attr] = elem.textContent;
else this.newValues[attr] = elem.getAttribute(attr); else this.newValues[attr] = elem.getAttribute(attr);
} }
this.apply = function() { this.apply = function() {
var bChangedTransform = false; var bChangedTransform = false;
for( attr in this.newValues ) { for(var attr in this.newValues ) {
if (this.newValues[attr]) { if (this.newValues[attr]) {
if (attr == "#text") this.elem.textContent = this.newValues[attr]; if (attr == "#text") this.elem.textContent = this.newValues[attr];
else this.elem.setAttribute(attr, this.newValues[attr]); else this.elem.setAttribute(attr, this.newValues[attr]);
@ -137,7 +142,7 @@ function ChangeElementCommand(elem, attrs, text) {
this.unapply = function() { this.unapply = function() {
var bChangedTransform = false; var bChangedTransform = false;
for( attr in this.oldValues ) { for(var attr in this.oldValues ) {
if (this.oldValues[attr]) { if (this.oldValues[attr]) {
if (attr == "#text") this.elem.textContent = this.oldValues[attr]; if (attr == "#text") this.elem.textContent = this.oldValues[attr];
else this.elem.setAttribute(attr, this.oldValues[attr]); else this.elem.setAttribute(attr, this.oldValues[attr]);
@ -363,7 +368,7 @@ function BatchCommand(text) {
}) ); }) );
// add the corner grips // add the corner grips
for (dir in this.selectorGrips) { for (var dir in this.selectorGrips) {
this.selectorGrips[dir] = this.selectorGroup.appendChild( this.selectorGrips[dir] = this.selectorGroup.appendChild(
addSvgElementFromJson({ addSvgElementFromJson({
"element": "circle", "element": "circle",
@ -389,7 +394,7 @@ function BatchCommand(text) {
this.rotateGrip.setAttribute("display", bShow); this.rotateGrip.setAttribute("display", bShow);
this.rotateGripConnector.setAttribute("display", bShow); this.rotateGripConnector.setAttribute("display", bShow);
var elem = this.selectedElement; var elem = this.selectedElement;
for (dir in this.selectorGrips) { for (var dir in this.selectorGrips) {
this.selectorGrips[dir].setAttribute("display", bShow); this.selectorGrips[dir].setAttribute("display", bShow);
} }
if(elem) this.updateGripCursors(canvas.getRotationAngle(elem)); if(elem) this.updateGripCursors(canvas.getRotationAngle(elem));
@ -400,7 +405,7 @@ function BatchCommand(text) {
var dir_arr = []; var dir_arr = [];
var steps = Math.round(angle / 45); var steps = Math.round(angle / 45);
if(steps < 0) steps += 8; if(steps < 0) steps += 8;
for (dir in this.selectorGrips) { for (var dir in this.selectorGrips) {
dir_arr.push(dir); dir_arr.push(dir);
} }
while(steps > 0) { while(steps > 0) {
@ -408,7 +413,7 @@ function BatchCommand(text) {
steps--; steps--;
} }
var i = 0; var i = 0;
for (dir in this.selectorGrips) { for (var dir in this.selectorGrips) {
this.selectorGrips[dir].setAttribute('style', ("cursor:" + dir_arr[i] + "-resize")); this.selectorGrips[dir].setAttribute('style', ("cursor:" + dir_arr[i] + "-resize"));
i++; i++;
}; };
@ -510,7 +515,7 @@ function BatchCommand(text) {
}; };
if(selected == selectedElements[0]) { if(selected == selectedElements[0]) {
for(dir in gripCoords) { for(var dir in gripCoords) {
var coords = gripCoords[dir]; var coords = gripCoords[dir];
assignAttributes(selectedGrips[dir], { assignAttributes(selectedGrips[dir], {
cx: coords[0], cy: coords[1] cx: coords[0], cy: coords[1]
@ -799,7 +804,7 @@ function BatchCommand(text) {
var handle = null; var handle = null;
if (!window.opera) svgroot.suspendRedraw(suspendLength); if (!window.opera) svgroot.suspendRedraw(suspendLength);
for (i in attrs) { for (var i in attrs) {
var ns = (i.substr(0,4) == "xml:" ? xmlns : var ns = (i.substr(0,4) == "xml:" ? xmlns :
i.substr(0,6) == "xlink:" ? xlinkns : null); i.substr(0,6) == "xlink:" ? xlinkns : null);
node.setAttributeNS(ns, i, attrs[i]); node.setAttributeNS(ns, i, attrs[i]);
@ -812,24 +817,24 @@ function BatchCommand(text) {
// makes resulting SVG smaller // makes resulting SVG smaller
var cleanupElement = function(element) { var cleanupElement = function(element) {
var handle = svgroot.suspendRedraw(60); var handle = svgroot.suspendRedraw(60);
if (element.getAttribute('fill-opacity') == '1') var defaults = {
element.removeAttribute('fill-opacity'); 'fill-opacity':1,
if (element.getAttribute('opacity') == '1') 'opacity':1,
element.removeAttribute('opacity'); 'stroke':'none',
if (element.getAttribute('stroke') == 'none') 'stroke-dasharray':'none',
element.removeAttribute('stroke'); 'stroke-opacity':1,
if (element.getAttribute('stroke-dasharray') == 'none') 'stroke-width':1,
element.removeAttribute('stroke-dasharray'); 'rx':0,
if (element.getAttribute('stroke-opacity') == '1') 'ry':0,
element.removeAttribute('stroke-opacity'); 'display':'inline'
if (element.getAttribute('stroke-width') == '1') }
element.removeAttribute('stroke-width'); for(var attr in defaults) {
if (element.getAttribute('rx') == '0') var val = defaults[attr];
element.removeAttribute('rx') if(element.getAttribute(attr) == val) {
if (element.getAttribute('ry') == '0') element.removeAttribute(attr);
element.removeAttribute('ry') }
if (element.getAttribute('display') == 'inline') }
element.removeAttribute('display');
svgroot.unsuspendRedraw(handle); svgroot.unsuspendRedraw(handle);
}; };
@ -854,12 +859,11 @@ function BatchCommand(text) {
// TODO: declare the variables and set them as null, then move this setup stuff to // TODO: declare the variables and set them as null, then move this setup stuff to
// an initialization function - probably just use clear() // an initialization function - probably just use clear()
var canvas = this; var canvas = this;
var container = c;
var svgns = "http://www.w3.org/2000/svg"; var svgns = "http://www.w3.org/2000/svg";
var xlinkns = "http://www.w3.org/1999/xlink"; var xlinkns = "http://www.w3.org/1999/xlink";
var xmlns = "http://www.w3.org/XML/1998/namespace"; var xmlns = "http://www.w3.org/XML/1998/namespace";
var idprefix = "svg_"; var idprefix = "svg_";
var svgdoc = c.ownerDocument; var svgdoc = container.ownerDocument;
var svgroot = svgdoc.createElementNS(svgns, "svg"); var svgroot = svgdoc.createElementNS(svgns, "svg");
svgroot.setAttribute("width", 640); svgroot.setAttribute("width", 640);
svgroot.setAttribute("height", 480); svgroot.setAttribute("height", 480);
@ -873,16 +877,20 @@ function BatchCommand(text) {
svgcontent.setAttribute("xmlns", svgns); svgcontent.setAttribute("xmlns", svgns);
svgcontent.setAttribute("xmlns:xlink", xlinkns); svgcontent.setAttribute("xmlns:xlink", xlinkns);
svgroot.appendChild(svgcontent); svgroot.appendChild(svgcontent);
// TODO: make this string optional and set by the client
// TODO: make sure this is always at the top of the SVG file right underneath the <svg> element (function() {
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); // TODO: make this string optional and set by the client
svgcontent.appendChild(comment); var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
// TODO For Issue 208: this is a start on a thumbnail svgcontent.appendChild(comment);
// var svgthumb = svgdoc.createElementNS(svgns, "use");
// svgthumb.setAttribute('width', '100'); // TODO For Issue 208: this is a start on a thumbnail
// svgthumb.setAttribute('height', '100'); // var svgthumb = svgdoc.createElementNS(svgns, "use");
// svgthumb.setAttributeNS(xlinkns, 'href', '#svgcontent'); // svgthumb.setAttribute('width', '100');
// svgroot.appendChild(svgthumb); // svgthumb.setAttribute('height', '100');
// svgthumb.setAttributeNS(xlinkns, 'href', '#svgcontent');
// svgroot.appendChild(svgthumb);
});
// z-ordered array of tuples containing layer names and <g> elements // z-ordered array of tuples containing layer names and <g> elements
// the first layer is the one at the bottom of the rendering // the first layer is the one at the bottom of the rendering
var all_layers = []; var all_layers = [];
@ -927,10 +935,13 @@ function BatchCommand(text) {
var cur_text = all_properties.text; var cur_text = all_properties.text;
var cur_properties = cur_shape; var cur_properties = cur_shape;
var freehand_min_x = null; var freehand = {
var freehand_max_x = null; minx: null,
var freehand_min_y = null; miny: null,
var freehand_max_y = null; maxx: null,
maxy: null
};
var current_path = null; var current_path = null;
var current_path_pts = []; var current_path_pts = [];
var current_path_pt = -1; var current_path_pt = -1;
@ -1158,7 +1169,7 @@ function BatchCommand(text) {
var attr; var attr;
var i; var i;
var childs = elem.childNodes; var childs = elem.childNodes;
for (i=0; i<indent; i++) out.push(" "); for (var i=0; i<indent; i++) out.push(" ");
out.push("<"); out.push(elem.nodeName); out.push("<"); out.push(elem.nodeName);
if(elem.id == 'svgcontent') { if(elem.id == 'svgcontent') {
// Process root element separately; Prevents errors caused // Process root element separately; Prevents errors caused
@ -1167,7 +1178,7 @@ function BatchCommand(text) {
out.push(' width="' + res.w + '" height="' + res.h out.push(' width="' + res.w + '" height="' + res.h
+ '" xmlns:xlink="'+xlinkns+'" xmlns="'+svgns+'"'); + '" xmlns:xlink="'+xlinkns+'" xmlns="'+svgns+'"');
} else { } else {
for (i=attrs.length-1; i>=0; i--) { for (var i=attrs.length-1; i>=0; i--) {
attr = attrs.item(i); attr = attrs.item(i);
var attrVal = attr.nodeValue; var attrVal = attr.nodeValue;
@ -1210,7 +1221,7 @@ function BatchCommand(text) {
out.push(">"); out.push(">");
indent++; indent++;
var bOneLine = false; var bOneLine = false;
for (i=0; i<childs.length; i++) for (var i=0; i<childs.length; i++)
{ {
var child = childs.item(i); var child = childs.item(i);
if (child.id == "selectorParentGroup") continue; if (child.id == "selectorParentGroup") continue;
@ -1238,7 +1249,7 @@ function BatchCommand(text) {
indent--; indent--;
if (!bOneLine) { if (!bOneLine) {
out.push("\n"); out.push("\n");
for (i=0; i<indent; i++) out.push(" "); for (var i=0; i<indent; i++) out.push(" ");
} }
out.push("</"); out.push(elem.nodeName); out.push(">"); out.push("</"); out.push(elem.nodeName); out.push(">");
} else { } else {
@ -1322,10 +1333,7 @@ function BatchCommand(text) {
}; };
// this is how we map paths to our preferred relative segment types // this is how we map paths to our preferred relative segment types
var pathMap = [ 0, 'z', 'M', 'M', 'L', 'L', 'C', 'C', 'Q', 'Q', 'A', 'A', var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'L', 'L', 'L', 'L', // TODO: be less lazy below and map them to h and v
'S', 'S', 'T', 'T' ];
var truePathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; 'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
var logMatrix = function(m) { var logMatrix = function(m) {
@ -1466,7 +1474,7 @@ function BatchCommand(text) {
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
var seg = changes["d"][i]; var seg = changes["d"][i];
var type = seg.type; var type = seg.type;
dstr += truePathMap[type]; dstr += pathMap[type];
switch(type) { switch(type) {
case 13: // relative horizontal line (h) case 13: // relative horizontal line (h)
case 12: // absolute horizontal line (H) case 12: // absolute horizontal line (H)
@ -2182,7 +2190,6 @@ function BatchCommand(text) {
// Some global variables that we may need to refactor // Some global variables that we may need to refactor
var root_sctm = null; var root_sctm = null;
var mouse_target = null;
// A (hopefully) quicker function to transform a point by a matrix // A (hopefully) quicker function to transform a point by a matrix
// (this function avoids any DOM calls and just does the math) // (this function avoids any DOM calls and just does the math)
@ -2356,7 +2363,7 @@ function BatchCommand(text) {
start_y = y; start_y = y;
// find mouse target // find mouse target
mouse_target = evt.target; var mouse_target = evt.target;
// go up until we hit a child of a layer // go up until we hit a child of a layer
while (mouse_target.parentNode.parentNode.tagName == "g") { while (mouse_target.parentNode.parentNode.tagName == "g") {
mouse_target = mouse_target.parentNode; mouse_target = mouse_target.parentNode;
@ -2494,10 +2501,10 @@ function BatchCommand(text) {
"style": "pointer-events:none" "style": "pointer-events:none"
} }
}); });
freehand_min_x = x; freehand.minx = x;
freehand_max_x = x; freehand.maxx = x;
freehand_min_y = y; freehand.miny = y;
freehand_max_y = y; freehand.miny = y;
break; break;
case "image": case "image":
started = true; started = true;
@ -2804,7 +2811,7 @@ function BatchCommand(text) {
} }
len = newList.length; len = newList.length;
for (i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); } for (var i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); }
if (elemsToRemove.length > 0) if (elemsToRemove.length > 0)
canvas.removeFromSelection(elemsToRemove); canvas.removeFromSelection(elemsToRemove);
@ -2945,10 +2952,10 @@ function BatchCommand(text) {
break; break;
case "fhellipse": case "fhellipse":
case "fhrect": case "fhrect":
freehand_min_x = Math.min(x, freehand_min_x); freehand.minx = Math.min(x, freehand.minx);
freehand_max_x = Math.max(x, freehand_max_x); freehand.maxx = Math.max(x, freehand.maxx);
freehand_min_y = Math.min(y, freehand_min_y); freehand.miny = Math.min(y, freehand.miny);
freehand_max_y = Math.max(y, freehand_max_y); freehand.maxy = Math.max(y, freehand.maxy);
// break; missing on purpose // break; missing on purpose
case "fhpath": case "fhpath":
start_x = x; start_x = x;
@ -4089,15 +4096,15 @@ function BatchCommand(text) {
keep = (element.rx.baseVal.value && element.ry.baseVal.value); keep = (element.rx.baseVal.value && element.ry.baseVal.value);
break; break;
case "fhellipse": case "fhellipse":
if ((freehand_max_x - freehand_min_x) > 0 && if ((freehand.maxx - freehand.minx) > 0 &&
(freehand_max_y - freehand_min_y) > 0) { (freehand.maxy - freehand.miny) > 0) {
element = addSvgElementFromJson({ element = addSvgElementFromJson({
"element": "ellipse", "element": "ellipse",
"attr": { "attr": {
"cx": (freehand_min_x + freehand_max_x) / 2, "cx": (freehand.minx + freehand.maxx) / 2,
"cy": (freehand_min_y + freehand_max_y) / 2, "cy": (freehand.miny + freehand.maxy) / 2,
"rx": (freehand_max_x - freehand_min_x) / 2, "rx": (freehand.maxx - freehand.minx) / 2,
"ry": (freehand_max_y - freehand_min_y) / 2, "ry": (freehand.maxy - freehand.miny) / 2,
"id": getId(), "id": getId(),
"fill": cur_shape.fill, "fill": cur_shape.fill,
"stroke": cur_shape.stroke, "stroke": cur_shape.stroke,
@ -4119,10 +4126,10 @@ function BatchCommand(text) {
element = addSvgElementFromJson({ element = addSvgElementFromJson({
"element": "rect", "element": "rect",
"attr": { "attr": {
"x": freehand_min_x, "x": freehand.minx,
"y": freehand_min_y, "y": freehand.miny,
"width": (freehand_max_x - freehand_min_x), "width": (freehand.maxx - freehand.minx),
"height": (freehand_max_y - freehand_min_y), "height": (freehand.maxy - freehand.miny),
"id": getId(), "id": getId(),
"fill": cur_shape.fill, "fill": cur_shape.fill,
"stroke": cur_shape.stroke, "stroke": cur_shape.stroke,
@ -5690,7 +5697,7 @@ function BatchCommand(text) {
call("changed", [current_path]); call("changed", [current_path]);
} }
this.quickClone = function(elem) { var ffClone = function(elem) {
// Hack for Firefox bugs where text element features aren't updated // Hack for Firefox bugs where text element features aren't updated
if(navigator.userAgent.indexOf('Gecko/') == -1) return elem; if(navigator.userAgent.indexOf('Gecko/') == -1) return elem;
var clone = elem.cloneNode(true) var clone = elem.cloneNode(true)
@ -5763,7 +5770,7 @@ function BatchCommand(text) {
if (attr == "#text") { if (attr == "#text") {
var old_w = canvas.getBBox(elem).width; var old_w = canvas.getBBox(elem).width;
elem.textContent = newValue; elem.textContent = newValue;
elem = canvas.quickClone(elem); elem = ffClone(elem);
// Hoped to solve the issue of moving text with text-anchor="start", // Hoped to solve the issue of moving text with text-anchor="start",
// but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd
@ -5787,11 +5794,11 @@ function BatchCommand(text) {
else elem.setAttribute(attr, newValue); else elem.setAttribute(attr, newValue);
if (i==0) if (i==0)
selectedBBoxes[i] = this.getBBox(elem); selectedBBoxes[i] = this.getBBox(elem);
// Use the Firefox quickClone hack for text elements with gradients or // Use the Firefox ffClone hack for text elements with gradients or
// where other text attributes are changed. // where other text attributes are changed.
if(elem.nodeName == 'text') { if(elem.nodeName == 'text') {
if((newValue+'').indexOf('url') == 0 || $.inArray(attr, ['font-size','font-family','x','y']) != -1) { if((newValue+'').indexOf('url') == 0 || $.inArray(attr, ['font-size','font-family','x','y']) != -1) {
elem = canvas.quickClone(elem); elem = ffClone(elem);
} }
} }
// Timeout needed for Opera & Firefox // Timeout needed for Opera & Firefox