Dynamically interacting with Observable from macOS app

I’m trying to embed Observable in a macOS app. On a view, I’ve a webView loading my graph, and a tableView below (coded in Objective-C).

I’d like to graph specific areas when selecting different lines in my tableView.
Like in this example, but areas changes are not triggered by an Observable button, but by my Objective-C code sending an info to Observable to move the area depending the row selected in the app.

How can I do that without reloading the full page ?

I thought about POST commands, but I’m not sure how this would work async from the view, or maybe WebSockets ?

Any working example is welcomed !

Edit: Forgot to mention that macOS app serves a local web server from which local Observable files are served. So full access on web server.

Edit: I’d go with websockets. Here’s a minimal self-contained example that demonstrates that it will work:

  const status = html`<output>waiting ...`;
  const ws = new WebSocket('ws://');
  ws.onopen = () => { status.value = 'Connected.' };  
  return status;

I’ve used https://github.com/PsichiX/simple-websocket-echo-server to test the connection. Just download it, run npm install, then the command npm run start.

Original post:

Some thoughts:

  • You can’t pass POST data to your Observable notebooks. POST data is received and handled by the server.
  • Websockets will (likely) not work because the notebook iframe is sandboxed.
  • WebRTC data channels might work, although I can offer neither proof nor a working example.
  • Your app could launch an HTTP server locally to which you can connect from your notebook, but would need to run via https, meaning you’d need a valid certificate.

My recommendation would be to look into WebRTC as a potential solution.

Thanks for those thoughts, just added an edit that the server is local, served by macOS app if this could help, we’re not on the internet

If you’re using a WKWebView, there are methods you can call to evaluate a JS string in the context of the web view. You could expose a global in the code you use to render the chart from the notebook that allows you to override the selection.

You could update the selection by doing something like module.redefine('selection', [], selectedItems) and using the selection variable in the notebook to adjust what’s visible.

My instinct would be to have your notebook listen to window.onmessage, and use that channel to send new data (via window.postMessage or whatever API your WebView exposes).