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