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/mina.js",
|
||||
"./src/svg.js",
|
||||
"./src/element.js",
|
||||
"./src/matrix.js",
|
||||
"./src/attr.js",
|
||||
"./src/class.js",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
// 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");
|
||||
// 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
|
||||
// limitations under the License.
|
||||
//
|
||||
// build: 2014-08-04
|
||||
// build: 2014-08-13
|
||||
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -1732,38 +1732,6 @@ function transform2matrix(tstr, bbox) {
|
|||
return m;
|
||||
}
|
||||
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;
|
||||
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
||||
function (a, b) {
|
||||
|
@ -2004,7 +1972,6 @@ function Element(el) {
|
|||
}
|
||||
}
|
||||
}
|
||||
(function (elproto) {
|
||||
/*\
|
||||
* Element.attr
|
||||
[ method ]
|
||||
|
@ -2030,7 +1997,7 @@ function Element(el) {
|
|||
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
||||
* and `-`: `"+=2em"`.
|
||||
\*/
|
||||
elproto.attr = function (params, value) {
|
||||
Element.prototype.attr = function (params, value) {
|
||||
var el = this,
|
||||
node = el.node;
|
||||
if (!params) {
|
||||
|
@ -2052,6 +2019,414 @@ function Element(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
|
||||
[ method ]
|
||||
|
@ -2117,6 +2492,38 @@ function Element(el) {
|
|||
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 ]
|
||||
|
@ -2645,7 +3052,7 @@ function Element(el) {
|
|||
x = x.x;
|
||||
}
|
||||
$(p.node, {
|
||||
viewBox: [x, y, width, height].join(S),
|
||||
viewBox: [x, y, width, height].join(" "),
|
||||
markerWidth: width,
|
||||
markerHeight: height,
|
||||
orient: "auto",
|
||||
|
@ -2955,406 +3362,36 @@ function Element(el) {
|
|||
return res;
|
||||
};
|
||||
}
|
||||
}(Element.prototype));
|
||||
/*\
|
||||
* 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;
|
||||
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()
|
||||
});
|
||||
console.log(svg);
|
||||
return "data:image/svg+xml;utf8," + svg;
|
||||
return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
|
||||
}
|
||||
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
|
||||
[ method ]
|
||||
**
|
||||
* See @Element.select
|
||||
\*/
|
||||
Fragment.prototype.select = Element.prototype.select;
|
||||
Fragment.prototype.select = elproto.select;
|
||||
/*\
|
||||
* Fragment.selectAll
|
||||
[ method ]
|
||||
**
|
||||
* See @Element.selectAll
|
||||
\*/
|
||||
Fragment.prototype.selectAll = Element.prototype.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
|
||||
Fragment.prototype.selectAll = elproto.selectAll;
|
||||
});
|
||||
}
|
||||
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");
|
||||
|
@ -4688,6 +4725,9 @@ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
|||
}
|
||||
id = id.attr("id");
|
||||
}
|
||||
if (String(id).charAt() == "#") {
|
||||
id = id.substring(1);
|
||||
}
|
||||
return this.el("use", {"xlink:href": "#" + id});
|
||||
} else {
|
||||
return Element.prototype.use.call(this);
|
||||
|
@ -4997,6 +5037,18 @@ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
|
|||
f.removeChild(f.firstChild);
|
||||
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
|
||||
[ method ]
|
||||
|
@ -6733,6 +6785,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
|||
};
|
||||
setproto.type = "set";
|
||||
// export
|
||||
Snap.Set = Set;
|
||||
Snap.set = function () {
|
||||
var set = new Set;
|
||||
if (arguments.length) {
|
||||
|
@ -7420,7 +7473,6 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
|||
Str = String,
|
||||
$ = Snap._.$;
|
||||
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
|
||||
[ 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": [{
|
||||
"url": "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",
|
||||
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/matrix.js"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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");
|
||||
// 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,
|
||||
$ = Snap._.$;
|
||||
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
|
||||
[ 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);
|
||||
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
|
||||
[ method ]
|
||||
|
|
|
@ -303,6 +303,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
|
|||
};
|
||||
setproto.type = "set";
|
||||
// export
|
||||
Snap.Set = Set;
|
||||
Snap.set = function () {
|
||||
var set = new Set;
|
||||
if (arguments.length) {
|
||||
|
|
953
src/svg.js
953
src/svg.js
|
@ -942,38 +942,6 @@ function transform2matrix(tstr, bbox) {
|
|||
return m;
|
||||
}
|
||||
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;
|
||||
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
|
||||
function (a, b) {
|
||||
|
@ -1214,7 +1182,6 @@ function Element(el) {
|
|||
}
|
||||
}
|
||||
}
|
||||
(function (elproto) {
|
||||
/*\
|
||||
* Element.attr
|
||||
[ method ]
|
||||
|
@ -1240,7 +1207,7 @@ function Element(el) {
|
|||
* (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
|
||||
* and `-`: `"+=2em"`.
|
||||
\*/
|
||||
elproto.attr = function (params, value) {
|
||||
Element.prototype.attr = function (params, value) {
|
||||
var el = this,
|
||||
node = el.node;
|
||||
if (!params) {
|
||||
|
@ -1262,910 +1229,6 @@ function Element(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
|
||||
[ method ]
|
||||
|
@ -2201,20 +1264,6 @@ Snap.parse = function (svg) {
|
|||
function Fragment(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
|
||||
/*\
|
||||
* Snap.fragment
|
||||
|
|
Loading…
Reference in New Issue