Sync with SVG-Edit

This commit is contained in:
Jacques Distler 2010-09-10 15:19:23 -05:00
parent e99fcf720c
commit e5ca66ae41
17 changed files with 1962 additions and 467 deletions

View file

@ -11,11 +11,29 @@ if(!window.console) {
window.console.log = function(str) {}; window.console.log = function(str) {};
window.console.dir = function(str) {}; window.console.dir = function(str) {};
} }
// <3 IE
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
(function(){ (function(){
// canvg(target, s) // canvg(target, s)
// target: canvas element or the id of a canvas element // target: canvas element or the id of a canvas element
// s: svg string or url to svg file // s: svg string or url to svg file
this.canvg = function (target, s) { // opts: optional hash of options
// ignoreMouse: true => ignore mouse events
// ignoreAnimation: true => ignore animations
// renderCallback: function => will call the function after the first render is completed
// forceRedraw: function => will call the function on every frame, if it returns true, will redraw
this.canvg = function (target, s, opts) {
if (typeof target == 'string') { if (typeof target == 'string') {
target = document.getElementById(target); target = document.getElementById(target);
} }
@ -30,6 +48,7 @@ if(!window.console) {
svg = target.svg; svg = target.svg;
svg.stop(); svg.stop();
} }
svg.opts = opts;
var ctx = target.getContext('2d'); var ctx = target.getContext('2d');
if (s.substr(0,1) == '<') { if (s.substr(0,1) == '<') {
@ -43,7 +62,7 @@ if(!window.console) {
} }
function build() { function build() {
var svg = {}; var svg = { };
svg.FRAMERATE = 30; svg.FRAMERATE = 30;
@ -52,6 +71,7 @@ if(!window.console) {
svg.Definitions = {}; svg.Definitions = {};
svg.Styles = {}; svg.Styles = {};
svg.Animations = []; svg.Animations = [];
svg.Images = [];
svg.ctx = ctx; svg.ctx = ctx;
svg.ViewPort = new (function () { svg.ViewPort = new (function () {
this.viewPorts = []; this.viewPorts = [];
@ -69,6 +89,14 @@ if(!window.console) {
}); });
} }
svg.init(); svg.init();
// images loaded
svg.ImagesLoaded = function() {
for (var i=0; i<svg.Images.length; i++) {
if (!svg.Images[i].loaded) return false;
}
return true;
}
// trim // trim
svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); } svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }
@ -290,6 +318,13 @@ if(!window.console) {
this.angleTo = function(p) { this.angleTo = function(p) {
return Math.atan2(p.y - this.y, p.x - this.x); return Math.atan2(p.y - this.y, p.x - this.x);
} }
this.applyTransform = function(v) {
var xp = this.x * v[0] + this.y * v[2] + v[4];
var yp = this.x * v[1] + this.y * v[3] + v[5];
this.x = xp;
this.y = yp;
}
} }
svg.CreatePoint = function(s) { svg.CreatePoint = function(s) {
var a = svg.ToNumberArray(s); var a = svg.ToNumberArray(s);
@ -389,6 +424,10 @@ if(!window.console) {
} }
} }
this.isPointInBox = function(x, y) {
return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);
}
this.addPoint(x1, y1); this.addPoint(x1, y1);
this.addPoint(x2, y2); this.addPoint(x2, y2);
} }
@ -404,6 +443,9 @@ if(!window.console) {
this.apply = function(ctx) { this.apply = function(ctx) {
ctx.translate(this.p.x || 0.0, this.p.y || 0.0); ctx.translate(this.p.x || 0.0, this.p.y || 0.0);
} }
this.applyToPoint = function(p) {
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
}
} }
// rotate // rotate
@ -417,6 +459,12 @@ if(!window.console) {
ctx.rotate(this.angle.Angle.toRadians()); ctx.rotate(this.angle.Angle.toRadians());
ctx.translate(-this.cx, -this.cy); ctx.translate(-this.cx, -this.cy);
} }
this.applyToPoint = function(p) {
var a = this.angle.Angle.toRadians();
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]);
p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]);
}
} }
this.Type.scale = function(s) { this.Type.scale = function(s) {
@ -424,6 +472,9 @@ if(!window.console) {
this.apply = function(ctx) { this.apply = function(ctx) {
ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0);
} }
this.applyToPoint = function(p) {
p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);
}
} }
this.Type.matrix = function(s) { this.Type.matrix = function(s) {
@ -431,6 +482,9 @@ if(!window.console) {
this.apply = function(ctx) { this.apply = function(ctx) {
ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
} }
this.applyToPoint = function(p) {
p.applyTransform(this.m);
}
} }
this.Type.SkewBase = function(s) { this.Type.SkewBase = function(s) {
@ -455,12 +509,19 @@ if(!window.console) {
this.Type.skewY.prototype = new this.Type.SkewBase; this.Type.skewY.prototype = new this.Type.SkewBase;
this.transforms = []; this.transforms = [];
this.apply = function(ctx) { this.apply = function(ctx) {
for (var i=0; i<this.transforms.length; i++) { for (var i=0; i<this.transforms.length; i++) {
this.transforms[i].apply(ctx); this.transforms[i].apply(ctx);
} }
} }
this.applyToPoint = function(p) {
for (var i=0; i<this.transforms.length; i++) {
this.transforms[i].applyToPoint(p);
}
}
var data = v.split(/\s(?=[a-z])/); var data = v.split(/\s(?=[a-z])/);
for (var i=0; i<data.length; i++) { for (var i=0; i<data.length; i++) {
var type = data[i].split('(')[0]; var type = data[i].split('(')[0];
@ -470,6 +531,43 @@ if(!window.console) {
} }
} }
// aspect ratio
svg.AspectRatio = function(ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) {
// aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
aspectRatio = svg.compressSpaces(aspectRatio);
aspectRatio = aspectRatio.replace(/^defer\s/,''); // ignore defer
var align = aspectRatio.split(' ')[0] || 'xMidYMid';
var meetOrSlice = aspectRatio.split(' ')[1] || 'meet';
// calculate scale
var scaleX = width / desiredWidth;
var scaleY = height / desiredHeight;
var scaleMin = Math.min(scaleX, scaleY);
var scaleMax = Math.max(scaleX, scaleY);
if (meetOrSlice == 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; }
if (meetOrSlice == 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; }
refX = new svg.Property('refX', refX);
refY = new svg.Property('refY', refY);
if (refX.hasValue() && refY.hasValue()) {
ctx.translate(-scaleMin * refX.Length.toPixels('x'), -scaleMin * refY.Length.toPixels('y'));
}
else {
// align
if (align.match(/^xMid/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width / 2.0 - desiredWidth / 2.0, 0);
if (align.match(/YMid$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height / 2.0 - desiredHeight / 2.0);
if (align.match(/^xMax/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width - desiredWidth, 0);
if (align.match(/YMax$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height - desiredHeight);
}
// scale
if (meetOrSlice == 'meet') ctx.scale(scaleMin, scaleMin);
if (meetOrSlice == 'slice') ctx.scale(scaleMax, scaleMax);
// translate
ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY);
}
// elements // elements
svg.Element = {} svg.Element = {}
@ -505,6 +603,9 @@ if(!window.console) {
// base render // base render
this.render = function(ctx) { this.render = function(ctx) {
// don't render display=none
if (this.attribute('display').value == 'none') return;
ctx.save(); ctx.save();
this.setContext(ctx); this.setContext(ctx);
this.renderChildren(ctx); this.renderChildren(ctx);
@ -581,10 +682,14 @@ if(!window.console) {
this.styles[name] = new svg.Property(name, value); this.styles[name] = new svg.Property(name, value);
} }
} }
}
// add id
if (this.attribute('id').hasValue()) {
if (svg.Definitions[this.attribute('id').value] == null) {
svg.Definitions[this.attribute('id').value] = this;
}
} }
// set id
if (this.attribute('id').hasValue()) svg.Definitions[this.attribute('id').value] = this;
} }
} }
@ -660,6 +765,7 @@ if(!window.console) {
this.renderChildren = function(ctx) { this.renderChildren = function(ctx) {
this.path(ctx); this.path(ctx);
svg.Mouse.checkPath(this, ctx);
if (ctx.fillStyle != '') ctx.fill(); if (ctx.fillStyle != '') ctx.fill();
if (ctx.strokeStyle != '') ctx.stroke(); if (ctx.strokeStyle != '') ctx.stroke();
@ -743,36 +849,17 @@ if(!window.console) {
width = viewBox[2]; width = viewBox[2];
height = viewBox[3]; height = viewBox[3];
// aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute svg.AspectRatio(ctx,
var preserveAspectRatio = svg.compressSpaces(this.attribute('preserveAspectRatio').value); this.attribute('preserveAspectRatio').value,
preserveAspectRatio = preserveAspectRatio.replace(/^defer\s/,''); // ignore defer svg.ViewPort.width(),
var align = preserveAspectRatio.split(' ')[0] || 'xMidYMid'; width,
var meetOrSlice = preserveAspectRatio.split(' ')[1] || 'meet'; svg.ViewPort.height(),
height,
// calculate scale minX,
var scaleX = svg.ViewPort.width() / width; minY,
var scaleY = svg.ViewPort.height() / height; this.attribute('refX').value,
var scaleMin = Math.min(scaleX, scaleY); this.attribute('refY').value);
var scaleMax = Math.max(scaleX, scaleY);
if (meetOrSlice == 'meet') { width *= scaleMin; height *= scaleMin; }
if (meetOrSlice == 'slice') { width *= scaleMax; height *= scaleMax; }
if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) {
ctx.translate(-scaleMin * this.attribute('refX').Length.toPixels('x'), -scaleMin * this.attribute('refY').Length.toPixels('y'));
}
else {
// align
if (align.match(/^xMid/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(svg.ViewPort.width() / 2.0 - width / 2.0, 0);
if (align.match(/YMid$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, svg.ViewPort.height() / 2.0 - height / 2.0);
if (align.match(/^xMax/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(svg.ViewPort.width() - width, 0);
if (align.match(/YMax$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, svg.ViewPort.height() - height);
}
// scale
if (meetOrSlice == 'meet') ctx.scale(scaleMin, scaleMin);
if (meetOrSlice == 'slice') ctx.scale(scaleMax, scaleMax);
ctx.translate(-minX, -minY);
svg.ViewPort.RemoveCurrent(); svg.ViewPort.RemoveCurrent();
svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]); svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
} }
@ -920,6 +1007,7 @@ if(!window.console) {
this.getMarkers = function() { this.getMarkers = function() {
var markers = []; var markers = [];
for (var i=0; i<this.points.length - 1; i++) { for (var i=0; i<this.points.length - 1; i++) {
markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]); markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]);
} }
@ -969,6 +1057,7 @@ if(!window.console) {
this.reset = function() { this.reset = function() {
this.i = -1; this.i = -1;
this.command = ''; this.command = '';
this.previousCommand = '';
this.control = new svg.Point(0, 0); this.control = new svg.Point(0, 0);
this.current = new svg.Point(0, 0); this.current = new svg.Point(0, 0);
this.points = []; this.points = [];
@ -987,7 +1076,7 @@ if(!window.console) {
this.isRelativeCommand = function() { this.isRelativeCommand = function() {
return this.command == this.command.toLowerCase(); return this.command == this.command.toLowerCase();
} }
this.getToken = function() { this.getToken = function() {
this.i = this.i + 1; this.i = this.i + 1;
return this.tokens[this.i]; return this.tokens[this.i];
@ -998,6 +1087,7 @@ if(!window.console) {
} }
this.nextCommand = function() { this.nextCommand = function() {
this.previousCommand = this.command;
this.command = this.getToken(); this.command = this.getToken();
} }
@ -1019,8 +1109,13 @@ if(!window.console) {
} }
this.getReflectedControlPoint = function() { this.getReflectedControlPoint = function() {
if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') {
return this.current;
}
// reflect point
var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);
return this.makeAbsolute(p); return p;
} }
this.makeAbsolute = function(p) { this.makeAbsolute = function(p) {
@ -1146,7 +1241,6 @@ if(!window.console) {
if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y); if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
} }
} }
else if (pp.command.toUpperCase() == 'A') { else if (pp.command.toUpperCase() == 'A') {
while (!pp.isCommandOrEnd()) { while (!pp.isCommandOrEnd()) {
var curr = pp.current; var curr = pp.current;
@ -1304,7 +1398,7 @@ if(!window.console) {
// definitions element // definitions element
svg.Element.defs = function(node) { svg.Element.defs = function(node) {
this.base = svg.Element.ElementBase; this.base = svg.Element.ElementBase;
this.base(node); this.base(node);
this.render = function(ctx) { this.render = function(ctx) {
// NOOP // NOOP
@ -1324,15 +1418,20 @@ if(!window.console) {
var child = this.children[i]; var child = this.children[i];
this.stops.push(child); this.stops.push(child);
} }
this.getGradient = function() { this.getGradient = function() {
// OVERRIDE ME! // OVERRIDE ME!
} }
this.createGradient = function(ctx, element) { this.createGradient = function(ctx, element) {
var stopsContainer = this;
if (this.attribute('xlink:href').hasValue()) {
stopsContainer = this.attribute('xlink:href').Definition.getDefinition();
}
var g = this.getGradient(ctx, element); var g = this.getGradient(ctx, element);
for (var i=0; i<this.stops.length; i++) { for (var i=0; i<stopsContainer.stops.length; i++) {
g.addColorStop(this.stops[i].offset, this.stops[i].color); g.addColorStop(stopsContainer.stops[i].offset, stopsContainer.stops[i].color);
} }
return g; return g;
} }
@ -1360,7 +1459,15 @@ if(!window.console) {
? bb.y() + bb.height() * this.attribute('y2').numValue() ? bb.y() + bb.height() * this.attribute('y2').numValue()
: this.attribute('y2').Length.toPixels('y')); : this.attribute('y2').Length.toPixels('y'));
return ctx.createLinearGradient(x1, y1, x2, y2); var p1 = new svg.Point(x1, y1);
var p2 = new svg.Point(x2, y2);
if (this.attribute('gradientTransform').hasValue()) {
var transform = new svg.Transform(this.attribute('gradientTransform').value);
transform.applyToPoint(p1);
transform.applyToPoint(p2);
}
return ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
} }
} }
svg.Element.linearGradient.prototype = new svg.Element.GradientBase; svg.Element.linearGradient.prototype = new svg.Element.GradientBase;
@ -1397,7 +1504,15 @@ if(!window.console) {
? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue() ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
: this.attribute('r').Length.toPixels()); : this.attribute('r').Length.toPixels());
return ctx.createRadialGradient(fx, fy, 0, cx, cy, r); var c = new svg.Point(cx, cy);
var f = new svg.Point(fx, fy);
if (this.attribute('gradientTransform').hasValue()) {
var transform = new svg.Transform(this.attribute('gradientTransform').value);
transform.applyToPoint(c);
transform.applyToPoint(f);
}
return ctx.createRadialGradient(f.x, f.y, 0, c.x, c.y, r);
} }
} }
svg.Element.radialGradient.prototype = new svg.Element.GradientBase; svg.Element.radialGradient.prototype = new svg.Element.GradientBase;
@ -1555,10 +1670,26 @@ if(!window.console) {
var x = this.attribute('x').Length.toPixels('x'); var x = this.attribute('x').Length.toPixels('x');
var y = this.attribute('y').Length.toPixels('y'); var y = this.attribute('y').Length.toPixels('y');
for (var i=0; i<this.children.length; i++) { for (var i=0; i<this.children.length; i++) {
this.children[i].x = x; var child = this.children[i];
this.children[i].y = y;
this.children[i].render(ctx); if (child.attribute('x').hasValue()) {
x += this.children[i].measureText(ctx); child.x = child.attribute('x').Length.toPixels('x');
}
else {
if (child.attribute('dx').hasValue()) x += child.attribute('dx').Length.toPixels('x');
child.x = x;
x += child.measureText(ctx);
}
if (child.attribute('y').hasValue()) {
child.y = child.attribute('y').Length.toPixels('y');
}
else {
if (child.attribute('dy').hasValue()) y += child.attribute('dy').Length.toPixels('y');
child.y = y;
}
child.render(ctx);
} }
} }
} }
@ -1578,7 +1709,9 @@ if(!window.console) {
} }
this.measureText = function(ctx) { this.measureText = function(ctx) {
return ctx.measureText(svg.compressSpaces(this.getText())).width; var textToMeasure = svg.compressSpaces(this.getText());
if (!ctx.measureText) return textToMeasure.length * 10;
return ctx.measureText(textToMeasure).width;
} }
} }
svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase; svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase;
@ -1608,6 +1741,85 @@ if(!window.console) {
} }
svg.Element.tref.prototype = new svg.Element.TextElementBase; svg.Element.tref.prototype = new svg.Element.TextElementBase;
// a element
svg.Element.a = function(node) {
this.base = svg.Element.TextElementBase;
this.base(node);
this.hasText = true;
for (var i=0; i<node.childNodes.length; i++) {
if (node.childNodes[i].nodeType != 3) this.hasText = false;
}
// this might contain text
this.text = this.hasText ? node.childNodes[0].nodeValue : '';
this.getText = function() {
return this.text;
}
this.baseRenderChildren = this.renderChildren;
this.renderChildren = function(ctx) {
if (this.hasText) {
// render as text element
this.baseRenderChildren(ctx);
var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
svg.Mouse.checkBoundingBox(this, new svg.BoundingBox(this.x, this.y - fontSize.Length.toPixels('y'), this.x + this.measureText(ctx), this.y));
}
else {
// render as temporary group
var g = new svg.Element.g();
g.children = this.children;
g.parent = this;
g.render(ctx);
}
}
this.onclick = function() {
window.open(this.attribute('xlink:href').value);
}
this.onmousemove = function() {
svg.ctx.canvas.style.cursor = 'pointer';
}
}
svg.Element.a.prototype = new svg.Element.TextElementBase;
// image element
svg.Element.image = function(node) {
this.base = svg.Element.RenderedElementBase;
this.base(node);
svg.Images.push(this);
this.img = document.createElement('img');
this.loaded = false;
var that = this;
this.img.onload = function() { that.loaded = true; }
this.img.src = this.attribute('xlink:href').value;
this.renderChildren = function(ctx) {
var x = this.attribute('x').Length.toPixels('x');
var y = this.attribute('y').Length.toPixels('y');
var width = this.attribute('width').Length.toPixels('x');
var height = this.attribute('height').Length.toPixels('y');
if (width == 0 || height == 0) return;
ctx.save();
ctx.translate(x, y);
svg.AspectRatio(ctx,
this.attribute('preserveAspectRatio').value,
width,
this.img.width,
height,
this.img.height,
0,
0);
ctx.drawImage(this.img, 0, 0);
ctx.restore();
}
}
svg.Element.image.prototype = new svg.Element.RenderedElementBase;
// group element // group element
svg.Element.g = function(node) { svg.Element.g = function(node) {
this.base = svg.Element.RenderedElementBase; this.base = svg.Element.RenderedElementBase;
@ -1621,14 +1833,7 @@ if(!window.console) {
this.base(node); this.base(node);
} }
svg.Element.symbol.prototype = new svg.Element.RenderedElementBase; svg.Element.symbol.prototype = new svg.Element.RenderedElementBase;
// a element
svg.Element.a = function(node) {
this.base = svg.Element.RenderedElementBase;
this.base(node);
}
svg.Element.a.prototype = new svg.Element.RenderedElementBase;
// style element // style element
svg.Element.style = function(node) { svg.Element.style = function(node) {
this.base = svg.Element.ElementBase; this.base = svg.Element.ElementBase;
@ -1658,7 +1863,6 @@ if(!window.console) {
svg.Styles[cssClass] = props; svg.Styles[cssClass] = props;
} }
} }
} }
} }
} }
@ -1676,8 +1880,17 @@ if(!window.console) {
if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').Length.toPixels('y')); if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').Length.toPixels('y'));
} }
this.getDefinition = function() {
return this.attribute('xlink:href').Definition.getDefinition();
}
this.path = function(ctx) {
var element = this.getDefinition();
if (element != null) element.path(ctx);
}
this.renderChildren = function(ctx) { this.renderChildren = function(ctx) {
var element = this.attribute('xlink:href').Definition.getDefinition(); var element = this.getDefinition();
if (element != null) element.render(ctx); if (element != null) element.render(ctx);
} }
} }
@ -1732,33 +1945,89 @@ if(!window.console) {
// load from xml // load from xml
svg.loadXml = function(ctx, xml) { svg.loadXml = function(ctx, xml) {
svg.init(ctx); svg.init(ctx);
var mapXY = function(p) {
var e = ctx.canvas;
while (e) {
p.x -= e.offsetLeft;
p.y -= e.offsetTop;
e = e.offsetParent;
}
if (window.scrollX) p.x += window.scrollX;
if (window.scrollY) p.y += window.scrollY;
return p;
}
// bind mouse
if (svg.opts == null || svg.opts['ignoreMouse'] != true) {
ctx.canvas.onclick = function(e) {
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
svg.Mouse.onclick(p.x, p.y);
};
ctx.canvas.onmousemove = function(e) {
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
svg.Mouse.onmousemove(p.x, p.y);
};
}
var dom = svg.parseXml(xml); var dom = svg.parseXml(xml);
var e = svg.CreateElement(dom.documentElement); var e = svg.CreateElement(dom.documentElement);
// set canvas size
if (e.attribute('width').hasValue()) {
ctx.canvas.width = e.attribute('width').Length.toPixels(ctx.canvas.parentNode.clientWidth);
}
if (e.attribute('height').hasValue()) {
ctx.canvas.height = e.attribute('height').Length.toPixels(ctx.canvas.parentNode.clientHeight);
}
svg.ViewPort.SetCurrent(ctx.canvas.clientWidth, ctx.canvas.clientHeight);
// render loop // render loop
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight); var isFirstRender = true;
e.render(ctx); var draw = function() {
// set canvas size
if (e.style('width').hasValue()) {
ctx.canvas.width = e.style('width').Length.toPixels(ctx.canvas.parentNode.clientWidth);
}
if (e.style('height').hasValue()) {
ctx.canvas.height = e.style('height').Length.toPixels(ctx.canvas.parentNode.clientHeight);
}
svg.ViewPort.SetCurrent(ctx.canvas.clientWidth, ctx.canvas.clientHeight);
// clear and render
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
e.render(ctx);
if (isFirstRender) {
isFirstRender = false;
if (svg.opts != null && typeof(svg.opts['renderCallback']) == 'function') svg.opts['renderCallback']();
}
}
var waitingForImages = true;
if (svg.ImagesLoaded()) {
waitingForImages = false;
draw();
}
svg.intervalID = setInterval(function() { svg.intervalID = setInterval(function() {
// update animations
var needUpdate = false; var needUpdate = false;
for (var i=0; i<svg.Animations.length; i++) {
needUpdate = needUpdate | svg.Animations[i].update(1000 / svg.FRAMERATE); if (waitingForImages && svg.ImagesLoaded()) {
waitingForImages = false;
needUpdate = true;
} }
// need update from mouse events?
if (svg.opts == null || svg.opts['ignoreMouse'] != true) {
needUpdate = needUpdate | svg.Mouse.hasEvents();
}
// need update from animations?
if (svg.opts == null || svg.opts['ignoreAnimation'] != true) {
for (var i=0; i<svg.Animations.length; i++) {
needUpdate = needUpdate | svg.Animations[i].update(1000 / svg.FRAMERATE);
}
}
// need update from redraw?
if (svg.opts != null && typeof(svg.opts['forceRedraw']) == 'function') {
if (svg.opts['forceRedraw']() == true) needUpdate = true;
}
// render if needed // render if needed
if (needUpdate) { if (needUpdate) {
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight); draw();
e.render(ctx); svg.Mouse.runEvents(); // run and clear our events
} }
}, 1000 / svg.FRAMERATE); }, 1000 / svg.FRAMERATE);
} }
@ -1769,6 +2038,56 @@ if(!window.console) {
} }
} }
svg.Mouse = new (function() {
this.events = [];
this.hasEvents = function() { return this.events.length != 0; }
this.onclick = function(x, y) {
this.events.push({ type: 'onclick', x: x, y: y,
run: function(e) { if (e.onclick) e.onclick(); }
});
}
this.onmousemove = function(x, y) {
this.events.push({ type: 'onmousemove', x: x, y: y,
run: function(e) { if (e.onmousemove) e.onmousemove(); }
});
}
this.eventElements = [];
this.checkPath = function(element, ctx) {
for (var i=0; i<this.events.length; i++) {
var e = this.events[i];
if (ctx.isPointInPath && ctx.isPointInPath(e.x, e.y)) this.eventElements[i] = element;
}
}
this.checkBoundingBox = function(element, bb) {
for (var i=0; i<this.events.length; i++) {
var e = this.events[i];
if (bb.isPointInBox(e.x, e.y)) this.eventElements[i] = element;
}
}
this.runEvents = function() {
svg.ctx.canvas.style.cursor = '';
for (var i=0; i<this.events.length; i++) {
var e = this.events[i];
var element = this.eventElements[i];
while (element) {
e.run(element);
element = element.parent;
}
}
// done running, clear
this.events = [];
this.eventElements = [];
}
});
return svg; return svg;
} }
})(); })();

