34
35:- module(swish_render_c3,
36 [ term_rendering//3 37 ]). 38:- use_module(library(apply)). 39:- use_module(library(lists)). 40:- use_module(library(gensym)). 41:- use_module(library(error)). 42:- use_module(library(dif)). 43:- use_module(library(http/html_write)). 44:- use_module(library(http/js_write)). 45:- if(exists_source(library(dicts))). 46:- use_module(library(dicts)). 47:- endif. 48:- use_module('../render'). 49
50:- register_renderer(c3, "Render data as tables"). 51
56
61
65
66term_rendering(C30, _Vars, _Options) -->
67 { is_dict(C30, Tag),
68 Tag == c3,
69 valid_c3(C30, C3),
70 gensym('c3js', Id),
71 atom_concat(#, Id, RefId),
72 put_dict(bindto, C3, RefId, C3b)
73 },
74 html(div([ class(['render-C3', 'reactive-size', 'export-dom']),
75 'data-render'('As C3 chart')
76 ],
77 [ div(id(Id), []),
78 \js_script({|javascript(C3b)||
79(function() {
80 if ( $.ajaxScript ) {
81 var div = $.ajaxScript.parent();
82 var data = C3b;
83 var chart;
84 var sizing = {};
85 var tmo;
86
87 div.on("export-dom", function(ev, r) {
88 var svg = div.find("svg");
89 svg.attr("xmlns", "http://www.w3.org/2000/svg");
90 svg.css("font", "10px sans-serif");
91 svg.find(".c3-path,.c3-line,.tick,.domain").css("fill", "none");
92 svg.find(".tick,.domain").css("stroke", "#000");
93 r.element = svg[0];
94 r.extension = "svg";
95 r.contentType = "image/svg+xml";
96 });
97
98 div.on("reactive-resize", function() {
99 if ( chart ) {
100 if ( tmo ) clearTimeout(tmo);
101 tmo = setTimeout(function() {
102 if ( updateSize() ) chart.resize(data.size);
103 }, 1000);
104 }
105 });
106
107 function updateSize() {
108 data.size = data.size||{};
109 var w0 = data.size.width;
110 var h0 = data.size.height;
111
112 if ( data.size.width == undefined || sizing.width ) {
113 var w = div.parents("div.answer").innerWidth();
114 data.size.width = Math.max(w*0.85, 100);
115 sizing.width = true;
116 if ( data.size.height == undefined || sizing.height ) {
117 data.size.height = data.size.width/2+50;
118 sizing.height = true;
119 }
120 }
121
122 return data.size.width != w0 || data.size.height != h0;
123 }
124
125 require(["d3", "c3"], function(d3, c3) {
126 updateSize();
127 chart = c3.generate(data);
128 });
129 }
130})();
131 |})
132 ])).
133
134
138
139valid_c3(C30, C31) :-
140 Data0 = C30.data,
141 valid_c3_data(Data0, Data),
142 ( same_term(Data0, Data)
143 -> C31 = C30
144 ; C31 = C30.put(data,Data)
145 ).
146
147valid_c3_data(Data0, Data) :-
148 Rows0 = Data0.get(rows), !,
149 must_be(acyclic, Rows0),
150 rows_to_matrix(Rows0, Rows),
151 must_be(list(ground), Rows),
152 ( same_term(Rows0, Rows)
153 -> Data0 = Data
154 ; Data = Data0.put(rows,Rows)
155 ).
156valid_c3_data(Data0, Data) :-
157 Columns0 = Data0.get(columns), !,
158 must_be(acyclic, Columns0),
159 ( rows_to_matrix(Columns0, Columns)
160 -> true
161 ; maplist(is_list, Columns0)
162 -> Columns = Columns0
163 ),
164 must_be(list(ground), Columns),
165 ( same_term(Columns0, Columns)
166 -> Data0 = Data
167 ; Data = Data0.put(columns,Columns)
168 ).
169valid_c3_data(Data, Data) :-
170 throw(error(c3_no_data(Data), _)).
171
181
182:- if(current_predicate(dicts_to_compounds/4)). 183rows_to_matrix(Dicts, [Keys|Rows]) :-
184 maplist(is_dict, Dicts), !,
185 maplist(dict_keys, Dicts, KeysList),
186 append(KeysList, Keys0),
187 sort(Keys0, Keys),
188 dicts_to_compounds(Dicts, Keys, dict_fill(undefined), Compounds),
189 maplist(compound_arguments, Compounds, Rows).
190:- endif. 191rows_to_matrix(Compounds, Rows) :-
192 functor([_], F, A),
193 dif(Name/Arity, F/A), 194 maplist(name_arity_compound(Name, Arity), Compounds, Rows), !.
195rows_to_matrix(Lists, Lists) :-
196 maplist(length_list(_Columns), Lists).
197
198name_arity_compound(Name, Arity, Compound, Arguments) :-
199 compound(Compound),
200 compound_name_arity(Compound, Name, Arity),
201 compound_name_arguments(Compound, Name, Arguments).
202
203compound_arguments(Compound, Arguments) :-
204 compound_name_arguments(Compound, _, Arguments).
205
206length_list(Length, List) :-
207 length(List, Length).
208
209:- multifile
210 prolog:error_message//1. 211
212prolog:error_message(c3_no_data(C3)) -->
213 [ 'C3.data contains no rows nor columns: ~p'-[C3] ]