Merge branch 'dev'

master
Dmitry Baranovskiy 2014-06-03 19:28:07 +10:00
commit 064ad5b081
39 changed files with 7686 additions and 4200 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ TAGS
*~
_*
.DS_Store
node_modules
playground

View File

@ -31,12 +31,16 @@ module.exports = function(grunt) {
"./src/amd-banner.js",
"./src/mina.js",
"./src/svg.js",
"./src/matrix.js",
"./src/attr.js",
"./src/attradd.js",
"./src/paper.js",
"./src/path.js",
"./src/set.js",
"./src/equal.js",
"./src/mouse.js",
"./src/filter.js",
"./src/amd-footer.js",
"./src/amd-footer.js"
]
}
},

View File

@ -1,6 +1,6 @@
{
"name": "Snap.svg",
"version": "0.1.1",
"version": "0.3.0",
"homepage": "http://snapsvg.io",
"authors": [
"Dmitry Baranovskiy <dmitry@baranovskiy.com>"

View File

@ -2,7 +2,7 @@
"name": "Snap.svg",
"repo": "adobe-webplatform/Snap.svg",
"description": "The JavaScript library for modern SVG graphics.",
"version": "0.1.1",
"version": "0.3.0",
"keywords": ["svg", "snap", "js", "javascript"],
"dependencies": {},
"development": {},

View File

@ -81,7 +81,7 @@
display: "none"
});
var flag,
len = pth.getTotalLength();
len = Snap.path.getTotalLength(pth.attr("d"));
Snap.animate(0, len, function (l) {
// Safari bug workaround: forcing redraw
g.attr({width: 100 + (flag = !flag ? 1e-5 : 0) + "%"});

80
demos/clock/index.html Normal file
View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="copyright" content="Copyright © 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.">
<title>Snap</title>
<style media="screen">
body {
background: #fff;
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script>
window.onload = function () {
var s = Snap(600, 600);
var path = "",
nums = s.text(300, 300, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]).attr({
font: "300 40px Helvetica Neue",
textAnchor: "middle"
});
for (var i = 0; i < 72; i++) {
var r = i % 6 ? i % 3 ? 247 : 240 : 230,
sin = Math.sin(Snap.rad(5 * i)),
cos = Math.cos(Snap.rad(5 * i));
path += "M" + [300 + 250 * cos, 300 + 250 * sin] + "L" + [300 + r * cos, 300 + r * sin];
if (!(i % 6)) {
nums.select("tspan:nth-child(" + (i / 6 + 1) + ")").attr({
x: 300 + 200 * Math.cos(Snap.rad(5 * i - 60)),
y: 300 + 200 * Math.sin(Snap.rad(5 * i - 60)) + 15,
});
}
}
var table = s.g(nums, s.path(path).attr({
fill: "none",
stroke: "#000",
strokeWidth: 2
})).attr({
transform: "t0,210"
});
s.g(table).attr({
clip: s.circle(300, 300, 100)
});
var hand = s.line(300, 200, 300, 400).attr({
fill: "none",
stroke: "#f63",
strokeWidth: 2
});
s.circle(300, 300, 100).attr({
stroke: "#000",
strokeWidth: 10,
fillOpacity: 0
}).click(function () {
Snap.animate(0, 360, function (val) {
table.transform("t" +
[
210 * Math.cos(Snap.rad(val + 90)),
210 * Math.sin(Snap.rad(val + 90))
]);
hand.transform("r" + [val, 300, 300]);
}, 12000);
});
};
</script>
</head>
<body>
</body>
</html>

180
demos/tutorial/1.html Normal file
View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tutorial</title>
<link rel="stylesheet" href="../../doc/fonts/stylesheet.css">
<link rel="stylesheet" href="../../doc/css/prism.css">
<style media="screen">
pre.code {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 10px;
height: 280px;
overflow: auto;
background: #181818;
border: solid 2px #181818;
}
#codelines {
display: none;
}
#svg {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
border: solid 2px #ccc;
width: 300px;
height: 300px;
float: left;
margin-right: 10px;
font: 1em source-sans-pro, Source Sans Pro, Helvetica, sans-serif;
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script src="../../doc/js/prism.js"></script>
<script>
var S;
window.onload = function () {
var s = Snap(850, 35);
function chooser(s, count) {
var loop = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60",
line = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60c30,0,60-60,90-60a30,30,0,0,1,0,60a30,30,0,0,1,0-60",
l1 = Snap.path.getTotalLength(loop),
l2 = Snap.path.getTotalLength(line),
cur = 1,
p = s.path({
path: loop,
fill: "none",
stroke: "#f00",
strokeWidth: 6,
strokeLinecap: "round"
});
for (var i = 1; i <= count; i++) {
s.text(90 * i - 55, 49, i).attr({
font: "45px source-sans-pro, Source Sans Pro, Helvetica, sans-serif",
textAnchor: "middle"
});
(function (i) {
s.circle(90 * i - 55, 35, 40).attr({
opacity: 0
}).click(eve.f("tut.click", i - 1));
}(i));
}
s.path("M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z").transform("t" + (90 * (count + 1) - 68) + ",18s2");
var but = s.circle(90 * (count + 1) - 55, 35, 30).attr({
fillOpacity: 0,
stroke: "#333",
strokeWidth: 2
});
eve.on("tut.click", function (I) {
p.attr({
path: loop,
transform: "t" + (90 * I) + ",0"
});
cur = I + 1;
});
function frameHandler(frame) {
function anim() {
cur++;
if (cur > count) {
return;
}
if (typeof frame == "function") {
frame(cur);
}
Snap.animate(0, l2 - l1, function (val) {
p.attr({
path: Snap.path.getSubpath(line, val, val + l1)
});
}, 500, function () {
p.attr({
path: loop,
transform: p.transform() + "t90,0"
});
});
}
if (typeof frame == "function") {
but.click(anim);
} else {
anim();
}
}
return frameHandler;
}
var g = s.g();
g.attr({
transform: "s.5,.5,0,0"
});
var str = "",
code = document.getElementById("code");
var domcodelines = document.querySelectorAll("#codelines li"),
codelines = [],
replacers = {},
lines = [],
callback = function (i) {
lines = [];
for (var j = 1; j <= i; j++) {
replacers[j - 1] && lines.pop();
lines.push(codelines[j - 1]);
}
Snap("#svg").clear();
str = lines.join("\n");
eval(str);
code.innerHTML = Prism.highlight(str, Prism.languages.javascript);
code.parentNode.scrollTop = code.parentNode.scrollTopMax || 1e9;
};
for (var i = 0, ii = domcodelines.length; i < ii; i++) {
codelines[i] = domcodelines[i].innerHTML;
if (domcodelines[i].className == "replace") {
replacers[i] = true;
}
}
callback(1);
chooser(g, codelines.length)(callback);
eve.on("tut.click", function (I) {
callback(I + 1);
});
};
</script>
</head>
<body>
<ol id="codelines">
<li>// Simple dashed pattern on circle
var s = Snap("#svg");</li>
<li>// This will be our shape. It could be anything.
var bigCircle = s.circle(150, 150, 100);</li>
<li>bigCircle.attr({
stroke: "#000",
strokeWidth: 5
});</li>
<li>// Now let's create pattern
var p = s.path("M110,95,95,110M115,100,100,115").attr({
fill: "none",
stroke: "#bada55",
strokeWidth: 4
});
</li>
<li>//This is where our pattern cut will happen:
var cut = s.rect(100, 100, 10, 10).attr({fill: "#fff", opacity: .5})</li>
<li>cut.remove();</li>
<li>//make it a pattern
var ptrn = p.pattern(100, 100, 10, 10);
//ptrn is an invisible &lt;pattern> element.</li>
<li>// Then use it as a fill on the big circle
bigCircle.attr({
fill: ptrn
});</li>
<li>//We still have access to original path for the pattern, lets animate it a bit:</li>
<li>p.animate({strokeWidth: 1, stroke: "#FF4136"}, 1e3);
//Note that pattern could have as many elements as you want</li>
</ol>
<svg id="svg"></svg>
<pre class="javascript code"><code data-language="javascript" class="language-javascript" id="code"></code></pre>
<svg width="0" height="0">
<pattern id="pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10" viewBox="0 0 10 10">
<path d="M-5,0,10,15M0-5,15,10" stroke="white" stroke-width="5"/>
</pattern>
</svg>
</body>
</html>

194
demos/tutorial/2.html Normal file
View File

@ -0,0 +1,194 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tutorial</title>
<link rel="stylesheet" href="../../doc/fonts/stylesheet.css">
<link rel="stylesheet" href="../../doc/css/prism.css">
<style media="screen">
pre.code {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 10px;
height: 280px;
overflow: auto;
background: #181818;
border: solid 2px #181818;
}
#codelines {
display: none;
}
#svg {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
border: solid 2px #ccc;
width: 300px;
height: 300px;
float: left;
margin-right: 10px;
font: 1em source-sans-pro, Source Sans Pro, Helvetica, sans-serif;
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script src="../../doc/js/prism.js"></script>
<script>
var S;
window.onload = function () {
var s = Snap(850, 35);
function chooser(s, count) {
var loop = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60",
line = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60c30,0,60-60,90-60a30,30,0,0,1,0,60a30,30,0,0,1,0-60",
l1 = Snap.path.getTotalLength(loop),
l2 = Snap.path.getTotalLength(line),
cur = 1,
p = s.path({
path: loop,
fill: "none",
stroke: "#f00",
strokeWidth: 6,
strokeLinecap: "round"
});
for (var i = 1; i <= count; i++) {
s.text(90 * i - 55, 49, i).attr({
font: "45px source-sans-pro, Source Sans Pro, Helvetica, sans-serif",
textAnchor: "middle"
});
(function (i) {
s.circle(90 * i - 55, 35, 40).attr({
opacity: 0
}).click(eve.f("tut.click", i - 1));
}(i));
}
s.path("M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z").transform("t" + (90 * (count + 1) - 68) + ",18s2");
var but = s.circle(90 * (count + 1) - 55, 35, 30).attr({
fillOpacity: 0,
stroke: "#333",
strokeWidth: 2
});
eve.on("tut.click", function (I) {
p.attr({
path: loop,
transform: "t" + (90 * I) + ",0"
});
cur = I + 1;
});
function frameHandler(frame) {
function anim() {
cur++;
if (cur > count) {
return;
}
if (typeof frame == "function") {
frame(cur);
}
Snap.animate(0, l2 - l1, function (val) {
p.attr({
path: Snap.path.getSubpath(line, val, val + l1)
});
}, 500, function () {
p.attr({
path: loop,
transform: p.transform() + "t90,0"
});
});
}
if (typeof frame == "function") {
but.click(anim);
} else {
anim();
}
}
return frameHandler;
}
var g = s.g();
g.attr({
transform: "s.5,.5,0,0"
});
var str = "",
code = document.getElementById("code");
var domcodelines = document.querySelectorAll("#codelines li"),
codelines = [],
replacers = {},
lines = [],
callback = function (i) {
lines = [];
for (var j = 1; j <= i; j++) {
replacers[j - 1] && lines.pop();
lines.push(codelines[j - 1]);
}
Snap("#svg").clear();
str = lines.join("\n");
eval(str);
code.innerHTML = Prism.highlight(str, Prism.languages.javascript);
code.parentNode.scrollTop = code.parentNode.scrollTopMax || 1e9;
};
for (var i = 0, ii = domcodelines.length; i < ii; i++) {
codelines[i] = domcodelines[i].innerHTML;
if (domcodelines[i].className == "replace") {
replacers[i] = true;
}
}
callback(1);
chooser(g, codelines.length)(callback);
eve.on("tut.click", function (I) {
callback(I + 1);
});
};
</script>
</head>
<body>
<ol id="codelines">
<li>// Simple dashed pattern on circle with mask
var s = Snap("#svg");
var bigCircle = s.circle(150, 150, 100).attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 6
});
var p = s.path("M110,95,95,110M115,100,100,115").attr({
fill: "none",
stroke: "#bada55",
strokeWidth: 4
});
var ptrn = p.pattern(100, 100, 10, 10);
bigCircle.attr({
fill: ptrn
});
//Here is our circle from the first Snap-bit.
</li>
<li>//Lets create a masking circle</li>
<li>var ring = s.circle(150, 150, 92).attr({
fill: "none",
stroke: "#fff",
strokeWidth: 10
});</li>
<li>//This looks correct, but only because our background is white</li>
<li>s.rect(0, 150, 300, 30).attr({fill: "#85144B"}).insertBefore(bigCircle);
//Uh-oh, lets try to apply this ring as a mask:</li>
<li>bigCircle.attr({
mask: ring
});</li>
<li>//Not exactly what we want. We need to invert the mask</li>
<li>var mask = s.mask();</li>
<li>// Background rect:
mask.add(s.rect(0, 0, "100%", "100%").attr({fill: "#fff"}));</li>
<li>// and our ring, but black
mask.add(ring.attr({stroke: "#000"}));</li>
<li>bigCircle.attr({
mask: mask
});</li>
<li>//Now, lets animate the ring:</li>
<li>ring.animate({r: 10}, 1e3);</li>
</ol>
<svg id="svg"></svg>
<pre class="javascript code"><code data-language="javascript" class="language-javascript" id="code"></code></pre>
<svg width="0" height="0">
<pattern id="pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10" viewBox="0 0 10 10">
<path d="M-5,0,10,15M0-5,15,10" stroke="white" stroke-width="5"/>
</pattern>
</svg>
</body>
</html>