View file

@ -0,0 +1,198 @@
// jQuery Context Menu Plugin
//
// Version 1.01
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// Modified by Alexis Deveria
//
// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
//
// Terms of Use
//
// This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC.
//
if(jQuery)( function() {
$.extend($.fn, {
contextMenu: function(o, callback) {
// Defaults
if( o.menu == undefined ) return false;
if( o.inSpeed == undefined ) o.inSpeed = 150;
if( o.outSpeed == undefined ) o.outSpeed = 75;
// 0 needs to be -1 for expected results (no fade)
if( o.inSpeed == 0 ) o.inSpeed = -1;
if( o.outSpeed == 0 ) o.outSpeed = -1;
// Loop each context menu
$(this).each( function() {
var el = $(this);
var offset = $(el).offset();
// Add contextMenu class
$('#' + o.menu).addClass('contextMenu');
// Simulate a true right click
$(this).mousedown( function(e) {
var evt = e;
$(this).mouseup( function(e) {
var srcElement = $(this);
$(this).unbind('mouseup');
if( evt.button == 2 || o.allowLeft) {
e.stopPropagation();
// Hide context menus that may be showing
$(".contextMenu").hide();
// Get this context menu
var menu = $('#' + o.menu);
if( $(el).hasClass('disabled') ) return false;
// Detect mouse position
var d = {}, x = e.pageX, y = e.pageY;
var x_off = $(window).width() - menu.width(),
y_off = $(window).height() - menu.height();
if(x > x_off) x = x_off-15;
if(y > y_off) y = y_off-15;
// Show the menu
$(document).unbind('click');
$(menu).css({ top: y, left: x }).fadeIn(o.inSpeed);
// Hover events
$(menu).find('A').mouseover( function() {
$(menu).find('LI.hover').removeClass('hover');
$(this).parent().addClass('hover');
}).mouseout( function() {
$(menu).find('LI.hover').removeClass('hover');
});
// Keyboard
$(document).keypress( function(e) {
switch( e.keyCode ) {
case 38: // up
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:last').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
}
break;
case 40: // down
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:first').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
}
break;
case 13: // enter
$(menu).find('LI.hover A').trigger('click');
break;
case 27: // esc
$(document).trigger('click');
break
}
});
// When items are selected
$('#' + o.menu).find('A').unbind('mouseup');
$('#' + o.menu).find('LI:not(.disabled) A').mouseup( function() {
$(document).unbind('click').unbind('keypress');
$(".contextMenu").hide();
// Callback
if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} );
return false;
});
// Hide bindings
setTimeout( function() { // Delay for Mozilla
$(document).click( function() {
$(document).unbind('click').unbind('keypress');
$(menu).fadeOut(o.outSpeed);
return false;
});
}, 0);
}
});
});
// Disable text selection
if( $.browser.mozilla ) {
$('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
} else if( $.browser.msie ) {
$('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
} else {
$('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
}
// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
$(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; });
});
return $(this);
},
// Disable context menu items on the fly
disableContextMenuItems: function(o) {
if( o == undefined ) {
// Disable all
$(this).find('LI').addClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
}
}
});
return( $(this) );
},
// Enable context menu items on the fly
enableContextMenuItems: function(o) {
if( o == undefined ) {
// Enable all
$(this).find('LI.disabled').removeClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
}
}
});
return( $(this) );
},
// Disable context menu(s)
disableContextMenu: function() {
$(this).each( function() {
$(this).addClass('disabled');
});
return( $(this) );
},
// Enable context menu(s)
enableContextMenu: function() {
$(this).each( function() {
$(this).removeClass('disabled');
});
return( $(this) );
},
// Destroy context menu(s)
destroyContextMenu: function() {
// Destroy specified context menus
$(this).each( function() {
// Disable action
$(this).unbind('mousedown').unbind('mouseup');
});
return( $(this) );
}
});
})(jQuery);

