Chart.elements.Rectangle.prototype.draw影响同页其他图表(Angular)

Chart.elements.Rectangle.prototype.draw inpacting on other charts in the same page(Angular)

我在不同的组件中创建了 2 个图表,这 2 个图表在同一页面(同一组件)中使用。图表有不同的逻辑和风格,调试图表我意识到绘图功能正在影响另一个图表,反之亦然。 这两个图表都有绘图功能,并且正在从 'chart-js' 导入图表,有人知道我如何在绘图功能中区分这些图表吗? 我已经尝试查询选择器图表并执行 if 检查绘制函数检查 id 但它不起作用

绘制方法如下

  private customizeChartJs() {
const el = this.hostElement.nativeElement.querySelector('#customerRetention');
if (el) {
  try {
    Chart.elements.Rectangle.prototype.draw = function () {
      console.log(this._chart);

      const ctx = this._chart.ctx;
      console.log();

      const vm = this._view;

      let left;
      let right;
      let top;
      let bottom;
      let signX;
      let signY;
      let borderSkipped;
      let borderWidth = vm.borderWidth;
      let nextCornerId;
      let nextCorner;
      let width;
      let height;
      let x;
      let y;
      const roundedCorner = this._chart.options.roundedCorner;
      // Set Radius Here
      const cornerRadius = 10;

      // If radius is large enough to cause drawing errors a max radius is imposed
      if (!vm.horizontal) {
        // bar

        left = vm.x - vm.width;
        right = vm.x + vm.width / 2;
        top = vm.y;
        bottom = vm.base;
        signX = 5;
        signY = bottom > top ? 1 : -1;
        borderSkipped = vm.borderSkipped || 'bottom';
      } else {
        // horizontal bar
        left = vm.base;
        right = vm.x;
        top = vm.y - vm.height / 2;
        bottom = vm.y + vm.height / 2;
        signX = right > left ? 1 : -1;
        signY = 1;
        borderSkipped = vm.borderSkipped || 'left';
      }

      // Canvas doesn't allow us to stroke inside the width so we can
      // adjust the sizes to fit if we're setting a stroke on the line
      if (borderWidth) {
        // borderWidth shold be less than bar width and bar height.
        const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
        borderWidth = borderWidth > barSize ? barSize : borderWidth;
        const halfStroke = borderWidth / 2;
        // Adjust borderWidth when bar top position is near vm.base(zero).
        const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
        const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
        const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
        const borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
        // not become a vertical line?
        if (borderLeft !== borderRight) {
          top = borderTop;
          bottom = borderBottom;
        }
        // not become a horizontal line?
        if (borderTop !== borderBottom) {
          left = borderLeft;
          right = borderRight;
        }
      }

      ctx.beginPath();
      ctx.strokeStyle = vm.borderColor;
      ctx.lineWidth = borderWidth;

      ctx.fillStyle = vm.backgroundColor;

      // Corner points, from bottom-left to bottom-right clockwise
      // | 1 2 |
      // | 0 3 |
      const corners = [
        [left, bottom],
        [left, top],
        [right, top],
        [right, bottom],
      ];

      // Find first (starting) corner with fallback to 'bottom'
      const borders = ['bottom', 'left', 'top', 'right'];
      let startCorner = borders.indexOf(borderSkipped, 0);
      if (startCorner === -1) {
        startCorner = 0;
      }

      function cornerAt(index) {
        return corners[(startCorner + index) % 4];
      }

      // Draw rectangle from 'startCorner'
      let corner = cornerAt(0);
      ctx.moveTo(corner[0], corner[1]);

      for (let i = 1; i < 4; i++) {
        corner = cornerAt(i);
        nextCornerId = i + 1;
        if (nextCornerId === 4) {
          nextCornerId = 0;
        }

        nextCorner = cornerAt(nextCornerId);
        width = corners[2][0] - corners[1][0];
        height = corners[0][1] - corners[1][1];
        x = corners[1][0];
        y = corners[1][1];

        let radius = cornerRadius;

        // Fix radius being too large
        if (radius > height / 2) {
          radius = height / 2;
        }
        if (radius > width / 2) {
          radius = width / 2;
        }

        if (!vm.horizontal) {
          ctx.beginPath();
          ctx.moveTo(x + radius, y);
          ctx.lineTo(x + width - radius, y);
          ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
          ctx.lineTo(x + width, y + height);
          ctx.lineTo(x, y + height);
          ctx.lineTo(x, y);
          ctx.quadraticCurveTo(x, y, x, y);
          ctx.closePath();
        } else if (vm.horizontal && !roundedCorner) {
          ctx.moveTo(x + radius, y);
          ctx.lineTo(x + width - radius, y);
          ctx.lineTo(x + width, y, x + width, y + radius);
          ctx.lineTo(x + width, y + height - radius);
          ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
          ctx.lineTo(x + radius, y + height);
          ctx.lineTo(x, y + height, x, y + height - radius);
          ctx.lineTo(x, y + radius);
          ctx.lineTo(x, y, x + radius, y);
        } else {
          ctx.moveTo(x + radius, y);
          ctx.lineTo(x + width - radius, y);
          ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
          ctx.lineTo(x + width, y + height - radius);
          ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
          ctx.lineTo(x + radius, y + height);
          ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
          ctx.lineTo(x, y + radius);
          ctx.quadraticCurveTo(x, y, x + radius, y);
        }
      }

      ctx.fill();
      if (borderWidth) {
        ctx.stroke();
      }
    };

    Chart.defaults.CustomerRetention = Chart.defaults.bar;

    Chart.Tooltip.positioners.custom = (elements, position) => {
      if (!elements.length) {
        return false;
      }
      const { forceFirstTooltipsToLeft } = elements[0]._chart.options.custom;
      let x = -299;
      let y = 0;

      // primeiros 3 itens da esquerda precisam abrir tooltip pra direita
      if (forceFirstTooltipsToLeft && elements[0]._index < 3) {
        x = 10;
      } else {
        const maxIndex = elements[0]._xScale.maxIndex;

        if (maxIndex > 9 && elements[0]._index < 3) {
          x = 10;
        }
      }
      if (elements.length > 1) {
        let indexElementTaller: number;

        x += elements[0]._model.x;

        indexElementTaller = elements[0]._model.y <= elements[1]._model.y ? 0 : 1;

        const tallerElementHeight = 280 - 27 - elements[indexElementTaller]._model.y;

        if (tallerElementHeight < 30) {
          y += -20;
        }
        y += elements[indexElementTaller]._model.y;
      } else {
        x += elements[0]._model.x;

        y += elements[0]._model.y;
      }
      y += -20;

      return { x, y };
    };

    Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
      draw(ease) {
        Chart.controllers.bar.prototype.draw.call(this, ease);

        const customOptions: any = this.chart.options.custom;
        const tooltipTitleData: any[] = this.chart.tooltip._options.titles;

        const ctx = this.chart.chart.ctx;
        ctx.clearRect(0, this.chart.height - 37, 1000, 22);
      },
    });
  } catch (e) {
    console.error(e);
  }
}

}

我想你可以尝试使用 RectangleElement 的方法 extend,还有 BarController,添加 属性 dataElementType,像这样:

const rectangleElement = Chart.elements.Rectangle;
const otherRectangleElement = rectangleElement.extend({
    draw() {
        const ctx = this._chart.ctx;
        // ...
    }
}

Chart.defaults.CustomerRetention = Chart.defaults.bar;

Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
    dataElementType: otherRectangleElement,
    draw(ease) {
        Chart.controllers.bar.prototype.draw.call(this, ease);
        // ...
    }
}