Skip to content

Blank Canvas JavaScript

andygill edited this page Oct 5, 2014 · 13 revisions

Blank Canvas can be used to generate JavaScript for use outside the direct interaction. We try share generated code idioms between the server/client model, and the stand alone model.

Definition Meaning
Client-side Code executing a JavaScript engine
Server-side Code executing on a Haskell process
Generator-side Part of the code-generation phase
Offline Client-side + pre-generated code
Online Client-side + Server-side together

So, we have two modes, Online, where the code is generated on the fly, and Offline, where we pre-compute blocks of JavaScript. We have to be careful, so that the blocks of code cooperate within there own mode.

Top-level code

As a top-level concern, we generate code of the form:

"function(bc) { .. } "

bc is a JavaScript object that contains the following values.

Arrays:

  • canvas[] -- The are all the available contexts, contexts[0] is the default/start
  • images[] --
  • gradients --
  • patterns --

Q: how do we allocate the specific elements? Client (dynamic) or Server (static)?

bc also contains the following methods

  • getImage(String url, Function k) { .. }

k, the last argument, is the continuation.

Example Code

Most code is straight line. For example

...
moveTo(100,200)
...

Translates to

function(bc) { ...; bc.canvas[0].moveTo(100,200); ... }

The interesting things happen when the BlankCanvas API has a non-() return value.

There are two cases, client-side things, and generator/server-side things.

Consider createLinearGradient

CanvasGradient createLinearGradient(...)

Because CanvasGradient is abstract, we can use it as a handle into the gradients array in bc, and allocate the location at code generation time. (Hmm, this assumes non-reentrancy)

Consider isPointInPath

boolean isPointInPath(float x, float y)

This is a computation that must be performed on the client, and:

  • In Online mode, the reply that must be returned to the server; and
  • In Offline mode, the reply must be passed somehow to the next command (which is an open-ish problem.)

Online specific answers

For online-generated code, methods like isPointInPath will always be last.

Q: how will the result be communicated? Via a continuation? Via a return (this would not allow having built-in delays for things like loading images.)

Offline specific answers

It is not directly possible to generate isPointInPath in Offline specific mode.

(About the handle/control flow version, that does allow it)

Client/Sever Usage

function(bc,k) { ...; return k(bc.canvas[0].isPointOnPath()); }

Stand Alone Usage

Images!

Images are tricky. They take time to load, and you might want to do other things while waiting. Blank Canvas has the simple "wait till loaded" model. We can improve on this in various ways. For now, we continue to wait for the result.

// Client-side allocation
function(bc,k) { 
  ...; 
  var img = new Image(...); 
  ix = bc.images.push(img); 
  img.onload = function() { k(ix); } 
}

// Server-side allocation; can do things after the allocation
function(bc,k) { 
  ...; 
  var img = new Image(...); 
  var ix = <<PREALLOCATED LOCATION>>;
  bc.images[ix] = img; 
  img.onload = function() { 
      // ix is in scope, and can be used
      ...
      ((Code AFTER newImage))
}
Clone this wiki locally