Commit | Line | Data |
---|---|---|
6a1aa64f DV |
1 | /* |
2 | PlotKit Layout | |
3 | ============== | |
4 | ||
5 | Handles laying out data on to a virtual canvas square canvas between 0.0 | |
6 | and 1.0. If you want to add new chart/plot types such as point plots, | |
7 | you need to add them here. | |
8 | ||
9 | Copyright | |
10 | --------- | |
11 | Copyright 2005,2006 (c) Alastair Tse <alastair^liquidx.net> | |
12 | For use under the BSD license. <http://www.liquidx.net/plotkit> | |
13 | ||
14 | */ | |
15 | ||
16 | try { | |
17 | if (typeof(PlotKit.Base) == 'undefined') | |
18 | { | |
19 | throw "" | |
20 | } | |
21 | } | |
22 | catch (e) { | |
23 | throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Base" | |
24 | } | |
25 | ||
26 | // -------------------------------------------------------------------- | |
27 | // Start of Layout definition | |
28 | // -------------------------------------------------------------------- | |
29 | ||
30 | if (typeof(PlotKit.Layout) == 'undefined') { | |
31 | PlotKit.Layout = {}; | |
32 | } | |
33 | ||
34 | PlotKit.Layout.NAME = "PlotKit.Layout"; | |
35 | PlotKit.Layout.VERSION = PlotKit.VERSION; | |
36 | ||
37 | PlotKit.Layout.__repr__ = function() { | |
38 | return "[" + this.NAME + " " + this.VERSION + "]"; | |
39 | }; | |
40 | ||
41 | PlotKit.Layout.toString = function() { | |
42 | return this.__repr__(); | |
43 | } | |
44 | ||
6a1aa64f DV |
45 | // -------------------------------------------------------------------- |
46 | // Start of Layout definition | |
47 | // -------------------------------------------------------------------- | |
48 | ||
49 | PlotKit.Layout = function(style, options) { | |
50 | ||
51 | this.options = { | |
6a1aa64f DV |
52 | "xOriginIsZero": true, |
53 | "yOriginIsZero": true, | |
54 | "xAxis": null, // [xmin, xmax] | |
55 | "yAxis": null, // [ymin, ymax] | |
56 | "xTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.) | |
57 | "yTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.) | |
6a1aa64f DV |
58 | }; |
59 | ||
60 | // valid external options : TODO: input verification | |
61 | this.style = style; | |
62 | MochiKit.Base.update(this.options, options ? options : {}); | |
63 | ||
b64a4f1a DV |
64 | this.minxval = 0; |
65 | this.maxxval = null; | |
66 | this.xscale = null; // val -> pos factor (eg, xval * xscale = xpos) | |
6a1aa64f | 67 | |
b64a4f1a DV |
68 | this.minyval = 0; |
69 | this.maxyval = null; | |
70 | this.yscale = null; | |
6a1aa64f | 71 | |
6a1aa64f | 72 | this.points = new Array(); // array of points to plot for line plots |
6a1aa64f DV |
73 | |
74 | this.xticks = new Array(); | |
75 | this.yticks = new Array(); | |
76 | ||
77 | // internal states | |
78 | this.datasets = new Array(); | |
79 | this.minxdelta = 0; | |
80 | this.xrange = 1; | |
81 | this.yrange = 1; | |
6a1aa64f DV |
82 | }; |
83 | ||
84 | // -------------------------------------------------------------------- | |
85 | // Dataset Manipulation | |
86 | // -------------------------------------------------------------------- | |
87 | ||
88 | ||
89 | PlotKit.Layout.prototype.addDataset = function(setname, set_xy) { | |
90 | this.datasets[setname] = set_xy; | |
91 | }; | |
92 | ||
6a1aa64f DV |
93 | // -------------------------------------------------------------------- |
94 | // Evaluates the layout for the current data and style. | |
95 | // -------------------------------------------------------------------- | |
96 | ||
97 | PlotKit.Layout.prototype.evaluate = function() { | |
98 | this._evaluateLimits(); | |
0bece959 DV |
99 | this._evaluateLineCharts(); |
100 | this._evaluateLineTicks(); | |
6a1aa64f DV |
101 | }; |
102 | ||
103 | ||
6a1aa64f DV |
104 | // -------------------------------------------------------------------- |
105 | // START Internal Functions | |
106 | // -------------------------------------------------------------------- | |
107 | ||
108 | PlotKit.Layout.prototype._evaluateLimits = function() { | |
109 | // take all values from all datasets and find max and min | |
110 | var map = PlotKit.Base.map; | |
111 | var items = PlotKit.Base.items; | |
112 | var itemgetter = MochiKit.Base.itemgetter; | |
113 | var collapse = PlotKit.Base.collapse; | |
114 | var listMin = MochiKit.Base.listMin; | |
115 | var listMax = MochiKit.Base.listMax; | |
116 | var isNil = MochiKit.Base.isUndefinedOrNull; | |
117 | ||
6a1aa64f | 118 | var all = collapse(map(itemgetter(1), items(this.datasets))); |
0bece959 DV |
119 | this.minxval = listMin(map(parseFloat, map(itemgetter(0), all))); |
120 | this.maxxval = listMax(map(parseFloat, map(itemgetter(0), all))); | |
6a1aa64f | 121 | this.xrange = this.maxxval - this.minxval; |
0bece959 | 122 | this.xscale = (this.xrange != 0 ? 1/this.xrange : 1.0); |
6a1aa64f | 123 | |
0bece959 DV |
124 | this.minyval = this.options.yAxis[0]; |
125 | this.maxyval = this.options.yAxis[1]; | |
6a1aa64f | 126 | this.yrange = this.maxyval - this.minyval; |
0bece959 | 127 | this.yscale = (this.yrange != 0 ? 1/this.yrange : 1.0); |
6a1aa64f DV |
128 | }; |
129 | ||
6a1aa64f DV |
130 | // Create the line charts |
131 | PlotKit.Layout.prototype._evaluateLineCharts = function() { | |
132 | var items = PlotKit.Base.items; | |
133 | ||
134 | var setCount = items(this.datasets).length; | |
135 | ||
136 | // add all the rects | |
137 | this.points = new Array(); | |
138 | var i = 0; | |
139 | for (var setName in this.datasets) { | |
140 | var dataset = this.datasets[setName]; | |
141 | if (PlotKit.Base.isFuncLike(dataset)) continue; | |
142 | dataset.sort(function(a, b) { return compare(parseFloat(a[0]), parseFloat(b[0])); }); | |
143 | for (var j = 0; j < dataset.length; j++) { | |
144 | var item = dataset[j]; | |
145 | var point = { | |
146 | x: ((parseFloat(item[0]) - this.minxval) * this.xscale), | |
147 | y: 1.0 - ((parseFloat(item[1]) - this.minyval) * this.yscale), | |
148 | xval: parseFloat(item[0]), | |
149 | yval: parseFloat(item[1]), | |
150 | name: setName | |
151 | }; | |
152 | ||
153 | // limit the x, y values so they do not overdraw | |
154 | if (point.y <= 0.0) { | |
155 | point.y = 0.0; | |
156 | } | |
157 | if (point.y >= 1.0) { | |
158 | point.y = 1.0; | |
159 | } | |
160 | if ((point.x >= 0.0) && (point.x <= 1.0)) { | |
161 | this.points.push(point); | |
162 | } | |
163 | } | |
164 | i++; | |
165 | } | |
166 | }; | |
167 | ||
6a1aa64f DV |
168 | |
169 | PlotKit.Layout.prototype._evaluateLineTicksForXAxis = function() { | |
170 | var isNil = MochiKit.Base.isUndefinedOrNull; | |
171 | ||
9f5cb229 DV |
172 | this.xticks = new Array(); |
173 | var makeTicks = function(tick) { | |
174 | var label = tick.label; | |
175 | if (isNil(label)) | |
176 | label = tick.v.toString(); | |
177 | var pos = this.xscale * (tick.v - this.minxval); | |
178 | if ((pos >= 0.0) && (pos <= 1.0)) { | |
179 | this.xticks.push([pos, label]); | |
6a1aa64f | 180 | } |
9f5cb229 DV |
181 | }; |
182 | MochiKit.Iter.forEach(this.options.xTicks, bind(makeTicks, this)); | |
6a1aa64f DV |
183 | }; |
184 | ||
185 | PlotKit.Layout.prototype._evaluateLineTicksForYAxis = function() { | |
186 | var isNil = MochiKit.Base.isUndefinedOrNull; | |
187 | ||
9f5cb229 DV |
188 | this.yticks = new Array(); |
189 | var makeTicks = function(tick) { | |
190 | var label = tick.label; | |
191 | if (isNil(label)) | |
192 | label = tick.v.toString(); | |
193 | var pos = 1.0 - (this.yscale * (tick.v - this.minyval)); | |
194 | if ((pos >= 0.0) && (pos <= 1.0)) { | |
195 | this.yticks.push([pos, label]); | |
196 | } | |
197 | }; | |
198 | MochiKit.Iter.forEach(this.options.yTicks, bind(makeTicks, this)); | |
6a1aa64f DV |
199 | }; |
200 | ||
201 | PlotKit.Layout.prototype._evaluateLineTicks = function() { | |
202 | this._evaluateLineTicksForXAxis(); | |
203 | this._evaluateLineTicksForYAxis(); | |
204 | }; | |
205 | ||
6a1aa64f DV |
206 | |
207 | // -------------------------------------------------------------------- | |
208 | // END Internal Functions | |
209 | // -------------------------------------------------------------------- | |
210 | ||
211 | ||
212 | // Namespace Iniitialisation | |
213 | ||
214 | PlotKit.LayoutModule = {}; | |
215 | PlotKit.LayoutModule.Layout = PlotKit.Layout; | |
216 | ||
217 | PlotKit.LayoutModule.EXPORT = [ | |
218 | "Layout" | |
219 | ]; | |
220 | ||
221 | PlotKit.LayoutModule.EXPORT_OK = []; | |
222 | ||
223 | PlotKit.LayoutModule.__new__ = function() { | |
224 | var m = MochiKit.Base; | |
225 | ||
226 | m.nameFunctions(this); | |
227 | ||
228 | this.EXPORT_TAGS = { | |
229 | ":common": this.EXPORT, | |
230 | ":all": m.concat(this.EXPORT, this.EXPORT_OK) | |
231 | }; | |
232 | }; | |
233 | ||
234 | PlotKit.LayoutModule.__new__(); | |
235 | MochiKit.Base._exportSymbols(this, PlotKit.LayoutModule); | |
236 | ||
237 |