pie-chart - 在 Chartjs 中显示饼图之外的值

标签 pie-chart chart.js

当我将鼠标悬停在饼图上时,值会显示在工具提示中。但是,我想显示饼图之外的值。我想制作像这样的图表: enter image description here 这个怎么做?

最佳答案

我能够使用plugin API使用chart.js v2.3.0获得类似的工作和 extending chart types API 。您应该能够以此为起点,并根据您的需求进行调整。

这是渲染后的样子。

enter image description here

请注意,这需要深入挖掘 Chart.js 的内部结构,如果它们改变了 future 工具提示的定位或呈现方式,则可能会崩溃。我还添加了一个名为 showAllTooltips 的新配置选项,以允许在某些图表上有选择地使用该插件。这应该适用于所有图表类型,但目前我仅将其用于饼图、圆环图、条形图和折线图。

话虽如此,这是上图的可行解决方案。

Chart.plugins.register({
  beforeRender: function (chart) {
    if (chart.config.options.showAllTooltips) {
      // create a namespace to persist plugin state (which unfortunately we have to do)
      if (!chart.showAllTooltipsPlugin) {
        chart.showAllTooltipsPlugin = {};
      }

      // turn off normal tooltips in case it was also enabled (which is the global default)
      chart.options.tooltips.enabled = false;

      // we can't use the chart tooltip because there is only one tooltip per chart which gets
      // re-positioned via animation steps.....so let's create a place to hold our tooltips
      chart.showAllTooltipsPlugin.tooltipsCollection = [];

      // create a tooltip for each plot on the chart
      chart.config.data.datasets.forEach(function (dataset, i) {
        chart.getDatasetMeta(i).data.forEach(function (sector, j) {
          // but only create one for pie and doughnut charts if the plot is large enough to even see
          if (!_.contains(['doughnut', 'pie'], sector._chart.config.type) || sector._model.circumference > 0.1) {
            var tooltip;

            // create a new tooltip based upon configuration
            if (chart.config.options.showAllTooltips.extendOut) {
              // this tooltip reverses the location of the carets from the default
              tooltip = new Chart.TooltipReversed({
                _chart: chart.chart,
                _chartInstance: chart,
                _data: chart.data,
                _options: chart.options.tooltips,
                _active: [sector]
              }, chart);
            } else {
              tooltip = new Chart.Tooltip({
                _chart: chart.chart,
                _chartInstance: chart,
                _data: chart.data,
                _options: chart.options.tooltips,
                _active: [sector]
              }, chart);
            }

            // might as well initialize this now...it would be a waste to do it once we are looping over our tooltips
            tooltip.initialize();

            // save the tooltips so they can be rendered later
            chart.showAllTooltipsPlugin.tooltipsCollection.push(tooltip);
          }
        });
      });
    }
  },

  afterDraw: function (chart, easing) {
    if (chart.config.options.showAllTooltips) {
      // we want to wait until everything on the chart has been rendered before showing the
      // tooltips for the first time...otherwise it looks weird
      if (!chart.showAllTooltipsPlugin.initialRenderComplete) {
        // still animating until easing === 1
        if (easing !== 1) {
          return;
        }

        // animation is complete, let's remember that fact
        chart.showAllTooltipsPlugin.initialRenderComplete = true;
      }

      // at this point the chart has been fully rendered for the first time so start rendering tooltips
      Chart.helpers.each(chart.showAllTooltipsPlugin.tooltipsCollection, function (tooltip) {
        // create a namespace to persist plugin state within this tooltip (which unfortunately we have to do)
        if (!tooltip.showAllTooltipsPlugin) {
          tooltip.showAllTooltipsPlugin = {};
        }

        // re-enable this tooltip otherise it won't be drawn (remember we disabled all tooltips in beforeRender)
        tooltip._options.enabled = true;

        // perform standard tooltip setup (which determines it's alignment and x, y coordinates)
        tooltip.update(); // determines alignment/position and stores in _view
        tooltip.pivot(); // we don't actually need this since we are not animating tooltips, but let's be consistent
        tooltip.transition(easing).draw(); // render and animate the tooltip

        // disable this tooltip in case something else tries to do something with it later
        tooltip._options.enabled = false;
      });
    }
  },
});

// A 'reversed' tooltip places the caret on the opposite side from the current default.
// In order to do this we just need to change the 'alignment' logic
Chart.TooltipReversed = Chart.Tooltip.extend({
  // Note: tooltipSize is the size of the box (not including the caret)
  determineAlignment: function(tooltipSize) {
    var me = this;
    var model = me._model;
    var chart = me._chart;
    var chartArea = me._chartInstance.chartArea;

    // set caret position to top or bottom if tooltip y position will extend outsite the chart top/bottom
    if (model.y < tooltipSize.height) {
      model.yAlign = 'top';
    } else if (model.y > (chart.height - tooltipSize.height)) {
      model.yAlign = 'bottom';
    }

    var leftAlign, rightAlign; // functions to determine left, right alignment
    var overflowLeft, overflowRight; // functions to determine if left/right alignment causes tooltip to go outside chart
    var yAlign; // function to get the y alignment if the tooltip goes outside of the left or right edges
    var midX = (chartArea.left + chartArea.right) / 2;
    var midY = (chartArea.top + chartArea.bottom) / 2;

    if (model.yAlign === 'center') {
      leftAlign = function(x) {
        return x >= midX;
      };
      rightAlign = function(x) {
        return x < midX;
      };
    } else {
      leftAlign = function(x) {
        return x <= (tooltipSize.width / 2);
      };
      rightAlign = function(x) {
        return x >= (chart.width - (tooltipSize.width / 2));
      };
    }

    overflowLeft = function(x) {
      return x - tooltipSize.width < 0;
    };
    overflowRight = function(x) {
      return x + tooltipSize.width > chart.width;
    };
    yAlign = function(y) {
      return y <= midY ? 'bottom' : 'top';
    };

    if (leftAlign(model.x)) {
      model.xAlign = 'left';

      // Is tooltip too wide and goes over the right side of the chart.?
      if (overflowLeft(model.x)) {
        model.xAlign = 'center';
        model.yAlign = yAlign(model.y);
      }
    } else if (rightAlign(model.x)) {
      model.xAlign = 'right';

      // Is tooltip too wide and goes outside left edge of canvas?
      if (overflowRight(model.x)) {
        model.xAlign = 'center';
        model.yAlign = yAlign(model.y);
      }
    }
  }
});

关于pie-chart - 在 Chartjs 中显示饼图之外的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34199230/

相关文章:

javascript - Chartjs 和动态数据数组

css - 在 chartjs 中更改饼图和折线图中标签的字体系列

javascript - 如何在chart.js中制作没有ticks.min/max的列的固定宽度?

ios - 无法在 CorePlot 中实现像环一样的饼图

java - 为什么在将事件添加到每个饼图切片后,JavaFX PieChart 标签不显示? (Java 8)

python - 将 Matplotlib 饼图百分比标签覆盖为总和不等于 100% 的特定值

javascript - Chart.js 动画 : onComplete event fired on hover

r - 谷歌地图中的饼图使用 plotGoogleMaps

python - 从字典创建饼图并更改箭头

javascript - Chartjs 在标签中显示不同单位的多个信息