View on GitHub

Canvas.hs

Canvas.hs, a Haskell library designed to communicate with HTML5/canvas

Basic datatypes

Basic datatypes are used in the shapes, they serve as building block for shapes.

Color

Colors are basic structures used in the API and can be used in the fill and stroke properties of shapes. Colors have red/green/blue in the range 0 to 255, and alpha in the range 0.0 to 1.0

Example

{"r": 255, "g": 255, "b": 255, "a": 1.0}

Points

Points are lists of numbers that represent x and y pairs. A points list always contains an even number of items.

Example

1 { "points": [ 10, 0, 10, 10, 0, 10, 0, 0] }

Common properties

All shapes have keys for the following properties in their data:

Shapes

Line

A line consists of a list of points that will be connected. When scaling or rotating this will happen from the upper left x and y coordinates of the invisible rect incapsulating the line.

Specific keys

Bare Minimum

White (default) line from (10,0) to (10,10)

1 {
2     "type": "line",
3     "data": {
4         "points": [ 10, 0, 10, 10 ]
5     }
6 }

Realworld Example

Red line from (10, 0) to (10, 10)

1 {
2     "type": "line",
3     "data": {
4         "points": [ 10, 0, 10, 10 ],
5         "stroke": {"r": 255, "g": 0, "b": 0, "a": 1.0},
6         "strokeWidth": 2
7     }
8 }

Polygon

A polygon is a closed path where the beginning of the path is connected to the end (unlike a Line). When scaling or rotating this will happen from the upper left x and y coordinates of the invisible rect incapsulating the polygon.

Specific keys

Bare Minimum

White (default) polygon from (73, 192) to (73, 160) to (340, 23) to (500, 109) to (499, 139) to (342, 93) to (73, 192)

1 {
2     "type": "polygon",
3     "data": {
4         "points": [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],
5     }
6 }

Realworld Example

Green polygon (semitransparant) with Yellow stroke (2px) from (73, 192) to (73, 160) to (340, 23) to (500, 109) to (499, 139) to (342, 93) to (73, 192)

1 {
2     "type": "polygon",
3     "data": {
4         "points": [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],
5         "stroke": {"r": 255, "g": 255, "b": 0, "a": 1.0},
6         "strokeWidth": 2,
7         "fill": {"r":0, "g":255, "b":0, "a":0.75}
8     }
9 }

Rect

A rect is a simple rectangle with a width and a height. When scaling or rotating this will happen from the upper left x and y coordinates.

Specific keys

Bare Minimum

White (default) square from (10, 10) to (20, 30)

1 {
2     "type": "rect",
3     "data": {
4         "x": 10,
5         "y": 10,
6         "width": 10,
7         "height": 20,
8     }
9 }

Realworld Example

Green square with blue stroke from (10, 10) to (20, 30)

 1 {
 2     "type": "rect",
 3     "data": {
 4         "x": 10,
 5         "y": 10,
 6         "width": 10,
 7         "height": 20,
 8         "stroke": {"r": 255, "g": 0, "b": 0, "a": 1.0},
 9         "strokeWidth": 2,
10         "fill": {"r":0, "g":255, "b":0, "a":0.75}
11     }
12 }

Arc

An Arc has a centerpoint, a radius and an angle. The angle states how large the arc should be in degrees. When scaling or rotating, this will happen from center x and y of the center of the imaginary circle that results if the arc would be extended to a full circle.

Specific keys

Example

White (default) arc with center (20, 20) and radius 70

1 {
2     "type": "arc",
3     "data": {
4         "x": 20,
5         "y": 20,
6         "radius": 70,
7         "angleDeg": 80
8     }
9 }

Circle

A circle has a centerpoint and a radius. The total size of a circle is therefore twice the radius. When scaling or rotating, this will happen from center x and y of the circle.

Specific keys

Bare Minimum

White (default) circle with center (20, 20) and radius 5

1 {
2     "type": "circle",
3     "data": {
4         "x": 20,
5         "y": 20,
6         "radius": 5
7     }
8 }

Realworld Example

Black circle with purple stroke (2px) with center (20, 20) and radius 5

 1 {
 2     "type": "circle",
 3     "data": {
 4         "x": 20,
 5         "y": 20,
 6         "radius": 5,
 7         "stroke": {"r": 255, "g": 0, "b": 255, "a": 1.0},
 8         "strokeWidth": 2,
 9         "fill": {"r":0, "g":0, "b":0, "a":1.0}
10     }
11 }

Text

Text has some text to display and some properties defining the font/size/etc.