View file

@ -0,0 +1,22 @@
// jQuery Context Menu Plugin
//
// Version 1.01
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
//
// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
//
// Terms of Use
//
// This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC.
//
jQuery&&function(){$.extend($.fn,{contextMenu:function(a,e){if(a.menu==undefined)return false;if(a.inSpeed==undefined)a.inSpeed=150;if(a.outSpeed==undefined)a.outSpeed=75;if(a.inSpeed==0)a.inSpeed=-1;if(a.outSpeed==0)a.outSpeed=-1;$(this).each(function(){var d=$(this),i=$(d).offset();$("#"+a.menu).addClass("contextMenu");$(this).mousedown(function(j){j.stopPropagation();$(this).mouseup(function(f){f.stopPropagation();var k=$(this);$(this).unbind("mouseup");if(j.button==2){$(".contextMenu").hide();
var b=$("#"+a.menu);if($(d).hasClass("disabled"))return false;var c={},g,h;if(self.innerHeight){c.pageYOffset=self.pageYOffset;c.pageXOffset=self.pageXOffset;c.innerHeight=self.innerHeight;c.innerWidth=self.innerWidth}else if(document.documentElement&&document.documentElement.clientHeight){c.pageYOffset=document.documentElement.scrollTop;c.pageXOffset=document.documentElement.scrollLeft;c.innerHeight=document.documentElement.clientHeight;c.innerWidth=document.documentElement.clientWidth}else if(document.body){c.pageYOffset=
document.body.scrollTop;c.pageXOffset=document.body.scrollLeft;c.innerHeight=document.body.clientHeight;c.innerWidth=document.body.clientWidth}f.pageX?g=f.pageX:g=f.clientX+c.scrollLeft;f.pageY?h=f.pageY:h=f.clientY+c.scrollTop;$(document).unbind("click");$(b).css({top:h,left:g}).fadeIn(a.inSpeed);$(b).find("A").mouseover(function(){$(b).find("LI.hover").removeClass("hover");$(this).parent().addClass("hover")}).mouseout(function(){$(b).find("LI.hover").removeClass("hover")});$(document).keypress(function(l){switch(l.keyCode){case 38:if($(b).find("LI.hover").size()==
0)$(b).find("LI:last").addClass("hover");else{$(b).find("LI.hover").removeClass("hover").prevAll("LI:not(.disabled)").eq(0).addClass("hover");$(b).find("LI.hover").size()==0&&$(b).find("LI:last").addClass("hover")}break;case 40:if($(b).find("LI.hover").size()==0)$(b).find("LI:first").addClass("hover");else{$(b).find("LI.hover").removeClass("hover").nextAll("LI:not(.disabled)").eq(0).addClass("hover");$(b).find("LI.hover").size()==0&&$(b).find("LI:first").addClass("hover")}break;case 13:$(b).find("LI.hover A").trigger("click");
break;case 27:$(document).trigger("click");break}});$("#"+a.menu).find("A").unbind("click");$("#"+a.menu).find("LI:not(.disabled) A").click(function(){$(document).unbind("click").unbind("keypress");$(".contextMenu").hide();e&&e($(this).attr("href").substr(1),$(k),{x:g-i.left,y:h-i.top,docX:g,docY:h});return false});setTimeout(function(){$(document).click(function(){$(document).unbind("click").unbind("keypress");$(b).fadeOut(a.outSpeed);return false})},0)}})});if($.browser.mozilla)$("#"+a.menu).each(function(){$(this).css({MozUserSelect:"none"})});
else $.browser.msie?$("#"+a.menu).each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})}):$("#"+a.menu).each(function(){$(this).bind("mousedown.disableTextSelect",function(){return false})});$(d).add($("UL.contextMenu")).bind("contextmenu",function(){return false})});return $(this)},disableContextMenuItems:function(a){if(a==undefined){$(this).find("LI").addClass("disabled");return $(this)}$(this).each(function(){if(a!=undefined)for(var e=a.split(","),d=0;d<e.length;d++)$(this).find('A[href="'+
e[d]+'"]').parent().addClass("disabled")});return $(this)},enableContextMenuItems:function(a){if(a==undefined){$(this).find("LI.disabled").removeClass("disabled");return $(this)}$(this).each(function(){if(a!=undefined)for(var e=a.split(","),d=0;d<e.length;d++)$(this).find('A[href="'+e[d]+'"]').parent().removeClass("disabled")});return $(this)},disableContextMenu:function(){$(this).each(function(){$(this).addClass("disabled")});return $(this)},enableContextMenu:function(){$(this).each(function(){$(this).removeClass("disabled")});
return $(this)},destroyContextMenu:function(){$(this).each(function(){$(this).unbind("mousedown").unbind("mouseup")});return $(this)}})}(jQuery);

