// 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}; RGraph.SVG = RGraph.SVG || {}; // Module pattern (function (win, doc, undefined) { RGraph.SVG.SemiCircularProgress = function (conf) { // // A setter that the constructor uses (at the end) // to set all of the properties // // @param string name The name of the property to set // @param string value The value to set the property to // this.set = function (name, value) { if (arguments.length === 1 && typeof name === 'object') { for (i in arguments[0]) { if (typeof i === 'string') { name = ret.name; value = ret.value; if (name === 'backgroundColor') {name = 'backgroundFill';} if (name === 'backgroundColorOpacity') {name = 'backgroundFillOpacity';} this.set(name, value); } } } else { // Go through all of the properties and make sure // that they're using the correct capitalisation name = this.properties_lowercase_map[name.toLowerCase()] || name; if (name === 'backgroundColor') {name = 'backgroundFill';} if (name === 'backgroundColorOpacity') {name = 'backgroundFillOpacity';} var ret = RGraph.SVG.commonSetter({ object: this, name: name, value: value }); name = ret.name; value = ret.value; this.properties[name] = value; // If setting the colors, update the originalColors // property too if (name === 'colors') { this.originalColors = RGraph.SVG.arrayClone(value); this.colorsParsed = false; } } return this; }; // // A getter. // // @param name string The name of the property to get // this.get = function (name) { // Go through all of the properties and make sure // that they're using the correct capitalisation name = this.properties_lowercase_map[name.toLowerCase()] || name; return this.properties[name]; }; this.type = 'semicircularprogress'; this.min = RGraph.SVG.stringsToNumbers(conf.min); this.max = RGraph.SVG.stringsToNumbers(conf.max); this.value = RGraph.SVG.stringsToNumbers(conf.value); this.id = conf.id; this.uid = RGraph.SVG.createUID(); this.container = document.getElementById(this.id); this.layers = {}; // MUST be before the SVG tag is created! this.svg = RGraph.SVG.createSVG({object: this,container: this.container}); this.svgAllGroup = RGraph.SVG.createAllGroup(this); this.clipid = null; // Used to clip the canvas this.isRGraph = true; this.isrgraph = true; this.rgraph = true; this.width = Number(this.svg.getAttribute('width')); this.height = Number(this.svg.getAttribute('height')); this.data = conf.data; // Is this used? Don't think so. this.colorsParsed = false; this.originalColors = {}; this.gradientCounter = 1; this.nodes = {}; this.coords = []; this.shadowNodes = []; this.firstDraw = true; // After the first draw this will be false // Used for adjusting this.adjusting_mousedown = false; // Bounds checking if (this.value > this.max) this.value = this.max; if (this.value < this.min) this.value = this.min; // Add this object to the ObjectRegistry RGraph.SVG.OR.add(this); // Set the DIV container to be inline-block this.container.style.display = 'inline-block'; this.properties = { centerx: null, centery: null, radius: null, width: 60, marginLeft: 35, marginRight: 35, marginTop: 35, marginBottom: 35, backgroundStrokeLinewidth: 0.25, backgroundStroke: 'gray', backgroundFill: null, backgroundFillOpacity: 0.15, backgroundGrid: false, backgroundGridMargin: 20, backgroundGridColor: '#ddd', backgroundGridLinewidth: 1, backgroundGridCircles: true, backgroundGridRadials: true, backgroundGridRadialsCount: 10, colors: ['#6d6','#FFA5A5','#A0A2F8','yellow','gray','pink','orange','cyan','green'], colorsStroke: 'transparent', textColor: 'black', textFont: 'Arial, Verdana, sans-serif', textSize: 12, textBold: false, textItalic: false, text: null, scale: false, scaleMin: null, // Defaults to the charts min value scaleMax: null, // Defaults to the charts max value scaleDecimals: 0, scalePoint: '.', scaleThousand: ',', scaleFormatter: null, scaleUnitsPre: '', scaleUnitsPost: '', scaleLabelsCount: 10, scaleLabelsFont: null, scaleLabelsSize: null, scaleLabelsColor: null, scaleLabelsBold: null, scaleLabelsItalic: null, scaleLabelsOffsetr: 0, scaleLabelsOffsetx: 0, scaleLabelsOffsety: 0, labelsMin: true, labelsMinSpecific: null, labelsMinPoint: null, labelsMinThousand: null, labelsMinDecimals: null, labelsMinFormatter: null, labelsMinFont: null, labelsMinSize: null, labelsMinBold: null, labelsMinItalic: null, labelsMinColor: null, labelsMinUnitsPre: null, labelsMinUnitsPost: null, labelsMax: true, labelsMaxSpecific: null, labelsMaxPoint: null, labelsMaxThousand: null, labelsMaxFormatter: null, labelsMaxFont: null, labelsMaxSize: null, labelsMaxBold: null, labelsMaxItalic: null, labelsMaxColor: null, labelsMaxDecimals: null, labelsMaxUnitsPre: null, labelsMaxUnitsPost: null, labelsCenter: true, labelsCenterIndex: 0, labelsCenterSpecific: null, labelsCenterPoint: null, labelsCenterThousand: null, labelsCenterFormatter: null, labelsCenterFont: null, labelsCenterSize: 40, labelsCenterBold: true, labelsCenterItalic: null, labelsCenterColor: null, labelsCenterDecimals: null, labelsCenterUnitsPre: null, labelsCenterUnitsPost: null, linewidth: 1, tooltips: null, tooltipsOverride: null, tooltipsEffect: 'fade', tooltipsCssClass: 'RGraph_tooltip', tooltipsCss: null, tooltipsEvent: 'click', tooltipsFormattedThousand: ',', tooltipsFormattedPoint: '.', tooltipsFormattedDecimals: 0, tooltipsFormattedUnitsPre: '', tooltipsFormattedUnitsPost: '', tooltipsFormattedKeyColors: null, tooltipsFormattedKeyColorsShape: 'square', tooltipsFormattedKeyLabels: [], tooltipsFormattedTableHeaders: null, tooltipsFormattedTableData: null, tooltipsPointer: true, tooltipsPointerOffsetx: 0, tooltipsPointerOffsety: 0, tooltipsPositionStatic: true, adjustable: false, highlightStroke: 'rgba(0,0,0,0)', highlightFill: 'rgba(255,255,255,0.7)', highlightLinewidth: 1, title: '', titleX: null, titleY: null, titleHalign: 'center', titleValign: null, titleFont: null, titleSize: null, titleColor: null, titleBold: null, titleItalic: null, titleSubtitle: null, titleSubtitleSize: null, titleSubtitleColor: '#aaa', titleSubtitleFont: null, titleSubtitleBold: null, titleSubtitleItalic: null, clip: null }; // // Add the reverse look-up table for property names // so that property names can be specified in any case. // this.properties_lowercase_map = []; for (var i in this.properties) { if (typeof i === 'string') { this.properties_lowercase_map[i.toLowerCase()] = i; } } // // Copy the global object properties to this instance // RGraph.SVG.getGlobals(this); // // "Decorate" the object with the generic effects if the effects library has been included // if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') { RGraph.SVG.FX.decorate(this); } // Add the responsive function to the object this.responsive = RGraph.SVG.responsive; var properties = this.properties; // // The draw method draws the Bar chart // this.draw = function () { // Fire the beforedraw event RGraph.SVG.fireCustomEvent(this, 'onbeforedraw'); // Reset this to prevent it from growing this.nodes = {}; // Should be the first(ish) thing that's done in the // .draw() function except for the onbeforedraw event // and the installation of clipping. this.width = Number(this.svg.getAttribute('width')); this.height = Number(this.svg.getAttribute('height')); // Create the defs tag if necessary RGraph.SVG.createDefs(this); // Add these this.graphWidth = this.width - properties.marginLeft - properties.marginRight; this.graphHeight = this.height - properties.marginTop - properties.marginBottom; // Work out the center point this.centerx = (this.graphWidth / 2) + properties.marginLeft; this.centery = this.height - properties.marginBottom; this.radius = Math.min(this.graphWidth / 2, this.graphHeight); // Allow the user to override the calculated centerx/y/radius this.radius = typeof properties.radius === 'number' ? properties.radius : this.radius; this.centerx = typeof properties.centerx === 'number' ? properties.centerx : this.centerx; this.centery = typeof properties.centery === 'number' ? properties.centery : this.centery; // // Allow the centerx/centery/radius to be a plus/minus // if (typeof properties.radius === 'string' && properties.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(properties.radius); if (typeof properties.centerx === 'string' && properties.centerx.match(/^\+|-\d+$/) ) this.centerx += parseFloat(properties.centerx); if (typeof properties.centery === 'string' && properties.centery.match(/^\+|-\d+$/) ) this.centery += parseFloat(properties.centery); // Set the width of the meter this.progressWidth = properties.width || (this.radius / 3); // Parse the colors for gradients RGraph.SVG.resetColorsToOriginalValues({object:this}); this.parseColors(); // Install clipping if requested if (this.properties.clip) { this.clipid = RGraph.SVG.installClipping(this); // Add the clip ID to the all group this.svgAllGroup.setAttribute( 'clip-path', 'url(#{1})'.format(this.clipid) ); } else { // No clipping - so ensure that there's no clip-path // attribute this.clipid = null; this.svgAllGroup.removeAttribute('clip-path'); } this.drawBackground(); // Draw the background "grid" this.drawMeter(); // Draw the segments RGraph.SVG.drawTitle(this); // Draw the title and subtitle this.drawLabels(); // Draw the labels this.drawScale(); // Draw the scale var obj = this; // Add the tooltip event listener if (!RGraph.SVG.isNull(properties.tooltips) && (properties.tooltips.length || RGraph.SVG.isString(properties.tooltips)) ) { for (var i=0; i obj.radius) { // return; //} var value = obj.getValue(e); obj.value = value; RGraph.SVG.redraw(obj.svg); }; // // Only add the adjusting event listeners once // var obj = this; RGraph.SVG.runOnce('rgraph-svg-scp-adjusting-event-listeners-' + obj.uid, function () { // // Create a reference so that code thats inside // the event listeners can easily access the // object obj.svg.addEventListener('mousedown', function (e) { var mouseX = e.offsetX, mouseY = e.offsetY; if (RGraph.SVG.ISFF) { mouseX = e.pageX - e.currentTarget.offsetLeft; mouseY = e.pageY - e.currentTarget.offsetTop; } var radius = RGraph.SVG.TRIG.getHypLength({ x1: mouseX, y1: mouseY, x2: obj.centerx, y2: obj.centery, object: obj }); // The first click that starts adjusting // must be within the progress meter area // // Allow the pointer to be inside the meter // /* || radius < (obj.radius - obj.progressWidth) */ if (radius > obj.radius) { return; } obj.adjusting_mousedown = true; func(e); // Fire the beforedraw event RGraph.SVG.fireCustomEvent(obj, 'onadjustbegin'); }, false); obj.container.addEventListener('mousemove', function (e) { if (obj.adjusting_mousedown) { func(e); // Fire the beforedraw event RGraph.SVG.fireCustomEvent(obj, 'onadjust'); } }, false); window.addEventListener('mouseup', function (e) { obj.adjusting_mousedown = false; // Fire the beforedraw event RGraph.SVG.fireCustomEvent(obj, 'onadjustend'); }, false); }); } // // Fire the onfirstdraw event // if (this.firstDraw) { this.firstDraw = false; RGraph.SVG.fireCustomEvent(this, 'onfirstdraw'); } // Fire the draw event RGraph.SVG.fireCustomEvent(this, 'ondraw'); // // Install any inline responsive configuration. This // should be last in the draw function - even after // the draw events. // RGraph.SVG.installInlineResponsive(this); return this; }; // // New create() shortcut function // For example: // this.create('rect,x:0,y:0,width:100,height:100'[,parent]); // // @param str string The tag definition to parse and create // @param object The (optional) parent element // @return object The new tag // this.create = function (str) { var def = RGraph.SVG.create.parseStr(this, str); def.svg = this.svg; // By default the parent is the SVG tag - but if // requested then change it to the tag that has // been given if (arguments[1]) { def.parent = arguments[1]; } return RGraph.SVG.create(def); }; // // This function returns the value that the mouse is positioned at, regardless of // the actual indicated value. // // @param object e The event object // this.getValue = function (e) { var mouseX = e.offsetX, mouseY = e.offsetY; if (RGraph.SVG.ISFF) { mouseX = e.pageX - e.currentTarget.offsetLeft; mouseY = e.pageY - e.currentTarget.offsetTop; } var angle = RGraph.SVG.TRIG.getAngleByXY({ cx: this.centerx, cy: this.centery, x: mouseX, y: mouseY }); var value = ((angle - this.angleStart) / (this.angleEnd - this.angleStart)); // Adjust the angle aso that it goes from 0 - 3.14 if (mouseX < this.centerx) { angle = angle - RGraph.SVG.TRIG.PI - RGraph.SVG.TRIG.HALFPI; } else if (mouseX > this.centerx) { angle += RGraph.SVG.TRIG.HALFPI; } else if (mouseX === this.centerx) { angle = RGraph.SVG.TRIG.HALFPI; } value = (this.max - this.min) * (angle / RGraph.SVG.TRIG.PI); if (value < this.min) value = this.min; if (value > this.max) value = this.max; return value; }; // // This function returns the relevant angle for the given // value. // // @param number value The value that you want to get an // angle for // this.getAngle = function (value, outofbounds = false) { if (!outofbounds && (value > this.max || value < this.min) ) { return null; } return (((value - this.min) / (this.max - this.min)) * RGraph.SVG.TRIG.PI) - RGraph.SVG.TRIG.HALFPI; }; // // Draw the background "grid" // this.drawBackground = function () { if (properties.backgroundGrid) { var margin = properties.backgroundGridMargin; var outerRadius = this.radius + margin; var innerRadius = this.radius - properties.width - margin; // Draw the background grid "circles" if (properties.backgroundGridCircles) { // Create the path for the outer line of the grid var arcPath1 = RGraph.SVG.TRIG.getArcPath3({ cx: this.centerx, cy: this.centery, r: outerRadius, start: -RGraph.SVG.TRIG.HALFPI, end: RGraph.SVG.TRIG.HALFPI, anticlockwise: false, lineto: false, moveto: true }); // Create the path for the inner line of the grid var arcPath2 = RGraph.SVG.TRIG.getArcPath3({ cx: this.centerx, cy: this.centery, r: innerRadius, start: RGraph.SVG.TRIG.HALFPI, end: -RGraph.SVG.TRIG.HALFPI, anticlockwise: true, lineto: true }); RGraph.SVG.create({ svg: this.svg, type: 'path', parent: this.svgAllGroup, attr: { d: arcPath1 + ' ' + arcPath2 + ' z', stroke: properties.backgroundGridColor, fill: 'transparent' } }); } // // Draw the background grid radials // if (properties.backgroundGridRadials) { // Calculate the radius increment var increment = (RGraph.SVG.TRIG.HALFPI - (0 - RGraph.SVG.TRIG.HALFPI) ) / properties.backgroundGridRadialsCount; var angle = -RGraph.SVG.TRIG.HALFPI; for (var i=0,path=''; i (this.scale.labels.length / 2)) ? 'left' : 'right'), text: this.scale.labels[i] }); } // Draw the zero label // // Draw the zero label // var xy = RGraph.SVG.TRIG.getRadiusEndPoint({ angle: -RGraph.SVG.TRIG.PI, r: this.radius + (properties.backgroundGrid ? properties.backgroundGridMargin : 0) + textConf.size + properties.scaleLabelsOffsetr + 5 }); RGraph.SVG.text({ object: this, parent: this.svgAllGroup, tag: 'scale', font: textConf.font, size: textConf.size, color: textConf.color, bold: textConf.bold, italic: textConf.italic, x: xy[0] + this.centerx + (properties.scaleLabelsOffsetx || 0), y: xy[1] + this.centery + (properties.scaleLabelsOffsety || 0), valign: 'center', halign: 'right', text: (typeof properties.scaleFormatter === 'function') ? properties.scaleFormatter(this, this.min) : properties.scaleUnitsPre + (typeof properties.scaleMin === 'number' ? properties.scaleMin : this.min).toFixed(properties.scaleDecimals).replace(/\./, properties.scalePoint) + properties.scaleUnitsPost, }); } }; // // This function can be used to highlight a segment on the chart // // @param object segment The segment to highlight // this.highlight = function (segment) { // Remove any highlight that's already been // installed this.removeHighlight(); var highlight = RGraph.SVG.create({ svg: this.svg, type: 'path', parent: this.nodes.barGroup, attr: { d: segment.getAttribute('d'), fill: properties.highlightFill, stroke: properties.highlightStroke, 'stroke-width': properties.highlightLinewidth }, style: { pointerEvents: 'none' } }); // Store the highlight node in the registry RGraph.SVG.REG.set('highlight', highlight); // Add the event listener that clears the highlight path if // there is any. Must be MOUSEDOWN (ie before the click event) var obj = this; document.body.addEventListener('mousedown', function (e) { obj.removeHighlight(); }, false); }; // // This function can be used to remove the highlight that is added // by tooltips // this.removeHighlight = function () { RGraph.SVG.removeHighlight(); }; // // This allows for easy specification of gradients // this.parseColors = function () { // Save the original colors so that they can be restored when the canvas is reset if (!Object.keys(this.originalColors).length) { this.originalColors = { colors: RGraph.SVG.arrayClone(properties.colors), highlightFill: RGraph.SVG.arrayClone(properties.highlightFill), backgroundFill: RGraph.SVG.arrayClone(properties.backgroundFill) } } // colors var colors = properties.colors; if (colors) { for (var i=0; i