Examples of what I'd like to see (in order of presumed complexity):
Initiated from JavaScript:
1) read value from JavaScript of NetLogo global variable
2) click button in NetLogo from JavaScript
3) set value of slider in NetLogo from JavaScript
Initiated from NetLogo:
1) update a JavaScript variable when a NetLogo variable is changed
2) update a JavaScript array when a new value is added to a NetLogo list
I suspect that communication initiated in NetLogo and sending data to JavaScript may not be possible now.
What I'd like to be able to do is take data being displayed in a NetLogo grapher and display it in a JavaScript grapher.
Here's are a couple of example of html5 based grapher that I'd like to adapt for this purpose:
http://bl.ocks.org/1182434
http://lab.dev.concord.org/examples/surface-temperature/surface-temperature.html
I'd also like to be able to reset, start, and stop the model from JavaScript.
The way that I've done this is to create a class that extends JApplet,
have it embed an org.nlogo.lite.AppletPanel, and mimic the startup stuff that the org.nlogo.lite.Applet does
Have this class expose some public methods that give pass-through access to AppletPanel's
report() and command()
functions
through liveconnect, this will give you 1 and 3, and could give you the EFFECT of 2, though not for a 'forever' button.
i haven't needed the other direction yet myself, but i think that it could work to create a kind of listener construct in your Applet, and then pass on events that you can get by implementing org.nlogo.api.NetLogoListener and registering for events.
i can send you code for the javascript-to-java direction, but it's all been rather sketchy experimental stuff and i'm not sure it is robust.
best,
--c
Corey,
I thought I might be able to read the value of a NetLogo global variable just using liveconnect -- but haven't tried yet.
I would love to look at your code if it's available under an open source license.
i will make a github project and let you know when it's set up
btw -- i made this sketch in the course of thinking about how to make a WISE4 "step" based on a netlogo applet. i know you and others at concord have done a bunch of work with WISE so maybe there's some possible teaming up there...
in that context, i wanted some scriptable interactions, but also wanted to be able to save the state ( so, you'll see a sketch of doing export-world to a string that will then be read by javascript...
more soon,
-c
Stephen> Initiated from NetLogo:
Stephen> 1) update a JavaScript variable when a NetLogo variable is
Stephen> changed 2) update a JavaScript array when a new value is added
Stephen> to a NetLogo list
Stephen> I suspect that communication initiated in NetLogo and sending
Stephen> data to JavaScript may not be possible now.
The solution plan Corey describes seems to me like it would work.
Another approach would be to make an extension. The disadvantage is
that code in the model would have to explicitly call the extension
primitives, rather than communication being automatically triggered by
button presses and variable changes and so forth. But it might be
easier to get this way up and running since it wouldn't require making a
custom NetLogo jar, just an ordinary extension.
--
Seth Tisue | Northwestern University | http://tisue.net
lead developer, NetLogo: http://ccl.northwestern.edu/netlogo/
I'm looking at this code at the beginning of org.nlogo.lite.Applet and wondering if I can get access to the panel property and from this get access to global variables in the workspace?
I presume the answer is no (otherwise you and Corey might have mentioned it).
In OTrunk we embed an nlogo.lite.interface.component which gives us much more access to the internals.
public class Applet extends JApplet
implements Events.CompiledEvent.Handler, ScalaObject
{
private AppletPanel panel;
public void init()
{
VMCheck.detectBadJVMs();
EventQueue..MODULE$.invokeLater(new Runnable() {
public void run() { Applet.this.init2(); null; Applet.this.go(null); }
});
}
public void destroy() {
RuntimeErrorDialog.deactivate();
}
public AppletPanel panel() {
return this.panel; }
public void panel_$eq(AppletPanel paramAppletPanel) { this.panel = paramAppletPanel; }
if memory serves me right, my original reason for re-producing the Applet's structure in my JApplet was that I thought that the panel member variable was not visible to me as a subclass.
HOWEVER, i think that either this has changed since then (maybe even, been converted to scala?) or i didn't understand how scala worked.
TODAY when i make a subclass of Applet against the 5.0 jar, eclipse tells me that panel is not visible, BUT if i do
this.panel(),
i do get an instance of AppletPanel, as i'd hoped.
this doesn't completely solve the problem, as i can't call all of the methods on this AppletPanel that i think i should be able to.
that is, even though i am able to call report()
https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L178
on this instance, i cannot call
command()
https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L143
or
commandLater()
https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L159
Seth --- can you illuminate?
Thanks!
-c
--c
Stephen> I'm looking at this code at the beginning of
Stephen> org.nlogo.lite.Applet and wondering if I can get access to the
Stephen> panel property and from this get access to global variables in
Stephen> the workspace?
It looks you have an old version. In 5.0 it's public. In the Scala
code we have:
class Applet extends JApplet ... {
var panel: AppletPanel ...
public is the default access level in Scala.
And, javap shows:
% javap -classpath /Applications/NetLogo\ 5.0/NetLogo.jar org.nlogo.lite.Applet | grep -w panel
public org.nlogo.lite.AppletPanel panel();
Corey> TODAY when i make a subclass of Applet against the 5.0 jar,
Corey> eclipse tells me that panel is not visible, BUT if i do
Corey> this.panel(),
The field itself is private, the getter method is public. So you need
the parens. (The Scala compiler only ever generates private fields.)
Corey> this doesn't completely solve the problem, as i can't call all
Corey> of the methods on this AppletPanel that i think i should be able
Corey> to.
Corey> that is, even though i am able to call report()
Corey> https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L178
Corey> on this instance, i cannot call
Corey> command()
Corey> https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L143
Corey> or commandLater()
Corey> https://github.com/NetLogo/NetLogo/blob/master/src/main/org/nlogo/lite/AppletPanel.scala#L159
Corey> Seth --- can you illuminate?
Sorry, not sure what's going on here. Maybe you could show your code
and the error message you're getting? Maybe try compiling the code
from the command line instead of through Eclipse?
The methods certainly exist:
% javap -classpath /Applications/NetLogo\ 5.0/NetLogo.jar org.nlogo.lite.AppletPanel | grep report
public java.lang.Object report(java.lang.String) throws org.nlogo.api.CompilerException;
% javap -classpath /Applications/NetLogo\ 5.0/NetLogo.jar org.nlogo.lite.AppletPanel | grep command
public void command(java.lang.String) throws org.nlogo.api.CompilerException;
public void commandLater(java.lang.String) throws org.nlogo.api.CompilerException;
>>>>> "Stephen" == Stephen Bannasch <stephen....@deanbrook.org>writes:
Stephen> I'm looking at this code at the beginning of
Stephen> org.nlogo.lite.Applet and wondering if I can get access to the
Stephen> panel property and from this get access to global variables in
Stephen> the workspace?
It looks you have an old version.
Stephen> I was looking directly at the code using the JD-GUI Java
Stephen> decompiler in this jar distributed with NetLogo 5.0:
It just dawned on me what's going on here.
You and Corey are looking at NetLogoLite.jar, I (as the transcripts I
posted show) am looking at NetLogo.jar.
NetLogoLite.jar has been through ProGuard to make it smaller. All sorts
of stuff gets stripped out when that happens. ProGuard doesn't just
remove whole unused classes, it removes individual unused methods, too.
While you're just trying to get something up and running, I'd suggest
you just use NetLogo.jar. It always includes everything.
Later, if you need to actually ship your thing to lots of users and you
care about jar size in that context, well, one of us could update the
ProGuard config so that it produces a NetLogoLite.jar that has the
particular thing you need. That config is in
https://github.com/NetLogo/NetLogo/blob/master/project/build/proguard/lite.txt
Hope that clears this up,
NOW --> Stephen, your idea (extending org.nlogo.lite.Applet) is much better than what I had done before.
So I'm going to switch over to doing that.
That will take out most of my code, actually :) but if there's anything interesting left, I'll still start a github repo for it.
Best,
-c
There's not much of interest here, but I've created a repo:
g...@github.com:cbradyatinquire/NetLogoAppletLiveConnect.git
The simple subclass of org.nlogo.lite.Applet is there, along with an HTML page that uses it.
(possibly most valuable for a copy-pasteable list of the .jars that NetLogo.jar references -- some of these are surely omissible but i just referenced them all :) )
-C
Cool, I got it working locally.
I added a shell script to build the wisenetlogo.jar, simplified the applet jar requirements to run (only the NetLogo jar isrequired).
I added the NetLogo and scala-library jars to the repo. This is annoying because they are large but this also makes this repo self-contained. The compilation and testing the example can now all be done with the resources in the repo.
I only needed to specify a class path to the NetLogo jar to compile -- but without the scala-library jar also available there were compilation errors.
These changes are available in a pull request.
Combined the NetLogo and scala-library jars are over 14MB uncompressed. This is way too big to deploy to classrooms in any
scale.
Hi Seth,
Is there a way I can make a new version of the netlog lite jar that I can use practically as when running netlogo as an applet?
Or is that something I need to rely on you doing sometime in the future? If this is the case do any of your funded projectshavethis as a goal? And if this is also true do you have any sense of a timeline?
Yes. Assuming you can build NetLogo, then:
emacs project/build/proguard/lite.txt
# make your edits, forcing whatever methods you want kept to be kept
rm NetLogoLite.jar
make NetLogoLite.jar
This will re-run ProGuard with your new config.
Optional final step: send pull request.
> do any of your funded projectshavethis as a goal? And if this is also true do you have any sense of a timeline?
Yes, if you do nothing it will probably happen here anyway eventually.
No, not one I'd want you counting on.
Here's an example where I am saving and restoring model state from an applet running using JUST an un-modified NetLogoLite.jar.
https://github.com/stepheneb/netlogo-gcc
I'm using one of Bob's latest Global Climate change models.
See: https://github.com/stepheneb/netlogo-gcc/blob/master/netlogo.html#L46-70
Actually ... saving the state works ... but restoring the state doesn't yet. it's probably just errors in my use of Java,
which I'm not completely familiar with.
I'm trying to access the world.importWorld() function with this signature:
public strictfp void importWorld(Importer.ErrorHandler paramErrorHandler,
ImporterUser paramImporterUser, Importer.StringReader paramStringReader,
BufferedReader paramBufferedReader)
I'm getting these errors:
Uncaught Error: java.lang.IllegalArgumentException: No method found
matching name importWorld and arguments
[com.sun.java.browser.plugin2.liveconnect.v1.JavaNameSpace,
com.sun.java.browser.plugin2.liveconnect.v1.JavaNameSpace, java.io.StringReader,
com.sun.java.browser.plugin2.liveconnect.v1.JavaNameSpace]
Uncaught Error: Error calling method on NPObject.
Once we get saving and restoring the state working properly I'd like to know how to click buttons and set the slider from
JavaScript.
Then I'd like to know how to read a NetLogo variable from JavaScript.
...
>Once we get saving and restoring the state working properly I'd like to know how to click buttons and set the slider from JavaScript.
>
>Then I'd like to know how to read a NetLogo variable from JavaScript.
For example when I get the state of the World there are a series of GLOBALS:
min-pxcor -24
max-pxcor 24
min-pycor -15
max-pycor 15
perspective 0
subject nobody
nextIndex 57
directed-links ""NEITHER""
ticks 0
albedo 0.4
earth-top -7
model_speed 17
num-clouds 0
num-co2 0
sky-top 10
starter 0
sun-brightness 1.2
temperature 12"
I can read world.maxPxcor():
$ world = applet.panel().workspace().org$nlogo$lite$LiteWorkspace$$world;
$ world.maxPxcor()
=> 24
But that's using a method.
How can I for example read the value of "temperature" or "albedo"?
>> Here's an example where I am saving and restoring model state from
>> an applet running using JUST an un-modified NetLogoLite.jar.
Note that for this to work on a server, you'll need
NetLogoLite.jar.pack.gz as well. As a bonus, this will greatly speed
loading. See <https://github.com/NetLogo/NetLogo/issues/95>
Stephen> For example when I get the state of the World there are a
Stephen> series of GLOBALS: [...]
Stephen> How can I for example read the value of "temperature" or
Stephen> "albedo"?
Here's a Scala REPL session demonstrating the needed calls:
% cd /Applications/NetLogo\ 5.0
% scala -Yrepl-sync -Djava.awt.headless=true -classpath NetLogo.jar
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
scala> import org.nlogo.headless.HeadlessWorkspace
import org.nlogo.headless.HeadlessWorkspace
scala> val ws = HeadlessWorkspace.newInstance
ws: org.nlogo.headless.HeadlessWorkspace = org.nlogo.headless.HeadlessWorkspace@3522971b
scala> ws.open("models/Sample Models/Earth Science/Climate Change.nlogo")
scala> val globals = ws.world.program.globals
globals: java.util.List[String] = [SUN-BRIGHTNESS, ALBEDO, SKY-TOP, EARTH-TOP, TEMPERATURE]
scala> ws.command("setup")
scala> ws.world.observer.getVariable(globals.indexOf("ALBEDO"))
res8: java.lang.Object = 0.6
scala> ws.world.observer.getVariable(globals.indexOf("TEMPERATURE"))
res9: java.lang.Object = 12.0
scala> ws.world.observer.variables
res4: Array[java.lang.Object] = Array(1.0, 0.6, 17.0, 0.0, 12.0)
Stephen> I'm trying to access the world.importWorld() function with
Stephen> this signature:
Stephen> public strictfp void importWorld(Importer.ErrorHandler
Stephen> paramErrorHandler, ImporterUser paramImporterUser,
Stephen> Importer.StringReader paramStringReader, BufferedReader
Stephen> paramBufferedReader)
It's a lot easier to use the importWorld method on Workspace, which
takes many fewer parameters. There's one version that reads from
the filesystem, which you don't want; instead, use:
void importWorld(java.io.Reader reader)
throws java.io.IOException;
It should work to stuff your string into a java.io.StringReader which
you then pass in.
Stephen> Once we get saving and restoring the state working properly
Stephen> I'd like to know how to click buttons and set the slider from
Stephen> JavaScript.
Setting the variable associated with a slider will move the slider.
Do you actually need to press a button, so the user will see it being
pressed, or do you just need to run the same code that a button press
would run? The latter is easy, just run e.g. commands("setup") on the
workspace. If you need the actual button to go down, that's also
possible; let me know.
>>>>> "Stephen" == Stephen Bannasch <stephen....@deanbrook.org>writes:
Stephen> I'm trying to access the world.importWorld() function with
Stephen> this signature:
Stephen> public strictfp void importWorld(Importer.ErrorHandler
Stephen> paramErrorHandler, ImporterUser paramImporterUser,
Stephen> Importer.StringReader paramStringReader, BufferedReader
Stephen> paramBufferedReader)
It's a lot easier to use the importWorld method on Workspace, which
takes many fewer parameters. There's one version that reads from
the filesystem, which you don't want; instead, use:
void importWorld(java.io.Reader reader)
throws java.io.IOException;
It should work to stuff your string into a java.io.StringReader which
you then pass in.
I have a LiteWorkspace object in JavaScript and can get globals with it by going through it's world property:
nl_world = nl_workspace.org$nlogo$lite$LiteWorkspace$$world;
nl_observer = nl_world.observer();
nl_globals.get(3)
=> "TEMPERATURE"
nl_observer.getVariable(3)
=> 12
>scala> ws.command("setup")
But my LiteWorkspace object has no method "command":
nl_workspace.command("setup")
=> TypeError: Object org.nlogo.lite.LiteWorkspace@7bceb175 has no method 'command'
I was going to try that soon -- am first seeing just how far I can get without doing that.
I've been able to get much more working with the existing NetLogoLite jar than I thought at first. If I don't have to update itthen deploying externally would be much easier.
But it may well be that I've hit a hard limit now enforced by the Proguard stripping patterns.
Stephen> I've been able to get much more working with the existing
Stephen> NetLogoLite jar than I thought at first. If I don't have to
Stephen> update itthen deploying externally would be much easier.
In the short term, yes. In the longer term, we'd include your ProGuard
config changes in the official jar in some 5.0.x release so you wouldn't
need to go on using a custom jar.
Stephen> Which is why I was trying to use this more complex form
Stephen> ... but I'm pretty sure that errorHandler, importerUser, and
Stephen> bufferedReader are supposed to be instances of those classes,
Stephen> not the classes themselves. I'm not certain how to make them.
Stephen> var errorHandler =
Stephen> applet.Packages.org.nlogo.api.ImportErrorHandler; var
Stephen> importerUser = applet.Packages.org.nlogo.api.ImporterUser; var
Stephen> bufferedReader = applet.Packages.java.io.BufferedReader; var
Stephen> sr = new applet.Packages.java.io.StringReader(nl_state);
Stephen> nl_world.importWorld(errorHandler, importerUser, sr,
Stephen> bufferedReader);
This path you're trying to go down is a difficult one, and unnecessary.
There is no straightforward way to fill in all these arguments yourself.
It would be a lot easier to just edit the ProGuard config and build a
new lite jar that includes the methods you need.
<P1101778B.png>
That worked!
I tried this as a command to start the model running -- but it basically locks up the applet (and the browser somehwat):
nl_panel.command("loop [ execute]");
The model starts running but I can't stop it.
I have a similar problem if I add the following to the model:
to start-running
loop [ execute ]
end
If I call that from JavaScript I both don't get control back in the browser AND the model doesn't start.
If I execute: start-running in the NetLogop application command center the model starts running but them I can't stop it.
--------
Separately an error is generated if a model is running and I try and restore the state ... so I'd like to be able to tell if a model is running and stop it if it is.
Here are some basic commands/operations I'd like to know how to do.
- Is the model running?
- Is the model stopped?
- Start the model running continuously.
I found this variety of suggestions for how to make a model keep runnning but none of them seem to apply:
Stephen> Here are some basic commands/operations I'd like to know how
Stephen> to do.
Stephen> - Is the model running? - Is the model stopped? - Start the
Stephen> model running continuously.
Stephen> I tried this as a command to start the model running -- but it
Stephen> basically locks up the applet (and the browser somehwat):
Stephen> nl_panel.command("loop [ execute]");
Stephen> The model starts running but I can't stop it.
Sounds like you want the commandLater() method instead of command().
commandLater "runs NetLogo commands in the background. Returns
immediately, without waiting for the commands to finish."
If you add a global variable to your model named "done?", then you could
do something like:
nl_panel.commandLater(
"set done? false while [not done?] [ execute ]")
Then if you want it stop after the current time through the loop
finishes, nl_panel.command/commandLater("set done? true").
There's also a "halt" method on workspace, but you usually won't want to
use that because it stops running code in its tracks, rather than waiting
for the current iteration to finish.
To answer "Is the model stopped?", you could use the anyPrimaryJobs
method on JobManager; a jobManager field is public in AbstractWorkspace.
"Primary" jobs are pieces of running NetLogo code not associated with
monitors (monitor jobs are "secondary" and remain active as long as
the monitor exists).
Anyway, all of the above is the approach I'd suggest if you *don't* plan
to make the "setup" and "go" buttons in the actual model visible to the
user, because you want to control the model entirely from JavaScript.
Is that the path you're on...?
You may be able to borrow previously used solutions from Concord's
previous work with embedding InterfaceComponent within OTrunk. Applet
and InterfaceComponent both inherit from AppletPanel, so many of the
available methods are the same.
Unfortunately some methods exist only in InterfaceComponent even though,
there's no good reason they aren't on AppletPanel instead. For example,
another solution plan would be to leave the "setup" and "go" buttons in
the model interface, and then arrange to actually click on buttons from
JavaScript, just as if the user had pressed them herself.
InterfaceComponent has a pressButton() method for this; you just pass it
the button name, which should be unique. But you're not using
InterfaceComponent, you're using Applet/AppletPanel. So to get the
pressButton method, you have some choices:
1) Move it from InterfaceComponent to AppletPanel yourself and make yourself a
new jar.
2) Ask us to move it, and as many other methods as we can, to
AppletPanel, and make a new jar for you.
If you find InterfaceComponent has methods AppletPanel lacks, feel free
to fool around with (1) in the short term -- it will probably actually
be easy in most cases -- but if you run into any trouble, (2) is
probably something that should happen anyway and we may need it
ourselves on our ABM+ grant, so that's better in the long run.
Stephen> 2) Testing:
Stephen> Mac OS X 10.6.8:
Stephen> It works on Chrome and Safari on my Mac. The applet fails to
Stephen> load/display properly on FF.
Stephen> This is what the applet looks like FF on both Mac OS X and
Stephen> Windows 7: [...]
In the past, a display like this where nothing shows but the sideways
NetLogo banner has sometimes indicated that the applet just needs to be
made a little larger.
However, given that you're on Mac OS X 10.6, that might not be the
problem here. Are you familiar with "Plugin 1" and "Plugin 2" on Mac OS
X? If I recall the history correctly, Firefox switched to "Plugin 2"
before the other browsers did, and before the new plugin was good enough
quality to run NetLogo applets. Apple continued to improve Plugin 2 on
Mac OS X 10.7, but 10.6 remained stuck with an old, substandard version.
My guess is that if you try it on Firefox on a Mac OS X 10.7 system that
is up-to-date with Software Update, you'll find that it works. Firefox
on 10.6 might be a lost cause.
I'm not entirely surely I'm remembering this history exactly right, but
if you're having trouble, it's a line of inquiry to pursue, anyway.
Nathan Kimball might know more about the browser differences; see e.g.
<http://groups.yahoo.com/group/netlogo-users/message/13402>
Thanks for that suggestion. I just got the JS buttons working so when I removed the buttons in the model and tightened up the layout I saw this happening when I made the width and height properties on the applet element too small.
Now the example works in FF!
http://stepheneb.github.com/netlogo-gcc/index.html
At 9:33 PM -0500 3/6/12, Seth Tisue wrote:
>Anyway, all of the above is the approach I'd suggest if you *don't* plan
>to make the "setup" and "go" buttons in the actual model visible to the
>user, because you want to control the model entirely from JavaScript.
>Is that the path you're on...?
Yes.
Next I'm going to wire the Temperature Global variable in the NL model to the grapher.
Besides having the ability to style and layout the buttons nicely one of the other reason for being able to control the NL model from the browser is that there are many cases where the action of STARTING a model has important secondary effects.
For example for VISUAL I'm going to graph the temperature data from this model in the JS grapher. But we also want studentsto be able to collect multiple model runs. If a student has just collected 20s of a model run and then pressed the "Reset" button the browser needs to know this in order to save (or give the user the option of saving) the data that was justcollected.
NetLogo is not currently written to be able to notify JavaScript functions in the browser when events like this happen in the Java applet context.
And ... while we've solved these problems with the sensor applet -- it was difficult and fraught -- and my judgement is that this area of communication is fragile. Sometimes things get broken with browser updates because it's not used widely or tested well.
Of course polling the Temperature Global variable from JavaScript is also not very reliable. It's not that the code won't work -- it's that I'll need to set an interval timer in JS to start polling when the model starts. This does not have much to do with the speed of the model.
What I actually need are the array of Temperatures generated during the run of the model.
So after I get the first implementation using interval polling of the single Temperature datum, I'll modify the model code to also save an list of the temperatures.
Then I'll need to figure out how to efficiently get data in an NL list into and array in JS.
I forgot to describe the most immediate and obvious need ...
Clicking the JavaScript start button not only starts the NL model (which the NL button already did) the event will also start the JS interval timer that collects data from the NL applet.
Clicking the "Stop" button will stop the NL model and stop the JS interval timer and complete the transfer of anydatain the NL model to the grapher.
Stephen> If a student has just collected 20s of a model run and then
Stephen> pressed the "Reset" button the browser needs to know this in
Stephen> order to save (or give the user the option of saving) the data
Stephen> that was justcollected.
Stephen> NetLogo is not currently written to be able to notify
Stephen> JavaScript functions in the browser when events like this
Stephen> happen in the Java applet context.
Couldn't you just attach a NetLogoListener (in org.nlogo.api) for
this...? AppletPanel has a listenerManager method, which returns a
NetLogoListenerManager object, which has an addListener method.
Are you thinking of our log4j-based logging stuff? That stuff isn't
available in NetLogo applets (so far, just because there hasn't been a
customer), but NetLogoListener should work.
Stephen> And ... while we've solved these problems with the sensor
Stephen> applet -- it was difficult and fraught -- and my judgement is
Stephen> that this area of communication is fragile. Sometimes things
Stephen> get broken with browser updates because it's not used widely
Stephen> or tested well.
Yeah, it's hard to know how far to trust LiveConnect.
Stephen> Of course polling the Temperature Global variable from
Stephen> JavaScript is also not very reliable. It's not that the code
Stephen> won't work -- it's that I'll need to set an interval timer in
Stephen> JS to start polling when the model starts. This does not have
Stephen> much to do with the speed of the model.
Indeed, I would not suggest polling.
Stephen> Then I'll need to figure out how to efficiently get data in an
Stephen> NL list into and array in JS.
If it helps, LogoList implements java.util.AbstractSequentialList, which
has a toArray method.
I'm not sure what I could do
Here's what we did in our sensor-applets work:
The html sets an applet param with the name of a JavaScript function that acts as a listener for events from the applet (which is an instance of an OTSensorApplet):
<param name="listenerPath" value="jsListener"/>
https://github.com/concord-consortium/sensor-applets/blob/master/example.html#L54
The initDataProxy() method in the OTSensorApplet class:
Creating a JavascriptDataBridge object which ties the applet and the JS context and the listenerPath property together:
When the JavascriptDataBridge object is initialized it create a window object which is used to communicate to the JS context:
window = JSObject.getWindow(applet)
The handleEvent() method of the JavascriptDataBridge instance:
puts together data being generated in the applet into a string which is then evaled in the JS context.
The method getJsEventCall() constructs the string to be evaluated in the JS context.
Which might look something like this: "jsListener.dataReceived(<type>,<count>,<data>);"
I think something similar would need to be added to NetLogo in order to get communication working from the NetLogo Java applet ==> a function in the JavaScript browser context.
>Are you thinking of our log4j-based logging stuff? That stuff isn't
>available in NetLogo applets (so far, just because there hasn't been a
>customer), but NetLogoListener should work.
I hadn't consider this -- not sure if it would help or not.
> Stephen> And ... while we've solved these problems with the sensor
> Stephen> applet -- it was difficult and fraught -- and my judgement is
> Stephen> that this area of communication is fragile. Sometimes things
> Stephen> get broken with browser updates because it's not used widely
> Stephen> or tested well.
>
>Yeah, it's hard to know how far to trust LiveConnect.
Yeah ... the problem right now in IE9 is that this statement fails:
sw = new applet.Packages.java.io.StringWriter();
With this error:
java.lang.IllegalArgumentException: No method found matching name java.io.StringWriter
and arguments [sun.plugin2.main.client.MessagePassingJSObject]
Which is pretty confusing since it works everywhere else
> Stephen> Of course polling the Temperature Global variable from
> Stephen> JavaScript is also not very reliable. It's not that the code
> Stephen> won't work -- it's that I'll need to set an interval timer in
> Stephen> JS to start polling when the model starts. This does not have
> Stephen> much to do with the speed of the model.
>
>Indeed, I would not suggest polling.
I've got stupid polling working well now.
> Stephen> Then I'll need to figure out how to efficiently get data in an
> Stephen> NL list into and array in JS.
>
>If it helps, LogoList implements java.util.AbstractSequentialList, which
>has a toArray method.
Great -- this will allow much smarter polling.
I'll poll at whatever interval I like and either just copy the entire array of data to the JS context -- or if I end up needingto ask for just the new elements in the array I haven't yet received.