% Copyright 2010-2019 by Renée Ahrens % Copyright 2010-2019 by Olof Frahm % Copyright 2010-2019 by Jens Kluttig % Copyright 2010-2019 by Matthias Schulz % Copyright 2010-2019 by Stephan Schuster % Copyright 2019 by Jannis Pohlmann % Copyright 2019 by Till Tantau % % This file may be distributed and/or modified % % 1. under the LaTeX Project Public License and/or % 2. under the GNU Free Documentation License. % % See the file doc/generic/pgf/licenses/LICENSE for more details. \section{The Binding Layer} \label{section-gd-binding-layer} \ifluatex \else This section of the manual can only be typeset using Lua\TeX. \expandafter\endinput \fi \subsection{Overview} This section explains how the \emph{binding} of the graph drawing system to a particular display layer works. Let me stress that all of this is important only for readers who % \begin{itemize} \item either wish to write new display system (see Section~\ref{section-gd-display-layer}) \item or wish to know more about how the graph drawing system works on the pure \pgfname\ layer (this is were the binding occurs). \end{itemize} \emph{Bindings} are used to encapsulate the details of the communication between the graph drawing system and a display system (see Section~\ref{section-gd-display-layer} for an introduction to display systems). Consider a display system that communicates with the graph drawing system. At some point, the display system would like to run an algorithm to lay out a graph. To achieve this, it will call different functions from the class |InterfaceToDisplay| and the effect of this is that a representation of the to-be-drawn graph is constructed internally and that the appropriate algorithms are run. All of this is in some sense independent of the actual display system, the class |InterfaceToDisplay| offers the same standard interface to all display systems. At some point, however, the graph drawing system may need to ``talk back'' to the display system. For instance, once the graph has been laid out, to trigger the actual rendering of the graph, the graph drawing system must ``tell'' the display layer where the vertices lie. For some display systems this is easy: if the display system itself is written in Lua, it could just access the syntactic digraph directly. However, for systems like \tikzname\ or systems written in another language, the graph drawing system needs a set of functions that it can call that will tell the display system what is going on. This is were bindings come in. The class |Binding| is an interface that defines numerous methods that will be called by the graph drawing system in different situations (see the documentation below for details). For instance, there is a function |renderVertex| that is called by the graph drawing system whenever a vertex should be rendered by the display system. The class is really just an interface in the sense of object-oriented programming. For each display system you need to create a subclass of |Binding| like |BindingToPGF| or |BindingToASCII| that implement the methods declared by |Binding|. The number of methods that need to be implemented depends on the display system. In the following, you will find the documentation of the |Binding| class in Section~\ref{section-gd-binding-doc}. Following this, we first have a quick look at how the |BindingToPGF| works and then go over a simple example of a binding to a more or less imaginary display system. This example should help readers interested in implementing their own bindings. \subsection{The Binding Class and the Interface Core} \label{section-gd-binding-doc} \includeluadocumentationof{pgf.gd.bindings.Binding} \includeluadocumentationof{pgf.gd.interface.InterfaceCore} \subsection{The Binding To PGF} \includeluadocumentationof{pgf.gd.bindings.BindingToPGF} \subsection{An Example Binding Class} \label{section-gd-binding-layer-example} In the present section a complete binding is presented to an imaginary ``\textsc{ascii} art display system'' is presented. The idea is that this display system will depict graphs using just normal letters and spaces so that, when the text is typeset in a monospace font, a visualization of the graph results. For instance: \bigskip \noindent \begin{minipage}[t]{.5\textwidth} \emph{Graph rendered by |BindingToPGF|:} \medskip \tikz [anchor=base]\graph [layered layout,level distance=2.35cm,sibling distance=1.2cm,edges={rounded corners,>={Stealth[round,sep]}}] { Alice; Bob; Charly; Dave; Eve; Fritz; George; Alice -> Bob; Alice -> Charly; Charly -> Dave; Bob -> Dave; Dave -> Eve; Eve -> Fritz; Fritz -> Alice; George -> Eve; George -> Fritz; Alice -> George; }; \end{minipage}% \begin{minipage}[t]{.49\textwidth} \emph{Graph rendered by |BindingToASCII|:} \begin{verbatim} Alice ....... .. . . . ... . . . ... .. . .. .. . . . Charly Bob . . .. . . . . . . . . . . . .. . . . .. . . Dave George . .. . ... . . . .. . . . ... .. . . ... .. . .. Eve . .. .. . .. . . . . . . .. . .. ... Fritz \end{verbatim} \end{minipage} \bigskip The binding will reside in a file |BindingToASCII.lua|, whose contents is detailed below, and which is used by calling the |bind| function of |InterfaceToDisplay|, see its documentation for details. The binding's code starts with some initializations: % \begin{codeexample}[code only] -- File BindingToASCII.lua -- Imports local lib = require "pgf.gd.lib" -- Subclass the Binding class: local BindingToASCII = lib.class { base_class = require "pgf.gd.bindings.Binding" } \end{codeexample} The interesting code is the code for ``rendering'' a graph. The graph drawing system will invoke the binding's methods |renderStart| and |renderStop| to signal that the graph drawing algorithms have finished and that the vertices and edges can now be drawn. In our \textsc{ascii} renderer, we use a two-dimensional field holding characters that severs as the ``drawing canvas''. At the beginning of the rendering, we initialize it with blanks: % \begin{codeexample}[code only] local canvas function BindingToASCII:renderStart() canvas = {} -- Clear the canvas for x=-30,30 do canvas [x] = {} for y=-30,30 do canvas[x][y] = ' ' end end end \end{codeexample} In order to ``render'' a vertex, the graph drawing system will call the |renderVertex| method. The binding of \tikzname\ does a lot of complicated things in this method to retrieve the underlying node's box from internal table and to somehow reinstall the box in \TeX's output stream; for our \textsc{ascii} binding things are much simpler: We simply put the vertex's name at the canvas position corresponding to the vertex's |pos| coordinate. Note that this simple version of an \textsc{ascii} renderer does not try to scale things; thus, array out of bounds might occur here. % \begin{codeexample}[code only] function BindingToASCII:renderVertex(v) canvas [math.floor(v.pos.x)][math.floor(v.pos.y)] = v.name end \end{codeexample} The rendering of edges is a more complicated process. Given two vertices, we put dots at the canvas positions between them; provided there are no vertices (so edges are behind the nodes). Here is the essential part of the code (for the complete code, have a look at |pgf/gd/examples/BindingToASCII.lua|): % \begin{codeexample}[code only] function BindingToASCII:renderEdge(e) local function connect (p,q) -- Connect the points p and q local x1, y1, x2, y2 = math.floor(p.x+0.5), math.floor(p.y+0.5), math.floor(q.x+0.5), math.floor(q.y+0.5) ... local delta_x = x2-x1 local delta_y = y2-y1 ... local slope = delta_y/delta_x for i=x1,x2 do local x,y = i, math.floor(y1 + (i-x1)*slope + 0.5) if canvas[x][y] == " " then canvas[x][y] = '.' end end ... end -- Iterate over all points on the path from tail to head: local p = e.tail.pos for i=1,#e.path do connect(p, e.tail.pos + e.path[i]) p = e.tail.pos + e.path[i] end connect(p, e.head.pos) end \end{codeexample} The methods |renderVertex| and |renderEdge| will be called once for each vertex and edge of the to-be-rendered graph. At the end, the |renderStop| method is called. In our case, this method will output the canvas using |print|. A slight complication arises when node names are longer than just one character. In this case, the following code ``centers'' them on their coordinate and makes sure that they do not get overwritten by the dots forming edges: % \begin{codeexample}[code only] function BindingToASCII:renderStop() for y=10,-30,-1 do local t = {} for x=-30,30 do local s = canvas[x][y] for i=1,#s do pos = x+30+i-math.floor(#s/2) if not t[pos] or t[pos] == " " or t[pos] == "." then t[pos] = string.sub(s,i,i) end end end print(table.concat(t)) end end \end{codeexample} At the end, we need to return the created object: % \begin{codeexample}[code only] return BindingToASCII \end{codeexample}