You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为chartjs-chart-venn韦恩图设置点击激活背景色及hover高亮

解决Chart.js韦恩图点击保持激活色及hover高亮问题

问题描述

使用chartjs-chart-venn创建韦恩图时,存在两个待解决的需求:

  • 点击区域后设置的激活红色背景仅短暂显示就恢复原色,无法持久保持
  • 需要实现hover时高亮整个圆形区域的效果

原因分析

原代码直接修改points[0].element.options.backgroundColor属于临时变更,Chart.js更新时会从数据集的backgroundColor数组读取颜色值,导致临时修改被覆盖。同时缺少对hover高亮的配置,以及持久化跟踪选中状态的逻辑。

解决方案

  1. 添加选中状态跟踪:用React的useState保存当前选中区域的索引,实现状态持久化
  2. 修改点击事件逻辑:点击时更新选中索引,同步修改数据集的backgroundColor数组,将选中项设为激活色,其他项恢复默认色
  3. 配置hover高亮:在图表配置的options中添加hover配置,设置hover时的背景色和边框样式
  4. 更新渲染依赖:将选中状态加入useEffect的依赖数组,确保状态变化时图表重新渲染

修改后的完整代码

import React, { useEffect, useRef, useState } from "react";
import { VennDiagramChart } from "chartjs-chart-venn";

export default function Diagram() {
  // 保存选中的区域索引,初始为null表示无选中
  const [selectedIndex, setSelectedIndex] = useState(null);
  
  // 默认颜色数组
  const defaultColors = [
    "rgba(222, 215, 243, 0.4)",
    "rgba(253, 244, 204, 0.4)",
    "rgba(237, 221, 205, 0.4)",
    "rgba(229, 216, 195, 0.4)",
    "rgba(153, 102, 255, 0.4)",
    "rgba(255, 159, 64, 0.4)",
  ];

  const config = {
    type: "venn",
    title: {
      display: true,
      text: 'Sports',
    },
    data: {
      labels: [
        "Volleyball",
        "Tenis",
        "Football",
        "Volleyball ∩ Tenis",
        "Volleyball ∩ Football",
        "Tenis ∩ Football",
        "Volleyball ∩ Tenis ∩ Football",
      ],
      datasets: [
        {
          label: "Sports",
          data: [
            { label: 'Volleyball', sets: ["Volleyball"], value: 4},
            { label: 'Tenis', sets: ["Tenis"], value: 4, },
            { label: 'Football', sets: ["Football"], value: 4, }, 
            { label: 'Volleyball ∩ Tenis', sets: ["Volleyball", "Tenis"], value: '',  },
            { label: 'Volleyball ∩ Football', sets: ["Volleyball", "Football"], value:'', },
            { label: 'Tenis ∩ Football', sets: ["Tenis", "Football"], value: '', }, 
            { label: 'Volleyball ∩ Tenis ∩ Football', sets: ["Volleyball", "Tenis", "Football"], value: 3,  }, 
          ],
          // 根据选中状态动态生成背景色
          backgroundColor: defaultColors.map((color, index) => 
            selectedIndex === index ? 'red' : color
          ),
          borderColor: [
            "rgba(155, 130, 217, 0.4)",
            "rgba(250, 226, 118, 0.4)",
            "rgba(202, 152, 101, 0.4)",
            "rgba(246, 217, 93, 0.4)",
            "rgba(153, 102, 255, 0.4)",
            "rgba(255, 159, 64, 0.4)",
          ],
          borderWidth: 2,
        },
      ],
    },
    options: {
      events: ['click', 'mousemove'], // 保留hover事件
      interaction: {
        mode: 'nearest',
        intersect: false,
      },
      layout: {
        padding: 20
      },
      title: {
        display: true,
        text: "Chart.js Venn Diagram Chart",
      },
      onClick: (event, elements, chart) => {
        const points = chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true);
        if (points.length > 0) {
          const dataIndex = points[0].index;
          // 切换选中状态:点击已选中的则取消,否则选中当前项
          setSelectedIndex(selectedIndex === dataIndex ? null : dataIndex);
        }
      },
      // 配置hover高亮
      hover: {
        backgroundColor: 'rgba(255, 0, 0, 0.6)', // hover时背景色
        borderColor: 'rgba(0, 0, 0, 1)', // hover时边框色
        borderWidth: 3
      }
    },
    scales:[
      {
        x: {
          ticks: {
            font: {
              size: 14
            },
            color: 'black'
          }
        },
        y: {
          ticks: {
            font: {
              size: 14
            },
            color: 'black'
          }
        }
      }
    ]
  };

  const chartRef = useRef(null);

  useEffect(() => {
    const ctx = document.getElementById("canvas2").getContext("2d");
    if (chartRef.current) {
      chartRef.current.destroy();
    }
    chartRef.current = new VennDiagramChart(ctx, config);
    return () => {
      if (chartRef.current) {
        chartRef.current.destroy();
      }
    };
  }, [selectedIndex]); // 选中状态变化时重新渲染图表

  return (
    <>
      <div className="chart-container" style={{maxWidth: "700px"}}>
        <canvas id="canvas2"></canvas>
      </div>
    </>
  );
}

关键修改说明

  • 选中状态管理:通过useState记录选中的dataIndex,点击时切换状态(再次点击取消选中)
  • 动态背景色:数据集的backgroundColor根据selectedIndex动态生成,确保选中项保持红色
  • hover配置:添加hover选项,设置hover时的背景色和边框样式,实现高亮效果
  • 依赖更新:将selectedIndex加入useEffect依赖,确保状态变化时图表重新渲染,应用新的颜色配置

内容的提问来源于stack exchange,提问作者fox_dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:29:51