Specific keys

Bare Minimum

Hello Protocol! centered around (20, 20) with default font and size (chosen by the client)

1 {
2     "type": "text",
3     "data": {
4         "x": 20,
5         "y": 20,
6         "text": "Hello Protocol!",
7         "align": "center"
8     }
9 }

Realworld Example

Hello Rotation and Scaling! in Helvetica (14px) centered around (20, 20) with a rotation of 20 degrees around (20, 20) and a xScale of 2.0

 1 {
 2     "type": "text",
 3     "data": {
 4         "x": 20,
 5         "y": 20,
 6         "text": "Hello Rotation and Scaling!",
 7         "align": "center",
 8         "fontFamily": "Helvetica",
 9         "fontSize": 14,
10         "rotationDeg": 20,
11         "xScale": 2.0
12     }
13 }

Containers

A container is here to provide the scaling, rotation and event binding to multiple objects. The container creates its own coordinate system therefor everything inside is relative to the containers dimentions, location and rotation.

Example

 1 {
 2     "type": "container",
 3     "data": {
 4         "id": "container_b",
 5         "x": 10,
 6         "y": 10,
 7         "width": 100,
 8         "height": 200,
 9         "scaleX": 5.0,
10         "scaleY": 10.0,
11         "rotationDeg": 180
12     },
13     "children" : [
14         {
15             "type": "circle",
16             "data": {
17                 "id": "circle_nr_1",
18                 "x": 20,
19                 "y": 20,
20                 "radius": 5,
21                 "stroke": {"r": 255, "g": 0, "b": 0, "a": 1.0},
22                 "strokeWidth": 2,
23                 "fill": {"r":0, "g":255, "b":0, "a":0.75}
24             }
25         },
26         {
27             "type": "polygon",
28             "data": {
29                 "id": "polygon_nr_23",
30                 "points": [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],
31                 "stroke": {"r": 255, "g": 0, "b": 0, "a": 1.0},
32                 "strokeWidth": 2,
33                 "fill": {"r":0, "g":255, "b":0, "a":0.75},
34                 "rotationDeg": 90
35             }
36         }
37     ]
38 }

The Canvas

The container that represents the root of the canvas will be sent as the root object. By Default the canvas will resize to the dimentions of the root container. If you want to go FullWindow or FullScreen you should use actions. After going FullWindow or FullScreen you can adjust the positioning of shapes when the ResizeWindow event is called. This happens automaticly if you go FullWindow of FullScreen.

Example

1 {
2     "shape": {
3         
4     },
5     "actions": [{
6         
7     }]
8 }

Events

##EventData All shapes drawn above are not interactive, clicking/dragging/etc. won’t trigger events. Eventdata can be added to a shape with the “event” key, when the user presses the mousebutton and the cursor intersects a shape with eventdata a message is sent to the server informing that a specific shape is pressed.

Eventdata consists of an id and a set booleans on which events shapes will react. Currently supported are: * Mouse down (User presses and holds left mouse button) * Mouse click (User clicks left mouse button) * Mouse up (User lets go of left mouse button) * Mouse double click (User clicks left mouse button twice) * Mouse drag (User presses leftmousebutton and drags around) * Mouse enter (Mousecursor enters shape) * Mouse out (Mousecursor leaves shape) * Scroll (User scrolls on shape)

Eventdata example

 1 {
 2     "type": "circle",
 3     "data": {
 4         "x": 20,
 5         "y": 20,
 6         "radius": 5,
 7         "stroke": "rgba(255,255,255,1)",
 8         "strokeWidth": 2,
 9         "fill": "rgba(255,0,0,1)"
10     },
11     "eventData": {
12     	"eventId": "circle_nr_1",
13     	"listen" : ["mousedown","mouseclick","mouseup","mousedoubleclick","mousedrag","mouseover", "mouseout"]
14     }
15 }

When an event is triggered, javascript will search for a object that is intersected and is interested in that event, if a object was found, the object key is populated with the ID of that object.

MouseEvents

###MouseDown Triggered when a user presses and holds the left mousebutton, its location (a point) and an id of a pressed object is transmitted. If no id can be transmitted the mousedown event will not be sent. The x and y coordinates are absolute to the intire canvas and not relative to the container of the object referenced by the id.

Example

