graphael-rails 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Rakefile +1 -0
  2. data/VERSION +1 -1
  3. data/graphael-rails.gemspec +53 -12
  4. data/vendor/assets/javascripts/g.raphael/README.markdown +21 -0
  5. data/vendor/assets/javascripts/g.raphael/docs/blueprint-min.png +0 -0
  6. data/vendor/assets/javascripts/g.raphael/docs/dr-print.css +218 -0
  7. data/vendor/assets/javascripts/g.raphael/docs/dr.css +404 -0
  8. data/vendor/assets/javascripts/g.raphael/docs/reference.html +350 -0
  9. data/vendor/assets/javascripts/g.raphael/docs/reference.js +35 -0
  10. data/vendor/assets/javascripts/g.raphael/g.bar.js +621 -0
  11. data/vendor/assets/javascripts/g.raphael/g.dot.js +156 -0
  12. data/vendor/assets/javascripts/g.raphael/g.line.js +329 -0
  13. data/vendor/assets/javascripts/g.raphael/g.pie.js +255 -0
  14. data/vendor/assets/javascripts/g.raphael/g.raphael.js +887 -0
  15. data/vendor/assets/javascripts/g.raphael/g.raphael.json +9 -0
  16. data/vendor/assets/javascripts/g.raphael/min/g.bar-min.js +7 -0
  17. data/vendor/assets/javascripts/g.raphael/min/g.dot-min.js +7 -0
  18. data/vendor/assets/javascripts/g.raphael/min/g.line-min.js +7 -0
  19. data/vendor/assets/javascripts/g.raphael/min/g.pie-min.js +1 -0
  20. data/vendor/assets/javascripts/g.raphael/min/g.raphael-min.js +7 -0
  21. data/vendor/assets/javascripts/g.raphael/raphael-min.js +9 -0
  22. data/vendor/assets/javascripts/g.raphael/test/barchart.html +37 -0
  23. data/vendor/assets/javascripts/g.raphael/test/barchart2.html +51 -0
  24. data/vendor/assets/javascripts/g.raphael/test/brightness.html +47 -0
  25. data/vendor/assets/javascripts/g.raphael/test/css/demo-print.css +17 -0
  26. data/vendor/assets/javascripts/g.raphael/test/css/demo.css +21 -0
  27. data/vendor/assets/javascripts/g.raphael/test/dotchart.html +35 -0
  28. data/vendor/assets/javascripts/g.raphael/test/images/bg.png +0 -0
  29. data/vendor/assets/javascripts/g.raphael/test/images/bgbg.png +0 -0
  30. data/vendor/assets/javascripts/g.raphael/test/linechart.html +66 -0
  31. data/vendor/assets/javascripts/g.raphael/test/piechart.html +26 -0
  32. data/vendor/assets/javascripts/g.raphael/test/piechart2.html +46 -0
  33. data/vendor/assets/javascripts/g.raphael/test/tooltips.html +85 -0
  34. data/vendor/assets/javascripts/raphael/README.markdown +3 -0
  35. data/vendor/assets/javascripts/raphael/history.md +82 -0
  36. data/vendor/assets/javascripts/raphael/license.txt +21 -0
  37. data/vendor/assets/javascripts/raphael/make +45 -0
  38. data/vendor/assets/javascripts/raphael/raphael-min.js +10 -0
  39. data/vendor/assets/javascripts/raphael/raphael.core.js +5189 -0
  40. data/vendor/assets/javascripts/raphael/raphael.js +5815 -0
  41. data/vendor/assets/javascripts/raphael/raphael.svg.js +1360 -0
  42. data/vendor/assets/javascripts/raphael/raphael.vml.js +973 -0
  43. data/vendor/assets/javascripts/raphael/reference.html +2489 -0
  44. data/vendor/assets/javascripts/raphael/reference.js +248 -0
  45. metadata +47 -6
