Added filters and rewrote animation library (mina). It still WIP

master
Dmitry Baranovskiy 2013-08-15 18:29:47 +10:00
parent d07cb4cf1b
commit 3cf4c5e7d6
10 changed files with 602 additions and 197 deletions

View File

@ -34,7 +34,8 @@ module.exports = function(grunt) {
"savage.path.js", "savage.path.js",
"savage.set.js", "savage.set.js",
"savage.equal.js", "savage.equal.js",
"savage.mouse.js" "savage.mouse.js",
"savage.filter.default.js"
] ]
} }
} }

140
mina.js
View File

@ -41,110 +41,81 @@ window.mina = (function () {
timer = function () { timer = function () {
return +new Date; return +new Date;
}, },
sta = function (val) {
var a = this;
if (val == null) {
return a.s;
}
var ds = a.s - val;
a.b += a.dur * ds;
a.B += a.dur * ds;
a.s = val;
},
speed = function (val) {
var a = this;
if (val == null) {
return a.spd;
}
a.spd = val;
},
duration = function (val) {
var a = this;
if (val == null) {
return a.dur;
}
a.s = a.s * val / a.dur;
a.dur = val;
},
frame = function () { frame = function () {
var value, one; for (var i = 0, ii = animations.length; i < ii; i++) {
for (var i = 0; i < animations.length; i++) {
var a = animations[i], var a = animations[i],
gen = a.b + (a.gen() - a.b) * a["*"] + a["+"]; b = a.get(),
if (isArray(a.a)) { res;
value = []; a.s = (b - a.b) / (a.dur / a.spd);
for (var j = 0, jj = a.a.length; j < jj; j++) { if (a.s >= 1) {
value[j] = a.dif[j](gen); animations.splice(i, 1);
one = a.A[j] - a.a[j]; a.s = 1;
value[j] = one ? }
a.a[j] + a.easing((value[j] - a.a[j]) / one) * one : if (isArray(a.start)) {
a.a[j]; 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 { } else {
value = a.dif(gen); res = a.start + (a.end - a.start) * a.easing(a.s);
one = a.A - a.a;
value = a.a + a.easing((value - a.a) / one) * one;
}
try {
if (a.stopper(gen)) {
if (--a.iterations) {
a["+"] += a.b - a.B; // -dur
} else {
animations.splice(i--, 1);
a.framer(a.A);
a.callback && a.callback();
}
} else {
a.framer(value);
}
} catch (e) {
console.error(e);
// swallow
} }
a.set(res);
} }
animations.length && requestAnimFrame(frame); animations.length && requestAnimFrame(frame);
}, },
setSpeed = function (speed) { mina = function (a, A, b, B, get, set, easing) {
this["*"] = Math.abs(speed);
this.speed = speed;
if (speed < 0) {
var t = this.a;
this.a = this.A;
this.A = t;
this.dif = diff(this.a, this.b, this.A, this.B);
// TODO remove?
this.stopper = stopperEnd(this.b, this.B);
}
},
stopme = function () {
for (var i = 0, ii = animations.length; i < ii; i++) {
if (animations[i] == this) {
animations.splice(i, 1);
return;
}
}
},
queue = function (a, A, b, B, framer, callback, gen, stopper) {
var anim = { var anim = {
framer: framer, start: a,
callback: callback, end: A,
dif: diff(a, b, A, B),
easing: mina.linear,
"+": 0,
"*": 1,
gen: gen,
speed: 1,
iterations: 1,
stopper: stopper,
a: a,
b: b, b: b,
A: A, s: 0,
B: B, dur: B - b,
setSpeed: setSpeed, spd: 1,
stop: stopme get: get,
set: set,
easing: easing || mina.linear,
status: sta,
speed: speed,
duration: duration
}; };
animations.push(anim); animations.push(anim);
animations.length == 1 && requestAnimFrame(frame); animations.length == 1 && requestAnimFrame(frame);
return anim; return anim;
},
stopperEnd = function (a, A) {
return function (value) {
return a < A ? value >= A : value <= A;
};
},
stopperStart = function (a, A) {
return function (value) {
return a < A ? value <= a : value >= a;
};
},
mina = function (a, A, ms, frameHandler, callback) {
var b = timer(),
B = b + ms;
frameHandler(a);
return queue(a, A, b, B, frameHandler, callback, timer, stopperEnd(b, B));
}; };
mina.time = timer;
mina.linear = function (n) { mina.linear = function (n) {
return n; return n;
}; };
mina.easeout = function (n) { mina.easeout = function (n) {
return Math.pow(n, 1.7); return Math.pow(n, 1.7);
}; };
mina.easein = function (n) { mina.easein = function (n) {
return Math.pow(n, .48); return Math.pow(n, .48);
}; };
mina.easeinout = function (n) { mina.easeinout = function (n) {
@ -170,7 +141,8 @@ window.mina = (function () {
if (n == !!n) { if (n == !!n) {
return n; return n;
} }
return Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1; return Math.pow(2, -10 * n) * Math.sin((n - .075) *
(2 * Math.PI) / .3) + 1;
}; };
mina.bounce = function (n) { mina.bounce = function (n) {
var s = 7.5625, var s = 7.5625,

6
savage-min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,16 @@
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var names = {}, var names = {},
reUnit = /[a-z]+$/i, reUnit = /[a-z]+$/i,

103
savage.filter.default.js Normal file
View File

@ -0,0 +1,103 @@
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype,
pproto = Paper.prototype,
rgurl = /^\s*url\((.+)\)/,
Str = String,
$ = Savage._.$;
Savage.filter = {};
pproto.filter = function (filstr) {
var f = Savage.parse(Str(filstr)),
id = Savage._.id(),
width = $(this.node, "width") || this.node.offsetWidth,
height = $(this.node, "height") || this.node.offsetHeight,
filter = $("filter");
$(filter, {
id: id,
filterUnits: "userSpaceOnUse",
x: 0,
y: 0,
width: width,
height: height
});
filter.appendChild(f.node);
this.defs.appendChild(filter);
return new Element(filter);
};
eve.on("savage.util.getattr.filter", function () {
eve.stop();
var p = $(this.node, "filter");
if (p) {
var match = Str(p).match(rgurl);
return match && Savage.select(match[1]);
}
});
eve.on("savage.util.attr.filter", function (value) {
if (value instanceof Element && value.type == "filter") {
eve.stop();
var id = value.node.id;
if (!id) {
$(value.node, {id: value.id});
id = value.id;
}
$(this.node, {
filter: "url(#" + id + ")"
});
}
if (!value) {
eve.stop();
this.node.removeAttribute("filter");
}
});
Savage.filter.blur = function (x, y) {
if (x == null) {
x = 2;
}
var def = y == null ? x : [x, y];
return Savage.format('\<feGaussianBlur stdDeviation="{def}"/>', {
def: def
});
};
Savage.filter.blur.toString = function () {
return this();
};
Savage.filter.shadow = function (dx, dy, blur, color) {
color = Savage.color(color || "#000");
if (blur == null) {
blur = 2;
}
if (dx == null) {
dx = 0;
dy = 4;
}
if (dy == null) {
dy = dx;
}
return Savage.format('<feColorMatrix type="matrix" in="SourceAlpha" result="colored" values="0 0 0 0 {r} 0 0 0 0 {g} 0 0 0 0 {b} 0 0 0 {o} 0"/><feGaussianBlur in="colored" stdDeviation="{blur}" result="blur"/><feOffset in="blur" dx="{dx}" dy="{dy}" result="offsetBlur"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="SourceGraphic"/></feMerge>', {
r: color.r,
g: color.g,
b: color.b,
o: color.opacity,
dx: dx,
dy: dy,
blur: blur
});
};
Savage.filter.shadow.toString = function () {
return this();
};
});

396
savage.js
View File

@ -28,7 +28,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
// build: 2013-08-09 // build: 2013-08-15
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -444,110 +444,81 @@ window.mina = (function () {
timer = function () { timer = function () {
return +new Date; return +new Date;
}, },
sta = function (val) {
var a = this;
if (val == null) {
return a.s;
}
var ds = a.s - val;
a.b += a.dur * ds;
a.B += a.dur * ds;
a.s = val;
},
speed = function (val) {
var a = this;
if (val == null) {
return a.spd;
}
a.spd = val;
},
duration = function (val) {
var a = this;
if (val == null) {
return a.dur;
}
a.s = a.s * val / a.dur;
a.dur = val;
},
frame = function () { frame = function () {
var value, one; for (var i = 0, ii = animations.length; i < ii; i++) {
for (var i = 0; i < animations.length; i++) {
var a = animations[i], var a = animations[i],
gen = a.b + (a.gen() - a.b) * a["*"] + a["+"]; b = a.get(),
if (isArray(a.a)) { res;
value = []; a.s = (b - a.b) / (a.dur / a.spd);
for (var j = 0, jj = a.a.length; j < jj; j++) { if (a.s >= 1) {
value[j] = a.dif[j](gen); animations.splice(i, 1);
one = a.A[j] - a.a[j]; a.s = 1;
value[j] = one ? }
a.a[j] + a.easing((value[j] - a.a[j]) / one) * one : if (isArray(a.start)) {
a.a[j]; 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 { } else {
value = a.dif(gen); res = a.start + (a.end - a.start) * a.easing(a.s);
one = a.A - a.a;
value = a.a + a.easing((value - a.a) / one) * one;
}
try {
if (a.stopper(gen)) {
if (--a.iterations) {
a["+"] += a.b - a.B; // -dur
} else {
animations.splice(i--, 1);
a.framer(a.A);
a.callback && a.callback();
}
} else {
a.framer(value);
}
} catch (e) {
console.error(e);
// swallow
} }
a.set(res);
} }
animations.length && requestAnimFrame(frame); animations.length && requestAnimFrame(frame);
}, },
setSpeed = function (speed) { mina = function (a, A, b, B, get, set, easing) {
this["*"] = Math.abs(speed);
this.speed = speed;
if (speed < 0) {
var t = this.a;
this.a = this.A;
this.A = t;
this.dif = diff(this.a, this.b, this.A, this.B);
// TODO remove?
this.stopper = stopperEnd(this.b, this.B);
}
},
stopme = function () {
for (var i = 0, ii = animations.length; i < ii; i++) {
if (animations[i] == this) {
animations.splice(i, 1);
return;
}
}
},
queue = function (a, A, b, B, framer, callback, gen, stopper) {
var anim = { var anim = {
framer: framer, start: a,
callback: callback, end: A,
dif: diff(a, b, A, B),
easing: mina.linear,
"+": 0,
"*": 1,
gen: gen,
speed: 1,
iterations: 1,
stopper: stopper,
a: a,
b: b, b: b,
A: A, s: 0,
B: B, dur: B - b,
setSpeed: setSpeed, spd: 1,
stop: stopme get: get,
set: set,
easing: easing || mina.linear,
status: sta,
speed: speed,
duration: duration
}; };
animations.push(anim); animations.push(anim);
animations.length == 1 && requestAnimFrame(frame); animations.length == 1 && requestAnimFrame(frame);
return anim; return anim;
},
stopperEnd = function (a, A) {
return function (value) {
return a < A ? value >= A : value <= A;
};
},
stopperStart = function (a, A) {
return function (value) {
return a < A ? value <= a : value >= a;
};
},
mina = function (a, A, ms, frameHandler, callback) {
var b = timer(),
B = b + ms;
frameHandler(a);
return queue(a, A, b, B, frameHandler, callback, timer, stopperEnd(b, B));
}; };
mina.time = timer;
mina.linear = function (n) { mina.linear = function (n) {
return n; return n;
}; };
mina.easeout = function (n) { mina.easeout = function (n) {
return Math.pow(n, 1.7); return Math.pow(n, 1.7);
}; };
mina.easein = function (n) { mina.easein = function (n) {
return Math.pow(n, .48); return Math.pow(n, .48);
}; };
mina.easeinout = function (n) { mina.easeinout = function (n) {
@ -573,7 +544,8 @@ window.mina = (function () {
if (n == !!n) { if (n == !!n) {
return n; return n;
} }
return Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1; return Math.pow(2, -10 * n) * Math.sin((n - .075) *
(2 * Math.PI) / .3) + 1;
}; };
mina.bounce = function (n) { mina.bounce = function (n) {
var s = 7.5625, var s = 7.5625,
@ -970,6 +942,9 @@ function $(el, attr) {
el = $(el); el = $(el);
} }
if (typeof attr == "string") { if (typeof attr == "string") {
if (attr.substring(0, 6) == "xlink:") {
return el.getAttributeNS(xlink, attr.substring(6));
}
return el.getAttribute(attr); return el.getAttribute(attr);
} }
for (var key in attr) if (attr[has](key)) { for (var key in attr) if (attr[has](key)) {
@ -991,6 +966,7 @@ function $(el, attr) {
return el; return el;
} }
Savage._.$ = $; Savage._.$ = $;
Savage._.id = ID;
function getAttrs(el) { function getAttrs(el) {
var attrs = el.attributes, var attrs = el.attributes,
name, name,
@ -1020,6 +996,52 @@ function is(o, type) {
(type == "object" && o === Object(o)) || (type == "object" && o === Object(o)) ||
objectToString.call(o).slice(8, -1).toLowerCase() == type; objectToString.call(o).slice(8, -1).toLowerCase() == type;
} }
/*\
* Savage.format
[ method ]
**
* Replaces construction of type `{<name>}` to the corresponding argument.
**
> Parameters
**
- token (string) string to format
- json (object) object which properties will be used as a replacement
= (string) formated string
> Usage
| // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
| paper.path(Savage.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
| x: 10,
| y: 20,
| dim: {
| width: 40,
| height: 50,
| "negative width": -40
| }
| }));
\*/
Savage.format = (function () {
var tokenRegex = /\{([^\}]+)\}/g,
objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
replacer = function (all, key, obj) {
var res = obj;
key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
name = name || quotedName;
if (res) {
if (name in res) {
res = res[name];
}
typeof res == "function" && isFunc && (res = res());
}
});
res = (res == null || res == obj ? all : res) + "";
return res;
};
return function (str, obj) {
return Str(str).replace(tokenRegex, function (all, key) {
return replacer(all, key, obj);
});
};
})();
var preload = (function () { var preload = (function () {
function onerror() { function onerror() {
this.parentNode.removeChild(this); this.parentNode.removeChild(this);
@ -1514,7 +1536,7 @@ Savage.getRGB = cacher(function (colour) {
} }
rgb = {r: red, g: green, b: blue, toString: rgbtoString}; rgb = {r: red, g: green, b: blue, toString: rgbtoString};
rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
is(opacity, "finite") && (rgb.opacity = opacity); rgb.opacity = is(opacity, "finite") ? opacity : 1;
return rgb; return rgb;
} }
return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
@ -1614,6 +1636,7 @@ packageRGB = function (r, g, b, o) {
r: r, r: r,
g: g, g: g,
b: b, b: b,
opacity: is(o, "finite") ? o : 1,
hex: Savage.rgb(r, g, b), hex: Savage.rgb(r, g, b),
toString: rgbtoString toString: rgbtoString
}; };
@ -1648,12 +1671,14 @@ Savage.color = function (clr) {
clr.r = rgb.r; clr.r = rgb.r;
clr.g = rgb.g; clr.g = rgb.g;
clr.b = rgb.b; clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex; clr.hex = rgb.hex;
} else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
rgb = Savage.hsl2rgb(clr); rgb = Savage.hsl2rgb(clr);
clr.r = rgb.r; clr.r = rgb.r;
clr.g = rgb.g; clr.g = rgb.g;
clr.b = rgb.b; clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex; clr.hex = rgb.hex;
} else { } else {
if (is(clr, "string")) { if (is(clr, "string")) {
@ -2411,22 +2436,41 @@ function arrayFirstValue(arr) {
return p; return p;
}; };
// animation // animation
function applyAttr(el, key, f) { function slice(from, to, f) {
var at = {}; return function (arr) {
return function (value) { var res = arr.slice(from, to);
at[key] = f ? f(value) : value; if (res.length == 1) {
el.attr(at); res = res[0];
}
return f ? f(res) : res;
}; };
} }
elproto.animate = function (attrs, ms, callback) { elproto.animate = function (attrs, ms, callback) {
var fkeys = [], tkeys = [], keys = {}, from, to, f, eq;
for (var key in attrs) if (attrs[has](key)) { for (var key in attrs) if (attrs[has](key)) {
if (this.equal) { if (this.equal) {
var eq = this.equal(key, Str(attrs[key])); eq = this.equal(key, Str(attrs[key]));
return mina(eq.from, eq.to, ms, applyAttr(this, key, eq.f)); from = eq.from;
to = eq.to;
f = eq.f;
} else { } else {
return mina(+this.attr(key), +attrs[key], ms, applyAttr(this, key)); from = +this.attr(key);
to = +attrs[key];
} }
var len = is(from, "array") ? from.length : 1;
keys[key] = slice(fkeys.length, fkeys.length + len, f);
fkeys = fkeys.concat(from);
tkeys = tkeys.concat(to);
} }
var now = mina.time(),
el = this;
return mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
var attr = {};
for (var key in keys) if (keys[has](key)) {
attr[key] = keys[key](val);
}
el.attr(attr);
});
}; };
}(Element.prototype)); }(Element.prototype));
Savage.parse = function (svg) { Savage.parse = function (svg) {
@ -2434,10 +2478,13 @@ Savage.parse = function (svg) {
pointer = f; pointer = f;
eve.on("elemental.tag", function (data, extra, raw) { eve.on("elemental.tag", function (data, extra, raw) {
var tag = $(data); var tag = $(data);
$(tag, extra); extra && $(tag, extra);
pointer.appendChild(tag); pointer.appendChild(tag);
pointer = tag; pointer = tag;
}); });
eve.on("elemental.text", function (text) {
pointer.appendChild(document.createTextNode(text));
});
eve.on("elemental./tag", function () { eve.on("elemental./tag", function () {
pointer = pointer.parentNode; pointer = pointer.parentNode;
}); });
@ -2446,7 +2493,7 @@ Savage.parse = function (svg) {
eve("savage.parsed", f); eve("savage.parsed", f);
}); });
elemental().parse(svg).end(); elemental().parse(svg).end();
return f; return new Fragment(f);
}; };
function Fragment(frag) { function Fragment(frag) {
this.node = frag; this.node = frag;
@ -2465,7 +2512,7 @@ Savage.fragment = function () {
f.appendChild(item); f.appendChild(item);
} }
if (typeof item == "string") { if (typeof item == "string") {
f.appendChild(Savage.parse(item)); f.appendChild(Savage.parse(item).node);
} }
} }
return new Fragment(f); return new Fragment(f);
@ -3234,6 +3281,19 @@ Savage.plugin = function (f) {
}; };
return Savage; return Savage;
}()); }());
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype, var elproto = Element.prototype,
is = Savage.is, is = Savage.is,
@ -4572,6 +4632,19 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
Savage.path.toString = toString; Savage.path.toString = toString;
Savage.path.clone = pathClone; Savage.path.clone = pathClone;
}); });
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var mmax = Math.max, var mmax = Math.max,
mmin = Math.min; mmin = Math.min;
@ -4771,6 +4844,19 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
return set; return set;
}; };
}); });
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var names = {}, var names = {},
reUnit = /[a-z]+$/i, reUnit = /[a-z]+$/i,
@ -4906,6 +4992,19 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
} }
}; };
}); });
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype, var elproto = Element.prototype,
has = "hasOwnProperty", has = "hasOwnProperty",
@ -5446,3 +5545,106 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
!draggable.length && Savage.unmousemove(dragMove).unmouseup(dragUp); !draggable.length && Savage.unmousemove(dragMove).unmouseup(dragUp);
}; };
}); });
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype,
pproto = Paper.prototype,
rgurl = /^\s*url\((.+)\)/,
Str = String,
$ = Savage._.$;
Savage.filter = {};
pproto.filter = function (filstr) {
var f = Savage.parse(Str(filstr)),
id = Savage._.id(),
width = $(this.node, "width") || this.node.offsetWidth,
height = $(this.node, "height") || this.node.offsetHeight,
filter = $("filter");
$(filter, {
id: id,
filterUnits: "userSpaceOnUse",
x: 0,
y: 0,
width: width,
height: height
});
filter.appendChild(f.node);
this.defs.appendChild(filter);
return new Element(filter);
};
eve.on("savage.util.getattr.filter", function () {
eve.stop();
var p = $(this.node, "filter");
if (p) {
var match = Str(p).match(rgurl);
return match && Savage.select(match[1]);
}
});
eve.on("savage.util.attr.filter", function (value) {
if (value instanceof Element && value.type == "filter") {
eve.stop();
var id = value.node.id;
if (!id) {
$(value.node, {id: value.id});
id = value.id;
}
$(this.node, {
filter: "url(#" + id + ")"
});
}
if (!value) {
eve.stop();
this.node.removeAttribute("filter");
}
});
Savage.filter.blur = function (x, y) {
if (x == null) {
x = 2;
}
var def = y == null ? x : [x, y];
return Savage.format('\<feGaussianBlur stdDeviation="{def}"/>', {
def: def
});
};
Savage.filter.blur.toString = function () {
return this();
};
Savage.filter.shadow = function (dx, dy, blur, color) {
color = Savage.color(color || "#000");
if (blur == null) {
blur = 2;
}
if (dx == null) {
dx = 0;
dy = 4;
}
if (dy == null) {
dy = dx;
}
return Savage.format('<feColorMatrix type="matrix" in="SourceAlpha" result="colored" values="0 0 0 0 {r} 0 0 0 0 {g} 0 0 0 0 {b} 0 0 0 {o} 0"/><feGaussianBlur in="colored" stdDeviation="{blur}" result="blur"/><feOffset in="blur" dx="{dx}" dy="{dy}" result="offsetBlur"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="SourceGraphic"/></feMerge>', {
r: color.r,
g: color.g,
b: color.b,
o: color.opacity,
dx: dx,
dy: dy,
blur: blur
});
};
Savage.filter.shadow.toString = function () {
return this();
};
});