202
demos/tutorial/3.html Normal file
View File

@ -0,0 +1,202 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tutorial</title>
<link rel="stylesheet" href="../../doc/fonts/stylesheet.css">
<link rel="stylesheet" href="../../doc/css/prism.css">
<style media="screen">
pre.code {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 10px;
height: 280px;
overflow: auto;
background: #181818;
border: solid 2px #181818;
}
#codelines {
display: none;
}
#svg {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
border: solid 2px #ccc;
width: 300px;
height: 300px;
float: left;
margin-right: 10px;
font: 1em source-sans-pro, Source Sans Pro, Helvetica, sans-serif;
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script src="../../doc/js/prism.js"></script>
<script>
var S;
window.onload = function () {
var s = Snap(850, 35);
function chooser(s, count) {
var loop = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60",
line = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60c30,0,60-60,90-60a30,30,0,0,1,0,60a30,30,0,0,1,0-60",
l1 = Snap.path.getTotalLength(loop),
l2 = Snap.path.getTotalLength(line),
cur = 1,
p = s.path({
path: loop,
fill: "none",
stroke: "#f00",
strokeWidth: 6,
strokeLinecap: "round"
});
for (var i = 1; i <= count; i++) {
s.text(90 * i - 55, 49, i).attr({
font: "45px source-sans-pro, Source Sans Pro, Helvetica, sans-serif",
textAnchor: "middle"
});
(function (i) {
s.circle(90 * i - 55, 35, 40).attr({
opacity: 0
}).click(eve.f("tut.click", i - 1));
}(i));
}
s.path("M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z").transform("t" + (90 * (count + 1) - 68) + ",18s2");
var but = s.circle(90 * (count + 1) - 55, 35, 30).attr({
fillOpacity: 0,
stroke: "#333",
strokeWidth: 2
});
eve.on("tut.click", function (I) {
p.attr({
path: loop,
transform: "t" + (90 * I) + ",0"
});
cur = I + 1;
});
function frameHandler(frame) {
function anim() {
cur++;
if (cur > count) {
return;
}
if (typeof frame == "function") {
frame(cur);
}
Snap.animate(0, l2 - l1, function (val) {
p.attr({
path: Snap.path.getSubpath(line, val, val + l1)
});
}, 500, function () {
p.attr({
path: loop,
transform: p.transform() + "t90,0"
});
});
}
if (typeof frame == "function") {
but.click(anim);
} else {
anim();
}
}
return frameHandler;
}
var g = s.g();
g.attr({
transform: "s.5,.5,0,0"
});
var str = "",
code = document.getElementById("code");
var domcodelines = document.querySelectorAll("#codelines li"),
codelines = [],
replacers = {},
lines = [],
callback = function (i) {
lines = [];
for (var j = 1; j <= i; j++) {
replacers[j - 1] && lines.pop();
lines.push(codelines[j - 1]);
}
Snap("#svg").clear();
str = lines.join("\n");
eval(str);
code.innerHTML = Prism.highlight(str, Prism.languages.javascript);
code.parentNode.scrollTop = code.parentNode.scrollTopMax || 1e9;
};
for (var i = 0, ii = domcodelines.length; i < ii; i++) {
codelines[i] = domcodelines[i].innerHTML;
if (domcodelines[i].className == "replace") {
replacers[i] = true;
}
}
callback(1);
chooser(g, codelines.length)(callback);
eve.on("tut.click", function (I) {
callback(I + 1);
});
};
</script>
</head>
<body>
<ol id="codelines">
<li>// Simple dashed pattern on circle with mask
// Lets connect mask and circle together. Also useful if we have a path
// and cant calculate offset easily.
var s = Snap("#svg");
// So, lets start with an empty circle.
// Its important that it will not have any attributes set
var bigCircle = s.circle(150, 150, 100);</li>
<li>//-----------------------------------------------------
// Lets use it again for patterned fill
var c1 = bigCircle.use();
// Create pattern
var p = s.path("M110,95,95,110M115,100,100,115").attr({
fill: "none",
stroke: "#bada55",
strokeWidth: 4
});
var ptrn = p.pattern(100, 100, 10, 10);
// and apply some nice attributes
c1.attr({
fill: ptrn
});</li>
<li>//-----------------------------------------------------
// Lets use it for stroke
var c2 = bigCircle.use();
c2.attr({
fill: "none",
stroke: "#000",
strokeWidth: 6
});</li>
<li>// Lets create a masking circle</li>
<li>var ring = bigCircle.use();
ring.attr({
fill: "none",
stroke: "#000",
strokeWidth: 20 // we need only inner 10px of it
});</li>
<li>// Hide bigCircle by moving it to &lt;defs>
bigCircle.toDefs();</li>
<li>var mask = s.mask();</li>
<li>// Background rect:
mask.add(s.rect(0, 0, "100%", "100%").attr({fill: "#fff"}));</li>
<li>// and our ring
mask.add(ring);</li>
<li>c1.attr({
mask: mask
});</li>
<li>//Now, lets animate bigCircle:</li>
<li>bigCircle.animate({r: 50}, 5e3, mina.elastic);
// Despite bigCircle is not visible it affect all 3 “uses” of it.</li>
</ol>
<svg id="svg"></svg>
<pre class="javascript code"><code data-language="javascript" class="language-javascript" id="code"></code></pre>
<svg width="0" height="0">
<pattern id="pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10" viewBox="0 0 10 10">
<path d="M-5,0,10,15M0-5,15,10" stroke="white" stroke-width="5"/>
</pattern>
</svg>
</body>
</html>

180
demos/tutorial/4.html Normal file
View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tutorial</title>
<link rel="stylesheet" href="../../doc/fonts/stylesheet.css">
<link rel="stylesheet" href="../../doc/css/prism.css">
<style media="screen">
pre.code {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 10px;
height: 280px;
overflow: auto;
background: #181818;
border: solid 2px #181818;
}
#codelines {
display: none;
}
#svg {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
border: solid 2px #ccc;
width: 300px;
height: 300px;
float: left;
margin-right: 10px;
font: 1em source-sans-pro, Source Sans Pro, Helvetica, sans-serif;
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script src="../../doc/js/prism.js"></script>
<script>
var S;
window.onload = function () {
var s = Snap(850, 35);
function chooser(s, count) {
var loop = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60",
line = "M35,65a30,30,0,0,0,0-60a30,30,0,0,0,0,60c30,0,60-60,90-60a30,30,0,0,1,0,60a30,30,0,0,1,0-60",
l1 = Snap.path.getTotalLength(loop),
l2 = Snap.path.getTotalLength(line),
cur = 1,
p = s.path({
path: loop,
fill: "none",
stroke: "#f00",
strokeWidth: 6,
strokeLinecap: "round"
});
for (var i = 1; i <= count; i++) {
s.text(90 * i - 55, 49, i).attr({
font: "45px source-sans-pro, Source Sans Pro, Helvetica, sans-serif",
textAnchor: "middle"
});
(function (i) {
s.circle(90 * i - 55, 35, 40).attr({
opacity: 0
}).click(eve.f("tut.click", i - 1));
}(i));
}
s.path("M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z").transform("t" + (90 * (count + 1) - 68) + ",18s2");
var but = s.circle(90 * (count + 1) - 55, 35, 30).attr({
fillOpacity: 0,
stroke: "#333",
strokeWidth: 2
});
eve.on("tut.click", function (I) {
p.attr({
path: loop,
transform: "t" + (90 * I) + ",0"
});
cur = I + 1;
});
function frameHandler(frame) {
function anim() {
cur++;
if (cur > count) {
return;
}
if (typeof frame == "function") {
frame(cur);
}
Snap.animate(0, l2 - l1, function (val) {
p.attr({
path: Snap.path.getSubpath(line, val, val + l1)
});
}, 500, function () {
p.attr({
path: loop,
transform: p.transform() + "t90,0"
});
});
}
if (typeof frame == "function") {
but.click(anim);
} else {
anim();
}
}
return frameHandler;
}
var g = s.g();
g.attr({
transform: "s.5,.5,0,0"
});
var str = "",
code = document.getElementById("code");
var domcodelines = document.querySelectorAll("#codelines li"),
codelines = [],
replacers = {},
lines = [],
callback = function (i) {
lines = [];
for (var j = 1; j <= i; j++) {
replacers[j - 1] && lines.pop();
lines.push(codelines[j - 1]);
}
Snap("#svg").clear();
str = lines.join("\n");
eval(str);
code.innerHTML = Prism.highlight(str, Prism.languages.javascript);
code.parentNode.scrollTop = code.parentNode.scrollTopMax || 1e9;
};
for (var i = 0, ii = domcodelines.length; i < ii; i++) {
codelines[i] = domcodelines[i].innerHTML;
if (domcodelines[i].className == "replace") {
replacers[i] = true;
}
}
callback(1);
chooser(g, codelines.length)(callback);
eve.on("tut.click", function (I) {
callback(I + 1);
});
};
</script>
</head>
<body>
<ol id="codelines">
<li>// Text on the path
var s = Snap("#svg");</li>
<li>// Setting the background
var bg = s.rect(50, 50, 200, 200, 10).attr({fill: "#ccc"});</li>
<li>var t = s.text(150, 150, "Test Text").attr({
font: "30px Helvetica, sans-serif",
textAnchor: "middle",
fill: "#ddd"
});</li>
<li>// Lets create a mask</li>
<li>var t2 = t.use().attr({
stroke: "#000",
strokeWidth: 10,
strokeLinecap: "round",
strokeLinejoin: "round"
});
</li>
<li>var mask = s.mask();</li>
<li>// Background rect:
mask.add(s.rect(0, 0, "100%", "100%").attr({fill: "#fff"}));</li>
<li>// and our ring
mask.add(t2);</li>
<li>bg.attr({
mask: mask
});</li>
<li>//Now, lets animate:</li>
<li>t2.animate({strokeWidth: 4}, 5e3, mina.bounce);</li>
</ol>
<svg id="svg"></svg>
<pre class="javascript code"><code data-language="javascript" class="language-javascript" id="code"></code></pre>
<svg width="0" height="0">
<pattern id="pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10" viewBox="0 0 10 10">
<path d="M-5,0,10,15M0-5,15,10" stroke="white" stroke-width="5"/>
</pattern>
</svg>
</body>
</html>

View File