View file

@ -256,8 +256,9 @@ svgEditor.addExtension("Connector", function(S) {
svgCanvas.moveSelectedElements = function() { svgCanvas.moveSelectedElements = function() {
svgCanvas.removeFromSelection($(conn_sel).toArray()); svgCanvas.removeFromSelection($(conn_sel).toArray());
mse.apply(this, arguments); var cmd = mse.apply(this, arguments);
updateConnectors(); updateConnectors();
return cmd;
} }
se_ns = svgCanvas.getEditorNS(); se_ns = svgCanvas.getEditorNS();
@ -486,6 +487,12 @@ svgEditor.addExtension("Connector", function(S) {
} }
}, },
selectedChanged: function(opts) { selectedChanged: function(opts) {
// TODO: Find better way to skip operations if no connectors are in use
if(!$(svgcontent).find(conn_sel).length) return;
if(svgCanvas.getMode() == 'connector') {
svgCanvas.setMode('select');
}
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;

View file

@ -0,0 +1,150 @@
/*
* ext-grid.js
*
* Licensed under the Apache License, Version 2
*
* Copyright(c) 2010 Redou Mine
*
*/
svgEditor.addExtension("view_grid", function(s) {
/*
* Config for grid-lines
*/
var gridConfig = {
'1x1': { height: 1, width: 1, color: '#CCC', strokeWidth: 0.05, opacity: 1 },
'5x5': { height: 5, width: 5, color: '#BBB', strokeWidth: 0.2, opacity: 1 },
'10x10': { height: 10, width: 10, color: '#AAA', strokeWidth: 0.2, opacity: 1 },
'100x100': { height: 100, width: 100, color: '#888', strokeWidth: 0.2, opacity: 1 }
};
var svgdoc = document.getElementById("svgcanvas").ownerDocument,
svgns = "http://www.w3.org/2000/svg",
dims = svgEditor.curConfig.dimensions,
svgroot = s.svgroot;
/*
* copied from svgcanvas.js line 1138-1157 (version: 2.5 rc1)
*/
var assignAttributes = function(node, attrs, suspendLength, unitCheck) {
if (!suspendLength) suspendLength = 0;
// Opera has a problem with suspendRedraw() apparently
var handle = null;
if (!window.opera) 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 || !unitCheck) {
node.setAttributeNS(ns, i, attrs[i]);
} else {
setUnitAttr(node, i, attrs[i]);
}
}
if (!window.opera) svgroot.unsuspendRedraw(handle);
};
// create svg for grid
var canvasgrid = svgdoc.createElementNS(svgns, "svg");
assignAttributes(canvasgrid, {
'id': 'canvasGrid',
'width': '100%',
'height': '100%',
'x': 0,
'y': 0,
'overflow': 'visible',
'viewBox': '0 0 ' + dims[0] + ' ' + dims[1],
'display': 'none'
});
$('#canvasBackground').append(canvasgrid);
// create each grid
$.each(gridConfig, function(key, value) {
// grid-pattern
var gridPattern = svgdoc.createElementNS(svgns, "pattern");
assignAttributes(gridPattern, {
'id': 'gridpattern' + key,
'patternUnits': 'userSpaceOnUse',
'x': -(value.strokeWidth / 2), // position for strokewidth
'y': -(value.strokeWidth / 2), // position for strokewidth
'width': value.width,
'height': value.height
});
var gridPattern_hoLine = svgdoc.createElementNS(svgns, "line");
assignAttributes(gridPattern_hoLine, {
'fill': 'none',
'stroke-width': value.strokeWidth,
'x1': 0,
'y1': 0,
'x2': value.width,
'y2': 0,
'stroke': value.color
});
var gridPattern_veLine = svgdoc.createElementNS(svgns, "line");
assignAttributes(gridPattern_veLine, {
'fill': 'none',
'stroke-width': value.strokeWidth,
'x1': 0,
'y1': 0,
'x2': 0,
'y2': value.height,
'stroke': value.color
});
gridPattern.appendChild(gridPattern_hoLine);
gridPattern.appendChild(gridPattern_veLine);
$('#svgroot defs').append(gridPattern);
// grid-box
var gridBox = svgdoc.createElementNS(svgns, "rect");
assignAttributes(gridBox, {
'width': '100%',
'height': '100%',
'x': 0,
'y': 0,
'stroke-width': 0,
'stroke': 'none',
'fill': 'url(#gridpattern' + key + ')',
'opacity': value.opacity,
'style': 'pointer-events: none; display:visible;'
});
$('#canvasGrid').append(gridBox);
});
return {
name: "view_grid",
svgicons: "extensions/grid-icon.xml",
zoomChanged: function(zoomlevel) {
// update size
var viewBox = "0 0 " + svgCanvas.contentW + " " + svgCanvas.contentH;
$('#canvasGrid').attr("viewBox", viewBox);
},
buttons: [{
id: "view_grid",
type: "context",
panel: "editor_panel",
title: "Show/Hide Grid [G]",
events: {
'click': function() {
var gr = !$('#view_grid').hasClass('push_button_pressed');
if (gr) {
svgEditor.curConfig.gridSnapping = true;
$('#view_grid').addClass('push_button_pressed').removeClass('tool_button');
$('#canvasGrid').attr('display', 'normal');
}
else {
svgEditor.curConfig.gridSnapping = false;
$('#view_grid').removeClass('push_button_pressed').addClass('tool_button');
$('#canvasGrid').attr('display', 'none');
}
}
}
}]
};
});

View file

