var barChartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
+ label: 'Dataset 1',
backgroundColor: "rgba(220,220,220,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}, {
+ label: 'Dataset 2',
backgroundColor: "rgba(151,187,205,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}]
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive: true,
- hoverMode: 'bar',
+ hoverMode: 'single',
scaleBeginAtZero: false,
});
}
//Number - Spacing between data sets within X values
barDatasetSpacing : 1,
- //String - Hover mode for events
- hoverMode : 'bars', // 'bar', 'dataset'
+ //String / Boolean - Hover mode for events.
+ hoverMode : 'single', // 'label', 'dataset', 'false'
//Function - Custom hover handler
onHover : null,
//Function - Custom hover handler
- hoverDuration : 400,
+ hoverAnimationDuration : 400,
//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].backgroundColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
this.ScaleClass = Chart.Scale.extend({
offsetGridLines : true,
- calculateBarX : function(datasetCount, datasetIndex, barIndex){
+ calculateBarX : function(datasetCount, datasetIndex, elementIndex){
//Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
var xWidth = this.calculateBaseWidth(),
- xAbsolute = this.calculateX(barIndex) - (xWidth/2),
+ xAbsolute = this.calculateX(elementIndex) - (xWidth/2),
barWidth = this.calculateBarWidth(datasetCount);
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
},
onHover: function(e){
- var active;
+
+ // If exiting chart
if(e.type == 'mouseout'){
return false;
}
- if(this.options.hoverMode == 'bar'){
- active = this.getBarAtEvent(e);
- }
- else if(this.options.hoverMode == 'bars'){}
+
+ var active = function(){
+ switch(this.options.hoverMode){
+ case 'single':
+ return this.getBarAtEvent(e);
+ case 'label':
+ return this.getBarsAtEvent(e);
+ case 'dataset':
+ return this.getDatasetAtEvent(e);
+ default:
+ return e;
+ }
+ }.call(this);
- // Remove styling for last active
+ // Remove styling for last active (even if it may still be active)
if(this.lastActive){
- if(this.options.hoverMode == 'bar'){
- this.lastActive.rectangle.backgroundColor = this.data.datasets[this.lastActive.datasetIndex].backgroundColor;
- this.lastActive.rectangle.borderColor = this.data.datasets[this.lastActive.datasetIndex].borderColor;
- this.lastActive.rectangle.borderWidth = 0;
+ switch(this.options.hoverMode){
+ case 'single':
+ this.lastActive.element.backgroundColor = this.data.datasets[this.lastActive.datasetIndex].backgroundColor;
+ this.lastActive.element.borderColor = this.data.datasets[this.lastActive.datasetIndex].borderColor;
+ this.lastActive.element.borderWidth = 0;
+ break;
+ case 'label':
+ break;
+ case 'dataset':
+ break;
+ default:
+ // do nothing
}
- else if(this.options.hoverMode == 'bars'){}
}
- // Custom Hover actions
+ // On Hover hook
if(this.options.onHover){
this.options.onHover.call(this, active);
}
- else if(active){
- // or default hover action
- if(this.options.hoverMode == 'bar'){
- active.rectangle.backgroundColor = this.data.datasets[active.datasetIndex].hoverBackgroundColor || Color(active.rectangle.backgroundColor).saturate(0.5).darken(0.25).rgbString();
- active.rectangle.borderColor = this.data.datasets[active.datasetIndex].hoverBorderColor || Color(active.rectangle.borderColor).saturate(0.5).darken(0.25).rgbString();
+
+ // Built in hover actions
+ if(active && this.options.hoverMode){
+ switch(this.options.hoverMode){
+ case 'single':
+ active.element.backgroundColor = this.data.datasets[active.datasetIndex].hoverBackgroundColor || helpers.color(active.element.backgroundColor).saturate(0.5).darken(0.25).rgbString();
+ active.element.borderColor = this.data.datasets[active.datasetIndex].hoverBorderColor || helpers.color(active.element.borderColor).saturate(0.5).darken(0.25).rgbString();
+ break;
+ case 'label':
+ break;
+ case 'dataset':
+ break;
+ default:
+ // do nothing
}
- else if(this.options.hoverMode == 'bars'){}
-
}
+ // Only animate for major events
if(!this.animating){
// If entering
if(!this.lastActive && active){
- this.render(false, this.options.hoverDuration);
+ this.render(false, this.options.hoverAnimationDuration);
}
- // If different bar
- if(this.lastActive && active && this.lastActive.rectangle !== active.rectangle){
- this.render(false, this.options.hoverDuration);
+ // If different element
+ if(this.lastActive && active && this.lastActive.element !== active.element){
+ this.render(false, this.options.hoverAnimationDuration);
}
// if Leaving
if (this.lastActive && !active){
- this.render(false, this.options.hoverDuration);
+ this.render(false, this.options.hoverAnimationDuration);
}
}
+ // Remember Last Active
this.lastActive = active;
if (this.options.showTooltips){
- this.showTooltip(active);
+ this.showTooltip(active, this.options.hoverMode);
}
},
// Calculate the base point for the bar.
var barsArray = [],
eventPosition = helpers.getRelativePosition(e),
datasetIterator = function(dataset){
- barsArray.push(dataset.metaData[barIndex]);
+ barsArray.push(dataset.metaData[elementIndex]);
},
- barIndex;
+ elementIndex;
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) {
- for (barIndex = 0; barIndex < this.data.datasets[datasetIndex].metaData.length; barIndex++) {
- if (this.data.datasets[datasetIndex].metaData[barIndex].inRange(eventPosition.x,eventPosition.y)){
+ 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;
}
var eventPosition = helpers.getRelativePosition(e);
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; ++datasetIndex) {
- for (var barIndex = 0; barIndex < this.data.datasets[datasetIndex].metaData.length; ++barIndex) {
- if (this.data.datasets[datasetIndex].metaData[barIndex].inRange(eventPosition.x, eventPosition.y)) {
+ 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 = {
- rectangle : this.data.datasets[datasetIndex].metaData[barIndex],
+ element : this.data.datasets[datasetIndex].metaData[elementIndex],
datasetIndex : datasetIndex,
- barIndex : barIndex,
+ elementIndex : elementIndex,
};
return bar;
}
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
+ },
+ color = helpers.color = function(color){
+ if(!window.Color){
+ console.log('Color.js not found!');
+ return color;
+ }
+ return window.Color(color);
+ },
+ isArray = helpers.isArray = function(obj){
+ if (!Array.isArray) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+ }
+ return Array.isArray(obj);
};
-
//Store a reference to each instance - allowing us to globally resize chart instances on window resize.
//Destroy method on the chart will remove the instance of the chart from this reference.
Chart.instances = {};
delete Chart.instances[this.id];
},
- showTooltip : function(ChartElements, forceRedraw){
- // Only redraw the chart if we've actually changed what we're hovering on.
- if (typeof this.activeElements === 'undefined') this.activeElements = [];
-
- var isChanged = (function(Elements){
- var changed = false;
+ showTooltip : function(elements, hoverMode){
- if (Elements.length !== this.activeElements.length){
- changed = true;
- return changed;
+ // Hide if no elements
+ if(!elements){
+ if(this.options.customTooltips){
+ this.options.customTooltips(false);
+ }
+ if(!this.animating){
+ this.render(false, this.options.hoverAnimationDuration);
}
-
- each(Elements, function(element, index){
- if (element !== this.activeElements[index]){
- changed = true;
- }
- }, this);
- return changed;
- }).call(this, ChartElements);
-
- if (!isChanged && !forceRedraw){
return;
}
- else{
- this.activeElements = ChartElements;
- }
- this.draw();
- if(this.options.customTooltips){
- this.options.customTooltips(false);
- }
- if (ChartElements.length > 0){
- // If we have multiple datasets, show a MultiTooltip for all of the data points at that index
- if (this.data.datasets && this.data.datasets.length > 1) {
+
+ switch(hoverMode){
+ case 'single':
+ var tooltipPosition = elements.element.tooltipPosition();
+ new Chart.Tooltip({
+ x: Math.round(tooltipPosition.x),
+ y: Math.round(tooltipPosition.y),
+ xPadding: this.options.tooltipXPadding,
+ yPadding: this.options.tooltipYPadding,
+ backgroundColor: this.options.tooltipBackgroundColor,
+ textColor: this.options.tooltipFontColor,
+ fontFamily: this.options.tooltipFontFamily,
+ fontStyle: this.options.tooltipFontStyle,
+ fontSize: this.options.tooltipFontSize,
+ caretHeight: this.options.tooltipCaretSize,
+ cornerRadius: this.options.tooltipCornerRadius,
+ text: template(this.options.tooltipTemplate, elements.element),
+ chart: this.chart,
+ custom: this.options.customTooltips
+ }).draw();
+ break;
+ case 'label':
var dataArray,
dataIndex;
for (var i = this.data.datasets.length - 1; i >= 0; i--) {
dataArray = this.data.datasets[i].metaData;
- dataIndex = indexOf(dataArray, ChartElements[0]);
+ dataIndex = indexOf(dataArray, elements[0]);
if (dataIndex !== -1){
break;
}
labels: tooltipLabels,
legendColors: tooltipColors,
legendColorBackground : this.options.multiTooltipKeyBackground,
- title: ChartElements[0].label,
+ title: elements[0].label,
chart: this.chart,
ctx: this.chart.ctx,
custom: this.options.customTooltips
}).draw();
-
- } else {
- each(ChartElements, function(Element) {
- var tooltipPosition = Element.tooltipPosition();
- new Chart.Tooltip({
- x: Math.round(tooltipPosition.x),
- y: Math.round(tooltipPosition.y),
- xPadding: this.options.tooltipXPadding,
- yPadding: this.options.tooltipYPadding,
- backgroundColor: this.options.tooltipBackgroundColor,
- textColor: this.options.tooltipFontColor,
- fontFamily: this.options.tooltipFontFamily,
- fontStyle: this.options.tooltipFontStyle,
- fontSize: this.options.tooltipFontSize,
- caretHeight: this.options.tooltipCaretSize,
- cornerRadius: this.options.tooltipCornerRadius,
- text: template(this.options.tooltipTemplate, Element),
- chart: this.chart,
- custom: this.options.customTooltips
- }).draw();
- }, this);
- }
+ break;
+ case 'dataset':
+ break;
+ default:
}
+
return this;
},
toBase64Image : function(){
// Color transitions if possible
if(typeof value === 'string'){
try{
- var color = Color(this._start[key]).mix(Color(this[key]), ease);
+ var color = helpers.color(this._start[key]).mix(helpers.color(this[key]), ease);
this._vm[key] = color.rgbString();
} catch(err){
this._vm[key] = value;
{
return (chartX >= this.x - this.width / 2 && chartX <= this.x + this.width / 2) && (chartY >= this.base && chartY <= this.y);
}
- }
+ },
+ tooltipPosition : function(){
+ if (this.y < this.base){
+ return {
+ x : this.x,
+ y : this.y
+ };
+ }
+ else{
+ return {
+ x : this.x,
+ y : this.base
+ };
+ }
+ },
});
Chart.Animation = Chart.Element.extend({