Rough Tooltips for 'single' hoverMode

This commit is contained in:
Tanner Linsley 2015-05-12 12:55:48 -06:00
parent afb22d15ae
commit 15f724f146
3 changed files with 135 additions and 97 deletions

View File

@ -22,9 +22,11 @@
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()]
}]
@ -34,7 +36,7 @@
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive: true,
hoverMode: 'bar',
hoverMode: 'single',
scaleBeginAtZero: false,
});
}

View File

@ -34,14 +34,14 @@
//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>"
@ -62,10 +62,10 @@
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;
@ -116,61 +116,87 @@
},
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'){}
// Remove styling for last 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;
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 (even if it may still be active)
if(this.lastActive){
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.
@ -229,13 +255,13 @@
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;
}
@ -251,12 +277,12 @@
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;
}

View File

@ -883,9 +883,21 @@
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 = {};
@ -988,45 +1000,46 @@
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 = [];
showTooltip : function(elements, hoverMode){
var isChanged = (function(Elements){
var changed = false;
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;
}
@ -1096,34 +1109,17 @@
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(){
@ -1206,7 +1202,7 @@
// 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;
@ -1392,7 +1388,21 @@
{
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({