Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow HTMLView to communicate back to server #727

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

tcstewar
Copy link
Collaborator

The HTMLView component is very useful for making all sorts of arbitrary display things. It'd be kinda nice if it could also be used to make arbitrary input systems. That is, to be able to catch mouse events (or whatever else) that happen in the HTMLView component and pass those back to the server.

I implemented a quick prototype that only required adding 4 lines to nengo_gui. All it does is allow the javascript to send messages back to the python code. For example, here's an HTMLView Node that lets you click on it, and it'll use that as a 2D value that is the output of the Node:

import nengo

model = nengo.Network()
with model:

    def input_function(t):
        pos = getattr(input_function, '_nengo_message_', None)
        if pos is None:
            pos = [0, 0]
        else:
            pos = [float(x)/100 for x in pos.split(',')]
        pos[1] = -pos[1]

        script = '''
            var pt = this.createSVGPoint();
            pt.x = event.clientX;
            pt.y = event.clientY;
            var loc = pt.matrixTransform(this.getScreenCTM().inverse());
            this.parentNode.ws.send('' + loc.x + ',' + loc.y);
        '''

        cx = pos[0]*100
        cy = -pos[1]*100

        input_function._nengo_html_ = '''
        <svg width="100%" height="100%" viewbox="-100 -100 200 200"
onmousedown="{script}">
            <circle cx={cx} cy={cy} r=5 stroke="black"/>
        </svg>
        '''.format(**locals())

        return pos

    control = nengo.Node(input_function)
    ens = nengo.Ensemble(100, 2)
    nengo.Connection(control, ens)

The first addition is adding the WebSocket ws to the parentNode of the HTMLView div, which allows the this.parentNode.ws.send() call to send arbitrary information back to the server. The second addition is catching that message on the server side and assigning it to the _nengo_message_ variable, so that pos = getattr(input_function, '_nengo_message_', None) will work.

So, overall, I was happy that this basic functionality can happen with such a small change. I'd like to keep this functionality fairly bare-bones, leaving it up to the individual to implement more complex things (for example, in the above example, I might want to hook into the onmouseevent instead of onmousedown, or I might want to do a completely different transform on the javascript side). But it might be nice to have some common transformations made a bit easier with helper functions.

In any case, I'm mostly going to leave this PR here as it is until we get a few more examples of people using it, and see what sort of polishing might be appropriate.

@studywolf
Copy link
Contributor

super cool! can't wait to play around with this!

@tcstewar
Copy link
Collaborator Author

Note to anyone playing around with this: the above code is Chrome-specific. I need to sort out a different way to get the event object in Firefox... sigh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants