【问题标题】:Chart JS Show HTML in Tooltip图表 JS 在工具提示中显示 HTML
【发布时间】:2021-12-20 18:28:46
【问题描述】:

我一直在研究 Chart JS 的文档,试图弄清楚当您将鼠标悬停在特定点上时如何修改折线图工具提示的内容。

基本上,只要将鼠标悬停在单个点上,我想在所有相同的垂直轴上显示值。我尝试过这样的事情:

tooltips: {
    callbacks: {
        label: function(tooltipItem, data){
            console.log(data);
            var html = "";
            for(var dataset in data.datasets){
                html += "<label>" + data.datasets[dataset].label + ": " + data.datasets[dataset].data[tooltipItem.index] + "%</label><br/>";
            }
            return html;
        }
    },
},

这在一定程度上可以循环遍历每个数据集并为每个数据集附加&lt;label&gt;Example: 0%&lt;br/&gt;&lt;/label&gt;,但是当我返回该 HTML 时,工具提示会按字面意思显示字符串:

<label>Example1: 1%</label><br/><label>Example2: 5%</label><br/> ...

而不是呈现正确的 HTML:

Example1: 1%
Example2: 5%
...

现在,我知道 Chart JS 版本 1.0 具有 tooltipTemplate 选项,但我似乎无法弄清楚是否有任何方法可以在 tooltips.callbacks.label 选项中返回 HTML。有关于如何做自定义工具提示的文档,如果我无法弄清楚,我最终会使用它,但我们将不胜感激。