1 {
2     "event":"mousedown",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

MouseClick

Triggered when the mouse is pressed and released (“clicked”), same data as mousedown.

Example

1 {
2     "event":"mouseclick",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

MouseUp

Triggered when the mouse is released after it was down for some time, same data as mousedown.

Example

1 {
2     "event":"mouseclick",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

MouseDoubleClick

Triggered when the mouse is clicked twice, same data as mousedown.

Example

1 {
2     "event":"mousedoubleclick",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

MouseDrag

Triggered when a shape is pressed and dragged from one point to another, contains start and end locations.

Example

 1 {
 2     "event":"mousedrag",
 3     "data":{
 4         "id1": "myAwesomeShape",
 5         "x1": 150,
 6         "y1": 150,
 7         "x2": 250,
 8         "y2": 250
 9     }
10 }

MouseOver

Triggered when the mouse enters a shape that is interested in that event. Note: only works on shapes that have eventdata and are interested in MouseOver events.

Example

1 {
2     "event":"mouseover",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

MouseOut

Same as MouseOver, but when the mouse leaves a shape

Example

1 {
2     "event":"mouseout",
3     "data":{
4         "id": "myAwesomeShape",
5         "x": 150,
6         "y": 150
7     }
8 }

Scroll

Scroll events are triggered when a user scrolls an element, id, xdelta and ydelta’s are sent to the client ####Example

1 {
2     "event":"scroll",
3     "data":{
4         "id": "myAwesomeShape",
5         "xdelta": 20,
6         "ydelta": 10
7     }
8 }

Key Events

Key events are not connected to objects, a key is pressed with some modifiers (Ctrl/Alt/Shift/Super). The super key is equal to the windows key.

KeyDown

Triggered when a key is pressed and hold down.

Example

 1 {
 2     "event":"keydown",
 3     "data":{
 4         "key": "a",
 5         "control": true,
 6         "alt": false,
 7         "shift": false,
 8         "super": false
 9     }
10 }

KeyUp

Triggered when a key is released.

Example

 1 {
 2     "event":"keyup",
 3     "data":{
 4         "key": "c",
 5         "control": true,
 6         "alt": false,
 7         "shift": false,
 8         "super": false
 9     }
10 }

Other Events

Upload

Event triggered when a file is uploaded after drop-in or selection in the file dialog. To open the fill dialog send a PresentFileOpenDialog action. ####Example

1 {
2     "event":"upload",
3     "data":{
4         "file": "data base 64 string"
5     }
6 }

ResizeWindow

Event triggered when the window resizes. This event is also triggerd on first time launch. ####Example

1 {
2     "event":"resizewindow",
3     "data":{
4         "width": 800,
5         "height": 600
6     }
7 }

Prompt

Simple event to return entered values in a prompt. When a prompt is canceled no event will be sent.

Example

1 {
2     "event":"prompt",
3     "data":{
4         "value": "John Doe"
5     }
6 }

Action

Actions are messages that trigger certain javascript functions from the server. So it is like events but from server to client, from haskell to javascript. ####Example

1 {
2     "shape": {
3         
4     },
5     "actions": [{
6         
7     }]
8 }

WindowDisplayType

Type is an enumeration where 0 is FizedSize 1 is FullWindow and 2 is FullScreen. Width and height are required with FixedSize and are ignored with the other types.

Example

 1 {
 2     "action":"windowdisplaytype",
 3     "data":{
 4         "type": 0,
 5         "width": 800,
 6         "height": 600
 7     }
 8 }
 9 {
10     "action":"windowdisplaytype",
11     "data":{
12         "type": 1
13     }
14 }

Debugger

Simple action to enable or disable the canvas debugger.

Example

1 {
2     "action":"debugger",
3     "data":{
4         "enabled": true
5     }
6 }

Prompt

Simple action to prompt the user for string input. Placeholder is optional. After entering the action will return a prompt event. Prompting is blocking so while entering the interface will halt.

Example

1 {
2     "action":"prompt",
3     "data":{
4         "message": "Please enter your name…",
5         "placeholder": "John Doe"
6     }
7 }

File Actions

RequestUpload

Simple action to present a file select dialog box. The multiple parameter indicates that multiple files can be uploaded.

Example

1 {
2     "action":"requestupload",
3     "data": {
4         "multiple": true
5     }
6 }

Download

Action to sava a file, this will trigger the browser to download.

Example

1 {
2     "action":"download",
3     "data":{
4         "file": "data base 64 string"
5     }
6 }

AcceptFileDragNDrop

Simple action to enable drag’n’drop file uploads. The multiple parameter indicates that multiple files can be uploaded.

Example

1 {
2     "action":"acceptfiledragndrop",
3     "data":{
4         "enabled": true,
5         "multiple": true
6     }
7 }