Polar Area deep data

This commit is contained in:
Tanner Linsley 2015-05-26 22:02:41 -06:00
parent e774a893da
commit 3a32144d89
4 changed files with 208 additions and 283 deletions

View File

@ -1,76 +1,67 @@
<!doctype html>
<html>
<head>
<title>Polar Area Chart</title>
<script src="../Chart.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:30%">
<canvas id="chart-area" width="300" height="300"/>
</div>
<button id="randomizeData">Randomize Data</button>
<head>
<title>Polar Area Chart</title>
<script src="../Chart.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<script>
<body>
<div id="canvas-holder" style="width:100%">
<canvas id="chart-area" width="300" height="300" />
</div>
<button id="randomizeData">Randomize Data</button>
<script>
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
var config = {
data: {
data: [{
value: randomScalingFactor(),
backgroundColor: "#F7464A",
label: "Red"
}, {
value: randomScalingFactor(),
backgroundColor: "#46BFBD",
label: "Green"
}, {
value: randomScalingFactor(),
backgroundColor: "#FDB45C",
label: "Yellow"
}, {
value: randomScalingFactor(),
backgroundColor: "#949FB1",
label: "Grey"
}, {
value: randomScalingFactor(),
backgroundColor: "#4D5360",
label: "Dark Grey"
}]
},
options: {
responsive: true
}
};
var polarData = [
{
value: randomScalingFactor(),
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: randomScalingFactor(),
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: randomScalingFactor(),
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
},
{
value: randomScalingFactor(),
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: randomScalingFactor(),
color: "#4D5360",
highlight: "#616774",
label: "Dark Grey"
}
window.onload = function() {
var ctx = document.getElementById("chart-area").getContext("2d");
window.myPolarArea = new Chart(ctx).PolarArea(config);
};
];
$('#randomizeData').click(function() {
$.each(polarData, function(i, piece) {
polarData[i].value = randomScalingFactor();
polarData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
});
window.myPolarArea.update();
});
</script>
</body>
window.onload = function(){
var ctx = document.getElementById("chart-area").getContext("2d");
window.myPolarArea = new Chart(ctx).PolarArea({
data: polarData,
options: {
responsive:true
}
});
};
$('#randomizeData').click(function(){
$.each(polarData, function(i, piece){
polarData[i].value = randomScalingFactor();
polarData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
});
window.myPolarArea.update();
});
</script>
</body>
</html>

View File

@ -1372,7 +1372,7 @@
},
draw: function() {
var ctx = this.ctx;
var ctx = this._chart.ctx;
var vm = this._vm;
ctx.beginPath();

View File

@ -74,7 +74,7 @@
innerRadius: (this.options.animateScale) ? 0 : (this.outerRadius / 100) * this.options.percentageInnerCutout,
});
if (!metaSlice.backgroundColor) {
slice.backgroundColor = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
slice.backgroundColor = 'hsl(' + (360 * index / this.data.data.length) + ', 100%, 50%)';
}
metaSlice.save();
this.data.metaData.push(metaSlice);

View File

@ -1,30 +1,30 @@
(function(){
"use strict";
(function() {
"use strict";
var root = this,
Chart = root.Chart,
//Cache a local reference to Chart.helpers
helpers = Chart.helpers;
var root = this,
Chart = root.Chart,
//Cache a local reference to Chart.helpers
helpers = Chart.helpers;
var defaultConfig = {
//Boolean - Stroke a line around each segment in the chart
segmentShowStroke : true,
var defaultConfig = {
//String - The colour of the stroke on each segment.
segmentStrokeColor : "#fff",
segment: {
//String - The colour of the border on each segment.
borderColor: "#fff",
//Number - The width of the stroke value in pixels
segmentStrokeWidth : 2,
//Number - The width of the border value in pixels
borderWidth: 2,
},
scale: {
scaleType: "radialLinear",
display: true,
//Boolean - Whether to animate scaling the chart from the centre
animate : false,
scale: {
scaleType: "radialLinear",
display: true,
//Boolean - Whether to animate scaling the chart from the centre
animate: false,
lineArc: true,
lineArc: true,
// grid line settings
gridLines: {
show: true,
@ -44,238 +44,172 @@
fontColor: "#666",
fontFamily: "Helvetica Neue",
//Boolean - Show a backdrop to the scale label
showLabelBackdrop : true,
//Boolean - Show a backdrop to the scale label
showLabelBackdrop: true,
//String - The colour of the label backdrop
backdropColor : "rgba(255,255,255,0.75)",
//String - The colour of the label backdrop
backdropColor: "rgba(255,255,255,0.75)",
//Number - The backdrop padding above & below the label in pixels
backdropPaddingY : 2,
//Number - The backdrop padding above & below the label in pixels
backdropPaddingY: 2,
//Number - The backdrop padding to the side of the label in pixels
backdropPaddingX : 2,
//Number - The backdrop padding to the side of the label in pixels
backdropPaddingX: 2,
}
},
},
//Number - Amount of animation steps
animationSteps : 100,
//Boolean - Whether to animate the rotation of the chart
animateRotate: true,
//String - Animation easing effect.
animationEasing : "easeOutBounce",
//Boolean - Whether to animate the rotation of the chart
animateRotate : true,
//String - A legend template
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
};
//String - A legend template
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
};
Chart.Type.extend({
//Passing in a name registers this chart in the Chart namespace
name: "PolarArea",
//Providing a defaults will also register the deafults in the chart namespace
defaults : defaultConfig,
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
//Config is automatically merged by the core of Chart.js, and is available at this.options
initialize: function(){
this.segments = [];
//Declare segment class as a chart instance specific class, so it can share props for this instance
this.SegmentArc = Chart.Arc.extend({
showStroke : this.options.segmentShowStroke,
strokeWidth : this.options.segmentStrokeWidth,
strokeColor : this.options.segmentStrokeColor,
ctx : this.chart.ctx,
innerRadius : 0,
x : this.chart.width/2,
y : this.chart.height/2
});
Chart.Type.extend({
//Passing in a name registers this chart in the Chart namespace
name: "PolarArea",
//Providing a defaults will also register the deafults in the chart namespace
defaults: defaultConfig,
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
//Config is automatically merged by the core of Chart.js, and is available at this.options
initialize: function() {
var self = this;
var ScaleClass = Chart.scales.getScaleConstructor(this.options.scale.scaleType);
this.scale = new ScaleClass({
options: this.options.scale,
lineArc: true,
width: this.chart.width,
height: this.chart.height,
xCenter: this.chart.width/2,
yCenter: this.chart.height/2,
ctx : this.chart.ctx,
valuesCount: this.data.length,
calculateRange: function() {
this.min = null;
this.max = null;
// Scale setup
var self = this;
var ScaleClass = Chart.scales.getScaleConstructor(this.options.scale.scaleType);
this.scale = new ScaleClass({
options: this.options.scale,
lineArc: true,
width: this.chart.width,
height: this.chart.height,
xCenter: this.chart.width / 2,
yCenter: this.chart.height / 2,
ctx: this.chart.ctx,
valuesCount: this.data.length,
calculateRange: function() {
this.min = null;
this.max = null;
helpers.each(self.data, function(data) {
helpers.each(self.data.data, function(data) {
if (this.min === null) {
this.min = data.value;
} else if (data.value < this.min) {
this.min = data.value;
}
if (this.max === null) {
this.max = data.value;
} else if (data.value > this.max) {
this.max = data.value;
}
}, this);
}
});
}
});
this.updateScaleRange();
this.scale.calculateRange();
this.scale.generateTicks();
this.scale.buildYLabels();
//Declare segment class as a chart instance specific class, so it can share props for this instance
this.Slice = Chart.Arc.extend();
helpers.each(this.data,function(segment,index){
this.addData(segment,index,true);
},this);
//Set up tooltip events on the chart
if (this.options.showTooltips) {
helpers.bindEvents(this, this.options.events, this.onHover);
}
//Set up tooltip events on the chart
if (this.options.showTooltips){
helpers.bindEvents(this, this.options.events, function(evt){
var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
helpers.each(this.segments,function(segment){
segment.restore(["fillColor"]);
});
// Create new slice for each piece of data
this.data.metaData = [];
helpers.each(this.data.data, function(slice, index) {
var metaSlice = new this.Slice({
_chart: this.chart,
innerRadius: 0,
startAngle: Math.PI * 1.5,
endAngle: Math.PI * 1.5,
x: this.chart.width / 2,
y: this.chart.height / 2
});
if (typeof slice == 'number') {
helpers.extend(metaSlice, {
value: slice
});
} else {
helpers.extend(metaSlice, slice);
}
if (!metaSlice.backgroundColor) {
slice.backgroundColor = 'hsl(' + (360 * index / this.data.data.length) + ', 100%, 50%)';
}
metaSlice.save();
this.data.metaData.push(metaSlice);
}, this);
helpers.each(activeSegments,function(activeSegment){
activeSegment.fillColor = activeSegment.highlightColor;
});
this.showTooltip(activeSegments);
});
}
// Create tooltip instance exclusively for this chart with some defaults.
this.tooltip = new Chart.Tooltip({
_chart: this.chart,
_data: this.data,
_options: this.options,
}, this);
this.render();
},
getSegmentsAtEvent : function(e){
var segmentsArray = [];
var location = helpers.getRelativePosition(e);
this.update();
helpers.each(this.segments,function(segment){
if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
},this);
},
updateScaleRange: function() {
helpers.extend(this.scale, {
size: helpers.min([this.chart.width, this.chart.height]),
xCenter: this.chart.width / 2,
yCenter: this.chart.height / 2
});
},
update: function() {
return segmentsArray;
},
addData : function(segment, atIndex, silent){
var index = atIndex || this.segments.length;
this.updateScaleRange();
this.scale.calculateRange();
this.scale.generateTicks();
this.scale.buildYLabels();
this.segments.splice(index, 0, new this.SegmentArc({
fillColor: segment.color,
highlightColor: segment.highlight || segment.color,
label: segment.label,
value: segment.value,
outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
startAngle: Math.PI * 1.5
}));
if (!silent){
this.reflow();
this.update();
}
},
removeData: function(atIndex){
var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
this.segments.splice(indexToDelete, 1);
this.reflow();
this.update();
},
calculateTotal: function(data){
this.total = 0;
helpers.each(data,function(segment){
this.total += segment.value;
},this);
this.scale.valuesCount = this.segments.length;
},
updateScaleRange: function(){
helpers.extend(this.scale, {
size: helpers.min([this.chart.width, this.chart.height]),
xCenter: this.chart.width/2,
yCenter: this.chart.height/2
});
this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.segment.borderWidth / 2) / 2;
},
update : function(){
var circumference = 1 / this.data.data.length * 2;
// Map new data to data points
if(this.data.length == this.segments.length){
helpers.each(this.data, function(segment, i){
helpers.extend(this.segments[i], {
fillColor: segment.color,
highlightColor: segment.highlight || segment.color,
label: segment.label,
value: segment.value,
});
},this);
} else{
// Data size changed without properly inserting, just redraw the chart
this.initialize(this.data);
}
// Map new data to data points
helpers.each(this.data.metaData, function(slice, index) {
this.calculateTotal(this.segments);
var datapoint = this.data.data[index];
helpers.each(this.segments,function(segment){
segment.save();
});
this.reflow();
this.render();
},
reflow : function(){
helpers.extend(this.SegmentArc.prototype,{
x : this.chart.width/2,
y : this.chart.height/2
});
this.updateScaleRange();
this.scale.calculateRange();
this.scale.generateTicks();
this.scale.buildYLabels();
var startAngle = Math.PI * 1.5 + (Math.PI * circumference) * index;
var endAngle = startAngle + (circumference * Math.PI);
helpers.extend(this.scale,{
xCenter: this.chart.width/2,
yCenter: this.chart.height/2
});
helpers.extend(slice, {
_index: index,
x: this.chart.width / 2,
y: this.chart.height / 2,
value: datapoint.value,
label: datapoint.label,
innerRadius: 0,
outerRadius: this.scale.calculateCenterOffset(slice.value),
startAngle: startAngle,
endAngle: endAngle,
helpers.each(this.segments, function(segment){
//segment.update({
// outerRadius : this.scale.calculateCenterOffset(segment.value)
//});
helpers.extend(segment, {
outerRadius: this.scale.calculateCenterOffset(segment.value)
});
}, this);
backgroundColor: datapoint.backgroundColor,
hoverBackgroundColor: datapoint.hoverBackgroundColor || datapoint.backgroundColor,
borderWidth: this.options.borderWidth,
borderColor: this.options.segmentStrokeColor,
});
slice.pivot();
},
draw : function(ease){
var easingDecimal = ease || 1;
//Clear & draw the canvas
this.clear();
helpers.each(this.segments,function(segment, index){
segment.transition({
circumference : this.scale.getCircumference(),
outerRadius : this.scale.calculateCenterOffset(segment.value)
},easingDecimal);
}, this);
segment.endAngle = segment.startAngle + segment.circumference;
this.render();
},
draw: function(ease) {
var easingDecimal = ease || 1;
// If we've removed the first segment we need to set the first one to
// start at the top.
if (index === 0){
segment.startAngle = Math.PI * 1.5;
}
this.clear();
//Check to see if it's the last segment, if not get the next and update the start angle
if (index < this.segments.length - 1){
this.segments[index+1].startAngle = segment.endAngle;
}
segment.draw();
}, this);
this.scale.draw();
}
});
helpers.each(this.data.metaData, function(segment, index) {
segment.transition(easingDecimal).draw();
}, this);
this.scale.draw();
}
});
}).call(this);