// 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}; RGraph.SVG = RGraph.SVG || {}; // Module pattern (function (win, doc, undefined) { var RG = RGraph, ua = navigator.userAgent, ma = Math, win = window, doc = document; RG.SVG.Rose = 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') { var ret = RG.SVG.commonSetter({ object: this, name: i, value: arguments[0][i] }); name = ret.name; value = ret.value; this.set(name, value); } } } else { var ret = RG.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 = RG.SVG.arrayClone(value); this.colorsParsed = false; } } return this; }; this.id = conf.id; this.uid = RG.SVG.createUID(); this.container = document.getElementById(this.id); this.layers = {}; // MUST be before the SVG tag is created! this.svg = RG.SVG.createSVG({object: this,container: this.container}); this.isRGraph = true; this.width = Number(this.svg.getAttribute('width')); this.height = Number(this.svg.getAttribute('height')); this.data = RG.SVG.arrayClone(conf.data); this.originalData = RG.SVG.arrayClone(conf.data); this.type = 'rose'; 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; // Add this object to the ObjectRegistry RG.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, gutterLeft: 35, gutterRight: 35, gutterTop: 35, gutterBottom: 35, backgroundGrid: true, backgroundGridColor: '#ddd', backgroundGridRadialsCount: null, backgroundGridRadialsAngleOffset: 0, backgroundGridConcentricsCount: 5, backgroundGridLinewidth: 1, strokestyle: 'white', colors: [ 'red', 'black', 'orange', 'green', '#6ff', '#ccc', 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal' ], colorsOpacity: 1, textColor: 'black', textFont: 'sans-serif', textSize: 12, textBold: false, textItalic: false, labels: [], labelsFont: null, labelsSize: null, labelsColor: null, labelsBold: null, labelsItalic: null, labelsRadialMargin: 10, labelsAngleOffset: 0, 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', tooltipsEvent: 'click', highlightStroke: 'rgba(0,0,0,0)', highlightFill: 'rgba(255,255,255,0.7)', highlightLinewidth: 1, title: '', titleSize: 16, titleX: null, titleY: null, titleHalign: 'center', titleValign: null, titleColor: 'black', titleFont: null, titleBold: false, titleItalic: false, titleSubtitle: null, titleSubtitleSize: 10, titleSubtitleX: null, titleSubtitleY: null, titleSubtitleHalign: 'center', titleSubtitleValign: null, titleSubtitleColor: '#aaa', titleSubtitleFont: null, titleSubtitleBold: false, titleSubtitleItalic: false, shadow: false, shadowOffsetx: 2, shadowOffsety: 2, shadowBlur: 2, shadowOpacity: 0.25, margin: 0, exploded: 0, key: null, keyColors: null, keyOffsetx: 0, keyOffsety: 0, keyTextOffsetx: 0, keyTextOffsety: -1, keyTextSize: null, keyTextBold: null, keyTextItalic: null, segmentsAngleOffset: 0, variant: 'normal' }; // // Copy the global object properties to this instance // RG.SVG.getGlobals(this); /** * "Decorate" the object with the generic effects if the effects library has been included */ if (RG.SVG.FX && typeof RG.SVG.FX.decorate === 'function') { RG.SVG.FX.decorate(this); } var prop = this.properties; // // The draw method draws the Bar chart // this.draw = function () { // Fire the beforedraw event RG.SVG.fireCustomEvent(this, 'onbeforedraw'); // Should the first thing that's done inthe.draw() function // except for the onbeforedraw event this.width = Number(this.svg.getAttribute('width')); this.height = Number(this.svg.getAttribute('height')); // Reset the data back to the original values this.data = RG.SVG.arrayClone(this.originalData); // Reset the angles array to stop it growing this.angles = []; // Create the arrays in the angles2 array based on // the data that we've been passed for (var i=0; i 0) { // This draws the radials for the non-equi-angular ONLY if (prop.variant === 'non-equi-angular') { // Number of radials always matches the number of data pieces var radials = this.data.length; // Work out the total of the second part of each data bit for (var i=0,total=0; i 0) { for (var j=1; j<=concentrics; j++) { // Add circle to the scene RG.SVG.create({ svg: this.svg, type: 'circle', parent: grid, attr: { cx: this.centerx, cy: this.centery, r: this.radius * (j/concentrics), fill: 'transparent', stroke: prop.backgroundGridColor, 'stroke-width': prop.backgroundGridLinewidth } }); } } } }; // // Draws the radar // this.drawRose = function (opt) { // Jump to another function if we're drawing a non-equi-angular chart if (prop.variant === 'non-equi-angular') { return this.drawRoseNonEquiAngular(opt); } var radians = RG.SVG.TRIG.TWOPI / this.data.length; var group = RG.SVG.create({ svg: this.svg, type:'g', parent: this.svg.all, attr: { id: 'rgraph_rose_segments_' + this.id } }); // Now loop thru the data for (var i=0,seq=0; i this.centerx) { halign = 'left'; } else if (ma.round(endpoint[0]) === this.centerx) { halign = 'center'; } else { halign = 'right'; } RG.SVG.text({ object: this, svg: this.svg, parent: this.svg.all, tag: 'labels', text: typeof prop.labels[i] === 'string' ? prop.labels[i] : '', size: prop.labelsSize, x: endpoint[0], y: endpoint[1], halign: halign, valign: 'center', background: 'rgba(255,255,255,0.7)', padding:2, color: prop.labelsColor || prop.textColor, bold: typeof prop.labelsBold === 'boolean' ? prop.labelsBold : prop.textBold, italic: typeof prop.labelsItalic === 'boolean' ? prop.labelsItalic : prop.textItalic, font: prop.labelsFont || prop.textFont }); } }; /** * This function can be used to highlight a segment on the chart * * @param object circle The circle to highlight */ this.highlight = function (path) { var path = path.getAttribute('d'); var highlight = RG.SVG.create({ svg: this.svg, parent: this.svg.all, type: 'path', attr: { d: path, fill: prop.highlightFill, stroke: prop.highlightStroke, 'stroke-width': prop.highlightLinewidth }, style: { pointerEvents: 'none' } }); if (prop.tooltipsEvent === 'mousemove') { highlight.addEventListener('mouseout', function (e) { highlight.parentNode.removeChild(highlight); RG.SVG.hideTooltip(); RG.SVG.REG.set('highlight', null); }, false); } // Store the highlight rect in the registry so // it can be cleared later RG.SVG.REG.set('highlight', highlight); }; /** * 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: RG.SVG.arrayClone(prop.colors), highlightFill: RG.SVG.arrayClone(prop.highlightFill) } } // colors var colors = prop.colors; if (colors) { for (var i=0; i