View File

@ -1,3 +1,16 @@
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype, var elproto = Element.prototype,
has = "hasOwnProperty", has = "hasOwnProperty",

View File

@ -1,3 +1,16 @@
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var elproto = Element.prototype, var elproto = Element.prototype,
is = Savage.is, is = Savage.is,

View File

@ -1,3 +1,16 @@
// 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.
Savage.plugin(function (Savage, Element, Paper, glob) { Savage.plugin(function (Savage, Element, Paper, glob) {
var mmax = Math.max, var mmax = Math.max,
mmin = Math.min; mmin = Math.min;

99
svg.js
View File

@ -66,6 +66,9 @@ function $(el, attr) {
el = $(el); el = $(el);
} }
if (typeof attr == "string") { if (typeof attr == "string") {
if (attr.substring(0, 6) == "xlink:") {
return el.getAttributeNS(xlink, attr.substring(6));
}
return el.getAttribute(attr); return el.getAttribute(attr);
} }
for (var key in attr) if (attr[has](key)) { for (var key in attr) if (attr[has](key)) {
@ -87,6 +90,7 @@ function $(el, attr) {
return el; return el;
} }
Savage._.$ = $; Savage._.$ = $;
Savage._.id = ID;
function getAttrs(el) { function getAttrs(el) {
var attrs = el.attributes, var attrs = el.attributes,
name, name,
@ -116,6 +120,52 @@ function is(o, type) {
(type == "object" && o === Object(o)) || (type == "object" && o === Object(o)) ||
objectToString.call(o).slice(8, -1).toLowerCase() == type; objectToString.call(o).slice(8, -1).toLowerCase() == type;
} }
/*\
* Savage.format
[ method ]
**
* Replaces construction of type `{<name>}` to the corresponding argument.
**
> Parameters
**
- token (string) string to format
- json (object) object which properties will be used as a replacement
= (string) formated string
> Usage
| // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
| paper.path(Savage.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
| x: 10,
| y: 20,
| dim: {
| width: 40,
| height: 50,
| "negative width": -40
| }
| }));
\*/
Savage.format = (function () {
var tokenRegex = /\{([^\}]+)\}/g,
objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
replacer = function (all, key, obj) {
var res = obj;
key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
name = name || quotedName;
if (res) {
if (name in res) {
res = res[name];
}
typeof res == "function" && isFunc && (res = res());
}
});
res = (res == null || res == obj ? all : res) + "";
return res;
};
return function (str, obj) {
return Str(str).replace(tokenRegex, function (all, key) {
return replacer(all, key, obj);
});
};
})();
var preload = (function () { var preload = (function () {
function onerror() { function onerror() {
this.parentNode.removeChild(this); this.parentNode.removeChild(this);
@ -610,7 +660,7 @@ Savage.getRGB = cacher(function (colour) {
} }
rgb = {r: red, g: green, b: blue, toString: rgbtoString}; rgb = {r: red, g: green, b: blue, toString: rgbtoString};
rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
is(opacity, "finite") && (rgb.opacity = opacity); rgb.opacity = is(opacity, "finite") ? opacity : 1;
return rgb; return rgb;
} }
return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
@ -710,6 +760,7 @@ packageRGB = function (r, g, b, o) {
r: r, r: r,
g: g, g: g,
b: b, b: b,
opacity: is(o, "finite") ? o : 1,
hex: Savage.rgb(r, g, b), hex: Savage.rgb(r, g, b),
toString: rgbtoString toString: rgbtoString
}; };
@ -744,12 +795,14 @@ Savage.color = function (clr) {
clr.r = rgb.r; clr.r = rgb.r;
clr.g = rgb.g; clr.g = rgb.g;
clr.b = rgb.b; clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex; clr.hex = rgb.hex;
} else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
rgb = Savage.hsl2rgb(clr); rgb = Savage.hsl2rgb(clr);
clr.r = rgb.r; clr.r = rgb.r;
clr.g = rgb.g; clr.g = rgb.g;
clr.b = rgb.b; clr.b = rgb.b;
clr.opacity = 1;
clr.hex = rgb.hex; clr.hex = rgb.hex;
} else { } else {
if (is(clr, "string")) { if (is(clr, "string")) {
@ -1507,22 +1560,41 @@ function arrayFirstValue(arr) {
return p; return p;
}; };
// animation // animation
function applyAttr(el, key, f) { function slice(from, to, f) {
var at = {}; return function (arr) {
return function (value) { var res = arr.slice(from, to);
at[key] = f ? f(value) : value; if (res.length == 1) {
el.attr(at); res = res[0];
}
return f ? f(res) : res;
}; };
} }
elproto.animate = function (attrs, ms, callback) { elproto.animate = function (attrs, ms, callback) {
var fkeys = [], tkeys = [], keys = {}, from, to, f, eq;
for (var key in attrs) if (attrs[has](key)) { for (var key in attrs) if (attrs[has](key)) {
if (this.equal) { if (this.equal) {
var eq = this.equal(key, Str(attrs[key])); eq = this.equal(key, Str(attrs[key]));
return mina(eq.from, eq.to, ms, applyAttr(this, key, eq.f)); from = eq.from;
to = eq.to;
f = eq.f;
} else { } else {
return mina(+this.attr(key), +attrs[key], ms, applyAttr(this, key)); from = +this.attr(key);
to = +attrs[key];
} }
var len = is(from, "array") ? from.length : 1;
keys[key] = slice(fkeys.length, fkeys.length + len, f);
fkeys = fkeys.concat(from);
tkeys = tkeys.concat(to);
} }
var now = mina.time(),
el = this;
return mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
var attr = {};
for (var key in keys) if (keys[has](key)) {
attr[key] = keys[key](val);
}
el.attr(attr);
});
}; };
}(Element.prototype)); }(Element.prototype));
Savage.parse = function (svg) { Savage.parse = function (svg) {
@ -1530,10 +1602,13 @@ Savage.parse = function (svg) {
pointer = f; pointer = f;
eve.on("elemental.tag", function (data, extra, raw) { eve.on("elemental.tag", function (data, extra, raw) {
var tag = $(data); var tag = $(data);
$(tag, extra); extra && $(tag, extra);
pointer.appendChild(tag); pointer.appendChild(tag);
pointer = tag; pointer = tag;
}); });
eve.on("elemental.text", function (text) {
pointer.appendChild(document.createTextNode(text));
});
eve.on("elemental./tag", function () { eve.on("elemental./tag", function () {
pointer = pointer.parentNode; pointer = pointer.parentNode;
}); });
@ -1542,7 +1617,7 @@ Savage.parse = function (svg) {
eve("savage.parsed", f); eve("savage.parsed", f);
}); });
elemental().parse(svg).end(); elemental().parse(svg).end();
return f; return new Fragment(f);
}; };
function Fragment(frag) { function Fragment(frag) {
this.node = frag; this.node = frag;
@ -1561,7 +1636,7 @@ Savage.fragment = function () {
f.appendChild(item); f.appendChild(item);
} }
if (typeof item == "string") { if (typeof item == "string") {
f.appendChild(Savage.parse(item)); f.appendChild(Savage.parse(item).node);
} }
} }
return new Fragment(f); return new Fragment(f);