mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-06 00:14:03 +01:00
Custom tooltip: add data points infos (#3201)
Expose tooltip items from tooltip model and added `x` and `y` properties to `TooltipItemInterface`
This commit is contained in:
committed by
Evert Timberg
parent
a0388eff4c
commit
3bd4d283f7
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -226,12 +226,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,
|
||||
@@ -248,7 +248,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
|
||||
{
|
||||
@@ -283,10 +283,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.
|
||||
@@ -303,7 +303,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() {},
|
||||
|
||||
@@ -373,7 +373,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() {}
|
||||
}
|
||||
```
|
||||
@@ -442,7 +442,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:
|
||||
|
||||
|
||||
104
samples/dataPoints-customTooltips.html
Normal file
104
samples/dataPoints-customTooltips.html
Normal file
@@ -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>
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -508,6 +510,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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user