What's the best way to update HTML elements with processingJs?

ch3ch3
edited June 2016 in JavaScript Mode

I am just about to finish project in processing 2.2.1 Javascript mode, which apart from the canvas itself, has a few html elements (a textarea input and a couple of divs), which needs to be updated by processing. In fact processing also reads back the textarea, so it needs to be a two way interaction.

HTML and native javascript is a little grey area for me, but I did manage to find bits of code here and there to do what I want. Looking at the example from this page (Making your sketch "see" javascript) http://processingjs.org/articles/PomaxGuide.html#jstosketch.html

I started using the bindJavascript method which works locally, but unfortunately breaks when running from the online server (TypeError: pjs.bindJavascript is not a function). I assume I have the various bits of code in the wrong order or something and when the app runs from the server where there may be some delay, javascript fails to bind the function correctly.

Is there maybe a simple way for processingJs to control the HTML dom? Like change the content of a div, style or just some text?

thank you

Answers

  • Answer ✓

    The bindJavascript example code is very clear in terms of the order of dependencies and even includes a timer to wait for everything to be in place; so this doesn't seem likely to be the problem. The example code defines a global bindJavascript function; but the error you report has it attached to pjs. Have you done this deliberately?

  • I understand stating the definition of the javascript functions in processing and then sourcing them in the html, but have to say I don't fully understand how bindJavascript works.

    Regardless, after many hours of scratching my head to why my sketch wasn't running online, I figured that 250 milliseconds were not enough to load all the media on time. The issue is gone by increasing the timer to 1 second.

    thanks

    • Be aware that we can write somewhat write JS code in Pjs.
    • Of course that breaks Java/JS cross-mode compatibility.
    • There are some JS syntax that can fail Pjs' Java to JS transpiler.
    • But most JS syntax can still be accepted by the transpiler.
  • yeah I've noticed. I am loading a javascript library for bigIntegers, so I am already using var here and there, which I am sure doesn't run in java mode.

    It's been a little bit of a struggle to get my head around the mixture of the two, especially since I wasn't as familiar with javascript.

    But I am getting really close to the end of this rather long project for which I am very excited and thank you for all the help over the past few months. Hopefully soon enough, I will be sharing it with all you! =]

  • @ch3 said:

    I figured that 250 milliseconds were not enough to load all the media on time.

    Ouch! :-O

    Must admit I only scanned the example code and hadn't spotted that it was a setTimeout: it's not best practice to simply set an arbitrary pause like that. Instead the script should be using setInterval; continue checking repeatedly until everything is in place and then deleting the setInterval instance.

    Extending the delay to 1 second could still lead to errors for users on slow connections and also means some users will wait longer than necessary.

  • yeah you are right. Maybe I should attempt to re-write this part with a while(not loaded) loop or something.

  • OK - I have to eat my words a bit here. Looking again (more thoroughly) at the setTimeout example code it's essentially a 'recursive' function that should continue looping until pjs is populated (i.e. loaded and parsed):

    var bound = false;
    
       function bindJavascript() {
         var pjs = Processing.getInstanceById('mysketch3');
         if(pjs!=null) {
           pjs.bindJavascript(this);
           bound = true;
         }
         // whilst pjs is not populated continue to run bindJavascript
         if(!bound) setTimeout(bindJavascript, 250);
       }
    
    bindJavascript();
    

    setInterval is still far more elegant in this situation (untested but should be right):

    var loopUntilLoaded = setInterval(function() {
            if(pjs != null) {
               pjs.bindJavascript(this);
               clearInterval(loopUntilLoaded);
             }
    }, 250);
    

    Are you loading any other resources with your sketch? It may be that by extending the delay to 1 second you've given the browser time to load those as well... IIRC there might be some additional steps you have to take to ensure pre-loading of things such as images in PJS; and you've simply found a crude workaround to that issue :/

    TBH it's very hard to debug such issues without being able to test against actual code :(|)

  • Yeah it looks like it's meant to work as a recursive function, but looking at the numbers I'm printing out, I can't get it to run more than twice and it fails. I am still a little confused to whether this function runs from the javaScript or the processing side of the sketch.

    It's a little hard to isolate the problem to just a bit of code, so here is the whole lot in case you are willing to take a closer look. If the processing to javascript bridge works, you should see a very long number at the grey textarea below the canvas.

    You can run the work in progress here: http://pub.ch3.gr/js/imgGen/

    ...and download the project : http://pub.ch3.gr/js/imgGen/imgGen.zip

  • @ch3 - haven't had time to check your code but have you read: Processing.js has to cheat to simulate Processing's synchronous I/O. I have a feeling that this is your issue...

  • yeah, I am already pre-loading the images. I will take another look to this document though, it may have more valuable info

  • I went through a major redesign and migrated all the UI stuff into native html5 buttons, slider etc so I can have it working on touch screens and as well as having a more responsive web design. (A bit sad, as I had spend hours to make all these fully functional buttons, switches and sliders)

    After clearing up loads of unwanted code, I ended up removing the entire bindJavascript() function and call from both sides. Suprizingly my project still works both ways, without the use of that binding setup.

    Just to exmplain how it runs at the moment. In the html template, I source a bind.js file, where I have all the function calls between the two.

    // Processing to HTML
    
    function HUI_updateImgInfo( inStep, inX, inY, inCd, inLimit )
    {
        document.getElementById('stepSize').innerHTML = inStep;
        document.getElementById('xSize').innerHTML = inX;
        document.getElementById('ySize').innerHTML = inY;
        document.getElementById('cDepth').innerHTML = inCd;
        document.getElementById('limit').innerHTML = inLimit;
    }
    
    ...
    
    
    // HTML JS to Processing
    
    function processingSetId( value )
    {
        Processing.getInstanceById("imgGen").setIdFromTextField(value);
    }
    
    ...
    

    In the processing sketch I run the relevant JS functions to update the html DOM in this way: HUI_updateId( aNumber );

    ...and from the HTML side I have buttons and sliders with the onclick or onchange attribute set to something like this:

    processingSetId(this.value);

    I tried it to run it both locally, on the webserver and through my smartphone as well and it seems to run just fine. Do you see any problem with this arrangment?

    http://pub.ch3.gr/js/imgGen3/

Sign In or Register to comment.