Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom tooltip: add data points infos #3201

Merged
merged 11 commits into from
Oct 19, 2016
9 changes: 8 additions & 1 deletion docs/01-Chart-Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ afterBody | `Array[tooltipItem], data` | Text to render after the body section
beforeFooter | `Array[tooltipItem], data` | Text to render before the footer section
footer | `Array[tooltipItem], data` | Text to render as the footer
afterFooter | `Array[tooltipItem], data` | Text to render after the footer section
dataPoints | `Array[tooltipItem]` | List of matching point informations.

#### Tooltip Item Interface

Expand All @@ -288,7 +289,13 @@ The tooltip items passed to the tooltip callbacks implement the following interf
datasetIndex: Number,

// Index of this data item in the dataset
index: Number
index: Number,

// X position of matching point
x: Number,

// Y position of matching point
y: Number,
}
```

Expand Down
16 changes: 8 additions & 8 deletions docs/09-Advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ Scale instances are given the following properties during the fitting process.
{
left: Number, // left edge of the scale bounding box
right: Number, // right edge of the bounding box'
top: Number,
top: Number,
bottom: Number,
width: Number, // the same as right - left
height: Number, // the same as bottom - top

// Margin on each side. Like css, this is outside the bounding box.
// Margin on each side. Like css, this is outside the bounding box.
margins: {
left: Number,
right: Number,
Expand All @@ -246,7 +246,7 @@ Scale instances are given the following properties during the fitting process.
```

#### Scale Interface
To work with Chart.js, custom scale types must implement the following interface.
To work with Chart.js, custom scale types must implement the following interface.

```javascript
{
Expand Down Expand Up @@ -281,10 +281,10 @@ To work with Chart.js, custom scale types must implement the following interface
Optionally, the following methods may also be overwritten, but an implementation is already provided by the `Chart.Scale` base class.

```javascript
// Transform the ticks array of the scale instance into strings. The default implementation simply calls this.options.ticks.callback(numericalTick, index, ticks);
// Transform the ticks array of the scale instance into strings. The default implementation simply calls this.options.ticks.callback(numericalTick, index, ticks);
convertTicksToLabels: function() {},

// Determine how much the labels will rotate by. The default implementation will only rotate labels if the scale is horizontal.
// Determine how much the labels will rotate by. The default implementation will only rotate labels if the scale is horizontal.
calculateTickRotation: function() {},

// Fits the scale into the canvas.
Expand All @@ -301,7 +301,7 @@ Optionally, the following methods may also be overwritten, but an implementation

The Core.Scale base class also has some utility functions that you may find useful.
```javascript
{
{
// Returns true if the scale instance is horizontal
isHorizontal: function() {},

Expand Down Expand Up @@ -371,7 +371,7 @@ The following methods may optionally be overridden by derived dataset controller
// chart types using a single scale
linkScales: function() {},

// Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
// Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
buildOrUpdateElements: function() {}
}
```
Expand Down Expand Up @@ -440,7 +440,7 @@ Plugins should derive from Chart.PluginBase and implement the following interfac

### Building Chart.js

Chart.js uses <a href="http://gulpjs.com/" target="_blank">gulp</a> to build the library into a single JavaScript file.
Chart.js uses <a href="http://gulpjs.com/" target="_blank">gulp</a> to build the library into a single JavaScript file.

Firstly, we need to ensure development dependencies are installed. With node and npm installed, after cloning the Chart.js repo to a local directory, and navigating to that directory in the command line, we can run the following:

Expand Down
104 changes: 104 additions & 0 deletions samples/dataPoints-customTooltips.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!doctype html>
<html>

