将工具提示放在条形图的中心

时间:2017-07-31 12:26:24

标签: javascript charts chart.js

无法找到一种方法将工具提示放在这样的栏中心(是的,我知道它并不完全位于此屏幕截图的中心位置,但仍然存在):

enter image description here

如果我使用custom工具提示选项,我只能在条形图上方获得插入符号的GET /../tn/d9dd6c39d71276487ae798d976f8f629_tn.jpg x个位置。但无法获得酒吧的高度/宽度。

这是我传递给Chart构造函数的选项对象的一部分:

y

3 个答案:

答案 0 :(得分:1)

您可以使用datasets中的值来锻炼悬停的项目的相对高度,并相应地调整CSS。

以下是靠近中心,但不是确切的中心。如果你想要准确,我的计算需要纠正。

自定义工具提示功能包括以下内容:

// find relative proportion
var dataIndex = tooltip.dataPoints[0].index;
var datasetIndex = tooltip.dataPoints[0].datasetIndex;
var totalHeight = 0;

var thisHeight = this._chart.config.data.datasets[datasetIndex].data[dataIndex];

for (var i = 0; i <= datasetIndex; i++)
{
  totalHeight += this._chart.config.data.datasets[i].data[dataIndex];
}

var positionY = this._chart.canvas.offsetTop;
var positionX = this._chart.canvas.offsetLeft;
var chartHeight = this._chart.canvas.scrollHeight;
var tooltipHalfHeight = tooltip.height / 2;

// Display, position, and set styles for font
tooltipEl.style.left = positionX + tooltip.caretX + 'px';
tooltipEl.style.top = tooltip.caretY + ((chartHeight - tooltip.caretY - positionY) * (thisHeight / totalHeight / 2)) - tooltipHalfHeight + 'px';

&#13;
&#13;
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.bundle.min.js"></script>
  <script src="script.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);*/
		}
		.chartjs-tooltip-key {
			display: inline-block;
			width: 10px;
			height: 10px;
			margin-right: 10px;
		}
	</style>
</head>

<body>
  <div id="chartjs-tooltip">
			<table></table>
</div>
  <canvas id="myChart" width="400" height="400"></canvas>

  <script>
var customTooltips = function(tooltip) {
			// Tooltip Element
			var tooltipEl = document.getElementById('chartjs-tooltip');
			if (!tooltipEl) {
				tooltipEl = document.createElement('div');
				tooltipEl.id = 'chartjs-tooltip';
				tooltipEl.innerHTML = "<table></table>"
				this._chart.canvas.parentNode.appendChild(tooltipEl);
			}
			// Hide if no tooltip
			if (tooltip.opacity === 0) {
				tooltipEl.style.opacity = 0;
				return;
			}
			// Set caret Position
			tooltipEl.classList.remove('above', 'below', 'no-transform');
			if (tooltip.yAlign) {
				tooltipEl.classList.add(tooltip.yAlign);
			} else {
				tooltipEl.classList.add('no-transform');
			}
			function getBody(bodyItem) {
				return bodyItem.lines;
			}
			// Set Text
			if (tooltip.body) {
				var titleLines = tooltip.title || [];
				var bodyLines = tooltip.body.map(getBody);
				var innerHtml = '<thead>';
				titleLines.forEach(function(title) {
					innerHtml += '<tr><th>' + title + '</th></tr>';
				});
				innerHtml += '</thead><tbody>';
				bodyLines.forEach(function(body, i) {
					var colors = tooltip.labelColors[i];
					var style = 'background:' + colors.backgroundColor;
					style += '; border-color:' + colors.borderColor;
					style += '; border-width: 2px'; 
					var span = '<span class="chartjs-tooltip-key" style="' + style + '"></span>';
					innerHtml += '<tr><td>' + span + body + '</td></tr>';
				});
				innerHtml += '</tbody>';
				var tableRoot = tooltipEl.querySelector('table');
				tableRoot.innerHTML = innerHtml;
			}
			
			// find relative proportion
			var dataIndex = tooltip.dataPoints[0].index;
			var datasetIndex = tooltip.dataPoints[0].datasetIndex;
			var totalHeight = 0;
			
			var thisHeight = this._chart.config.data.datasets[datasetIndex].data[dataIndex];
			
			for (var i = 0; i <= datasetIndex; i++)
			{
  			  totalHeight += this._chart.config.data.datasets[i].data[dataIndex];
			}

			var positionY = this._chart.canvas.offsetTop;
			var positionX = this._chart.canvas.offsetLeft;
			var chartHeight = this._chart.canvas.scrollHeight;
			var tooltipHalfHeight = tooltip.height / 2;
			
			// Display, position, and set styles for font
			tooltipEl.style.opacity = 1;
			tooltipEl.style.left = positionX + tooltip.caretX + 'px';
			tooltipEl.style.top = tooltip.caretY + ((chartHeight - tooltip.caretY - positionY) * (thisHeight / totalHeight / 2)) - tooltipHalfHeight + 'px';
			tooltipEl.style.fontFamily = tooltip._fontFamily;
			tooltipEl.style.fontSize = tooltip.fontSize;
			tooltipEl.style.fontStyle = tooltip._fontStyle;
			tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
		};
		
		var ctx = document.getElementById("myChart").getContext('2d');
    var myChart = new Chart(ctx, {
      type: 'bar',
      data: {
        labels: ["This", "That", "Something else", "Important thing", "Oh really?", "What!!"],
        datasets: [{
          label: '# of Votes',
          data: [12, 19, 3, 5, 2, 3],
          backgroundColor: [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 206, 86, 0.2)',
            'rgba(75, 192, 192, 0.2)',
            'rgba(153, 102, 255, 0.2)',
            'rgba(255, 159, 64, 0.2)'
          ],
          borderColor: [
            'rgba(255,99,132,1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 206, 86, 1)',
            'rgba(75, 192, 192, 1)',
            'rgba(153, 102, 255, 1)',
            'rgba(255, 159, 64, 1)'
          ],
          borderWidth: 1
        }, {
          data: [2, 5, 13, 5, 3, 4],
          backgroundColor: [
            'rgba(255, 206, 86, 0.2)',
            'rgba(75, 192, 192, 0.2)',
            'rgba(153, 102, 255, 0.2)',
            'rgba(255, 159, 64, 0.2)',
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)'
          ],
          borderColor: [
            'rgba(255, 206, 86, 1)',
            'rgba(75, 192, 192, 1)',
            'rgba(153, 102, 255, 1)',
            'rgba(255, 159, 64, 1)',
            'rgba(255,99,132,1)',
            'rgba(54, 162, 235, 1)'
          ],
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          xAxes: [{
            stacked: true,
          }],
          yAxes: [{
            stacked: true
          }]
        },
        tooltips: {
          enabled: false,
          custom: customTooltips,
        }
      }
    });
  </script>
