plotly / dash-canvas

An interactive image editing component for Dash
https://dash.plot.ly/canvas
Other
84 stars 26 forks source link

Setting json_data does not render the rectangle in the canvas #46

Open bhashithe opened 4 years ago

bhashithe commented 4 years ago

Hello all!

I am creating an annotation using dash_canvas. I am storing my annotations (the json_data generated by the canvas) in a database, so that later someone could verify them using the dash it self.

So i need to be able to get the data from the database and render the rectangle on the, to this end i have created a callback function with @board.callback(Output('editable', 'json_data'), [Input('url', 'pathname')])

This somehow does not render the rectangle in the image. Anyone has any pointers where i could go with this?

Michael-fore commented 4 years ago

I am having the same issues, working fine with pencil but nothing with the square or circle

Michael-fore commented 4 years ago

I would be willing to try and fix this if anyone can start me off in the right direction

bhashithe commented 4 years ago

I am having the same issues, working fine with pencil but nothing with the square or circle

I did not know that it was working with pencil, let me check on that. Also my javascript, react and canvas knowledge is limited. I might not be able to help in that regard.

Michael-fore commented 4 years ago

parse_jsonstring_line() parse_jsonstring_rectangle()

looks like these are functions in from dash_canvas.utils

i would bet using these would fix the issue

Michael-fore commented 4 years ago

' Up to now only path objects are processed (created with Pencil tool).'

bhashithe commented 4 years ago

I don't know i am understanding this correctly but I am assuming that this cannot be a python issue. Because, rendering the objects in the HTML DOM is taken care of by React. So if we send the correct json_data as the Output then typically it should work, because I am asserting the format of the json_data to be in the correct format.

In that case, i think the JS, React needs to be verified to be working. I do not have a super good grasp on React to actually do it.

Edit: I took some time to look at the JS. Could be the case the my json_data is not in the correct format.

key: "componentDidUpdate",
                    value: function(t) {
                        var e = this,
                            r = this._sketch;
                        if (this.props.image_content !== t.image_content) {
                            var n = new Image,
                                i = this.state.height,
                                o = 1;
                            if (n.onload = function() {
                                    var t = n.height,
                                        a = n.width;
                                    i = Math.round(t * r.props.width / a), o = i / t, e.setState({
                                        height: i
                                    }), r.clear();
                                    var s = {
                                        left: 0,
                                        top: 0,
                                        scale: o
                                    };
                                    r.addImg(e.props.image_content, s)
                                }, n.src = this.props.image_content, this.props.setProps) {
                                var a = JSON.stringify(this._sketch.toJSON());
                                this.props.setProps({
                                    json_data: a
                                })
                            }
                            r._fc.setZoom(this.props.zoom)
                        }
                    }

If someone can point out whats going on with _sketch object i'd be grateful. Looks like it is a SketchField object

christianwengert commented 3 years ago

I do not even get it working with the pencil. Did someone really make this work?

import json

from dash.exceptions import PreventUpdate
from dash_canvas import DashCanvas
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc

filename = 'https://www.publicdomainpictures.net/pictures/60000/nahled/flower-outline-coloring-page.jpg'
canvas_width = 300

app = dash.Dash(__name__)

app.layout = html.Div([
        html.Div([
            dcc.Store(id='store', storage_type='local'),
            html.Button('Load', id='button'),
            DashCanvas(
                id='canvas-color',
                width=canvas_width,
                filename=filename,
                hide_buttons=['line', 'zoom', 'pan'],
                )
                ], className="six columns"),
        ])
@app.callback(Output('store', 'data'),
              [
                  Input('canvas-color', 'json_data')
              ])
def store(x):    
    return json.loads(x)

@app.callback(Output('canvas-color', 'json_data'),
              [
                  Input('button', 'n_clicks')
              ], [
                State('store', 'data')
              ])
def load(x, d):
    if x is None:
        raise PreventUpdate
    return json.dumps(d)

if __name__ == '__main__':
    app.run_server(debug=True)
christianwengert commented 3 years ago

This will do it, use a Graph instead of Canvas

from dash.exceptions import PreventUpdate
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc

app = dash.Dash(__name__)

app.layout = html.Div([
        html.Div([
            dcc.Store(id='store', storage_type='local'),
            html.Button('Load', id='button'),
            dcc.Graph(id='g',),
        ])
    ])

@app.callback(
    Output('store', 'data'),
    [
        Input('g', 'relayoutData')
    ]
)
def store(x):
    if x and 'shapes' in x:
        return x
    raise PreventUpdate

@app.callback(Output('g', 'figure'),
              [
                  Input('button', 'n_clicks')
              ], [
                State('store', 'data')
              ])
def load(x, d):
    import plotly.graph_objects as go

    fig = go.Figure()
    fig.update_layout(dragmode='drawopenpath')

    for s in d.get('shapes', []):
        fig.add_shape(s)

    return fig

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