// 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}; // // The traditional radar chart constructor // // @param string id The ID of the canvas // @param array data An array of data to represent // RGraph.Radar = function (conf) { conf.data = RGraph.stringsToNumbers(conf.data); if (typeof conf.data[0] === 'number') { conf.data = [conf.data]; } this.id = conf.id; this.canvas = document.getElementById(conf.id); this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; this.canvas.__object__ = this; this.type = 'radar'; this.isRGraph = true; this.isrgraph = true; this.rgraph = true; this.data = []; this.max = 0; this.uid = RGraph.createUID(); this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.createUID(); this.colorsParsed = false; this.coords = []; this.coordsText = []; this.original_data = []; this.original_colors = []; this.firstDraw = true; // After the first draw this will be false this.stopAnimationRequested = false;// Used to control the animations // // Add the data to the .original_data array and work out the max value // // 2/5/14 Now also use this loop to ensure that the data pieces // are numbers // for (var i=0,len=conf.data.length; i 0) { // This goes back to the start coords of this particular dataset this.context.lineTo(coords_dataset[0][0], coords_dataset[0][1]); //Now move down to the end point of the previous dataset this.context.moveTo(last_coords[0][0], last_coords[0][1]); for (var i=coords_dataset.length - 1; i>=0; --i) { this.context.lineTo(last_coords[i][0], last_coords[i][1]); } } // This is used by the next iteration of the loop var last_coords = coords_dataset; this.context.closePath(); this.context.fill(); this.context.stroke(); this.drawTickmarks(dataset); } // Reset the globalAlpha if (typeof alpha == 'number') { this.context.globalAlpha = oldAlpha; } }; // // Gets the coordinates for a particular mark // // @param number i The index of the data (ie which one it is) // @return array A two element array of the coordinates // this.getCoordinates = function (dataset, index) { // The number of data points var len = this.data[dataset].length; // The magnitude of the data (NOT the x/y coords) var mag = (this.data[dataset][index] / this.max) * this.radius; // // Get the angle // var angle = (RGraph.TWOPI / len) * index; // In radians angle -= RGraph.HALFPI; // // Work out the X/Y coordinates // var x = Math.cos(angle) * mag; var y = Math.sin(angle) * mag; // // Put the coordinate in the right quadrant // x = this.centerx + x; y = this.centery + y; return [x,y]; }; // // This function adds the labels to the chart // this.drawLabels = function () { if (properties.labels && properties.labels.length) { // // If the labels option is a string then turn it // into an array. // if (typeof properties.labels === 'string') { properties.labels = RGraph.arrayPad({ array: [], length: this.data[0].length, value: properties.labels }); } for (var i=0; i 0) { this.context.lineWidth = 1; this.context.strokeStyle = 'gray'; this.context.fillStyle = properties.labelsColor || properties.textColor; var bgFill = properties.labelsBackgroundFill, bold = properties.labelsBold, bgBoxed = properties.labelsBoxed, offset = properties.labelsOffsetRadius, font = properties.textFont, size = properties.textSize, radius = this.radius, color = properties.labelsColor || properties.textColor for (var i=0; i -1) { for (var i=0; i -1) { for (var i=0; i -1) { for (var i=0; i -1) { for (var i=0; i -1) RGraph.text({object: this,font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,tag: 'labels.axes.specific', x:this.centerx,y:this.centery - this.radius + ((this.radius / labels.length) * i),text:reversed_labels[i],valign:'center',halign:'center',bounding:reversed_boxed[i],boundingFill:'white'}); if (axes.indexOf('s') > -1) RGraph.text({object: this,font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,tag: 'labels.axes.specific', x:this.centerx,y:this.centery + ((this.radius / labels.length) * (i+1)),text:labels[i],valign:'center',halign:'center',bounding:boxed[i],boundingFill:'white'}); if (axes.indexOf('w') > -1) RGraph.text({object: this,font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,tag: 'labels.axes.specific', x:this.centerx - this.radius + ((this.radius / labels.length) * i),y:this.centery,text:reversed_labels[i],valign:'center',halign:'center',bounding:reversed_boxed[i],boundingFill:'white'}); if (axes.indexOf('e') > -1) RGraph.text({object: this,font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,tag: 'labels.axes.specific', x:this.centerx + ((this.radius / labels.length) * (i+1)),y:this.centery,text:labels[i],valign:'center',halign:'center',bounding:boxed[i],boundingFill:'white'}); } }; // // This method eases getting the focussed point (if any) // // @param event e The event object // this.getShape = function (e) { for (var i=0; i (x - 5) && mouseY > (y - 5) && mouseY < (y + 5) && (this.properties.clip ? RGraph.clipTo.test(this, mouseX, mouseY) : true) ) { if (RGraph.parseTooltipText) { var tooltip = RGraph.parseTooltipText(properties.tooltips, index); } var indexes = RGraph.sequentialIndexToGrouped(index, this.data); var dataset = indexes[0]; var idx = indexes[1]; return { object: this, x: x, y: y, index: idx, dataset: dataset, sequentialIndex: index, label: properties.labels && typeof properties.labels[idx] === 'string' ? properties.labels[idx] : null, tooltip: typeof tooltip === 'string' ? tooltip : null } } } }; // // Each object type has its own Highlight() function which // highlights the appropriate shape // // @param object shape The shape to highlight // this.highlight = function (shape) { if (typeof properties.highlightStyle === 'function') { (properties.highlightStyle)(shape); // Inverted highlighting } else if (properties.highlightStyle === 'invert') { var radius = 25; this.path( 'b a % % % % % true', shape.x,shape.y,radius,4.72, -1.57 ); for (var a=0; a<=360; a+=(360 / this.data[0].length)) { this.path('a % % % % % false'); this.context.arc( this.centerx, this.centery, this.radius, RGraph.toRadians(a) - RGraph.HALFPI, RGraph.toRadians(a) + 0.001 - RGraph.HALFPI, false ); } // Go back to the top of the chart and then stroke/fill it this.path( 'a % % % % % false c f %', this.centerx,this.centery,this.radius,0 - RGraph.HALFPI,0.001 - RGraph.HALFPI, properties.highlightFill ); // Draw the stroke around the circular cutout this.path( 'b a % % % % % false s %', shape.x,shape.y,radius,0,6.29, properties.highlightStroke ); } else { RGraph.Highlight.point(this, shape); } }; // // The getObjectByXY() worker method. Don't call this call: // // RGraph.ObjectRegistry.getObjectByXY(e) // // @param object e The event object // this.getObjectByXY = function (e) { var mouseXY = RGraph.getMouseXY(e); var extra = 5; if ( mouseXY[0] > (this.centerx - this.radius - extra) && mouseXY[0] < (this.centerx + this.radius + extra) && mouseXY[1] > (this.centery - this.radius - extra) && mouseXY[1] < (this.centery + this.radius + extra) ) { return this; } }; // // This draws tickmarks on the points // // @param number dataset The index of the dataset to // draw tickmarks for // this.drawTickmarks = function (dataset) { if (properties.tickmarks) { var index = 0; var radius = properties.tickmarksRadius; for (var index=0; index this.max) { return null; } // Radar doesn't support minimum value var radius = (value / this.max) * this.radius; return radius; }; // // This function returns the angle (in radians) for a particular index. // // @param number numitems The total number of items // @param number index The zero index number of the item to get the angle for // this.getAngle = function (numitems, index) { var angle = (RGraph.TWOPI / numitems) * index; angle -= RGraph.HALFPI; return angle; }; // // 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 (this.original_colors.length === 0) { this.original_colors.colors = RGraph.arrayClone(properties.colors); this.original_colors.keyColors = RGraph.arrayClone(properties.keyColors); this.original_colors.titleColor = RGraph.arrayClone(properties.titleColor); this.original_colors.textColor = RGraph.arrayClone(properties.textColor); this.original_colors.labelsColor = RGraph.arrayClone(properties.labelsColor); this.original_colors.labelsAxesColor = RGraph.arrayClone(properties.labelsAxesColor); this.original_colors.highlightStroke = RGraph.arrayClone(properties.highlightStroke); this.original_colors.highlightFill = RGraph.arrayClone(properties.highlightFill); this.original_colors.circleFill = RGraph.arrayClone(properties.circleFill); this.original_colors.circleStroke = RGraph.arrayClone(properties.circleStroke); this.original_colors.colorsStroke = RGraph.arrayClone(properties.colorsStroke); } for (var i=0; i=0; --dataset) { // Draw the path again so that it can be checked obj.context.beginPath(); obj.context.moveTo(obj.coords2[dataset][0][0], obj.coords2[dataset][0][1]); for (var j=0; j 0) { obj.context.lineTo(obj.coords2[dataset - 1][0][0], obj.coords2[dataset - 1][0][1]); for (var j=(obj.coords2[dataset - 1].length - 1); j>=0; --j) { obj.context.lineTo(obj.coords2[dataset - 1][j][0], obj.coords2[dataset - 1][j][1]); } } obj.context.closePath(); if (obj.context.isPointInPath(mouseXY[0], mouseXY[1])) { var inPath = true; break; } } // Call the events if (inPath) { var fillTooltips = properties.fillTooltips; // // Click event // if (e.type == 'click') { if (properties.fillClick) { properties.fillClick(e, dataset); } if (properties.fillTooltips && properties.fillTooltips[dataset]) { obj.datasetTooltip(e, dataset); } } // // Mousemove event // if (e.type == 'mousemove') { if (properties.fillMousemove) { properties.fillMousemove(e, dataset); } if (!RGraph.isNull(fillTooltips)) { e.target.style.cursor = 'pointer'; } if (properties.fillTooltips && properties.fillTooltips[dataset]) { e.target.style.cursor = 'pointer'; } } e.stopPropagation(); } else if (e.type == 'mousemove') { obj.canvas.style.cursor = 'default'; } }; // // Add the click listener // if (properties.fillClick || !RGraph.isNull(properties.fillTooltips)) { this.canvas.addEventListener('click', func, false); } // // Add the mousemove listener // if (properties.fillMousemove || !RGraph.isNull(properties.fillTooltips)) { this.canvas.addEventListener('mousemove', func, false); } }; // // This highlights a specific dataset on the chart // // @param number dataset The index of the dataset (which starts at zero) // this.highlightDataset = function (dataset) { this.context.beginPath(); for (var j=0; j 0) { this.context.lineTo(this.coords2[dataset - 1][0][0], this.coords2[dataset - 1][0][1]); for (var j=(this.coords2[dataset - 1].length - 1); j>=0; --j) { this.context.lineTo(this.coords2[dataset - 1][j][0], this.coords2[dataset - 1][j][1]); } } this.context.strokeStyle = properties.fillHighlightStroke; this.context.fillStyle = properties.fillHighlightFill; this.context.stroke(); this.context.fill(); }; // // Shows a tooltip for a dataset (a "fill" tooltip), You can pecify these // with the fillTooltips option // this.datasetTooltip = function (e, dataset) { // Highlight the dataset this.highlightDataset(dataset); // Use the First datapoints coords for the Y position of the tooltip NOTE The X position is changed in the // obj.positionTooltip() method so set the index to be the first one var text = properties.fillTooltips[dataset]; var x = this.coords2[dataset][0][0] + RGraph.getCanvasXY(this.canvas)[0]; var y = this.coords2[dataset][0][1] + RGraph.getCanvasXY(this.canvas)[1]; // Show a tooltip RGraph.tooltip({ object: this, text: text, x: x, y: y, index: 0, event: e }); }; // // This function handles highlighting an entire data-series for the interactive // key // // @param int index The index of the data series to be highlighted // this.interactiveKeyHighlight = function (index) { var coords = this.coords2[index]; if (coords) { var pre_linewidth = this.context.lineWidth; var pre_linecap = this.context.lineCap; // ------------------------------------------ // this.context.lineWidth = properties.linewidth + 10; this.context.lineCap = 'round'; this.context.strokeStyle = properties.keyInteractiveHighlightChartStroke; this.context.beginPath(); for (var i=0,len=coords.length; i