@ -3,8 +3,8 @@
<head>
<meta charset="utf-8">
<title>Tutorial</title>
<link rel="stylesheet" href="../../dist/fonts/stylesheet.css">
<link rel="stylesheet" href="../../dist/css/prism.css">
<link rel="stylesheet" href="../../doc/fonts/stylesheet.css">
<link rel="stylesheet" href="../../doc/css/prism.css">
<style media="screen">
pre.code {
-moz-border-radius: 10px;
@ -32,7 +32,7 @@
}
</style>
<script src="../../dist/snap.svg-min.js"></script>
<script src="../../dist/js/prism.js"></script>
<script src="../../doc/js/prism.js"></script>
<script>
var S;
window.onload = function () {

10
dist/snap.svg-min.js vendored

File diff suppressed because one or more lines are too long

3744
dist/snap.svg.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,10 @@ h5:hover a.dr-sourceline {
.dr-type {
float: left;
}
.dr-title {
float: left;
margin: 0 8px 0 0;
}
.dr-type em,
.dr-returns em,
.dr-property em {
@ -137,4 +141,4 @@ ol.dr-json ol.dr-json {
list-style: none;
margin: 0;
padding: 0;
}
}

File diff suppressed because it is too large Load Diff

20
dr.json
View File

@ -4,24 +4,30 @@
"template": "template.dot",
"files": [{
"url": "src/svg.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/svg.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js"
}, {
"url": "src/matrix.js",
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/matrix.js"
}, {
"url": "src/paper.js",
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/paper.js"
}, {
"url": "src/equal.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/equal.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/equal.js"
}, {
"url": "src/mina.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/mina.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/mina.js"
}, {
"url": "src/filter.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/filter.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/filter.js"
}, {
"url": "src/mouse.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/mouse.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/mouse.js"
}, {
"url": "src/path.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/path.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js"
}, {
"url": "src/set.js",
"link": "https://github.com/adobe-webplatform/savage/blob/master/src/set.js"
"link": "https://github.com/adobe-webplatform/Snap.svg/blob/master/src/set.js"
}]
}

31
history.md Normal file
View File

@ -0,0 +1,31 @@
#0.3.0
* Added `.addClass()`, `.removeClass()`, `.toggleClass()` and `.hasClass()` APIs
* Added `Paper.mask()`, `Paper.ptrn()`, `Paper.use()`, `Paper.svg()`
* Mask & pattern elements are sharing paper methods (just like group)
* Added `Set.bind()` method
* Added syncronisation for `Set.animate()`
* Added opacity to the shadow filter
* Added ability to specify attributes as `"+=10"` or `"-=1em"` or `"*=2"`
* Fix negative scale
* Fix for `path2curve`
* Fixed shared `<defs>` issue
* Various bug fixes
#0.2.0
* Added support for text path
* Added `getBBox` method to the paper object
* Added `Element.appendTo()` and `Element.prependTo()`
* Added `getElementByPoint()`
* Added `Set.remove()` method
* Get rid of internal SVG parser in favor of the browser
* Fix for `xlink:href` setting for images
* Fix `Element.animate()`
* Fix for animate and stroke-dashoffset
* Absolute transforms fix
* Fix for animation of SVG transformations, matrices and polygon points
* Various bug fixes
#0.1.0
* Initial release

View File

@ -1,22 +1,22 @@
{
"name": "snapsvg",
"version": "0.2.0",
"description": "JavaScript Vector Library",
"main": "Gruntfile.js",
"repository": {
"type": "git",
"url": "git@github.com:adobe-webplatform/Snap.svg.git"
},
"author": "Dmitry Baranovskiy",
"license": "Apache License v2",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-exec": "~0.4.2",
"mocha": "*",
"expect.js": "*",
"eve": "*",
"dr.js": "~0.1.0"
}
"name": "snapsvg",
"version": "0.3.0",
"description": "JavaScript Vector Library",
"main": "Gruntfile.js",
"repository": {
"type": "git",
"url": "git@github.com:adobe-webplatform/Snap.svg.git"
},
"author": "Dmitry Baranovskiy",
"license": "Apache License v2",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-exec": "~0.4.2",
"mocha": "*",
"expect.js": "*",
"eve": "~0.4.2",
"dr.js": "~0.1.0"
}
}

411
src/attr.js Normal file
View File

@ -0,0 +1,411 @@
// 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 has = "hasOwnProperty",
make = Snap._.make,
wrap = Snap._.wrap,
is = Snap.is,
getSomeDefs = Snap._.getSomeDefs,
reURLValue = /^url\(#?([^)]+)\)$/,
$ = Snap._.$,
URL = Snap.url,
Str = String,
separator = Snap._.separator,
E = "";
// Attributes event handlers
eve.on("snap.util.attr.mask", function (value) {
if (value instanceof Element || value instanceof Fragment) {
eve.stop();
if (value instanceof Fragment && value.node.childNodes.length == 1) {
value = value.node.firstChild;
getSomeDefs(this).appendChild(value);
value = wrap(value);
}
if (value.type == "mask") {
var mask = value;
} else {
mask = make("mask", getSomeDefs(this));
mask.node.appendChild(value.node);
}
!mask.node.id && $(mask.node, {
id: mask.id
});
$(this.node, {
mask: URL(mask.id)
});
}
});
(function (clipIt) {
eve.on("snap.util.attr.clip", clipIt);
eve.on("snap.util.attr.clip-path", clipIt);
eve.on("snap.util.attr.clipPath", clipIt);
}(function (value) {
if (value instanceof Element || value instanceof Fragment) {
eve.stop();
if (value.type == "clipPath") {
var clip = value;
} else {
clip = make("clipPath", getSomeDefs(this));
clip.node.appendChild(value.node);
!clip.node.id && $(clip.node, {
id: clip.id
});
}
$(this.node, {
"clip-path": URL(clip.id)
});
}
}));
function fillStroke(name) {
return function (value) {
eve.stop();
if (value instanceof Fragment && value.node.childNodes.length == 1 &&
(value.node.firstChild.tagName == "radialGradient" ||
value.node.firstChild.tagName == "linearGradient" ||
value.node.firstChild.tagName == "pattern")) {
value = value.node.firstChild;
getSomeDefs(this).appendChild(value);
value = wrap(value);
}
if (value instanceof Element) {
if (value.type == "radialGradient" || value.type == "linearGradient"
|| value.type == "pattern") {
if (!value.node.id) {
$(value.node, {
id: value.id
});
}
var fill = URL(value.node.id);
} else {
fill = value.attr(name);
}
} else {
fill = Snap.color(value);
if (fill.error) {
var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value);
if (grad) {
if (!grad.node.id) {
$(grad.node, {
id: grad.id
});
}
fill = URL(grad.node.id);
} else {
fill = value;
}
} else {
fill = Str(fill);
}
}
var attrs = {};
attrs[name] = fill;
$(this.node, attrs);
this.node.style[name] = E;
};
}
eve.on("snap.util.attr.fill", fillStroke("fill"));
eve.on("snap.util.attr.stroke", fillStroke("stroke"));
var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i;
eve.on("snap.util.grad.parse", function parseGrad(string) {
string = Str(string);
var tokens = string.match(gradrg);
if (!tokens) {
return null;
}
var type = tokens[1],
params = tokens[2],
stops = tokens[3];
params = params.split(/\s*,\s*/).map(function (el) {
return +el == el ? +el : el;
});
if (params.length == 1 && params[0] == 0) {
params = [];
}
stops = stops.split("-");
stops = stops.map(function (el) {
el = el.split(":");
var out = {
color: el[0]
};
if (el[1]) {
out.offset = parseFloat(el[1]);
}
return out;
});
return {
type: type,
params: params,
stops: stops
};
});
eve.on("snap.util.attr.d", function (value) {
eve.stop();
if (is(value, "array") && is(value[0], "array")) {
value = Snap.path.toString.call(value);
}
value = Str(value);
if (value.match(/[ruo]/i)) {
value = Snap.path.toAbsolute(value);
}
$(this.node, {d: value});
})(-1);
eve.on("snap.util.attr.#text", function (value) {
eve.stop();
value = Str(value);
var txt = glob.doc.createTextNode(value);
while (this.node.firstChild) {
this.node.removeChild(this.node.firstChild);
}
this.node.appendChild(txt);
})(-1);
eve.on("snap.util.attr.path", function (value) {
eve.stop();
this.attr({d: value});
})(-1);
eve.on("snap.util.attr.class", function (value) {
eve.stop();
this.node.className.baseVal = value;
})(-1);
eve.on("snap.util.attr.viewBox", function (value) {
var vb;
if (is(value, "object") && "x" in value) {
vb = [value.x, value.y, value.width, value.height].join(" ");
} else if (is(value, "array")) {
vb = value.join(" ");
} else {
vb = value;
}
$(this.node, {
viewBox: vb
});
eve.stop();
})(-1);
eve.on("snap.util.attr.transform", function (value) {
this.transform(value);
eve.stop();
})(-1);
eve.on("snap.util.attr.r", function (value) {
if (this.type == "rect") {
eve.stop();
$(this.node, {
rx: value,
ry: value
});
}
})(-1);
eve.on("snap.util.attr.textpath", function (value) {
eve.stop();
if (this.type == "text") {
var id, tp, node;
if (!value && this.textPath) {
tp = this.textPath;
while (tp.node.firstChild) {
this.node.appendChild(tp.node.firstChild);
}
tp.remove();
delete this.textPath;
return;
}
if (is(value, "string")) {
var defs = getSomeDefs(this),
path = wrap(defs.parentNode).path(value);
defs.appendChild(path.node);
id = path.id;
path.attr({id: id});
} else {
value = wrap(value);
if (value instanceof Element) {
id = value.attr("id");
if (!id) {
id = value.id;
value.attr({id: id});
}
}
}
if (id) {
tp = this.textPath;
node = this.node;
if (tp) {
tp.attr({"xlink:href": "#" + id});
} else {
tp = $("textPath", {
"xlink:href": "#" + id
});
while (node.firstChild) {
tp.appendChild(node.firstChild);
}
node.appendChild(tp);
this.textPath = wrap(tp);
}
}
}
})(-1);
eve.on("snap.util.attr.text", function (value) {
if (this.type == "text") {
var i = 0,
node = this.node,
tuner = function (chunk) {
var out = $("tspan");
if (is(chunk, "array")) {
for (var i = 0; i < chunk.length; i++) {
out.appendChild(tuner(chunk[i]));
}
} else {
out.appendChild(glob.doc.createTextNode(chunk));
}
out.normalize && out.normalize();
return out;
};
while (node.firstChild) {
node.removeChild(node.firstChild);
}
var tuned = tuner(value);
while (tuned.firstChild) {
node.appendChild(tuned.firstChild);
}
}
eve.stop();
})(-1);
function setFontSize(value) {
eve.stop();
if (value == +value) {
value += "px";
}
this.node.style.fontSize = value;
}
eve.on("snap.util.attr.fontSize", setFontSize)(-1);
eve.on("snap.util.attr.font-size", setFontSize)(-1);
eve.on("snap.util.getattr.transform", function () {
eve.stop();
return this.transform();
})(-1);
eve.on("snap.util.getattr.textpath", function () {
eve.stop();
return this.textPath;
})(-1);
// Markers
(function () {
function getter(end) {
return function () {
eve.stop();
var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end);
if (style == "none") {
return style;
} else {
return Snap(glob.doc.getElementById(style.match(reURLValue)[1]));
}
};
}
function setter(end) {
return function (value) {
eve.stop();
var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1);
if (value == "" || !value) {
this.node.style[name] = "none";
return;
}
if (value.type == "marker") {
var id = value.node.id;
if (!id) {
$(value.node, {id: value.id});
}
this.node.style[name] = URL(id);
return;
}
};
}
eve.on("snap.util.getattr.marker-end", getter("end"))(-1);
eve.on("snap.util.getattr.markerEnd", getter("end"))(-1);
eve.on("snap.util.getattr.marker-start", getter("start"))(-1);
eve.on("snap.util.getattr.markerStart", getter("start"))(-1);
eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1);
eve.on("snap.util.getattr.markerMid", getter("mid"))(-1);
eve.on("snap.util.attr.marker-end", setter("end"))(-1);
eve.on("snap.util.attr.markerEnd", setter("end"))(-1);
eve.on("snap.util.attr.marker-start", setter("start"))(-1);
eve.on("snap.util.attr.markerStart", setter("start"))(-1);
eve.on("snap.util.attr.marker-mid", setter("mid"))(-1);
eve.on("snap.util.attr.markerMid", setter("mid"))(-1);
}());
eve.on("snap.util.getattr.r", function () {
if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) {
eve.stop();
return $(this.node, "rx");
}
})(-1);
function textExtract(node) {
var out = [];
var children = node.childNodes;
for (var i = 0, ii = children.length; i < ii; i++) {
var chi = children[i];
if (chi.nodeType == 3) {
out.push(chi.nodeValue);
}
if (chi.tagName == "tspan") {
if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) {
out.push(chi.firstChild.nodeValue);
} else {
out.push(textExtract(chi));
}
}
}
return out;
}
eve.on("snap.util.getattr.text", function () {
if (this.type == "text" || this.type == "tspan") {
eve.stop();
var out = textExtract(this.node);
return out.length == 1 ? out[0] : out;
}
})(-1);
eve.on("snap.util.getattr.#text", function () {
return this.node.textContent;
})(-1);
eve.on("snap.util.getattr.viewBox", function () {
eve.stop();
var vb = $(this.node, "viewBox");
if (vb) {
vb = vb.split(separator);
return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]);
} else {
return;
}
})(-1);
eve.on("snap.util.getattr.points", function () {
var p = $(this.node, "points");
eve.stop();
if (p) {
return p.split(separator);
} else {
return;
}
})(-1);
eve.on("snap.util.getattr.path", function () {
var p = $(this.node, "d");
eve.stop();
return p;
})(-1);
eve.on("snap.util.getattr.class", function () {
return this.node.className.baseVal;
})(-1);
function getFontSize() {
eve.stop();
return this.node.style.fontSize;
}
eve.on("snap.util.getattr.fontSize", getFontSize)(-1);
eve.on("snap.util.getattr.font-size", getFontSize)(-1);
});

