// o---------------------------------------------------------------------------------o // | This file is part of the RGraph package - you can learn more at: | // | | // | https://www.rgraph.net/license.html | // | | // | RGraph is dual-licensed under the Open Source GPL license. That means that it's | // | free to use and there are no restrictions on what you can use RGraph for! | // | If the GPL license does not suit you however, then there's an inexpensive | // | commercial license option available. See the URL above for more details. | // o---------------------------------------------------------------------------------o RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true}; // // The Activity meter constructor // RGraph.Activity = function (conf) { var id = conf.id, canvas = document.getElementById(id), min = conf.min, max = conf.max, value = conf.value; // id, min, max, value // Get the canvas and context objects this.id = id; this.canvas = canvas; this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null; this.canvas.__object__ = this; this.type = 'activity'; this.min = RGraph.stringsToNumbers(min); this.max = RGraph.stringsToNumbers(max); this.value = RGraph.stringsToNumbers(value); this.centerx = null; this.centery = null; this.radius = null; this.isRGraph = true; this.isrgraph = true; this.rgraph = true; this.currentValue = null; this.uid = RGraph.createUID(); this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.createUID(); this.colorsParsed = false; this.coordsText = []; this.angles = this.coords = []; this.original_colors = []; this.images = []; this.firstDraw = true; // After the first draw this will be false this.stopAnimationRequested = false;// Used to control the animations // // If the value is zero set it to very // slightly more than zero so the meter // is drawn correctly. // // Likewise with the maximum value // if (typeof this.value === 'number') { this.value = [this.value]; } for (var i=0; i this.max) this.value[i] = this.max; if (this.value[i] < this.min) this.value[i] = this.min; } // // Set the current value // this.currentValue = RGraph.arrayClone(this.value); // // Make the margins easy to access // this.marginLeft = properties.marginLeft; this.marginRight = properties.marginRight; this.marginTop = properties.marginTop; this.marginBottom = properties.marginBottom; this.centerx = ((this.canvas.width - this.marginLeft - this.marginRight) / 2) + this.marginLeft; this.centery = ((this.canvas.height - this.marginBottom - this.marginTop) / 2) + this.marginTop; this.radius = Math.min( (this.canvas.width - this.marginLeft - this.marginRight) / 2, (this.canvas.height - this.marginTop - this.marginBottom) / 2 ); // // Stop this growing uncontrollably // this.coordsText = []; // // Custom centerx, centery and radius // if (typeof properties.centerx === 'number') this.centerx = properties.centerx; if (typeof properties.centery === 'number') this.centery = properties.centery; if (typeof properties.radius === 'number') this.radius = properties.radius; // // Allow the centerx/centery/radius to be a plus/minus // if (typeof this.properties.radius === 'string' && this.properties.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(this.properties.radius); if (typeof this.properties.centerx === 'string' && this.properties.centerx.match(/^\+|-\d+$/) ) this.centerx += parseFloat(this.properties.centerx); if (typeof this.properties.centery === 'string' && this.properties.centery.match(/^\+|-\d+$/) ) this.centery += parseFloat(this.properties.centery); // The width variable is the width of an individual ring this.width = typeof properties.width === 'number' ? properties.width : ((this.radius * 0.75) / this.value.length); this.width = this.width - properties.marginInner - properties.marginInner; // Allow for +/-xx style width if (typeof properties.width === 'string') { this.width += Number(properties.width); } // // Parse the colors for gradients. Its down here so that the center X/Y can be used // if (!this.colorsParsed) { this.parseColors(); // Don't want to do this again this.colorsParsed = true; } // // Install clipping // if (!RGraph.isNull(this.properties.clip)) { RGraph.clipTo.start(this, this.properties.clip); } // // Draw the meter and its label // this.drawBackground(); this.drawMeter(); this.drawLabels(); this.drawIcons(); this.drawEnds(); // // Setup the context menu if required // if (properties.contextmenu) { RGraph.showContext(this); } // // Add custom text thats specified // RGraph.addCustomText(this); // // This installs the event listeners // RGraph.installEventListeners(this); // // End clipping // if (!RGraph.isNull(this.properties.clip)) { RGraph.clipTo.end(); } // // Fire the onfirstdraw event // if (this.firstDraw) { this.firstDraw = false; RGraph.fireCustomEvent(this, 'onfirstdraw'); this.firstDrawFunc(); } // // Fire the RGraph draw event // RGraph.fireCustomEvent(this, 'ondraw'); // // Install any inline responsive configuration. This // should be last in the draw function - even after // the draw events. // RGraph.installInlineResponsive(this); return this; }; // // Used in chaining. Runs a function there and then - not waiting for // the events to fire (eg the onbeforedraw event) // // @param function func The function to execute // this.exec = function (func) { func(this); return this; }; // // Draw the background"grid" // this.drawBackground = function () { // First thing to do is clear the canvas to the backgroundColor if (properties.backgroundColor) { this.path( 'fs % fr -5 -5 % %', properties.backgroundColor, this.canvas.width + 10, this.canvas.height + 10 ); } // Draw the grid? if (properties.backgroundGrid) { // Draw the background grey circles if (properties.backgroundGridCircles) { // How many background circles? if (typeof properties.backgroundGridCirclesCount === 'number') { var count = properties.backgroundGridCirclesCount; } else { var count = this.value.length + 1; } for (var i=0; i= obj.width) { width -= 10; height -= 10; } // If a width has been stipulated then use it if (typeof properties.iconsWidth === 'number') { width = properties.iconsWidth; } // If a height has been specified then use it if (typeof properties.iconsHeight === 'number') { height = properties.iconsHeight; } var x = obj.centerx - (width / 3) + ((properties.ends === 'straight' || properties.ends === 'square') ? 15 : 0); var y = (obj.centery - obj.coords[this.index].radiusOuter + ((obj.coords[this.index].radiusOuter - obj.coords[this.index].radiusInner) / 2) - (height / 2) ); x += properties.iconsOffsetx; y += properties.iconsOffsety; obj.context.drawImage( this, x, y, width, height ); }; } } }; // // Draws the rounded ends to the bars // this.drawEnds = function () { if (properties.ends === 'straight' || properties.ends === 'square') { return; } for (var i=0; i RGraph.TWOPI) { angle -= RGraph.TWOPI; } // Calculate the value based on the angle and min/max values var value = ((angle / RGraph.TWOPI) * (this.max - this.min)) + this.min; // Ensure that the value is in range value = Math.max(value, this.min); value = Math.min(value, this.max); return value; }; // // The getObjectByXY() worker method. Don't call this call: // // RGraph.ObjectRegistry.getObjectByXY(e) // // @param object e The event object // this.getObjectByXY = function (e) { var mouseXY = RGraph.getMouseXY(e), width = this.width; // Work out the radius var radius = RGraph.getHypLength( this.centerx, this.centery, mouseXY[0], mouseXY[1] ); if (radius > this.radius || radius < (this.radius * 0.25) ) { return null; } return this; }; // // This method handles the adjusting calculation for when the mouse is moved // // @param object e The event object // this.adjusting_mousemove = function (e) { // // Handle adjusting for the Bar // if (properties.adjustable && RGraph.Registry.get('adjusting') && RGraph.Registry.get('adjusting').uid == this.uid) { var mouseXY = RGraph.getMouseXY(e); var radius = RGraph.getHypLength( this.centerx, this.centery, mouseXY[0], mouseXY[1] ); var index = this.getIndexByRadius(radius); // Store the index in the radius if (typeof RGraph.Registry.get('adjusting.index') !== 'number') { RGraph.Registry.set('adjusting.index', index); RGraph.addCustomEventListener(this, 'onadjustend', function () { RGraph.Registry.set('adjusting.index', null); }); } else { index = RGraph.Registry.get('adjusting.index') } if (typeof index === 'number') { this.value[index] = this.getValue(e); RGraph.clear(this.canvas); RGraph.redrawCanvas(this.canvas); RGraph.fireCustomEvent(this, 'onadjust'); } } }; // // Returns the relevant index of the relevant datapoint. // But only if it's in range. // // @param number radius The radius to check // this.getIndexByRadius = function (radius) { // Loop through the shapes to determine the correct shape for (var i=0; i this.coords[i].radiusInner) { return i; } } return null; }; // // This method returns the appropriate angle for a value // // @param number value The value // this.getAngle = function (value) { // Higher than max if (value > this.max || value < this.min) { return null; } var angle = (((value - this.min) / (this.max - this.min)) * RGraph.TWOPI) - RGraph.HALFPI; if (value === this.max) angle -= 0.00001; if (value === this.min) angle += 0.00001; return angle; }; // // Each object type has its own Highlight() function which highlights the appropriate shape // // @param object shape The shape to highlight // this.highlight = function (shape) { if (typeof properties.highlightStyle === 'function') { if (properties.tooltipsHighlight) { (properties.highlightStyle)(shape); } // Highlight all of the rings except this one - essentially an inverted highlight } else if (typeof properties.highlightStyle === 'string' && properties.highlightStyle === 'invert') { if (properties.tooltipsHighlight) { this.context.beginPath(); for (var i=0; i