vc-popup
Version:
vue popup components with power position and animation support and back key support as well
1,673 lines (1,655 loc) • 268 kB
JavaScript
// Snap.svg 0.5.1
//
// Copyright (c) 2013 – 2017 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.
//
// build: 2017-02-07
// 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.
// ┌────────────────────────────────────────────────────────────┐ \\
// │ Eve 0.5.0 - JavaScript Events Library │ \\
// ├────────────────────────────────────────────────────────────┤ \\
// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
// └────────────────────────────────────────────────────────────┘ \\
(function (glob, factory) {
// AMD support
if (typeof define == "function" && define.amd) {
// Define as an anonymous module
define(["eve"], function (eve) {
return factory(glob, eve);
});
} else if (typeof exports != "undefined") {
// Next for Node.js or CommonJS
var eve = require("eve");
module.exports = factory(glob, eve);
} else {
// Browser globals (glob is window)
// Snap adds itself to window
factory(glob, glob.eve);
}
}(window || this, function (window, eve) {
// Copyright (c) 2017 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.
var mina = (function (eve) {
var animations = {},
requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
setTimeout(callback, 16, new Date().getTime());
return true;
},
requestID,
isArray = Array.isArray || function (a) {
return a instanceof Array ||
Object.prototype.toString.call(a) == "[object Array]";
},
idgen = 0,
idprefix = "M" + (+new Date).toString(36),
ID = function () {
return idprefix + (idgen++).toString(36);
},
diff = function (a, b, A, B) {
if (isArray(a)) {
res = [];
for (var i = 0, ii = a.length; i < ii; i++) {
res[i] = diff(a[i], b, A[i], B);
}
return res;
}
var dif = (A - a) / (B - b);
return function (bb) {
return a + dif * (bb - b);
};
},
timer = Date.now || function () {
return +new Date;
},
sta = function (val) {
var a = this;
if (val == null) {
return a.s;
}
var ds = a.s - val;
a.b += a.dur * ds;
a.B += a.dur * ds;
a.s = val;
},
speed = function (val) {
var a = this;
if (val == null) {
return a.spd;
}
a.spd = val;
},
duration = function (val) {
var a = this;
if (val == null) {
return a.dur;
}
a.s = a.s * val / a.dur;
a.dur = val;
},
stopit = function () {
var a = this;
delete animations[a.id];
a.update();
eve("mina.stop." + a.id, a);
},
pause = function () {
var a = this;
if (a.pdif) {
return;
}
delete animations[a.id];
a.update();
a.pdif = a.get() - a.b;
},
resume = function () {
var a = this;
if (!a.pdif) {
return;
}
a.b = a.get() - a.pdif;
delete a.pdif;
animations[a.id] = a;
frame();
},
update = function () {
var a = this,
res;
if (isArray(a.start)) {
res = [];
for (var j = 0, jj = a.start.length; j < jj; j++) {
res[j] = +a.start[j] +
(a.end[j] - a.start[j]) * a.easing(a.s);
}
} else {
res = +a.start + (a.end - a.start) * a.easing(a.s);
}
a.set(res);
},
frame = function (timeStamp) {
// Manual invokation?
if (!timeStamp) {
// Frame loop stopped?
if (!requestID) {
// Start frame loop...
requestID = requestAnimFrame(frame);
}
return;
}
var len = 0;
for (var i in animations) if (animations.hasOwnProperty(i)) {
var a = animations[i],
b = a.get(),
res;
len++;
a.s = (b - a.b) / (a.dur / a.spd);
if (a.s >= 1) {
delete animations[i];
a.s = 1;
len--;
(function (a) {
setTimeout(function () {
eve("mina.finish." + a.id, a);
});
}(a));
}
a.update();
}
requestID = len ? requestAnimFrame(frame) : false;
},
/*\
* mina
[ method ]
**
* Generic animation of numbers
**
- a (number) start _slave_ number
- A (number) end _slave_ number
- b (number) start _master_ number (start time in general case)
- B (number) end _master_ number (end time in general case)
- get (function) getter of _master_ number (see @mina.time)
- set (function) setter of _slave_ number
- easing (function) #optional easing function, default is @mina.linear
= (object) animation descriptor
o {
o id (string) animation id,
o start (number) start _slave_ number,
o end (number) end _slave_ number,
o b (number) start _master_ number,
o s (number) animation status (0..1),
o dur (number) animation duration,
o spd (number) animation speed,
o get (function) getter of _master_ number (see @mina.time),
o set (function) setter of _slave_ number,
o easing (function) easing function, default is @mina.linear,
o status (function) status getter/setter,
o speed (function) speed getter/setter,
o duration (function) duration getter/setter,
o stop (function) animation stopper
o pause (function) pauses the animation
o resume (function) resumes the animation
o update (function) calles setter with the right value of the animation
o }
\*/
mina = function (a, A, b, B, get, set, easing) {
var anim = {
id: ID(),
start: a,
end: A,
b: b,
s: 0,
dur: B - b,
spd: 1,
get: get,
set: set,
easing: easing || mina.linear,
status: sta,
speed: speed,
duration: duration,
stop: stopit,
pause: pause,
resume: resume,
update: update
};
animations[anim.id] = anim;
var len = 0, i;
for (i in animations) if (animations.hasOwnProperty(i)) {
len++;
if (len == 2) {
break;
}
}
len == 1 && frame();
return anim;
};
/*\
* mina.time
[ method ]
**
* Returns the current time. Equivalent to:
| function () {
| return (new Date).getTime();
| }
\*/
mina.time = timer;
/*\
* mina.getById
[ method ]
**
* Returns an animation by its id
- id (string) animation's id
= (object) See @mina
\*/
mina.getById = function (id) {
return animations[id] || null;
};
/*\
* mina.linear
[ method ]
**
* Default linear easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.linear = function (n) {
return n;
};
/*\
* mina.easeout
[ method ]
**
* Easeout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easeout = function (n) {
return Math.pow(n, 1.7);
};
/*\
* mina.easein
[ method ]
**
* Easein easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easein = function (n) {
return Math.pow(n, .48);
};
/*\
* mina.easeinout
[ method ]
**
* Easeinout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easeinout = function (n) {
if (n == 1) {
return 1;
}
if (n == 0) {
return 0;
}
var q = .48 - n / 1.04,
Q = Math.sqrt(.1734 + q * q),
x = Q - q,
X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1),
y = -Q - q,
Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1),
t = X + Y + .5;
return (1 - t) * 3 * t * t + t * t * t;
};
/*\
* mina.backin
[ method ]
**
* Backin easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.backin = function (n) {
if (n == 1) {
return 1;
}
var s = 1.70158;
return n * n * ((s + 1) * n - s);
};
/*\
* mina.backout
[ method ]
**
* Backout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.backout = function (n) {
if (n == 0) {
return 0;
}
n = n - 1;
var s = 1.70158;
return n * n * ((s + 1) * n + s) + 1;
};
/*\
* mina.elastic
[ method ]
**
* Elastic easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.elastic = function (n) {
if (n == !!n) {
return n;
}
return Math.pow(2, -10 * n) * Math.sin((n - .075) *
(2 * Math.PI) / .3) + 1;
};
/*\
* mina.bounce
[ method ]
**
* Bounce easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.bounce = function (n) {
var s = 7.5625,
p = 2.75,
l;
if (n < 1 / p) {
l = s * n * n;
} else {
if (n < 2 / p) {
n -= 1.5 / p;
l = s * n * n + .75;
} else {
if (n < 2.5 / p) {
n -= 2.25 / p;
l = s * n * n + .9375;
} else {
n -= 2.625 / p;
l = s * n * n + .984375;
}
}
}
return l;
};
window.mina = mina;
return mina;
})(typeof eve == "undefined" ? function () {} : eve);
// Copyright (c) 2013 - 2017 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.
var Snap = (function(root) {
Snap.version = "0.5.1";
/*\
* Snap
[ method ]
**
* Creates a drawing surface or wraps existing SVG element.
**
- width (number|string) width of surface
- height (number|string) height of surface
* or
- DOM (SVGElement) element to be wrapped into Snap structure
* or
- array (array) array of elements (will return set of elements)
* or
- query (string) CSS query selector
= (object) @Element
\*/
function Snap(w, h) {
if (w) {
if (w.nodeType) {
return wrap(w);
}
if (is(w, "array") && Snap.set) {
return Snap.set.apply(Snap, w);
}
if (w instanceof Element) {
return w;
}
if (h == null) {
try {
w = glob.doc.querySelector(String(w));
return wrap(w);
} catch (e) {
return null;
}
}
}
w = w == null ? "100%" : w;
h = h == null ? "100%" : h;
return new Paper(w, h);
}
Snap.toString = function () {
return "Snap v" + this.version;
};
Snap._ = {};
var glob = {
win: root.window,
doc: root.window.document
};
Snap._.glob = glob;
var has = "hasOwnProperty",
Str = String,
toFloat = parseFloat,
toInt = parseInt,
math = Math,
mmax = math.max,
mmin = math.min,
abs = math.abs,
pow = math.pow,
PI = math.PI,
round = math.round,
E = "",
S = " ",
objectToString = Object.prototype.toString,
ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,
bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
separator = Snap._.separator = /[,\s]+/,
whitespace = /[\s]/g,
commaSpaces = /[\s]*,[\s]*/,
hsrg = {hs: 1, rg: 1},
pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\s]*,?[\s]*/ig,
idgen = 0,
idprefix = "S" + (+new Date).toString(36),
ID = function (el) {
return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36);
},
xlink = "http://www.w3.org/1999/xlink",
xmlns = "http://www.w3.org/2000/svg",
hub = {},
/*\
* Snap.url
[ method ]
**
* Wraps path into `"url('<path>')"`.
- value (string) path
= (string) wrapped path
\*/
URL = Snap.url = function (url) {
return "url('#" + url + "')";
};
function $(el, attr) {
if (attr) {
if (el == "#text") {
el = glob.doc.createTextNode(attr.text || attr["#text"] || "");
}
if (el == "#comment") {
el = glob.doc.createComment(attr.text || attr["#text"] || "");
}
if (typeof el == "string") {
el = $(el);
}
if (typeof attr == "string") {
if (el.nodeType == 1) {
if (attr.substring(0, 6) == "xlink:") {
return el.getAttributeNS(xlink, attr.substring(6));
}
if (attr.substring(0, 4) == "xml:") {
return el.getAttributeNS(xmlns, attr.substring(4));
}
return el.getAttribute(attr);
} else if (attr == "text") {
return el.nodeValue;
} else {
return null;
}
}
if (el.nodeType == 1) {
for (var key in attr) if (attr[has](key)) {
var val = Str(attr[key]);
if (val) {
if (key.substring(0, 6) == "xlink:") {
el.setAttributeNS(xlink, key.substring(6), val);
} else if (key.substring(0, 4) == "xml:") {
el.setAttributeNS(xmlns, key.substring(4), val);
} else {
el.setAttribute(key, val);
}
} else {
el.removeAttribute(key);
}
}
} else if ("text" in attr) {
el.nodeValue = attr.text;
}
} else {
el = glob.doc.createElementNS(xmlns, el);
}
return el;
}
Snap._.$ = $;
Snap._.id = ID;
function getAttrs(el) {
var attrs = el.attributes,
name,
out = {};
for (var i = 0; i < attrs.length; i++) {
if (attrs[i].namespaceURI == xlink) {
name = "xlink:";
} else {
name = "";
}
name += attrs[i].name;
out[name] = attrs[i].textContent;
}
return out;
}
function is(o, type) {
type = Str.prototype.toLowerCase.call(type);
if (type == "finite") {
return isFinite(o);
}
if (type == "array" &&
(o instanceof Array || Array.isArray && Array.isArray(o))) {
return true;
}
return type == "null" && o === null ||
type == typeof o && o !== null ||
type == "object" && o === Object(o) ||
objectToString.call(o).slice(8, -1).toLowerCase() == type;
}
/*\
* Snap.format
[ method ]
**
* Replaces construction of type `{<name>}` to the corresponding argument
**
- token (string) string to format
- json (object) object which properties are used as a replacement
= (string) formatted string
> Usage
| // this draws a rectangular shape equivalent to "M10,20h40v50h-40z"
| paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
| x: 10,
| y: 20,
| dim: {
| width: 40,
| height: 50,
| "negative width": -40
| }
| }));
\*/
Snap.format = (function () {
var tokenRegex = /\{([^\}]+)\}/g,
objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
replacer = function (all, key, obj) {
var res = obj;
key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
name = name || quotedName;
if (res) {
if (name in res) {
res = res[name];
}
typeof res == "function" && isFunc && (res = res());
}
});
res = (res == null || res == obj ? all : res) + "";
return res;
};
return function (str, obj) {
return Str(str).replace(tokenRegex, function (all, key) {
return replacer(all, key, obj);
});
};
})();
function clone(obj) {
if (typeof obj == "function" || Object(obj) !== obj) {
return obj;
}
var res = new obj.constructor;
for (var key in obj) if (obj[has](key)) {
res[key] = clone(obj[key]);
}
return res;
}
Snap._.clone = clone;
function repush(array, item) {
for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
return array.push(array.splice(i, 1)[0]);
}
}
function cacher(f, scope, postprocessor) {
function newf() {
var arg = Array.prototype.slice.call(arguments, 0),
args = arg.join("\u2400"),
cache = newf.cache = newf.cache || {},
count = newf.count = newf.count || [];
if (cache[has](args)) {
repush(count, args);
return postprocessor ? postprocessor(cache[args]) : cache[args];
}
count.length >= 1e3 && delete cache[count.shift()];
count.push(args);
cache[args] = f.apply(scope, arg);
return postprocessor ? postprocessor(cache[args]) : cache[args];
}
return newf;
}
Snap._.cacher = cacher;
function angle(x1, y1, x2, y2, x3, y3) {
if (x3 == null) {
var x = x1 - x2,
y = y1 - y2;
if (!x && !y) {
return 0;
}
return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
} else {
return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3);
}
}
function rad(deg) {
return deg % 360 * PI / 180;
}
function deg(rad) {
return rad * 180 / PI % 360;
}
function x_y() {
return this.x + S + this.y;
}
function x_y_w_h() {
return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
}
/*\
* Snap.rad
[ method ]
**
* Transform angle to radians
- deg (number) angle in degrees
= (number) angle in radians
\*/
Snap.rad = rad;
/*\
* Snap.deg
[ method ]
**
* Transform angle to degrees
- rad (number) angle in radians
= (number) angle in degrees
\*/
Snap.deg = deg;
/*\
* Snap.sin
[ method ]
**
* Equivalent to `Math.sin()` only works with degrees, not radians.
- angle (number) angle in degrees
= (number) sin
\*/
Snap.sin = function (angle) {
return math.sin(Snap.rad(angle));
};
/*\
* Snap.tan
[ method ]
**
* Equivalent to `Math.tan()` only works with degrees, not radians.
- angle (number) angle in degrees
= (number) tan
\*/
Snap.tan = function (angle) {
return math.tan(Snap.rad(angle));
};
/*\
* Snap.cos
[ method ]
**
* Equivalent to `Math.cos()` only works with degrees, not radians.
- angle (number) angle in degrees
= (number) cos
\*/
Snap.cos = function (angle) {
return math.cos(Snap.rad(angle));
};
/*\
* Snap.asin
[ method ]
**
* Equivalent to `Math.asin()` only works with degrees, not radians.
- num (number) value
= (number) asin in degrees
\*/
Snap.asin = function (num) {
return Snap.deg(math.asin(num));
};
/*\
* Snap.acos
[ method ]
**
* Equivalent to `Math.acos()` only works with degrees, not radians.
- num (number) value
= (number) acos in degrees
\*/
Snap.acos = function (num) {
return Snap.deg(math.acos(num));
};
/*\
* Snap.atan
[ method ]
**
* Equivalent to `Math.atan()` only works with degrees, not radians.
- num (number) value
= (number) atan in degrees
\*/
Snap.atan = function (num) {
return Snap.deg(math.atan(num));
};
/*\
* Snap.atan2
[ method ]
**
* Equivalent to `Math.atan2()` only works with degrees, not radians.
- num (number) value
= (number) atan2 in degrees
\*/
Snap.atan2 = function (num) {
return Snap.deg(math.atan2(num));
};
/*\
* Snap.angle
[ method ]
**
* Returns an angle between two or three points
- x1 (number) x coord of first point
- y1 (number) y coord of first point
- x2 (number) x coord of second point
- y2 (number) y coord of second point
- x3 (number) #optional x coord of third point
- y3 (number) #optional y coord of third point
= (number) angle in degrees
\*/
Snap.angle = angle;
/*\
* Snap.len
[ method ]
**
* Returns distance between two points
- x1 (number) x coord of first point
- y1 (number) y coord of first point
- x2 (number) x coord of second point
- y2 (number) y coord of second point
= (number) distance
\*/
Snap.len = function (x1, y1, x2, y2) {
return Math.sqrt(Snap.len2(x1, y1, x2, y2));
};
/*\
* Snap.len2
[ method ]
**
* Returns squared distance between two points
- x1 (number) x coord of first point
- y1 (number) y coord of first point
- x2 (number) x coord of second point
- y2 (number) y coord of second point
= (number) distance
\*/
Snap.len2 = function (x1, y1, x2, y2) {
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
};
/*\
* Snap.closestPoint
[ method ]
**
* Returns closest point to a given one on a given path.
- path (Element) path element
- x (number) x coord of a point
- y (number) y coord of a point
= (object) in format
{
x (number) x coord of the point on the path
y (number) y coord of the point on the path
length (number) length of the path to the point
distance (number) distance from the given point to the path
}
\*/
// Copied from http://bl.ocks.org/mbostock/8027637
Snap.closestPoint = function (path, x, y) {
function distance2(p) {
var dx = p.x - x,
dy = p.y - y;
return dx * dx + dy * dy;
}
var pathNode = path.node,
pathLength = pathNode.getTotalLength(),
precision = pathLength / pathNode.pathSegList.numberOfItems * .125,
best,
bestLength,
bestDistance = Infinity;
// linear scan for coarse approximation
for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
best = scan;
bestLength = scanLength;
bestDistance = scanDistance;
}
}
// binary search for precise estimate
precision *= .5;
while (precision > .5) {
var before,
after,
beforeLength,
afterLength,
beforeDistance,
afterDistance;
if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
best = before;
bestLength = beforeLength;
bestDistance = beforeDistance;
} else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
best = after;
bestLength = afterLength;
bestDistance = afterDistance;
} else {
precision *= .5;
}
}
best = {
x: best.x,
y: best.y,
length: bestLength,
distance: Math.sqrt(bestDistance)
};
return best;
}
/*\
* Snap.is
[ method ]
**
* Handy replacement for the `typeof` operator
- o (…) any object or primitive
- type (string) name of the type, e.g., `string`, `function`, `number`, etc.
= (boolean) `true` if given value is of given type
\*/
Snap.is = is;
/*\
* Snap.snapTo
[ method ]
**
* Snaps given value to given grid
- values (array|number) given array of values or step of the grid
- value (number) value to adjust
- tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`.
= (number) adjusted value
\*/
Snap.snapTo = function (values, value, tolerance) {
tolerance = is(tolerance, "finite") ? tolerance : 10;
if (is(values, "array")) {
var i = values.length;
while (i--) if (abs(values[i] - value) <= tolerance) {
return values[i];
}
} else {
values = +values;
var rem = value % values;
if (rem < tolerance) {
return value - rem;
}
if (rem > values - tolerance) {
return value - rem + values;
}
}
return value;
};
// Colour
/*\
* Snap.getRGB
[ method ]
**
* Parses color string as RGB object
- color (string) color string in one of the following formats:
# <ul>
# <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li>
# <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li>
# <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li>
# <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li>
# <li>rgba(•••, •••, •••, •••) — also with opacity</li>
# <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li>
# <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li>
# <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li>
# <li>hsba(•••, •••, •••, •••) — also with opacity</li>
# <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
# <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li>
# <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li>
# <li>hsla(•••, •••, •••, •••) — also with opacity</li>
# <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
# <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li>
# </ul>
* Note that `%` can be used any time: `rgb(20%, 255, 50%)`.
= (object) RGB object in the following format:
o {
o r (number) red,
o g (number) green,
o b (number) blue,
o hex (string) color in HTML/CSS format: #••••••,
o error (boolean) true if string can't be parsed
o }
\*/
Snap.getRGB = cacher(function (colour) {
if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
}
if (colour == "none") {
return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString};
}
!(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
if (!colour) {
return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
}
var res,
red,
green,
blue,
opacity,
t,
values,
rgb = colour.match(colourRegExp);
if (rgb) {
if (rgb[2]) {
blue = toInt(rgb[2].substring(5), 16);
green = toInt(rgb[2].substring(3, 5), 16);
red = toInt(rgb[2].substring(1, 3), 16);
}
if (rgb[3]) {
blue = toInt((t = rgb[3].charAt(3)) + t, 16);
green = toInt((t = rgb[3].charAt(2)) + t, 16);
red = toInt((t = rgb[3].charAt(1)) + t, 16);
}
if (rgb[4]) {
values = rgb[4].split(commaSpaces);
red = toFloat(values[0]);
values[0].slice(-1) == "%" && (red *= 2.55);
green = toFloat(values[1]);
values[1].slice(-1) == "%" && (green *= 2.55);
blue = toFloat(values[2]);
values[2].slice(-1) == "%" && (blue *= 2.55);
rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
}
if (rgb[5]) {
values = rgb[5].split(commaSpaces);
red = toFloat(values[0]);
values[0].slice(-1) == "%" && (red /= 100);
green = toFloat(values[1]);
values[1].slice(-1) == "%" && (green /= 100);
blue = toFloat(values[2]);
values[2].slice(-1) == "%" && (blue /= 100);
(values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
return Snap.hsb2rgb(red, green, blue, opacity);
}
if (rgb[6]) {
values = rgb[6].split(commaSpaces);
red = toFloat(values[0]);
values[0].slice(-1) == "%" && (red /= 100);
green = toFloat(values[1]);
values[1].slice(-1) == "%" && (green /= 100);
blue = toFloat(values[2]);
values[2].slice(-1) == "%" && (blue /= 100);
(values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
return Snap.hsl2rgb(red, green, blue, opacity);
}
red = mmin(math.round(red), 255);
green = mmin(math.round(green), 255);
blue = mmin(math.round(blue), 255);
opacity = mmin(mmax(opacity, 0), 1);
rgb = {r: red, g: green, b: blue, toString: rgbtoString};
rgb.hex = "#" + (16777216 | blue | green << 8 | red << 16).toString(16).slice(1);
rgb.opacity = is(opacity, "finite") ? opacity : 1;
return rgb;
}
return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
}, Snap);
/*\
* Snap.hsb
[ method ]
**
* Converts HSB values to a hex representation of the color
- h (number) hue
- s (number) saturation
- b (number) value or brightness
= (string) hex representation of the color
\*/
Snap.hsb = cacher(function (h, s, b) {
return Snap.hsb2rgb(h, s, b).hex;
});
/*\
* Snap.hsl
[ method ]
**
* Converts HSL values to a hex representation of the color
- h (number) hue
- s (number) saturation
- l (number) luminosity
= (string) hex representation of the color
\*/
Snap.hsl = cacher(function (h, s, l) {
return Snap.hsl2rgb(h, s, l).hex;
});
/*\
* Snap.rgb
[ method ]
**
* Converts RGB values to a hex representation of the color
- r (number) red
- g (number) green
- b (number) blue
= (string) hex representation of the color
\*/
Snap.rgb = cacher(function (r, g, b, o) {
if (is(o, "finite")) {
var round = math.round;
return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")";
}
return "#" + (16777216 | b | g << 8 | r << 16).toString(16).slice(1);
});
var toHex = function (color) {
var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0],
red = "rgb(255, 0, 0)";
toHex = cacher(function (color) {
if (color.toLowerCase() == "red") {
return red;
}
i.style.color = red;
i.style.color = color;
var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
return out == red ? null : out;
});
return toHex(color);
},
hsbtoString = function () {
return "hsb(" + [this.h, this.s, this.b] + ")";
},
hsltoString = function () {
return "hsl(" + [this.h, this.s, this.l] + ")";
},
rgbtoString = function () {
return this.opacity == 1 || this.opacity == null ?
this.hex :
"rgba(" + [this.r, this.g, this.b, this.opacity] + ")";
},
prepareRGB = function (r, g, b) {
if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) {
b = r.b;
g = r.g;
r = r.r;
}
if (g == null && is(r, string)) {
var clr = Snap.getRGB(r);
r = clr.r;
g = clr.g;
b = clr.b;
}
if (r > 1 || g > 1 || b > 1) {
r /= 255;
g /= 255;
b /= 255;
}
return [r, g, b];
},
packageRGB = function (r, g, b, o) {
r = math.round(r * 255);
g = math.round(g * 255);
b = math.round(b * 255);
var rgb = {
r: r,
g: g,
b: b,
opacity: is(o, "finite") ? o : 1,
hex: Snap.rgb(r, g, b),
toString: rgbtoString
};
is(o, "finite") && (rgb.opacity = o);
return rgb;
};
/*\
* Snap.color
[ method ]
**
* Parses the color string and returns an object featuring the color's component values
- clr (string) color string in one of the supported formats (see @Snap.getRGB)
= (object) Combined RGB/HSB object in the following format:
o {
o r (number) red,
o g (number) green,
o b (number) blue,
o hex (string) color in HTML/CSS format: #••••••,
o error (boolean) `true` if string can't be parsed,
o h (number) hue,
o s (number) saturation,
o v (number) value (brightness),
o l (number) lightness
o }
\*/
Snap.color = function (clr) {
var rgb;
if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
rgb = Snap.hsb2rgb(clr);
clr.r = rgb.r;
clr.g = rgb.g;
clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex;
} else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
rgb = Snap.hsl2rgb(clr);
clr.r = rgb.r;
clr.g = rgb.g;
clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex;
} else {
if (is(clr, "string")) {
clr = Snap.getRGB(clr);
}
if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) {
rgb = Snap.rgb2hsl(clr);
clr.h = rgb.h;
clr.s = rgb.s;
clr.l = rgb.l;
rgb = Snap.rgb2hsb(clr);
clr.v = rgb.b;
} else {
clr = {hex: "none"};
clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
clr.error = 1;
}
}
clr.toString = rgbtoString;
return clr;
};
/*\
* Snap.hsb2rgb
[ method ]
**
* Converts HSB values to an RGB object
- h (number) hue
- s (number) saturation
- v (number) value or brightness
= (object) RGB object in the following format:
o {
o r (number) red,
o g (number) green,
o b (number) blue,
o hex (string) color in HTML/CSS format: #••••••
o }
\*/
Snap.hsb2rgb = function (h, s, v, o) {
if (is(h, "object") && "h" in h && "s" in h && "b" in h) {
v = h.b;
s = h.s;
o = h.o;
h = h.h;
}
h *= 360;
var R, G, B, X, C;
h = h % 360 / 60;
C = v * s;
X = C * (1 - abs(h % 2 - 1));
R = G = B = v - C;
h = ~~h;
R += [C, X, 0, 0, X, C][h];
G += [X, C, C, X, 0, 0][h];
B += [0, 0, X, C, C, X][h];
return packageRGB(R, G, B, o);
};
/*\
* Snap.hsl2rgb
[ method ]
**
* Converts HSL values to an RGB object
- h (number) hue
- s (number) saturation
- l (number) luminosity
= (object) RGB object in the following format:
o {
o r (number) red,
o g (number) green,
o b (number) blue,
o hex (string) color in HTML/CSS format: #••••••
o }
\*/
Snap.hsl2rgb = function (h, s, l, o) {
if (is(h, "object") && "h" in h && "s" in h && "l" in h) {
l = h.l;
s = h.s;
h = h.h;
}
if (h > 1 || s > 1 || l > 1) {
h /= 360;
s /= 100;
l /= 100;
}
h *= 360;
var R, G, B, X, C;
h = h % 360 / 60;
C = 2 * s * (l < .5 ? l : 1 - l);
X = C * (1 - abs(h % 2 - 1));
R = G = B = l - C / 2;
h = ~~h;
R += [C, X, 0, 0, X, C][h];
G += [X, C, C, X, 0, 0][h];
B += [0, 0, X, C, C, X][h];
return packageRGB(R, G, B, o);
};
/*\
* Snap.rgb2hsb
[ method ]
**
* Converts RGB values to an HSB object
- r (number) red
- g (number) green
- b (number) blue
= (object) HSB object in the following format:
o {
o h (number) hue,
o s (number) saturation,
o b (number) brightness
o }
\*/
Snap.rgb2hsb = function (r, g, b) {
b = prepareRGB(r, g, b);
r = b[0];
g = b[1];
b = b[2];
var H, S, V, C;
V = mmax(r, g, b);
C = V - mmin(r, g, b);
H = C == 0 ? null :
V == r ? (g - b) / C :
V == g ? (b - r) / C + 2 :
(r - g) / C + 4;
H = (H + 360) % 6 * 60 / 360;
S = C == 0 ? 0 : C / V;
return {h: H, s: S, b: V, toString: hsbtoString};
};
/*\
* Snap.rgb2hsl
[ method ]
**
* Converts RGB values to an HSL object
- r (number) red
- g (number) green
- b (number) blue
= (object) HSL object in the following format:
o {
o h (number) hue,
o s (number) saturation,
o l (number) luminosity
o }
\*/
Snap.rgb2hsl = function (r, g, b) {
b = prepareRGB(r, g, b);
r = b[0];
g = b[1];
b = b[2];
var H, S, L, M, m, C;
M = mmax(r, g, b);
m = mmin(r, g, b);
C = M - m;
H = C == 0 ? null :
M == r ? (g - b) / C :
M == g ? (b - r) / C + 2 :
(r - g) / C + 4;
H = (H + 360) % 6 * 60 / 360;
L = (M + m) / 2;
S = C == 0 ? 0 :
L < .5 ? C / (2 * L) :
C / (2 - 2 * L);
return {h: H, s: S, l: L, toString: hsltoString};
};
// Transformations
/*\
* Snap.parsePathString
[ method ]
**
* Utility method
**
* Parses given path string into an array of arrays of path segments
- pathString (string|array) path string or array of segments (in the last case it is returned straight away)
= (array) array of segments
\*/
Snap.parsePathString = function (pathString) {
if (!pathString) {
return null;
}
var pth = Snap.path(pathString);
if (pth.arr) {
return Snap.path.clone(pth.arr);
}
var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
data = [];
if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption
data = Snap.path.clone(pathString);
}
if (!data.length) {
Str(pathString).replace(pathCommand, function (a, b, c) {
var params = [],
name = b.toLowerCase();
c.replace(pathValues, function (a, b) {
b && params.push(+b);
});
if (name == "m" && params.length > 2) {
data.push([b].concat(params.splice(0, 2)));
name = "l";
b = b == "m" ? "l" : "L";
}
if (name == "o" && params.length == 1) {
data.push([b, params[0]]);
}
if (name == "r") {
data.push([b].concat(params));
} else while (params.length >= paramCounts[name]) {
data.push([b].concat(params.splice(0, paramCounts[name])));
if (!paramCounts[name]) {
break;
}
}
});
}
data.toString = Snap.path.toString;
pth.arr = Snap.path.clone(data);
return data;
};
/*\
* Snap.parseTransformString
[ method ]
**
* Utility method
**
* Parses given transform string into an array of transformations
- TString (string|array) transform string or array of transformations (in the last case it is returned straight away)
= (array) array of transformations
\*/
var parseTransformString = Snap.parseTransformString = function (TString) {
if (!TString) {
return null;
}
var paramCounts = {r: 3, s: 4, t: 2, m: 6},
data = [];
if (is(TString, "array") && is(TString[0], "array")) { // rough assumption
data = Snap.path.clone(TString);
}
if (!data.length) {
Str(TString).replace(tCommand, function (a, b, c) {
var params = [],
name = b.toLowerCase();
c.replace(pathValues, function (a, b) {
b && params.push(+b);
});
data.push([b].concat(params));
});
}
data.toString = Snap.path.toString;
return data;
};
function svgTransform2string(tstr) {
var res = [];
tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) {
params = params.split(/\s*,\s*|\s+/);
if (name == "rotate" && params.length == 1) {
params.push(0, 0);
}
if (name == "scale") {
if (params.length > 2) {
params = params.slice(0, 2);
} else if (params.length == 2) {
params.push(0, 0);
}
if (params.length == 1) {
params.push(params[0], 0, 0);
}
}
if (name == "skewX") {
res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]);
} else if (name == "skewY") {
res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]);
} else {
res.push([name.charAt(0)].concat(params));
}
return all;
});
return res;
}
Snap._.svgTransform2string = svgTransform2string;
Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i;
function transform2matrix(tstr, bbox) {
var tdata = parseTransformString(tstr),
m = new Snap.Matrix;
if (tdata) {
for (var i = 0, ii = tdata.length; i < ii; i++) {
var t = tdata[i],
tlen = t.length,
command = Str(t[0]).toLowerCase(),
absolute = t[0] != command,
inver = absolute ? m.invert() : 0,
x1,
y1,
x2,
y2,
bb;
if (command == "t" && tlen == 2){
m.translate(t[1], 0);
} else if (command == "t" && tlen == 3) {
if (absolute) {
x1 = inver.x(0, 0);
y1 = inver.y(0, 0);
x2 = inver.x(t[1], t[2]);
y2 = inver.y(t[1], t[2]);
m.translate(x2 - x1, y2 - y1);
} else {
m.translate(t[1], t[2]);
}
} else if (command == "r") {
if (tlen == 2) {
bb = bb || bbox;
m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
} else if (tlen == 4) {
if (absolute) {
x2 = inver.x(t[2], t[3]);
y2 = inver.y(t[2], t[3]);
m.rotate(t[1], x2, y2);
} else {
m.rotate(t[1], t[2], t[3]);
}
}
} else if (command == "s") {
if (tlen == 2 || tlen == 3) {
bb = bb || bbox;
m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
} else if (tlen == 4) {
if (absolute) {
x2 = inver.x(t[2], t[3]);
y2 = inver.y(t[2], t[3]);
m.scale(t[1], t[1], x2, y2);
} else {
m.scale(t[1], t[1], t[2], t[3]);
}
} else if (tlen == 5) {
if (absolute) {
x2 = inver.x(t[3], t[4]);
y2 = inver.y(t[3], t[4]);
m.scale(t[1], t[2], x2, y2);
} else {
m.scale(t[1], t[2], t[3], t[4]);
}
}
} else if (command == "m" && tlen == 7) {
m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
}
}
}
return m;
}
Snap._.transform2matrix = transform2matrix;
Snap._unit2px = unit2px;
var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
function (a, b) {
var adown = a.nodeType == 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a == bup || !!(bup && bup.nodeType == 1 && (
adown.contains ?
adown.contains(bup) :
a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
));
} :
function (a, b) {
if (b) {
while (b) {
b = b.parentNode;
if (b == a) {
return true;
}
}
}
return false;
};
function getSomeDefs(el) {
var p = el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) ||
el.node.parentNode && wrap(el.node.parentNode) ||
Snap.select("svg") ||
Snap(0, 0),
pdefs = p.select("defs"),
defs = pdefs == null ? false : pdefs.node;
if (!defs) {
defs = make("defs", p.node).node;
}
return defs;
}
function getSomeSVG(el) {
return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg");
}
Snap._.getSomeDefs = getSomeDefs;
Snap._.getSomeSVG = getSomeSVG;
function unit2px(el, name, value) {
var svg = getSomeSVG(el).node,
out = {},
mgr = svg.querySelector(".svg---mgr");
if (!mgr) {
mgr = $("rect");
$(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"});
svg.appendChild(mgr);
}
function getW(val) {
if (val == null) {
return E;
}
if (val == +val) {
return val;
}
$(mgr, {width: val});
try {
return mgr.getBBox().width;
} catch (e) {
return 0;
}
}
function getH(val) {
if (val == null) {
return E;
}
if (val == +val) {
return val;
}
$(mgr, {height: val});
try {
return mgr.getBBox().height;
} catch (e) {
return 0;
}
}
function set(nam, f) {
if (name == null) {
out[nam] = f(el.attr(nam) || 0);
} else if (nam == name) {
out = f(value == null ? el.attr(nam) || 0 : value);
}
}
switch (el.type) {
case "rect":
set("rx", getW);
set("ry", getH);
case "image":
set("width", getW);
set("height", getH);
case "text":
set("x", getW);
set("y", getH);
break;
case "circle":
set("cx", getW);
set("cy", getH);
set("r", getW);
break;
case "ellipse":
set("cx", getW);
set("cy", getH);
set("rx", getW);
set("ry", getH);
break;
case "line":
set("x1", getW);
set("x2", getW);
set("y1", getH);
set("y2", getH);
break;
case "mar