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.
11 Copyright 2005,2006 (c) Alastair Tse <alastair^liquidx.net>
12 For use under the BSD license. <http://www.liquidx.net/plotkit>
17 if (typeof(PlotKit
.Base
) == 'undefined')
23 throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Base"
26 // --------------------------------------------------------------------
27 // Start of Layout definition
28 // --------------------------------------------------------------------
30 if (typeof(PlotKit
.Layout
) == 'undefined') {
34 PlotKit
.Layout
.NAME
= "PlotKit.Layout";
35 PlotKit
.Layout
.VERSION
= PlotKit
.VERSION
;
37 PlotKit
.Layout
.__repr__
= function() {
38 return "[" + this.NAME
+ " " + this.VERSION
+ "]";
41 PlotKit
.Layout
.toString
= function() {
42 return this.__repr__();
45 // --------------------------------------------------------------------
46 // Start of Layout definition
47 // --------------------------------------------------------------------
49 PlotKit
.Layout
= function(style
, options
) {
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.)
60 // valid external options : TODO: input verification
62 MochiKit
.Base
.update(this.options
, options
? options
: {});
66 this.xscale
= null; // val -> pos factor (eg, xval * xscale = xpos)
72 this.points
= new Array(); // array of points to plot for line plots
74 this.xticks
= new Array();
75 this.yticks
= new Array();
78 this.datasets
= new Array();
83 this.hitTestCache
= {x2maxy
: null};
87 // --------------------------------------------------------------------
88 // Dataset Manipulation
89 // --------------------------------------------------------------------
92 PlotKit
.Layout
.prototype.addDataset
= function(setname
, set_xy
) {
93 this.datasets
[setname
] = set_xy
;
96 PlotKit
.Layout
.prototype.removeDataset
= function(setname
, set_xy
) {
97 delete this.datasets
[setname
];
100 // --------------------------------------------------------------------
101 // Evaluates the layout for the current data and style.
102 // --------------------------------------------------------------------
104 PlotKit
.Layout
.prototype.evaluate
= function() {
105 this._evaluateLimits();
106 this._evaluateScales();
107 if (this.style
== "line") {
108 this._evaluateLineCharts();
109 this._evaluateLineTicks();
116 // --------------------------------------------------------------------
117 // START Internal Functions
118 // --------------------------------------------------------------------
120 PlotKit
.Layout
.prototype._evaluateLimits
= function() {
121 // take all values from all datasets and find max and min
122 var map
= PlotKit
.Base
.map
;
123 var items
= PlotKit
.Base
.items
;
124 var itemgetter
= MochiKit
.Base
.itemgetter
;
125 var collapse
= PlotKit
.Base
.collapse
;
126 var listMin
= MochiKit
.Base
.listMin
;
127 var listMax
= MochiKit
.Base
.listMax
;
128 var isNil
= MochiKit
.Base
.isUndefinedOrNull
;
131 var all
= collapse(map(itemgetter(1), items(this.datasets
)));
132 if (isNil(this.options
.xAxis
)) {
133 if (this.options
.xOriginIsZero
)
136 this.minxval
= listMin(map(parseFloat
, map(itemgetter(0), all
)));
138 this.maxxval
= listMax(map(parseFloat
, map(itemgetter(0), all
)));
141 this.minxval
= this.options
.xAxis
[0];
142 this.maxxval
= this.options
.xAxis
[1];
143 this.xscale
= this.maxval
- this.minxval
;
146 if (isNil(this.options
.yAxis
)) {
147 if (this.options
.yOriginIsZero
)
150 this.minyval
= listMin(map(parseFloat
, map(itemgetter(1), all
)));
152 this.maxyval
= listMax(map(parseFloat
, map(itemgetter(1), all
)));
155 this.minyval
= this.options
.yAxis
[0];
156 this.maxyval
= this.options
.yAxis
[1];
157 this.yscale
= this.maxyval
- this.minyval
;
162 PlotKit
.Layout
.prototype._evaluateScales
= function() {
163 this.xrange
= this.maxxval
- this.minxval
;
164 if (this.xrange
== 0)
167 this.xscale
= 1/this.xrange
;
169 this.yrange
= this.maxyval
- this.minyval
;
170 if (this.yrange
== 0)
173 this.yscale
= 1/this.yrange
;
177 // Create the line charts
178 PlotKit
.Layout
.prototype._evaluateLineCharts
= function() {
179 var items
= PlotKit
.Base
.items
;
181 var setCount
= items(this.datasets
).length
;
184 this.points
= new Array();
186 for (var setName
in this.datasets
) {
187 var dataset
= this.datasets
[setName
];
188 if (PlotKit
.Base
.isFuncLike(dataset
)) continue;
189 dataset
.sort(function(a
, b
) { return compare(parseFloat(a
[0]), parseFloat(b
[0])); });
190 for (var j
= 0; j
< dataset
.length
; j
++) {
191 var item
= dataset
[j
];
193 x
: ((parseFloat(item
[0]) - this.minxval
) * this.xscale
),
194 y
: 1.0 - ((parseFloat(item
[1]) - this.minyval
) * this.yscale
),
195 xval
: parseFloat(item
[0]),
196 yval
: parseFloat(item
[1]),
200 // limit the x, y values so they do not overdraw
201 if (point
.y
<= 0.0) {
204 if (point
.y
>= 1.0) {
207 if ((point
.x
>= 0.0) && (point
.x
<= 1.0)) {
208 this.points
.push(point
);
216 PlotKit
.Layout
.prototype._evaluateLineTicksForXAxis
= function() {
217 var isNil
= MochiKit
.Base
.isUndefinedOrNull
;
219 this.xticks
= new Array();
220 var makeTicks
= function(tick
) {
221 var label
= tick
.label
;
223 label
= tick
.v
.toString();
224 var pos
= this.xscale
* (tick
.v
- this.minxval
);
225 if ((pos
>= 0.0) && (pos
<= 1.0)) {
226 this.xticks
.push([pos
, label
]);
229 MochiKit
.Iter
.forEach(this.options
.xTicks
, bind(makeTicks
, this));
232 PlotKit
.Layout
.prototype._evaluateLineTicksForYAxis
= function() {
233 var isNil
= MochiKit
.Base
.isUndefinedOrNull
;
235 this.yticks
= new Array();
236 var makeTicks
= function(tick
) {
237 var label
= tick
.label
;
239 label
= tick
.v
.toString();
240 var pos
= 1.0 - (this.yscale
* (tick
.v
- this.minyval
));
241 if ((pos
>= 0.0) && (pos
<= 1.0)) {
242 this.yticks
.push([pos
, label
]);
245 MochiKit
.Iter
.forEach(this.options
.yTicks
, bind(makeTicks
, this));
248 PlotKit
.Layout
.prototype._evaluateLineTicks
= function() {
249 this._evaluateLineTicksForXAxis();
250 this._evaluateLineTicksForYAxis();
254 // --------------------------------------------------------------------
255 // END Internal Functions
256 // --------------------------------------------------------------------
259 // Namespace Iniitialisation
261 PlotKit
.LayoutModule
= {};
262 PlotKit
.LayoutModule
.Layout
= PlotKit
.Layout
;
264 PlotKit
.LayoutModule
.EXPORT
= [
268 PlotKit
.LayoutModule
.EXPORT_OK
= [];
270 PlotKit
.LayoutModule
.__new__
= function() {
271 var m
= MochiKit
.Base
;
273 m
.nameFunctions(this);
276 ":common": this.EXPORT
,
277 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
281 PlotKit
.LayoutModule
.__new__();
282 MochiKit
.Base
._exportSymbols(this, PlotKit
.LayoutModule
);