</body>

</html>
&#13;
&#13;
&#13;

Plunker:http://plnkr.co/edit/f0EqpYe6zJMyIDxY4Xg9?p=preview

答案 1 :(得分:1)

您可能已经知道,要将自定义工具提示放在条形图的中心,您可能需要其中一些 (条形)属性,例如 - 宽度,高度,顶部和左侧位置。但不幸的是,没有直接获得这些属性的方法,而是你需要自己计算它们。

要获取/计算这些属性,可以使用以下函数(可以命名为任何内容),它将返回一个包含所有这些(宽度,高度,顶部,左侧)属性的对象。特别是酒吧,当盘旋时。

function getBAR(chart) {
   const dataPoints = tooltipModel.dataPoints,
         datasetIndex = chart.data.datasets.length - 1,
         datasetMeta = chart.getDatasetMeta(datasetIndex),
         scaleBottom = chart.scales['y-axis-0'].bottom,
         bar = datasetMeta.data[dataPoints[0].index]._model,
         canvasPosition = chart.canvas.getBoundingClientRect(),
         paddingLeft = parseFloat(getComputedStyle(chart.canvas).paddingLeft),
         paddingTop = parseFloat(getComputedStyle(chart.canvas).paddingTop),
         scrollLeft = document.body.scrollLeft,
         scrollTop = document.body.scrollTop;

   return {
      top: bar.y + canvasPosition.top + paddingTop + scrollTop,
      left: bar.x - (bar.width / 2) + canvasPosition.left + paddingLeft + scrollLeft,
      width: bar.width,
      height: scaleBottom - bar.y
   }
}

计算中心位置

检索所需属性后,您可以计算条形图的中心位置:

  

= - +( - /)

  

= - +( - /)

然后,创建自定义工具提示元素并相应地进行定位。

ᴘʀᴇᴠɪᴇᴡ

bar-chart

ʟɪᴠᴇ ᴇxᴀᴍᴘʟᴇ

