ChartJS 折线图 - 多条线,在工具提示上显示一个值多条、提示、工具、折线图

2023-09-07 11:40:25 作者:有一种感觉是〈想念〉

我正在尝试制作一个必须显示每个客户的帐户移动的图表.

I'm trying to make a Graph which has to show the Account movement from each Customer.

我要做什么

我有树线;第一行:最低余​​额,如果客户的余额少于最小值.余额,他的余额将自动从他的银行帐户中加载.

I've tree lines ; First line : The minimum balance, if the customer has less than the min. balance, his balance will auto load from his bank account.

第二行:当前余额

第三行:最大余额:如果客户有超过最大余额.他的余额将成为他银行账户上系统的差额.

Third Line: The maximum balance : If the customer has more than the max. balance he will become the difference from the system on his bank account.

图片链接 : chartjs 工具提示问题

正如您在工具提示中看到的那样,是所有 3 个值.直线的值与客户无关,因为限制(最大值和最小值由客户自己设置).

As you see in the tooltip are the all 3 values. The values of the straight lines are irrelevant for the customer because the Limits (max and min are setted from the customer his own) .

推荐答案

要实现这一点,您可以扩展折线图以添加一个选项来显示/隐藏每个数据集低音上的工具提示.烦人的是只有很少的变化,但整个方法必须被覆盖才能在那里得到变化,所以下面看起来很多,但它基本上是对以下方法的 3 处变化

To achieve this you can extend the line graph to add an option to show/hide tool-tips on a per dataset basses. The annoying thing is there are only a few changes but whole methods have to be overridden to get the changes in there so the below looks like a lot but its basically 3 changes to the following methods

初始化 - 添加选项以在每个点中存储 showTooltip 选项

Initialize - added option to store showTooltip option in each point

getPointsAtEvent - 添加检查以确保我们希望在获取积分时显示工具提示

getPointsAtEvent - added check to make sure we want to disaply a tool tip when getting points

showTooltip - 再次添加检查以确保我们想要显示工具提示

showTooltip - added check again to make sure we want to dispaly a tool tip

然后使用它,图表设置相同,但您将其设为 LineTooltip(这就是我所说的扩展图表)并在数据集调用 showToolip 中传递一个额外选项.

to then use it the chart is set up the same but instead you make it a LineTooltip (thats what i have called the extended chart) and pass anextra option in the datasets call showToolip.

 datasets: [{
        label: "My First dataset",
        fillColor: "rgba(220,220,220,0.5)",
        strokeColor: "rgba(220,220,220,0.8)",
        highlightFill: "rgba(220,220,220,0.75)",
        highlightStroke: "rgba(220,220,220,1)",
        showTooltip: false, //NEW OPTION DON"T NEED TO INCLUDE IT IF YOU WANT TO DISPLAY BUT WON"T HURT IF YOU DO
        data: [15, 10, 10, 10, 10, 10, 10]
    }, {
        label: "My second dataset",
        fillColor: "rgba(220,220,220,0.5)",
        strokeColor: "rgba(220,220,220,0.8)",
        highlightFill: "rgba(220,220,220,0.75)",
        highlightStroke: "rgba(220,220,220,1)",
        showTooltip: false, //NEW OPTION DON"T NEED TO INCLUDE IT IF YOU WANT TO DISPLAY BUT WON"T HURT IF YOU DO
        data: [100, 100, 100, 100, 100, 100, 100]
    }, {
        label: "My third dataset",
        fillColor: "rgba(151,187,205,0.5)",
        strokeColor: "rgba(151,187,205,0.8)",
        highlightFill: "rgba(151,187,205,0.75)",
        highlightStroke: "rgba(151,187,205,1)",
        data: [28, 48, 40, 19, 86, 27, 90]
    }]

我在下面的代码中添加了更大的注释横幅,以尝试突出显示更改的位置.我还将此功能添加到我的 chartjs 分支中,因为这可能对更多人有用 https://github.com/leighquince/Chart.js,使用这个你可以使用普通折线图并添加showTooltip

i have added bigger comment banners in the below code to try and highlight where the changes got made. I have also added this feature to my fork of chartjs as this could be useful to more people https://github.com/leighquince/Chart.js, using this you can just use a normal line chart and add the showTooltip

以下是将 Line 扩展为自定义图表以包含此功能的示例,我在 LineTooltip 中调用了该功能,但您可以随意调用它.

Below is the example of extending the Line into a custom chart to include this feature, ive called in LineTooltip as but could be called anything you like that.

