This blog covers:

hyde raphael javascript scheme spock chicken

Recent posts

The Duct Tape: Interfacing Spock and Raphael
posted on 2013-05-06 19:00 CET

The Duct Tape: Interfacing Spock and Raphael

The Long-Term Goal

The long-term goal of this series of blog posts ist to create a simple 2D-triangle mesher as described in the article A Simple Mesh Generator in MATLAB. Here is a rough outline of how I will proceed:

  • Interfacing to the Raphael Javascript library (this post).
  • Generating a Delaunay triangulation of a set of points.
  • the mesh generator itself, which will reuse code from the two steps before.

The Short-Term Goal

The goals of today's post are:

  • Introduce the Chicken scheme to C compiler.
  • Introduce the "Spock" scheme to Javascript compiler.
  • Introduce the Raphael Javascript library for vector graphics.
  • Explain how to use the Raphael library from scheme using Spock.

So let's go!

The Chicken Scheme compiler

This blog is mainly about the programming language Scheme, a Lisp dialect (though die-hard Common Lispers will dispute that). My favorite implemenation is Chicken Scheme. Its salient points are:

  • Very portable. I have build and run it under ARM, Loongson, x86 and amd64 hardware running both Linux and OpenBSD.
  • Easy to use foreign function interface to libraries written in C (or Fortran) for that matter.
  • Batteries included. These come as chicken extensions called "eggs". A list of available eggs can be found at the egg index.
  • Very nice and supportive community.
  • For the complete sales pitch see http://wiki.call-cc.org/elevator-pitch.

The Spock Scheme to Javascript compiler.

Spock is a compiler from R5RS-Scheme (plus a few extensions) to Javascript. It uses the compilation strategy described in the Cheney on the MTA paper by Henry Baker. Chicken Scheme itself uses the very same compilation strategy.

Spock is available as a chicken egg and can be installed by:

$ chicken-install spock

This will install a chicken-spock executable wherever the chicken scheme compiler is installed. We will use the following command:

$ chicken-spock -optimize -o raph1.js raph1.scm

to compile the scheme source file raph1.scm to the Javascript target raph1.js. The Spock egg is described in more detail at the Spock page in the Chicken wiki.

The Raphael Vector Graphics Library

Raphael is a small Javascript library for creating vector graphics. It may be used to create a wide range of diagrams and presentations (see the homepage) for demos. A Javascript based tutorial may be found at: http://net.tutsplus.com/tutorials/javascript-ajax/an-introduction-to-the-raphael-js-library/.

Right now we are interested in translating the following Javascript code into Scheme:

var paper=Raphael("Graphics", 400, 400);
var circ, my_path;

circ=paper.circle(100, 100, 6);
circ.attr("fill", "black");

my_path=paper.path("M150,10L10,300L300,300Z");
my_path.attr("stroke", "black");
my_path.attr("stroke-width", 3);
my_path.attr("fill", "blue");

A short explanation of what the above code does:

  • Line 1 creates a drawing area (a canvas) of size 400x400 pixels in the element of the DOM with the id "Graphics" (usually an HTML <div> element).
  • Line 4 and 5 draw a black circle with a radius of 6 pixels.
  • Line 7-10 draw a blue filled triangle with a black outline of width 3.

For details please see the tutorial mentioned above.

The above code can be translated to Scheme using the following special Spock syntax:

[syntax] (%inline NAME ARG1 ARG2 ...)
[syntax] (%inline .METHOD NAME ARG1 ARG2 ...)

The first line corresponds to the Javascript:

NAME(ARG1, ARG2, ...);

and the second to the method call:

NAME.METHOD(ARG1, ARG2, ...);

So the above code sould be expressed as:

(let* ((paper (%inline Raphael (jstring "Graphics") 400 400))
       (circ (%inline .circle paper 100 100 6))
       (my-path (%inline .path paper (jstring "M150,10L10,300L300,300Z"))))
  (%inline .attr circ (jstring "fill") (jstring "black"))
  (%inline .attr path (jstring "stroke") (jstring "black"))
  (%inline .attr path (jstring "stroke-width") 3)
  (%inline .attr path (jstring "fill") (jstring "blue")))

Jstring is a procedure found in the spock runtime library. The jstring call is necessary because of the difference between Schene and Javascript strings:

  • Javascript strings are immutable.
  • R5RS Scheme strings are mutable. In Javascript they are represented as a SPOCK.String object. Jstring converts a Scheme string to an immutable Javascript string. It is smart enough to figure out, when no conversion is necessary, e.g. when a Scheme string literal is used.

Other useful syntax includes:

[syntax] (%new CLASS ARG1 ARG2 ...)
[syntax] (%host-ref NAME ARG1)
[syntax] (%host-set! NAME ARG1 VALUE)
[syntax] (%property-ref NAME X)
[syntax] (%property-set! NAME X Y)

These correspond to the following Javascript code:

new CLASS(ARG1, ARG2, ...);
NAME.ARG1;
NAME.ARG1 = VALUE;
X.NAME;
X.NAME=Y;

Now we are ready to assemble a short demo.

Putting it all together

