123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- (function(){
- "use strict";
- var root = this,
- Chart = root.Chart,
- helpers = Chart.helpers;
- Chart.Type.extend({
- name: "Radar",
- defaults:{
- //Boolean - Whether to show lines for each scale point
- scaleShowLine : true,
- //Boolean - Whether we show the angle lines out of the radar
- angleShowLineOut : true,
- //Boolean - Whether to show labels on the scale
- scaleShowLabels : false,
- // Boolean - Whether the scale should begin at zero
- scaleBeginAtZero : true,
- //String - Colour of the angle line
- angleLineColor : "rgba(0,0,0,.1)",
- //Number - Pixel width of the angle line
- angleLineWidth : 1,
- //String - Point label font declaration
- pointLabelFontFamily : "'Arial'",
- //String - Point label font weight
- pointLabelFontStyle : "normal",
- //Number - Point label font size in pixels
- pointLabelFontSize : 10,
- //String - Point label font colour
- pointLabelFontColor : "#666",
- //Boolean - Whether to show a dot for each point
- pointDot : true,
- //Number - Radius of each point dot in pixels
- pointDotRadius : 3,
- //Number - Pixel width of point dot stroke
- pointDotStrokeWidth : 1,
- //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
- pointHitDetectionRadius : 20,
- //Boolean - Whether to show a stroke for datasets
- datasetStroke : true,
- //Number - Pixel width of dataset stroke
- datasetStrokeWidth : 2,
- //Boolean - Whether to fill the dataset with a colour
- datasetFill : true,
- //String - A legend template
- 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>"
- },
- initialize: function(data){
- this.PointClass = Chart.Point.extend({
- strokeWidth : this.options.pointDotStrokeWidth,
- radius : this.options.pointDotRadius,
- display: this.options.pointDot,
- hitDetectionRadius : this.options.pointHitDetectionRadius,
- ctx : this.chart.ctx
- });
- this.datasets = [];
- this.buildScale(data);
- //Set up tooltip events on the chart
- if (this.options.showTooltips){
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
- var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
- this.eachPoints(function(point){
- point.restore(['fillColor', 'strokeColor']);
- });
- helpers.each(activePointsCollection, function(activePoint){
- activePoint.fillColor = activePoint.highlightFill;
- activePoint.strokeColor = activePoint.highlightStroke;
- });
- this.showTooltip(activePointsCollection);
- });
- }
- //Iterate through each of the datasets, and build this into a property of the chart
- helpers.each(data.datasets,function(dataset){
- var datasetObject = {
- label: dataset.label || null,
- fillColor : dataset.fillColor,
- strokeColor : dataset.strokeColor,
- pointColor : dataset.pointColor,
- pointStrokeColor : dataset.pointStrokeColor,
- points : []
- };
- this.datasets.push(datasetObject);
- helpers.each(dataset.data,function(dataPoint,index){
- //Add a new point for each piece of data, passing any required data to draw.
- var pointPosition;
- if (!this.scale.animation){
- pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
- }
- datasetObject.points.push(new this.PointClass({
- value : dataPoint,
- label : data.labels[index],
- datasetLabel: dataset.label,
- x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
- y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
- strokeColor : dataset.pointStrokeColor,
- fillColor : dataset.pointColor,
- highlightFill : dataset.pointHighlightFill || dataset.pointColor,
- highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
- }));
- },this);
- },this);
- this.render();
- },
- eachPoints : function(callback){
- helpers.each(this.datasets,function(dataset){
- helpers.each(dataset.points,callback,this);
- },this);
- },
- getPointsAtEvent : function(evt){
- var mousePosition = helpers.getRelativePosition(evt),
- fromCenter = helpers.getAngleFromPoint({
- x: this.scale.xCenter,
- y: this.scale.yCenter
- }, mousePosition);
- var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount,
- pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex),
- activePointsCollection = [];
- // If we're at the top, make the pointIndex 0 to get the first of the array.
- if (pointIndex >= this.scale.valuesCount || pointIndex < 0){
- pointIndex = 0;
- }
- if (fromCenter.distance <= this.scale.drawingArea){
- helpers.each(this.datasets, function(dataset){
- activePointsCollection.push(dataset.points[pointIndex]);
- });
- }
- return activePointsCollection;
- },
- buildScale : function(data){
- this.scale = new Chart.RadialScale({
- display: this.options.showScale,
- fontStyle: this.options.scaleFontStyle,
- fontSize: this.options.scaleFontSize,
- fontFamily: this.options.scaleFontFamily,
- fontColor: this.options.scaleFontColor,
- showLabels: this.options.scaleShowLabels,
- showLabelBackdrop: this.options.scaleShowLabelBackdrop,
- backdropColor: this.options.scaleBackdropColor,
- backdropPaddingY : this.options.scaleBackdropPaddingY,
- backdropPaddingX: this.options.scaleBackdropPaddingX,
- lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
- lineColor: this.options.scaleLineColor,
- angleLineColor : this.options.angleLineColor,
- angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0,
- // Point labels at the edge of each line
- pointLabelFontColor : this.options.pointLabelFontColor,
- pointLabelFontSize : this.options.pointLabelFontSize,
- pointLabelFontFamily : this.options.pointLabelFontFamily,
- pointLabelFontStyle : this.options.pointLabelFontStyle,
- height : this.chart.height,
- width: this.chart.width,
- xCenter: this.chart.width/2,
- yCenter: this.chart.height/2,
- ctx : this.chart.ctx,
- templateString: this.options.scaleLabel,
- labels: data.labels,
- valuesCount: data.datasets[0].data.length
- });
- this.scale.setScaleSize();
- this.updateScaleRange(data.datasets);
- this.scale.buildYLabels();
- },
- updateScaleRange: function(datasets){
- var valuesArray = (function(){
- var totalDataArray = [];
- helpers.each(datasets,function(dataset){
- if (dataset.data){
- totalDataArray = totalDataArray.concat(dataset.data);
- }
- else {
- helpers.each(dataset.points, function(point){
- totalDataArray.push(point.value);
- });
- }
- });
- return totalDataArray;
- })();
- var scaleSizes = (this.options.scaleOverride) ?
- {
- steps: this.options.scaleSteps,
- stepValue: this.options.scaleStepWidth,
- min: this.options.scaleStartValue,
- max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
- } :
- helpers.calculateScaleRange(
- valuesArray,
- helpers.min([this.chart.width, this.chart.height])/2,
- this.options.scaleFontSize,
- this.options.scaleBeginAtZero,
- this.options.scaleIntegersOnly
- );
- helpers.extend(
- this.scale,
- scaleSizes
- );
- },
- addData : function(valuesArray,label){
- //Map the values array for each of the datasets
- this.scale.valuesCount++;
- helpers.each(valuesArray,function(value,datasetIndex){
- var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
- this.datasets[datasetIndex].points.push(new this.PointClass({
- value : value,
- label : label,
- x: pointPosition.x,
- y: pointPosition.y,
- strokeColor : this.datasets[datasetIndex].pointStrokeColor,
- fillColor : this.datasets[datasetIndex].pointColor
- }));
- },this);
- this.scale.labels.push(label);
- this.reflow();
- this.update();
- },
- removeData : function(){
- this.scale.valuesCount--;
- this.scale.labels.shift();
- helpers.each(this.datasets,function(dataset){
- dataset.points.shift();
- },this);
- this.reflow();
- this.update();
- },
- update : function(){
- this.eachPoints(function(point){
- point.save();
- });
- this.reflow();
- this.render();
- },
- reflow: function(){
- helpers.extend(this.scale, {
- width : this.chart.width,
- height: this.chart.height,
- size : helpers.min([this.chart.width, this.chart.height]),
- xCenter: this.chart.width/2,
- yCenter: this.chart.height/2
- });
- this.updateScaleRange(this.datasets);
- this.scale.setScaleSize();
- this.scale.buildYLabels();
- },
- draw : function(ease){
- var easeDecimal = ease || 1,
- ctx = this.chart.ctx;
- this.clear();
- this.scale.draw();
- helpers.each(this.datasets,function(dataset){
- //Transition each point first so that the line and point drawing isn't out of sync
- helpers.each(dataset.points,function(point,index){
- if (point.hasValue()){
- point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
- }
- },this);
- //Draw the line between all the points
- ctx.lineWidth = this.options.datasetStrokeWidth;
- ctx.strokeStyle = dataset.strokeColor;
- ctx.beginPath();
- helpers.each(dataset.points,function(point,index){
- if (index === 0){
- ctx.moveTo(point.x,point.y);
- }
- else{
- ctx.lineTo(point.x,point.y);
- }
- },this);
- ctx.closePath();
- ctx.stroke();
- ctx.fillStyle = dataset.fillColor;
- ctx.fill();
- //Now draw the points over the line
- //A little inefficient double looping, but better than the line
- //lagging behind the point positions
- helpers.each(dataset.points,function(point){
- if (point.hasValue()){
- point.draw();
- }
- });
- },this);
- }
- });
- }).call(this);
|