Chart.types.Line.extend({

  name: "LineTooltip",
  /*
   * we have to add one item in the init so need to rewrite it again here with the one edit
   */
  initialize: function(data) {
    //have to get the helpers as we are using this outside chart where it was declared
    var helpers = Chart.helpers;
    //Declare the extension of the default point, to cater for the options passed in to the constructor
    this.PointClass = Chart.Point.extend({
      strokeWidth: this.options.pointDotStrokeWidth,
      radius: this.options.pointDotRadius,
      display: this.options.pointDot,
      hitDetectionRadius: this.options.pointHitDetectionRadius,
      ctx: this.chart.ctx,
      inRange: function(mouseX) {
        return (Math.pow(mouseX - this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius, 2));
      }
    });

    this.datasets = [];

    //Set up tooltip events on the chart
    if (this.options.showTooltips) {
      helpers.bindEvents(this, this.options.tooltipEvents, function(evt) {
        var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
        this.eachPoints(function(point) {
          point.restore(['fillColor', 'strokeColor']);
        });
        helpers.each(activePoints, function(activePoint) {
          activePoint.fillColor = activePoint.highlightFill;
          activePoint.strokeColor = activePoint.highlightStroke;
        });
        this.showTooltip(activePoints);
      });
    }

    //Iterate through each of the datasets, and build this into a property of the chart
    helpers.each(data.datasets, function(dataset) {
      var datasetObject = {
        label: dataset.label || null,
        fillColor: dataset.fillColor,
        strokeColor: dataset.strokeColor,
        pointColor: dataset.pointColor,
        pointStrokeColor: dataset.pointStrokeColor,
        showTooltip: dataset.showTooltip,
        points: []
      };

      this.datasets.push(datasetObject);


      helpers.each(dataset.data, function(dataPoint, index) {
        //Add a new point for each piece of data, passing any required data to draw.
        datasetObject.points.push(new this.PointClass({

          /*
           * set wether to show the tooltip or not, left this as being able to be undfined
           * and default to true
           */
          showTooltip: dataset.showTooltip === undefined ? true : dataset.showTooltip,
          value: dataPoint,
          label: data.labels[index],
          datasetLabel: dataset.label,
          strokeColor: dataset.pointStrokeColor,
          fillColor: dataset.pointColor,
          highlightFill: dataset.pointHighlightFill || dataset.pointColor,
          highlightStroke: dataset.pointHighlightStroke || dataset.pointStrokeColor
        }));
      }, this);

      this.buildScale(data.labels);


      this.eachPoints(function(point, index) {
        helpers.extend(point, {
          x: this.scale.calculateX(index),
          y: this.scale.endPoint
        });
        point.save();
      }, this);

    }, this);


    this.render();
  },
  /*
   * need to edit how points at event works so it only uses points that we want to show the tool tip for
   */
  getPointsAtEvent: function(e) {
    //have to get the helpers as we are using this outside chart where it was declared
    var helpers = Chart.helpers;
    var pointsArray = [],
      eventPosition = helpers.getRelativePosition(e);
    helpers.each(this.datasets, function(dataset) {
      helpers.each(dataset.points, function(point) {
        if (point.inRange(eventPosition.x, eventPosition.y) && point.showTooltip) pointsArray.push(point);
      });
    }, this);
    return pointsArray;
  },
  /*
   * also need to change how the core showTooltip functions as otherwise, it trys to be helpful
   * and grab any points it thinks also need to be displayed
   */
  showTooltip: function(ChartElements, forceRedraw) {
    //have to get the helpers as we are using this outside chart where it was declared
    var helpers = Chart.helpers;
    var each = helpers.each;
    var indexOf = helpers.indexOf;
    var min = helpers.min;
    var max = helpers.min;
    // Only redraw the chart if we've actually changed what we're hovering on.
    if (typeof this.activeElements === 'undefined') this.activeElements = [];

    var isChanged = (function(Elements) {
      var changed = false;

      if (Elements.length !== this.activeElements.length) {
        changed = true;
        return changed;
      }

      each(Elements, function(element, index) {
        if (element !== this.activeElements[index]) {
          changed = true;
        }
      }, this);
      return changed;
    }).call(this, ChartElements);

    if (!isChanged && !forceRedraw) {
      return;
    } else {
      this.activeElements = ChartElements;
    }
    this.draw();
    if (ChartElements.length > 0) {
      // If we have multiple datasets, show a MultiTooltip for all of the data points at that index
      if (this.datasets && this.datasets.length > 1) {
        var dataArray,
          dataIndex;

        for (var i = this.datasets.length - 1; i >= 0; i--) {
          dataArray = this.datasets[i].points || this.datasets[i].bars || this.datasets[i].segments;
          dataIndex = indexOf(dataArray, ChartElements[0]);
          if (dataIndex !== -1) {
            break;
          }
        }
        var tooltipLabels = [],
          tooltipColors = [],
          medianPosition = (function(index) {

            // Get all the points at that particular index
            var Elements = [],
              dataCollection,
              xPositions = [],
              yPositions = [],
              xMax,
              yMax,
              xMin,
              yMin;
            helpers.each(this.datasets, function(dataset) {
              dataCollection = dataset.points || dataset.bars || dataset.segments;
              /*
               *check to make sure we want to show the point
               */
              if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue() && (dataCollection[dataIndex].showTooltip === undefined || dataCollection[dataIndex].showTooltip)) {
                Elements.push(dataCollection[dataIndex]);
              }
            });

            helpers.each(Elements, function(element) {
              xPositions.push(element.x);
              yPositions.push(element.y);


              //Include any colour information about the element
              tooltipLabels.push(helpers.template(this.options.multiTooltipTemplate, element));
              tooltipColors.push({
                fill: element._saved.fillColor || element.fillColor,
                stroke: element._saved.strokeColor || element.strokeColor
              });

            }, this);

            yMin = min(yPositions);
            yMax = max(yPositions);

            xMin = min(xPositions);
            xMax = max(xPositions);

            return {
              x: (xMin > this.chart.width / 2) ? xMin : xMax,
              y: (yMin + yMax) / 2
            };
          }).call(this, dataIndex);

        new Chart.MultiTooltip({
          x: medianPosition.x,
          y: medianPosition.y,
          xPadding: this.options.tooltipXPadding,
          yPadding: this.options.tooltipYPadding,
          xOffset: this.options.tooltipXOffset,
          fillColor: this.options.tooltipFillColor,
          textColor: this.options.tooltipFontColor,
          fontFamily: this.options.tooltipFontFamily,
          fontStyle: this.options.tooltipFontStyle,
          fontSize: this.options.tooltipFontSize,
          titleTextColor: this.options.tooltipTitleFontColor,
          titleFontFamily: this.options.tooltipTitleFontFamily,
          titleFontStyle: this.options.tooltipTitleFontStyle,
          titleFontSize: this.options.tooltipTitleFontSize,
          cornerRadius: this.options.tooltipCornerRadius,
          labels: tooltipLabels,
          legendColors: tooltipColors,
          legendColorBackground: this.options.multiTooltipKeyBackground,
          title: ChartElements[0].label,
          chart: this.chart,
          ctx: this.chart.ctx
        }).draw();

      } else {
        each(ChartElements, function(Element) {
          var tooltipPosition = Element.tooltipPosition();
          new Chart.Tooltip({
            x: Math.round(tooltipPosition.x),
            y: Math.round(tooltipPosition.y),
            xPadding: this.options.tooltipXPadding,
            yPadding: this.options.tooltipYPadding,
            fillColor: this.options.tooltipFillColor,
            textColor: this.options.tooltipFontColor,
            fontFamily: this.options.tooltipFontFamily,
            fontStyle: this.options.tooltipFontStyle,
            fontSize: this.options.tooltipFontSize,
            caretHeight: this.options.tooltipCaretSize,
            cornerRadius: this.options.tooltipCornerRadius,
            text: template(this.options.tooltipTemplate, Element),
            chart: this.chart
          }).draw();
        }, this);
      }
    }
    return this;
  },

});