@@ -0,0 +1,255 @@
1
+ /*
2
+ * g.Raphael 0.5 - Charting library, based on Raphaël
3
+ *
4
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6
+ */
7
+ (function () {
8
+
9
+ function Piechart(paper, cx, cy, r, values, opts) {
10
+ opts = opts || {};
11
+
12
+ var chartinst = this,
13
+ sectors = [],
14
+ covers = paper.set(),
15
+ chart = paper.set(),
16
+ series = paper.set(),
17
+ order = [],
18
+ len = values.length,
19
+ angle = 0,
20
+ total = 0,
21
+ others = 0,
22
+ cut = 9,
23
+ defcut = true;
24
+
25
+ function sector(cx, cy, r, startAngle, endAngle, fill) {
26
+ var rad = Math.PI / 180,
27
+ x1 = cx + r * Math.cos(-startAngle * rad),
28
+ x2 = cx + r * Math.cos(-endAngle * rad),
29
+ xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad),
30
+ y1 = cy + r * Math.sin(-startAngle * rad),
31
+ y2 = cy + r * Math.sin(-endAngle * rad),
32
+ ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad),
33
+ res = [
34
+ "M", cx, cy,
35
+ "L", x1, y1,
36
+ "A", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2,
37
+ "z"
38
+ ];
39
+
40
+ res.middle = { x: xm, y: ym };
41
+ return res;
42
+ }
43
+
44
+ chart.covers = covers;
45
+
46
+ if (len == 1) {
47
+ series.push(paper.circle(cx, cy, r).attr({ fill: chartinst.colors[0], stroke: opts.stroke || "#fff", "stroke-width": opts.strokewidth == null ? 1 : opts.strokewidth }));
48
+ covers.push(paper.circle(cx, cy, r).attr(chartinst.shim));
49
+ total = values[0];
50
+ values[0] = { value: values[0], order: 0, valueOf: function () { return this.value; } };
51
+ series[0].middle = {x: cx, y: cy};
52
+ series[0].mangle = 180;
53
+ } else {
54
+ for (var i = 0; i < len; i++) {
55
+ total += values[i];
56
+ values[i] = { value: values[i], order: i, valueOf: function () { return this.value; } };
57
+ }
58
+
59
+ values.sort(function (a, b) {
60
+ return b.value - a.value;
61
+ });
62
+
63
+ for (i = 0; i < len; i++) {
64
+ if (defcut && values[i] * 360 / total <= 1.5) {
65
+ cut = i;
66
+ defcut = false;
67
+ }
68
+
69
+ if (i > cut) {
70
+ defcut = false;
71
+ values[cut].value += values[i];
72
+ values[cut].others = true;
73
+ others = values[cut].value;
74
+ }
75
+ }
76
+
77
+ len = Math.min(cut + 1, values.length);
78
+ others && values.splice(len) && (values[cut].others = true);
79
+
80
+ for (i = 0; i < len; i++) {
81
+ var mangle = angle - 360 * values[i] / total / 2;
82
+
83
+ if (!i) {
84
+ angle = 90 - mangle;
85
+ mangle = angle - 360 * values[i] / total / 2;
86
+ }
87
+
88
+ if (opts.init) {
89
+ var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(",");
90
+ }
91
+
92
+ var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
93
+ var p = paper.path(opts.init ? ipath : path).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#666", stroke: opts.stroke || "#fff", "stroke-width": (opts.strokewidth == null ? 1 : opts.strokewidth), "stroke-linejoin": "round" });
94
+
95
+ p.value = values[i];
96
+ p.middle = path.middle;
97
+ p.mangle = mangle;
98
+ sectors.push(p);
99
+ series.push(p);
100
+ opts.init && p.animate({ path: path.join(",") }, (+opts.init - 1) || 1000, ">");
101
+ }
102
+
103
+ for (i = 0; i < len; i++) {
104
+ p = paper.path(sectors[i].attr("path")).attr(chartinst.shim);
105
+ opts.href && opts.href[i] && p.attr({ href: opts.href[i] });
106
+ p.attr = function () {};
107
+ covers.push(p);
108
+ series.push(p);
109
+ }
110
+ }
111
+
112
+ chart.hover = function (fin, fout) {
113
+ fout = fout || function () {};
114
+
115
+ var that = this;
116
+
117
+ for (var i = 0; i < len; i++) {
118
+ (function (sector, cover, j) {
119
+ var o = {
120
+ sector: sector,
121
+ cover: cover,
122
+ cx: cx,
123
+ cy: cy,
124
+ mx: sector.middle.x,
125
+ my: sector.middle.y,
126
+ mangle: sector.mangle,
127
+ r: r,
128
+ value: values[j],
129
+ total: total,
130
+ label: that.labels && that.labels[j]
131
+ };
132
+ cover.mouseover(function () {
133
+ fin.call(o);
134
+ }).mouseout(function () {
135
+ fout.call(o);
136
+ });
137
+ })(series[i], covers[i], i);
138
+ }
139
+ return this;
140
+ };
141
+
142
+ // x: where label could be put
143
+ // y: where label could be put
144
+ // value: value to show
145
+ // total: total number to count %
146
+ chart.each = function (f) {
147
+ var that = this;
148
+
149
+ for (var i = 0; i < len; i++) {
150
+ (function (sector, cover, j) {
151
+ var o = {
152
+ sector: sector,
153
+ cover: cover,
154
+ cx: cx,
155
+ cy: cy,
156
+ x: sector.middle.x,
157
+ y: sector.middle.y,
158
+ mangle: sector.mangle,
159
+ r: r,
160
+ value: values[j],
161
+ total: total,
162
+ label: that.labels && that.labels[j]
163
+ };
164
+ f.call(o);
165
+ })(series[i], covers[i], i);
166
+ }
167
+ return this;
168
+ };
169
+
170
+ chart.click = function (f) {
171
+ var that = this;
172
+
173
+ for (var i = 0; i < len; i++) {
174
+ (function (sector, cover, j) {
175
+ var o = {
176
+ sector: sector,
177
+ cover: cover,
178
+ cx: cx,
179
+ cy: cy,
180
+ mx: sector.middle.x,
181
+ my: sector.middle.y,
182
+ mangle: sector.mangle,
183
+ r: r,
184
+ value: values[j],
185
+ total: total,
186
+ label: that.labels && that.labels[j]
187
+ };
188
+ cover.click(function () { f.call(o); });
189
+ })(series[i], covers[i], i);
190
+ }
191
+ return this;
192
+ };
193
+
194
+ chart.inject = function (element) {
195
+ element.insertBefore(covers[0]);
196
+ };
197
+
198
+ var legend = function (labels, otherslabel, mark, dir) {
199
+ var x = cx + r + r / 5,
200
+ y = cy,
201
+ h = y + 10;
202
+
203
+ labels = labels || [];
204
+ dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east";
205
+ mark = paper[mark && mark.toLowerCase()] || "circle";
206
+ chart.labels = paper.set();
207
+
208
+ for (var i = 0; i < len; i++) {
209
+ var clr = series[i].attr("fill"),
210
+ j = values[i].order,
211
+ txt;
212
+
213
+ values[i].others && (labels[j] = otherslabel || "Others");
214
+ labels[j] = chartinst.labelise(labels[j], values[i], total);
215
+ chart.labels.push(paper.set());
216
+ chart.labels[i].push(paper[mark](x + 5, h, 5).attr({ fill: clr, stroke: "none" }));
217
+ chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
218
+ covers[i].label = chart.labels[i];
219
+ h += txt.getBBox().height * 1.2;
220
+ }
221
+
222
+ var bb = chart.labels.getBBox(),
223
+ tr = {
224
+ east: [0, -bb.height / 2],
225
+ west: [-bb.width - 2 * r - 20, -bb.height / 2],
226
+ north: [-r - bb.width / 2, -r - bb.height - 10],
227
+ south: [-r - bb.width / 2, r + 10]
228
+ }[dir];
229
+
230
+ chart.labels.translate.apply(chart.labels, tr);
231
+ chart.push(chart.labels);
232
+ };
233
+
234
+ if (opts.legend) {
235
+ legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
236
+ }
237
+
238
+ chart.push(series, covers);
239
+ chart.series = series;
240
+ chart.covers = covers;
241
+
242
+ return chart;
243
+ };
244
+
245
+ //inheritance
246
+ var F = function() {};
247
+ F.prototype = Raphael.g;
248
+ Piechart.prototype = new F;
249
+
250
+ //public
251
+ Raphael.fn.piechart = function(cx, cy, r, values, opts) {
252
+ return new Piechart(this, cx, cy, r, values, opts);
253
+ }
254
+
255
+ })();
@@ -0,0 +1,887 @@
1
+ /*!
2
+ * g.Raphael 0.5 - Charting library, based on Raphaël
3
+ *
4
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6
+ */
7
+
8
+ /*
9
+ * Tooltips on Element prototype
10
+ */
11
+ /*\
12
+ * Element.popup
13
+ [ method ]
14
+ **
15
+ * Puts the context Element in a 'popup' tooltip. Can also be used on sets.
16
+ **
17
+ > Parameters
18
+ **
19
+ - dir (string) location of Element relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`.
20
+ - size (number) amount of bevel/padding around the Element, as well as half the width and height of the tail [default: `5`]
21
+ - x (number) x coordinate of the popup's tail [default: Element's `x` or `cx`]
22
+ - y (number) y coordinate of the popup's tail [default: Element's `y` or `cy`]
23
+ **
24
+ = (object) path element of the popup
25
+ > Usage
26
+ | paper.circle(50, 50, 5).attr({
27
+ | stroke: "#fff",
28
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
29
+ | }).popup();
30
+ \*/
31
+ Raphael.el.popup = function (dir, size, x, y) {
32
+ var paper = this.paper || this[0].paper,
33
+ bb, xy, center, cw, ch;
34
+
35
+ if (!paper) return;
36
+
37
+ switch (this.type) {
38
+ case 'text':
39
+ case 'circle':
40
+ case 'ellipse': center = true; break;
41
+ default: center = false;
42
+ }
43
+
44
+ dir = dir == null ? 'up' : dir;
45
+ size = size || 5;
46
+ bb = this.getBBox();
47
+
48
+ x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
49
+ y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
50
+ cw = Math.max(bb.width / 2 - size, 0);
51
+ ch = Math.max(bb.height / 2 - size, 0);
52
+
53
+ this.translate(x - bb.x - (center ? bb.width / 2 : 0), y - bb.y - (center ? bb.height / 2 : 0));
54
+ bb = this.getBBox();
55
+
56
+ var paths = {
57
+ up: [
58
+ 'M', x, y,
59
+ 'l', -size, -size, -cw, 0,
60
+ 'a', size, size, 0, 0, 1, -size, -size,
61
+ 'l', 0, -bb.height,
62
+ 'a', size, size, 0, 0, 1, size, -size,
63
+ 'l', size * 2 + cw * 2, 0,
64
+ 'a', size, size, 0, 0, 1, size, size,
65
+ 'l', 0, bb.height,
66
+ 'a', size, size, 0, 0, 1, -size, size,
67
+ 'l', -cw, 0,
68
+ 'z'
69
+ ].join(','),
70
+ down: [
71
+ 'M', x, y,
72
+ 'l', size, size, cw, 0,
73
+ 'a', size, size, 0, 0, 1, size, size,
74
+ 'l', 0, bb.height,
75
+ 'a', size, size, 0, 0, 1, -size, size,
76
+ 'l', -(size * 2 + cw * 2), 0,
77
+ 'a', size, size, 0, 0, 1, -size, -size,
78
+ 'l', 0, -bb.height,
79
+ 'a', size, size, 0, 0, 1, size, -size,
80
+ 'l', cw, 0,
81
+ 'z'
82
+ ].join(','),
83
+ left: [
84
+ 'M', x, y,
85
+ 'l', -size, size, 0, ch,
86
+ 'a', size, size, 0, 0, 1, -size, size,
87
+ 'l', -bb.width, 0,
88
+ 'a', size, size, 0, 0, 1, -size, -size,
89
+ 'l', 0, -(size * 2 + ch * 2),
90
+ 'a', size, size, 0, 0, 1, size, -size,
91
+ 'l', bb.width, 0,
92
+ 'a', size, size, 0, 0, 1, size, size,
93
+ 'l', 0, ch,
94
+ 'z'
95
+ ].join(','),
96
+ right: [
97
+ 'M', x, y,
98
+ 'l', size, -size, 0, -ch,
99
+ 'a', size, size, 0, 0, 1, size, -size,
100
+ 'l', bb.width, 0,
101
+ 'a', size, size, 0, 0, 1, size, size,
102
+ 'l', 0, size * 2 + ch * 2,
103
+ 'a', size, size, 0, 0, 1, -size, size,
104
+ 'l', -bb.width, 0,
105
+ 'a', size, size, 0, 0, 1, -size, -size,
106
+ 'l', 0, -ch,
107
+ 'z'
108
+ ].join(',')
109
+ };
110
+
111
+ xy = {
112
+ up: { x: -!center * (bb.width / 2), y: -size * 2 - (center ? bb.height / 2 : bb.height) },
113
+ down: { x: -!center * (bb.width / 2), y: size * 2 + (center ? bb.height / 2 : bb.height) },
114
+ left: { x: -size * 2 - (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) },
115
+ right: { x: size * 2 + (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) }
116
+ }[dir];
117
+
118
+ this.translate(xy.x, xy.y);
119
+ return paper.path(paths[dir]).attr({ fill: "#000", stroke: "none" }).insertBefore(this.node ? this : this[0]);
120
+ };
121
+
122
+ /*\
123
+ * Element.tag
124
+ [ method ]
125
+ **
126
+ * Puts the context Element in a 'tag' tooltip. Can also be used on sets.
127
+ **
128
+ > Parameters
129
+ **
130
+ - angle (number) angle of orientation in degrees [default: `0`]
131
+ - r (number) radius of the loop [default: `5`]
132
+ - x (number) x coordinate of the center of the tag loop [default: Element's `x` or `cx`]
133
+ - y (number) y coordinate of the center of the tag loop [default: Element's `x` or `cx`]
134
+ **
135
+ = (object) path element of the tag
136
+ > Usage
137
+ | paper.circle(50, 50, 15).attr({
138
+ | stroke: "#fff",
139
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
140
+ | }).tag(60);
141
+ \*/
142
+ Raphael.el.tag = function (angle, r, x, y) {
143
+ var d = 3,
144
+ paper = this.paper || this[0].paper;
145
+
146
+ if (!paper) return;
147
+
148
+ var p = paper.path().attr({ fill: '#000', stroke: '#000' }),
149
+ bb = this.getBBox(),
150
+ dx, R, center, tmp;
151
+
152
+ switch (this.type) {
153
+ case 'text':
154
+ case 'circle':
155
+ case 'ellipse': center = true; break;
156
+ default: center = false;
157
+ }
158
+
159
+ angle = angle || 0;
160
+ x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
161
+ y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
162
+ r = r == null ? 5 : r;
163
+ R = .5522 * r;
164
+
165
+ if (bb.height >= r * 2) {
166
+ p.attr({
167
+ path: [
168
+ "M", x, y + r,
169
+ "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2,
170
+ "m", 0, -r * 2 -d,
171
+ "a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2,
172
+ "L", x + r + d, y + bb.height / 2 + d,
173
+ "l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0,
174
+ "L", x, y - r - d
175
+ ].join(",")
176
+ });
177
+ } else {
178
+ dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2));
179
+ p.attr({
180
+ path: [
181
+ "M", x, y + r,
182
+ "c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r,
183
+ "M", x + dx, y - bb.height / 2 - d,
184
+ "a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d,
185
+ "l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d,
186
+ "L", x + dx, y - bb.height / 2 - d
187
+ ].join(",")
188
+ });
189
+ }
190
+
191
+ angle = 360 - angle;
192
+ p.rotate(angle, x, y);
193
+
194
+ if (this.attrs) {
195
+ //elements
196
+ this.attr(this.attrs.x ? 'x' : 'cx', x + r + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2);
197
+ this.rotate(angle, x, y);
198
+ angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - r - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y);
199
+ } else {
200
+ //sets
201
+ if (angle > 90 && angle < 270) {
202
+ this.translate(x - bb.x - bb.width - r - d, y - bb.y - bb.height / 2);
203
+ this.rotate(angle - 180, bb.x + bb.width + r + d, bb.y + bb.height / 2);
204
+ } else {
205
+ this.translate(x - bb.x + r + d, y - bb.y - bb.height / 2);
206
+ this.rotate(angle, bb.x - r - d, bb.y + bb.height / 2);
207
+ }
208
+ }
209
+
210
+ return p.insertBefore(this.node ? this : this[0]);
211
+ };
212
+
213
+ /*\
214
+ * Element.drop
215
+ [ method ]
216
+ **
217
+ * Puts the context Element in a 'drop' tooltip. Can also be used on sets.
218
+ **
219
+ > Parameters
220
+ **
221
+ - angle (number) angle of orientation in degrees [default: `0`]
222
+ - x (number) x coordinate of the drop's point [default: Element's `x` or `cx`]
223
+ - y (number) y coordinate of the drop's point [default: Element's `x` or `cx`]
224
+ **
225
+ = (object) path element of the drop
226
+ > Usage
227
+ | paper.circle(50, 50, 8).attr({
228
+ | stroke: "#fff",
229
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
230
+ | }).drop(60);
231
+ \*/
232
+ Raphael.el.drop = function (angle, x, y) {
233
+ var bb = this.getBBox(),
234
+ paper = this.paper || this[0].paper,
235
+ center, size, p, dx, dy;
236
+
237
+ if (!paper) return;
238
+
239
+ switch (this.type) {
240
+ case 'text':
241
+ case 'circle':
242
+ case 'ellipse': center = true; break;
243
+ default: center = false;
244
+ }
245
+
246
+ angle = angle || 0;
247
+
248
+ x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
249
+ y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
250
+ size = Math.max(bb.width, bb.height) + Math.min(bb.width, bb.height);
251
+ p = paper.path([
252
+ "M", x, y,
253
+ "l", size, 0,
254
+ "A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7,
255
+ "z"
256
+ ]).attr({fill: "#000", stroke: "none"}).rotate(22.5 - angle, x, y);
257
+
258
+ angle = (angle + 90) * Math.PI / 180;
259
+ dx = (x + size * Math.sin(angle)) - (center ? 0 : bb.width / 2);
260
+ dy = (y + size * Math.cos(angle)) - (center ? 0 : bb.height / 2);
261
+
262
+ this.attrs ?
263
+ this.attr(this.attrs.x ? 'x' : 'cx', dx).attr(this.attrs.y ? 'y' : 'cy', dy) :
264
+ this.translate(dx - bb.x, dy - bb.y);
265
+
266
+ return p.insertBefore(this.node ? this : this[0]);
267
+ };
268
+
269
+ /*\
270
+ * Element.flag
271
+ [ method ]
272
+ **
273
+ * Puts the context Element in a 'flag' tooltip. Can also be used on sets.
274
+ **
275
+ > Parameters
276
+ **
277
+ - angle (number) angle of orientation in degrees [default: `0`]
278
+ - x (number) x coordinate of the flag's point [default: Element's `x` or `cx`]
279
+ - y (number) y coordinate of the flag's point [default: Element's `x` or `cx`]
280
+ **
281
+ = (object) path element of the flag
282
+ > Usage
283
+ | paper.circle(50, 50, 10).attr({
284
+ | stroke: "#fff",
285
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
286
+ | }).flag(60);
287
+ \*/
288
+ Raphael.el.flag = function (angle, x, y) {
289
+ var d = 3,
290
+ paper = this.paper || this[0].paper;
291
+
292
+ if (!paper) return;
293
+
294
+ var p = paper.path().attr({ fill: '#000', stroke: '#000' }),
295
+ bb = this.getBBox(),
296
+ h = bb.height / 2,
297
+ center;
298
+
299
+ switch (this.type) {
300
+ case 'text':
301
+ case 'circle':
302
+ case 'ellipse': center = true; break;
303
+ default: center = false;
304
+ }
305
+
306
+ angle = angle || 0;
307
+ x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
308
+ y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2: bb.y);
309
+
310
+ p.attr({
311
+ path: [
312
+ "M", x, y,
313
+ "l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0,
314
+ "z"
315
+ ].join(",")
316
+ });
317
+
318
+ angle = 360 - angle;
319
+ p.rotate(angle, x, y);
320
+
321
+ if (this.attrs) {
322
+ //elements
323
+ this.attr(this.attrs.x ? 'x' : 'cx', x + h + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2);
324
+ this.rotate(angle, x, y);
325
+ angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - h - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y);
326
+ } else {
327
+ //sets
328
+ if (angle > 90 && angle < 270) {
329
+ this.translate(x - bb.x - bb.width - h - d, y - bb.y - bb.height / 2);
330
+ this.rotate(angle - 180, bb.x + bb.width + h + d, bb.y + bb.height / 2);
331
+ } else {
332
+ this.translate(x - bb.x + h + d, y - bb.y - bb.height / 2);
333
+ this.rotate(angle, bb.x - h - d, bb.y + bb.height / 2);
334
+ }
335
+ }
336
+
337
+ return p.insertBefore(this.node ? this : this[0]);
338
+ };
339
+
340
+ /*\
341
+ * Element.label
342
+ [ method ]
343
+ **
344
+ * Puts the context Element in a 'label' tooltip. Can also be used on sets.
345
+ **
346
+ = (object) path element of the label.
347
+ > Usage
348
+ | paper.circle(50, 50, 10).attr({
349
+ | stroke: "#fff",
350
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
351
+ | }).label();
352
+ \*/
353
+ Raphael.el.label = function () {
354
+ var bb = this.getBBox(),
355
+ paper = this.paper || this[0].paper,
356
+ r = Math.min(20, bb.width + 10, bb.height + 10) / 2;
357
+
358
+ if (!paper) return;
359
+
360
+ return paper.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({ stroke: 'none', fill: '#000' }).insertBefore(this.node ? this : this[0]);
361
+ };
362
+
363
+ /*\
364
+ * Element.blob
365
+ [ method ]
366
+ **
367
+ * Puts the context Element in a 'blob' tooltip. Can also be used on sets.
368
+ **
369
+ > Parameters
370
+ **
371
+ - angle (number) angle of orientation in degrees [default: `0`]
372
+ - x (number) x coordinate of the blob's tail [default: Element's `x` or `cx`]
373
+ - y (number) y coordinate of the blob's tail [default: Element's `x` or `cx`]
374
+ **
375
+ = (object) path element of the blob
376
+ > Usage
377
+ | paper.circle(50, 50, 8).attr({
378
+ | stroke: "#fff",
379
+ | fill: "0-#c9de96-#8ab66b:44-#398235"
380
+ | }).blob(60);
381
+ \*/
382
+ Raphael.el.blob = function (angle, x, y) {
383
+ var bb = this.getBBox(),
384
+ rad = Math.PI / 180,
385
+ paper = this.paper || this[0].paper,
386
+ p, center, size;
387
+
388
+ if (!paper) return;
389
+
390
+ switch (this.type) {
391
+ case 'text':
392
+ case 'circle':
393
+ case 'ellipse': center = true; break;
394
+ default: center = false;
395
+ }
396
+
397
+ p = paper.path().attr({ fill: "#000", stroke: "none" });
398
+ angle = (+angle + 1 ? angle : 45) + 90;
399
+ size = Math.min(bb.height, bb.width);
400
+ x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
401
+ y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
402
+
403
+ var w = Math.max(bb.width + size, size * 25 / 12),
404
+ h = Math.max(bb.height + size, size * 25 / 12),
405
+ x2 = x + size * Math.sin((angle - 22.5) * rad),
406
+ y2 = y + size * Math.cos((angle - 22.5) * rad),
407
+ x1 = x + size * Math.sin((angle + 22.5) * rad),
408
+ y1 = y + size * Math.cos((angle + 22.5) * rad),
409
+ dx = (x1 - x2) / 2,
410
+ dy = (y1 - y2) / 2,
411
+ rx = w / 2,
412
+ ry = h / 2,
413
+ k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)),
414
+ cx = k * rx * dy / ry + (x1 + x2) / 2,
415
+ cy = k * -ry * dx / rx + (y1 + y2) / 2;
416
+
417
+ p.attr({
418
+ x: cx,
419
+ y: cy,
420
+ path: [
421
+ "M", x, y,
422
+ "L", x1, y1,
423
+ "A", rx, ry, 0, 1, 1, x2, y2,
424
+ "z"
425
+ ].join(",")
426
+ });
427
+
428
+ this.translate(cx - bb.x - bb.width / 2, cy - bb.y - bb.height / 2);
429
+
430
+ return p.insertBefore(this.node ? this : this[0]);
431
+ };
432
+
433
+ /*
434
+ * Tooltips on Paper prototype
435
+ */
436
+ /*\
437
+ * Paper.label
438
+ [ method ]
439
+ **
440
+ * Puts the given `text` into a 'label' tooltip. The text is given a default style according to @g.txtattr. See @Element.label
441
+ **
442
+ > Parameters
443
+ **
444
+ - x (number) x coordinate of the center of the label
445
+ - y (number) y coordinate of the center of the label
446
+ - text (string) text to place inside the label
447
+ **
448
+ = (object) set containing the label path and the text element
449
+ > Usage
450
+ | paper.label(50, 50, "$9.99");
451
+ \*/
452
+ Raphael.fn.label = function (x, y, text) {
453
+ var set = this.set();
454
+
455
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
456
+ return set.push(text.label(), text);
457
+ };
458
+
459
+ /*\
460
+ * Paper.popup
461
+ [ method ]
462
+ **
463
+ * Puts the given `text` into a 'popup' tooltip. The text is given a default style according to @g.txtattr. See @Element.popup
464
+ *
465
+ * Note: The `dir` parameter has changed from g.Raphael 0.4.1 to 0.5. The options `0`, `1`, `2`, and `3` has been changed to `'down'`, `'left'`, `'up'`, and `'right'` respectively.
466
+ **
467
+ > Parameters
468
+ **
469
+ - x (number) x coordinate of the popup's tail
470
+ - y (number) y coordinate of the popup's tail
471
+ - text (string) text to place inside the popup
472
+ - dir (string) location of the text relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`.
473
+ - size (number) amount of padding around the Element [default: `5`]
474
+ **
475
+ = (object) set containing the popup path and the text element
476
+ > Usage
477
+ | paper.popup(50, 50, "$9.99", 'down');
478
+ \*/
479
+ Raphael.fn.popup = function (x, y, text, dir, size) {
480
+ var set = this.set();
481
+
482
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
483
+ return set.push(text.popup(dir, size), text);
484
+ };
485
+
486
+ /*\
487
+ * Paper.tag
488
+ [ method ]
489
+ **
490
+ * Puts the given text into a 'tag' tooltip. The text is given a default style according to @g.txtattr. See @Element.tag
491
+ **
492
+ > Parameters
493
+ **
494
+ - x (number) x coordinate of the center of the tag loop
495
+ - y (number) y coordinate of the center of the tag loop
496
+ - text (string) text to place inside the tag
497
+ - angle (number) angle of orientation in degrees [default: `0`]
498
+ - r (number) radius of the loop [default: `5`]
499
+ **
500
+ = (object) set containing the tag path and the text element
501
+ > Usage
502
+ | paper.tag(50, 50, "$9.99", 60);
503
+ \*/
504
+ Raphael.fn.tag = function (x, y, text, angle, r) {
505
+ var set = this.set();
506
+
507
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
508
+ return set.push(text.tag(angle, r), text);
509
+ };
510
+
511
+ /*\
512
+ * Paper.flag
513
+ [ method ]
514
+ **
515
+ * Puts the given `text` into a 'flag' tooltip. The text is given a default style according to @g.txtattr. See @Element.flag
516
+ **
517
+ > Parameters
518
+ **
519
+ - x (number) x coordinate of the flag's point
520
+ - y (number) y coordinate of the flag's point
521
+ - text (string) text to place inside the flag
522
+ - angle (number) angle of orientation in degrees [default: `0`]
523
+ **
524
+ = (object) set containing the flag path and the text element
525
+ > Usage
526
+ | paper.flag(50, 50, "$9.99", 60);
527
+ \*/
528
+ Raphael.fn.flag = function (x, y, text, angle) {
529
+ var set = this.set();
530
+
531
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
532
+ return set.push(text.flag(angle), text);
533
+ };
534
+
535
+ /*\
536
+ * Paper.drop
537
+ [ method ]
538
+ **
539
+ * Puts the given text into a 'drop' tooltip. The text is given a default style according to @g.txtattr. See @Element.drop
540
+ **
541
+ > Parameters
542
+ **
543
+ - x (number) x coordinate of the drop's point
544
+ - y (number) y coordinate of the drop's point
545
+ - text (string) text to place inside the drop
546
+ - angle (number) angle of orientation in degrees [default: `0`]
547
+ **
548
+ = (object) set containing the drop path and the text element
549
+ > Usage
550
+ | paper.drop(50, 50, "$9.99", 60);
551
+ \*/
552
+ Raphael.fn.drop = function (x, y, text, angle) {
553
+ var set = this.set();
554
+
555
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
556
+ return set.push(text.drop(angle), text);
557
+ };
558
+
559
+ /*\
560
+ * Paper.blob
561
+ [ method ]
562
+ **
563
+ * Puts the given text into a 'blob' tooltip. The text is given a default style according to @g.txtattr. See @Element.blob
564
+ **
565
+ > Parameters
566
+ **
567
+ - x (number) x coordinate of the blob's tail
568
+ - y (number) y coordinate of the blob's tail
569
+ - text (string) text to place inside the blob
570
+ - angle (number) angle of orientation in degrees [default: `0`]
571
+ **
572
+ = (object) set containing the blob path and the text element
573
+ > Usage
574
+ | paper.blob(50, 50, "$9.99", 60);
575
+ \*/
576
+ Raphael.fn.blob = function (x, y, text, angle) {
577
+ var set = this.set();
578
+
579
+ text = this.text(x, y, text).attr(Raphael.g.txtattr);
580
+ return set.push(text.blob(angle), text);
581
+ };
582
+
583
+ /**
584
+ * Brightness functions on the Element prototype
585
+ */
586
+ /*\
587
+ * Element.lighter
588
+ [ method ]
589
+ **
590
+ * Makes the context element lighter by increasing the brightness and reducing the saturation by a given factor. Can be called on Sets.
591
+ **
592
+ > Parameters
593
+ **
594
+ - times (number) adjustment factor [default: `2`]
595
+ **
596
+ = (object) Element
597
+ > Usage
598
+ | paper.circle(50, 50, 20).attr({
599
+ | fill: "#ff0000",
600
+ | stroke: "#fff",
601
+ | "stroke-width": 2
602
+ | }).lighter(6);
603
+ \*/
604
+ Raphael.el.lighter = function (times) {
605
+ times = times || 2;
606
+
607
+ var fs = [this.attrs.fill, this.attrs.stroke];
608
+
609
+ this.fs = this.fs || [fs[0], fs[1]];
610
+
611
+ fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
612
+ fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
613
+ fs[0].b = Math.min(fs[0].b * times, 1);
614
+ fs[0].s = fs[0].s / times;
615
+ fs[1].b = Math.min(fs[1].b * times, 1);
616
+ fs[1].s = fs[1].s / times;
617
+
618
+ this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
619
+ return this;
620
+ };
621
+
622
+ /*\
623
+ * Element.darker
624
+ [ method ]
625
+ **
626
+ * Makes the context element darker by decreasing the brightness and increasing the saturation by a given factor. Can be called on Sets.
627
+ **
628
+ > Parameters
629
+ **
630
+ - times (number) adjustment factor [default: `2`]
631
+ **
632
+ = (object) Element
633
+ > Usage
634
+ | paper.circle(50, 50, 20).attr({
635
+ | fill: "#ff0000",
636
+ | stroke: "#fff",
637
+ | "stroke-width": 2
638
+ | }).darker(6);
639
+ \*/
640
+ Raphael.el.darker = function (times) {
641
+ times = times || 2;
642
+
643
+ var fs = [this.attrs.fill, this.attrs.stroke];
644
+
645
+ this.fs = this.fs || [fs[0], fs[1]];
646
+
647
+ fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
648
+ fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
649
+ fs[0].s = Math.min(fs[0].s * times, 1);
650
+ fs[0].b = fs[0].b / times;
651
+ fs[1].s = Math.min(fs[1].s * times, 1);
652
+ fs[1].b = fs[1].b / times;
653
+
654
+ this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
655
+ return this;
656
+ };
657
+
658
+ /*\
659
+ * Element.resetBrightness
660
+ [ method ]
661
+ **
662
+ * Resets brightness and saturation levels to their original values. See @Element.lighter and @Element.darker. Can be called on Sets.
663
+ **
664
+ = (object) Element
665
+ > Usage
666
+ | paper.circle(50, 50, 20).attr({
667
+ | fill: "#ff0000",
668
+ | stroke: "#fff",
669
+ | "stroke-width": 2
670
+ | }).lighter(6).resetBrightness();
671
+ \*/
672
+ Raphael.el.resetBrightness = function () {
673
+ if (this.fs) {
674
+ this.attr({ fill: this.fs[0], stroke: this.fs[1] });
675
+ delete this.fs;
676
+ }
677
+ return this;
678
+ };
679
+
680
+ //alias to set prototype
681
+ (function () {
682
+ var brightness = ['lighter', 'darker', 'resetBrightness'],
683
+ tooltips = ['popup', 'tag', 'flag', 'label', 'drop', 'blob'];
684
+
685
+ for (var f in tooltips) (function (name) {
686
+ Raphael.st[name] = function () {
687
+ return Raphael.el[name].apply(this, arguments);
688
+ };
689
+ })(tooltips[f]);
690
+
691
+ for (var f in brightness) (function (name) {
692
+ Raphael.st[name] = function () {
693
+ for (var i = 0; i < this.length; i++) {
694
+ this[i][name].apply(this[i], arguments);
695
+ }
696
+
697
+ return this;
698
+ };
699
+ })(brightness[f]);
700
+ })();
701
+
702
+ //chart prototype for storing common functions
703
+ Raphael.g = {
704
+ /*\
705
+ * g.shim
706
+ [ object ]
707
+ **
708
+ * An attribute object that charts will set on all generated shims (shims being the invisible objects that mouse events are bound to)
709
+ **
710
+ > Default value
711
+ | { stroke: 'none', fill: '#000', 'fill-opacity': 0 }
712
+ \*/
713
+ shim: { stroke: 'none', fill: '#000', 'fill-opacity': 0 },
714
+
715
+ /*\
716
+ * g.txtattr
717
+ [ object ]
718
+ **
719
+ * An attribute object that charts and tooltips will set on any generated text
720
+ **
721
+ > Default value
722
+ | { font: '12px Arial, sans-serif', fill: '#fff' }
723
+ \*/
724
+ txtattr: { font: '12px Arial, sans-serif', fill: '#fff' },
725
+
726
+ /*\
727
+ * g.colors
728
+ [ array ]
729
+ **
730
+ * An array of color values that charts will iterate through when drawing chart data values.
731
+ **
732
+ \*/
733
+ colors: (function () {
734
+ var hues = [.6, .2, .05, .1333, .75, 0],
735
+ colors = [];
736
+
737
+ for (var i = 0; i < 10; i++) {
738
+ if (i < hues.length) {
739
+ colors.push('hsb(' + hues[i] + ',.75, .75)');
740
+ } else {
741
+ colors.push('hsb(' + hues[i - hues.length] + ', 1, .5)');
742
+ }
743
+ }
744
+
745
+ return colors;
746
+ })(),
747
+
748
+ snapEnds: function(from, to, steps) {
749
+ var f = from,
750
+ t = to;
751
+
752
+ if (f == t) {
753
+ return {from: f, to: t, power: 0};
754
+ }
755
+
756
+ function round(a) {
757
+ return Math.abs(a - .5) < .25 ? ~~(a) + .5 : Math.round(a);
758
+ }
759
+
760
+ var d = (t - f) / steps,
761
+ r = ~~(d),
762
+ R = r,
763
+ i = 0;
764
+
765
+ if (r) {
766
+ while (R) {
767
+ i--;
768
+ R = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
769
+ }
770
+
771
+ i ++;
772
+ } else {
773
+ while (!r) {
774
+ i = i || 1;
775
+ r = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
776
+ i++;
777
+ }
778
+
779
+ i && i--;
780
+ }
781
+
782
+ t = round(to * Math.pow(10, i)) / Math.pow(10, i);
783
+
784
+ if (t < to) {
785
+ t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i);
786
+ }
787
+
788
+ f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i);
789
+ return { from: f, to: t, power: i };
790
+ },
791
+
792
+ axis: function (x, y, length, from, to, steps, orientation, labels, type, dashsize, paper) {
793
+ dashsize = dashsize == null ? 2 : dashsize;
794
+ type = type || "t";
795
+ steps = steps || 10;
796
+ paper = arguments[arguments.length-1] //paper is always last argument
797
+
798
+ var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0],
799
+ ends = this.snapEnds(from, to, steps),
800
+ f = ends.from,
801
+ t = ends.to,
802
+ i = ends.power,
803
+ j = 0,
804
+ txtattr = { font: "11px 'Fontin Sans', Fontin-Sans, sans-serif" },
805
+ text = paper.set(),
806
+ d;
807
+
808
+ d = (t - f) / steps;
809
+
810
+ var label = f,
811
+ rnd = i > 0 ? i : 0;
812
+ dx = length / steps;
813
+
814
+ if (+orientation == 1 || +orientation == 3) {
815
+ var Y = y,
816
+ addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1));
817
+
818
+ while (Y >= y - length) {
819
+ type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0]));
820
+ text.push(paper.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" }));
821
+ label += d;
822
+ Y -= dx;
823
+ }
824
+
825
+ if (Math.round(Y + dx - (y - length))) {
826
+ type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0]));
827
+ text.push(paper.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" }));
828
+ }
829
+ } else {
830
+ label = f;
831
+ rnd = (i > 0) * i;
832
+ addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation);
833
+
834
+ var X = x,
835
+ dx = length / steps,
836
+ txt = 0,
837
+ prev = 0;
838
+
839
+ while (X <= x + length) {
840
+ type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1]));
841
+ text.push(txt = paper.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr));
842
+
843
+ var bb = txt.getBBox();
844
+
845
+ if (prev >= bb.x - 5) {
846
+ text.pop(text.length - 1).remove();
847
+ } else {
848
+ prev = bb.x + bb.width;
849
+ }
850
+
851
+ label += d;
852
+ X += dx;
853
+ }
854
+
855
+ if (Math.round(X - dx - x - length)) {
856
+ type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1]));
857
+ text.push(paper.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr));
858
+ }
859
+ }
860
+
861
+ var res = paper.path(path);
862
+
863
+ res.text = text;
864
+ res.all = paper.set([res, text]);
865
+ res.remove = function () {
866
+ this.text.remove();
867
+ this.constructor.prototype.remove.call(this);
868
+ };
869
+
870
+ return res;
871
+ },
872
+
873
+ labelise: function(label, val, total) {
874
+ if (label) {
875
+ return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) {
876
+ if (value) {
877
+ return (+val).toFixed(value.replace(/^#+\.?/g, "").length);
878
+ }
879
+ if (percent) {
880
+ return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%";
881
+ }
882
+ });
883
+ } else {
884
+ return (+val).toFixed(0);
885
+ }
886
+ }
887
+ }