89
src/attradd.js Normal file
View File

@ -0,0 +1,89 @@
// 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 operators = {
"+": function (x, y) {
return x + y;
},
"-": function (x, y) {
return x - y;
},
"/": function (x, y) {
return x / y;
},
"*": function (x, y) {
return x * y;
}
},
Str = String,
reUnit = /[a-z]+$/i,
reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;
function getNumber(val) {
return val;
}
function getUnit(unit) {
return function (val) {
return +val.toFixed(3) + unit;
};
}
eve.on("snap.util.attr", function (val) {
var plus = Str(val).match(reAddon);
if (plus) {
var evnt = eve.nt(),
name = evnt.substring(evnt.lastIndexOf(".") + 1),
a = this.attr(name),
atr = {};
eve.stop();
var unit = plus[3] || "",
aUnit = a.match(reUnit),
op = operators[plus[1]];
if (aUnit && aUnit == unit) {
val = op(parseFloat(a), +plus[2]);
} else {
a = this.asPX(name);
val = op(this.asPX(name), this.asPX(name, plus[2] + unit));
}
if (isNaN(a) || isNaN(val)) {
return;
}
atr[name] = val;
this.attr(atr);
}
})(-10);
eve.on("snap.util.equal", function (name, b) {
var A, B, a = Str(this.attr(name) || ""),
el = this,
bplus = Str(b).match(reAddon);
if (bplus) {
eve.stop();
var unit = bplus[3] || "",
aUnit = a.match(reUnit),
op = operators[bplus[1]];
if (aUnit && aUnit == unit) {
return {
from: parseFloat(a),
to: op(parseFloat(a), +bplus[2]),
f: getUnit(aUnit)
};
} else {
a = this.asPX(name);
return {
from: a,
to: op(a, this.asPX(name, bplus[2] + unit)),
f: getNumber
};
}
}
})(-10);
});

View File

@ -104,6 +104,9 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
return out;
}
Element.prototype.equal = function (name, b) {
return eve("snap.util.equal", this, name, b).firstDefined();
};
eve.on("snap.util.equal", function (name, b) {
var A, B, a = Str(this.attr(name) || ""),
el = this;
if (a == +a && b == +b) {
@ -142,16 +145,16 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
};
}
if (name == "points") {
A = Str(a).split(",");
B = Str(b).split(",");
A = Str(a).split(Snap._.separator);
B = Str(b).split(Snap._.separator);
return {
from: A,
to: B,
f: function (val) { return val; }
};
}
var aUnit = a.match(reUnit),
bUnit = Str(b).match(reUnit);
aUnit = a.match(reUnit);
var bUnit = Str(b).match(reUnit);
if (aUnit && aUnit == bUnit) {
return {
from: parseFloat(a),
@ -165,5 +168,5 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
f: getNumber
};
}
};
});
});

View File

@ -111,10 +111,20 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
**
* Returns an SVG markup string for the shadow filter
**
- dx (number) horizontal shift of the shadow, in pixels
- dy (number) vertical shift of the shadow, in pixels
- dx (number) #optional horizontal shift of the shadow, in pixels
- dy (number) #optional vertical shift of the shadow, in pixels
- blur (number) #optional amount of blur
- color (string) #optional color of the shadow
- opacity (number) #optional `0..1` opacity of the shadow
* or
- dx (number) #optional horizontal shift of the shadow, in pixels
- dy (number) #optional vertical shift of the shadow, in pixels
- color (string) #optional color of the shadow
- opacity (number) #optional `0..1` opacity of the shadow
* which makes blur default to `4`. Or
- dx (number) #optional horizontal shift of the shadow, in pixels
- dy (number) #optional vertical shift of the shadow, in pixels
- opacity (number) #optional `0..1` opacity of the shadow
= (string) filter representation
> Usage
| var f = paper.filter(Snap.filter.shadow(0, 2, 3)),
@ -122,14 +132,22 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
| filter: f
| });
\*/
Snap.filter.shadow = function (dx, dy, blur, color) {
Snap.filter.shadow = function (dx, dy, blur, color, opacity) {
if (typeof blur == "string") {
color = blur;
opacity = color;
blur = 4;
}
if (typeof color != "string") {
opacity = color;
color = "#000";
}
color = color || "#000";
if (blur == null) {
blur = 4;
}
if (typeof blur == "string") {
color = blur;
blur = 4;
if (opacity == null) {
opacity = 1;
}
if (dx == null) {
dx = 0;
@ -139,11 +157,12 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
dy = dx;
}
color = Snap.color(color);
return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
color: color,
dx: dx,
dy: dy,
blur: blur
blur: blur,
opacity: opacity
});
};
Snap.filter.shadow.toString = function () {

309
src/matrix.js Normal file
View File

@ -0,0 +1,309 @@
// 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 objectToString = Object.prototype.toString,
Str = String,
math = Math,
E = "";
function Matrix(a, b, c, d, e, f) {
if (b == null && objectToString.call(a) == "[object SVGMatrix]") {
this.a = a.a;
this.b = a.b;
this.c = a.c;
this.d = a.d;
this.e = a.e;
this.f = a.f;
return;
}
if (a != null) {
this.a = +a;
this.b = +b;
this.c = +c;
this.d = +d;
this.e = +e;
this.f = +f;
} else {
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
}
}
(function (matrixproto) {
/*\
* Matrix.add
[ method ]
**
* Adds the given matrix to existing one
- a (number)
- b (number)
- c (number)
- d (number)
- e (number)
- f (number)
* or
- matrix (object) @Matrix
\*/
matrixproto.add = function (a, b, c, d, e, f) {
var out = [[], [], []],
m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
x, y, z, res;
if (a && a instanceof Matrix) {
matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
}
for (x = 0; x < 3; x++) {
for (y = 0; y < 3; y++) {
res = 0;
for (z = 0; z < 3; z++) {
res += m[x][z] * matrix[z][y];
}
out[x][y] = res;
}
}
this.a = out[0][0];
this.b = out[1][0];
this.c = out[0][1];
this.d = out[1][1];
this.e = out[0][2];
this.f = out[1][2];
return this;
};
/*\
* Matrix.invert
[ method ]
**
* Returns an inverted version of the matrix
= (object) @Matrix
\*/
matrixproto.invert = function () {
var me = this,
x = me.a * me.d - me.b * me.c;
return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
};
/*\
* Matrix.clone
[ method ]
**
* Returns a copy of the matrix
= (object) @Matrix
\*/
matrixproto.clone = function () {
return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
};
/*\
* Matrix.translate
[ method ]
**
* Translate the matrix
- x (number) horizontal offset distance
- y (number) vertical offset distance
\*/
matrixproto.translate = function (x, y) {
return this.add(1, 0, 0, 1, x, y);
};
/*\
* Matrix.scale
[ method ]
**
* Scales the matrix
- x (number) amount to be scaled, with `1` resulting in no change
- y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.)
- cx (number) #optional horizontal origin point from which to scale
- cy (number) #optional vertical origin point from which to scale
* Default cx, cy is the middle point of the element.
\*/
matrixproto.scale = function (x, y, cx, cy) {
y == null && (y = x);
(cx || cy) && this.add(1, 0, 0, 1, cx, cy);
this.add(x, 0, 0, y, 0, 0);
(cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
return this;
};
/*\
* Matrix.rotate
[ method ]
**
* Rotates the matrix
- a (number) angle of rotation, in degrees
- x (number) horizontal origin point from which to rotate
- y (number) vertical origin point from which to rotate
\*/
matrixproto.rotate = function (a, x, y) {
a = Snap.rad(a);
x = x || 0;
y = y || 0;
var cos = +math.cos(a).toFixed(9),
sin = +math.sin(a).toFixed(9);
this.add(cos, sin, -sin, cos, x, y);
return this.add(1, 0, 0, 1, -x, -y);
};
/*\
* Matrix.x
[ method ]
**
* Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y
- x (number)
- y (number)
= (number) x
\*/
matrixproto.x = function (x, y) {
return x * this.a + y * this.c + this.e;
};
/*\
* Matrix.y
[ method ]
**
* Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x
- x (number)
- y (number)
= (number) y
\*/
matrixproto.y = function (x, y) {
return x * this.b + y * this.d + this.f;
};
matrixproto.get = function (i) {
return +this[Str.fromCharCode(97 + i)].toFixed(4);
};
matrixproto.toString = function () {
return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
};
matrixproto.offset = function () {
return [this.e.toFixed(4), this.f.toFixed(4)];
};
function norm(a) {
return a[0] * a[0] + a[1] * a[1];
}
function normalize(a) {
var mag = math.sqrt(norm(a));
a[0] && (a[0] /= mag);
a[1] && (a[1] /= mag);
}
/*\
* Matrix.determinant
[ method ]
**
* Finds determinant of the given matrix.
= (number) determinant
\*/
matrixproto.determinant = function () {
return this.a * this.d - this.b * this.c;
};
/*\
* Matrix.split
[ method ]
**
* Splits matrix into primitive transformations
= (object) in format:
o dx (number) translation by x
o dy (number) translation by y
o scalex (number) scale by x
o scaley (number) scale by y
o shear (number) shear
o rotate (number) rotation in deg
o isSimple (boolean) could it be represented via simple transformations
\*/
matrixproto.split = function () {
var out = {};
// translation
out.dx = this.e;
out.dy = this.f;
// scale and shear
var row = [[this.a, this.c], [this.b, this.d]];
out.scalex = math.sqrt(norm(row[0]));
normalize(row[0]);
out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
out.scaley = math.sqrt(norm(row[1]));
normalize(row[1]);
out.shear /= out.scaley;
if (this.determinant() < 0) {
out.scalex = -out.scalex;
}
// rotation
var sin = -row[0][1],
cos = row[1][1];
if (cos < 0) {
out.rotate = Snap.deg(math.acos(cos));
if (sin < 0) {
out.rotate = 360 - out.rotate;
}
} else {
out.rotate = Snap.deg(math.asin(sin));
}
out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
return out;
};
/*\
* Matrix.toTransformString
[ method ]
**
* Returns transform string that represents given matrix
= (string) transform string
\*/
matrixproto.toTransformString = function (shorter) {
var s = shorter || this.split();
if (!+s.shear.toFixed(9)) {
s.scalex = +s.scalex.toFixed(4);
s.scaley = +s.scaley.toFixed(4);
s.rotate = +s.rotate.toFixed(4);
return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) +
(s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
(s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E);
} else {
return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
}
};
})(Matrix.prototype);
/*\
* Snap.Matrix
[ method ]
**
* Matrix constructor, extend on your own risk.
* To create matrices use @Snap.matrix.
\*/
Snap.Matrix = Matrix;
/*\
* Snap.matrix
[ method ]
**
* Utility method
**
* Returns a matrix based on the given parameters
- a (number)
- b (number)
- c (number)
- d (number)
- e (number)
- f (number)
* or
- svgMatrix (SVGMatrix)
= (object) @Matrix
\*/
Snap.matrix = function (a, b, c, d, e, f) {
return new Matrix(a, b, c, d, e, f);
};
});

