The GRADIFF Specification v0.1-rc21

A Differential File Format for Graphs and Diagrams

Published on:

1. General Information#

1.1. About this Specification#

This specification aims to describe the GRADIFF file format as precisely as possible, to serve as a reference for implementers of software wanting to support GRADIFF. A Rust-based reference implementation of GRADIFF is available at https://codeberg.org/gradis/gradiff-rs.

This document is written in the AsciiDoc markup language. For more information on AsciiDoc, refer to https://asciidoc.org.

The document will contain both free-text descriptions of the various components of a GRADIFF file as well as ABNF snippets for a more formal definition. See https://www.rfc-editor.org/rfc/rfc5234.html for details on ABNF, and https://www.rfc-editor.org/rfc/rfc7405.html for details on the case-sensitive extension of ABNF used throughout this document.

The GRADIFF specification is © 2022 Lucas Hinderberger. It is licensed under the Creative Commons BY-SA 4.0 license. For a summary, refer to https://creativecommons.org/licenses/by-sa/4.0/

As an exception, all examples are published under the terms of CC0 1.0. For a summary refer to https://creativecommons.org/publicdomain/zero/1.0/.

1.2. Purpose and Summary#

The purpose of the GRADIFF file format is to provide a text-based file format for graphs and diagrams which can be easily versioned, stand-alone as well as in a version control system.

To achieve this purpose, GRADIFF is an unambiguous differential file format. This means that a GRADIFF file consists of multiple incremental changes instead of a direct representation of the diagram’s structure, as is the case with most other formats (to retrieve such a structural representation, the changes described in a GRADIFF file must be replayed, a technique known as Event Sourcing). It also means that the GRADIFF specification leaves no room for ambiguities/variations when de/encoding GRADIFF files, such as e.g. leading/trailing zeroes. In other words: One GRADIFF File has only one correct way of being (re-)encoded.

This ensures that diffs between two versions of a diagram remain simple, comprehensible and stable. It also enables standalone versioning of a diagram (meaning without the use of a dedicated version control system) through the use of partial replays.

It is not the purpose of the GRADIFF file format to become a portable and permanent format for diagrams, such as for example SVG or PDF. It is intended as a format used throughout the creation and collaborative editing of diagrams, not for the archival or distribution (to end users) of diagrams.

1.3. Status#

GRADIFF v0.1 will focus on the simplest possible use case: Simple labelled diagrams of boxes and arrows.

Based on GRADIFF v0.1, an MVP version of libgradiff (the reference implementation of GRADIFF) and GRADIS (a graphical editor for GRADIFF diagrams) will be built.

In future iterations, more useful features will be added, such as other shapes, and more styling options.

1.4. Versioning and Compatibility#

The GRADIFF Specification is versioned in a major.minor scheme. There is no Patch version.

Increments of the major version of GRADIFF indicate breaking changes to the format whereas increments of the minor version indicate that new features were added to the format without invalidating GRADIFF files written using older versions of the format. In other words, a valid GRADIFF v1.x file is always also a valid GRADIFF v1.x+1 file, but not necessarily a valid v2.x file.

Caution
For GRADIFF v0.x (i.e. pre-v1.0), new minor-version releases can contain breaking changes. Any breaking changes will be announced in the specification’s changelog.

1.5. Units and Coordinate System#

GRADIFF uses a coordinate system extending from the bottom-left corner of the page outwards in the X (right) and Y (up) directions.

The depth axis (Z) is subdivided into discrete, integer steps starting at zero for the Canvas and increasing in the positive direction. Negative Z values are not allowed. If two objects have the same Z position, their drawing precedence is determined by the lexicographical order of their IDs; the object with the lowest-ranked ID is drawn first (e.g. object objBar is drawn before objFoo).

Millimeters are chosen as unit to ensure consistent printing and scaled on-screen rendering, regardless of screen resolution.

