JAVASCRIPT   25

Chart.Radar.js

Guest on 5th June 2021 05:39:35 PM

  1. (function(){
  2.       "use strict";
  3.  
  4.       var root = this,
  5.             Chart = root.Chart,
  6.             helpers = Chart.helpers;
  7.  
  8.  
  9.  
  10.       Chart.Type.extend({
  11.             name: "Radar",
  12.             defaults:{
  13.                   //Boolean - Whether to show lines for each scale point
  14.                   scaleShowLine : true,
  15.  
  16.                   //Boolean - Whether we show the angle lines out of the radar
  17.                   angleShowLineOut : true,
  18.  
  19.                   //Boolean - Whether to show labels on the scale
  20.                   scaleShowLabels : false,
  21.  
  22.                   // Boolean - Whether the scale should begin at zero
  23.                   scaleBeginAtZero : true,
  24.  
  25.                   //String - Colour of the angle line
  26.                   angleLineColor : "rgba(0,0,0,.1)",
  27.  
  28.                   //Number - Pixel width of the angle line
  29.                   angleLineWidth : 1,
  30.  
  31.                   //String - Point label font declaration
  32.                   pointLabelFontFamily : "'Arial'",
  33.  
  34.                   //String - Point label font weight
  35.                   pointLabelFontStyle : "normal",
  36.  
  37.                   //Number - Point label font size in pixels
  38.                   pointLabelFontSize : 10,
  39.  
  40.                   //String - Point label font colour
  41.                   pointLabelFontColor : "#666",
  42.  
  43.                   //Boolean - Whether to show a dot for each point
  44.                   pointDot : true,
  45.  
  46.                   //Number - Radius of each point dot in pixels
  47.                   pointDotRadius : 3,
  48.  
  49.                   //Number - Pixel width of point dot stroke
  50.                   pointDotStrokeWidth : 1,
  51.  
  52.                   //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
  53.                   pointHitDetectionRadius : 20,
  54.  
  55.                   //Boolean - Whether to show a stroke for datasets
  56.                   datasetStroke : true,
  57.  
  58.                   //Number - Pixel width of dataset stroke
  59.                   datasetStrokeWidth : 2,
  60.  
  61.                   //Boolean - Whether to fill the dataset with a colour
  62.                   datasetFill : true,
  63.  
  64.                   //String - A legend template
  65.                   legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
  66.  
  67.             },
  68.  
  69.             initialize: function(data){
  70.                   this.PointClass = Chart.Point.extend({
  71.                         strokeWidth : this.options.pointDotStrokeWidth,
  72.                         radius : this.options.pointDotRadius,
  73.                         display: this.options.pointDot,
  74.                         hitDetectionRadius : this.options.pointHitDetectionRadius,
  75.                         ctx : this.chart.ctx
  76.                   });
  77.  
  78.                   this.datasets = [];
  79.  
  80.                   this.buildScale(data);
  81.  
  82.                   //Set up tooltip events on the chart
  83.                   if (this.options.showTooltips){
  84.                         helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
  85.                               var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
  86.  
  87.                               this.eachPoints(function(point){
  88.                                     point.restore(['fillColor', 'strokeColor']);
  89.                               });
  90.                               helpers.each(activePointsCollection, function(activePoint){
  91.                                     activePoint.fillColor = activePoint.highlightFill;
  92.                                     activePoint.strokeColor = activePoint.highlightStroke;
  93.                               });
  94.  
  95.                               this.showTooltip(activePointsCollection);
  96.                         });
  97.                   }
  98.  
  99.                   //Iterate through each of the datasets, and build this into a property of the chart
  100.                   helpers.each(data.datasets,function(dataset){
  101.  
  102.                         var datasetObject = {
  103.                               label: dataset.label || null,
  104.                               fillColor : dataset.fillColor,
  105.                               strokeColor : dataset.strokeColor,
  106.                               pointColor : dataset.pointColor,
  107.                               pointStrokeColor : dataset.pointStrokeColor,
  108.                               points : []
  109.                         };
  110.  
  111.                         this.datasets.push(datasetObject);
  112.  
  113.                         helpers.each(dataset.data,function(dataPoint,index){
  114.                               //Add a new point for each piece of data, passing any required data to draw.
  115.                               var pointPosition;
  116.                               if (!this.scale.animation){
  117.                                     pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
  118.                               }
  119.                               datasetObject.points.push(new this.PointClass({
  120.                                     value : dataPoint,
  121.                                     label : data.labels[index],
  122.                                     datasetLabel: dataset.label,
  123.                                     x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
  124.                                     y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
  125.                                     strokeColor : dataset.pointStrokeColor,
  126.                                     fillColor : dataset.pointColor,
  127.                                     highlightFill : dataset.pointHighlightFill || dataset.pointColor,
  128.                                     highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
  129.                               }));
  130.                         },this);
  131.  
  132.                   },this);
  133.  
  134.                   this.render();
  135.             },
  136.             eachPoints : function(callback){
  137.                   helpers.each(this.datasets,function(dataset){
  138.                         helpers.each(dataset.points,callback,this);
  139.                   },this);
  140.             },
  141.  
  142.             getPointsAtEvent : function(evt){
  143.                   var mousePosition = helpers.getRelativePosition(evt),
  144.                         fromCenter = helpers.getAngleFromPoint({
  145.                               x: this.scale.xCenter,
  146.                               y: this.scale.yCenter
  147.                         }, mousePosition);
  148.  
  149.                   var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount,
  150.                         pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex),
  151.                         activePointsCollection = [];
  152.  
  153.                   // If we're at the top, make the pointIndex 0 to get the first of the array.
  154.                   if (pointIndex >= this.scale.valuesCount || pointIndex < 0){
  155.                         pointIndex = 0;
  156.                   }
  157.  
  158.                   if (fromCenter.distance <= this.scale.drawingArea){
  159.                         helpers.each(this.datasets, function(dataset){
  160.                               activePointsCollection.push(dataset.points[pointIndex]);
  161.                         });
  162.                   }
  163.  
  164.                   return activePointsCollection;
  165.             },
  166.  
  167.             buildScale : function(data){
  168.                   this.scale = new Chart.RadialScale({
  169.                         display: this.options.showScale,
  170.                         fontStyle: this.options.scaleFontStyle,
  171.                         fontSize: this.options.scaleFontSize,
  172.                         fontFamily: this.options.scaleFontFamily,
  173.                         fontColor: this.options.scaleFontColor,
  174.                         showLabels: this.options.scaleShowLabels,
  175.                         showLabelBackdrop: this.options.scaleShowLabelBackdrop,
  176.                         backdropColor: this.options.scaleBackdropColor,
  177.                         backdropPaddingY : this.options.scaleBackdropPaddingY,
  178.                         backdropPaddingX: this.options.scaleBackdropPaddingX,
  179.                         lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
  180.                         lineColor: this.options.scaleLineColor,
  181.                         angleLineColor : this.options.angleLineColor,
  182.                         angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0,
  183.                         // Point labels at the edge of each line
  184.                         pointLabelFontColor : this.options.pointLabelFontColor,
  185.                         pointLabelFontSize : this.options.pointLabelFontSize,
  186.                         pointLabelFontFamily : this.options.pointLabelFontFamily,
  187.                         pointLabelFontStyle : this.options.pointLabelFontStyle,
  188.                         height : this.chart.height,
  189.                         width: this.chart.width,
  190.                         xCenter: this.chart.width/2,
  191.                         yCenter: this.chart.height/2,
  192.                         ctx : this.chart.ctx,
  193.                         templateString: this.options.scaleLabel,
  194.                         labels: data.labels,
  195.                         valuesCount: data.datasets[0].data.length
  196.                   });
  197.  
  198.                   this.scale.setScaleSize();
  199.                   this.updateScaleRange(data.datasets);
  200.                   this.scale.buildYLabels();
  201.             },
  202.             updateScaleRange: function(datasets){
  203.                   var valuesArray = (function(){
  204.                         var totalDataArray = [];
  205.                         helpers.each(datasets,function(dataset){
  206.                               if (dataset.data){
  207.                                     totalDataArray = totalDataArray.concat(dataset.data);
  208.                               }
  209.                               else {
  210.                                     helpers.each(dataset.points, function(point){
  211.                                           totalDataArray.push(point.value);
  212.                                     });
  213.                               }
  214.                         });
  215.                         return totalDataArray;
  216.                   })();
  217.  
  218.  
  219.                   var scaleSizes = (this.options.scaleOverride) ?
  220.                         {
  221.                               steps: this.options.scaleSteps,
  222.                               stepValue: this.options.scaleStepWidth,
  223.                               min: this.options.scaleStartValue,
  224.                               max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
  225.                         } :
  226.                         helpers.calculateScaleRange(
  227.                               valuesArray,
  228.                               helpers.min([this.chart.width, this.chart.height])/2,
  229.                               this.options.scaleFontSize,
  230.                               this.options.scaleBeginAtZero,
  231.                               this.options.scaleIntegersOnly
  232.                         );
  233.  
  234.                   helpers.extend(
  235.                         this.scale,
  236.                         scaleSizes
  237.                   );
  238.  
  239.             },
  240.             addData : function(valuesArray,label){
  241.                   //Map the values array for each of the datasets
  242.                   this.scale.valuesCount++;
  243.                   helpers.each(valuesArray,function(value,datasetIndex){
  244.                         var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
  245.                         this.datasets[datasetIndex].points.push(new this.PointClass({
  246.                               value : value,
  247.                               label : label,
  248.                               x: pointPosition.x,
  249.                               y: pointPosition.y,
  250.                               strokeColor : this.datasets[datasetIndex].pointStrokeColor,
  251.                               fillColor : this.datasets[datasetIndex].pointColor
  252.                         }));
  253.                   },this);
  254.  
  255.                   this.scale.labels.push(label);
  256.  
  257.                   this.reflow();
  258.  
  259.                   this.update();
  260.             },
  261.             removeData : function(){
  262.                   this.scale.valuesCount--;
  263.                   this.scale.labels.shift();
  264.                   helpers.each(this.datasets,function(dataset){
  265.                         dataset.points.shift();
  266.                   },this);
  267.                   this.reflow();
  268.                   this.update();
  269.             },
  270.             update : function(){
  271.                   this.eachPoints(function(point){
  272.                         point.save();
  273.                   });
  274.                   this.reflow();
  275.                   this.render();
  276.             },
  277.             reflow: function(){
  278.                   helpers.extend(this.scale, {
  279.                         width : this.chart.width,
  280.                         height: this.chart.height,
  281.                         size : helpers.min([this.chart.width, this.chart.height]),
  282.                         xCenter: this.chart.width/2,
  283.                         yCenter: this.chart.height/2
  284.                   });
  285.                   this.updateScaleRange(this.datasets);
  286.                   this.scale.setScaleSize();
  287.                   this.scale.buildYLabels();
  288.             },
  289.             draw : function(ease){
  290.                   var easeDecimal = ease || 1,
  291.                         ctx = this.chart.ctx;
  292.                   this.clear();
  293.                   this.scale.draw();
  294.  
  295.                   helpers.each(this.datasets,function(dataset){
  296.  
  297.                         //Transition each point first so that the line and point drawing isn't out of sync
  298.                         helpers.each(dataset.points,function(point,index){
  299.                               if (point.hasValue()){
  300.                                     point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
  301.                               }
  302.                         },this);
  303.  
  304.  
  305.  
  306.                         //Draw the line between all the points
  307.                         ctx.lineWidth = this.options.datasetStrokeWidth;
  308.                         ctx.strokeStyle = dataset.strokeColor;
  309.                         ctx.beginPath();
  310.                         helpers.each(dataset.points,function(point,index){
  311.                               if (index === 0){
  312.                                     ctx.moveTo(point.x,point.y);
  313.                               }
  314.                               else{
  315.                                     ctx.lineTo(point.x,point.y);
  316.                               }
  317.                         },this);
  318.                         ctx.closePath();
  319.                         ctx.stroke();
  320.  
  321.                         ctx.fillStyle = dataset.fillColor;
  322.                         ctx.fill();
  323.  
  324.                         //Now draw the points over the line
  325.                         //A little inefficient double looping, but better than the line
  326.                         //lagging behind the point positions
  327.                         helpers.each(dataset.points,function(point){
  328.                               if (point.hasValue()){
  329.                                     point.draw();
  330.                               }
  331.                         });
  332.  
  333.                   },this);
  334.  
  335.             }
  336.  
  337.       });
  338.  
  339.  
  340.  
  341.  
  342.  
  343. }).call(this);

Raw Paste


Login or Register to edit or fork this paste. It's free.