<head>
<title>Custom Tooltips using Data Points</title>
<script src="../dist/Chart.bundle.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<style>
canvas{
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.chartjs-tooltip {
opacity: 1;
position: absolute;
background: rgba(0, 0, 0, .7);
color: white;
border-radius: 3px;
-webkit-transition: all .1s ease;
transition: all .1s ease;
pointer-events: none;
-webkit-transform: translate(-50%, 0);
transform: translate(-50%, 0);
padding: 4px;
}

.chartjs-tooltip-key {
display: inline-block;
width: 10px;
height: 10px;
}
</style>
</head>

<body>
<div id="canvas-holder1" style="width:75%;">
<canvas id="chart1"></canvas>
</div>
<div class="chartjs-tooltip" id="tooltip-0"></div>
<div class="chartjs-tooltip" id="tooltip-1"></div>
<script>
var customTooltips = function (tooltip) {
$(this._chart.canvas).css("cursor", "pointer");

$(".chartjs-tooltip").css({
opacity: 0,
});

if (!tooltip || !tooltip.opacity) {
return;
}

if (tooltip.dataPoints.length > 0) {
tooltip.dataPoints.forEach(function (dataPoint) {
var content = [dataPoint.xLabel, dataPoint.yLabel].join(": ");
var $tooltip = $("#tooltip-" + dataPoint.datasetIndex);

$tooltip.html(content);
$tooltip.css({
opacity: 1,
top: dataPoint.y + "px",
left: dataPoint.x + "px",
});
});
}
};
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var lineChartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
pointHitRadius: 100,
label: "My First dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}, {
pointHitRadius: 100,
label: "My Second dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}]
};

window.onload = function() {
var chartEl = document.getElementById("chart1");
var chart = new Chart(chartEl, {
type: "line",
data: lineChartData,
options: {
title:{
display: true,
text: "Chart.js - Custom Tooltips using Data Points"
},
tooltips: {
enabled: false,
custom: customTooltips
}
}
});
};
</script>
</body>

</html>
7 changes: 6 additions & 1 deletion src/core/core.tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ module.exports = function(Chart) {
xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
index: index,
datasetIndex: datasetIndex
datasetIndex: datasetIndex,
x: element._model.x,
y: element._model.y
};
}

Expand Down Expand Up @@ -504,6 +506,9 @@ module.exports = function(Chart) {
model.caretPadding = helpers.getValueOrDefault(tooltipPosition.padding, 2);
model.labelColors = labelColors;

// data points
model.dataPoints = tooltipItems;

// We need to determine alignment of the tooltip
tooltipSize = getTooltipSize(this, model);
alignment = determineAlignment(this, tooltipSize);
Expand Down
60 changes: 60 additions & 0 deletions test/core.tooltip.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -542,4 +542,64 @@ describe('Core.Tooltip', function() {
expect(tooltip._view.x).toBeCloseToPixel(269);
expect(tooltip._view.y).toBeCloseToPixel(155);
});

it('Should have dataPoints', function() {
var chartInstance = window.acquireChart({
type: 'line',
data: {
datasets: [{
label: 'Dataset 1',
data: [10, 20, 30],
pointHoverBorderColor: 'rgb(255, 0, 0)',
pointHoverBackgroundColor: 'rgb(0, 255, 0)'
}, {
label: 'Dataset 2',
data: [40, 40, 40],
pointHoverBorderColor: 'rgb(0, 0, 255)',
pointHoverBackgroundColor: 'rgb(0, 255, 255)'
}],
labels: ['Point 1', 'Point 2', 'Point 3']
},
options: {
tooltips: {
mode: 'single'
}
}
});

// Trigger an event over top of the
var pointIndex = 1;
var datasetIndex = 0;
var meta = chartInstance.getDatasetMeta(datasetIndex);
var point = meta.data[pointIndex];
var node = chartInstance.chart.canvas;
var rect = node.getBoundingClientRect();
var evt = new MouseEvent('mousemove', {
view: window,
bubbles: true,
cancelable: true,
clientX: rect.left + point._model.x,
clientY: rect.top + point._model.y
});

// Manully trigger rather than having an async test
node.dispatchEvent(evt);

// Check and see if tooltip was displayed
var tooltip = chartInstance.tooltip;

expect(tooltip._view instanceof Object).toBe(true);
expect(tooltip._view.dataPoints instanceof Array).toBe(true);
expect(tooltip._view.dataPoints.length).toEqual(1);
expect(tooltip._view.dataPoints[0].index).toEqual(pointIndex);
expect(tooltip._view.dataPoints[0].datasetIndex).toEqual(datasetIndex);
expect(tooltip._view.dataPoints[0].xLabel).toEqual(
chartInstance.config.data.labels[pointIndex]
);
expect(tooltip._view.dataPoints[0].yLabel).toEqual(
chartInstance.config.data.datasets[datasetIndex].data[pointIndex]
);
expect(tooltip._view.dataPoints[0].x).toBeCloseToPixel(point._model.x);
expect(tooltip._view.dataPoints[0].y).toBeCloseToPixel(point._model.y);
});
});