For typographical sizing, the unit used is the DTP point (see https://en.wikipedia.org/wiki/Point_(typography)#Desktop_publishing_point).

2. Structure and Parsing#

2.1. Top-level Structure of a GRADIFF file#

A GRADIFF file is a UTF-8 encoded plain-text file with UNIX line endings (line feed).

It consists of a File Header, followed by zero or more Chunks.

For better visual separation, it is required to insert two blank lines before each Chunk.

Note
Chunk includes a trailing line feed, see Section 2.3.1, “Structure of a Chunk”.

The final Chunk may be followed by an arbitrary number of additional blank lines.

This is the ABNF definition for a GRADIFF file:

file = file-header LF *(2LF chunk) *LF

2.2. File Header#

2.2.1. Structure of the File Header#

The File Header introduces a GRADIFF file with legal and compatibility information.

It consists of an optional section containing legal boilerplate, followed by a line containing version information.

This is the ABNF definition for the File Header (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”):

file-header = [boilerplate 2LF] format-version

2.2.2. Legal Boilerplate#

At the beginning of a GRADIFF file, you can place legal boilerplate in free-text lines that begin with a hash sign (#).

This is the ABNF definition for the Legal Boilerplate (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”).

boilerplate = HASH *BPLCHAR *[LF HASH *BPLCHAR]

2.2.3. Format Version#

Format Version identifies the version of GRADIFF that was used to encode a given file. Using the Format Version in the File Header, GRADIFF implementations can determine if and how they are able to parse a GRADIFF file.

It consists of the word GRADIFF, followed by the version of GRADIFF used. For the present version of GRADIFF, this would for example be:

GRADIFF v0.1

For information about the semantics of the GRADIFF version, please see Section 1.4, “Versioning and Compatibility”.

The permissible range of both major and minor GRADIFF versions is [0;255].

This is the ABNF definition for the Format Version (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”):

format-version = %s"GRADIFF v" major-version DOT minor-version
major-version = 1*3DIGIT
minor-version = 1*3DIGIT

2.2.4. Examples#

A minimal file header
GRADIFF v0.1
A file header with legal boilerplate
# Copyright 2022 John Doe and Contributors <noreply@gradis-project.org>
# SPDX-License-Identifier: CC0-1.0

GRADIFF v0.1

2.3. Chunks#

A Chunk encapsulates a single, coherent set of one or more Changes that was performed on a GRADIFF diagram. A complete diagram is represented by the sum of all Changes represented in all Chunks.

When a GRADIFF diagram is changed, a new Chunk is appended to the diagram’s Chunks. That way, a complete history of changes is preserved.

Besides the Changes themselves, each Chunk also contains metadata about the Change, such as a Timestamp.

Note
The first Chunk in a diagram must start with a CREATE change that creates a Canvas. See Section 4.3, “Canvas” for details.

2.3.1. Structure of a Chunk#

A Chunk is introduced by the sequence [Chunk], and consists of the Chunk’s Metadata Attributes, followed by a separating clear line, concluded by one or more Changes.

The Chunk’s Metadata consists of attributes that may be helpful in analyzing the editing history of a GRADIFF diagram.

This is the ABNF definition for a Chunk (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”):

chunk = %s"[Chunk]" LF 1*(attribute LF) LF 1*(change LF)

2.3.2. Chunk Metadata#

The Chunk Metadata consists of Attributes, where each Attribute is a Key-Value-Mapping.

Note
While in general an Attribute a doesn’t contain line breaks, for String Values it can actually span multiple lines, as indicated by the definition of String Values.

The name of an attribute must start with at least one ASCII alphabetic character and it must not be longer than 64 characters.

This is the ABNF definition of an Attribute (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of values, please refer to Section 2.5.4, “Value”):

attribute = attribute-name COLON SP value
attribute-name = ALPHA *63ATTRNCHAR
Note
Implementations must retain the order of all Attributes found in the Chunk when saving a previously loaded file. This is to ensure that diffs remain stable and noise-free.

For a list of available Chunk Metadata Attributes, please refer to Section 3, “Chunk Metadata Attributes”.

2.3.3. Examples#

This is an example for a set of GRADIFF chunks:

[Chunk]
Timestamp: @2022-08-30T17:30:00Z

CREATE ptBoxHelloAnchor: PointAbsolute(30, 70)
CREATE boxHello: Box($ptBoxHelloAnchor, 40, 40)
SET boxHello.Text = "Hello World!"


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T22:00:00Z

CREATE ptBoxFoobarAnchor: PointAbsolute(60, 60)
CREATE boxFoobar: Box($ptBoxFoobarAnchor, 20, 20)
SET boxFoobar.Text = "Foo, Bar and Baz"
SET boxFoobar.TextColor = FF0000FF

2.4. Changes#

Changes are the atomic building blocks of a GRADIS diagram. Each Change represents a single, small-scale modification to the diagram, such as changing the text or size of an object.

There are six types of Changes:

2.4.1. CREATE#

A CREATE Change creates a new object in the diagram.

When creating an object, you must give it a unique identifier and specify all parameters that are necessary for initializing the object. The concrete parameters for each type of object are specified in the object’s corresponding section in the Section 4, “Object Reference”.

This is the ABNF definition for a CREATE Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definitions of identifiers and values, please refer to Section 2.5.2, “Identifier” and Section 2.5.4, “Value”):

create-change = %s"CREATE" SP identifier COLON SP object-constructor
object-constructor = identifier LPAREN [constructor-params] RPAREN
constructor-params = value *(COMMA SP value)

A CREATE Change can look like this:

CREATE boxHello: Box($ptBoxHelloAnchor, 40, 40)

2.4.2. SET#

A SET Change sets the value of a property of an existing object in the diagram.

This is the ABNF definition for a SET Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of values, please refer to Section 2.5.4, “Value”; for the definition of parameter paths, please refer to Section 2.5.3, “Parameter Path”):

