jimmybow / visdcc

Dash Core Components for Visualization.
MIT License
144 stars 18 forks source link

Window resize event #44

Closed AdrianIssott closed 2 years ago

AdrianIssott commented 2 years ago

Hi,

I'd like to be able to use the window resize event to trigger a dash callback.

I've got close to that with the following:

from dash import Dash, html, dcc
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import visdcc
import pandas as pd

def generate_html_table_from_df(df, id):
    Thead = html.Thead(
        [html.Tr([html.Th(col) for col in df.columns])]
    )
    Tbody = html.Tbody(
        [html.Tr(
            [html.Td( df.iloc[i, j], id = '{}_{}_{}'.format(id, i, j) ) for j in range(len(df.columns))]
         ) for i in range(len(df))]
    )
    return html.Table([Thead, Tbody], id = id, className = "display")

df = pd.DataFrame({'name': ['Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
                            'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
                            'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff'],
                   'age': [18, 71, 14, 56, 22, 28, 15,
                           18, 71, 14, 56, 22, 28, 15,
                           18, 71, 14, 56, 22, 28, 15]}, columns = ['name', 'age'])

external_scripts = ['https://code.jquery.com/jquery-3.3.1.min.js',
                    'https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.js']
external_stylesheets = ['https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.css']

app = Dash(__name__, 
    external_scripts = external_scripts,
    external_stylesheets = external_stylesheets
)

app.layout = html.Div([
    html.Button('Add window event', id = 'button'),
    visdcc.Run_js(id = 'javascript', run = "$('#datatable').DataTable()", event = 'null'),
    html.Br(),
    html.Div(
        generate_html_table_from_df(df, id = 'datatable'), 
        style = {'width': '40%'}
    ),
    html.Div(id = 'output_div')
])

@app.callback(
    Output('javascript', 'run'),
    [Input('button', 'n_clicks')])
def myfun(x): 
    if x is None: return ''
    return '''
    // Copied from https://community.plotly.com/t/accessing-dash-element-props-on-client-side/15798/6
    function findAttribute(object, key) {
        var value;
        var path;
        Object.keys(object).some(function(k) {
            if (k === key) {
                value = object[k];
                path = k + '.' + path
                return true;
            }
            if (k.indexOf('__reactInternalInstance') == -1 //_reacInternal is annoyingly recursive?
                && object[k] 
                && typeof object[k] === 'object' 
                && object.hasOwnProperty(k)) {
                [value, path] = findAttribute(object[k], key);
                if(value !== undefined) {path = k + '.' + path}
                return value !== undefined;
            }
        });

        return [value, path];
    }

    var target = $('#datatable')[0];
    window.addEventListener('resize', function(evt) {
        console.log(evt);
        var dataTableSetter;
        var _unused;
        [dataTableSetter , _unused] = findAttribute(target, 'setProps');
        console.log(dataTableSetter);
        dataTableSetter({
            'event': {'x': window.innerHeight, 'y': window.innerWidth},
        });
    })
    console.log(this)
    '''

@app.callback(
    Output('output_div', 'children'),
    [Input('javascript', 'event')])
def myfun(x): 
    return str(x)

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

I can see in the browser debugger that dataTableSetter ends up calling the dash setProps function. However, it says there are no watched properties so doesn't pass on the event.

I'd also like to be able to do this without using a DataTable. Is that possible?

I'm using:

jimmybow commented 2 years ago

setProps is a prop of react.js Component, so I'm not sure if your method can work. you can just using setProps directly, see the example code https://github.com/jimmybow/visdcc/blob/master/example/Run_js/Add_event_and_callback.py#L53

jimmybow commented 2 years ago

setProps is not a Attribute of your $('#datatable')[0]

AdrianIssott commented 2 years ago

setProps is not a Attribute of your $('#datatable')[0]

Oh! Right yes calling that directly does sort this out, thanks!