frangoteam / FUXA

Web-based Process Visualization (SCADA/HMI/Dashboard) software
https://frangoteam.org
MIT License
2.79k stars 817 forks source link

User Defined Global Color Pallets #1438

Open robbudge opened 1 week ago

robbudge commented 1 week ago

Describe the feature User Specified Line & Fill colour tables, when configuring the colour options on most items, the user manually sets each colour per value manually. often utilizing the same pallet in multiple objects.

Describe the solution you'd like in the settings page have the option to declare colour pallets, linking a Line & Fill colour to a value, Basically the same as the object properly page.

Then on the object property page, the options of manual (Existing Configuration) or pallet, where only the value and pallet would need to be selected.

this way a global colour change could be performed by modifying the pallet. for example a safe condition (Closed / OFF) could be quickly changed from Red to Green determining on the Standard.

robbudge commented 5 days ago

for anyone utilizing widgets, it is possible to use global colour pallets by using 'Custom Styles' under layout. Custom styles allows editing or adding to the pages css.

my example in Custom Styles I added

:root { --di_state: '#fffff0ff', '#fffff1cc', '#fffff288', '#fffff344', '#fffff400', '#ffffff00', '#92d05040', '#ffffff00', '#ff000040', '#ffff0040';

--ait_state: '#C6E0B4ff', '#FFD4D4ff', '#FFE699ff', '#FFE699ff', '#FFD4D4ff', '#000000ff', '#d9d9d9ff', '#d9d9d9ff', '#ff0000ff', '#ff0000ff', '#000000ff', '#3399FFff', '#ff0000ff';

--valve_state: '#FFD4D4d4', '#D4FFD4d4', '#ff0000ff', '#92D050ff', '#7DFF00ff', '#FF7D00ff', '#E7E6E640', '#E7E6E640', '#000000ff', '#ff0000ff', '#ff0000ff', '#ff0000ff', '#000000ff', '#3399FFff', '#3399FFff', '#3399FFff', '#FFFF00ff', '#ED7D31ff', '#954ECAd4';

--lock_state: '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#ff0000ff', '#ffff00ff', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000', '#00000000';

--mode: '#d4d4d400', '#C00000d4', '#70AD47d4', '#3399FFd4', '#3399FFd4', '#3399FFd4', '#70AD47d4';

}

the widget contains shapes with ID's of mode,status and lock. the widget script obtains the colour code and opacity from the css data

let stateColor =[];
let stateOpacity=[];
let modeColor =[];
let modeOpacity=[];
let lockColor =[];
let lockOpacity=[];
  //!export-start
    let _pn_mode      = 0;
    let _pn_status  = 0;
//!export-end
 // Send Variables To Fuxa
function postValue(id, value) {
  console.error('Not defined!');
}

  function putValue(id, value) {
  if (id === '_pn_mode') _pn_mode   = value;
  if (id === '_pn_status') _pn_status   = value;
    update();
}

  function update(){
    if (_pn_status < 0 || _pn_status >= stateColor.length) {
        console.error(`Invalid status: ${_pn_status}. Out of bounds.`);
        return; // Exit the function if out of bounds
    }
        //console.log('State:',_pn_status,', Color:',stateColor[_pn_status],', opacity:',stateOpacity[_pn_status]);
        let status = document.getElementById("status");
        status.style.fill=stateColor[_pn_status];
        status.style.opacity=stateOpacity[_pn_status];

        let lock = document.getElementById("lock");
        lock.style.fill=lockColor[_pn_status];
        lock.style.opacity=lockOpacity[_pn_status];

    if (_pn_mode < 0 || _pn_mode >= modeColor.length) {
        console.error(`Invalid mode: ${_pn_mode}. Out of bounds.`);
        return; // Exit the function if out of bounds
    }
        //console.log('mode:',_pn_mode,', Color:',modeColor[_pn_mode],', opacity:',modeOpacity[_pn_mode]);
        let mode = document.getElementById("mode");
        mode.style.fill=modeColor[_pn_mode];
        mode.style.opacity=modeOpacity[_pn_mode];
  }
function getColors(cssVar, colorArray, opacityArray) {
    // Get the raw colors from the specified CSS variable
    //console.log('Obtaining css Colors for ',cssVar);
    const rawColors = getComputedStyle(document.documentElement)
        .getPropertyValue(cssVar)
        .trim();
    //console.log('RawData:',rawColors);
    if (!rawColors) {
        console.error(`CSS variable ${cssVar} is not defined or empty.`);
        return;
    }

    // Split by commas with optional spaces and clean single quotes
    const entries = rawColors
        .split(/\s*,\s*/)
        .map(entry => entry.replace(/^'|'$/g, '').trim());

    // Parse each entry and extract RGB + opacity
    entries.forEach(entry => {
        if (entry.length !== 9) {
            console.error(`Invalid color format: ${entry}`);
            return; // Skip invalid entries
        }

        const rgb = entry.slice(0, 7); // First 7 chars for #RRGGBB
        //console.log('RGB Codes:',rgb);
        const alphaHex = entry.slice(7, 9); // Last 2 chars for opacity (AA)
        const opacity = parseInt(alphaHex, 16) / 255; // Convert to 0-1.0 range

        colorArray.push(rgb);
        opacityArray.push(opacity);
    });
}

    function init() {
        _pn_status=0;
        _ps_mode=0;
        getColors('--mode', modeColor, modeOpacity);
        getColors('--valve_state', stateColor, stateOpacity);
        getColors('--lock_state', lockColor, lockOpacity);
        update();
    }

    init();

this now allows us to change colours as per request from the custom css data. Every site / system appears to require slight different colour codes for various status.