set-change = %s"SET" SP param-path SP EQUAL SP value

A SET Change can look like this:

SET boxHello.Text = "Hello World!"

2.4.3. DELETE#

A DELETE Change deletes an object from a GRADIFF diagram.

Note
Deleting objects is only allowed when no other objects refer to them any more. Thus, to for example delete a Point object, you first need to modify the Arrow objects that refer to that Point, e.g. by replacing the Point with another Point or by deleting it from the arrow (if possible).

This is the ABNF definition for a DELETE Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of identifiers, please refer to Section 2.5.2, “Identifier”):

delete-change = %s"DELETE" SP identifier

A DELETE Change can look like this:

DELETE boxHello

2.4.4. RENAME#

A RENAME Change gives an object in a GRADIFF diagram a new identifier and updates all object properties of dependent objects that refer to the depended-upon object’s old name. All following Changes must refer to the object using its new identifier.

For the avoidance of doubt, Changes that occurred before the RENAME change do not need to be modified to refer to the object’s new name, since the point of GRADIFF is to be an incremental file format with immutable Chunks.

Caution
Implementations must ensure proper cache invalidation, if the object that is to be renamed is already depended upon by other objects, and those objects' properties are cached.

This is the ABNF definition for a RENAME Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of identifiers, please refer to Section 2.5.2, “Identifier”):

rename-change = %s"RENAME" SP identifier SP RARROW SP identifier

A RENAME Change can look like this:

RENAME boxHello -> boxBonjour

2.4.5. ARRINSERT#

Some objects in a GRADIFF diagram can have array properties. An ARRINSERT Change inserts a value into the property array at the specified index. If there already is a value at the specified index, it, and any following array elements, will be moved to the next-highest positions; the array will thus be enlarged by one.

This is the ABNF definition for an ARRINSERT Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of parameter paths, please refer to Section 2.5.3, “Parameter Path”; for the definition of array indices, please refer to Section 2.5.1, “Array Index”):

arrinsert-change = %s"ARRINSERT" SP param-path array-index COLON SP value

An ARRINSERT Change can look like this:

ARRINSERT fooArrow.Points[1]: $intermediatePointID

2.4.6. ARRDELETE#

An ARRDELETE Change deletes the element at the given index from a property array.

If there are elements after the deleted element, they will each be moved to the next-lowest positions; the array will thus be shortened by one.

Trying to delete from a non-existing index is not allowed.

This is the ABNF definition for an ARRDELETE Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of parameter paths, please refer to Section 2.5.3, “Parameter Path”; for the definition of array indices, please refer to Section 2.5.1, “Array Index”):

arrdelete-change = %s"ARRDELETE" SP param-path array-index

An ARRDELETE Change can look like this:

ARRDELETE fooArrow.Points[2]

2.4.7. SELECT#

A SELECT Change selects another Canvas.

By default, the last created Canvas is selected automatically.

This is the ABNF definition for a SELECT Change (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”; for the definition of identifiers, please refer to Section 2.5.2, “Identifier”):

select-change = %s"SELECT" SP identifier

A SELECT Change can look like this:

SELECT canvasB

2.5. Common Definitions#

2.5.1. Array Index#

An array index is used to refer to a particular element of an array.

It consists of the 0-based index, contained in square brackets.

The index must not exceed 4,294,967,295 (2^32 - 1).

Note
Implementations must not encode array indices with superfluous leading zeroes. This is to ensure that the diff of a modified GRADIFF file includes only the changes that actually occurred, instead of variations in encoding values that actually have not changed.

This is the ABNF definition of an Array Index (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”):

array-index = LSQBRACK 1*10DIGIT RSQBRACK

2.5.2. Identifier#

Identifiers are used for naming Attributes, Objects and Properties.

Contrary to String Values, Identifiers are limited in character set and length, with 32 characters being the maximum length for a valid GRADIFF identifier.

Note
When multiple identifiers are specified to be used in conjunction with each other, each of the single identifiers has its own individual length limit.

This is the ABNF definition of an Identifier (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”):

identifier = 1*32IDCHAR

2.5.3. Parameter Path#

