fix #8056 - more refinements to checking data
[g.raphael] / g.dot.js
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         var colorValue = function (value, total, s, b) {
9             return 'hsb(' + [Math.min((1 - value / total) * .4, 1), s || .75, b || .75] + ')';
10         };
11
12     function Dotchart(paper, x, y, width, height, valuesx, valuesy, size, opts) {
13         
14         var chartinst = this;
15         
16         function drawAxis(ax) {
17             +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));
18             +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));
19             +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));
20             +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));
21         }
22
23         opts = opts || {};
24         var xdim = chartinst.snapEnds(Math.min.apply(Math, valuesx), Math.max.apply(Math, valuesx), valuesx.length - 1),
25             minx = xdim.from,
26             maxx = xdim.to,
27             gutter = opts.gutter || 10,
28             ydim = chartinst.snapEnds(Math.min.apply(Math, valuesy), Math.max.apply(Math, valuesy), valuesy.length - 1),
29             miny = ydim.from,
30             maxy = ydim.to,
31             len = Math.max(valuesx.length, valuesy.length, size.length),
32             symbol = paper[opts.symbol] || "circle",
33             res = paper.set(),
34             series = paper.set(),
35             max = opts.max || 100,
36             top = Math.max.apply(Math, size),
37             R = [],
38             k = Math.sqrt(top / Math.PI) * 2 / max;
39
40         for (var i = 0; i < len; i++) {
41             R[i] = Math.min(Math.sqrt(size[i] / Math.PI) * 2 / k, max);
42         }
43
44         gutter = Math.max.apply(Math, R.concat(gutter));
45
46         var axis = paper.set(),
47             maxR = Math.max.apply(Math, R);
48
49         if (opts.axis) {
50             var ax = (opts.axis + "").split(/[,\s]+/);
51
52             drawAxis.call(chartinst, ax);
53
54             var g = [], b = [];
55
56             for (var i = 0, ii = ax.length; i < ii; i++) {
57                 var bb = ax[i].all ? ax[i].all.getBBox()[["height", "width"][i % 2]] : 0;
58
59                 g[i] = bb + gutter;
60                 b[i] = bb;
61             }
62
63             gutter = Math.max.apply(Math, g.concat(gutter));
64
65             for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
66                 ax[i].remove();
67                 ax[i] = 1;
68             }
69
70             drawAxis.call(chartinst, ax);
71
72             for (var i = 0, ii = ax.length; i < ii; i++) if (ax[i].all) {
73                 axis.push(ax[i].all);
74             }
75
76             res.axis = axis;
77         }
78
79         var kx = (width - gutter * 2) / ((maxx - minx) || 1),
80             ky = (height - gutter * 2) / ((maxy - miny) || 1);
81
82         for (var i = 0, ii = valuesy.length; i < ii; i++) {
83             var sym = paper.raphael.is(symbol, "array") ? symbol[i] : symbol,
84                 X = x + gutter + (valuesx[i] - minx) * kx,
85                 Y = y + height - gutter - (valuesy[i] - miny) * ky;
86
87             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" }));
88         }
89
90         var covers = paper.set();
91
92         for (var i = 0, ii = valuesy.length; i < ii; i++) {
93             var X = x + gutter + (valuesx[i] - minx) * kx,
94                 Y = y + height - gutter - (valuesy[i] - miny) * ky;
95
96             covers.push(paper.circle(X, Y, maxR).attr(chartinst.shim));
97             opts.href && opts.href[i] && covers[i].attr({href: opts.href[i]});
98             covers[i].r = +R[i].toFixed(3);
99             covers[i].x = +X.toFixed(3);
100             covers[i].y = +Y.toFixed(3);
101             covers[i].X = valuesx[i];
102             covers[i].Y = valuesy[i];
103             covers[i].value = size[i] || 0;
104             covers[i].dot = series[i];
105         }
106
107         res.covers = covers;
108         res.series = series;
109         res.push(series, axis, covers);
110
111         res.hover = function (fin, fout) {
112             covers.mouseover(fin).mouseout(fout);
113             return this;
114         };
115
116         res.click = function (f) {
117             covers.click(f);
118             return this;
119         };
120
121         res.each = function (f) {
122             if (!paper.raphael.is(f, "function")) {
123                 return this;
124             }
125
126             for (var i = covers.length; i--;) {
127                 f.call(covers[i]);
128             }
129
130             return this;
131         };
132
133         res.href = function (map) {
134             var cover;
135
136             for (var i = covers.length; i--;) {
137                 cover = covers[i];
138
139                 if (cover.X == map.x && cover.Y == map.y && cover.value == map.value) {
140                     cover.attr({href: map.href});
141                 }
142             }
143         };
144         return res;
145     };
146     
147     //inheritance
148     var F = function() {};
149     F.prototype = Raphael.g
150     Dotchart.prototype = new F;
151     
152     //public
153     Raphael.fn.dotchart = function(x, y, width, height, valuesx, valuesy, size, opts) {
154         return new Dotchart(this, x, y, width, height, valuesx, valuesy, size, opts);
155     }
156 })();