// 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.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') { 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); //if (typeof conf.data === 'string') { // conf.data = conf.data.split(/,|\|/); //} //for (var i=0; i 0) { // This draws the radials for the non-equi-angular ONLY if (properties.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 RGraph.SVG.create({ svg: this.svg, type: 'circle', parent: grid, attr: { cx: this.centerx, cy: this.centery, r: this.radius * (j/concentrics), fill: 'transparent', stroke: properties.backgroundGridColor, 'stroke-width': properties.backgroundGridLinewidth } }); } } } }; // // Draws the Rose chart // this.drawRose = function () { var opt = arguments[0] || {}; // Empty the this.coords array so that animations don't // continually add new segments on top of old ones. for (var i=0; i this.centerx) { halign = 'left'; } else if (Math.round(endpoint[0]) === this.centerx) { halign = 'center'; } else { halign = 'right'; } RGraph.SVG.text({ object: this, svg: this.svg, parent: group, tag: 'labels', text: typeof properties.labels[i] === 'string' ? properties.labels[i] : '', x: endpoint[0], y: endpoint[1], halign: halign, valign: 'center', background: 'rgba(255,255,255,0.7)', padding:2, size: textConf.size, color: textConf.color, bold: textConf.bold, italic: textConf.italic, font: textConf.font }); } }; // // This function can be used to highlight a segment on the chart // // @param object circle The circle to highlight // this.highlight = function (path) { // // Get the details of the segment and then uswe the arcPath as // the d attribute to a path object. // var centerx = path.getAttribute('data-centerx'), centery = path.getAttribute('data-centery'), radius = path.getAttribute('data-radius'), radiusInner = path.getAttribute('data-radius-inner'), start = path.getAttribute('data-start-angle'), end = path.getAttribute('data-end-angle'); var arcPath = RGraph.SVG.TRIG.getArcPath3({ cx: centerx, cy: centery, r: radius, start: start, end: end, lineto: true }); var arcPath_array = RGraph.SVG.TRIG.getArcPath3({ cx: centerx, cy: centery, r: radius, start: start, end: end, lineto: true, array: true }); if (radiusInner) { var arcPath2 = RGraph.SVG.TRIG.getArcPath3({ cx: centerx, cy: centery, r: radiusInner, start: end, end: start, lineto: true, anticlockwise: true }); } else { arcPath2 = ' L {1} {2}'.format(centerx, centery); } var highlight = RGraph.SVG.create({ svg: this.svg, parent: this.svgAllGroup, type: 'path', attr: { d: 'M {1} {2} '.format(arcPath_array[1], arcPath_array[2]) + arcPath + ' ' + arcPath2 + ' z', fill: properties.highlightFill, stroke: properties.highlightStroke, 'stroke-width': properties.highlightLinewidth }, style: { pointerEvents: 'none' } }); if (properties.tooltipsEvent === 'mousemove') { highlight.addEventListener('mouseout', function (e) { highlight.parentNode.removeChild(highlight); RGraph.SVG.hideTooltip(); RGraph.SVG.REG.set('highlight', null); }, false); } // Store the highlight rect in the registry so // it can be cleared later RGraph.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: RGraph.SVG.arrayClone(properties.colors), highlightFill: RGraph.SVG.arrayClone(properties.highlightFill) } } // colors var colors = properties.colors; if (colors) { for (var i=0; i= frames) { callback(obj); } else { RGraph.SVG.FX.update(iterator); } } iterator(); return this; }; // // The grow effect // this.roundRobin = this.roundrobin = function (opt) { var obj = this, opt = arguments[0] || {}, frame = -1, frames = opt.frames || 60, callback = opt.callback || function () {}; properties.effectRoundrobinMultiplier = 0.01; this.draw(); function iterator () { // Increase the frame counter ++frame; // Get the multiplier using easing var multiplier = RGraph.SVG.FX.getEasingMultiplier(frames, frame); // Set the multiplier that the radius of the segments is // multiplied with. properties.effectRoundrobinMultiplier = multiplier; // Redraw the segments obj.drawRose(); if (frame >= frames) { callback(obj); } else { RGraph.SVG.FX.update(iterator); } } iterator(); return this; }; // // A worker function that handles Bar chart specific tooltip substitutions // this.tooltipSubstitutions = function (opt) { var indexes = RGraph.SVG.sequentialIndexToGrouped(opt.index, this.data); if (properties.variant === 'non-equi-angular') { // Stacked if (typeof this.data[0][0] === 'object') { var tmp = []; // Add all of the arrays to a temporary array for (var i=0; i 0) { return {continue: true}; } color = colors[specific.index]; value = this.data[specific.dataset][0]; value2 = typeof this.data[specific.dataset][1] === 'number' ? this.data[specific.dataset][1] : null label = properties.tooltipsFormattedKeyLabels[specific.dataset];//this.data[specific.dataset][0]; // STACKED NON-EQUI-ANGULAR } else if (RGraph.SVG.isArray(this.data[specific.dataset][0])) { color = colors[index]; value = this.data[specific.dataset][0][index]; value = typeof this.data[specific.dataset][0][index] === 'number' ? this.data[specific.dataset][0][index] : null; value2 = typeof this.data[specific.dataset][1] === 'number' ? this.data[specific.dataset][1] : null; label = properties.tooltipsFormattedKeyLabels[index]; } // STACKED REGULAR CHART } else if (typeof this.data[specific.dataset] === 'object') { //label = properties.tooltipsFormattedKeyLabels[specific.dataset] || ''; color = !RGraph.SVG.isNull(properties.tooltipsFormattedKeyColors) && properties.tooltipsFormattedKeyColors[index] ? properties.tooltipsFormattedKeyColors[index] : color; } return { label: label, color: color, value: value, value2: value2 }; }; // // This allows for static tooltip positioning // this.positionTooltipStatic = function (args) { var obj = args.object, e = args.event, tooltip = args.tooltip, index = args.index, svgXY = RGraph.SVG.getSVGXY(obj.svg), angles = this.angles[index]; // Get the angles from the data attributes on the tag and // REMEMBER TO CONVERT THEM TO NUMBERS var startAngle = parseFloat(angles.element.getAttribute('data-start-angle')); var endAngle = parseFloat(angles.element.getAttribute('data-end-angle')); var radiusInner = parseFloat(angles.element.getAttribute('data-radius-inner')); var radiusOuter = parseFloat(angles.element.getAttribute('data-radius')); var angle = ((endAngle - startAngle) / 2) + startAngle - RGraph.SVG.TRIG.HALFPI; if (isNaN(radiusInner)) { radiusInner = 0; } var coords = RGraph.SVG.TRIG.toCartesian({ cx: this.centerx, cy: this.centery, r: ((radiusOuter - radiusInner) / 2) + radiusInner, angle: angle }); // Position the tooltip in the X direction args.tooltip.style.left = ( svgXY[0] // The X coordinate of the canvas - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width + coords.x ) + 'px'; args.tooltip.style.top = ( svgXY[1] // The Y coordinate of the canvas - tooltip.offsetHeight // The height of the tooltip - 10 // An arbitrary amount + coords.y ) + 'px'; }; // // This function handles clipping to scale values. Because // each chart handles scales differently, a worker function // is needed instead of it all being done centrally in the // main function. // // @param object clipPath The parent cipPath element // this.clipToScaleWorker = function (clipPath) { if (RegExp.$1 === 'min') from = this.min; else from = Number(RegExp.$1); if (RegExp.$2 === 'max') to = this.max; else to = Number(RegExp.$2); var r1 = this.getRadius(from), r2 = this.getRadius(to); // Change the radius if the number is "min" if (RegExp.$1 === 'min') { r1 = 0; } // Change the radius if the number is "max" if (RegExp.$2 === 'max') { r2 = Math.max(this.width, this.height); } var path1 = RGraph.SVG.TRIG.getArcPath3({ cx: this.centerx, cy: this.centery, radius: r1, start: 0, end: RGraph.SVG.TRIG.TWOPI, anticlockwise: false }); var path2 = RGraph.SVG.TRIG.getArcPath3({ cx: this.centerx, cy: this.centery, radius: r2, start: RGraph.SVG.TRIG.TWOPI, end: 0, anticlockwise: true }); RGraph.SVG.create({ svg: this.svg, parent: clipPath, type: 'path', attr: { d: 'M {1} {2} {3} {4} z'.format( this.centerx, this.centery, path1, path2 ) } }); // Now set the clip-path attribute on the // all-elements group this.svgAllGroup.setAttribute( 'clip-path', 'url(#' + clipPath.id + ')' ); }; // // Set the options that the user has provided // for (i in conf.options) { if (typeof i === 'string') { this.set(i, conf.options[i]); } } }; return this; // End module pattern })(window, document);