View File

@ -74,6 +74,7 @@ var mina = (function (eve) {
stopit = function () {
var a = this;
delete animations[a.id];
a.update();
eve("mina.stop." + a.id, a);
},
pause = function () {
@ -82,6 +83,7 @@ var mina = (function (eve) {
return;
}
delete animations[a.id];
a.update();
a.pdif = a.get() - a.b;
},
resume = function () {
@ -93,6 +95,20 @@ var mina = (function (eve) {
delete a.pdif;
animations[a.id] = a;
},
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 () {
var len = 0;
for (var i in animations) if (animations.hasOwnProperty(i)) {
@ -111,20 +127,10 @@ var mina = (function (eve) {
});
}(a));
}
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);
a.update();
}
len && requestAnimFrame(frame);
},
// SIERRA Unfamiliar with the word _slave_ in this context. Also, I don't know what _gereal_ means. Do you mean _general_?
/*\
* mina
[ method ]
@ -154,6 +160,9 @@ var mina = (function (eve) {
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) {
@ -173,7 +182,8 @@ var mina = (function (eve) {
duration: duration,
stop: stopit,
pause: pause,
resume: resume
resume: resume,
update: update
};
animations[anim.id] = anim;
var len = 0, i;

View File

@ -25,9 +25,10 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
mousemove: "touchmove",
mouseup: "touchend"
},
getScroll = function (xy) {
var name = xy == "y" ? "scrollTop" : "scrollLeft";
return glob.doc.documentElement[name] || glob.doc.body[name];
getScroll = function (xy, el) {
var name = xy == "y" ? "scrollTop" : "scrollLeft",
doc = el && el.node ? el.node.ownerDocument : glob.doc;
return doc[name in doc.documentElement ? "documentElement" : "body"][name];
},
preventDefault = function () {
this.returnValue = false;
@ -45,35 +46,35 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
if (glob.doc.addEventListener) {
return function (obj, type, fn, element) {
var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
f = function (e) {
var scrollY = getScroll("y"),
scrollX = getScroll("x");
if (supportsTouch && touchMap[has](type)) {
for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
f = function (e) {
var scrollY = getScroll("y", element),
scrollX = getScroll("x", element);
if (supportsTouch && touchMap[has](type)) {
for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
var olde = e;
e = e.targetTouches[i];
e.originalEvent = olde;
e.preventDefault = preventTouch;
e.stopPropagation = stopTouch;
break;
}
}
break;
}
}
}
var x = e.clientX + scrollX,
y = e.clientY + scrollY;
return fn.call(element, e, x, y);
return fn.call(element, e, x, y);
};
if (type !== realName) {
obj.addEventListener(type, f, false);
if (type !== realName) {
obj.addEventListener(type, f, false);
}
obj.addEventListener(realName, f, false);
return function () {
if (type !== realName) {
obj.removeEventListener(type, f, false);
if (type !== realName) {
obj.removeEventListener(type, f, false);
}
obj.removeEventListener(realName, f, false);
@ -83,9 +84,9 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
} else if (glob.doc.attachEvent) {
return function (obj, type, fn, element) {
var f = function (e) {
e = e || glob.win.event;
var scrollY = getScroll("y"),
scrollX = getScroll("x"),
e = e || element.node.ownerDocument.window.event;
var scrollY = getScroll("y", element),
scrollX = getScroll("x", element),
x = e.clientX + scrollX,
y = e.clientY + scrollY;
e.preventDefault = e.preventDefault || preventDefault;
@ -128,7 +129,6 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
}
var node = dragi.el.node,
o,
glob = Snap._.glob,
next = node.nextSibling,
parent = node.parentNode,
display = node.style.display;
@ -348,7 +348,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
this.events.push({
name: eventName,
f: fn,
unbind: addEvent(this.shape || this.node || glob.doc, eventName, fn, scope || this)
unbind: addEvent(this.node || document, eventName, fn, scope || this)
});
}
return this;

686
src/paper.js Normal file
View File

@ -0,0 +1,686 @@
// 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 proto = Paper.prototype,
is = Snap.is;
/*\
* Paper.rect
[ method ]
*
* Draws a rectangle
**
- x (number) x coordinate of the top left corner
- y (number) y coordinate of the top left corner
- width (number) width
- height (number) height
- rx (number) #optional horizontal radius for rounded corners, default is 0
- ry (number) #optional vertical radius for rounded corners, default is rx or 0
= (object) the `rect` element
**
> Usage
| // regular rectangle
| var c = paper.rect(10, 10, 50, 50);
| // rectangle with rounded corners
| var c = paper.rect(40, 40, 50, 50, 10);
\*/
proto.rect = function (x, y, w, h, rx, ry) {
var attr;
if (ry == null) {
ry = rx;
}
if (is(x, "object") && x == "[object Object]") {
attr = x;
} else if (x != null) {
attr = {
x: x,
y: y,
width: w,
height: h
};
if (rx != null) {
attr.rx = rx;
attr.ry = ry;
}
}
return this.el("rect", attr);
};
/*\
* Paper.circle
[ method ]
**
* Draws a circle
**
- x (number) x coordinate of the centre
- y (number) y coordinate of the centre
- r (number) radius
= (object) the `circle` element
**
> Usage
| var c = paper.circle(50, 50, 40);
\*/
proto.circle = function (cx, cy, r) {
var attr;
if (is(cx, "object") && cx == "[object Object]") {
attr = cx;
} else if (cx != null) {
attr = {
cx: cx,
cy: cy,
r: r
};
}
return this.el("circle", attr);
};
var preload = (function () {
function onerror() {
this.parentNode.removeChild(this);
}
return function (src, f) {
var img = glob.doc.createElement("img"),
body = glob.doc.body;
img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
img.onload = function () {
f.call(img);
img.onload = img.onerror = null;
body.removeChild(img);
};
img.onerror = onerror;
body.appendChild(img);
img.src = src;
};
}());
/*\
* Paper.image
[ method ]
**
* Places an image on the surface
**
- src (string) URI of the source image
- x (number) x offset position
- y (number) y offset position
- width (number) width of the image
- height (number) height of the image
= (object) the `image` element
* or
= (object) Snap element object with type `image`
**
> Usage
| var c = paper.image("apple.png", 10, 10, 80, 80);
\*/
proto.image = function (src, x, y, width, height) {
var el = this.el("image");
if (is(src, "object") && "src" in src) {
el.attr(src);
} else if (src != null) {
var set = {
"xlink:href": src,
preserveAspectRatio: "none"
};
if (x != null && y != null) {
set.x = x;
set.y = y;
}
if (width != null && height != null) {
set.width = width;
set.height = height;
} else {
preload(src, function () {
Snap._.$(el.node, {
width: this.offsetWidth,
height: this.offsetHeight
});
});
}
Snap._.$(el.node, set);
}
return el;
};
/*\
* Paper.ellipse
[ method ]
**
* Draws an ellipse
**
- x (number) x coordinate of the centre
- y (number) y coordinate of the centre
- rx (number) horizontal radius
- ry (number) vertical radius
= (object) the `ellipse` element
**
> Usage
| var c = paper.ellipse(50, 50, 40, 20);
\*/
proto.ellipse = function (cx, cy, rx, ry) {
var attr;
if (is(cx, "object") && cx == "[object Object]") {
attr = cx;
} else if (cx != null) {
attr ={
cx: cx,
cy: cy,
rx: rx,
ry: ry
};
}
return this.el("ellipse", attr);
};
// SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier.
/*\
* Paper.path
[ method ]
**
* Creates a `<path>` element using the given string as the path's definition
- pathString (string) #optional path string in SVG format
* Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example:
| "M10,20L30,40"
* This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates.
*
# <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p>
# <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
# <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
# <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
# <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
# <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
# <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
# <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
# <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
# <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
# <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
# <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
# <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/CatmullRom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
* * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier.
* Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point.
> Usage
| var c = paper.path("M10 10L90 90");
| // draw a diagonal line:
| // move to 10,10, line to 90,90
\*/
proto.path = function (d) {
var attr;
if (is(d, "object") && !is(d, "array")) {
attr = d;
} else if (d) {
attr = {d: d};
}
return this.el("path", attr);
};
/*\
* Paper.g
[ method ]
**
* Creates a group element
**
- varargs () #optional elements to nest within the group
= (object) the `g` element
**
> Usage
| var c1 = paper.circle(),
| c2 = paper.rect(),
| g = paper.g(c2, c1); // note that the order of elements is different
* or
| var c1 = paper.circle(),
| c2 = paper.rect(),
| g = paper.g();
| g.add(c2, c1);
\*/
/*\
* Paper.group
[ method ]
**
* See @Paper.g
\*/
proto.group = proto.g = function (first) {
var attr,
el = this.el("g");
if (arguments.length == 1 && first && !first.type) {
el.attr(first);
} else if (arguments.length) {
el.add(Array.prototype.slice.call(arguments, 0));
}
return el;
};
/*\
* Paper.svg
[ method ]
**
* Creates a nested SVG element.
- x (number) @optional X of the element
- y (number) @optional Y of the element
- width (number) @optional width of the element
- height (number) @optional height of the element
- vbx (number) @optional viewbox X
- vby (number) @optional viewbox Y
- vbw (number) @optional viewbox width
- vbh (number) @optional viewbox height
**
= (object) the `svg` element
**
\*/
proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) {
var attrs = {};
if (is(x, "object") && y == null) {
attrs = x;
} else {
if (x != null) {
attrs.x = x;
}
if (y != null) {
attrs.y = y;
}
if (width != null) {
attrs.width = width;
}
if (height != null) {
attrs.height = height;
}
if (vbx != null && vby != null && vbw != null && vbh != null) {
attrs.viewBox = [vbx, vby, vbw, vbh];
}
}
return this.el("svg", attrs);
};
/*\
* Paper.mask
[ method ]
**
* Equivalent in behaviour to @Paper.g, except its a mask.
**
= (object) the `mask` element
**
\*/
proto.mask = function (first) {
var attr,
el = this.el("mask");
if (arguments.length == 1 && first && !first.type) {
el.attr(first);
} else if (arguments.length) {
el.add(Array.prototype.slice.call(arguments, 0));
}
return el;
};
/*\
* Paper.ptrn
[ method ]
**
* Equivalent in behaviour to @Paper.g, except its a mask.
- x (number) @optional X of the element
- y (number) @optional Y of the element
- width (number) @optional width of the element
- height (number) @optional height of the element
- vbx (number) @optional viewbox X
- vby (number) @optional viewbox Y
- vbw (number) @optional viewbox width
- vbh (number) @optional viewbox height
**
= (object) the `mask` element
**
\*/
proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) {
if (is(x, "object")) {
var attr = x;
} else if (!arguments.length) {
attr = {patternUnits: "userSpaceOnUse"};
} else {
attr = {};
if (x != null) {
attr.x = x;
}
if (y != null) {
attr.y = y;
}
if (width != null) {
attr.width = width;
}
if (height != null) {
attr.height = height;
}
if (vx != null && vy != null && vw != null && vh != null) {
attr.viewBox = [vx, vy, vw, vh];
}
}
return this.el("pattern", attr);
};
/*\
* Paper.use
[ method ]
**
* Creates a <use> element.
- id (string) @optional id of element to link
* or
- id (Element) @optional element to link
**
= (object) the `use` element
**
\*/
proto.use = function (id) {
if (id != null) {
var el = make("use", this.node);
if (id instanceof Element) {
if (!id.attr("id")) {
id.attr({id: ID()});
}
id = id.attr("id");
}
return this.el("use", {"xlink:href": id});
} else {
return Element.prototype.use.call(this);
}
};
/*\
* Paper.text
[ method ]
**
* Draws a text string
**
- x (number) x coordinate position
- y (number) y coordinate position
- text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements
= (object) the `text` element
**
> Usage
| var t1 = paper.text(50, 50, "Snap");
| var t2 = paper.text(50, 50, ["S","n","a","p"]);
| // Text path usage
| t1.attr({textpath: "M10,10L100,100"});
| // or
| var pth = paper.path("M10,10L100,100");
| t1.attr({textpath: pth});
\*/
proto.text = function (x, y, text) {
var attr = {};
if (is(x, "object")) {
attr = x;
} else if (x != null) {
attr = {
x: x,
y: y,
text: text || ""
};
}
return this.el("text", attr);
};
/*\
* Paper.line
[ method ]
**
* Draws a line
**
- x1 (number) x coordinate position of the start
- y1 (number) y coordinate position of the start
- x2 (number) x coordinate position of the end
- y2 (number) y coordinate position of the end
= (object) the `line` element
**
> Usage
| var t1 = paper.line(50, 50, 100, 100);
\*/
proto.line = function (x1, y1, x2, y2) {
var attr = {};
if (is(x1, "object")) {
attr = x1;
} else if (x1 != null) {
attr = {
x1: x1,
x2: x2,
y1: y1,
y2: y2
};
}
return this.el("line", attr);
};
/*\
* Paper.polyline
[ method ]
**
* Draws a polyline
**
- points (array) array of points
* or
- varargs () points
= (object) the `polyline` element
**
> Usage
| var p1 = paper.polyline([10, 10, 100, 100]);
| var p2 = paper.polyline(10, 10, 100, 100);
\*/
proto.polyline = function (points) {
if (arguments.length > 1) {
points = Array.prototype.slice.call(arguments, 0);
}
var attr = {};
if (is(points, "object") && !is(points, "array")) {
attr = points;
} else if (points != null) {
attr = {points: points};
}
return this.el("polyline", attr);
};
/*\
* Paper.polygon
[ method ]
**
* Draws a polygon. See @Paper.polyline
\*/
proto.polygon = function (points) {
if (arguments.length > 1) {
points = Array.prototype.slice.call(arguments, 0);
}
var attr = {};
if (is(points, "object") && !is(points, "array")) {
attr = points;
} else if (points != null) {
attr = {points: points};
}
return this.el("polygon", attr);
};
// gradients
(function () {
var $ = Snap._.$;
// gradients' helpers
function Gstops() {
return this.selectAll("stop");
}
function GaddStop(color, offset) {
var stop = $("stop"),
attr = {
offset: +offset + "%"
};
color = Snap.color(color);
attr["stop-color"] = color.hex;
if (color.opacity < 1) {
attr["stop-opacity"] = color.opacity;
}
$(stop, attr);
this.node.appendChild(stop);
return this;
}
function GgetBBox() {
if (this.type == "linearGradient") {
var x1 = $(this.node, "x1") || 0,
x2 = $(this.node, "x2") || 1,
y1 = $(this.node, "y1") || 0,
y2 = $(this.node, "y2") || 0;
return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1));
} else {
var cx = this.node.cx || .5,
cy = this.node.cy || .5,
r = this.node.r || 0;
return Snap._.box(cx - r, cy - r, r * 2, r * 2);
}
}
function gradient(defs, str) {
var grad = eve("snap.util.grad.parse", null, str).firstDefined(),
el;
if (!grad) {
return null;
}
grad.params.unshift(defs);
if (grad.type.toLowerCase() == "l") {
el = gradientLinear.apply(0, grad.params);
} else {
el = gradientRadial.apply(0, grad.params);
}
if (grad.type != grad.type.toLowerCase()) {
$(el.node, {
gradientUnits: "userSpaceOnUse"
});
}
var stops = grad.stops,
len = stops.length,
start = 0,
j = 0;
function seed(i, end) {
var step = (end - start) / (i - j);
for (var k = j; k < i; k++) {
stops[k].offset = +(+start + step * (k - j)).toFixed(2);
}
j = i;
start = end;
}
len--;
for (var i = 0; i < len; i++) if ("offset" in stops[i]) {
seed(i, stops[i].offset);
}
stops[len].offset = stops[len].offset || 100;
seed(len, stops[len].offset);
for (i = 0; i <= len; i++) {
var stop = stops[i];
el.addStop(stop.color, stop.offset);
}
return el;
}
function gradientLinear(defs, x1, y1, x2, y2) {
var el = Snap._.make("linearGradient", defs);
el.stops = Gstops;
el.addStop = GaddStop;
el.getBBox = GgetBBox;
if (x1 != null) {
$(el.node, {
x1: x1,
y1: y1,
x2: x2,
y2: y2
});
}
return el;
}
function gradientRadial(defs, cx, cy, r, fx, fy) {
var el = Snap._.make("radialGradient", defs);
el.stops = Gstops;
el.addStop = GaddStop;
el.getBBox = GgetBBox;
if (cx != null) {
$(el.node, {
cx: cx,
cy: cy,
r: r
});
}
if (fx != null && fy != null) {
$(el.node, {
fx: fx,
fy: fy
});
}
return el;
}
/*\
* Paper.gradient
[ method ]
**
* Creates a gradient element
**
- gradient (string) gradient descriptor
> Gradient Descriptor
* The gradient descriptor is an expression formatted as
* follows: `<type>(<coords>)<colors>`. The `<type>` can be
* either linear or radial. The uppercase `L` or `R` letters
* indicate absolute coordinates offset from the SVG surface.
* Lowercase `l` or `r` letters indicate coordinates
* calculated relative to the element to which the gradient is
* applied. Coordinates specify a linear gradient vector as
* `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`,
* `r` and optional `fx`, `fy` specifying a focal point away
* from the center of the circle. Specify `<colors>` as a list
* of dash-separated CSS color values. Each color may be
* followed by a custom offset value, separated with a colon
* character.
> Examples
* Linear gradient, relative from top-left corner to bottom-right
* corner, from black through red to white:
| var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff");
* Linear gradient, absolute from (0, 0) to (100, 100), from black
* through red at 25% to white:
| var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff");
* Radial gradient, relative from the center of the element with radius
* half the width, from black to white:
| var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff");
* To apply the gradient:
| paper.circle(50, 50, 40).attr({
| fill: g
| });
= (object) the `gradient` element
\*/
proto.gradient = function (str) {
return gradient(this.defs, str);
};
proto.gradientLinear = function (x1, y1, x2, y2) {
return gradientLinear(this.defs, x1, y1, x2, y2);
};
proto.gradientRadial = function (cx, cy, r, fx, fy) {
return gradientRadial(this.defs, cx, cy, r, fx, fy);
};
/*\
* Paper.toString
[ method ]
**
* Returns SVG code for the @Paper
= (string) SVG code for the @Paper
\*/
proto.toString = function () {
var doc = this.node.ownerDocument,
f = doc.createDocumentFragment(),
d = doc.createElement("div"),
svg = this.node.cloneNode(true),
res;
f.appendChild(d);
d.appendChild(svg);
Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"});
res = d.innerHTML;
f.removeChild(f.firstChild);
return res;
};
/*\
* Paper.clear
[ method ]
**
* Removes all child nodes of the paper, except <defs>.
\*/
proto.clear = function () {
var node = this.node.firstChild,
next;
while (node) {
next = node.nextSibling;
if (node.tagName != "defs") {
node.parentNode.removeChild(node);
} else {
proto.clear.call({node: node});
}
node = next;
}
};
}());
});

