Commit 9962a268 by Dmitry Baranovskiy

Added split method to matrix, fixed caching a bit, first iteration of fix for…

Added split method to matrix, fixed caching a bit, first iteration of fix for correct transformation in IE for gradient and images.
parent f02c9d89
......@@ -659,6 +659,11 @@
R._path2string = function () {
return this.join(",").replace(p2s, "$1");
};
function repush(array, item) {
for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
return array.push(array.splice(i, 1)[0]);
}
}
function cacher(f, scope, postprocessor) {
function newf() {
var arg = Array.prototype.slice.call(arguments, 0),
......@@ -666,6 +671,7 @@
cache = newf.cache = newf.cache || {},
count = newf.count = newf.count || [];
if (cache[has](args)) {
repush(count, args);
return postprocessor ? postprocessor(cache[args]) : cache[args];
}
count.length >= 1e3 && delete cache[count.shift()];
......@@ -1650,6 +1656,7 @@
}
},
equaliseTransform = function (t1, t2) {
t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
t1 = R.parseTransformString(t1) || [];
t2 = R.parseTransformString(t2) || [];
var maxlength = mmax(t1.length, t2.length),
......@@ -1660,9 +1667,9 @@
for (; i < maxlength; i++) {
tt1 = t1[i] || getEmpty(t2[i]);
tt2 = t2[i] || getEmpty(tt1);
if ( (tt1[0] != tt2[0]) ||
(tt1[0] == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
(tt1[0] == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
if ((tt1[0] != tt2[0]) ||
(tt1[0] == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
(tt1[0] == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
) {
return;
}
......@@ -1738,80 +1745,123 @@
this.f = 0;
}
}
var matrixproto = Matrix.prototype;
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;
(function (matrixproto) {
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]];
}
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];
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;
}
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];
};
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);
};
matrixproto.clone = function () {
return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
};
matrixproto.translate = function (x, y) {
this.add(1, 0, 0, 1, x, y);
};
matrixproto.scale = function (x, y, cx, cy) {
y == null && (y = x);
this.add(1, 0, 0, 1, cx, cy);
this.add(x, 0, 0, y, 0, 0);
this.add(1, 0, 0, 1, -cx, -cy);
};
matrixproto.rotate = function (a, x, y) {
a = R.rad(a);
var cos = +math.cos(a).toFixed(9),
sin = +math.sin(a).toFixed(9);
this.add(cos, sin, -sin, cos, x, y);
this.add(1, 0, 0, 1, -x, -y);
};
matrixproto.x = function (x, y) {
return x * this.a + y * this.c + this.e;
};
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 R.svg ?
"matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
[this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
};
matrixproto.toFilter = function () {
return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
};
matrixproto.offset = function () {
return [this.e.toFixed(4), this.f.toFixed(4)];
};
function norm(a) {
return a[0] * a[0] + a[1] * a[1];
}
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];
};
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);
};
matrixproto.clone = function () {
return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
};
matrixproto.translate = function (x, y) {
this.add(1, 0, 0, 1, x, y);
};
matrixproto.scale = function (x, y, cx, cy) {
y == null && (y = x);
this.add(1, 0, 0, 1, cx, cy);
this.add(x, 0, 0, y, 0, 0);
this.add(1, 0, 0, 1, -cx, -cy);
};
matrixproto.rotate = function (a, x, y) {
a = R.rad(a);
var cos = +math.cos(a).toFixed(9),
sin = +math.sin(a).toFixed(9);
this.add(cos, sin, -sin, cos, x, y);
this.add(1, 0, 0, 1, -x, -y);
};
matrixproto.x = function (x, y) {
return x * this.a + y * this.c + this.e;
};
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 R.svg ?
"matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
[this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
};
matrixproto.toFilter = function () {
return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmedthod='auto expand')";
};
matrixproto.offset = function () {
return [this.e.toFixed(4), this.f.toFixed(4)];
};
function normalize(a) {
var mag = math.sqrt(norm(a));
a[0] /= mag;
a[1] /= mag;
}
matrixproto.split = function () {
var out = {};
// translation
out.dx = this.e;
out.dy = this.f;
this.e = this.f = 0;
// 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;
// rotation
out.rotate = R.deg(math.asin(-row[0][1]));
out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
return out;
};
matrixproto.toTransformString = function () {
var s = this.split();
if (s.isSimple) {
return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0];
} else {
return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
}
};
})(Matrix.prototype);
// SVG
if (R.svg) {
var xlink = "http://www.w3.org/1999/xlink",
......@@ -2609,7 +2659,6 @@
extractTransform(this, tstr);
this.clip && $(this.clip, {transform: this.matrix.invert()});
// this.gradient && $(this.gradient, {gradientTransform: this.matrix.invert()});
this.pattern && updatePosition(this);
this.node && $(this.node, {transform: this.matrix});
......@@ -3154,18 +3203,19 @@
dy: m.y(dx, dy)
};
},
setCoords = function (p) {
setCoords = function (p, sx, sy, dx, dy, deg) {
var _ = p._,
sx = _.sx,
sy = _.sy,
deg = _.deg,
dx = _.dx,
dy = _.dy,
m = p.matrix,
// sp = m.split(),
// sx = sp.scalex,
// sy = sp.scaley,
// deg = sp.rotate,
// dx = sp.dx,
// dy = sp.dy,
fillpos = _.fillpos,
o = p.node,
s = o.style,
y = 1,
m = p.matrix,
flip = "",
dxdy,
kx = zoom / sx,
......@@ -3330,7 +3380,7 @@
fill.on = false;
}
if (fill.on && params.fill) {
var isURL = params.fill.match(ISURL);
var isURL = Str(params.fill).match(ISURL);
if (isURL) {
fill.parentNode == node && node.removeChild(fill);
fill.rotate = true;
......@@ -3534,50 +3584,34 @@
extractTransform(this, tstr);
var matrix = this.matrix.clone(),
vbs = this.paper._viewBoxShift,
skew = this.skew;
skew = this.skew,
o = this.node;
matrix.translate(-.5, -.5);
if (vbs) {
matrix.scale(vbs.scale, vbs.scale, -1, -1);
matrix.add(1, 0, 0, 1, vbs.dx, vbs.dy);
}
if (this.type == "image") {
if (Str(tstr).indexOf("m") + 1) {
this.node.style.filter = matrix.toFilter();
matrix.translate(vbs.dx, vbs.dy);
}
if (Str(this.attrs.fill).indexOf("-") + 1 || this.type == "image") {
skew.matrix = "1 0 0 1";
skew.offset = "0 0";
var split = matrix.split();
if (!split.isSimple) {
o.style.filter = matrix.toFilter();
var bb = this.getBBox(),
bbt = this.getBBox(1),
im = matrix.invert(),
dx = im.x(bb.x, bb.y) - im.x(bbt.x, bbt.y),
dy = im.y(bb.x, bb.y) - im.y(bbt.x, bbt.y);
// skew.offset = dx + S + dy;
// this.node.getElementsByTagName(fillString)[0].position = skew.offset;
dx = bb.x - bbt.x,
dy = bb.y - bbt.y;
o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
setCoords(this, 1, 1, dx, dy, 0);
} else {
this.node.style.filter = E;
setCoords(this);
o.style.filter = E;
alert("clean");
setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
}
} else {
// o = this.node,
// _ = this._,
// fillpos = _.fillpos,
// deg,
// matrix = this.matrix;
// fill = o.getElementsByTagName(fillString)[0],
// angle = fill.angle;
this.node.style.filter = E;
o.style.filter = E;
skew.matrix = Str(matrix);
skew.offset = matrix.offset();
// if (0&&angle) {
// angle = R.rad(270 - angle);
// var dx = 100 * math.cos(angle),
// dy = 100 * math.sin(angle),
// zx = matrix.x(0, 0),
// zy = matrix.y(0, 0),
// mx = matrix.x(dx, dy),
// my = matrix.y(dx, dy);
// angle = R.angle(zx, zy, mx, my);
// fill.angle = (270 - angle) % 360;
// }
}
return this;
};
......@@ -3692,6 +3726,7 @@
res[i] = this.attrs[i];
}
res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
res.transform = this._.transform;
return res;
}
if (value == null && R.is(name, "string")) {
......@@ -3878,7 +3913,7 @@
res._.fillpos = [x, y];
res._.fillsize = [w, h];
node.appendChild(fill);
setCoords(res);
setCoords(res, 1, 1, 0, 0, 0);
return res;
};
theText = function (vml, x, y, text) {
......@@ -3892,7 +3927,7 @@
path.textpathok = true;
o.string = Str(text);
o.on = true;
el.style.cssText = "position:absolute;left:0;top:0;width:1;height:1";
el.style.cssText = "position:absolute;left:0;top:0;width:1px;height:1px";
el.coordsize = zoom + S + zoom;
el.coordorigin = "0 0";
var p = new Element(el, vml),
......@@ -5074,15 +5109,13 @@
R.is(f, "function") && f.call(el);
});
})(e.callback, that, e.anim);
if (--e.repeat) {
that.attr(e.origin);
e.start = Now;
} else {
that.attr(to);
animationElements.splice(l--, 1);
that.attr(to);
animationElements.splice(l--, 1);
if (e.repeat > 1 && !e.next) {
runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
}
if (e.next && !e.stop) {
runAnimation(e.anim, e.el, e.next, null, e.totalOrigin);
runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
}
}
}
......@@ -5090,7 +5123,7 @@
animationElements.length && requestAnimFrame(animation);
},
upto255 = function (color) {
return mmax(mmin(color, 255), 0);
return color > 255 ? 255 : color < 0 ? 0 : color;
};
/*\
* Element.animateWith
......@@ -5228,7 +5261,7 @@
a.times = math.floor(mmax(times, 0)) || 1;
return a;
};
function runAnimation(anim, element, percent, status, totalOrigin) {
function runAnimation(anim, element, percent, status, totalOrigin, times) {
percent = toFloat(percent);
var params,
isInAnim,
......@@ -5319,25 +5352,25 @@
}
}
} else {
var m = (element.matrix || new Matrix).m,
var m = (element.matrix || new Matrix),
to2 = {_:{transform: _.transform}, getBBox: function () { return element.getBBox(); }};
from[attr] = [
m[0][0],
m[1][0],
m[0][1],
m[1][1],
m[0][2],
m[1][2]
m.a,
m.b,
m.c,
m.d,
m.e,
m.f
];
extractTransform(to2, to[attr]);
to[attr] = to2._.transform;
diff[attr] = [
(to2.matrix.m[0][0] - m[0][0]) / ms,
(to2.matrix.m[1][0] - m[1][0]) / ms,
(to2.matrix.m[0][1] - m[0][1]) / ms,
(to2.matrix.m[1][1] - m[1][1]) / ms,
(to2.matrix.m[0][2] - m[0][2]) / ms,
(to2.matrix.m[1][2] - m[1][2]) / ms
(to2.matrix.a - m.a) / ms,
(to2.matrix.b - m.b) / ms,
(to2.matrix.c - m.c) / ms,
(to2.matrix.d - m.d) / ms,
(to2.matrix.e - m.e) / ms,
(to2.matrix.e - m.f) / ms
];
// from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
// var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
......@@ -5407,7 +5440,7 @@
callback: params.callback,
prev: prev,
next: next,
repeat: anim.times,
repeat: times || anim.times,
origin: element.attr(),
totalOrigin: totalOrigin
};
......@@ -5909,34 +5942,103 @@
oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
/*
* Eve 0.2.1 - JavaScript Events Library
* Eve 0.2.3 - JavaScript Events Library
*
* Copyright (c) 2010 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
var eve = R.eve = (function () {
var version = "0.2.1",
var version = "0.2.3",
has = "hasOwnProperty",
separator = /[\.\/]/,
wildcard = "*",
fun = function () {},
numsort = function (a, b) {
return a - b;
},
current_event,
events = {n: {}},
/*\
* eve
[ method ]
**
* Fires event with given `name`, given scope and other parameters.
**
> Arguments
**
- name (string) name of the event, dot (`.`) or slash (`/`) separated
- scope (object) context for the event handlers
- varargs (...) the rest of arguments will be sent to event handlers
**
= (array) array of errors, if any. Each element of the array is in format:
o {
o error (string) error message
o func (function) handler that caused error
o }
\*/
eve = function (name, scope) {
var e = events,
args = Array.prototype.slice.call(arguments, 2),
listeners = eve.listeners(name),
z = 0,
f = false,
l,
indexed = [],
queue = {},
errors = [];
for (var i = 0, ii = listeners.length; i < ii; i++) {
try {
listeners[i].apply(scope, args);
} catch (ex) {
errors.push({error: ex && ex.message || ex, func: listeners[i]});
current_event = name;
for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
indexed.push(listeners[i].zIndex);
if (listeners[i].zIndex < 0) {
queue[listeners[i].zIndex] = listeners[i];
}
}
indexed.sort(numsort);
while (indexed[z] < 0) {
l = queue[indexed[z++]];
if (l.apply(scope, args) === f) {
return f;
}
}
if (errors.length) {
return errors;
for (i = 0; i < ii; i++) {
l = listeners[i];
if ("zIndex" in l) {
if (l.zIndex == indexed[z]) {
if (l.apply(scope, args) === f) {
return f;
}
do {
z++;
l = queue[indexed[z]];
if (l) {
if (l.apply(scope, args) === f) {
return f;
}
}
} while (l)
} else {
queue[l.zIndex] = l;
}
} else {
if (l.apply(scope, args) === f) {
return f;
}
}
}
};
/*\
* eve.listeners
[ method ]
**
* Internal method which gives you array of all event handlers that will be triggered by the given `name`.
**
> Arguments
**
- name (string) name of the event, dot (`.`) or slash (`/`) separated
**
= (array) array of event handlers
\*/
eve.listeners = function (name) {
var names = name.split(separator),
e = events,
......@@ -5968,6 +6070,30 @@
}
return out;
};
/*\
* eve.on
[ method ]
**
* Binds given event handler with a given name. You can use wildcards “`*`” for the names:
| eve.on("*.under.*", f);
| eve("mouse.under.floor"); // triggers f
* Use @eve to trigger the listener.
**
> Arguments
**
- name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
- f (function) event handler function
**
= (function) returned function accept one number parameter that represents z-index of the handler. It is optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
> Example:
| eve.on("mouse", eat)(2);
| eve.on("mouse", scream);
| eve.on("mouse", catch)(1);
* This will ensure that `catch` function will be called before `eat`.
* If you want to put you hadler before not indexed handlers specify negative value.
* Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
\*/
eve.on = function (name, f) {
var names = name.split(separator),
e = events;
......@@ -5978,10 +6104,46 @@
}
e.f = e.f || [];
for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
return false;
return fun;
}
e.f.push(f);
return function (zIndex) {
if (+zIndex == +zIndex) {
f.zIndex = +zIndex;
}
};
};
/*\
* eve.nt
[ method ]
**
* Could be used inside event handler to figure out actual name of the event.
**
> Arguments
**
- subname (string) #optional subname of the event
**
= (string) name of the event, if `subname` is not specified
* or
= (boolean) `true`, if current event’s name contains `subname`
\*/
eve.nt = function (subname) {
if (subname) {
return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
}
return current_event;
};
/*\
* eve.unbind
[ method ]
**
* Removes given function from the list of event listeners assigned to given name.
**
> Arguments
**
- name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
- f (function) event handler function
\*/
eve.unbind = function (name, f) {
var names = name.split(separator),
e,
......@@ -6032,8 +6194,13 @@
e = e.n;
}
}
return true;
};
/*\
* eve.version
[ property (string) ]
**
* Current version of the library.
\*/
eve.version = version;
eve.toString = function () {
return "You are running Eve " + version;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment