Stable Bar Chart, DRY core functions

This commit is contained in:
Tanner Linsley 2015-05-15 00:04:42 -06:00
parent b432a3d6db
commit f79ebdaa88
2 changed files with 83 additions and 106 deletions

View File

@ -101,11 +101,11 @@
},this);
// Set defaults for bars
this.eachBars(function(bar, index, datasetIndex){
this.eachElement(function(bar, index, datasetIndex){
helpers.extend(bar, {
width : this.scale.calculateBarWidth(this.data.datasets.length),
x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
y: this.calculateBarBase(),
y: this.calculateBaseY(),
_datasetIndex: datasetIndex,
_index: index,
});
@ -128,7 +128,7 @@
// If exiting chart
if(e.type == 'mouseout'){
return false;
return this;
}
this.lastActive = this.lastActive || [];
@ -137,9 +137,9 @@
this.active = function(){
switch(this.options.hoverMode){
case 'single':
return this.getBarAtEvent(e);
return this.getElementAtEvent(e);
case 'label':
return this.getBarsAtEvent(e);
return this.getElementsAtEvent(e);
case 'dataset':
return this.getDatasetAtEvent(e);
default:
@ -153,7 +153,7 @@
}
// Remove styling for last active (even if it may still be active)
if(this.lastActive){
if(this.lastActive.length){
switch(this.options.hoverMode){
case 'single':
this.lastActive[0].backgroundColor = this.data.datasets[this.lastActive[0]._datasetIndex].backgroundColor;
@ -170,11 +170,11 @@
case 'dataset':
break;
default:
// do nothing
// Don't change anything
}
}
// Built in hover actions
// Built in hover styling
if(this.active.length && this.options.hoverMode){
switch(this.options.hoverMode){
case 'single':
@ -190,7 +190,7 @@
case 'dataset':
break;
default:
// do nothing
// Don't change anything
}
}
@ -219,16 +219,8 @@
}
// Hover animations
if(!this.animating){
// If entering
if(!this.lastActive.length && this.active.length){
console.log('entering');
this.tooltip.pivot();
this.stop();
this.render(false, this.options.hoverAnimationDuration);
}
var changed;
helpers.each(this.active, function(element, index){
@ -237,33 +229,22 @@
}
}, this);
// If different element
if(this.lastActive.length && this.active.length && changed){
console.log('changing');
this.tooltip.pivot();
this.stop();
this.render(false, this.options.hoverAnimationDuration);
}
// If entering, leaving, or changing elements, animate the change via pivot
if ((!this.lastActive.length && this.active.length) ||
(this.lastActive.length && !this.active.length)||
(this.lastActive.length && this.active.length && changed)){
// if Leaving
if (this.lastActive.length && !this.active.length){
console.log('leaving');
this.tooltip.pivot();
this.stop();
this.render(false, this.options.hoverAnimationDuration);
this.render(this.options.hoverAnimationDuration);
}
}
// Remember Last Active
this.lastActive = this.active;
return this;
},
// Calculate the base point for the bar.
// If the scale has a 0 point, use that as the base
// If the scale min and max are both positive, use the bottom as a base
// If the scale min and max are both negative, use the top as a base
calculateBarBase: function() {
calculateBaseY: function() {
var base = this.scale.endPoint;
if (this.scale.beginAtZero || ((this.scale.min <= 0 && this.scale.max >= 0) || (this.scale.min >= 0 && this.scale.max <= 0)))
@ -283,7 +264,7 @@
this.scale.update();
this.eachBars(function(bar, index, datasetIndex){
this.eachElement(function(bar, index, datasetIndex){
helpers.extend(bar, {
width : this.scale.calculateBarWidth(this.data.datasets.length),
x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
@ -302,51 +283,6 @@
this.render();
},
eachBars : function(callback){
helpers.each(this.data.datasets,function(dataset, datasetIndex){
helpers.each(dataset.metaData, callback, this, datasetIndex);
},this);
},
eachValue : function(callback){
helpers.each(this.data.datasets,function(dataset, datasetIndex){
helpers.each(dataset.data, callback, this, datasetIndex);
},this);
},
getBarsAtEvent : function(e){
var barsArray = [],
eventPosition = helpers.getRelativePosition(e),
datasetIterator = function(dataset){
barsArray.push(dataset.metaData[elementIndex]);
},
elementIndex;
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) {
for (elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; elementIndex++) {
if (this.data.datasets[datasetIndex].metaData[elementIndex].inRange(eventPosition.x,eventPosition.y)){
helpers.each(this.data.datasets, datasetIterator);
}
}
}
return barsArray.length ? barsArray : [];
},
// Get the single bar that was clicked on
// @return : An object containing the dataset index and bar index of the matching bar. Also contains the rectangle that was drawn
getBarAtEvent : function(e) {
var bar = [];
var eventPosition = helpers.getRelativePosition(e);
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; ++datasetIndex) {
for (var elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; ++elementIndex) {
if (this.data.datasets[datasetIndex].metaData[elementIndex].inRange(eventPosition.x, eventPosition.y)) {
bar.push(this.data.datasets[datasetIndex].metaData[elementIndex]);
return bar;
}
}
}
return [];
},
buildScale : function(labels){
var self = this;
@ -406,17 +342,16 @@
this.scale = new this.ScaleClass(scaleOptions);
},
// This should be incorportated into the init as something like a default value. "Reflow" seems like a weird word for a fredraw function
/*reflow : function(){
helpers.extend(this.BarClass.prototype,{
y: this.calculateBarBase(), // so that we animate from the baseline
base : this.calculateBarBase()
redraw : function(){
var base = this.calculateBaseY();
this.eachElement(function(element, index, datasetIndex){
helpers.extend(element,{
y: base,
base : base
});
});
var newScaleProps = helpers.extend({
height : this.chart.height,
width : this.chart.width
});
this.scale.update(newScaleProps);
},*/
render();
},
draw : function(ease){
var easingDecimal = ease || 1;
@ -425,10 +360,10 @@
this.scale.draw(easingDecimal);
//Draw all the bars for each dataset
this.eachBars(function(bar, index, datasetIndex){
this.eachElement(function(bar, index, datasetIndex){
if (bar.hasValue()){
// Update the bar basepoint
bar.base = this.calculateBarBase();
bar.base = this.calculateBaseY();
//Transition
bar.transition(easingDecimal).draw();
}

View File

@ -945,15 +945,12 @@
}
return this;
},
reflow : noop,
render : function(reflow, customDuration){
if (reflow){
this.reflow();
}
redraw : noop,
render : function(duration){
if (this.options.animation && !reflow){
if (this.options.animation){
var animation = new Chart.Animation();
animation.numSteps = (customDuration || this.options.animationDuration) / 16.66; //60 fps
animation.numSteps = (duration || this.options.animationDuration) / 16.66; //60 fps
animation.easing = this.options.animationEasing;
// render function
@ -969,7 +966,7 @@
animation.onAnimationProgress = this.options.onAnimationProgress;
animation.onAnimationComplete = this.options.onAnimationComplete;
Chart.animationService.addAnimation(this, animation, customDuration);
Chart.animationService.addAnimation(this, animation, duration);
}
else{
this.draw();
@ -977,6 +974,51 @@
}
return this;
},
eachElement : function(callback){
helpers.each(this.data.datasets,function(dataset, datasetIndex){
helpers.each(dataset.metaData, callback, this, datasetIndex);
},this);
},
eachValue : function(callback){
helpers.each(this.data.datasets,function(dataset, datasetIndex){
helpers.each(dataset.data, callback, this, datasetIndex);
},this);
},
getElementsAtEvent : function(e){
var elementsArray = [],
eventPosition = helpers.getRelativePosition(e),
datasetIterator = function(dataset){
elementsArray.push(dataset.metaData[elementIndex]);
},
elementIndex;
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) {
for (elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; elementIndex++) {
if (this.data.datasets[datasetIndex].metaData[elementIndex].inRange(eventPosition.x,eventPosition.y)){
helpers.each(this.data.datasets, datasetIterator);
}
}
}
return elementsArray.length ? elementsArray : [];
},
// Get the single element that was clicked on
// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was drawn
getElementAtEvent : function(e) {
var element = [];
var eventPosition = helpers.getRelativePosition(e);
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; ++datasetIndex) {
for (var elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; ++elementIndex) {
if (this.data.datasets[datasetIndex].metaData[elementIndex].inRange(eventPosition.x, eventPosition.y)) {
element.push(this.data.datasets[datasetIndex].metaData[elementIndex]);
return element;
}
}
}
return [];
},
generateLegend : function(){
return template(this.options.legendTemplate,this);
},
@ -1337,10 +1379,10 @@
switch(this._options.hoverMode){
case 'single':
helpers.extend(this, {
text: template(this._options.tooltipTemplate, this._active),
text: template(this._options.tooltipTemplate, this._active[0]),
});
var tooltipPosition = this._active[0].tooltipPosition();
helpers.extend(this.tooltip, {
helpers.extend(this, {
x: Math.round(tooltipPosition.x),
y: Math.round(tooltipPosition.y),
});
@ -2116,9 +2158,9 @@
frameDuration: 17,
animations: [],
dropFrames: 0,
addAnimation: function(chartInstance, animationObject, customDuration) {
addAnimation: function(chartInstance, animationObject, duration) {
if(!customDuration){
if(!duration){
chartInstance.animating = true;
}