Finally we need an html file to provide a display canvas for the Raphael library and to include the the Javascript code we need (the Rapael library itself, the Spock runtime library and the Javascript code generated from our scheme code by chicken-spock. The display canvas for the Raphael library is provided by an html div element with an id attribute of Graphics. Its width and height CSS-attributes determine the the size of the canvas.

Next comes an html form which contains a single button. It fires off this javascript code:

SPOCK.run(___main); SPOCK.flush()

This is how the scheme main procedure is called in SPOCK-ese. The complete html for the file index.html follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <title>Delaunay Triangulation</title>

  <script type="text/javascript" src="lib/raphael.js" charset="UTF-8">
  </script>

  <script type="text/javascript" src="lib/spock-runtime.js" charset="UTF-8">
  </script>

  <script type="text/javascript" src="./raph1.js" charset="UTF-8">
  </script>

</head>
<body>

<h1>Graphics</h1>
<p>
<div id="graphics" style="width: 400px; height: 400px"></div>  
</p>

<form action="javascript:calc_table()">
  <input type="button" name="calculate" id="calculate" value="Calculate!" 
         onclick="SPOCK.run(___main); SPOCK.flush();">
</form>

</body>
</html>

At last, here is the complete scheme code for reference purposes. It should go into a file named raph1.scm and be compiled to Javascript by:

chicken-spock -optimize -o raph1.js raph1.scm

;; [procedure]js-raphael ID X-SIZE Y-SIZE
;; return a new Raphael canvas object. It uses the DOM
;; element with Id ID as a canvas. Canvas size is
;; X-SIZE x Y-SIZE
;;
(define (js-raphael id xsize ysize)
   (%property-set!
      "innerHTML"  (%inline document.getElementById (jstring id)) 
      (jstring ""))
   (%inline Raphael (jstring id) xsize ysize))

;; [procedure] point->string POINT 
;; convert a 2D point (a list of two numbers) to
;;                a string
;; example: (point->string 120 150) ==> "120,150"
;;
(define (point->string pt)
  (string-append (number->string (car pt)) ","
                 (number->string (cadr pt))))

;; [procedure] draw-closed-poly PAPER POINTS FILL
;;
;;  Draw a closed polygon from the list of
;;  points POINTS on the Raphael canvas PAPER
;;  using the fill color FILL.
;;
(define (draw-closed-poly paper points fill)
  (let ((path1 (string-append "M" (point->string (car points))))
        (path2 (apply
                  string-append
                  (map (lambda (p)
                         (string-append "L" (point->string p)))
                       (cdr points))))
        (path3 "Z"))
     (let ((my-path (%inline .path paper
                       (jstring (string-append path1 path2 path3)))))
       (%inline .attr my-path "stroke" "black")
       (%inline .attr my-path "stroke-width" 3)
       (%inline .attr my-path "fill" fill))))
    
;; [procedure] draw-point PAPER X Y
;;
;;  Draw a point at co-ordinates X Y
;;  on the Raphael canvas PAPER. Fill color
;;  is black.
;;
(define (draw-point paper x y)
  (let ((my-circle (%inline .circle paper x y 6)))
     (%inline .attr my-circle "fill" "black")))


;; [procedure] random-float
;; returns a random float between 0.0 and 1.0
(define (random-float)
  (%inline Math.random))

(define (random-floats-1 n acc)
  (if (zero? n)
      acc
      (random-floats-1 (- n 1) (cons (random-float) acc))))

;; [procedure] random-floats N
;; returns a list of random floats between 0.0 and 1.0 of size N.
(define (random-floats n)
  (random-floats-1 n '()))

(define (random-points-1 n xmin ymin xmax ymax acc)
  (if (zero? n)
      acc
      (random-points-1 (- n 1) xmin ymin xmax ymax 
                       (cons (list (+ xmin (* (random-float) (- xmax xmin)))
                                   (+ ymin (* (random-float) (- ymax ymin))))
                             acc))))

;; [procedure] random-points N XMIN YMIN XMAX YMAX
;; returns a list of random points of size N.
;; the points are from the intervall
;; [XMIN, XMAX] X [YMIN, YMAX]
;;
(define (random-points n xmin ymin xmax ymax)
  (random-points-1 n xmin ymin xmax ymax))

;; [procedure] MAIN
;; The main procedure. Draw a blue closed polygon at
;; points [150, 10], [10, 300], [300, 300].
;; Also draw 10 random points from the square
;; [20, 20] x [290, 290].
;;
(define (main)
  (let ((paper (js-raphael "graphics" 350 350)))
    (%inline .clear paper)
    (draw-closed-poly paper '((150 10) (10 300) (300 300)) "blue")
    (for-each (lambda (pt)
                (draw-point paper (car pt) (cadr pt)))
              (random-points 10 20 20 290 290))))

If you want, you can try out the demo.

So that's it for now. I hope you enjoyed the post.

First post!
posted on 2013-04-22 18:05 CET

This is the first post to this blog. It is meant to contain my irrelevant ramblings on Scheme and other stuff. It is made with Hyde, a static site generator application written in Chicken Scheme. The templates were shamelessly appropriated and modified from Christian Kellerman from http://github.com/ckeen/hyde-blog.

I hope you enjoy reading this blog.


Unless noted otherwise code on this site is licensed under a 2 clause BSD-license, other content is licensed under a Creative Commons Attribution Share-Alike 3.0 Unported License