diff --git a/public/svg-edit/editor/browser.js b/public/svg-edit/editor/browser.js
index 57f5598f..960ef953 100644
--- a/public/svg-edit/editor/browser.js
+++ b/public/svg-edit/editor/browser.js
@@ -17,7 +17,6 @@ var svgedit = svgedit || {};
if (!svgedit.browser) {
svgedit.browser = {};
}
-
var supportsSvg_ = (function() {
return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
})();
@@ -35,6 +34,7 @@ var svg = document.createElementNS(svgns, 'svg');
var isOpera_ = !!window.opera;
var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0;
var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
+var isIE_ = userAgent.indexOf('MSIE') >= 0;
var supportsSelectors_ = (function() {
return !!svg.querySelector;
@@ -69,20 +69,20 @@ var supportsPathInsertItemBefore_ = (function() {
return false;
})();
-// text character positioning
-var supportsTextCharPos_ = (function() {
+// text character positioning (for IE9)
+var supportsGoodTextCharPos_ = (function() {
var retValue = false;
+ var svgroot = document.createElementNS(svgns, 'svg');
var svgcontent = document.createElementNS(svgns, 'svg');
- document.documentElement.appendChild(svgcontent);
- try {
- var text = document.createElementNS(svgns,'text');
- text.textContent = 'a';
- svgcontent.appendChild(text);
- text.getStartPositionOfChar(0);
- retValue = true;
- } catch(err) {}
- document.documentElement.removeChild(svgcontent);
- return retValue;
+ document.documentElement.appendChild(svgroot);
+ svgcontent.setAttribute('x', 5);
+ svgroot.appendChild(svgcontent);
+ var text = document.createElementNS(svgns,'text');
+ text.textContent = 'a';
+ svgcontent.appendChild(text);
+ var pos = text.getStartPositionOfChar(0).x;
+ document.documentElement.removeChild(svgroot);
+ return (pos === 0);
})();
var supportsPathBBox_ = (function() {
@@ -96,6 +96,24 @@ var supportsPathBBox_ = (function() {
return (bbox.height > 4 && bbox.height < 5);
})();
+// Support for correct bbox sizing on groups with horizontal/vertical lines
+var supportsHVLineContainerBBox_ = (function() {
+ var svgcontent = document.createElementNS(svgns, 'svg');
+ document.documentElement.appendChild(svgcontent);
+ var path = document.createElementNS(svgns, 'path');
+ path.setAttribute('d','M0,0 10,0');
+ var path2 = document.createElementNS(svgns, 'path');
+ path2.setAttribute('d','M5,0 15,0');
+ var g = document.createElementNS(svgns, 'g');
+ g.appendChild(path);
+ g.appendChild(path2);
+ svgcontent.appendChild(g);
+ var bbox = g.getBBox();
+ document.documentElement.removeChild(svgcontent);
+ // Webkit gives 0, FF gives 10, Opera (correctly) gives 15
+ return (bbox.width == 15);
+})();
+
var supportsEditableText_ = (function() {
// TODO: Find better way to check support for this
return isOpera_;
@@ -134,6 +152,7 @@ var supportsNativeSVGTransformLists_ = (function() {
svgedit.browser.isOpera = function() { return isOpera_; }
svgedit.browser.isWebkit = function() { return isWebkit_; }
svgedit.browser.isGecko = function() { return isGecko_; }
+svgedit.browser.isIE = function() { return isIE_; }
svgedit.browser.supportsSelectors = function() { return supportsSelectors_; }
svgedit.browser.supportsXpath = function() { return supportsXpath_; }
@@ -141,7 +160,8 @@ svgedit.browser.supportsXpath = function() { return supportsXpath_; }
svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; }
svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; }
svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; }
-svgedit.browser.supportsTextCharPos = function() { return supportsTextCharPos_; }
+svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; }
+svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; }
svgedit.browser.supportsEditableText = function() { return supportsEditableText_; }
svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; }
svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; }
diff --git a/public/svg-edit/editor/draw.js b/public/svg-edit/editor/draw.js
index f3152633..8db3138b 100644
--- a/public/svg-edit/editor/draw.js
+++ b/public/svg-edit/editor/draw.js
@@ -23,6 +23,9 @@ var svg_ns = "http://www.w3.org/2000/svg";
var se_ns = "http://svg-edit.googlecode.com";
var xmlns_ns = "http://www.w3.org/2000/xmlns/";
+var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use';
+var visElems_arr = visElems.split(',');
+
var RandomizeModes = {
LET_DOCUMENT_DECIDE: 0,
ALWAYS_RANDOMIZE: 1,
@@ -375,8 +378,8 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
orphans.push(child);
}
}
- // if child has a bbox (i.e. not a
or element), then it is an orphan
- else if(svgedit.utilities.getBBox(child) && child.nodeName != 'defs') { // Opera returns a BBox for defs
+ // if child has is "visible" (i.e. not a or element), then it is an orphan
+ else if(~visElems_arr.indexOf(child.nodeName)) {
var bb = svgedit.utilities.getBBox(child);
orphans.push(child);
}
diff --git a/public/svg-edit/editor/history.js b/public/svg-edit/editor/history.js
index d5edda2e..47678768 100644
--- a/public/svg-edit/editor/history.js
+++ b/public/svg-edit/editor/history.js
@@ -224,7 +224,7 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
svgedit.transformlist.removeElementFromListMap(this.elem);
if(this.nextSibling == null) {
- console.log('Error: reference element was lost');
+ if(window.console) console.log('Error: reference element was lost');
}
this.parent.insertBefore(this.elem, this.nextSibling);
diff --git a/public/svg-edit/editor/locale/locale.js b/public/svg-edit/editor/locale/locale.js
index e480a2ae..9538905e 100644
--- a/public/svg-edit/editor/locale/locale.js
+++ b/public/svg-edit/editor/locale/locale.js
@@ -304,15 +304,15 @@ var svgEditor = (function($, Editor) {
var url = conf.langPath + "lang." + lang_param + ".js";
- $.ajax({
- 'url': url,
- 'dataType': "script",
- error: function(xhr) {
- if(xhr.responseText) {
- Editor.readLang(eval(xhr.responseText));
- }
+ $.getScript(url, function(d) {
+ // Fails locally in Chrome 5+
+ if(!d) {
+ var s = document.createElement('script');
+ s.src = url;
+ document.querySelector('head').appendChild(s);
}
});
+
};
return Editor;
diff --git a/public/svg-edit/editor/math.js b/public/svg-edit/editor/math.js
index d69bc3f1..86ee4cf5 100644
--- a/public/svg-edit/editor/math.js
+++ b/public/svg-edit/editor/math.js
@@ -183,6 +183,20 @@ svgedit.math.transformListToTransform = function(tlist, min, max) {
};
+// Function: svgedit.math.getMatrix
+// Get the matrix object for a given element
+//
+// Parameters:
+// elem - The DOM element to check
+//
+// Returns:
+// The matrix object associated with the element's transformlist
+svgedit.math.getMatrix = function(elem) {
+ var tlist = svgedit.transformlist.getTransformList(elem);
+ return svgedit.math.transformListToTransform(tlist).matrix;
+};
+
+
// Function: svgedit.math.snapToAngle
// Returns a 45 degree angle coordinate associated with the two given
// coordinates
diff --git a/public/svg-edit/editor/path.js b/public/svg-edit/editor/path.js
new file mode 100644
index 00000000..e4901826
--- /dev/null
+++ b/public/svg-edit/editor/path.js
@@ -0,0 +1,980 @@
+/**
+ * Package: svgedit.path
+ *
+ * Licensed under the Apache License, Version 2
+ *
+ * Copyright(c) 2011 Alexis Deveria
+ * Copyright(c) 2011 Jeff Schiller
+ */
+
+// Dependencies:
+// 1) jQuery
+// 2) browser.js
+// 3) math.js
+// 4) svgutils.js
+
+var svgedit = svgedit || {};
+
+(function() {
+
+if (!svgedit.path) {
+ svgedit.path = {};
+}
+
+var svgns = "http://www.w3.org/2000/svg";
+
+var uiStrings = {
+ "pathNodeTooltip": "Drag node to move it. Double-click node to change segment type",
+ "pathCtrlPtTooltip": "Drag control point to adjust curve properties"
+};
+
+var segData = {
+ 2: ['x','y'],
+ 4: ['x','y'],
+ 6: ['x','y','x1','y1','x2','y2'],
+ 8: ['x','y','x1','y1'],
+ 10: ['x','y','r1','r2','angle','largeArcFlag','sweepFlag'],
+ 12: ['x'],
+ 14: ['y'],
+ 16: ['x','y','x2','y2'],
+ 18: ['x','y']
+};
+
+var pathFuncs = [];
+
+var link_control_pts = true;
+
+// Stores references to paths via IDs.
+// TODO: Make this cross-document happy.
+var pathData = {};
+
+svgedit.path.setLinkControlPoints = function(lcp) {
+ link_control_pts = lcp;
+};
+
+svgedit.path.path = null;
+
+var editorContext_ = null;
+
+svgedit.path.init = function(editorContext) {
+ editorContext_ = editorContext;
+
+ pathFuncs = [0,'ClosePath'];
+ var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc',
+ 'LinetoHorizontal', 'LinetoVertical','CurvetoCubicSmooth','CurvetoQuadraticSmooth'];
+ $.each(pathFuncsStrs, function(i,s) {
+ pathFuncs.push(s+'Abs');
+ pathFuncs.push(s+'Rel');
+ });
+};
+
+svgedit.path.insertItemBefore = function(elem, newseg, index) {
+ // Support insertItemBefore on paths for FF2
+ var list = elem.pathSegList;
+
+ if(svgedit.browser.supportsPathInsertItemBefore()) {
+ list.insertItemBefore(newseg, index);
+ return;
+ }
+ var len = list.numberOfItems;
+ var arr = [];
+ for(var i=0; i 0) {
+ new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
+ new_angleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
+ }
+ else {
+ new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
+ new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
+ }
+
+ // rotate the points
+ nct1.x = r1 * Math.cos(new_anglea) + pt.x;
+ nct1.y = r1 * Math.sin(new_anglea) + pt.y;
+ nct2.x = r2 * Math.cos(new_angleb) + pt.x;
+ nct2.y = r2 * Math.sin(new_angleb) + pt.y;
+
+ return [nct1, nct2];
+ }
+ return undefined;
+};
+
+svgedit.path.Segment = function(index, item) {
+ this.selected = false;
+ this.index = index;
+ this.item = item;
+ this.type = item.pathSegType;
+
+ this.ctrlpts = [];
+ this.ptgrip = null;
+ this.segsel = null;
+};
+
+svgedit.path.Segment.prototype.showCtrlPts = function(y) {
+ for (var i in this.ctrlpts) {
+ this.ctrlpts[i].setAttribute("display", y ? "inline" : "none");
+ }
+};
+
+svgedit.path.Segment.prototype.selectCtrls = function(y) {
+ $('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2').
+ attr('fill', y ? '#0FF' : '#EEE');
+};
+
+svgedit.path.Segment.prototype.show = function(y) {
+ if(this.ptgrip) {
+ this.ptgrip.setAttribute("display", y ? "inline" : "none");
+ this.segsel.setAttribute("display", y ? "inline" : "none");
+ // Show/hide all control points if available
+ this.showCtrlPts(y);
+ }
+};
+
+svgedit.path.Segment.prototype.select = function(y) {
+ if(this.ptgrip) {
+ this.ptgrip.setAttribute("stroke", y ? "#0FF" : "#00F");
+ this.segsel.setAttribute("display", y ? "inline" : "none");
+ if(this.ctrlpts) {
+ this.selectCtrls(y);
+ }
+ this.selected = y;
+ }
+};
+
+svgedit.path.Segment.prototype.addGrip = function() {
+ this.ptgrip = svgedit.path.getPointGrip(this, true);
+ this.ctrlpts = svgedit.path.getControlPoints(this, true);
+ this.segsel = svgedit.path.getSegSelector(this, true);
+};
+
+svgedit.path.Segment.prototype.update = function(full) {
+ if(this.ptgrip) {
+ var pt = svgedit.path.getGripPt(this);
+ svgedit.utilities.assignAttributes(this.ptgrip, {
+ 'cx': pt.x,
+ 'cy': pt.y
+ });
+
+ svgedit.path.getSegSelector(this, true);
+
+ if(this.ctrlpts) {
+ if(full) {
+ this.item = svgedit.path.path.elem.pathSegList.getItem(this.index);
+ this.type = this.item.pathSegType;
+ }
+ svgedit.path.getControlPoints(this);
+ }
+ // this.segsel.setAttribute("display", y?"inline":"none");
+ }
+};
+
+svgedit.path.Segment.prototype.move = function(dx, dy) {
+ var item = this.item;
+
+ if(this.ctrlpts) {
+ var cur_pts = [item.x += dx, item.y += dy,
+ item.x1, item.y1, item.x2 += dx, item.y2 += dy];
+ } else {
+ var cur_pts = [item.x += dx, item.y += dy];
+ }
+ svgedit.path.replacePathSeg(this.type, this.index, cur_pts);
+
+ if(this.next && this.next.ctrlpts) {
+ var next = this.next.item;
+ var next_pts = [next.x, next.y,
+ next.x1 += dx, next.y1 += dy, next.x2, next.y2];
+ svgedit.path.replacePathSeg(this.next.type, this.next.index, next_pts);
+ }
+
+ if(this.mate) {
+ // The last point of a closed subpath has a "mate",
+ // which is the "M" segment of the subpath
+ var item = this.mate.item;
+ var pts = [item.x += dx, item.y += dy];
+ svgedit.path.replacePathSeg(this.mate.type, this.mate.index, pts);
+ // Has no grip, so does not need "updating"?
+ }
+
+ this.update(true);
+ if(this.next) this.next.update(true);
+};
+
+svgedit.path.Segment.prototype.setLinked = function(num) {
+ var seg, anum, pt;
+ if (num == 2) {
+ anum = 1;
+ seg = this.next;
+ if(!seg) return;
+ pt = this.item;
+ } else {
+ anum = 2;
+ seg = this.prev;
+ if(!seg) return;
+ pt = seg.item;
+ }
+
+ var item = seg.item;
+
+ item['x' + anum] = pt.x + (pt.x - this.item['x' + num]);
+ item['y' + anum] = pt.y + (pt.y - this.item['y' + num]);
+
+ var pts = [item.x, item.y,
+ item.x1, item.y1,
+ item.x2, item.y2];
+
+ svgedit.path.replacePathSeg(seg.type, seg.index, pts);
+ seg.update(true);
+};
+
+svgedit.path.Segment.prototype.moveCtrl = function(num, dx, dy) {
+ var item = this.item;
+
+ item['x' + num] += dx;
+ item['y' + num] += dy;
+
+ var pts = [item.x,item.y,
+ item.x1,item.y1, item.x2,item.y2];
+
+ svgedit.path.replacePathSeg(this.type, this.index, pts);
+ this.update(true);
+};
+
+svgedit.path.Segment.prototype.setType = function(new_type, pts) {
+ svgedit.path.replacePathSeg(new_type, this.index, pts);
+ this.type = new_type;
+ this.item = svgedit.path.path.elem.pathSegList.getItem(this.index);
+ this.showCtrlPts(new_type === 6);
+ this.ctrlpts = svgedit.path.getControlPoints(this);
+ this.update(true);
+};
+
+svgedit.path.Path = function(elem) {
+ if(!elem || elem.tagName !== "path") {
+ throw "svgedit.path.Path constructed without a element";
+ }
+
+ this.elem = elem;
+ this.segs = [];
+ this.selected_pts = [];
+ svgedit.path.path = this;
+
+ this.init();
+};
+
+// Reset path data
+svgedit.path.Path.prototype.init = function() {
+ // Hide all grips, etc
+ $(svgedit.path.getGripContainer()).find("*").attr("display", "none");
+ var segList = this.elem.pathSegList;
+ var len = segList.numberOfItems;
+ this.segs = [];
+ this.selected_pts = [];
+ this.first_seg = null;
+
+ // Set up segs array
+ for(var i=0; i < len; i++) {
+ var item = segList.getItem(i);
+ var segment = new svgedit.path.Segment(i, item);
+ segment.path = this;
+ this.segs.push(segment);
+ }
+
+ var segs = this.segs;
+ var start_i = null;
+
+ for(var i=0; i < len; i++) {
+ var seg = segs[i];
+ var next_seg = (i+1) >= len ? null : segs[i+1];
+ var prev_seg = (i-1) < 0 ? null : segs[i-1];
+
+ if(seg.type === 2) {
+ if(prev_seg && prev_seg.type !== 1) {
+ // New sub-path, last one is open,
+ // so add a grip to last sub-path's first point
+ var start_seg = segs[start_i];
+ start_seg.next = segs[start_i+1];
+ start_seg.next.prev = start_seg;
+ start_seg.addGrip();
+ }
+ // Remember that this is a starter seg
+ start_i = i;
+ } else if(next_seg && next_seg.type === 1) {
+ // This is the last real segment of a closed sub-path
+ // Next is first seg after "M"
+ seg.next = segs[start_i+1];
+
+ // First seg after "M"'s prev is this
+ seg.next.prev = seg;
+ seg.mate = segs[start_i];
+ seg.addGrip();
+ if(this.first_seg == null) {
+ this.first_seg = seg;
+ }
+ } else if(!next_seg) {
+ if(seg.type !== 1) {
+ // Last seg, doesn't close so add a grip
+ // to last sub-path's first point
+ var start_seg = segs[start_i];
+ start_seg.next = segs[start_i+1];
+ start_seg.next.prev = start_seg;
+ start_seg.addGrip();
+ seg.addGrip();
+
+ if(!this.first_seg) {
+ // Open path, so set first as real first and add grip
+ this.first_seg = segs[start_i];
+ }
+ }
+ } else if(seg.type !== 1){
+ // Regular segment, so add grip and its "next"
+ seg.addGrip();
+
+ // Don't set its "next" if it's an "M"
+ if(next_seg && next_seg.type !== 2) {
+ seg.next = next_seg;
+ seg.next.prev = seg;
+ }
+ }
+ }
+ return this;
+};
+
+svgedit.path.Path.prototype.eachSeg = function(fn) {
+ var len = this.segs.length
+ for(var i=0; i < len; i++) {
+ var ret = fn.call(this.segs[i], i);
+ if(ret === false) break;
+ }
+};
+
+svgedit.path.Path.prototype.addSeg = function(index) {
+ // Adds a new segment
+ var seg = this.segs[index];
+ if(!seg.prev) return;
+
+ var prev = seg.prev;
+ var newseg;
+ switch(seg.item.pathSegType) {
+ case 4:
+ var new_x = (seg.item.x + prev.item.x) / 2;
+ var new_y = (seg.item.y + prev.item.y) / 2;
+ newseg = this.elem.createSVGPathSegLinetoAbs(new_x, new_y);
+ break;
+ case 6: //make it a curved segment to preserve the shape (WRS)
+ // http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation
+ var p0_x = (prev.item.x + seg.item.x1)/2;
+ var p1_x = (seg.item.x1 + seg.item.x2)/2;
+ var p2_x = (seg.item.x2 + seg.item.x)/2;
+ var p01_x = (p0_x + p1_x)/2;
+ var p12_x = (p1_x + p2_x)/2;
+ var new_x = (p01_x + p12_x)/2;
+ var p0_y = (prev.item.y + seg.item.y1)/2;
+ var p1_y = (seg.item.y1 + seg.item.y2)/2;
+ var p2_y = (seg.item.y2 + seg.item.y)/2;
+ var p01_y = (p0_y + p1_y)/2;
+ var p12_y = (p1_y + p2_y)/2;
+ var new_y = (p01_y + p12_y)/2;
+ newseg = this.elem.createSVGPathSegCurvetoCubicAbs(new_x,new_y, p0_x,p0_y, p01_x,p01_y);
+ var pts = [seg.item.x,seg.item.y,p12_x,p12_y,p2_x,p2_y];
+ svgedit.path.replacePathSeg(seg.type,index,pts);
+ break;
+ }
+
+ svgedit.path.insertItemBefore(this.elem, newseg, index);
+};
+
+svgedit.path.Path.prototype.deleteSeg = function(index) {
+ var seg = this.segs[index];
+ var list = this.elem.pathSegList;
+
+ seg.show(false);
+ var next = seg.next;
+ if(seg.mate) {
+ // Make the next point be the "M" point
+ var pt = [next.item.x, next.item.y];
+ svgedit.path.replacePathSeg(2, next.index, pt);
+
+ // Reposition last node
+ svgedit.path.replacePathSeg(4, seg.index, pt);
+
+ list.removeItem(seg.mate.index);
+ } else if(!seg.prev) {
+ // First node of open path, make next point the M
+ var item = seg.item;
+ var pt = [next.item.x, next.item.y];
+ svgedit.path.replacePathSeg(2, seg.next.index, pt);
+ list.removeItem(index);
+
+ } else {
+ list.removeItem(index);
+ }
+};
+
+svgedit.path.Path.prototype.subpathIsClosed = function(index) {
+ var closed = false;
+ // Check if subpath is already open
+ svgedit.path.path.eachSeg(function(i) {
+ if(i <= index) return true;
+ if(this.type === 2) {
+ // Found M first, so open
+ return false;
+ } else if(this.type === 1) {
+ // Found Z first, so closed
+ closed = true;
+ return false;
+ }
+ });
+
+ return closed;
+};
+
+svgedit.path.Path.prototype.removePtFromSelection = function(index) {
+ var pos = this.selected_pts.indexOf(index);
+ if(pos == -1) {
+ return;
+ }
+ this.segs[index].select(false);
+ this.selected_pts.splice(pos, 1);
+};
+
+svgedit.path.Path.prototype.clearSelection = function() {
+ this.eachSeg(function(i) {
+ // 'this' is the segment here
+ this.select(false);
+ });
+ this.selected_pts = [];
+};
+
+svgedit.path.Path.prototype.storeD = function() {
+ this.last_d = this.elem.getAttribute('d');
+};
+
+svgedit.path.Path.prototype.show = function(y) {
+ // Shows this path's segment grips
+ this.eachSeg(function() {
+ // 'this' is the segment here
+ this.show(y);
+ });
+ if(y) {
+ this.selectPt(this.first_seg.index);
+ }
+ return this;
+};
+
+// Move selected points
+svgedit.path.Path.prototype.movePts = function(d_x, d_y) {
+ var i = this.selected_pts.length;
+ while(i--) {
+ var seg = this.segs[this.selected_pts[i]];
+ seg.move(d_x, d_y);
+ }
+};
+
+svgedit.path.Path.prototype.moveCtrl = function(d_x, d_y) {
+ var seg = this.segs[this.selected_pts[0]];
+ seg.moveCtrl(this.dragctrl, d_x, d_y);
+ if(link_control_pts) {
+ seg.setLinked(this.dragctrl);
+ }
+};
+
+svgedit.path.Path.prototype.setSegType = function(new_type) {
+ this.storeD();
+ var i = this.selected_pts.length;
+ var text;
+ while(i--) {
+ var sel_pt = this.selected_pts[i];
+
+ // Selected seg
+ var cur = this.segs[sel_pt];
+ var prev = cur.prev;
+ if(!prev) continue;
+
+ if(!new_type) { // double-click, so just toggle
+ text = "Toggle Path Segment Type";
+
+ // Toggle segment to curve/straight line
+ var old_type = cur.type;
+
+ new_type = (old_type == 6) ? 4 : 6;
+ }
+
+ new_type = new_type-0;
+
+ var cur_x = cur.item.x;
+ var cur_y = cur.item.y;
+ var prev_x = prev.item.x;
+ var prev_y = prev.item.y;
+ var points;
+ switch ( new_type ) {
+ case 6:
+ if(cur.olditem) {
+ var old = cur.olditem;
+ points = [cur_x,cur_y, old.x1,old.y1, old.x2,old.y2];
+ } else {
+ var diff_x = cur_x - prev_x;
+ var diff_y = cur_y - prev_y;
+ // get control points from straight line segment
+ /*
+ var ct1_x = (prev_x + (diff_y/2));
+ var ct1_y = (prev_y - (diff_x/2));
+ var ct2_x = (cur_x + (diff_y/2));
+ var ct2_y = (cur_y - (diff_x/2));
+ */
+ //create control points on the line to preserve the shape (WRS)
+ var ct1_x = (prev_x + (diff_x/3));
+ var ct1_y = (prev_y + (diff_y/3));
+ var ct2_x = (cur_x - (diff_x/3));
+ var ct2_y = (cur_y - (diff_y/3));
+ points = [cur_x,cur_y, ct1_x,ct1_y, ct2_x,ct2_y];
+ }
+ break;
+ case 4:
+ points = [cur_x,cur_y];
+
+ // Store original prevve segment nums
+ cur.olditem = cur.item;
+ break;
+ }
+
+ cur.setType(new_type, points);
+ }
+ svgedit.path.path.endChanges(text);
+};
+
+svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) {
+ this.clearSelection();
+ if(pt == null) {
+ this.eachSeg(function(i) {
+ // 'this' is the segment here.
+ if(this.prev) {
+ pt = i;
+ }
+ });
+ }
+ this.addPtsToSelection(pt);
+ if(ctrl_num) {
+ this.dragctrl = ctrl_num;
+
+ if(link_control_pts) {
+ this.segs[pt].setLinked(ctrl_num);
+ }
+ }
+};
+
+// Update position of all points
+svgedit.path.Path.prototype.update = function() {
+ var elem = this.elem;
+ if(svgedit.utilities.getRotationAngle(elem)) {
+ this.matrix = svgedit.math.getMatrix(elem);
+ this.imatrix = this.matrix.inverse();
+ } else {
+ this.matrix = null;
+ this.imatrix = null;
+ }
+
+ this.eachSeg(function(i) {
+ this.item = elem.pathSegList.getItem(i);
+ this.update();
+ });
+
+ return this;
+};
+
+svgedit.path.getPath_ = function(elem) {
+ var p = pathData[elem.id];
+ if(!p) p = pathData[elem.id] = new svgedit.path.Path(elem);
+ return p;
+};
+
+svgedit.path.removePath_ = function(id) {
+ if(id in pathData) delete pathData[id];
+};
+
+var getRotVals = function(x, y) {
+ dx = x - oldcx;
+ dy = y - oldcy;
+
+ // rotate the point around the old center
+ r = Math.sqrt(dx*dx + dy*dy);
+ theta = Math.atan2(dy,dx) + angle;
+ dx = r * Math.cos(theta) + oldcx;
+ dy = r * Math.sin(theta) + oldcy;
+
+ // dx,dy should now hold the actual coordinates of each
+ // point after being rotated
+
+ // now we want to rotate them around the new center in the reverse direction
+ dx -= newcx;
+ dy -= newcy;
+
+ r = Math.sqrt(dx*dx + dy*dy);
+ theta = Math.atan2(dy,dx) - angle;
+
+ return {'x':(r * Math.cos(theta) + newcx)/1,
+ 'y':(r * Math.sin(theta) + newcy)/1};
+};
+
+// If the path was rotated, we must now pay the piper:
+// Every path point must be rotated into the rotated coordinate system of
+// its old center, then determine the new center, then rotate it back
+// This is because we want the path to remember its rotation
+
+// TODO: This is still using ye olde transform methods, can probably
+// be optimized or even taken care of by recalculateDimensions
+svgedit.path.recalcRotatedPath = function() {
+ var current_path = svgedit.path.path.elem;
+ var angle = svgedit.utilities.getRotationAngle(current_path, true);
+ if(!angle) return;
+// selectedBBoxes[0] = svgedit.path.path.oldbbox;
+ var box = svgedit.utilities.getBBox(current_path),
+ oldbox = svgedit.path.path.oldbbox,//selectedBBoxes[0],
+ oldcx = oldbox.x + oldbox.width/2,
+ oldcy = oldbox.y + oldbox.height/2,
+ newcx = box.x + box.width/2,
+ newcy = box.y + box.height/2,
+
+ // un-rotate the new center to the proper position
+ dx = newcx - oldcx,
+ dy = newcy - oldcy,
+ r = Math.sqrt(dx*dx + dy*dy),
+ theta = Math.atan2(dy,dx) + angle;
+
+ newcx = r * Math.cos(theta) + oldcx;
+ newcy = r * Math.sin(theta) + oldcy;
+
+ var list = current_path.pathSegList,
+ i = list.numberOfItems;
+ while (i) {
+ i -= 1;
+ var seg = list.getItem(i),
+ type = seg.pathSegType;
+ if(type == 1) continue;
+
+ var rvals = getRotVals(seg.x,seg.y),
+ points = [rvals.x, rvals.y];
+ if(seg.x1 != null && seg.x2 != null) {
+ c_vals1 = getRotVals(seg.x1, seg.y1);
+ c_vals2 = getRotVals(seg.x2, seg.y2);
+ points.splice(points.length, 0, c_vals1.x , c_vals1.y, c_vals2.x, c_vals2.y);
+ }
+ svgedit.path.replacePathSeg(type, i, points);
+ } // loop for each point
+
+ box = svgedit.utilities.getBBox(current_path);
+// selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y;
+// selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height;
+
+ // now we must set the new transform to be rotated around the new center
+ var R_nc = svgroot.createSVGTransform(),
+ tlist = svgedit.transformlist.getTransformList(current_path);
+ R_nc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
+ tlist.replaceItem(R_nc,0);
+};
+
+// ====================================
+// Public API starts here
+
+svgedit.path.clearData = function() {
+ pathData = {};
+};
+
+})();
diff --git a/public/svg-edit/editor/spinbtn/JQuerySpinBtn.min.js b/public/svg-edit/editor/spinbtn/JQuerySpinBtn.min.js
index dd6c76cd..f7532073 100644
--- a/public/svg-edit/editor/spinbtn/JQuerySpinBtn.min.js
+++ b/public/svg-edit/editor/spinbtn/JQuerySpinBtn.min.js
@@ -1 +1,7 @@
-$.fn.SpinButton=function(a){return this.each(function(){this.repeating=false;this.spinCfg={min:a&&!isNaN(parseFloat(a.min))?Number(a.min):null,max:a&&!isNaN(parseFloat(a.max))?Number(a.max):null,step:a&&a.step?Number(a.step):1,page:a&&a.page?Number(a.page):10,upClass:a&&a.upClass?a.upClass:"up",downClass:a&&a.downClass?a.downClass:"down",reset:a&&a.reset?a.reset:this.value,delay:a&&a.delay?Number(a.delay):500,interval:a&&a.interval?Number(a.interval):100,_btn_width:20,_btn_height:12,_direction:null,_delay:null,_repeat:null,callback:a&&a.callback?a.callback:null,};this.adjustValue=function(d){var c=(isNaN(this.value)?this.spinCfg.reset:Number(this.value))+Number(d);if(this.spinCfg.min!==null){c=Math.max(c,this.spinCfg.min)}if(this.spinCfg.max!==null){c=Math.min(c,this.spinCfg.max)}this.value=c;if($.isFunction(this.spinCfg.callback)){this.spinCfg.callback(this)}};$(this).addClass(a&&a.spinClass?a.spinClass:"spin-button").mousemove(function(g){var c=g.pageX||g.x;var h=g.pageY||g.y;var d=g.target||g.srcElement;var f=(c>b(d,"offsetLeft")+d.offsetWidth-this.spinCfg._btn_width)?((h=120){this.adjustValue(this.spinCfg.step)}else{if(c.wheelDelta<=-120){this.adjustValue(-this.spinCfg.step)}}c.preventDefault()}).change(function(c){this.adjustValue(0)});if(this.addEventListener){this.addEventListener("DOMMouseScroll",function(c){if(c.detail>0){this.adjustValue(-this.spinCfg.step)}else{if(c.detail<0){this.adjustValue(this.spinCfg.step)}}c.preventDefault()},false)}});function b(e,g){var f=e[g],d=document.body;while((e=e.offsetParent)&&(e!=d)){if(!$.browser.msie||(e.currentStyle.position!="relative")){f+=e[g]}}return f}};
\ No newline at end of file
+$.fn.SpinButton=function(b){function f(a,c){for(var e=a[c],d=document.body;(a=a.offsetParent)&&a!=d;)if(!$.browser.msie||a.currentStyle.position!="relative")e+=a[c];return e}return this.each(function(){this.repeating=false;this.spinCfg={min:b&&!isNaN(parseFloat(b.min))?Number(b.min):null,max:b&&!isNaN(parseFloat(b.max))?Number(b.max):null,step:b&&b.step?Number(b.step):1,stepfunc:b&&b.stepfunc?b.stepfunc:false,page:b&&b.page?Number(b.page):10,upClass:b&&b.upClass?b.upClass:"up",downClass:b&&b.downClass?
+b.downClass:"down",reset:b&&b.reset?b.reset:this.value,delay:b&&b.delay?Number(b.delay):500,interval:b&&b.interval?Number(b.interval):100,_btn_width:20,_direction:null,_delay:null,_repeat:null,callback:b&&b.callback?b.callback:null};this.spinCfg.smallStep=b&&b.smallStep?b.smallStep:this.spinCfg.step/2;this.adjustValue=function(a){a=isNaN(this.value)?this.spinCfg.reset:$.isFunction(this.spinCfg.stepfunc)?this.spinCfg.stepfunc(this,a):Number((Number(this.value)+Number(a)).toFixed(5));if(this.spinCfg.min!==
+null)a=Math.max(a,this.spinCfg.min);if(this.spinCfg.max!==null)a=Math.min(a,this.spinCfg.max);this.value=a;$.isFunction(this.spinCfg.callback)&&this.spinCfg.callback(this)};$(this).addClass(b&&b.spinClass?b.spinClass:"spin-button").mousemove(function(a){var c=a.pageX||a.x,e=a.pageY||a.y;a=a.target||a.srcElement;var d=svgEditor.tool_scale||1,g=$(a).height()/2;c=c>f(a,"offsetLeft")+a.offsetWidth*d-this.spinCfg._btn_width?e=120)this.adjustValue(this.spinCfg.step);else a.wheelDelta<=-120&&this.adjustValue(-this.spinCfg.step);a.preventDefault()}).change(function(){this.adjustValue(0)});this.addEventListener&&this.addEventListener("DOMMouseScroll",function(a){if(a.detail>0)this.adjustValue(-this.spinCfg.step);else a.detail<0&&this.adjustValue(this.spinCfg.step);a.preventDefault()},false)})};
\ No newline at end of file
diff --git a/public/svg-edit/editor/svg-editor.html b/public/svg-edit/editor/svg-editor.html
index 0fd4dc43..0e4a18d5 100644
--- a/public/svg-edit/editor/svg-editor.html
+++ b/public/svg-edit/editor/svg-editor.html
@@ -35,6 +35,7 @@
+
diff --git a/public/svg-edit/editor/svg-editor.js b/public/svg-edit/editor/svg-editor.js
index f6eea4fb..4d3e8ad6 100644
--- a/public/svg-edit/editor/svg-editor.js
+++ b/public/svg-edit/editor/svg-editor.js
@@ -1509,9 +1509,9 @@
if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
promptImgURL();
}
- } else if(elname == 'text') {
+ } /*else if(elname == 'text') {
// TODO: Do something here for new text
- }
+ }*/
}
if(!is_node && currentMode != 'pathedit') {
@@ -1887,6 +1887,10 @@
}
});
+ $('#g_title').change(function() {
+ svgCanvas.setGroupTitle(this.value);
+ });
+
$('.attr_changer').change(function() {
var attr = this.getAttribute("data-attr");
var val = this.value;
@@ -1898,15 +1902,17 @@
return false;
}
- if(isNaN(val)) {
- val = svgCanvas.convertToNum(attr, val);
- } else if(curConfig.baseUnit !== 'px') {
- // Convert unitless value to one with given unit
+ if (attr !== "id") {
+ if (isNaN(val)) {
+ val = svgCanvas.convertToNum(attr, val);
+ } else if(curConfig.baseUnit !== 'px') {
+ // Convert unitless value to one with given unit
- var unitData = svgedit.units.getTypeMap();
+ var unitData = svgedit.units.getTypeMap();
- if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") {
- val *= unitData[curConfig.baseUnit];
+ if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") {
+ val *= unitData[curConfig.baseUnit];
+ }
}
}
@@ -1965,9 +1971,11 @@
$("#toggle_stroke_tools").toggle(function() {
$(".stroke_tool").css('display','table-cell');
$(this).text('<<');
+ resetScrollPos();
}, function() {
$(".stroke_tool").css('display','none');
$(this).text('>>');
+ resetScrollPos();
});
// This is a common function used when a tool has been clicked (chosen)
@@ -3195,7 +3203,7 @@
} else if (preferences) {
hidePreferences();
}
-
+ resetScrollPos();
};
var hideSourceEditor = function(){
@@ -3219,6 +3227,42 @@
var win_wh = {width:$(window).width(), height:$(window).height()};
+ var resetScrollPos = $.noop, curScrollPos;
+
+ // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9)
+ if(svgedit.browser.isIE()) {
+ (function() {
+ resetScrollPos = function() {
+ if(workarea[0].scrollLeft === 0
+ && workarea[0].scrollTop === 0) {
+ workarea[0].scrollLeft = curScrollPos.left;
+ workarea[0].scrollTop = curScrollPos.top;
+ }
+ }
+
+ curScrollPos = {
+ left: workarea[0].scrollLeft,
+ top: workarea[0].scrollTop
+ };
+
+ $(window).resize(resetScrollPos);
+ svgEditor.ready(function() {
+ // TODO: Find better way to detect when to do this to minimize
+ // flickering effect
+ setTimeout(function() {
+ resetScrollPos();
+ }, 500);
+ });
+
+ workarea.scroll(function() {
+ curScrollPos = {
+ left: workarea[0].scrollLeft,
+ top: workarea[0].scrollTop
+ };
+ });
+ }());
+ }
+
$(window).resize(function(evt) {
if (editingsource) {
properlySourceSizeTextArea();
@@ -3436,7 +3480,15 @@
if(!selectedElement) return;
var type = this.type;
- if(selectedElement.tagName === 'g') {
+ switch ( selectedElement.tagName ) {
+ case 'use':
+ case 'image':
+ case 'foreignObject':
+ // These elements don't have fill or stroke, so don't change
+ // the current value
+ return;
+ case 'g':
+ case 'a':
var gPaint = null;
var childs = selectedElement.getElementsByTagName('*');
@@ -3458,8 +3510,8 @@
var paintColor = gPaint;
var paintOpacity = 1;
-
- } else {
+ break;
+ default:
var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity"));
if (isNaN(paintOpacity)) {
paintOpacity = 1.0;
@@ -4196,7 +4248,9 @@
$('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize });
$('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity });
$('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur });
- $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom });
+ $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom })
+ // Set default zoom
+ .val(svgCanvas.getZoom() * 100);
$("#workarea").contextMenu({
menu: 'cmenu_canvas',
@@ -4583,7 +4637,7 @@
updateCanvas(true);
// });
- // var revnums = "svg-editor.js ($Rev: 1973 $) ";
+ // var revnums = "svg-editor.js ($Rev: 2028 $) ";
// revnums += svgCanvas.getVersion();
// $('#copyright')[0].setAttribute("title", revnums);
diff --git a/public/svg-edit/editor/svgcanvas.js b/public/svg-edit/editor/svgcanvas.js
index 6059a408..b6ecac24 100644
--- a/public/svg-edit/editor/svgcanvas.js
+++ b/public/svg-edit/editor/svgcanvas.js
@@ -20,6 +20,7 @@
// 8) history.js
// 9) select.js
// 10) draw.js
+// 11) path.js
if(!window.console) {
window.console = {};
@@ -236,95 +237,6 @@ var cur_shape = all_properties.shape;
// default size of 1 until it needs to grow bigger
var selectedElements = new Array(1);
-
-// Function: getElem
-// Get a DOM element by ID within the SVG root element.
-//
-// Parameters:
-// id - String with the element's new ID
-var getElem = null;
-if (svgedit.browser.supportsSelectors()) {
- getElem = function(id) {
- // querySelector lookup
- return svgroot.querySelector('#'+id);
- };
-} else if (svgedit.browser.supportsXpath()) {
- getElem = function(id) {
- // xpath lookup
- return svgdoc.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="'+id+'"]',
- container, function() { return "http://www.w3.org/2000/svg"; },
- 9, null).singleNodeValue;
- };
-} else {
- getElem = function(id) {
- // jQuery lookup: twice as slow as xpath in FF
- return $(svgroot).find('[id=' + id + ']')[0];
- };
-}
-canvas.getElem = getElem;
-
-// Function: assignAttributes
-// Assigns multiple attributes to an element.
-//
-// Parameters:
-// node - DOM element to apply new attribute values to
-// attrs - Object with attribute keys/values
-// suspendLength - Optional integer of milliseconds to suspend redraw
-// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr
-var assignAttributes = canvas.assignAttributes = function(node, attrs, suspendLength, unitCheck) {
- if(!suspendLength) suspendLength = 0;
- // Opera has a problem with suspendRedraw() apparently
- var handle = null;
- if (!svgedit.browser.isOpera()) svgroot.suspendRedraw(suspendLength);
-
- for (var i in attrs) {
- var ns = (i.substr(0,4) === "xml:" ? xmlns :
- i.substr(0,6) === "xlink:" ? xlinkns : null);
-
- if(ns) {
- node.setAttributeNS(ns, i, attrs[i]);
- } else if(!unitCheck) {
- node.setAttribute(i, attrs[i]);
- } else {
- svgedit.units.setUnitAttr(node, i, attrs[i]);
- }
-
- }
-
- if (!svgedit.browser.isOpera()) svgroot.unsuspendRedraw(handle);
-};
-
-// Function: cleanupElement
-// Remove unneeded (default) attributes, makes resulting SVG smaller
-//
-// Parameters:
-// element - DOM element to clean up
-var cleanupElement = this.cleanupElement = function(element) {
- var handle = svgroot.suspendRedraw(60);
- var defaults = {
- 'fill-opacity':1,
- 'stop-opacity':1,
- 'opacity':1,
- 'stroke':'none',
- 'stroke-dasharray':'none',
- 'stroke-linejoin':'miter',
- 'stroke-linecap':'butt',
- 'stroke-opacity':1,
- 'stroke-width':1,
- 'rx':0,
- 'ry':0
- }
-
- for(var attr in defaults) {
- var val = defaults[attr];
- if(element.getAttribute(attr) == val) {
- element.removeAttribute(attr);
- }
- }
-
- svgroot.unsuspendRedraw(handle);
-};
-
// Function: addSvgElementFromJson
// Create a new SVG element based on the given object keys/values and add it to the current layer
// The element will be ran through cleanupElement before being returned
@@ -337,7 +249,7 @@ var cleanupElement = this.cleanupElement = function(element) {
//
// Returns: The new element
var addSvgElementFromJson = this.addSvgElementFromJson = function(data) {
- var shape = getElem(data.attr.id);
+ var shape = svgedit.utilities.getElem(data.attr.id);
// if shape is a path but we need to create a rect/ellipse, then remove the path
var current_layer = getCurrentDrawing().getCurrentLayer();
if (shape && data.element != shape.tagName) {
@@ -351,7 +263,7 @@ var addSvgElementFromJson = this.addSvgElementFromJson = function(data) {
}
}
if(data.curStyles) {
- assignAttributes(shape, {
+ svgedit.utilities.assignAttributes(shape, {
"fill": cur_shape.fill,
"stroke": cur_shape.stroke,
"stroke-width": cur_shape.stroke_width,
@@ -364,8 +276,8 @@ var addSvgElementFromJson = this.addSvgElementFromJson = function(data) {
"style": "pointer-events:inherit"
}, 100);
}
- assignAttributes(shape, data.attr, 100);
- cleanupElement(shape);
+ svgedit.utilities.assignAttributes(shape, data.attr, 100);
+ svgedit.utilities.cleanupElement(shape);
return shape;
};
@@ -379,12 +291,13 @@ var matrixMultiply = canvas.matrixMultiply = svgedit.math.matrixMultiply;
var hasMatrixTransform = canvas.hasMatrixTransform = svgedit.math.hasMatrixTransform;
var transformListToTransform = canvas.transformListToTransform = svgedit.math.transformListToTransform;
var snapToAngle = svgedit.math.snapToAngle;
+var getMatrix = svgedit.math.getMatrix;
// initialize from units.js
// send in an object implementing the ElementContainer interface (see units.js)
svgedit.units.init({
getBaseUnit: function() { return curConfig.baseUnit; },
- getElement: getElem,
+ getElement: svgedit.utilities.getElem,
getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; },
getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; },
getRoundDigits: function() { return save_options.round_digits; }
@@ -394,6 +307,10 @@ var convertToNum = canvas.convertToNum = svgedit.units.convertToNum;
// import from svgutils.js
svgedit.utilities.init({
+ getDOMDocument: function() { return svgdoc; },
+ getDOMContainer: function() { return container; },
+ getSVGRoot: function() { return svgroot; },
+ // TODO: replace this mostly with a way to get the current drawing.
getSelectedElements: function() { return selectedElements; },
getSVGContent: function() { return svgcontent; }
});
@@ -403,6 +320,9 @@ var setHref = canvas.setHref = svgedit.utilities.setHref;
var getPathBBox = svgedit.utilities.getPathBBox;
var getBBox = canvas.getBBox = svgedit.utilities.getBBox;
var getRotationAngle = canvas.getRotationAngle = svgedit.utilities.getRotationAngle;
+var getElem = canvas.getElem = svgedit.utilities.getElem;
+var assignAttributes = canvas.assignAttributes = svgedit.utilities.assignAttributes;
+var cleanupElement = this.cleanupElement = svgedit.utilities.cleanupElement;
// import from sanitize.js
var nsMap = svgedit.sanitize.getNSMap();
@@ -457,6 +377,17 @@ canvas.undoMgr = new svgedit.history.UndoManager({
if (values["stdDeviation"]) {
canvas.setBlurOffsets(cmd.elem.parentNode, values["stdDeviation"]);
}
+
+ // Remove & Re-add hack for Webkit (issue 775)
+ if(cmd.elem.tagName === 'use' && svgedit.browser.isWebkit()) {
+ var elem = cmd.elem;
+ if(!elem.getAttribute('x') && !elem.getAttribute('y')) {
+ var parent = elem.parentNode;
+ var sib = elem.nextSibling;
+ parent.removeChild(elem);
+ parent.insertBefore(elem, sib);
+ }
+ }
}
}
}
@@ -477,6 +408,12 @@ svgedit.select.init(curConfig, {
// this object manages selectors for us
var selectorManager = this.selectorManager = svgedit.select.getSelectorManager();
+// Import from path.js
+svgedit.path.init({
+ getCurrentZoom: function() { return current_zoom; },
+ getSVGRoot: function() { return svgroot; }
+});
+
// Function: snapToGrid
// round value to for snapping
// NOTE: This function did not move to svgutils.js since it depends on curConfig.
@@ -493,8 +430,6 @@ var snapToGrid = svgedit.utilities.snapToGrid;
// Interface strings, usually for title elements
var uiStrings = {
- "pathNodeTooltip": "Drag node to move it. Double-click node to change segment type",
- "pathCtrlPtTooltip": "Drag control point to adjust curve properties",
"exportNoBlur": "Blurred elements will appear as un-blurred",
"exportNoforeignObject": "foreignObject elements will not appear",
"exportNoDashArray": "Strokes will appear filled",
@@ -583,7 +518,7 @@ var cur_text = all_properties.text,
cur_properties = cur_shape,
// Array with selected elements' Bounding box object
- selectedBBoxes = new Array(1),
+// selectedBBoxes = new Array(1),
// The DOM element that was just selected
justSelected = null,
@@ -1079,7 +1014,7 @@ this.setRotationAngle = function(val, preventUndo) {
val = parseFloat(val);
var elem = selectedElements[0];
var oldTransform = elem.getAttribute("transform");
- var bbox = getBBox(elem);
+ var bbox = svgedit.utilities.getBBox(elem);
var cx = bbox.x+bbox.width/2, cy = bbox.y+bbox.height/2;
var tlist = getTransformList(elem);
@@ -1171,7 +1106,7 @@ var remapElement = this.remapElement = function(selected,changes,m) {
if(doSnapping) for(var o in changes) changes[o] = snapToGrid(changes[o]);
assignAttributes(selected, changes, 1000, true);
}
- box = getBBox(selected);
+ box = svgedit.utilities.getBBox(selected);
for(var i = 0; i < 2; i++) {
var type = i === 0 ? 'fill' : 'stroke';
@@ -1619,7 +1554,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
// if it's a regular group, we have special processing to flatten transforms
if ((selected.tagName == "g" && !gsvg) || selected.tagName == "a") {
- var box = getBBox(selected),
+ var box = svgedit.utilities.getBBox(selected),
oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2},
newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2,
transformListToTransform(tlist).matrix),
@@ -1976,7 +1911,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
else {
// FIXME: box might be null for some elements ( etc), need to handle this
- var box = getBBox(selected);
+ var box = svgedit.utilities.getBBox(selected);
// Paths (and possbly other shapes) will have no BBox while still in ,
// but we still may need to recalculate them (see issue 595).
@@ -2192,19 +2127,6 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
// Root Current Transformation Matrix in user units
var root_sctm = null;
-// Function: getMatrix
-// Get the matrix object for a given element
-//
-// Parameters:
-// elem - The DOM element to check
-//
-// Returns:
-// The matrix object associated with the element's transformlist
-var getMatrix = function(elem) {
- var tlist = getTransformList(elem);
- return transformListToTransform(tlist).matrix;
-}
-
// Group: Selection
// Function: clearSelection
@@ -2220,7 +2142,7 @@ var clearSelection = this.clearSelection = function(noCall) {
selectorManager.releaseSelector(elem);
selectedElements[i] = null;
}
- selectedBBoxes[0] = null;
+// selectedBBoxes[0] = null;
}
if(!noCall) call("selected", selectedElements);
};
@@ -2250,7 +2172,7 @@ var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) {
var i = elemsToAdd.length;
while (i--) {
var elem = elemsToAdd[i];
- if (!elem || !getBBox(elem)) continue;
+ if (!elem || !svgedit.utilities.getBBox(elem)) continue;
if(elem.tagName === 'a' && elem.childNodes.length === 1) {
// Make "a" element's child be the selected element
@@ -2263,7 +2185,7 @@ var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) {
selectedElements[j] = elem;
// only the first selectedBBoxes element is ever used in the codebase these days
- if (j == 0) selectedBBoxes[j] = getBBox(elem);
+// if (j == 0) selectedBBoxes[0] = svgedit.utilities.getBBox(elem);
j++;
var sel = selectorManager.requestSelector(elem);
@@ -2349,58 +2271,6 @@ this.selectAllInCurrentLayer = function() {
}
};
-// Function: smoothControlPoints
-// Takes three points and creates a smoother line based on them
-//
-// Parameters:
-// ct1 - Object with x and y values (first control point)
-// ct2 - Object with x and y values (second control point)
-// pt - Object with x and y values (third point)
-//
-// Returns:
-// Array of two "smoothed" point objects
-var smoothControlPoints = this.smoothControlPoints = function(ct1, ct2, pt) {
- // each point must not be the origin
- var x1 = ct1.x - pt.x,
- y1 = ct1.y - pt.y,
- x2 = ct2.x - pt.x,
- y2 = ct2.y - pt.y;
-
- if ( (x1 != 0 || y1 != 0) && (x2 != 0 || y2 != 0) ) {
- var anglea = Math.atan2(y1,x1),
- angleb = Math.atan2(y2,x2),
- r1 = Math.sqrt(x1*x1+y1*y1),
- r2 = Math.sqrt(x2*x2+y2*y2),
- nct1 = svgroot.createSVGPoint(),
- nct2 = svgroot.createSVGPoint();
- if (anglea < 0) { anglea += 2*Math.PI; }
- if (angleb < 0) { angleb += 2*Math.PI; }
-
- var angleBetween = Math.abs(anglea - angleb),
- angleDiff = Math.abs(Math.PI - angleBetween)/2;
-
- var new_anglea, new_angleb;
- if (anglea - angleb > 0) {
- new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
- new_angleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
- }
- else {
- new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
- new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
- }
-
- // rotate the points
- nct1.x = r1 * Math.cos(new_anglea) + pt.x;
- nct1.y = r1 * Math.sin(new_anglea) + pt.y;
- nct2.x = r2 * Math.cos(new_angleb) + pt.x;
- nct2.y = r2 * Math.sin(new_angleb) + pt.y;
-
- return [nct1, nct2];
- }
- return undefined;
-};
-
-
// Function: getMouseTarget
// Gets the desired element from a mouse event
//
@@ -2465,8 +2335,6 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
// Mouse events
(function() {
- var off_x, off_y;
-
var d_attr = null,
start_x = null,
start_y = null,
@@ -2495,18 +2363,11 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
}
root_sctm = svgcontent.getScreenCTM().inverse();
+
var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ),
mouse_x = pt.x * current_zoom,
mouse_y = pt.y * current_zoom;
- if($.browser.msie) {
- var off = $(container.parentNode).offset();
- off_x = svgcontent.getAttribute('x')-0 + off.left - container.parentNode.scrollLeft;
- off_y = svgcontent.getAttribute('y')-0 + off.top - container.parentNode.scrollTop;
- mouse_x = -(off_x - evt.pageX);
- mouse_y = -(off_y - evt.pageY);
- }
-
evt.preventDefault();
if(right_click) {
@@ -2635,7 +2496,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
// Getting the BBox from the selection box, since we know we
// want to orient around it
- init_bbox = getBBox($('#selectedBox0')[0]);
+ init_bbox = svgedit.utilities.getBBox($('#selectedBox0')[0]);
var bb = {};
$.each(init_bbox, function(key, val) {
bb[key] = val/current_zoom;
@@ -2841,17 +2702,12 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
{
if (!started) return;
if(evt.button === 1 || canvas.spaceKey) return;
+
var selected = selectedElements[0],
pt = transformPoint( evt.pageX, evt.pageY, root_sctm ),
mouse_x = pt.x * current_zoom,
mouse_y = pt.y * current_zoom,
shape = getElem(getId());
- // IE9 gives the wrong root_sctm
- // TODO: Use non-browser sniffing way to make this work
- if($.browser.msie) {
- mouse_x = -(off_x - evt.pageX);
- mouse_y = -(off_y - evt.pageY);
- }
var real_x = x = mouse_x / current_zoom;
var real_y = y = mouse_y / current_zoom;
@@ -2885,11 +2741,11 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
for (var i = 0; i < len; ++i) {
var selected = selectedElements[i];
if (selected == null) break;
- if (i==0) {
- var box = getBBox(selected);
+// if (i==0) {
+// var box = svgedit.utilities.getBBox(selected);
// selectedBBoxes[i].x = box.x + dx;
// selectedBBoxes[i].y = box.y + dy;
- }
+// }
// update the dummy transform in our transform list
// to be a translate
@@ -2958,7 +2814,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
// the shape's coordinates
var tlist = getTransformList(selected),
hasMatrix = hasMatrixTransform(tlist),
- box=hasMatrix?init_bbox:getBBox(selected),
+ box = hasMatrix ? init_bbox : svgedit.utilities.getBBox(selected),
left=box.x, top=box.y, width=box.width,
height=box.height, dx=(x-start_x), dy=(y-start_y);
@@ -3161,8 +3017,14 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
start_y = snapToGrid(start_y);
}
if(evt.shiftKey) {
- var x1 = path.dragging?path.dragging[0]:start_x;
- var y1 = path.dragging?path.dragging[1]:start_y;
+ var path = svgedit.path.path;
+ if(path) {
+ var x1 = path.dragging?path.dragging[0]:start_x;
+ var y1 = path.dragging?path.dragging[1]:start_y;
+ } else {
+ var x1 = start_x;
+ var y1 = start_y;
+ }
var xya = snapToAngle(x1,y1,x,y);
x=xya.x; y=xya.y;
}
@@ -3196,7 +3058,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
break;
case "rotate":
- var box = getBBox(selected),
+ var box = svgedit.utilities.getBBox(selected),
cx = box.x + box.width/2,
cy = box.y + box.height/2,
m = getMatrix(selected),
@@ -3269,16 +3131,23 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
if (selectedElements[1] == null) {
// set our current stroke/fill properties to the element's
var selected = selectedElements[0];
- if (selected.tagName != "g" && selected.tagName != "image" && selected.tagName != "foreignObject") {
- cur_properties.fill = selected.getAttribute("fill");
- cur_properties.fill_opacity = selected.getAttribute("fill-opacity");
- cur_properties.stroke = selected.getAttribute("stroke");
- cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity");
- cur_properties.stroke_width = selected.getAttribute("stroke-width");
- cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray");
- cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin");
- cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap");
+ switch ( selected.tagName ) {
+ case "g":
+ case "use":
+ case "image":
+ case "foreignObject":
+ break;
+ default:
+ cur_properties.fill = selected.getAttribute("fill");
+ cur_properties.fill_opacity = selected.getAttribute("fill-opacity");
+ cur_properties.stroke = selected.getAttribute("stroke");
+ cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity");
+ cur_properties.stroke_width = selected.getAttribute("stroke-width");
+ cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray");
+ cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin");
+ cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap");
}
+
if (selected.tagName == "text") {
cur_text.font_size = selected.getAttribute("font-size");
cur_text.font_family = selected.getAttribute("font-family");
@@ -3318,10 +3187,12 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
// Remove non-scaling stroke
if(svgedit.browser.supportsNonScalingStroke()) {
var elem = selectedElements[0];
- elem.removeAttribute('style');
- svgedit.utilities.walkTree(elem, function(elem) {
+ if (elem) {
elem.removeAttribute('style');
- });
+ svgedit.utilities.walkTree(elem, function(elem) {
+ elem.removeAttribute('style');
+ });
+ }
}
}
@@ -3887,7 +3758,14 @@ var textActions = canvas.textActions = function() {
// && !svgedit.math.rectsIntersect(transbb, {x: pt.x, y: pt.y, width:0, height:0})) {
// textActions.toSelectMode(true);
// }
- if(last_x === mouse_x && last_y === mouse_y && evt.target !== curtext) {
+
+ if(
+ evt.target !== curtext
+ && mouse_x < last_x + 2
+ && mouse_x > last_x - 2
+ && mouse_y < last_y + 2
+ && mouse_y > last_y - 2) {
+
textActions.toSelectMode(true);
}
@@ -3976,7 +3854,7 @@ var textActions = canvas.textActions = function() {
var xform = curtext.getAttribute('transform');
- textbb = getBBox(curtext);
+ textbb = svgedit.utilities.getBBox(curtext);
matrix = xform?getMatrix(curtext):null;
@@ -3993,6 +3871,15 @@ var textActions = canvas.textActions = function() {
var start = curtext.getStartPositionOfChar(i);
var end = curtext.getEndPositionOfChar(i);
+ if(!svgedit.browser.supportsGoodTextCharPos()) {
+ var offset = canvas.contentW * current_zoom;
+ start.x -= offset;
+ end.x -= offset;
+
+ start.x /= current_zoom;
+ end.x /= current_zoom;
+ }
+
// Get a "bbox" equivalent for each character. Uses the
// bbox data of the actual text for y, height purposes
@@ -4015,809 +3902,58 @@ var textActions = canvas.textActions = function() {
}
}();
+// TODO: Migrate all of this code into path.js
// Group: Path edit functions
// Functions relating to editing path elements
var pathActions = canvas.pathActions = function() {
var subpath = false;
- var pathData = {};
var current_path;
- var path;
var newPoint, firstCtrl;
- var segData = {
- 2: ['x','y'],
- 4: ['x','y'],
- 6: ['x','y','x1','y1','x2','y2'],
- 8: ['x','y','x1','y1'],
- 10: ['x','y','r1','r2','angle','largeArcFlag','sweepFlag'],
- 12: ['x'],
- 14: ['y'],
- 16: ['x','y','x2','y2'],
- 18: ['x','y']
- };
- function retPath() {
- return path;
- }
-
function resetD(p) {
p.setAttribute("d", pathActions.convertPath(p));
}
-
- function insertItemBefore(elem, newseg, index) {
- // Support insertItemBefore on paths for FF2
- var list = elem.pathSegList;
-
- if(svgedit.browser.supportsPathInsertItemBefore()) {
- list.insertItemBefore(newseg, index);
- return;
- }
- var len = list.numberOfItems;
- var arr = [];
- for(var i=0; i= len ? null : segs[i+1];
- var prev_seg = (i-1) < 0 ? null : segs[i-1];
-
- if(seg.type === 2) {
- if(prev_seg && prev_seg.type !== 1) {
- // New sub-path, last one is open,
- // so add a grip to last sub-path's first point
- var start_seg = segs[start_i];
- start_seg.next = segs[start_i+1];
- start_seg.next.prev = start_seg;
- start_seg.addGrip();
- }
- // Remember that this is a starter seg
- start_i = i;
- } else if(next_seg && next_seg.type === 1) {
- // This is the last real segment of a closed sub-path
- // Next is first seg after "M"
- seg.next = segs[start_i+1];
-
- // First seg after "M"'s prev is this
- seg.next.prev = seg;
- seg.mate = segs[start_i];
- seg.addGrip();
- if(p.first_seg == null) {
- p.first_seg = seg;
- }
- } else if(!next_seg) {
- if(seg.type !== 1) {
- // Last seg, doesn't close so add a grip
- // to last sub-path's first point
- var start_seg = segs[start_i];
- start_seg.next = segs[start_i+1];
- start_seg.next.prev = start_seg;
- start_seg.addGrip();
- seg.addGrip();
-
- if(!p.first_seg) {
- // Open path, so set first as real first and add grip
- p.first_seg = segs[start_i];
- }
- }
- } else if(seg.type !== 1){
- // Regular segment, so add grip and its "next"
- seg.addGrip();
-
- // Don't set its "next" if it's an "M"
- if(next_seg && next_seg.type !== 2) {
- seg.next = next_seg;
- seg.next.prev = seg;
- }
- }
- }
- return p;
- }
-
- this.init();
-
- // Update position of all points
- this.update = function() {
- if(getRotationAngle(p.elem)) {
- p.matrix = getMatrix(path.elem);
- p.imatrix = p.matrix.inverse();
- } else {
- p.matrix = null;
- p.imatrix = null;
- }
-
- p.eachSeg(function(i) {
- this.item = elem.pathSegList.getItem(i);
- this.update();
- });
-
- return p;
- }
-
- this.eachSeg = function(fn) {
- var len = p.segs.length
- for(var i=0; i < len; i++) {
- var ret = fn.call(p.segs[i], i);
- if(ret === false) break;
- }
- }
-
- this.addSeg = function(index) {
- // Adds a new segment
- var seg = p.segs[index];
- if(!seg.prev) return;
-
- var prev = seg.prev;
- var newseg;
- switch(seg.item.pathSegType) {
- case 4:
- var new_x = (seg.item.x + prev.item.x) / 2;
- var new_y = (seg.item.y + prev.item.y) / 2;
- newseg = elem.createSVGPathSegLinetoAbs(new_x, new_y);
- break;
- case 6: //make it a curved segment to preserve the shape (WRS)
- // http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation
- var p0_x = (prev.item.x + seg.item.x1)/2;
- var p1_x = (seg.item.x1 + seg.item.x2)/2;
- var p2_x = (seg.item.x2 + seg.item.x)/2;
- var p01_x = (p0_x + p1_x)/2;
- var p12_x = (p1_x + p2_x)/2;
- var new_x = (p01_x + p12_x)/2;
- var p0_y = (prev.item.y + seg.item.y1)/2;
- var p1_y = (seg.item.y1 + seg.item.y2)/2;
- var p2_y = (seg.item.y2 + seg.item.y)/2;
- var p01_y = (p0_y + p1_y)/2;
- var p12_y = (p1_y + p2_y)/2;
- var new_y = (p01_y + p12_y)/2;
- newseg = elem.createSVGPathSegCurvetoCubicAbs(new_x,new_y, p0_x,p0_y, p01_x,p01_y);
- var pts = [seg.item.x,seg.item.y,p12_x,p12_y,p2_x,p2_y];
- replacePathSeg(seg.type,index,pts);
- break;
- }
-
- insertItemBefore(elem, newseg, index);
- }
-
- this.deleteSeg = function(index) {
- var seg = p.segs[index];
- var list = elem.pathSegList;
-
- seg.show(false);
- var next = seg.next;
- if(seg.mate) {
- // Make the next point be the "M" point
- var pt = [next.item.x, next.item.y];
- replacePathSeg(2, next.index, pt);
-
- // Reposition last node
- replacePathSeg(4, seg.index, pt);
-
- list.removeItem(seg.mate.index);
- } else if(!seg.prev) {
- // First node of open path, make next point the M
- var item = seg.item;
- var pt = [next.item.x, next.item.y];
- replacePathSeg(2, seg.next.index, pt);
- list.removeItem(index);
-
- } else {
- list.removeItem(index);
- }
- }
-
- this.endChanges = function(text) {
- if(svgedit.browser.isWebkit()) resetD(p.elem);
- var cmd = new ChangeElementCommand(elem, {d: p.last_d}, text);
+ // TODO: Move into path.js
+ svgedit.path.Path.prototype.endChanges = function(text) {
+ if(svgedit.browser.isWebkit()) resetD(this.elem);
+ var cmd = new ChangeElementCommand(this.elem, {d: this.last_d}, text);
addCommandToHistory(cmd);
- call("changed", [elem]);
+ call("changed", [this.elem]);
}
- this.subpathIsClosed = function(index) {
- var closed = false;
- // Check if subpath is already open
- path.eachSeg(function(i) {
- if(i <= index) return true;
- if(this.type === 2) {
- // Found M first, so open
- return false;
- } else if(this.type === 1) {
- // Found Z first, so closed
- closed = true;
- return false;
- }
- });
-
- return closed;
- }
-
- this.addPtsToSelection = function(indexes) {
+ svgedit.path.Path.prototype.addPtsToSelection = function(indexes) {
if(!$.isArray(indexes)) indexes = [indexes];
for(var i=0; i< indexes.length; i++) {
var index = indexes[i];
- var seg = p.segs[index];
+ var seg = this.segs[index];
if(seg.ptgrip) {
- if(p.selected_pts.indexOf(index) == -1 && index >= 0) {
- p.selected_pts.push(index);
+ if(this.selected_pts.indexOf(index) == -1 && index >= 0) {
+ this.selected_pts.push(index);
}
}
};
- p.selected_pts.sort();
- var i = p.selected_pts.length,
+ this.selected_pts.sort();
+ var i = this.selected_pts.length,
grips = new Array(i);
// Loop through points to be selected and highlight each
while(i--) {
- var pt = p.selected_pts[i];
- var seg = p.segs[pt];
+ var pt = this.selected_pts[i];
+ var seg = this.segs[pt];
seg.select(true);
grips[i] = seg.ptgrip;
}
// TODO: Correct this:
pathActions.canDeleteNodes = true;
- pathActions.closed_subpath = p.subpathIsClosed(p.selected_pts[0]);
+ pathActions.closed_subpath = this.subpathIsClosed(this.selected_pts[0]);
call("selected", grips);
}
- this.removePtFromSelection = function(index) {
- var pos = p.selected_pts.indexOf(index);
- if(pos == -1) {
- return;
- }
- p.segs[index].select(false);
- p.selected_pts.splice(pos, 1);
- }
-
-
- this.clearSelection = function() {
- p.eachSeg(function(i) {
- this.select(false);
- });
- p.selected_pts = [];
- }
-
- this.selectPt = function(pt, ctrl_num) {
- p.clearSelection();
- if(pt == null) {
- p.eachSeg(function(i) {
- if(this.prev) {
- pt = i;
- }
- });
- }
- p.addPtsToSelection(pt);
- if(ctrl_num) {
- p.dragctrl = ctrl_num;
-
- if(link_control_pts) {
- p.segs[pt].setLinked(ctrl_num);
- }
- }
- }
-
- this.storeD = function() {
- this.last_d = elem.getAttribute('d');
- }
-
- this.show = function(y) {
- // Shows this path's segment grips
- p.eachSeg(function() {
- this.show(y);
- });
- if(y) {
- p.selectPt(p.first_seg.index);
- }
- return p;
- }
-
- // Move selected points
- this.movePts = function(d_x, d_y) {
- var i = p.selected_pts.length;
- while(i--) {
- var seg = p.segs[p.selected_pts[i]];
- seg.move(d_x, d_y);
- }
- }
-
- this.moveCtrl = function(d_x, d_y) {
- var seg = p.segs[p.selected_pts[0]];
- seg.moveCtrl(p.dragctrl, d_x, d_y);
- if(link_control_pts) {
- seg.setLinked(p.dragctrl);
- }
- }
-
- this.setSegType = function(new_type) {
- p.storeD();
- var i = p.selected_pts.length;
- var text;
- while(i--) {
- var sel_pt = p.selected_pts[i];
-
- // Selected seg
- var cur = p.segs[sel_pt];
- var prev = cur.prev;
- if(!prev) continue;
-
- if(!new_type) { // double-click, so just toggle
- text = "Toggle Path Segment Type";
-
- // Toggle segment to curve/straight line
- var old_type = cur.type;
-
- new_type = (old_type == 6) ? 4 : 6;
- }
-
- new_type = new_type-0;
-
- var cur_x = cur.item.x;
- var cur_y = cur.item.y;
- var prev_x = prev.item.x;
- var prev_y = prev.item.y;
- var points;
- switch ( new_type ) {
- case 6:
- if(cur.olditem) {
- var old = cur.olditem;
- points = [cur_x,cur_y, old.x1,old.y1, old.x2,old.y2];
- } else {
- var diff_x = cur_x - prev_x;
- var diff_y = cur_y - prev_y;
- // get control points from straight line segment
- /*
- var ct1_x = (prev_x + (diff_y/2));
- var ct1_y = (prev_y - (diff_x/2));
- var ct2_x = (cur_x + (diff_y/2));
- var ct2_y = (cur_y - (diff_x/2));
- */
- //create control points on the line to preserve the shape (WRS)
- var ct1_x = (prev_x + (diff_x/3));
- var ct1_y = (prev_y + (diff_y/3));
- var ct2_x = (cur_x - (diff_x/3));
- var ct2_y = (cur_y - (diff_y/3));
- points = [cur_x,cur_y, ct1_x,ct1_y, ct2_x,ct2_y];
- }
- break;
- case 4:
- points = [cur_x,cur_y];
-
- // Store original prevve segment nums
- cur.olditem = cur.item;
- break;
- }
-
- cur.setType(new_type, points);
- }
- path.endChanges(text);
- return;
- }
-
- }
-
- function getPath(elem) {
- var p = pathData[elem.id];
- if(!p) p = pathData[elem.id] = new Path(elem);
- return p;
- }
-
-
- var pathFuncs = [],
- current_path = null,
+ var current_path = null,
drawn_path = null,
- link_control_pts = true,
hasMoved = false;
// This function converts a polyline (created by the fh_path tool) into
@@ -4851,7 +3987,7 @@ var pathActions = canvas.pathActions = function() {
// if the previous segment had a control point, we want to smooth out
// the control points on both sides
if (prevCtlPt) {
- var newpts = smoothControlPoints( prevCtlPt, ct1, curpos );
+ var newpts = svgedit.path.smoothControlPoints( prevCtlPt, ct1, curpos );
if (newpts && newpts.length == 2) {
var prevArr = d[d.length-1].split(',');
prevArr[2] = newpts[0].x;
@@ -4888,124 +4024,8 @@ var pathActions = canvas.pathActions = function() {
}
return element;
};
-
- // This replaces the segment at the given index. Type is given as number.
- var replacePathSeg = function(type, index, pts, elem) {
- var path = elem || retPath().elem;
- var func = 'createSVGPathSeg' + pathFuncs[type];
- var seg = path[func].apply(path, pts);
-
- if(svgedit.browser.supportsPathReplaceItem()) {
- path.pathSegList.replaceItem(seg, index);
- } else {
- var segList = path.pathSegList;
- var len = segList.numberOfItems;
- var arr = [];
- for(var i=0; i or a ,
// in which we shouldn't need to convert anyway.
@@ -6836,7 +5852,7 @@ this.setSvgString = function(xmlString) {
// reset transform lists
svgedit.transformlist.resetListMap();
clearSelection();
- pathActions.clearData();
+ svgedit.path.clearData();
svgroot.appendChild(selectorManager.selectorParentGroup);
addCommandToHistory(batchCmd);
@@ -6880,6 +5896,8 @@ this.importSvgString = function(xmlString) {
}
}
+ var batchCmd = new BatchCommand("Import SVG");
+
if(useExisting) {
var symbol = import_ids[uid].symbol;
var ts = import_ids[uid].xform;
@@ -6889,8 +5907,6 @@ this.importSvgString = function(xmlString) {
this.prepareSvg(newDoc);
- var batchCmd = new BatchCommand("Import SVG");
-
// import new svg document into our document
var svg = svgdoc.importNode(newDoc.documentElement, true);
@@ -6961,7 +5977,7 @@ this.importSvgString = function(xmlString) {
use_el.setAttribute("transform", ts);
recalculateDimensions(use_el);
- $(use_el).data('symbol', symbol);
+ $(use_el).data('symbol', symbol).data('ref', symbol);
addToSelection([use_el]);
// TODO: Find way to add this in a recalculateDimensions-parsable way
@@ -6978,7 +5994,7 @@ this.importSvgString = function(xmlString) {
return true;
};
-
+// TODO(codedread): Move all layer/context functions in draw.js
// Layer API Functions
// Group: Layers
@@ -7408,7 +6424,7 @@ this.getZoom = function(){return current_zoom;};
// Function: getVersion
// Returns a string which describes the revision number of SvgCanvas.
this.getVersion = function() {
- return "svgcanvas.js ($Rev: 1972 $)";
+ return "svgcanvas.js ($Rev: 2028 $)";
};
// Function: setUiStrings
@@ -7841,7 +6857,7 @@ var findDuplicateGradient = function(grad) {
};
function reorientGrads(elem, m) {
- var bb = getBBox(elem);
+ var bb = svgedit.utilities.getBBox(elem);
for(var i = 0; i < 2; i++) {
var type = i === 0 ? 'fill' : 'stroke';
var attrVal = elem.getAttribute(type);
@@ -8305,6 +7321,23 @@ this.setFontFamily = function(val) {
}
};
+
+// Function: setFontColor
+// Set the new font color
+//
+// Parameters:
+// val - String with the new font color
+this.setFontColor = function(val) {
+ cur_text.fill = val;
+ changeSelectedAttribute("fill", val);
+};
+
+// Function: getFontColor
+// Returns the current font color
+this.getFontSize = function() {
+ return cur_text.fill;
+};
+
// Function: getFontSize
// Returns the current font size
this.getFontSize = function() {
@@ -8699,7 +7732,7 @@ var changeSelectedAttributeNoUndo = function(attr, newValue, elems) {
if (oldval == null) oldval = "";
if (oldval !== String(newValue)) {
if (attr == "#text") {
- var old_w = getBBox(elem).width;
+ var old_w = svgedit.utilities.getBBox(elem).width;
elem.textContent = newValue;
// FF bug occurs on on rotated elements
@@ -8727,8 +7760,8 @@ var changeSelectedAttributeNoUndo = function(attr, newValue, elems) {
setHref(elem, newValue);
}
else elem.setAttribute(attr, newValue);
- if (i==0)
- selectedBBoxes[i] = getBBox(elem);
+// if (i==0)
+// selectedBBoxes[0] = svgedit.utilities.getBBox(elem);
// Use the Firefox ffClone hack for text elements with gradients or
// where other text attributes are changed.
if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) {
@@ -8760,7 +7793,7 @@ var changeSelectedAttributeNoUndo = function(attr, newValue, elems) {
// remove old rotate
tlist.removeItem(n);
- var box = getBBox(elem);
+ var box = svgedit.utilities.getBBox(elem);
var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix);
var cx = center.x,
cy = center.y;
@@ -8816,6 +7849,9 @@ this.deleteSelectedElements = function() {
// this will unselect the element and remove the selectedOutline
selectorManager.releaseSelector(t);
+ // Remove the path if present.
+ svgedit.path.removePath_(t.id);
+
// Get the parent if it's a single-child anchor
if(parent.tagName === 'a' && parent.childNodes.length === 1) {
t = parent;
@@ -8848,8 +7884,13 @@ this.cutSelectedElements = function() {
var parent = selected.parentNode;
var t = selected;
+
// this will unselect the element and remove the selectedOutline
selectorManager.releaseSelector(t);
+
+ // Remove the path if present.
+ svgedit.path.removePath_(t.id);
+
var nextSibling = t.nextSibling;
var elem = parent.removeChild(t);
selectedCopy.push(selected); //for the copy
@@ -9097,7 +8138,7 @@ var pushGroupProperties = this.pushGroupProperties = function(g, undoable) {
}
// get child's old center of rotation
- var cbox = getBBox(elem);
+ var cbox = svgedit.utilities.getBBox(elem);
var ceqm = transformListToTransform(chtlist).matrix;
var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm);
@@ -9186,7 +8227,7 @@ this.ungroupSelectedElement = function() {
} else if(g.tagName === 'use') {
// Somehow doesn't have data set, so retrieve
var symbol = getElem(getHref(g).substr(1));
- $(g).data('symbol', symbol);
+ $(g).data('symbol', symbol).data('ref', symbol);
convertToGroup(g);
return;
}
@@ -9350,28 +8391,28 @@ this.moveSelectedElements = function(dx, dy, undoable) {
while (i--) {
var selected = selectedElements[i];
if (selected != null) {
- if (i==0)
- selectedBBoxes[i] = getBBox(selected);
+// if (i==0)
+// selectedBBoxes[0] = svgedit.utilities.getBBox(selected);
- var b = {};
- for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j];
- selectedBBoxes[i] = b;
+// var b = {};
+// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j];
+// selectedBBoxes[i] = b;
var xform = svgroot.createSVGTransform();
var tlist = getTransformList(selected);
// dx and dy could be arrays
if (dx.constructor == Array) {
- if (i==0) {
- selectedBBoxes[i].x += dx[i];
- selectedBBoxes[i].y += dy[i];
- }
+// if (i==0) {
+// selectedBBoxes[0].x += dx[0];
+// selectedBBoxes[0].y += dy[0];
+// }
xform.setTranslate(dx[i],dy[i]);
} else {
- if (i==0) {
- selectedBBoxes[i].x += dx;
- selectedBBoxes[i].y += dy;
- }
+// if (i==0) {
+// selectedBBoxes[0].x += dx;
+// selectedBBoxes[0].y += dy;
+// }
xform.setTranslate(dx,dy);
}
@@ -9646,7 +8687,6 @@ this.getPrivateMethods = function() {
BatchCommand: BatchCommand,
call: call,
ChangeElementCommand: ChangeElementCommand,
- cleanupElement: cleanupElement,
copyElem: copyElem,
ffClone: ffClone,
findDefs: findDefs,
@@ -9684,32 +8724,4 @@ this.getPrivateMethods = function() {
return obj;
};
-(function() {
- // Temporary fix until MS fixes:
- // https://connect.microsoft.com/IE/feedback/details/599257/
- var disableAdvancedTextEdit = function() {
- var curtext;
- var textInput = $('#text').css({
- position: 'static'
- });
-
- $.each(['mouseDown','mouseUp','mouseMove', 'setCursor', 'init', 'select', 'toEditMode'], function() {
- textActions[this] = $.noop;
- });
-
- textActions.init = function(elem) {
- curtext = elem;
- $(curtext).unbind('dblclick').bind('dblclick', function() {
- textInput.focus();
- });
- }
-
- canvas.textActions = textActions;
- }
-
- if (!svgedit.browser.supportsTextCharPos()) {
- disableAdvancedTextEdit();
- }
-})();
-
}
diff --git a/public/svg-edit/editor/svgutils.js b/public/svg-edit/editor/svgutils.js
index 3dbf0f9d..931fb334 100644
--- a/public/svg-edit/editor/svgutils.js
+++ b/public/svg-edit/editor/svgutils.js
@@ -9,8 +9,8 @@
// Dependencies:
// 1) jQuery
-// 2) browser.js: only for getBBox()
-// 3) svgtransformlist.js: only for getRotationAngle()
+// 2) browser.js
+// 3) svgtransformlist.js
var svgedit = svgedit || {};
@@ -26,6 +26,7 @@ if (!svgedit.utilities) {
var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var SVGNS = 'http://www.w3.org/2000/svg';
var XLINKNS = 'http://www.w3.org/1999/xlink';
+var XMLNS = "http://www.w3.org/XML/1998/namespace";
// Much faster than running getBBox() every time
var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use';
@@ -33,9 +34,15 @@ var visElems_arr = visElems.split(',');
//var hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath';
var editorContext_ = null;
+var domdoc_ = null;
+var domcontainer_ = null;
+var svgroot_ = null;
svgedit.utilities.init = function(editorContext) {
editorContext_ = editorContext;
+ domdoc_ = editorContext.getDOMDocument();
+ domcontainer_ = editorContext.getDOMContainer();
+ svgroot_ = editorContext.getSVGRoot();
};
// Function: svgedit.utilities.toXml
@@ -402,6 +409,52 @@ svgedit.utilities.getPathBBox = function(path) {
};
};
+// Function: groupBBFix
+// Get the given/selected element's bounding box object, checking for
+// horizontal/vertical lines (see issue 717)
+// Note that performance is currently terrible, so some way to improve would
+// be great.
+//
+// Parameters:
+// selected - Container or