";
+
+ // internal state
+ this.xlabels = new Array();
+ this.ylabels = new Array();
+ this.isFirstRender = true;
+
+ this.area = {
+ x: this.options.padding.left,
+ y: this.options.padding.top,
+ w: this.width - this.options.padding.left - this.options.padding.right,
+ h: this.height - this.options.padding.top - this.options.padding.bottom
+ };
+
+ MochiKit.DOM.updateNodeAttributes(this.container,
+ {"style":{ "position": "relative", "width": this.width + "px"}});
+
+ // load event system if we have Signals
+ try {
+ this.event_isinside = null;
+ if (MochiKit.Signal && this.options.enableEvents) {
+ this._initialiseEvents();
+ }
+ }
+ catch (e) {
+ // still experimental
+ }
+};
+
+PlotKit.CanvasRenderer.IECanvasEmulationIfNeeded = function(htc) {
+ var ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
+ var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ if ((!ie) || (ie[1] < 6) || (opera))
+ return false;
+
+ if (isUndefinedOrNull(MochiKit.DOM.getElement('VMLRender'))) {
+ // before we add VMLRender, we need to recreate all canvas tags
+ // programmatically otherwise IE will not recognise it
+
+ var nodes = document.getElementsByTagName('canvas');
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ if (node.getContext) { return; } // Other implementation, abort
+ var newNode = MochiKit.DOM.CANVAS(
+ {id: node.id,
+ width: "" + parseInt(node.width),
+ height: "" + parseInt(node.height)}, "");
+ newNode.style.width = parseInt(node.width) + "px";
+ newNode.style.height = parseInt(node.height) + "px";
+ node.id = node.id + "_old";
+ MochiKit.DOM.swapDOM(node, newNode);
+ }
+
+ document.namespaces.add("v");
+ var vmlopts = {'id':'VMLRender',
+ 'codebase':'vgx.dll',
+ 'classid':'CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E'};
+ var vml = MochiKit.DOM.createDOM('object', vmlopts);
+ document.body.appendChild(vml);
+ var vmlStyle = document.createStyleSheet();
+ vmlStyle.addRule("canvas", "behavior: url('" + htc + "');");
+ vmlStyle.addRule("v\\:*", "behavior: url(#VMLRender);");
+ }
+ return true;
+};
+
+PlotKit.CanvasRenderer.prototype.render = function() {
+ if (this.isIE) {
+ // VML takes a while to start up, so we just poll every this.IEDelay
+ try {
+ if (this.renderDelay) {
+ this.renderDelay.cancel();
+ this.renderDelay = null;
+ }
+ var context = this.element.getContext("2d");
+ }
+ catch (e) {
+ this.isFirstRender = false;
+ if (this.maxTries-- > 0) {
+ this.renderDelay = MochiKit.Async.wait(this.IEDelay);
+ this.renderDelay.addCallback(bind(this.render, this));
+ }
+ return;
+ }
+ }
+
+ if (this.options.drawBackground)
+ this._renderBackground();
+
+ if (this.style == "bar") {
+ this._renderBarChart();
+ this._renderBarAxis();
+ }
+ else if (this.style == "pie") {
+ this._renderPieChart();
+ this._renderPieAxis();
+ }
+ else if (this.style == "line") {
+ this._renderLineChart();
+ this._renderLineAxis();
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderBarChartWrap = function(data, plotFunc) {
+ var context = this.element.getContext("2d");
+ var colorCount = this.options.colorScheme.length;
+ var colorScheme = this.options.colorScheme;
+ var setNames = MochiKit.Base.keys(this.layout.datasets);
+ var setCount = setNames.length;
+
+ for (var i = 0; i < setCount; i++) {
+ var setName = setNames[i];
+ var color = colorScheme[i%colorCount];
+ context.save();
+ context.fillStyle = color.toRGBString();
+ if (this.options.strokeColor)
+ context.strokeStyle = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ context.strokeStyle = color[this.options.strokeColorTransform]().toRGBString();
+
+ context.lineWidth = this.options.strokeWidth;
+ var forEachFunc = function(obj) {
+ if (obj.name == setName)
+ plotFunc(context, obj);
+ };
+
+ MochiKit.Iter.forEach(data, bind(forEachFunc, this));
+ context.restore();
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderBarChart = function() {
+ var bind = MochiKit.Base.bind;
+
+ var drawRect = function(context, bar) {
+ var x = this.area.w * bar.x + this.area.x;
+ var y = this.area.h * bar.y + this.area.y;
+ var w = this.area.w * bar.w;
+ var h = this.area.h * bar.h;
+ if ((w < 1) || (h < 1))
+ return;
+ if (this.options.shouldFill)
+ context.fillRect(x, y, w, h);
+ if (this.options.shouldStroke)
+ context.strokeRect(x, y, w, h);
+ };
+ this._renderBarChartWrap(this.layout.bars, bind(drawRect, this));
+};
+
+PlotKit.CanvasRenderer.prototype._renderLineChart = function() {
+ var context = this.element.getContext("2d");
+ var colorCount = this.options.colorScheme.length;
+ var colorScheme = this.options.colorScheme;
+ var setNames = MochiKit.Base.keys(this.layout.datasets);
+ var setCount = setNames.length;
+ var bind = MochiKit.Base.bind;
+ var partial = MochiKit.Base.partial;
+
+ for (var i = 0; i < setCount; i++) {
+ var setName = setNames[i];
+ var color = colorScheme[i%colorCount];
+ var strokeX = this.options.strokeColorTransform;
+
+ // setup graphics context
+ context.save();
+ context.fillStyle = color.toRGBString();
+ if (this.options.strokeColor)
+ context.strokeStyle = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ context.strokeStyle = color[strokeX]().toRGBString();
+
+ context.lineWidth = this.options.strokeWidth;
+
+ // create paths
+ var makePath = function() {
+ context.beginPath();
+ context.moveTo(this.area.x, this.area.y + this.area.h);
+ var addPoint = function(context, point) {
+ if (point.name == setName)
+ context.lineTo(this.area.w * point.x + this.area.x,
+ this.area.h * point.y + this.area.y);
+ };
+ MochiKit.Iter.forEach(this.layout.points, partial(addPoint, context), this);
+ context.lineTo(this.area.w + this.area.x,
+ this.area.h + this.area.y);
+ context.lineTo(this.area.x, this.area.y + this.area.h);
+ context.closePath();
+ };
+
+ if (this.options.shouldFill) {
+ bind(makePath, this)();
+ context.fill();
+ }
+ if (this.options.shouldStroke) {
+ bind(makePath, this)();
+ context.stroke();
+ }
+
+ context.restore();
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderPieChart = function() {
+ var context = this.element.getContext("2d");
+ var colorCount = this.options.colorScheme.length;
+ var slices = this.layout.slices;
+
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var radius = Math.min(this.area.w * this.options.pieRadius,
+ this.area.h * this.options.pieRadius);
+
+ if (this.isIE) {
+ centerx = parseInt(centerx);
+ centery = parseInt(centery);
+ radius = parseInt(radius);
+ }
+
+
+ // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1
+ // so we have to subtract 90 degrees to make it start at y = 1, x = 0
+
+ for (var i = 0; i < slices.length; i++) {
+ var color = this.options.colorScheme[i%colorCount];
+ context.save();
+ context.fillStyle = color.toRGBString();
+
+ var makePath = function() {
+ context.beginPath();
+ context.moveTo(centerx, centery);
+ context.arc(centerx, centery, radius,
+ slices[i].startAngle - Math.PI/2,
+ slices[i].endAngle - Math.PI/2,
+ false);
+ context.lineTo(centerx, centery);
+ context.closePath();
+ };
+
+ if (Math.abs(slices[i].startAngle - slices[i].endAngle) > 0.001) {
+ if (this.options.shouldFill) {
+ makePath();
+ context.fill();
+ }
+
+ if (this.options.shouldStroke) {
+ makePath();
+ context.lineWidth = this.options.strokeWidth;
+ if (this.options.strokeColor)
+ context.strokeStyle = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ context.strokeStyle = color[this.options.strokeColorTransform]().toRGBString();
+ context.stroke();
+ }
+ }
+ context.restore();
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderBarAxis = function() {
+ this._renderAxis();
+}
+
+PlotKit.CanvasRenderer.prototype._renderLineAxis = function() {
+ this._renderAxis();
+};
+
+
+PlotKit.CanvasRenderer.prototype._renderAxis = function() {
+ if (!this.options.drawXAxis && !this.options.drawYAxis)
+ return;
+
+ var context = this.element.getContext("2d");
+
+ var labelStyle = {"style":
+ {"position": "absolute",
+ "fontSize": this.options.axisLabelFontSize + "px",
+ "zIndex": 10,
+ "color": this.options.axisLabelColor.toRGBString(),
+ "width": this.options.axisLabelWidth + "px",
+ "overflow": "hidden"
+ }
+ };
+
+ // axis lines
+ context.save();
+ context.strokeStyle = this.options.axisLineColor.toRGBString();
+ context.lineWidth = this.options.axisLineWidth;
+
+
+ if (this.options.drawYAxis) {
+ if (this.layout.yticks) {
+ var drawTick = function(tick) {
+ var x = this.area.x;
+ var y = this.area.y + tick[0] * this.area.h;
+ context.beginPath();
+ context.moveTo(x, y);
+ context.lineTo(x - this.options.axisTickSize, y);
+ context.closePath();
+ context.stroke();
+
+ var label = DIV(labelStyle, tick[1]);
+ label.style.top = (y - this.options.axisLabelFontSize) + "px";
+ label.style.left = (x - this.options.padding.left - this.options.axisTickSize) + "px";
+ label.style.textAlign = "right";
+ label.style.width = (this.options.padding.left - this.options.axisTickSize * 2) + "px";
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ this.ylabels.push(label);
+ };
+
+ MochiKit.Iter.forEach(this.layout.yticks, bind(drawTick, this));
+ }
+
+ context.beginPath();
+ context.moveTo(this.area.x, this.area.y);
+ context.lineTo(this.area.x, this.area.y + this.area.h);
+ context.closePath();
+ context.stroke();
+ }
+
+ if (this.options.drawXAxis) {
+ if (this.layout.xticks) {
+ var drawTick = function(tick) {
+ var x = this.area.x + tick[0] * this.area.w;
+ var y = this.area.y + this.area.h;
+ context.beginPath();
+ context.moveTo(x, y);
+ context.lineTo(x, y + this.options.axisTickSize);
+ context.closePath();
+ context.stroke();
+
+ var label = DIV(labelStyle, tick[1]);
+ label.style.top = (y + this.options.axisTickSize) + "px";
+ label.style.left = (x - this.options.axisLabelWidth/2) + "px";
+ label.style.textAlign = "center";
+ label.style.width = this.options.axisLabelWidth + "px";
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ this.xlabels.push(label);
+ };
+
+ MochiKit.Iter.forEach(this.layout.xticks, bind(drawTick, this));
+ }
+
+ context.beginPath();
+ context.moveTo(this.area.x, this.area.y + this.area.h);
+ context.lineTo(this.area.x + this.area.w, this.area.y + this.area.h);
+ context.closePath();
+ context.stroke();
+ }
+
+ context.restore();
+
+};
+
+PlotKit.CanvasRenderer.prototype._renderPieAxis = function() {
+ if (!this.options.drawXAxis)
+ return;
+
+ if (this.layout.xticks) {
+ // make a lookup dict for x->slice values
+ var lookup = new Array();
+ for (var i = 0; i < this.layout.slices.length; i++) {
+ lookup[this.layout.slices[i].xval] = this.layout.slices[i];
+ }
+
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var radius = Math.min(this.area.w * this.options.pieRadius,
+ this.area.h * this.options.pieRadius);
+ var labelWidth = this.options.axisLabelWidth;
+
+ for (var i = 0; i < this.layout.xticks.length; i++) {
+ var slice = lookup[this.layout.xticks[i][0]];
+ if (MochiKit.Base.isUndefinedOrNull(slice))
+ continue;
+
+
+ var angle = (slice.startAngle + slice.endAngle)/2;
+ // normalize the angle
+ var normalisedAngle = angle;
+ if (normalisedAngle > Math.PI * 2)
+ normalisedAngle = normalisedAngle - Math.PI * 2;
+ else if (normalisedAngle < 0)
+ normalisedAngle = normalisedAngle + Math.PI * 2;
+
+ var labelx = centerx + Math.sin(normalisedAngle) * (radius + 10);
+ var labely = centery - Math.cos(normalisedAngle) * (radius + 10);
+
+ var attrib = {"position": "absolute",
+ "zIndex": 11,
+ "width": labelWidth + "px",
+ "fontSize": this.options.axisLabelFontSize + "px",
+ "overflow": "hidden",
+ "color": this.options.axisLabelColor.toHexString()
+ };
+
+ if (normalisedAngle <= Math.PI * 0.5) {
+ // text on top and align left
+ attrib["textAlign"] = "left";
+ attrib["verticalAlign"] = "top";
+ attrib["left"] = labelx + "px";
+ attrib["top"] = (labely - this.options.axisLabelFontSize) + "px";
+ }
+ else if ((normalisedAngle > Math.PI * 0.5) && (normalisedAngle <= Math.PI)) {
+ // text on bottom and align left
+ attrib["textAlign"] = "left";
+ attrib["verticalAlign"] = "bottom";
+ attrib["left"] = labelx + "px";
+ attrib["top"] = labely + "px";
+
+ }
+ else if ((normalisedAngle > Math.PI) && (normalisedAngle <= Math.PI*1.5)) {
+ // text on bottom and align right
+ attrib["textAlign"] = "right";
+ attrib["verticalAlign"] = "bottom";
+ attrib["left"] = (labelx - labelWidth) + "px";
+ attrib["top"] = labely + "px";
+ }
+ else {
+ // text on top and align right
+ attrib["textAlign"] = "right";
+ attrib["verticalAlign"] = "bottom";
+ attrib["left"] = (labelx - labelWidth) + "px";
+ attrib["top"] = (labely - this.options.axisLabelFontSize) + "px";
+ }
+
+ var label = DIV({'style': attrib}, this.layout.xticks[i][1]);
+ this.xlabels.push(label);
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ }
+
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderBackground = function() {
+ var context = this.element.getContext("2d");
+ context.save();
+ context.fillStyle = this.options.backgroundColor.toRGBString();
+ context.fillRect(0, 0, this.width, this.height);
+ context.restore();
+};
+
+PlotKit.CanvasRenderer.prototype.clear = function() {
+ if (this.isIE) {
+ // VML takes a while to start up, so we just poll every this.IEDelay
+ try {
+ if (this.clearDelay) {
+ this.clearDelay.cancel();
+ this.clearDelay = null;
+ }
+ var context = this.element.getContext("2d");
+ }
+ catch (e) {
+ this.isFirstRender = false;
+ this.clearDelay = MochiKit.Async.wait(this.IEDelay);
+ this.clearDelay.addCallback(bind(this.clear, this));
+ return;
+ }
+ }
+
+ var context = this.element.getContext("2d");
+ context.clearRect(0, 0, this.width, this.height);
+
+
+ for (var i = 0; i < this.xlabels.length; i++) {
+ MochiKit.DOM.removeElement(this.xlabels[i]);
+ }
+ for (var i = 0; i < this.ylabels.length; i++) {
+ MochiKit.DOM.removeElement(this.ylabels[i]);
+ }
+ this.xlabels = new Array();
+ this.ylabels = new Array();
+
+};
+
+PlotKit.CanvasRenderer.prototype._initialiseEvents = function() {
+ var connect = MochiKit.Signal.connect;
+ var bind = MochiKit.Base.bind;
+ MochiKit.Signal.registerSignals(this, ['onmouseover', 'onclick', 'onmouseout', 'onmousemove']);
+ //connect(this.element, 'onmouseover', bind(this.onmouseover, this));
+ //connect(this.element, 'onmouseout', bind(this.onmouseout, this));
+ //connect(this.element, 'onmousemove', bind(this.onmousemove, this));
+ connect(this.element, 'onclick', bind(this.onclick, this));
+};
+
+PlotKit.CanvasRenderer.prototype._resolveObject = function(e) {
+ // does not work in firefox
+ //var x = (e.event().offsetX - this.area.x) / this.area.w;
+ //var y = (e.event().offsetY - this.area.y) / this.area.h;
+
+ var x = (e.mouse().page.x - PlotKit.Base.findPosX(this.element) - this.area.x) / this.area.w;
+ var y = (e.mouse().page.y - PlotKit.Base.findPosY(this.element) - this.area.y) / this.area.h;
+
+ //log(x, y);
+
+ var isHit = this.layout.hitTest(x, y);
+ if (isHit)
+ return isHit;
+ return null;
+};
+
+PlotKit.CanvasRenderer.prototype._createEventObject = function(layoutObj, e) {
+ if (layoutObj == null) {
+ return null;
+ }
+
+ e.chart = layoutObj
+ return e;
+};
+
+
+PlotKit.CanvasRenderer.prototype.onclick = function(e) {
+ var layoutObject = this._resolveObject(e);
+ var eventObject = this._createEventObject(layoutObject, e);
+ if (eventObject != null)
+ MochiKit.Signal.signal(this, "onclick", eventObject);
+};
+
+PlotKit.CanvasRenderer.prototype.onmouseover = function(e) {
+ var layoutObject = this._resolveObject(e);
+ var eventObject = this._createEventObject(layoutObject, e);
+ if (eventObject != null)
+ signal(this, "onmouseover", eventObject);
+};
+
+PlotKit.CanvasRenderer.prototype.onmouseout = function(e) {
+ var layoutObject = this._resolveObject(e);
+ var eventObject = this._createEventObject(layoutObject, e);
+ if (eventObject == null)
+ signal(this, "onmouseout", e);
+ else
+ signal(this, "onmouseout", eventObject);
+
+};
+
+PlotKit.CanvasRenderer.prototype.onmousemove = function(e) {
+ var layoutObject = this._resolveObject(e);
+ var eventObject = this._createEventObject(layoutObject, e);
+
+ if ((layoutObject == null) && (this.event_isinside == null)) {
+ // TODO: should we emit an event anyway?
+ return;
+ }
+
+ if ((layoutObject != null) && (this.event_isinside == null))
+ signal(this, "onmouseover", eventObject);
+
+ if ((layoutObject == null) && (this.event_isinside != null))
+ signal(this, "onmouseout", eventObject);
+
+ if ((layoutObject != null) && (this.event_isinside != null))
+ signal(this, "onmousemove", eventObject);
+
+ this.event_isinside = layoutObject;
+ //log("move", x, y);
+};
+
+PlotKit.CanvasRenderer.isSupported = function(canvasName) {
+ var canvas = null;
+ try {
+ if (MochiKit.Base.isUndefinedOrNull(canvasName))
+ canvas = MochiKit.DOM.CANVAS({});
+ else
+ canvas = MochiKit.DOM.getElement(canvasName);
+ var context = canvas.getContext("2d");
+ }
+ catch (e) {
+ var ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
+ var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ if ((!ie) || (ie[1] < 6) || (opera))
+ return false;
+ return true;
+ }
+ return true;
+};
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/Layout.js b/activemq-web-console/src/main/webapp/js/plotkit/Layout.js
new file mode 100644
index 0000000000..f57951a370
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/Layout.js
@@ -0,0 +1,588 @@
+/*
+ PlotKit Layout
+ --------------
+
+ Handles laying out data on to a virtual canvas square canvas between 0.0
+ and 1.0. If you want to add new chart/plot types such as point plots,
+ you need to add them here.
+
+ Copyright
+ ---------
+ Copyright 2005,2006 (c) Alastair Tse
+ For use under the BSD license.
+
+*/
+
+try {
+ if (typeof(PlotKit.Base) == 'undefined')
+ {
+ throw ""
+ }
+}
+catch (e) {
+ throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Base"
+}
+
+// --------------------------------------------------------------------
+// Start of Layout definition
+// --------------------------------------------------------------------
+
+if (typeof(PlotKit.Layout) == 'undefined') {
+ PlotKit.Layout = {};
+}
+
+PlotKit.Layout.NAME = "PlotKit.Layout";
+PlotKit.Layout.VERSION = PlotKit.VERSION;
+
+PlotKit.Layout.__repr__ = function() {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+PlotKit.Layout.toString = function() {
+ return this.__repr__();
+}
+
+PlotKit.Layout.valid_styles = ["bar", "line", "pie", "point"];
+
+// --------------------------------------------------------------------
+// Start of Layout definition
+// --------------------------------------------------------------------
+
+PlotKit.Layout = function(style, options) {
+
+ this.options = {
+ "barWidthFillFraction": 0.75,
+ "xOriginIsZero": true,
+ "yOriginIsZero": true,
+ "xAxis": null, // [xmin, xmax]
+ "yAxis": null, // [ymin, ymax]
+ "xTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.)
+ "yTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.)
+ "xNumberOfTicks": 10,
+ "yNumberOfTicks": 5,
+ "xTickPrecision": 1,
+ "yTickPrecision": 3,
+ "pieRadius": 0.4
+ };
+
+ // valid external options : TODO: input verification
+ this.style = style;
+ MochiKit.Base.update(this.options, options ? options : {});
+
+ // externally visible states
+ // overriden if xAxis and yAxis are set in options
+ if (!MochiKit.Base.isUndefinedOrNull(this.options.xAxis)) {
+ this.minxval = this.options.xAxis[0];
+ this.maxxval = this.options.xAxis[1];
+ this.xscale = this.maxxval - this.minxval;
+ }
+ else {
+ this.minxval = 0;
+ this.maxxval = null;
+ this.xscale = null; // val -> pos factor (eg, xval * xscale = xpos)
+ }
+
+ if (!MochiKit.Base.isUndefinedOrNull(this.options.yAxis)) {
+ this.minyval = this.options.yAxis[0];
+ this.maxyval = this.options.yAxis[1];
+ this.yscale = this.maxyval - this.maxymin;
+ }
+ else {
+ this.minyval = 0;
+ this.maxyval = null;
+ this.yscale = null;
+ }
+
+ this.bars = new Array(); // array of bars to plot for bar charts
+ this.points = new Array(); // array of points to plot for line plots
+ this.slices = new Array(); // array of slices to draw for pie charts
+
+ this.xticks = new Array();
+ this.yticks = new Array();
+
+ // internal states
+ this.datasets = new Array();
+ this.minxdelta = 0;
+ this.xrange = 1;
+ this.yrange = 1;
+
+ this.hitTestCache = {x2maxy: null};
+
+};
+
+// --------------------------------------------------------------------
+// Dataset Manipulation
+// --------------------------------------------------------------------
+
+
+PlotKit.Layout.prototype.addDataset = function(setname, set_xy) {
+ this.datasets[setname] = set_xy;
+};
+
+PlotKit.Layout.prototype.removeDataset = function(setname, set_xy) {
+ this.datasets[setname] = null;
+};
+
+PlotKit.Layout.prototype.addDatasetFromTable = function(name, tableElement, xcol, ycol) {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+ var scrapeText = MochiKit.DOM.scrapeText;
+ var strip = MochiKit.Format.strip;
+
+ if (isNil(xcol))
+ xcol = 0;
+ if (isNil(ycol))
+ ycol = 1;
+
+ var rows = tableElement.tBodies[0].rows;
+ var data = new Array();
+ if (!isNil(rows)) {
+ for (var i = 0; i < rows.length; i++) {
+ data.push([parseFloat(strip(scrapeText(rows[i].cells[xcol]))),
+ parseFloat(strip(scrapeText(rows[i].cells[ycol])))]);
+ }
+ this.addDataset(name, data);
+ return true;
+ }
+ return false;
+};
+
+// --------------------------------------------------------------------
+// Evaluates the layout for the current data and style.
+// --------------------------------------------------------------------
+
+PlotKit.Layout.prototype.evaluate = function() {
+ this._evaluateLimits();
+ this._evaluateScales();
+ if (this.style == "bar") {
+ this._evaluateBarCharts();
+ this._evaluateBarTicks();
+ }
+ else if (this.style == "line") {
+ this._evaluateLineCharts();
+ this._evaluateLineTicks();
+ }
+ else if (this.style == "pie") {
+ this._evaluatePieCharts();
+ this._evaluatePieTicks();
+ }
+};
+
+
+
+// Given the fractional x, y positions, report the corresponding
+// x, y values.
+PlotKit.Layout.prototype.hitTest = function(x, y) {
+ // TODO: make this more efficient with better datastructures
+ // for this.bars, this.points and this.slices
+
+ var f = MochiKit.Format.twoDigitFloat;
+
+ if ((this.style == "bar") && this.bars && (this.bars.length > 0)) {
+ for (var i = 0; i < this.bars.length; i++) {
+ var bar = this.bars[i];
+ if ((x >= bar.x) && (x <= bar.x + bar.w)
+ && (y >= bar.y) && (y - bar.y <= bar.h))
+ return bar;
+ }
+ }
+
+ else if (this.style == "line") {
+ if (this.hitTestCache.x2maxy == null) {
+ this._regenerateHitTestCache();
+ }
+
+ // 1. find the xvalues that equal or closest to the give x
+ var xval = x / this.xscale;
+ var xvalues = this.hitTestCache.xvalues;
+ var xbefore = null;
+ var xafter = null;
+
+ for (var i = 1; i < xvalues.length; i++) {
+ if (xvalues[i] > xval) {
+ xbefore = xvalues[i-1];
+ xafter = xvalues[i];
+ break;
+ }
+ }
+
+ if ((xbefore != null)) {
+ var ybefore = this.hitTestCache.x2maxy[xbefore];
+ var yafter = this.hitTestCache.x2maxy[xafter];
+ var yval = (1.0 - y)/this.yscale;
+
+ // interpolate whether we will fall inside or outside
+ var gradient = (yafter - ybefore) / (xafter - xbefore);
+ var projmaxy = ybefore + gradient * (xval - xbefore);
+ if (projmaxy >= yval) {
+ // inside the highest curve (roughly)
+ var obj = {xval: xval, yval: yval,
+ xafter: xafter, yafter: yafter,
+ xbefore: xbefore, ybefore: ybefore,
+ yprojected: projmaxy
+ };
+ return obj;
+ }
+ }
+ }
+
+ else if (this.style == "pie") {
+ var dist = Math.sqrt((y-0.5)*(y-0.5) + (x-0.5)*(x-0.5));
+ if (dist > this.options.pieRadius)
+ return null;
+
+ // TODO: actually doesn't work if we don't know how the Canvas
+ // lays it out, need to fix!
+ var angle = Math.atan2(y - 0.5, x - 0.5) - Math.PI/2;
+ for (var i = 0; i < this.slices.length; i++) {
+ var slice = this.slices[i];
+ if (slice.startAngle < angle && slice.endAngle >= angle)
+ return slice;
+ }
+ }
+
+ return null;
+};
+
+// Reports valid position rectangle for X value (only valid for bar charts)
+PlotKit.Layout.prototype.rectForX = function(x) {
+ return null;
+};
+
+// Reports valid angles through which X value encloses (only valid for pie charts)
+PlotKit.Layout.prototype.angleRangeForX = function(x) {
+ return null;
+};
+
+// --------------------------------------------------------------------
+// START Internal Functions
+// --------------------------------------------------------------------
+
+PlotKit.Layout.prototype._evaluateLimits = function() {
+ // take all values from all datasets and find max and min
+ var map = MochiKit.Base.map;
+ var items = MochiKit.Base.items;
+ var itemgetter = MochiKit.Base.itemgetter;
+ var collapse = PlotKit.Base.collapse;
+ var listMin = MochiKit.Base.listMin;
+ var listMax = MochiKit.Base.listMax;
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+
+ var all = collapse(map(itemgetter(1), items(this.datasets)));
+
+ if (isNil(this.options.xAxis)) {
+ if (this.options.xOriginIsZero)
+ this.minxval = 0;
+ else
+ this.minxval = listMin(map(parseFloat, map(itemgetter(0), all)));
+ }
+
+ if (isNil(this.options.yAxis)) {
+ if (this.options.yOriginIsZero)
+ this.minyval = 0;
+ else
+ this.minyval = listMin(map(parseFloat, map(itemgetter(1), all)));
+ }
+
+ this.maxxval = listMax(map(parseFloat, map(itemgetter(0), all)));
+ this.maxyval = listMax(map(parseFloat, map(itemgetter(1), all)));
+};
+
+PlotKit.Layout.prototype._evaluateScales = function() {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+
+ this.xrange = this.maxxval - this.minxval;
+ if (this.xrange == 0)
+ this.xscale = 1.0;
+ else
+ this.xscale = 1/this.xrange;
+
+ this.yrange = this.maxyval - this.minyval;
+ if (this.yrange == 0)
+ this.yscale = 1.0;
+ else
+ this.yscale = 1/this.yrange;
+};
+
+PlotKit.Layout.prototype._uniqueXValues = function() {
+ var collapse = PlotKit.Base.collapse;
+ var map = MochiKit.Base.map;
+ var uniq = PlotKit.Base.uniq;
+ var getter = MochiKit.Base.itemgetter;
+
+ var xvalues = map(parseFloat, map(getter(0), collapse(map(getter(1), items(this.datasets)))));
+ xvalues.sort(MochiKit.Base.compare);
+ return uniq(xvalues);
+};
+
+// Create the bars
+PlotKit.Layout.prototype._evaluateBarCharts = function() {
+ var keys = MochiKit.Base.keys;
+ var items = MochiKit.Base.items;
+
+ var setCount = keys(this.datasets).length;
+
+ // work out how far separated values are
+ var xdelta = 10000000;
+ var xvalues = this._uniqueXValues();
+ for (var i = 1; i < xvalues.length; i++) {
+ xdelta = Math.min(Math.abs(xvalues[i] - xvalues[i-1]), xdelta);
+ }
+
+ var barWidth = 0;
+ var barWidthForSet = 0;
+ var barMargin = 0;
+ if (xvalues.length == 1) {
+ // note we have to do something smarter if we only plot one value
+ xdelta = 1.0;
+ this.xscale = 1.0;
+ this.minxval = xvalues[0];
+ barWidth = 1.0 * this.options.barWidthFillFraction;
+ barWidthForSet = barWidth/setCount;
+ barMargin = (1.0 - this.options.barWidthFillFraction)/2;
+ }
+ else {
+ // readjust xscale to fix with bar charts
+ this.xscale = (1.0 - xdelta/this.xrange)/this.xrange;
+ barWidth = xdelta * this.xscale * this.options.barWidthFillFraction;
+ barWidthForSet = barWidth / setCount;
+ barMargin = xdelta * this.xscale * (1.0 - this.options.barWidthFillFraction)/2;
+ }
+
+ this.minxdelta = xdelta; // need this for tick positions
+
+ // add all the rects
+ this.bars = new Array();
+ var i = 0;
+ for (var setName in this.datasets) {
+ var dataset = this.datasets[setName];
+ for (var j = 0; j < dataset.length; j++) {
+ var item = dataset[j];
+ var rect = {
+ x: ((parseFloat(item[0]) - this.minxval) * this.xscale) + (i * barWidthForSet) + barMargin,
+ y: 1.0 - ((parseFloat(item[1]) - this.minyval) * this.yscale),
+ w: barWidthForSet,
+ h: ((parseFloat(item[1]) - this.minyval) * this.yscale),
+ xval: parseFloat(item[0]),
+ yval: parseFloat(item[1]),
+ name: setName
+ };
+ this.bars.push(rect);
+ }
+ i++;
+ }
+};
+
+
+// Create the line charts
+PlotKit.Layout.prototype._evaluateLineCharts = function() {
+ var keys = MochiKit.Base.keys;
+ var items = MochiKit.Base.items;
+
+ var setCount = keys(this.datasets).length;
+
+ // add all the rects
+ this.points = new Array();
+ var i = 0;
+ for (var setName in this.datasets) {
+ var dataset = this.datasets[setName];
+ dataset.sort(function(a, b) { return compare(parseFloat(a[0]), parseFloat(b[0])); });
+ for (var j = 0; j < dataset.length; j++) {
+ var item = dataset[j];
+ var point = {
+ x: ((parseFloat(item[0]) - this.minxval) * this.xscale),
+ y: 1.0 - ((parseFloat(item[1]) - this.minyval) * this.yscale),
+ xval: parseFloat(item[0]),
+ yval: parseFloat(item[1]),
+ name: setName
+ };
+ this.points.push(point);
+ }
+ i++;
+ }
+};
+
+// Create the pie charts
+PlotKit.Layout.prototype._evaluatePieCharts = function() {
+ var items = MochiKit.Base.items;
+ var sum = MochiKit.Iter.sum;
+ var getter = MochiKit.Base.itemgetter;
+
+ var setCount = keys(this.datasets).length;
+
+ // we plot the y values of the first dataset
+ var dataset = items(this.datasets)[0][1];
+ var total = sum(map(getter(1), dataset));
+
+ this.slices = new Array();
+ var currentAngle = 0.0;
+ for (var i = 0; i < dataset.length; i++) {
+ var fraction = dataset[i][1] / total;
+ var startAngle = currentAngle * Math.PI * 2;
+ var endAngle = (currentAngle + fraction) * Math.PI * 2;
+
+ var slice = {fraction: fraction,
+ xval: dataset[i][0],
+ yval: dataset[i][1],
+ startAngle: startAngle,
+ endAngle: endAngle
+ };
+ this.slices.push(slice);
+ currentAngle += fraction;
+ }
+};
+
+PlotKit.Layout.prototype._evaluateLineTicksForXAxis = function() {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+
+ if (this.options.xTicks) {
+ // we use use specified ticks with optional labels
+
+ this.xticks = new Array();
+ var makeTicks = function(tick) {
+ var label = tick.label;
+ if (isNil(label))
+ label = tick.v.toString();
+ var pos = this.xscale * (tick.v - this.minxval);
+ this.xticks.push([pos, label]);
+ };
+ MochiKit.Iter.forEach(this.options.xTicks, bind(makeTicks, this));
+ }
+ else if (this.options.xNumberOfTicks) {
+ // we use defined number of ticks as hint to auto generate
+ var xvalues = this._uniqueXValues();
+ var roughSeparation = this.xrange / this.options.xNumberOfTicks;
+ var tickCount = 0;
+
+ this.xticks = new Array();
+ for (var i = 0; i <= xvalues.length; i++) {
+ if (xvalues[i] >= (tickCount) * roughSeparation) {
+ var pos = this.xscale * (xvalues[i] - this.minxval);
+ if ((pos > 1.0) || (pos < 0.0))
+ return;
+ this.xticks.push([pos, xvalues[i]]);
+ tickCount++;
+ }
+ if (tickCount > this.options.xNumberOfTicks)
+ break;
+ }
+ }
+};
+
+PlotKit.Layout.prototype._evaluateLineTicksForYAxis = function() {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+
+
+ if (this.options.yTicks) {
+ this.yticks = new Array();
+ var makeTicks = function(tick) {
+ var label = tick.label;
+ if (isNil(label))
+ label = tick.v.toString();
+ var pos = 1.0 - (this.yscale * (tick.v + this.minxval));
+ if ((pos < 0.0) || (pos > 1.0))
+ return;
+ this.yticks.push([pos, label]);
+ };
+ MochiKit.Iter.forEach(this.options.yTicks, bind(makeTicks, this));
+ }
+ else if (this.options.yNumberOfTicks) {
+ // We use the optionally defined number of ticks as a guide
+ this.yticks = new Array();
+
+ // if we get this separation right, we'll have good looking graphs
+ var roundInt = PlotKit.Base.roundInterval;
+ var prec = this.options.yTickPrecision;
+ var roughSeparation = roundInt(this.yrange,
+ this.options.yNumberOfTicks,
+ this.options.yTickPrecision);
+
+ for (var i = 0; i <= this.options.yNumberOfTicks; i++) {
+ var yval = this.minyval + (i * roughSeparation);
+ var pos = 1.0 - ((yval - this.minyval) * this.yscale);
+ this.yticks.push([pos, MochiKit.Format.roundToFixed(yval, 1)]);
+ }
+ }
+};
+
+PlotKit.Layout.prototype._evaluateLineTicks = function() {
+ this._evaluateLineTicksForXAxis();
+ this._evaluateLineTicksForYAxis();
+};
+
+PlotKit.Layout.prototype._evaluateBarTicks = function() {
+ this._evaluateLineTicks();
+ var centerInBar = function(tick) {
+ return [tick[0] + (this.minxdelta * this.xscale)/2, tick[1]];
+ };
+ this.xticks = MochiKit.Base.map(bind(centerInBar, this), this.xticks);
+};
+
+PlotKit.Layout.prototype._evaluatePieTicks = function() {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+ var formatter = MochiKit.Format.numberFormatter("#%");
+
+ this.xticks = new Array();
+ if (this.options.xTicks) {
+ // make a lookup dict for x->slice values
+ var lookup = new Array();
+ for (var i = 0; i < this.slices.length; i++) {
+ lookup[this.slices[i].xval] = this.slices[i];
+ }
+
+ for (var i =0; i < this.options.xTicks.length; i++) {
+ var tick = this.options.xTicks[i];
+ var slice = lookup[tick.v];
+ var label = tick.label;
+ if (slice) {
+ if (isNil(label))
+ label = tick.v.toString();
+ label += " (" + formatter(slice.fraction) + ")";
+ this.xticks.push([tick.v, label]);
+ }
+ }
+ }
+ else {
+ // we make our own labels from all the slices
+ for (var i =0; i < this.slices.length; i++) {
+ var slice = this.slices[i];
+ var label = slice.xval + " (" + formatter(slice.fraction) + ")";
+ this.xticks.push([slice.xval, label]);
+ }
+ }
+};
+
+PlotKit.Layout.prototype._regenerateHitTestCache = function() {
+ this.hitTestCache.xvalues = this._uniqueXValues();
+ this.hitTestCache.xlookup = new Array();
+ this.hitTestCache.x2maxy = new Array();
+
+ var listMax = MochiKit.Base.listMax;
+ var itemgetter = MochiKit.Base.itemgetter;
+ var map = MochiKit.Base.map;
+
+ // generate a lookup table for x values to y values
+ var setNames = keys(this.datasets);
+ for (var i = 0; i < setNames.length; i++) {
+ var dataset = this.datasets[setNames[i]];
+ for (var j = 0; j < dataset.length; j++) {
+ var xval = dataset[j][0];
+ var yval = dataset[j][1];
+ if (this.hitTestCache.xlookup[xval])
+ this.hitTestCache.xlookup[xval].push([yval, setNames[i]]);
+ else
+ this.hitTestCache.xlookup[xval] = [[yval, setNames[i]]];
+ }
+ }
+
+ for (var x in this.hitTestCache.xlookup) {
+ var yvals = this.hitTestCache.xlookup[x];
+ this.hitTestCache.x2maxy[x] = listMax(map(itemgetter(0), yvals));
+ }
+
+
+};
+
+// --------------------------------------------------------------------
+// END Internal Functions
+// --------------------------------------------------------------------
+
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/SVG.js b/activemq-web-console/src/main/webapp/js/plotkit/SVG.js
new file mode 100644
index 0000000000..ce2427cc4c
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/SVG.js
@@ -0,0 +1,677 @@
+/*
+ PlotKit SVG
+ ===========
+ SVG Renderer for PlotKit
+
+ Copyright
+ ---------
+ Copyright 2005,2006 (c) Alastair Tse
+ For use under the BSD license.
+*/
+
+// -------------------------------------------------------------------------
+// NOTES: - If you use XHTML1.1 strict, then you must include each MochiKit
+// file individuall.
+// - For IE support, you must include the AdobeSVG object hack.
+// See tests/svg.html for details.
+// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
+// Check required components
+// -------------------------------------------------------------------------
+
+try {
+ if (typeof(PlotKit.Layout) == 'undefined')
+ {
+ throw "";
+ }
+}
+catch (e) {
+ throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Layout"
+}
+
+
+// ---------------------------------------------------------------------------
+// SVG Renderer
+// ---------------------------------------------------------------------------
+
+PlotKit.SVGRenderer = function(element, layout, options) {
+ if (arguments.length > 0)
+ this.__init__(element, layout, options);
+};
+
+PlotKit.SVGRenderer.NAME = "PlotKit.SVGRenderer";
+PlotKit.SVGRenderer.VERSION = PlotKit.VERSION;
+
+PlotKit.SVGRenderer.__repr__ = function() {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+PlotKit.SVGRenderer.toString = function() {
+ return this.__repr__();
+}
+
+PlotKit.SVGRenderer.isSupported = function() {
+ // TODO
+ return true;
+};
+
+PlotKit.SVGRenderer.prototype.__init__ = function(element, layout, options) {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+
+ // default options
+ this.options = {
+ "drawBackground": true,
+ "backgroundColor": Color.whiteColor(),
+ "padding": {left: 30, right: 30, top: 5, bottom: 10},
+ "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[1]),
+ "strokeColor": Color.whiteColor(),
+ "strokeColorTransform": "asStrokeColor",
+ "strokeWidth": 0.5,
+ "shouldFill": true,
+ "shouldStroke": true,
+ "drawXAxis": true,
+ "drawYAxis": true,
+ "axisLineColor": Color.blackColor(),
+ "axisLineWidth": 0.5,
+ "axisTickSize": 3,
+ "axisLabelColor": Color.blackColor(),
+ "axisLabelFont": "Arial",
+ "axisLabelFontSize": 9,
+ "axisLabelWidth": 50,
+ "axisLabelUseDiv": true,
+ "pieRadius": 0.4,
+ "enableEvents": true
+ };
+
+ MochiKit.Base.update(this.options, options ? options : {});
+ this.layout = layout;
+ this.style = layout.style;
+ this.element = MochiKit.DOM.getElement(element);
+ this.container = this.element.parentNode;
+ this.height = parseInt(this.element.getAttribute("height"));
+ this.width = parseInt(this.element.getAttribute("width"));
+ this.document = document;
+ this.root = this.element;
+
+ // Adobe SVG Support:
+ // - if an exception is thrown, then no Adobe SVG Plugin support.
+ try {
+ this.document = this.element.getSVGDocument();
+ this.root = isNil(this.document.documentElement) ? this.element : this.document.documentElement;
+ }
+ catch (e) {
+ }
+
+ this.element.style.zIndex = 1;
+
+ if (isNil(this.element))
+ throw "SVGRenderer() - passed SVG object is not found";
+
+ if (isNil(this.container) || this.container.nodeName.toLowerCase() != "div")
+ throw "SVGRenderer() - No DIV's around the SVG.";
+
+ // internal state
+ this.xlabels = new Array();
+ this.ylabels = new Array();
+
+ // initialise some meta structures in SVG
+ this.defs = this.createSVGElement("defs");
+
+ this.area = {
+ x: this.options.padding.left,
+ y: this.options.padding.top,
+ w: this.width - this.options.padding.left - this.options.padding.right,
+ h: this.height - this.options.padding.top - this.options.padding.bottom
+ };
+
+ MochiKit.DOM.updateNodeAttributes(this.container,
+ {"style":{ "position": "relative", "width": this.width + "px"}});
+
+
+};
+
+
+PlotKit.SVGRenderer.prototype.render = function() {
+ if (this.options.drawBackground)
+ this._renderBackground();
+
+ if (this.style == "bar") {
+ this._renderBarChart();
+ this._renderBarAxis();
+ }
+ else if (this.style == "pie") {
+ this._renderPieChart();
+ this._renderPieAxis();
+ }
+ else if (this.style == "line") {
+ this._renderLineChart();
+ this._renderLineAxis();
+ }
+};
+
+PlotKit.SVGRenderer.prototype._renderBarOrLine = function(data, plotFunc, startFunc, endFunc) {
+
+ var colorCount = this.options.colorScheme.length;
+ var colorScheme = this.options.colorScheme;
+ var setNames = MochiKit.Base.keys(this.layout.datasets);
+ var setCount = setNames.length;
+
+ for (var i = 0; i < setCount; i++) {
+ var setName = setNames[i];
+ var attrs = new Array();
+ var color = colorScheme[i%colorCount];
+
+ if (this.options.shouldFill)
+ attrs["fill"] = color.toRGBString();
+ else
+ attrs["fill"] = "none";
+
+ if (this.options.shouldStroke &&
+ (this.options.strokeColor || this.options.strokeColorTransform)) {
+ if (this.options.strokeColor)
+ attrs["stroke"] = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
+ attrs["strokeWidth"] = this.options.strokeWidth;
+ }
+
+ if (startFunc)
+ startFunc(attrs);
+
+ var forEachFunc = function(obj) {
+ if (obj.name == setName)
+ plotFunc(attrs, obj);
+ };
+
+ MochiKit.Iter.forEach(data, bind(forEachFunc, this));
+ if (endFunc)
+ endFunc(attrs);
+ }
+};
+
+PlotKit.SVGRenderer.prototype._renderBarChart = function() {
+ var bind = MochiKit.Base.bind;
+
+ var drawRect = function(attrs, bar) {
+ var x = this.area.w * bar.x + this.area.x;
+ var y = this.area.h * bar.y + this.area.y;
+ var w = this.area.w * bar.w;
+ var h = this.area.h * bar.h;
+ this._drawRect(x, y, w, h, attrs);
+ };
+ this._renderBarOrLine(this.layout.bars, bind(drawRect, this));
+};
+
+PlotKit.SVGRenderer.prototype._renderLineChart = function() {
+ var bind = MochiKit.Base.bind;
+
+ var addPoint = function(attrs, point) {
+ this._tempPointsBuffer += (this.area.w * point.x + this.area.x) + "," +
+ (this.area.h * point.y + this.area.y) + " ";
+ };
+
+ var startLine = function(attrs) {
+ this._tempPointsBuffer = "";
+ this._tempPointsBuffer += (this.area.x) + "," + (this.area.y+this.area.h) + " ";
+ };
+
+ var endLine = function(attrs) {
+ this._tempPointsBuffer += (this.area.w + this.area.x) + "," +(this.area.h + this.area.y);
+ attrs["points"] = this._tempPointsBuffer;
+ var elem = this.createSVGElement("polygon", attrs);
+ this.root.appendChild(elem);
+ };
+
+ this._renderBarOrLine(this.layout.points,
+ bind(addPoint, this),
+ bind(startLine, this),
+ bind(endLine, this));
+};
+
+
+PlotKit.SVGRenderer.prototype._renderPieChart = function() {
+ var colorCount = this.options.colorScheme.length;
+ var slices = this.layout.slices;
+
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var radius = Math.min(this.area.w * this.options.pieRadius,
+ this.area.h * this.options.pieRadius);
+
+ // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1
+ // so we have to subtract 90 degrees to make it start at y = 1, x = 0
+
+ // workaround if we only have 1 slice of 100%
+ if (slices.length == 1 && (Math.abs(slices[0].startAngle) - Math.abs(slices[0].endAngle) < 0.1)) {
+ var attrs = {"cx": centerx , "cy": centery , "r": radius };
+ var color = this.options.colorScheme[0];
+ if (this.options.shouldFill)
+ attrs["fill"] = color.toRGBString();
+ else
+ attrs["fill"] = "none";
+
+ if (this.options.shouldStroke &&
+ (this.options.strokeColor || this.options.strokeColorTransform)) {
+ if (this.options.strokeColor)
+ attrs["stroke"] = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
+ attrs["style"] = "stroke-width: " + this.options.strokeWidth;
+ }
+
+ this.root.appendChild(this.createSVGElement("circle", attrs));
+ return;
+ }
+
+ for (var i = 0; i < slices.length; i++) {
+ var attrs = new Array();
+ var color = this.options.colorScheme[i%colorCount];
+ if (this.options.shouldFill)
+ attrs["fill"] = color.toRGBString();
+ else
+ attrs["fill"] = "none";
+
+ if (this.options.shouldStroke &&
+ (this.options.strokeColor || this.options.strokeColorTransform)) {
+ if (this.options.strokeColor)
+ attrs["stroke"] = this.options.strokeColor.toRGBString();
+ else if (this.options.strokeColorTransform)
+ attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString();
+ attrs["style"] = "stroke-width:" + this.options.strokeWidth;
+ }
+
+ var largearc = 0;
+ if (Math.abs(slices[i].endAngle - slices[i].startAngle) > Math.PI)
+ largearc = 1;
+ var x1 = Math.cos(slices[i].startAngle - Math.PI/2) * radius;
+ var y1 = Math.sin(slices[i].startAngle - Math.PI/2) * radius;
+ var x2 = Math.cos(slices[i].endAngle - Math.PI/2) * radius;
+ var y2 = Math.sin(slices[i].endAngle - Math.PI/2) * radius;
+ var rx = x2 - x1;
+ var ry = y2 - y1;
+
+ var pathString = "M" + centerx + "," + centery + " ";
+ pathString += "l" + x1 + "," + y1 + " ";
+ pathString += "a" + radius + "," + radius + " 0 " + largearc + ",1 " + rx + "," + ry + " z";
+
+ attrs["d"] = pathString;
+
+ var elem = this.createSVGElement("path", attrs);
+ this.root.appendChild(elem);
+ }
+};
+
+PlotKit.SVGRenderer.prototype._renderBarAxis = function() {
+ this._renderAxis();
+}
+
+PlotKit.SVGRenderer.prototype._renderLineAxis = function() {
+ this._renderAxis();
+};
+
+
+PlotKit.SVGRenderer.prototype._renderAxis = function() {
+
+ if (!this.options.drawXAxis && !this.options.drawYAxis)
+ return;
+
+ var labelStyle = {"style":
+ {"position": "absolute",
+ "textAlign": "center",
+ "fontSize": this.options.axisLabelFontSize + "px",
+ "zIndex": 10,
+ "color": this.options.axisLabelColor.toRGBString(),
+ "width": this.options.axisLabelWidth + "px",
+ "overflow": "hidden"
+ }
+ };
+
+ // axis lines
+ var lineAttrs = {
+ "stroke": this.options.axisLineColor.toRGBString(),
+ "strokeWidth": this.options.axisLineWidth
+ };
+
+
+ if (this.options.drawYAxis) {
+ if (this.layout.yticks) {
+ var drawTick = function(tick) {
+ var x = this.area.x;
+ var y = this.area.y + tick[0] * this.area.h;
+ this._drawLine(x, y, x - 3, y, lineAttrs);
+
+ if (this.options.axisLabelUseDiv) {
+ var label = DIV(labelStyle, tick[1]);
+ label.style.top = (y - this.options.axisLabelFontSize) + "px";
+ label.style.left = (x - this.options.padding.left + this.options.axisTickSize) + "px";
+ label.style.textAlign = "left";
+ label.style.width = (this.options.padding.left - 3) + "px";
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ this.ylabels.push(label);
+ }
+ else {
+ var attrs = {
+ y: y + 3,
+ x: (x - this.options.padding.left + 3),
+ width: (this.options.padding.left - this.options.axisTickSize) + "px",
+ height: (this.options.axisLabelFontSize + 3) + "px",
+ fontFamily: "Arial",
+ fontSize: this.options.axisLabelFontSize + "px",
+ fill: this.options.axisLabelColor.toRGBString()
+ };
+
+ /* we can do clipping just like DIVs
+ http://www.xml.com/pub/a/2004/06/02/svgtype.html */
+ /*
+ var mask = this.createSVGElement("mask", {id: "mask" + tick[0]});
+ var maskShape = this.createSVGElement("rect",
+ {y: y + 3,
+ x: (x - this.options.padding.left + 3),
+ width: (this.options.padding.left - this.options.axisTickSize) + "px",
+ height: (this.options.axisLabelFontSize + 3) + "px",
+ style: {"fill": "#ffffff", "stroke": "#000000"}});
+ mask.appendChild(maskShape);
+ this.defs.appendChild(mask);
+
+ attrs["filter"] = "url(#mask" + tick[0] + ")";
+ */
+
+ var label = this.createSVGElement("text", attrs);
+ label.appendChild(this.document.createTextNode(tick[1]));
+ this.root.appendChild(label);
+ }
+ };
+
+ MochiKit.Iter.forEach(this.layout.yticks, bind(drawTick, this));
+ }
+
+ this._drawLine(this.area.x, this.area.y, this.area.x, this.area.y + this.area.h, lineAttrs);
+ }
+
+ if (this.options.drawXAxis) {
+ if (this.layout.xticks) {
+ var drawTick = function(tick) {
+ var x = this.area.x + tick[0] * this.area.w;
+ var y = this.area.y + this.area.h;
+ this._drawLine(x, y, x, y + this.options.axisTickSize, lineAttrs);
+
+ if (this.options.axisLabelUseDiv) {
+ var label = DIV(labelStyle, tick[1]);
+ label.style.top = (y + this.options.axisTickSize) + "px";
+ label.style.left = (x - this.options.axisLabelWidth/2) + "px";
+ label.style.textAlign = "center";
+ label.style.width = this.options.axisLabelWidth + "px";
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ this.xlabels.push(label);
+ }
+ else {
+ var attrs = {
+ y: (y + this.options.axisTickSize + this.options.axisLabelFontSize),
+ x: x - 3,
+ width: this.options.axisLabelWidth + "px",
+ height: (this.options.axisLabelFontSize + 3) + "px",
+ fontFamily: "Arial",
+ fontSize: this.options.axisLabelFontSize + "px",
+ fill: this.options.axisLabelColor.toRGBString(),
+ textAnchor: "middle"
+ };
+ var label = this.createSVGElement("text", attrs);
+ label.appendChild(this.document.createTextNode(tick[1]));
+ this.root.appendChild(label);
+ }
+ };
+
+ MochiKit.Iter.forEach(this.layout.xticks, bind(drawTick, this));
+ }
+
+ this._drawLine(this.area.x, this.area.y + this.area.h, this.area.x + this.area.w, this.area.y + this.area.h, lineAttrs)
+ }
+};
+
+PlotKit.SVGRenderer.prototype._renderPieAxis = function() {
+
+ if (this.layout.xticks) {
+ // make a lookup dict for x->slice values
+ var lookup = new Array();
+ for (var i = 0; i < this.layout.slices.length; i++) {
+ lookup[this.layout.slices[i].xval] = this.layout.slices[i];
+ }
+
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var radius = Math.min(this.area.w * this.options.pieRadius + 10,
+ this.area.h * this.options.pieRadius + 10);
+ var labelWidth = this.options.axisLabelWidth;
+
+ for (var i = 0; i < this.layout.xticks.length; i++) {
+ var slice = lookup[this.layout.xticks[i][0]];
+ if (MochiKit.Base.isUndefinedOrNull(slice))
+ continue;
+
+
+ var angle = (slice.startAngle + slice.endAngle)/2;
+ // normalize the angle
+ var normalisedAngle = angle;
+ if (normalisedAngle > Math.PI * 2)
+ normalisedAngle = normalisedAngle - Math.PI * 2;
+ else if (normalisedAngle < 0)
+ normalisedAngle = normalisedAngle + Math.PI * 2;
+
+ var labelx = centerx + Math.sin(normalisedAngle) * (radius + 10);
+ var labely = centery - Math.cos(normalisedAngle) * (radius + 10);
+
+ var attrib = {
+ "position": "absolute",
+ "zIndex": 11,
+ "width": labelWidth + "px",
+ "fontSize": this.options.axisLabelFontSize + "px",
+ "overflow": "hidden",
+ "color": this.options.axisLabelColor.toHexString()
+ };
+
+ var svgattrib = {
+ "width": labelWidth + "px",
+ "fontSize": this.options.axisLabelFontSize + "px",
+ "height": (this.options.axisLabelFontSize + 3) + "px",
+ "fill": this.options.axisLabelColor.toRGBString()
+ };
+
+ if (normalisedAngle <= Math.PI * 0.5) {
+ // text on top and align left
+ MochiKit.Base.update(attrib, {
+ 'textAlign': 'left', 'verticalAlign': 'top',
+ 'left': labelx + 'px',
+ 'top': (labely - this.options.axisLabelFontSize) + "px"
+ });
+ MochiKit.Base.update(svgattrib, {
+ "x": labelx,
+ "y" :(labely - this.options.axisLabelFontSize),
+ "textAnchor": "left"
+ });
+ }
+ else if ((normalisedAngle > Math.PI * 0.5) && (normalisedAngle <= Math.PI)) {
+ // text on bottom and align left
+ MochiKit.Base.update(attrib, {
+ 'textAlign': 'left', 'verticalAlign': 'bottom',
+ 'left': labelx + 'px',
+ 'top': labely + "px"
+ });
+ MochiKit.Base.update(svgattrib, {
+ 'textAnchor': 'left',
+ 'x': labelx,
+ 'y': labely
+ });
+ }
+ else if ((normalisedAngle > Math.PI) && (normalisedAngle <= Math.PI*1.5)) {
+ // text on bottom and align right
+ MochiKit.Base.update(attrib, {
+ 'textAlign': 'right', 'verticalAlign': 'bottom',
+ 'left': labelx + 'px',
+ 'top': labely + "px"
+ });
+ MochiKit.Base.update(svgattrib, {
+ 'textAnchor': 'right',
+ 'x': labelx - labelWidth,
+ 'y': labely
+ });
+ }
+ else {
+ // text on top and align right
+ MochiKit.Base.update(attrib, {
+ 'textAlign': 'left', 'verticalAlign': 'bottom',
+ 'left': labelx + 'px',
+ 'top': labely + "px"
+ });
+ MochiKit.Base.update(svgattrib, {
+ 'textAnchor': 'left',
+ 'x': labelx - labelWidth,
+ 'y': labely - this.options.axisLabelFontSize
+ });
+ }
+
+ if (this.options.axisLabelUseDiv) {
+ var label = DIV({'style': attrib}, this.layout.xticks[i][1]);
+ this.xlabels.push(label);
+ MochiKit.DOM.appendChildNodes(this.container, label);
+ }
+ else {
+ var label = this.createSVGElement("text", svgattrib);
+ label.appendChild(this.document.createTextNode(this.layout.xticks[i][1]))
+ this.root.appendChild(label);
+ }
+ }
+
+ }
+};
+
+PlotKit.SVGRenderer.prototype._renderBackground = function() {
+ var opts = {"stroke": "none",
+ "fill": this.options.backgroundColor.toRGBString()
+ };
+ this._drawRect(0, 0, this.width, this.height, opts);
+};
+
+PlotKit.SVGRenderer.prototype._drawRect = function(x, y, w, h, moreattrs) {
+ var attrs = {x: x + "px", y: y + "px", width: w + "px", height: h + "px"};
+ if (moreattrs)
+ MochiKit.Base.update(attrs, moreattrs);
+
+ var elem = this.createSVGElement("rect", attrs);
+ this.root.appendChild(elem);
+};
+
+PlotKit.SVGRenderer.prototype._drawLine = function(x1, y1, x2, y2, moreattrs) {
+ var attrs = {x1: x1 + "px", y1: y1 + "px", x2: x2 + "px", y2: y2 + "px"};
+ if (moreattrs)
+ MochiKit.Base.update(attrs, moreattrs);
+
+ var elem = this.createSVGElement("line", attrs);
+ this.root.appendChild(elem);
+}
+
+PlotKit.SVGRenderer.prototype.clear = function() {
+ while(this.element.firstChild) {
+ this.element.removeChild(this.element.firstChild);
+ }
+
+ if (this.options.axisLabelUseDiv) {
+ for (var i = 0; i < this.xlabels.length; i++) {
+ MochiKit.DOM.removeElement(this.xlabels[i]);
+ }
+ for (var i = 0; i < this.ylabels.length; i++) {
+ MochiKit.DOM.removeElement(this.ylabels[i]);
+ }
+ }
+ this.xlabels = new Array();
+ this.ylabels = new Array();
+};
+
+PlotKit.SVGRenderer.prototype.createSVGElement = function(name, attrs) {
+ var isNil = MochiKit.Base.isUndefinedOrNull;
+ var elem;
+ var doc = isNil(this.document) ? document : this.document;
+
+ try {
+ elem = doc.createElementNS("http://www.w3.org/2000/svg", name);
+ }
+ catch (e) {
+ elem = doc.createElement(name);
+ elem.setAttribute("xmlns", "http://www.w3.org/2000/svg");
+ }
+
+ if (attrs)
+ MochiKit.DOM.updateNodeAttributes(elem, attrs);
+
+ // TODO: we don't completely emulate the MochiKit.DOM.createElement
+ // as we don't care about nodes contained. We really should though.
+
+ return elem;
+
+};
+
+PlotKit.SVGRenderer.SVGNS = 'http://www.w3.org/2000/svg';
+
+PlotKit.SVGRenderer.SVG = function(attrs) {
+ // we have to do things differently for IE+AdobeSVG.
+ // My guess this works (via trial and error) is that we need to
+ // have an SVG object in order to use SVGDocument.createElementNS
+ // but IE doesn't allow us to that.
+
+ var ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
+ var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ if (ie && (ie[1] >= 6) && (!opera)) {
+ var width = attrs["width"] ? attrs["width"] : "100";
+ var height = attrs["height"] ? attrs["height"] : "100";
+ var eid = attrs["id"] ? attrs["id"] : "notunique";
+
+ var html = '';
+
+ var canvas = document.createElement(html);
+
+ // create embedded SVG inside SVG.
+ var group = canvas.getSVGDocument().createElementNS(PlotKit.SVGRenderer.SVGNS, "svg");
+ group.setAttribute("width", width);
+ group.setAttribute("height", height);
+ canvas.getSVGDocument().appendChild(group);
+
+ return canvas;
+ }
+ else {
+ return PlotKit.SVGRenderer.prototype.createSVGElement("svg", attrs);
+ }
+};
+
+PlotKit.SVGRenderer.isSupported = function() {
+ var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ var ieVersion = navigator.appVersion.match(/MSIE (\d\.\d)/);
+ var safariVersion = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
+ var operaVersion = navigator.userAgent.match(/Opera\/(\d*\.\d*)/);
+ var mozillaVersion = navigator.userAgent.match(/rv:(\d*\.\d*).*Gecko/);
+
+
+ if (ieVersion && (ieVersion[1] >= 6) && !isOpera) {
+ var dummysvg = document.createElement('');
+ try {
+ dummysvg.getSVGDocument();
+ dummysvg = null;
+ return true;
+ }
+ catch (e) {
+ return false;
+ }
+ }
+
+ /* support not really there yet. no text and paths are buggy
+ if (safariVersion && (safariVersion[1] > 419))
+ return true;
+ */
+
+ if (operaVersion && (operaVersion[1] > 8.9))
+ return true
+
+ if (mozillaVersion && (mozillaVersion > 1.7))
+ return true;
+
+ return false;
+};
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/SweetCanvas.js b/activemq-web-console/src/main/webapp/js/plotkit/SweetCanvas.js
new file mode 100644
index 0000000000..07492ae847
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/SweetCanvas.js
@@ -0,0 +1,281 @@
+/*
+ PlotKit Sweet Canvas Renderer
+ =============================
+ Canvas Renderer for PlotKit which looks pretty!
+
+ Copyright
+ ---------
+ Copyright 2005,2006 (c) Alastair Tse
+ For use under the BSD license.
+*/
+
+// -------------------------------------------------------------------------
+// Check required components
+// -------------------------------------------------------------------------
+
+try {
+ if (typeof(PlotKit.CanvasRenderer) == 'undefined')
+ {
+ throw "";
+ }
+}
+catch (e) {
+ throw "SweetCanvas depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Layout, Canvas}"
+}
+
+
+if (typeof(PlotKit.SweetCanvasRenderer) == 'undefined') {
+ PlotKit.SweetCanvasRenderer = {};
+}
+
+PlotKit.SweetCanvasRenderer = function(element, layout, options) {
+ if (arguments.length > 0) {
+ this.__init__(element, layout, options);
+ }
+};
+
+PlotKit.SweetCanvasRenderer.NAME = "PlotKit.SweetCanvasRenderer";
+PlotKit.SweetCanvasRenderer.VERSION = PlotKit.VERSION;
+
+PlotKit.SweetCanvasRenderer.__repr__ = function() {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+PlotKit.SweetCanvasRenderer.toString = function() {
+ return this.__repr__();
+};
+
+// ---------------------------------------------------------------------
+// Subclassing Magic
+// ---------------------------------------------------------------------
+
+PlotKit.SweetCanvasRenderer.prototype = new PlotKit.CanvasRenderer();
+PlotKit.SweetCanvasRenderer.prototype.constructor = PlotKit.SweetCanvasRenderer;
+PlotKit.SweetCanvasRenderer.__super__ = PlotKit.CanvasRenderer.prototype;
+
+// ---------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------
+
+PlotKit.SweetCanvasRenderer.prototype.__init__ = function(el, layout, opts) {
+ var moreOpts = PlotKit.Base.officeBlue();
+ MochiKit.Base.update(moreOpts, opts);
+ PlotKit.SweetCanvasRenderer.__super__.__init__.call(this, el, layout, moreOpts);
+};
+
+// ---------------------------------------------------------------------
+// Extended Plotting Functions
+// ---------------------------------------------------------------------
+
+PlotKit.SweetCanvasRenderer.prototype._renderBarChart = function() {
+ var bind = MochiKit.Base.bind;
+ var shadowColor = Color.blackColor().colorWithAlpha(0.1).toRGBString();
+
+ var prepareFakeShadow = function(context, x, y, w, h) {
+ context.fillStyle = shadowColor;
+ context.fillRect(x-2, y-2, w+4, h+2);
+ context.fillStyle = shadowColor;
+ context.fillRect(x-1, y-1, w+2, h+1);
+ };
+
+ var colorCount = this.options.colorScheme.length;
+ var colorScheme = this.options.colorScheme;
+ var setNames = MochiKit.Base.keys(this.layout.datasets);
+ var setCount = setNames.length;
+
+ var chooseColor = function(name) {
+ for (var i = 0; i < setCount; i++) {
+ if (name == setNames[i])
+ return colorScheme[i%colorCount];
+ }
+ return colorScheme[0];
+ };
+
+ var drawRect = function(context, bar) {
+ var x = this.area.w * bar.x + this.area.x;
+ var y = this.area.h * bar.y + this.area.y;
+ var w = this.area.w * bar.w;
+ var h = this.area.h * bar.h;
+
+ if ((w < 1) || (h < 1))
+ return;
+
+ context.save();
+
+ context.shadowBlur = 5.0;
+ context.shadowColor = Color.fromHexString("#888888").toRGBString();
+
+ if (this.isIE) {
+ context.save();
+ context.fillStyle = "#cccccc";
+ context.fillRect(x-2, y-2, w+4, h+2);
+ context.restore();
+ }
+ else {
+ prepareFakeShadow(context, x, y, w, h);
+ }
+
+ context.fillStyle = chooseColor(bar.name).toRGBString();
+ context.fillRect(x, y, w, h);
+
+ context.shadowBlur = 0;
+ context.strokeStyle = Color.whiteColor().toRGBString();
+ context.lineWidth = 2.0;
+
+ context.strokeRect(x, y, w, h);
+
+ context.restore();
+
+ };
+ this._renderBarChartWrap(this.layout.bars, bind(drawRect, this));
+};
+
+PlotKit.CanvasRenderer.prototype._renderLineChart = function() {
+ var context = this.element.getContext("2d");
+ var colorCount = this.options.colorScheme.length;
+ var colorScheme = this.options.colorScheme;
+ var setNames = MochiKit.Base.keys(this.layout.datasets);
+ var setCount = setNames.length;
+ var bind = MochiKit.Base.bind;
+
+
+ for (var i = 0; i < setCount; i++) {
+ var setName = setNames[i];
+ var color = colorScheme[i%colorCount];
+ var strokeX = this.options.strokeColorTransform;
+
+ // setup graphics context
+ context.save();
+
+ // create paths
+ var makePath = function() {
+ context.beginPath();
+ context.moveTo(this.area.x, this.area.y + this.area.h);
+ var addPoint = function(context, point) {
+ if (point.name == setName)
+ context.lineTo(this.area.w * point.x + this.area.x,
+ this.area.h * point.y + this.area.y);
+ };
+ MochiKit.Iter.forEach(this.layout.points, partial(addPoint, context), this);
+ context.lineTo(this.area.w + this.area.x,
+ this.area.h + this.area.y);
+ context.lineTo(this.area.x, this.area.y + this.area.h);
+ context.closePath();
+ };
+
+ // faux shadow for firefox
+ context.save();
+ if (this.isIE) {
+ context.fillStyle = "#cccccc";
+ }
+ else {
+ context.fillStyle = Color.blackColor().colorWithAlpha(0.2).toRGBString();
+ }
+
+ context.translate(-1, -2);
+ bind(makePath, this)();
+ context.fill();
+ context.restore();
+
+ context.shadowBlur = 5.0;
+ context.shadowColor = Color.fromHexString("#888888").toRGBString();
+ context.fillStyle = color.toRGBString();
+ context.lineWidth = 2.0;
+ context.strokeStyle = Color.whiteColor().toRGBString();
+
+ bind(makePath, this)();
+ context.fill();
+ bind(makePath, this)();
+ context.stroke();
+
+ context.restore();
+ }
+};
+
+PlotKit.CanvasRenderer.prototype._renderPieChart = function() {
+ var context = this.element.getContext("2d");
+
+ var colorCount = this.options.colorScheme.length;
+ var slices = this.layout.slices;
+
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var radius = Math.min(this.area.w * this.options.pieRadius,
+ this.area.h * this.options.pieRadius);
+
+ if (this.isIE) {
+ centerx = parseInt(centerx);
+ centery = parseInt(centery);
+ radius = parseInt(radius);
+ }
+
+ // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1
+ // so we have to subtract 90 degrees to make it start at y = 1, x = 0
+
+ if (!this.isIE) {
+ context.save();
+ var shadowColor = Color.blackColor().colorWithAlpha(0.2);
+ context.fillStyle = shadowColor.toRGBString();
+ context.shadowBlur = 5.0;
+ context.shadowColor = Color.fromHexString("#888888").toRGBString();
+ context.translate(1, 1);
+ context.beginPath();
+ context.moveTo(centerx, centery);
+ context.arc(centerx, centery, radius + 2, 0, Math.PI*2, false);
+ context.closePath();
+ context.fill();
+ context.restore();
+ }
+
+ context.save();
+ context.strokeStyle = Color.whiteColor().toRGBString();
+ context.lineWidth = 2.0;
+ for (var i = 0; i < slices.length; i++) {
+ var color = this.options.colorScheme[i%colorCount];
+ context.fillStyle = color.toRGBString();
+
+ var makePath = function() {
+ context.beginPath();
+ context.moveTo(centerx, centery);
+ context.arc(centerx, centery, radius,
+ slices[i].startAngle - Math.PI/2,
+ slices[i].endAngle - Math.PI/2,
+ false);
+ context.lineTo(centerx, centery);
+ context.closePath();
+ };
+
+ if (Math.abs(slices[i].startAngle - slices[i].endAngle) > 0.0001) {
+ makePath();
+ context.fill();
+ makePath();
+ context.stroke();
+ }
+ }
+ context.restore();
+};
+
+PlotKit.SweetCanvasRenderer.prototype._renderBackground = function() {
+ var context = this.element.getContext("2d");
+
+ if (this.layout.style == "bar" || this.layout.style == "line") {
+ context.save();
+ context.fillStyle = this.options.backgroundColor.toRGBString();
+ context.fillRect(this.area.x, this.area.y, this.area.w, this.area.h);
+ context.strokeStyle = Color.whiteColor().toRGBString();
+ context.lineWidth = 1.0;
+ for (var i = 0; i < this.layout.yticks.length; i++) {
+ var y = this.layout.yticks[i][0] * this.area.h + this.area.y;
+ var x = this.area.x;
+ context.beginPath();
+ context.moveTo(x, y);
+ context.lineTo(x + this.area.w, y);
+ context.closePath();
+ context.stroke();
+ }
+ context.restore();
+ }
+ else {
+ PlotKit.SweetCanvasRenderer.__super__._renderBackground.call(this);
+ }
+};
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/SweetSVG.js b/activemq-web-console/src/main/webapp/js/plotkit/SweetSVG.js
new file mode 100644
index 0000000000..6fd6d479c9
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/SweetSVG.js
@@ -0,0 +1,196 @@
+/*
+ PlotKit Sweet SVG Renderer
+ ==========================
+ SVG Renderer for PlotKit which looks pretty!
+
+ Copyright
+ ---------
+ Copyright 2005,2006 (c) Alastair Tse
+ For use under the BSD license.
+*/
+
+
+// -------------------------------------------------------------------------
+// Check required components
+// -------------------------------------------------------------------------
+
+try {
+ if (typeof(PlotKit.SVGRenderer) == 'undefined')
+ {
+ throw "";
+ }
+}
+catch (e) {
+ throw "SweetSVG depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Layout, SVG}"
+}
+
+
+if (typeof(PlotKit.SweetSVGRenderer) == 'undefined') {
+ PlotKit.SweetSVGRenderer = {};
+}
+
+PlotKit.SweetSVGRenderer = function(element, layout, options) {
+ if (arguments.length > 0) {
+ this.__init__(element, layout, options);
+ }
+};
+
+PlotKit.SweetSVGRenderer.NAME = "PlotKit.SweetSVGRenderer";
+PlotKit.SweetSVGRenderer.VERSION = PlotKit.VERSION;
+
+PlotKit.SweetSVGRenderer.__repr__ = function() {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+PlotKit.SweetSVGRenderer.toString = function() {
+ return this.__repr__();
+};
+
+// ---------------------------------------------------------------------
+// Subclassing Magic
+// ---------------------------------------------------------------------
+
+PlotKit.SweetSVGRenderer.prototype = new PlotKit.SVGRenderer();
+PlotKit.SweetSVGRenderer.prototype.constructor = PlotKit.SweetSVGRenderer;
+PlotKit.SweetSVGRenderer.__super__ = PlotKit.SVGRenderer.prototype;
+
+// ---------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------
+
+PlotKit.SweetSVGRenderer.prototype.__init__ = function(element, layout, options) {
+ var moreOpts = PlotKit.Base.officeBlue();
+ MochiKit.Base.update(moreOpts, options);
+ PlotKit.SweetSVGRenderer.__super__.__init__.call(this, element, layout, moreOpts);
+ //this._addDropShadowFilter();
+};
+
+PlotKit.SweetSVGRenderer.prototype._addDropShadowFilter = function() {
+ var filter = this.createSVGElement("filter", {x: 0, y: 0, "id":"dropShadow"});
+ var goffset = this.createSVGElement("feOffset",
+ {"in": "SourceGraphic", "dx": 0, "dy": 0, "result": "topCopy"});
+ var blur = this.createSVGElement("feGaussianBlur",
+ {"in": "SourceAlpha", "StdDeviation": 2, "result": "shadow"});
+ var soffset = this.createSVGElement("feOffset",
+ {"in": "shadow", "dx": -1, "dy": -2, "result":"movedShadow"});
+ var merge = this.createSVGElement("feMerge");
+ var gmerge = this.createSVGElement("feMergeNode", {"in":"topCopy"});
+ var smerge = this.createSVGElement("feMergeNode", {"in":"movedShadow"});
+
+ merge.appendChild(gmerge);
+ merge.appendChild(smerge);
+ filter.appendChild(goffset);
+ filter.appendChild(blur);
+ filter.appendChild(soffset);
+ filter.appendChild(merge);
+ this.defs.appendChild(filter);
+};
+
+// ---------------------------------------------------------------------
+// Extended Plotting Functions
+// ---------------------------------------------------------------------
+
+PlotKit.SweetSVGRenderer.prototype._renderBarChart = function() {
+ var bind = MochiKit.Base.bind;
+ var shadowColor = Color.blackColor().toRGBString();
+ var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15";
+ var strokeStyle = "stroke-width: 2.0; stroke:" + Color.whiteColor().toRGBString();
+
+ var drawRect = function(attrs, bar) {
+ var x = this.area.w * bar.x + this.area.x;
+ var y = this.area.h * bar.y + this.area.y;
+ var w = this.area.w * bar.w;
+ var h = this.area.h * bar.h;
+
+ if ((w < 1) || (h < 1))
+ return;
+
+ //attrs["filter"] = "url(#dropShadow)";
+ attrs["style"] = strokeStyle;
+ this._drawRect(x - 2, y - 1, w+4, h+2, {"style":shadowStyle});
+ this._drawRect(x, y, w, h, attrs);
+ };
+ this._renderBarOrLine(this.layout.bars, bind(drawRect, this));
+
+};
+
+PlotKit.SweetSVGRenderer.prototype._renderLineChart = function() {
+ var bind = MochiKit.Base.bind;
+ var shadowColor = Color.blackColor().toRGBString();
+ var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15";
+ var strokeStyle = "stroke-width: 2.0; stroke:" + Color.whiteColor().toRGBString();
+
+ var addPoint = function(attrs, point) {
+ this._tempPointsBuffer += (this.area.w * point.x + this.area.x) + "," +
+ (this.area.h * point.y + this.area.y) + " ";
+ };
+
+ var startLine = function(attrs) {
+ this._tempPointsBuffer = "";
+ this._tempPointsBuffer += (this.area.x) + "," + (this.area.y+this.area.h) + " ";
+ };
+
+ var endLine = function(attrs) {
+ this._tempPointsBuffer += (this.area.w + this.area.x) + "," +(this.area.h + this.area.y);
+ attrs["points"] = this._tempPointsBuffer;
+
+ attrs["stroke"] = "none";
+ attrs["transform"] = "translate(-2, -1)";
+ attrs["style"] = shadowStyle;
+ var shadow = this.createSVGElement("polygon", attrs);
+ this.root.appendChild(shadow);
+
+ attrs["transform"] = "";
+ attrs["style"] = strokeStyle;
+ var elem = this.createSVGElement("polygon", attrs);
+ this.root.appendChild(elem);
+
+
+ };
+
+ this._renderBarOrLine(this.layout.points,
+ bind(addPoint, this),
+ bind(startLine, this),
+ bind(endLine, this));
+};
+
+PlotKit.SweetSVGRenderer.prototype._renderPieChart = function() {
+ var centerx = this.area.x + this.area.w * 0.5;
+ var centery = this.area.y + this.area.h * 0.5;
+ var shadowColor = Color.blackColor().toRGBString();
+ var radius = Math.min(this.area.w * this.options.pieRadius,
+ this.area.h * this.options.pieRadius);
+ var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15";
+
+ var shadow = this.createSVGElement("circle",
+ {"style": shadowStyle, "cx": centerx + 1, "cy": centery + 1, "r": radius + 1});
+ this.root.appendChild(shadow);
+
+ PlotKit.SweetSVGRenderer.__super__._renderPieChart.call(this);
+};
+
+
+PlotKit.SweetSVGRenderer.prototype._renderBackground = function() {
+ var attrs = {
+ "fill": this.options.backgroundColor.toRGBString(),
+ "stroke": "none"
+ };
+
+
+ if (this.layout.style == "bar" || this.layout.style == "line") {
+ this._drawRect(this.area.x, this.area.y,
+ this.area.w, this.area.h, attrs);
+ for (var i = 0; i < this.layout.yticks.length; i++) {
+ this._drawRect(this.area.x,
+ this.layout.yticks[i][0] * this.area.h + this.area.y,
+ this.area.w,
+ 1,
+ {"fill": Color.whiteColor().toRGBString()});
+ }
+ }
+ else {
+ PlotKit.SweetSVGRenderer.__super__._renderBackground.call(this);
+
+ }
+
+};
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/dummy.svg b/activemq-web-console/src/main/webapp/js/plotkit/dummy.svg
new file mode 100644
index 0000000000..6a82bd4ea6
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/dummy.svg
@@ -0,0 +1,9 @@
+
+
diff --git a/activemq-web-console/src/main/webapp/js/plotkit/iecanvas.htc b/activemq-web-console/src/main/webapp/js/plotkit/iecanvas.htc
new file mode 100644
index 0000000000..065a57b1ab
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/js/plotkit/iecanvas.htc
@@ -0,0 +1,389 @@
+/*----------------------------------------------------------------------------\
+| IE Canvas 1.0 |
+|-----------------------------------------------------------------------------|
+| Created by Emil A Eklund |
+| (http://eae.net/contact/emil) |
+|-----------------------------------------------------------------------------|
+| Implementation of the canvas API for Internet Explorer. Uses VML. |
+|-----------------------------------------------------------------------------|
+| Copyright (c) 2005 Emil A Eklund |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is free software; you can redistribute it and/or modify it |
+| under the terms of the MIT License. |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission is hereby granted, free of charge, to any person obtaining a |
+| copy of this software and associated documentation files (the "Software"), |
+| to deal in the Software without restriction, including without limitation |
+| the rights to use, copy, modify, merge, publish, distribute, sublicense, |
+| and/or sell copies of the Software, and to permit persons to whom the |
+| Software is furnished to do so, subject to the following conditions: |
+| The above copyright notice and this permission notice shall be included in |
+| all copies or substantial portions of the Software. |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
+| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
+| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
+| DEALINGS IN THE SOFTWARE. |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| http://eae.net/license/mit |
+|-----------------------------------------------------------------------------|
+| Dependencies: canvas.js - For initialization of canvas elements |
+|-----------------------------------------------------------------------------|
+| 2005-12-27 | Work started. |
+| 2005-12-29 | First version posted. |
+| 2006-01-03 | Fixed bug in moveTo and lineTo, arguments where not converted |
+| | to int which could cause IE to enter an endless loop. Disabled |
+| | antalias for fillRect to better comply with the Mozilla, Opera |
+| | and possibly Safari implementations where using fillRect is |
+| | about the only way to raw non antialiased lines. |
+|-----------------------------------------------------------------------------|
+| Created 2005-12-27 | All changes are in the log above. | Updated 2006-01-03 |
+\----------------------------------------------------------------------------*/
+
+
+
+
+
+
+
diff --git a/activemq-web-console/src/main/webapp/queueGraph.jsp b/activemq-web-console/src/main/webapp/queueGraph.jsp
new file mode 100644
index 0000000000..b74b60d3eb
--- /dev/null
+++ b/activemq-web-console/src/main/webapp/queueGraph.jsp
@@ -0,0 +1,55 @@
+
+
+Queues
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<%---
+Other values we can graph...
+
+${row.consumerCount} |
+${row.enqueueCount} |
+${row.dequeueCount} |
+--%>
+
+
+
+
+
\ No newline at end of file
diff --git a/activemq-web-console/src/main/webapp/queues.jsp b/activemq-web-console/src/main/webapp/queues.jsp
index f14d5d818a..4f166ef2df 100644
--- a/activemq-web-console/src/main/webapp/queues.jsp
+++ b/activemq-web-console/src/main/webapp/queues.jsp
@@ -17,6 +17,8 @@
Queues
+Queue Graph
+