Colorful Table | Table Data Visualizer

Enhance table readability with interactive gradient-filled columns. Click on any column to apply a color gradient based on cell values.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Colorful Table | Table Data Visualizer
// @name:zh-CN   彩色表格 | 表格数据可视化
// @description  Enhance table readability with interactive gradient-filled columns. Click on any column to apply a color gradient based on cell values.
// @description:zh-CN  通过渐变填充列来增强表格可读性。点击任何列可根据单元格值应用颜色渐变。
// @namespace    http://tampermonkey.net/
// @version      0.5
// @author       Yearly
// @match        *://*/*
// @icon         data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAwIiBoZWlnaHQ9IjgwMCIgdmlld0JveD0iMCAwIDExIDExIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiM0NEMiIGQ9Ik0wIDBoNHYzSDB6Ii8+PHBhdGggZmlsbD0iIzRDNCIgZD0iTTAgNGg0djNIMHoiLz48cGF0aCBmaWxsPSIjQzQ0IiBkPSJNMCA4aDR2M0gweiIvPjxwYXRoIGZpbGw9IiM0Q0MiIGQ9Ik01IDBoMTF2M0g1eiIvPjxwYXRoIGZpbGw9IiNDQzQiIGQ9Ik01IDRoMTF2M0g1eiIvPjxwYXRoIGZpbGw9IiNDNEMiIGQ9Ik01IDhoMTF2M0g1eiIvPjwvc3ZnPg==
// @grant        none
// @license      GPL-3.0
// ==/UserScript==

(function() {
    'use strict';

    const DEBOUNCE_DELAY = 300;
    const POLL_INTERVAL = 1000;
    const HUE_RANGE = 120;
    const SATURATION = '80%';
    const LIGHTNESS = '88%';

    function extractFirstFloat(str) {
        const match = str.match(/[-+]?\d*\.?\d+/);
        return match ? parseFloat(match[0]) : NaN;
    }

    function applyGradient(table, column) {
        const values = Array.from(table.rows)
            .map(row => row.cells[column])
            .filter(cell => cell)
            .map(cell => extractFirstFloat(cell.textContent || cell.innerText))
            .filter(val => !isNaN(val));

        if (values.length === 0) return;

        const min = Math.min(...values);
        const max = Math.max(...values);
        if (min === max) return;

        const headerCell = table.rows[0]?.cells[column];
        if (!headerCell) return;

        headerCell.gradient_fill_increase = !headerCell.gradient_fill_increase;
        const isIncreasing = headerCell.gradient_fill_increase;

        Array.from(table.rows).forEach(row => {
            const cell = row.cells[column];
            if (!cell) return;

            const value = extractFirstFloat(cell.textContent || cell.innerText);
            if (isNaN(value)) return;

            const hue = isIncreasing
                ? HUE_RANGE - ((value - min) / (max - min)) * HUE_RANGE
                : ((value - min) / (max - min)) * HUE_RANGE;

            cell.style.backgroundColor = `hsl(${hue}, ${SATURATION}, ${LIGHTNESS})`;
        });
    }

    function debounce(func, delay) {
        let timeoutId;
        return function(...args) {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => func.apply(this, args), delay);
        };
    }

    function initializeTable(table) {
        if (table.hasAttribute('data-gradient-initialized')) return;
        table.setAttribute('data-gradient-initialized', 'true');

        table.addEventListener('click', debounce(event => {
            const column = event.target.cellIndex;
            if (column !== undefined) {
                applyGradient(table, column);
            }
        }, DEBOUNCE_DELAY));
    }

    function initializeTables() {
        document.querySelectorAll('table:not([data-gradient-initialized])').forEach(initializeTable);
    }

    // Initial call and setup interval
    initializeTables();
    setInterval(initializeTables, POLL_INTERVAL);
})();