【问题讨论】:

    标签: javascript chart.js


    【解决方案1】:

    遗憾的是,从 v2.4 开始,回调目前不允许 HTML。您需要编写一个自定义工具提示函数。

    可以在 chart-js 的示例文件夹中找到示例(尽管有些比我找到的其他更好)。

    https://github.com/chartjs/Chart.js/tree/v2.4.0/samples/tooltips

    尝试运行示例以了解选项和修改如何影响工具提示功能。

    以自定义函数的折线图示例为例:

    Chart.defaults.global.pointHitDetectionRadius = 1;
    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>"
            document.body.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);
            //PUT CUSTOM HTML TOOLTIP CONTENT HERE (innerHTML)
            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;
        }
        var position = this._chart.canvas.getBoundingClientRect();
        // Display, position, and set styles for font
        tooltipEl.style.opacity = 1;
        tooltipEl.style.left = position.left + tooltip.caretX + 'px';
        tooltipEl.style.top = position.top + tooltip.caretY + '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';
    };
    

    然后将此设置为图表选项中的自定义工具提示功能:

    window.myLine = new Chart(chartEl, {
        type: 'line',
        data: lineChartData,
        options: {
            title:{
                display:true,
                text:'Chart.js Line Chart - Custom Tooltips'
            },
            tooltips: {
                enabled: false,
                mode: 'index',
                position: 'nearest',
                //Set the name of the custom function here
                custom: customTooltips
            }
        }
    });
    

    编辑:抱歉,我只阅读了您的问题的标题,而不是完整的问题。通过将交互模式更改为选项中的索引,您可以更简单地完成您的要求,并且工具提示中没有 HTML(除非出于其他原因需要)。有一个示例可以展示它是如何工作的。

    【讨论】:

    • 您应该向 OP 提供一些示例,说明如何实现他的需求。
    • 基于链接示例提供的示例。
    • 请提供使用交互模式索引的示例。
    【解决方案2】:

    很好,虽然用之前的解决方案来解决问题,但我认为chart.js 提供的解决方案有点……令人困惑。同样可以以更易于理解的方式应用。根据 chart.js 指南,我创建了一个将在工具提示中使用的 HTML。我得到的是以下内容:

    首先我给你使用的代码,然后我解释它:

    tooltip: {
                    // Disable the on-canvas tooltip
                    enabled: false,
    
                    external: (context) => {
                        // Tooltip Element
                        let tooltipEl = document.getElementById('chartjs-tooltip');
    
                        // Create element on first render
                        if (!tooltipEl) {
                            tooltipEl = document.createElement('div');
                            tooltipEl.id = 'chartjs-tooltip';
                            tooltipEl.innerHTML = '<table></table>';
                            document.body.appendChild(tooltipEl);
                        }
    
                        // Hide if no tooltip
                        const tooltipModel = context.tooltip;
                        if (tooltipModel.opacity === 0) {
                            tooltipEl.style.opacity = '0';
                            return;
                        }
    
                        // Set caret Position (above, below,no-transform ).As I need above I don't delete that class
                        tooltipEl.classList.remove('below', 'no-transform');
    
    
                        // Set HTML & Data
                        if (tooltipModel.body) {
                            const dataFromCurrentElement = tooltipModel.dataPoints[0];
                            const currentElement = dataFromCurrentElement.dataIndex;
                            const formattedValue = dataFromCurrentElement.formattedValue.trim();
                            const currentDataToShow = formattedValue.substr(1, formattedValue.length - 2).split(' ');
                            const innerHtml = `
                            <div style="border-collapse: separate; overflow: hidden; border-radius: 10px; box-shadow: 0 6px 12px rgba(0,0,0,.175);">
    
                                <div style="background-color: #ECEFF1; padding-top: 5px; padding-bottom: 6px; padding-left: 7px; color: #000; font-family: 'Poppins'; font-size: 14px; border-bottom: solid 1px #DDD">
                                   Name
                                </div>
                                <div style="display: flex; padding: 1.2rem; background-color: white">
                                    <div style="display: flex; margin-right: 1.2rem;align-items: center;  ">
                                        <div style="border-radius: 100%; background-color: #6785C1; height: 13px; width: 13px;"></div>
                                    </div>
                                    <div style="display: flex;  flex-direction: column;  font-family: 'Poppins'; font-size: 14px">
                                        <div>Revenue: <span style="font-weight: 600">${currentDataToShow[0].substr(0, currentDataToShow[0].length - 1)}</span></div>
                                        <div>Revenue per employee: <span style="font-weight: 600">${currentDataToShow[1].substr(0, currentDataToShow[1].length - 1)}</span></div>
                                        <div>Net income per employee: <span style="font-weight: 600">${this.customReportUtilities.parseNumberFunction(Number(currentDataToShow[2]) * 100)}</span></div>
                                    </div>
                                </div>
                             </div>
                        `;
    
                            tooltipEl.querySelector('table').innerHTML = innerHtml;
                        }
    
                        const position = context.chart.canvas.getBoundingClientRect();
    
                        // Display, position, and set styles for font
                        tooltipEl.style.opacity = '1';
                        tooltipEl.style.position = 'absolute';
                        tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + 'px';
                        tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + 'px';
                        tooltipEl.style.padding = tooltipModel.padding + 'px ' + tooltipModel.padding + 'px';
                        tooltipEl.style.pointerEvents = 'none';
                    }
                }
    

    这是相同的代码,不必重复,与上面的一样值得

    1. 我们使用tooltip false从chartjs中隐藏工具提示,然后在外部我们传递函数以使用我们的HTML作为工具提示

      let tooltipEl = document.getElementById('chartjs-tooltip');

    2. 我们收集id为chartjs-tooltip的容器,如果它不存在(鼠标没有放在图表上)我们创建它(如下if)。

                      let tooltipEl = document.getElementById('chartjs-tooltip');
                      if (!tooltipEl) {
                          tooltipEl = document.createElement('div');
                          tooltipEl.id = 'chartjs-tooltip';
                          tooltipEl.innerHTML = '<table></table>';
                          document.body.appendChild(tooltipEl);
                      }
      
    3. 当用户没有将光标悬停在元素上时,我们会隐藏工具提示(这是因为否则它总是会被看到。

      const tooltipModel = context.tooltip; if (tooltipModel.opacity === 0) { tooltipEl.style.opacity = '0'; return; }

    4. 我们指示工具提示的位置,以在上方、下方或不转换之间进行选择。我已经删除了除上面之外的所有内容,因为它是我想要保留的课程。

    tooltipEl.classList.remove('below', 'no-transform');

    1. 我们获取当前元素的数据并使用其样式形成 HTML ... 将其作为字符串保存在变量中,然后将字符串与 HTML 一起传递给它。

                             if (tooltipModel.body) {
                          const dataFromCurrentElement = tooltipModel.dataPoints[0];
                          const currentElement = dataFromCurrentElement.dataIndex;
                          const formattedValue = dataFromCurrentElement.formattedValue.trim();
                          const currentDataToShow = formattedValue.substr(1, formattedValue.length - 2).split(' ');
                          const innerHtml = `
                          <div style="border-collapse: separate; overflow: hidden; border-radius: 10px; box-shadow: 0 6px 12px rgba(0,0,0,.175);"> <div style="background-color: #ECEFF1; padding-top: 5px; padding-bottom: 6px; padding-left: 7px; color: #000; font-family: 'Poppins'; font-size: 14px; border-bottom: solid 1px #DDD">
                                 Name
                              </div>
                              <div style="display: flex; padding: 1.2rem; background-color: white">
                                  <div style="display: flex; margin-right: 1.2rem;align-items: center;  ">
                                      <div style="border-radius: 100%; background-color: #6785C1; height: 13px; width: 13px;"></div>
                                  </div>
                                  <div style="display: flex;  flex-direction: column;  font-family: 'Poppins'; font-size: 14px">
                                      <div>Revenue: <span style="font-weight: 600">${currentDataToShow[0].substr(0, currentDataToShow[0].length - 1)}</span></div>
                                      <div>Revenue per employee: <span style="font-weight: 600">${currentDataToShow[1].substr(0, currentDataToShow[1].length - 1)}</span></div>
                                      <div>Net income per employee: <span style="font-weight: 600">${this.customReportUtilities.parseNumberFunction(Number(currentDataToShow[2]) * 100)}</span></div>
                                  </div>
                              </div>
                           </div>
                      `;
      
                          tooltipEl.querySelector('table').innerHTML = innerHtml;
                      }
      
    2. 我们终于完成了容器的配置

      const position = context.chart.canvas.getBoundingClientRect();

                      // Display, position, and set styles for font
                      tooltipEl.style.opacity = '1';
                      tooltipEl.style.position = 'absolute';
                      tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + 'px';
                      tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + 'px';
                      tooltipEl.style.padding = tooltipModel.padding + 'px ' + tooltipModel.padding + 'px';
                      tooltipEl.style.pointerEvents = 'none';
      

    我不得不使用一些额外的样式作为溢出来显示边框半径。关于该主题的 Chart.js 文档:https://www.chartjs.org/docs/latest/samples/tooltip/html.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多