Excalidraw can import and export its scenes in json; the format
consists of 5 top-level entries, of which the important one is
elements
, which is an array containing the description of
each basic glyph in the scene.
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [
{
"type": "rectangle",
"fillStyle": "solid",
[...]
"groupIds": []
},
{
"type": "rectangle",
"fillStyle": "solid",
[...]
"groupIds": []
}
],
"appState": {
"viewBackgroundColor": "#ffffff",
"gridSize": null
}
}
Note that there doesn’t appear to be a device size / viewport / viewbox. I’m also unsure what the units are; looking at the SVG export it seems to be the same default “px”, i.e. 1/96th of an inch, i.e. about a quarter of a mm.
Most attributes are pretty straight-forward,
The following are for text (but it doesn’t seem to hurt if irrelevant parameters are passed to another shape type),
Each glyph is assigned some identification,
Finally the following attributes for collaboration,
minixcali
defines a very basic R6 class
ExcaliDocument
which initialises the 5 top-level nodes of
the json object. Two methods are defined,
$add
, to add glyphs to the elements
field$export
, to save the object to a json file (via
jsonlite
)The $add
method simply appends glyph(s) to the list of
elements. Each glyph needs to be a well-formed list of attributes, such
as
list(type = "rectangle",
x = -407.242554, y = 0,
width = 44, height = 44,
angle = 0,
strokeColor = "#495057",
backgroundColor = "#ced4da",
fillStyle = "hachure",
strokeWidth = 1,
strokeStyle = "solid",
roughness = 1L,
opacity = 100L,
strokeSharpness = "sharp",
isDeleted = FALSE,
groupIds = list(),
boundElementIds = NA,
id = "2732dc14872d3709d5978813d7bf550c",
seed = 1260353516L,
version = 32L,
versionNonce = 784119031L)
minixcali
provides 4 functions
(xkd_rectangle()
, xkd_ellipse()
,
xkd_draw()
, xkd_text()
) to generate such lists
from the set of default parameters.
## List of 27
## $ type : chr "text"
## $ x : num 0
## $ y : num 0
## $ width : num 100
## $ height : num 100
## $ angle : num 0
## $ strokeColor : chr "#555555"
## $ backgroundColor: chr "#868e96"
## $ fillStyle : chr "solid"
## $ strokeWidth : int 2
## $ strokeStyle : chr "solid"
## $ roughness : int 0
## $ opacity : int 100
## $ groupIds : list()
## $ strokeSharpness: chr "sharp"
## $ isDeleted : logi FALSE
## $ boundElementIds: logi NA
## $ text : chr "new label"
## $ fontSize : int 36
## $ fontFamily : int 1
## $ textAlign : chr "left"
## $ verticalAlign : chr "top"
## $ baseline : int 32
## $ version : num 1
## $ versionNonce : num 12345
## $ id : chr "1f9a050f82d6fa104fb83235d82ff816"
## $ seed : int 2102342236
To create multiple shapes at once it can be useful to create a list
or data.frame of attributes, and use purrr
functions to
iterate over them,
a <- tibble::tribble(~x, ~y, ~width, ~height, ~roughness, ~backgroundColor,
-300 , -80, 300, 300, 0, "#ced4da",
10 , -80, 300, 300, 1, "#ced4da",
320 , -80, 300, 300, 2, "#ced4da")
a$strokeWidth <- 2
d <- Excali_doc()
invoke(d$add, pmap(a, xkd_rectangle))
str(d$elements, max.level = 1)
## List of 3
## $ :List of 21
## $ :List of 21
## $ :List of 21
We can the export the full tree to json and open it in Excalidraw,
The drawing may be edited at https://excalidraw.com/#json=5181621544157184,h3q8WL5-2HPBFjkjQeu5RA
line
, arrow
and draw
elements
(the difference is in the interaction with online tools; there’s none
from the JSON perspective) require a points
attribute that
encodes (x,y) node coordinates in an array structure.
Say we have inherited some (x,y) coordinates representing a polygon
from a drawing program; we can insert them into the points
attribute and from there generate the scene as above. It is also
possible to group multiple paths by giving them a common
group
attribute, as illustrated below. The resulting group
can then be edited (moved, rotated, attribute changes, etc.) as one
object in Excalidraw.
source(system.file("samples/pdl.R", package = "minixcali"))
str(.kevin) # stored coords in the package under data/
## List of 6
## $ :List of 7
## ..$ x : num -3.14
## ..$ y : num 128
## ..$ width : num 29.5
## ..$ height : num 22.8
## ..$ backgroundColor: chr "#ced4da"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:11, 1:2] -11.4 -39 -36.2 -22.2 -20.4 ...
## $ :List of 7
## ..$ x : num -13.2
## ..$ y : num 92.9
## ..$ width : num 115
## ..$ height : num 115
## ..$ backgroundColor: chr "#d8f0f9"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:18, 1:2] 0 0.26 18.2 45.32 73.92 ...
## $ :List of 7
## ..$ x : num -0.922
## ..$ y : num 104
## ..$ width : num 2.6
## ..$ height : num 2.83
## ..$ backgroundColor: chr "#000000"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:8, 1:2] 0 0.694 2.256 2.604 2.083 ...
## $ :List of 7
## ..$ x : num 41.5
## ..$ y : num 187
## ..$ width : num 1.45
## ..$ height : num 29.6
## ..$ backgroundColor: chr "#ced4da"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:3, 1:2] -18.6 -18.6 -20 0 26.8 ...
## $ :List of 7
## ..$ x : num 45.6
## ..$ y : num 189
## ..$ width : int 0
## ..$ height : num 26
## ..$ backgroundColor: chr "#ced4da"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:2, 1:2] 0 0 0 26
## $ :List of 7
## ..$ x : num 13.1
## ..$ y : num 153
## ..$ width : num 47
## ..$ height : num 15.2
## ..$ backgroundColor: chr "#ced4da"
## ..$ strokeColor : chr "#000000"
## ..$ points : num [1:5, 1:2] 0 0 15.9 41.9 47 ...
d <- Excali_doc()
for (l in .kevin) {
call <- c(l,
list(
groupIds = list(list("kevin")),
strokeSharpness = "round",
fillStyle = "solid",
strokeWidth = 1L,
roughness = 0L
)
)
shape <- invoke(xkd_draw, call)
d$add(shape)
}
d$export('drawing.json')
Drawing at https://excalidraw.com/#json=5903088405708800,72BcP2Ry6NHWbHEUpidg9w