// version: 2017-11-25 /** * o--------------------------------------------------------------------------------o * | This file is part of the RGraph package - you can learn more at: | * | | * | http://www.rgraph.net | * | | * | RGraph is licensed under the Open Source MIT license. That means that it's | * | totally free to use and there are no restrictions on what you can do with it! | * o--------------------------------------------------------------------------------o */ RGraph = window.RGraph || {isRGraph: true}; // Module pattern (function (win, doc, undefined) { var RG = RGraph, ua = navigator.userAgent, ma = Math; /** * This is a useful function which is basically a shortcut for drawing left, right, top and bottom alligned text. * * @param object context The context * @param string font The font * @param int size The size of the text * @param int x The X coordinate * @param int y The Y coordinate * @param string text The text to draw * @parm string The vertical alignment. Can be null. "center" gives center aligned text, "top" gives top aligned text. * Anything else produces bottom aligned text. Default is bottom. * @param string The horizontal alignment. Can be null. "center" gives center aligned text, "right" gives right aligned text. * Anything else produces left aligned text. Default is left. * @param bool Whether to show a bounding box around the text. Defaults not to * @param int The angle that the text should be rotate at (IN DEGREES) * @param string Background color for the text * @param bool Whether the text is bold or not */ RG.text = RG.Text = function (context, font, size, x, y, text) { // "Cache" the args as a local variable var args = arguments; // Handle undefined - change it to an empty string if ((typeof(text) != 'string' && typeof(text) != 'number') || text == 'undefined') { return; } /** * This accommodates multi-line text */ if (typeof(text) == 'string' && text.match(/\r\n/)) { var dimensions = RGraph.MeasureText('M', args[11], font, size); /** * Measure the text (width and height) */ var arr = text.split('\r\n'); /** * Adjust the Y position */ // This adjusts the initial y position if (args[6] && args[6] == 'center') y = (y - (dimensions[1] * ((arr.length - 1) / 2))); for (var i=1; i<arr.length; ++i) { RGraph.Text(context, font, size, args[9] == -90 ? (x + (size * 1.5)) : x, y + (dimensions[1] * i), arr[i], args[6] ? args[6] : null, args[7], args[8], args[9], args[10], args[11], args[12]); } // Update text to just be the first line text = arr[0]; } // Accommodate MSIE if (document.all && RGraph.ISOLD) { y += 2; } context.font = (args[11] ? 'Bold ': '') + size + 'pt ' + font; var i; var origX = x; var origY = y; var originalFillStyle = context.fillStyle; var originalLineWidth = context.lineWidth; // Need these now the angle can be specified, ie defaults for the former two args if (typeof(args[6]) == 'undefined') args[6] = 'bottom'; // Vertical alignment. Default to bottom/baseline if (typeof(args[7]) == 'undefined') args[7] = 'left'; // Horizontal alignment. Default to left if (typeof(args[8]) == 'undefined') args[8] = null; // Show a bounding box. Useful for positioning during development. Defaults to false if (typeof(args[9]) == 'undefined') args[9] = 0; // Angle (IN DEGREES) that the text should be drawn at. 0 is middle right, and it goes clockwise // The alignment is recorded here for purposes of Opera compatibility if (navigator.userAgent.indexOf('Opera') != -1) { context.canvas.__rgraph_valign__ = args[6]; context.canvas.__rgraph_halign__ = args[7]; } // First, translate to x/y coords context.save(); context.canvas.__rgraph_originalx__ = x; context.canvas.__rgraph_originaly__ = y; context.translate(x, y); x = 0; y = 0; // Rotate the canvas if need be if (args[9]) { context.rotate(args[9] / (180 / RGraph.PI)); } // Vertical alignment - defaults to bottom if (args[6]) { var vAlign = args[6]; if (vAlign == 'center') { context.textBaseline = 'middle'; } else if (vAlign == 'top') { context.textBaseline = 'top'; } } // Hoeizontal alignment - defaults to left if (args[7]) { var hAlign = args[7]; var width = context.measureText(text).width; if (hAlign) { if (hAlign == 'center') { context.textAlign = 'center'; } else if (hAlign == 'right') { context.textAlign = 'right'; } } } context.fillStyle = originalFillStyle; /** * Draw a bounding box if requested */ context.save(); context.fillText(text,0,0); context.lineWidth = 1; var width = context.measureText(text).width; var width_offset = (hAlign == 'center' ? (width / 2) : (hAlign == 'right' ? width : 0)); var height = size * 1.5; // !!! var height_offset = (vAlign == 'center' ? (height / 2) : (vAlign == 'top' ? height : 0)); var ieOffset = RGraph.ISOLD ? 2 : 0; if (args[8]) { context.strokeRect(-3 - width_offset, 0 - 3 - height - ieOffset + height_offset, width + 6, height + 6); /** * If requested, draw a background for the text */ if (args[10]) { context.fillStyle = args[10]; context.fillRect(-3 - width_offset, 0 - 3 - height - ieOffset + height_offset, width + 6, height + 6); } context.fillStyle = originalFillStyle; /** * Do the actual drawing of the text */ context.fillText(text,0,0); } context.restore(); // Reset the lineWidth context.lineWidth = originalLineWidth; context.restore(); }; /** * This function returns the mouse position in relation to the canvas * * @param object e The event object. */ RG.getMouseXY = function (e) { var el = (RGraph.ISOLD ? event.srcElement : e.target); var x; var y; // ??? var paddingLeft = el.style.paddingLeft ? parseInt(el.style.paddingLeft) : 0; var paddingTop = el.style.paddingTop ? parseInt(el.style.paddingTop) : 0; var borderLeft = el.style.borderLeftWidth ? parseInt(el.style.borderLeftWidth) : 0; var borderTop = el.style.borderTopWidth ? parseInt(el.style.borderTopWidth) : 0; if (RGraph.ISIE8) e = event; // Browser with offsetX and offsetY if (typeof(e.offsetX) == 'number' && typeof(e.offsetY) == 'number') { x = e.offsetX; y = e.offsetY; // FF and other } else { x = 0; y = 0; while (el != document.body && el) { x += el.offsetLeft; y += el.offsetTop; el = el.offsetParent; } x = e.pageX - x; y = e.pageY - y; } return [x, y]; }; /** * This function attempts to "fill in" missing functions from the canvas * context object. Only two at the moment - measureText() nd fillText(). * * @param object context The canvas 2D context */ RG.oldBrowserCompat = RG.OldBrowserCompat = function (co) { if (!co) { return; } if (!co.measureText) { // This emulates the measureText() function co.measureText = function (text) { var textObj = document.createElement('DIV'); textObj.innerHTML = text; textObj.style.position = 'absolute'; textObj.style.top = '-100px'; textObj.style.left = 0; document.body.appendChild(textObj); var width = {width: textObj.offsetWidth}; textObj.style.display = 'none'; return width; } } if (!co.fillText) { // This emulates the fillText() method co.fillText = function (text, targetX, targetY) { return false; } } // If IE8, add addEventListener() if (!co.canvas.addEventListener) { window.addEventListener = function (ev, func, bubble) { return this.attachEvent('on' + ev, func); } co.canvas.addEventListener = function (ev, func, bubble) { return this.attachEvent('on' + ev, func); } } }; /** * Similar to the jQuery each() function - this lets you iterate easily over an array. The 'this' variable is set] * to the array in the callback function. * * @param array arr The array * @param function func The function to call * @param object Optionally you can specify the object that the "this" variable is set to */ RG.each = function (arr, func) { for(var i=0, len=arr.length; i<len; i+=1) { if (typeof arguments[2] !== 'undefined') { var ret = func.call(arguments[2], i, arr[i]); } else { var ret = func.call(arr, i, arr[i]); } if (ret === false) { return; } } }; /** * An old function the was used before all 4 gutters were added * * DEPRECATED * * @param object obj The chart object */ RG.getHeight = RG.GetHeight = function (obj) { return obj.canvas.height; }; /** * An old function the was used before all 4 gutters were added * * DEPRECATED * * @param object obj The chart object */ RG.getWidth = RG.GetWidth = function (obj) { return obj.canvas.width; }; /** * A timer function for measuring... time! * * @param string label A string to associate with this 'checkpoint' */ RG.timer = RG.Timer = function (label) { if(typeof RG.TIMER_LAST_CHECKPOINT == 'undefined') { RG.TIMER_LAST_CHECKPOINT = Date.now(); } var now = Date.now(); console.log(label+': ' + (now - RG.TIMER_LAST_CHECKPOINT).toString()); RG.TIMER_LAST_CHECKPOINT = now; }; /** * If you prefer, you can use the SetConfig() method to set the configuration information * for your chart. You may find that setting the configuration this way eases reuse. * * @param object obj The graph object * @param object config The graph configuration information */ RG.setConfig = RG.SetConfig = function (obj, config) { for (i in config) { if (typeof i === 'string') { obj.Set(i, config[i]); } } return obj; }; // End module pattern })(window, document); /** * Checks whether strings or numbers are empty or not. It also * handles null or variables set to undefined. If a variable really * is undefined - ie it hasn't been declared at all - you need to use * "typeof variable" and check the return value - which will be undefined. * * @param mixed value The variable to check */ window.$empty = function (value) { if (!value || value.length <= 0) { return true; } return false; };