Chart.js 3.9 和 Vue:无法处理 onClick 事件

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

通常,StackOverflow 是我的最后手段,因为我不喜欢被惹恼,我想你也不喜欢,但我很绝望。

我想捕获图表栏上的点击,但我在日志中没有看到点击事件已被抛出的痕迹。我使用的是 Chart.js 2.8.9,但升级到 3.9,认为这可能是一个错误。

这是我加载图形的 vue 文件:

<template>
    <div>
        <h4>Gráficas de miembros activos</h4>
        <div>
            <!-- Pasamos chartData y el evento bar-clicked -->
            <bar-chart :chart-data="datos" :opciones="opciones" @bar-clicked="handleBarClick" />
        </div>
    </div>
</template>

<script>
    import BarChart from "../components/BarChart";
    import api from "@/api";

    export default {
        name: "Graficas",
        components: { BarChart },
        data() {
            return {
                datos: {},   // Datos del gráfico
                opciones: {} // Opciones del gráfico
            };
        },
        methods: {
            graficar: function (sector_id) {
                api.graficas(sector_id).then((r) => {
                    this.datos = r.data; 

                    // Configuración de colores y bordes de las barras
                    this.datos.datasets[0].backgroundColor = [
                        'rgba(255, 99, 132, 0.2)',
                        'rgba(255, 159, 64, 0.2)',
                        'rgba(255, 205, 86, 0.2)',
                        'rgba(75, 192, 192, 0.2)',
                        'rgba(54, 162, 235, 0.2)',
                        'rgba(153, 102, 255, 0.2)',
                        'rgba(201, 203, 207, 0.2)'
                    ];
                    this.datos.datasets[0].borderColor = [
                        'rgb(255, 99, 132)',
                        'rgb(255, 159, 64)',
                        'rgb(255, 205, 86)',
                        'rgb(75, 192, 192)',
                        'rgb(54, 162, 235)',
                        'rgb(153, 102, 255)',
                        'rgb(201, 203, 207)'
                    ];
                    this.datos.datasets[0].borderWidth = 1;

                    // Opciones del gráfico
                    this.opciones = {
                        scales: {
                            y: {
                                beginAtZero: true
                            }
                        },
                        responsive: true,
                        maintainAspectRatio: false,
                        height: 300
                    };
                })
                .catch(error => {
                    console.log(error);
                });
            },
            handleBarClick({ data, dataIndex, datasetIndex }) {
                // Este método captura el evento bar-clicked y muestra la información del clic
                console.log(`Clicked bar at index ${dataIndex} in dataset ${datasetIndex}:`, data);
            }
        },
        mounted() {
            const sector_id = this.$route.params.id ?? 0;
            this.graficar(sector_id);
        },
    };
</script>

这是我们创建的用于扩展 Chart.js 的类:

import { Chart, registerables } from 'chart.js';

Chart.register(...registerables); // Registro de todos los componentes necesarios

export default {
  props: {
    chartData: {
      type: Object,
      required: true
    },
    opciones: {
      type: Object,
      default: () => ({})
    }
  },
  mounted() {
    const canvas = this.$refs.canvas;

    // Verificamos que el canvas existe y tiene contexto 2D
    if (!canvas || !canvas.getContext) {
      console.error("No se pudo obtener el contexto del canvas.");
      return;
    }

    const ctx = canvas.getContext('2d');

    // Configuración de las opciones de la gráfica
    this.opciones.scales = {
      y: {
        beginAtZero: true
      }
    };
    this.opciones.plugins = {
      datalabels: {
        color: "black",
        textAlign: "center",
        anchor: 'start',
        font: {
          weight: "bold",
          size: 14,
        }
      }
    };
    this.opciones.responsive = true;
    this.opciones.maintainAspectRatio = false;
    this.opciones.hover = {
      mode: 'nearest',
      intersect: true
    };
    this.opciones.interaction = {
      mode: 'index',
      intersect: false
    };

    // Establecemos una altura fija para el canvas a través de CSS
    canvas.style.height = '400px';
    canvas.style.width = '100%'; 

    // Instancia del gráfico
    this.chartInstance = new Chart(ctx, {
      type: 'bar',
      data: this.chartData,
      options: {
        ...this.opciones,
        onClick: (event, elements) => {
          console.log('onClick event triggered');
          if (elements.length > 0) {
            const element = elements[0];
            const dataIndex = element.index;
            const datasetIndex = element.datasetIndex;
            console.log('Data point clicked:', dataIndex, datasetIndex);
            const data = this.chartData.datasets[datasetIndex].data[dataIndex];
            this.$emit('bar-clicked', { data, dataIndex, datasetIndex });
          } else {
            console.log('No elements clicked.');
          }
        }
      }
    });

  },
  watch: {
    chartData(newData) {
      if (this.chartInstance) {
        this.chartInstance.data = newData;
        this.chartInstance.update();
      }
    },
    opciones(newOptions) {
      if (this.chartInstance) {
        this.chartInstance.options = newOptions;
        this.chartInstance.update();
      }
    }
  },
  beforeDestroy() {
    if (this.chartInstance) {
      this.chartInstance.destroy();
    }
  },
  render(h) {
    return h('canvas', { ref: 'canvas' });
  }
};

后端返回的JSON很简单,所以错误不应该出现:

    {
  "datasets": [
    {
      "data": [
        15,
        5,
        0,
        0,
        0
      ],
      "label": "Sector San Felipe De Jesus"
    }
  ],
  "labels": [
    "Matrimonios",
    "MaRes",
    "J\u00f3venes",
    "Adolescentes",
    "Asistentes Eclesiales"
  ]
}

显示了图形,但我在日志中没有看到单击的痕迹。有什么想法吗? Graph is shown but nothing in the logs

javascript vuejs2 chart.js
1个回答
0
投票

以防万一它发生在其他人身上。有两个阻碍:

  1. 安装了一个不兼容的插件:chartjs-plugin-datalabels。必须卸载它:npm uninstall Chartjs-plugin-datalabels并重新编译:npm install
  2. 点击位置不正确。根据这篇文章,它必须放置在画布内而不是选项:
    canvas.onclick = (evt) => {
      const res = chart.getElementsAtEventForMode(
        evt,
        'nearest',
        { intersect: true },
        true
      );
      // If didn't click on a bar, `res` will be an empty array
      if (res.length === 0) {
        return;
      }
      // Alerts "You clicked on A" if you click the "A" chart
      alert('You clicked on ' + chart.data.labels[res[0].index]);
    };
© www.soinside.com 2019 - 2024. All rights reserved.