public/javascripts/jquery.svg/jquery.svganim.js
/* http://keith-wood.name/svg.html
SVG attribute animations for jQuery v1.4.3.
Written by Keith Wood (kbwood{at}iinet.com.au) June 2008.
Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
Please attribute the author if you use it. */
(function($) { // Hide scope, no $ conflict
// Enable animation for all of these SVG numeric attributes -
// named as svg-* or svg* (with first character upper case)
$.each(['x', 'y', 'width', 'height', 'rx', 'ry', 'cx', 'cy', 'r', 'x1', 'y1', 'x2', 'y2',
'stroke-width', 'strokeWidth', 'opacity', 'fill-opacity', 'fillOpacity',
'stroke-opacity', 'strokeOpacity', 'font-size', 'fontSize'],
function(i, attrName) {
var ccName = attrName.charAt(0).toUpperCase() + attrName.substr(1);
$.fx.step['svg' + ccName] = $.fx.step['svg-' + attrName] = function(fx) {
var realAttrName = $.svg._attrNames[attrName] || attrName;
var attr = fx.elem.attributes.getNamedItem(realAttrName);
if (!fx.set) {
fx.start = (attr ? parseFloat(attr.nodeValue) : 0);
var offset = fx.options.curAnim['svg-' + attrName] ||
fx.options.curAnim['svg' + ccName];
if (/^[+-]=/.exec(offset)) {
fx.end = fx.start + parseFloat(offset.replace(/=/, ''));
}
$(fx.elem).css(realAttrName, '');
fx.set = true;
}
var value = (fx.pos * (fx.end - fx.start) + fx.start) + (fx.unit == '%' ? '%' : '');
(attr ? attr.nodeValue = value : fx.elem.setAttribute(realAttrName, value));
};
}
);
// Enable animation for the SVG viewBox attribute
$.fx.step['svgViewBox'] = $.fx.step['svg-viewBox'] = function(fx) {
var attr = fx.elem.attributes.getNamedItem('viewBox');
if (!fx.set) {
fx.start = parseViewBox(attr ? attr.nodeValue : '');
var offset = fx.options.curAnim['svg-viewBox'] || fx.options.curAnim['svgViewBox'];
fx.end = parseViewBox(offset);
if (/^[+-]=/.exec(offset)) {
offset = offset.split(' ');
while (offset.length < 4) {
offset.push('0');
}
for (var i = 0; i < 4; i++) {
if (/^[+-]=/.exec(offset[i])) {
fx.end[i] = fx.start[i] + parseFloat(offset[i].replace(/=/, ''));
}
}
}
fx.set = true;
}
var value = $.map(fx.start, function(n, i) {
return (fx.pos * (fx.end[i] - n) + n);
}).join(' ');
(attr ? attr.nodeValue = value : fx.elem.setAttribute('viewBox', value));
};
/* Parse a viewBox definition: x, y, width, height.
@param value (string) the definition
@return (number[4]) the extracted values */
function parseViewBox(value) {
var viewBox = value.split(' ');
for (var i = 0; i < viewBox.length; i++) {
viewBox[i] = parseFloat(viewBox[i]);
if (isNaN(viewBox[i])) {
viewBox[i] = 0;
}
}
while (viewBox.length < 4) {
viewBox.push(0);
}
return viewBox;
}
// Enable animation for the SVG transform attribute
$.fx.step['svgTransform'] = $.fx.step['svg-transform'] = function(fx) {
var attr = fx.elem.attributes.getNamedItem('transform');
if (!fx.set) {
fx.start = parseTransform(attr ? attr.nodeValue : '');
fx.end = parseTransform(fx.end, fx.start);
fx.set = true;
}
var transform = '';
for (var i = 0; i < fx.end.order.length; i++) {
switch (fx.end.order.charAt(i)) {
case 't':
transform += (fx.start.translateX != fx.end.translateX || fx.start.translateY != fx.end.translateY ?
' translate(' + (fx.pos * (fx.end.translateX - fx.start.translateX) + fx.start.translateX) + ',' +
(fx.pos * (fx.end.translateY - fx.start.translateY) + fx.start.translateY) + ')' : '');
break;
case 's':
transform += (fx.start.scaleX != fx.end.scaleX || fx.start.scaleY != fx.end.scaleY ?
' scale(' + (fx.pos * (fx.end.scaleX - fx.start.scaleX) + fx.start.scaleX) + ',' +
(fx.pos * (fx.end.scaleY - fx.start.scaleY) + fx.start.scaleY) + ')' : '');
break;
case 'r':
transform += (fx.start.rotateA != fx.end.rotateA ||
fx.start.rotateX != fx.end.rotateX || fx.start.rotateY != fx.end.rotateY ?
' rotate(' + (fx.pos * (fx.end.rotateA - fx.start.rotateA) + fx.start.rotateA) + ',' +
(fx.pos * (fx.end.rotateX - fx.start.rotateX) + fx.start.rotateX) + ',' +
(fx.pos * (fx.end.rotateY - fx.start.rotateY) + fx.start.rotateY) + ')' : '');
break;
case 'x':
transform += (fx.start.skewX != fx.end.skewX ?
' skewX(' + (fx.pos * (fx.end.skewX - fx.start.skewX) + fx.start.skewX) + ')' : '');
case 'y':
transform += (fx.start.skewY != fx.end.skewY ?
' skewY(' + (fx.pos * (fx.end.skewY - fx.start.skewY) + fx.start.skewY) + ')' : '');
break;
case 'm':
var matrix = '';
for (var j = 0; j < 6; j++) {
matrix += ',' + (fx.pos * (fx.end.matrix[j] - fx.start.matrix[j]) + fx.start.matrix[j]);
}
transform += ' matrix(' + matrix.substr(1) + ')';
break;
}
}
(attr ? attr.nodeValue = transform : fx.elem.setAttribute('transform', transform));
};
/* Decode a transform string and extract component values.
@param value (string) the transform string to parse
@param original (object) the settings from the original node
@return (object) the combined transformation attributes */
function parseTransform(value, original) {
value = value || '';
if (typeof value == 'object') {
value = value.nodeValue;
}
var transform = $.extend({translateX: 0, translateY: 0, scaleX: 0, scaleY: 0,
rotateA: 0, rotateX: 0, rotateY: 0, skewX: 0, skewY: 0,
matrix: [0, 0, 0, 0, 0, 0]}, original || {});
transform.order = '';
var pattern = /([a-zA-Z]+)\(\s*([+-]?[\d\.]+)\s*(?:[\s,]\s*([+-]?[\d\.]+)\s*(?:[\s,]\s*([+-]?[\d\.]+)\s*(?:[\s,]\s*([+-]?[\d\.]+)\s*[\s,]\s*([+-]?[\d\.]+)\s*[\s,]\s*([+-]?[\d\.]+)\s*)?)?)?\)/g;
var result = pattern.exec(value);
while (result) {
switch (result[1]) {
case 'translate':
transform.order += 't';
transform.translateX = parseFloat(result[2]);
transform.translateY = (result[3] ? parseFloat(result[3]) : 0);
break;
case 'scale':
transform.order += 's';
transform.scaleX = parseFloat(result[2]);
transform.scaleY = (result[3] ? parseFloat(result[3]) : transform.scaleX);
break;
case 'rotate':
transform.order += 'r';
transform.rotateA = parseFloat(result[2]);
transform.rotateX = (result[3] ? parseFloat(result[3]) : 0);
transform.rotateY = (result[4] ? parseFloat(result[4]) : 0);
break;
case 'skewX':
transform.order += 'x';
transform.skewX = parseFloat(result[2]);
break;
case 'skewY':
transform.order += 'y';
transform.skewY = parseFloat(result[2]);
break;
case 'matrix':
transform.order += 'm';
transform.matrix = [parseFloat(result[2]), parseFloat(result[3]),
parseFloat(result[4]), parseFloat(result[5]),
parseFloat(result[6]), parseFloat(result[7])];
break;
}
result = pattern.exec(value);
}
return transform;
}
// Enable animation for all of these SVG colour properties - based on jquery.color.js
$.each(['fill', 'stroke'],
function(i, attrName) {
var ccName = attrName.charAt(0).toUpperCase() + attrName.substr(1);
$.fx.step['svg' + ccName] = $.fx.step['svg-' + attrName] = function(fx) {
if (!fx.set) {
fx.start = getColour(fx.elem, attrName);
var toNone = (fx.end == 'none');
fx.end = (toNone ? getColour(fx.elem.parentNode, attrName) : getRGB(fx.end));
fx.end[3] = toNone;
$(fx.elem).css(attrName, '');
fx.set = true;
}
var attr = fx.elem.attributes.getNamedItem(attrName);
var colour = 'rgb(' + [
Math.min(Math.max(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 0), 255),
Math.min(Math.max(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 0), 255),
Math.min(Math.max(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 0), 255)
].join(',') + ')';
colour = (fx.end[3] && fx.state == 1 ? 'none' : colour);
(attr ? attr.nodeValue = colour : fx.elem.setAttribute(attrName, colour));
}
}
);
/* Find this attribute value somewhere up the node hierarchy.
@param elem (element) the starting element to find the attribute
@param attr (string) the attribute name
@return (number[3]) RGB components for the attribute colour */
function getColour(elem, attr) {
var colour;
do {
colour = (elem.attributes && elem.attributes.getNamedItem(attr) ?
elem.attributes.getNamedItem(attr).nodeValue : '');
// Keep going until we find an element that has colour, or exit SVG
if ((colour != '' && colour != 'none') || $(elem).hasClass('hasSVG')) {
break;
}
} while (elem = elem.parentNode);
return getRGB(colour);
}
/* Parse strings looking for common colour formats.
@param colour (string) colour description to parse
@return (number[3]) RGB components of this colour */
function getRGB(colour) {
var result;
// Check if we're already dealing with an array of colors
if (colour && colour.constructor == Array && (colour.length == 3 || colour.length == 4)) {
return colour;
}
// Look for rgb(num,num,num)
if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(colour)) {
return [parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10)];
}
// Look for rgb(num%,num%,num%)
if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(colour)) {
return [parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55,
parseFloat(result[3]) * 2.55];
}
// Look for #a0b1c2
if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(colour)) {
return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
}
// Look for #abc
if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(colour)) {
return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16),
parseInt(result[3] + result[3], 16)];
}
// Otherwise, we're most likely dealing with a named color
return colours[$.trim(colour).toLowerCase()] || colours['none'];
}
// The SVG named colours
var colours = {
'': [255, 255, 255, 1],
none: [255, 255, 255, 1],
aliceblue: [240, 248, 255],
antiquewhite: [250, 235, 215],
aqua: [ 0, 255, 255],
aquamarine: [127, 255, 212],
azure: [240, 255, 255],
beige: [245, 245, 220],
bisque: [255, 228, 196],
black: [ 0, 0, 0],
blanchedalmond: [255, 235, 205],
blue: [ 0, 0, 255],
blueviolet: [138, 43, 226],
brown: [165, 42, 42],
burlywood: [222, 184, 135],
cadetblue: [ 95, 158, 160],
chartreuse: [127, 255, 0],
chocolate: [210, 105, 30],
coral: [255, 127, 80],
cornflowerblue: [100, 149, 237],
cornsilk: [255, 248, 220],
crimson: [220, 20, 60],
cyan: [ 0, 255, 255],
darkblue: [ 0, 0, 139],
darkcyan: [ 0, 139, 139],
darkgoldenrod: [184, 134, 11],
darkgray: [169, 169, 169],
darkgreen: [ 0, 100, 0],
darkgrey: [169, 169, 169],
darkkhaki: [189, 183, 107],
darkmagenta: [139, 0, 139],
darkolivegreen: [ 85, 107, 47],
darkorange: [255, 140, 0],
darkorchid: [153, 50, 204],
darkred: [139, 0, 0],
darksalmon: [233, 150, 122],
darkseagreen: [143, 188, 143],
darkslateblue: [ 72, 61, 139],
darkslategray: [ 47, 79, 79],
darkslategrey: [ 47, 79, 79],
darkturquoise: [ 0, 206, 209],
darkviolet: [148, 0, 211],
deeppink: [255, 20, 147],
deepskyblue: [ 0, 191, 255],
dimgray: [105, 105, 105],
dimgrey: [105, 105, 105],
dodgerblue: [ 30, 144, 255],
firebrick: [178, 34, 34],
floralwhite: [255, 250, 240],
forestgreen: [ 34, 139, 34],
fuchsia: [255, 0, 255],
gainsboro: [220, 220, 220],
ghostwhite: [248, 248, 255],
gold: [255, 215, 0],
goldenrod: [218, 165, 32],
gray: [128, 128, 128],
grey: [128, 128, 128],
green: [ 0, 128, 0],
greenyellow: [173, 255, 47],
honeydew: [240, 255, 240],
hotpink: [255, 105, 180],
indianred: [205, 92, 92],
indigo: [ 75, 0, 130],
ivory: [255, 255, 240],
khaki: [240, 230, 140],
lavender: [230, 230, 250],
lavenderblush: [255, 240, 245],
lawngreen: [124, 252, 0],
lemonchiffon: [255, 250, 205],
lightblue: [173, 216, 230],
lightcoral: [240, 128, 128],
lightcyan: [224, 255, 255],
lightgoldenrodyellow: [250, 250, 210],
lightgray: [211, 211, 211],
lightgreen: [144, 238, 144],
lightgrey: [211, 211, 211],
lightpink: [255, 182, 193],
lightsalmon: [255, 160, 122],
lightseagreen: [ 32, 178, 170],
lightskyblue: [135, 206, 250],
lightslategray: [119, 136, 153],
lightslategrey: [119, 136, 153],
lightsteelblue: [176, 196, 222],
lightyellow: [255, 255, 224],
lime: [ 0, 255, 0],
limegreen: [ 50, 205, 50],
linen: [250, 240, 230],
magenta: [255, 0, 255],
maroon: [128, 0, 0],
mediumaquamarine: [102, 205, 170],
mediumblue: [ 0, 0, 205],
mediumorchid: [186, 85, 211],
mediumpurple: [147, 112, 219],
mediumseagreen: [ 60, 179, 113],
mediumslateblue: [123, 104, 238],
mediumspringgreen: [ 0, 250, 154],
mediumturquoise: [ 72, 209, 204],
mediumvioletred: [199, 21, 133],
midnightblue: [ 25, 25, 112],
mintcream: [245, 255, 250],
mistyrose: [255, 228, 225],
moccasin: [255, 228, 181],
navajowhite: [255, 222, 173],
navy: [ 0, 0, 128],
oldlace: [253, 245, 230],
olive: [128, 128, 0],
olivedrab: [107, 142, 35],
orange: [255, 165, 0],
orangered: [255, 69, 0],
orchid: [218, 112, 214],
palegoldenrod: [238, 232, 170],
palegreen: [152, 251, 152],
paleturquoise: [175, 238, 238],
palevioletred: [219, 112, 147],
papayawhip: [255, 239, 213],
peachpuff: [255, 218, 185],
peru: [205, 133, 63],
pink: [255, 192, 203],
plum: [221, 160, 221],
powderblue: [176, 224, 230],
purple: [128, 0, 128],
red: [255, 0, 0],
rosybrown: [188, 143, 143],
royalblue: [ 65, 105, 225],
saddlebrown: [139, 69, 19],
salmon: [250, 128, 114],
sandybrown: [244, 164, 96],
seagreen: [ 46, 139, 87],
seashell: [255, 245, 238],
sienna: [160, 82, 45],
silver: [192, 192, 192],
skyblue: [135, 206, 235],
slateblue: [106, 90, 205],
slategray: [112, 128, 144],
slategrey: [112, 128, 144],
snow: [255, 250, 250],
springgreen: [ 0, 255, 127],
steelblue: [ 70, 130, 180],
tan: [210, 180, 140],
teal: [ 0, 128, 128],
thistle: [216, 191, 216],
tomato: [255, 99, 71],
turquoise: [ 64, 224, 208],
violet: [238, 130, 238],
wheat: [245, 222, 179],
white: [255, 255, 255],
whitesmoke: [245, 245, 245],
yellow: [255, 255, 0],
yellowgreen: [154, 205, 50]
};
})(jQuery);