在chartjs中显示饼图外的值

时间:2015-12-10 10:19:45

标签: pie-chart chart.js

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

1 个答案:

答案 0 :(得分:0)

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

以下是渲染后的样子。

enter image description here

请注意,这需要深入挖掘chart.js内部,如果它们改变了工具提示在未来的定位或呈现方式,则可能会中断。我还添加了一个名为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);
      }
    }
  }
});