plotly / dash-table

OBSOLETE: now part of https://github.com/plotly/dash
https://dash.plotly.com
MIT License
420 stars 74 forks source link

Highlighting current cell (or row) with fixed_columns #871

Open bjonen opened 3 years ago

bjonen commented 3 years ago

My goal is to highlight the row of the datatable the user is currently hovering over. On a standard dash table without fixed columns this can easily be achieved with css.

Dash-table however implements tables with fixed columns by using two separate tables (each with phantom cells where the other is active). To highlight an active row (to my knowledge) one has to resort to javascript to select all relevant tds and change their properties.

While the implementation in JS is relatively simple, there is significant lag which makes this workaround unusable at the moment. During my analysis I made the following observations:

1) This lag happens also when one only highlights the current row using JS.
2) The lag disappears on smaller tables. 3) The lag disappears completely when turning off fixed_columns!! 4) Chrome performance analysis indicates that 50% of the time is spent in this function https://github.com/plotly/dash-table/blob/e76790886cf38df654dba1ef3bfe7011785f01f2/src/dash-table/components/ControlledTable/index.tsx#L339

As the problem also happens when highlighting only one cell I am sure that it is not the selector that is taking the time. Below I provide a minimal example of highlighting one cell on a table with 2 fixed columns.

To run the minimal example:

Let me know if I can provide any further information.

System: dash_table: 4.11.2 Google Chrome on Mac OSX

app.py

import dash
import dash_table
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
df = pd.concat([df]*20)

app = dash.Dash(__name__)

app.layout = dash_table.DataTable(
    id='table',
    columns=[{"name": i, "id": i} for i in df.columns],
    data=df.to_dict('records'),
    fixed_columns={'headers': True, 'data': 2},
)

if __name__ == '__main__':
    app.run_server(debug=True)

assets/myjs.js

var add_listener_to_tds = function() {
    const selector = `.cell-table tbody tr`;
    const rows = document.querySelectorAll(selector);

    var set_style_enter = function() {
        this.classList.add('current-row')
    }

    var set_style_exit = function() {
        this.classList.remove('current-row')
    }

    console.log('all rows', rows)
    for(i = 0; i < rows.length; i++){
        var ele = rows[i];
        const tds = ele.querySelectorAll('td')
        for (j = 0; j < tds.length; j++){  // loop over tds
            var td = tds[j]
            td.addEventListener('mouseenter', set_style_enter, false)
            td.addEventListener('mouseleave', set_style_exit, false)
            td.classList.remove('current-row')
        }
    }
};

assets/mycss.css

.current-row {
    background-color: rgb(218, 230, 247) !important;
    transition: transform 0.1s linear !important;
}