5 Provides HTML Canvas Renderer. This is supported under:
10 - IE 6 (via VML Emulation)
12 It uses DIVs for labels.
16 Copyright 2005,2006 (c) Alastair Tse <alastair^liquidx.net>
17 For use under the BSD license. <http://www.liquidx.net/plotkit>
20 // --------------------------------------------------------------------
21 // Check required components
22 // --------------------------------------------------------------------
25 if (typeof(PlotKit
.Base
) == 'undefined')
31 throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Base,Layout}"
35 // ------------------------------------------------------------------------
36 // Defines the renderer class
37 // ------------------------------------------------------------------------
39 if (typeof(PlotKit
.CanvasRenderer
) == 'undefined') {
40 PlotKit
.CanvasRenderer
= {};
43 PlotKit
.CanvasRenderer
.NAME
= "PlotKit.CanvasRenderer";
44 PlotKit
.CanvasRenderer
.VERSION
= PlotKit
.VERSION
;
46 PlotKit
.CanvasRenderer
.__repr__
= function() {
47 return "[" + this.NAME
+ " " + this.VERSION
+ "]";
50 PlotKit
.CanvasRenderer
.toString
= function() {
51 return this.__repr__();
54 PlotKit
.CanvasRenderer
= function(element
, layout
, options
) {
55 if (arguments
.length
> 0)
56 this.__init__(element
, layout
, options
);
59 PlotKit
.CanvasRenderer
.prototype.__init__
= function(element
, layout
, options
) {
60 var isNil
= MochiKit
.Base
.isUndefinedOrNull
;
61 var Color
= MochiKit
.Color
.Color
;
65 "drawBackground": true,
66 "backgroundColor": Color
.whiteColor(),
67 "colorScheme": PlotKit
.Base
.palette(PlotKit
.Base
.baseColors()[0]),
68 "strokeColor": Color
.whiteColor(),
69 "strokeColorTransform": "asStrokeColor",
75 "axisLineColor": Color
.blackColor(),
78 "axisLabelColor": Color
.blackColor(),
79 "axisLabelFont": "Arial",
80 "axisLabelFontSize": 9,
85 MochiKit
.Base
.update(this.options
, options
? options
: {});
88 this.element
= MochiKit
.DOM
.getElement(element
);
89 this.container
= this.element
.parentNode
;
91 // Stuff relating to Canvas on IE support
92 this.isIE
= PlotKit
.Base
.excanvasSupported();
94 if (this.isIE
&& !isNil(G_vmlCanvasManager
)) {
97 this.renderDelay
= null;
98 this.clearDelay
= null;
99 this.element
= G_vmlCanvasManager
.initElement(this.element
);
102 this.height
= this.element
.height
;
103 this.width
= this.element
.width
;
105 // --- check whether everything is ok before we return
107 if (isNil(this.element
))
108 throw "CanvasRenderer() - passed canvas is not found";
110 if (!this.isIE
&& !(PlotKit
.CanvasRenderer
.isSupported(this.element
)))
111 throw "CanvasRenderer() - Canvas is not supported.";
113 if (isNil(this.container
) || (this.container
.nodeName
.toLowerCase() != "div"))
114 throw "CanvasRenderer() - <canvas> needs to be enclosed in <div>";
117 this.xlabels
= new Array();
118 this.ylabels
= new Array();
119 this.isFirstRender
= true;
122 x
: this.options
.yAxisLabelWidth
+ 2 * this.options
.axisTickSize
,
125 this.area
.w
= this.width
- this.area
.x
- this.options
.rightGap
;
126 this.area
.h
= this.height
- this.options
.axisLabelFontSize
-
127 2 * this.options
.axisTickSize
;
129 MochiKit
.DOM
.updateNodeAttributes(this.container
,
130 {"style":{ "position": "relative", "width": this.width
+ "px"}});
134 PlotKit
.CanvasRenderer
.prototype._renderLineAxis
= function() {
139 PlotKit
.CanvasRenderer
.prototype._renderAxis
= function() {
140 if (!this.options
.drawXAxis
&& !this.options
.drawYAxis
)
143 var context
= this.element
.getContext("2d");
145 var labelStyle
= {"style":
146 {"position": "absolute",
147 "fontSize": this.options
.axisLabelFontSize
+ "px",
149 "color": this.options
.axisLabelColor
.toRGBString(),
150 "width": this.options
.axisLabelWidth
+ "px",
157 context
.strokeStyle
= this.options
.axisLineColor
.toRGBString();
158 context
.lineWidth
= this.options
.axisLineWidth
;
161 if (this.options
.drawYAxis
) {
162 if (this.layout
.yticks
) {
163 var drawTick
= function(tick
) {
164 if (typeof(tick
) == "function") return;
166 var y
= this.area
.y
+ tick
[0] * this.area
.h
;
168 context
.moveTo(x
, y
);
169 context
.lineTo(x
- this.options
.axisTickSize
, y
);
173 var label
= DIV(labelStyle
, tick
[1]);
174 var top
= (y
- this.options
.axisLabelFontSize
/ 2);
175 if (top
< 0) top
= 0;
177 if (top
+ this.options
.axisLabelFontSize
+ 3 > this.height
) {
178 label
.style
.bottom
= "0px";
180 label
.style
.top
= top
+ "px";
182 label
.style
.left
= "0px";
183 label
.style
.textAlign
= "right";
184 label
.style
.width
= this.options
.yAxisLabelWidth
+ "px";
185 MochiKit
.DOM
.appendChildNodes(this.container
, label
);
186 this.ylabels
.push(label
);
189 MochiKit
.Iter
.forEach(this.layout
.yticks
, bind(drawTick
, this));
191 // The lowest tick on the y-axis often overlaps with the leftmost
192 // tick on the x-axis. Shift the bottom tick up a little bit to
193 // compensate if necessary.
194 var bottomTick
= this.ylabels
[0];
195 var fontSize
= this.options
.axisLabelFontSize
;
196 var bottom
= parseInt(bottomTick
.style
.top
) + fontSize
;
197 if (bottom
> this.height
- fontSize
) {
198 bottomTick
.style
.top
= (parseInt(bottomTick
.style
.top
) -
199 fontSize
/ 2) + "px";
204 context
.moveTo(this.area
.x
, this.area
.y
);
205 context
.lineTo(this.area
.x
, this.area
.y
+ this.area
.h
);
210 if (this.options
.drawXAxis
) {
211 if (this.layout
.xticks
) {
212 var drawTick
= function(tick
) {
213 if (typeof(dataset
) == "function") return;
215 var x
= this.area
.x
+ tick
[0] * this.area
.w
;
216 var y
= this.area
.y
+ this.area
.h
;
218 context
.moveTo(x
, y
);
219 context
.lineTo(x
, y
+ this.options
.axisTickSize
);
223 var label
= DIV(labelStyle
, tick
[1]);
224 label
.style
.textAlign
= "center";
225 label
.style
.bottom
= "0px";
227 var left
= (x
- this.options
.axisLabelWidth
/2);
228 if (left
+ this.options
.axisLabelWidth
> this.width
) {
229 left
= this.width
- this.options
.xAxisLabelWidth
;
230 label
.style
.textAlign
= "right";
234 label
.style
.textAlign
= "left";
237 label
.style
.left
= left
+ "px";
238 label
.style
.width
= this.options
.xAxisLabelWidth
+ "px";
239 MochiKit
.DOM
.appendChildNodes(this.container
, label
);
240 this.xlabels
.push(label
);
243 MochiKit
.Iter
.forEach(this.layout
.xticks
, bind(drawTick
, this));
247 context
.moveTo(this.area
.x
, this.area
.y
+ this.area
.h
);
248 context
.lineTo(this.area
.x
+ this.area
.w
, this.area
.y
+ this.area
.h
);
257 PlotKit
.CanvasRenderer
.prototype.clear
= function() {
259 // VML takes a while to start up, so we just poll every this.IEDelay
261 if (this.clearDelay
) {
262 this.clearDelay
.cancel();
263 this.clearDelay
= null;
265 var context
= this.element
.getContext("2d");
268 this.isFirstRender
= false;
269 this.clearDelay
= MochiKit
.Async
.wait(this.IEDelay
);
270 this.clearDelay
.addCallback(bind(this.clear
, this));
275 var context
= this.element
.getContext("2d");
276 context
.clearRect(0, 0, this.width
, this.height
);
278 MochiKit
.Iter
.forEach(this.xlabels
, MochiKit
.DOM
.removeElement
);
279 MochiKit
.Iter
.forEach(this.ylabels
, MochiKit
.DOM
.removeElement
);
280 this.xlabels
= new Array();
281 this.ylabels
= new Array();
284 // ----------------------------------------------------------------
285 // Everything below here is experimental and undocumented.
286 // ----------------------------------------------------------------
289 PlotKit
.CanvasRenderer
.isSupported
= function(canvasName
) {
292 if (MochiKit
.Base
.isUndefinedOrNull(canvasName
))
293 canvas
= MochiKit
.DOM
.CANVAS({});
295 canvas
= MochiKit
.DOM
.getElement(canvasName
);
296 var context
= canvas
.getContext("2d");
299 var ie
= navigator
.appVersion
.match(/MSIE (\d\.\d)/);
300 var opera
= (navigator
.userAgent
.toLowerCase().indexOf("opera") != -1);
301 if ((!ie
) || (ie
[1] < 6) || (opera
))
308 // Namespace Iniitialisation
311 PlotKit
.Canvas
.CanvasRenderer
= PlotKit
.CanvasRenderer
;
313 PlotKit
.Canvas
.EXPORT
= [
317 PlotKit
.Canvas
.EXPORT_OK
= [
321 PlotKit
.Canvas
.__new__
= function() {
322 var m
= MochiKit
.Base
;
324 m
.nameFunctions(this);
327 ":common": this.EXPORT
,
328 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
332 PlotKit
.Canvas
.__new__();
333 MochiKit
.Base
._exportSymbols(this, PlotKit
.Canvas
);