View File

@ -300,8 +300,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
}
var l1 = bezlen.apply(0, bez1),
l2 = bezlen.apply(0, bez2),
n1 = ~~(l1 / 5),
n2 = ~~(l2 / 5),
n1 = ~~(l1 / 8),
n2 = ~~(l2 / 8),
dots1 = [],
dots2 = [],
xy = {},
@ -451,7 +451,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
function rectPath(x, y, w, h, r) {
if (r) {
return [
["M", x + r, y],
["M", +x + (+r), y],
["l", w - r * 2, 0],
["a", r, r, 0, 0, 1, r, r],
["l", 0, h - r * 2],
@ -471,6 +471,10 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
if (a == null && ry == null) {
ry = rx;
}
x = +x;
y = +y;
rx = +rx;
ry = +ry;
if (a != null) {
var rad = Math.PI / 180,
x1 = x + rx * Math.cos(-ry * rad),
@ -501,30 +505,18 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
},
ellipse: function (el) {
var attr = unit2px(el);
return ellipsePath(attr.cx, attr.cy, attr.rx, attr.ry);
return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry);
},
rect: function (el) {
var attr = unit2px(el);
return rectPath(attr.x, attr.y, attr.width, attr.height, attr.rx, attr.ry);
return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry);
},
image: function (el) {
var attr = unit2px(el);
return rectPath(attr.x, attr.y, attr.width, attr.height);
},
text: function (el) {
var bbox = el.node.getBBox();
return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
},
g: function (el) {
var bbox = el.node.getBBox();
return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
},
symbol: function (el) {
var bbox = el.getBBox();
return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height);
},
line: function (el) {
return "M" + [el.attr("x1"), el.attr("y1"), el.attr("x2"), el.attr("y2")];
return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")];
},
polyline: function (el) {
return "M" + el.attr("points");
@ -532,10 +524,6 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
polygon: function (el) {
return "M" + el.attr("points") + "z";
},
svg: function (el) {
var bbox = el.node.getBBox();
return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
},
deflt: function (el) {
var bbox = el.node.getBBox();
return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
@ -664,8 +652,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
r[3] = pa[3];
r[4] = pa[4];
r[5] = pa[5];
r[6] = +(pa[6] + x);
r[7] = +(pa[7] + y);
r[6] = +pa[6] + x;
r[7] = +pa[7] + y;
break;
case "V":
r[1] = +pa[1] + y;
@ -724,8 +712,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
if (pa0 != "O") {
switch (r[0]) {
case "Z":
x = mx;
y = my;
x = +mx;
y = +my;
break;
case "H":
x = r[1];
@ -857,49 +845,73 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
};
}
function curveDim(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
c = p1x - c1x,
t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
y = [p1y, p2y],
x = [p1x, p2x],
dot;
abs(t1) > "1e12" && (t1 = .5);
abs(t2) > "1e12" && (t2 = .5);
if (t1 > 0 && t1 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
x.push(dot.x);
y.push(dot.y);
// Returns bounding box of cubic bezier curve.
// Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
// Original version: NISHIO Hirokazu
// Modifications: https://github.com/timo22345
function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
var tvalues = [],
bounds = [[], []],
a, b, c, t, t1, t2, b2ac, sqrtb2ac;
for (var i = 0; i < 2; ++i) {
if (i == 0) {
b = 6 * x0 - 12 * x1 + 6 * x2;
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
c = 3 * x1 - 3 * x0;
} else {
b = 6 * y0 - 12 * y1 + 6 * y2;
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
c = 3 * y1 - 3 * y0;
}
if (abs(a) < 1e-12) {
if (abs(b) < 1e-12) {
continue;
}
t = -c / b;
if (0 < t && t < 1) {
tvalues.push(t);
}
continue;
}
b2ac = b * b - 4 * c * a;
sqrtb2ac = math.sqrt(b2ac);
if (b2ac < 0) {
continue;
}
t1 = (-b + sqrtb2ac) / (2 * a);
if (0 < t1 && t1 < 1) {
tvalues.push(t1);
}
t2 = (-b - sqrtb2ac) / (2 * a);
if (0 < t2 && t2 < 1) {
tvalues.push(t2);
}
}
if (t2 > 0 && t2 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
x.push(dot.x);
y.push(dot.y);
}
a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
c = p1y - c1y;
t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
abs(t1) > "1e12" && (t1 = .5);
abs(t2) > "1e12" && (t2 = .5);
if (t1 > 0 && t1 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
x.push(dot.x);
y.push(dot.y);
}
if (t2 > 0 && t2 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
x.push(dot.x);
y.push(dot.y);
var x, y, j = tvalues.length,
jlen = j,
mt;
while (j--) {
t = tvalues[j];
mt = 1 - t;
bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
}
bounds[0][jlen] = x0;
bounds[1][jlen] = y0;
bounds[0][jlen + 1] = x3;
bounds[1][jlen + 1] = y3;
bounds[0].length = bounds[1].length = jlen + 2;
return {
min: {x: mmin.apply(0, x), y: mmin.apply(0, y)},
max: {x: mmax.apply(0, x), y: mmax.apply(0, y)}
min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])},
max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])}
};
}
function path2curve(path, path2) {
var pth = !path2 && paths(path);
if (!path2 && pth.curve) {
@ -909,12 +921,12 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
p2 = path2 && pathToAbsolute(path2),
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
processPath = function (path, d) {
processPath = function (path, d, pcom) {
var nx, ny;
if (!path) {
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
}
!(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
!(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
switch (path[0]) {
case "M":
d.X = path[1];
@ -924,13 +936,25 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
break;
case "S":
nx = d.x + (d.x - (d.bx || d.x));
ny = d.y + (d.y - (d.by || d.y));
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
nx = d.x * 2 - d.bx; // And reflect the previous
ny = d.y * 2 - d.by; // command's control point relative to the current point.
}
else { // or some else or nothing
nx = d.x;
ny = d.y;
}
path = ["C", nx, ny].concat(path.slice(1));
break;
case "T":
d.qx = d.x + (d.x - (d.qx || d.x));
d.qy = d.y + (d.y - (d.qy || d.y));
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
d.qx = d.x * 2 - d.qx; // And make a reflection similar
d.qy = d.y * 2 - d.qy; // to case "S".
}
else { // or something else or nothing
d.qx = d.x;
d.qy = d.y;
}
path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
case "Q":
@ -958,6 +982,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
pp[i].shift();
var pi = pp[i];
while (pi.length) {
pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
p2 && (pcoms2[i] = "A"); // the same as above
pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
}
pp.splice(i, 1);
@ -973,12 +999,41 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
a1.y = path1[i][2];
ii = mmax(p.length, p2 && p2.length || 0);
}
};
},
pcoms1 = [], // path commands of original path p
pcoms2 = [], // path commands of original path p2
pfirst = "", // temporary holder for original path command
pcom = ""; // holder for previous path command of original path
for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
p[i] = processPath(p[i], attrs);
fixArc(p, i);
p2 && (p2[i] = processPath(p2[i], attrs2));
p2 && fixArc(p2, i);
p[i] && (pfirst = p[i][0]); // save current path command
if (pfirst != "C") // C is not saved yet, because it may be result of conversion
{
pcoms1[i] = pfirst; // Save current path command
i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
}
p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
// which may produce multiple C:s
// so we have to make sure that C is also C in original path
fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
if (p2) { // the same procedures is done to p2
p2[i] && (pfirst = p2[i][0]);
if (pfirst != "C") {
pcoms2[i] = pfirst;
i && (pcom = pcoms2[i - 1]);
}
p2[i] = processPath(p2[i], attrs2, pcom);
if (pcoms2[i] != "A" && pfirst == "C") {
pcoms2[i] = "C";
}
fixArc(p2, i);
}
fixM(p, p2, attrs, attrs2, i);
fixM(p2, p, attrs2, attrs, i);
var seg = p[i],

View File

@ -18,6 +18,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
// Set
var Set = function (items) {
this.items = [];
this.bindings = {};
this.length = 0;
this.type = "set";
if (items) {
@ -81,15 +82,114 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
}
return this;
};
/*\
* Set.animate
[ method ]
**
* Animates each element in set in sync.
*
**
- 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
* or
- animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]`
> Usage
| // animate all elements in set to radius 10
| set.animate({r: 10}, 500, mina.easein);
| // or
| // animate first element to radius 10, but second to radius 20 and in different time
| set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]);
= (Element) the current element
\*/
setproto.animate = function (attrs, ms, easing, callback) {
if (typeof easing == "function" && !easing.length) {
callback = easing;
easing = mina.linear;
}
if (attrs instanceof Snap._.Animation) {
callback = attrs.callback;
easing = attrs.easing;
ms = easing.dur;
attrs = attrs.attr;
}
var args = arguments;
if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) {
var each = true;
}
var begin,
handler = function () {
if (begin) {
this.b = begin;
} else {
begin = this.b;
}
},
cb = 0,
callbacker = callback && function () {
if (cb++ == this.length) {
callback.call(this);
}
};
return this.forEach(function (el, i) {
eve.once("snap.animcreated." + el.id, handler);
if (each) {
args[i] && el.animate.apply(el, args[i]);
} else {
el.animate(attrs, ms, easing, callbacker);
}
});
};
setproto.remove = function () {
while (this.length) {
this.pop().remove();
}
return this;
};
/*\
* Set.bind
[ method ]
**
* Specifies how to handle a specific attribute when applied
* to a set.
*
**
- attr (string) attribute name
- callback (function) function to run
* or
- attr (string) attribute name
- element (Element) specific element in the set to apply the attribute to
* or
- attr (string) attribute name
- element (Element) specific element in the set to apply the attribute to
- eattr (string) attribute on the element to bind the attribute to
= (object) Set object
\*/
setproto.bind = function (attr, a, b) {
var data = {};
if (typeof a == "function") {
this.bindings[attr] = a;
} else {
var aname = b || attr;
this.bindings[attr] = function (v) {
data[aname] = v;
a.attr(data);
};
}
return this;
};
setproto.attr = function (value) {
var unbound = {};
for (var k in value) {
if (this.bindings[k]) {
this.bindings[k](value[k]);
} else {
unbound[k] = value[k];
}
}
for (var i = 0, ii = this.items.length; i < ii; i++) {
this.items[i].attr(value);
this.items[i].attr(unbound);
}
return this;
};
@ -210,4 +310,4 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
}
return set;
};
});
});

