如何检测chart js 3.7.1轴标签的点击?

问题描述 投票:0回答:3

如何使用 Chart.js 检测轴标签的点击

在下面的示例中,我只能检测到图形本身的点击

https://stackblitz.com/edit/ng2-charts-bar-template-qchyz6

events chart.js click axis
3个回答
7
投票

您需要实现一个自定义插件来监听画布的所有事件:

const findLabel = (labels, evt) => {
  let found = false;
  let res = null;

  labels.forEach(l => {
    l.labels.forEach((label, index) => {
      if (evt.x > label.x && evt.x < label.x2 && evt.y > label.y && evt.y < label.y2) {
        res = {
          label: label.label,
          index
        };
        found = true;
      }
    });
  });

  return [found, res];
};

const getLabelHitboxes = (scales) => (Object.values(scales).map((s) => ({
  scaleId: s.id,
  labels: s._labelItems.map((e, i) => ({
    x: e.translation[0] - s._labelSizes.widths[i],
    x2: e.translation[0] + s._labelSizes.widths[i] / 2,
    y: e.translation[1] - s._labelSizes.heights[i] / 2,
    y2: e.translation[1] + s._labelSizes.heights[i] / 2,
    label: e.label,
    index: i
  }))
})));

const plugin = {
  id: 'customHover',
  afterEvent: (chart, event, opts) => {
    const evt = event.event;

    if (evt.type !== 'click') {
      return;
    }

    const [found, labelInfo] = findLabel(getLabelHitboxes(chart.scales), evt);

    if (found) {
      console.log(labelInfo);
    }

  }
}

Chart.register(plugin);

const options = {
  type: 'line',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: '# of Votes',
        data: [12, 19, 3, 5, 2, 3],
        borderColor: 'pink'
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        borderColor: 'orange'
      }
    ]
  },
  options: {}
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>


0
投票

如果 X 轴上的标签有旋转,那么您可以尝试下面的代码。不要在此处运行代码,只需复制并在您的 IDE 中尝试即可。

import {Chart as ChartJS} from 'chart.js';

// Function to calculate cotangent (ctg) from radians
const ctg = (radians: number): number => 1 / Math.tan(radians);

const findLabel = (labels: any, evt: any): LabelData | undefined => {
  let res: LabelData | undefined = undefined;
  const scalesYwidth = evt.chart.scales.y.width;
  const scalesXheight = evt.chart.scales.x.height;
  const eventY = evt.y - (evt.chart.height - scalesXheight);
  let min = Infinity;

  for (const l of labels) {
    for (const index in l.labels) {
      const label = l.labels[index];

      if (eventY > 10 && evt.x > scalesYwidth - 10) {
        if (evt.x > label.x && evt.x < label.x2) {
          const b = Math.abs(eventY * ctg(label.rotation));
          const xClosest = Math.abs(label.x2 - (evt.x + b));
 
          if (xClosest < min) {
            min = xClosest;
            res = {
              label: label.label,
              index: +index,
              axis: 'x'
            };
          }
        }
      } else if (evt.x < scalesYwidth - 10 && evt.y > label.y && evt.y < label.y2) {
        res = {
          label: label.label,
          index: +index,
          axis: 'y'
        };
      }
    }
  }

  return res;
};

const getLabelHitboxes = (scales: any) =>
  Object.values(scales).map((s: any) => {
    return {
      scaleId: s.id,
      labels: s._labelItems.map((e: any, i: number) => {
        const ts = e.options.translation;
        return {
          x: ts[0] - s._labelSizes.widths[i],
          x2: ts[0] + s._labelSizes.widths[i] / 2,
          y: ts[1] - s._labelSizes.heights[i] / 2,
          y2: ts[1] + s._labelSizes.heights[i] / 2,
          rotation: e.options.rotation,
          label: e.label,
          index: i
        };
      })
    };
  });

const getLabelEventData = (chart: ChartJS, chartEvent: any): LabelData | undefined =>
  findLabel(getLabelHitboxes(chart.scales), chartEvent);

export const getChartPluginLabelClick = (onClick?: (data?: LabelData) => void) => ({
  id: 'customHover',
  afterEvent: (chart: ChartJS, event: any, opts: any) => {
    const evt = event.event;
    if (evt.type !== 'click') return;
    const data = getLabelEventData(chart, evt);
    onClick && onClick(data);
  }
});
// register global
// ChartJS.register(getPlugin());

export interface LabelData {
  label: string | string[];
  index: number;
  axis: 'x' | 'y';
}
import {Chart as ChartJS} from 'chart.js';
import {Chart} from 'react-chartjs-2';
import 'chart.js/auto';

<div style={{position: 'relative', height: '600px', width: '100%'}}>
        <Chart
          ref={ref}
          type="bar"
          plugins={[
            getChartPluginLabelClick((data?: LabelData) => {
              console.log(data);
            })
          ]}
          options={options}
          data={data}
          onClick={onClick}
        />
</div>


-1
投票

使用 ng2-charts (chart-js v3.7.1) 适配 Angular

只需使用Chart.register

即将以下函数放入组件 ngOnInit()

RegisterPlugin() {
    Chart.register(
      {
        id: 'yAxisCustomClick',
        afterEvent: (chart: Chart<'bar'>, event: {
          event: ChartEvent;
          replay: boolean;
          changed?: boolean | undefined;
          cancelable: false;
          inChartArea: boolean
        }) => {
          const evt = event.event;
          if (evt.type === 'click' && evt.x! < Object.values(chart.scales).filter(s => s.id === 'x')[0].getBasePixel()) {
            const labelIndex = Object.values(chart.scales).filter(s => s.id === 'y')[0].getValueForPixel(evt.y!);
            const label = Object.values(chart.scales).filter(s => s.id === 'y')[0].getTicks()[labelIndex!]?.label;
            if (label) {
              console.log('Do the stuff for', label)
            }
          }
        }
      }
    );
  }

更新了 stackblitz 中的示例 https://stackblitz.com/edit/ng2-charts-bar-template-qchyz6

© www.soinside.com 2019 - 2024. All rights reserved.