2019-06-14 07:33:43 +00:00
define ( [ "eve" ] , function ( eve ) {
/ * \
* Raphael
[ method ]
* *
* Creates a canvas object on which to draw .
* You must do this first , as all future calls to drawing methods
* from this instance will be bound to this canvas .
> Parameters
* *
- container ( HTMLElement | string ) DOM element or its ID which is going to be a parent for drawing surface
- width ( number )
- height ( number )
- callback ( function ) # optional callback function which is going to be executed in the context of newly created paper
* or
- x ( number )
- y ( number )
- width ( number )
- height ( number )
- callback ( function ) # optional callback function which is going to be executed in the context of newly created paper
* or
- all ( array ) ( first 3 or 4 elements in the array are equal to [ containerID , width , height ] or [ x , y , width , height ] . The rest are element descriptions in format { type : type , < attributes > } ) . See @ Paper . add .
- callback ( function ) # optional callback function which is going to be executed in the context of newly created paper
* or
- onReadyCallback ( function ) function that is going to be called on DOM ready event . You can also subscribe to this event via Eve ’ s “ DOMLoad ” event . In this case method returns ` undefined ` .
= ( object ) @ Paper
> Usage
| // Each of the following examples create a canvas
| // that is 320px wide by 200px high.
| // Canvas is created at the viewport’ s 10,50 coordinate.
| var paper = Raphael ( 10 , 50 , 320 , 200 ) ;
| // Canvas is created at the top left corner of the #notepad element
| // (or its top right corner in dir="rtl" elements)
| var paper = Raphael ( document . getElementById ( "notepad" ) , 320 , 200 ) ;
| // Same as above
| var paper = Raphael ( "notepad" , 320 , 200 ) ;
| // Image dump
| var set = Raphael ( [ "notepad" , 320 , 200 , {
| type : "rect" ,
| x : 10 ,
| y : 10 ,
| width : 25 ,
| height : 25 ,
| stroke : "#f00"
| } , {
| type : "text" ,
| x : 30 ,
| y : 40 ,
| text : "Dump"
| } ] ) ;
\ * /
function R ( first ) {
if ( R . is ( first , "function" ) ) {
return loaded ? first ( ) : eve . on ( "raphael.DOMload" , first ) ;
} else if ( R . is ( first , array ) ) {
return R . _engine . create [ apply ] ( R , first . splice ( 0 , 3 + R . is ( first [ 0 ] , nu ) ) ) . add ( first ) ;
} else {
var args = Array . prototype . slice . call ( arguments , 0 ) ;
if ( R . is ( args [ args . length - 1 ] , "function" ) ) {
var f = args . pop ( ) ;
return loaded ? f . call ( R . _engine . create [ apply ] ( R , args ) ) : eve . on ( "raphael.DOMload" , function ( ) {
f . call ( R . _engine . create [ apply ] ( R , args ) ) ;
} ) ;
} else {
return R . _engine . create [ apply ] ( R , arguments ) ;
}
}
}
2019-08-28 10:59:33 +00:00
R . version = "2.3.0" ;
2019-06-14 07:33:43 +00:00
R . eve = eve ;
var loaded ,
separator = /[, ]+/ ,
elements = { circle : 1 , rect : 1 , path : 1 , ellipse : 1 , text : 1 , image : 1 } ,
formatrg = /\{(\d+)\}/g ,
proto = "prototype" ,
has = "hasOwnProperty" ,
g = {
doc : document ,
win : window
} ,
oldRaphael = {
was : Object . prototype [ has ] . call ( g . win , "Raphael" ) ,
is : g . win . Raphael
} ,
Paper = function ( ) {
/ * \
* Paper . ca
[ property ( object ) ]
* *
* Shortcut for @ Paper . customAttributes
\ * /
/ * \
* Paper . customAttributes
[ property ( object ) ]
* *
* If you have a set of attributes that you would like to represent
* as a function of some number you can do it easily with custom attributes :
> Usage
| paper . customAttributes . hue = function ( num ) {
| num = num % 1 ;
| return { fill : "hsb(" + num + ", 0.75, 1)" } ;
| } ;
| // Custom attribute “hue” will change fill
| // to be given hue with fixed saturation and brightness.
| // Now you can use it like this:
| var c = paper . circle ( 10 , 10 , 10 ) . attr ( { hue : . 45 } ) ;
| // or even like this:
| c . animate ( { hue : 1 } , 1e3 ) ;
|
| // You could also create custom attribute
| // with multiple parameters:
| paper . customAttributes . hsb = function ( h , s , b ) {
| return { fill : "hsb(" + [ h , s , b ] . join ( "," ) + ")" } ;
| } ;
| c . attr ( { hsb : "0.5 .8 1" } ) ;
| c . animate ( { hsb : [ 1 , 0 , 0.5 ] } , 1e3 ) ;
\ * /
this . ca = this . customAttributes = { } ;
} ,
paperproto ,
appendChild = "appendChild" ,
apply = "apply" ,
concat = "concat" ,
//taken from Modernizr touch test: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js#L40
supportsTouch = ( 'ontouchstart' in window ) || window . TouchEvent || window . DocumentTouch && document instanceof DocumentTouch ,
E = "" ,
S = " " ,
Str = String ,
split = "split" ,
events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel" [ split ] ( S ) ,
touchMap = {
mousedown : "touchstart" ,
mousemove : "touchmove" ,
mouseup : "touchend"
} ,
lowerCase = Str . prototype . toLowerCase ,
math = Math ,
mmax = math . max ,
mmin = math . min ,
abs = math . abs ,
pow = math . pow ,
PI = math . PI ,
nu = "number" ,
string = "string" ,
array = "array" ,
toString = "toString" ,
fillString = "fill" ,
objectToString = Object . prototype . toString ,
paper = { } ,
push = "push" ,
ISURL = R . _ISURL = /^url\(['"]?(.+?)['"]?\)$/i ,
colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i ,
isnan = { "NaN" : 1 , "Infinity" : 1 , "-Infinity" : 1 } ,
bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/ ,
round = math . round ,
setAttribute = "setAttribute" ,
toFloat = parseFloat ,
toInt = parseInt ,
upperCase = Str . prototype . toUpperCase ,
availableAttrs = R . _availableAttrs = {
"arrow-end" : "none" ,
"arrow-start" : "none" ,
blur : 0 ,
"clip-rect" : "0 0 1e9 1e9" ,
cursor : "default" ,
cx : 0 ,
cy : 0 ,
fill : "#fff" ,
"fill-opacity" : 1 ,
font : '10px "Arial"' ,
"font-family" : '"Arial"' ,
"font-size" : "10" ,
"font-style" : "normal" ,
"font-weight" : 400 ,
gradient : 0 ,
height : 0 ,
href : "http://raphaeljs.com/" ,
"letter-spacing" : 0 ,
opacity : 1 ,
path : "M0,0" ,
r : 0 ,
rx : 0 ,
ry : 0 ,
src : "" ,
stroke : "#000" ,
"stroke-dasharray" : "" ,
"stroke-linecap" : "butt" ,
"stroke-linejoin" : "butt" ,
"stroke-miterlimit" : 0 ,
"stroke-opacity" : 1 ,
"stroke-width" : 1 ,
target : "_blank" ,
"text-anchor" : "middle" ,
title : "Raphael" ,
transform : "" ,
width : 0 ,
x : 0 ,
y : 0 ,
"class" : ""
} ,
availableAnimAttrs = R . _availableAnimAttrs = {
blur : nu ,
"clip-rect" : "csv" ,
cx : nu ,
cy : nu ,
fill : "colour" ,
"fill-opacity" : nu ,
"font-size" : nu ,
height : nu ,
opacity : nu ,
path : "path" ,
r : nu ,
rx : nu ,
ry : nu ,
stroke : "colour" ,
"stroke-opacity" : nu ,
"stroke-width" : nu ,
transform : "transform" ,
width : nu ,
x : nu ,
y : nu
} ,
whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g ,
commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ ,
hsrg = { hs : 1 , rg : 1 } ,
p2s = /,?([achlmqrstvxz]),?/gi ,
pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig ,
tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig ,
pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig ,
radial _gradient = R . _radial _gradient = /^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/ ,
eldata = { } ,
sortByKey = function ( a , b ) {
return a . key - b . key ;
} ,
sortByNumber = function ( a , b ) {
return toFloat ( a ) - toFloat ( b ) ;
} ,
fun = function ( ) { } ,
pipe = function ( x ) {
return x ;
} ,
rectPath = R . _rectPath = function ( x , y , w , h , r ) {
if ( r ) {
return [ [ "M" , x + r , y ] , [ "l" , w - r * 2 , 0 ] , [ "a" , r , r , 0 , 0 , 1 , r , r ] , [ "l" , 0 , h - r * 2 ] , [ "a" , r , r , 0 , 0 , 1 , - r , r ] , [ "l" , r * 2 - w , 0 ] , [ "a" , r , r , 0 , 0 , 1 , - r , - r ] , [ "l" , 0 , r * 2 - h ] , [ "a" , r , r , 0 , 0 , 1 , r , - r ] , [ "z" ] ] ;
}
return [ [ "M" , x , y ] , [ "l" , w , 0 ] , [ "l" , 0 , h ] , [ "l" , - w , 0 ] , [ "z" ] ] ;
} ,
ellipsePath = function ( x , y , rx , ry ) {
if ( ry == null ) {
ry = rx ;
}
return [ [ "M" , x , y ] , [ "m" , 0 , - ry ] , [ "a" , rx , ry , 0 , 1 , 1 , 0 , 2 * ry ] , [ "a" , rx , ry , 0 , 1 , 1 , 0 , - 2 * ry ] , [ "z" ] ] ;
} ,
getPath = R . _getPath = {
path : function ( el ) {
return el . attr ( "path" ) ;
} ,
circle : function ( el ) {
var a = el . attrs ;
return ellipsePath ( a . cx , a . cy , a . r ) ;
} ,
ellipse : function ( el ) {
var a = el . attrs ;
return ellipsePath ( a . cx , a . cy , a . rx , a . ry ) ;
} ,
rect : function ( el ) {
var a = el . attrs ;
return rectPath ( a . x , a . y , a . width , a . height , a . r ) ;
} ,
image : function ( el ) {
var a = el . attrs ;
return rectPath ( a . x , a . y , a . width , a . height ) ;
} ,
text : function ( el ) {
var bbox = el . _getBBox ( ) ;
return rectPath ( bbox . x , bbox . y , bbox . width , bbox . height ) ;
} ,
set : function ( el ) {
var bbox = el . _getBBox ( ) ;
return rectPath ( bbox . x , bbox . y , bbox . width , bbox . height ) ;
}
} ,
/ * \
* Raphael . mapPath
[ method ]
* *
* Transform the path string with given matrix .
> Parameters
- path ( string ) path string
- matrix ( object ) see @ Matrix
= ( string ) transformed path string
\ * /
mapPath = R . mapPath = function ( path , matrix ) {
if ( ! matrix ) {
return path ;
}
var x , y , i , j , ii , jj , pathi ;
path = path2curve ( path ) ;
for ( i = 0 , ii = path . length ; i < ii ; i ++ ) {
pathi = path [ i ] ;
for ( j = 1 , jj = pathi . length ; j < jj ; j += 2 ) {
x = matrix . x ( pathi [ j ] , pathi [ j + 1 ] ) ;
y = matrix . y ( pathi [ j ] , pathi [ j + 1 ] ) ;
pathi [ j ] = x ;
pathi [ j + 1 ] = y ;
}
}
return path ;
} ;
R . _g = g ;
/ * \
* Raphael . type
[ property ( string ) ]
* *
* Can be “ SVG ” , “ VML ” or empty , depending on browser support .
\ * /
R . type = ( g . win . SVGAngle || g . doc . implementation . hasFeature ( "http://www.w3.org/TR/SVG11/feature#BasicStructure" , "1.1" ) ? "SVG" : "VML" ) ;
if ( R . type == "VML" ) {
var d = g . doc . createElement ( "div" ) ,
b ;
d . innerHTML = '<v:shape adj="1"/>' ;
b = d . firstChild ;
b . style . behavior = "url(#default#VML)" ;
if ( ! ( b && typeof b . adj == "object" ) ) {
return ( R . type = E ) ;
}
d = null ;
}
/ * \
* Raphael . svg
[ property ( boolean ) ]
* *
* ` true ` if browser supports SVG .
\ * /
/ * \
* Raphael . vml
[ property ( boolean ) ]
* *
* ` true ` if browser supports VML .
\ * /
R . svg = ! ( R . vml = R . type == "VML" ) ;
R . _Paper = Paper ;
/ * \
* Raphael . fn
[ property ( object ) ]
* *
* You can add your own method to the canvas . For example if you want to draw a pie chart ,
* you can create your own pie chart function and ship it as a Raphaël plugin . To do this
* you need to extend the ` Raphael.fn ` object . You should modify the ` fn ` object before a
* Raphaël instance is created , otherwise it will take no effect . Please note that the
* ability for namespaced plugins was removed in Raphael 2.0 . It is up to the plugin to
* ensure any namespacing ensures proper context .
> Usage
| Raphael . fn . arrow = function ( x1 , y1 , x2 , y2 , size ) {
| return this . path ( ... ) ;
| } ;
| // or create namespace
| Raphael . fn . mystuff = {
| arrow : function ( ) { … } ,
| star : function ( ) { … } ,
| // etc…
| } ;
| var paper = Raphael ( 10 , 10 , 630 , 480 ) ;
| // then use it
| paper . arrow ( 10 , 10 , 30 , 30 , 5 ) . attr ( { fill : "#f00" } ) ;
| paper . mystuff . arrow ( ) ;
| paper . mystuff . star ( ) ;
\ * /
R . fn = paperproto = Paper . prototype = R . prototype ;
R . _id = 0 ;
/ * \
* Raphael . is
[ method ]
* *
* Handful of replacements for ` typeof ` operator .
> Parameters
- o ( … ) any object or primitive
- type ( string ) name of the type , i . e . “ string ” , “ function ” , “ number ” , etc .
= ( boolean ) is given value is of given type
\ * /
R . is = function ( o , type ) {
type = lowerCase . call ( type ) ;
if ( type == "finite" ) {
return ! isnan [ has ] ( + o ) ;
}
if ( type == "array" ) {
return o instanceof Array ;
}
return ( type == "null" && o === null ) ||
( type == typeof o && o !== null ) ||
( type == "object" && o === Object ( o ) ) ||
( type == "array" && Array . isArray && Array . isArray ( o ) ) ||
objectToString . call ( o ) . slice ( 8 , - 1 ) . toLowerCase ( ) == type ;
} ;
function clone ( obj ) {
if ( typeof obj == "function" || Object ( obj ) !== obj ) {
return obj ;
}
var res = new obj . constructor ;
for ( var key in obj ) if ( obj [ has ] ( key ) ) {
res [ key ] = clone ( obj [ key ] ) ;
}
return res ;
}
/ * \
* Raphael . angle
[ method ]
* *
* Returns angle between two or three points
> Parameters
- x1 ( number ) x coord of first point
- y1 ( number ) y coord of first point
- x2 ( number ) x coord of second point
- y2 ( number ) y coord of second point
- x3 ( number ) # optional x coord of third point
- y3 ( number ) # optional y coord of third point
= ( number ) angle in degrees .
\ * /
R . angle = function ( x1 , y1 , x2 , y2 , x3 , y3 ) {
if ( x3 == null ) {
var x = x1 - x2 ,
y = y1 - y2 ;
if ( ! x && ! y ) {
return 0 ;
}
return ( 180 + math . atan2 ( - y , - x ) * 180 / PI + 360 ) % 360 ;
} else {
return R . angle ( x1 , y1 , x3 , y3 ) - R . angle ( x2 , y2 , x3 , y3 ) ;
}
} ;
/ * \
* Raphael . rad
[ method ]
* *
* Transform angle to radians
> Parameters
- deg ( number ) angle in degrees
= ( number ) angle in radians .
\ * /
R . rad = function ( deg ) {
return deg % 360 * PI / 180 ;
} ;
/ * \
* Raphael . deg
[ method ]
* *
* Transform angle to degrees
> Parameters
- rad ( number ) angle in radians
= ( number ) angle in degrees .
\ * /
R . deg = function ( rad ) {
return Math . round ( ( rad * 180 / PI % 360 ) * 1000 ) / 1000 ;
} ;
/ * \
* Raphael . snapTo
[ method ]
* *
* Snaps given value to given grid .
> Parameters
- values ( array | number ) given array of values or step of the grid
- value ( number ) value to adjust
- tolerance ( number ) # optional tolerance for snapping . Default is ` 10 ` .
= ( number ) adjusted value .
\ * /
R . snapTo = function ( values , value , tolerance ) {
tolerance = R . is ( tolerance , "finite" ) ? tolerance : 10 ;
if ( R . is ( values , array ) ) {
var i = values . length ;
while ( i -- ) if ( abs ( values [ i ] - value ) <= tolerance ) {
return values [ i ] ;
}
} else {
values = + values ;
var rem = value % values ;
if ( rem < tolerance ) {
return value - rem ;
}
if ( rem > values - tolerance ) {
return value - rem + values ;
}
}
return value ;
} ;
/ * \
* Raphael . createUUID
[ method ]
* *
* Returns RFC4122 , version 4 ID
\ * /
var createUUID = R . createUUID = ( function ( uuidRegEx , uuidReplacer ) {
return function ( ) {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" . replace ( uuidRegEx , uuidReplacer ) . toUpperCase ( ) ;
} ;
} ) ( /[xy]/g , function ( c ) {
var r = math . random ( ) * 16 | 0 ,
v = c == "x" ? r : ( r & 3 | 8 ) ;
return v . toString ( 16 ) ;
} ) ;
/ * \
* Raphael . setWindow
[ method ]
* *
* Used when you need to draw in ` <iframe> ` . Switched window to the iframe one .
> Parameters
- newwin ( window ) new window object
\ * /
R . setWindow = function ( newwin ) {
eve ( "raphael.setWindow" , R , g . win , newwin ) ;
g . win = newwin ;
g . doc = g . win . document ;
if ( R . _engine . initWin ) {
R . _engine . initWin ( g . win ) ;
}
} ;
var toHex = function ( color ) {
if ( R . vml ) {
// http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
var trim = /^\s+|\s+$/g ;
var bod ;
try {
var docum = new ActiveXObject ( "htmlfile" ) ;
docum . write ( "<body>" ) ;
docum . close ( ) ;
bod = docum . body ;
} catch ( e ) {
bod = createPopup ( ) . document . body ;
}
var range = bod . createTextRange ( ) ;
toHex = cacher ( function ( color ) {
try {
bod . style . color = Str ( color ) . replace ( trim , E ) ;
var value = range . queryCommandValue ( "ForeColor" ) ;
value = ( ( value & 255 ) << 16 ) | ( value & 65280 ) | ( ( value & 16711680 ) >>> 16 ) ;
return "#" + ( "000000" + value . toString ( 16 ) ) . slice ( - 6 ) ;
} catch ( e ) {
return "none" ;
}
} ) ;
} else {
var i = g . doc . createElement ( "i" ) ;
i . title = "Rapha\xebl Colour Picker" ;
i . style . display = "none" ;
g . doc . body . appendChild ( i ) ;
toHex = cacher ( function ( color ) {
i . style . color = color ;
return g . doc . defaultView . getComputedStyle ( i , E ) . getPropertyValue ( "color" ) ;
} ) ;
}
return toHex ( color ) ;
} ,
hsbtoString = function ( ) {
return "hsb(" + [ this . h , this . s , this . b ] + ")" ;
} ,
hsltoString = function ( ) {
return "hsl(" + [ this . h , this . s , this . l ] + ")" ;
} ,
rgbtoString = function ( ) {
return this . hex ;
} ,
prepareRGB = function ( r , g , b ) {
if ( g == null && R . is ( r , "object" ) && "r" in r && "g" in r && "b" in r ) {
b = r . b ;
g = r . g ;
r = r . r ;
}
if ( g == null && R . is ( r , string ) ) {
var clr = R . getRGB ( r ) ;
r = clr . r ;
g = clr . g ;
b = clr . b ;
}
if ( r > 1 || g > 1 || b > 1 ) {
r /= 255 ;
g /= 255 ;
b /= 255 ;
}
return [ r , g , b ] ;
} ,
packageRGB = function ( r , g , b , o ) {
r *= 255 ;
g *= 255 ;
b *= 255 ;
var rgb = {
r : r ,
g : g ,
b : b ,
hex : R . rgb ( r , g , b ) ,
toString : rgbtoString
} ;
R . is ( o , "finite" ) && ( rgb . opacity = o ) ;
return rgb ;
} ;
/ * \
* Raphael . color
[ method ]
* *
* Parses the color string and returns object with all values for the given color .
> Parameters
- clr ( string ) color string in one of the supported formats ( see @ Raphael . getRGB )
= ( object ) Combined RGB & HSB object in format :
o {
o r ( number ) red ,
o g ( number ) green ,
o b ( number ) blue ,
o hex ( string ) color in HTML / CSS format : # • • • • • • ,
o error ( boolean ) ` true ` if string can ’ t be parsed ,
o h ( number ) hue ,
o s ( number ) saturation ,
o v ( number ) value ( brightness ) ,
o l ( number ) lightness
o }
\ * /
R . color = function ( clr ) {
var rgb ;
if ( R . is ( clr , "object" ) && "h" in clr && "s" in clr && "b" in clr ) {
rgb = R . hsb2rgb ( clr ) ;
clr . r = rgb . r ;
clr . g = rgb . g ;
clr . b = rgb . b ;
clr . hex = rgb . hex ;
} else if ( R . is ( clr , "object" ) && "h" in clr && "s" in clr && "l" in clr ) {
rgb = R . hsl2rgb ( clr ) ;
clr . r = rgb . r ;
clr . g = rgb . g ;
clr . b = rgb . b ;
clr . hex = rgb . hex ;
} else {
if ( R . is ( clr , "string" ) ) {
clr = R . getRGB ( clr ) ;
}
if ( R . is ( clr , "object" ) && "r" in clr && "g" in clr && "b" in clr ) {
rgb = R . rgb2hsl ( clr ) ;
clr . h = rgb . h ;
clr . s = rgb . s ;
clr . l = rgb . l ;
rgb = R . rgb2hsb ( clr ) ;
clr . v = rgb . b ;
} else {
clr = { hex : "none" } ;
clr . r = clr . g = clr . b = clr . h = clr . s = clr . v = clr . l = - 1 ;
}
}
clr . toString = rgbtoString ;
return clr ;
} ;
/ * \
* Raphael . hsb2rgb
[ method ]
* *
* Converts HSB values to RGB object .
> Parameters
- h ( number ) hue
- s ( number ) saturation
- v ( number ) value or brightness
= ( object ) RGB object in format :
o {
o r ( number ) red ,
o g ( number ) green ,
o b ( number ) blue ,
o hex ( string ) color in HTML / CSS format : # • • • • • •
o }
\ * /
R . hsb2rgb = function ( h , s , v , o ) {
if ( this . is ( h , "object" ) && "h" in h && "s" in h && "b" in h ) {
v = h . b ;
s = h . s ;
o = h . o ;
h = h . h ;
}
h *= 360 ;
var R , G , B , X , C ;
h = ( h % 360 ) / 60 ;
C = v * s ;
X = C * ( 1 - abs ( h % 2 - 1 ) ) ;
R = G = B = v - C ;
h = ~ ~ h ;
R += [ C , X , 0 , 0 , X , C ] [ h ] ;
G += [ X , C , C , X , 0 , 0 ] [ h ] ;
B += [ 0 , 0 , X , C , C , X ] [ h ] ;
return packageRGB ( R , G , B , o ) ;
} ;
/ * \
* Raphael . hsl2rgb
[ method ]
* *
* Converts HSL values to RGB object .
> Parameters
- h ( number ) hue
- s ( number ) saturation
- l ( number ) luminosity
= ( object ) RGB object in format :
o {
o r ( number ) red ,
o g ( number ) green ,
o b ( number ) blue ,
o hex ( string ) color in HTML / CSS format : # • • • • • •
o }
\ * /
R . hsl2rgb = function ( h , s , l , o ) {
if ( this . is ( h , "object" ) && "h" in h && "s" in h && "l" in h ) {
l = h . l ;
s = h . s ;
h = h . h ;
}
if ( h > 1 || s > 1 || l > 1 ) {
h /= 360 ;
s /= 100 ;
l /= 100 ;
}
h *= 360 ;
var R , G , B , X , C ;
h = ( h % 360 ) / 60 ;
C = 2 * s * ( l < . 5 ? l : 1 - l ) ;
X = C * ( 1 - abs ( h % 2 - 1 ) ) ;
R = G = B = l - C / 2 ;
h = ~ ~ h ;
R += [ C , X , 0 , 0 , X , C ] [ h ] ;
G += [ X , C , C , X , 0 , 0 ] [ h ] ;
B += [ 0 , 0 , X , C , C , X ] [ h ] ;
return packageRGB ( R , G , B , o ) ;
} ;
/ * \
* Raphael . rgb2hsb
[ method ]
* *
* Converts RGB values to HSB object .
> Parameters
- r ( number ) red
- g ( number ) green
- b ( number ) blue
= ( object ) HSB object in format :
o {
o h ( number ) hue
o s ( number ) saturation
o b ( number ) brightness
o }
\ * /
R . rgb2hsb = function ( r , g , b ) {
b = prepareRGB ( r , g , b ) ;
r = b [ 0 ] ;
g = b [ 1 ] ;
b = b [ 2 ] ;
var H , S , V , C ;
V = mmax ( r , g , b ) ;
C = V - mmin ( r , g , b ) ;
H = ( C == 0 ? null :
V == r ? ( g - b ) / C :
V == g ? ( b - r ) / C + 2 :
( r - g ) / C + 4
) ;
H = ( ( H + 360 ) % 6 ) * 60 / 360 ;
S = C == 0 ? 0 : C / V ;
return { h : H , s : S , b : V , toString : hsbtoString } ;
} ;
/ * \
* Raphael . rgb2hsl
[ method ]
* *
* Converts RGB values to HSL object .
> Parameters
- r ( number ) red
- g ( number ) green
- b ( number ) blue
= ( object ) HSL object in format :
o {
o h ( number ) hue
o s ( number ) saturation
o l ( number ) luminosity
o }
\ * /
R . rgb2hsl = function ( r , g , b ) {
b = prepareRGB ( r , g , b ) ;
r = b [ 0 ] ;
g = b [ 1 ] ;
b = b [ 2 ] ;
var H , S , L , M , m , C ;
M = mmax ( r , g , b ) ;
m = mmin ( r , g , b ) ;
C = M - m ;
H = ( C == 0 ? null :
M == r ? ( g - b ) / C :
M == g ? ( b - r ) / C + 2 :
( r - g ) / C + 4 ) ;
H = ( ( H + 360 ) % 6 ) * 60 / 360 ;
L = ( M + m ) / 2 ;
S = ( C == 0 ? 0 :
L < . 5 ? C / ( 2 * L ) :
C / ( 2 - 2 * L ) ) ;
return { h : H , s : S , l : L , toString : hsltoString } ;
} ;
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 ) ,
args = arg . join ( "\u2400" ) ,
cache = newf . cache = newf . cache || { } ,
count = newf . count = newf . count || [ ] ;
if ( cache [ has ] ( args ) ) {
repush ( count , args ) ;
return postprocessor ? postprocessor ( cache [ args ] ) : cache [ args ] ;
}
count . length >= 1e3 && delete cache [ count . shift ( ) ] ;
count . push ( args ) ;
cache [ args ] = f [ apply ] ( scope , arg ) ;
return postprocessor ? postprocessor ( cache [ args ] ) : cache [ args ] ;
}
return newf ;
}
var preload = R . _preload = function ( src , f ) {
var img = g . doc . createElement ( "img" ) ;
img . style . cssText = "position:absolute;left:-9999em;top:-9999em" ;
img . onload = function ( ) {
f . call ( this ) ;
this . onload = null ;
g . doc . body . removeChild ( this ) ;
} ;
img . onerror = function ( ) {
g . doc . body . removeChild ( this ) ;
} ;
g . doc . body . appendChild ( img ) ;
img . src = src ;
} ;
function clrToString ( ) {
return this . hex ;
}
/ * \
* Raphael . getRGB
[ method ]
* *
* Parses colour string as RGB object
> Parameters
- colour ( string ) colour string in one of formats :
# < ul >
# < li > Colour name ( “ < code > red < / c o d e > ” , “ < c o d e > g r e e n < / c o d e > ” , “ < c o d e > c o r n f l o w e r b l u e < / c o d e > ” , e t c ) < / l i >
# < li > # • • • — shortened HTML colour : ( “ < code > # 000 < / c o d e > ” , “ < c o d e > # f c 0 < / c o d e > ” , e t c ) < / l i >
# < li > # • • • • • • — full length HTML colour : ( “ < code > # 000000 < / c o d e > ” , “ < c o d e > # b d 2 3 0 0 < / c o d e > ” ) < / l i >
# < li > rgb ( • • • , • • • , • • • ) — red , green and blue channels ’ values : ( “ < code > rgb ( 200 , & nbsp ; 100 , & nbsp ; 0 ) < / c o d e > ” ) < / l i >
# < li > rgb ( • • • % , • • • % , • • • % ) — same as above , but in % : ( “ < code > rgb ( 100 % , & nbsp ; 175 % , & nbsp ; 0 % ) < / c o d e > ” ) < / l i >
# < li > hsb ( • • • , • • • , • • • ) — hue , saturation and brightness values : ( “ < code > hsb ( 0.5 , & nbsp ; 0.25 , & nbsp ; 1 ) < / c o d e > ” ) < / l i >
# < li > hsb ( • • • % , • • • % , • • • % ) — same as above , but in % < / l i >
# < li > hsl ( • • • , • • • , • • • ) — same as hsb < / l i >
# < li > hsl ( • • • % , • • • % , • • • % ) — same as hsb < / l i >
# < / u l >
= ( object ) RGB object in format :
o {
o r ( number ) red ,
o g ( number ) green ,
o b ( number ) blue
o hex ( string ) color in HTML / CSS format : # • • • • • • ,
o error ( boolean ) true if string can ’ t be parsed
o }
\ * /
R . getRGB = cacher ( function ( colour ) {
if ( ! colour || ! ! ( ( colour = Str ( colour ) ) . indexOf ( "-" ) + 1 ) ) {
return { r : - 1 , g : - 1 , b : - 1 , hex : "none" , error : 1 , toString : clrToString } ;
}
if ( colour == "none" ) {
return { r : - 1 , g : - 1 , b : - 1 , hex : "none" , toString : clrToString } ;
}
! ( hsrg [ has ] ( colour . toLowerCase ( ) . substring ( 0 , 2 ) ) || colour . charAt ( ) == "#" ) && ( colour = toHex ( colour ) ) ;
var res ,
red ,
green ,
blue ,
opacity ,
t ,
values ,
rgb = colour . match ( colourRegExp ) ;
if ( rgb ) {
if ( rgb [ 2 ] ) {
blue = toInt ( rgb [ 2 ] . substring ( 5 ) , 16 ) ;
green = toInt ( rgb [ 2 ] . substring ( 3 , 5 ) , 16 ) ;
red = toInt ( rgb [ 2 ] . substring ( 1 , 3 ) , 16 ) ;
}
if ( rgb [ 3 ] ) {
blue = toInt ( ( t = rgb [ 3 ] . charAt ( 3 ) ) + t , 16 ) ;
green = toInt ( ( t = rgb [ 3 ] . charAt ( 2 ) ) + t , 16 ) ;
red = toInt ( ( t = rgb [ 3 ] . charAt ( 1 ) ) + t , 16 ) ;
}
if ( rgb [ 4 ] ) {
values = rgb [ 4 ] [ split ] ( commaSpaces ) ;
red = toFloat ( values [ 0 ] ) ;
values [ 0 ] . slice ( - 1 ) == "%" && ( red *= 2.55 ) ;
green = toFloat ( values [ 1 ] ) ;
values [ 1 ] . slice ( - 1 ) == "%" && ( green *= 2.55 ) ;
blue = toFloat ( values [ 2 ] ) ;
values [ 2 ] . slice ( - 1 ) == "%" && ( blue *= 2.55 ) ;
rgb [ 1 ] . toLowerCase ( ) . slice ( 0 , 4 ) == "rgba" && ( opacity = toFloat ( values [ 3 ] ) ) ;
values [ 3 ] && values [ 3 ] . slice ( - 1 ) == "%" && ( opacity /= 100 ) ;
}
if ( rgb [ 5 ] ) {
values = rgb [ 5 ] [ split ] ( commaSpaces ) ;
red = toFloat ( values [ 0 ] ) ;
values [ 0 ] . slice ( - 1 ) == "%" && ( red *= 2.55 ) ;
green = toFloat ( values [ 1 ] ) ;
values [ 1 ] . slice ( - 1 ) == "%" && ( green *= 2.55 ) ;
blue = toFloat ( values [ 2 ] ) ;
values [ 2 ] . slice ( - 1 ) == "%" && ( blue *= 2.55 ) ;
( values [ 0 ] . slice ( - 3 ) == "deg" || values [ 0 ] . slice ( - 1 ) == "\xb0" ) && ( red /= 360 ) ;
rgb [ 1 ] . toLowerCase ( ) . slice ( 0 , 4 ) == "hsba" && ( opacity = toFloat ( values [ 3 ] ) ) ;
values [ 3 ] && values [ 3 ] . slice ( - 1 ) == "%" && ( opacity /= 100 ) ;
return R . hsb2rgb ( red , green , blue , opacity ) ;
}
if ( rgb [ 6 ] ) {
values = rgb [ 6 ] [ split ] ( commaSpaces ) ;
red = toFloat ( values [ 0 ] ) ;
values [ 0 ] . slice ( - 1 ) == "%" && ( red *= 2.55 ) ;
green = toFloat ( values [ 1 ] ) ;
values [ 1 ] . slice ( - 1 ) == "%" && ( green *= 2.55 ) ;
blue = toFloat ( values [ 2 ] ) ;
values [ 2 ] . slice ( - 1 ) == "%" && ( blue *= 2.55 ) ;
( values [ 0 ] . slice ( - 3 ) == "deg" || values [ 0 ] . slice ( - 1 ) == "\xb0" ) && ( red /= 360 ) ;
rgb [ 1 ] . toLowerCase ( ) . slice ( 0 , 4 ) == "hsla" && ( opacity = toFloat ( values [ 3 ] ) ) ;
values [ 3 ] && values [ 3 ] . slice ( - 1 ) == "%" && ( opacity /= 100 ) ;
return R . hsl2rgb ( red , green , blue , opacity ) ;
}
rgb = { r : red , g : green , b : blue , toString : clrToString } ;
rgb . hex = "#" + ( 16777216 | blue | ( green << 8 ) | ( red << 16 ) ) . toString ( 16 ) . slice ( 1 ) ;
R . is ( opacity , "finite" ) && ( rgb . opacity = opacity ) ;
return rgb ;
}
return { r : - 1 , g : - 1 , b : - 1 , hex : "none" , error : 1 , toString : clrToString } ;
} , R ) ;
/ * \
* Raphael . hsb
[ method ]
* *
* Converts HSB values to hex representation of the colour .
> Parameters
- h ( number ) hue
- s ( number ) saturation
- b ( number ) value or brightness
= ( string ) hex representation of the colour .
\ * /
R . hsb = cacher ( function ( h , s , b ) {
return R . hsb2rgb ( h , s , b ) . hex ;
} ) ;
/ * \
* Raphael . hsl
[ method ]
* *
* Converts HSL values to hex representation of the colour .
> Parameters
- h ( number ) hue
- s ( number ) saturation
- l ( number ) luminosity
= ( string ) hex representation of the colour .
\ * /
R . hsl = cacher ( function ( h , s , l ) {
return R . hsl2rgb ( h , s , l ) . hex ;
} ) ;
/ * \
* Raphael . rgb
[ method ]
* *
* Converts RGB values to hex representation of the colour .
> Parameters
- r ( number ) red
- g ( number ) green
- b ( number ) blue
= ( string ) hex representation of the colour .
\ * /
R . rgb = cacher ( function ( r , g , b ) {
function round ( x ) { return ( x + 0.5 ) | 0 ; }
return "#" + ( 16777216 | round ( b ) | ( round ( g ) << 8 ) | ( round ( r ) << 16 ) ) . toString ( 16 ) . slice ( 1 ) ;
} ) ;
/ * \
* Raphael . getColor
[ method ]
* *
* On each call returns next colour in the spectrum . To reset it back to red call @ Raphael . getColor . reset
> Parameters
- value ( number ) # optional brightness , default is ` 0.75 `
= ( string ) hex representation of the colour .
\ * /
R . getColor = function ( value ) {
var start = this . getColor . start = this . getColor . start || { h : 0 , s : 1 , b : value || . 75 } ,
rgb = this . hsb2rgb ( start . h , start . s , start . b ) ;
start . h += . 075 ;
if ( start . h > 1 ) {
start . h = 0 ;
start . s -= . 2 ;
start . s <= 0 && ( this . getColor . start = { h : 0 , s : 1 , b : start . b } ) ;
}
return rgb . hex ;
} ;
/ * \
* Raphael . getColor . reset
[ method ]
* *
* Resets spectrum position for @ Raphael . getColor back to red .
\ * /
R . getColor . reset = function ( ) {
delete this . start ;
} ;
// http://schepers.cc/getting-to-the-point
function catmullRom2bezier ( crp , z ) {
var d = [ ] ;
for ( var i = 0 , iLen = crp . length ; iLen - 2 * ! z > i ; i += 2 ) {
var p = [
{ x : + crp [ i - 2 ] , y : + crp [ i - 1 ] } ,
{ x : + crp [ i ] , y : + crp [ i + 1 ] } ,
{ x : + crp [ i + 2 ] , y : + crp [ i + 3 ] } ,
{ x : + crp [ i + 4 ] , y : + crp [ i + 5 ] }
] ;
if ( z ) {
if ( ! i ) {
p [ 0 ] = { x : + crp [ iLen - 2 ] , y : + crp [ iLen - 1 ] } ;
} else if ( iLen - 4 == i ) {
p [ 3 ] = { x : + crp [ 0 ] , y : + crp [ 1 ] } ;
} else if ( iLen - 2 == i ) {
p [ 2 ] = { x : + crp [ 0 ] , y : + crp [ 1 ] } ;
p [ 3 ] = { x : + crp [ 2 ] , y : + crp [ 3 ] } ;
}
} else {
if ( iLen - 4 == i ) {
p [ 3 ] = p [ 2 ] ;
} else if ( ! i ) {
p [ 0 ] = { x : + crp [ i ] , y : + crp [ i + 1 ] } ;
}
}
d . push ( [ "C" ,
( - p [ 0 ] . x + 6 * p [ 1 ] . x + p [ 2 ] . x ) / 6 ,
( - p [ 0 ] . y + 6 * p [ 1 ] . y + p [ 2 ] . y ) / 6 ,
( p [ 1 ] . x + 6 * p [ 2 ] . x - p [ 3 ] . x ) / 6 ,
( p [ 1 ] . y + 6 * p [ 2 ] . y - p [ 3 ] . y ) / 6 ,
p [ 2 ] . x ,
p [ 2 ] . y
] ) ;
}
return d ;
}
/ * \
* Raphael . parsePathString
[ method ]
* *
* Utility method
* *
* Parses given path string into an array of arrays of path segments .
> Parameters
- pathString ( string | array ) path string or array of segments ( in the last case it will be returned straight away )
= ( array ) array of segments .
\ * /
R . parsePathString = function ( pathString ) {
if ( ! pathString ) {
return null ;
}
var pth = paths ( pathString ) ;
if ( pth . arr ) {
return pathClone ( pth . arr ) ;
}
var paramCounts = { a : 7 , c : 6 , h : 1 , l : 2 , m : 2 , r : 4 , q : 4 , s : 4 , t : 2 , v : 1 , z : 0 } ,
data = [ ] ;
if ( R . is ( pathString , array ) && R . is ( pathString [ 0 ] , array ) ) { // rough assumption
data = pathClone ( pathString ) ;
}
if ( ! data . length ) {
Str ( pathString ) . replace ( pathCommand , function ( a , b , c ) {
var params = [ ] ,
name = b . toLowerCase ( ) ;
c . replace ( pathValues , function ( a , b ) {
b && params . push ( + b ) ;
} ) ;
if ( name == "m" && params . length > 2 ) {
data . push ( [ b ] [ concat ] ( params . splice ( 0 , 2 ) ) ) ;
name = "l" ;
b = b == "m" ? "l" : "L" ;
}
if ( name == "r" ) {
data . push ( [ b ] [ concat ] ( params ) ) ;
} else while ( params . length >= paramCounts [ name ] ) {
data . push ( [ b ] [ concat ] ( params . splice ( 0 , paramCounts [ name ] ) ) ) ;
if ( ! paramCounts [ name ] ) {
break ;
}
}
} ) ;
}
data . toString = R . _path2string ;
pth . arr = pathClone ( data ) ;
return data ;
} ;
/ * \
* Raphael . parseTransformString
[ method ]
* *
* Utility method
* *
* Parses given path string into an array of transformations .
> Parameters
- TString ( string | array ) transform string or array of transformations ( in the last case it will be returned straight away )
= ( array ) array of transformations .
\ * /
R . parseTransformString = cacher ( function ( TString ) {
if ( ! TString ) {
return null ;
}
var paramCounts = { r : 3 , s : 4 , t : 2 , m : 6 } ,
data = [ ] ;
if ( R . is ( TString , array ) && R . is ( TString [ 0 ] , array ) ) { // rough assumption
data = pathClone ( TString ) ;
}
if ( ! data . length ) {
Str ( TString ) . replace ( tCommand , function ( a , b , c ) {
var params = [ ] ,
name = lowerCase . call ( b ) ;
c . replace ( pathValues , function ( a , b ) {
b && params . push ( + b ) ;
} ) ;
data . push ( [ b ] [ concat ] ( params ) ) ;
} ) ;
}
data . toString = R . _path2string ;
return data ;
} , this , function ( elem ) {
if ( ! elem ) return elem ;
var newData = [ ] ;
for ( var i = 0 ; i < elem . length ; i ++ ) {
var newLevel = [ ] ;
for ( var j = 0 ; j < elem [ i ] . length ; j ++ ) {
newLevel . push ( elem [ i ] [ j ] ) ;
}
newData . push ( newLevel ) ;
}
return newData ; } ) ;
// PATHS
var paths = function ( ps ) {
var p = paths . ps = paths . ps || { } ;
if ( p [ ps ] ) {
p [ ps ] . sleep = 100 ;
} else {
p [ ps ] = {
sleep : 100
} ;
}
setTimeout ( function ( ) {
for ( var key in p ) if ( p [ has ] ( key ) && key != ps ) {
p [ key ] . sleep -- ;
! p [ key ] . sleep && delete p [ key ] ;
}
} ) ;
return p [ ps ] ;
} ;
/ * \
* Raphael . findDotsAtSegment
[ method ]
* *
* Utility method
* *
* Find dot coordinates on the given cubic bezier curve at the given t .
> Parameters
- p1x ( number ) x of the first point of the curve
- p1y ( number ) y of the first point of the curve
- c1x ( number ) x of the first anchor of the curve
- c1y ( number ) y of the first anchor of the curve
- c2x ( number ) x of the second anchor of the curve
- c2y ( number ) y of the second anchor of the curve
- p2x ( number ) x of the second point of the curve
- p2y ( number ) y of the second point of the curve
- t ( number ) position on the curve ( 0. . 1 )
= ( object ) point information in format :
o {
o x : ( number ) x coordinate of the point
o y : ( number ) y coordinate of the point
o m : {
o x : ( number ) x coordinate of the left anchor
o y : ( number ) y coordinate of the left anchor
o }
o n : {
o x : ( number ) x coordinate of the right anchor
o y : ( number ) y coordinate of the right anchor
o }
o start : {
o x : ( number ) x coordinate of the start of the curve
o y : ( number ) y coordinate of the start of the curve
o }
o end : {
o x : ( number ) x coordinate of the end of the curve
o y : ( number ) y coordinate of the end of the curve
o }
o alpha : ( number ) angle of the curve derivative at the point
o }
\ * /
R . findDotsAtSegment = function ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y , t ) {
var t1 = 1 - t ,
t13 = pow ( t1 , 3 ) ,
t12 = pow ( t1 , 2 ) ,
t2 = t * t ,
t3 = t2 * t ,
x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x ,
y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y ,
mx = p1x + 2 * t * ( c1x - p1x ) + t2 * ( c2x - 2 * c1x + p1x ) ,
my = p1y + 2 * t * ( c1y - p1y ) + t2 * ( c2y - 2 * c1y + p1y ) ,
nx = c1x + 2 * t * ( c2x - c1x ) + t2 * ( p2x - 2 * c2x + c1x ) ,
ny = c1y + 2 * t * ( c2y - c1y ) + t2 * ( p2y - 2 * c2y + c1y ) ,
ax = t1 * p1x + t * c1x ,
ay = t1 * p1y + t * c1y ,
cx = t1 * c2x + t * p2x ,
cy = t1 * c2y + t * p2y ,
alpha = ( 90 - math . atan2 ( mx - nx , my - ny ) * 180 / PI ) ;
( mx > nx || my < ny ) && ( alpha += 180 ) ;
return {
x : x ,
y : y ,
m : { x : mx , y : my } ,
n : { x : nx , y : ny } ,
start : { x : ax , y : ay } ,
end : { x : cx , y : cy } ,
alpha : alpha
} ;
} ;
/ * \
* Raphael . bezierBBox
[ method ]
* *
* Utility method
* *
* Return bounding box of a given cubic bezier curve
> Parameters
- p1x ( number ) x of the first point of the curve
- p1y ( number ) y of the first point of the curve
- c1x ( number ) x of the first anchor of the curve
- c1y ( number ) y of the first anchor of the curve
- c2x ( number ) x of the second anchor of the curve
- c2y ( number ) y of the second anchor of the curve
- p2x ( number ) x of the second point of the curve
- p2y ( number ) y of the second point of the curve
* or
- bez ( array ) array of six points for bezier curve
= ( object ) point information in format :
o {
o min : {
o x : ( number ) x coordinate of the left point
o y : ( number ) y coordinate of the top point
o }
o max : {
o x : ( number ) x coordinate of the right point
o y : ( number ) y coordinate of the bottom point
o }
o }
\ * /
R . bezierBBox = function ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y ) {
if ( ! R . is ( p1x , "array" ) ) {
p1x = [ p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y ] ;
}
var bbox = curveDim . apply ( null , p1x ) ;
return {
x : bbox . min . x ,
y : bbox . min . y ,
x2 : bbox . max . x ,
y2 : bbox . max . y ,
width : bbox . max . x - bbox . min . x ,
height : bbox . max . y - bbox . min . y
} ;
} ;
/ * \
* Raphael . isPointInsideBBox
[ method ]
* *
* Utility method
* *
* Returns ` true ` if given point is inside bounding boxes .
> Parameters
- bbox ( string ) bounding box
- x ( string ) x coordinate of the point
- y ( string ) y coordinate of the point
= ( boolean ) ` true ` if point inside
\ * /
R . isPointInsideBBox = function ( bbox , x , y ) {
return x >= bbox . x && x <= bbox . x2 && y >= bbox . y && y <= bbox . y2 ;
} ;
/ * \
* Raphael . isBBoxIntersect
[ method ]
* *
* Utility method
* *
* Returns ` true ` if two bounding boxes intersect
> Parameters
- bbox1 ( string ) first bounding box
- bbox2 ( string ) second bounding box
= ( boolean ) ` true ` if they intersect
\ * /
R . isBBoxIntersect = function ( bbox1 , bbox2 ) {
var i = R . isPointInsideBBox ;
return i ( bbox2 , bbox1 . x , bbox1 . y )
|| i ( bbox2 , bbox1 . x2 , bbox1 . y )
|| i ( bbox2 , bbox1 . x , bbox1 . y2 )
|| i ( bbox2 , bbox1 . x2 , bbox1 . y2 )
|| i ( bbox1 , bbox2 . x , bbox2 . y )
|| i ( bbox1 , bbox2 . x2 , bbox2 . y )
|| i ( bbox1 , bbox2 . x , bbox2 . y2 )
|| i ( bbox1 , bbox2 . x2 , bbox2 . y2 )
|| ( bbox1 . x < bbox2 . x2 && bbox1 . x > bbox2 . x || bbox2 . x < bbox1 . x2 && bbox2 . x > bbox1 . x )
&& ( bbox1 . y < bbox2 . y2 && bbox1 . y > bbox2 . y || bbox2 . y < bbox1 . y2 && bbox2 . y > bbox1 . y ) ;
} ;
function base3 ( t , p1 , p2 , p3 , p4 ) {
var t1 = - 3 * p1 + 9 * p2 - 9 * p3 + 3 * p4 ,
t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3 ;
return t * t2 - 3 * p1 + 3 * p2 ;
}
function bezlen ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , z ) {
if ( z == null ) {
z = 1 ;
}
z = z > 1 ? 1 : z < 0 ? 0 : z ;
var z2 = z / 2 ,
n = 12 ,
Tvalues = [ - 0.1252 , 0.1252 , - 0.3678 , 0.3678 , - 0.5873 , 0.5873 , - 0.7699 , 0.7699 , - 0.9041 , 0.9041 , - 0.9816 , 0.9816 ] ,
Cvalues = [ 0.2491 , 0.2491 , 0.2335 , 0.2335 , 0.2032 , 0.2032 , 0.1601 , 0.1601 , 0.1069 , 0.1069 , 0.0472 , 0.0472 ] ,
sum = 0 ;
for ( var i = 0 ; i < n ; i ++ ) {
var ct = z2 * Tvalues [ i ] + z2 ,
xbase = base3 ( ct , x1 , x2 , x3 , x4 ) ,
ybase = base3 ( ct , y1 , y2 , y3 , y4 ) ,
comb = xbase * xbase + ybase * ybase ;
sum += Cvalues [ i ] * math . sqrt ( comb ) ;
}
return z2 * sum ;
}
function getTatLen ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , ll ) {
if ( ll < 0 || bezlen ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 ) < ll ) {
return ;
}
var t = 1 ,
step = t / 2 ,
t2 = t - step ,
l ,
e = . 01 ;
l = bezlen ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , t2 ) ;
while ( abs ( l - ll ) > e ) {
step /= 2 ;
t2 += ( l < ll ? 1 : - 1 ) * step ;
l = bezlen ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , t2 ) ;
}
return t2 ;
}
function intersect ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 ) {
if (
mmax ( x1 , x2 ) < mmin ( x3 , x4 ) ||
mmin ( x1 , x2 ) > mmax ( x3 , x4 ) ||
mmax ( y1 , y2 ) < mmin ( y3 , y4 ) ||
mmin ( y1 , y2 ) > mmax ( y3 , y4 )
) {
return ;
}
var nx = ( x1 * y2 - y1 * x2 ) * ( x3 - x4 ) - ( x1 - x2 ) * ( x3 * y4 - y3 * x4 ) ,
ny = ( x1 * y2 - y1 * x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 * y4 - y3 * x4 ) ,
denominator = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 ) ;
if ( ! denominator ) {
return ;
}
var px = nx / denominator ,
py = ny / denominator ,
px2 = + px . toFixed ( 2 ) ,
py2 = + py . toFixed ( 2 ) ;
if (
px2 < + mmin ( x1 , x2 ) . toFixed ( 2 ) ||
px2 > + mmax ( x1 , x2 ) . toFixed ( 2 ) ||
px2 < + mmin ( x3 , x4 ) . toFixed ( 2 ) ||
px2 > + mmax ( x3 , x4 ) . toFixed ( 2 ) ||
py2 < + mmin ( y1 , y2 ) . toFixed ( 2 ) ||
py2 > + mmax ( y1 , y2 ) . toFixed ( 2 ) ||
py2 < + mmin ( y3 , y4 ) . toFixed ( 2 ) ||
py2 > + mmax ( y3 , y4 ) . toFixed ( 2 )
) {
return ;
}
return { x : px , y : py } ;
}
function inter ( bez1 , bez2 ) {
return interHelper ( bez1 , bez2 ) ;
}
function interCount ( bez1 , bez2 ) {
return interHelper ( bez1 , bez2 , 1 ) ;
}
function interHelper ( bez1 , bez2 , justCount ) {
var bbox1 = R . bezierBBox ( bez1 ) ,
bbox2 = R . bezierBBox ( bez2 ) ;
if ( ! R . isBBoxIntersect ( bbox1 , bbox2 ) ) {
return justCount ? 0 : [ ] ;
}
var l1 = bezlen . apply ( 0 , bez1 ) ,
l2 = bezlen . apply ( 0 , bez2 ) ,
n1 = mmax ( ~ ~ ( l1 / 5 ) , 1 ) ,
n2 = mmax ( ~ ~ ( l2 / 5 ) , 1 ) ,
dots1 = [ ] ,
dots2 = [ ] ,
xy = { } ,
res = justCount ? 0 : [ ] ;
for ( var i = 0 ; i < n1 + 1 ; i ++ ) {
var p = R . findDotsAtSegment . apply ( R , bez1 . concat ( i / n1 ) ) ;
dots1 . push ( { x : p . x , y : p . y , t : i / n1 } ) ;
}
for ( i = 0 ; i < n2 + 1 ; i ++ ) {
p = R . findDotsAtSegment . apply ( R , bez2 . concat ( i / n2 ) ) ;
dots2 . push ( { x : p . x , y : p . y , t : i / n2 } ) ;
}
for ( i = 0 ; i < n1 ; i ++ ) {
for ( var j = 0 ; j < n2 ; j ++ ) {
var di = dots1 [ i ] ,
di1 = dots1 [ i + 1 ] ,
dj = dots2 [ j ] ,
dj1 = dots2 [ j + 1 ] ,
ci = abs ( di1 . x - di . x ) < . 001 ? "y" : "x" ,
cj = abs ( dj1 . x - dj . x ) < . 001 ? "y" : "x" ,
is = intersect ( di . x , di . y , di1 . x , di1 . y , dj . x , dj . y , dj1 . x , dj1 . y ) ;
if ( is ) {
if ( xy [ is . x . toFixed ( 4 ) ] == is . y . toFixed ( 4 ) ) {
continue ;
}
xy [ is . x . toFixed ( 4 ) ] = is . y . toFixed ( 4 ) ;
var t1 = di . t + abs ( ( is [ ci ] - di [ ci ] ) / ( di1 [ ci ] - di [ ci ] ) ) * ( di1 . t - di . t ) ,
t2 = dj . t + abs ( ( is [ cj ] - dj [ cj ] ) / ( dj1 [ cj ] - dj [ cj ] ) ) * ( dj1 . t - dj . t ) ;
if ( t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001 ) {
if ( justCount ) {
res ++ ;
} else {
res . push ( {
x : is . x ,
y : is . y ,
t1 : mmin ( t1 , 1 ) ,
t2 : mmin ( t2 , 1 )
} ) ;
}
}
}
}
}
return res ;
}
/ * \
* Raphael . pathIntersection
[ method ]
* *
* Utility method
* *
* Finds intersections of two paths
> Parameters
- path1 ( string ) path string
- path2 ( string ) path string
= ( array ) dots of intersection
o [
o {
o x : ( number ) x coordinate of the point
o y : ( number ) y coordinate of the point
o t1 : ( number ) t value for segment of path1
o t2 : ( number ) t value for segment of path2
o segment1 : ( number ) order number for segment of path1
o segment2 : ( number ) order number for segment of path2
o bez1 : ( array ) eight coordinates representing beziér curve for the segment of path1
o bez2 : ( array ) eight coordinates representing beziér curve for the segment of path2
o }
o ]
\ * /
R . pathIntersection = function ( path1 , path2 ) {
return interPathHelper ( path1 , path2 ) ;
} ;
R . pathIntersectionNumber = function ( path1 , path2 ) {
return interPathHelper ( path1 , path2 , 1 ) ;
} ;
function interPathHelper ( path1 , path2 , justCount ) {
path1 = R . _path2curve ( path1 ) ;
path2 = R . _path2curve ( path2 ) ;
var x1 , y1 , x2 , y2 , x1m , y1m , x2m , y2m , bez1 , bez2 ,
res = justCount ? 0 : [ ] ;
for ( var i = 0 , ii = path1 . length ; i < ii ; i ++ ) {
var pi = path1 [ i ] ;
if ( pi [ 0 ] == "M" ) {
x1 = x1m = pi [ 1 ] ;
y1 = y1m = pi [ 2 ] ;
} else {
if ( pi [ 0 ] == "C" ) {
bez1 = [ x1 , y1 ] . concat ( pi . slice ( 1 ) ) ;
x1 = bez1 [ 6 ] ;
y1 = bez1 [ 7 ] ;
} else {
bez1 = [ x1 , y1 , x1 , y1 , x1m , y1m , x1m , y1m ] ;
x1 = x1m ;
y1 = y1m ;
}
for ( var j = 0 , jj = path2 . length ; j < jj ; j ++ ) {
var pj = path2 [ j ] ;
if ( pj [ 0 ] == "M" ) {
x2 = x2m = pj [ 1 ] ;
y2 = y2m = pj [ 2 ] ;
} else {
if ( pj [ 0 ] == "C" ) {
bez2 = [ x2 , y2 ] . concat ( pj . slice ( 1 ) ) ;
x2 = bez2 [ 6 ] ;
y2 = bez2 [ 7 ] ;
} else {
bez2 = [ x2 , y2 , x2 , y2 , x2m , y2m , x2m , y2m ] ;
x2 = x2m ;
y2 = y2m ;
}
var intr = interHelper ( bez1 , bez2 , justCount ) ;
if ( justCount ) {
res += intr ;
} else {
for ( var k = 0 , kk = intr . length ; k < kk ; k ++ ) {
intr [ k ] . segment1 = i ;
intr [ k ] . segment2 = j ;
intr [ k ] . bez1 = bez1 ;
intr [ k ] . bez2 = bez2 ;
}
res = res . concat ( intr ) ;
}
}
}
}
}
return res ;
}
/ * \
* Raphael . isPointInsidePath
[ method ]
* *
* Utility method
* *
* Returns ` true ` if given point is inside a given closed path .
> Parameters
- path ( string ) path string
- x ( number ) x of the point
- y ( number ) y of the point
= ( boolean ) true , if point is inside the path
\ * /
R . isPointInsidePath = function ( path , x , y ) {
var bbox = R . pathBBox ( path ) ;
return R . isPointInsideBBox ( bbox , x , y ) &&
interPathHelper ( path , [ [ "M" , x , y ] , [ "H" , bbox . x2 + 10 ] ] , 1 ) % 2 == 1 ;
} ;
R . _removedFactory = function ( methodname ) {
return function ( ) {
eve ( "raphael.log" , null , "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object" , methodname ) ;
} ;
} ;
/ * \
* Raphael . pathBBox
[ method ]
* *
* Utility method
* *
* Return bounding box of a given path
> Parameters
- path ( string ) path string
= ( object ) bounding box
o {
o x : ( number ) x coordinate of the left top point of the box
o y : ( number ) y coordinate of the left top point of the box
o x2 : ( number ) x coordinate of the right bottom point of the box
o y2 : ( number ) y coordinate of the right bottom point of the box
o width : ( number ) width of the box
o height : ( number ) height of the box
o cx : ( number ) x coordinate of the center of the box
o cy : ( number ) y coordinate of the center of the box
o }
\ * /
var pathDimensions = R . pathBBox = function ( path ) {
var pth = paths ( path ) ;
if ( pth . bbox ) {
return clone ( pth . bbox ) ;
}
if ( ! path ) {
return { x : 0 , y : 0 , width : 0 , height : 0 , x2 : 0 , y2 : 0 } ;
}
path = path2curve ( path ) ;
var x = 0 ,
y = 0 ,
X = [ ] ,
Y = [ ] ,
p ;
for ( var i = 0 , ii = path . length ; i < ii ; i ++ ) {
p = path [ i ] ;
if ( p [ 0 ] == "M" ) {
x = p [ 1 ] ;
y = p [ 2 ] ;
X . push ( x ) ;
Y . push ( y ) ;
} else {
var dim = curveDim ( x , y , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] ) ;
X = X [ concat ] ( dim . min . x , dim . max . x ) ;
Y = Y [ concat ] ( dim . min . y , dim . max . y ) ;
x = p [ 5 ] ;
y = p [ 6 ] ;
}
}
var xmin = mmin [ apply ] ( 0 , X ) ,
ymin = mmin [ apply ] ( 0 , Y ) ,
xmax = mmax [ apply ] ( 0 , X ) ,
ymax = mmax [ apply ] ( 0 , Y ) ,
width = xmax - xmin ,
height = ymax - ymin ,
bb = {
x : xmin ,
y : ymin ,
x2 : xmax ,
y2 : ymax ,
width : width ,
height : height ,
cx : xmin + width / 2 ,
cy : ymin + height / 2
} ;
pth . bbox = clone ( bb ) ;
return bb ;
} ,
pathClone = function ( pathArray ) {
var res = clone ( pathArray ) ;
res . toString = R . _path2string ;
return res ;
} ,
pathToRelative = R . _pathToRelative = function ( pathArray ) {
var pth = paths ( pathArray ) ;
if ( pth . rel ) {
return pathClone ( pth . rel ) ;
}
if ( ! R . is ( pathArray , array ) || ! R . is ( pathArray && pathArray [ 0 ] , array ) ) { // rough assumption
pathArray = R . parsePathString ( pathArray ) ;
}
var res = [ ] ,
x = 0 ,
y = 0 ,
mx = 0 ,
my = 0 ,
start = 0 ;
if ( pathArray [ 0 ] [ 0 ] == "M" ) {
x = pathArray [ 0 ] [ 1 ] ;
y = pathArray [ 0 ] [ 2 ] ;
mx = x ;
my = y ;
start ++ ;
res . push ( [ "M" , x , y ] ) ;
}
for ( var i = start , ii = pathArray . length ; i < ii ; i ++ ) {
var r = res [ i ] = [ ] ,
pa = pathArray [ i ] ;
if ( pa [ 0 ] != lowerCase . call ( pa [ 0 ] ) ) {
r [ 0 ] = lowerCase . call ( pa [ 0 ] ) ;
switch ( r [ 0 ] ) {
case "a" :
r [ 1 ] = pa [ 1 ] ;
r [ 2 ] = pa [ 2 ] ;
r [ 3 ] = pa [ 3 ] ;
r [ 4 ] = pa [ 4 ] ;
r [ 5 ] = pa [ 5 ] ;
r [ 6 ] = + ( pa [ 6 ] - x ) . toFixed ( 3 ) ;
r [ 7 ] = + ( pa [ 7 ] - y ) . toFixed ( 3 ) ;
break ;
case "v" :
r [ 1 ] = + ( pa [ 1 ] - y ) . toFixed ( 3 ) ;
break ;
case "m" :
mx = pa [ 1 ] ;
my = pa [ 2 ] ;
default :
for ( var j = 1 , jj = pa . length ; j < jj ; j ++ ) {
r [ j ] = + ( pa [ j ] - ( ( j % 2 ) ? x : y ) ) . toFixed ( 3 ) ;
}
}
} else {
r = res [ i ] = [ ] ;
if ( pa [ 0 ] == "m" ) {
mx = pa [ 1 ] + x ;
my = pa [ 2 ] + y ;
}
for ( var k = 0 , kk = pa . length ; k < kk ; k ++ ) {
res [ i ] [ k ] = pa [ k ] ;
}
}
var len = res [ i ] . length ;
switch ( res [ i ] [ 0 ] ) {
case "z" :
x = mx ;
y = my ;
break ;
case "h" :
x += + res [ i ] [ len - 1 ] ;
break ;
case "v" :
y += + res [ i ] [ len - 1 ] ;
break ;
default :
x += + res [ i ] [ len - 2 ] ;
y += + res [ i ] [ len - 1 ] ;
}
}
res . toString = R . _path2string ;
pth . rel = pathClone ( res ) ;
return res ;
} ,
pathToAbsolute = R . _pathToAbsolute = function ( pathArray ) {
var pth = paths ( pathArray ) ;
if ( pth . abs ) {
return pathClone ( pth . abs ) ;
}
if ( ! R . is ( pathArray , array ) || ! R . is ( pathArray && pathArray [ 0 ] , array ) ) { // rough assumption
pathArray = R . parsePathString ( pathArray ) ;
}
if ( ! pathArray || ! pathArray . length ) {
return [ [ "M" , 0 , 0 ] ] ;
}
var res = [ ] ,
x = 0 ,
y = 0 ,
mx = 0 ,
my = 0 ,
start = 0 ;
if ( pathArray [ 0 ] [ 0 ] == "M" ) {
x = + pathArray [ 0 ] [ 1 ] ;
y = + pathArray [ 0 ] [ 2 ] ;
mx = x ;
my = y ;
start ++ ;
res [ 0 ] = [ "M" , x , y ] ;
}
var crz = pathArray . length == 3 && pathArray [ 0 ] [ 0 ] == "M" && pathArray [ 1 ] [ 0 ] . toUpperCase ( ) == "R" && pathArray [ 2 ] [ 0 ] . toUpperCase ( ) == "Z" ;
for ( var r , pa , i = start , ii = pathArray . length ; i < ii ; i ++ ) {
res . push ( r = [ ] ) ;
pa = pathArray [ i ] ;
if ( pa [ 0 ] != upperCase . call ( pa [ 0 ] ) ) {
r [ 0 ] = upperCase . call ( pa [ 0 ] ) ;
switch ( r [ 0 ] ) {
case "A" :
r [ 1 ] = pa [ 1 ] ;
r [ 2 ] = pa [ 2 ] ;
r [ 3 ] = pa [ 3 ] ;
r [ 4 ] = pa [ 4 ] ;
r [ 5 ] = pa [ 5 ] ;
r [ 6 ] = + ( pa [ 6 ] + x ) ;
r [ 7 ] = + ( pa [ 7 ] + y ) ;
break ;
case "V" :
r [ 1 ] = + pa [ 1 ] + y ;
break ;
case "H" :
r [ 1 ] = + pa [ 1 ] + x ;
break ;
case "R" :
var dots = [ x , y ] [ concat ] ( pa . slice ( 1 ) ) ;
for ( var j = 2 , jj = dots . length ; j < jj ; j ++ ) {
dots [ j ] = + dots [ j ] + x ;
dots [ ++ j ] = + dots [ j ] + y ;
}
res . pop ( ) ;
res = res [ concat ] ( catmullRom2bezier ( dots , crz ) ) ;
break ;
case "M" :
mx = + pa [ 1 ] + x ;
my = + pa [ 2 ] + y ;
default :
for ( j = 1 , jj = pa . length ; j < jj ; j ++ ) {
r [ j ] = + pa [ j ] + ( ( j % 2 ) ? x : y ) ;
}
}
} else if ( pa [ 0 ] == "R" ) {
dots = [ x , y ] [ concat ] ( pa . slice ( 1 ) ) ;
res . pop ( ) ;
res = res [ concat ] ( catmullRom2bezier ( dots , crz ) ) ;
r = [ "R" ] [ concat ] ( pa . slice ( - 2 ) ) ;
} else {
for ( var k = 0 , kk = pa . length ; k < kk ; k ++ ) {
r [ k ] = pa [ k ] ;
}
}
switch ( r [ 0 ] ) {
case "Z" :
x = mx ;
y = my ;
break ;
case "H" :
x = r [ 1 ] ;
break ;
case "V" :
y = r [ 1 ] ;
break ;
case "M" :
mx = r [ r . length - 2 ] ;
my = r [ r . length - 1 ] ;
default :
x = r [ r . length - 2 ] ;
y = r [ r . length - 1 ] ;
}
}
res . toString = R . _path2string ;
pth . abs = pathClone ( res ) ;
return res ;
} ,
l2c = function ( x1 , y1 , x2 , y2 ) {
return [ x1 , y1 , x2 , y2 , x2 , y2 ] ;
} ,
q2c = function ( x1 , y1 , ax , ay , x2 , y2 ) {
var _13 = 1 / 3 ,
_23 = 2 / 3 ;
return [
_13 * x1 + _23 * ax ,
_13 * y1 + _23 * ay ,
_13 * x2 + _23 * ax ,
_13 * y2 + _23 * ay ,
x2 ,
y2
] ;
} ,
a2c = function ( x1 , y1 , rx , ry , angle , large _arc _flag , sweep _flag , x2 , y2 , recursive ) {
// for more information of where this math came from visit:
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
var _120 = PI * 120 / 180 ,
rad = PI / 180 * ( + angle || 0 ) ,
res = [ ] ,
xy ,
rotate = cacher ( function ( x , y , rad ) {
var X = x * math . cos ( rad ) - y * math . sin ( rad ) ,
Y = x * math . sin ( rad ) + y * math . cos ( rad ) ;
return { x : X , y : Y } ;
} ) ;
if ( ! recursive ) {
xy = rotate ( x1 , y1 , - rad ) ;
x1 = xy . x ;
y1 = xy . y ;
xy = rotate ( x2 , y2 , - rad ) ;
x2 = xy . x ;
y2 = xy . y ;
var cos = math . cos ( PI / 180 * angle ) ,
sin = math . sin ( PI / 180 * angle ) ,
x = ( x1 - x2 ) / 2 ,
y = ( y1 - y2 ) / 2 ;
var h = ( x * x ) / ( rx * rx ) + ( y * y ) / ( ry * ry ) ;
if ( h > 1 ) {
h = math . sqrt ( h ) ;
rx = h * rx ;
ry = h * ry ;
}
var rx2 = rx * rx ,
ry2 = ry * ry ,
k = ( large _arc _flag == sweep _flag ? - 1 : 1 ) *
math . sqrt ( abs ( ( rx2 * ry2 - rx2 * y * y - ry2 * x * x ) / ( rx2 * y * y + ry2 * x * x ) ) ) ,
cx = k * rx * y / ry + ( x1 + x2 ) / 2 ,
cy = k * - ry * x / rx + ( y1 + y2 ) / 2 ,
f1 = math . asin ( ( ( y1 - cy ) / ry ) . toFixed ( 9 ) ) ,
f2 = math . asin ( ( ( y2 - cy ) / ry ) . toFixed ( 9 ) ) ;
f1 = x1 < cx ? PI - f1 : f1 ;
f2 = x2 < cx ? PI - f2 : f2 ;
f1 < 0 && ( f1 = PI * 2 + f1 ) ;
f2 < 0 && ( f2 = PI * 2 + f2 ) ;
if ( sweep _flag && f1 > f2 ) {
f1 = f1 - PI * 2 ;
}
if ( ! sweep _flag && f2 > f1 ) {
f2 = f2 - PI * 2 ;
}
} else {
f1 = recursive [ 0 ] ;
f2 = recursive [ 1 ] ;
cx = recursive [ 2 ] ;
cy = recursive [ 3 ] ;
}
var df = f2 - f1 ;
if ( abs ( df ) > _120 ) {
var f2old = f2 ,
x2old = x2 ,
y2old = y2 ;
f2 = f1 + _120 * ( sweep _flag && f2 > f1 ? 1 : - 1 ) ;
x2 = cx + rx * math . cos ( f2 ) ;
y2 = cy + ry * math . sin ( f2 ) ;
res = a2c ( x2 , y2 , rx , ry , angle , 0 , sweep _flag , x2old , y2old , [ f2 , f2old , cx , cy ] ) ;
}
df = f2 - f1 ;
var c1 = math . cos ( f1 ) ,
s1 = math . sin ( f1 ) ,
c2 = math . cos ( f2 ) ,
s2 = math . sin ( f2 ) ,
t = math . tan ( df / 4 ) ,
hx = 4 / 3 * rx * t ,
hy = 4 / 3 * ry * t ,
m1 = [ x1 , y1 ] ,
m2 = [ x1 + hx * s1 , y1 - hy * c1 ] ,
m3 = [ x2 + hx * s2 , y2 - hy * c2 ] ,
m4 = [ x2 , y2 ] ;
m2 [ 0 ] = 2 * m1 [ 0 ] - m2 [ 0 ] ;
m2 [ 1 ] = 2 * m1 [ 1 ] - m2 [ 1 ] ;
if ( recursive ) {
return [ m2 , m3 , m4 ] [ concat ] ( res ) ;
} else {
res = [ m2 , m3 , m4 ] [ concat ] ( res ) . join ( ) [ split ] ( "," ) ;
var newres = [ ] ;
for ( var i = 0 , ii = res . length ; i < ii ; i ++ ) {
newres [ i ] = i % 2 ? rotate ( res [ i - 1 ] , res [ i ] , rad ) . y : rotate ( res [ i ] , res [ i + 1 ] , rad ) . x ;
}
return newres ;
}
} ,
findDotAtSegment = function ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y , t ) {
var t1 = 1 - t ;
return {
x : pow ( t1 , 3 ) * p1x + pow ( t1 , 2 ) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow ( t , 3 ) * p2x ,
y : pow ( t1 , 3 ) * p1y + pow ( t1 , 2 ) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow ( t , 3 ) * p2y
} ;
} ,
curveDim = cacher ( function ( 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 ) ;
}
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 ) ;
}
return {
min : { x : mmin [ apply ] ( 0 , x ) , y : mmin [ apply ] ( 0 , y ) } ,
max : { x : mmax [ apply ] ( 0 , x ) , y : mmax [ apply ] ( 0 , y ) }
} ;
} ) ,
path2curve = R . _path2curve = cacher ( function ( path , path2 ) {
var pth = ! path2 && paths ( path ) ;
if ( ! path2 && pth . curve ) {
return pathClone ( pth . curve ) ;
}
var p = pathToAbsolute ( path ) ,
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 , pcom ) {
var nx , ny , tq = { T : 1 , Q : 1 } ;
if ( ! path ) {
return [ "C" , d . x , d . y , d . x , d . y , d . x , d . y ] ;
}
! ( path [ 0 ] in tq ) && ( d . qx = d . qy = null ) ;
switch ( path [ 0 ] ) {
case "M" :
d . X = path [ 1 ] ;
d . Y = path [ 2 ] ;
break ;
case "A" :
path = [ "C" ] [ concat ] ( a2c [ apply ] ( 0 , [ d . x , d . y ] [ concat ] ( path . slice ( 1 ) ) ) ) ;
break ;
case "S" :
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" :
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" :
d . qx = path [ 1 ] ;
d . qy = path [ 2 ] ;
path = [ "C" ] [ concat ] ( q2c ( d . x , d . y , path [ 1 ] , path [ 2 ] , path [ 3 ] , path [ 4 ] ) ) ;
break ;
case "L" :
path = [ "C" ] [ concat ] ( l2c ( d . x , d . y , path [ 1 ] , path [ 2 ] ) ) ;
break ;
case "H" :
path = [ "C" ] [ concat ] ( l2c ( d . x , d . y , path [ 1 ] , d . y ) ) ;
break ;
case "V" :
path = [ "C" ] [ concat ] ( l2c ( d . x , d . y , d . x , path [ 1 ] ) ) ;
break ;
case "Z" :
path = [ "C" ] [ concat ] ( l2c ( d . x , d . y , d . X , d . Y ) ) ;
break ;
}
return path ;
} ,
fixArc = function ( pp , i ) {
if ( pp [ i ] . length > 7 ) {
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 ) ;
ii = mmax ( p . length , p2 && p2 . length || 0 ) ;
}
} ,
fixM = function ( path1 , path2 , a1 , a2 , i ) {
if ( path1 && path2 && path1 [ i ] [ 0 ] == "M" && path2 [ i ] [ 0 ] != "M" ) {
path2 . splice ( i , 0 , [ "M" , a2 . x , a2 . y ] ) ;
a1 . bx = 0 ;
a1 . by = 0 ;
a1 . x = path1 [ i ] [ 1 ] ;
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 ] && ( 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 ] ,
seg2 = p2 && p2 [ i ] ,
seglen = seg . length ,
seg2len = p2 && seg2 . length ;
attrs . x = seg [ seglen - 2 ] ;
attrs . y = seg [ seglen - 1 ] ;
attrs . bx = toFloat ( seg [ seglen - 4 ] ) || attrs . x ;
attrs . by = toFloat ( seg [ seglen - 3 ] ) || attrs . y ;
attrs2 . bx = p2 && ( toFloat ( seg2 [ seg2len - 4 ] ) || attrs2 . x ) ;
attrs2 . by = p2 && ( toFloat ( seg2 [ seg2len - 3 ] ) || attrs2 . y ) ;
attrs2 . x = p2 && seg2 [ seg2len - 2 ] ;
attrs2 . y = p2 && seg2 [ seg2len - 1 ] ;
}
if ( ! p2 ) {
pth . curve = pathClone ( p ) ;
}
return p2 ? [ p , p2 ] : p ;
} , null , pathClone ) ,
parseDots = R . _parseDots = cacher ( function ( gradient ) {
var dots = [ ] ;
for ( var i = 0 , ii = gradient . length ; i < ii ; i ++ ) {
var dot = { } ,
par = gradient [ i ] . match ( /^([^:]*):?([\d\.]*)/ ) ;
dot . color = R . getRGB ( par [ 1 ] ) ;
if ( dot . color . error ) {
return null ;
}
dot . opacity = dot . color . opacity ;
dot . color = dot . color . hex ;
par [ 2 ] && ( dot . offset = par [ 2 ] + "%" ) ;
dots . push ( dot ) ;
}
for ( i = 1 , ii = dots . length - 1 ; i < ii ; i ++ ) {
if ( ! dots [ i ] . offset ) {
var start = toFloat ( dots [ i - 1 ] . offset || 0 ) ,
end = 0 ;
for ( var j = i + 1 ; j < ii ; j ++ ) {
if ( dots [ j ] . offset ) {
end = dots [ j ] . offset ;
break ;
}
}
if ( ! end ) {
end = 100 ;
j = ii ;
}
end = toFloat ( end ) ;
var d = ( end - start ) / ( j - i + 1 ) ;
for ( ; i < j ; i ++ ) {
start += d ;
dots [ i ] . offset = start + "%" ;
}
}
}
return dots ;
} ) ,
tear = R . _tear = function ( el , paper ) {
el == paper . top && ( paper . top = el . prev ) ;
el == paper . bottom && ( paper . bottom = el . next ) ;
el . next && ( el . next . prev = el . prev ) ;
el . prev && ( el . prev . next = el . next ) ;
} ,
tofront = R . _tofront = function ( el , paper ) {
if ( paper . top === el ) {
return ;
}
tear ( el , paper ) ;
el . next = null ;
el . prev = paper . top ;
paper . top . next = el ;
paper . top = el ;
} ,
toback = R . _toback = function ( el , paper ) {
if ( paper . bottom === el ) {
return ;
}
tear ( el , paper ) ;
el . next = paper . bottom ;
el . prev = null ;
paper . bottom . prev = el ;
paper . bottom = el ;
} ,
insertafter = R . _insertafter = function ( el , el2 , paper ) {
tear ( el , paper ) ;
el2 == paper . top && ( paper . top = el ) ;
el2 . next && ( el2 . next . prev = el ) ;
el . next = el2 . next ;
el . prev = el2 ;
el2 . next = el ;
} ,
insertbefore = R . _insertbefore = function ( el , el2 , paper ) {
tear ( el , paper ) ;
el2 == paper . bottom && ( paper . bottom = el ) ;
el2 . prev && ( el2 . prev . next = el ) ;
el . prev = el2 . prev ;
el2 . prev = el ;
el . next = el2 ;
} ,
/ * \
* Raphael . toMatrix
[ method ]
* *
* Utility method
* *
* Returns matrix of transformations applied to a given path
> Parameters
- path ( string ) path string
- transform ( string | array ) transformation string
= ( object ) @ Matrix
\ * /
toMatrix = R . toMatrix = function ( path , transform ) {
var bb = pathDimensions ( path ) ,
el = {
_ : {
transform : E
} ,
getBBox : function ( ) {
return bb ;
}
} ;
extractTransform ( el , transform ) ;
return el . matrix ;
} ,
/ * \
* Raphael . transformPath
[ method ]
* *
* Utility method
* *
* Returns path transformed by a given transformation
> Parameters
- path ( string ) path string
- transform ( string | array ) transformation string
= ( string ) path
\ * /
transformPath = R . transformPath = function ( path , transform ) {
return mapPath ( path , toMatrix ( path , transform ) ) ;
} ,
extractTransform = R . _extractTransform = function ( el , tstr ) {
if ( tstr == null ) {
return el . _ . transform ;
}
tstr = Str ( tstr ) . replace ( /\.{3}|\u2026/g , el . _ . transform || E ) ;
var tdata = R . parseTransformString ( tstr ) ,
deg = 0 ,
dx = 0 ,
dy = 0 ,
sx = 1 ,
sy = 1 ,
_ = el . _ ,
m = new Matrix ;
_ . transform = tdata || [ ] ;
if ( tdata ) {
for ( var i = 0 , ii = tdata . length ; i < ii ; i ++ ) {
var t = tdata [ i ] ,
tlen = t . length ,
command = Str ( t [ 0 ] ) . toLowerCase ( ) ,
absolute = t [ 0 ] != command ,
inver = absolute ? m . invert ( ) : 0 ,
x1 ,
y1 ,
x2 ,
y2 ,
bb ;
if ( command == "t" && tlen == 3 ) {
if ( absolute ) {
x1 = inver . x ( 0 , 0 ) ;
y1 = inver . y ( 0 , 0 ) ;
x2 = inver . x ( t [ 1 ] , t [ 2 ] ) ;
y2 = inver . y ( t [ 1 ] , t [ 2 ] ) ;
m . translate ( x2 - x1 , y2 - y1 ) ;
} else {
m . translate ( t [ 1 ] , t [ 2 ] ) ;
}
} else if ( command == "r" ) {
if ( tlen == 2 ) {
bb = bb || el . getBBox ( 1 ) ;
m . rotate ( t [ 1 ] , bb . x + bb . width / 2 , bb . y + bb . height / 2 ) ;
deg += t [ 1 ] ;
} else if ( tlen == 4 ) {
if ( absolute ) {
x2 = inver . x ( t [ 2 ] , t [ 3 ] ) ;
y2 = inver . y ( t [ 2 ] , t [ 3 ] ) ;
m . rotate ( t [ 1 ] , x2 , y2 ) ;
} else {
m . rotate ( t [ 1 ] , t [ 2 ] , t [ 3 ] ) ;
}
deg += t [ 1 ] ;
}
} else if ( command == "s" ) {
if ( tlen == 2 || tlen == 3 ) {
bb = bb || el . getBBox ( 1 ) ;
m . scale ( t [ 1 ] , t [ tlen - 1 ] , bb . x + bb . width / 2 , bb . y + bb . height / 2 ) ;
sx *= t [ 1 ] ;
sy *= t [ tlen - 1 ] ;
} else if ( tlen == 5 ) {
if ( absolute ) {
x2 = inver . x ( t [ 3 ] , t [ 4 ] ) ;
y2 = inver . y ( t [ 3 ] , t [ 4 ] ) ;
m . scale ( t [ 1 ] , t [ 2 ] , x2 , y2 ) ;
} else {
m . scale ( t [ 1 ] , t [ 2 ] , t [ 3 ] , t [ 4 ] ) ;
}
sx *= t [ 1 ] ;
sy *= t [ 2 ] ;
}
} else if ( command == "m" && tlen == 7 ) {
m . add ( t [ 1 ] , t [ 2 ] , t [ 3 ] , t [ 4 ] , t [ 5 ] , t [ 6 ] ) ;
}
_ . dirtyT = 1 ;
el . matrix = m ;
}
}
/ * \
* Element . matrix
[ property ( object ) ]
* *
* Keeps @ Matrix object , which represents element transformation
\ * /
el . matrix = m ;
_ . sx = sx ;
_ . sy = sy ;
_ . deg = deg ;
_ . dx = dx = m . e ;
_ . dy = dy = m . f ;
if ( sx == 1 && sy == 1 && ! deg && _ . bbox ) {
_ . bbox . x += + dx ;
_ . bbox . y += + dy ;
} else {
_ . dirtyT = 1 ;
}
} ,
getEmpty = function ( item ) {
var l = item [ 0 ] ;
switch ( l . toLowerCase ( ) ) {
case "t" : return [ l , 0 , 0 ] ;
case "m" : return [ l , 1 , 0 , 0 , 1 , 0 , 0 ] ;
case "r" : if ( item . length == 4 ) {
return [ l , 0 , item [ 2 ] , item [ 3 ] ] ;
} else {
return [ l , 0 ] ;
}
case "s" : if ( item . length == 5 ) {
return [ l , 1 , 1 , item [ 3 ] , item [ 4 ] ] ;
} else if ( item . length == 3 ) {
return [ l , 1 , 1 ] ;
} else {
return [ l , 1 ] ;
}
}
} ,
equaliseTransform = R . _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 ) ,
from = [ ] ,
to = [ ] ,
i = 0 , j , jj ,
tt1 , tt2 ;
for ( ; i < maxlength ; i ++ ) {
tt1 = t1 [ i ] || getEmpty ( t2 [ i ] ) ;
tt2 = t2 [ i ] || getEmpty ( tt1 ) ;
if ( ( tt1 [ 0 ] != tt2 [ 0 ] ) ||
( tt1 [ 0 ] . toLowerCase ( ) == "r" && ( tt1 [ 2 ] != tt2 [ 2 ] || tt1 [ 3 ] != tt2 [ 3 ] ) ) ||
( tt1 [ 0 ] . toLowerCase ( ) == "s" && ( tt1 [ 3 ] != tt2 [ 3 ] || tt1 [ 4 ] != tt2 [ 4 ] ) )
) {
return ;
}
from [ i ] = [ ] ;
to [ i ] = [ ] ;
for ( j = 0 , jj = mmax ( tt1 . length , tt2 . length ) ; j < jj ; j ++ ) {
j in tt1 && ( from [ i ] [ j ] = tt1 [ j ] ) ;
j in tt2 && ( to [ i ] [ j ] = tt2 [ j ] ) ;
}
}
return {
from : from ,
to : to
} ;
} ;
R . _getContainer = function ( x , y , w , h ) {
var container ;
container = h == null && ! R . is ( x , "object" ) ? g . doc . getElementById ( x ) : x ;
if ( container == null ) {
return ;
}
if ( container . tagName ) {
if ( y == null ) {
return {
container : container ,
width : container . style . pixelWidth || container . offsetWidth ,
height : container . style . pixelHeight || container . offsetHeight
} ;
} else {
return {
container : container ,
width : y ,
height : w
} ;
}
}
return {
container : 1 ,
x : x ,
y : y ,
width : w ,
height : h
} ;
} ;
/ * \
* Raphael . pathToRelative
[ method ]
* *
* Utility method
* *
* Converts path to relative form
> Parameters
- pathString ( string | array ) path string or array of segments
= ( array ) array of segments .
\ * /
R . pathToRelative = pathToRelative ;
R . _engine = { } ;
/ * \
* Raphael . path2curve
[ method ]
* *
* Utility method
* *
* Converts path to a new path where all segments are cubic bezier curves .
> Parameters
- pathString ( string | array ) path string or array of segments
= ( array ) array of segments .
\ * /
R . path2curve = path2curve ;
/ * \
* Raphael . matrix
[ method ]
* *
* Utility method
* *
* Returns matrix based on given parameters .
> Parameters
- a ( number )
- b ( number )
- c ( number )
- d ( number )
- e ( number )
- f ( number )
= ( object ) @ Matrix
\ * /
R . matrix = function ( a , b , c , d , e , f ) {
return new Matrix ( a , b , c , d , e , f ) ;
} ;
function Matrix ( a , b , c , d , e , f ) {
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 given matrix to existing one .
> Parameters
- 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 ] ;
} ;
/ * \
* Matrix . invert
[ method ]
* *
* Returns 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 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
> Parameters
- x ( number )
- y ( number )
\ * /
matrixproto . translate = function ( x , y ) {
this . add ( 1 , 0 , 0 , 1 , x , y ) ;
} ;
/ * \
* Matrix . scale
[ method ]
* *
* Scales the matrix
> Parameters
- x ( number )
- y ( number ) # optional
- cx ( number ) # optional
- cy ( number ) # optional
\ * /
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 ) ;
} ;
/ * \
* Matrix . rotate
[ method ]
* *
* Rotates the matrix
> Parameters
- a ( number )
- x ( number )
- y ( number )
\ * /
matrixproto . rotate = function ( a , x , y ) {
a = R . 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 ) ;
this . add ( 1 , 0 , 0 , 1 , - x , - y ) ;
} ;
/ * \
* Matrix . x
[ method ]
* *
* Return x coordinate for given point after transformation described by the matrix . See also @ Matrix . y
> Parameters
- x ( number )
- y ( number )
= ( number ) x
\ * /
matrixproto . x = function ( x , y ) {
return x * this . a + y * this . c + this . e ;
} ;
/ * \
* Matrix . y
[ method ]
* *
* Return y coordinate for given point after transformation described by the matrix . See also @ Matrix . x
> Parameters
- 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 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 ] ;
}
function normalize ( a ) {
var mag = math . sqrt ( norm ( a ) ) ;
a [ 0 ] && ( a [ 0 ] /= mag ) ;
a [ 1 ] && ( a [ 1 ] /= mag ) ;
}
/ * \
* 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 ;
// rotation
var sin = - row [ 0 ] [ 1 ] ,
cos = row [ 1 ] [ 1 ] ;
if ( cos < 0 ) {
out . rotate = R . deg ( math . acos ( cos ) ) ;
if ( sin < 0 ) {
out . rotate = 360 - out . rotate ;
}
} else {
out . rotate = R . 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 ]
* *
* Return transform string that represents given matrix
= ( string ) transform string
\ * /
matrixproto . toTransformString = function ( shorter ) {
var s = shorter || this [ split ] ( ) ;
if ( s . isSimple ) {
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 , s . dy ] : E ) +
( s . scalex != 1 || s . scaley != 1 ? "s" + [ s . scalex , s . scaley , 0 , 0 ] : E ) +
( s . rotate ? "r" + [ s . rotate , 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 ) ;
var preventDefault = function ( ) {
this . returnValue = false ;
} ,
preventTouch = function ( ) {
return this . originalEvent . preventDefault ( ) ;
} ,
stopPropagation = function ( ) {
this . cancelBubble = true ;
} ,
stopTouch = function ( ) {
return this . originalEvent . stopPropagation ( ) ;
} ,
getEventPosition = function ( e ) {
var scrollY = g . doc . documentElement . scrollTop || g . doc . body . scrollTop ,
scrollX = g . doc . documentElement . scrollLeft || g . doc . body . scrollLeft ;
return {
x : e . clientX + scrollX ,
y : e . clientY + scrollY
} ;
} ,
addEvent = ( function ( ) {
if ( g . doc . addEventListener ) {
return function ( obj , type , fn , element ) {
var f = function ( e ) {
var pos = getEventPosition ( e ) ;
return fn . call ( element , e , pos . x , pos . y ) ;
} ;
obj . addEventListener ( type , f , false ) ;
if ( supportsTouch && touchMap [ type ] ) {
var _f = function ( e ) {
var pos = getEventPosition ( e ) ,
olde = e ;
for ( var i = 0 , ii = e . targetTouches && e . targetTouches . length ; i < ii ; i ++ ) {
if ( e . targetTouches [ i ] . target == obj ) {
e = e . targetTouches [ i ] ;
e . originalEvent = olde ;
e . preventDefault = preventTouch ;
e . stopPropagation = stopTouch ;
break ;
}
}
return fn . call ( element , e , pos . x , pos . y ) ;
} ;
obj . addEventListener ( touchMap [ type ] , _f , false ) ;
}
return function ( ) {
obj . removeEventListener ( type , f , false ) ;
if ( supportsTouch && touchMap [ type ] )
obj . removeEventListener ( touchMap [ type ] , _f , false ) ;
return true ;
} ;
} ;
} else if ( g . doc . attachEvent ) {
return function ( obj , type , fn , element ) {
var f = function ( e ) {
e = e || g . win . event ;
var scrollY = g . doc . documentElement . scrollTop || g . doc . body . scrollTop ,
scrollX = g . doc . documentElement . scrollLeft || g . doc . body . scrollLeft ,
x = e . clientX + scrollX ,
y = e . clientY + scrollY ;
e . preventDefault = e . preventDefault || preventDefault ;
e . stopPropagation = e . stopPropagation || stopPropagation ;
return fn . call ( element , e , x , y ) ;
} ;
obj . attachEvent ( "on" + type , f ) ;
var detacher = function ( ) {
obj . detachEvent ( "on" + type , f ) ;
return true ;
} ;
return detacher ;
} ;
}
} ) ( ) ,
drag = [ ] ,
dragMove = function ( e ) {
var x = e . clientX ,
y = e . clientY ,
scrollY = g . doc . documentElement . scrollTop || g . doc . body . scrollTop ,
scrollX = g . doc . documentElement . scrollLeft || g . doc . body . scrollLeft ,
dragi ,
j = drag . length ;
while ( j -- ) {
dragi = drag [ j ] ;
if ( supportsTouch && e . touches ) {
var i = e . touches . length ,
touch ;
while ( i -- ) {
touch = e . touches [ i ] ;
if ( touch . identifier == dragi . el . _drag . id ) {
x = touch . clientX ;
y = touch . clientY ;
( e . originalEvent ? e . originalEvent : e ) . preventDefault ( ) ;
break ;
}
}
} else {
e . preventDefault ( ) ;
}
var node = dragi . el . node ,
o ,
next = node . nextSibling ,
parent = node . parentNode ,
display = node . style . display ;
g . win . opera && parent . removeChild ( node ) ;
node . style . display = "none" ;
o = dragi . el . paper . getElementByPoint ( x , y ) ;
node . style . display = display ;
g . win . opera && ( next ? parent . insertBefore ( node , next ) : parent . appendChild ( node ) ) ;
o && eve ( "raphael.drag.over." + dragi . el . id , dragi . el , o ) ;
x += scrollX ;
y += scrollY ;
eve ( "raphael.drag.move." + dragi . el . id , dragi . move _scope || dragi . el , x - dragi . el . _drag . x , y - dragi . el . _drag . y , x , y , e ) ;
}
} ,
dragUp = function ( e ) {
R . unmousemove ( dragMove ) . unmouseup ( dragUp ) ;
var i = drag . length ,
dragi ;
while ( i -- ) {
dragi = drag [ i ] ;
dragi . el . _drag = { } ;
eve ( "raphael.drag.end." + dragi . el . id , dragi . end _scope || dragi . start _scope || dragi . move _scope || dragi . el , e ) ;
}
drag = [ ] ;
} ,
/ * \
* Raphael . el
[ property ( object ) ]
* *
* You can add your own method to elements . This is useful when you want to hack default functionality or
* want to wrap some common transformation or attributes in one method . In difference to canvas methods ,
* you can redefine element method at any time . Expending element methods wouldn ’ t affect set .
> Usage
| Raphael . el . red = function ( ) {
| this . attr ( { fill : "#f00" } ) ;
| } ;
| // then use it
| paper . circle ( 100 , 100 , 20 ) . red ( ) ;
\ * /
elproto = R . el = { } ;
/ * \
* Element . click
[ method ]
* *
* Adds event handler for click for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unclick
[ method ]
* *
* Removes event handler for click for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . dblclick
[ method ]
* *
* Adds event handler for double click for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . undblclick
[ method ]
* *
* Removes event handler for double click for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . mousedown
[ method ]
* *
* Adds event handler for mousedown for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unmousedown
[ method ]
* *
* Removes event handler for mousedown for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . mousemove
[ method ]
* *
* Adds event handler for mousemove for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unmousemove
[ method ]
* *
* Removes event handler for mousemove for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . mouseout
[ method ]
* *
* Adds event handler for mouseout for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unmouseout
[ method ]
* *
* Removes event handler for mouseout for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . mouseover
[ method ]
* *
* Adds event handler for mouseover for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unmouseover
[ method ]
* *
* Removes event handler for mouseover for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . mouseup
[ method ]
* *
* Adds event handler for mouseup for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . unmouseup
[ method ]
* *
* Removes event handler for mouseup for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . touchstart
[ method ]
* *
* Adds event handler for touchstart for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . untouchstart
[ method ]
* *
* Removes event handler for touchstart for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . touchmove
[ method ]
* *
* Adds event handler for touchmove for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . untouchmove
[ method ]
* *
* Removes event handler for touchmove for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . touchend
[ method ]
* *
* Adds event handler for touchend for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . untouchend
[ method ]
* *
* Removes event handler for touchend for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . touchcancel
[ method ]
* *
* Adds event handler for touchcancel for the element .
> Parameters
- handler ( function ) handler for the event
= ( object ) @ Element
\ * /
/ * \
* Element . untouchcancel
[ method ]
* *
* Removes event handler for touchcancel for the element .
> Parameters
- handler ( function ) # optional handler for the event
= ( object ) @ Element
\ * /
for ( var i = events . length ; i -- ; ) {
( function ( eventName ) {
R [ eventName ] = elproto [ eventName ] = function ( fn , scope ) {
if ( R . is ( fn , "function" ) ) {
this . events = this . events || [ ] ;
this . events . push ( { name : eventName , f : fn , unbind : addEvent ( this . shape || this . node || g . doc , eventName , fn , scope || this ) } ) ;
}
return this ;
} ;
R [ "un" + eventName ] = elproto [ "un" + eventName ] = function ( fn ) {
var events = this . events || [ ] ,
l = events . length ;
while ( l -- ) {
if ( events [ l ] . name == eventName && ( R . is ( fn , "undefined" ) || events [ l ] . f == fn ) ) {
events [ l ] . unbind ( ) ;
events . splice ( l , 1 ) ;
! events . length && delete this . events ;
}
}
return this ;
} ;
} ) ( events [ i ] ) ;
}
/ * \
* Element . data
[ method ]
* *
* Adds or retrieves given value associated with given key .
* *
* See also @ Element . removeData
> Parameters
- key ( string ) key to store data
- value ( any ) # optional value to store
= ( object ) @ Element
* or , if value is not specified :
= ( any ) value
* or , if key and value are not specified :
= ( object ) Key / value pairs for all the data associated with the element .
> Usage
| for ( var i = 0 , i < 5 , i ++ ) {
| paper . circle ( 10 + 15 * i , 10 , 10 )
| . attr ( { fill : "#000" } )
| . data ( "i" , i )
| . click ( function ( ) {
| alert ( this . data ( "i" ) ) ;
| } ) ;
| }
\ * /
elproto . data = function ( key , value ) {
var data = eldata [ this . id ] = eldata [ this . id ] || { } ;
if ( arguments . length == 0 ) {
return data ;
}
if ( arguments . length == 1 ) {
if ( R . is ( key , "object" ) ) {
for ( var i in key ) if ( key [ has ] ( i ) ) {
this . data ( i , key [ i ] ) ;
}
return this ;
}
eve ( "raphael.data.get." + this . id , this , data [ key ] , key ) ;
return data [ key ] ;
}
data [ key ] = value ;
eve ( "raphael.data.set." + this . id , this , value , key ) ;
return this ;
} ;
/ * \
* Element . removeData
[ method ]
* *
* Removes value associated with an element by given key .
* If key is not provided , removes all the data of the element .
> Parameters
- key ( string ) # optional key
= ( object ) @ Element
\ * /
elproto . removeData = function ( key ) {
if ( key == null ) {
delete eldata [ this . id ] ;
} else {
eldata [ this . id ] && delete eldata [ this . id ] [ key ] ;
}
return this ;
} ;
/ * \
* Element . getData
[ method ]
* *
* Retrieves the element data
= ( object ) data
\ * /
elproto . getData = function ( ) {
return clone ( eldata [ this . id ] || { } ) ;
} ;
/ * \
* Element . hover
[ method ]
* *
* Adds event handlers for hover for the element .
> Parameters
- f _in ( function ) handler for hover in
- f _out ( function ) handler for hover out
- icontext ( object ) # optional context for hover in handler
- ocontext ( object ) # optional context for hover out handler
= ( object ) @ Element
\ * /
elproto . hover = function ( f _in , f _out , scope _in , scope _out ) {
return this . mouseover ( f _in , scope _in ) . mouseout ( f _out , scope _out || scope _in ) ;
} ;
/ * \
* Element . unhover
[ method ]
* *
* Removes event handlers for hover for the element .
> Parameters
- f _in ( function ) handler for hover in
- f _out ( function ) handler for hover out
= ( object ) @ Element
\ * /
elproto . unhover = function ( f _in , f _out ) {
return this . unmouseover ( f _in ) . unmouseout ( f _out ) ;
} ;
var draggable = [ ] ;
/ * \
* Element . drag
[ method ]
* *
* Adds event handlers for drag of the element .
> Parameters
- onmove ( function ) handler for moving
- onstart ( function ) handler for drag start
- onend ( function ) handler for drag end
- mcontext ( object ) # optional context for moving handler
- scontext ( object ) # optional context for drag start handler
- econtext ( object ) # optional context for drag end handler
* Additionally following ` drag ` events will be triggered : ` drag.start.<id> ` on start ,
* ` drag.end.<id> ` on end and ` drag.move.<id> ` on every move . When element will be dragged over another element
* ` drag.over.<id> ` will be fired as well .
*
* Start event and start handler will be called in specified context or in context of the element with following parameters :
o x ( number ) x position of the mouse
o y ( number ) y position of the mouse
o event ( object ) DOM event object
* Move event and move handler will be called in specified context or in context of the element with following parameters :
o dx ( number ) shift by x from the start point
o dy ( number ) shift by y from the start point
o x ( number ) x position of the mouse
o y ( number ) y position of the mouse
o event ( object ) DOM event object
* End event and end handler will be called in specified context or in context of the element with following parameters :
o event ( object ) DOM event object
= ( object ) @ Element
\ * /
elproto . drag = function ( onmove , onstart , onend , move _scope , start _scope , end _scope ) {
function start ( e ) {
( e . originalEvent || e ) . preventDefault ( ) ;
var x = e . clientX ,
y = e . clientY ,
scrollY = g . doc . documentElement . scrollTop || g . doc . body . scrollTop ,
scrollX = g . doc . documentElement . scrollLeft || g . doc . body . scrollLeft ;
this . _drag . id = e . identifier ;
if ( supportsTouch && e . touches ) {
var i = e . touches . length , touch ;
while ( i -- ) {
touch = e . touches [ i ] ;
this . _drag . id = touch . identifier ;
if ( touch . identifier == this . _drag . id ) {
x = touch . clientX ;
y = touch . clientY ;
break ;
}
}
}
this . _drag . x = x + scrollX ;
this . _drag . y = y + scrollY ;
! drag . length && R . mousemove ( dragMove ) . mouseup ( dragUp ) ;
drag . push ( { el : this , move _scope : move _scope , start _scope : start _scope , end _scope : end _scope } ) ;
onstart && eve . on ( "raphael.drag.start." + this . id , onstart ) ;
onmove && eve . on ( "raphael.drag.move." + this . id , onmove ) ;
onend && eve . on ( "raphael.drag.end." + this . id , onend ) ;
eve ( "raphael.drag.start." + this . id , start _scope || move _scope || this , this . _drag . x , this . _drag . y , e ) ;
}
this . _drag = { } ;
draggable . push ( { el : this , start : start } ) ;
this . mousedown ( start ) ;
return this ;
} ;
/ * \
* Element . onDragOver
[ method ]
* *
* Shortcut for assigning event handler for ` drag.over.<id> ` event , where id is id of the element ( see @ Element . id ) .
> Parameters
- f ( function ) handler for event , first argument would be the element you are dragging over
\ * /
elproto . onDragOver = function ( f ) {
f ? eve . on ( "raphael.drag.over." + this . id , f ) : eve . unbind ( "raphael.drag.over." + this . id ) ;
} ;
/ * \
* Element . undrag
[ method ]
* *
* Removes all drag event handlers from given element .
\ * /
elproto . undrag = function ( ) {
var i = draggable . length ;
while ( i -- ) if ( draggable [ i ] . el == this ) {
this . unmousedown ( draggable [ i ] . start ) ;
draggable . splice ( i , 1 ) ;
eve . unbind ( "raphael.drag.*." + this . id ) ;
}
! draggable . length && R . unmousemove ( dragMove ) . unmouseup ( dragUp ) ;
drag = [ ] ;
} ;
/ * \
* Paper . circle
[ method ]
* *
* Draws a circle .
* *
> Parameters
* *
- x ( number ) x coordinate of the centre
- y ( number ) y coordinate of the centre
- r ( number ) radius
= ( object ) Raphaël element object with type “ circle ”
* *
> Usage
| var c = paper . circle ( 50 , 50 , 40 ) ;
\ * /
paperproto . circle = function ( x , y , r ) {
var out = R . _engine . circle ( this , x || 0 , y || 0 , r || 0 ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . rect
[ method ]
*
* Draws a rectangle .
* *
> Parameters
* *
- x ( number ) x coordinate of the top left corner
- y ( number ) y coordinate of the top left corner
- width ( number ) width
- height ( number ) height
- r ( number ) # optional radius for rounded corners , default is 0
= ( object ) Raphaël element object with type “ rect ”
* *
> Usage
| // regular rectangle
| var c = paper . rect ( 10 , 10 , 50 , 50 ) ;
| // rectangle with rounded corners
| var c = paper . rect ( 40 , 40 , 50 , 50 , 10 ) ;
\ * /
paperproto . rect = function ( x , y , w , h , r ) {
var out = R . _engine . rect ( this , x || 0 , y || 0 , w || 0 , h || 0 , r || 0 ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . ellipse
[ method ]
* *
* Draws an ellipse .
* *
> Parameters
* *
- x ( number ) x coordinate of the centre
- y ( number ) y coordinate of the centre
- rx ( number ) horizontal radius
- ry ( number ) vertical radius
= ( object ) Raphaël element object with type “ ellipse ”
* *
> Usage
| var c = paper . ellipse ( 50 , 50 , 40 , 20 ) ;
\ * /
paperproto . ellipse = function ( x , y , rx , ry ) {
var out = R . _engine . ellipse ( this , x || 0 , y || 0 , rx || 0 , ry || 0 ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . path
[ method ]
* *
* Creates a path element by given path data string .
> Parameters
- pathString ( string ) # optional path string in SVG format .
* Path string consists of one - letter commands , followed by comma seprarated arguments in numercal form . Example :
| "M10,20L30,40"
* Here we can see two commands : “ M ” , with arguments ` (10, 20) ` and “ L ” with arguments ` (30, 40) ` . Upper case letter mean command is absolute , lower case — relative .
*
# < 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 > . < / p >
# < table > < thead > < tr > < th > Command < / t h > < t h > N a m e < / t h > < t h > P a r a m e t e r s < / t h > < / t r > < / t h e a d > < t b o d y >
# < tr > < td > M < / t d > < t d > m o v e t o < / t d > < t d > ( x y ) + < / t d > < / t r >
# < tr > < td > Z < / t d > < t d > c l o s e p a t h < / t d > < t d > ( n o n e ) < / t d > < / t r >
# < tr > < td > L < / t d > < t d > l i n e t o < / t d > < t d > ( x y ) + < / t d > < / t r >
# < tr > < td > H < / t d > < t d > h o r i z o n t a l l i n e t o < / t d > < t d > x + < / t d > < / t r >
# < tr > < td > V < / t d > < t d > v e r t i c a l l i n e t o < / t d > < t d > y + < / t d > < / t r >
# < tr > < td > C < / t d > < t d > c u r v e t o < / t d > < t d > ( x 1 y 1 x 2 y 2 x y ) + < / t d > < / t r >
# < tr > < td > S < / t d > < t d > s m o o t h c u r v e t o < / t d > < t d > ( x 2 y 2 x y ) + < / t d > < / t r >
# < tr > < td > Q < / t d > < t d > q u a d r a t i c B é z i e r c u r v e t o < / t d > < t d > ( x 1 y 1 x y ) + < / t d > < / t r >
# < tr > < td > T < / t d > < t d > s m o o t h q u a d r a t i c B é z i e r c u r v e t o < / t d > < t d > ( x y ) + < / t d > < / t r >
# < tr > < td > A < / t d > < t d > e l l i p t i c a l a r c < / t d > < t d > ( r x r y x - a x i s - r o t a t i o n l a r g e - a r c - f l a g s w e e p - f l a g x y ) + < / t d > < / t r >
# < tr > < td > R < /td><td><a href="http:/ / en . wikipedia . org / wiki / Catmull – Rom _spline # Catmull . E2 . 80.93 Rom _spline " > Catmull - Rom curveto < / a > * < / t d > < t d > x 1 y 1 ( x y ) + < / t d > < / t r > < / t b o d y > < / t a b l e >
* * “ Catmull - Rom curveto ” is a not standard SVG command and added in 2.0 to make life easier .
* Note : there is a special case when path consist of just three commands : “ M10 , 10 R … z ” . In this case path will smoothly connects to its beginning .
> Usage
| var c = paper . path ( "M10 10L90 90" ) ;
| // draw a diagonal line:
| // move to 10,10, line to 90,90
* For example of path strings , check out these icons : http : //raphaeljs.com/icons/
\ * /
paperproto . path = function ( pathString ) {
pathString && ! R . is ( pathString , string ) && ! R . is ( pathString [ 0 ] , array ) && ( pathString += E ) ;
var out = R . _engine . path ( R . format [ apply ] ( R , arguments ) , this ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . image
[ method ]
* *
* Embeds an image into the surface .
* *
> Parameters
* *
- src ( string ) URI of the source image
- x ( number ) x coordinate position
- y ( number ) y coordinate position
- width ( number ) width of the image
- height ( number ) height of the image
= ( object ) Raphaël element object with type “ image ”
* *
> Usage
| var c = paper . image ( "apple.png" , 10 , 10 , 80 , 80 ) ;
\ * /
paperproto . image = function ( src , x , y , w , h ) {
var out = R . _engine . image ( this , src || "about:blank" , x || 0 , y || 0 , w || 0 , h || 0 ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . text
[ method ]
* *
* Draws a text string . If you need line breaks , put “ \ n ” in the string .
* *
> Parameters
* *
- x ( number ) x coordinate position
- y ( number ) y coordinate position
- text ( string ) The text string to draw
= ( object ) Raphaël element object with type “ text ”
* *
> Usage
| var t = paper . text ( 50 , 50 , "Raphaël\nkicks\nbutt!" ) ;
\ * /
paperproto . text = function ( x , y , text ) {
var out = R . _engine . text ( this , x || 0 , y || 0 , Str ( text ) ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Paper . set
[ method ]
* *
* Creates array - like object to keep and operate several elements at once .
* Warning : it doesn ’ t create any elements for itself in the page , it just groups existing elements .
* Sets act as pseudo elements — all methods available to an element can be used on a set .
= ( object ) array - like object that represents set of elements
* *
> Usage
| var st = paper . set ( ) ;
| st . push (
| paper . circle ( 10 , 10 , 5 ) ,
| paper . circle ( 30 , 10 , 5 )
| ) ;
| st . attr ( { fill : "red" } ) ; // changes the fill of both circles
\ * /
paperproto . set = function ( itemsArray ) {
! R . is ( itemsArray , "array" ) && ( itemsArray = Array . prototype . splice . call ( arguments , 0 , arguments . length ) ) ;
var out = new Set ( itemsArray ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
out [ "paper" ] = this ;
out [ "type" ] = "set" ;
return out ;
} ;
/ * \
* Paper . setStart
[ method ]
* *
* Creates @ Paper . set . All elements that will be created after calling this method and before calling
* @ Paper . setFinish will be added to the set .
* *
> Usage
| paper . setStart ( ) ;
| paper . circle ( 10 , 10 , 5 ) ,
| paper . circle ( 30 , 10 , 5 )
| var st = paper . setFinish ( ) ;
| st . attr ( { fill : "red" } ) ; // changes the fill of both circles
\ * /
paperproto . setStart = function ( set ) {
this . _ _set _ _ = set || this . set ( ) ;
} ;
/ * \
* Paper . setFinish
[ method ]
* *
* See @ Paper . setStart . This method finishes catching and returns resulting set .
* *
= ( object ) set
\ * /
paperproto . setFinish = function ( set ) {
var out = this . _ _set _ _ ;
delete this . _ _set _ _ ;
return out ;
} ;
/ * \
* Paper . getSize
[ method ]
* *
* Obtains current paper actual size .
* *
= ( object )
\ * /
paperproto . getSize = function ( ) {
var container = this . canvas . parentNode ;
return {
width : container . offsetWidth ,
height : container . offsetHeight
} ;
} ;
/ * \
* Paper . setSize
[ method ]
* *
* If you need to change dimensions of the canvas call this method
* *
> Parameters
* *
- width ( number ) new width of the canvas
- height ( number ) new height of the canvas
\ * /
paperproto . setSize = function ( width , height ) {
return R . _engine . setSize . call ( this , width , height ) ;
} ;
/ * \
* Paper . setViewBox
[ method ]
* *
* Sets the view box of the paper . Practically it gives you ability to zoom and pan whole paper surface by
* specifying new boundaries .
* *
> Parameters
* *
- x ( number ) new x position , default is ` 0 `
- y ( number ) new y position , default is ` 0 `
- w ( number ) new width of the canvas
- h ( number ) new height of the canvas
- fit ( boolean ) ` true ` if you want graphics to fit into new boundary box
\ * /
paperproto . setViewBox = function ( x , y , w , h , fit ) {
return R . _engine . setViewBox . call ( this , x , y , w , h , fit ) ;
} ;
/ * \
* Paper . top
[ property ]
* *
* Points to the topmost element on the paper
\ * /
/ * \
* Paper . bottom
[ property ]
* *
* Points to the bottom element on the paper
\ * /
paperproto . top = paperproto . bottom = null ;
/ * \
* Paper . raphael
[ property ]
* *
* Points to the @ Raphael object / function
\ * /
paperproto . raphael = R ;
var getOffset = function ( elem ) {
var box = elem . getBoundingClientRect ( ) ,
doc = elem . ownerDocument ,
body = doc . body ,
docElem = doc . documentElement ,
clientTop = docElem . clientTop || body . clientTop || 0 , clientLeft = docElem . clientLeft || body . clientLeft || 0 ,
top = box . top + ( g . win . pageYOffset || docElem . scrollTop || body . scrollTop ) - clientTop ,
left = box . left + ( g . win . pageXOffset || docElem . scrollLeft || body . scrollLeft ) - clientLeft ;
return {
y : top ,
x : left
} ;
} ;
/ * \
* Paper . getElementByPoint
[ method ]
* *
* Returns you topmost element under given point .
* *
= ( object ) Raphaël element object
> Parameters
* *
- x ( number ) x coordinate from the top left corner of the window
- y ( number ) y coordinate from the top left corner of the window
> Usage
| paper . getElementByPoint ( mouseX , mouseY ) . attr ( { stroke : "#f00" } ) ;
\ * /
paperproto . getElementByPoint = function ( x , y ) {
var paper = this ,
svg = paper . canvas ,
target = g . doc . elementFromPoint ( x , y ) ;
if ( g . win . opera && target . tagName == "svg" ) {
var so = getOffset ( svg ) ,
sr = svg . createSVGRect ( ) ;
sr . x = x - so . x ;
sr . y = y - so . y ;
sr . width = sr . height = 1 ;
var hits = svg . getIntersectionList ( sr , null ) ;
if ( hits . length ) {
target = hits [ hits . length - 1 ] ;
}
}
if ( ! target ) {
return null ;
}
while ( target . parentNode && target != svg . parentNode && ! target . raphael ) {
target = target . parentNode ;
}
target == paper . canvas . parentNode && ( target = svg ) ;
target = target && target . raphael ? paper . getById ( target . raphaelid ) : null ;
return target ;
} ;
/ * \
* Paper . getElementsByBBox
[ method ]
* *
* Returns set of elements that have an intersecting bounding box
* *
> Parameters
* *
- bbox ( object ) bbox to check with
= ( object ) @ Set
\ * /
paperproto . getElementsByBBox = function ( bbox ) {
var set = this . set ( ) ;
this . forEach ( function ( el ) {
if ( R . isBBoxIntersect ( el . getBBox ( ) , bbox ) ) {
set . push ( el ) ;
}
} ) ;
return set ;
} ;
/ * \
* Paper . getById
[ method ]
* *
* Returns you element by its internal ID .
* *
> Parameters
* *
- id ( number ) id
= ( object ) Raphaël element object
\ * /
paperproto . getById = function ( id ) {
var bot = this . bottom ;
while ( bot ) {
if ( bot . id == id ) {
return bot ;
}
bot = bot . next ;
}
return null ;
} ;
/ * \
* Paper . forEach
[ method ]
* *
* Executes given function for each element on the paper
*
* If callback function returns ` false ` it will stop loop running .
* *
> Parameters
* *
- callback ( function ) function to run
- thisArg ( object ) context object for the callback
= ( object ) Paper object
> Usage
| paper . forEach ( function ( el ) {
| el . attr ( { stroke : "blue" } ) ;
| } ) ;
\ * /
paperproto . forEach = function ( callback , thisArg ) {
var bot = this . bottom ;
while ( bot ) {
if ( callback . call ( thisArg , bot ) === false ) {
return this ;
}
bot = bot . next ;
}
return this ;
} ;
/ * \
* Paper . getElementsByPoint
[ method ]
* *
* Returns set of elements that have common point inside
* *
> Parameters
* *
- x ( number ) x coordinate of the point
- y ( number ) y coordinate of the point
= ( object ) @ Set
\ * /
paperproto . getElementsByPoint = function ( x , y ) {
var set = this . set ( ) ;
this . forEach ( function ( el ) {
if ( el . isPointInside ( x , y ) ) {
set . push ( el ) ;
}
} ) ;
return set ;
} ;
function x _y ( ) {
return this . x + S + this . y ;
}
function x _y _w _h ( ) {
return this . x + S + this . y + S + this . width + " \xd7 " + this . height ;
}
/ * \
* Element . isPointInside
[ method ]
* *
* Determine if given point is inside this element ’ s shape
* *
> Parameters
* *
- x ( number ) x coordinate of the point
- y ( number ) y coordinate of the point
= ( boolean ) ` true ` if point inside the shape
\ * /
elproto . isPointInside = function ( x , y ) {
var rp = this . realPath = getPath [ this . type ] ( this ) ;
if ( this . attr ( 'transform' ) && this . attr ( 'transform' ) . length ) {
rp = R . transformPath ( rp , this . attr ( 'transform' ) ) ;
}
return R . isPointInsidePath ( rp , x , y ) ;
} ;
/ * \
* Element . getBBox
[ method ]
* *
* Return bounding box for a given element
* *
> Parameters
* *
- isWithoutTransform ( boolean ) flag , ` true ` if you want to have bounding box before transformations . Default is ` false ` .
= ( object ) Bounding box object :
o {
o x : ( number ) top left corner x
o y : ( number ) top left corner y
o x2 : ( number ) bottom right corner x
o y2 : ( number ) bottom right corner y
o width : ( number ) width
o height : ( number ) height
o }
\ * /
elproto . getBBox = function ( isWithoutTransform ) {
if ( this . removed ) {
return { } ;
}
var _ = this . _ ;
if ( isWithoutTransform ) {
if ( _ . dirty || ! _ . bboxwt ) {
this . realPath = getPath [ this . type ] ( this ) ;
_ . bboxwt = pathDimensions ( this . realPath ) ;
_ . bboxwt . toString = x _y _w _h ;
_ . dirty = 0 ;
}
return _ . bboxwt ;
}
if ( _ . dirty || _ . dirtyT || ! _ . bbox ) {
if ( _ . dirty || ! this . realPath ) {
_ . bboxwt = 0 ;
this . realPath = getPath [ this . type ] ( this ) ;
}
_ . bbox = pathDimensions ( mapPath ( this . realPath , this . matrix ) ) ;
_ . bbox . toString = x _y _w _h ;
_ . dirty = _ . dirtyT = 0 ;
}
return _ . bbox ;
} ;
/ * \
* Element . clone
[ method ]
* *
= ( object ) clone of a given element
* *
\ * /
elproto . clone = function ( ) {
if ( this . removed ) {
return null ;
}
var out = this . paper [ this . type ] ( ) . attr ( this . attr ( ) ) ;
this . _ _set _ _ && this . _ _set _ _ . push ( out ) ;
return out ;
} ;
/ * \
* Element . glow
[ method ]
* *
* Return set of elements that create glow - like effect around given element . See @ Paper . set .
*
* Note : Glow is not connected to the element . If you change element attributes it won ’ t adjust itself .
* *
> Parameters
* *
- glow ( object ) # optional parameters object with all properties optional :
o {
o width ( number ) size of the glow , default is ` 10 `
o fill ( boolean ) will it be filled , default is ` false `
o opacity ( number ) opacity , default is ` 0.5 `
o offsetx ( number ) horizontal offset , default is ` 0 `
o offsety ( number ) vertical offset , default is ` 0 `
o color ( string ) glow colour , default is ` black `
o }
= ( object ) @ Paper . set of elements that represents glow
\ * /
elproto . glow = function ( glow ) {
if ( this . type == "text" ) {
return null ;
}
glow = glow || { } ;
var s = {
width : ( glow . width || 10 ) + ( + this . attr ( "stroke-width" ) || 1 ) ,
fill : glow . fill || false ,
opacity : glow . opacity == null ? . 5 : glow . opacity ,
offsetx : glow . offsetx || 0 ,
offsety : glow . offsety || 0 ,
color : glow . color || "#000"
} ,
c = s . width / 2 ,
r = this . paper ,
out = r . set ( ) ,
path = this . realPath || getPath [ this . type ] ( this ) ;
path = this . matrix ? mapPath ( path , this . matrix ) : path ;
for ( var i = 1 ; i < c + 1 ; i ++ ) {
out . push ( r . path ( path ) . attr ( {
stroke : s . color ,
fill : s . fill ? s . color : "none" ,
"stroke-linejoin" : "round" ,
"stroke-linecap" : "round" ,
"stroke-width" : + ( s . width / c * i ) . toFixed ( 3 ) ,
opacity : + ( s . opacity / c ) . toFixed ( 3 )
} ) ) ;
}
return out . insertBefore ( this ) . translate ( s . offsetx , s . offsety ) ;
} ;
var curveslengths = { } ,
getPointAtSegmentLength = function ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y , length ) {
if ( length == null ) {
return bezlen ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y ) ;
} else {
return R . findDotsAtSegment ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y , getTatLen ( p1x , p1y , c1x , c1y , c2x , c2y , p2x , p2y , length ) ) ;
}
} ,
getLengthFactory = function ( istotal , subpath ) {
return function ( path , length , onlystart ) {
path = path2curve ( path ) ;
var x , y , p , l , sp = "" , subpaths = { } , point ,
len = 0 ;
for ( var i = 0 , ii = path . length ; i < ii ; i ++ ) {
p = path [ i ] ;
if ( p [ 0 ] == "M" ) {
x = + p [ 1 ] ;
y = + p [ 2 ] ;
} else {
l = getPointAtSegmentLength ( x , y , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] ) ;
if ( len + l > length ) {
if ( subpath && ! subpaths . start ) {
point = getPointAtSegmentLength ( x , y , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] , length - len ) ;
sp += [ "C" + point . start . x , point . start . y , point . m . x , point . m . y , point . x , point . y ] ;
if ( onlystart ) { return sp ; }
subpaths . start = sp ;
sp = [ "M" + point . x , point . y + "C" + point . n . x , point . n . y , point . end . x , point . end . y , p [ 5 ] , p [ 6 ] ] . join ( ) ;
len += l ;
x = + p [ 5 ] ;
y = + p [ 6 ] ;
continue ;
}
if ( ! istotal && ! subpath ) {
point = getPointAtSegmentLength ( x , y , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] , length - len ) ;
return { x : point . x , y : point . y , alpha : point . alpha } ;
}
}
len += l ;
x = + p [ 5 ] ;
y = + p [ 6 ] ;
}
sp += p . shift ( ) + p ;
}
subpaths . end = sp ;
point = istotal ? len : subpath ? subpaths : R . findDotsAtSegment ( x , y , p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , 1 ) ;
point . alpha && ( point = { x : point . x , y : point . y , alpha : point . alpha } ) ;
return point ;
} ;
} ;
var getTotalLength = getLengthFactory ( 1 ) ,
getPointAtLength = getLengthFactory ( ) ,
getSubpathsAtLength = getLengthFactory ( 0 , 1 ) ;
/ * \
* Raphael . getTotalLength
[ method ]
* *
* Returns length of the given path in pixels .
* *
> Parameters
* *
- path ( string ) SVG path string .
* *
= ( number ) length .
\ * /
R . getTotalLength = getTotalLength ;
/ * \
* Raphael . getPointAtLength
[ method ]
* *
* Return coordinates of the point located at the given length on the given path .
* *
> Parameters
* *
- path ( string ) SVG path string
- length ( number )
* *
= ( object ) representation of the point :
o {
o x : ( number ) x coordinate
o y : ( number ) y coordinate
o alpha : ( number ) angle of derivative
o }
\ * /
R . getPointAtLength = getPointAtLength ;
/ * \
* Raphael . getSubpath
[ method ]
* *
* Return subpath of a given path from given length to given length .
* *
> Parameters
* *
- path ( string ) SVG path string
- from ( number ) position of the start of the segment
- to ( number ) position of the end of the segment
* *
= ( string ) pathstring for the segment
\ * /
R . getSubpath = function ( path , from , to ) {
if ( this . getTotalLength ( path ) - to < 1e-6 ) {
return getSubpathsAtLength ( path , from ) . end ;
}
var a = getSubpathsAtLength ( path , to , 1 ) ;
return from ? getSubpathsAtLength ( a , from ) . end : a ;
} ;
/ * \
* Element . getTotalLength
[ method ]
* *
* Returns length of the path in pixels . Only works for element of “ path ” type .
= ( number ) length .
\ * /
elproto . getTotalLength = function ( ) {
var path = this . getPath ( ) ;
if ( ! path ) {
return ;
}
if ( this . node . getTotalLength ) {
return this . node . getTotalLength ( ) ;
}
return getTotalLength ( path ) ;
} ;
/ * \
* Element . getPointAtLength
[ method ]
* *
* Return coordinates of the point located at the given length on the given path . Only works for element of “ path ” type .
* *
> Parameters
* *
- length ( number )
* *
= ( object ) representation of the point :
o {
o x : ( number ) x coordinate
o y : ( number ) y coordinate
o alpha : ( number ) angle of derivative
o }
\ * /
elproto . getPointAtLength = function ( length ) {
var path = this . getPath ( ) ;
if ( ! path ) {
return ;
}
return getPointAtLength ( path , length ) ;
} ;
/ * \
* Element . getPath
[ method ]
* *
* Returns path of the element . Only works for elements of “ path ” type and simple elements like circle .
= ( object ) path
* *
\ * /
elproto . getPath = function ( ) {
var path ,
getPath = R . _getPath [ this . type ] ;
if ( this . type == "text" || this . type == "set" ) {
return ;
}
if ( getPath ) {
path = getPath ( this ) ;
}
return path ;
} ;
/ * \
* Element . getSubpath
[ method ]
* *
* Return subpath of a given element from given length to given length . Only works for element of “ path ” type .
* *
> Parameters
* *
- from ( number ) position of the start of the segment
- to ( number ) position of the end of the segment
* *
= ( string ) pathstring for the segment
\ * /
elproto . getSubpath = function ( from , to ) {
var path = this . getPath ( ) ;
if ( ! path ) {
return ;
}
return R . getSubpath ( path , from , to ) ;
} ;
/ * \
* Raphael . easing _formulas
[ property ]
* *
* Object that contains easing formulas for animation . You could extend it with your own . By default it has following list of easing :
# < ul >
# < li > “ linear ” < / l i >
# < li > “ & lt ; ” or “ easeIn ” or “ ease - in ” < / l i >
# < li > “ > ” or “ easeOut ” or “ ease - out ” < / l i >
# < li > “ & lt ; > ” or “ easeInOut ” or “ ease - in - out ” < / l i >
# < li > “ backIn ” or “ back - in ” < / l i >
# < li > “ backOut ” or “ back - out ” < / l i >
# < li > “ elastic ” < / l i >
# < li > “ bounce ” < / l i >
# < / u l >
# < p > See also < a href = "http://raphaeljs.com/easing.html" > Easing demo < / a > . < / p >
\ * /
var ef = R . easing _formulas = {
linear : function ( n ) {
return n ;
} ,
"<" : function ( n ) {
return pow ( n , 1.7 ) ;
} ,
">" : function ( n ) {
return pow ( n , . 48 ) ;
} ,
"<>" : function ( n ) {
var q = . 48 - n / 1.04 ,
Q = math . sqrt ( . 1734 + q * q ) ,
x = Q - q ,
X = pow ( abs ( x ) , 1 / 3 ) * ( x < 0 ? - 1 : 1 ) ,
y = - Q - q ,
Y = pow ( abs ( y ) , 1 / 3 ) * ( y < 0 ? - 1 : 1 ) ,
t = X + Y + . 5 ;
return ( 1 - t ) * 3 * t * t + t * t * t ;
} ,
backIn : function ( n ) {
var s = 1.70158 ;
return n * n * ( ( s + 1 ) * n - s ) ;
} ,
backOut : function ( n ) {
n = n - 1 ;
var s = 1.70158 ;
return n * n * ( ( s + 1 ) * n + s ) + 1 ;
} ,
elastic : function ( n ) {
if ( n == ! ! n ) {
return n ;
}
return pow ( 2 , - 10 * n ) * math . sin ( ( n - . 075 ) * ( 2 * PI ) / . 3 ) + 1 ;
} ,
bounce : function ( n ) {
var s = 7.5625 ,
p = 2.75 ,
l ;
if ( n < ( 1 / p ) ) {
l = s * n * n ;
} else {
if ( n < ( 2 / p ) ) {
n -= ( 1.5 / p ) ;
l = s * n * n + . 75 ;
} else {
if ( n < ( 2.5 / p ) ) {
n -= ( 2.25 / p ) ;
l = s * n * n + . 9375 ;
} else {
n -= ( 2.625 / p ) ;
l = s * n * n + . 984375 ;
}
}
}
return l ;
}
} ;
ef . easeIn = ef [ "ease-in" ] = ef [ "<" ] ;
ef . easeOut = ef [ "ease-out" ] = ef [ ">" ] ;
ef . easeInOut = ef [ "ease-in-out" ] = ef [ "<>" ] ;
ef [ "back-in" ] = ef . backIn ;
ef [ "back-out" ] = ef . backOut ;
var animationElements = [ ] ,
requestAnimFrame = window . requestAnimationFrame ||
window . webkitRequestAnimationFrame ||
window . mozRequestAnimationFrame ||
window . oRequestAnimationFrame ||
window . msRequestAnimationFrame ||
function ( callback ) {
setTimeout ( callback , 16 ) ;
} ,
animation = function ( ) {
var Now = + new Date ,
l = 0 ;
for ( ; l < animationElements . length ; l ++ ) {
var e = animationElements [ l ] ;
if ( e . el . removed || e . paused ) {
continue ;
}
var time = Now - e . start ,
ms = e . ms ,
easing = e . easing ,
from = e . from ,
diff = e . diff ,
to = e . to ,
t = e . t ,
that = e . el ,
set = { } ,
now ,
init = { } ,
key ;
if ( e . initstatus ) {
time = ( e . initstatus * e . anim . top - e . prev ) / ( e . percent - e . prev ) * ms ;
e . status = e . initstatus ;
delete e . initstatus ;
e . stop && animationElements . splice ( l -- , 1 ) ;
} else {
e . status = ( e . prev + ( e . percent - e . prev ) * ( time / ms ) ) / e . anim . top ;
}
if ( time < 0 ) {
continue ;
}
if ( time < ms ) {
var pos = easing ( time / ms ) ;
for ( var attr in from ) if ( from [ has ] ( attr ) ) {
switch ( availableAnimAttrs [ attr ] ) {
case nu :
now = + from [ attr ] + pos * ms * diff [ attr ] ;
break ;
case "colour" :
now = "rgb(" + [
upto255 ( round ( from [ attr ] . r + pos * ms * diff [ attr ] . r ) ) ,
upto255 ( round ( from [ attr ] . g + pos * ms * diff [ attr ] . g ) ) ,
upto255 ( round ( from [ attr ] . b + pos * ms * diff [ attr ] . b ) )
] . join ( "," ) + ")" ;
break ;
case "path" :
now = [ ] ;
for ( var i = 0 , ii = from [ attr ] . length ; i < ii ; i ++ ) {
now [ i ] = [ from [ attr ] [ i ] [ 0 ] ] ;
for ( var j = 1 , jj = from [ attr ] [ i ] . length ; j < jj ; j ++ ) {
now [ i ] [ j ] = + from [ attr ] [ i ] [ j ] + pos * ms * diff [ attr ] [ i ] [ j ] ;
}
now [ i ] = now [ i ] . join ( S ) ;
}
now = now . join ( S ) ;
break ;
case "transform" :
if ( diff [ attr ] . real ) {
now = [ ] ;
for ( i = 0 , ii = from [ attr ] . length ; i < ii ; i ++ ) {
now [ i ] = [ from [ attr ] [ i ] [ 0 ] ] ;
for ( j = 1 , jj = from [ attr ] [ i ] . length ; j < jj ; j ++ ) {
now [ i ] [ j ] = from [ attr ] [ i ] [ j ] + pos * ms * diff [ attr ] [ i ] [ j ] ;
}
}
} else {
var get = function ( i ) {
return + from [ attr ] [ i ] + pos * ms * diff [ attr ] [ i ] ;
} ;
// now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
now = [ [ "m" , get ( 0 ) , get ( 1 ) , get ( 2 ) , get ( 3 ) , get ( 4 ) , get ( 5 ) ] ] ;
}
break ;
case "csv" :
if ( attr == "clip-rect" ) {
now = [ ] ;
i = 4 ;
while ( i -- ) {
now [ i ] = + from [ attr ] [ i ] + pos * ms * diff [ attr ] [ i ] ;
}
}
break ;
default :
var from2 = [ ] [ concat ] ( from [ attr ] ) ;
now = [ ] ;
i = that . paper . customAttributes [ attr ] . length ;
while ( i -- ) {
now [ i ] = + from2 [ i ] + pos * ms * diff [ attr ] [ i ] ;
}
break ;
}
set [ attr ] = now ;
}
that . attr ( set ) ;
( function ( id , that , anim ) {
setTimeout ( function ( ) {
eve ( "raphael.anim.frame." + id , that , anim ) ;
} ) ;
} ) ( that . id , that , e . anim ) ;
} else {
( function ( f , el , a ) {
setTimeout ( function ( ) {
eve ( "raphael.anim.frame." + el . id , el , a ) ;
eve ( "raphael.anim.finish." + el . id , el , a ) ;
R . is ( f , "function" ) && f . call ( el ) ;
} ) ;
} ) ( e . callback , that , e . anim ) ;
that . attr ( to ) ;
animationElements . splice ( l -- , 1 ) ;
if ( e . repeat > 1 && ! e . next ) {
for ( key in to ) if ( to [ has ] ( key ) ) {
init [ key ] = e . totalOrigin [ key ] ;
}
e . el . attr ( init ) ;
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 , e . repeat ) ;
}
}
}
animationElements . length && requestAnimFrame ( animation ) ;
} ,
upto255 = function ( color ) {
return color > 255 ? 255 : color < 0 ? 0 : color ;
} ;
/ * \
* Element . animateWith
[ method ]
* *
* Acts similar to @ Element . animate , but ensure that given animation runs in sync with another given element .
* *
> Parameters
* *
- el ( object ) element to sync with
- anim ( object ) animation to sync with
- params ( object ) # optional final attributes for the element , see also @ Element . attr
- ms ( number ) # optional number of milliseconds for animation to run
- easing ( string ) # optional easing type . Accept on of @ Raphael . easing _formulas or CSS format : ` cubic‐bezier(XX, XX, XX, XX) `
- callback ( function ) # optional callback function . Will be called at the end of animation .
* or
- element ( object ) element to sync with
- anim ( object ) animation to sync with
- animation ( object ) # optional animation object , see @ Raphael . animation
* *
= ( object ) original element
\ * /
elproto . animateWith = function ( el , anim , params , ms , easing , callback ) {
var element = this ;
if ( element . removed ) {
callback && callback . call ( element ) ;
return element ;
}
var a = params instanceof Animation ? params : R . animation ( params , ms , easing , callback ) ,
x , y ;
runAnimation ( a , element , a . percents [ 0 ] , null , element . attr ( ) ) ;
for ( var i = 0 , ii = animationElements . length ; i < ii ; i ++ ) {
if ( animationElements [ i ] . anim == anim && animationElements [ i ] . el == el ) {
animationElements [ ii - 1 ] . start = animationElements [ i ] . start ;
break ;
}
}
return element ;
//
//
// var a = params ? R.animation(params, ms, easing, callback) : anim,
// status = element.status(anim);
// return this.animate(a).status(a, status * anim.ms / a.ms);
} ;
function CubicBezierAtTime ( t , p1x , p1y , p2x , p2y , duration ) {
var cx = 3 * p1x ,
bx = 3 * ( p2x - p1x ) - cx ,
ax = 1 - cx - bx ,
cy = 3 * p1y ,
by = 3 * ( p2y - p1y ) - cy ,
ay = 1 - cy - by ;
function sampleCurveX ( t ) {
return ( ( ax * t + bx ) * t + cx ) * t ;
}
function solve ( x , epsilon ) {
var t = solveCurveX ( x , epsilon ) ;
return ( ( ay * t + by ) * t + cy ) * t ;
}
function solveCurveX ( x , epsilon ) {
var t0 , t1 , t2 , x2 , d2 , i ;
for ( t2 = x , i = 0 ; i < 8 ; i ++ ) {
x2 = sampleCurveX ( t2 ) - x ;
if ( abs ( x2 ) < epsilon ) {
return t2 ;
}
d2 = ( 3 * ax * t2 + 2 * bx ) * t2 + cx ;
if ( abs ( d2 ) < 1e-6 ) {
break ;
}
t2 = t2 - x2 / d2 ;
}
t0 = 0 ;
t1 = 1 ;
t2 = x ;
if ( t2 < t0 ) {
return t0 ;
}
if ( t2 > t1 ) {
return t1 ;
}
while ( t0 < t1 ) {
x2 = sampleCurveX ( t2 ) ;
if ( abs ( x2 - x ) < epsilon ) {
return t2 ;
}
if ( x > x2 ) {
t0 = t2 ;
} else {
t1 = t2 ;
}
t2 = ( t1 - t0 ) / 2 + t0 ;
}
return t2 ;
}
return solve ( t , 1 / ( 200 * duration ) ) ;
}
elproto . onAnimation = function ( f ) {
f ? eve . on ( "raphael.anim.frame." + this . id , f ) : eve . unbind ( "raphael.anim.frame." + this . id ) ;
return this ;
} ;
function Animation ( anim , ms ) {
var percents = [ ] ,
newAnim = { } ;
this . ms = ms ;
this . times = 1 ;
if ( anim ) {
for ( var attr in anim ) if ( anim [ has ] ( attr ) ) {
newAnim [ toFloat ( attr ) ] = anim [ attr ] ;
percents . push ( toFloat ( attr ) ) ;
}
percents . sort ( sortByNumber ) ;
}
this . anim = newAnim ;
this . top = percents [ percents . length - 1 ] ;
this . percents = percents ;
}
/ * \
* Animation . delay
[ method ]
* *
* Creates a copy of existing animation object with given delay .
* *
> Parameters
* *
- delay ( number ) number of ms to pass between animation start and actual animation
* *
= ( object ) new altered Animation object
| var anim = Raphael . animation ( { cx : 10 , cy : 20 } , 2e3 ) ;
| circle1 . animate ( anim ) ; // run the given animation immediately
| circle2 . animate ( anim . delay ( 500 ) ) ; // run the given animation after 500 ms
\ * /
Animation . prototype . delay = function ( delay ) {
var a = new Animation ( this . anim , this . ms ) ;
a . times = this . times ;
a . del = + delay || 0 ;
return a ;
} ;
/ * \
* Animation . repeat
[ method ]
* *
* Creates a copy of existing animation object with given repetition .
* *
> Parameters
* *
- repeat ( number ) number iterations of animation . For infinite animation pass ` Infinity `
* *
= ( object ) new altered Animation object
\ * /
Animation . prototype . repeat = function ( times ) {
var a = new Animation ( this . anim , this . ms ) ;
a . del = this . del ;
a . times = math . floor ( mmax ( times , 0 ) ) || 1 ;
return a ;
} ;
function runAnimation ( anim , element , percent , status , totalOrigin , times ) {
percent = toFloat ( percent ) ;
var params ,
isInAnim ,
isInAnimSet ,
percents = [ ] ,
next ,
prev ,
timestamp ,
ms = anim . ms ,
from = { } ,
to = { } ,
diff = { } ;
if ( status ) {
for ( i = 0 , ii = animationElements . length ; i < ii ; i ++ ) {
var e = animationElements [ i ] ;
if ( e . el . id == element . id && e . anim == anim ) {
if ( e . percent != percent ) {
animationElements . splice ( i , 1 ) ;
isInAnimSet = 1 ;
} else {
isInAnim = e ;
}
element . attr ( e . totalOrigin ) ;
break ;
}
}
} else {
status = + to ; // NaN
}
for ( var i = 0 , ii = anim . percents . length ; i < ii ; i ++ ) {
if ( anim . percents [ i ] == percent || anim . percents [ i ] > status * anim . top ) {
percent = anim . percents [ i ] ;
prev = anim . percents [ i - 1 ] || 0 ;
ms = ms / anim . top * ( percent - prev ) ;
next = anim . percents [ i + 1 ] ;
params = anim . anim [ percent ] ;
break ;
} else if ( status ) {
element . attr ( anim . anim [ anim . percents [ i ] ] ) ;
}
}
if ( ! params ) {
return ;
}
if ( ! isInAnim ) {
for ( var attr in params ) if ( params [ has ] ( attr ) ) {
if ( availableAnimAttrs [ has ] ( attr ) || element . paper . customAttributes [ has ] ( attr ) ) {
from [ attr ] = element . attr ( attr ) ;
( from [ attr ] == null ) && ( from [ attr ] = availableAttrs [ attr ] ) ;
to [ attr ] = params [ attr ] ;
switch ( availableAnimAttrs [ attr ] ) {
case nu :
diff [ attr ] = ( to [ attr ] - from [ attr ] ) / ms ;
break ;
case "colour" :
from [ attr ] = R . getRGB ( from [ attr ] ) ;
var toColour = R . getRGB ( to [ attr ] ) ;
diff [ attr ] = {
r : ( toColour . r - from [ attr ] . r ) / ms ,
g : ( toColour . g - from [ attr ] . g ) / ms ,
b : ( toColour . b - from [ attr ] . b ) / ms
} ;
break ;
case "path" :
var pathes = path2curve ( from [ attr ] , to [ attr ] ) ,
toPath = pathes [ 1 ] ;
from [ attr ] = pathes [ 0 ] ;
diff [ attr ] = [ ] ;
for ( i = 0 , ii = from [ attr ] . length ; i < ii ; i ++ ) {
diff [ attr ] [ i ] = [ 0 ] ;
for ( var j = 1 , jj = from [ attr ] [ i ] . length ; j < jj ; j ++ ) {
diff [ attr ] [ i ] [ j ] = ( toPath [ i ] [ j ] - from [ attr ] [ i ] [ j ] ) / ms ;
}
}
break ;
case "transform" :
var _ = element . _ ,
eq = equaliseTransform ( _ [ attr ] , to [ attr ] ) ;
if ( eq ) {
from [ attr ] = eq . from ;
to [ attr ] = eq . to ;
diff [ attr ] = [ ] ;
diff [ attr ] . real = true ;
for ( i = 0 , ii = from [ attr ] . length ; i < ii ; i ++ ) {
diff [ attr ] [ i ] = [ from [ attr ] [ i ] [ 0 ] ] ;
for ( j = 1 , jj = from [ attr ] [ i ] . length ; j < jj ; j ++ ) {
diff [ attr ] [ i ] [ j ] = ( to [ attr ] [ i ] [ j ] - from [ attr ] [ i ] [ j ] ) / ms ;
}
}
} else {
var m = ( element . matrix || new Matrix ) ,
to2 = {
_ : { transform : _ . transform } ,
getBBox : function ( ) {
return element . getBBox ( 1 ) ;
}
} ;
from [ attr ] = [
m . a ,
m . b ,
m . c ,
m . d ,
m . e ,
m . f
] ;
extractTransform ( to2 , to [ attr ] ) ;
to [ attr ] = to2 . _ . transform ;
diff [ attr ] = [
( 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 . f - m . f ) / ms
] ;
// from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
// var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
// extractTransform(to2, to[attr]);
// diff[attr] = [
// (to2._.sx - _.sx) / ms,
// (to2._.sy - _.sy) / ms,
// (to2._.deg - _.deg) / ms,
// (to2._.dx - _.dx) / ms,
// (to2._.dy - _.dy) / ms
// ];
}
break ;
case "csv" :
var values = Str ( params [ attr ] ) [ split ] ( separator ) ,
from2 = Str ( from [ attr ] ) [ split ] ( separator ) ;
if ( attr == "clip-rect" ) {
from [ attr ] = from2 ;
diff [ attr ] = [ ] ;
i = from2 . length ;
while ( i -- ) {
diff [ attr ] [ i ] = ( values [ i ] - from [ attr ] [ i ] ) / ms ;
}
}
to [ attr ] = values ;
break ;
default :
values = [ ] [ concat ] ( params [ attr ] ) ;
from2 = [ ] [ concat ] ( from [ attr ] ) ;
diff [ attr ] = [ ] ;
i = element . paper . customAttributes [ attr ] . length ;
while ( i -- ) {
diff [ attr ] [ i ] = ( ( values [ i ] || 0 ) - ( from2 [ i ] || 0 ) ) / ms ;
}
break ;
}
}
}
var easing = params . easing ,
easyeasy = R . easing _formulas [ easing ] ;
if ( ! easyeasy ) {
easyeasy = Str ( easing ) . match ( bezierrg ) ;
if ( easyeasy && easyeasy . length == 5 ) {
var curve = easyeasy ;
easyeasy = function ( t ) {
return CubicBezierAtTime ( t , + curve [ 1 ] , + curve [ 2 ] , + curve [ 3 ] , + curve [ 4 ] , ms ) ;
} ;
} else {
easyeasy = pipe ;
}
}
timestamp = params . start || anim . start || + new Date ;
e = {
anim : anim ,
percent : percent ,
timestamp : timestamp ,
start : timestamp + ( anim . del || 0 ) ,
status : 0 ,
initstatus : status || 0 ,
stop : false ,
ms : ms ,
easing : easyeasy ,
from : from ,
diff : diff ,
to : to ,
el : element ,
callback : params . callback ,
prev : prev ,
next : next ,
repeat : times || anim . times ,
origin : element . attr ( ) ,
totalOrigin : totalOrigin
} ;
animationElements . push ( e ) ;
if ( status && ! isInAnim && ! isInAnimSet ) {
e . stop = true ;
e . start = new Date - ms * status ;
if ( animationElements . length == 1 ) {
return animation ( ) ;
}
}
if ( isInAnimSet ) {
e . start = new Date - e . ms * status ;
}
animationElements . length == 1 && requestAnimFrame ( animation ) ;
} else {
isInAnim . initstatus = status ;
isInAnim . start = new Date - isInAnim . ms * status ;
}
eve ( "raphael.anim.start." + element . id , element , anim ) ;
}
/ * \
* Raphael . animation
[ method ]
* *
* Creates an animation object that can be passed to the @ Element . animate or @ Element . animateWith methods .
* See also @ Animation . delay and @ Animation . repeat methods .
* *
> Parameters
* *
- params ( object ) final attributes for the element , see also @ Element . attr
- ms ( number ) number of milliseconds for animation to run
- easing ( string ) # optional easing type . Accept one of @ Raphael . easing _formulas or CSS format : ` cubic‐bezier(XX, XX, XX, XX) `
- callback ( function ) # optional callback function . Will be called at the end of animation .
* *
= ( object ) @ Animation
\ * /
R . animation = function ( params , ms , easing , callback ) {
if ( params instanceof Animation ) {
return params ;
}
if ( R . is ( easing , "function" ) || ! easing ) {
callback = callback || easing || null ;
easing = null ;
}
params = Object ( params ) ;
ms = + ms || 0 ;
var p = { } ,
json ,
attr ;
for ( attr in params ) if ( params [ has ] ( attr ) && toFloat ( attr ) != attr && toFloat ( attr ) + "%" != attr ) {
json = true ;
p [ attr ] = params [ attr ] ;
}
if ( ! json ) {
// if percent-like syntax is used and end-of-all animation callback used
if ( callback ) {
// find the last one
var lastKey = 0 ;
for ( var i in params ) {
var percent = toInt ( i ) ;
if ( params [ has ] ( i ) && percent > lastKey ) {
lastKey = percent ;
}
}
lastKey += '%' ;
// if already defined callback in the last keyframe, skip
! params [ lastKey ] . callback && ( params [ lastKey ] . callback = callback ) ;
}
return new Animation ( params , ms ) ;
} else {
easing && ( p . easing = easing ) ;
callback && ( p . callback = callback ) ;
return new Animation ( { 100 : p } , ms ) ;
}
} ;
/ * \
* Element . animate
[ method ]
* *
* Creates and starts animation for given element .
* *
> Parameters
* *
- params ( object ) final attributes for the element , see also @ Element . attr
- ms ( number ) number of milliseconds for animation to run
- easing ( string ) # optional easing type . Accept one of @ Raphael . easing _formulas or CSS format : ` cubic‐bezier(XX, XX, XX, XX) `
- callback ( function ) # optional callback function . Will be called at the end of animation .
* or
- animation ( object ) animation object , see @ Raphael . animation
* *
= ( object ) original element
\ * /
elproto . animate = function ( params , ms , easing , callback ) {
var element = this ;
if ( element . removed ) {
callback && callback . call ( element ) ;
return element ;
}
var anim = params instanceof Animation ? params : R . animation ( params , ms , easing , callback ) ;
runAnimation ( anim , element , anim . percents [ 0 ] , null , element . attr ( ) ) ;
return element ;
} ;
/ * \
* Element . setTime
[ method ]
* *
* Sets the status of animation of the element in milliseconds . Similar to @ Element . status method .
* *
> Parameters
* *
- anim ( object ) animation object
- value ( number ) number of milliseconds from the beginning of the animation
* *
= ( object ) original element if ` value ` is specified
* Note , that during animation following events are triggered :
*
* On each animation frame event ` anim.frame.<id> ` , on start ` anim.start.<id> ` and on end ` anim.finish.<id> ` .
\ * /
elproto . setTime = function ( anim , value ) {
if ( anim && value != null ) {
this . status ( anim , mmin ( value , anim . ms ) / anim . ms ) ;
}
return this ;
} ;
/ * \
* Element . status
[ method ]
* *
* Gets or sets the status of animation of the element .
* *
> Parameters
* *
- anim ( object ) # optional animation object
- value ( number ) # optional 0 – 1. If specified , method works like a setter and sets the status of a given animation to the value . This will cause animation to jump to the given position .
* *
= ( number ) status
* or
= ( array ) status if ` anim ` is not specified . Array of objects in format :
o {
o anim : ( object ) animation object
o status : ( number ) status
o }
* or
= ( object ) original element if ` value ` is specified
\ * /
elproto . status = function ( anim , value ) {
var out = [ ] ,
i = 0 ,
len ,
e ;
if ( value != null ) {
runAnimation ( anim , this , - 1 , mmin ( value , 1 ) ) ;
return this ;
} else {
len = animationElements . length ;
for ( ; i < len ; i ++ ) {
e = animationElements [ i ] ;
if ( e . el . id == this . id && ( ! anim || e . anim == anim ) ) {
if ( anim ) {
return e . status ;
}
out . push ( {
anim : e . anim ,
status : e . status
} ) ;
}
}
if ( anim ) {
return 0 ;
}
return out ;
}
} ;
/ * \
* Element . pause
[ method ]
* *
* Stops animation of the element with ability to resume it later on .
* *
> Parameters
* *
- anim ( object ) # optional animation object
* *
= ( object ) original element
\ * /
elproto . pause = function ( anim ) {
for ( var i = 0 ; i < animationElements . length ; i ++ ) if ( animationElements [ i ] . el . id == this . id && ( ! anim || animationElements [ i ] . anim == anim ) ) {
if ( eve ( "raphael.anim.pause." + this . id , this , animationElements [ i ] . anim ) !== false ) {
animationElements [ i ] . paused = true ;
}
}
return this ;
} ;
/ * \
* Element . resume
[ method ]
* *
* Resumes animation if it was paused with @ Element . pause method .
* *
> Parameters
* *
- anim ( object ) # optional animation object
* *
= ( object ) original element
\ * /
elproto . resume = function ( anim ) {
for ( var i = 0 ; i < animationElements . length ; i ++ ) if ( animationElements [ i ] . el . id == this . id && ( ! anim || animationElements [ i ] . anim == anim ) ) {
var e = animationElements [ i ] ;
if ( eve ( "raphael.anim.resume." + this . id , this , e . anim ) !== false ) {
delete e . paused ;
this . status ( e . anim , e . status ) ;
}
}
return this ;
} ;
/ * \
* Element . stop
[ method ]
* *
* Stops animation of the element .
* *
> Parameters
* *
- anim ( object ) # optional animation object
* *
= ( object ) original element
\ * /
elproto . stop = function ( anim ) {
for ( var i = 0 ; i < animationElements . length ; i ++ ) if ( animationElements [ i ] . el . id == this . id && ( ! anim || animationElements [ i ] . anim == anim ) ) {
if ( eve ( "raphael.anim.stop." + this . id , this , animationElements [ i ] . anim ) !== false ) {
animationElements . splice ( i -- , 1 ) ;
}
}
return this ;
} ;
function stopAnimation ( paper ) {
for ( var i = 0 ; i < animationElements . length ; i ++ ) if ( animationElements [ i ] . el . paper == paper ) {
animationElements . splice ( i -- , 1 ) ;
}
}
eve . on ( "raphael.remove" , stopAnimation ) ;
eve . on ( "raphael.clear" , stopAnimation ) ;
elproto . toString = function ( ) {
return "Rapha\xebl\u2019s object" ;
} ;
// Set
var Set = function ( items ) {
this . items = [ ] ;
this . length = 0 ;
this . type = "set" ;
if ( items ) {
for ( var i = 0 , ii = items . length ; i < ii ; i ++ ) {
if ( items [ i ] && ( items [ i ] . constructor == elproto . constructor || items [ i ] . constructor == Set ) ) {
this [ this . items . length ] = this . items [ this . items . length ] = items [ i ] ;
this . length ++ ;
}
}
}
} ,
setproto = Set . prototype ;
/ * \
* Set . push
[ method ]
* *
* Adds each argument to the current set .
= ( object ) original element
\ * /
setproto . push = function ( ) {
var item ,
len ;
for ( var i = 0 , ii = arguments . length ; i < ii ; i ++ ) {
item = arguments [ i ] ;
if ( item && ( item . constructor == elproto . constructor || item . constructor == Set ) ) {
len = this . items . length ;
this [ len ] = this . items [ len ] = item ;
this . length ++ ;
}
}
return this ;
} ;
/ * \
* Set . pop
[ method ]
* *
* Removes last element and returns it .
= ( object ) element
\ * /
setproto . pop = function ( ) {
this . length && delete this [ this . length -- ] ;
return this . items . pop ( ) ;
} ;
/ * \
* Set . forEach
[ method ]
* *
* Executes given function for each element in the set .
*
* If function returns ` false ` it will stop loop running .
* *
> Parameters
* *
- callback ( function ) function to run
- thisArg ( object ) context object for the callback
= ( object ) Set object
\ * /
setproto . forEach = function ( callback , thisArg ) {
for ( var i = 0 , ii = this . items . length ; i < ii ; i ++ ) {
if ( callback . call ( thisArg , this . items [ i ] , i ) === false ) {
return this ;
}
}
return this ;
} ;
for ( var method in elproto ) if ( elproto [ has ] ( method ) ) {
setproto [ method ] = ( function ( methodname ) {
return function ( ) {
var arg = arguments ;
return this . forEach ( function ( el ) {
el [ methodname ] [ apply ] ( el , arg ) ;
} ) ;
} ;
} ) ( method ) ;
}
setproto . attr = function ( name , value ) {
if ( name && R . is ( name , array ) && R . is ( name [ 0 ] , "object" ) ) {
for ( var j = 0 , jj = name . length ; j < jj ; j ++ ) {
this . items [ j ] . attr ( name [ j ] ) ;
}
} else {
for ( var i = 0 , ii = this . items . length ; i < ii ; i ++ ) {
this . items [ i ] . attr ( name , value ) ;
}
}
return this ;
} ;
/ * \
* Set . clear
[ method ]
* *
* Removes all elements from the set
\ * /
setproto . clear = function ( ) {
while ( this . length ) {
this . pop ( ) ;
}
} ;
/ * \
* Set . splice
[ method ]
* *
* Removes given element from the set
* *
> Parameters
* *
- index ( number ) position of the deletion
- count ( number ) number of element to remove
- insertion … ( object ) # optional elements to insert
= ( object ) set elements that were deleted
\ * /
setproto . splice = function ( index , count , insertion ) {
index = index < 0 ? mmax ( this . length + index , 0 ) : index ;
count = mmax ( 0 , mmin ( this . length - index , count ) ) ;
var tail = [ ] ,
todel = [ ] ,
args = [ ] ,
i ;
for ( i = 2 ; i < arguments . length ; i ++ ) {
args . push ( arguments [ i ] ) ;
}
for ( i = 0 ; i < count ; i ++ ) {
todel . push ( this [ index + i ] ) ;
}
for ( ; i < this . length - index ; i ++ ) {
tail . push ( this [ index + i ] ) ;
}
var arglen = args . length ;
for ( i = 0 ; i < arglen + tail . length ; i ++ ) {
this . items [ index + i ] = this [ index + i ] = i < arglen ? args [ i ] : tail [ i - arglen ] ;
}
i = this . items . length = this . length -= count - arglen ;
while ( this [ i ] ) {
delete this [ i ++ ] ;
}
return new Set ( todel ) ;
} ;
/ * \
* Set . exclude
[ method ]
* *
* Removes given element from the set
* *
> Parameters
* *
- element ( object ) element to remove
= ( boolean ) ` true ` if object was found & removed from the set
\ * /
setproto . exclude = function ( el ) {
for ( var i = 0 , ii = this . length ; i < ii ; i ++ ) if ( this [ i ] == el ) {
this . splice ( i , 1 ) ;
return true ;
}
} ;
setproto . animate = function ( params , ms , easing , callback ) {
( R . is ( easing , "function" ) || ! easing ) && ( callback = easing || null ) ;
var len = this . items . length ,
i = len ,
item ,
set = this ,
collector ;
if ( ! len ) {
return this ;
}
callback && ( collector = function ( ) {
! -- len && callback . call ( set ) ;
} ) ;
easing = R . is ( easing , string ) ? easing : collector ;
var anim = R . animation ( params , ms , easing , collector ) ;
item = this . items [ -- i ] . animate ( anim ) ;
while ( i -- ) {
this . items [ i ] && ! this . items [ i ] . removed && this . items [ i ] . animateWith ( item , anim , anim ) ;
( this . items [ i ] && ! this . items [ i ] . removed ) || len -- ;
}
return this ;
} ;
setproto . insertAfter = function ( el ) {
var i = this . items . length ;
while ( i -- ) {
this . items [ i ] . insertAfter ( el ) ;
}
return this ;
} ;
setproto . getBBox = function ( ) {
var x = [ ] ,
y = [ ] ,
x2 = [ ] ,
y2 = [ ] ;
for ( var i = this . items . length ; i -- ; ) if ( ! this . items [ i ] . removed ) {
var box = this . items [ i ] . getBBox ( ) ;
x . push ( box . x ) ;
y . push ( box . y ) ;
x2 . push ( box . x + box . width ) ;
y2 . push ( box . y + box . height ) ;
}
x = mmin [ apply ] ( 0 , x ) ;
y = mmin [ apply ] ( 0 , y ) ;
x2 = mmax [ apply ] ( 0 , x2 ) ;
y2 = mmax [ apply ] ( 0 , y2 ) ;
return {
x : x ,
y : y ,
x2 : x2 ,
y2 : y2 ,
width : x2 - x ,
height : y2 - y
} ;
} ;
setproto . clone = function ( s ) {
s = this . paper . set ( ) ;
for ( var i = 0 , ii = this . items . length ; i < ii ; i ++ ) {
s . push ( this . items [ i ] . clone ( ) ) ;
}
return s ;
} ;
setproto . toString = function ( ) {
return "Rapha\xebl\u2018s set" ;
} ;
setproto . glow = function ( glowConfig ) {
var ret = this . paper . set ( ) ;
this . forEach ( function ( shape , index ) {
var g = shape . glow ( glowConfig ) ;
if ( g != null ) {
g . forEach ( function ( shape2 , index2 ) {
ret . push ( shape2 ) ;
} ) ;
}
} ) ;
return ret ;
} ;
/ * \
* Set . isPointInside
[ method ]
* *
* Determine if given point is inside this set ’ s elements
* *
> Parameters
* *
- x ( number ) x coordinate of the point
- y ( number ) y coordinate of the point
= ( boolean ) ` true ` if point is inside any of the set ' s elements
\ * /
setproto . isPointInside = function ( x , y ) {
var isPointInside = false ;
this . forEach ( function ( el ) {
if ( el . isPointInside ( x , y ) ) {
isPointInside = true ;
return false ; // stop loop
}
} ) ;
return isPointInside ;
} ;
/ * \
* Raphael . registerFont
[ method ]
* *
* Adds given font to the registered set of fonts for Raphaël . Should be used as an internal call from within Cufón ’ s font file .
* Returns original parameter , so it could be used with chaining .
# < a href = "http://wiki.github.com/sorccu/cufon/about" > More about Cufón and how to convert your font form TTF , OTF , etc to JavaScript file . < / a >
* *
> Parameters
* *
- font ( object ) the font to register
= ( object ) the font you passed in
> Usage
| Cufon . registerFont ( Raphael . registerFont ( { … } ) ) ;
\ * /
R . registerFont = function ( font ) {
if ( ! font . face ) {
return font ;
}
this . fonts = this . fonts || { } ;
var fontcopy = {
w : font . w ,
face : { } ,
glyphs : { }
} ,
family = font . face [ "font-family" ] ;
for ( var prop in font . face ) if ( font . face [ has ] ( prop ) ) {
fontcopy . face [ prop ] = font . face [ prop ] ;
}
if ( this . fonts [ family ] ) {
this . fonts [ family ] . push ( fontcopy ) ;
} else {
this . fonts [ family ] = [ fontcopy ] ;
}
if ( ! font . svg ) {
fontcopy . face [ "units-per-em" ] = toInt ( font . face [ "units-per-em" ] , 10 ) ;
for ( var glyph in font . glyphs ) if ( font . glyphs [ has ] ( glyph ) ) {
var path = font . glyphs [ glyph ] ;
fontcopy . glyphs [ glyph ] = {
w : path . w ,
k : { } ,
d : path . d && "M" + path . d . replace ( /[mlcxtrv]/g , function ( command ) {
return { l : "L" , c : "C" , x : "z" , t : "m" , r : "l" , v : "c" } [ command ] || "M" ;
} ) + "z"
} ;
if ( path . k ) {
for ( var k in path . k ) if ( path [ has ] ( k ) ) {
fontcopy . glyphs [ glyph ] . k [ k ] = path . k [ k ] ;
}
}
}
}
return font ;
} ;
/ * \
* Paper . getFont
[ method ]
* *
* Finds font object in the registered fonts by given parameters . You could specify only one word from the font name , like “ Myriad ” for “ Myriad Pro ” .
* *
> Parameters
* *
- family ( string ) font family name or any word from it
- weight ( string ) # optional font weight
- style ( string ) # optional font style
- stretch ( string ) # optional font stretch
= ( object ) the font object
> Usage
| paper . print ( 100 , 100 , "Test string" , paper . getFont ( "Times" , 800 ) , 30 ) ;
\ * /
paperproto . getFont = function ( family , weight , style , stretch ) {
stretch = stretch || "normal" ;
style = style || "normal" ;
weight = + weight || { normal : 400 , bold : 700 , lighter : 300 , bolder : 800 } [ weight ] || 400 ;
if ( ! R . fonts ) {
return ;
}
var font = R . fonts [ family ] ;
if ( ! font ) {
var name = new RegExp ( "(^|\\s)" + family . replace ( /[^\w\d\s+!~.:_-]/g , E ) + "(\\s|$)" , "i" ) ;
for ( var fontName in R . fonts ) if ( R . fonts [ has ] ( fontName ) ) {
if ( name . test ( fontName ) ) {
font = R . fonts [ fontName ] ;
break ;
}
}
}
var thefont ;
if ( font ) {
for ( var i = 0 , ii = font . length ; i < ii ; i ++ ) {
thefont = font [ i ] ;
if ( thefont . face [ "font-weight" ] == weight && ( thefont . face [ "font-style" ] == style || ! thefont . face [ "font-style" ] ) && thefont . face [ "font-stretch" ] == stretch ) {
break ;
}
}
}
return thefont ;
} ;
/ * \
* Paper . print
[ method ]
* *
* Creates path that represent given text written using given font at given position with given size .
* Result of the method is path element that contains whole text as a separate path .
* *
> Parameters
* *
- x ( number ) x position of the text
- y ( number ) y position of the text
- string ( string ) text to print
- font ( object ) font object , see @ Paper . getFont
- size ( number ) # optional size of the font , default is ` 16 `
- origin ( string ) # optional could be ` "baseline" ` or ` "middle" ` , default is ` "middle" `
- letter _spacing ( number ) # optional number in range ` -1..1 ` , default is ` 0 `
- line _spacing ( number ) # optional number in range ` 1..3 ` , default is ` 1 `
= ( object ) resulting path element , which consist of all letters
> Usage
| var txt = r . print ( 10 , 50 , "print" , r . getFont ( "Museo" ) , 30 ) . attr ( { fill : "#fff" } ) ;
\ * /
paperproto . print = function ( x , y , string , font , size , origin , letter _spacing , line _spacing ) {
origin = origin || "middle" ; // baseline|middle
letter _spacing = mmax ( mmin ( letter _spacing || 0 , 1 ) , - 1 ) ;
line _spacing = mmax ( mmin ( line _spacing || 1 , 3 ) , 1 ) ;
var letters = Str ( string ) [ split ] ( E ) ,
shift = 0 ,
notfirst = 0 ,
path = E ,
scale ;
R . is ( font , "string" ) && ( font = this . getFont ( font ) ) ;
if ( font ) {
scale = ( size || 16 ) / font . face [ "units-per-em" ] ;
var bb = font . face . bbox [ split ] ( separator ) ,
top = + bb [ 0 ] ,
lineHeight = bb [ 3 ] - bb [ 1 ] ,
shifty = 0 ,
height = + bb [ 1 ] + ( origin == "baseline" ? lineHeight + ( + font . face . descent ) : lineHeight / 2 ) ;
for ( var i = 0 , ii = letters . length ; i < ii ; i ++ ) {
if ( letters [ i ] == "\n" ) {
shift = 0 ;
curr = 0 ;
notfirst = 0 ;
shifty += lineHeight * line _spacing ;
} else {
var prev = notfirst && font . glyphs [ letters [ i - 1 ] ] || { } ,
curr = font . glyphs [ letters [ i ] ] ;
shift += notfirst ? ( prev . w || font . w ) + ( prev . k && prev . k [ letters [ i ] ] || 0 ) + ( font . w * letter _spacing ) : 0 ;
notfirst = 1 ;
}
if ( curr && curr . d ) {
path += R . transformPath ( curr . d , [ "t" , shift * scale , shifty * scale , "s" , scale , scale , top , height , "t" , ( x - top ) / scale , ( y - height ) / scale ] ) ;
}
}
}
return this . path ( path ) . attr ( {
fill : "#000" ,
stroke : "none"
} ) ;
} ;
/ * \
* Paper . add
[ method ]
* *
* Imports elements in JSON array in format ` {type: type, <attributes>} `
* *
> Parameters
* *
- json ( array )
= ( object ) resulting set of imported elements
> Usage
| paper . add ( [
| {
| type : "circle" ,
| cx : 10 ,
| cy : 10 ,
| r : 5
| } ,
| {
| type : "rect" ,
| x : 10 ,
| y : 10 ,
| width : 10 ,
| height : 10 ,
| fill : "#fc0"
| }
| ] ) ;
\ * /
paperproto . add = function ( json ) {
if ( R . is ( json , "array" ) ) {
var res = this . set ( ) ,
i = 0 ,
ii = json . length ,
j ;
for ( ; i < ii ; i ++ ) {
j = json [ i ] || { } ;
elements [ has ] ( j . type ) && res . push ( this [ j . type ] ( ) . attr ( j ) ) ;
}
}
return res ;
} ;
/ * \
* Raphael . format
[ method ]
* *
* Simple format function . Replaces construction of type “ ` {<number>} ` ” to the corresponding argument .
* *
> Parameters
* *
- token ( string ) string to format
- … ( string ) rest of arguments will be treated as parameters for replacement
= ( string ) formated string
> Usage
| var x = 10 ,
| y = 20 ,
| width = 40 ,
| height = 50 ;
| // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
| paper . path ( Raphael . format ( "M{0},{1}h{2}v{3}h{4}z" , x , y , width , height , - width ) ) ;
\ * /
R . format = function ( token , params ) {
var args = R . is ( params , array ) ? [ 0 ] [ concat ] ( params ) : arguments ;
token && R . is ( token , string ) && args . length - 1 && ( token = token . replace ( formatrg , function ( str , i ) {
return args [ ++ i ] == null ? E : args [ i ] ;
} ) ) ;
return token || E ;
} ;
/ * \
* Raphael . fullfill
[ method ]
* *
* A little bit more advanced format function than @ Raphael . format . 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 ( Raphael . fullfill ( "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
| }
| } ) ) ;
\ * /
R . fullfill = ( 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 String ( str ) . replace ( tokenRegex , function ( all , key ) {
return replacer ( all , key , obj ) ;
} ) ;
} ;
} ) ( ) ;
/ * \
* Raphael . ninja
[ method ]
* *
* If you want to leave no trace of Raphaël ( Well , Raphaël creates only one global variable ` Raphael ` , but anyway . ) You can use ` ninja ` method .
* Beware , that in this case plugins could stop working , because they are depending on global variable existence .
* *
= ( object ) Raphael object
> Usage
| ( function ( local _raphael ) {
| var paper = local _raphael ( 10 , 10 , 320 , 200 ) ;
| …
| } ) ( Raphael . ninja ( ) ) ;
\ * /
R . ninja = function ( ) {
if ( oldRaphael . was ) {
g . win . Raphael = oldRaphael . is ;
} else {
// IE8 raises an error when deleting window property
window . Raphael = undefined ;
try {
delete window . Raphael ;
} catch ( e ) { }
}
return R ;
} ;
/ * \
* Raphael . st
[ property ( object ) ]
* *
* You can add your own method to elements and sets . It is wise to add a set method for each element method
* you added , so you will be able to call the same method on sets too .
* *
* See also @ Raphael . el .
> Usage
| Raphael . el . red = function ( ) {
| this . attr ( { fill : "#f00" } ) ;
| } ;
| Raphael . st . red = function ( ) {
| this . forEach ( function ( el ) {
| el . red ( ) ;
| } ) ;
| } ;
| // then use it
| paper . set ( paper . circle ( 100 , 100 , 20 ) , paper . circle ( 110 , 100 , 20 ) ) . red ( ) ;
\ * /
R . st = setproto ;
eve . on ( "raphael.DOMload" , function ( ) {
loaded = true ;
} ) ;
// Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
( function ( doc , loaded , f ) {
if ( doc . readyState == null && doc . addEventListener ) {
doc . addEventListener ( loaded , f = function ( ) {
doc . removeEventListener ( loaded , f , false ) ;
doc . readyState = "complete" ;
} , false ) ;
doc . readyState = "loading" ;
}
function isLoaded ( ) {
( /in/ ) . test ( doc . readyState ) ? setTimeout ( isLoaded , 9 ) : R . eve ( "raphael.DOMload" ) ;
}
isLoaded ( ) ;
} ) ( document , "DOMContentLoaded" ) ;
return R ;
} ) ;