vendor/assets/javascripts/raphael.js in raphaeljs-rails-2.0.0 vs vendor/assets/javascripts/raphael.js in raphaeljs-rails-2.1.2
- old
+ new
@@ -1,35 +1,60 @@
// ┌────────────────────────────────────────────────────────────────────┐ \\
-// │ Raphaël 2.1.0 - JavaScript Vector Library │ \\
+// │ Raphaël 2.1.2 - JavaScript Vector Library │ \\
// ├────────────────────────────────────────────────────────────────────┤ \\
// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\
// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\
// ├────────────────────────────────────────────────────────────────────┤ \\
// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\
// └────────────────────────────────────────────────────────────────────┘ \\
+// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ┌────────────────────────────────────────────────────────────┐ \\
+// │ Eve 0.4.2 - JavaScript Events Library │ \\
+// ├────────────────────────────────────────────────────────────┤ \\
+// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
+// └────────────────────────────────────────────────────────────┘ \\
-// ┌──────────────────────────────────────────────────────────────────────────────────────┐ \\
-// │ Eve 0.3.4 - JavaScript Events Library │ \\
-// ├──────────────────────────────────────────────────────────────────────────────────────┤ \\
-// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
-// │ Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. │ \\
-// └──────────────────────────────────────────────────────────────────────────────────────┘ \\
-
(function (glob) {
- var version = "0.3.4",
+ var version = "0.4.2",
has = "hasOwnProperty",
separator = /[\.\/]/,
wildcard = "*",
fun = function () {},
numsort = function (a, b) {
return a - b;
},
current_event,
stop,
events = {n: {}},
-
+ /*\
+ * eve
+ [ method ]
+
+ * Fires event with given `name`, given scope and other parameters.
+
+ > Arguments
+
+ - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
+ - scope (object) context for the event handlers
+ - varargs (...) the rest of arguments will be sent to event handlers
+
+ = (object) array of returned values from the listeners
+ \*/
eve = function (name, scope) {
+ name = String(name);
var e = events,
oldstop = stop,
args = Array.prototype.slice.call(arguments, 2),
listeners = eve.listeners(name),
z = 0,
@@ -85,11 +110,24 @@
}
stop = oldstop;
current_event = ce;
return out.length ? out : null;
};
-
+ // Undocumented. Debug only.
+ eve._events = events;
+ /*\
+ * eve.listeners
+ [ method ]
+
+ * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
+
+ > Arguments
+
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated
+
+ = (array) array of event handlers
+ \*/
eve.listeners = function (name) {
var names = name.split(separator),
e = events,
item,
items,
@@ -118,18 +156,44 @@
es = nes;
}
return out;
};
-
+ /*\
+ * eve.on
+ [ method ]
+ **
+ * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
+ | eve.on("*.under.*", f);
+ | eve("mouse.under.floor"); // triggers f
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+ > Example:
+ | eve.on("mouse", eatIt)(2);
+ | eve.on("mouse", scream);
+ | eve.on("mouse", catchIt)(1);
+ * This will ensure that `catchIt()` function will be called before `eatIt()`.
+ *
+ * If you want to put your handler before non-indexed handlers, specify a negative value.
+ * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+ \*/
eve.on = function (name, f) {
+ name = String(name);
+ if (typeof f != "function") {
+ return function () {};
+ }
var names = name.split(separator),
e = events;
for (var i = 0, ii = names.length; i < ii; i++) {
e = e.n;
- !e[names[i]] && (e[names[i]] = {n: {}});
- e = e[names[i]];
+ e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
}
e.f = e.f || [];
for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
return fun;
}
@@ -138,24 +202,96 @@
if (+zIndex == +zIndex) {
f.zIndex = +zIndex;
}
};
};
-
+ /*\
+ * eve.f
+ [ method ]
+ **
+ * Returns function that will fire given event with optional arguments.
+ * Arguments that will be passed to the result function will be also
+ * concated to the list of final arguments.
+ | el.onclick = eve.f("click", 1, 2);
+ | eve.on("click", function (a, b, c) {
+ | console.log(a, b, c); // 1, 2, [event object]
+ | });
+ > Arguments
+ - event (string) event name
+ - varargs (…) and any other arguments
+ = (function) possible event handler function
+ \*/
+ eve.f = function (event) {
+ var attrs = [].slice.call(arguments, 1);
+ return function () {
+ eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
+ };
+ };
+ /*\
+ * eve.stop
+ [ method ]
+ **
+ * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+ \*/
eve.stop = function () {
stop = 1;
};
-
+ /*\
+ * eve.nt
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ > Arguments
+ **
+ - subname (string) #optional subname of the event
+ **
+ = (string) name of the event, if `subname` is not specified
+ * or
+ = (boolean) `true`, if current event’s name contains `subname`
+ \*/
eve.nt = function (subname) {
if (subname) {
return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
}
return current_event;
};
-
-
+ /*\
+ * eve.nts
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ **
+ = (array) names of the event
+ \*/
+ eve.nts = function () {
+ return current_event.split(separator);
+ };
+ /*\
+ * eve.off
+ [ method ]
+ **
+ * Removes given function from the list of event listeners assigned to given name.
+ * If no arguments specified all the events will be cleared.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ \*/
+ /*\
+ * eve.unbind
+ [ method ]
+ **
+ * See @eve.off
+ \*/
eve.off = eve.unbind = function (name, f) {
+ if (!name) {
+ eve._events = events = {n: {}};
+ return;
+ }
var names = name.split(separator),
e,
key,
splice,
i, ii, j, jj,
@@ -203,37 +339,117 @@
}
e = e.n;
}
}
};
-
+ /*\
+ * eve.once
+ [ method ]
+ **
+ * Binds given event handler with a given name to only run once then unbind itself.
+ | eve.once("login", f);
+ | eve("login"); // triggers f
+ | eve("login"); // no listeners
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) same return function as @eve.on
+ \*/
eve.once = function (name, f) {
var f2 = function () {
- var res = f.apply(this, arguments);
eve.unbind(name, f2);
- return res;
+ return f.apply(this, arguments);
};
return eve.on(name, f2);
};
-
+ /*\
+ * eve.version
+ [ property (string) ]
+ **
+ * Current version of the library.
+ \*/
eve.version = version;
eve.toString = function () {
return "You are running Eve " + version;
};
(typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
})(this);
-
-
// ┌─────────────────────────────────────────────────────────────────────┐ \\
-// │ "Raphaël 2.1.0" - JavaScript Vector Library │ \\
+// │ "Raphaël 2.1.2" - JavaScript Vector Library │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\
// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\
// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
// └─────────────────────────────────────────────────────────────────────┘ \\
-(function () {
-
+
+(function (glob, factory) {
+ // AMD support
+ if (typeof define === "function" && define.amd) {
+ // Define as an anonymous module
+ define(["eve"], function( eve ) {
+ return factory(glob, eve);
+ });
+ } else {
+ // Browser globals (glob is window)
+ // Raphael adds itself to window
+ factory(glob, glob.eve);
+ }
+}(this, function (window, 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);
@@ -247,11 +463,11 @@
} else {
return R._engine.create[apply](R, arguments);
}
}
}
- R.version = "2.1.0";
+ R.version = "2.1.2";
R.eve = eve;
var loaded,
separator = /[, ]+/,
elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1},
formatrg = /\{(\d+)\}/g,
@@ -264,19 +480,49 @@
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",
- supportsTouch = "createTouch" in g.doc,
+ supportsTouch = ('ontouchstart' in g.win) || g.win.DocumentTouch && g.doc instanceof DocumentTouch, //taken from Modernizr touch test
E = "",
S = " ",
Str = String,
split = "split",
events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S),
@@ -423,13 +669,26 @@
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;
@@ -445,11 +704,16 @@
}
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"/>';
@@ -458,19 +722,63 @@
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;
R._oid = 0;
-
+ /*\
+ * Raphael.is
+ [ method ]
+ **
+ * Handfull replacement 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);
}
@@ -483,21 +791,34 @@
(type == "array" && Array.isArray && Array.isArray(o)) ||
objectToString.call(o).slice(8, -1).toLowerCase() == type;
};
function clone(obj) {
- if (Object(obj) !== 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) {
@@ -506,19 +827,45 @@
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
+ - deg (number) angle in radians
+ = (number) angle in degrees.
+ \*/
R.deg = function (rad) {
return rad * 180 / PI % 360;
};
-
+ /*\
+ * 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) {
@@ -534,23 +881,35 @@
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) {
@@ -617,11 +976,11 @@
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;
@@ -634,12 +993,31 @@
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;
@@ -669,11 +1047,27 @@
}
}
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;
h = h.h;
@@ -690,11 +1084,27 @@
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;
@@ -715,11 +1125,26 @@
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];
@@ -734,11 +1159,26 @@
);
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];
@@ -796,16 +1236,42 @@
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</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li>
+ # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li>
+ # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li>
+ # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li>
+ # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li>
+ # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li>
+ # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
+ # <li>hsl(•••, •••, •••) — same as hsb</li>
+ # <li>hsl(•••%, •••%, •••%) — same as hsb</li>
+ # </ul>
+ = (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") {
@@ -873,23 +1339,61 @@
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) {
return "#" + (16777216 | b | (g << 8) | (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) {
@@ -897,11 +1401,16 @@
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
@@ -940,20 +1449,30 @@
]);
}
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);
}
@@ -981,11 +1500,21 @@
}
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},
@@ -1022,11 +1551,50 @@
!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,
@@ -1051,11 +1619,40 @@
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);
@@ -1066,15 +1663,38 @@
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)
@@ -1173,12 +1793,12 @@
if (!R.isBBoxIntersect(bbox1, bbox2)) {
return justCount ? 0 : [];
}
var l1 = bezlen.apply(0, bez1),
l2 = bezlen.apply(0, bez2),
- n1 = ~~(l1 / 5),
- n2 = ~~(l2 / 5),
+ n1 = mmax(~~(l1 / 5), 1),
+ n2 = mmax(~~(l2 / 5), 1),
dots1 = [],
dots2 = [],
xy = {},
res = justCount ? 0 : [];
for (var i = 0; i < n1 + 1; i++) {
@@ -1203,28 +1823,51 @@
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 && t2 >= 0 && t2 <= 1) {
+ if (t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001) {
if (justCount) {
res++;
} else {
res.push({
x: is.x,
y: is.y,
- t1: t1,
- t2: t2
+ 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);
@@ -1280,32 +1923,64 @@
}
}
}
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 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,
+ var x = 0,
y = 0,
X = [],
Y = [],
p;
for (var i = 0, ii = path.length; i < ii; i++) {
@@ -1325,17 +2000,21 @@
}
var xmin = mmin[apply](0, X),
ymin = mmin[apply](0, Y),
xmax = mmax[apply](0, X),
ymax = mmax[apply](0, Y),
- bb = {
+ width = xmax - xmin,
+ height = ymax - ymin,
+ bb = {
x: xmin,
y: ymin,
x2: xmax,
y2: ymax,
- width: xmax - xmin,
- height: ymax - ymin
+ width: width,
+ height: height,
+ cx: xmin + width / 2,
+ cy: ymin + height / 2
};
pth.bbox = clone(bb);
return bb;
},
pathClone = function (pathArray) {
@@ -1680,11 +2359,11 @@
}
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) {
+ processPath = function (path, d, pcom) {
var nx, ny;
if (!path) {
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
}
!(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
@@ -1695,17 +2374,29 @@
break;
case "A":
path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
break;
case "S":
- nx = d.x + (d.x - (d.bx || d.x));
- ny = d.y + (d.y - (d.by || d.y));
+ if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
+ nx = d.x * 2 - d.bx; // And reflect the previous
+ ny = d.y * 2 - d.by; // command's control point relative to the current point.
+ }
+ else { // or some else or nothing
+ nx = d.x;
+ ny = d.y;
+ }
path = ["C", nx, ny][concat](path.slice(1));
break;
case "T":
- d.qx = d.x + (d.x - (d.qx || d.x));
- d.qy = d.y + (d.y - (d.qy || d.y));
+ if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
+ d.qx = d.x * 2 - d.qx; // And make a reflection similar
+ d.qy = d.y * 2 - d.qy; // to case "S".
+ }
+ else { // or something else or nothing
+ d.qx = d.x;
+ d.qy = d.y;
+ }
path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
case "Q":
d.qx = path[1];
d.qy = path[2];
@@ -1849,11 +2540,22 @@
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
@@ -1863,11 +2565,22 @@
}
};
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) {
@@ -1943,11 +2656,16 @@
_.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;
@@ -2037,16 +2755,51 @@
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) {
@@ -2064,11 +2817,25 @@
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;
@@ -2091,46 +2858,103 @@
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);
@@ -2154,11 +2978,24 @@
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;
@@ -2190,18 +3027,24 @@
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) +
+ 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)];
}
@@ -2210,19 +3053,26 @@
// WebKit rendering bug workaround method
var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/);
if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") ||
(navigator.vendor == "Google Inc." && version && version[1] < 8)) {
-
+ /*\
+ * Paper.safari
+ [ method ]
+ **
+ * There is an inconvenient rendering bug in Safari (WebKit):
+ * sometimes the rendering should be forced.
+ * This method should help with dealing with this bug.
+ \*/
paperproto.safari = function () {
var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"});
setTimeout(function () {rect.remove();});
};
} else {
paperproto.safari = fun;
}
-
+
var preventDefault = function () {
this.returnValue = false;
},
preventTouch = function () {
return this.originalEvent.preventDefault();
@@ -2231,36 +3081,54 @@
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 realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
- f = function (e) {
- 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;
- if (supportsTouch && touchMap[has](type)) {
+ 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) {
- var olde = e;
e = e.targetTouches[i];
e.originalEvent = olde;
e.preventDefault = preventTouch;
e.stopPropagation = stopTouch;
break;
}
}
- }
- return fn.call(element, e, x, y);
- };
- obj.addEventListener(realName, f, false);
+
+ return fn.call(element, e, pos.x, pos.y);
+ };
+ obj.addEventListener(touchMap[type], _f, false);
+ }
+
return function () {
- obj.removeEventListener(realName, f, false);
+ 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) {
@@ -2291,11 +3159,11 @@
scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
dragi,
j = drag.length;
while (j--) {
dragi = drag[j];
- if (supportsTouch) {
+ if (supportsTouch && e.touches) {
var i = e.touches.length,
touch;
while (i--) {
touch = e.touches[i];
if (touch.identifier == dragi.el._drag.id) {
@@ -2333,44 +3201,233 @@
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 usefull 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 || [];
@@ -2379,24 +3436,52 @@
return this;
};
R["un" + eventName] = elproto["un" + eventName] = function (fn) {
var events = this.events || [],
l = events.length;
- while (l--) if (events[l].name == eventName && events[l].f == fn) {
- events[l].unbind();
- events.splice(l, 1);
- !events.length && delete this.events;
- return this;
+ 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 asociated 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]);
}
@@ -2407,37 +3492,119 @@
}
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) {
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
+ * Additionaly 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 scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ 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.x = e.clientX + scrollX;
- this._drag.y = e.clientY + scrollY;
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);
@@ -2446,90 +3613,294 @@
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</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
+ # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
+ # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
+ # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
+ # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
+ # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
+ # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
+ # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
+ # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
+ # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
+ # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
+ # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
+ * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
+ * Note: there is a special case when path consist of just three commands: “M10,10R…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.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,
@@ -2540,11 +3911,24 @@
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") {
@@ -2566,33 +3950,93 @@
}
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);
@@ -2604,16 +4048,48 @@
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 = this.realPath || getPath[this.type](this);
+ 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._;
@@ -2635,20 +4111,46 @@
_.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 || {};
@@ -2727,41 +4229,167 @@
};
};
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 () {
- if (this.type != "path") {return;}
+ var path = this.getPath();
+ if (!path) {
+ return;
+ }
+
if (this.node.getTotalLength) {
return this.node.getTotalLength();
}
- return getTotalLength(this.attrs.path);
+
+ 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) {
- if (this.type != "path") {return;}
- return getPointAtLength(this.attrs.path, 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) {
- if (this.type != "path") {return;}
- return R.getSubpath(this.attrs.path, 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”</li>
+ # <li>“<” or “easeIn” or “ease-in”</li>
+ # <li>“>” or “easeOut” or “ease-out”</li>
+ # <li>“<>” or “easeInOut” or “ease-in-out”</li>
+ # <li>“backIn” or “back-in”</li>
+ # <li>“backOut” or “back-out”</li>
+ # <li>“elastic”</li>
+ # <li>“bounce”</li>
+ # </ul>
+ # <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) {
@@ -2958,11 +4586,31 @@
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;
@@ -3053,19 +4701,44 @@
}
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.prototype.repeat = function (times) {
+ /*\
+ * 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;
};
@@ -3273,11 +4946,26 @@
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) {
@@ -3299,29 +4987,80 @@
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;
@@ -3346,31 +5085,64 @@
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);
}
@@ -3401,11 +5173,17 @@
}
}
}
},
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];
@@ -3415,16 +5193,35 @@
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;
}
@@ -3451,17 +5248,34 @@
this.items[i].attr(name, value);
}
}
return this;
};
-
+ /*\
+ * Set.clear
+ [ method ]
+ **
+ * Removeds 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 = [],
@@ -3484,11 +5298,21 @@
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;
}
@@ -3509,10 +5333,11 @@
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;
@@ -3545,21 +5370,73 @@
width: x2 - x,
height: y2 - y
};
};
setproto.clone = function (s) {
- s = new Set;
+ 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)) {
+ console.log('runned');
+ 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 || {};
@@ -3595,11 +5472,26 @@
}
}
}
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) {
@@ -3624,20 +5516,41 @@
}
}
}
return thefont;
};
-
- paperproto.print = function (x, y, string, font, size, origin, letter_spacing) {
+ /*\
+ * 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));
+ 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],
@@ -3646,11 +5559,11 @@
for (var i = 0, ii = letters.length; i < ii; i++) {
if (letters[i] == "\n") {
shift = 0;
curr = 0;
notfirst = 0;
- shifty += lineHeight;
+ 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;
@@ -3664,11 +5577,38 @@
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,
@@ -3679,19 +5619,59 @@
}
}
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;
@@ -3711,16 +5691,48 @@
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 existance.
+ **
+ = (object) Raphael object
+ > Usage
+ | (function (local_raphael) {
+ | var paper = local_raphael(10, 10, 320, 200);
+ | …
+ | })(Raphael.ninja());
+ \*/
R.ninja = function () {
oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
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;
// 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 () {
@@ -3733,28 +5745,28 @@
(/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload");
}
isLoaded();
})(document, "DOMContentLoaded");
- oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
-
eve.on("raphael.DOMload", function () {
loaded = true;
});
-})();
-
// ┌─────────────────────────────────────────────────────────────────────┐ \\
// │ Raphaël - JavaScript Vector Library │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ SVG Module │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\
// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\
// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
// └─────────────────────────────────────────────────────────────────────┘ \\
-window.Raphael.svg && function (R) {
+
+(function(){
+ if (!R.svg) {
+ return;
+ }
var has = "hasOwnProperty",
Str = String,
toFloat = parseFloat,
toInt = parseInt,
math = Math,
@@ -3992,11 +6004,11 @@
to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
}
attr = {};
attr["marker-" + se] = "url(#" + markerId + ")";
if (to || from) {
- attr.d = Raphael.getSubpath(attrs.path, from, to);
+ attr.d = R.getSubpath(attrs.path, from, to);
}
$(node, attr);
o._.arrows[se + "Path"] = pathId;
o._.arrows[se + "Marker"] = markerId;
o._.arrows[se + "dx"] = delta;
@@ -4008,11 +6020,11 @@
to = R.getTotalLength(attrs.path) - from;
} else {
from = 0;
to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
}
- o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
+ o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)});
delete o._.arrows[se + "Path"];
delete o._.arrows[se + "Marker"];
delete o._.arrows[se + "dx"];
delete o._.arrows[se + "Type"];
delete o._.arrows[se + "String"];
@@ -4066,10 +6078,15 @@
case "blur":
o.blur(value);
break;
case "href":
case "title":
+ var hl = $("title");
+ var val = R._g.doc.createTextNode(value);
+ hl.appendChild(val);
+ node.appendChild(hl);
+ break;
case "target":
var pn = node.parentNode;
if (pn.tagName.toLowerCase() != "a") {
var hl = $("a");
pn.insertBefore(hl, node);
@@ -4337,20 +6354,61 @@
dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
},
Element = function (node, svg) {
var X = 0,
Y = 0;
-
+ /*\
+ * Element.node
+ [ property (object) ]
+ **
+ * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
+ **
+ * Note: Don’t mess with it.
+ > Usage
+ | // draw a circle at coordinate 10,10 with radius of 10
+ | var c = paper.circle(10, 10, 10);
+ | c.node.onclick = function () {
+ | c.attr("fill", "red");
+ | };
+ \*/
this[0] = this.node = node;
-
+ /*\
+ * Element.raphael
+ [ property (object) ]
+ **
+ * Internal reference to @Raphael object. In case it is not available.
+ > Usage
+ | Raphael.el.red = function () {
+ | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill"));
+ | hsb.h = 1;
+ | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex});
+ | }
+ \*/
node.raphael = true;
-
+ /*\
+ * Element.id
+ [ property (number) ]
+ **
+ * Unique id of the element. Especially usesful when you want to listen to events of the element,
+ * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method.
+ \*/
this.id = R._oid++;
node.raphaelid = this.id;
this.matrix = R.matrix();
this.realPath = null;
-
+ /*\
+ * Element.paper
+ [ property (object) ]
+ **
+ * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions.
+ > Usage
+ | Raphael.el.cross = function () {
+ | this.attr({fill: "red"});
+ | this.paper.path("M10,10L50,50M50,10L10,50")
+ | .attr({stroke: "red"});
+ | }
+ \*/
this.paper = svg;
this.attrs = this.attrs || {};
this._ = {
transform: [],
sx: 1,
@@ -4359,15 +6417,25 @@
dx: 0,
dy: 0,
dirty: 1
};
!svg.bottom && (svg.bottom = this);
-
+ /*\
+ * Element.prev
+ [ property (object) ]
+ **
+ * Reference to the previous element in the hierarchy.
+ \*/
this.prev = svg.top;
svg.top && (svg.top.next = this);
svg.top = this;
-
+ /*\
+ * Element.next
+ [ property (object) ]
+ **
+ * Reference to the next element in the hierarchy.
+ \*/
this.next = null;
},
elproto = R.el;
Element.prototype = elproto;
@@ -4383,11 +6451,24 @@
stroke: "#000",
path: pathString
});
return p;
};
-
+ /*\
+ * Element.rotate
+ [ method ]
+ **
+ * Deprecated! Use @Element.transform instead.
+ * Adds rotation by given angle around given point to the list of
+ * transformations of the element.
+ > Parameters
+ - deg (number) angle in degrees
+ - cx (number) #optional x coordinate of the centre of rotation
+ - cy (number) #optional y coordinate of the centre of rotation
+ * If cx & cy aren’t specified centre of the shape is used as a point of rotation.
+ = (object) @Element
+ \*/
elproto.rotate = function (deg, cx, cy) {
if (this.removed) {
return this;
}
deg = Str(deg).split(separator);
@@ -4403,11 +6484,25 @@
cy = bbox.y + bbox.height / 2;
}
this.transform(this._.transform.concat([["r", deg, cx, cy]]));
return this;
};
-
+ /*\
+ * Element.scale
+ [ method ]
+ **
+ * Deprecated! Use @Element.transform instead.
+ * Adds scale by given amount relative to given point to the list of
+ * transformations of the element.
+ > Parameters
+ - sx (number) horisontal scale amount
+ - sy (number) vertical scale amount
+ - cx (number) #optional x coordinate of the centre of scale
+ - cy (number) #optional y coordinate of the centre of scale
+ * If cx & cy aren’t specified centre of the shape is used instead.
+ = (object) @Element
+ \*/
elproto.scale = function (sx, sy, cx, cy) {
if (this.removed) {
return this;
}
sx = Str(sx).split(separator);
@@ -4425,11 +6520,21 @@
cx = cx == null ? bbox.x + bbox.width / 2 : cx;
cy = cy == null ? bbox.y + bbox.height / 2 : cy;
this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
return this;
};
-
+ /*\
+ * Element.translate
+ [ method ]
+ **
+ * Deprecated! Use @Element.transform instead.
+ * Adds translation by given amount to the list of transformations of the element.
+ > Parameters
+ - dx (number) horisontal shift
+ - dy (number) vertical shift
+ = (object) @Element
+ \*/
elproto.translate = function (dx, dy) {
if (this.removed) {
return this;
}
dx = Str(dx).split(separator);
@@ -4439,11 +6544,47 @@
dx = toFloat(dx[0]) || 0;
dy = +dy || 0;
this.transform(this._.transform.concat([["t", dx, dy]]));
return this;
};
-
+ /*\
+ * Element.transform
+ [ method ]
+ **
+ * Adds transformation to the element which is separate to other attributes,
+ * i.e. translation doesn’t change `x` or `y` of the rectange. The format
+ * of transformation string is similar to the path string syntax:
+ | "t100,100r30,100,100s2,2,100,100r45s1.5"
+ * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for
+ * scale and `m` is for matrix.
+ *
+ * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`.
+ *
+ * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100;
+ * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin
+ * coordinates as optional parameters, the default is the centre point of the element.
+ * Matrix accepts six parameters.
+ > Usage
+ | var el = paper.rect(10, 20, 300, 200);
+ | // translate 100, 100, rotate 45°, translate -100, 0
+ | el.transform("t100,100r45t-100,0");
+ | // if you want you can append or prepend transformations
+ | el.transform("...t50,50");
+ | el.transform("s2...");
+ | // or even wrap
+ | el.transform("t50,50...t-50-50");
+ | // to reset transformation call method with empty string
+ | el.transform("");
+ | // to get current value call it without parameters
+ | console.log(el.transform());
+ > Parameters
+ - tstr (string) #optional transformation string
+ * If tstr isn’t specified
+ = (string) current transformation string
+ * else
+ = (object) @Element
+ \*/
elproto.transform = function (tstr) {
var _ = this._;
if (tstr == null) {
return _.transform;
}
@@ -4458,21 +6599,38 @@
this.attr({"stroke-width": sw});
}
return this;
};
-
+ /*\
+ * Element.hide
+ [ method ]
+ **
+ * Makes element invisible. See @Element.show.
+ = (object) @Element
+ \*/
elproto.hide = function () {
!this.removed && this.paper.safari(this.node.style.display = "none");
return this;
};
-
+ /*\
+ * Element.show
+ [ method ]
+ **
+ * Makes element visible. See @Element.hide.
+ = (object) @Element
+ \*/
elproto.show = function () {
!this.removed && this.paper.safari(this.node.style.display = "");
return this;
};
-
+ /*\
+ * Element.remove
+ [ method ]
+ **
+ * Removes element from the paper.
+ \*/
elproto.remove = function () {
if (this.removed || !this.node.parentNode) {
return;
}
var paper = this.paper;
@@ -4506,11 +6664,91 @@
bbox = bbox || {};
}
hide && this.hide();
return bbox;
};
-
+ /*\
+ * Element.attr
+ [ method ]
+ **
+ * Sets the attributes of the element.
+ > Parameters
+ - attrName (string) attribute’s name
+ - value (string) value
+ * or
+ - params (object) object of name/value pairs
+ * or
+ - attrName (string) attribute’s name
+ * or
+ - attrNames (array) in this case method returns array of current values for given attribute names
+ = (object) @Element if attrsName & value or params are passed in.
+ = (...) value of the attribute if only attrsName is passed in.
+ = (array) array of values of the attribute if attrsNames is passed in.
+ = (object) object of attributes if nothing is passed in.
+ > Possible parameters
+ # <p>Please refer to the <a href="http://www.w3.org/TR/SVG/" title="The W3C Recommendation for the SVG language describes these properties in detail.">SVG specification</a> for an explanation of these parameters.</p>
+ o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `medium`, length: `long`, `short`, `midium`.
+ o clip-rect (string) comma or space separated values: x, y, width and height
+ o cursor (string) CSS type of the cursor
+ o cx (number) the x-axis coordinate of the center of the circle, or ellipse
+ o cy (number) the y-axis coordinate of the center of the circle, or ellipse
+ o fill (string) colour, gradient or image
+ o fill-opacity (number)
+ o font (string)
+ o font-family (string)
+ o font-size (number) font size in pixels
+ o font-weight (string)
+ o height (number)
+ o href (string) URL, if specified element behaves as hyperlink
+ o opacity (number)
+ o path (string) SVG path string format
+ o r (number) radius of the circle, ellipse or rounded corner on the rect
+ o rx (number) horisontal radius of the ellipse
+ o ry (number) vertical radius of the ellipse
+ o src (string) image URL, only works for @Element.image element
+ o stroke (string) stroke colour
+ o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”]
+ o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”]
+ o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”]
+ o stroke-miterlimit (number)
+ o stroke-opacity (number)
+ o stroke-width (number) stroke width in pixels, default is '1'
+ o target (string) used with href
+ o text (string) contents of the text element. Use `\n` for multiline text
+ o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`”
+ o title (string) will create tooltip with a given text
+ o transform (string) see @Element.transform
+ o width (number)
+ o x (number)
+ o y (number)
+ > Gradients
+ * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90°
+ * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black.
+ *
+ * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” –
+ * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point
+ * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses.
+ > Path String
+ # <p>Please refer to <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 documentation regarding path string</a>. Raphaël fully supports it.</p>
+ > Colour Parsing
+ # <ul>
+ # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li>
+ # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li>
+ # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li>
+ # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li>
+ # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li>
+ # <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200, 100, 0, .5)</code>”)</li>
+ # <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%, 175%, 0%, 50%)</code>”)</li>
+ # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li>
+ # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
+ # <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li>
+ # <li>hsl(•••, •••, •••) — almost the same as hsb, see <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" title="HSL and HSV - Wikipedia, the free encyclopedia">Wikipedia page</a></li>
+ # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
+ # <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li>
+ # <li>Optionally for hsb and hsl you could specify hue as a degree: “<code>hsl(240deg, 1, .5)</code>” or, if you want to go fancy, “<code>hsl(240°, 1, .5)</code>”</li>
+ # </ul>
+ \*/
elproto.attr = function (name, value) {
if (this.removed) {
return this;
}
if (name == null) {
@@ -4567,11 +6805,17 @@
}
}
setFillAndStroke(this, params);
return this;
};
-
+ /*\
+ * Element.toFront
+ [ method ]
+ **
+ * Moves the element so it is the closest to the viewer’s eyes, on top of other elements.
+ = (object) @Element
+ \*/
elproto.toFront = function () {
if (this.removed) {
return this;
}
if (this.node.parentNode.tagName.toLowerCase() == "a") {
@@ -4581,11 +6825,17 @@
}
var svg = this.paper;
svg.top != this && R._tofront(this, svg);
return this;
};
-
+ /*\
+ * Element.toBack
+ [ method ]
+ **
+ * Moves the element so it is the furthest from the viewer’s eyes, behind other elements.
+ = (object) @Element
+ \*/
elproto.toBack = function () {
if (this.removed) {
return this;
}
var parent = this.node.parentNode;
@@ -4596,11 +6846,17 @@
}
R._toback(this, this.paper);
var svg = this.paper;
return this;
};
-
+ /*\
+ * Element.insertAfter
+ [ method ]
+ **
+ * Inserts current object after the given one.
+ = (object) @Element
+ \*/
elproto.insertAfter = function (element) {
if (this.removed) {
return this;
}
var node = element.node || element[element.length - 1].node;
@@ -4610,11 +6866,17 @@
node.parentNode.appendChild(this.node);
}
R._insertafter(this, element, this.paper);
return this;
};
-
+ /*\
+ * Element.insertBefore
+ [ method ]
+ **
+ * Inserts current object before the given one.
+ = (object) @Element
+ \*/
elproto.insertBefore = function (element) {
if (this.removed) {
return this;
}
var node = element.node || element[0].node;
@@ -4641,10 +6903,11 @@
delete t._blur;
delete t.attrs.blur;
}
t.node.removeAttribute("filter");
}
+ return t;
};
R._engine.circle = function (svg, x, y, r) {
var el = $("circle");
svg.canvas && svg.canvas.appendChild(el);
var res = new Element(el, svg);
@@ -4782,11 +7045,20 @@
top = top.prev;
}
this._viewBox = [x, y, w, h, !!fit];
return this;
};
-
+ /*\
+ * Paper.renderfix
+ [ method ]
+ **
+ * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant
+ * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness.
+ * This method fixes the issue.
+ **
+ Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method.
+ \*/
R.prototype.renderfix = function () {
var cnvs = this.canvas,
s = cnvs.style,
pos;
try {
@@ -4805,11 +7077,16 @@
this._top = (this._top + top) % 1;
s.top = this._top + "px";
}
}
};
-
+ /*\
+ * Paper.clear
+ [ method ]
+ **
+ * Clears the paper, i.e. removes all the elements.
+ \*/
R.prototype.clear = function () {
R.eve("raphael.clear", this);
var c = this.canvas;
while (c.firstChild) {
c.removeChild(c.firstChild);
@@ -4817,11 +7094,16 @@
this.bottom = this.top = null;
(this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
c.appendChild(this.desc);
c.appendChild(this.defs = $("defs"));
};
-
+ /*\
+ * Paper.remove
+ [ method ]
+ **
+ * Removes the paper from the DOM.
+ \*/
R.prototype.remove = function () {
eve("raphael.remove", this);
this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
for (var i in this) {
this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
@@ -4836,22 +7118,26 @@
el[methodname].apply(el, arg);
});
};
})(method);
}
-}(window.Raphael);
+})();
// ┌─────────────────────────────────────────────────────────────────────┐ \\
// │ Raphaël - JavaScript Vector Library │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ VML Module │ \\
// ├─────────────────────────────────────────────────────────────────────┤ \\
// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\
// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\
// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
// └─────────────────────────────────────────────────────────────────────┘ \\
-window.Raphael.vml && function (R) {
+
+(function(){
+ if (!R.vml) {
+ return;
+ }
var has = "hasOwnProperty",
Str = String,
toFloat = parseFloat,
math = Math,
round = math.round,
@@ -5023,10 +7309,11 @@
var cx = +a.cx,
cy = +a.cy,
rx = +a.rx || +a.r || 0,
ry = +a.ry || +a.r || 0;
node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom));
+ o._.dirty = 1;
}
if ("clip-rect" in params) {
var rect = Str(params["clip-rect"]).split(separator);
if (rect.length == 4) {
rect[2] = +rect[2] + (+rect[0]);
@@ -5312,11 +7599,11 @@
skew = this.skew,
o = this.node,
split,
isGrad = ~Str(this.attrs.fill).indexOf("-"),
isPatt = !Str(this.attrs.fill).indexOf("url(");
- matrix.translate(-.5, -.5);
+ matrix.translate(1, 1);
if (isPatt || isGrad || this.type == "image") {
skew.matrix = "1 0 0 1";
skew.offset = "0 0";
split = matrix.split();
if ((isGrad && split.noRotation) || !split.isSimple) {
@@ -5553,10 +7840,11 @@
} else {
s.filter = f;
s.margin = 0;
delete this.attrs.blur;
}
+ return this;
};
R._engine.path = function (pathString, vml) {
var el = createNode("shape");
el.style.cssText = cssDot;
@@ -5810,6 +8098,14 @@
el[methodname].apply(el, arg);
});
};
})(method);
}
-}(window.Raphael);
+})();
+
+ // EXPOSE
+ // SVG and VML are appended just before the EXPOSE line
+ // Even with AMD, Raphael should be defined globally
+ oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
+
+ return R;
+}));
\ No newline at end of file