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,258 @@
|
|
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
|
+
(function () {
|
9
|
+
var colorValue = function (value, total, s, b) {
|
10
|
+
return 'hsb(' + [Math.min((1 - value / total) * .4, 1), s || .75, b || .75] + ')';
|
11
|
+
};
|
12
|
+
|
13
|
+
function Dotchart(paper, x, y, width, height, valuesx, valuesy, size, opts) {
|
14
|
+
|
15
|
+
function drawAxis(ax) {
|
16
|
+
+ax[0] && (ax[0] = chartinst.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, opts.axisxlabels || null, opts.axisxtype || "t", null, paper));
|
17
|
+
+ax[1] && (ax[1] = chartinst.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, opts.axisylabels || null, opts.axisytype || "t", null, paper));
|
18
|
+
+ax[2] && (ax[2] = chartinst.axis(x + gutter, y + height - gutter + maxR, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, opts.axisxlabels || null, opts.axisxtype || "t", null, paper));
|
19
|
+
+ax[3] && (ax[3] = chartinst.axis(x + gutter - maxR, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, opts.axisylabels || null, opts.axisytype || "t", null, paper));
|
20
|
+
}
|
21
|
+
|
22
|
+
//providing defaults
|
23
|
+
|
24
|
+
opts = opts || {};
|
25
|
+
var chartinst = this;
|
26
|
+
var xdim = chartinst.snapEnds(Math.min.apply(Math, valuesx), Math.max.apply(Math, valuesx), valuesx.length - 1),
|
27
|
+
minx = xdim.from,
|
28
|
+
maxx = xdim.to,
|
29
|
+
gutter = opts.gutter || 10,
|
30
|
+
ydim = chartinst.snapEnds(Math.min.apply(Math, valuesy), Math.max.apply(Math, valuesy), valuesy.length - 1),
|
31
|
+
miny = ydim.from,
|
32
|
+
maxy = ydim.to,
|
33
|
+
len = Math.max(valuesx.length, valuesy.length, size.length),
|
34
|
+
symbol = paper[opts.symbol] || "circle",
|
35
|
+
res = paper.set(),
|
36
|
+
series = paper.set(),
|
37
|
+
max = opts.max || 100,
|
38
|
+
top = Math.max.apply(Math, size),
|
39
|
+
R = [],
|
40
|
+
k = Math.sqrt(top / Math.PI) * 2 / max;
|
41
|
+
|
42
|
+
for (var i = 0; i < len; i++) {
|
43
|
+
R[i] = Math.min(Math.sqrt(size[i] / Math.PI) * 2 / k, max);
|
44
|
+
}
|
45
|
+
|
46
|
+
gutter = Math.max.apply(Math, R.concat(gutter));
|
47
|
+
|
48
|
+
/*\
|
49
|
+
* dotchart.axis
|
50
|
+
[ object ]
|
51
|
+
**
|
52
|
+
* Set containing Elements of the chart axis. Only exists if `'axis'` definition string was passed to @Paper.dotchart
|
53
|
+
**
|
54
|
+
\*/
|
55
|
+
var axis = paper.set(),
|
56
|
+
maxR = Math.max.apply(Math, R);
|
57
|
+
|
58
|
+
if (opts.axis) {
|
59
|
+
var ax = (opts.axis + "").split(/[,\s]+/);
|
60
|
+
|
61
|
+
drawAxis.call(chartinst, ax);
|
62
|
+
|
63
|
+
var g = [], b = [];
|
64
|
+
|
65
|
+
for (var i = 0, ii = ax.length; i < ii; i++) {
|
66
|
+
var bb = ax[i].all ? ax[i].all.getBBox()[["height", "width"][i % 2]] : 0;
|
67
|
+
|
68
|
+
g[i] = bb + gutter;
|
69
|
+
b[i] = bb;
|
70
|
+
}
|
71
|
+
|
72
|
+
gutter = Math.max.apply(Math, g.concat(gutter));
|
73
|
+
|
74
|
+
for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
|
75
|
+
ax[i].remove();
|
76
|
+
ax[i] = 1;
|
77
|
+
}
|
78
|
+
|
79
|
+
drawAxis.call(chartinst, ax);
|
80
|
+
|
81
|
+
for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
|
82
|
+
axis.push(ax[i].all);
|
83
|
+
}
|
84
|
+
|
85
|
+
res.axis = axis;
|
86
|
+
}
|
87
|
+
|
88
|
+
var kx = (width - gutter * 2) / ((maxx - minx) || 1),
|
89
|
+
ky = (height - gutter * 2) / ((maxy - miny) || 1);
|
90
|
+
|
91
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
92
|
+
var sym = paper.raphael.is(symbol, "array") ? symbol[i] : symbol,
|
93
|
+
X = x + gutter + (valuesx[i] - minx) * kx,
|
94
|
+
Y = y + height - gutter - (valuesy[i] - miny) * ky;
|
95
|
+
|
96
|
+
sym && R[i] && series.push(paper[sym](X, Y, R[i]).attr({ fill: opts.heat ? colorValue(R[i], maxR) : chartinst.colors[0], "fill-opacity": opts.opacity ? R[i] / max : 1, stroke: "none" }));
|
97
|
+
}
|
98
|
+
|
99
|
+
var covers = paper.set();
|
100
|
+
|
101
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
102
|
+
var X = x + gutter + (valuesx[i] - minx) * kx,
|
103
|
+
Y = y + height - gutter - (valuesy[i] - miny) * ky;
|
104
|
+
|
105
|
+
covers.push(paper.circle(X, Y, maxR).attr(chartinst.shim));
|
106
|
+
opts.href && opts.href[i] && covers[i].attr({href: opts.href[i]});
|
107
|
+
covers[i].r = +R[i].toFixed(3);
|
108
|
+
covers[i].x = +X.toFixed(3);
|
109
|
+
covers[i].y = +Y.toFixed(3);
|
110
|
+
covers[i].X = valuesx[i];
|
111
|
+
covers[i].Y = valuesy[i];
|
112
|
+
covers[i].value = size[i] || 0;
|
113
|
+
covers[i].dot = series[i];
|
114
|
+
}
|
115
|
+
|
116
|
+
/*\
|
117
|
+
* dotchart.covers
|
118
|
+
[ object ]
|
119
|
+
**
|
120
|
+
* Set of Elements positioned above the symbols and mirroring them in size and shape. Covers are used as a surface for events capturing. Each cover has a property `'dot'` being a reference to the actual data-representing symbol.
|
121
|
+
**
|
122
|
+
**
|
123
|
+
\*/
|
124
|
+
res.covers = covers;
|
125
|
+
/*\
|
126
|
+
* dotchart.series
|
127
|
+
[ object ]
|
128
|
+
**
|
129
|
+
* Set of Elements containing the actual data-representing symbols.
|
130
|
+
**
|
131
|
+
**
|
132
|
+
\*/
|
133
|
+
res.series = series;
|
134
|
+
res.push(series, axis, covers);
|
135
|
+
|
136
|
+
/*\
|
137
|
+
* dotchart.hover
|
138
|
+
[ method ]
|
139
|
+
> Parameters
|
140
|
+
- mouseover handler (function) handler for the event
|
141
|
+
- mouseout handler (function) handler for the event
|
142
|
+
* Conveniece method to set up hover-in and hover-out event handlers
|
143
|
+
= (object) @dotchart object
|
144
|
+
**
|
145
|
+
\*/
|
146
|
+
res.hover = function (fin, fout) {
|
147
|
+
covers.mouseover(fin).mouseout(fout);
|
148
|
+
return this;
|
149
|
+
};
|
150
|
+
|
151
|
+
/*\
|
152
|
+
* dotchart.click
|
153
|
+
[ method ]
|
154
|
+
> Parameters
|
155
|
+
- click handler (function) handler for the event
|
156
|
+
* Conveniece method to set up click event handler
|
157
|
+
= (object) @dotchart object
|
158
|
+
**
|
159
|
+
\*/
|
160
|
+
res.click = function (f) {
|
161
|
+
covers.click(f);
|
162
|
+
return this;
|
163
|
+
};
|
164
|
+
|
165
|
+
/*\
|
166
|
+
* dotchart.each
|
167
|
+
[ method ]
|
168
|
+
> Parameters
|
169
|
+
- callback (function) called for every item in @dotchart.covers.
|
170
|
+
- this (object) callback is executed in a context of a cover element object
|
171
|
+
* Conveniece method iterating on every symbol in the chart
|
172
|
+
= (object) @dotchart object
|
173
|
+
**
|
174
|
+
\*/
|
175
|
+
res.each = function (f) {
|
176
|
+
if (!paper.raphael.is(f, "function")) {
|
177
|
+
return this;
|
178
|
+
}
|
179
|
+
|
180
|
+
for (var i = covers.length; i--;) {
|
181
|
+
f.call(covers[i]);
|
182
|
+
}
|
183
|
+
|
184
|
+
return this;
|
185
|
+
};
|
186
|
+
|
187
|
+
/*\
|
188
|
+
* dotchart.href
|
189
|
+
[ method ]
|
190
|
+
> Parameters
|
191
|
+
- map (array) Array of objects `{x: 1, y: 20, value: 15, href: "http://www.raphaeljs.com"}`
|
192
|
+
* Iterates on all @dotchart.covers elements. If x, y and value on the object are the same as on the cover it sets up a link on a symbol using the passef `href`.
|
193
|
+
= (object) @dotchart object
|
194
|
+
**
|
195
|
+
\*/
|
196
|
+
res.href = function (map) {
|
197
|
+
var cover;
|
198
|
+
|
199
|
+
for (var i = covers.length; i--;) {
|
200
|
+
cover = covers[i];
|
201
|
+
|
202
|
+
if (cover.X == map.x && cover.Y == map.y && cover.value == map.value) {
|
203
|
+
cover.attr({href: map.href});
|
204
|
+
}
|
205
|
+
}
|
206
|
+
};
|
207
|
+
return res;
|
208
|
+
};
|
209
|
+
|
210
|
+
//inheritance
|
211
|
+
var F = function() {};
|
212
|
+
F.prototype = Raphael.g
|
213
|
+
Dotchart.prototype = new F;
|
214
|
+
|
215
|
+
/*
|
216
|
+
* dotchart method on paper
|
217
|
+
*/
|
218
|
+
/*\
|
219
|
+
* Paper.dotchart
|
220
|
+
[ method ]
|
221
|
+
**
|
222
|
+
* Plots a dot chart
|
223
|
+
**
|
224
|
+
> Parameters
|
225
|
+
- x (number) x coordinate of the chart
|
226
|
+
- y (number) y coordinate of the chart
|
227
|
+
- width (number) width of the chart (respected by all elements in the set)
|
228
|
+
- height (number) height of the chart (respected by all elements in the set)
|
229
|
+
- valuesx (array) values used to plot x asis
|
230
|
+
- valuesy (array) values used to plot y asis
|
231
|
+
- size (array) values used as data
|
232
|
+
- opts (object) options for the chart
|
233
|
+
> Possible options
|
234
|
+
o {
|
235
|
+
o max (number) maximum diameter of a dot [default: 100]
|
236
|
+
o symbol (string) symbol used for rendering on the chart. The only possible option is `'circle'` [default]
|
237
|
+
o gutter (number) distance between symbols on the chart [default: 10]
|
238
|
+
o heat (boolean) whether or not to enable coloring higher value symbols with warmer hue [default: false]
|
239
|
+
o opacity (number) opacity of the symbols [default: 1]
|
240
|
+
o href (array) array of URLs to set up click-throughs on the symbols
|
241
|
+
o axis (string) Which axes should be renedered. String of four values evaluated in order `'top right bottom left'` e.g. `'0 0 1 1'`.
|
242
|
+
o axisxstep (number) the number of steps to plot on the axis X
|
243
|
+
o axisystep (number) the number of steps to plot on the axis Y
|
244
|
+
o axisxlabels (array) labels to be rendered instead of numeric values on axis X
|
245
|
+
o axisylabels (array) labels to be rendered instead of numeric values on axis Y
|
246
|
+
o axisxtype (string) Possible values: `'t'` [default], `'|'`, `' '`, `'-'`, `'+'`
|
247
|
+
o axisytype (string) Possible values: `'t'` [default], `'|'`, `' '`, `'-'`, `'+'`
|
248
|
+
o }
|
249
|
+
**
|
250
|
+
= (object) @dotchart object
|
251
|
+
> Usage
|
252
|
+
| //life, expectancy, country and spending per capita (fictional data)
|
253
|
+
| r.dotchart(0, 0, 620, 260, [76, 70, 67, 71, 69], [0, 1, 2, 3, 4], [100, 120, 140, 160, 500], {max: 10, axisylabels: ['Mexico', 'Argentina', 'Cuba', 'Canada', 'United States of America'], heat: true, axis: '0 0 1 1'})
|
254
|
+
\*/
|
255
|
+
Raphael.fn.dotchart = function(x, y, width, height, valuesx, valuesy, size, opts) {
|
256
|
+
return new Dotchart(this, x, y, width, height, valuesx, valuesy, size, opts);
|
257
|
+
}
|
258
|
+
})();
|
@@ -0,0 +1,489 @@
|
|
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
|
+
(function () {
|
9
|
+
|
10
|
+
function shrink(values, dim) {
|
11
|
+
var k = values.length / dim,
|
12
|
+
j = 0,
|
13
|
+
l = k,
|
14
|
+
sum = 0,
|
15
|
+
res = [];
|
16
|
+
|
17
|
+
while (j < values.length) {
|
18
|
+
l--;
|
19
|
+
|
20
|
+
if (l < 0) {
|
21
|
+
sum += values[j] * (1 + l);
|
22
|
+
res.push(sum / k);
|
23
|
+
sum = values[j++] * -l;
|
24
|
+
l += k;
|
25
|
+
} else {
|
26
|
+
sum += values[j++] * 1;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
return res;
|
30
|
+
}
|
31
|
+
|
32
|
+
function getAnchors(p1x, p1y, p2x, p2y, p3x, p3y) {
|
33
|
+
var l1 = (p2x - p1x) / 2,
|
34
|
+
l2 = (p3x - p2x) / 2,
|
35
|
+
a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)),
|
36
|
+
b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y));
|
37
|
+
|
38
|
+
a = p1y < p2y ? Math.PI - a : a;
|
39
|
+
b = p3y < p2y ? Math.PI - b : b;
|
40
|
+
|
41
|
+
var alpha = Math.PI / 2 - ((a + b) % (Math.PI * 2)) / 2,
|
42
|
+
dx1 = l1 * Math.sin(alpha + a),
|
43
|
+
dy1 = l1 * Math.cos(alpha + a),
|
44
|
+
dx2 = l2 * Math.sin(alpha + b),
|
45
|
+
dy2 = l2 * Math.cos(alpha + b);
|
46
|
+
|
47
|
+
return {
|
48
|
+
x1: p2x - dx1,
|
49
|
+
y1: p2y + dy1,
|
50
|
+
x2: p2x + dx2,
|
51
|
+
y2: p2y + dy2
|
52
|
+
};
|
53
|
+
}
|
54
|
+
|
55
|
+
function Linechart(paper, x, y, width, height, valuesx, valuesy, opts) {
|
56
|
+
|
57
|
+
var chartinst = this;
|
58
|
+
|
59
|
+
opts = opts || {};
|
60
|
+
|
61
|
+
if (!paper.raphael.is(valuesx[0], "array")) {
|
62
|
+
valuesx = [valuesx];
|
63
|
+
}
|
64
|
+
|
65
|
+
if (!paper.raphael.is(valuesy[0], "array")) {
|
66
|
+
valuesy = [valuesy];
|
67
|
+
}
|
68
|
+
|
69
|
+
var gutter = opts.gutter || 10,
|
70
|
+
len = Math.max(valuesx[0].length, valuesy[0].length),
|
71
|
+
symbol = opts.symbol || "",
|
72
|
+
colors = opts.colors || chartinst.colors,
|
73
|
+
columns = null,
|
74
|
+
dots = null,
|
75
|
+
chart = paper.set(),
|
76
|
+
path = [];
|
77
|
+
|
78
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
79
|
+
len = Math.max(len, valuesy[i].length);
|
80
|
+
}
|
81
|
+
|
82
|
+
/*\
|
83
|
+
* linechart.shades
|
84
|
+
[ object ]
|
85
|
+
**
|
86
|
+
* Set containing Elements corresponding to shades plotted in the chart (if `opts.shade` was `true`).
|
87
|
+
**
|
88
|
+
**
|
89
|
+
\*/
|
90
|
+
var shades = paper.set();
|
91
|
+
|
92
|
+
for (i = 0, ii = valuesy.length; i < ii; i++) {
|
93
|
+
if (opts.shade) {
|
94
|
+
shades.push(paper.path().attr({ stroke: "none", fill: colors[i], opacity: opts.nostroke ? 1 : .3 }));
|
95
|
+
}
|
96
|
+
|
97
|
+
if (valuesy[i].length > width - 2 * gutter) {
|
98
|
+
valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
|
99
|
+
len = width - 2 * gutter;
|
100
|
+
}
|
101
|
+
|
102
|
+
if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
|
103
|
+
valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
var allx = Array.prototype.concat.apply([], valuesx),
|
108
|
+
ally = Array.prototype.concat.apply([], valuesy),
|
109
|
+
xdim = chartinst.snapEnds(Math.min.apply(Math, allx), Math.max.apply(Math, allx), valuesx[0].length - 1),
|
110
|
+
minx = xdim.from,
|
111
|
+
maxx = xdim.to,
|
112
|
+
ydim = chartinst.snapEnds(Math.min.apply(Math, ally), Math.max.apply(Math, ally), valuesy[0].length - 1),
|
113
|
+
miny = ydim.from,
|
114
|
+
maxy = ydim.to,
|
115
|
+
kx = (width - gutter * 2) / ((maxx - minx) || 1),
|
116
|
+
ky = (height - gutter * 2) / ((maxy - miny) || 1);
|
117
|
+
|
118
|
+
/*\
|
119
|
+
* linechart.axis
|
120
|
+
[ object ]
|
121
|
+
**
|
122
|
+
* Set containing Elements of the chart axis. The set is populated if `'axis'` definition string was passed to @Paper.linechart
|
123
|
+
**
|
124
|
+
**
|
125
|
+
\*/
|
126
|
+
var axis = paper.set();
|
127
|
+
|
128
|
+
if (opts.axis) {
|
129
|
+
var ax = (opts.axis + "").split(/[,\s]+/);
|
130
|
+
+ax[0] && axis.push(chartinst.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2, paper));
|
131
|
+
+ax[1] && axis.push(chartinst.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3, paper));
|
132
|
+
+ax[2] && axis.push(chartinst.axis(x + gutter, y + height - gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0, paper));
|
133
|
+
+ax[3] && axis.push(chartinst.axis(x + gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1, paper));
|
134
|
+
}
|
135
|
+
|
136
|
+
/*\
|
137
|
+
* linechart.lines
|
138
|
+
[ object ]
|
139
|
+
**
|
140
|
+
* Set containing Elements corresponding to lines plotted in the chart.
|
141
|
+
**
|
142
|
+
**
|
143
|
+
\*/
|
144
|
+
var lines = paper.set(),
|
145
|
+
/*\
|
146
|
+
* linechart.symbols
|
147
|
+
[ object ]
|
148
|
+
**
|
149
|
+
* Set containing Elements corresponding to symbols plotted in the chart.
|
150
|
+
**
|
151
|
+
**
|
152
|
+
\*/
|
153
|
+
symbols = paper.set(),
|
154
|
+
line;
|
155
|
+
|
156
|
+
for (i = 0, ii = valuesy.length; i < ii; i++) {
|
157
|
+
if (!opts.nostroke) {
|
158
|
+
lines.push(line = paper.path().attr({
|
159
|
+
stroke: colors[i],
|
160
|
+
"stroke-width": opts.width || 2,
|
161
|
+
"stroke-linejoin": "round",
|
162
|
+
"stroke-linecap": "round",
|
163
|
+
"stroke-dasharray": opts.dash || ""
|
164
|
+
}));
|
165
|
+
}
|
166
|
+
|
167
|
+
var sym = Raphael.is(symbol, "array") ? symbol[i] : symbol,
|
168
|
+
symset = paper.set();
|
169
|
+
|
170
|
+
path = [];
|
171
|
+
|
172
|
+
for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
|
173
|
+
var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
|
174
|
+
Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
|
175
|
+
|
176
|
+
(Raphael.is(sym, "array") ? sym[j] : sym) && symset.push(paper[Raphael.is(sym, "array") ? sym[j] : sym](X, Y, (opts.width || 2) * 3).attr({ fill: colors[i], stroke: "none" }));
|
177
|
+
|
178
|
+
if (opts.smooth) {
|
179
|
+
if (j && j != jj - 1) {
|
180
|
+
var X0 = x + gutter + ((valuesx[i] || valuesx[0])[j - 1] - minx) * kx,
|
181
|
+
Y0 = y + height - gutter - (valuesy[i][j - 1] - miny) * ky,
|
182
|
+
X2 = x + gutter + ((valuesx[i] || valuesx[0])[j + 1] - minx) * kx,
|
183
|
+
Y2 = y + height - gutter - (valuesy[i][j + 1] - miny) * ky,
|
184
|
+
a = getAnchors(X0, Y0, X, Y, X2, Y2);
|
185
|
+
|
186
|
+
path = path.concat([a.x1, a.y1, X, Y, a.x2, a.y2]);
|
187
|
+
}
|
188
|
+
|
189
|
+
if (!j) {
|
190
|
+
path = ["M", X, Y, "C", X, Y];
|
191
|
+
}
|
192
|
+
} else {
|
193
|
+
path = path.concat([j ? "L" : "M", X, Y]);
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
if (opts.smooth) {
|
198
|
+
path = path.concat([X, Y, X, Y]);
|
199
|
+
}
|
200
|
+
|
201
|
+
symbols.push(symset);
|
202
|
+
|
203
|
+
if (opts.shade) {
|
204
|
+
shades[i].attr({ path: path.concat(["L", X, y + height - gutter, "L", x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, "z"]).join(",") });
|
205
|
+
}
|
206
|
+
|
207
|
+
!opts.nostroke && line.attr({ path: path.join(",") });
|
208
|
+
}
|
209
|
+
|
210
|
+
function createColumns(f) {
|
211
|
+
// unite Xs together
|
212
|
+
var Xs = [];
|
213
|
+
|
214
|
+
for (var i = 0, ii = valuesx.length; i < ii; i++) {
|
215
|
+
Xs = Xs.concat(valuesx[i]);
|
216
|
+
}
|
217
|
+
|
218
|
+
Xs.sort(function(a,b) { return a - b; });
|
219
|
+
// remove duplicates
|
220
|
+
|
221
|
+
var Xs2 = [],
|
222
|
+
xs = [];
|
223
|
+
|
224
|
+
for (i = 0, ii = Xs.length; i < ii; i++) {
|
225
|
+
Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);
|
226
|
+
}
|
227
|
+
|
228
|
+
Xs = Xs2;
|
229
|
+
ii = Xs.length;
|
230
|
+
|
231
|
+
var cvrs = f || paper.set();
|
232
|
+
|
233
|
+
for (i = 0; i < ii; i++) {
|
234
|
+
var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,
|
235
|
+
w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,
|
236
|
+
C;
|
237
|
+
|
238
|
+
f ? (C = {}) : cvrs.push(C = paper.rect(X - 1, y, Math.max(w + 1, 1), height).attr({ stroke: "none", fill: "#000", opacity: 0 }));
|
239
|
+
C.values = [];
|
240
|
+
C.symbols = paper.set();
|
241
|
+
C.y = [];
|
242
|
+
C.x = xs[i];
|
243
|
+
C.axis = Xs[i];
|
244
|
+
|
245
|
+
for (var j = 0, jj = valuesy.length; j < jj; j++) {
|
246
|
+
Xs2 = valuesx[j] || valuesx[0];
|
247
|
+
|
248
|
+
for (var k = 0, kk = Xs2.length; k < kk; k++) {
|
249
|
+
if (Xs2[k] == Xs[i]) {
|
250
|
+
C.values.push(valuesy[j][k]);
|
251
|
+
C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);
|
252
|
+
C.symbols.push(chart.symbols[j][k]);
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
f && f.call(C);
|
258
|
+
}
|
259
|
+
|
260
|
+
!f && (columns = cvrs);
|
261
|
+
}
|
262
|
+
|
263
|
+
function createDots(f) {
|
264
|
+
var cvrs = f || paper.set(),
|
265
|
+
C;
|
266
|
+
|
267
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
268
|
+
for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
|
269
|
+
var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
|
270
|
+
nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,
|
271
|
+
Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
|
272
|
+
f ? (C = {}) : cvrs.push(C = paper.circle(X, Y, Math.abs(nearX - X) / 2).attr({ stroke: "#000", fill: "#000", opacity: 1 }));
|
273
|
+
C.x = X;
|
274
|
+
C.y = Y;
|
275
|
+
C.value = valuesy[i][j];
|
276
|
+
C.line = chart.lines[i];
|
277
|
+
C.shade = chart.shades[i];
|
278
|
+
C.symbol = chart.symbols[i][j];
|
279
|
+
C.symbols = chart.symbols[i];
|
280
|
+
C.axis = (valuesx[i] || valuesx[0])[j];
|
281
|
+
f && f.call(C);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
!f && (dots = cvrs);
|
286
|
+
}
|
287
|
+
|
288
|
+
chart.push(lines, shades, symbols, axis, columns, dots);
|
289
|
+
chart.lines = lines;
|
290
|
+
chart.shades = shades;
|
291
|
+
chart.symbols = symbols;
|
292
|
+
chart.axis = axis;
|
293
|
+
|
294
|
+
/*\
|
295
|
+
* linechart.hoverColumn
|
296
|
+
[ method ]
|
297
|
+
> Parameters
|
298
|
+
- mouseover handler (function) handler for the event
|
299
|
+
- mouseout handler (function) handler for the event
|
300
|
+
- this (object) callback is executed in a context of a cover element
|
301
|
+
* Conveniece method to set up hover-in and hover-out event handlers on the entire area of the chart.
|
302
|
+
* The handlers are passed a event object containing
|
303
|
+
o {
|
304
|
+
o x (number) x coordinate on all lines in the chart
|
305
|
+
o y (array) y coordinates of all lines corresponding to the x
|
306
|
+
o }
|
307
|
+
= (object) @linechart object
|
308
|
+
**
|
309
|
+
\*/
|
310
|
+
|
311
|
+
chart.hoverColumn = function (fin, fout) {
|
312
|
+
!columns && createColumns();
|
313
|
+
columns.mouseover(fin).mouseout(fout);
|
314
|
+
return this;
|
315
|
+
};
|
316
|
+
|
317
|
+
/*\
|
318
|
+
* linechart.clickColumn
|
319
|
+
[ method ]
|
320
|
+
> Parameters
|
321
|
+
- click handler (function) handler for the event
|
322
|
+
- this (object) callback is executed in a context of a cover element
|
323
|
+
* Conveniece method to set up click event handler on the antire area of the chart.
|
324
|
+
* The handler is passed a event object containing
|
325
|
+
o {
|
326
|
+
o x (number) x coordinate on all lines in the chart
|
327
|
+
o y (array) y coordinates of all lines corresponding to the x
|
328
|
+
o }
|
329
|
+
= (object) @linechart object
|
330
|
+
**
|
331
|
+
\*/
|
332
|
+
chart.clickColumn = function (f) {
|
333
|
+
!columns && createColumns();
|
334
|
+
columns.click(f);
|
335
|
+
return this;
|
336
|
+
};
|
337
|
+
|
338
|
+
/*\
|
339
|
+
* linechart.hrefColumn
|
340
|
+
[ method ]
|
341
|
+
> Parameters
|
342
|
+
- cols (object) object containing values as keys and URLs as values, e.g. {1: 'http://www.raphaeljs.com', 2: 'http://g.raphaeljs.com'}
|
343
|
+
* Creates click-throughs on the whole area of the chart corresponding to x values
|
344
|
+
= (object) @linechart object
|
345
|
+
**
|
346
|
+
\*/
|
347
|
+
chart.hrefColumn = function (cols) {
|
348
|
+
var hrefs = paper.raphael.is(arguments[0], "array") ? arguments[0] : arguments;
|
349
|
+
|
350
|
+
if (!(arguments.length - 1) && typeof cols == "object") {
|
351
|
+
for (var x in cols) {
|
352
|
+
for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {
|
353
|
+
columns[i].attr("href", cols[x]);
|
354
|
+
}
|
355
|
+
}
|
356
|
+
}
|
357
|
+
|
358
|
+
!columns && createColumns();
|
359
|
+
|
360
|
+
for (i = 0, ii = hrefs.length; i < ii; i++) {
|
361
|
+
columns[i] && columns[i].attr("href", hrefs[i]);
|
362
|
+
}
|
363
|
+
|
364
|
+
return this;
|
365
|
+
};
|
366
|
+
|
367
|
+
/*\
|
368
|
+
* linechart.hover
|
369
|
+
[ method ]
|
370
|
+
> Parameters
|
371
|
+
- mouseover handler (function) handler for the event
|
372
|
+
- mouseout handler (function) handler for the event
|
373
|
+
* Conveniece method to set up hover-in and hover-out event handlers working on the lines of the chart.
|
374
|
+
* Use @linechart.hoverColumn to work with the entire chart area.
|
375
|
+
= (object) @linechart object
|
376
|
+
**
|
377
|
+
\*/
|
378
|
+
chart.hover = function (fin, fout) {
|
379
|
+
!dots && createDots();
|
380
|
+
dots.mouseover(fin).mouseout(fout);
|
381
|
+
return this;
|
382
|
+
};
|
383
|
+
|
384
|
+
/*\
|
385
|
+
* linechart.click
|
386
|
+
[ method ]
|
387
|
+
> Parameters
|
388
|
+
- click handler (function) handler for the event
|
389
|
+
- this (object) callback is executed in a context of a cover element
|
390
|
+
* Conveniece method to set up click event handler on the lines of the chart
|
391
|
+
* Use @linechart.clickColumn to work with the entire chart area.
|
392
|
+
= (object) @linechart object
|
393
|
+
**
|
394
|
+
\*/
|
395
|
+
chart.click = function (f) {
|
396
|
+
!dots && createDots();
|
397
|
+
dots.click(f);
|
398
|
+
return this;
|
399
|
+
};
|
400
|
+
|
401
|
+
/*\
|
402
|
+
* linechart.each
|
403
|
+
[ method ]
|
404
|
+
> Parameters
|
405
|
+
- callback (function) function executed for every data point
|
406
|
+
- this (object) context of the callback function.
|
407
|
+
o {
|
408
|
+
o x (number) x coordinate of the data point
|
409
|
+
o y (number) y coordinate of the data point
|
410
|
+
o value (number) value represented by the data point
|
411
|
+
o }
|
412
|
+
* Iterates over each unique data point plotted on every line on the chart.
|
413
|
+
= (object) @linechart object
|
414
|
+
**
|
415
|
+
\*/
|
416
|
+
chart.each = function (f) {
|
417
|
+
createDots(f);
|
418
|
+
return this;
|
419
|
+
};
|
420
|
+
|
421
|
+
/*\
|
422
|
+
* linechart.eachColumn
|
423
|
+
[ method ]
|
424
|
+
> Parameters
|
425
|
+
- callback (function) function executed for every column
|
426
|
+
- this (object) context of the callback function.
|
427
|
+
o {
|
428
|
+
o x (number) x coordinate of the data point
|
429
|
+
o y (array) y coordinates of data points existing for the given x
|
430
|
+
o values (array) values represented by the data points existing for the given x
|
431
|
+
o }
|
432
|
+
* Iterates over each column area (area plotted above the chart).
|
433
|
+
= (object) @linechart object
|
434
|
+
**
|
435
|
+
\*/
|
436
|
+
chart.eachColumn = function (f) {
|
437
|
+
createColumns(f);
|
438
|
+
return this;
|
439
|
+
};
|
440
|
+
|
441
|
+
return chart;
|
442
|
+
};
|
443
|
+
|
444
|
+
//inheritance
|
445
|
+
var F = function() {};
|
446
|
+
F.prototype = Raphael.g;
|
447
|
+
Linechart.prototype = new F;
|
448
|
+
|
449
|
+
/*
|
450
|
+
* linechart method on paper
|
451
|
+
*/
|
452
|
+
/*\
|
453
|
+
* Paper.linechart
|
454
|
+
[ method ]
|
455
|
+
**
|
456
|
+
* Creates a line chart
|
457
|
+
**
|
458
|
+
> Parameters
|
459
|
+
**
|
460
|
+
- x (number) x coordinate of the chart
|
461
|
+
- y (number) y coordinate of the chart
|
462
|
+
- width (number) width of the chart (including the axis)
|
463
|
+
- height (number) height of the chart (including the axis)
|
464
|
+
- valuesx (array) values to plot on axis x
|
465
|
+
- valuesy (array) values to plot on axis y
|
466
|
+
- opts (object) options for the chart
|
467
|
+
o {
|
468
|
+
o gutter (number) distance between symbols on the chart
|
469
|
+
o symbol (string) (array) symbol to be plotted as nodes of the chart, if array are passed symbols are printed iteratively. Currently `'circle'` and `''` (no symbol) are the only supported options.
|
470
|
+
o width (number) controls the size of the plotted symbol. Also controls the thickness of the line using a formula stroke-width=width/2. This option is likely to change in the future versions of g.raphael.
|
471
|
+
o colors (array) colors to plot data series. Raphael default colors are used if not passed
|
472
|
+
o shade (boolean) whether or not to plot a shade of the chart [default: false]. Currently only a shade between the line and x axis is supported.
|
473
|
+
o nostroke (boolean) whether or not to plot lines [default: false]. Only practical when shade is enabled.
|
474
|
+
o dash (string) changes display of the line from continues to dashed or dotted (Possible values are the same as stroke-dasharray attribute, see @Element.attr).
|
475
|
+
o smooth (boolean) changes display of the line from point-to-point straight lines to curves (type C, see @Paper.path).
|
476
|
+
o axis (string) Which axes should be renedered. String of four values evaluated in order `'top right bottom left'` e.g. `'0 0 1 1'`.
|
477
|
+
o axisxstep (number) distance between values on axis X
|
478
|
+
o axisystep (number) distance between values on axis Y
|
479
|
+
o }
|
480
|
+
**
|
481
|
+
= (object) path element of the popup
|
482
|
+
> Usage
|
483
|
+
| r.linechart(0, 0, 99, 99, [1,2,3,4,5], [[1,2,3,4,5], [1,3,9,16,25], [100,50,25,12,6]], {smooth: true, colors: ['#F00', '#0F0', '#FF0'], symbol: 'circle'});
|
484
|
+
\*/
|
485
|
+
Raphael.fn.linechart = function(x, y, width, height, valuesx, valuesy, opts) {
|
486
|
+
return new Linechart(this, x, y, width, height, valuesx, valuesy, opts);
|
487
|
+
}
|
488
|
+
|
489
|
+
})();
|