mirror of
https://github.com/JonnyBro/JaBa.git
synced 2024-11-30 00:54:57 +05:00
343 lines
No EOL
9.9 KiB
JavaScript
343 lines
No EOL
9.9 KiB
JavaScript
(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); |