var ctx = document.getElementById("chart").getContext("2d");
var data = {
  labels: ["January", "February", "March", "April", "May", "June", "July"],
  datasets: [{
    label: "My First dataset",
    fillColor: "rgba(220,220,220,0.5)",
    strokeColor: "rgba(220,220,220,0.8)",
    highlightFill: "rgba(220,220,220,0.75)",
    highlightStroke: "rgba(220,220,220,1)",
    showTooltip: false, //TO USE JUST ADD THIS NEW OPTION ONLY REALLY NEEDS TO PRESENT IF SETTING TO FALSE
    data: [15, 10, 10, 10, 10, 10, 10]
  }, {
    label: "My second dataset",
    fillColor: "rgba(220,220,220,0.5)",
    strokeColor: "rgba(220,220,220,0.8)",
    highlightFill: "rgba(220,220,220,0.75)",
    highlightStroke: "rgba(220,220,220,1)",
    showTooltip: false, //TO USE JUST ADD THIS NEW OPTION ONLY REALLY NEEDS TO PRESENT IF SETTING TO FALSE
    data: [100, 100, 100, 100, 100, 100, 100]
  }, {
    label: "My third dataset",
    fillColor: "rgba(151,187,205,0.5)",
    strokeColor: "rgba(151,187,205,0.8)",
    highlightFill: "rgba(151,187,205,0.75)",
    highlightStroke: "rgba(151,187,205,1)",
    data: [28, 48, 40, 19, 86, 27, 90]
  }]
};


var myBarChart = new Chart(ctx).LineTooltip(data);

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
<canvas id="chart" width="600px"></canvas>

如果你觉得这很容易查看,那就给个小提琴http://jsfiddle.net/leighking2/1Lammwpt/

and a fiddle if you find that easy to view http://jsfiddle.net/leighking2/1Lammwpt/