// ┌─────────────────────────────────────────────────────────────────────┐ \\
-// │ Raphaël 2 - JavaScript Vector Library │ \\
+// │ Raphaël - JavaScript Vector Library │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ SVG Module │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
}
return el;
},
- gradients = {},
- rgGrad = /^url\(#(.*)\)$/,
- removeGradientFill = function (node, paper) {
- var oid = node.getAttribute("fill");
- oid = oid && oid.match(rgGrad);
- if (oid && !--gradients[oid[1]]) {
- delete gradients[oid[1]];
- paper.defs.removeChild(R._g.doc.getElementById(oid[1]));
- }
- },
addGradientFill = function (element, gradient) {
var type = "linear",
id = element.id + gradient,
if (!dots) {
return null;
}
- if (element.gradient) {
+ id = id.replace(/[\(\)\s,\xb0#]/g, "_");
+
+ if (element.gradient && id != element.gradient.id) {
SVG.defs.removeChild(element.gradient);
delete element.gradient;
}
- id = id.replace(/[\(\)\s,\xb0#]/g, "-");
- el = $(type + "Gradient", {id: id});
- element.gradient = el;
- $(el, type == "radial" ? {
- fx: fx,
- fy: fy
- } : {
- x1: vector[0],
- y1: vector[1],
- x2: vector[2],
- y2: vector[3],
- gradientTransform: element.matrix.invert()
- });
- SVG.defs.appendChild(el);
- for (var i = 0, ii = dots.length; i < ii; i++) {
- el.appendChild($("stop", {
- offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
- "stop-color": dots[i].color || "#fff"
- }));
+ if (!element.gradient) {
+ el = $(type + "Gradient", {id: id});
+ element.gradient = el;
+ $(el, type == "radial" ? {
+ fx: fx,
+ fy: fy
+ } : {
+ x1: vector[0],
+ y1: vector[1],
+ x2: vector[2],
+ y2: vector[3],
+ gradientTransform: element.matrix.invert()
+ });
+ SVG.defs.appendChild(el);
+ for (var i = 0, ii = dots.length; i < ii; i++) {
+ el.appendChild($("stop", {
+ offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
+ "stop-color": dots[i].color || "#fff"
+ }));
+ }
}
}
$(o, {
o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
var el = $("clipPath"),
rc = $("rect");
- el.id = R._createUUID();
+ el.id = R.createUUID();
$(rc, {
x: rect[0],
y: rect[1],
o.clip = rc;
}
if (!value) {
- var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E));
- clip && clip.parentNode.removeChild(clip);
- $(node, {"clip-path": E});
- delete o.clip;
+ var path = node.getAttribute("clip-path");
+ if (path) {
+ var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
+ clip && clip.parentNode.removeChild(clip);
+ $(node, {"clip-path": E});
+ delete o.clip;
+ }
}
break;
case "path":
if (isURL) {
el = $("pattern");
var ig = $("image");
- el.id = R._createUUID();
+ el.id = R.createUUID();
$(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
$(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
el.appendChild(ig);
Element.prototype = elproto;
elproto.constructor = Element;
- /*\
- * Element.path
- [ method ]
- **
- * Creates a path element by given path data string.
- > Parameters
- - pathString (string) #optional path string in SVG format.
- * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example:
- | "M10,20L30,40"
- * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative.
- *
- x <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a>.</p>
- # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
- # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
- # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
- # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
- # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
- # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
- # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
- # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
- # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
- # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
- # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
- # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
- * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
- > Usage
- | var c = paper.path("M10 10L90 90");
- | // draw a diagonal line:
- | // move to 10,10, line to 90,90
- \*/
R._engine.path = function (pathString, SVG) {
var el = $("path");
SVG.canvas && SVG.canvas.appendChild(el);
* Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for
* scale and `m` is for matrix.
*
+ * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`.
+ *
* So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100;
* rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin
* coordinates as optional parameters, the default is the centre point of the element.
if (this.removed) {
return;
}
+ var paper = this.paper;
+ paper.__set__ && paper.__set__.exclude(this);
eve.unbind("*.*." + this.id);
- R._tear(this, this.paper);
+ if (this.gradient) {
+ paper.defs.removeChild(this.gradient);
+ }
+ R._tear(this, paper);
this.node.parentNode.removeChild(this.node);
for (var i in this) {
- delete this[i];
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
}
this.removed = true;
};
o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `midium`, length: `long`, `short`, `midium`.
o clip-rect (string) comma or space separated values: x, y, width and height
o cursor (string) CSS type of the cursor
- o cx (number)
- o cy (number)
+ o cx (number) the x-axis coordinate of the center of the circle, or ellipse
+ o cy (number) the y-axis coordinate of the center of the circle, or ellipse
o fill (string) colour, gradient or image
o fill-opacity (number)
o font (string)
o href (string) URL, if specified element behaves as hyperlink
o opacity (number)
o path (string) SVG path string format
- o r (number)
- o rx (number)
- o ry (number)
+ o r (number) radius of the circle, ellipse or rounded corner on the rect
+ o rx (number) horisontal radius of the ellipse
+ o ry (number) vertical radius of the ellipse
o src (string) image URL, only works for @Element.image element
o stroke (string) stroke colour
o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”]
} else if (name != null && R.is(name, "object")) {
params = name;
}
- for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
+ for (var key in params) {
+ eve("attr." + key + "." + this.id, this, params[key]);
+ }
+ for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
this.attrs[key] = params[key];
for (var subkey in par) if (par[has](subkey)) {
if (this.removed) {
return this;
}
- this.node.parentNode.appendChild(this.node);
+ if (this.node.parentNode.tagName.toLowerCase() == "a") {
+ this.node.parentNode.parentNode.appendChild(this.node.parentNode);
+ } else {
+ this.node.parentNode.appendChild(this.node);
+ }
var svg = this.paper;
svg.top != this && R._tofront(this, svg);
return this;
if (this.removed) {
return this;
}
- if (this.node.parentNode.firstChild != this.node) {
- this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
- R._toback(this, this.paper);
- var svg = this.paper;
+ var parent = this.node.parentNode;
+ if (parent.tagName.toLowerCase() == "a") {
+ parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild);
+ } else if (parent.firstChild != this.node) {
+ parent.insertBefore(this.node, this.node.parentNode.firstChild);
}
+ R._toback(this, this.paper);
+ var svg = this.paper;
return this;
};
/*\
var fltr = $("filter"),
blur = $("feGaussianBlur");
t.attrs.blur = size;
- fltr.id = R._createUUID();
+ fltr.id = R.createUUID();
$(blur, {stdDeviation: +size || 1.5});
fltr.appendChild(blur);
t.paper.defs.appendChild(fltr);
R.prototype.renderfix = function () {
var cnvs = this.canvas,
s = cnvs.style,
- pos = cnvs.getScreenCTM(),
+ pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
left = -pos.e % 1,
top = -pos.f % 1;
if (left || top) {
eve("remove", this);
this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
for (var i in this) {
- this[i] = removed(i);
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
}
};
var setproto = R.st;