/** * o------------------------------------------------------------------------------o * | This file is part of the RGraph package - you can learn more at: | * | | * | http://www.rgraph.net | * | | * | This package is licensed under the RGraph license. For all kinds of business | * | purposes there is a small one-time licensing fee to pay and for non | * | commercial purposes it is free to use. You can read the full license here: | * | | * | http://www.rgraph.net/LICENSE.txt | * o------------------------------------------------------------------------------o */ if (typeof(RGraph) == 'undefined') RGraph = {}; /** * The bi-polar/age frequency constructor. * * @param string id The id of the canvas * @param array left The left set of data points * @param array right The right set of data points */ RGraph.Bipolar = function (id, left, right) { // Get the canvas and context objects this.id = id; this.canvas = document.getElementById(id); this.context = this.canvas.getContext('2d'); this.canvas.__object__ = this; this.type = 'bipolar'; this.coords = []; this.max = 0; this.isRGraph = true; /** * Compatibility with older browsers */ RGraph.OldBrowserCompat(this.context); // The left and right data respectively this.left = left; this.right = right; this.data = [left, right]; this.properties = { 'chart.margin': 2, 'chart.xtickinterval': null, 'chart.labels': [], 'chart.text.size': 10, 'chart.text.color': 'black', 'chart.text.font': 'Verdana', 'chart.title.left': '', 'chart.title.right': '', 'chart.gutter.center': 60, 'chart.gutter.left': 25, 'chart.gutter.right': 25, 'chart.gutter.top': 25, 'chart.gutter.bottom': 25, 'chart.title': '', 'chart.title.background': null, 'chart.title.hpos': null, 'chart.title.vpos': null, 'chart.title.bold': true, 'chart.title.font': null, 'chart.colors': ['#0f0'], 'chart.contextmenu': null, 'chart.tooltips': null, 'chart.tooltips.effect': 'fade', 'chart.tooltips.css.class': 'RGraph_tooltip', 'chart.tooltips.highlight': true, 'chart.highlight.stroke': 'black', 'chart.highlight.fill': 'rgba(255,255,255,0.5)', 'chart.units.pre': '', 'chart.units.post': '', 'chart.shadow': false, 'chart.shadow.color': '#666', 'chart.shadow.offsetx': 3, 'chart.shadow.offsety': 3, 'chart.shadow.blur': 3, 'chart.annotatable': false, 'chart.annotate.color': 'black', 'chart.xmax': null, 'chart.scale.decimals': null, 'chart.scale.point': '.', 'chart.scale.thousand': ',', 'chart.axis.color': 'black', 'chart.zoom.factor': 1.5, 'chart.zoom.fade.in': true, 'chart.zoom.fade.out': true, 'chart.zoom.hdir': 'right', 'chart.zoom.vdir': 'down', 'chart.zoom.frames': 25, 'chart.zoom.delay': 16.666, 'chart.zoom.shadow': true, 'chart.zoom.mode': 'canvas', 'chart.zoom.thumbnail.width': 75, 'chart.zoom.thumbnail.height': 75, 'chart.zoom.background': true, 'chart.zoom.action': 'zoom', 'chart.resizable': false, 'chart.resize.handle.adjust': [0,0], 'chart.resize.handle.background': null, 'chart.strokestyle': '#333' } // Pad the arrays so they're the same size while (this.left.length < this.right.length) this.left.push(0); while (this.left.length > this.right.length) this.right.push(0); } /** * The setter * * @param name string The name of the parameter to set * @param value mixed The value of the paraneter */ RGraph.Bipolar.prototype.Set = function (name, value) { this.properties[name.toLowerCase()] = value; } /** * The getter * * @param name string The name of the parameter to get */ RGraph.Bipolar.prototype.Get = function (name) { return this.properties[name.toLowerCase()]; } /** * Draws the graph */ RGraph.Bipolar.prototype.Draw = function () { /** * Fire the onbeforedraw event */ RGraph.FireCustomEvent(this, 'onbeforedraw'); /** * Clear all of this canvases event handlers (the ones installed by RGraph) */ RGraph.ClearEventListeners(this.id); /** * This is new in May 2011 and facilitates indiviual gutter settings, * eg chart.gutter.left */ this.gutterLeft = this.Get('chart.gutter.left'); this.gutterRight = this.Get('chart.gutter.right'); this.gutterTop = this.Get('chart.gutter.top'); this.gutterBottom = this.Get('chart.gutter.bottom'); // Reset the data to what was initially supplied this.left = this.data[0]; this.right = this.data[1]; /** * Reset the coords array */ this.coords = []; this.GetMax(); this.DrawAxes(); this.DrawTicks(); this.DrawLeftBars(); this.DrawRightBars(); if (this.Get('chart.axis.color') != 'black') { this.DrawAxes(); // Draw the axes again (if the axes color is not black) } this.DrawLabels(); this.DrawTitles(); /** * Setup the context menu if required */ if (this.Get('chart.contextmenu')) { RGraph.ShowContext(this); } /** * Install the on* event handlers */ if (this.Get('chart.tooltips')) { // Register the object so that it gets redrawn RGraph.Register(this); /** * Install the window onclick handler */ /** * Install the window event handler */ var eventHandler_window_click = function () { RGraph.Redraw(); } window.addEventListener('click', eventHandler_window_click, false); RGraph.AddEventListener('window_' + this.id, 'click', eventHandler_window_click); /** * If the cursor is over a hotspot, change the cursor to a hand */ var eventHandler_canvas_mousemove = function (e) { e = RGraph.FixEventObject(e); var canvas = document.getElementById(this.id); var obj = canvas.__object__; /** * Get the mouse X/Y coordinates */ var mouseCoords = RGraph.getMouseXY(e); var bar = obj.getBar(e); /** * Loop through the bars determining if the mouse is over a bar */ for (var i=0; i= left && mouseX <= (left + width ) && mouseY >= top && mouseY <= (top + height) ) { /** * Get the tooltip text */ if (typeof(obj.Get('chart.tooltips')) == 'function') { var text = obj.Get('chart.tooltips')(i); } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[i]) == 'function') { var text = obj.Get('chart.tooltips')[i](i); } else if (typeof(obj.Get('chart.tooltips')) == 'object') { var text = obj.Get('chart.tooltips')[i]; } else { var text = ''; } if (text) { canvas.style.cursor = 'pointer'; } return; } } canvas.style.cursor = 'default'; } this.canvas.addEventListener('mousemove', eventHandler_canvas_mousemove, false); RGraph.AddEventListener(this.id, 'mouseover', eventHandler_canvas_mousemove); /** * Install the onclick event handler for the tooltips */ var eventHandler_canvas_click = function (e) { e = RGraph.FixEventObject(e); var canvas = document.getElementById(this.id) var obj = canvas.__object__; /** * Redraw the graph first, in effect resetting the graph to as it was when it was first drawn * This "deselects" any already selected bar */ RGraph.Clear(canvas); obj.Draw(); /** * Get the mouse X/Y coordinates */ var mouseCoords = RGraph.getMouseXY(e); var bar = obj.getBar(e); /** * This bit shows the tooltip (if required) */ if (bar) { var mouseX = mouseCoords[0]; // In relation to the canvas var mouseY = mouseCoords[1]; // In relation to the canvas var left = bar[0]; var top = bar[1]; var width = bar[2]; var height = bar[3]; var index = bar[4]; /** * Show a tooltip if it's defined */ if (obj.Get('chart.tooltips')) { /** * Get the tooltip text */ if (typeof(obj.Get('chart.tooltips')) == 'function') { var text = obj.Get('chart.tooltips')(index); } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[index]) == 'function') { var text = obj.Get('chart.tooltips')[index](index); } else if (typeof(obj.Get('chart.tooltips')) == 'object') { var text = obj.Get('chart.tooltips')[index]; } else { var text = ''; } // Only now show a tooltip if one has been set if (text) { obj.context.beginPath(); obj.context.strokeStyle = obj.Get('chart.highlight.stroke'); obj.context.fillStyle = obj.Get('chart.highlight.fill'); obj.context.strokeRect(left, top, width, height); obj.context.fillRect(left, top, width, height); obj.context.stroke(); obj.context.fill(); RGraph.Tooltip(canvas, text, e.pageX, e.pageY, index); } } } /** * Stop the event bubbling */ e.stopPropagation(); return false; } this.canvas.addEventListener('click', eventHandler_canvas_click, false); RGraph.AddEventListener(this.id, 'click', eventHandler_canvas_click); // This resets the bipolar graph if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.display = 'none'; RGraph.Registry.Set('chart.tooltip', null) } } /** * If the canvas is annotatable, do install the event handlers */ if (this.Get('chart.annotatable')) { RGraph.Annotate(this); } /** * This bit shows the mini zoom window if requested */ if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') { RGraph.ShowZoomWindow(this); } /** * This function enables resizing */ if (this.Get('chart.resizable')) { RGraph.AllowResizing(this); } /** * Add the common .getShape() method */ this.getShape = this.getBar; /** * Fire the RGraph ondraw event */ RGraph.FireCustomEvent(this, 'ondraw'); } /** * Draws the axes */ RGraph.Bipolar.prototype.DrawAxes = function () { // Draw the left set of axes this.context.beginPath(); this.context.strokeStyle = this.Get('chart.axis.color'); this.axisWidth = (RGraph.GetWidth(this) - this.Get('chart.gutter.center') - this.gutterLeft - this.gutterRight) / 2; this.axisHeight = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom; this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom); this.context.lineTo(this.gutterLeft + this.axisWidth, RGraph.GetHeight(this) - this.gutterBottom); this.context.lineTo(this.gutterLeft + this.axisWidth, this.gutterTop); this.context.stroke(); // Draw the right set of axes this.context.beginPath(); var x = this.gutterLeft + this.axisWidth + this.Get('chart.gutter.center'); this.context.moveTo(x, this.gutterTop); this.context.lineTo(x, RGraph.GetHeight(this) - this.gutterBottom); this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom); this.context.stroke(); } /** * Draws the tick marks on the axes */ RGraph.Bipolar.prototype.DrawTicks = function () { var numDataPoints = this.left.length; var barHeight = ( (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom)- (this.left.length * (this.Get('chart.margin') * 2) )) / numDataPoints; // Draw the left Y tick marks for (var i = RGraph.GetHeight(this) - this.gutterBottom; i >= this.gutterTop; i -= (barHeight + ( this.Get('chart.margin') * 2)) ) { if (i < (RGraph.GetHeight(this) - this.gutterBottom) ) { this.context.beginPath(); this.context.moveTo(this.gutterLeft + this.axisWidth, i); this.context.lineTo(this.gutterLeft + this.axisWidth + 3, i); this.context.stroke(); } } //Draw the right axis Y tick marks for (var i = RGraph.GetHeight(this) - this.gutterBottom; i >= this.gutterTop; i -= (barHeight + ( this.Get('chart.margin') * 2)) ) { if (i < (RGraph.GetHeight(this) - this.gutterBottom) ) { this.context.beginPath(); this.context.moveTo(this.gutterLeft + this.axisWidth + this.Get('chart.gutter.center'), i); this.context.lineTo(this.gutterLeft + this.axisWidth + this.Get('chart.gutter.center') - 3, i); this.context.stroke(); } } var xInterval = this.axisWidth / 10; // Is chart.xtickinterval specified ? If so, use that. if (typeof(this.Get('chart.xtickinterval')) == 'number') { xInterval = this.Get('chart.xtickinterval'); } // Draw the left sides X tick marks for (i=this.gutterLeft; i<(this.gutterLeft + this.axisWidth); i+=xInterval) { this.context.beginPath(); this.context.moveTo(i, RGraph.GetHeight(this) - this.gutterBottom); this.context.lineTo(i, (RGraph.GetHeight(this) - this.gutterBottom) + 4); this.context.closePath(); this.context.stroke(); } // Draw the right sides X tick marks var stoppingPoint = RGraph.GetWidth(this) - this.gutterRight; for (i=(this.gutterLeft + this.axisWidth + this.Get('chart.gutter.center') + xInterval); i<=stoppingPoint; i+=xInterval) { this.context.beginPath(); this.context.moveTo(i, RGraph.GetHeight(this) - this.gutterBottom); this.context.lineTo(i, (RGraph.GetHeight(this) - this.gutterBottom) + 4); this.context.closePath(); this.context.stroke(); } // Store this for later this.barHeight = barHeight; } /** * Figures out the maximum value, or if defined, uses xmax */ RGraph.Bipolar.prototype.GetMax = function() { var max = 0; var dec = this.Get('chart.scale.decimals'); // chart.xmax defined if (this.Get('chart.xmax')) { max = this.Get('chart.xmax'); this.scale = []; this.scale[0] = Number((max / 5) * 1).toFixed(dec); this.scale[1] = Number((max / 5) * 2).toFixed(dec); this.scale[2] = Number((max / 5) * 3).toFixed(dec); this.scale[3] = Number((max / 5) * 4).toFixed(dec); this.scale[4] = Number(max).toFixed(dec); this.max = max; // Generate the scale ourselves } else { this.leftmax = RGraph.array_max(this.left); this.rightmax = RGraph.array_max(this.right); max = Math.max(this.leftmax, this.rightmax); this.scale = RGraph.getScale(max, this); this.scale[0] = Number(this.scale[0]).toFixed(dec); this.scale[1] = Number(this.scale[1]).toFixed(dec); this.scale[2] = Number(this.scale[2]).toFixed(dec); this.scale[3] = Number(this.scale[3]).toFixed(dec); this.scale[4] = Number(this.scale[4]).toFixed(dec); this.max = this.scale[4]; } // Don't need to return it as it is stored in this.max } /** * Function to draw the left hand bars */ RGraph.Bipolar.prototype.DrawLeftBars = function () { // Set the stroke colour this.context.strokeStyle = this.Get('chart.strokestyle'); for (i=0; i= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height) ) { return [left,top,width,height,i]; } } return null; }