A Parameter Path is used to identify the parameter of a particular Object instance.

It consists of the ID of the object followed by the name of the Parameter, as indicated in the Object Reference (see Section 4, “Object Reference”). Object ID and Parameter name are separated by a dot.

This is the ABNF definition of a Parameter Path (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”, for the definition of identifiers, please refer to Section 2.5.2, “Identifier”):

param-path = identifier DOT identifier

2.5.4. Value#

Values embody user-defined data e.g. in Attributes or Object Properties.

There are five data types in GRADIFF: Strings, Numbers, Timestamps, Colors and Identifier Values.

String Values can contain arbitrary Unicode characters. They are delimited by quotation marks. Quotation marks inside String Values are escaped using a backslash (the same applies to backslashes themselves). They can also be split across multiple lines by way of adding a line feed followed by a space between two pairs of quotation mark-delimited substrings.

Number Values are floating point numbers that must be parsed into IEEE754 double-precision (64-bit) numbers. This means that their range equals that of an IEEE754 double-precision number, unless the range is more restricted in the documentation of the respective Attribute or Object Property. The fractional part of a Number Value may be omitted, if zero. If omitted, the dot that introduces the fractional part must also be omitted. Infinity is expressed by inf or -inf. NaN (Not a Number) is not allowed.

Note
Implementations must encode Number Values in a way that uses as few digits as possible (e.g. they must use 1.23 instead of 1.230). Implementations must not convert double-precision numbers to single-precision numbers when saving a previously loaded file.