@ -17,7 +17,7 @@ svgEditor.addExtension("imagelib", function() {
{ {
name: 'IAN Symbol Libraries', name: 'IAN Symbol Libraries',
url: 'http://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php', url: 'http://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
description: 'Free library of 2300+ illustrations' description: 'Free library of illustrations'
} }
]; ];
@ -90,7 +90,7 @@ svgEditor.addExtension("imagelib", function() {
function showBrowser() { function showBrowser() {
var browser = $('#imgbrowse'); var browser = $('#imgbrowse');
if(!browser.length) { if(!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse>\ $('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>\
</div></div>').insertAfter('#svg_docprops'); </div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse'); browser = $('#imgbrowse');
@ -101,24 +101,27 @@ svgEditor.addExtension("imagelib", function() {
var header = $('<h1>').prependTo(browser).text(all_libs); var header = $('<h1>').prependTo(browser).text(all_libs);
var cancel = $('<input type=button value=Cancel>').appendTo(browser).click(function() { var cancel = $('<button>Cancel</button>').appendTo(browser).click(function() {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
}).css({ }).css({
position: 'absolute', position: 'absolute',
top: 5, top: 5,
right: 5 right: -10
}); });
var back = $('<input type=button value="Show libraries">').appendTo(browser).click(function() { var back = $('<button>Show libraries</button>').appendTo(browser).click(function() {
frame.attr('src', 'about:blank').hide(); frame.attr('src', 'about:blank').hide();
lib_opts.show(); lib_opts.show();
header.text(all_libs); header.text(all_libs);
}).css({ }).css({
position: 'absolute', position: 'absolute',
top: 5, top: 5,
left: 5 left: 10
}); });
cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true));
$.each(img_libs, function(i, opts) { $.each(img_libs, function(i, opts) {
$('<li>').appendTo(lib_opts).text(opts.name).click(function() { $('<li>').appendTo(lib_opts).text(opts.name).click(function() {
frame.attr('src', opts.url).show(); frame.attr('src', opts.url).show();
@ -175,7 +178,7 @@ svgEditor.addExtension("imagelib", function() {
#imgbrowse > div,\ #imgbrowse > div,\
#imgbrowse > ul {\ #imgbrowse > ul {\
position: absolute;\ position: absolute;\
top: 36px;\ top: 45px;\
left: 10px;\ left: 10px;\
right: 10px;\ right: 10px;\
bottom: 10px;\ bottom: 10px;\

View file

@ -1,10 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg">
<g id="tool_imagelib"> <g id="tool_imagelib">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"> <svg width="201" height="211" xmlns="http://www.w3.org/2000/svg">
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,194.72501l0,0c0,-10.30901 35.8172,-18.666 80,-18.666c44.18298,0 80,8.35699 80,18.666l0,74.66699c0,10.30899 -35.81702,18.66699 -80,18.66699c-44.1828,0 -80,-8.358 -80,-18.66699l0,-74.66699z"/> <g>
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,114.608l0,0c0,-10.309 35.8172,-18.6668 80,-18.6668c44.18298,0 80,8.3578 80,18.6668l0,74.66699c0,10.30901 -35.81702,18.666 -80,18.666c-44.1828,0 -80,-8.35699 -80,-18.666l0,-74.66699z"/> <path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m2.75,49.51761l56.56,-46.26761c12.73,8.25 25.71001,7 46.44,0.75l-56.03999,47.23944l-22.72002,25.01056l-24.23999,-26.73239z" id="svg_2" stroke-width="7"/>
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,33.6667l0,0c0,-10.3094 35.8172,-18.6667 80,-18.6667c44.18298,0 80,8.3573 80,18.6667l0,74.6663c0,10.31 -35.81702,18.667 -80,18.667c-44.1828,0 -80,-8.357 -80,-18.667l0,-74.6663z"/> <path fill="#a03333" stroke="#3f3f3f" d="m3.75,203.25002c14.33301,7 30.66699,7 46,0l0,-152.00002c-14.66699,8 -32.33301,8 -47,0l1,152.00002zm45.75,-152.25002l56.25,-46.75l0,151l-56,48.00002m-47.25,-154.25002l57.25,-46.5" id="svg_1" stroke-width="7" stroke-linecap="round"/>
<path id="svg_1" fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m230,32.33334c0,10.30931 -35.81726,18.66666 -80,18.66666c-44.1828,0 -80,-8.35735 -80,-18.66666"/> <path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m49.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_5"/>
</svg> <path fill="#2f8e2f" stroke="#3f3f3f" d="m50.75,202.25c14.33301,7 30.66699,7.04253 46,0.04253l0,-151.04253c-14.66699,8 -32.33301,8 -47,0l1,151zm45.75,-151.25l56.25,-46.75l0,144.01219l-56,51.98782m-47.25,-151.25002l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_6"/>
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m95.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_10"/>
<path fill="#336393" stroke="#3f3f3f" d="m96.75,200.29445c14.33301,7 30.66699,7 46,0l0,-149.04445c-14.66699,8 -32.33301,8 -47,0l1,149.04445zm45.75,-149.29445l56.25,-46.75l0,148.04445l-56,48m-47.25,-151.29445l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_11"/>
</g>
</svg>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -18,7 +18,7 @@ svgEditor.addExtension("server_opensave", {
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function(win, data) { save: function(win, data) {
var svg = "<?xml version='1.0'?>\n" + data; var svg = "<?xml version=\"1.0\"?>\n" + data;
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_'); var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');
@ -42,33 +42,34 @@ svgEditor.addExtension("server_opensave", {
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
canvg(c, data.svg); canvg(c, data.svg, {renderCallback: function() {
var datauri = c.toDataURL('image/png'); var datauri = c.toDataURL('image/png');
var uiStrings = svgEditor.uiStrings; var uiStrings = svgEditor.uiStrings;
var note = ''; var note = '';
// Check if there's issues // Check if there's issues
if(issues.length) { if(issues.length) {
var pre = "\n \u2022 "; var pre = "\n \u2022 ";
note += ("\n\n" + pre + issues.join(pre)); note += ("\n\n" + pre + issues.join(pre));
} }
if(note.length) { if(note.length) {
alert(note); alert(note);
} }
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_'); var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');
var form = $('<form>').attr({ var form = $('<form>').attr({
method: 'post', method: 'post',
action: save_png_action, action: save_png_action,
target: 'output_frame' target: 'output_frame'
}) .append('<input type="hidden" name="output_png" value="' + datauri + '">') }) .append('<input type="hidden" name="output_png" value="' + datauri + '">')
.append('<input type="hidden" name="filename" value="' + filename + '">') .append('<input type="hidden" name="filename" value="' + filename + '">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}});
} }

View file

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg">
<!--
Sample icons file. This file looks like an SVG file with groups as its
children. Each group element has an ID that must match the ID of the button given
in the extension. The SVG inside the group makes up the actual icon, and
needs use a viewBox instead of width/height for it to scale properly.
Multiple icons can be included, each within their own group.
-->
<g id="view_grid">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g>
<rect fill="#ffffff" stroke="#848484" x="2" y="2" width="20" height="20"/>
<line fill="none" stroke="#848484" x1="11.84375" y1="-1.53125" x2="11.84375" y2="18.46875" transform="rotate(90, 11.8429, 8.46955)"/>
<line fill="none" stroke="#848484" x1="11.90625" y1="5.21875" x2="11.90625" y2="25.21875" transform="rotate(90, 11.9054, 15.2196)"/>
<line fill="none" stroke="#848484" x1="8.5" y1="2.03125" x2="8.5" y2="22.03125"/>
<line fill="none" stroke="#848484" x1="15.5" y1="2.03125" x2="15.5" y2="22.03125"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="3.25" y="3.28125" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="10" y="3.28125" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="16.75" y="3.28125" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="3.28125" y="9.75" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="10.03125" y="9.75" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="16.78125" y="9.75" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="3.3125" y="16.59375" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="10.0625" y="16.59375" width="4" height="4"/>
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="16.8125" y="16.59375" width="4" height="4"/>
</g>
</svg>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -540,6 +540,18 @@
</svg> </svg>
</g> </g>
<g id="context_menu">
<svg width="120" height="120" xmlns="http://www.w3.org/2000/svg">
<path stroke-width="0" id="svg_11" d="m4.5,46.5l52,0l-26,38l-26,-38z" stroke="#000" fill="#000"/>
<g id="svg_16">
<line stroke-width="10" id="svg_12" y2="27.5" x2="117.5" y1="27.5" x1="59.5" stroke="#000" fill="#000"/>
<line id="svg_13" stroke-width="10" y2="51.5" x2="117.5" y1="51.5" x1="59.5" stroke="#000" fill="#000"/>
<line id="svg_14" stroke-width="10" y2="73.5" x2="117.5" y1="73.5" x1="59.5" stroke="#000" fill="#000"/>
<line id="svg_15" stroke-width="10" y2="97.5" x2="117.5" y1="97.5" x1="59.5" stroke="#000" fill="#000"/>
</g>
</svg>
</g>
<g id="move_bottom"> <g id="move_bottom">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23"> <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23">
<defs> <defs>
@ -721,8 +733,8 @@
</g> </g>
<g id="fontsize"> <g id="fontsize">
<svg width="50" height="50" xmlns="http://www.w3.org/2000/svg" xmlns:xml="http://www.w3.org/XML/1998/namespace"> <svg width="50" height="50" xmlns="http://www.w3.org/2000/svg">
<text fill="#606060" stroke="none" x="14.451" y="41.4587" id="svg_2" font-size="26" font-family="serif" text-anchor="middle" xml:space="preserve">T</text> <text fill="#606060" stroke="none" x="14.451" y="41.4587" id="svg_2" font-size="26" font-family="serif" text-anchor="middle">T</text>
<text fill="#000000" stroke="none" x="28.853" y="41.8685" font-size="52" font-family="serif" text-anchor="middle" xml:space="preserve" id="svg_3">T</text> <text fill="#000000" stroke="none" x="28.853" y="41.8685" font-size="52" font-family="serif" text-anchor="middle" xml:space="preserve" id="svg_3">T</text>
</svg> </svg>
</g> </g>

View file

@ -12,4 +12,4 @@
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/ */
(function(b){b.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};function a(d){if(typeof d.data!=="string"){return}var c=d.handler,e=d.data.toLowerCase().split(" ");d.handler=function(n){if(this!==n.target&&(/textarea|select/i.test(n.target.nodeName)||n.target.type==="text")){return}var h=n.type!=="keypress"&&b.hotkeys.specialKeys[n.which],o=String.fromCharCode(n.which).toLowerCase(),k,m="",g={};if(n.altKey&&h!=="alt"){m+="alt+"}if(n.ctrlKey&&h!=="ctrl"){m+="ctrl+"}if(n.metaKey&&!n.ctrlKey&&h!=="meta"){m+="meta+"}if(n.shiftKey&&h!=="shift"){m+="shift+"}if(h){g[m+h]=true}else{g[m+o]=true;g[m+b.hotkeys.shiftNums[o]]=true;if(m==="shift+"){g[b.hotkeys.shiftNums[o]]=true}}for(var j=0,f=e.length;j<f;j++){if(g[e[j]]){return c.apply(this,arguments)}}}}b.each(["keydown","keyup","keypress"],function(){b.event.special[this]={add:a}})})(jQuery); (function(b){b.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta",219:"[",221:"]"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};function a(d){if(typeof d.data!=="string"){return}var c=d.handler,e=d.data.toLowerCase().split(" ");d.handler=function(n){if(this!==n.target&&(/textarea|select/i.test(n.target.nodeName)||n.target.type==="text")){return}var h=n.type!=="keypress"&&b.hotkeys.specialKeys[n.which],o=String.fromCharCode(n.which).toLowerCase(),k,m="",g={};if(n.altKey&&h!=="alt"){m+="alt+"}if(n.ctrlKey&&h!=="ctrl"){m+="ctrl+"}if(n.metaKey&&!n.ctrlKey&&h!=="meta"){m+="meta+"}if(n.shiftKey&&h!=="shift"){m+="shift+"}if(h){g[m+h]=true}else{g[m+o]=true;g[m+b.hotkeys.shiftNums[o]]=true;if(m==="shift+"){g[b.hotkeys.shiftNums[o]]=true}}for(var j=0,f=e.length;j<f;j++){if(g[e[j]]){return c.apply(this,arguments)}}}}b.each(["keydown","keyup","keypress"],function(){b.event.special[this]={add:a}})})(jQuery);

View file

@ -190,7 +190,7 @@
padding: 0px; padding: 0px;
padding-left: 2px; padding-left: 2px;
padding-right: 2px; padding-right: 2px;
width: 106px; width: 123px;
height: 20px; height: 20px;
border-right: 1px solid #FFFFFF; border-right: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF; border-bottom: 1px solid #FFFFFF;
@ -212,6 +212,10 @@
margin-right: 3px; margin-right: 3px;
} }
#svg_editor .layer_button:last-child {
margin-right: 0;
}
#svg_editor .layer_buttonpressed { #svg_editor .layer_buttonpressed {
width: 14px; width: 14px;
height: 14px; height: 14px;
@ -226,7 +230,7 @@
#svg_editor #layerlist { #svg_editor #layerlist {
margin: 1px; margin: 1px;
padding: 0px; padding: 0px;
width: 110px; width: 127px;
border-collapse: collapse; border-collapse: collapse;
border: 1px solid #808080; border: 1px solid #808080;
background-color: #FFFFFF; background-color: #FFFFFF;
@ -444,16 +448,7 @@
fill: #FFF !important; fill: #FFF !important;
} }
#svg_editor #selected_panel, #tools_top div[id$="_panel"]:not(#editor_panel):not(#history_panel) {
#svg_editor #multiselected_panel,
#svg_editor #g_panel,
#svg_editor #rect_panel,
#svg_editor #circle_panel,
#svg_editor #ellipse_panel,
#svg_editor #line_panel,
#svg_editor #image_panel,
#svg_editor #text_panel,
#svg_editor #path_node_panel {
display: none; display: none;
} }
@ -934,6 +929,16 @@ span.zoom_tool {
z-index: 6; z-index: 6;
} }
#save_output_btns {
display: none;
text-align: left;
}
#save_output_btns p {
margin: .5em 1.5em;
display: inline-block;
}
#bg_blocks { #bg_blocks {
overflow: auto; overflow: auto;
margin-left: 30px; margin-left: 30px;
@ -1005,8 +1010,9 @@ span.zoom_tool {
color: #444; color: #444;
} }
#canvas_title { #canvas_title, #canvas_bg_url {
display: block; display: block;
width: 96%;
} }
#svg_source_editor #svg_source_textarea { #svg_source_editor #svg_source_textarea {
@ -1214,4 +1220,76 @@ span.zoom_tool {
-webkit-border-radius: 0px; -webkit-border-radius: 0px;
} }
/* Generic context menu styles */
.contextMenu {
position: absolute;
z-index: 99999;
border: solid 1px rgba(0,0,0,.33);
background: rgba(255,255,255,.95);
padding: 5px 0;
margin: 0px;
display: none;
font: 14px/17px Lucida Sans, Helvetica, Verdana, sans-serif;
border-radius: 5px;
-moz-border-radius: 5px;
-moz-box-shadow: 2px 5px 10px rgba(0,0,0,.3);
-webkit-box-shadow: 2px 5px 10px rgba(0,0,0,.3);
box-shadow: 2px 5px 10px rgba(0,0,0,.3);
}
.contextMenu LI {
list-style: none;
padding: 0px;
margin: 0px;
}
.contextMenu A {
-moz-user-select: none;
-webkit-user-select: none;
color: #222;
text-decoration: none;
display: block;
line-height: 20px;
height: 20px;
background-position: 6px center;
background-repeat: no-repeat;
outline: none;
padding: 0px 15px 1px 20px;
}
.contextMenu LI.hover A {
background-color: #2e5dea;
color: white;
cursor: default;
}
.contextMenu LI.disabled A {
color: #999;
}
.contextMenu LI.hover.disabled A {
background-color: transparent;
}
.contextMenu LI.separator {
border-top: solid 1px #E3E3E3;
padding-top: 5px;
margin-top: 5px;
}
/*
Adding Icons
You can add icons to the context menu by adding
classes to the respective LI element(s)
*/
/*
.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); }
.contextMenu LI.cut A { background-image: url(images/cut.png); }
.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); }
.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); }
.contextMenu LI.delete A { background-image: url(images/page_white_delete.png); }
.contextMenu LI.quit A { background-image: url(images/door.png); }
*/
foreignObject {line-height:1.0} foreignObject {line-height:1.0}

View file

@ -16,6 +16,7 @@
<script type="text/javascript" src="svgicons/jquery.svgicons.js"></script> <script type="text/javascript" src="svgicons/jquery.svgicons.js"></script>
<script type="text/javascript" src="jquerybbq/jquery.bbq.min.js"></script> <script type="text/javascript" src="jquerybbq/jquery.bbq.min.js"></script>
<script type="text/javascript" src="spinbtn/JQuerySpinBtn.js"></script> <script type="text/javascript" src="spinbtn/JQuerySpinBtn.js"></script>
<script type="text/javascript" src="contextmenu/jquery.contextMenu.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>
@ -61,6 +62,7 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<div id="layer_rename" class="layer_button" title="Rename Layer"></div> <div id="layer_rename" class="layer_button" title="Rename Layer"></div>
<div id="layer_up" class="layer_button" title="Move Layer Up"></div> <div id="layer_up" class="layer_button" title="Move Layer Up"></div>
<div id="layer_down" class="layer_button" title="Move Layer Down"></div> <div id="layer_down" class="layer_button" title="Move Layer Down"></div>
<div id="layer_moreopts" class="layer_button" title="More Options"></div>
</fieldset> </fieldset>
<table id="layerlist"> <table id="layerlist">
@ -562,6 +564,10 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<button id="tool_source_save">Apply Changes</button> <button id="tool_source_save">Apply Changes</button>
<button id="tool_source_cancel">Cancel</button> <button id="tool_source_cancel">Cancel</button>
</div> </div>
<div id="save_output_btns">
<p id="copy_save_note">Copy the contents of this box into a text editor, then save the file with a .svg extension.</p>
<button id="copy_save_done">Done</button>
</div>
<form> <form>
<textarea id="svg_source_textarea" spellcheck="false"></textarea> <textarea id="svg_source_textarea" spellcheck="false"></textarea>
</form> </form>
@ -581,7 +587,7 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<legend id="svginfo_image_props">Image Properties</legend> <legend id="svginfo_image_props">Image Properties</legend>
<label> <label>
<span id="svginfo_title">Title:</span> <span id="svginfo_title">Title:</span>
<input type="text" id="canvas_title" size="24"/> <input type="text" id="canvas_title"/>
</label> </label>
<fieldset id="change_resolution"> <fieldset id="change_resolution">
@ -650,10 +656,16 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<fieldset id="change_background"> <fieldset id="change_background">
<legend id="svginfo_change_background">Editor Background</legend> <legend id="svginfo_change_background">Editor Background</legend>
<div id="bg_blocks"></div> <div id="bg_blocks"></div>
<label><span id="svginfo_bg_url">URL:</span> <input type="text" id="canvas_bg_url" size="21"/></label> <label><span id="svginfo_bg_url">URL:</span> <input type="text" id="canvas_bg_url"/></label>
<p id="svginfo_bg_note">Note: Background will not be saved with image.</p> <p id="svginfo_bg_note">Note: Background will not be saved with image.</p>
</fieldset> </fieldset>
<fieldset id="change_grid">
<legend id="svginfo_grid_settings">Grid</legend>
<label><span id="svginfo_snap_onoff">Snapping on/off</span><input type="checkbox" value="snapping_on" id="grid_snapping_on"></label>
<label><span id="svginfo_snap_step">Snapping Step-Size:</span> <input type="text" id="grid_snapping_step" size="3" value="10"/></label>
</fieldset>
</fieldset> </fieldset>
</div> </div>
@ -667,5 +679,23 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
</div> </div>
</div> </div>
<ul id="cmenu_canvas" class="contextMenu">
<li><a href="#cut">Cut</a></li>
<li><a href="#copy">Copy</a></li>
<li><a href="#paste">Paste</a></li>
<li><a href="#paste_in_place">Paste in Place</a></li>
<li class="separator"><a href="#delete">Delete</a></li>
<li class="separator"><a href="#move_up">Bring Forward</a></li>
<li><a href="#move_down">Send Backward</a></li>
</ul>
<ul id="cmenu_layers" class="contextMenu">
<li><a href="#dupe">Duplicate Layer...</a></li>
<li><a href="#delete">Delete Layer</a></li>
<li><a href="#merge_down">Merge Down</a></li>
<li><a href="#merge_all">Merge All</a></li>
</ul>
</body> </body>
</html> </html>

View file

@ -11,6 +11,8 @@
*/ */
(function() { (function() {
// TODO: Find out what causes bugs in jQuery animate for IE9
if($.browser.msie) $.fx.off = true;
if(!window.svgEditor) window.svgEditor = function($) { if(!window.svgEditor) window.svgEditor = function($) {
var svgCanvas; var svgCanvas;
@ -46,10 +48,12 @@
langPath: 'locale/', langPath: 'locale/',
extPath: 'extensions/', extPath: 'extensions/',
jGraduatePath: 'jgraduate/images/', jGraduatePath: 'jgraduate/images/',
extensions: ['ext-markers.js','ext-connector.js', 'ext-eyedropper.js', 'ext-imagelib.js', 'ext-itex.js'], extensions: ['ext-markers.js','ext-connector.js', 'ext-eyedropper.js', 'ext-imagelib.js','ext-grid.js', 'ext-itex.js'],
initTool: 'select', initTool: 'select',
wireframe: false, wireframe: false,
colorPickerCSS: null colorPickerCSS: null,
gridSnapping: false,
snappingStep: 5
}, },
uiStrings = Editor.uiStrings = { uiStrings = Editor.uiStrings = {
"invalidAttrValGiven":"Invalid value given", "invalidAttrValGiven":"Invalid value given",
@ -435,13 +439,14 @@
"#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4", "#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4",
]; ];
isMac = false, //(navigator.platform.indexOf("Mac") != -1); isMac = (navigator.platform.indexOf("Mac") != -1);
modKey = "", //(isMac ? "meta+" : "ctrl+"); modKey = (isMac ? "meta+" : "ctrl+"); // ⌘
path = svgCanvas.pathActions, path = svgCanvas.pathActions,
undoMgr = svgCanvas.undoMgr, undoMgr = svgCanvas.undoMgr,
Utils = svgCanvas.Utils, Utils = svgCanvas.Utils,
default_img_url = curConfig.imgPath + "logo.png", default_img_url = curConfig.imgPath + "logo.png",
workarea = $("#workarea"), workarea = $("#workarea"),
canv_menu = $("#cmenu_canvas"),
show_save_warning = false, show_save_warning = false,
exportWindow = null, exportWindow = null,
tool_scale = 1; tool_scale = 1;
@ -496,9 +501,12 @@
}()); }());
var setSelectMode = function() { var setSelectMode = function() {
$('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); var curr = $('.tool_button_current');
$('#tool_select').addClass('tool_button_current').removeClass('tool_button'); if(curr[0].id !== 'tool_select') {
$('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); curr.removeClass('tool_button_current').addClass('tool_button');
$('#tool_select').addClass('tool_button_current').removeClass('tool_button');
$('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}');
}
svgCanvas.setMode('select'); svgCanvas.setMode('select');
}; };
@ -539,6 +547,15 @@
// Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable
var ua = navigator.userAgent;
// Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 )
// IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves )
if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) {
showSourceEditor(0,true);
return;
}
var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg)); var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg));
// Alert will only appear the first time saved OR the first time the bug is encountered // Alert will only appear the first time saved OR the first time the bug is encountered
@ -548,7 +565,7 @@
var note = uiStrings.saveFromBrowser.replace('%s', 'SVG'); var note = uiStrings.saveFromBrowser.replace('%s', 'SVG');
// Check if FF and has <defs/> // Check if FF and has <defs/>
if(navigator.userAgent.indexOf('Gecko/') !== -1) { if(ua.indexOf('Gecko/') !== -1) {
if(svg.indexOf('<defs') !== -1) { if(svg.indexOf('<defs') !== -1) {
note += "\n\n" + uiStrings.defsFailOnSave; note += "\n\n" + uiStrings.defsFailOnSave;
$.pref('save_notice_done', 'all'); $.pref('save_notice_done', 'all');
@ -576,25 +593,25 @@
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
canvg(c, data.svg); canvg(c, data.svg, {renderCallback: function() {
var datauri = c.toDataURL('image/png'); var datauri = c.toDataURL('image/png');
exportWindow.location.href = datauri; exportWindow.location.href = datauri;
var done = $.pref('export_notice_done');
var done = $.pref('export_notice_done'); if(done !== "all") {
if(done !== "all") { var note = uiStrings.saveFromBrowser.replace('%s', 'PNG');
var note = uiStrings.saveFromBrowser.replace('%s', 'PNG');
// Check if there's issues
// Check if there's issues if(issues.length) {
if(issues.length) { var pre = "\n \u2022 ";
var pre = "\n \u2022 "; note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre));
note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre)); }
}
// Note that this will also prevent the notice even though new issues may appear later.
// Note that this will also prevent the notice even though new issues may appear later. // May want to find a way to deal with that without annoying the user
// May want to find a way to deal with that without annoying the user $.pref('export_notice_done', 'all');
$.pref('export_notice_done', 'all'); exportWindow.alert(note);
exportWindow.alert(note); }
} }});
}; };
// called when we've selected a different element // called when we've selected a different element
@ -610,7 +627,6 @@
// select mode and this event fires - we need our UI to be in sync // select mode and this event fires - we need our UI to be in sync
if (mode != "multiselect" && !is_node) { if (mode != "multiselect" && !is_node) {
setSelectMode();
updateToolbar(); updateToolbar();
} }
@ -628,6 +644,10 @@
// called when any element has changed // called when any element has changed
var elementChanged = function(window,elems) { var elementChanged = function(window,elems) {
if(svgCanvas.getMode() == "select") {
setSelectMode();
}
for (var i = 0; i < elems.length; ++i) { for (var i = 0; i < elems.length; ++i) {
var elem = elems[i]; var elem = elems[i];
@ -712,7 +732,7 @@
opts.fn(); opts.fn();
} }
if(opts.icon) { if(opts.icon) {
var icon = $.getSvgIcon(opts.icon).clone(); var icon = $.getSvgIcon(opts.icon, true);
} else { } else {
// //
var icon = $(opts.sel).children().eq(0).clone(); var icon = $(opts.sel).children().eq(0).clone();
@ -1345,10 +1365,8 @@
if(svgCanvas.addedNew) { if(svgCanvas.addedNew) {
if(elname == 'image') { if(elname == 'image') {
var xlinkNS = "http://www.w3.org/1999/xlink";
var href = elem.getAttributeNS(xlinkNS, "href");
// Prompt for URL if not a data URL // Prompt for URL if not a data URL
if(href.indexOf('data:') !== 0) { if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
promptImgURL(); promptImgURL();
} }
} else if(elname == 'text') { } else if(elname == 'text') {
@ -1455,9 +1473,7 @@
} }
} // text } // text
else if(el_name == 'image') { else if(el_name == 'image') {
var xlinkNS="http://www.w3.org/1999/xlink"; setImageURL(svgCanvas.getHref(elem));
var href = elem.getAttributeNS(xlinkNS, "href");
setImageURL(href);
} // image } // image
else if(el_name == 'g' || el_name == 'use') { else if(el_name == 'g' || el_name == 'use') {
$('#container_panel').show(); $('#container_panel').show();
@ -1476,6 +1492,8 @@
} // if (elem != null) } // if (elem != null)
else if (multiselected) { else if (multiselected) {
$('#multiselected_panel').show(); $('#multiselected_panel').show();
} else {
$('#cmenu_canvas li').disableContextMenuItems('#delete,#cut,#copy,#move_up,#move_down');
} }
// update history buttons // update history buttons
@ -1497,6 +1515,9 @@
if ( (elem && !is_node) || multiselected) { if ( (elem && !is_node) || multiselected) {
// update the selected elements' layer // update the selected elements' layer
$('#selLayerNames').removeAttr('disabled').val(currentLayer); $('#selLayerNames').removeAttr('disabled').val(currentLayer);
// Enable regular menu options
canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_down,#move_up');
} }
else { else {
$('#selLayerNames').attr('disabled', 'disabled'); $('#selLayerNames').attr('disabled', 'disabled');
@ -1766,7 +1787,9 @@
$('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
$(button).addClass('tool_button_current').removeClass('tool_button'); $(button).addClass('tool_button_current').removeClass('tool_button');
// when a tool is selected, we should deselect any currently selected elements // when a tool is selected, we should deselect any currently selected elements
svgCanvas.clearSelection(); if(button !== '#tool_select') {
svgCanvas.clearSelection();
}
return true; return true;
}; };
@ -1851,8 +1874,11 @@
} }
on_button = false; on_button = false;
}).mousedown(function(evt) { }).mousedown(function(evt) {
var islib = $(evt.target).closest('div.tools_flyout').length; // $(".contextMenu").hide();
if(!islib) $('.tools_flyout:visible').fadeOut(); // console.log('cm', $(evt.target).closest('.contextMenu'));
var islib = $(evt.target).closest('div.tools_flyout, .contextMenu').length;
if(!islib) $('.tools_flyout:visible,.contextMenu').fadeOut(250);
}); });
overlay.bind('mousedown',function() { overlay.bind('mousedown',function() {
@ -2197,17 +2223,35 @@
} }
}; };
var cutSelected = function() {
if (selectedElement != null || multiselected) {
svgCanvas.cutSelectedElements();
}
};
var copySelected = function() {
if (selectedElement != null || multiselected) {
svgCanvas.copySelectedElements();
}
};
var moveToTopSelected = function() { var moveToTopSelected = function() {
if (selectedElement != null) { if (selectedElement != null) {
svgCanvas.moveToTopSelectedElement(); svgCanvas.moveToTopSelectedElement();
} }
}; };
var moveToBottomSelected = function() { var moveToBottomSelected = function() {
if (selectedElement != null) { if (selectedElement != null) {
svgCanvas.moveToBottomSelectedElement(); svgCanvas.moveToBottomSelectedElement();
} }
}; };
var moveUpDownSelected = function(dir) {
if (selectedElement != null) {
svgCanvas.moveUpDownSelected(dir);
}
};
var convertToPath = function() { var convertToPath = function() {
if (selectedElement != null) { if (selectedElement != null) {
@ -2422,9 +2466,13 @@
$('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : "");
} }
var showSourceEditor = function(){ var showSourceEditor = function(e, forSaving){
if (editingsource) return; if (editingsource) return;
editingsource = true; editingsource = true;
$('#save_output_btns').toggle(!!forSaving);
$('#tool_source_back').toggle(!forSaving);
var str = svgCanvas.getSvgString(); var str = svgCanvas.getSvgString();
$('#svg_source_textarea').val(str); $('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn(); $('#svg_source_editor').fadeIn();
@ -2463,6 +2511,12 @@
if(url) { if(url) {
$('#canvas_bg_url').val(url); $('#canvas_bg_url').val(url);
} }
$('grid_snapping_step').attr('value', curConfig.snappingStep);
if (curConfig.gridSnapping == true) {
$('#grid_snapping_on').attr('checked', 'checked');
} else {
$('#grid_snapping_on').removeAttr('checked');
}
$('#svg_docprops').fadeIn(); $('#svg_docprops').fadeIn();
}; };
@ -2549,6 +2603,10 @@
// set icon size // set icon size
setIconSize($('#iconsize').val()); setIconSize($('#iconsize').val());
// set grid setting
curConfig.gridSnapping = $('#grid_snapping_on').attr('checked');
curConfig.snappingStep = $('#grid_snapping_step').val();
updateCanvas(); updateCanvas();
hideDocProperties(); hideDocProperties();
}; };
@ -2563,25 +2621,18 @@
} }
var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) {
var icon = (typeof icon_id == 'string') ? $.getSvgIcon(icon_id) : icon_id; var icon = (typeof icon_id == 'string') ? $.getSvgIcon(icon_id, true) : icon_id;
if(!icon) { if(!icon) {
console.log('NOTE: Icon image missing: ' + icon_id); console.log('NOTE: Icon image missing: ' + icon_id);
return; return;
} }
icon = icon.clone(); try {
$(elem).empty().append(icon); icon = icon.clone();
// if(forcedSize) { $(elem).empty().append(icon);
// var obj = {}; } catch(e) {
// obj[elem + ' .svg_icon'] = forcedSize; // icon = svgCanvas.copyElem(icon[0]);
// $.resizeSvgIcons(obj); }
// } else {
// var size = curPrefs.iconsize;
// if(size && size !== 'm') {
// var icon_sizes = { s:16, m:24, l:32, xl:48}, obj = {};
// obj[elem + ' .svg_icon'] = icon_sizes[size];
// $.resizeSvgIcons(obj);
// }
// }
} }
var ua_prefix; var ua_prefix;
@ -2908,7 +2959,9 @@
$('#change_image_url').click(promptImgURL); $('#change_image_url').click(promptImgURL);
function promptImgURL() { function promptImgURL() {
$.prompt(uiStrings.enterNewImgURL, default_img_url, function(url) { var curhref = svgCanvas.getHref(selectedElement);
curhref = curhref.indexOf("data:") === 0?"":curhref;
$.prompt(uiStrings.enterNewImgURL, curhref, function(url) {
if(url) setImageURL(url); if(url) setImageURL(url);
}); });
} }
@ -2945,9 +2998,11 @@
var i = shortcutButtons.length; var i = shortcutButtons.length;
while (i--) { while (i--) {
var button = document.getElementById(shortcutButtons[i]); var button = document.getElementById(shortcutButtons[i]);
var title = button.title; if (button != null) {
var index = title.indexOf("Ctrl+"); var title = button.title;
button.title = [title.substr(0,index), "Cmd+", title.substr(index+5)].join(''); var index = title.indexOf("Ctrl+");
button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join('');
}
} }
} }
@ -3059,44 +3114,71 @@
operaRepaint(); operaRepaint();
}; };
// set up gradients to be used for the buttons
var svgdocbox = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\
fill="#' + curConfig.initFill.color + '" opacity="' + curConfig.initFill.opacity + '"/>\
<linearGradient id="gradbox_">\
<stop stop-color="#000" offset="0.0"/>\
<stop stop-color="#FF0000" offset="1.0"/>\
</linearGradient></svg>', 'text/xml');
var boxgrad = svgdocbox.getElementById('gradbox_');
boxgrad.id = 'gradbox_fill';
svgdocbox.documentElement.setAttribute('width',16.5);
$('#fill_color').append( document.importNode(svgdocbox.documentElement,true) );
boxgrad.id = 'gradbox_stroke'; if(window.DOMParser) {
svgdocbox.documentElement.setAttribute('width',16.5); // set up gradients to be used for the buttons
$('#stroke_color').append( document.importNode(svgdocbox.documentElement,true) ); var svgdocbox = new DOMParser().parseFromString(
$('#stroke_color rect').attr({ '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\
'fill': '#' + curConfig.initStroke.color, fill="#' + curConfig.initFill.color + '" opacity="' + curConfig.initFill.opacity + '"/>\
'opacity': curConfig.initStroke.opacity <linearGradient id="gradbox_">\
}); <stop stop-color="#000" offset="0.0"/>\
<stop stop-color="#FF0000" offset="1.0"/>\
$('#stroke_width').val(curConfig.initStroke.width); </linearGradient></svg>', 'text/xml');
$('#group_opacity').val(curConfig.initOpacity * 100); var docElem = svgdocbox.documentElement;
// Use this SVG elem to test vectorEffect support
var test_el = svgdocbox.documentElement.firstChild; var boxgrad = svgdocbox.getElementById('gradbox_');
test_el.setAttribute('style','vector-effect:non-scaling-stroke'); boxgrad.id = 'gradbox_fill';
var supportsNonSS = (test_el.style.vectorEffect == 'non-scaling-stroke'); docElem.setAttribute('width',16.5);
test_el.removeAttribute('style'); $('#fill_color').append( document.importNode(docElem,true) );
// Use this to test support for blur element. Seems to work to test support in Webkit boxgrad.id = 'gradbox_stroke';
var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); docElem.setAttribute('width',16.5);
if(typeof blur_test.stdDeviationX === "undefined") { $('#stroke_color').append( document.importNode(docElem,true) );
$('#tool_blur').hide(); $('#stroke_color rect').attr({
'fill': '#' + curConfig.initStroke.color,
'opacity': curConfig.initStroke.opacity
});
$('#stroke_width').val(curConfig.initStroke.width);
$('#group_opacity').val(curConfig.initOpacity * 100);
// Use this SVG elem to test vectorEffect support
var test_el = docElem.firstChild;
test_el.setAttribute('style','vector-effect:non-scaling-stroke');
var supportsNonSS = (test_el.style.vectorEffect == 'non-scaling-stroke');
test_el.removeAttribute('style');
// Use this to test support for blur element. Seems to work to test support in Webkit
var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
if(typeof blur_test.stdDeviationX === "undefined") {
$('#tool_blur').hide();
}
$(blur_test).remove();
} else {
var svgns = "http://www.w3.org/2000/svg";
var svgdocbox = document.createElementNS(svgns, 'svg');
var rect = svgCanvas.addSvgElementFromJson({
element: 'rect',
attr: {
width: '100%',
height: '100%',
fill: '#' + curConfig.initFill.color,
opacity: curConfig.initFill.opacity
}
});
svgdocbox.appendChild(rect);
var linearGradient = svgCanvas.addSvgElementFromJson({
element: 'linearGradient',
attr: {
id: 'gradbox_'
}
});
svgdocbox.appendChild(linearGradient);
var docElem = svgdocbox;
} }
$(blur_test).remove();
// Test for embedImage support (use timeout to not interfere with page load) // Test for embedImage support (use timeout to not interfere with page load)
setTimeout(function() { setTimeout(function() {
@ -3499,17 +3581,17 @@
{sel:'#tool_text', fn: clickText, evt: 'click', key: 7}, {sel:'#tool_text', fn: clickText, evt: 'click', key: 7},
{sel:'#tool_image', fn: clickImage, evt: 'mouseup', key: 8}, {sel:'#tool_image', fn: clickImage, evt: 'mouseup', key: 8},
{sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: 9}, {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: 9},
{sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey+'N', true]}, {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: ['N', true]},
{sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey+'S', true]}, {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: ['S', true]},
{sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, {sel:'#tool_export', fn: clickExport, evt: 'mouseup'},
{sel:'#tool_open', fn: clickOpen, evt: 'mouseup', key: [modKey+'O', true]}, {sel:'#tool_open', fn: clickOpen, evt: 'mouseup', key: ['O', true]},
{sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, {sel:'#tool_import', fn: clickImport, evt: 'mouseup'},
{sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: ['U', true]}, {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: ['U', true]},
{sel:'#tool_wireframe', fn: clickWireframe, evt: 'click', key: ['F', true]}, {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click', key: ['F', true]},
{sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true},
{sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'},
{sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'},
{sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup', key: [modKey+'P', true]}, {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup', key: ['P', true]},
{sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]},
{sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, {sel:'#tool_reorient', fn: reorientPath, evt: 'click'},
{sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'}, {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'},
@ -3520,10 +3602,10 @@
{sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'shift+up'}, {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'shift+up'},
{sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'shift+down'}, {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'shift+down'},
{sel:'#tool_topath', fn: convertToPath, evt: 'click'}, {sel:'#tool_topath', fn: convertToPath, evt: 'click'},
{sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey+'Z', true]}, {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: ['Z', true]},
{sel:'#tool_redo', fn: clickRedo, evt: 'click', key: [modKey+'Y', true]}, {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]},
{sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey+'C', true]}, {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: ['C', true]},
{sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey+'G', true]}, {sel:'#tool_group', fn: clickGroup, evt: 'click', key: ['G', true]},
{sel:'#tool_ungroup', fn: clickGroup, evt: 'click'}, {sel:'#tool_ungroup', fn: clickGroup, evt: 'click'},
{sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'},
{sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'},
@ -3532,15 +3614,18 @@
// {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'}, // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'},
{sel:'#tool_bold', fn: clickBold, evt: 'mousedown'}, {sel:'#tool_bold', fn: clickBold, evt: 'mousedown'},
{sel:'#tool_italic', fn: clickItalic, evt: 'mousedown'}, {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown'},
{sel:'#sidepanel_handle', fn: toggleSidePanel, key: [modKey+'X']}, {sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']},
{sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'},
// Shortcuts not associated with buttons // Shortcuts not associated with buttons
{key: 'shift+left', fn: function(){rotateSelected(0)}}, {key: 'shift+left', fn: function(){rotateSelected(0)}},
{key: 'shift+right', fn: function(){rotateSelected(1)}}, {key: 'shift+right', fn: function(){rotateSelected(1)}},
{key: 'shift+O', fn: selectPrev}, {key: 'shift+O', fn: selectPrev},
{key: 'shift+P', fn: selectNext}, {key: 'shift+P', fn: selectNext},
{key: ['ctrl+up', true], fn: function(){zoomImage(2);}}, {key: [modKey+'up', true], fn: function(){zoomImage(2);}},
{key: ['ctrl+down', true], fn: function(){zoomImage(.5);}}, {key: [modKey+'down', true], fn: function(){zoomImage(.5);}},
{key: [modKey+'[', true], fn: function(){moveUpDownSelected('Down');}},
{key: [modKey+']', true], fn: function(){moveUpDownSelected('Up');}},
{key: ['up', true], fn: function(){moveSelected(0,-1);}}, {key: ['up', true], fn: function(){moveSelected(0,-1);}},
{key: ['down', true], fn: function(){moveSelected(0,1);}}, {key: ['down', true], fn: function(){moveSelected(0,1);}},
{key: ['left', true], fn: function(){moveSelected(-1,0);}}, {key: ['left', true], fn: function(){moveSelected(-1,0);}},
@ -3705,6 +3790,48 @@
$('#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 });
$("#workarea").contextMenu({
menu: 'cmenu_canvas',
inSpeed: 0
},
function(action, el, pos) {
switch ( action ) {
case 'delete':
deleteSelected();
break;
case 'cut':
cutSelected();
break;
case 'copy':
copySelected();
break;
case 'paste':
svgCanvas.pasteElements();
break;
case 'paste_in_place':
svgCanvas.pasteElements('in_place');
break;
case 'move_down':
moveUpDownSelected('Down');
break;
case 'move_up':
moveUpDownSelected('Up');
break;
}
if(svgCanvas.clipBoard.length) {
canv_menu.enableContextMenuItems('#paste,#paste_in_place');
}
});
$('.contextMenu li').mousedown(function(ev) {
ev.preventDefault();
})
$('#cmenu_canvas li').disableContextMenu();
canv_menu.enableContextMenuItems('#delete,#cut,#copy');
window.onbeforeunload = function() { window.onbeforeunload = function() {
// Suppress warning if page is empty // Suppress warning if page is empty
if(undoMgr.getUndoStackSize() === 0) { if(undoMgr.getUndoStackSize() === 0) {
@ -3835,7 +3962,7 @@
updateCanvas(true); updateCanvas(true);
// }); // });
// var revnums = "svg-editor.js ($Rev: 1659 $) "; // var revnums = "svg-editor.js ($Rev: 1706 $) ";
// revnums += svgCanvas.getVersion(); // revnums += svgCanvas.getVersion();
// $('#copyright')[0].setAttribute("title", revnums); // $('#copyright')[0].setAttribute("title", revnums);
@ -3996,7 +4123,7 @@
Editor.addExtension = function() { Editor.addExtension = function() {
var args = arguments; var args = arguments;
$(function() { $(function() {
svgCanvas.addExtension.apply(this, args); if(svgCanvas) svgCanvas.addExtension.apply(this, args);
}); });
}; };

File diff suppressed because it is too large Load diff

View file

@ -128,7 +128,40 @@ $(function() {
(function($) { (function($) {
var svg_icons = {}; function makeSVG(el) {
// manually create a copy of the element
var new_el = document.createElementNS(el.namespaceURI, el.nodeName);
$.each(el.attributes, function(i, attr) {
var ns = attr.namespaceURI;
if(ns) {
new_el.setAttributeNS(ns, attr.nodeName, attr.nodeValue);
} else {
new_el.setAttribute(attr.nodeName, attr.nodeValue);
}
if(attr.nodeName == 'transform') {
console.log('val1:', attr.nodeValue);
console.log('val2:', new_el.getAttribute('transform'));
}
});
// now create copies of all children
$.each(el.childNodes, function(i, child) {
switch(child.nodeType) {
case 1: // element node
new_el.appendChild(makeSVG(child));
break;
case 3: // text node
new_el.textContent = child.nodeValue;
break;
default:
break;
}
});
return new_el;
}
var svg_icons = {}, fixIDs;
$.svgIcons = function(file, opts) { $.svgIcons = function(file, opts) {
var svgns = "http://www.w3.org/2000/svg", var svgns = "http://www.w3.org/2000/svg",
@ -168,7 +201,19 @@ $(function() {
}); });
} else { } else {
if(err.responseXML) { if(err.responseXML) {
// Is there a non-ActiveX solution in IE9?
svgdoc = err.responseXML; svgdoc = err.responseXML;
if(!svgdoc.childNodes.length) {
if(window.ActiveXObject) {
svgdoc = new ActiveXObject("Microsoft.XMLDOM");
svgdoc.loadXML(err.responseText);
} else {
$(useFallback);
}
} else {
$(useFallback);
}
$(function() { $(function() {
getIcons('ajax'); getIcons('ajax');
}); });
@ -220,20 +265,29 @@ $(function() {
} }
} }
}); });
elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent');
var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
testImg = $(new Image()).attr({ elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent');
src: testSrc,
width: 0, if(!opts.no_img) {
height: 0
}).appendTo('body') var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
.load(function () {
// Safari 4 crashes, Opera and Chrome don't testImg = $(new Image()).attr({
makeIcons(!isSafari); src: testSrc,
}).error(function () { width: 0,
makeIcons(); height: 0
}); }).appendTo('body')
.load(function () {
// Safari 4 crashes, Opera and Chrome don't
makeIcons(!isSafari);
}).error(function () {
makeIcons();
});
} else {
setTimeout(function() {
if(!icons_made) makeIcons();
},500);
}
} }
function makeIcons(toImage, fallback) { function makeIcons(toImage, fallback) {
@ -290,9 +344,12 @@ $(function() {
var id = elem.getAttribute('id'); var id = elem.getAttribute('id');
if(id == 'svg_eof') return; if(id == 'svg_eof') return;
holder = $('#' + id); holder = $('#' + id);
if(elem.getElementsByTagNameNS) {
var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0];
var svgroot = svgdoc.createElementNS(svgns, "svg"); } else {
var svg = elem.getElementsByTagName('svg')[0];
}
var svgroot = document.createElementNS(svgns, "svg");
svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' ')); svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' '));
// Make flexible by converting width/height to viewBox // Make flexible by converting width/height to viewBox
@ -318,7 +375,13 @@ $(function() {
// With cloning, causes issue in Opera/Win/Non-EN // With cloning, causes issue in Opera/Win/Non-EN
if(!isOpera) svg = svg.cloneNode(true); if(!isOpera) svg = svg.cloneNode(true);
svgroot.appendChild(svg); // TODO: Figure out why makeSVG is necessary for IE9
try {
svgroot.appendChild(svg);
} catch(e) {
// For IE9
svgroot.appendChild(makeSVG(svg));
}
if(toImage) { if(toImage) {
// Without cloning, Safari will crash // Without cloning, Safari will crash
@ -339,8 +402,12 @@ $(function() {
$.each(opts.placement, function(sel, id) { $.each(opts.placement, function(sel, id) {
if(!svg_icons[id]) return; if(!svg_icons[id]) return;
$(sel).each(function(i) { $(sel).each(function(i) {
var copy = svg_icons[id].clone(); // TODO: Figure out why makeSVG is necessary for IE9
if(i > 0 && !toImage) copy = fixIDs(copy, i, true); try {
var copy = svg_icons[id].clone();
} catch(e) {
var copy = makeSVG(svg_icons[id][0]);
}
setIcon($(this), copy, id); setIcon($(this), copy, id);
}) })
}); });
@ -348,18 +415,16 @@ $(function() {
if(!fallback) { if(!fallback) {
if(toImage) temp_holder.remove(); if(toImage) temp_holder.remove();
if(data_el) data_el.remove(); if(data_el) data_el.remove();
testImg.remove(); if(testImg) testImg.remove();
} }
if(opts.resize) $.resizeSvgIcons(opts.resize); if(opts.resize) $.resizeSvgIcons(opts.resize);
icons_made = true; icons_made = true;
if(opts.callback) opts.callback(svg_icons); if(opts.callback) opts.callback(svg_icons);
} }
function fixIDs(svg_el, svg_num, force) { fixIDs = function(svg_el, svg_num, force) {
var defs = svg_el.find('defs'); var defs = svg_el.find('defs');
if(!defs.length) return svg_el; if(!defs.length) return svg_el;
@ -433,7 +498,13 @@ $(function() {
} }
} }
$.getSvgIcon = function(id) { return svg_icons[id]; } $.getSvgIcon = function(id, uniqueClone) {
var icon = svg_icons[id];
if(uniqueClone) {
icon = fixIDs(icon, 0, true).clone(true);
}
return icon;
}
$.resizeSvgIcons = function(obj) { $.resizeSvgIcons = function(obj) {
// FF2 and older don't detect .svg_icon, so we change it detect svg elems instead // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead

View file

@ -87,7 +87,7 @@
curseg = seglist.getItem(1); curseg = seglist.getItem(1);
equal(curseg.pathSegTypeAsLetter, "L", "Before conversion, segment #2 type"); equal(curseg.pathSegTypeAsLetter, "L", "Before conversion, segment #2 type");
curseg = seglist.getItem(2); curseg = seglist.getItem(2);
equal(curseg.pathSegType, 1, "Before conversion, segment #3 type"); equal(curseg.pathSegTypeAsLetter, "Z", "Before conversion, segment #3 type" + d_abs);
// convert and verify segments // convert and verify segments
var d = convert(p1, true); var d = convert(p1, true);