Initial check-in
[dygraphs.git] / plotkit_v091 / PlotKit / SVG.js
1 /*
2 PlotKit SVG
3 ===========
4 SVG Renderer for PlotKit
5
6 Copyright
7 ---------
8 Copyright 2005,2006 (c) Alastair Tse <alastair^liquidx.net>
9 For use under the BSD license. <http://www.liquidx.net/plotkit>
10 */
11
12 // -------------------------------------------------------------------------
13 // NOTES: - If you use XHTML1.1 strict, then you must include each MochiKit
14 // file individuall.
15 // - For IE support, you must include the AdobeSVG object hack.
16 // See tests/svg.html for details.
17 // -------------------------------------------------------------------------
18 // -------------------------------------------------------------------------
19 // Check required components
20 // -------------------------------------------------------------------------
21
22 try {
23 if (typeof(PlotKit.Layout) == 'undefined')
24 {
25 throw "";
26 }
27 }
28 catch (e) {
29 throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Layout"
30 }
31
32
33 // ---------------------------------------------------------------------------
34 // SVG Renderer
35 // ---------------------------------------------------------------------------
36
37 PlotKit.SVGRenderer = function(element, layout, options) {
38 if (arguments.length > 0)
39 this.__init__(element, layout, options);
40 };
41
42 PlotKit.SVGRenderer.NAME = "PlotKit.SVGRenderer";
43 PlotKit.SVGRenderer.VERSION = PlotKit.VERSION;
44
45 PlotKit.SVGRenderer.__repr__ = function() {
46 return "[" + this.NAME + " " + this.VERSION + "]";
47 };
48
49 PlotKit.SVGRenderer.toString = function() {
50 return this.__repr__();
51 }
52
53 PlotKit.SVGRenderer.SVGNS = 'http://www.w3.org/2000/svg';
54
55 PlotKit.SVGRenderer.prototype.__init__ = function(element, layout, options) {
56 var isNil = MochiKit.Base.isUndefinedOrNull;
57
58 // default options
59 this.options = {
60 "drawBackground": true,
61 "backgroundColor": Color.whiteColor(),
62 "padding": {left: 30, right: 30, top: 5, bottom: 10},
63 "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[1]),
64 "strokeColor": Color.whiteColor(),
65 "strokeColorTransform": "asStrokeColor",
66 "strokeWidth": 0.5,
67 "shouldFill": true,
68 "shouldStroke": true,
69 "drawXAxis": true,
70 "drawYAxis": true,
71 "axisLineColor": Color.blackColor(),
72 "axisLineWidth": 0.5,
73 "axisTickSize": 3,
74 "axisLabelColor": Color.blackColor(),
75 "axisLabelFont": "Arial",
76 "axisLabelFontSize": 9,
77 "axisLabelWidth": 50,
78 "axisLabelUseDiv": true,
79 "pieRadius": 0.4,
80 "enableEvents": true
81 };
82
83 MochiKit.Base.update(this.options, options ? options : {});
84 this.layout = layout;
85 this.element = MochiKit.DOM.getElement(element);
86 this.container = this.element.parentNode;
87 this.height = parseInt(this.element.getAttribute("height"));
88 this.width = parseInt(this.element.getAttribute("width"));
89 this.document = document;
90 this.root = this.element;
91
92 // Adobe SVG Support:
93 // - if an exception is thrown, then no Adobe SVG Plugin support.
94 try {
95 this.document = this.element.getSVGDocument();
96 this.root = isNil(this.document.documentElement) ? this.element : this.document.documentElement;
97 }
98 catch (e) {
99 }
100
101 this.element.style.zIndex = 1;
102
103 if (isNil(this.element))
104 throw "SVGRenderer() - passed SVG object is not found";
105
106 if (isNil(this.container) || this.container.nodeName.toLowerCase() != "div")
107 throw "SVGRenderer() - No DIV's around the SVG.";
108
109 // internal state
110 this.xlabels = new Array();
111 this.ylabels = new Array();
112
113 // initialise some meta structures in SVG
114 this.defs = this.createSVGElement("defs");
115
116 this.area = {
117 x: this.options.padding.left,
118 y: this.options.padding.top,
119 w: this.width - this.options.padding.left - this.options.padding.right,
120 h: this.height - this.options.padding.top - this.options.padding.bottom
121 };
122
123 MochiKit.DOM.updateNodeAttributes(this.container,
124 {"style":{ "position": "relative", "width": this.width + "px"}});
125
126
127 };
128
129
130 PlotKit.SVGRenderer.prototype.render = function() {
131 if (this.options.drawBackground)
132 this._renderBackground();
133
134 if (this.layout.style == "bar") {
135 this._renderBarChart();
136 this._renderBarAxis();
137 }
138 else if (this.layout.style == "pie") {
139 this._renderPieChart();
140 this._renderPieAxis();
141 }
142 else if (this.layout.style == "line") {
143 this._renderLineChart();
144 this._renderLineAxis();
145 }
146 };
147
148 PlotKit.SVGRenderer.prototype._renderBarOrLine = function(data, plotFunc, startFunc, endFunc) {
149
150 var colorCount = this.options.colorScheme.length;
151 var colorScheme = this.options.colorScheme;
152 var setNames = MochiKit.Base.keys(this.layout.datasets);
153 var setCount = setNames.length;
154
155 for (var i = 0; i < setCount; i++) {
156 var setName = setNames[i];
157 var attrs = new Array();
158 var color = colorScheme[i%colorCount];
159
160 if (this.options.shouldFill)
161 attrs["fill"] = color.toRGBString();
162 else
163 attrs["fill"] = "none";
164
165 if (this.options.shouldStroke &&
166 (this.options.strokeColor || this.options.strokeColorTransform)) {
167 if (this.options.strokeColor)
168 attrs["stroke"] = this.options.strokeColor.toRGBString();
169 else if (this.options.strokeColorTransform)
170 attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
171 attrs["strokeWidth"] = this.options.strokeWidth;
172 }
173
174 if (startFunc)
175 startFunc(attrs);
176
177 var forEachFunc = function(obj) {
178 if (obj.name == setName)
179 plotFunc(attrs, obj);
180 };
181
182 MochiKit.Iter.forEach(data, bind(forEachFunc, this));
183 if (endFunc)
184 endFunc(attrs);
185 }
186 };
187
188 PlotKit.SVGRenderer.prototype._renderBarChart = function() {
189 var bind = MochiKit.Base.bind;
190
191 var drawRect = function(attrs, bar) {
192 var x = this.area.w * bar.x + this.area.x;
193 var y = this.area.h * bar.y + this.area.y;
194 var w = this.area.w * bar.w;
195 var h = this.area.h * bar.h;
196 this._drawRect(x, y, w, h, attrs);
197 };
198 this._renderBarOrLine(this.layout.bars, bind(drawRect, this));
199 };
200
201 PlotKit.SVGRenderer.prototype._renderLineChart = function() {
202 var bind = MochiKit.Base.bind;
203
204 var addPoint = function(attrs, point) {
205 this._tempPointsBuffer += (this.area.w * point.x + this.area.x) + "," +
206 (this.area.h * point.y + this.area.y) + " ";
207 };
208
209 var startLine = function(attrs) {
210 this._tempPointsBuffer = "";
211 this._tempPointsBuffer += (this.area.x) + "," + (this.area.y+this.area.h) + " ";
212 };
213
214 var endLine = function(attrs) {
215 this._tempPointsBuffer += (this.area.w + this.area.x) + "," +(this.area.h + this.area.y);
216 attrs["points"] = this._tempPointsBuffer;
217 var elem = this.createSVGElement("polygon", attrs);
218 this.root.appendChild(elem);
219 };
220
221 this._renderBarOrLine(this.layout.points,
222 bind(addPoint, this),
223 bind(startLine, this),
224 bind(endLine, this));
225 };
226
227
228 PlotKit.SVGRenderer.prototype._renderPieChart = function() {
229 var colorCount = this.options.colorScheme.length;
230 var slices = this.layout.slices;
231
232 var centerx = this.area.x + this.area.w * 0.5;
233 var centery = this.area.y + this.area.h * 0.5;
234 var radius = Math.min(this.area.w * this.options.pieRadius,
235 this.area.h * this.options.pieRadius);
236
237 // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1
238 // so we have to subtract 90 degrees to make it start at y = 1, x = 0
239
240 // workaround if we only have 1 slice of 100%
241 if (slices.length == 1 && (Math.abs(slices[0].startAngle) - Math.abs(slices[0].endAngle) < 0.1)) {
242 var attrs = {"cx": centerx , "cy": centery , "r": radius };
243 var color = this.options.colorScheme[0];
244 if (this.options.shouldFill)
245 attrs["fill"] = color.toRGBString();
246 else
247 attrs["fill"] = "none";
248
249 if (this.options.shouldStroke &&
250 (this.options.strokeColor || this.options.strokeColorTransform)) {
251 if (this.options.strokeColor)
252 attrs["stroke"] = this.options.strokeColor.toRGBString();
253 else if (this.options.strokeColorTransform)
254 attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
255 attrs["style"] = "stroke-width: " + this.options.strokeWidth;
256 }
257
258 this.root.appendChild(this.createSVGElement("circle", attrs));
259 return;
260 }
261
262 for (var i = 0; i < slices.length; i++) {
263 var attrs = new Array();
264 var color = this.options.colorScheme[i%colorCount];
265 if (this.options.shouldFill)
266 attrs["fill"] = color.toRGBString();
267 else
268 attrs["fill"] = "none";
269
270 if (this.options.shouldStroke &&
271 (this.options.strokeColor || this.options.strokeColorTransform)) {
272 if (this.options.strokeColor)
273 attrs["stroke"] = this.options.strokeColor.toRGBString();
274 else if (this.options.strokeColorTransform)
275 attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
276 attrs["style"] = "stroke-width:" + this.options.strokeWidth;
277 }
278
279 var largearc = 0;
280 if (Math.abs(slices[i].endAngle - slices[i].startAngle) > Math.PI)
281 largearc = 1;
282 var x1 = Math.cos(slices[i].startAngle - Math.PI/2) * radius;
283 var y1 = Math.sin(slices[i].startAngle - Math.PI/2) * radius;
284 var x2 = Math.cos(slices[i].endAngle - Math.PI/2) * radius;
285 var y2 = Math.sin(slices[i].endAngle - Math.PI/2) * radius;
286 var rx = x2 - x1;
287 var ry = y2 - y1;
288
289 var pathString = "M" + centerx + "," + centery + " ";
290 pathString += "l" + x1 + "," + y1 + " ";
291 pathString += "a" + radius + "," + radius + " 0 " + largearc + ",1 " + rx + "," + ry + " z";
292
293 attrs["d"] = pathString;
294
295 var elem = this.createSVGElement("path", attrs);
296 this.root.appendChild(elem);
297 }
298 };
299
300 PlotKit.SVGRenderer.prototype._renderBarAxis = function() {
301 this._renderAxis();
302 }
303
304 PlotKit.SVGRenderer.prototype._renderLineAxis = function() {
305 this._renderAxis();
306 };
307
308
309 PlotKit.SVGRenderer.prototype._renderAxis = function() {
310
311 if (!this.options.drawXAxis && !this.options.drawYAxis)
312 return;
313
314 var labelStyle = {"style":
315 {"position": "absolute",
316 "textAlign": "center",
317 "fontSize": this.options.axisLabelFontSize + "px",
318 "zIndex": 10,
319 "color": this.options.axisLabelColor.toRGBString(),
320 "width": this.options.axisLabelWidth + "px",
321 "overflow": "hidden"
322 }
323 };
324
325 // axis lines
326 var lineAttrs = {
327 "stroke": this.options.axisLineColor.toRGBString(),
328 "strokeWidth": this.options.axisLineWidth
329 };
330
331
332 if (this.options.drawYAxis) {
333 if (this.layout.yticks) {
334 var drawTick = function(tick) {
335 var x = this.area.x;
336 var y = this.area.y + tick[0] * this.area.h;
337 this._drawLine(x, y, x - 3, y, lineAttrs);
338
339 if (this.options.axisLabelUseDiv) {
340 var label = DIV(labelStyle, tick[1]);
341 label.style.top = (y - this.options.axisLabelFontSize) + "px";
342 label.style.left = (x - this.options.padding.left + this.options.axisTickSize) + "px";
343 label.style.textAlign = "left";
344 label.style.width = (this.options.padding.left - 3) + "px";
345 MochiKit.DOM.appendChildNodes(this.container, label);
346 this.ylabels.push(label);
347 }
348 else {
349 var attrs = {
350 y: y + 3,
351 x: (x - this.options.padding.left + 3),
352 width: (this.options.padding.left - this.options.axisTickSize) + "px",
353 height: (this.options.axisLabelFontSize + 3) + "px",
354 fontFamily: "Arial",
355 fontSize: this.options.axisLabelFontSize + "px",
356 fill: this.options.axisLabelColor.toRGBString()
357 };
358
359 /* we can do clipping just like DIVs
360 http://www.xml.com/pub/a/2004/06/02/svgtype.html */
361 /*
362 var mask = this.createSVGElement("mask", {id: "mask" + tick[0]});
363 var maskShape = this.createSVGElement("rect",
364 {y: y + 3,
365 x: (x - this.options.padding.left + 3),
366 width: (this.options.padding.left - this.options.axisTickSize) + "px",
367 height: (this.options.axisLabelFontSize + 3) + "px",
368 style: {"fill": "#ffffff", "stroke": "#000000"}});
369 mask.appendChild(maskShape);
370 this.defs.appendChild(mask);
371
372 attrs["filter"] = "url(#mask" + tick[0] + ")";
373 */
374
375 var label = this.createSVGElement("text", attrs);
376 label.appendChild(this.document.createTextNode(tick[1]));
377 this.root.appendChild(label);
378 }
379 };
380
381 MochiKit.Iter.forEach(this.layout.yticks, bind(drawTick, this));
382 }
383
384 this._drawLine(this.area.x, this.area.y, this.area.x, this.area.y + this.area.h, lineAttrs);
385 }
386
387 if (this.options.drawXAxis) {
388 if (this.layout.xticks) {
389 var drawTick = function(tick) {
390 var x = this.area.x + tick[0] * this.area.w;
391 var y = this.area.y + this.area.h;
392 this._drawLine(x, y, x, y + this.options.axisTickSize, lineAttrs);
393
394 if (this.options.axisLabelUseDiv) {
395 var label = DIV(labelStyle, tick[1]);
396 label.style.top = (y + this.options.axisTickSize) + "px";
397 label.style.left = (x - this.options.axisLabelWidth/2) + "px";
398 label.style.textAlign = "center";
399 label.style.width = this.options.axisLabelWidth + "px";
400 MochiKit.DOM.appendChildNodes(this.container, label);
401 this.xlabels.push(label);
402 }
403 else {
404 var attrs = {
405 y: (y + this.options.axisTickSize + this.options.axisLabelFontSize),
406 x: x - 3,
407 width: this.options.axisLabelWidth + "px",
408 height: (this.options.axisLabelFontSize + 3) + "px",
409 fontFamily: "Arial",
410 fontSize: this.options.axisLabelFontSize + "px",
411 fill: this.options.axisLabelColor.toRGBString(),
412 textAnchor: "middle"
413 };
414 var label = this.createSVGElement("text", attrs);
415 label.appendChild(this.document.createTextNode(tick[1]));
416 this.root.appendChild(label);
417 }
418 };
419
420 MochiKit.Iter.forEach(this.layout.xticks, bind(drawTick, this));
421 }
422
423 this._drawLine(this.area.x, this.area.y + this.area.h, this.area.x + this.area.w, this.area.y + this.area.h, lineAttrs)
424 }
425 };
426
427 PlotKit.SVGRenderer.prototype._renderPieAxis = function() {
428
429 if (this.layout.xticks) {
430 // make a lookup dict for x->slice values
431 var lookup = new Array();
432 for (var i = 0; i < this.layout.slices.length; i++) {
433 lookup[this.layout.slices[i].xval] = this.layout.slices[i];
434 }
435
436 var centerx = this.area.x + this.area.w * 0.5;
437 var centery = this.area.y + this.area.h * 0.5;
438 var radius = Math.min(this.area.w * this.options.pieRadius + 10,
439 this.area.h * this.options.pieRadius + 10);
440 var labelWidth = this.options.axisLabelWidth;
441
442 for (var i = 0; i < this.layout.xticks.length; i++) {
443 var slice = lookup[this.layout.xticks[i][0]];
444 if (MochiKit.Base.isUndefinedOrNull(slice))
445 continue;
446
447
448 var angle = (slice.startAngle + slice.endAngle)/2;
449 // normalize the angle
450 var normalisedAngle = angle;
451 if (normalisedAngle > Math.PI * 2)
452 normalisedAngle = normalisedAngle - Math.PI * 2;
453 else if (normalisedAngle < 0)
454 normalisedAngle = normalisedAngle + Math.PI * 2;
455
456 var labelx = centerx + Math.sin(normalisedAngle) * (radius + 10);
457 var labely = centery - Math.cos(normalisedAngle) * (radius + 10);
458
459 var attrib = {
460 "position": "absolute",
461 "zIndex": 11,
462 "width": labelWidth + "px",
463 "fontSize": this.options.axisLabelFontSize + "px",
464 "overflow": "hidden",
465 "color": this.options.axisLabelColor.toHexString()
466 };
467
468 var svgattrib = {
469 "width": labelWidth + "px",
470 "fontSize": this.options.axisLabelFontSize + "px",
471 "height": (this.options.axisLabelFontSize + 3) + "px",
472 "fill": this.options.axisLabelColor.toRGBString()
473 };
474
475 if (normalisedAngle <= Math.PI * 0.5) {
476 // text on top and align left
477 MochiKit.Base.update(attrib, {
478 'textAlign': 'left', 'verticalAlign': 'top',
479 'left': labelx + 'px',
480 'top': (labely - this.options.axisLabelFontSize) + "px"
481 });
482 MochiKit.Base.update(svgattrib, {
483 "x": labelx,
484 "y" :(labely - this.options.axisLabelFontSize),
485 "textAnchor": "left"
486 });
487 }
488 else if ((normalisedAngle > Math.PI * 0.5) && (normalisedAngle <= Math.PI)) {
489 // text on bottom and align left
490 MochiKit.Base.update(attrib, {
491 'textAlign': 'left', 'verticalAlign': 'bottom',
492 'left': labelx + 'px',
493 'top': labely + "px"
494 });
495 MochiKit.Base.update(svgattrib, {
496 'textAnchor': 'left',
497 'x': labelx,
498 'y': labely
499 });
500 }
501 else if ((normalisedAngle > Math.PI) && (normalisedAngle <= Math.PI*1.5)) {
502 // text on bottom and align right
503 MochiKit.Base.update(attrib, {
504 'textAlign': 'right', 'verticalAlign': 'bottom',
505 'left': labelx + 'px',
506 'top': labely + "px"
507 });
508 MochiKit.Base.update(svgattrib, {
509 'textAnchor': 'right',
510 'x': labelx - labelWidth,
511 'y': labely
512 });
513 }
514 else {
515 // text on top and align right
516 MochiKit.Base.update(attrib, {
517 'textAlign': 'left', 'verticalAlign': 'bottom',
518 'left': labelx + 'px',
519 'top': labely + "px"
520 });
521 MochiKit.Base.update(svgattrib, {
522 'textAnchor': 'left',
523 'x': labelx - labelWidth,
524 'y': labely - this.options.axisLabelFontSize
525 });
526 }
527
528 if (this.options.axisLabelUseDiv) {
529 var label = DIV({'style': attrib}, this.layout.xticks[i][1]);
530 this.xlabels.push(label);
531 MochiKit.DOM.appendChildNodes(this.container, label);
532 }
533 else {
534 var label = this.createSVGElement("text", svgattrib);
535 label.appendChild(this.document.createTextNode(this.layout.xticks[i][1]))
536 this.root.appendChild(label);
537 }
538 }
539
540 }
541 };
542
543 PlotKit.SVGRenderer.prototype._renderBackground = function() {
544 var opts = {"stroke": "none",
545 "fill": this.options.backgroundColor.toRGBString()
546 };
547 this._drawRect(0, 0, this.width, this.height, opts);
548 };
549
550 PlotKit.SVGRenderer.prototype._drawRect = function(x, y, w, h, moreattrs) {
551 var attrs = {x: x + "px", y: y + "px", width: w + "px", height: h + "px"};
552 if (moreattrs)
553 MochiKit.Base.update(attrs, moreattrs);
554
555 var elem = this.createSVGElement("rect", attrs);
556 this.root.appendChild(elem);
557 };
558
559 PlotKit.SVGRenderer.prototype._drawLine = function(x1, y1, x2, y2, moreattrs) {
560 var attrs = {x1: x1 + "px", y1: y1 + "px", x2: x2 + "px", y2: y2 + "px"};
561 if (moreattrs)
562 MochiKit.Base.update(attrs, moreattrs);
563
564 var elem = this.createSVGElement("line", attrs);
565 this.root.appendChild(elem);
566 }
567
568 PlotKit.SVGRenderer.prototype.clear = function() {
569 while(this.element.firstChild) {
570 this.element.removeChild(this.element.firstChild);
571 }
572
573 if (this.options.axisLabelUseDiv) {
574 for (var i = 0; i < this.xlabels.length; i++) {
575 MochiKit.DOM.removeElement(this.xlabels[i]);
576 }
577 for (var i = 0; i < this.ylabels.length; i++) {
578 MochiKit.DOM.removeElement(this.ylabels[i]);
579 }
580 }
581 this.xlabels = new Array();
582 this.ylabels = new Array();
583 };
584
585
586 PlotKit.SVGRenderer.prototype.createSVGElement = function(name, attrs) {
587 var isNil = MochiKit.Base.isUndefinedOrNull;
588 var elem;
589 var doc = isNil(this.document) ? document : this.document;
590
591 try {
592 elem = doc.createElementNS(PlotKit.SVGRenderer.SVGNS, name);
593 }
594 catch (e) {
595 elem = doc.createElement(name);
596 elem.setAttribute("xmlns", PlotKit.SVGRenderer.SVGNS);
597 }
598
599 if (attrs)
600 MochiKit.DOM.updateNodeAttributes(elem, attrs);
601
602 // TODO: we don't completely emulate the MochiKit.DOM.createElement
603 // as we don't care about nodes contained. We really should though.
604
605 return elem;
606
607 };
608
609
610 PlotKit.SVGRenderer.SVG = function(attrs) {
611 // we have to do things differently for IE+AdobeSVG.
612 // My guess this works (via trial and error) is that we need to
613 // have an SVG object in order to use SVGDocument.createElementNS
614 // but IE doesn't allow us to that.
615
616 var ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
617 var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
618 if (ie && (ie[1] >= 6) && (!opera)) {
619 var width = attrs["width"] ? attrs["width"] : "100";
620 var height = attrs["height"] ? attrs["height"] : "100";
621 var eid = attrs["id"] ? attrs["id"] : "notunique";
622
623 var html = '<svg:svg width="' + width + '" height="' + height + '" ';
624 html += 'id="' + eid + '" version="1.1" baseProfile="full" />';
625
626 var canvas = document.createElement(html);
627
628 // create embedded SVG inside SVG.
629 var group = canvas.getSVGDocument().createElementNS(PlotKit.SVGRenderer.SVGNS, "svg");
630 group.setAttribute("width", width);
631 group.setAttribute("height", height);
632 canvas.getSVGDocument().appendChild(group);
633
634 return canvas;
635 }
636 else {
637 return PlotKit.SVGRenderer.prototype.createSVGElement("svg", attrs);
638 }
639 };
640
641 PlotKit.SVGRenderer.isSupported = function() {
642 var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
643 var ieVersion = navigator.appVersion.match(/MSIE (\d\.\d)/);
644 var safariVersion = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
645 var operaVersion = navigator.userAgent.match(/Opera\/(\d*\.\d*)/);
646 var mozillaVersion = navigator.userAgent.match(/rv:(\d*\.\d*).*Gecko/);
647 var svgFeature = "http://www.w3.org/TR/SVG11/feature#SVG";
648
649 if (ieVersion && (ieVersion[1] >= 6) && !isOpera) {
650 return document.implementation.hasFeature(svgFeature,"1.1");
651 /*
652 var dummysvg = document.createElement('<svg:svg width="1" height="1" baseProfile="full" version="1.1" id="dummy">');
653 try {
654 dummysvg.getSVGDocument();
655 dummysvg = null;
656 return true;
657 }
658 catch (e) {
659 return false;
660 }
661 */
662
663 }
664
665 /* support not really there yet. no text and paths are buggy
666 if (safariVersion && (safariVersion[1] > 419))
667 return true;
668 */
669
670 if (operaVersion && (operaVersion[1] > 8.9))
671 return true
672
673 if (mozillaVersion && (mozillaVersion > 1.7))
674 return true;
675
676 return false;
677 };
678
679 // Namespace Iniitialisation
680
681 PlotKit.SVG = {}
682 PlotKit.SVG.SVGRenderer = PlotKit.SVGRenderer;
683
684 PlotKit.SVG.EXPORT = [
685 "SVGRenderer"
686 ];
687
688 PlotKit.SVG.EXPORT_OK = [
689 "SVGRenderer"
690 ];
691
692 PlotKit.SVG.__new__ = function() {
693 var m = MochiKit.Base;
694
695 m.nameFunctions(this);
696
697 this.EXPORT_TAGS = {
698 ":common": this.EXPORT,
699 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
700 };
701 };
702
703 PlotKit.SVG.__new__();
704 MochiKit.Base._exportSymbols(this, PlotKit.SVG);
705