Added toDataURL() methods to paper and element. Extracted element methods as module.
parent
28b7a7a753
commit
59e4a15cda
|
@ -31,6 +31,7 @@ module.exports = function(grunt) {
|
||||||
"./src/amd-banner.js",
|
"./src/amd-banner.js",
|
||||||
"./src/mina.js",
|
"./src/mina.js",
|
||||||
"./src/svg.js",
|
"./src/svg.js",
|
||||||
|
"./src/element.js",
|
||||||
"./src/matrix.js",
|
"./src/matrix.js",
|
||||||
"./src/attr.js",
|
"./src/attr.js",
|
||||||
"./src/class.js",
|
"./src/class.js",
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
// Snap.svg 0.3.0
|
// Snap.svg 0.3.0
|
||||||
//
|
//
|
||||||
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
// Copyright (c) 2013 – 2014 Adobe Systems Incorporated. All rights reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
// build: 2014-08-04
|
// build: 2014-08-13
|
||||||
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -1732,38 +1732,6 @@ function transform2matrix(tstr, bbox) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
Snap._.transform2matrix = transform2matrix;
|
Snap._.transform2matrix = transform2matrix;
|
||||||
function extractTransform(el, tstr) {
|
|
||||||
if (tstr == null) {
|
|
||||||
var doReturn = true;
|
|
||||||
if (el.type == "linearGradient" || el.type == "radialGradient") {
|
|
||||||
tstr = el.node.getAttribute("gradientTransform");
|
|
||||||
} else if (el.type == "pattern") {
|
|
||||||
tstr = el.node.getAttribute("patternTransform");
|
|
||||||
} else {
|
|
||||||
tstr = el.node.getAttribute("transform");
|
|
||||||
}
|
|
||||||
if (!tstr) {
|
|
||||||
return new Snap.Matrix;
|
|
||||||
}
|
|
||||||
tstr = svgTransform2string(tstr);
|
|
||||||
} else {
|
|
||||||
if (!Snap._.rgTransform.test(tstr)) {
|
|
||||||
tstr = svgTransform2string(tstr);
|
|
||||||
} else {
|
|
||||||
tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
|
|
||||||
}
|
|
||||||
if (is(tstr, "array")) {
|
|
||||||
tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
|
|
||||||
}
|
|
||||||
el._.transform = tstr;
|
|
||||||
}
|
|
||||||
var m = transform2matrix(tstr, el.getBBox(1));
|
|
||||||
if (doReturn) {
|
|
||||||
return m;
|
|
||||||
} else {
|
|
||||||
el.matrix = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Snap._unit2px = unit2px;
|
Snap._unit2px = unit2px;
|
||||||
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
||||||
function (a, b) {
|
function (a, b) {
|
||||||
|
@ -2004,7 +1972,6 @@ function Element(el) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(function (elproto) {
|
|
||||||
/*\
|
/*\
|
||||||
* Element.attr
|
* Element.attr
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -2030,7 +1997,7 @@ function Element(el) {
|
||||||
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
||||||
* and `-`: `"+=2em"`.
|
* and `-`: `"+=2em"`.
|
||||||
\*/
|
\*/
|
||||||
elproto.attr = function (params, value) {
|
Element.prototype.attr = function (params, value) {
|
||||||
var el = this,
|
var el = this,
|
||||||
node = el.node;
|
node = el.node;
|
||||||
if (!params) {
|
if (!params) {
|
||||||
|
@ -2052,6 +2019,414 @@ function Element(el) {
|
||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
/*\
|
||||||
|
* Snap.parse
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Parses SVG fragment and converts it into a @Fragment
|
||||||
|
**
|
||||||
|
- svg (string) SVG string
|
||||||
|
= (Fragment) the @Fragment
|
||||||
|
\*/
|
||||||
|
Snap.parse = function (svg) {
|
||||||
|
var f = glob.doc.createDocumentFragment(),
|
||||||
|
full = true,
|
||||||
|
div = glob.doc.createElement("div");
|
||||||
|
svg = Str(svg);
|
||||||
|
if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) {
|
||||||
|
svg = "<svg>" + svg + "</svg>";
|
||||||
|
full = false;
|
||||||
|
}
|
||||||
|
div.innerHTML = svg;
|
||||||
|
svg = div.getElementsByTagName("svg")[0];
|
||||||
|
if (svg) {
|
||||||
|
if (full) {
|
||||||
|
f = svg;
|
||||||
|
} else {
|
||||||
|
while (svg.firstChild) {
|
||||||
|
f.appendChild(svg.firstChild);
|
||||||
|
}
|
||||||
|
div.innerHTML = E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Fragment(f);
|
||||||
|
};
|
||||||
|
function Fragment(frag) {
|
||||||
|
this.node = frag;
|
||||||
|
}
|
||||||
|
// SIERRA Snap.fragment() could especially use a code example
|
||||||
|
/*\
|
||||||
|
* Snap.fragment
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates a DOM fragment from a given list of elements or strings
|
||||||
|
**
|
||||||
|
- varargs (…) SVG string
|
||||||
|
= (Fragment) the @Fragment
|
||||||
|
\*/
|
||||||
|
Snap.fragment = function () {
|
||||||
|
var args = Array.prototype.slice.call(arguments, 0),
|
||||||
|
f = glob.doc.createDocumentFragment();
|
||||||
|
for (var i = 0, ii = args.length; i < ii; i++) {
|
||||||
|
var item = args[i];
|
||||||
|
if (item.node && item.node.nodeType) {
|
||||||
|
f.appendChild(item.node);
|
||||||
|
}
|
||||||
|
if (item.nodeType) {
|
||||||
|
f.appendChild(item);
|
||||||
|
}
|
||||||
|
if (typeof item == "string") {
|
||||||
|
f.appendChild(Snap.parse(item).node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Fragment(f);
|
||||||
|
};
|
||||||
|
|
||||||
|
function make(name, parent) {
|
||||||
|
var res = $(name);
|
||||||
|
parent.appendChild(res);
|
||||||
|
var el = wrap(res);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
function Paper(w, h) {
|
||||||
|
var res,
|
||||||
|
desc,
|
||||||
|
defs,
|
||||||
|
proto = Paper.prototype;
|
||||||
|
if (w && w.tagName == "svg") {
|
||||||
|
if (w.snap in hub) {
|
||||||
|
return hub[w.snap];
|
||||||
|
}
|
||||||
|
var doc = w.ownerDocument;
|
||||||
|
res = new Element(w);
|
||||||
|
desc = w.getElementsByTagName("desc")[0];
|
||||||
|
defs = w.getElementsByTagName("defs")[0];
|
||||||
|
if (!desc) {
|
||||||
|
desc = $("desc");
|
||||||
|
desc.appendChild(doc.createTextNode("Created with Snap"));
|
||||||
|
res.node.appendChild(desc);
|
||||||
|
}
|
||||||
|
if (!defs) {
|
||||||
|
defs = $("defs");
|
||||||
|
res.node.appendChild(defs);
|
||||||
|
}
|
||||||
|
res.defs = defs;
|
||||||
|
for (var key in proto) if (proto[has](key)) {
|
||||||
|
res[key] = proto[key];
|
||||||
|
}
|
||||||
|
res.paper = res.root = res;
|
||||||
|
} else {
|
||||||
|
res = make("svg", glob.doc.body);
|
||||||
|
$(res.node, {
|
||||||
|
height: h,
|
||||||
|
version: 1.1,
|
||||||
|
width: w,
|
||||||
|
xmlns: xmlns
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
function wrap(dom) {
|
||||||
|
if (!dom) {
|
||||||
|
return dom;
|
||||||
|
}
|
||||||
|
if (dom instanceof Element || dom instanceof Fragment) {
|
||||||
|
return dom;
|
||||||
|
}
|
||||||
|
if (dom.tagName && dom.tagName.toLowerCase() == "svg") {
|
||||||
|
return new Paper(dom);
|
||||||
|
}
|
||||||
|
if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") {
|
||||||
|
return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]);
|
||||||
|
}
|
||||||
|
return new Element(dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
Snap._.make = make;
|
||||||
|
Snap._.wrap = wrap;
|
||||||
|
/*\
|
||||||
|
* Paper.el
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates an element on paper with a given name and no attributes
|
||||||
|
**
|
||||||
|
- name (string) tag name
|
||||||
|
- attr (object) attributes
|
||||||
|
= (Element) the current element
|
||||||
|
> Usage
|
||||||
|
| var c = paper.circle(10, 10, 10); // is the same as...
|
||||||
|
| var c = paper.el("circle").attr({
|
||||||
|
| cx: 10,
|
||||||
|
| cy: 10,
|
||||||
|
| r: 10
|
||||||
|
| });
|
||||||
|
| // and the same as
|
||||||
|
| var c = paper.el("circle", {
|
||||||
|
| cx: 10,
|
||||||
|
| cy: 10,
|
||||||
|
| r: 10
|
||||||
|
| });
|
||||||
|
\*/
|
||||||
|
Paper.prototype.el = function (name, attr) {
|
||||||
|
var el = make(name, this.node);
|
||||||
|
attr && el.attr(attr);
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
// default
|
||||||
|
eve.on("snap.util.getattr", function () {
|
||||||
|
var att = eve.nt();
|
||||||
|
att = att.substring(att.lastIndexOf(".") + 1);
|
||||||
|
var css = att.replace(/[A-Z]/g, function (letter) {
|
||||||
|
return "-" + letter.toLowerCase();
|
||||||
|
});
|
||||||
|
if (cssAttr[has](css)) {
|
||||||
|
return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css);
|
||||||
|
} else {
|
||||||
|
return $(this.node, att);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var cssAttr = {
|
||||||
|
"alignment-baseline": 0,
|
||||||
|
"baseline-shift": 0,
|
||||||
|
"clip": 0,
|
||||||
|
"clip-path": 0,
|
||||||
|
"clip-rule": 0,
|
||||||
|
"color": 0,
|
||||||
|
"color-interpolation": 0,
|
||||||
|
"color-interpolation-filters": 0,
|
||||||
|
"color-profile": 0,
|
||||||
|
"color-rendering": 0,
|
||||||
|
"cursor": 0,
|
||||||
|
"direction": 0,
|
||||||
|
"display": 0,
|
||||||
|
"dominant-baseline": 0,
|
||||||
|
"enable-background": 0,
|
||||||
|
"fill": 0,
|
||||||
|
"fill-opacity": 0,
|
||||||
|
"fill-rule": 0,
|
||||||
|
"filter": 0,
|
||||||
|
"flood-color": 0,
|
||||||
|
"flood-opacity": 0,
|
||||||
|
"font": 0,
|
||||||
|
"font-family": 0,
|
||||||
|
"font-size": 0,
|
||||||
|
"font-size-adjust": 0,
|
||||||
|
"font-stretch": 0,
|
||||||
|
"font-style": 0,
|
||||||
|
"font-variant": 0,
|
||||||
|
"font-weight": 0,
|
||||||
|
"glyph-orientation-horizontal": 0,
|
||||||
|
"glyph-orientation-vertical": 0,
|
||||||
|
"image-rendering": 0,
|
||||||
|
"kerning": 0,
|
||||||
|
"letter-spacing": 0,
|
||||||
|
"lighting-color": 0,
|
||||||
|
"marker": 0,
|
||||||
|
"marker-end": 0,
|
||||||
|
"marker-mid": 0,
|
||||||
|
"marker-start": 0,
|
||||||
|
"mask": 0,
|
||||||
|
"opacity": 0,
|
||||||
|
"overflow": 0,
|
||||||
|
"pointer-events": 0,
|
||||||
|
"shape-rendering": 0,
|
||||||
|
"stop-color": 0,
|
||||||
|
"stop-opacity": 0,
|
||||||
|
"stroke": 0,
|
||||||
|
"stroke-dasharray": 0,
|
||||||
|
"stroke-dashoffset": 0,
|
||||||
|
"stroke-linecap": 0,
|
||||||
|
"stroke-linejoin": 0,
|
||||||
|
"stroke-miterlimit": 0,
|
||||||
|
"stroke-opacity": 0,
|
||||||
|
"stroke-width": 0,
|
||||||
|
"text-anchor": 0,
|
||||||
|
"text-decoration": 0,
|
||||||
|
"text-rendering": 0,
|
||||||
|
"unicode-bidi": 0,
|
||||||
|
"visibility": 0,
|
||||||
|
"word-spacing": 0,
|
||||||
|
"writing-mode": 0
|
||||||
|
};
|
||||||
|
|
||||||
|
eve.on("snap.util.attr", function (value) {
|
||||||
|
var att = eve.nt(),
|
||||||
|
attr = {};
|
||||||
|
att = att.substring(att.lastIndexOf(".") + 1);
|
||||||
|
attr[att] = value;
|
||||||
|
var style = att.replace(/-(\w)/gi, function (all, letter) {
|
||||||
|
return letter.toUpperCase();
|
||||||
|
}),
|
||||||
|
css = att.replace(/[A-Z]/g, function (letter) {
|
||||||
|
return "-" + letter.toLowerCase();
|
||||||
|
});
|
||||||
|
if (cssAttr[has](css)) {
|
||||||
|
this.node.style[style] = value == null ? E : value;
|
||||||
|
} else {
|
||||||
|
$(this.node, attr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(function (proto) {}(Paper.prototype));
|
||||||
|
|
||||||
|
// simple ajax
|
||||||
|
/*\
|
||||||
|
* Snap.ajax
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Simple implementation of Ajax
|
||||||
|
**
|
||||||
|
- url (string) URL
|
||||||
|
- postData (object|string) data for post request
|
||||||
|
- callback (function) callback
|
||||||
|
- scope (object) #optional scope of callback
|
||||||
|
* or
|
||||||
|
- url (string) URL
|
||||||
|
- callback (function) callback
|
||||||
|
- scope (object) #optional scope of callback
|
||||||
|
= (XMLHttpRequest) the XMLHttpRequest object, just in case
|
||||||
|
\*/
|
||||||
|
Snap.ajax = function (url, postData, callback, scope){
|
||||||
|
var req = new XMLHttpRequest,
|
||||||
|
id = ID();
|
||||||
|
if (req) {
|
||||||
|
if (is(postData, "function")) {
|
||||||
|
scope = callback;
|
||||||
|
callback = postData;
|
||||||
|
postData = null;
|
||||||
|
} else if (is(postData, "object")) {
|
||||||
|
var pd = [];
|
||||||
|
for (var key in postData) if (postData.hasOwnProperty(key)) {
|
||||||
|
pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key]));
|
||||||
|
}
|
||||||
|
postData = pd.join("&");
|
||||||
|
}
|
||||||
|
req.open((postData ? "POST" : "GET"), url, true);
|
||||||
|
if (postData) {
|
||||||
|
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
||||||
|
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
eve.once("snap.ajax." + id + ".0", callback);
|
||||||
|
eve.once("snap.ajax." + id + ".200", callback);
|
||||||
|
eve.once("snap.ajax." + id + ".304", callback);
|
||||||
|
}
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if (req.readyState != 4) return;
|
||||||
|
eve("snap.ajax." + id + "." + req.status, scope, req);
|
||||||
|
};
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
req.send(postData);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Snap.load
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX)
|
||||||
|
**
|
||||||
|
- url (string) URL
|
||||||
|
- callback (function) callback
|
||||||
|
- scope (object) #optional scope of callback
|
||||||
|
\*/
|
||||||
|
Snap.load = function (url, callback, scope) {
|
||||||
|
Snap.ajax(url, function (req) {
|
||||||
|
var f = Snap.parse(req.responseText);
|
||||||
|
scope ? callback.call(scope, f) : callback(f);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var getOffset = function (elem) {
|
||||||
|
var box = elem.getBoundingClientRect(),
|
||||||
|
doc = elem.ownerDocument,
|
||||||
|
body = doc.body,
|
||||||
|
docElem = doc.documentElement,
|
||||||
|
clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
|
||||||
|
top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
|
||||||
|
left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
|
||||||
|
return {
|
||||||
|
y: top,
|
||||||
|
x: left
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Snap.getElementByPoint
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns you topmost element under given point.
|
||||||
|
**
|
||||||
|
= (object) Snap element object
|
||||||
|
- x (number) x coordinate from the top left corner of the window
|
||||||
|
- y (number) y coordinate from the top left corner of the window
|
||||||
|
> Usage
|
||||||
|
| Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
|
||||||
|
\*/
|
||||||
|
Snap.getElementByPoint = function (x, y) {
|
||||||
|
var paper = this,
|
||||||
|
svg = paper.canvas,
|
||||||
|
target = glob.doc.elementFromPoint(x, y);
|
||||||
|
if (glob.win.opera && target.tagName == "svg") {
|
||||||
|
var so = getOffset(target),
|
||||||
|
sr = target.createSVGRect();
|
||||||
|
sr.x = x - so.x;
|
||||||
|
sr.y = y - so.y;
|
||||||
|
sr.width = sr.height = 1;
|
||||||
|
var hits = target.getIntersectionList(sr, null);
|
||||||
|
if (hits.length) {
|
||||||
|
target = hits[hits.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return wrap(target);
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Snap.plugin
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Let you write plugins. You pass in a function with four arguments, like this:
|
||||||
|
| Snap.plugin(function (Snap, Element, Paper, global, Fragment) {
|
||||||
|
| Snap.newmethod = function () {};
|
||||||
|
| Element.prototype.newmethod = function () {};
|
||||||
|
| Paper.prototype.newmethod = function () {};
|
||||||
|
| });
|
||||||
|
* Inside the function you have access to all main objects (and their
|
||||||
|
* prototypes). This allow you to extend anything you want.
|
||||||
|
**
|
||||||
|
- f (function) your plugin body
|
||||||
|
\*/
|
||||||
|
Snap.plugin = function (f) {
|
||||||
|
f(Snap, Element, Paper, glob, Fragment);
|
||||||
|
};
|
||||||
|
glob.win.Snap = Snap;
|
||||||
|
return Snap;
|
||||||
|
}());
|
||||||
|
|
||||||
|
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
||||||
|
var elproto = Element.prototype,
|
||||||
|
is = Snap.is,
|
||||||
|
Str = String,
|
||||||
|
unit2px = Snap._unit2px,
|
||||||
|
$ = Snap._.$,
|
||||||
|
make = Snap._.make,
|
||||||
|
getSomeDefs = Snap._.getSomeDefs,
|
||||||
|
has = "hasOwnProperty",
|
||||||
|
wrap = Snap._.wrap;
|
||||||
/*\
|
/*\
|
||||||
* Element.getBBox
|
* Element.getBBox
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -2117,6 +2492,38 @@ function Element(el) {
|
||||||
var propString = function () {
|
var propString = function () {
|
||||||
return this.string;
|
return this.string;
|
||||||
};
|
};
|
||||||
|
function extractTransform(el, tstr) {
|
||||||
|
if (tstr == null) {
|
||||||
|
var doReturn = true;
|
||||||
|
if (el.type == "linearGradient" || el.type == "radialGradient") {
|
||||||
|
tstr = el.node.getAttribute("gradientTransform");
|
||||||
|
} else if (el.type == "pattern") {
|
||||||
|
tstr = el.node.getAttribute("patternTransform");
|
||||||
|
} else {
|
||||||
|
tstr = el.node.getAttribute("transform");
|
||||||
|
}
|
||||||
|
if (!tstr) {
|
||||||
|
return new Snap.Matrix;
|
||||||
|
}
|
||||||
|
tstr = Snap._.svgTransform2string(tstr);
|
||||||
|
} else {
|
||||||
|
if (!Snap._.rgTransform.test(tstr)) {
|
||||||
|
tstr = Snap._.svgTransform2string(tstr);
|
||||||
|
} else {
|
||||||
|
tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
|
||||||
|
}
|
||||||
|
if (is(tstr, "array")) {
|
||||||
|
tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
|
||||||
|
}
|
||||||
|
el._.transform = tstr;
|
||||||
|
}
|
||||||
|
var m = Snap._.transform2matrix(tstr, el.getBBox(1));
|
||||||
|
if (doReturn) {
|
||||||
|
return m;
|
||||||
|
} else {
|
||||||
|
el.matrix = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*\
|
/*\
|
||||||
* Element.transform
|
* Element.transform
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -2645,7 +3052,7 @@ function Element(el) {
|
||||||
x = x.x;
|
x = x.x;
|
||||||
}
|
}
|
||||||
$(p.node, {
|
$(p.node, {
|
||||||
viewBox: [x, y, width, height].join(S),
|
viewBox: [x, y, width, height].join(" "),
|
||||||
markerWidth: width,
|
markerWidth: width,
|
||||||
markerHeight: height,
|
markerHeight: height,
|
||||||
orient: "auto",
|
orient: "auto",
|
||||||
|
@ -2955,406 +3362,36 @@ function Element(el) {
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}(Element.prototype));
|
elproto.toDataURL = function () {
|
||||||
/*\
|
if (window && window.btoa) {
|
||||||
* Snap.parse
|
var bb = this.getBBox(),
|
||||||
[ method ]
|
svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', {
|
||||||
**
|
x: +bb.x.toFixed(3),
|
||||||
* Parses SVG fragment and converts it into a @Fragment
|
y: +bb.y.toFixed(3),
|
||||||
**
|
width: +bb.width.toFixed(3),
|
||||||
- svg (string) SVG string
|
height: +bb.height.toFixed(3),
|
||||||
= (Fragment) the @Fragment
|
contents: this.outerSVG()
|
||||||
\*/
|
});
|
||||||
Snap.parse = function (svg) {
|
console.log(svg);
|
||||||
var f = glob.doc.createDocumentFragment(),
|
return "data:image/svg+xml;utf8," + svg;
|
||||||
full = true,
|
return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
|
||||||
div = glob.doc.createElement("div");
|
|
||||||
svg = Str(svg);
|
|
||||||
if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) {
|
|
||||||
svg = "<svg>" + svg + "</svg>";
|
|
||||||
full = false;
|
|
||||||
}
|
}
|
||||||
div.innerHTML = svg;
|
|
||||||
svg = div.getElementsByTagName("svg")[0];
|
|
||||||
if (svg) {
|
|
||||||
if (full) {
|
|
||||||
f = svg;
|
|
||||||
} else {
|
|
||||||
while (svg.firstChild) {
|
|
||||||
f.appendChild(svg.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div.innerHTML = E;
|
|
||||||
return new Fragment(f);
|
|
||||||
};
|
};
|
||||||
function Fragment(frag) {
|
|
||||||
this.node = frag;
|
|
||||||
}
|
|
||||||
/*\
|
/*\
|
||||||
* Fragment.select
|
* Fragment.select
|
||||||
[ method ]
|
[ method ]
|
||||||
**
|
**
|
||||||
* See @Element.select
|
* See @Element.select
|
||||||
\*/
|
\*/
|
||||||
Fragment.prototype.select = Element.prototype.select;
|
Fragment.prototype.select = elproto.select;
|
||||||
/*\
|
/*\
|
||||||
* Fragment.selectAll
|
* Fragment.selectAll
|
||||||
[ method ]
|
[ method ]
|
||||||
**
|
**
|
||||||
* See @Element.selectAll
|
* See @Element.selectAll
|
||||||
\*/
|
\*/
|
||||||
Fragment.prototype.selectAll = Element.prototype.selectAll;
|
Fragment.prototype.selectAll = elproto.selectAll;
|
||||||
// SIERRA Snap.fragment() could especially use a code example
|
|
||||||
/*\
|
|
||||||
* Snap.fragment
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates a DOM fragment from a given list of elements or strings
|
|
||||||
**
|
|
||||||
- varargs (…) SVG string
|
|
||||||
= (Fragment) the @Fragment
|
|
||||||
\*/
|
|
||||||
Snap.fragment = function () {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 0),
|
|
||||||
f = glob.doc.createDocumentFragment();
|
|
||||||
for (var i = 0, ii = args.length; i < ii; i++) {
|
|
||||||
var item = args[i];
|
|
||||||
if (item.node && item.node.nodeType) {
|
|
||||||
f.appendChild(item.node);
|
|
||||||
}
|
|
||||||
if (item.nodeType) {
|
|
||||||
f.appendChild(item);
|
|
||||||
}
|
|
||||||
if (typeof item == "string") {
|
|
||||||
f.appendChild(Snap.parse(item).node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Fragment(f);
|
|
||||||
};
|
|
||||||
|
|
||||||
function make(name, parent) {
|
|
||||||
var res = $(name);
|
|
||||||
parent.appendChild(res);
|
|
||||||
var el = wrap(res);
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
function Paper(w, h) {
|
|
||||||
var res,
|
|
||||||
desc,
|
|
||||||
defs,
|
|
||||||
proto = Paper.prototype;
|
|
||||||
if (w && w.tagName == "svg") {
|
|
||||||
if (w.snap in hub) {
|
|
||||||
return hub[w.snap];
|
|
||||||
}
|
|
||||||
var doc = w.ownerDocument;
|
|
||||||
res = new Element(w);
|
|
||||||
desc = w.getElementsByTagName("desc")[0];
|
|
||||||
defs = w.getElementsByTagName("defs")[0];
|
|
||||||
if (!desc) {
|
|
||||||
desc = $("desc");
|
|
||||||
desc.appendChild(doc.createTextNode("Created with Snap"));
|
|
||||||
res.node.appendChild(desc);
|
|
||||||
}
|
|
||||||
if (!defs) {
|
|
||||||
defs = $("defs");
|
|
||||||
res.node.appendChild(defs);
|
|
||||||
}
|
|
||||||
res.defs = defs;
|
|
||||||
for (var key in proto) if (proto[has](key)) {
|
|
||||||
res[key] = proto[key];
|
|
||||||
}
|
|
||||||
res.paper = res.root = res;
|
|
||||||
} else {
|
|
||||||
res = make("svg", glob.doc.body);
|
|
||||||
$(res.node, {
|
|
||||||
height: h,
|
|
||||||
version: 1.1,
|
|
||||||
width: w,
|
|
||||||
xmlns: xmlns
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
function wrap(dom) {
|
|
||||||
if (!dom) {
|
|
||||||
return dom;
|
|
||||||
}
|
|
||||||
if (dom instanceof Element || dom instanceof Fragment) {
|
|
||||||
return dom;
|
|
||||||
}
|
|
||||||
if (dom.tagName && dom.tagName.toLowerCase() == "svg") {
|
|
||||||
return new Paper(dom);
|
|
||||||
}
|
|
||||||
if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") {
|
|
||||||
return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]);
|
|
||||||
}
|
|
||||||
return new Element(dom);
|
|
||||||
}
|
|
||||||
|
|
||||||
Snap._.make = make;
|
|
||||||
Snap._.wrap = wrap;
|
|
||||||
/*\
|
|
||||||
* Paper.el
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates an element on paper with a given name and no attributes
|
|
||||||
**
|
|
||||||
- name (string) tag name
|
|
||||||
- attr (object) attributes
|
|
||||||
= (Element) the current element
|
|
||||||
> Usage
|
|
||||||
| var c = paper.circle(10, 10, 10); // is the same as...
|
|
||||||
| var c = paper.el("circle").attr({
|
|
||||||
| cx: 10,
|
|
||||||
| cy: 10,
|
|
||||||
| r: 10
|
|
||||||
| });
|
|
||||||
| // and the same as
|
|
||||||
| var c = paper.el("circle", {
|
|
||||||
| cx: 10,
|
|
||||||
| cy: 10,
|
|
||||||
| r: 10
|
|
||||||
| });
|
|
||||||
\*/
|
|
||||||
Paper.prototype.el = function (name, attr) {
|
|
||||||
var el = make(name, this.node);
|
|
||||||
attr && el.attr(attr);
|
|
||||||
return el;
|
|
||||||
};
|
|
||||||
// default
|
|
||||||
eve.on("snap.util.getattr", function () {
|
|
||||||
var att = eve.nt();
|
|
||||||
att = att.substring(att.lastIndexOf(".") + 1);
|
|
||||||
var css = att.replace(/[A-Z]/g, function (letter) {
|
|
||||||
return "-" + letter.toLowerCase();
|
|
||||||
});
|
|
||||||
if (cssAttr[has](css)) {
|
|
||||||
return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css);
|
|
||||||
} else {
|
|
||||||
return $(this.node, att);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var cssAttr = {
|
|
||||||
"alignment-baseline": 0,
|
|
||||||
"baseline-shift": 0,
|
|
||||||
"clip": 0,
|
|
||||||
"clip-path": 0,
|
|
||||||
"clip-rule": 0,
|
|
||||||
"color": 0,
|
|
||||||
"color-interpolation": 0,
|
|
||||||
"color-interpolation-filters": 0,
|
|
||||||
"color-profile": 0,
|
|
||||||
"color-rendering": 0,
|
|
||||||
"cursor": 0,
|
|
||||||
"direction": 0,
|
|
||||||
"display": 0,
|
|
||||||
"dominant-baseline": 0,
|
|
||||||
"enable-background": 0,
|
|
||||||
"fill": 0,
|
|
||||||
"fill-opacity": 0,
|
|
||||||
"fill-rule": 0,
|
|
||||||
"filter": 0,
|
|
||||||
"flood-color": 0,
|
|
||||||
"flood-opacity": 0,
|
|
||||||
"font": 0,
|
|
||||||
"font-family": 0,
|
|
||||||
"font-size": 0,
|
|
||||||
"font-size-adjust": 0,
|
|
||||||
"font-stretch": 0,
|
|
||||||
"font-style": 0,
|
|
||||||
"font-variant": 0,
|
|
||||||
"font-weight": 0,
|
|
||||||
"glyph-orientation-horizontal": 0,
|
|
||||||
"glyph-orientation-vertical": 0,
|
|
||||||
"image-rendering": 0,
|
|
||||||
"kerning": 0,
|
|
||||||
"letter-spacing": 0,
|
|
||||||
"lighting-color": 0,
|
|
||||||
"marker": 0,
|
|
||||||
"marker-end": 0,
|
|
||||||
"marker-mid": 0,
|
|
||||||
"marker-start": 0,
|
|
||||||
"mask": 0,
|
|
||||||
"opacity": 0,
|
|
||||||
"overflow": 0,
|
|
||||||
"pointer-events": 0,
|
|
||||||
"shape-rendering": 0,
|
|
||||||
"stop-color": 0,
|
|
||||||
"stop-opacity": 0,
|
|
||||||
"stroke": 0,
|
|
||||||
"stroke-dasharray": 0,
|
|
||||||
"stroke-dashoffset": 0,
|
|
||||||
"stroke-linecap": 0,
|
|
||||||
"stroke-linejoin": 0,
|
|
||||||
"stroke-miterlimit": 0,
|
|
||||||
"stroke-opacity": 0,
|
|
||||||
"stroke-width": 0,
|
|
||||||
"text-anchor": 0,
|
|
||||||
"text-decoration": 0,
|
|
||||||
"text-rendering": 0,
|
|
||||||
"unicode-bidi": 0,
|
|
||||||
"visibility": 0,
|
|
||||||
"word-spacing": 0,
|
|
||||||
"writing-mode": 0
|
|
||||||
};
|
|
||||||
|
|
||||||
eve.on("snap.util.attr", function (value) {
|
|
||||||
var att = eve.nt(),
|
|
||||||
attr = {};
|
|
||||||
att = att.substring(att.lastIndexOf(".") + 1);
|
|
||||||
attr[att] = value;
|
|
||||||
var style = att.replace(/-(\w)/gi, function (all, letter) {
|
|
||||||
return letter.toUpperCase();
|
|
||||||
}),
|
|
||||||
css = att.replace(/[A-Z]/g, function (letter) {
|
|
||||||
return "-" + letter.toLowerCase();
|
|
||||||
});
|
|
||||||
if (cssAttr[has](css)) {
|
|
||||||
this.node.style[style] = value == null ? E : value;
|
|
||||||
} else {
|
|
||||||
$(this.node, attr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
(function (proto) {}(Paper.prototype));
|
|
||||||
|
|
||||||
// simple ajax
|
|
||||||
/*\
|
|
||||||
* Snap.ajax
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Simple implementation of Ajax
|
|
||||||
**
|
|
||||||
- url (string) URL
|
|
||||||
- postData (object|string) data for post request
|
|
||||||
- callback (function) callback
|
|
||||||
- scope (object) #optional scope of callback
|
|
||||||
* or
|
|
||||||
- url (string) URL
|
|
||||||
- callback (function) callback
|
|
||||||
- scope (object) #optional scope of callback
|
|
||||||
= (XMLHttpRequest) the XMLHttpRequest object, just in case
|
|
||||||
\*/
|
|
||||||
Snap.ajax = function (url, postData, callback, scope){
|
|
||||||
var req = new XMLHttpRequest,
|
|
||||||
id = ID();
|
|
||||||
if (req) {
|
|
||||||
if (is(postData, "function")) {
|
|
||||||
scope = callback;
|
|
||||||
callback = postData;
|
|
||||||
postData = null;
|
|
||||||
} else if (is(postData, "object")) {
|
|
||||||
var pd = [];
|
|
||||||
for (var key in postData) if (postData.hasOwnProperty(key)) {
|
|
||||||
pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key]));
|
|
||||||
}
|
|
||||||
postData = pd.join("&");
|
|
||||||
}
|
|
||||||
req.open((postData ? "POST" : "GET"), url, true);
|
|
||||||
if (postData) {
|
|
||||||
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
|
||||||
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
|
||||||
}
|
|
||||||
if (callback) {
|
|
||||||
eve.once("snap.ajax." + id + ".0", callback);
|
|
||||||
eve.once("snap.ajax." + id + ".200", callback);
|
|
||||||
eve.once("snap.ajax." + id + ".304", callback);
|
|
||||||
}
|
|
||||||
req.onreadystatechange = function() {
|
|
||||||
if (req.readyState != 4) return;
|
|
||||||
eve("snap.ajax." + id + "." + req.status, scope, req);
|
|
||||||
};
|
|
||||||
if (req.readyState == 4) {
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
req.send(postData);
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Snap.load
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX)
|
|
||||||
**
|
|
||||||
- url (string) URL
|
|
||||||
- callback (function) callback
|
|
||||||
- scope (object) #optional scope of callback
|
|
||||||
\*/
|
|
||||||
Snap.load = function (url, callback, scope) {
|
|
||||||
Snap.ajax(url, function (req) {
|
|
||||||
var f = Snap.parse(req.responseText);
|
|
||||||
scope ? callback.call(scope, f) : callback(f);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var getOffset = function (elem) {
|
|
||||||
var box = elem.getBoundingClientRect(),
|
|
||||||
doc = elem.ownerDocument,
|
|
||||||
body = doc.body,
|
|
||||||
docElem = doc.documentElement,
|
|
||||||
clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
|
|
||||||
top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
|
|
||||||
left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
|
|
||||||
return {
|
|
||||||
y: top,
|
|
||||||
x: left
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Snap.getElementByPoint
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns you topmost element under given point.
|
|
||||||
**
|
|
||||||
= (object) Snap element object
|
|
||||||
- x (number) x coordinate from the top left corner of the window
|
|
||||||
- y (number) y coordinate from the top left corner of the window
|
|
||||||
> Usage
|
|
||||||
| Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
|
|
||||||
\*/
|
|
||||||
Snap.getElementByPoint = function (x, y) {
|
|
||||||
var paper = this,
|
|
||||||
svg = paper.canvas,
|
|
||||||
target = glob.doc.elementFromPoint(x, y);
|
|
||||||
if (glob.win.opera && target.tagName == "svg") {
|
|
||||||
var so = getOffset(target),
|
|
||||||
sr = target.createSVGRect();
|
|
||||||
sr.x = x - so.x;
|
|
||||||
sr.y = y - so.y;
|
|
||||||
sr.width = sr.height = 1;
|
|
||||||
var hits = target.getIntersectionList(sr, null);
|
|
||||||
if (hits.length) {
|
|
||||||
target = hits[hits.length - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!target) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return wrap(target);
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Snap.plugin
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Let you write plugins. You pass in a function with four arguments, like this:
|
|
||||||
| Snap.plugin(function (Snap, Element, Paper, global, Fragment) {
|
|
||||||
| Snap.newmethod = function () {};
|
|
||||||
| Element.prototype.newmethod = function () {};
|
|
||||||
| Paper.prototype.newmethod = function () {};
|
|
||||||
| });
|
|
||||||
* Inside the function you have access to all main objects (and their
|
|
||||||
* prototypes). This allow you to extend anything you want.
|
|
||||||
**
|
|
||||||
- f (function) your plugin body
|
|
||||||
\*/
|
|
||||||
Snap.plugin = function (f) {
|
|
||||||
f(Snap, Element, Paper, glob, Fragment);
|
|
||||||
};
|
|
||||||
glob.win.Snap = Snap;
|
|
||||||
return Snap;
|
|
||||||
}());
|
|
||||||
|
|
||||||
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -4688,6 +4725,9 @@ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
||||||
}
|
}
|
||||||
id = id.attr("id");
|
id = id.attr("id");
|
||||||
}
|
}
|
||||||
|
if (String(id).charAt() == "#") {
|
||||||
|
id = id.substring(1);
|
||||||
|
}
|
||||||
return this.el("use", {"xlink:href": "#" + id});
|
return this.el("use", {"xlink:href": "#" + id});
|
||||||
} else {
|
} else {
|
||||||
return Element.prototype.use.call(this);
|
return Element.prototype.use.call(this);
|
||||||
|
@ -4997,6 +5037,18 @@ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
||||||
f.removeChild(f.firstChild);
|
f.removeChild(f.firstChild);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
/*\
|
||||||
|
* Paper.toDataURL
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns SVG code for the @Paper as Data URI string.
|
||||||
|
= (string) Data URI string
|
||||||
|
\*/
|
||||||
|
proto.toDataURL = function () {
|
||||||
|
if (window && window.btoa) {
|
||||||
|
return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this)));
|
||||||
|
}
|
||||||
|
};
|
||||||
/*\
|
/*\
|
||||||
* Paper.clear
|
* Paper.clear
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -6733,6 +6785,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
||||||
};
|
};
|
||||||
setproto.type = "set";
|
setproto.type = "set";
|
||||||
// export
|
// export
|
||||||
|
Snap.Set = Set;
|
||||||
Snap.set = function () {
|
Snap.set = function () {
|
||||||
var set = new Set;
|
var set = new Set;
|
||||||
if (arguments.length) {
|
if (arguments.length) {
|
||||||
|
@ -7420,7 +7473,6 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
||||||
Str = String,
|
Str = String,
|
||||||
$ = Snap._.$;
|
$ = Snap._.$;
|
||||||
Snap.filter = {};
|
Snap.filter = {};
|
||||||
// SIERRA Paper.filter(): I don't understand the note. Does that mean an HTML should dedicate a separate SVG region for a filter definition? What's the advantage over a DEFS?
|
|
||||||
/*\
|
/*\
|
||||||
* Paper.filter
|
* Paper.filter
|
||||||
[ method ]
|
[ method ]
|
||||||
|
|
1208
doc/reference.html
1208
doc/reference.html
File diff suppressed because it is too large
Load Diff
3
dr.json
3
dr.json
|
@ -5,6 +5,9 @@
|
||||||
"files": [{
|
"files": [{
|
||||||
"url": "src/svg.js",
|
"url": "src/svg.js",
|
||||||
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js"
|
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js"
|
||||||
|
}, {
|
||||||
|
"url": "src/element.js",
|
||||||
|
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/element.js"
|
||||||
}, {
|
}, {
|
||||||
"url": "src/matrix.js",
|
"url": "src/matrix.js",
|
||||||
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/matrix.js"
|
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/matrix.js"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Snap.svg @VERSION
|
// Snap.svg @VERSION
|
||||||
//
|
//
|
||||||
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
// Copyright (c) 2013 – 2014 Adobe Systems Incorporated. All rights reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -0,0 +1,986 @@
|
||||||
|
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
||||||
|
var elproto = Element.prototype,
|
||||||
|
is = Snap.is,
|
||||||
|
Str = String,
|
||||||
|
unit2px = Snap._unit2px,
|
||||||
|
$ = Snap._.$,
|
||||||
|
make = Snap._.make,
|
||||||
|
getSomeDefs = Snap._.getSomeDefs,
|
||||||
|
has = "hasOwnProperty",
|
||||||
|
wrap = Snap._.wrap;
|
||||||
|
/*\
|
||||||
|
* Element.getBBox
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns the bounding box descriptor for the given element
|
||||||
|
**
|
||||||
|
= (object) bounding box descriptor:
|
||||||
|
o {
|
||||||
|
o cx: (number) x of the center,
|
||||||
|
o cy: (number) x of the center,
|
||||||
|
o h: (number) height,
|
||||||
|
o height: (number) height,
|
||||||
|
o path: (string) path command for the box,
|
||||||
|
o r0: (number) radius of a circle that fully encloses the box,
|
||||||
|
o r1: (number) radius of the smallest circle that can be enclosed,
|
||||||
|
o r2: (number) radius of the largest circle that can be enclosed,
|
||||||
|
o vb: (string) box as a viewbox command,
|
||||||
|
o w: (number) width,
|
||||||
|
o width: (number) width,
|
||||||
|
o x2: (number) x of the right side,
|
||||||
|
o x: (number) x of the left side,
|
||||||
|
o y2: (number) y of the bottom edge,
|
||||||
|
o y: (number) y of the top edge
|
||||||
|
o }
|
||||||
|
\*/
|
||||||
|
elproto.getBBox = function (isWithoutTransform) {
|
||||||
|
if (!Snap.Matrix || !Snap.path) {
|
||||||
|
return this.node.getBBox();
|
||||||
|
}
|
||||||
|
var el = this,
|
||||||
|
m = new Snap.Matrix;
|
||||||
|
if (el.removed) {
|
||||||
|
return Snap._.box();
|
||||||
|
}
|
||||||
|
while (el.type == "use") {
|
||||||
|
if (!isWithoutTransform) {
|
||||||
|
m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0));
|
||||||
|
}
|
||||||
|
if (el.original) {
|
||||||
|
el = el.original;
|
||||||
|
} else {
|
||||||
|
var href = el.attr("xlink:href");
|
||||||
|
el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var _ = el._,
|
||||||
|
pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt;
|
||||||
|
try {
|
||||||
|
if (isWithoutTransform) {
|
||||||
|
_.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox());
|
||||||
|
return Snap._.box(_.bboxwt);
|
||||||
|
} else {
|
||||||
|
el.realPath = pathfinder(el);
|
||||||
|
el.matrix = el.transform().localMatrix;
|
||||||
|
_.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix)));
|
||||||
|
return Snap._.box(_.bbox);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Firefox doesn’t give you bbox of hidden element
|
||||||
|
return Snap._.box();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var propString = function () {
|
||||||
|
return this.string;
|
||||||
|
};
|
||||||
|
function extractTransform(el, tstr) {
|
||||||
|
if (tstr == null) {
|
||||||
|
var doReturn = true;
|
||||||
|
if (el.type == "linearGradient" || el.type == "radialGradient") {
|
||||||
|
tstr = el.node.getAttribute("gradientTransform");
|
||||||
|
} else if (el.type == "pattern") {
|
||||||
|
tstr = el.node.getAttribute("patternTransform");
|
||||||
|
} else {
|
||||||
|
tstr = el.node.getAttribute("transform");
|
||||||
|
}
|
||||||
|
if (!tstr) {
|
||||||
|
return new Snap.Matrix;
|
||||||
|
}
|
||||||
|
tstr = Snap._.svgTransform2string(tstr);
|
||||||
|
} else {
|
||||||
|
if (!Snap._.rgTransform.test(tstr)) {
|
||||||
|
tstr = Snap._.svgTransform2string(tstr);
|
||||||
|
} else {
|
||||||
|
tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
|
||||||
|
}
|
||||||
|
if (is(tstr, "array")) {
|
||||||
|
tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
|
||||||
|
}
|
||||||
|
el._.transform = tstr;
|
||||||
|
}
|
||||||
|
var m = Snap._.transform2matrix(tstr, el.getBBox(1));
|
||||||
|
if (doReturn) {
|
||||||
|
return m;
|
||||||
|
} else {
|
||||||
|
el.matrix = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*\
|
||||||
|
* Element.transform
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Gets or sets transformation of the element
|
||||||
|
**
|
||||||
|
- tstr (string) transform string in Snap or SVG format
|
||||||
|
= (Element) the current element
|
||||||
|
* or
|
||||||
|
= (object) transformation descriptor:
|
||||||
|
o {
|
||||||
|
o string (string) transform string,
|
||||||
|
o globalMatrix (Matrix) matrix of all transformations applied to element or its parents,
|
||||||
|
o localMatrix (Matrix) matrix of transformations applied only to the element,
|
||||||
|
o diffMatrix (Matrix) matrix of difference between global and local transformations,
|
||||||
|
o global (string) global transformation as string,
|
||||||
|
o local (string) local transformation as string,
|
||||||
|
o toString (function) returns `string` property
|
||||||
|
o }
|
||||||
|
\*/
|
||||||
|
elproto.transform = function (tstr) {
|
||||||
|
var _ = this._;
|
||||||
|
if (tstr == null) {
|
||||||
|
var papa = this,
|
||||||
|
global = new Snap.Matrix(this.node.getCTM()),
|
||||||
|
local = extractTransform(this),
|
||||||
|
ms = [local],
|
||||||
|
m = new Snap.Matrix,
|
||||||
|
i,
|
||||||
|
localString = local.toTransformString(),
|
||||||
|
string = Str(local) == Str(this.matrix) ?
|
||||||
|
Str(_.transform) : localString;
|
||||||
|
while (papa.type != "svg" && (papa = papa.parent())) {
|
||||||
|
ms.push(extractTransform(papa));
|
||||||
|
}
|
||||||
|
i = ms.length;
|
||||||
|
while (i--) {
|
||||||
|
m.add(ms[i]);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
string: string,
|
||||||
|
globalMatrix: global,
|
||||||
|
totalMatrix: m,
|
||||||
|
localMatrix: local,
|
||||||
|
diffMatrix: global.clone().add(local.invert()),
|
||||||
|
global: global.toTransformString(),
|
||||||
|
total: m.toTransformString(),
|
||||||
|
local: localString,
|
||||||
|
toString: propString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (tstr instanceof Snap.Matrix) {
|
||||||
|
this.matrix = tstr;
|
||||||
|
} else {
|
||||||
|
extractTransform(this, tstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.node) {
|
||||||
|
if (this.type == "linearGradient" || this.type == "radialGradient") {
|
||||||
|
$(this.node, {gradientTransform: this.matrix});
|
||||||
|
} else if (this.type == "pattern") {
|
||||||
|
$(this.node, {patternTransform: this.matrix});
|
||||||
|
} else {
|
||||||
|
$(this.node, {transform: this.matrix});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.parent
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns the element's parent
|
||||||
|
**
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.parent = function () {
|
||||||
|
return wrap(this.node.parentNode);
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.append
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Appends the given element to current one
|
||||||
|
**
|
||||||
|
- el (Element|Set) element to append
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
/*\
|
||||||
|
* Element.add
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* See @Element.append
|
||||||
|
\*/
|
||||||
|
elproto.append = elproto.add = function (el) {
|
||||||
|
if (el) {
|
||||||
|
if (el.type == "set") {
|
||||||
|
var it = this;
|
||||||
|
el.forEach(function (el) {
|
||||||
|
it.add(el);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
el = wrap(el);
|
||||||
|
this.node.appendChild(el.node);
|
||||||
|
el.paper = this.paper;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.appendTo
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Appends the current element to the given one
|
||||||
|
**
|
||||||
|
- el (Element) parent element to append to
|
||||||
|
= (Element) the child element
|
||||||
|
\*/
|
||||||
|
elproto.appendTo = function (el) {
|
||||||
|
if (el) {
|
||||||
|
el = wrap(el);
|
||||||
|
el.append(this);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.prepend
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Prepends the given element to the current one
|
||||||
|
**
|
||||||
|
- el (Element) element to prepend
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.prepend = function (el) {
|
||||||
|
if (el) {
|
||||||
|
if (el.type == "set") {
|
||||||
|
var it = this,
|
||||||
|
first;
|
||||||
|
el.forEach(function (el) {
|
||||||
|
if (first) {
|
||||||
|
first.after(el);
|
||||||
|
} else {
|
||||||
|
it.prepend(el);
|
||||||
|
}
|
||||||
|
first = el;
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
el = wrap(el);
|
||||||
|
var parent = el.parent();
|
||||||
|
this.node.insertBefore(el.node, this.node.firstChild);
|
||||||
|
this.add && this.add();
|
||||||
|
el.paper = this.paper;
|
||||||
|
this.parent() && this.parent().add();
|
||||||
|
parent && parent.add();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.prependTo
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Prepends the current element to the given one
|
||||||
|
**
|
||||||
|
- el (Element) parent element to prepend to
|
||||||
|
= (Element) the child element
|
||||||
|
\*/
|
||||||
|
elproto.prependTo = function (el) {
|
||||||
|
el = wrap(el);
|
||||||
|
el.prepend(this);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.before
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Inserts given element before the current one
|
||||||
|
**
|
||||||
|
- el (Element) element to insert
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.before = function (el) {
|
||||||
|
if (el.type == "set") {
|
||||||
|
var it = this;
|
||||||
|
el.forEach(function (el) {
|
||||||
|
var parent = el.parent();
|
||||||
|
it.node.parentNode.insertBefore(el.node, it.node);
|
||||||
|
parent && parent.add();
|
||||||
|
});
|
||||||
|
this.parent().add();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
el = wrap(el);
|
||||||
|
var parent = el.parent();
|
||||||
|
this.node.parentNode.insertBefore(el.node, this.node);
|
||||||
|
this.parent() && this.parent().add();
|
||||||
|
parent && parent.add();
|
||||||
|
el.paper = this.paper;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.after
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Inserts given element after the current one
|
||||||
|
**
|
||||||
|
- el (Element) element to insert
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.after = function (el) {
|
||||||
|
el = wrap(el);
|
||||||
|
var parent = el.parent();
|
||||||
|
if (this.node.nextSibling) {
|
||||||
|
this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
|
||||||
|
} else {
|
||||||
|
this.node.parentNode.appendChild(el.node);
|
||||||
|
}
|
||||||
|
this.parent() && this.parent().add();
|
||||||
|
parent && parent.add();
|
||||||
|
el.paper = this.paper;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.insertBefore
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Inserts the element after the given one
|
||||||
|
**
|
||||||
|
- el (Element) element next to whom insert to
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.insertBefore = function (el) {
|
||||||
|
el = wrap(el);
|
||||||
|
var parent = this.parent();
|
||||||
|
el.node.parentNode.insertBefore(this.node, el.node);
|
||||||
|
this.paper = el.paper;
|
||||||
|
parent && parent.add();
|
||||||
|
el.parent() && el.parent().add();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.insertAfter
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Inserts the element after the given one
|
||||||
|
**
|
||||||
|
- el (Element) element next to whom insert to
|
||||||
|
= (Element) the parent element
|
||||||
|
\*/
|
||||||
|
elproto.insertAfter = function (el) {
|
||||||
|
el = wrap(el);
|
||||||
|
var parent = this.parent();
|
||||||
|
el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
|
||||||
|
this.paper = el.paper;
|
||||||
|
parent && parent.add();
|
||||||
|
el.parent() && el.parent().add();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.remove
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Removes element from the DOM
|
||||||
|
= (Element) the detached element
|
||||||
|
\*/
|
||||||
|
elproto.remove = function () {
|
||||||
|
var parent = this.parent();
|
||||||
|
this.node.parentNode && this.node.parentNode.removeChild(this.node);
|
||||||
|
delete this.paper;
|
||||||
|
this.removed = true;
|
||||||
|
parent && parent.add();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.select
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Gathers the nested @Element matching the given set of CSS selectors
|
||||||
|
**
|
||||||
|
- query (string) CSS selector
|
||||||
|
= (Element) result of query selection
|
||||||
|
\*/
|
||||||
|
elproto.select = function (query) {
|
||||||
|
query = Str(query).replace(/([^\\]):/g, "$1\\:");
|
||||||
|
return wrap(this.node.querySelector(query));
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.selectAll
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Gathers nested @Element objects matching the given set of CSS selectors
|
||||||
|
**
|
||||||
|
- query (string) CSS selector
|
||||||
|
= (Set|array) result of query selection
|
||||||
|
\*/
|
||||||
|
elproto.selectAll = function (query) {
|
||||||
|
var nodelist = this.node.querySelectorAll(query),
|
||||||
|
set = (Snap.set || Array)();
|
||||||
|
for (var i = 0; i < nodelist.length; i++) {
|
||||||
|
set.push(wrap(nodelist[i]));
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.asPX
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns given attribute of the element as a `px` value (not %, em, etc.)
|
||||||
|
**
|
||||||
|
- attr (string) attribute name
|
||||||
|
- value (string) #optional attribute value
|
||||||
|
= (Element) result of query selection
|
||||||
|
\*/
|
||||||
|
elproto.asPX = function (attr, value) {
|
||||||
|
if (value == null) {
|
||||||
|
value = this.attr(attr);
|
||||||
|
}
|
||||||
|
return +unit2px(this, attr, value);
|
||||||
|
};
|
||||||
|
// SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar.
|
||||||
|
/*\
|
||||||
|
* Element.use
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates a `<use>` element linked to the current element
|
||||||
|
**
|
||||||
|
= (Element) the `<use>` element
|
||||||
|
\*/
|
||||||
|
elproto.use = function () {
|
||||||
|
var use,
|
||||||
|
id = this.node.id;
|
||||||
|
if (!id) {
|
||||||
|
id = this.id;
|
||||||
|
$(this.node, {
|
||||||
|
id: id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.type == "linearGradient" || this.type == "radialGradient" ||
|
||||||
|
this.type == "pattern") {
|
||||||
|
use = make(this.type, this.node.parentNode);
|
||||||
|
} else {
|
||||||
|
use = make("use", this.node.parentNode);
|
||||||
|
}
|
||||||
|
$(use.node, {
|
||||||
|
"xlink:href": "#" + id
|
||||||
|
});
|
||||||
|
use.original = this;
|
||||||
|
return use;
|
||||||
|
};
|
||||||
|
function fixids(el) {
|
||||||
|
var els = el.selectAll("*"),
|
||||||
|
it,
|
||||||
|
url = /^\s*url\(("|'|)(.*)\1\)\s*$/,
|
||||||
|
ids = [],
|
||||||
|
uses = {};
|
||||||
|
function urltest(it, name) {
|
||||||
|
var val = $(it.node, name);
|
||||||
|
val = val && val.match(url);
|
||||||
|
val = val && val[2];
|
||||||
|
if (val && val.charAt() == "#") {
|
||||||
|
val = val.substring(1);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (val) {
|
||||||
|
uses[val] = (uses[val] || []).concat(function (id) {
|
||||||
|
var attr = {};
|
||||||
|
attr[name] = URL(id);
|
||||||
|
$(it.node, attr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function linktest(it) {
|
||||||
|
var val = $(it.node, "xlink:href");
|
||||||
|
if (val && val.charAt() == "#") {
|
||||||
|
val = val.substring(1);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (val) {
|
||||||
|
uses[val] = (uses[val] || []).concat(function (id) {
|
||||||
|
it.attr("xlink:href", "#" + id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0, ii = els.length; i < ii; i++) {
|
||||||
|
it = els[i];
|
||||||
|
urltest(it, "fill");
|
||||||
|
urltest(it, "stroke");
|
||||||
|
urltest(it, "filter");
|
||||||
|
urltest(it, "mask");
|
||||||
|
urltest(it, "clip-path");
|
||||||
|
linktest(it);
|
||||||
|
var oldid = $(it.node, "id");
|
||||||
|
if (oldid) {
|
||||||
|
$(it.node, {id: it.id});
|
||||||
|
ids.push({
|
||||||
|
old: oldid,
|
||||||
|
id: it.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0, ii = ids.length; i < ii; i++) {
|
||||||
|
var fs = uses[ids[i].old];
|
||||||
|
if (fs) {
|
||||||
|
for (var j = 0, jj = fs.length; j < jj; j++) {
|
||||||
|
fs[j](ids[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*\
|
||||||
|
* Element.clone
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates a clone of the element and inserts it after the element
|
||||||
|
**
|
||||||
|
= (Element) the clone
|
||||||
|
\*/
|
||||||
|
elproto.clone = function () {
|
||||||
|
var clone = wrap(this.node.cloneNode(true));
|
||||||
|
if ($(clone.node, "id")) {
|
||||||
|
$(clone.node, {id: clone.id});
|
||||||
|
}
|
||||||
|
fixids(clone);
|
||||||
|
clone.insertAfter(this);
|
||||||
|
return clone;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.toDefs
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Moves element to the shared `<defs>` area
|
||||||
|
**
|
||||||
|
= (Element) the element
|
||||||
|
\*/
|
||||||
|
elproto.toDefs = function () {
|
||||||
|
var defs = getSomeDefs(this);
|
||||||
|
defs.appendChild(this.node);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.pattern
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Depricated. Use @Element.toPattern instead.
|
||||||
|
\*/
|
||||||
|
/*\
|
||||||
|
* Element.toPattern
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates a `<pattern>` element from the current element
|
||||||
|
**
|
||||||
|
* To create a pattern you have to specify the pattern rect:
|
||||||
|
- x (string|number)
|
||||||
|
- y (string|number)
|
||||||
|
- width (string|number)
|
||||||
|
- height (string|number)
|
||||||
|
= (Element) the `<pattern>` element
|
||||||
|
* You can use pattern later on as an argument for `fill` attribute:
|
||||||
|
| var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
|
||||||
|
| fill: "none",
|
||||||
|
| stroke: "#bada55",
|
||||||
|
| strokeWidth: 5
|
||||||
|
| }).pattern(0, 0, 10, 10),
|
||||||
|
| c = paper.circle(200, 200, 100);
|
||||||
|
| c.attr({
|
||||||
|
| fill: p
|
||||||
|
| });
|
||||||
|
\*/
|
||||||
|
elproto.pattern = elproto.toPattern = function (x, y, width, height) {
|
||||||
|
var p = make("pattern", getSomeDefs(this));
|
||||||
|
if (x == null) {
|
||||||
|
x = this.getBBox();
|
||||||
|
}
|
||||||
|
if (is(x, "object") && "x" in x) {
|
||||||
|
y = x.y;
|
||||||
|
width = x.width;
|
||||||
|
height = x.height;
|
||||||
|
x = x.x;
|
||||||
|
}
|
||||||
|
$(p.node, {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
patternUnits: "userSpaceOnUse",
|
||||||
|
id: p.id,
|
||||||
|
viewBox: [x, y, width, height].join(" ")
|
||||||
|
});
|
||||||
|
p.node.appendChild(this.node);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path.
|
||||||
|
// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values?
|
||||||
|
/*\
|
||||||
|
* Element.marker
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates a `<marker>` element from the current element
|
||||||
|
**
|
||||||
|
* To create a marker you have to specify the bounding rect and reference point:
|
||||||
|
- x (number)
|
||||||
|
- y (number)
|
||||||
|
- width (number)
|
||||||
|
- height (number)
|
||||||
|
- refX (number)
|
||||||
|
- refY (number)
|
||||||
|
= (Element) the `<marker>` element
|
||||||
|
* You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end.
|
||||||
|
\*/
|
||||||
|
// TODO add usage for markers
|
||||||
|
elproto.marker = function (x, y, width, height, refX, refY) {
|
||||||
|
var p = make("marker", getSomeDefs(this));
|
||||||
|
if (x == null) {
|
||||||
|
x = this.getBBox();
|
||||||
|
}
|
||||||
|
if (is(x, "object") && "x" in x) {
|
||||||
|
y = x.y;
|
||||||
|
width = x.width;
|
||||||
|
height = x.height;
|
||||||
|
refX = x.refX || x.cx;
|
||||||
|
refY = x.refY || x.cy;
|
||||||
|
x = x.x;
|
||||||
|
}
|
||||||
|
$(p.node, {
|
||||||
|
viewBox: [x, y, width, height].join(" "),
|
||||||
|
markerWidth: width,
|
||||||
|
markerHeight: height,
|
||||||
|
orient: "auto",
|
||||||
|
refX: refX || 0,
|
||||||
|
refY: refY || 0,
|
||||||
|
id: p.id
|
||||||
|
});
|
||||||
|
p.node.appendChild(this.node);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
// animation
|
||||||
|
function slice(from, to, f) {
|
||||||
|
return function (arr) {
|
||||||
|
var res = arr.slice(from, to);
|
||||||
|
if (res.length == 1) {
|
||||||
|
res = res[0];
|
||||||
|
}
|
||||||
|
return f ? f(res) : res;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var Animation = function (attr, ms, easing, callback) {
|
||||||
|
if (typeof easing == "function" && !easing.length) {
|
||||||
|
callback = easing;
|
||||||
|
easing = mina.linear;
|
||||||
|
}
|
||||||
|
this.attr = attr;
|
||||||
|
this.dur = ms;
|
||||||
|
easing && (this.easing = easing);
|
||||||
|
callback && (this.callback = callback);
|
||||||
|
};
|
||||||
|
Snap._.Animation = Animation;
|
||||||
|
/*\
|
||||||
|
* Snap.animation
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Creates an animation object
|
||||||
|
**
|
||||||
|
- attr (object) attributes of final destination
|
||||||
|
- duration (number) duration of the animation, in milliseconds
|
||||||
|
- easing (function) #optional one of easing functions of @mina or custom one
|
||||||
|
- callback (function) #optional callback function that fires when animation ends
|
||||||
|
= (object) animation object
|
||||||
|
\*/
|
||||||
|
Snap.animation = function (attr, ms, easing, callback) {
|
||||||
|
return new Animation(attr, ms, easing, callback);
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.inAnim
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns a set of animations that may be able to manipulate the current element
|
||||||
|
**
|
||||||
|
= (object) in format:
|
||||||
|
o {
|
||||||
|
o anim (object) animation object,
|
||||||
|
o mina (object) @mina object,
|
||||||
|
o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
|
||||||
|
o status (function) gets or sets the status of the animation,
|
||||||
|
o stop (function) stops the animation
|
||||||
|
o }
|
||||||
|
\*/
|
||||||
|
elproto.inAnim = function () {
|
||||||
|
var el = this,
|
||||||
|
res = [];
|
||||||
|
for (var id in el.anims) if (el.anims[has](id)) {
|
||||||
|
(function (a) {
|
||||||
|
res.push({
|
||||||
|
anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
|
||||||
|
mina: a,
|
||||||
|
curStatus: a.status(),
|
||||||
|
status: function (val) {
|
||||||
|
return a.status(val);
|
||||||
|
},
|
||||||
|
stop: function () {
|
||||||
|
a.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}(el.anims[id]));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Snap.animate
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Runs generic animation of one number into another with a caring function
|
||||||
|
**
|
||||||
|
- from (number|array) number or array of numbers
|
||||||
|
- to (number|array) number or array of numbers
|
||||||
|
- setter (function) caring function that accepts one number argument
|
||||||
|
- duration (number) duration, in milliseconds
|
||||||
|
- easing (function) #optional easing function from @mina or custom
|
||||||
|
- callback (function) #optional callback function to execute when animation ends
|
||||||
|
= (object) animation object in @mina format
|
||||||
|
o {
|
||||||
|
o id (string) animation id, consider it read-only,
|
||||||
|
o duration (function) gets or sets the duration of the animation,
|
||||||
|
o easing (function) easing,
|
||||||
|
o speed (function) gets or sets the speed of the animation,
|
||||||
|
o status (function) gets or sets the status of the animation,
|
||||||
|
o stop (function) stops the animation
|
||||||
|
o }
|
||||||
|
| var rect = Snap().rect(0, 0, 10, 10);
|
||||||
|
| Snap.animate(0, 10, function (val) {
|
||||||
|
| rect.attr({
|
||||||
|
| x: val
|
||||||
|
| });
|
||||||
|
| }, 1000);
|
||||||
|
| // in given context is equivalent to
|
||||||
|
| rect.animate({x: 10}, 1000);
|
||||||
|
\*/
|
||||||
|
Snap.animate = function (from, to, setter, ms, easing, callback) {
|
||||||
|
if (typeof easing == "function" && !easing.length) {
|
||||||
|
callback = easing;
|
||||||
|
easing = mina.linear;
|
||||||
|
}
|
||||||
|
var now = mina.time(),
|
||||||
|
anim = mina(from, to, now, now + ms, mina.time, setter, easing);
|
||||||
|
callback && eve.once("mina.finish." + anim.id, callback);
|
||||||
|
return anim;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.stop
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Stops all the animations for the current element
|
||||||
|
**
|
||||||
|
= (Element) the current element
|
||||||
|
\*/
|
||||||
|
elproto.stop = function () {
|
||||||
|
var anims = this.inAnim();
|
||||||
|
for (var i = 0, ii = anims.length; i < ii; i++) {
|
||||||
|
anims[i].stop();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.animate
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Animates the given attributes of the element
|
||||||
|
**
|
||||||
|
- attrs (object) key-value pairs of destination attributes
|
||||||
|
- duration (number) duration of the animation in milliseconds
|
||||||
|
- easing (function) #optional easing function from @mina or custom
|
||||||
|
- callback (function) #optional callback function that executes when the animation ends
|
||||||
|
= (Element) the current element
|
||||||
|
\*/
|
||||||
|
elproto.animate = function (attrs, ms, easing, callback) {
|
||||||
|
if (typeof easing == "function" && !easing.length) {
|
||||||
|
callback = easing;
|
||||||
|
easing = mina.linear;
|
||||||
|
}
|
||||||
|
if (attrs instanceof Animation) {
|
||||||
|
callback = attrs.callback;
|
||||||
|
easing = attrs.easing;
|
||||||
|
ms = easing.dur;
|
||||||
|
attrs = attrs.attr;
|
||||||
|
}
|
||||||
|
var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
|
||||||
|
el = this;
|
||||||
|
for (var key in attrs) if (attrs[has](key)) {
|
||||||
|
if (el.equal) {
|
||||||
|
eq = el.equal(key, Str(attrs[key]));
|
||||||
|
from = eq.from;
|
||||||
|
to = eq.to;
|
||||||
|
f = eq.f;
|
||||||
|
} else {
|
||||||
|
from = +el.attr(key);
|
||||||
|
to = +attrs[key];
|
||||||
|
}
|
||||||
|
var len = is(from, "array") ? from.length : 1;
|
||||||
|
keys[key] = slice(fkeys.length, fkeys.length + len, f);
|
||||||
|
fkeys = fkeys.concat(from);
|
||||||
|
tkeys = tkeys.concat(to);
|
||||||
|
}
|
||||||
|
var now = mina.time(),
|
||||||
|
anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
|
||||||
|
var attr = {};
|
||||||
|
for (var key in keys) if (keys[has](key)) {
|
||||||
|
attr[key] = keys[key](val);
|
||||||
|
}
|
||||||
|
el.attr(attr);
|
||||||
|
}, easing);
|
||||||
|
el.anims[anim.id] = anim;
|
||||||
|
anim._attrs = attrs;
|
||||||
|
anim._callback = callback;
|
||||||
|
eve("snap.animcreated." + el.id, anim);
|
||||||
|
eve.once("mina.finish." + anim.id, function () {
|
||||||
|
delete el.anims[anim.id];
|
||||||
|
callback && callback.call(el);
|
||||||
|
});
|
||||||
|
eve.once("mina.stop." + anim.id, function () {
|
||||||
|
delete el.anims[anim.id];
|
||||||
|
});
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
var eldata = {};
|
||||||
|
/*\
|
||||||
|
* Element.data
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Adds or retrieves given value associated with given key. (Don’t confuse
|
||||||
|
* with `data-` attributes)
|
||||||
|
*
|
||||||
|
* See also @Element.removeData
|
||||||
|
- key (string) key to store data
|
||||||
|
- value (any) #optional value to store
|
||||||
|
= (object) @Element
|
||||||
|
* or, if value is not specified:
|
||||||
|
= (any) value
|
||||||
|
> Usage
|
||||||
|
| for (var i = 0, i < 5, i++) {
|
||||||
|
| paper.circle(10 + 15 * i, 10, 10)
|
||||||
|
| .attr({fill: "#000"})
|
||||||
|
| .data("i", i)
|
||||||
|
| .click(function () {
|
||||||
|
| alert(this.data("i"));
|
||||||
|
| });
|
||||||
|
| }
|
||||||
|
\*/
|
||||||
|
elproto.data = function (key, value) {
|
||||||
|
var data = eldata[this.id] = eldata[this.id] || {};
|
||||||
|
if (arguments.length == 0){
|
||||||
|
eve("snap.data.get." + this.id, this, data, null);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
if (arguments.length == 1) {
|
||||||
|
if (Snap.is(key, "object")) {
|
||||||
|
for (var i in key) if (key[has](i)) {
|
||||||
|
this.data(i, key[i]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
eve("snap.data.get." + this.id, this, data[key], key);
|
||||||
|
return data[key];
|
||||||
|
}
|
||||||
|
data[key] = value;
|
||||||
|
eve("snap.data.set." + this.id, this, value, key);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.removeData
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Removes value associated with an element by given key.
|
||||||
|
* If key is not provided, removes all the data of the element.
|
||||||
|
- key (string) #optional key
|
||||||
|
= (object) @Element
|
||||||
|
\*/
|
||||||
|
elproto.removeData = function (key) {
|
||||||
|
if (key == null) {
|
||||||
|
eldata[this.id] = {};
|
||||||
|
} else {
|
||||||
|
eldata[this.id] && delete eldata[this.id][key];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Element.outerSVG
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns SVG code for the element, equivalent to HTML's `outerHTML`.
|
||||||
|
*
|
||||||
|
* See also @Element.innerSVG
|
||||||
|
= (string) SVG code for the element
|
||||||
|
\*/
|
||||||
|
/*\
|
||||||
|
* Element.toString
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* See @Element.outerSVG
|
||||||
|
\*/
|
||||||
|
elproto.outerSVG = elproto.toString = toString(1);
|
||||||
|
/*\
|
||||||
|
* Element.innerSVG
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns SVG code for the element's contents, equivalent to HTML's `innerHTML`
|
||||||
|
= (string) SVG code for the element
|
||||||
|
\*/
|
||||||
|
elproto.innerSVG = toString();
|
||||||
|
function toString(type) {
|
||||||
|
return function () {
|
||||||
|
var res = type ? "<" + this.type : "",
|
||||||
|
attr = this.node.attributes,
|
||||||
|
chld = this.node.childNodes;
|
||||||
|
if (type) {
|
||||||
|
for (var i = 0, ii = attr.length; i < ii; i++) {
|
||||||
|
res += " " + attr[i].name + '="' +
|
||||||
|
attr[i].value.replace(/"/g, '\\"') + '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chld.length) {
|
||||||
|
type && (res += ">");
|
||||||
|
for (i = 0, ii = chld.length; i < ii; i++) {
|
||||||
|
if (chld[i].nodeType == 3) {
|
||||||
|
res += chld[i].nodeValue;
|
||||||
|
} else if (chld[i].nodeType == 1) {
|
||||||
|
res += wrap(chld[i]).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type && (res += "</" + this.type + ">");
|
||||||
|
} else {
|
||||||
|
type && (res += "/>");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
elproto.toDataURL = function () {
|
||||||
|
if (window && window.btoa) {
|
||||||
|
var bb = this.getBBox(),
|
||||||
|
svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', {
|
||||||
|
x: +bb.x.toFixed(3),
|
||||||
|
y: +bb.y.toFixed(3),
|
||||||
|
width: +bb.width.toFixed(3),
|
||||||
|
height: +bb.height.toFixed(3),
|
||||||
|
contents: this.outerSVG()
|
||||||
|
});
|
||||||
|
return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/*\
|
||||||
|
* Fragment.select
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* See @Element.select
|
||||||
|
\*/
|
||||||
|
Fragment.prototype.select = elproto.select;
|
||||||
|
/*\
|
||||||
|
* Fragment.selectAll
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* See @Element.selectAll
|
||||||
|
\*/
|
||||||
|
Fragment.prototype.selectAll = elproto.selectAll;
|
||||||
|
});
|
|
@ -18,7 +18,6 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
||||||
Str = String,
|
Str = String,
|
||||||
$ = Snap._.$;
|
$ = Snap._.$;
|
||||||
Snap.filter = {};
|
Snap.filter = {};
|
||||||
// SIERRA Paper.filter(): I don't understand the note. Does that mean an HTML should dedicate a separate SVG region for a filter definition? What's the advantage over a DEFS?
|
|
||||||
/*\
|
/*\
|
||||||
* Paper.filter
|
* Paper.filter
|
||||||
[ method ]
|
[ method ]
|
||||||
|
|
12
src/paper.js
12
src/paper.js
|
@ -685,6 +685,18 @@ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
||||||
f.removeChild(f.firstChild);
|
f.removeChild(f.firstChild);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
/*\
|
||||||
|
* Paper.toDataURL
|
||||||
|
[ method ]
|
||||||
|
**
|
||||||
|
* Returns SVG code for the @Paper as Data URI string.
|
||||||
|
= (string) Data URI string
|
||||||
|
\*/
|
||||||
|
proto.toDataURL = function () {
|
||||||
|
if (window && window.btoa) {
|
||||||
|
return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this)));
|
||||||
|
}
|
||||||
|
};
|
||||||
/*\
|
/*\
|
||||||
* Paper.clear
|
* Paper.clear
|
||||||
[ method ]
|
[ method ]
|
||||||
|
|
|
@ -303,6 +303,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
||||||
};
|
};
|
||||||
setproto.type = "set";
|
setproto.type = "set";
|
||||||
// export
|
// export
|
||||||
|
Snap.Set = Set;
|
||||||
Snap.set = function () {
|
Snap.set = function () {
|
||||||
var set = new Set;
|
var set = new Set;
|
||||||
if (arguments.length) {
|
if (arguments.length) {
|
||||||
|
|
953
src/svg.js
953
src/svg.js
|
@ -942,38 +942,6 @@ function transform2matrix(tstr, bbox) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
Snap._.transform2matrix = transform2matrix;
|
Snap._.transform2matrix = transform2matrix;
|
||||||
function extractTransform(el, tstr) {
|
|
||||||
if (tstr == null) {
|
|
||||||
var doReturn = true;
|
|
||||||
if (el.type == "linearGradient" || el.type == "radialGradient") {
|
|
||||||
tstr = el.node.getAttribute("gradientTransform");
|
|
||||||
} else if (el.type == "pattern") {
|
|
||||||
tstr = el.node.getAttribute("patternTransform");
|
|
||||||
} else {
|
|
||||||
tstr = el.node.getAttribute("transform");
|
|
||||||
}
|
|
||||||
if (!tstr) {
|
|
||||||
return new Snap.Matrix;
|
|
||||||
}
|
|
||||||
tstr = svgTransform2string(tstr);
|
|
||||||
} else {
|
|
||||||
if (!Snap._.rgTransform.test(tstr)) {
|
|
||||||
tstr = svgTransform2string(tstr);
|
|
||||||
} else {
|
|
||||||
tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
|
|
||||||
}
|
|
||||||
if (is(tstr, "array")) {
|
|
||||||
tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
|
|
||||||
}
|
|
||||||
el._.transform = tstr;
|
|
||||||
}
|
|
||||||
var m = transform2matrix(tstr, el.getBBox(1));
|
|
||||||
if (doReturn) {
|
|
||||||
return m;
|
|
||||||
} else {
|
|
||||||
el.matrix = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Snap._unit2px = unit2px;
|
Snap._unit2px = unit2px;
|
||||||
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
||||||
function (a, b) {
|
function (a, b) {
|
||||||
|
@ -1214,7 +1182,6 @@ function Element(el) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(function (elproto) {
|
|
||||||
/*\
|
/*\
|
||||||
* Element.attr
|
* Element.attr
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -1240,7 +1207,7 @@ function Element(el) {
|
||||||
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
||||||
* and `-`: `"+=2em"`.
|
* and `-`: `"+=2em"`.
|
||||||
\*/
|
\*/
|
||||||
elproto.attr = function (params, value) {
|
Element.prototype.attr = function (params, value) {
|
||||||
var el = this,
|
var el = this,
|
||||||
node = el.node;
|
node = el.node;
|
||||||
if (!params) {
|
if (!params) {
|
||||||
|
@ -1262,910 +1229,6 @@ function Element(el) {
|
||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
/*\
|
|
||||||
* Element.getBBox
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns the bounding box descriptor for the given element
|
|
||||||
**
|
|
||||||
= (object) bounding box descriptor:
|
|
||||||
o {
|
|
||||||
o cx: (number) x of the center,
|
|
||||||
o cy: (number) x of the center,
|
|
||||||
o h: (number) height,
|
|
||||||
o height: (number) height,
|
|
||||||
o path: (string) path command for the box,
|
|
||||||
o r0: (number) radius of a circle that fully encloses the box,
|
|
||||||
o r1: (number) radius of the smallest circle that can be enclosed,
|
|
||||||
o r2: (number) radius of the largest circle that can be enclosed,
|
|
||||||
o vb: (string) box as a viewbox command,
|
|
||||||
o w: (number) width,
|
|
||||||
o width: (number) width,
|
|
||||||
o x2: (number) x of the right side,
|
|
||||||
o x: (number) x of the left side,
|
|
||||||
o y2: (number) y of the bottom edge,
|
|
||||||
o y: (number) y of the top edge
|
|
||||||
o }
|
|
||||||
\*/
|
|
||||||
elproto.getBBox = function (isWithoutTransform) {
|
|
||||||
if (!Snap.Matrix || !Snap.path) {
|
|
||||||
return this.node.getBBox();
|
|
||||||
}
|
|
||||||
var el = this,
|
|
||||||
m = new Snap.Matrix;
|
|
||||||
if (el.removed) {
|
|
||||||
return Snap._.box();
|
|
||||||
}
|
|
||||||
while (el.type == "use") {
|
|
||||||
if (!isWithoutTransform) {
|
|
||||||
m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0));
|
|
||||||
}
|
|
||||||
if (el.original) {
|
|
||||||
el = el.original;
|
|
||||||
} else {
|
|
||||||
var href = el.attr("xlink:href");
|
|
||||||
el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var _ = el._,
|
|
||||||
pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt;
|
|
||||||
try {
|
|
||||||
if (isWithoutTransform) {
|
|
||||||
_.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox());
|
|
||||||
return Snap._.box(_.bboxwt);
|
|
||||||
} else {
|
|
||||||
el.realPath = pathfinder(el);
|
|
||||||
el.matrix = el.transform().localMatrix;
|
|
||||||
_.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix)));
|
|
||||||
return Snap._.box(_.bbox);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Firefox doesn’t give you bbox of hidden element
|
|
||||||
return Snap._.box();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var propString = function () {
|
|
||||||
return this.string;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.transform
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Gets or sets transformation of the element
|
|
||||||
**
|
|
||||||
- tstr (string) transform string in Snap or SVG format
|
|
||||||
= (Element) the current element
|
|
||||||
* or
|
|
||||||
= (object) transformation descriptor:
|
|
||||||
o {
|
|
||||||
o string (string) transform string,
|
|
||||||
o globalMatrix (Matrix) matrix of all transformations applied to element or its parents,
|
|
||||||
o localMatrix (Matrix) matrix of transformations applied only to the element,
|
|
||||||
o diffMatrix (Matrix) matrix of difference between global and local transformations,
|
|
||||||
o global (string) global transformation as string,
|
|
||||||
o local (string) local transformation as string,
|
|
||||||
o toString (function) returns `string` property
|
|
||||||
o }
|
|
||||||
\*/
|
|
||||||
elproto.transform = function (tstr) {
|
|
||||||
var _ = this._;
|
|
||||||
if (tstr == null) {
|
|
||||||
var papa = this,
|
|
||||||
global = new Snap.Matrix(this.node.getCTM()),
|
|
||||||
local = extractTransform(this),
|
|
||||||
ms = [local],
|
|
||||||
m = new Snap.Matrix,
|
|
||||||
i,
|
|
||||||
localString = local.toTransformString(),
|
|
||||||
string = Str(local) == Str(this.matrix) ?
|
|
||||||
Str(_.transform) : localString;
|
|
||||||
while (papa.type != "svg" && (papa = papa.parent())) {
|
|
||||||
ms.push(extractTransform(papa));
|
|
||||||
}
|
|
||||||
i = ms.length;
|
|
||||||
while (i--) {
|
|
||||||
m.add(ms[i]);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
string: string,
|
|
||||||
globalMatrix: global,
|
|
||||||
totalMatrix: m,
|
|
||||||
localMatrix: local,
|
|
||||||
diffMatrix: global.clone().add(local.invert()),
|
|
||||||
global: global.toTransformString(),
|
|
||||||
total: m.toTransformString(),
|
|
||||||
local: localString,
|
|
||||||
toString: propString
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (tstr instanceof Snap.Matrix) {
|
|
||||||
this.matrix = tstr;
|
|
||||||
} else {
|
|
||||||
extractTransform(this, tstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.node) {
|
|
||||||
if (this.type == "linearGradient" || this.type == "radialGradient") {
|
|
||||||
$(this.node, {gradientTransform: this.matrix});
|
|
||||||
} else if (this.type == "pattern") {
|
|
||||||
$(this.node, {patternTransform: this.matrix});
|
|
||||||
} else {
|
|
||||||
$(this.node, {transform: this.matrix});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.parent
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns the element's parent
|
|
||||||
**
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.parent = function () {
|
|
||||||
return wrap(this.node.parentNode);
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.append
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Appends the given element to current one
|
|
||||||
**
|
|
||||||
- el (Element|Set) element to append
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
/*\
|
|
||||||
* Element.add
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* See @Element.append
|
|
||||||
\*/
|
|
||||||
elproto.append = elproto.add = function (el) {
|
|
||||||
if (el) {
|
|
||||||
if (el.type == "set") {
|
|
||||||
var it = this;
|
|
||||||
el.forEach(function (el) {
|
|
||||||
it.add(el);
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
el = wrap(el);
|
|
||||||
this.node.appendChild(el.node);
|
|
||||||
el.paper = this.paper;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.appendTo
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Appends the current element to the given one
|
|
||||||
**
|
|
||||||
- el (Element) parent element to append to
|
|
||||||
= (Element) the child element
|
|
||||||
\*/
|
|
||||||
elproto.appendTo = function (el) {
|
|
||||||
if (el) {
|
|
||||||
el = wrap(el);
|
|
||||||
el.append(this);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.prepend
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Prepends the given element to the current one
|
|
||||||
**
|
|
||||||
- el (Element) element to prepend
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.prepend = function (el) {
|
|
||||||
if (el) {
|
|
||||||
if (el.type == "set") {
|
|
||||||
var it = this,
|
|
||||||
first;
|
|
||||||
el.forEach(function (el) {
|
|
||||||
if (first) {
|
|
||||||
first.after(el);
|
|
||||||
} else {
|
|
||||||
it.prepend(el);
|
|
||||||
}
|
|
||||||
first = el;
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
el = wrap(el);
|
|
||||||
var parent = el.parent();
|
|
||||||
this.node.insertBefore(el.node, this.node.firstChild);
|
|
||||||
this.add && this.add();
|
|
||||||
el.paper = this.paper;
|
|
||||||
this.parent() && this.parent().add();
|
|
||||||
parent && parent.add();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.prependTo
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Prepends the current element to the given one
|
|
||||||
**
|
|
||||||
- el (Element) parent element to prepend to
|
|
||||||
= (Element) the child element
|
|
||||||
\*/
|
|
||||||
elproto.prependTo = function (el) {
|
|
||||||
el = wrap(el);
|
|
||||||
el.prepend(this);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.before
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Inserts given element before the current one
|
|
||||||
**
|
|
||||||
- el (Element) element to insert
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.before = function (el) {
|
|
||||||
if (el.type == "set") {
|
|
||||||
var it = this;
|
|
||||||
el.forEach(function (el) {
|
|
||||||
var parent = el.parent();
|
|
||||||
it.node.parentNode.insertBefore(el.node, it.node);
|
|
||||||
parent && parent.add();
|
|
||||||
});
|
|
||||||
this.parent().add();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
el = wrap(el);
|
|
||||||
var parent = el.parent();
|
|
||||||
this.node.parentNode.insertBefore(el.node, this.node);
|
|
||||||
this.parent() && this.parent().add();
|
|
||||||
parent && parent.add();
|
|
||||||
el.paper = this.paper;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.after
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Inserts given element after the current one
|
|
||||||
**
|
|
||||||
- el (Element) element to insert
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.after = function (el) {
|
|
||||||
el = wrap(el);
|
|
||||||
var parent = el.parent();
|
|
||||||
if (this.node.nextSibling) {
|
|
||||||
this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
|
|
||||||
} else {
|
|
||||||
this.node.parentNode.appendChild(el.node);
|
|
||||||
}
|
|
||||||
this.parent() && this.parent().add();
|
|
||||||
parent && parent.add();
|
|
||||||
el.paper = this.paper;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.insertBefore
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Inserts the element after the given one
|
|
||||||
**
|
|
||||||
- el (Element) element next to whom insert to
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.insertBefore = function (el) {
|
|
||||||
el = wrap(el);
|
|
||||||
var parent = this.parent();
|
|
||||||
el.node.parentNode.insertBefore(this.node, el.node);
|
|
||||||
this.paper = el.paper;
|
|
||||||
parent && parent.add();
|
|
||||||
el.parent() && el.parent().add();
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.insertAfter
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Inserts the element after the given one
|
|
||||||
**
|
|
||||||
- el (Element) element next to whom insert to
|
|
||||||
= (Element) the parent element
|
|
||||||
\*/
|
|
||||||
elproto.insertAfter = function (el) {
|
|
||||||
el = wrap(el);
|
|
||||||
var parent = this.parent();
|
|
||||||
el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
|
|
||||||
this.paper = el.paper;
|
|
||||||
parent && parent.add();
|
|
||||||
el.parent() && el.parent().add();
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.remove
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Removes element from the DOM
|
|
||||||
= (Element) the detached element
|
|
||||||
\*/
|
|
||||||
elproto.remove = function () {
|
|
||||||
var parent = this.parent();
|
|
||||||
this.node.parentNode && this.node.parentNode.removeChild(this.node);
|
|
||||||
delete this.paper;
|
|
||||||
this.removed = true;
|
|
||||||
parent && parent.add();
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.select
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Gathers the nested @Element matching the given set of CSS selectors
|
|
||||||
**
|
|
||||||
- query (string) CSS selector
|
|
||||||
= (Element) result of query selection
|
|
||||||
\*/
|
|
||||||
elproto.select = function (query) {
|
|
||||||
query = Str(query).replace(/([^\\]):/g, "$1\\:");
|
|
||||||
return wrap(this.node.querySelector(query));
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.selectAll
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Gathers nested @Element objects matching the given set of CSS selectors
|
|
||||||
**
|
|
||||||
- query (string) CSS selector
|
|
||||||
= (Set|array) result of query selection
|
|
||||||
\*/
|
|
||||||
elproto.selectAll = function (query) {
|
|
||||||
var nodelist = this.node.querySelectorAll(query),
|
|
||||||
set = (Snap.set || Array)();
|
|
||||||
for (var i = 0; i < nodelist.length; i++) {
|
|
||||||
set.push(wrap(nodelist[i]));
|
|
||||||
}
|
|
||||||
return set;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.asPX
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns given attribute of the element as a `px` value (not %, em, etc.)
|
|
||||||
**
|
|
||||||
- attr (string) attribute name
|
|
||||||
- value (string) #optional attribute value
|
|
||||||
= (Element) result of query selection
|
|
||||||
\*/
|
|
||||||
elproto.asPX = function (attr, value) {
|
|
||||||
if (value == null) {
|
|
||||||
value = this.attr(attr);
|
|
||||||
}
|
|
||||||
return +unit2px(this, attr, value);
|
|
||||||
};
|
|
||||||
// SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar.
|
|
||||||
/*\
|
|
||||||
* Element.use
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates a `<use>` element linked to the current element
|
|
||||||
**
|
|
||||||
= (Element) the `<use>` element
|
|
||||||
\*/
|
|
||||||
elproto.use = function () {
|
|
||||||
var use,
|
|
||||||
id = this.node.id;
|
|
||||||
if (!id) {
|
|
||||||
id = this.id;
|
|
||||||
$(this.node, {
|
|
||||||
id: id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.type == "linearGradient" || this.type == "radialGradient" ||
|
|
||||||
this.type == "pattern") {
|
|
||||||
use = make(this.type, this.node.parentNode);
|
|
||||||
} else {
|
|
||||||
use = make("use", this.node.parentNode);
|
|
||||||
}
|
|
||||||
$(use.node, {
|
|
||||||
"xlink:href": "#" + id
|
|
||||||
});
|
|
||||||
use.original = this;
|
|
||||||
return use;
|
|
||||||
};
|
|
||||||
function fixids(el) {
|
|
||||||
var els = el.selectAll("*"),
|
|
||||||
it,
|
|
||||||
url = /^\s*url\(("|'|)(.*)\1\)\s*$/,
|
|
||||||
ids = [],
|
|
||||||
uses = {};
|
|
||||||
function urltest(it, name) {
|
|
||||||
var val = $(it.node, name);
|
|
||||||
val = val && val.match(url);
|
|
||||||
val = val && val[2];
|
|
||||||
if (val && val.charAt() == "#") {
|
|
||||||
val = val.substring(1);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (val) {
|
|
||||||
uses[val] = (uses[val] || []).concat(function (id) {
|
|
||||||
var attr = {};
|
|
||||||
attr[name] = URL(id);
|
|
||||||
$(it.node, attr);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function linktest(it) {
|
|
||||||
var val = $(it.node, "xlink:href");
|
|
||||||
if (val && val.charAt() == "#") {
|
|
||||||
val = val.substring(1);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (val) {
|
|
||||||
uses[val] = (uses[val] || []).concat(function (id) {
|
|
||||||
it.attr("xlink:href", "#" + id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var i = 0, ii = els.length; i < ii; i++) {
|
|
||||||
it = els[i];
|
|
||||||
urltest(it, "fill");
|
|
||||||
urltest(it, "stroke");
|
|
||||||
urltest(it, "filter");
|
|
||||||
urltest(it, "mask");
|
|
||||||
urltest(it, "clip-path");
|
|
||||||
linktest(it);
|
|
||||||
var oldid = $(it.node, "id");
|
|
||||||
if (oldid) {
|
|
||||||
$(it.node, {id: it.id});
|
|
||||||
ids.push({
|
|
||||||
old: oldid,
|
|
||||||
id: it.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0, ii = ids.length; i < ii; i++) {
|
|
||||||
var fs = uses[ids[i].old];
|
|
||||||
if (fs) {
|
|
||||||
for (var j = 0, jj = fs.length; j < jj; j++) {
|
|
||||||
fs[j](ids[i].id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*\
|
|
||||||
* Element.clone
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates a clone of the element and inserts it after the element
|
|
||||||
**
|
|
||||||
= (Element) the clone
|
|
||||||
\*/
|
|
||||||
elproto.clone = function () {
|
|
||||||
var clone = wrap(this.node.cloneNode(true));
|
|
||||||
if ($(clone.node, "id")) {
|
|
||||||
$(clone.node, {id: clone.id});
|
|
||||||
}
|
|
||||||
fixids(clone);
|
|
||||||
clone.insertAfter(this);
|
|
||||||
return clone;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.toDefs
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Moves element to the shared `<defs>` area
|
|
||||||
**
|
|
||||||
= (Element) the element
|
|
||||||
\*/
|
|
||||||
elproto.toDefs = function () {
|
|
||||||
var defs = getSomeDefs(this);
|
|
||||||
defs.appendChild(this.node);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.pattern
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Depricated. Use @Element.toPattern instead.
|
|
||||||
\*/
|
|
||||||
/*\
|
|
||||||
* Element.toPattern
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates a `<pattern>` element from the current element
|
|
||||||
**
|
|
||||||
* To create a pattern you have to specify the pattern rect:
|
|
||||||
- x (string|number)
|
|
||||||
- y (string|number)
|
|
||||||
- width (string|number)
|
|
||||||
- height (string|number)
|
|
||||||
= (Element) the `<pattern>` element
|
|
||||||
* You can use pattern later on as an argument for `fill` attribute:
|
|
||||||
| var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
|
|
||||||
| fill: "none",
|
|
||||||
| stroke: "#bada55",
|
|
||||||
| strokeWidth: 5
|
|
||||||
| }).pattern(0, 0, 10, 10),
|
|
||||||
| c = paper.circle(200, 200, 100);
|
|
||||||
| c.attr({
|
|
||||||
| fill: p
|
|
||||||
| });
|
|
||||||
\*/
|
|
||||||
elproto.pattern = elproto.toPattern = function (x, y, width, height) {
|
|
||||||
var p = make("pattern", getSomeDefs(this));
|
|
||||||
if (x == null) {
|
|
||||||
x = this.getBBox();
|
|
||||||
}
|
|
||||||
if (is(x, "object") && "x" in x) {
|
|
||||||
y = x.y;
|
|
||||||
width = x.width;
|
|
||||||
height = x.height;
|
|
||||||
x = x.x;
|
|
||||||
}
|
|
||||||
$(p.node, {
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
patternUnits: "userSpaceOnUse",
|
|
||||||
id: p.id,
|
|
||||||
viewBox: [x, y, width, height].join(" ")
|
|
||||||
});
|
|
||||||
p.node.appendChild(this.node);
|
|
||||||
return p;
|
|
||||||
};
|
|
||||||
// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path.
|
|
||||||
// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values?
|
|
||||||
/*\
|
|
||||||
* Element.marker
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates a `<marker>` element from the current element
|
|
||||||
**
|
|
||||||
* To create a marker you have to specify the bounding rect and reference point:
|
|
||||||
- x (number)
|
|
||||||
- y (number)
|
|
||||||
- width (number)
|
|
||||||
- height (number)
|
|
||||||
- refX (number)
|
|
||||||
- refY (number)
|
|
||||||
= (Element) the `<marker>` element
|
|
||||||
* You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end.
|
|
||||||
\*/
|
|
||||||
// TODO add usage for markers
|
|
||||||
elproto.marker = function (x, y, width, height, refX, refY) {
|
|
||||||
var p = make("marker", getSomeDefs(this));
|
|
||||||
if (x == null) {
|
|
||||||
x = this.getBBox();
|
|
||||||
}
|
|
||||||
if (is(x, "object") && "x" in x) {
|
|
||||||
y = x.y;
|
|
||||||
width = x.width;
|
|
||||||
height = x.height;
|
|
||||||
refX = x.refX || x.cx;
|
|
||||||
refY = x.refY || x.cy;
|
|
||||||
x = x.x;
|
|
||||||
}
|
|
||||||
$(p.node, {
|
|
||||||
viewBox: [x, y, width, height].join(S),
|
|
||||||
markerWidth: width,
|
|
||||||
markerHeight: height,
|
|
||||||
orient: "auto",
|
|
||||||
refX: refX || 0,
|
|
||||||
refY: refY || 0,
|
|
||||||
id: p.id
|
|
||||||
});
|
|
||||||
p.node.appendChild(this.node);
|
|
||||||
return p;
|
|
||||||
};
|
|
||||||
// animation
|
|
||||||
function slice(from, to, f) {
|
|
||||||
return function (arr) {
|
|
||||||
var res = arr.slice(from, to);
|
|
||||||
if (res.length == 1) {
|
|
||||||
res = res[0];
|
|
||||||
}
|
|
||||||
return f ? f(res) : res;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var Animation = function (attr, ms, easing, callback) {
|
|
||||||
if (typeof easing == "function" && !easing.length) {
|
|
||||||
callback = easing;
|
|
||||||
easing = mina.linear;
|
|
||||||
}
|
|
||||||
this.attr = attr;
|
|
||||||
this.dur = ms;
|
|
||||||
easing && (this.easing = easing);
|
|
||||||
callback && (this.callback = callback);
|
|
||||||
};
|
|
||||||
Snap._.Animation = Animation;
|
|
||||||
/*\
|
|
||||||
* Snap.animation
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Creates an animation object
|
|
||||||
**
|
|
||||||
- attr (object) attributes of final destination
|
|
||||||
- duration (number) duration of the animation, in milliseconds
|
|
||||||
- easing (function) #optional one of easing functions of @mina or custom one
|
|
||||||
- callback (function) #optional callback function that fires when animation ends
|
|
||||||
= (object) animation object
|
|
||||||
\*/
|
|
||||||
Snap.animation = function (attr, ms, easing, callback) {
|
|
||||||
return new Animation(attr, ms, easing, callback);
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.inAnim
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns a set of animations that may be able to manipulate the current element
|
|
||||||
**
|
|
||||||
= (object) in format:
|
|
||||||
o {
|
|
||||||
o anim (object) animation object,
|
|
||||||
o mina (object) @mina object,
|
|
||||||
o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
|
|
||||||
o status (function) gets or sets the status of the animation,
|
|
||||||
o stop (function) stops the animation
|
|
||||||
o }
|
|
||||||
\*/
|
|
||||||
elproto.inAnim = function () {
|
|
||||||
var el = this,
|
|
||||||
res = [];
|
|
||||||
for (var id in el.anims) if (el.anims[has](id)) {
|
|
||||||
(function (a) {
|
|
||||||
res.push({
|
|
||||||
anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
|
|
||||||
mina: a,
|
|
||||||
curStatus: a.status(),
|
|
||||||
status: function (val) {
|
|
||||||
return a.status(val);
|
|
||||||
},
|
|
||||||
stop: function () {
|
|
||||||
a.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}(el.anims[id]));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Snap.animate
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Runs generic animation of one number into another with a caring function
|
|
||||||
**
|
|
||||||
- from (number|array) number or array of numbers
|
|
||||||
- to (number|array) number or array of numbers
|
|
||||||
- setter (function) caring function that accepts one number argument
|
|
||||||
- duration (number) duration, in milliseconds
|
|
||||||
- easing (function) #optional easing function from @mina or custom
|
|
||||||
- callback (function) #optional callback function to execute when animation ends
|
|
||||||
= (object) animation object in @mina format
|
|
||||||
o {
|
|
||||||
o id (string) animation id, consider it read-only,
|
|
||||||
o duration (function) gets or sets the duration of the animation,
|
|
||||||
o easing (function) easing,
|
|
||||||
o speed (function) gets or sets the speed of the animation,
|
|
||||||
o status (function) gets or sets the status of the animation,
|
|
||||||
o stop (function) stops the animation
|
|
||||||
o }
|
|
||||||
| var rect = Snap().rect(0, 0, 10, 10);
|
|
||||||
| Snap.animate(0, 10, function (val) {
|
|
||||||
| rect.attr({
|
|
||||||
| x: val
|
|
||||||
| });
|
|
||||||
| }, 1000);
|
|
||||||
| // in given context is equivalent to
|
|
||||||
| rect.animate({x: 10}, 1000);
|
|
||||||
\*/
|
|
||||||
Snap.animate = function (from, to, setter, ms, easing, callback) {
|
|
||||||
if (typeof easing == "function" && !easing.length) {
|
|
||||||
callback = easing;
|
|
||||||
easing = mina.linear;
|
|
||||||
}
|
|
||||||
var now = mina.time(),
|
|
||||||
anim = mina(from, to, now, now + ms, mina.time, setter, easing);
|
|
||||||
callback && eve.once("mina.finish." + anim.id, callback);
|
|
||||||
return anim;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.stop
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Stops all the animations for the current element
|
|
||||||
**
|
|
||||||
= (Element) the current element
|
|
||||||
\*/
|
|
||||||
elproto.stop = function () {
|
|
||||||
var anims = this.inAnim();
|
|
||||||
for (var i = 0, ii = anims.length; i < ii; i++) {
|
|
||||||
anims[i].stop();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.animate
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Animates the given attributes of the element
|
|
||||||
**
|
|
||||||
- attrs (object) key-value pairs of destination attributes
|
|
||||||
- duration (number) duration of the animation in milliseconds
|
|
||||||
- easing (function) #optional easing function from @mina or custom
|
|
||||||
- callback (function) #optional callback function that executes when the animation ends
|
|
||||||
= (Element) the current element
|
|
||||||
\*/
|
|
||||||
elproto.animate = function (attrs, ms, easing, callback) {
|
|
||||||
if (typeof easing == "function" && !easing.length) {
|
|
||||||
callback = easing;
|
|
||||||
easing = mina.linear;
|
|
||||||
}
|
|
||||||
if (attrs instanceof Animation) {
|
|
||||||
callback = attrs.callback;
|
|
||||||
easing = attrs.easing;
|
|
||||||
ms = easing.dur;
|
|
||||||
attrs = attrs.attr;
|
|
||||||
}
|
|
||||||
var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
|
|
||||||
el = this;
|
|
||||||
for (var key in attrs) if (attrs[has](key)) {
|
|
||||||
if (el.equal) {
|
|
||||||
eq = el.equal(key, Str(attrs[key]));
|
|
||||||
from = eq.from;
|
|
||||||
to = eq.to;
|
|
||||||
f = eq.f;
|
|
||||||
} else {
|
|
||||||
from = +el.attr(key);
|
|
||||||
to = +attrs[key];
|
|
||||||
}
|
|
||||||
var len = is(from, "array") ? from.length : 1;
|
|
||||||
keys[key] = slice(fkeys.length, fkeys.length + len, f);
|
|
||||||
fkeys = fkeys.concat(from);
|
|
||||||
tkeys = tkeys.concat(to);
|
|
||||||
}
|
|
||||||
var now = mina.time(),
|
|
||||||
anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
|
|
||||||
var attr = {};
|
|
||||||
for (var key in keys) if (keys[has](key)) {
|
|
||||||
attr[key] = keys[key](val);
|
|
||||||
}
|
|
||||||
el.attr(attr);
|
|
||||||
}, easing);
|
|
||||||
el.anims[anim.id] = anim;
|
|
||||||
anim._attrs = attrs;
|
|
||||||
anim._callback = callback;
|
|
||||||
eve("snap.animcreated." + el.id, anim);
|
|
||||||
eve.once("mina.finish." + anim.id, function () {
|
|
||||||
delete el.anims[anim.id];
|
|
||||||
callback && callback.call(el);
|
|
||||||
});
|
|
||||||
eve.once("mina.stop." + anim.id, function () {
|
|
||||||
delete el.anims[anim.id];
|
|
||||||
});
|
|
||||||
return el;
|
|
||||||
};
|
|
||||||
var eldata = {};
|
|
||||||
/*\
|
|
||||||
* Element.data
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Adds or retrieves given value associated with given key. (Don’t confuse
|
|
||||||
* with `data-` attributes)
|
|
||||||
*
|
|
||||||
* See also @Element.removeData
|
|
||||||
- key (string) key to store data
|
|
||||||
- value (any) #optional value to store
|
|
||||||
= (object) @Element
|
|
||||||
* or, if value is not specified:
|
|
||||||
= (any) value
|
|
||||||
> Usage
|
|
||||||
| for (var i = 0, i < 5, i++) {
|
|
||||||
| paper.circle(10 + 15 * i, 10, 10)
|
|
||||||
| .attr({fill: "#000"})
|
|
||||||
| .data("i", i)
|
|
||||||
| .click(function () {
|
|
||||||
| alert(this.data("i"));
|
|
||||||
| });
|
|
||||||
| }
|
|
||||||
\*/
|
|
||||||
elproto.data = function (key, value) {
|
|
||||||
var data = eldata[this.id] = eldata[this.id] || {};
|
|
||||||
if (arguments.length == 0){
|
|
||||||
eve("snap.data.get." + this.id, this, data, null);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
if (arguments.length == 1) {
|
|
||||||
if (Snap.is(key, "object")) {
|
|
||||||
for (var i in key) if (key[has](i)) {
|
|
||||||
this.data(i, key[i]);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
eve("snap.data.get." + this.id, this, data[key], key);
|
|
||||||
return data[key];
|
|
||||||
}
|
|
||||||
data[key] = value;
|
|
||||||
eve("snap.data.set." + this.id, this, value, key);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.removeData
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Removes value associated with an element by given key.
|
|
||||||
* If key is not provided, removes all the data of the element.
|
|
||||||
- key (string) #optional key
|
|
||||||
= (object) @Element
|
|
||||||
\*/
|
|
||||||
elproto.removeData = function (key) {
|
|
||||||
if (key == null) {
|
|
||||||
eldata[this.id] = {};
|
|
||||||
} else {
|
|
||||||
eldata[this.id] && delete eldata[this.id][key];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
/*\
|
|
||||||
* Element.outerSVG
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns SVG code for the element, equivalent to HTML's `outerHTML`.
|
|
||||||
*
|
|
||||||
* See also @Element.innerSVG
|
|
||||||
= (string) SVG code for the element
|
|
||||||
\*/
|
|
||||||
/*\
|
|
||||||
* Element.toString
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* See @Element.outerSVG
|
|
||||||
\*/
|
|
||||||
elproto.outerSVG = elproto.toString = toString(1);
|
|
||||||
/*\
|
|
||||||
* Element.innerSVG
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* Returns SVG code for the element's contents, equivalent to HTML's `innerHTML`
|
|
||||||
= (string) SVG code for the element
|
|
||||||
\*/
|
|
||||||
elproto.innerSVG = toString();
|
|
||||||
function toString(type) {
|
|
||||||
return function () {
|
|
||||||
var res = type ? "<" + this.type : "",
|
|
||||||
attr = this.node.attributes,
|
|
||||||
chld = this.node.childNodes;
|
|
||||||
if (type) {
|
|
||||||
for (var i = 0, ii = attr.length; i < ii; i++) {
|
|
||||||
res += " " + attr[i].name + '="' +
|
|
||||||
attr[i].value.replace(/"/g, '\\"') + '"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chld.length) {
|
|
||||||
type && (res += ">");
|
|
||||||
for (i = 0, ii = chld.length; i < ii; i++) {
|
|
||||||
if (chld[i].nodeType == 3) {
|
|
||||||
res += chld[i].nodeValue;
|
|
||||||
} else if (chld[i].nodeType == 1) {
|
|
||||||
res += wrap(chld[i]).toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type && (res += "</" + this.type + ">");
|
|
||||||
} else {
|
|
||||||
type && (res += "/>");
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}(Element.prototype));
|
|
||||||
/*\
|
/*\
|
||||||
* Snap.parse
|
* Snap.parse
|
||||||
[ method ]
|
[ method ]
|
||||||
|
@ -2201,20 +1264,6 @@ Snap.parse = function (svg) {
|
||||||
function Fragment(frag) {
|
function Fragment(frag) {
|
||||||
this.node = frag;
|
this.node = frag;
|
||||||
}
|
}
|
||||||
/*\
|
|
||||||
* Fragment.select
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* See @Element.select
|
|
||||||
\*/
|
|
||||||
Fragment.prototype.select = Element.prototype.select;
|
|
||||||
/*\
|
|
||||||
* Fragment.selectAll
|
|
||||||
[ method ]
|
|
||||||
**
|
|
||||||
* See @Element.selectAll
|
|
||||||
\*/
|
|
||||||
Fragment.prototype.selectAll = Element.prototype.selectAll;
|
|
||||||
// SIERRA Snap.fragment() could especially use a code example
|
// SIERRA Snap.fragment() could especially use a code example
|
||||||
/*\
|
/*\
|
||||||
* Snap.fragment
|
* Snap.fragment
|
||||||
|
|
Loading…
Reference in New Issue