Merge branch 'bzr/golem' of /Users/distler/Sites/code/instiki

This commit is contained in:
Jacques Distler 2010-09-10 15:20:20 -05:00
commit 04bb80be15
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.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(){
// canvg(target, s)
// target: canvas element or the id of a canvas element
// 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') {
target = document.getElementById(target);
}
@ -30,6 +48,7 @@ if(!window.console) {
svg = target.svg;
svg.stop();
}
svg.opts = opts;
var ctx = target.getContext('2d');
if (s.substr(0,1) == '<') {
@ -43,7 +62,7 @@ if(!window.console) {
}
function build() {
var svg = {};
var svg = { };
svg.FRAMERATE = 30;
@ -52,6 +71,7 @@ if(!window.console) {
svg.Definitions = {};
svg.Styles = {};
svg.Animations = [];
svg.Images = [];
svg.ctx = ctx;
svg.ViewPort = new (function () {
this.viewPorts = [];
@ -69,6 +89,14 @@ if(!window.console) {
});
}
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
svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }
@ -290,6 +318,13 @@ if(!window.console) {
this.angleTo = function(p) {
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) {
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(x2, y2);
}
@ -404,6 +443,9 @@ if(!window.console) {
this.apply = function(ctx) {
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
@ -417,6 +459,12 @@ if(!window.console) {
ctx.rotate(this.angle.Angle.toRadians());
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) {
@ -424,6 +472,9 @@ if(!window.console) {
this.apply = function(ctx) {
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) {
@ -431,6 +482,9 @@ if(!window.console) {
this.apply = function(ctx) {
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) {
@ -455,12 +509,19 @@ if(!window.console) {
this.Type.skewY.prototype = new this.Type.SkewBase;
this.transforms = [];
this.apply = function(ctx) {
for (var i=0; i<this.transforms.length; i++) {
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])/);
for (var i=0; i<data.length; i++) {
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
svg.Element = {}
@ -505,6 +603,9 @@ if(!window.console) {
// base render
this.render = function(ctx) {
// don't render display=none
if (this.attribute('display').value == 'none') return;
ctx.save();
this.setContext(ctx);
this.renderChildren(ctx);
@ -581,10 +682,14 @@ if(!window.console) {
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.path(ctx);
svg.Mouse.checkPath(this, ctx);
if (ctx.fillStyle != '') ctx.fill();
if (ctx.strokeStyle != '') ctx.stroke();
@ -743,36 +849,17 @@ if(!window.console) {
width = viewBox[2];
height = viewBox[3];
// aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
var preserveAspectRatio = svg.compressSpaces(this.attribute('preserveAspectRatio').value);
preserveAspectRatio = preserveAspectRatio.replace(/^defer\s/,''); // ignore defer
var align = preserveAspectRatio.split(' ')[0] || 'xMidYMid';
var meetOrSlice = preserveAspectRatio.split(' ')[1] || 'meet';
// calculate scale
var scaleX = svg.ViewPort.width() / width;
var scaleY = svg.ViewPort.height() / height;
var scaleMin = Math.min(scaleX, scaleY);
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.AspectRatio(ctx,
this.attribute('preserveAspectRatio').value,
svg.ViewPort.width(),
width,
svg.ViewPort.height(),
height,
minX,
minY,
this.attribute('refX').value,
this.attribute('refY').value);
svg.ViewPort.RemoveCurrent();
svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
}
@ -920,6 +1007,7 @@ if(!window.console) {
this.getMarkers = function() {
var markers = [];
for (var i=0; i<this.points.length - 1; i++) {
markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]);
}
@ -969,6 +1057,7 @@ if(!window.console) {
this.reset = function() {
this.i = -1;
this.command = '';
this.previousCommand = '';
this.control = new svg.Point(0, 0);
this.current = new svg.Point(0, 0);
this.points = [];
@ -987,7 +1076,7 @@ if(!window.console) {
this.isRelativeCommand = function() {
return this.command == this.command.toLowerCase();
}
this.getToken = function() {
this.i = this.i + 1;
return this.tokens[this.i];
@ -998,6 +1087,7 @@ if(!window.console) {
}
this.nextCommand = function() {
this.previousCommand = this.command;
this.command = this.getToken();
}
@ -1019,8 +1109,13 @@ if(!window.console) {
}
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);
return this.makeAbsolute(p);
return 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);
}
}
else if (pp.command.toUpperCase() == 'A') {
while (!pp.isCommandOrEnd()) {
var curr = pp.current;
@ -1304,7 +1398,7 @@ if(!window.console) {
// definitions element
svg.Element.defs = function(node) {
this.base = svg.Element.ElementBase;
this.base(node);
this.base(node);
this.render = function(ctx) {
// NOOP
@ -1324,15 +1418,20 @@ if(!window.console) {
var child = this.children[i];
this.stops.push(child);
}
this.getGradient = function() {
// OVERRIDE ME!
}
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);
for (var i=0; i<this.stops.length; i++) {
g.addColorStop(this.stops[i].offset, this.stops[i].color);
for (var i=0; i<stopsContainer.stops.length; i++) {
g.addColorStop(stopsContainer.stops[i].offset, stopsContainer.stops[i].color);
}
return g;
}
@ -1360,7 +1459,15 @@ if(!window.console) {
? bb.y() + bb.height() * this.attribute('y2').numValue()
: 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;
@ -1397,7 +1504,15 @@ if(!window.console) {
? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
: 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;
@ -1555,10 +1670,26 @@ if(!window.console) {
var x = this.attribute('x').Length.toPixels('x');
var y = this.attribute('y').Length.toPixels('y');
for (var i=0; i<this.children.length; i++) {
this.children[i].x = x;
this.children[i].y = y;
this.children[i].render(ctx);
x += this.children[i].measureText(ctx);
var child = this.children[i];
if (child.attribute('x').hasValue()) {
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) {
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;
@ -1608,6 +1741,85 @@ if(!window.console) {
}
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
svg.Element.g = function(node) {
this.base = svg.Element.RenderedElementBase;
@ -1621,14 +1833,7 @@ if(!window.console) {
this.base(node);
}
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
svg.Element.style = function(node) {
this.base = svg.Element.ElementBase;
@ -1658,7 +1863,6 @@ if(!window.console) {
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'));
}
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) {
var element = this.attribute('xlink:href').Definition.getDefinition();
var element = this.getDefinition();
if (element != null) element.render(ctx);
}
}
@ -1732,33 +1945,89 @@ if(!window.console) {
// load from xml
svg.loadXml = function(ctx, xml) {
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 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
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
e.render(ctx);
var isFirstRender = true;
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() {
// update animations
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
if (needUpdate) {
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
e.render(ctx);
draw();
svg.Mouse.runEvents(); // run and clear our events
}
}, 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;
}
})();
})();

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.removeFromSelection($(conn_sel).toArray());
mse.apply(this, arguments);
var cmd = mse.apply(this, arguments);
updateConnectors();
return cmd;
}
se_ns = svgCanvas.getEditorNS();
@ -486,6 +487,12 @@ svgEditor.addExtension("Connector", function(S) {
}
},
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
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',
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() {
var browser = $('#imgbrowse');
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');
browser = $('#imgbrowse');
@ -101,24 +101,27 @@ svgEditor.addExtension("imagelib", function() {
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();
}).css({
position: 'absolute',
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();
lib_opts.show();
header.text(all_libs);
}).css({
position: 'absolute',
top: 5,
left: 5
left: 10
});
cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true));
$.each(img_libs, function(i, opts) {
$('<li>').appendTo(lib_opts).text(opts.name).click(function() {
frame.attr('src', opts.url).show();
@ -175,7 +178,7 @@ svgEditor.addExtension("imagelib", function() {
#imgbrowse > div,\
#imgbrowse > ul {\
position: absolute;\
top: 36px;\
top: 45px;\
left: 10px;\
right: 10px;\
bottom: 10px;\

View file

@ -1,10 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg">
<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">
<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"/>
<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="#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 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"/>
</svg>
<svg width="201" height="211" xmlns="http://www.w3.org/2000/svg">
<g>
<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="#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 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"/>
<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>
</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({
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 filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');
@ -42,33 +42,34 @@ svgEditor.addExtension("server_opensave", {
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
canvg(c, data.svg);
var datauri = c.toDataURL('image/png');
var uiStrings = svgEditor.uiStrings;
var note = '';
// Check if there's issues
if(issues.length) {
var pre = "\n \u2022 ";
note += ("\n\n" + pre + issues.join(pre));
}
if(note.length) {
alert(note);
}
var title = svgCanvas.getDocumentTitle();
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');
var form = $('<form>').attr({
method: 'post',
action: save_png_action,
target: 'output_frame'
}) .append('<input type="hidden" name="output_png" value="' + datauri + '">')
.append('<input type="hidden" name="filename" value="' + filename + '">')
.appendTo('body')
.submit().remove();
canvg(c, data.svg, {renderCallback: function() {
var datauri = c.toDataURL('image/png');
var uiStrings = svgEditor.uiStrings;
var note = '';
// Check if there's issues
if(issues.length) {
var pre = "\n \u2022 ";
note += ("\n\n" + pre + issues.join(pre));
}
if(note.length) {
alert(note);
}
var title = svgCanvas.getDocumentTitle();
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');
var form = $('<form>').attr({
method: 'post',
action: save_png_action,
target: 'output_frame'
}) .append('<input type="hidden" name="output_png" value="' + datauri + '">')
.append('<input type="hidden" name="filename" value="' + filename + '">')
.appendTo('body')
.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>
</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">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23">
<defs>
@ -721,8 +733,8 @@
</g>
<g id="fontsize">
<svg width="50" height="50" xmlns="http://www.w3.org/2000/svg" xmlns:xml="http://www.w3.org/XML/1998/namespace">
<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>
<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">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>
</g>

View file

@ -12,4 +12,4 @@
* 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-left: 2px;
padding-right: 2px;
width: 106px;
width: 123px;
height: 20px;
border-right: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
@ -212,6 +212,10 @@
margin-right: 3px;
}
#svg_editor .layer_button:last-child {
margin-right: 0;
}
#svg_editor .layer_buttonpressed {
width: 14px;
height: 14px;
@ -226,7 +230,7 @@
#svg_editor #layerlist {
margin: 1px;
padding: 0px;
width: 110px;
width: 127px;
border-collapse: collapse;
border: 1px solid #808080;
background-color: #FFFFFF;
@ -444,16 +448,7 @@
fill: #FFF !important;
}
#svg_editor #selected_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 {
#tools_top div[id$="_panel"]:not(#editor_panel):not(#history_panel) {
display: none;
}
@ -934,6 +929,16 @@ span.zoom_tool {
z-index: 6;
}
#save_output_btns {
display: none;
text-align: left;
}
#save_output_btns p {
margin: .5em 1.5em;
display: inline-block;
}
#bg_blocks {
overflow: auto;
margin-left: 30px;
@ -1005,8 +1010,9 @@ span.zoom_tool {
color: #444;
}
#canvas_title {
#canvas_title, #canvas_bg_url {
display: block;
width: 96%;
}
#svg_source_editor #svg_source_textarea {
@ -1214,4 +1220,76 @@ span.zoom_tool {
-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}

View file

@ -16,6 +16,7 @@
<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="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="svg-editor.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_up" class="layer_button" title="Move Layer Up"></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>
<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_cancel">Cancel</button>
</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>
<textarea id="svg_source_textarea" spellcheck="false"></textarea>
</form>
@ -581,7 +587,7 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<legend id="svginfo_image_props">Image Properties</legend>
<label>
<span id="svginfo_title">Title:</span>
<input type="text" id="canvas_title" size="24"/>
<input type="text" id="canvas_title"/>
</label>
<fieldset id="change_resolution">
@ -650,10 +656,16 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
<fieldset id="change_background">
<legend id="svginfo_change_background">Editor Background</legend>
<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>
</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>
</div>
@ -667,5 +679,23 @@ script type="text/javascript" src="locale/locale.min.js"></script-->
</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>
</html>

View file

@ -11,6 +11,8 @@
*/
(function() {
// TODO: Find out what causes bugs in jQuery animate for IE9
if($.browser.msie) $.fx.off = true;
if(!window.svgEditor) window.svgEditor = function($) {
var svgCanvas;
@ -46,10 +48,12 @@
langPath: 'locale/',
extPath: 'extensions/',
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',
wireframe: false,
colorPickerCSS: null
colorPickerCSS: null,
gridSnapping: false,
snappingStep: 5
},
uiStrings = Editor.uiStrings = {
"invalidAttrValGiven":"Invalid value given",
@ -435,13 +439,14 @@
"#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4",
];
isMac = false, //(navigator.platform.indexOf("Mac") != -1);
modKey = "", //(isMac ? "meta+" : "ctrl+");
isMac = (navigator.platform.indexOf("Mac") != -1);
modKey = (isMac ? "meta+" : "ctrl+"); // ⌘
path = svgCanvas.pathActions,
undoMgr = svgCanvas.undoMgr,
Utils = svgCanvas.Utils,
default_img_url = curConfig.imgPath + "logo.png",
workarea = $("#workarea"),
canv_menu = $("#cmenu_canvas"),
show_save_warning = false,
exportWindow = null,
tool_scale = 1;
@ -496,9 +501,12 @@
}());
var setSelectMode = function() {
$('.tool_button_current').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}');
var curr = $('.tool_button_current');
if(curr[0].id !== 'tool_select') {
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');
};
@ -539,6 +547,15 @@
// 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));
// 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');
// Check if FF and has <defs/>
if(navigator.userAgent.indexOf('Gecko/') !== -1) {
if(ua.indexOf('Gecko/') !== -1) {
if(svg.indexOf('<defs') !== -1) {
note += "\n\n" + uiStrings.defsFailOnSave;
$.pref('save_notice_done', 'all');
@ -576,25 +593,25 @@
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
canvg(c, data.svg);
var datauri = c.toDataURL('image/png');
exportWindow.location.href = datauri;
var done = $.pref('export_notice_done');
if(done !== "all") {
var note = uiStrings.saveFromBrowser.replace('%s', 'PNG');
// Check if there's issues
if(issues.length) {
var pre = "\n \u2022 ";
note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre));
}
// 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
$.pref('export_notice_done', 'all');
exportWindow.alert(note);
}
canvg(c, data.svg, {renderCallback: function() {
var datauri = c.toDataURL('image/png');
exportWindow.location.href = datauri;
var done = $.pref('export_notice_done');
if(done !== "all") {
var note = uiStrings.saveFromBrowser.replace('%s', 'PNG');
// Check if there's issues
if(issues.length) {
var pre = "\n \u2022 ";
note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre));
}
// 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
$.pref('export_notice_done', 'all');
exportWindow.alert(note);
}
}});
};
// 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
if (mode != "multiselect" && !is_node) {
setSelectMode();
updateToolbar();
}
@ -628,6 +644,10 @@
// called when any element has changed
var elementChanged = function(window,elems) {
if(svgCanvas.getMode() == "select") {
setSelectMode();
}
for (var i = 0; i < elems.length; ++i) {
var elem = elems[i];
@ -712,7 +732,7 @@
opts.fn();
}
if(opts.icon) {
var icon = $.getSvgIcon(opts.icon).clone();
var icon = $.getSvgIcon(opts.icon, true);
} else {
//
var icon = $(opts.sel).children().eq(0).clone();
@ -1345,10 +1365,8 @@
if(svgCanvas.addedNew) {
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
if(href.indexOf('data:') !== 0) {
if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
promptImgURL();
}
} else if(elname == 'text') {
@ -1455,9 +1473,7 @@
}
} // text
else if(el_name == 'image') {
var xlinkNS="http://www.w3.org/1999/xlink";
var href = elem.getAttributeNS(xlinkNS, "href");
setImageURL(href);
setImageURL(svgCanvas.getHref(elem));
} // image
else if(el_name == 'g' || el_name == 'use') {
$('#container_panel').show();
@ -1476,6 +1492,8 @@
} // if (elem != null)
else if (multiselected) {
$('#multiselected_panel').show();
} else {
$('#cmenu_canvas li').disableContextMenuItems('#delete,#cut,#copy,#move_up,#move_down');
}
// update history buttons
@ -1497,6 +1515,9 @@
if ( (elem && !is_node) || multiselected) {
// update the selected elements' layer
$('#selLayerNames').removeAttr('disabled').val(currentLayer);
// Enable regular menu options
canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_down,#move_up');
}
else {
$('#selLayerNames').attr('disabled', 'disabled');
@ -1766,7 +1787,9 @@
$('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
$(button).addClass('tool_button_current').removeClass('tool_button');
// when a tool is selected, we should deselect any currently selected elements
svgCanvas.clearSelection();
if(button !== '#tool_select') {
svgCanvas.clearSelection();
}
return true;
};
@ -1851,8 +1874,11 @@
}
on_button = false;
}).mousedown(function(evt) {
var islib = $(evt.target).closest('div.tools_flyout').length;
if(!islib) $('.tools_flyout:visible').fadeOut();
// $(".contextMenu").hide();
// 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() {
@ -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() {
if (selectedElement != null) {
svgCanvas.moveToTopSelectedElement();
}
};
var moveToBottomSelected = function() {
if (selectedElement != null) {
svgCanvas.moveToBottomSelectedElement();
}
};
var moveUpDownSelected = function(dir) {
if (selectedElement != null) {
svgCanvas.moveUpDownSelected(dir);
}
};
var convertToPath = function() {
if (selectedElement != null) {
@ -2422,9 +2466,13 @@
$('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : "");
}
var showSourceEditor = function(){
var showSourceEditor = function(e, forSaving){
if (editingsource) return;
editingsource = true;
$('#save_output_btns').toggle(!!forSaving);
$('#tool_source_back').toggle(!forSaving);
var str = svgCanvas.getSvgString();
$('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn();
@ -2463,6 +2511,12 @@
if(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();
};
@ -2549,6 +2603,10 @@
// set icon size
setIconSize($('#iconsize').val());
// set grid setting
curConfig.gridSnapping = $('#grid_snapping_on').attr('checked');
curConfig.snappingStep = $('#grid_snapping_step').val();
updateCanvas();
hideDocProperties();
};
@ -2563,25 +2621,18 @@
}
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) {
console.log('NOTE: Icon image missing: ' + icon_id);
return;
}
icon = icon.clone();
$(elem).empty().append(icon);
// if(forcedSize) {
// var obj = {};
// obj[elem + ' .svg_icon'] = forcedSize;
// $.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);
// }
// }
try {
icon = icon.clone();
$(elem).empty().append(icon);
} catch(e) {
// icon = svgCanvas.copyElem(icon[0]);
}
}
var ua_prefix;
@ -2908,7 +2959,9 @@
$('#change_image_url').click(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);
});
}
@ -2945,9 +2998,11 @@
var i = shortcutButtons.length;
while (i--) {
var button = document.getElementById(shortcutButtons[i]);
var title = button.title;
var index = title.indexOf("Ctrl+");
button.title = [title.substr(0,index), "Cmd+", title.substr(index+5)].join('');
if (button != null) {
var title = button.title;
var index = title.indexOf("Ctrl+");
button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join('');
}
}
}
@ -3059,44 +3114,71 @@
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';
svgdocbox.documentElement.setAttribute('width',16.5);
$('#stroke_color').append( document.importNode(svgdocbox.documentElement,true) );
$('#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 = svgdocbox.documentElement.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();
if(window.DOMParser) {
// 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 docElem = svgdocbox.documentElement;
var boxgrad = svgdocbox.getElementById('gradbox_');
boxgrad.id = 'gradbox_fill';
docElem.setAttribute('width',16.5);
$('#fill_color').append( document.importNode(docElem,true) );
boxgrad.id = 'gradbox_stroke';
docElem.setAttribute('width',16.5);
$('#stroke_color').append( document.importNode(docElem,true) );
$('#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)
setTimeout(function() {
@ -3499,17 +3581,17 @@
{sel:'#tool_text', fn: clickText, evt: 'click', key: 7},
{sel:'#tool_image', fn: clickImage, evt: 'mouseup', key: 8},
{sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: 9},
{sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey+'N', true]},
{sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey+'S', true]},
{sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: ['N', true]},
{sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: ['S', true]},
{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_source', fn: showSourceEditor, evt: 'click', key: ['U', 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_save', fn: saveSourceEditor, 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_reorient', fn: reorientPath, 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_bottom', fn: moveToBottomSelected, evt: 'click', key: 'shift+down'},
{sel:'#tool_topath', fn: convertToPath, evt: 'click'},
{sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey+'Z', true]},
{sel:'#tool_redo', fn: clickRedo, evt: 'click', key: [modKey+'Y', true]},
{sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey+'C', true]},
{sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey+'G', true]},
{sel:'#tool_undo', fn: clickUndo, evt: 'click', key: ['Z', true]},
{sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]},
{sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: ['C', true]},
{sel:'#tool_group', fn: clickGroup, evt: 'click', key: ['G', true]},
{sel:'#tool_ungroup', fn: clickGroup, evt: 'click'},
{sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'},
{sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'},
@ -3532,15 +3614,18 @@
// {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'},
{sel:'#tool_bold', fn: clickBold, 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
{key: 'shift+left', fn: function(){rotateSelected(0)}},
{key: 'shift+right', fn: function(){rotateSelected(1)}},
{key: 'shift+O', fn: selectPrev},
{key: 'shift+P', fn: selectNext},
{key: ['ctrl+up', true], fn: function(){zoomImage(2);}},
{key: ['ctrl+down', true], fn: function(){zoomImage(.5);}},
{key: [modKey+'up', true], fn: function(){zoomImage(2);}},
{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: ['down', true], fn: function(){moveSelected(0,1);}},
{key: ['left', true], fn: function(){moveSelected(-1,0);}},
@ -3705,6 +3790,48 @@
$('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur });
$('#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() {
// Suppress warning if page is empty
if(undoMgr.getUndoStackSize() === 0) {
@ -3835,7 +3962,7 @@
updateCanvas(true);
// });
// var revnums = "svg-editor.js ($Rev: 1659 $) ";
// var revnums = "svg-editor.js ($Rev: 1706 $) ";
// revnums += svgCanvas.getVersion();
// $('#copyright')[0].setAttribute("title", revnums);
@ -3996,7 +4123,7 @@
Editor.addExtension = function() {
var args = arguments;
$(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($) {
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) {
var svgns = "http://www.w3.org/2000/svg",
@ -168,7 +201,19 @@ $(function() {
});
} else {
if(err.responseXML) {
// Is there a non-ActiveX solution in IE9?
svgdoc = err.responseXML;
if(!svgdoc.childNodes.length) {
if(window.ActiveXObject) {
svgdoc = new ActiveXObject("Microsoft.XMLDOM");
svgdoc.loadXML(err.responseText);
} else {
$(useFallback);
}
} else {
$(useFallback);
}
$(function() {
getIcons('ajax');
});
@ -220,20 +265,29 @@ $(function() {
}
}
});
elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent');
var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
testImg = $(new Image()).attr({
src: testSrc,
width: 0,
height: 0
}).appendTo('body')
.load(function () {
// Safari 4 crashes, Opera and Chrome don't
makeIcons(!isSafari);
}).error(function () {
makeIcons();
});
elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent');
if(!opts.no_img) {
var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
testImg = $(new Image()).attr({
src: testSrc,
width: 0,
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) {
@ -290,9 +344,12 @@ $(function() {
var id = elem.getAttribute('id');
if(id == 'svg_eof') return;
holder = $('#' + id);
var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0];
var svgroot = svgdoc.createElementNS(svgns, "svg");
if(elem.getElementsByTagNameNS) {
var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0];
} else {
var svg = elem.getElementsByTagName('svg')[0];
}
var svgroot = document.createElementNS(svgns, "svg");
svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' '));
// Make flexible by converting width/height to viewBox
@ -318,7 +375,13 @@ $(function() {
// With cloning, causes issue in Opera/Win/Non-EN
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) {
// Without cloning, Safari will crash
@ -339,8 +402,12 @@ $(function() {
$.each(opts.placement, function(sel, id) {
if(!svg_icons[id]) return;
$(sel).each(function(i) {
var copy = svg_icons[id].clone();
if(i > 0 && !toImage) copy = fixIDs(copy, i, true);
// TODO: Figure out why makeSVG is necessary for IE9
try {
var copy = svg_icons[id].clone();
} catch(e) {
var copy = makeSVG(svg_icons[id][0]);
}
setIcon($(this), copy, id);
})
});
@ -348,18 +415,16 @@ $(function() {
if(!fallback) {
if(toImage) temp_holder.remove();
if(data_el) data_el.remove();
testImg.remove();
if(testImg) testImg.remove();
}
if(opts.resize) $.resizeSvgIcons(opts.resize);
icons_made = true;
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');
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) {
// 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);
equal(curseg.pathSegTypeAsLetter, "L", "Before conversion, segment #2 type");
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
var d = convert(p1, true);