const chart = new Chart(ctx, {
   type: 'bar',
   data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr'],
      datasets: [{
         label: 'Revenue',
         data: [4, 2, 3, 3],
         backgroundColor: '#2d4e6d'
      }, {
         label: 'Expenses',
         data: [3, 3.5, 4, 1],
         backgroundColor: '#c06526'
      }, {
         label: 'Profit',
         data: [3, 2.5, 4, 2],
         backgroundColor: '#e0ecf0'
      }]
   },
   options: {
      scales: {
         xAxes: [{
            stacked: true
         }],
         yAxes: [{
            stacked: true,
            ticks: {
               beginAtZero: true
            }
         }]
      },
      tooltips: {
         enabled: false,
         custom: function(tooltipModel) {
         /*** jQuery IS USED FOR SIMPLICITY ***/
         
            /* TOOLTIP & CARET ELEMENT */
            let tooltip = $('#tooltip');
            let tooltipCaret = $('#tooltip-caret');

            /* CREATE TOOLTIP & CARET ELEMENT AT FIRST RENDER */
            if (!tooltip.length && !tooltipCaret.length) {
               tooltip = $('<div></div>').attr('id', 'tooltip');
               tooltipCaret = $('<div></div>').attr('id', 'tooltip-caret');
               $('body').append(tooltip, tooltipCaret);
            }

            /* HIDE IF NO TOOLTIP */
            if (!tooltipModel.opacity) {
               tooltip.hide();
               tooltipCaret.hide();
               return;
            }

            /* GET BAR PROPS (width, height, top, left) */
            const barWidth = getBAR(this._chart).width,
                  barHeight = getBAR(this._chart).height,
                  barTop = getBAR(this._chart).top,
                  barLeft = getBAR(this._chart).left;

            /* SET STYLE FOR TOOLTIP 
            	(these can also be set in separate css file) */
            tooltip.css({
               "display": "inline-block",
               "position": "absolute",
               "color": "rgba(255, 255, 255, 1)",
               "background": "rgba(0, 0, 0, 0.7)",
               "padding": "5px",
               "font": "12px Arial",
               "border-radius": "3px",
               "white-space": "nowrap",
               "pointerEvents": "none"
            });

            /* SET STYLE FOR TOOLTIP CARET 
            	(these can also be set in separate css file) */
            tooltipCaret.css({
               "display": "block",
               "position": "absolute",
               "width": 0,
               "pointerEvents": "none",
               "border-style": "solid",
               "border-width": "8px 10px 8px 0",
               "border-color": "transparent rgba(0, 0, 0, 0.7) transparent transparent"
            });

            /* ADD CONTENT IN TOOLTIP */
            tooltip.text('ChartJS');
            tooltip.append('<br><div class="color-box"></div><label style="display: block; margin: -16px 0 0 16px;"> Custom Tooltip<label>');

            /* POSITION TOOLTIP & CARET
            (position should be set after tooltip & caret is rendered) */
            const centerX = barLeft + (barWidth / 2),
                  centerY = barTop + (barHeight / 2)
            
            tooltip.css({
               "top": centerY - (tooltip.outerHeight() / 2) + 'px',
               "left": centerX + tooltipCaret.outerWidth() + 'px'
            });
            tooltipCaret.css({
               "top": centerY - (tooltipCaret.outerHeight() / 2) + 'px',
               "left": centerX + 'px'
            });

            /* FUNCTION TO GET BAR PROPS */
            function getBAR(chart) {
               const dataPoints = tooltipModel.dataPoints,
                     datasetIndex = chart.data.datasets.length - 1,
                     datasetMeta = chart.getDatasetMeta(datasetIndex),
                     scaleBottom = chart.scales['y-axis-0'].bottom,
                     bar = datasetMeta.data[dataPoints[0].index]._model,
                     canvasPosition = chart.canvas.getBoundingClientRect(),
                     paddingLeft = parseFloat(getComputedStyle(chart.canvas).paddingLeft),
                     paddingTop = parseFloat(getComputedStyle(chart.canvas).paddingTop),
                     scrollLeft = document.body.scrollLeft,
                     scrollTop = document.body.scrollTop;

               return {
                  top: bar.y + canvasPosition.top + paddingTop + scrollTop,
                  left: bar.x - (bar.width / 2) + canvasPosition.left + paddingLeft + scrollLeft,
                  width: bar.width,
                  height: scaleBottom - bar.y
               }
            }

         }
      }
   }
});
.color-box{width:12px;height:12px;background:#c06526;display:inline-block;margin-top:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>

更新

如果您希望将工具提示放在每个条形段的中心,请使用以下功能:

function getBARSegment(chart) {
   const dataPoints = tooltipModel.dataPoints,
         bar = chart.active[dataPoints[0].datasetIndex]._model,
         canvasPosition = chart.canvas.getBoundingClientRect(),
         paddingLeft = parseFloat(getComputedStyle(chart.canvas).paddingLeft),
         paddingTop = parseFloat(getComputedStyle(chart.canvas).paddingTop),
         scrollLeft = document.body.scrollLeft,
         scrollTop = document.body.scrollTop;

   return {
      top: bar.y + canvasPosition.top + paddingTop + scrollTop,
      left: bar.x - (bar.width / 2) + canvasPosition.left + paddingLeft + scrollLeft,
      width: bar.width,
      height: bar.base - bar.y
   }
}

ᴘʀᴇᴠɪᴇᴡ

bar-chart

ʟɪᴠᴇ ᴇxᴀᴍᴘʟᴇ

const chart = new Chart(ctx, {
   type: 'bar',
   data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr'],
      datasets: [{
         label: 'Revenue',
         data: [4, 2, 3, 3],
         backgroundColor: '#2d4e6d'
      }, {
         label: 'Expenses',
         data: [3, 3.5, 4, 1],
         backgroundColor: '#c06526'
      }, {
         label: 'Profit',
         data: [3, 2.5, 4, 2],
         backgroundColor: '#e0ecf0'
      }]
   },
   options: {
      scales: {
         xAxes: [{
            stacked: true
         }],
         yAxes: [{
            stacked: true,
            ticks: {
               beginAtZero: true
            }
         }]
      },
      tooltips: {
         enabled: false,
         custom: function(tooltipModel) {
            /*** jQuery IS USED FOR SIMPLICITY ***/

            /* TOOLTIP & CARET ELEMENT */
            let tooltip = $('#tooltip');
            let tooltipCaret = $('#tooltip-caret');

            /* CREATE TOOLTIP & CARET ELEMENT AT FIRST RENDER */
            if (!tooltip.length && !tooltipCaret.length) {
               tooltip = $('<div></div>').attr('id', 'tooltip');
               tooltipCaret = $('<div></div>').attr('id', 'tooltip-caret');
               $('body').append(tooltip, tooltipCaret);
            }

            /* HIDE IF NO TOOLTIP */
            if (!tooltipModel.opacity) {
               tooltip.hide();
               tooltipCaret.hide();
               return;
            }

            /* GET BAR PROPS (width, height, top, left) */
            const barWidth = getBARSegment(this._chart).width,
                  barHeight = getBARSegment(this._chart).height,
                  barTop = getBARSegment(this._chart).top,
                  barLeft = getBARSegment(this._chart).left;

            /* SET STYLE FOR TOOLTIP 
            	(these can also be set in separate css file) */
            tooltip.css({
               "display": "inline-block",
               "position": "absolute",
               "color": "rgba(255, 255, 255, 1)",
               "background": "rgba(0, 0, 0, 0.7)",
               "padding": "5px",
               "font": "12px Arial",
               "border-radius": "3px",
               "white-space": "nowrap",
               "pointerEvents": "none"
            });

            /* SET STYLE FOR TOOLTIP CARET 
            	(these can also be set in separate css file) */
            tooltipCaret.css({
               "display": "block",
               "position": "absolute",
               "width": 0,
               "pointerEvents": "none",
               "border-style": "solid",
               "border-width": "8px 10px 8px 0",
               "border-color": "transparent rgba(0, 0, 0, 0.7) transparent transparent"
            });

            /* ADD CONTENT IN TOOLTIP */
            tooltip.text('ChartJS');
            tooltip.append('<br><div class="color-box"></div><label style="display: block; margin: -16px 0 0 16px;"> Custom Tooltip<label>');

            /* POSITION TOOLTIP & CARET
            (position should be set after tooltip & caret is rendered) */
            const centerX = barLeft + (barWidth / 2),
                  centerY = barTop + (barHeight / 2)

            tooltip.css({
               "top": centerY - (tooltip.outerHeight() / 2) + 'px',
               "left": centerX + tooltipCaret.outerWidth() + 'px'
            });
            tooltipCaret.css({
               "top": centerY - (tooltipCaret.outerHeight() / 2) + 'px',
               "left": centerX + 'px'
            });

            /* FUNCTION TO GET BAR PROPS */
            function getBARSegment(chart) {
               const dataPoints = tooltipModel.dataPoints,
                     bar = chart.active[dataPoints[0].datasetIndex]._model,
                     canvasPosition = chart.canvas.getBoundingClientRect(),
                     paddingLeft = parseFloat(getComputedStyle(chart.canvas).paddingLeft),
                     paddingTop = parseFloat(getComputedStyle(chart.canvas).paddingTop),
                     scrollLeft = document.body.scrollLeft,
                     scrollTop = document.body.scrollTop;

               return {
                  top: bar.y + canvasPosition.top + paddingTop + scrollTop,
                  left: bar.x - (bar.width / 2) + canvasPosition.left + paddingLeft + scrollLeft,
                  width: bar.width,
                  height: bar.base - bar.y
               }
            }

         }
      }
   }
});
.color-box{width:12px;height:12px;background:#c06526;display:inline-block;margin-top:5px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="ctx"></canvas>

答案 2 :(得分:0)

Chartjs 2.8 允许您为工具提示添加自定义位置模式。有了这个,您可以创建一个中心位置选项:

char *

有关工作示例,请参见小提琴:https://jsfiddle.net/astroash/wk5y0fqd/36/