]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Custom tooltip: add data points infos (#3201)
authorbydooweedoo <bydooweedoo@gmail.com>
Wed, 19 Oct 2016 13:48:17 +0000 (21:48 +0800)
committerEvert Timberg <evert.timberg+github@gmail.com>
Wed, 19 Oct 2016 13:48:17 +0000 (08:48 -0500)
Expose tooltip items from tooltip model and added `x` and `y` properties to `TooltipItemInterface`

docs/01-Chart-Configuration.md
docs/09-Advanced.md
samples/dataPoints-customTooltips.html [new file with mode: 0644]
src/core/core.tooltip.js
test/core.tooltip.tests.js

index c12a102af9e8c97b6d66b764a678b06be2480cb2..bf9eb5baa61707917e0150a9dae7e423ebadd2a5 100644 (file)
@@ -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,
 }
 ```
 
index db346bc94d257f6ad09f363e823cd8804ffc0fa0..2f4a278b1e25a6f2600ba54fa2efcfb5e7ac9e5d 100644 (file)
@@ -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:
 
diff --git a/samples/dataPoints-customTooltips.html b/samples/dataPoints-customTooltips.html
new file mode 100644 (file)
index 0000000..8144168
--- /dev/null
@@ -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>
index af8d3197cd83c10595f31662382b4c10650b3801..fca8a581ec4de02ac4681bfab32d0be35e64a6f9 100755 (executable)
@@ -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);
index 29c6b721a4939988ea4b18d2af69f5f2ee8f9c90..5890e79e036628b8653b0c9ff4086beba2584969 100755 (executable)
@@ -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);
+       });
 });