1#
2# francy: Interactive Discrete Mathematics in GAP
3#
4
5#############################################################################
6##
7#M  Canvas( <title>, <options> ) . . . . . a new graphic canvas
8##
9InstallMethod(Canvas,
10  "a title string, a default configurations record",
11  true,
12  [IsString,
13   IsCanvasDefaults],
14  0,
15function(title, options)
16  return MergeObjects(Objectify(CanvasObjectType, rec(
17    id       := GenerateID(),
18    menus    := rec(),
19    graph    := rec(),
20    chart    := rec(),
21    messages := rec(),
22    title    := title
23  )), options);
24end);
25
26InstallOtherMethod(Canvas,
27  "a title string",
28  true,
29  [IsString],
30  0,
31function(title)
32  return Canvas(title, CanvasDefaults);
33end);
34
35#############################################################################
36##
37#M  Add( <canvas>, <francy object> ) . . . . . add objects to canvas
38##
39InstallOtherMethod(Add,
40  "a canvas, a graph",
41  true,
42  [IsCanvas,
43   IsFrancyGraph],
44  0,
45function(canvas, graph)
46  canvas!.graph := graph;
47  # unbind the chart, only graph should exist!
48  Unbind(canvas!.chart);
49  return canvas;
50end);
51
52InstallOtherMethod(Add,
53  "a canvas, a chart",
54  true,
55  [IsCanvas,
56   IsChart],
57  0,
58function(canvas, chart)
59  canvas!.chart := chart;
60  # unbind the graph, only chart should exist!
61  Unbind(canvas!.graph);
62  return canvas;
63end);
64
65InstallOtherMethod(Add,
66  "a canvas, a menu",
67  true,
68  [IsCanvas,
69   IsMenu],
70  0,
71function(canvas, menu)
72  canvas!.menus!.(menu!.id) := menu;
73  return canvas;
74end);
75
76InstallOtherMethod(Add,
77  "a canvas, a message",
78  true,
79  [IsCanvas,
80   IsFrancyMessage],
81  0,
82function(canvas, message)
83  canvas!.messages!.(message!.id) := message;
84  return canvas;
85end);
86
87InstallOtherMethod(Add,
88  "a canvas, a list of francy objects",
89  true,
90  [IsCanvas,
91   IsList],
92  0,
93function(canvas, objects)
94  local object;
95  for object in objects do
96    Add(canvas, object);
97  od;
98  return canvas;
99end);
100
101#############################################################################
102##
103#M  Remove( <canvas>, <francy object> ) . . . . . remove object from canvas
104##
105InstallOtherMethod(Remove,
106  "a canvas, a graph",
107  true,
108  [IsCanvas,
109   IsFrancyGraph],
110  0,
111function(canvas, graph)
112  Unbind(canvas!.graph);
113  canvas!.graph := rec();
114  canvas!.chart := rec();
115  return canvas;
116end);
117
118InstallOtherMethod(Remove,
119  "a canvas, a chart",
120  true,
121  [IsCanvas,
122   IsChart],
123  0,
124function(canvas, chart)
125  Unbind(canvas!.chart);
126  canvas!.graph := rec();
127  canvas!.chart := rec();
128  return canvas;
129end);
130
131InstallOtherMethod(Remove,
132  "a canvas, a menu",
133  true,
134  [IsCanvas,
135   IsMenu],
136  0,
137function(canvas, menu)
138  Unbind(canvas!.menus!.(menu!.id));
139  return canvas;
140end);
141
142InstallOtherMethod(Remove,
143  "a canvas, a message",
144  true,
145  [IsCanvas,
146   IsFrancyMessage],
147  0,
148function(canvas, message)
149  Unbind(canvas!.messages!.(message!.id));
150  return canvas;
151end);
152
153InstallOtherMethod(Remove,
154  "a canvas, a list of francy objects",
155  true,
156  [IsCanvas,
157   IsList],
158  0,
159function(canvas, objects)
160  local object;
161  for object in objects do
162    Remove(canvas, object);
163  od;
164  return canvas;
165end);
166
167#############################################################################
168##
169#M  Draw( ) . . . . .
170##
171InstallMethod(Draw,
172  "a canvas",
173  true,
174  [IsCanvas],
175  0,
176function(canvas)
177  local object;
178  object := rec();
179  object!.mime    := FrancyMIMEType;
180  object!.version := InstalledPackageVersion("francy");
181  object!.canvas  := Sanitize(canvas);
182  return Objectify(
183    JupyterRenderableType,
184    rec(
185      data := rec((FrancyMIMEType) := GapToJsonString(object)),
186      metadata := rec((FrancyMIMEType) := rec())
187    )
188  );
189end);
190
191#############################################################################
192##
193#M  DrawSplash( ) . . . . .
194##
195InstallMethod(DrawSplash,
196  "a canvas",
197  true,
198  [IsCanvas],
199  0,
200function(canvas)
201    local name, result, page;
202
203    name := Filename(DirectoryTemporary(), Concatenation("francy_", LowercaseString(ReplacedString(canvas!.title, " ", "_")) ,".html"));
204
205    result := Draw(canvas);
206
207    page := Concatenation(
208    "<!DOCTYPE html>\n\
209    <html>\n\
210      <head>\n\
211        <meta charset=\"utf-8\" content=\"text/html\" property=\"GAP,francy,d3.v5\"></meta>\n\
212        <link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.rawgit.com/mcmartins/francy/develop/js/extensions/browser/index.css\"></link>\n\
213        <script src=\"https://d3js.org/d3.v5.js\"></script>\n\
214        <script src=\"https://cdn.rawgit.com/mcmartins/francy/master/js/extensions/browser/francy.bundle.js\"></script>\n\
215        <title>Francy</title>\n\
216      </head>\n\
217      <body>\n\
218        <div id=\"francy\"></div>\n\
219        <script>\n\
220          var francy = new Francy({verbose: true, appendTo: 'body', callbackHandler: console.log});\n\
221          francy.load(", result!.data!.(FrancyMIMEType), ").render();\n\
222        </script>\n\
223      </body>\n\
224    </html>");
225
226    PrintTo(name, page);
227
228    if ARCH_IS_MAC_OS_X() or ARCH_IS_UNIX() then
229        Exec("open ",name);
230    elif ARCH_IS_WINDOWS() then
231        Exec("start ",name);
232    fi;
233
234    return page;
235end);
236