// 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.Radar = 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]; }; this.type = 'radar'; 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 = RGraph.SVG.arrayClone(conf.data); this.originalData = RGraph.SVG.arrayClone(conf.data); this.coords = []; this.coords2 = []; this.angles = []; this.angles2 = []; this.colorsParsed = false; this.originalColors = {}; this.gradientCounter = 1; this.nodes = []; this.shadowNodes = []; this.max = 0; this.redraw = false; this.highlight_node = null; this.firstDraw = true; // After the first draw this will be false // Convert the data to numbers in case they're passed in as strings this.originalData = RGraph.SVG.stringsToNumbers(this.originalData); //The originalData array should be a multi-dimensional array of each dataset, even if // there's only one dataset if (typeof this.originalData[0] === 'number') { this.originalData = [this.originalData]; } // 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, backgroundGrid: true, backgroundGridColor: '#ddd', backgroundGridRadialsCount: null, backgroundGridConcentricsCount: 5, backgroundGridLinewidth: 1, backgroundGridPoly: true, colors: [ 'red', 'black', 'orange', 'green', '#6ff', '#ccc', 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal' ], filled: false, filledOpacity: 0.25, filledAccumulative: true, textColor: 'black', textFont: 'Arial, Verdana, sans-serif', textSize: 12, textBold: false, textItalic: false, text: null, labels: [], labelsFont: null, labelsColor: null, labelsSize: null, labelsBold: null, labelsItalic: null, labelsOffset: 0, labelsFormattedDecimals: 0, labelsFormattedPoint: '.', labelsFormattedThousand: ',', labelsFormattedUnitsPre: '', labelsFormattedUnitsPost: '', scaleVisible: true, scaleUnitsPre: '', scaleUnitsPost: '', scaleMax: null, scaleMin: 0, scalePoint: '.', scaleThousand: ',', scaleRound: false, scaleDecimals: 0, scaleFormatter: null, scaleBold: null, scaleItalic: null, scaleColor: null, scaleSize: null, scaleFont: null, scaleLabelsCount: 5, linewidth: 1, tooltips: null, tooltipsOverride: null, tooltipsEffect: 'fade', tooltipsCssClass: 'RGraph_tooltip', tooltipsCss: null, tooltipsEvent: 'mousemove', 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, tickmarksStyle: 'circle', tickmarksLinewidth: 1, tickmarksSize: 6, tickmarksFill: 'white', 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,0.25)', key: null, keyColors: null, keyOffsetx: 0, keyOffsety: 0, keyLabelsOffsetx: 0, keyLabelsOffsety: -1, keyLabelsSize: null, keyLabelsBold: null, keyLabelsItalic: null, keyLabelsFont: null, keyLabelsColor: 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'); // 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')); // Reset the data back to the original values this.data = RGraph.SVG.arrayClone(this.originalData); // // The datasets have to have the same number of elements // if (this.data.length > 1) { var len = this.data[0].length; for (var i=1; i 0) { for (var i=0,len=radials; i 0) { if (properties.backgroundGridPoly) { for (var j=1; j<=concentrics; j++) { for (var i=0,len=radials,path=[]; i 0 && properties.filled && properties.filledAccumulative) { // Add a line completing the "circle" path.push('L {1} {2}'.format( this.coords2[dataset][0][0], this.coords2[dataset][0][1] )); // Move to the previous dataset path.push('M {1} {2}'.format( this.coords2[dataset - 1][0][0], this.coords2[dataset - 1][0][1] )); // Now backtrack over the previous dataset for (var i=this.coords2[dataset - 1].length - 1; i>=0; --i) { path.push('L {1} {2}'.format( this.coords2[dataset - 1][i][0], this.coords2[dataset - 1][i][1] )); } this.redraw = true; } else { // Add the closepath path.push('z'); } var path = RGraph.SVG.create({ svg: this.svg, type: 'path', parent: this.svgAllGroup, attr: { d: path.join(" "), stroke: properties.colors[dataset], fill: properties.filled ? properties.colors[dataset] : 'transparent', 'fill-opacity': properties.filledOpacity, 'stroke-width': properties.linewidth, 'clip-path': this.isTrace ? 'url(#trace-effect-clip)' : '', filter: properties.shadow ? 'url(#dropShadow)' : '' } }); path.setAttribute('data-dataset', dataset); } // Redraw the chart (this only runs if necessary this.redrawRadar(); }; // // Redraws the chart if required // this.redrawRadar = function () { if (this.redraw) { this.redraw = false; // Loop through ths coordinates for (var dataset = 0; dataset 0.75) { valign = 'bottom'; } else { valign = 'top'; } // Specify the alignment for labels which are on the axes if ( (i / len) === 0 ) {halign = 'center';} if ( (i / len) === 0.25 ) {valign = 'center';} if ( (i / len) === 0.5 ) {halign = 'center';} if ( (i / len) === 0.75 ) {valign = 'center';} RGraph.SVG.text({ object: this, svg: this.svg, parent: this.svgAllGroup, tag: 'labels', text: labels[i], x: x, y: y, halign: halign, valign: 'center', size: textConf.size, color: textConf.color, bold: textConf.bold, italic: textConf.italic, font: textConf.font }); } // Draw the scale if required if (properties.scaleVisible) { // Get the text configuration var textConf = RGraph.SVG.getTextConf({ object: this, prefix: 'scale' }); for (var i=0; i 0) { // Make the tooltipsEvent default to click if (properties.tooltipsEvent !== 'mousemove') { properties.tooltipsEvent = 'click'; } var group = RGraph.SVG.create({ svg: this.svg, type: 'g', parent: this.svgAllGroup, attr: { className: 'rgraph-radar-tooltip-hotspots' } }); for (var dataset=0,seq=0; dataset