Timestamp Values are non-quoted strings of the date-time format as described in RFC 3339 (see https://www.rfc-editor.org/rfc/rfc3339.html). They are prepended by an At sign (@) for unambiguous parsing of Values, since a Number Value could otherwise be a prefix of a Timestamp Value. For the avoidance of doubt, Timestamp Values in the context of GRADIFF must use upper-case "T" and "Z" markers as indicated in RFC 3339 and must not use any other separator than "T". Out-of-range values for months, days, hours minute and seconds (e.g. a timestamp referring to hour 25) are not permitted.

Note
Implementations must retain the offset of Timestamp Values when saving a previously loaded file. If the offset is zero, it should be retained whether the zero offset was expressed as +00:00, -00:00 or Z. Also, implementations must encode years, months, days, hours, minutes and seconds with leading zeroes, but must not encode nanoseconds with superfluous trailing zeroes. This is to ensure that the diff of a modified GRADIFF file includes only the changes that actually occurred, instead of variations in encoding values that actually have not changed.

Color Values are hex-encoded RGBA colors with 8 bits per channel, encoded as non-quoted strings of the format #RRGGBBAA.

Identifier Values simply wrap a GRADIFF Identifier (see Section 2.5.2, “Identifier”) for use in places where a Value is expected, by prepending the Identifier with a dollar sign.

This is the ABNF definition of a Value (for the definitions of the terminal symbols used, please refer to Section 2.5.5, “Terminal Symbols”, for the definition of identifiers, please refer to Section 2.5.2, “Identifier”):

value = color-value / identifier-value / num-value / str-value / timestamp-value
color-value = HASH 8HEXDIGIT
identifier-value = DOLLAR identifier
num-value = [MIN] (1*DIGIT [DOT 1*DIGIT] / %s"inf")
str-value = QUOT 1*(STRCHAR / ESC (ESC / QUOT) / LF SP) QUOT
timestamp-value = AT date-time ; defined in RFC3339, with case-sensitive semantics

2.5.5. Terminal Symbols#

The following terminal symbols are used in ABNF definitions throughout the document:

ALPHA = %x0041-005A / %x0061-007A ; ASCII alphabetic characters
AT = %x0040 ; an At sign (@)
COLON = %x003A ; a colon (:)
COMMA = %x002C ; a comma (,)
DIGIT = %x0030-%x0039 ; a digit (0-9)
DOLLAR = %x0024 ; an ASCII Dollar sign ($)
DOT = %x002E ; a dot (.)
ESC = %x005C ; a backslash (\) used for escaping
EQUAL = %x003D ; an equal sign (=)
HASH = %x0023 ; an ASCII hash (#)
HEXDIGIT = DIGIT / %x0041-0046 ; A hexadecimal digit, 0-9 or A-F
HYPHEN = %x002D ; a hyphen (-)
GT = %x003E ; a greater-than sign (>)
LF = %x000A ; a line feed
LPAREN = %x0028 ; a left parenthesis
LSQBRACK = %x005B ; a left square bracket ([)
MIN = HYPEN ; alias for HYPHEN, for rules where it is used as a minus sign
QUOT = %x0022 ; an ASCII quotation mark (")
RPAREN = %x0029 ; a right parenthesis
RSQBRACK = %x005D ; a right square bracket (])
SP = %x0020 ; an ASCII space ( )
UNDERSC = %x005F ; an underscore (_)

; Characters valid for use in Attribute Names
ATTRNCHAR = ALPHA / HYPHEN

; Any conceivable Unicode code point except for a line feed
BPLCHAR = %x0000-0009 / %000B-FFFF

; Characters valid for use in identifiers
IDCHAR = ALPHA / UNDERSC

; Any conceivable Unicode code point except for a backslash (\),
; quotation mark or line feed
STRCHAR = %x0000-0009 / %000B-0021 / %x0023-005B / %x005D-FFFF

; A right-facing ASCII arrow (->)
RARROW = DASH GT

Their numbers refer to Unicode code points, not UTF-8 encodings.

3. Chunk Metadata Attributes#

This contains a reference of all Chunk Metadata Attributes that are specified in this version of GRADIFF.

3.1. Required Attributes#

The following attributes are required to be present in every valid GRADIFF Chunk.

3.1.1. Timestamp#

A timestamp that contains the time the corresponding Chunk was added to the GRADIFF diagram.

The instant represented by it must be after or equal to the preceding Chunk’s Timestamp.

For more details on timestamp values, please refer to Section 2.5.4, “Value”.

3.2. Optional Attributes#

3.2.1. Author#

A string value naming the author (or comma-separated authors) of the Chunk.

It is recommended, although not required to use Email/Git-style names with appended email addresses in angled brackets. For example

Author: "John Doe <noreply@gradis-project.org>"

3.2.2. Generator#

A string value containing the name and version of the Software with which the Chunk was created.

There is no prescribed format for the Generator attribute, although it is recommended to keep it simple and use the short name of the software, followed by a space and a v-prefixed semantic version, if possible.

Generator: "GRADIS v1.2.3"

3.3. Custom Attributes#

It is permitted to set additional Chunk Metadata Attributes that are not in the aforementioned list of defined attributes, if and only if their names start with X-. Implementations must retain those header attributes when loading and saving GRADIFF chunks.

4. Object Reference#

This contains a reference of all objects that can be used within GRADIFF files.

4.1. Arrow#

An Arrow is an object that connects a number of Points (see Section 4.4, “Point”) with straight lines.

Note
In future releases of the specification, a smooth interpolation between the points may be introduced.

4.1.1. Constructors#

Default Constructor (Arrow)#

The default constructor of the Arrow type is called with the arguments (StartPointID, EndPointID) and populates the Arrow’s Points property with the two given PointIDs, respectively.

It leaves all other properties of the newly created Arrow to their default values, as indicated in their corresponding documentation.

4.1.2. Properties#

EndTipColor#

The color in which the tip of the Arrow is drawn that points to the end point of the arrow, as a Color Value.

This property defaults to #000000FF (black, non-transparent).

EndTipScale#

A factor that scales the end tip’s size up or down, as a Number Value.

For "EquilateralTriangle"-style tips, each side of the triangle has a length of 5 * LineThickness * EndTipScale.

The scale factor must be positive, nonzero and not infinite.

The EndTipScale defaults to 1.0.

EndTipStyle#

The style in which the tip of the Arrow is drawn that points to the end point of the arrow, as a String Value.

Valid values are one of "EquilateralTriangle" or "None".

Note
Implementations must place the tip inside of the arrow, pointing towards the final point of the Arrow and rotated along the direction of the end of the final arrow leg.

The EndTipStyle defaults to "EquilateralTriangle".

LineColor#

The color in which the line of the Arrow is drawn, as a Color Value.

This property defaults to #000000FF (black, non-transparent).

LineStyle#

The style in which the line of the Arrow is drawn, as a String Value.

Valid values are one of "Dashed", "Dotted" or "Solid".

The LineStyle defaults to "Solid".

LineThickness#

The thickness in which the line of the Arrow is drawn, as a Number Value in millimeters.

This also affects the size of the arrow’s tips, which will scale along with the line’s thickness.

The thickness must be positive, nonzero and not infinite.

The thickness defaults to 0.5mm.

Points#

Points is an array property containing the IDs of all points that are connected by this Arrow, in the order that they are connected, as Identifier Values.

This array must at all times have at least two entries. Attempting to delete one or both of the last two remaining entries is not permitted.

The Points property must not contain the same Point multiple times.

It is not allowed to add a point to this property that would introduce a circular dependency.

Caution
If a PointDerivedFromArrow (see Section 4.6, “PointDerivedFromArrow”) references this Arrow, it is not allowed to ARRDELETE Points if that would result in the point no longer referencing an existing arrow leg. It is recommended to change the Leg property of PointDerivedFromArrow first to avoid this situation.
StartTipColor#

The color in which the tip of the Arrow is drawn that points to the start point of the arrow, as a Color Value.

This property defaults to #000000FF (black, non-transparent).

StartTipScale#

A factor that scales the start tip’s size up or down, as a Number Value.

For "EquilateralTriangle"-style tips, each side of the triangle has a length of 5 * LineThickness * StartTipScale.

The scale factor must be positive, nonzero and not infinite.

The StartTipScale defaults to 1.0.

StartTipStyle#

The style in which the tip of the Arrow is drawn that points to the start point of the arrow, as a String Value.

Valid values are one of "EquilateralTriangle" or "None".

Note
Implementations must place the tip inside of the arrow, pointing towards the first point of the Arrow and rotated along the direction of the beginning of the final arrow leg.

The StartTipStyle defaults to "None".

Z#

The position of the Arrow on the depth axis, as a Number Value.

Its value must be positive, nonzero and not infinite.

The Z value is automatically initialized to one plus the maximum Z value present in the Canvas at the time of the object’s creation.

For more information about units and coordinate system used, as well as about the conflict resolution strategy in case two overlapping objects have the same Z position, please refer to Section 1.5, “Units and Coordinate System”.

4.2. Box#

A Box is a rectangular-shaped diagram object that can contain text.

4.2.1. Constructors#

Default Constructor (Box)#

The default constructor of the Box type is called with the arguments (AnchorPointID,Width,Height).

It leaves all other properties of the newly created box to their default values, as indicated in their corresponding documentation.

LabelBox Constructor#

The LabelBox constructor constructs a new Box that is pre-configured for easy use as an arrow label. It is called with the arguments (AnchorPointID, Width, Height, Text).

It sets both the AnchorPositionX and AnchorPositionY properties to "Center", BackgroundColor to #FFFFFF00 (white, fully transparent), BorderThickness and PaddingLeft/Right/Bottom/Top to 0 and leaves all other properties of the newly created box to their default values, as indicated in their corresponding documentation.

4.2.2. Properties#

AnchorPointID#

The AnchorPointID property contains the ID of the Point object which determines the position of this Box, as an Identifier Value.

It is not allowed to set an AnchorPointID that would introduce a circular dependency.

This property has no default value, it is initialized using the constructor.

AnchorPositionX#

The horizontal position of the Box’s anchor, relative to the Box, as a String Value.

Valid values are one of "Left", "Center" or "Right".

The AnchorPosition defaults to "Left".

AnchorPositionY#

The vertical position of the Box’s anchor, relative to the Box, as a String Value.

Valid values are one of "Top", "Center" or "Bottom".

The AnchorPosition defaults to "Top".

BackgroundColor#

The color with which the background of the Box is filled.

This property defaults to #FFFFFFFF (white, non-transparent).

BorderColor#

The color with which the border of the Box is filled.

This property defaults to #000000FF (black, non-transparent).

BorderThickness#

The thickness of the Box’s border, as a Number Value in millimeters.

If a thickness of zero is specified, the border will not be rendered.

Negative and infinite thicknesses are not allowed.

This property defaults to 0.5mm.

For more information about the unit used, please refer to Section 1.5, “Units and Coordinate System”.

FontFamily#

A String Value containing the name of the font family used to render the text.

This property must not contain an empty string.

This property defaults to "sans-serif", which resolves to a suitable sans-serif default font when rendering.

FontSize#

The font size, in points, as a Number Value.

It must be positive, nonzero and not infinite.

This property defaults to 12pt.

For more information about the unit used, please refer to Section 1.5, “Units and Coordinate System”.

FontStretch#

The horizontal stretch of the font used to render the text, as a Number Value.

The valid range for the font weight is [0.5;2.0].

This property defaults to 1.0.

FontStyle#

A String Value containing the style of the font used to render the text.

Valid values are one of "Normal", "Italic" and "Oblique".

This property defaults to "Normal".

FontWeight#

The weight of the font used to render the text, as a Number Value.

The valid range for the font weight is [100;900].

This property defaults to 400.

Height, Width#

The height/width of the Box, as a Number Value in millimeters.

These properties have no default value, they are always set using the constructor.

Their values must be positive, nonzero and not infinite.

For more information about the unit used, please refer to Section 1.5, “Units and Coordinate System”.

LineHeight#

The line height is expressed a factor of the normal line height, as a Number Value.

It must be positive, nonzero and not infinite.

This property defaults to 1.0, the normal line height.

PaddingBottom, PaddingLeft, PaddingRight and PaddingTop#

The inside padding of the Box, as a Number Value in millimeters.

The padding empty space starts at the inside edge of the Box’s border. The thickness of the border is not part of the padding.

It is not allowed to set these properties to positive or negative infinity.

The padding defaults to 4mm for all sides of the Box.

For more information about the unit used, please refer to Section 1.5, “Units and Coordinate System”.

Text#

The text contained in the object, as a String Value.

Text may contain line breaks, which must be rendered accordingly.

If the text’s size exceeds the size of the object, it shall be clipped by removing the overlapping text in accordance to the text’s alignment. This means that for top-aligned text, the bottom shall be clipped, for left-aligned text the right, for center-aligned text both top and bottom / left and right and so on. The padding of the object, if any, must be respected. Text is not allowed to render into the padding space, even if it could otherwise avoid clipping.

This property’s default value is an empty string.

TextColor#

The color with which the text is filled.

This property defaults to #000000FF (black, non-transparent).

TextHAlignment#

The horizontal alignment of the text, as a String Value.

Valid values are one of "Left", "Center" and "Right".

This property defaults to "Center".

TextVAlignment#

The vertical alignment of the text, as a String Value.

Valid values are one of "Top", "Center" and "Bottom".

This property defaults to "Center".

Z#

The position of the Box on the depth axis, as a Number Value.

Its value must be positive, nonzero and not infinite.

The Z value is automatically initialized to one plus the maximum Z value present in the Canvas at the time of the object’s creation.

For more information about units and coordinate system used, as well as about the conflict resolution strategy in case two overlapping objects have the same Z position, please refer to Section 1.5, “Units and Coordinate System”.

4.3. Canvas#

A Canvas determines the size and background of a diagram.

Each diagram must have exactly one Canvas object.

The first Chunk in a diagram must start with a CREATE change that creates a Canvas, using one of Canvas’s constructors (see Section 4.3.1, “Constructors”).

The ID for a Canvas object can be chosen freely.

4.3.1. Constructors#

Default Constructor (Canvas)#

The default constructor of the Canvas type is called with the arguments (Width,Height).

It leaves all other properties of the newly created canvas to their default values, as indicated in their corresponding documentation.

4.3.2. Properties#

BackgroundColor#

The color with which the background of the Canvas is filled.

This property defaults to #FFFFFFFF (white, non-transparent).

Height, Width#

The height/width of the Canvas, as a Number Value in millimeters.

These properties have no default value, they are always set using the constructor.

Their values must be positive and nonzero.

It is permitted to set the width and/or height to infinity.

For more information about the unit used, please refer to Section 1.5, “Units and Coordinate System”.

4.4. Point#

Point objects mark a point in the diagram that is used for other Objects to refer to. Points are not visible in the rendered diagram, but they are modifiable by the user. Point is an abstract object type, its concrete manifestations are Section 4.5, “PointAbsolute” and Section 4.7, “PointDerivedFromSide”.

4.5. PointAbsolute#

A PointAbsolute object is a Point (see Section 4.4, “Point”) of which the position is not derived from another object, but fixed to a set of X/Y coordinates.

4.5.1. Constructors#

Default Constructor (PointAbsolute)#

The default constructor of the PointAbsolute type is called with the arguments (X,Y).

4.5.2. Properties#

X, Y#

The X, Y coordinate of the point, as a Number Value in millimeters.

It is not allowed to set these properties to positive or negative infinity.

These properties have no default value, it is initialized using the constructor.

For more information about units and coordinate system used, please refer to Section 1.5, “Units and Coordinate System”.

4.6. PointDerivedFromArrow#

A PointDerivedFromArrow object is a Point (see Section 4.4, “Point”) of which the position is derived from the path of an Arrow leg (see Section 4.1, “Arrow”).

4.6.1. Constructors#

Default Constructor (PointDerivedFromArrow)#

The default constructor of the PointDerivedFromArrow type is called with the arguments (ArrowID, Leg).

It leaves all other properties of the newly created PointDerivedFromArrow to their default values, as indicated in their corresponding documentation.

4.6.2. Properties#

ArrowID#

The ArrowID property contains the ID of the Arrow object to which this point is attached, as an Identifier Value.

It is not allowed to set an ArrowID that would introduce a circular dependency.

Caution
When updating ArrowID, you must change the Leg property first if the new Arrow doesn’t have enough legs to accommodate for the current value of the Leg property (see Section 4.6.2.2, “Leg”).

This property has no default value, it is initialized using the constructor.

Leg#

The number of the Leg of the Arrow that this point is attached to, as a Number Value.

This must be an integer value in the range of [0,len(Arrow.Points)-2].

This property has no default value, it is initialized using the constructor.

OffsetLateral#

The offset from the center of the Arrow’s leg, orthogonal to its direction, as a Number Value, in millimeters.

It is not allowed to set this property to positive or negative infinity.

This property has the default value 0mm.

For more information about the coordinate system used, please refer to Section 1.5, “Units and Coordinate System”.

OffsetLongitudinal#

The offset from the center of the Arrow’s leg, along to its direction, as a Number Value.

It is not allowed to set this property to positive or negative infinity.

The value of this property is a factor of the total length of the leg, without a prescribed limit (although values around -0.5 to 0.5 are considered practical, with deviations until a magnitude of 2.0-3.0 likely being justified in exceptional circumstances).

This property has the default value 0.0.

For more information about the coordinate system used, please refer to Section 1.5, “Units and Coordinate System”.

4.7. PointDerivedFromSide#

A PointDerivedFromSide object is a Point (see Section 4.4, “Point”) of which the position is derived from another object’s position and dimensions by attaching it to one of the sides of that other object.

4.7.1. Constructors#

Default Constructor (PointDerivedFromSide)#

The default constructor of the PointDerivedFromSide type is called with the arguments (ParentID, Side).

It leaves all other properties of the newly created PointDerivedFromSide object to their default values, as indicated in their corresponding documentation.

4.7.2. Properties#

ParentID#

The ID of the parent object of which the position of this point is derived, as an Identifier Value.

PointDerivedFromSide can be derived from parents of type Box.

It is not allowed to set a ParentID that would introduce a circular dependency.

This property has no default value, it is initialized using the constructor.

Side#

The side of the parent object, at the center of which the point shall be placed.

Valid values are one of "Bottom", "Left", "Right", "Top".

This property has no default value, it is initialized using the constructor.

OffsetX, OffsetY#

The offset from the center of the Parent Object’s side, in X/Y direction, as a Number Value in millimeters.

It is not allowed to set this property to positive or negative infinity.

These properties default to 0mm.

For more information about units and coordinate system used, please refer to Section 1.5, “Units and Coordinate System”.

5. Examples#

5.1. An Empty Diagram#

# Copyright 2022 John Doe and Contributors <noreply@gradis-project.org>
# SPDX-License-Identifier: CC0-1.0

GRADIFF v0.1

5.2. A Blank Canvas#

# Copyright 2022 John Doe and Contributors <noreply@gradis-project.org>
# SPDX-License-Identifier: CC0-1.0

GRADIFF v0.1


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T17:30:00Z

CREATE canvas: Canvas(210, 297)

5.3. A "Hello World" Example#

# Copyright 2022 John Doe and Contributors <noreply@gradis-project.org>
# SPDX-License-Identifier: CC0-1.0

GRADIFF v0.1


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T17:30:00Z

CREATE canvas: Canvas(100, 100)
CREATE ptBoxHelloAnchor: PointAbsolute(30, 70)
CREATE boxHello: Box($ptBoxHelloAnchor, 40, 40)
SET boxHello.Text = "Hello World!"

5.4. Two boxes, connected with a labelled Arrow#

# Copyright 2022 John Doe and Contributors <noreply@gradis-project.org>
# SPDX-License-Identifier: CC0-1.0

GRADIFF v0.1


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T17:30:00Z

CREATE canvas: Canvas(100, 100)
CREATE ptBoxHelloAnchor: PointAbsolute(30, 70)
CREATE boxHello: Box($ptBoxHelloAnchor, 40, 40)
SET boxHello.Text = "Hello World!"


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T17:45:00Z

SET boxHello.Height = 20
SET boxHello.Width = 50
SET ptBoxHelloAnchor.X = 25
SET ptBoxHelloAnchor.Y = 90
CREATE ptBoxBonjourAnchor: PointAbsolute(25, 30)
CREATE boxBonjour: Box($ptBoxBonjourAnchor, 50, 20)
SET boxBonjour.Text = "Bonjour Le Monde!"


[Chunk]
Author: "John Doe <noreply@gradis-project.org>"
Timestamp: @2022-08-30T17:50:00Z

CREATE ptArrowSrc: PointDerivedFromSide($boxHello, "Bottom")
CREATE ptArrowDest: PointDerivedFromSide($boxBonjour, "Top")
CREATE arrow: Arrow($ptArrowSrc, $ptArrowDest)
CREATE ptArrowMiddle: PointDerivedFromArrow($arrow, 0)
CREATE lblTranslatesTo: LabelBox($ptArrowMiddle, 30, 10, "translates to")