1692
src/svg.js

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@
{{~it.out :item:index}}
<article id="{{=item[0].title}}">
<header>
<h3 class="{{=item[0].clas}}">{{=item[0].name}}<a href="#{{=item[0].title}}" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line {{=item[0].line}} in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#{{=item[0].line}}">&#x27ad;</a></h3>
<h3 class="{{=item[0].clas}}">{{=item[0].name}}<a href="#{{=item[0].title}}" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line {{=item[0].line}} in the source" href="https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js#L{{=item[0].line}}">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="{{=item[0].title}}-extra"></div>

75
test.html Normal file
View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 181.4199981689453 189.9199981689453">
<desc>Created with Snap</desc>
<defs>
<rect width="10" height="10" class="svg---mgr"/>
</defs>
<g>
<image xlink:href="http://labels.labellogiclive.com/picnic_12_p1_pic001_uk__v0.svg" preserveAspectRatio="none" x="0" y="0" width="181.42" height="189.92"/>
</g>
<g transform="matrix(1,0,0,1,9.5963,8.3968)">
<g style="cursor: auto;">
<text x="80.28845687866212" y="1.1127823638916006" style="font-family: Helvetica; font-size: 41px; font-style: normal; font-weight: normal; text-decoration: none; text-anchor: middle;">
<tspan space="preserve" x="80.28845687866212" dy="1em">&lt;&lt;title&gt;&gt;</tspan>
</text>
<rect x="0" y="0" width="160.57691375732423" height="49.3193147277832" fill="#ffffff" stroke="#000000" style="fill-opacity: 0; stroke-width: 0.5px; stroke-dasharray: 5px, 2px;"/>
</g>
<line x1="80.28845687866212" x2="80.28845687866212" y1="0" y2="-10" fill="none" stroke="#eeeeee" style="stroke-dasharray: 2px, 2px; stroke-width: 0.7px; visibility: hidden;"/>
<circle cx="80.28845687866212" cy="-10" r="2" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; visibility: hidden;"/>
<rect x="78.28845687866212" y="-2" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: n-resize; visibility: hidden;"/>
<rect x="158.57691375732423" y="22.6596573638916" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: e-resize; visibility: hidden;"/>
<rect x="78.28845687866212" y="47.3193147277832" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: s-resize; visibility: hidden;"/>
<rect x="-2" y="22.6596573638916" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: w-resize; visibility: hidden;"/>
</g>
<g transform="matrix(1,0,0,1,9.5963,59.6773)">
<g style="cursor: auto;">
<text x="80.43839973449704" y="1.263066406250001" style="font-family: Helvetica; font-size: 18px; font-style: normal; font-weight: normal; text-decoration: none; text-anchor: middle;">
<tspan space="preserve" x="80.43839973449704" dy="1em">&lt;&lt;description&gt;&gt;</tspan>
</text>
<rect x="0" y="0" width="160.87679946899408" height="23.229257812500002" fill="#ffffff" stroke="#000000" style="fill-opacity: 0; stroke-width: 0.5px; stroke-dasharray: 5px, 2px;"/>
</g>
<line x1="80.43839973449704" x2="80.43839973449704" y1="0" y2="-10" fill="none" stroke="#eeeeee" style="stroke-dasharray: 2px, 2px; stroke-width: 0.7px; visibility: hidden;"/>
<circle cx="80.43839973449704" cy="-10" r="2" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; visibility: hidden;"/>
<rect x="78.43839973449704" y="-2" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: n-resize; visibility: hidden;"/>
<rect x="158.87679946899408" y="9.614628906250001" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: e-resize; visibility: hidden;"/>
<rect x="78.43839973449704" y="21.229257812500002" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: s-resize; visibility: hidden;"/>
<rect x="-2" y="9.614628906250001" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: w-resize; visibility: hidden;"/>
</g>
<g transform="matrix(1,0,0,1,55.179,84.8677)">
<g style="cursor: auto;">
<text x="24.509714508056643" y="4.783778915405273" style="font-family: Helvetica; font-size: 10px; font-style: normal; font-weight: normal; text-decoration: none; text-anchor: middle;">
<tspan space="preserve" x="24.509714508056643" dy="1em">&lt;&lt;price&gt;&gt;</tspan>
</text>
<rect x="0" y="0" width="49.019429016113286" height="21.130057830810546" fill="#ffffff" stroke="#000000" style="fill-opacity: 0; stroke-width: 0.5px; stroke-dasharray: 5px, 2px;"/>
</g>
<line x1="24.509714508056643" x2="24.509714508056643" y1="0" y2="-10" fill="none" stroke="#eeeeee" style="stroke-dasharray: 2px, 2px; stroke-width: 0.7px; visibility: hidden;"/>
<circle cx="24.509714508056643" cy="-10" r="2" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; visibility: hidden;"/>
<rect x="22.509714508056643" y="-2" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: n-resize; visibility: hidden;"/>
<rect x="47.019429016113286" y="8.565028915405273" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: e-resize; visibility: hidden;"/>
<rect x="22.509714508056643" y="19.130057830810546" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: s-resize; visibility: hidden;"/>
<rect x="-2" y="8.565028915405273" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: w-resize; visibility: hidden;"/>
</g>
<g transform="matrix(1,0,0,1,9.5963,85.1675)">
<g style="cursor: move;">
<text x="21.660800247192384" y="2.757330703735356" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-weight: normal; text-decoration: none; text-anchor: middle;">
<tspan space="preserve" x="21.660800247192384" dy="1em">Use By:</tspan>
</text>
<rect x="0" y="0" width="43.32160049438477" height="20.53028640747071" fill="#ffffff" stroke="#000000" style="fill-opacity: 0; stroke-width: 0.5px; stroke-dasharray: 5px, 2px;"/>
</g>
<line x1="21.660800247192384" x2="21.660800247192384" y1="0" y2="-10" fill="none" stroke="#eeeeee" style="stroke-dasharray: 2px, 2px; stroke-width: 0.7px; visibility: visible;"/>
<circle cx="21.660800247192384" cy="-10" r="2" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; visibility: visible;"/>
<rect x="19.660800247192384" y="-2" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: n-resize; visibility: visible;"/>
<rect x="41.32160049438477" y="8.265143203735356" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: e-resize; visibility: visible;"/>
<rect x="19.660800247192384" y="18.53028640747071" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: s-resize; visibility: visible;"/>
<rect x="-2" y="8.265143203735356" width="4" height="4" fill="#000000" stroke="#eeeeee" style="stroke-width: 0.4px; cursor: w-resize; visibility: visible;"/>
</g>
</svg>
</body>
</html>

