NetLogo Global Climate model and JavaScript grapher
This example displays a NetLogo model sending data to a JavaScript grapher
NetLogo Global Climate model and JavaScript grapher
This example displays a NetLogo model sending data to a JavaScript grapher
| /* | |
| * Minimal classList shim for IE 9 | |
| * By Devon Govett | |
| * MIT LICENSE | |
| */ | |
| if (!("classList" in document.documentElement) && Object.defineProperty && typeof HTMLElement !== 'undefined') { | |
| Object.defineProperty(HTMLElement.prototype, 'classList', { | |
| get: function() { | |
| var self = this; | |
| function update(fn) { | |
| return function(value) { | |
| var classes = self.className.split(/\s+/), | |
| index = classes.indexOf(value); | |
| fn(classes, index, value); | |
| self.className = classes.join(" "); | |
| } | |
| } | |
| var ret = { | |
| add: update(function(classes, index, value) { | |
| ~index || classes.push(value); | |
| }), | |
| remove: update(function(classes, index) { | |
| ~index && classes.splice(index, 1); | |
| }), | |
| toggle: update(function(classes, index, value) { | |
| ~index ? classes.splice(index, 1) : classes.push(value); | |
| }), | |
| contains: function(value) { | |
| return !!~self.className.split(/\s+/).indexOf(value); | |
| }, | |
| item: function(i) { | |
| return self.className.split(/\s+/)[i] || null; | |
| } | |
| }; | |
| Object.defineProperty(ret, 'length', { | |
| get: function() { | |
| return self.className.split(/\s+/).length; | |
| } | |
| }); | |
| return ret; | |
| } | |
| }); | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>NetLogo Applet</title> | |
| <link href="styles.css" rel="stylesheet" type="text/css"> | |
| <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> | |
| <script src="http://mbostock.github.com/d3/d3.v2.js?2.8.1"></script> | |
| <script src="classlist-shim-for-ie.js" type="text/javascript"></script> | |
| <script src="https://raw.github.com/gist/2764196/610b262e9b266a6f71c58e0d2ad27a304475466c/dgApi.js" type="text/javascript"></script> | |
| </head> | |
| <body> | |
| <h1>Simple Global Climate Change NetLogo Applet</h1> | |
| <ul class="hlist"> | |
| <li> | |
| <div id="appletwrapper"> | |
| <ul class="hlist"> | |
| <li><button id="run-button" class="nlogo">Run</button></li> | |
| <li><button id="reset-button" class="nlogo">Reset</button></li> | |
| <li><button id="watch-sunray-button" class="nlogo">Watch Sunray</button></li> | |
| </ul> | |
| <applet id="applet" code="org.nlogo.lite.Applet" archive="http://stepheneb.github.com/netlogo-gcc/NetLogoLite.jar" width="590" height="430"> | |
| <param name="DefaultModel" value="http://stepheneb.github.com/netlogo-gcc/GCCModel.v3.nlogo"> | |
| </applet> | |
| </div> | |
| </li> | |
| <li> | |
| <div id="chart" class="chart"></div> | |
| </li> | |
| </ul> | |
| <script src="netlogo.js" type="text/javascript"></script> | |
| </body> | |
| </html> |
| /*global browser:true */ | |
| var applet = document.getElementById("applet"), | |
| run_button = document.getElementById("run-button"), | |
| reset_button = document.getElementById("reset-button"), | |
| watch_sunray_button = document.getElementById("watch-sunray-button"), | |
| nl_obj_panel, // org.nlogo.lite.Applet object | |
| nl_obj_workspace, // org.nlogo.lite.LiteWorkspace | |
| nl_obj_world, // org.nlogo.agent.World | |
| nl_obj_program, // org.nlogo.api.Program | |
| nl_obj_state, | |
| nl_obj_observer, | |
| nl_obj_globals, | |
| sw, | |
| pw, | |
| nlogo_elements, | |
| globals = [], i, | |
| data_array = [], | |
| graph; | |
| window.onload=function() { | |
| disable_nlogo_elements(); | |
| dgApi.initGame("NetLogo Data", [ { name: "ticks", type: 'numeric', description: "Current tick", precision: 0 }, | |
| { name: "temperature", type: 'numeric', description: "Global Climate Temperature", precision: 2 } | |
| ]); | |
| dgApi.beginRun(); | |
| // | |
| // NetLogo Applet Loading Handler | |
| // | |
| // Wait until the applet is loaded and initialized before enabling buttons | |
| // and creating JavaScript variables for Java objects in the applet. | |
| // | |
| applet.ready = false; | |
| applet.checked_more_than_once = false; | |
| window.setTimeout (function() { isAppletReady(); }, 250); | |
| function isAppletReady() { | |
| try { | |
| applet.ready = applet.panel(); | |
| } catch (e) { | |
| // Do nothing--we'll try again in the next timer interval. | |
| } | |
| if(applet.ready) { | |
| nl_setup_objects(); | |
| nl_obj_panel.commandLater("set done true"); | |
| sw = new applet.Packages.java.io.StringWriter(); | |
| pw = new applet.Packages.java.io.PrintWriter(sw); | |
| enable_nlogo_elements(); | |
| if(applet.checked_more_than_once) { | |
| clearInterval(applet.checked_more_than_once); | |
| applet.checked_more_than_once = false; | |
| } | |
| } else { | |
| if(!applet.checked_more_than_once) { | |
| applet.checked_more_than_once = window.setInterval(function() { isAppletReady(); }, 250); | |
| } | |
| } | |
| } | |
| // | |
| // Create these JavaScript objects to provide access to the | |
| // corresponding Java objects in NetLogo. | |
| // | |
| function nl_setup_objects() { | |
| nl_obj_panel = applet.panel(); | |
| nl_obj_workspace = nl_obj_panel.workspace(); | |
| nl_obj_world = nl_obj_workspace.org$nlogo$lite$LiteWorkspace$$world; | |
| nl_obj_program = nl_obj_world.program(); | |
| nl_obj_observer = nl_obj_world.observer(); | |
| nl_obj_globals = nl_obj_program.globals(); | |
| } | |
| // | |
| // NetLogo command interface | |
| // | |
| function nl_cmd_start() { | |
| nl_obj_panel.commandLater("set done false while [not done] [ execute ]"); | |
| } | |
| function nl_cmd_stop() { | |
| nl_obj_panel.commandLater("set done true"); | |
| } | |
| function nl_cmd_execute(cmd) { | |
| nl_obj_panel.commandLater(cmd); | |
| } | |
| function nl_cmd_save_state() { | |
| nl_obj_world.exportWorld(pw, true); | |
| nl_obj_state = sw.toString(); | |
| } | |
| function nl_cmd_restore_state() { | |
| if (nl_obj_state) { | |
| var sr = new applet.Packages.java.io.StringReader(nl_obj_state); | |
| nl_obj_workspace.importWorld(sr); | |
| nl_obj_panel.commandLater("display"); | |
| } | |
| } | |
| function nl_cmd_reset() { | |
| nl_cmd_stop(); | |
| nl_obj_panel.commandLater("startup"); | |
| } | |
| // | |
| // Managing the NetLogo data polling system | |
| // | |
| function startNLDataPoller() { | |
| applet.data_poller = window.setInterval(function() { nlDataPoller(); }, 200); | |
| } | |
| function stopNLDataPoller() { | |
| if (applet.data_poller) { | |
| clearInterval(applet.data_poller); | |
| applet.data_poller = false; | |
| } | |
| } | |
| function nlDataPoller() { | |
| data_array.push(nl_obj_observer.getVariable(3)); | |
| dgApi.addTick([ data_array.length, data_array[data_array.length-1] ]); | |
| } | |
| // | |
| // button handlers | |
| // | |
| run_button.onclick = function() { | |
| if (run_button.textContent == "Run") { | |
| run_button_run(); | |
| } else { | |
| run_button_stop(); | |
| } | |
| }; | |
| reset_button.onclick = function() { | |
| run_button_stop(); | |
| nl_cmd_reset(); | |
| data_array.length = 0; | |
| dgApi.endRun(); | |
| dgApi.beginRun(); | |
| }; | |
| watch_sunray_button.onclick = function() { | |
| nl_cmd_execute("watch one-of sunrays with [ycor > (max-pycor / 2 ) and heading > 90 ]"); | |
| }; | |
| // | |
| // button/view helpers | |
| // | |
| function run_button_run() { | |
| nl_cmd_start(); | |
| startNLDataPoller(); | |
| run_button.textContent = "Stop"; | |
| } | |
| function run_button_stop() { | |
| nl_cmd_stop(); | |
| stopNLDataPoller(); | |
| run_button.textContent = "Run"; | |
| } | |
| // | |
| // add the css class "inactive" to all dom elements that include the class "nlogo" | |
| // | |
| function disable_nlogo_elements() { | |
| nlogo_elements = document.getElementsByClassName("nlogo"); | |
| for (i=0; i < nlogo_elements.length; i++) { | |
| nlogo_elements[i].classList.add("inactive"); | |
| } | |
| } | |
| // | |
| // add the css class "active" to all dom elements that include the class "nlogo" | |
| // | |
| function enable_nlogo_elements() { | |
| nlogo_elements = document.getElementsByClassName("nlogo"); | |
| for (i=0; i < nlogo_elements.length; i++) { | |
| nlogo_elements[i].classList.remove("inactive"); | |
| nlogo_elements[i].classList.add("active"); | |
| } | |
| } | |
| }; |
| body { font: 12px Verdana, Arial, Helvetica, sans-serif; | |
| margin: 1.0em 2.0em; | |
| background-color: white;} | |
| h1 { font-size: 1.6em; | |
| font-weight: bold; } | |
| h2 { font-size: 1.4em; | |
| font-weight: bold; } | |
| h1 { font-size: 1.2em; | |
| font-weight: bold; } | |
| hr { margin: 2em 0em; } | |
| p { max-width: 600px; } | |
| #appletwrapper { border: 1px solid white; | |
| padding: 10px; | |
| width: 600px; | |
| height: 490px; | |
| background-color: white; } | |
| applet { padding: 0px; | |
| background-color: white; } | |
| table { border: 1px solid gray; | |
| border-spacing: 0px; | |
| border-collapse: collapse; | |
| font: 10px/24px Verdana, Arial, Helvetica, sans-serif; } | |
| table th { | |
| border: 1px solid gray; | |
| padding: 0em 1em; | |
| text-align: center; } | |
| table td { | |
| font-size: 0.9em; | |
| border: 1px solid gray; | |
| padding: 0em 1em; | |
| text-align: right; | |
| width: 14em; } | |
| table td.left { | |
| padding: 0em 1em 0em 2em; | |
| text-align: left; } | |
| ul { | |
| list-style-type: none; | |
| padding: 0em 0em; | |
| margin: 0.5em 0em 0em 0.5em; | |
| width: 100%; } | |
| ul li { | |
| margin: 0em; | |
| padding: 0em 1em; } | |
| ul.hlist li { | |
| display: table-cell; | |
| vertical-align: top; | |
| margin: 0em; | |
| padding: 0em 0.5em; } | |
| button.active { | |
| font-weight: bold; | |
| font-color: black; | |
| border-bottom: 2px solid black; } | |
| button { | |
| font-weight: normal; | |
| font-color: gray; | |
| border-bottom: 0px solid black; } | |
| pre { font-size: 0.8em; | |
| border: 1px solid gray; | |
| padding: 1em; | |
| background-color: #F0F0F0; | |
| width: 80em; | |
| height: 40em; | |
| overflow: scroll; } | |
| .chart { | |
| border: 1px solid white; | |
| background-color: #FAFAFA; | |
| margin-top: 20px; | |
| width: 580px; | |
| height: 465px; } | |
| circle, .line { | |
| fill: none; | |
| stroke: steelblue; | |
| stroke-width: 1px; } | |
| text.title { font-size: 1.2em; | |
| font-weight: bold; } | |
| text.axis { font-size: 1.0em; | |
| font-weight: normal; } | |
| circle { | |
| fill: white; | |
| fill-opacity: 0.2; | |
| cursor: move; } | |
| circle.selected { | |
| fill: #ff7f0e; | |
| stroke: #ff7f0e; } | |
| circle:hover { | |
| fill: #ff7f0e; | |
| stroke: #707f0e; } | |
| circle.selected:hover { | |
| fill: #ff7f0e; | |
| stroke: #ff7f0e; } |