Update SVG-Edit
This commit is contained in:
parent
0df40cb4cb
commit
ade1c1d113
|
@ -17,7 +17,6 @@ var svgedit = svgedit || {};
|
||||||
if (!svgedit.browser) {
|
if (!svgedit.browser) {
|
||||||
svgedit.browser = {};
|
svgedit.browser = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var supportsSvg_ = (function() {
|
var supportsSvg_ = (function() {
|
||||||
return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
|
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 isOpera_ = !!window.opera;
|
||||||
var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0;
|
var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0;
|
||||||
var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
|
var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
|
||||||
|
var isIE_ = userAgent.indexOf('MSIE') >= 0;
|
||||||
|
|
||||||
var supportsSelectors_ = (function() {
|
var supportsSelectors_ = (function() {
|
||||||
return !!svg.querySelector;
|
return !!svg.querySelector;
|
||||||
|
@ -69,20 +69,20 @@ var supportsPathInsertItemBefore_ = (function() {
|
||||||
return false;
|
return false;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// text character positioning
|
// text character positioning (for IE9)
|
||||||
var supportsTextCharPos_ = (function() {
|
var supportsGoodTextCharPos_ = (function() {
|
||||||
var retValue = false;
|
var retValue = false;
|
||||||
|
var svgroot = document.createElementNS(svgns, 'svg');
|
||||||
var svgcontent = document.createElementNS(svgns, 'svg');
|
var svgcontent = document.createElementNS(svgns, 'svg');
|
||||||
document.documentElement.appendChild(svgcontent);
|
document.documentElement.appendChild(svgroot);
|
||||||
try {
|
svgcontent.setAttribute('x', 5);
|
||||||
|
svgroot.appendChild(svgcontent);
|
||||||
var text = document.createElementNS(svgns,'text');
|
var text = document.createElementNS(svgns,'text');
|
||||||
text.textContent = 'a';
|
text.textContent = 'a';
|
||||||
svgcontent.appendChild(text);
|
svgcontent.appendChild(text);
|
||||||
text.getStartPositionOfChar(0);
|
var pos = text.getStartPositionOfChar(0).x;
|
||||||
retValue = true;
|
document.documentElement.removeChild(svgroot);
|
||||||
} catch(err) {}
|
return (pos === 0);
|
||||||
document.documentElement.removeChild(svgcontent);
|
|
||||||
return retValue;
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var supportsPathBBox_ = (function() {
|
var supportsPathBBox_ = (function() {
|
||||||
|
@ -96,6 +96,24 @@ var supportsPathBBox_ = (function() {
|
||||||
return (bbox.height > 4 && bbox.height < 5);
|
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() {
|
var supportsEditableText_ = (function() {
|
||||||
// TODO: Find better way to check support for this
|
// TODO: Find better way to check support for this
|
||||||
return isOpera_;
|
return isOpera_;
|
||||||
|
@ -134,6 +152,7 @@ var supportsNativeSVGTransformLists_ = (function() {
|
||||||
svgedit.browser.isOpera = function() { return isOpera_; }
|
svgedit.browser.isOpera = function() { return isOpera_; }
|
||||||
svgedit.browser.isWebkit = function() { return isWebkit_; }
|
svgedit.browser.isWebkit = function() { return isWebkit_; }
|
||||||
svgedit.browser.isGecko = function() { return isGecko_; }
|
svgedit.browser.isGecko = function() { return isGecko_; }
|
||||||
|
svgedit.browser.isIE = function() { return isIE_; }
|
||||||
|
|
||||||
svgedit.browser.supportsSelectors = function() { return supportsSelectors_; }
|
svgedit.browser.supportsSelectors = function() { return supportsSelectors_; }
|
||||||
svgedit.browser.supportsXpath = function() { return supportsXpath_; }
|
svgedit.browser.supportsXpath = function() { return supportsXpath_; }
|
||||||
|
@ -141,7 +160,8 @@ svgedit.browser.supportsXpath = function() { return supportsXpath_; }
|
||||||
svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; }
|
svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; }
|
||||||
svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; }
|
svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; }
|
||||||
svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; }
|
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.supportsEditableText = function() { return supportsEditableText_; }
|
||||||
svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; }
|
svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; }
|
||||||
svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; }
|
svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; }
|
||||||
|
|
|
@ -23,6 +23,9 @@ var svg_ns = "http://www.w3.org/2000/svg";
|
||||||
var se_ns = "http://svg-edit.googlecode.com";
|
var se_ns = "http://svg-edit.googlecode.com";
|
||||||
var xmlns_ns = "http://www.w3.org/2000/xmlns/";
|
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 = {
|
var RandomizeModes = {
|
||||||
LET_DOCUMENT_DECIDE: 0,
|
LET_DOCUMENT_DECIDE: 0,
|
||||||
ALWAYS_RANDOMIZE: 1,
|
ALWAYS_RANDOMIZE: 1,
|
||||||
|
@ -375,8 +378,8 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
|
||||||
orphans.push(child);
|
orphans.push(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if child has a bbox (i.e. not a <title> or <defs> element), then it is an orphan
|
// if child has is "visible" (i.e. not a <title> or <defs> element), then it is an orphan
|
||||||
else if(svgedit.utilities.getBBox(child) && child.nodeName != 'defs') { // Opera returns a BBox for defs
|
else if(~visElems_arr.indexOf(child.nodeName)) {
|
||||||
var bb = svgedit.utilities.getBBox(child);
|
var bb = svgedit.utilities.getBBox(child);
|
||||||
orphans.push(child);
|
orphans.push(child);
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
|
||||||
|
|
||||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||||
if(this.nextSibling == null) {
|
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);
|
this.parent.insertBefore(this.elem, this.nextSibling);
|
||||||
|
|
||||||
|
|
|
@ -304,15 +304,15 @@ var svgEditor = (function($, Editor) {
|
||||||
|
|
||||||
var url = conf.langPath + "lang." + lang_param + ".js";
|
var url = conf.langPath + "lang." + lang_param + ".js";
|
||||||
|
|
||||||
$.ajax({
|
$.getScript(url, function(d) {
|
||||||
'url': url,
|
// Fails locally in Chrome 5+
|
||||||
'dataType': "script",
|
if(!d) {
|
||||||
error: function(xhr) {
|
var s = document.createElement('script');
|
||||||
if(xhr.responseText) {
|
s.src = url;
|
||||||
Editor.readLang(eval(xhr.responseText));
|
document.querySelector('head').appendChild(s);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Editor;
|
return Editor;
|
||||||
|
|
|
@ -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
|
// Function: svgedit.math.snapToAngle
|
||||||
// Returns a 45 degree angle coordinate associated with the two given
|
// Returns a 45 degree angle coordinate associated with the two given
|
||||||
// coordinates
|
// coordinates
|
||||||
|
|
980
public/svg-edit/editor/path.js
Normal file
980
public/svg-edit/editor/path.js
Normal file
|
@ -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<len; i++) {
|
||||||
|
var cur_seg = list.getItem(i);
|
||||||
|
arr.push(cur_seg)
|
||||||
|
}
|
||||||
|
list.clear();
|
||||||
|
for(var i=0; i<len; i++) {
|
||||||
|
if(i == index) { //index+1
|
||||||
|
list.appendItem(newseg);
|
||||||
|
}
|
||||||
|
list.appendItem(arr[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: See if this should just live in replacePathSeg
|
||||||
|
svgedit.path.ptObjToArr = function(type, seg_item) {
|
||||||
|
var arr = segData[type], len = arr.length;
|
||||||
|
var out = Array(len);
|
||||||
|
for(var i=0; i<len; i++) {
|
||||||
|
out[i] = seg_item[arr[i]];
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getGripPt = function(seg, alt_pt) {
|
||||||
|
var out = {
|
||||||
|
x: alt_pt? alt_pt.x : seg.item.x,
|
||||||
|
y: alt_pt? alt_pt.y : seg.item.y
|
||||||
|
}, path = seg.path;
|
||||||
|
|
||||||
|
if(path.matrix) {
|
||||||
|
var pt = svgedit.math.transformPoint(out.x, out.y, path.matrix);
|
||||||
|
out = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.x *= editorContext_.getCurrentZoom();
|
||||||
|
out.y *= editorContext_.getCurrentZoom();
|
||||||
|
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getPointFromGrip = function(pt, path) {
|
||||||
|
var out = {
|
||||||
|
x: pt.x,
|
||||||
|
y: pt.y
|
||||||
|
}
|
||||||
|
|
||||||
|
if(path.matrix) {
|
||||||
|
var pt = svgedit.math.transformPoint(out.x, out.y, path.imatrix);
|
||||||
|
out.x = pt.x;
|
||||||
|
out.y = pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.x /= editorContext_.getCurrentZoom();
|
||||||
|
out.y /= editorContext_.getCurrentZoom();
|
||||||
|
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.addPointGrip = function(index, x, y) {
|
||||||
|
// create the container of all the point grips
|
||||||
|
var pointGripContainer = svgedit.path.getGripContainer();
|
||||||
|
|
||||||
|
var pointGrip = svgedit.utilities.getElem("pathpointgrip_"+index);
|
||||||
|
// create it
|
||||||
|
if (!pointGrip) {
|
||||||
|
pointGrip = document.createElementNS(svgns, "circle");
|
||||||
|
svgedit.utilities.assignAttributes(pointGrip, {
|
||||||
|
'id': "pathpointgrip_" + index,
|
||||||
|
'display': "none",
|
||||||
|
'r': 4,
|
||||||
|
'fill': "#0FF",
|
||||||
|
'stroke': "#00F",
|
||||||
|
'stroke-width': 2,
|
||||||
|
'cursor': 'move',
|
||||||
|
'style': 'pointer-events:all',
|
||||||
|
'xlink:title': uiStrings.pathNodeTooltip
|
||||||
|
});
|
||||||
|
pointGrip = pointGripContainer.appendChild(pointGrip);
|
||||||
|
|
||||||
|
var grip = $('#pathpointgrip_'+index);
|
||||||
|
grip.dblclick(function() {
|
||||||
|
if(svgedit.path.path) svgedit.path.path.setSegType();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(x && y) {
|
||||||
|
// set up the point grip element and display it
|
||||||
|
svgedit.utilities.assignAttributes(pointGrip, {
|
||||||
|
'cx': x,
|
||||||
|
'cy': y,
|
||||||
|
'display': "inline"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return pointGrip;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getGripContainer = function() {
|
||||||
|
var c = svgedit.utilities.getElem("pathpointgrip_container");
|
||||||
|
if (!c) {
|
||||||
|
var parent = svgedit.utilities.getElem("selectorParentGroup");
|
||||||
|
c = parent.appendChild(document.createElementNS(svgns, "g"));
|
||||||
|
c.id = "pathpointgrip_container";
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.addCtrlGrip = function(id) {
|
||||||
|
var pointGrip = svgedit.utilities.getElem("ctrlpointgrip_"+id);
|
||||||
|
if(pointGrip) return pointGrip;
|
||||||
|
|
||||||
|
pointGrip = document.createElementNS(svgns, "circle");
|
||||||
|
svgedit.utilities.assignAttributes(pointGrip, {
|
||||||
|
'id': "ctrlpointgrip_" + id,
|
||||||
|
'display': "none",
|
||||||
|
'r': 4,
|
||||||
|
'fill': "#0FF",
|
||||||
|
'stroke': "#55F",
|
||||||
|
'stroke-width': 1,
|
||||||
|
'cursor': 'move',
|
||||||
|
'style': 'pointer-events:all',
|
||||||
|
'xlink:title': uiStrings.pathCtrlPtTooltip
|
||||||
|
});
|
||||||
|
svgedit.path.getGripContainer().appendChild(pointGrip);
|
||||||
|
return pointGrip;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getCtrlLine = function(id) {
|
||||||
|
var ctrlLine = svgedit.utilities.getElem("ctrlLine_"+id);
|
||||||
|
if(ctrlLine) return ctrlLine;
|
||||||
|
|
||||||
|
ctrlLine = document.createElementNS(svgns, "line");
|
||||||
|
svgedit.utilities.assignAttributes(ctrlLine, {
|
||||||
|
'id': "ctrlLine_"+id,
|
||||||
|
'stroke': "#555",
|
||||||
|
'stroke-width': 1,
|
||||||
|
"style": "pointer-events:none"
|
||||||
|
});
|
||||||
|
svgedit.path.getGripContainer().appendChild(ctrlLine);
|
||||||
|
return ctrlLine;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getPointGrip = function(seg, update) {
|
||||||
|
var index = seg.index;
|
||||||
|
var pointGrip = svgedit.path.addPointGrip(index);
|
||||||
|
|
||||||
|
if(update) {
|
||||||
|
var pt = svgedit.path.getGripPt(seg);
|
||||||
|
svgedit.utilities.assignAttributes(pointGrip, {
|
||||||
|
'cx': pt.x,
|
||||||
|
'cy': pt.y,
|
||||||
|
'display': "inline"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointGrip;
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getControlPoints = function(seg) {
|
||||||
|
var item = seg.item;
|
||||||
|
var index = seg.index;
|
||||||
|
if(!("x1" in item) || !("x2" in item)) return null;
|
||||||
|
var cpt = {};
|
||||||
|
var pointGripContainer = svgedit.path.getGripContainer();
|
||||||
|
|
||||||
|
// Note that this is intentionally not seg.prev.item
|
||||||
|
var prev = svgedit.path.path.segs[index-1].item;
|
||||||
|
|
||||||
|
var seg_items = [prev, item];
|
||||||
|
|
||||||
|
for(var i=1; i<3; i++) {
|
||||||
|
var id = index + 'c' + i;
|
||||||
|
|
||||||
|
var ctrlLine = cpt['c' + i + '_line'] = svgedit.path.getCtrlLine(id);
|
||||||
|
|
||||||
|
var pt = svgedit.path.getGripPt(seg, {x:item['x' + i], y:item['y' + i]});
|
||||||
|
var gpt = svgedit.path.getGripPt(seg, {x:seg_items[i-1].x, y:seg_items[i-1].y});
|
||||||
|
|
||||||
|
svgedit.utilities.assignAttributes(ctrlLine, {
|
||||||
|
'x1': pt.x,
|
||||||
|
'y1': pt.y,
|
||||||
|
'x2': gpt.x,
|
||||||
|
'y2': gpt.y,
|
||||||
|
'display': "inline"
|
||||||
|
});
|
||||||
|
|
||||||
|
cpt['c' + i + '_line'] = ctrlLine;
|
||||||
|
|
||||||
|
// create it
|
||||||
|
pointGrip = cpt['c' + i] = svgedit.path.addCtrlGrip(id);
|
||||||
|
|
||||||
|
svgedit.utilities.assignAttributes(pointGrip, {
|
||||||
|
'cx': pt.x,
|
||||||
|
'cy': pt.y,
|
||||||
|
'display': "inline"
|
||||||
|
});
|
||||||
|
cpt['c' + i] = pointGrip;
|
||||||
|
}
|
||||||
|
return cpt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This replaces the segment at the given index. Type is given as number.
|
||||||
|
svgedit.path.replacePathSeg = function(type, index, pts, elem) {
|
||||||
|
var path = elem || svgedit.path.path.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<len; i++) {
|
||||||
|
var cur_seg = segList.getItem(i);
|
||||||
|
arr.push(cur_seg)
|
||||||
|
}
|
||||||
|
segList.clear();
|
||||||
|
for(var i=0; i<len; i++) {
|
||||||
|
if(i == index) {
|
||||||
|
segList.appendItem(seg);
|
||||||
|
} else {
|
||||||
|
segList.appendItem(arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
svgedit.path.getSegSelector = function(seg, update) {
|
||||||
|
var index = seg.index;
|
||||||
|
var segLine = svgedit.utilities.getElem("segline_" + index);
|
||||||
|
if(!segLine) {
|
||||||
|
var pointGripContainer = svgedit.path.getGripContainer();
|
||||||
|
// create segline
|
||||||
|
segLine = document.createElementNS(svgns, "path");
|
||||||
|
svgedit.utilities.assignAttributes(segLine, {
|
||||||
|
'id': "segline_" + index,
|
||||||
|
'display': 'none',
|
||||||
|
'fill': "none",
|
||||||
|
'stroke': "#0FF",
|
||||||
|
'stroke-width': 2,
|
||||||
|
'style':'pointer-events:none',
|
||||||
|
'd': 'M0,0 0,0'
|
||||||
|
});
|
||||||
|
pointGripContainer.appendChild(segLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(update) {
|
||||||
|
var prev = seg.prev;
|
||||||
|
if(!prev) {
|
||||||
|
segLine.setAttribute("display", "none");
|
||||||
|
return segLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pt = svgedit.path.getGripPt(prev);
|
||||||
|
// Set start point
|
||||||
|
svgedit.path.replacePathSeg(2, 0, [pt.x, pt.y], segLine);
|
||||||
|
|
||||||
|
var pts = svgedit.path.ptObjToArr(seg.type, seg.item, true);
|
||||||
|
for(var i=0; i < pts.length; i+=2) {
|
||||||
|
var pt = svgedit.path.getGripPt(seg, {x:pts[i], y:pts[i+1]});
|
||||||
|
pts[i] = pt.x;
|
||||||
|
pts[i+1] = pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
svgedit.path.replacePathSeg(seg.type, 1, pts, segLine);
|
||||||
|
}
|
||||||
|
return segLine;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
svgedit.path.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 = editorContext_.getSVGRoot().createSVGPoint(),
|
||||||
|
nct2 = editorContext_.getSVGRoot().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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 <path> 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 = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -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<b(d,"offsetTop")+this.spinCfg._btn_height)?1:-1):0;if(f!==this.spinCfg._direction){switch(f){case 1:$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass);break;case -1:$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);break;default:$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass)}this.spinCfg._direction=f}}).mouseout(function(){$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);this.spinCfg._direction=null}).mousedown(function(f){if(this.spinCfg._direction!=0){var c=this;var d=function(){c.adjustValue(c.spinCfg._direction*c.spinCfg.step)};d();c.spinCfg._delay=window.setTimeout(function(){d();c.spinCfg._repeat=window.setInterval(d,c.spinCfg.interval)},c.spinCfg.delay)}}).mouseup(function(c){window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).dblclick(function(c){if($.browser.msie){this.adjustValue(this.spinCfg._direction*this.spinCfg.step)}}).keydown(function(c){switch(c.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page);break}}).keypress(function(c){if(this.repeating){switch(c.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page);break}}else{this.repeating=true}}).keyup(function(c){this.repeating=false;this.adjustValue(0)}).bind("mousewheel",function(c){if(c.wheelDelta>=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}};
|
$.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<f(a,"offsetTop")+g*d?1:-1:0;if(c!==this.spinCfg._direction){switch(c){case 1:$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass);
|
||||||
|
break;case -1:$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);break;default:$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass)}this.spinCfg._direction=c}}).mouseout(function(){$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);this.spinCfg._direction=null;window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).mousedown(function(a){if(a.button===0&&this.spinCfg._direction!=0){var c=this,
|
||||||
|
e=a.shiftKey?c.spinCfg.smallStep:c.spinCfg.step,d=function(){c.adjustValue(c.spinCfg._direction*e)};d();c.spinCfg._delay=window.setTimeout(function(){d();c.spinCfg._repeat=window.setInterval(d,c.spinCfg.interval)},c.spinCfg.delay)}}).mouseup(function(){window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).dblclick(function(){$.browser.msie&&this.adjustValue(this.spinCfg._direction*this.spinCfg.step)}).keydown(function(a){switch(a.keyCode){case 38:this.adjustValue(this.spinCfg.step);
|
||||||
|
break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}}).keypress(function(a){if(this.repeating)switch(a.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}else this.repeating=true}).keyup(function(a){this.repeating=false;switch(a.keyCode){case 38:case 40:case 33:case 34:case 13:this.adjustValue(0)}}).bind("mousewheel",
|
||||||
|
function(a){if(a.wheelDelta>=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)})};
|
|
@ -35,6 +35,7 @@
|
||||||
<script type="text/javascript" src="history.js"></script>
|
<script type="text/javascript" src="history.js"></script>
|
||||||
<script type="text/javascript" src="select.js"></script>
|
<script type="text/javascript" src="select.js"></script>
|
||||||
<script type="text/javascript" src="draw.js"></script>
|
<script type="text/javascript" src="draw.js"></script>
|
||||||
|
<script type="text/javascript" src="path.js"></script>
|
||||||
<script type="text/javascript" src="svgcanvas.js"></script>
|
<script type="text/javascript" src="svgcanvas.js"></script>
|
||||||
<script type="text/javascript" src="svg-editor.js"></script>
|
<script type="text/javascript" src="svg-editor.js"></script>
|
||||||
<script type="text/javascript" src="locale/locale.js"></script>
|
<script type="text/javascript" src="locale/locale.js"></script>
|
||||||
|
|
|
@ -1509,9 +1509,9 @@
|
||||||
if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
|
if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
|
||||||
promptImgURL();
|
promptImgURL();
|
||||||
}
|
}
|
||||||
} else if(elname == 'text') {
|
} /*else if(elname == 'text') {
|
||||||
// TODO: Do something here for new text
|
// TODO: Do something here for new text
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_node && currentMode != 'pathedit') {
|
if(!is_node && currentMode != 'pathedit') {
|
||||||
|
@ -1887,6 +1887,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#g_title').change(function() {
|
||||||
|
svgCanvas.setGroupTitle(this.value);
|
||||||
|
});
|
||||||
|
|
||||||
$('.attr_changer').change(function() {
|
$('.attr_changer').change(function() {
|
||||||
var attr = this.getAttribute("data-attr");
|
var attr = this.getAttribute("data-attr");
|
||||||
var val = this.value;
|
var val = this.value;
|
||||||
|
@ -1898,6 +1902,7 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attr !== "id") {
|
||||||
if (isNaN(val)) {
|
if (isNaN(val)) {
|
||||||
val = svgCanvas.convertToNum(attr, val);
|
val = svgCanvas.convertToNum(attr, val);
|
||||||
} else if(curConfig.baseUnit !== 'px') {
|
} else if(curConfig.baseUnit !== 'px') {
|
||||||
|
@ -1909,6 +1914,7 @@
|
||||||
val *= unitData[curConfig.baseUnit];
|
val *= unitData[curConfig.baseUnit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if the user is changing the id, then de-select the element first
|
// if the user is changing the id, then de-select the element first
|
||||||
// change the ID, then re-select it with the new ID
|
// change the ID, then re-select it with the new ID
|
||||||
|
@ -1965,9 +1971,11 @@
|
||||||
$("#toggle_stroke_tools").toggle(function() {
|
$("#toggle_stroke_tools").toggle(function() {
|
||||||
$(".stroke_tool").css('display','table-cell');
|
$(".stroke_tool").css('display','table-cell');
|
||||||
$(this).text('<<');
|
$(this).text('<<');
|
||||||
|
resetScrollPos();
|
||||||
}, function() {
|
}, function() {
|
||||||
$(".stroke_tool").css('display','none');
|
$(".stroke_tool").css('display','none');
|
||||||
$(this).text('>>');
|
$(this).text('>>');
|
||||||
|
resetScrollPos();
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is a common function used when a tool has been clicked (chosen)
|
// This is a common function used when a tool has been clicked (chosen)
|
||||||
|
@ -3195,7 +3203,7 @@
|
||||||
} else if (preferences) {
|
} else if (preferences) {
|
||||||
hidePreferences();
|
hidePreferences();
|
||||||
}
|
}
|
||||||
|
resetScrollPos();
|
||||||
};
|
};
|
||||||
|
|
||||||
var hideSourceEditor = function(){
|
var hideSourceEditor = function(){
|
||||||
|
@ -3219,6 +3227,42 @@
|
||||||
|
|
||||||
var win_wh = {width:$(window).width(), height:$(window).height()};
|
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) {
|
$(window).resize(function(evt) {
|
||||||
if (editingsource) {
|
if (editingsource) {
|
||||||
properlySourceSizeTextArea();
|
properlySourceSizeTextArea();
|
||||||
|
@ -3436,7 +3480,15 @@
|
||||||
if(!selectedElement) return;
|
if(!selectedElement) return;
|
||||||
var type = this.type;
|
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 gPaint = null;
|
||||||
|
|
||||||
var childs = selectedElement.getElementsByTagName('*');
|
var childs = selectedElement.getElementsByTagName('*');
|
||||||
|
@ -3458,8 +3510,8 @@
|
||||||
var paintColor = gPaint;
|
var paintColor = gPaint;
|
||||||
|
|
||||||
var paintOpacity = 1;
|
var paintOpacity = 1;
|
||||||
|
break;
|
||||||
} else {
|
default:
|
||||||
var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity"));
|
var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity"));
|
||||||
if (isNaN(paintOpacity)) {
|
if (isNaN(paintOpacity)) {
|
||||||
paintOpacity = 1.0;
|
paintOpacity = 1.0;
|
||||||
|
@ -4196,7 +4248,9 @@
|
||||||
$('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize });
|
$('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize });
|
||||||
$('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity });
|
$('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity });
|
||||||
$('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur });
|
$('#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({
|
$("#workarea").contextMenu({
|
||||||
menu: 'cmenu_canvas',
|
menu: 'cmenu_canvas',
|
||||||
|
@ -4583,7 +4637,7 @@
|
||||||
updateCanvas(true);
|
updateCanvas(true);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// var revnums = "svg-editor.js ($Rev: 1973 $) ";
|
// var revnums = "svg-editor.js ($Rev: 2028 $) ";
|
||||||
// revnums += svgCanvas.getVersion();
|
// revnums += svgCanvas.getVersion();
|
||||||
// $('#copyright')[0].setAttribute("title", revnums);
|
// $('#copyright')[0].setAttribute("title", revnums);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
// Dependencies:
|
// Dependencies:
|
||||||
// 1) jQuery
|
// 1) jQuery
|
||||||
// 2) browser.js: only for getBBox()
|
// 2) browser.js
|
||||||
// 3) svgtransformlist.js: only for getRotationAngle()
|
// 3) svgtransformlist.js
|
||||||
|
|
||||||
var svgedit = svgedit || {};
|
var svgedit = svgedit || {};
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ if (!svgedit.utilities) {
|
||||||
var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||||
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";
|
||||||
|
|
||||||
// Much faster than running getBBox() every time
|
// Much faster than running getBBox() every time
|
||||||
var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use';
|
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 hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath';
|
||||||
|
|
||||||
var editorContext_ = null;
|
var editorContext_ = null;
|
||||||
|
var domdoc_ = null;
|
||||||
|
var domcontainer_ = null;
|
||||||
|
var svgroot_ = null;
|
||||||
|
|
||||||
svgedit.utilities.init = function(editorContext) {
|
svgedit.utilities.init = function(editorContext) {
|
||||||
editorContext_ = editorContext;
|
editorContext_ = editorContext;
|
||||||
|
domdoc_ = editorContext.getDOMDocument();
|
||||||
|
domcontainer_ = editorContext.getDOMContainer();
|
||||||
|
svgroot_ = editorContext.getSVGRoot();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function: svgedit.utilities.toXml
|
// 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 <use> DOM element
|
||||||
|
function groupBBFix(selected) {
|
||||||
|
if(svgedit.browser.supportsHVLineContainerBBox()) {
|
||||||
|
try { return selected.getBBox();} catch(e){}
|
||||||
|
}
|
||||||
|
var ref = $.data(selected, 'ref');
|
||||||
|
var matched = null;
|
||||||
|
|
||||||
|
if(ref) {
|
||||||
|
var copy = $(ref).children().clone().attr('visibility', 'hidden');
|
||||||
|
$(svgroot_).append(copy);
|
||||||
|
matched = copy.filter('line, path');
|
||||||
|
} else {
|
||||||
|
matched = $(selected).find('line, path');
|
||||||
|
}
|
||||||
|
|
||||||
|
var issue = false;
|
||||||
|
if(matched.length) {
|
||||||
|
matched.each(function() {
|
||||||
|
var bb = this.getBBox();
|
||||||
|
if(!bb.width || !bb.height) {
|
||||||
|
issue = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(issue) {
|
||||||
|
var elems = ref ? copy : $(selected).children();
|
||||||
|
ret = getStrokedBBox(elems);
|
||||||
|
} else {
|
||||||
|
ret = selected.getBBox();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = selected.getBBox();
|
||||||
|
}
|
||||||
|
if(ref) {
|
||||||
|
copy.remove();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Function: svgedit.utilities.getBBox
|
// Function: svgedit.utilities.getBBox
|
||||||
// Get the given/selected element's bounding box object, convert it to be more
|
// Get the given/selected element's bounding box object, convert it to be more
|
||||||
// usable when necessary
|
// usable when necessary
|
||||||
|
@ -414,20 +467,43 @@ svgedit.utilities.getBBox = function(elem) {
|
||||||
var ret = null;
|
var ret = null;
|
||||||
var elname = selected.nodeName;
|
var elname = selected.nodeName;
|
||||||
|
|
||||||
if(elname === 'text' && selected.textContent === '') {
|
switch ( elname ) {
|
||||||
|
case 'text':
|
||||||
|
if(selected.textContent === '') {
|
||||||
selected.textContent = 'a'; // Some character needed for the selector to use.
|
selected.textContent = 'a'; // Some character needed for the selector to use.
|
||||||
ret = selected.getBBox();
|
ret = selected.getBBox();
|
||||||
selected.textContent = '';
|
selected.textContent = '';
|
||||||
} else if(elname === 'path' && !svgedit.browser.supportsPathBBox()) {
|
} else {
|
||||||
|
try { ret = selected.getBBox();} catch(e){}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'path':
|
||||||
|
if(!svgedit.browser.supportsPathBBox()) {
|
||||||
ret = svgedit.utilities.getPathBBox(selected);
|
ret = svgedit.utilities.getPathBBox(selected);
|
||||||
} else if(elname === 'use' && !svgedit.browser.isWebkit() || elname === 'foreignObject') {
|
} else {
|
||||||
ret = selected.getBBox();
|
try { ret = selected.getBBox();} catch(e){}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
case 'a':
|
||||||
|
ret = groupBBFix(selected);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
if(elname === 'use') {
|
||||||
|
ret = groupBBFix(selected, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(elname === 'use' || elname === 'foreignObject') {
|
||||||
|
if(!ret) ret = selected.getBBox();
|
||||||
|
if(!svgedit.browser.isWebkit()) {
|
||||||
var bb = {};
|
var bb = {};
|
||||||
bb.width = ret.width;
|
bb.width = ret.width;
|
||||||
bb.height = ret.height;
|
bb.height = ret.height;
|
||||||
bb.x = ret.x + parseFloat(selected.getAttribute('x')||0);
|
bb.x = ret.x + parseFloat(selected.getAttribute('x')||0);
|
||||||
bb.y = ret.y + parseFloat(selected.getAttribute('y')||0);
|
bb.y = ret.y + parseFloat(selected.getAttribute('y')||0);
|
||||||
ret = bb;
|
ret = bb;
|
||||||
|
}
|
||||||
} else if(~visElems_arr.indexOf(elname)) {
|
} else if(~visElems_arr.indexOf(elname)) {
|
||||||
try { ret = selected.getBBox();}
|
try { ret = selected.getBBox();}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
|
@ -444,6 +520,8 @@ svgedit.utilities.getBBox = function(elem) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(ret) {
|
if(ret) {
|
||||||
ret = svgedit.utilities.bboxToObj(ret);
|
ret = svgedit.utilities.bboxToObj(ret);
|
||||||
}
|
}
|
||||||
|
@ -476,4 +554,94 @@ svgedit.utilities.getRotationAngle = function(elem, to_rad) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Function: getElem
|
||||||
|
// Get a DOM element by ID within the SVG root element.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// id - String with the element's new ID
|
||||||
|
if (svgedit.browser.supportsSelectors()) {
|
||||||
|
svgedit.utilities.getElem = function(id) {
|
||||||
|
// querySelector lookup
|
||||||
|
return svgroot_.querySelector('#'+id);
|
||||||
|
};
|
||||||
|
} else if (svgedit.browser.supportsXpath()) {
|
||||||
|
svgedit.utilities.getElem = function(id) {
|
||||||
|
// xpath lookup
|
||||||
|
return domdoc_.evaluate(
|
||||||
|
'svg:svg[@id="svgroot"]//svg:*[@id="'+id+'"]',
|
||||||
|
domcontainer_,
|
||||||
|
function() { return "http://www.w3.org/2000/svg"; },
|
||||||
|
9,
|
||||||
|
null).singleNodeValue;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
svgedit.utilities.getElem = function(id) {
|
||||||
|
// jQuery lookup: twice as slow as xpath in FF
|
||||||
|
return $(svgroot_).find('[id=' + id + ']')[0];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
svgedit.utilities.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
|
||||||
|
svgedit.utilities.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);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
Loading…
Reference in a new issue