1 PlotKit
.CanvasRenderer
= function(element
, layout
, options
) {
2 if (arguments
.length
> 0)
3 this.__init__(element
, layout
, options
);
6 PlotKit
.CanvasRenderer
.prototype.__init__
= function(element
, layout
, options
) {
7 var isNil
= MochiKit
.Base
.isUndefinedOrNull
;
8 var Color
= MochiKit
.Color
.Color
;
15 "axisLineColor": Color
.blackColor(),
18 "axisLabelColor": Color
.blackColor(),
19 "axisLabelFont": "Arial",
20 "axisLabelFontSize": 9,
23 MochiKit
.Base
.update(this.options
, options
? options
: {});
26 this.element
= MochiKit
.DOM
.getElement(element
);
27 this.container
= this.element
.parentNode
;
29 // Stuff relating to Canvas on IE support
30 this.isIE
= PlotKit
.Base
.excanvasSupported();
32 if (this.isIE
&& !isNil(G_vmlCanvasManager
)) {
35 this.renderDelay
= null;
36 this.clearDelay
= null;
37 this.element
= G_vmlCanvasManager
.initElement(this.element
);
40 this.height
= this.element
.height
;
41 this.width
= this.element
.width
;
43 // --- check whether everything is ok before we return
45 if (isNil(this.element
))
46 throw "CanvasRenderer() - passed canvas is not found";
48 if (!this.isIE
&& !(PlotKit
.CanvasRenderer
.isSupported(this.element
)))
49 throw "CanvasRenderer() - Canvas is not supported.";
51 if (isNil(this.container
) || (this.container
.nodeName
.toLowerCase() != "div"))
52 throw "CanvasRenderer() - <canvas> needs to be enclosed in <div>";
55 this.xlabels
= new Array();
56 this.ylabels
= new Array();
59 x
: this.options
.yAxisLabelWidth
+ 2 * this.options
.axisTickSize
,
62 this.area
.w
= this.width
- this.area
.x
- this.options
.rightGap
;
63 this.area
.h
= this.height
- this.options
.axisLabelFontSize
-
64 2 * this.options
.axisTickSize
;
66 MochiKit
.DOM
.updateNodeAttributes(this.container
,
67 {"style":{ "position": "relative", "width": this.width
+ "px"}});
71 PlotKit
.CanvasRenderer
.prototype._renderLineAxis
= function() {
76 PlotKit
.CanvasRenderer
.prototype._renderAxis
= function() {
77 if (!this.options
.drawXAxis
&& !this.options
.drawYAxis
)
80 var context
= this.element
.getContext("2d");
82 var labelStyle
= {"style":
83 {"position": "absolute",
84 "fontSize": this.options
.axisLabelFontSize
+ "px",
86 "color": this.options
.axisLabelColor
.toRGBString(),
87 "width": this.options
.axisLabelWidth
+ "px",
94 context
.strokeStyle
= this.options
.axisLineColor
.toRGBString();
95 context
.lineWidth
= this.options
.axisLineWidth
;
98 if (this.options
.drawYAxis
) {
99 if (this.layout
.yticks
) {
100 var drawTick
= function(tick
) {
101 if (typeof(tick
) == "function") return;
103 var y
= this.area
.y
+ tick
[0] * this.area
.h
;
105 context
.moveTo(x
, y
);
106 context
.lineTo(x
- this.options
.axisTickSize
, y
);
110 var label
= DIV(labelStyle
, tick
[1]);
111 var top
= (y
- this.options
.axisLabelFontSize
/ 2);
112 if (top
< 0) top
= 0;
114 if (top
+ this.options
.axisLabelFontSize
+ 3 > this.height
) {
115 label
.style
.bottom
= "0px";
117 label
.style
.top
= top
+ "px";
119 label
.style
.left
= "0px";
120 label
.style
.textAlign
= "right";
121 label
.style
.width
= this.options
.yAxisLabelWidth
+ "px";
122 MochiKit
.DOM
.appendChildNodes(this.container
, label
);
123 this.ylabels
.push(label
);
126 MochiKit
.Iter
.forEach(this.layout
.yticks
, bind(drawTick
, this));
128 // The lowest tick on the y-axis often overlaps with the leftmost
129 // tick on the x-axis. Shift the bottom tick up a little bit to
130 // compensate if necessary.
131 var bottomTick
= this.ylabels
[0];
132 var fontSize
= this.options
.axisLabelFontSize
;
133 var bottom
= parseInt(bottomTick
.style
.top
) + fontSize
;
134 if (bottom
> this.height
- fontSize
) {
135 bottomTick
.style
.top
= (parseInt(bottomTick
.style
.top
) -
136 fontSize
/ 2) + "px";
141 context
.moveTo(this.area
.x
, this.area
.y
);
142 context
.lineTo(this.area
.x
, this.area
.y
+ this.area
.h
);
147 if (this.options
.drawXAxis
) {
148 if (this.layout
.xticks
) {
149 var drawTick
= function(tick
) {
150 if (typeof(dataset
) == "function") return;
152 var x
= this.area
.x
+ tick
[0] * this.area
.w
;
153 var y
= this.area
.y
+ this.area
.h
;
155 context
.moveTo(x
, y
);
156 context
.lineTo(x
, y
+ this.options
.axisTickSize
);
160 var label
= DIV(labelStyle
, tick
[1]);
161 label
.style
.textAlign
= "center";
162 label
.style
.bottom
= "0px";
164 var left
= (x
- this.options
.axisLabelWidth
/2);
165 if (left
+ this.options
.axisLabelWidth
> this.width
) {
166 left
= this.width
- this.options
.xAxisLabelWidth
;
167 label
.style
.textAlign
= "right";
171 label
.style
.textAlign
= "left";
174 label
.style
.left
= left
+ "px";
175 label
.style
.width
= this.options
.xAxisLabelWidth
+ "px";
176 MochiKit
.DOM
.appendChildNodes(this.container
, label
);
177 this.xlabels
.push(label
);
180 MochiKit
.Iter
.forEach(this.layout
.xticks
, bind(drawTick
, this));
184 context
.moveTo(this.area
.x
, this.area
.y
+ this.area
.h
);
185 context
.lineTo(this.area
.x
+ this.area
.w
, this.area
.y
+ this.area
.h
);
194 PlotKit
.CanvasRenderer
.prototype.clear
= function() {
196 // VML takes a while to start up, so we just poll every this.IEDelay
198 if (this.clearDelay
) {
199 this.clearDelay
.cancel();
200 this.clearDelay
= null;
202 var context
= this.element
.getContext("2d");
205 this.clearDelay
= MochiKit
.Async
.wait(this.IEDelay
);
206 this.clearDelay
.addCallback(bind(this.clear
, this));
211 var context
= this.element
.getContext("2d");
212 context
.clearRect(0, 0, this.width
, this.height
);
214 MochiKit
.Iter
.forEach(this.xlabels
, MochiKit
.DOM
.removeElement
);
215 MochiKit
.Iter
.forEach(this.ylabels
, MochiKit
.DOM
.removeElement
);
216 this.xlabels
= new Array();
217 this.ylabels
= new Array();
220 // ----------------------------------------------------------------
221 // Everything below here is experimental and undocumented.
222 // ----------------------------------------------------------------
225 PlotKit
.CanvasRenderer
.isSupported
= function(canvasName
) {
228 if (MochiKit
.Base
.isUndefinedOrNull(canvasName
))
229 canvas
= MochiKit
.DOM
.CANVAS({});
231 canvas
= MochiKit
.DOM
.getElement(canvasName
);
232 var context
= canvas
.getContext("2d");
235 var ie
= navigator
.appVersion
.match(/MSIE (\d\.\d)/);
236 var opera
= (navigator
.userAgent
.toLowerCase().indexOf("opera") != -1);
237 if ((!ie
) || (ie
[1] < 6) || (opera
))