// 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.Pie = 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; 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; 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]; }; // Convert strings to numbers conf.data = RGraph.SVG.stringsToNumbers(conf.data); this.type = 'pie'; 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; this.angles = []; this.colorsParsed = false; this.originalColors = {}; this.gradientCounter = 1; this.nodes = []; this.shadowNodes = []; this.firstDraw = true; // After the first draw this will be false // 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, marginLeft: 35, marginRight: 35, marginTop: 35, marginBottom: 35, colors: [ '#f66', '#6f6', '#66f', '#ff6', '#6ff', '#ccc', 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal' ], colorsStroke: 'rgba(0,0,0,0)', textColor: 'black', textFont: 'Arial, Verdana, sans-serif', textSize: 12, textBold: false, textItalic: false, text: null, labels: [], labelsSticks: true, labelsSticksOffset: 50, labelsFormattedDecimals: 0, labelsFormattedPoint: '.', labelsFormattedThousand: ',', labelsFormattedUnitsPre: '', labelsFormattedUnitsPost: '', 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, highlightStroke: 'rgba(0,0,0,0)', highlightFill: 'rgba(255,255,255,0.7)', highlightLinewidth: 1, highlightStyle: 'normal', highlightStyleOutlineWidth: 7, title: '', titleX: null, titleY: null, titleHalign: 'center', titleValign: null, titleSize: null, titleColor: null, titleFont: null, titleBold: null, titleItalic: null, titleSubtitle: null, titleSubtitleSize: null, titleSubtitleColor: '#aaa', titleSubtitleFont: null, titleSubtitleBold: null, titleSubtitleItalic: null, shadow: false, shadowOffsetx: 2, shadowOffsety: 2, shadowBlur: 2, shadowColor: 'rgba(0,0,0,.25)', exploded: 0, roundRobinMultiplier: 1, donut: false, donutWidth: 75, key: null, keyColors: null, keyOffsetx: 0, keyOffsety: 0, keyLabelsOffsetx: 0, keyLabelsOffsety: -1, keyLabelsColor: null, keyLabelsFont: null, keyLabelsSize: null, keyLabelsBold: null, keyLabelsItalic: 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'); //(Re)set this so it doesn't grow endlessly this.angles = []; // 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); 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.graphHeight / 2) + properties.marginTop; this.radius = Math.min(this.graphWidth, this.graphHeight) / 2; // Allow the user to override the calculated centerx/y/radius this.centerx = typeof properties.centerx === 'number' ? properties.centerx : this.centerx; this.centery = typeof properties.centery === 'number' ? properties.centery : this.centery; this.radius = typeof properties.radius === 'number' ? properties.radius : this.radius; // // 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); // Parse the colors for gradients // Must be after the cx/cy/r calculations RGraph.SVG.resetColorsToOriginalValues({object:this}); this.parseColors(); // Go through the data and work out the maximum value this.max = RGraph.SVG.arrayMax(this.data); this.total = RGraph.SVG.arraySum(this.data); // Set the explosion to be an array if it's a number if (typeof properties.exploded === 'number' && properties.exploded > 0) { var val = properties.exploded; properties.exploded = []; for (var i=0; i 0 && angles[i].halfway < RGraph.SVG.TRIG.HALFPI) { halign = 'left'; valign = 'bottom'; } else if (angles[i].halfway > RGraph.SVG.TRIG.HALFPI && angles[i].halfway < RGraph.SVG.TRIG.PI) { halign = 'left'; valign = 'top'; } else if (angles[i].halfway > RGraph.SVG.TRIG.PI && angles[i].halfway < (RGraph.SVG.TRIG.HALFPI + RGraph.SVG.TRIG.PI)) { halign = 'right'; valign = 'top'; } else if (angles[i].halfway > (RGraph.SVG.TRIG.HALFPI + RGraph.SVG.TRIG.PI) && angles[i].halfway < RGraph.SVG.TRIG.TWOPI) { halign = 'right'; valign = 'top'; } RGraph.SVG.text({ object: this, parent: this.svgAllGroup, tag: 'labels', text: typeof labels[i] === 'string' ? labels[i] : '', x: x, y: y, valign: valign, halign: halign, font: textConf.font, size: textConf.size, bold: textConf.bold, italic: textConf.italic, color: textConf.color }); } }; // // Draws the ingraph labels // this.drawIngraphLabels = function () { if (properties.labelsIngraph) { var textConf = RGraph.SVG.getTextConf({ object: this, prefix: 'labelsIngraph' }); for (var i=0; i RGraph.SVG.TRIG.HALFPI) { var index = labels_left.length; labels_left[index] = []; labels_left[index].text = properties.labels[i]; labels_left[index].halign = 'right'; labels = labels_left; labels_coords[i].halign = 'right'; } else { var index = labels_right.length; labels_right[index] = []; labels_right[index].text = properties.labels[i]; labels_right[index].halign = 'right'; labels = labels_right; labels_coords[i].halign = 'left'; } endpoint_inner[0] += (explosion[1] || 0); endpoint_inner[1] += (explosion[2] || 0); endpoint_outer[0] += (explosion[1] || 0); endpoint_outer[1] += (explosion[2] || 0); var x,y; if (labels[index].text) { var stick = RGraph.SVG.create({ svg: this.svg, parent: this.svgAllGroup, type: 'path', attr: { d: 'M {1} {2} L {3} {4}'.format( this.centerx + endpoint_inner[0], this.centery + endpoint_inner[1], this.centerx + endpoint_outer[0], this.centery + endpoint_outer[1] ), stroke: '#999', fill: 'rgba(0,0,0,0)' } }); } // The path is altered later so this needs saving if (stick) { labels[index].stick = stick; } x = (this.centerx + endpoint_outer[0] + (angle > 1.57 ? -50 : 50)); y = (this.centery + endpoint_outer[1]); labels_coords[i].x = x ; labels_coords[i].y = y; labels_coords[i].text = properties.labels[i]; } // Calculate the spacing for each side var vspace_right = (this.height - properties.marginTop - properties.marginBottom) / labels_right.length; var vspace_left = (this.height - properties.marginTop - properties.marginBottom) / labels_left.length; // Reset these x = y = 0; // Get the text configuration var textConf = RGraph.SVG.getTextConf({ object: this, prefix: 'labels' }); // Loop through the RHS labels for (var i=0; i