# An introduction to the sketch package

## The R package sketch

Creates interactive illustrations embeddable in RMarkDown documents. The package compiles R code into JavaScript code by applying rewriting rules to the R AST. This allows users to develop JS-style visualisations using only the R syntax.

Figure 1. Illustration of the rewriting process.

## 1. Preliminaries

### 1.1 Installation

install.packages("sketch")

# Or for the latest development
install.packages("remotes")
remotes::install_github("kcf-jackson/sketch")

### 1.2 Running a sketch R file

There are two ways to run a sketch R file.

1. Save the sketch R file (with the usual .R extension), then call sketch::source_r with it.

2. If you use RStudio, there is an add-in “source a sketch R file” listed under this package (consider binding that to the key combination alt-shift-s), and that sources the active tab in the editor.

### 1.3 Embedding a sketch R file in RMarkDown document

Simply use sketch::insert_sketch in a code chunk:

sketch::insert_sketch(
file = "main.R", id = "sketch_1",
width = 800, height = 600
)

where file is the path to the sketch file, id, width and height are the identifier, width and height of the sketch. (The identifier is needed to manage multiple sketches in the same Rmd document.)

## 2. Basic examples

### 2.1 p5.js

The functions setup, draw, createCanvas, background, frameCount, fill and circle are from the p5.js library, and one can use them as they are in the R code. This also works for all the other functions in the library.

setup <- function() {
createCanvas(400, 300)
}

draw <- function() {
background(0, 0, 33)    # RGB colors

for (i in 1:3) {
dia <- sin(frameCount * 0.025) * 30 * i
fill(255, 70 * i, 0)       # RGB colors
circle(100 * i, 150, dia)   # (x, y, diameter)
}
}

### 2.2 DOM manipulation

The web browser variable document and all of its methods are available, and DOM attributes also work as expected.

#### helper.R

# Create a new DOM element with an innerText
dom <- function(tag_name, inner_text) {
declare (el)   # Declare variable before use
el <- document$createElement(tag_name) # document and its methods are available el$innerText <- inner_text   # attributes work as expected
return (el)   # return must be explicit
}

# Insert a DOM element into another
insert_into <- function(x, y) {
document$querySelector(y)$appendChild(x)
}

#### main.R

# Textbox
textbox <- dom("div", "Hello World!")

# Two buttons
button_1 <- dom("button", "1")
button_1$onclick <- function() { textbox$innerText <- "Hello again!" }

button_2 <- dom("button", "2")
button_2$onclick <- function() { textbox$innerText <- "Bye!" }

# HTML
insert_into(textbox, "body")
insert_into(button_1, "body")
insert_into(button_2, "body")

## 3 Special operators

### #| load_script()

Use #| together with load_script to load any JavaScript library, CSV / JSON data file or an other sketch R file.

• If the data file is named as my_file.json, then it will be available in the variable my_file_json. The data variable is not supposed to be modified (and is assigned the const tag). If one needs to change the data, please proceed by making a copy.

• The package does not resolve circular referencing, e.g. file A and file B sourcing each other at the same time. Please avoid that.

### declare() / let()

declare() / let() are empty R functions that act as a placeholder to facilitate the conversion to JavaScript. If you want to assign a value to a variable, you may proceed as:

declare (x)
x <- 3
# alternatively
let (x = 3)

Note that declare and let are 100% interchangeable, e.g. declare (x = 3) is also valid. declare is preferred for top-level variable declaration while let is preferred for local use.

If one uses variables without declaring them, JavaScript will declare it for you and place them in the global namespace.

### %=>% and %+%

• %=>% maps to the arrow function => in JavaScript.

• %+% maps to + in JavaScript. The reason for having this operator is that R does not perform string addition, but JS does. One may think of %+% as the semantic equivalent of paste0. Indeed,

%+% <- paste0
"a" %+% "b" %+% "c"  # gives "abc"

### lambda

The lambda function offers a convenient way to define anonymous function, which works similar to pryr::f. For instance, function(x, y) { return(x + y) } can be rewritten as lambda(x, y, x + y).

## 4 Common pitfalls (of writing JS in R)

### i. JavaScript uses 0-based indexing

// Web-browser console
x = [1,2,3]
x[0]  // 1

### ii. JavaScript function reads argument by position / order

// Web-browser console
first = function(x, y) { console.log(x) }
first(y = 3, x = 1)  // 3

### iii. return in JavaScript function must be explicit

add = function(x, y) { x + y }

add2 = function(x, y) { return(x + y) }
add(3, 4) // 7

### iv. JavaScript passes objects by reference (think R6 in R)

// Web-browser console
x = [1,2,3]    // Array(3) [ 1, 2, 3 ]
y = x          // Array(3) [ 1, 2, 3 ]
y[0] = 999
y              // Array(3) [ 999, 2, 3 ]
x              // Array(3) [ 999, 2, 3 ]

### v. A browser session has a pre-populated namespace

• e.g. the variables document, window, location, var, stop, open, focus are taken already. Avoid assigning values to these variables!

• The full list can be found by typing in the console of a browser:

// Web-browser console
for (let b in window) {
if (window.hasOwnProperty(b)) console.log(b);
}