38
test/attradd.js Normal file
View File

@ -0,0 +1,38 @@
describe("Attributes += methods", function () {
var s, r;
beforeEach(function () {
s = Snap(100, 100);
r = s.rect(10, 10, 50, 50);
});
afterEach(function () {
s.remove();
});
it("+=10", function () {
r.attr({x: "+=10"});
expect(r.node.getAttribute("x")).to.be("20");
});
it("-=10", function () {
r.attr({x: "-=10"});
expect(r.node.getAttribute("x")).to.be("0");
});
it("*=2", function () {
r.attr({x: "*=2"});
expect(r.node.getAttribute("x")).to.be("20");
});
it("/=2", function () {
r.attr({x: "/=2"});
expect(r.node.getAttribute("x")).to.be("5");
});
it("+=1em", function () {
var em = s.rect(0, 0, "1em", "1em");
em = em.getBBox().w;
r.attr({x: "+=1em"});
expect(r.node.getAttribute("x")).to.eql(10 + em);
});
it("-=.3em", function () {
var em = s.rect(0, 0, "1em", "1em");
em = em.getBBox().w;
r.attr({x: "-=.3em"});
expect((+r.node.getAttribute("x")).toFixed(2)).to.eql((10 - em * .3).toFixed(2));
});
});

55
test/class.js Normal file
View File

@ -0,0 +1,55 @@
describe("Class methods", function () {
var s, r;
beforeEach(function () {
s = Snap(100, 100);
r = s.rect(10, 10, 50, 50);
});
afterEach(function () {
s.remove();
});
it("elproto.addClass one", function() {
r.addClass("one");
expect(r.node.className.baseVal).to.be("one");
});
it("elproto.addClass two", function() {
r.addClass("one two");
expect(r.node.className.baseVal).to.be("one two");
});
it("elproto.addClass two (spacing)", function() {
r.addClass("\tone two ");
expect(r.node.className.baseVal).to.be("one two");
});
it("elproto.addClass three", function() {
r.addClass("one two three");
expect(r.node.className.baseVal).to.be("one two three");
});
it("elproto.removeClass 1", function() {
r.addClass("one two three");
r.removeClass("two");
expect(r.node.className.baseVal).to.be("one three");
});
it("elproto.removeClass 2", function() {
r.addClass("one two three");
r.removeClass("two one");
expect(r.node.className.baseVal).to.be("three");
});
it("elproto.hasClass", function() {
r.addClass("one two three");
expect(r.hasClass("two")).to.be(true);
});
it("elproto.toggleClass 1", function() {
r.addClass("one two three");
r.toggleClass("two one");
expect(r.node.className.baseVal).to.be("three");
});
it("elproto.toggleClass 2", function() {
r.addClass("one three");
r.toggleClass("two one", false);
expect(r.node.className.baseVal).to.be("three");
});
it("elproto.toggleClass 3", function() {
r.addClass("one three");
r.toggleClass("two one", true);
expect(r.node.className.baseVal).to.be("one three two");
});
});

View File

@ -55,28 +55,28 @@ describe("Filter methods", function () {
});
it("Snap.filter.shadow - dx & dy", function() {
var str = Snap.filter.shadow(5, 5);
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
str = Snap.filter.shadow(-1, 3);
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
});
it("Snap.filter.shadow - dx & dy, blur", function() {
var str = Snap.filter.shadow(5, 5, 5);
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="5"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="5"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
str = Snap.filter.shadow(-1, 3, 10);
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="10"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="10"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="#000000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
});
it("Snap.filter.shadow - dx & dy, color", function() {
var str = Snap.filter.shadow(5, 5, '#F00');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#ff0000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#ff0000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="#F00"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
str = Snap.filter.shadow(-1, 3, 'hsla(128deg, 50%, 50%, 0.8)');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="rgba(64,191,81,0.8)"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="4"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="rgba(64,191,81,0.8)"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="hsla(128deg, 50%, 50%, 0.8)"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
});
it("Snap.filter.shadow - dx & dy, blur & color", function() {
var str = Snap.filter.shadow(5, 5, 5, '#F00');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="5"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#ff0000"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="5"/><feOffset dx="5" dy="5" result="offsetblur"/><feFlood flood-color="#ff0000"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
str = Snap.filter.shadow(-1, 3, 10, 'hsla(128deg, 50%, 50%, 0.8)');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="10"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="rgba(64,191,81,0.8)"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
expect(str).to.be('<feGaussianBlur in="SourceAlpha" stdDeviation="10"/><feOffset dx="-1" dy="3" result="offsetblur"/><feFlood flood-color="rgba(64,191,81,0.8)"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="1"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>');
});

View File

@ -57,6 +57,28 @@ describe("Paper methods", function () {
paper.remove();
});
it("Paper.svg", function() {
var c = paper.svg();
expect(c.node.nodeName).to.be("svg");
expect(c.node.parentNode).to.be(paper.node);
});
it("Paper.svg(x, y)", function() {
var c = paper.svg(100, 200);
expect(c.node.nodeName).to.be("svg");
expect(c.node.x.baseVal.value).to.be(100);
expect(c.node.y.baseVal.value).to.be(200);
expect(c.node.parentNode).to.be(paper.node);
});
it("Paper.svg(x, y, w, h, viewbox)", function() {
var c = paper.svg(100, 200, 300, 400, 10, 20, 30, 40);
expect(c.node.nodeName).to.be("svg");
expect(c.node.x.baseVal.value).to.be(100);
expect(c.node.y.baseVal.value).to.be(200);
expect(c.node.width.baseVal.value).to.be(300);
expect(c.node.height.baseVal.value).to.be(400);
expect(c.node.getAttribute("viewBox")).to.be("10 20 30 40");
expect(c.node.parentNode).to.be(paper.node);
});
it("Paper.el", function() {
var c = paper.el("circle");
expect(c.node.nodeName).to.be("circle");

View File

@ -314,7 +314,7 @@ describe("Path methods", function () {
"M80 10 Q 110 40, 140 10 Z" +
"M80 50 Q 90 70, 100 50 T 120 50 Z" +
"M80 80 A 10 10 0 0 0 120 80 Z";
expect(Snap.path.isPointInside(path, 15, 35)).to.be(true);
expect(Snap.path.isPointInside(path, 35, 75)).to.be(true);
expect(Snap.path.isPointInside(path, 15, 102)).to.be(true);
@ -343,6 +343,9 @@ describe("Path methods", function () {
expect(Snap.path.isPointInside(path, 100, 70)).to.be(false);
expect(Snap.path.isPointInside(path, 115, 96)).to.be(false);
expect(Snap.path.isPointInside(path, 85, 96)).to.be(false);
// bug #248
expect(Snap.path.isPointInside("M1.4315332974182866,4.405806462382467 L57.26133189673147,176.23225849529868 A185.30156250000002,185.30156250000002 0 0 1 -172.2890356108522,-68.21405480708441 L-4.307225890271305,-1.7053513701771101 A4.6325390625,4.6325390625 0 0 0 1.4315332974182866,4.405806462382467 Z", -58.296875, 70.96875)).to.be(true);
});
it("Snap.path.intersection", function () {
@ -379,19 +382,19 @@ describe("Path methods", function () {
checkXY(5, 27.5, 50);
checkXY(6, 40, 85.71);
checkXY(7, 25.5, 90);
checkXY(8, 48.08, 108.79);
checkXY(9, 24.45, 110.99);
checkXY(8, 48.06, 108.75);
checkXY(9, 24.46, 110.77);
checkXY(10, 45, 100);
checkXY(11, 25, 100);
checkXY(12, 23.92, 121.52);
checkXY(13, 59.46, 141.32);
checkXY(12, 23.91, 121.7);
checkXY(13, 59.46, 141.31);
checkXY(14, 59, 140);
checkXY(15, 23, 140);
checkXY(16, 108.53, 24.91);
checkXY(16, 108.55, 24.82);
checkXY(17, 83.33, 10);
checkXY(18, 106, 42);
checkXY(19, 104.81, 50);
checkXY(20, 97.45, 99.7);
checkXY(20, 97.49, 99.44);
checkXY(21, 100.37, 80);
});
});

View File

@ -109,4 +109,33 @@ describe("Primitives creation", function () {
expect(C.getAttribute("x")).to.be("10");
expect(C.textContent).to.be("test");
});
it("creates a mask", function () {
var c = s.mask();
var C = document.querySelector("mask");
expect(C).to.not.be(null);
expect(C).to.be(c.node);
});
it("creates a pattern", function () {
var c = s.ptrn();
var C = document.querySelector("pattern");
expect(C).to.not.be(null);
expect(C).to.be(c.node);
});
it("creates a pattern(x, y)", function() {
var c = s.ptrn(100, 200);
expect(c.node.nodeName).to.be("pattern");
expect(c.node.x.baseVal.value).to.be(100);
expect(c.node.y.baseVal.value).to.be(200);
expect(c.node.parentNode).to.be(s.node);
});
it("creates a pattern(x, y, w, h, viewbox)", function() {
var c = s.ptrn(100, 200, 300, 400, 10, 20, 30, 40);
expect(c.node.nodeName).to.be("pattern");
expect(c.node.x.baseVal.value).to.be(100);
expect(c.node.y.baseVal.value).to.be(200);
expect(c.node.width.baseVal.value).to.be(300);
expect(c.node.height.baseVal.value).to.be(400);
expect(c.node.getAttribute("viewBox")).to.be("10 20 30 40");
expect(c.node.parentNode).to.be(s.node);
});
});

View File

@ -82,6 +82,51 @@ describe("Set methods", function () {
expect(set[1]).to.be(rect2);
expect(set[2]).to.be(rect3);
});
it("Set.attr", function() {
var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40);
var set = Snap.set(rect1, rect2);
set.attr({"fill": "#ff0000"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#ff0000");
set.attr({"stroke": "#0000ff"});
expect(rect1.node.getAttribute("stroke")).to.be("#0000ff");
expect(rect2.node.getAttribute("stroke")).to.be("#0000ff");
});
it("Set.bind", function() {
var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40);
var set = Snap.set(rect1, rect2);
// Setting "stroke" on set only applies it to rect1
set.bind("stroke", rect1);
// Setting "fill1" on set maps to fill attribute on rect1
set.bind("fill1", rect1, "fill");
// Setting "fill2" on set maps to fill attribute on rect2
set.bind("fill2", function(v) { rect2.attr({"fill": v}); });
// Set everything to black
rect1.attr({"fill": "#000000", "stroke": "#000000"});
rect2.attr({"fill": "#000000", "stroke": "#000000"});
set.attr({"fill1": "#00ff00"});
expect(rect1.node.getAttribute("fill")).to.be("#00ff00");
expect(rect2.node.getAttribute("fill")).to.be("#000000");
// Will trigger the fallback implementation of attr which is
// to set that attribute on all elements in the set.
set.attr({"fill": "#ff0000"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#ff0000");
set.attr({"fill2": "#00ff00"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#00ff00");
set.attr({"stroke": "#0000ff"});
expect(rect1.node.getAttribute("stroke")).to.be("#0000ff");
expect(rect2.node.getAttribute("stroke")).to.be("#000000");
});
it("Set.splice - remove only", function() {
var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40);
@ -119,4 +164,4 @@ describe("Set methods", function () {
expect(removedSet[1]).to.be(rect2);
expect(removedSet[2]).to.be(rect4);
});
});
});

View File

@ -15,7 +15,7 @@
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.">
<title>Savage Tests</title>
<title>Snap Tests</title>
<style media="screen">
svg {
position: absolute;
@ -28,15 +28,17 @@
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/expect.js/expect.js"></script>
<script src="../node_modules/expect.js/index.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script>mocha.setup("bdd");</script>
<script src="system.js"></script>
<script src="paper.js"></script>
<script src="snap-tests.js"></script>
<script src="class.js"></script>
<script src="primitives.js"></script>
<script src="colors.js"></script>
<script src="attrs.js"></script>
<script src="attradd.js"></script>
<script src="path.js"></script>
<script src="element.js"></script>
<script src="set.js"></script>