dash_creator 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +170 -0
  4. data/Rakefile +36 -0
  5. data/app/assets/config/dash_creator_manifest.js +2 -0
  6. data/app/assets/javascripts/dash_creator/application.js +24 -0
  7. data/app/assets/javascripts/dash_creator/chart.js +2 -0
  8. data/app/assets/javascripts/dash_creator/dashboard.js +2 -0
  9. data/app/assets/javascripts/dash_creator/dashboard_object.js +2 -0
  10. data/app/assets/javascripts/dash_creator/filter.js +2 -0
  11. data/app/assets/javascripts/dash_creator/libs/Chart.js +12269 -0
  12. data/app/assets/javascripts/dash_creator/libs/bootstrap.js +3535 -0
  13. data/app/assets/javascripts/dash_creator/libs/chartCreator.js +1582 -0
  14. data/app/assets/javascripts/dash_creator/libs/dashboardCreator.js +531 -0
  15. data/app/assets/javascripts/dash_creator/libs/daterangepicker.js +1626 -0
  16. data/app/assets/javascripts/dash_creator/libs/filterCreator.js +733 -0
  17. data/app/assets/javascripts/dash_creator/libs/jquery-ui.js +18706 -0
  18. data/app/assets/javascripts/dash_creator/libs/jquery.minicolors.js +1108 -0
  19. data/app/assets/javascripts/dash_creator/libs/moment.js +4301 -0
  20. data/app/assets/javascripts/dash_creator/libs/tether.js +1811 -0
  21. data/app/assets/javascripts/dash_creator/user.js +2 -0
  22. data/app/assets/stylesheets/dash_creator/application.css +16 -0
  23. data/app/assets/stylesheets/dash_creator/chart.css +4 -0
  24. data/app/assets/stylesheets/dash_creator/dashboard.css +4 -0
  25. data/app/assets/stylesheets/dash_creator/dashboard_object.css +4 -0
  26. data/app/assets/stylesheets/dash_creator/filter.css +4 -0
  27. data/app/assets/stylesheets/dash_creator/fonts/FontAwesome.otf +0 -0
  28. data/app/assets/stylesheets/dash_creator/fonts/fontawesome-webfont.eot +0 -0
  29. data/app/assets/stylesheets/dash_creator/fonts/fontawesome-webfont.svg +2671 -0
  30. data/app/assets/stylesheets/dash_creator/fonts/fontawesome-webfont.ttf +0 -0
  31. data/app/assets/stylesheets/dash_creator/fonts/fontawesome-webfont.woff +0 -0
  32. data/app/assets/stylesheets/dash_creator/fonts/fontawesome-webfont.woff2 +0 -0
  33. data/app/assets/stylesheets/dash_creator/libs/font-awesome.css +2199 -0
  34. data/app/assets/stylesheets/dash_creator/libs/jquery.minicolors.css +319 -0
  35. data/app/assets/stylesheets/dash_creator/libs/jquery.minicolors.png +0 -0
  36. data/app/assets/stylesheets/dash_creator/libs/style.css +13714 -0
  37. data/app/assets/stylesheets/dash_creator/user.css +4 -0
  38. data/app/controllers/dash_creator/application_controller.rb +3 -0
  39. data/app/controllers/dash_creator/chart_controller.rb +81 -0
  40. data/app/controllers/dash_creator/dashboard_controller.rb +37 -0
  41. data/app/controllers/dash_creator/dashboard_object_controller.rb +34 -0
  42. data/app/controllers/dash_creator/filter_controller.rb +60 -0
  43. data/app/controllers/dash_creator/user_controller.rb +82 -0
  44. data/app/helpers/dash_creator/application_helper.rb +4 -0
  45. data/app/helpers/dash_creator/chart_helper.rb +829 -0
  46. data/app/helpers/dash_creator/dashboard_helper.rb +4 -0
  47. data/app/helpers/dash_creator/dashboard_object_helper.rb +4 -0
  48. data/app/helpers/dash_creator/filter_helper.rb +237 -0
  49. data/app/helpers/dash_creator/user_helper.rb +4 -0
  50. data/app/jobs/dash_creator/application_job.rb +4 -0
  51. data/app/mailers/dash_creator/application_mailer.rb +6 -0
  52. data/app/models/dash_creator/application_record.rb +5 -0
  53. data/app/models/dash_creator/chart.rb +21 -0
  54. data/app/models/dash_creator/dashboard.rb +13 -0
  55. data/app/models/dash_creator/dashboard_object.rb +7 -0
  56. data/app/models/dash_creator/filter.rb +22 -0
  57. data/app/views/dash_creator/chart/_chart_creator.html.erb +230 -0
  58. data/app/views/dash_creator/chart/_modals.html.erb +74 -0
  59. data/app/views/dash_creator/chart/_plot_chart.html.erb +45 -0
  60. data/app/views/dash_creator/chart/create_chart.js.erb +53 -0
  61. data/app/views/dash_creator/dashboard/_dashboard_creator.html.erb +182 -0
  62. data/app/views/dash_creator/dashboard/_modals.html.erb +74 -0
  63. data/app/views/dash_creator/dashboard_object/_chart.html.erb +9 -0
  64. data/app/views/dash_creator/dashboard_object/_stat.html.erb +24 -0
  65. data/app/views/dash_creator/dashboard_object/_table.html.erb +16 -0
  66. data/app/views/dash_creator/filter/_filtering_card.html.erb +132 -0
  67. data/app/views/dash_creator/filter/_modals.html.erb +51 -0
  68. data/app/views/dash_creator/filter/_result_tables.html.erb +55 -0
  69. data/app/views/dash_creator/filter/apply_filtering.js.erb +46 -0
  70. data/app/views/dash_creator/filter/create_stat.js.erb +20 -0
  71. data/app/views/dash_creator/layouts/application.html.erb +64 -0
  72. data/app/views/dash_creator/layouts/menu/_left_menu.html.erb +12 -0
  73. data/app/views/dash_creator/user/_section_card.html.erb +17 -0
  74. data/app/views/dash_creator/user/creator.html.erb +11 -0
  75. data/app/views/dash_creator/user/dashboard.html.erb +10 -0
  76. data/config/initializers/dash_creator.rb +0 -0
  77. data/config/routes.rb +30 -0
  78. data/lib/dash_creator.rb +87 -0
  79. data/lib/dash_creator/acts_as_dash_creator.rb +16 -0
  80. data/lib/dash_creator/acts_as_dashboard_object.rb +19 -0
  81. data/lib/dash_creator/engine.rb +11 -0
  82. data/lib/dash_creator/version.rb +3 -0
  83. data/lib/generators/dash_creator/install/install_generator.rb +70 -0
  84. data/lib/generators/dash_creator/install/templates/_chart.html.erb +9 -0
  85. data/lib/generators/dash_creator/install/templates/_section_card.html.erb +17 -0
  86. data/lib/generators/dash_creator/install/templates/_stat.html.erb +24 -0
  87. data/lib/generators/dash_creator/install/templates/_table.html.erb +16 -0
  88. data/lib/generators/dash_creator/install/templates/add_indexes_to_dash_creator_tables.rb +15 -0
  89. data/lib/generators/dash_creator/install/templates/create_dash_creator_charts.rb +25 -0
  90. data/lib/generators/dash_creator/install/templates/create_dash_creator_dashboard_objects.rb +36 -0
  91. data/lib/generators/dash_creator/install/templates/create_dash_creator_dashboards.rb +28 -0
  92. data/lib/generators/dash_creator/install/templates/create_dash_creator_filters.rb +22 -0
  93. data/lib/generators/dash_creator/install/templates/dashboard.html.erb +10 -0
  94. data/lib/generators/dash_creator/install/templates/initializer.rb +48 -0
  95. data/lib/tasks/dash_creator_tasks.rake +4 -0
  96. metadata +196 -0
@@ -0,0 +1,1582 @@
1
+ /*!
2
+ * Chart Creator v1.0
3
+ * 2017 Elie Oriol
4
+ */
5
+
6
+ (function(factory) {
7
+ if (typeof define === 'function' && define.amd) {
8
+ define([ 'jquery', 'moment' ], factory);
9
+ }
10
+ else if (typeof exports === 'object') { // Node/CommonJS
11
+ module.exports = factory(require('jquery'), require('moment'));
12
+ }
13
+ else {
14
+ factory(jQuery, moment);
15
+ }
16
+ })(function($, moment) {
17
+ var ChartCreator = function(element, options, callback) {
18
+ this.parentEl = $(element);
19
+
20
+ if (typeof options !== 'object' || options === null)
21
+ options = {};
22
+
23
+ this.models_data = (typeof options.models_data === 'object') ?
24
+ options.models_data : {};
25
+
26
+ this.attributes_aliases = (typeof options.attributes_aliases === 'object') ?
27
+ options.attributes_aliases : {};
28
+
29
+ this.displayed_model_names = (typeof options.displayed_model_names === 'object') ?
30
+ options.displayed_model_names : {};
31
+
32
+ this.displayed_attribute_names = (typeof options.displayed_attribute_names === 'object') ?
33
+ options.displayed_attribute_names : {};
34
+
35
+ this.filter_creator = (typeof options.filter_creator === 'object') ?
36
+ options.filter_creator : null;
37
+
38
+ this.minicolors_options = (typeof options.minicolors_options === 'object') ?
39
+ options.minicolors_options : {};
40
+
41
+ this.callback = (typeof callback === 'function') ? callback : function() {};
42
+
43
+ if (typeof options.template !== 'string' && !(options.template instanceof $)) {
44
+ options.template = '<div class="row"> ' +
45
+ '<div class="col-md-10 offset-md-1 px-2" id="chart-container" style="background-color: #eee; border-radius: 10px; padding: 20px 10px; margin-bottom: 50px;"> ' +
46
+ '<h3>Chart Zone</h3> ' +
47
+ '<div class="chart-wrapper" style="height:370px; margin-bottom:50px;"> ' +
48
+ '<iframe class="chartjs-hidden-iframe" tabindex="-1" style="display: flex; overflow: hidden; border: 0; margin: 0; top: 0; left: 0; bottom: 0; right: 0; height: 100%; width: 100%; position: absolute; pointer-events: none; z-index: -1;"></iframe> ' +
49
+ '</div> ' +
50
+ '</div> ' +
51
+ '<hr> ' +
52
+ '<div class="col-md-12 px-2" id="var-container"> ' +
53
+ '<div class="row" id="y-container"> ' +
54
+ '<button id="add-var-btn" class="btn btn-primary pull-right">+</button> ' +
55
+ '</div> ' +
56
+ '<div class="row" id="x-container"> ' +
57
+ '<div class="col-sm-12" id="x-axis-select-div" style="margin-top:40px;"> ' +
58
+ '<div class="col-sm-2"> ' +
59
+ '<h5>Function of</h5> ' +
60
+ '</div> ' +
61
+ '<div class="form-group col-sm-10"> ' +
62
+ '<select name="x-axis" class="axis-select form-control">' +
63
+ '<option value="">Choose data</option>' +
64
+ '</select>' +
65
+ '</div> ' +
66
+ '</div> ' +
67
+ '</div> ' +
68
+ '</div> ' +
69
+ '<hr> ' +
70
+ '<div class="col-md-12 px-2" id="options-container"> ' +
71
+ '<div class="row" style="margin-top:60px;"> ' +
72
+ '<div class="col-sm-12" style="margin-bottom: 40px;"> ' +
73
+ '<h3 style="margin-bottom: 20px;">Label Options</h3> ' +
74
+ '<div class="row"> ' +
75
+ '<div class="col-sm-10 offset-sm-1"> ' +
76
+ '<div class="row" id="label-options"> ' +
77
+ '</div> ' +
78
+ '</div> ' +
79
+ '</div> ' +
80
+ '</div> ' +
81
+ '<div class="col-sm-6"> ' +
82
+ '<h3 style="margin-bottom: 20px;">Style Options</h3> ' +
83
+ '<div class="row"> ' +
84
+ '<div class="col-sm-10 offset-sm-1"> ' +
85
+ '<div class="row" id="style-options"> ' +
86
+ '</div> ' +
87
+ '</div> ' +
88
+ '</div> ' +
89
+ '</div> ' +
90
+ '<div class="col-sm-6"> ' +
91
+ '<h3 style="margin-bottom: 20px;">Color Options</h3> ' +
92
+ '<div class="row"> ' +
93
+ '<div class="col-sm-10 offset-sm-1"> ' +
94
+ '<div class="row" id="color-options"> ' +
95
+ '</div> ' +
96
+ '</div> ' +
97
+ '</div> ' +
98
+ '</div> ' +
99
+ '</div> ' +
100
+ '</div> ' +
101
+ '</div>';
102
+ }
103
+
104
+
105
+ this.container = $(options.template).appendTo(this.parentEl);
106
+ this.varContainer = this.container.find('#var-container');
107
+ this.yContainer = this.varContainer.find('#y-container');
108
+ this.xContainer = this.varContainer.find('#x-container');
109
+ this.labelOptionsContainer = this.container.find('#label-options');
110
+ this.styleOptionsContainer = this.container.find('#style-options');
111
+ this.colorOptionsContainer = this.container.find('#color-options');
112
+ this.addMainVar();
113
+
114
+ this.varContainer
115
+ .on('click', '#add-var-btn', $.proxy(this.addVar, this))
116
+ .on('click', '.remove-var-btn', $.proxy(this.removeVar, this))
117
+ .on('change', '[name="main-type"]', $.proxy(this.checkMainType, this))
118
+ .on('focusin', '.axis-select', $.proxy(this.axisSelection, this))
119
+ .on('change', '.axis-select', $.proxy(this.axisSelectionCallback, this));
120
+
121
+ this.labelOptionsContainer
122
+ .on('focusin', '.axis-select', $.proxy(this.axisSelection, this))
123
+ .on('change', '.axis-select', $.proxy(this.axisSelectionCallback, this))
124
+ .on('change', '#date-range-select', $.proxy(this.daterangeSelection, this))
125
+ .on('blur', '#date-range-select', $.proxy(this.daterangeSelection, this))
126
+ .on('change', '[name="labels-type"]', $.proxy(this.changeLabelTypeCallback, this))
127
+ .on('change', '[name="sub-labels-type"]', $.proxy(this.changeLabelTypeCallback, this))
128
+ .on('change', '[name="labels-num"]', $.proxy(this.changeLabelsNumCallback, this));
129
+
130
+ // Adjust number of color inputs in style options
131
+ this.container
132
+ .on('change', 'select', $.proxy(this.colorCallback, this))
133
+ .on('blur', 'select', $.proxy(this.colorCallback, this))
134
+ .on('change', 'input', $.proxy(this.colorCallback, this))
135
+ .on('click', 'input[type="radio"]', $.proxy(this.colorCallback, this));
136
+ };
137
+
138
+ ChartCreator.prototype = {
139
+
140
+ constructor: ChartCreator,
141
+
142
+ // --------------- Initialize main components ---------------
143
+ addMainVar: function() {
144
+ this.addMainVarToCreator();
145
+ this.addMainStyleToCreator();
146
+ this.addMainColorToCreator();
147
+ this.xContainer.find('#x-axis-select-div').hide();
148
+ },
149
+
150
+ addMainVarToCreator: function() {
151
+ var main_var_string = '<div class="col-sm-12 var-div" data-id="0"> ' +
152
+ '<div class="row"> ' +
153
+ '<div class="col-sm-12"> ' +
154
+ '<h5>Main variable</h5> ' +
155
+ '</div> ' +
156
+ '<div class="form-group col-sm-3 offset-sm-1"> ' +
157
+ '<select name="y-axis" class="axis-select form-control">' +
158
+ '<option value="">Choose main data</option>' +
159
+ '</select>' +
160
+ '</div> ' +
161
+ '<div class="form-group col-sm-3 offset-sm-1"> ' +
162
+ '<input type="text" name="dataset-label" class="form-control"> ' +
163
+ '</div> ' +
164
+ '<div class="form-group col-sm-3 offset-sm-1"> ' +
165
+ '<select name="main-type" class="type-select form-control">' +
166
+ '<option value="line">Line</option>' +
167
+ '<option value="bar">Bar</option>' +
168
+ '<option value="pie">Pie</option>' +
169
+ '<option value="doughnut">Doughnut</option>' +
170
+ '<option value="polar">Polar</option>' +
171
+ '<option value="radar">Radar</option>' +
172
+ '</select>' +
173
+ '</div> ' +
174
+ '</div> ' +
175
+ '</div> ';
176
+
177
+ $(main_var_string).prependTo(this.yContainer);
178
+ },
179
+
180
+ addMainStyleToCreator: function() {
181
+ var main_style_string = '<div class="col-sm-12 var-style-div" data-id="0"> ' +
182
+ '<div class="row"> ' +
183
+ '<div class="col-sm-12" style="margin-bottom: 20px;"> ' +
184
+ '<div class="row" id="style-general"> ' +
185
+ '<div class="col-sm-12"> ' +
186
+ '<strong>General</strong> ' +
187
+ '</div> ' +
188
+ '<div class="col-sm-12" id="title-div"> ' +
189
+ '<div class="form-group"> ' +
190
+ '<label for="title">Title</label> ' +
191
+ '<input type="text" name="title" id="title" class="form-control"> ' +
192
+ '</div> ' +
193
+ '</div> ' +
194
+ '<div class="col-sm-12" id="legend-div"> ' +
195
+ '<div class="row"> ' +
196
+ '<div class="col-sm-3"> ' +
197
+ '<div class="form-group"> ' +
198
+ '<label for="legend">Display legend</label> ' +
199
+ '<input type="checkbox" name="legend" class="form-control" checked="checked"> ' +
200
+ '</div> ' +
201
+ '</div> ' +
202
+ '<div class="col-sm-9"> ' +
203
+ '<div class="form-group"> ' +
204
+ '<label for="legend-pos">Legend Position</label> ' +
205
+ '<select name="legend-pos" class="form-control"> ' +
206
+ '<option value="top">Top</option> ' +
207
+ '<option value="right">Right</option> ' +
208
+ '<option value="bottom">Bottom</option> ' +
209
+ '<option value="left">Left</option> ' +
210
+ '</select> ' +
211
+ '</div> ' +
212
+ '</div> ' +
213
+ '</div> ' +
214
+ '</div> ' +
215
+ '</div> ' +
216
+ '</div> ' +
217
+ '<div class="col-sm-12" style="margin-bottom: 20px;"> ' +
218
+ '<div class="row" id="style-barline"> ' +
219
+ '<div class="col-sm-12"> ' +
220
+ '<strong>Bar/Line</strong> ' +
221
+ '</div> ' +
222
+ '<div class="col-sm-12" id="grid-div"> ' +
223
+ '<div class="row"> ' +
224
+ '<div class="col-sm-6"> ' +
225
+ '<div class="form-group"> ' +
226
+ '<label for="x-grid-lines">Vertical grid lines</label> ' +
227
+ '<input type="checkbox" name="x-grid-lines" class="form-control" checked="checked"> ' +
228
+ '</div> ' +
229
+ '</div> ' +
230
+ '<div class="col-sm-6"> ' +
231
+ '<div class="form-group"> ' +
232
+ '<label for="y-grid-lines">Horizontal</label> ' +
233
+ '<input type="checkbox" name="y-grid-lines" class="form-control" checked="checked"> ' +
234
+ '</div> ' +
235
+ '</div> ' +
236
+ '</div> ' +
237
+ '</div> ' +
238
+ '<div class="col-sm-12" id="y-axis-div"> ' +
239
+ '<div class="row"> ' +
240
+ '<div class="col-sm-4"> ' +
241
+ '<div class="form-group"> ' +
242
+ '<label for="y-axis-min">Y Axis Min</label> ' +
243
+ '<input type="number" name="y-axis-min" class="form-control"> ' +
244
+ '</div> ' +
245
+ '</div> ' +
246
+ '<div class="col-sm-4"> ' +
247
+ '<div class="form-group"> ' +
248
+ '<label for="y-axis-min">Max</label> ' +
249
+ '<input type="number" name="y-axis-max" class="form-control"> ' +
250
+ '</div> ' +
251
+ '</div> ' +
252
+ '<div class="col-sm-4"> ' +
253
+ '<div class="form-group"> ' +
254
+ '<label for="y-axis-min">Step</label> ' +
255
+ '<input type="number" name="y-axis-step" class="form-control"> ' +
256
+ '</div> ' +
257
+ '</div> ' +
258
+ '</div> ' +
259
+ '</div> ' +
260
+ '<div class="col-sm-12" id="labeling-step-div"> ' +
261
+ '<div class="form-group"> ' +
262
+ '<label for="labeling-step">X Axis Labeling step</label> ' +
263
+ '<input type="number" name="labeling-step" class="form-control" min="1" value="1"> ' +
264
+ '</div> ' +
265
+ '</div> ' +
266
+ '<div class="col-sm-12" id="stacked-div"> ' +
267
+ '<div class="form-group"> ' +
268
+ '<label for="stacked">Stacked</label> ' +
269
+ '<input type="checkbox" name="stacked" class="form-control"> ' +
270
+ '</div> ' +
271
+ '</div> ' +
272
+ '</div> ' +
273
+ '</div> ' +
274
+ // '<div class="col-sm-12" style="margin-bottom: 20px;"> ' +
275
+ // '<div class="row" id="style-line"> ' +
276
+ // '<div class="col-sm-12"> ' +
277
+ // '<strong>Line</strong> ' +
278
+ // '</div> ' +
279
+ // '<div class="col-sm-12" id="point-div"> ' +
280
+ // '<div class="row"> ' +
281
+ // '<div class="col-sm-6"> ' +
282
+ // '<div class="form-group"> ' +
283
+ // '<label for="y-axis-min">Point Style</label> ' +
284
+ // '<input type="number" name="point-style" class="form-control"> ' +
285
+ // '</div> ' +
286
+ // '</div> ' +
287
+ // '<div class="col-sm-6"> ' +
288
+ // '<div class="form-group"> ' +
289
+ // '<label for="y-axis-min">Size</label> ' +
290
+ // '<input type="number" name="point-size" class="form-control" min="1"> ' +
291
+ // '</div> ' +
292
+ // '</div> ' +
293
+ // '</div> ' +
294
+ // '</div> ' +
295
+ // '<div class="col-sm-12" id="line-div"> ' +
296
+ // '<div class="form-group"> ' +
297
+ // '<label for="stacked">Stacked</label> ' +
298
+ // '<input type="checkbox" name="stacked" class="form-control"> ' +
299
+ // '</div> ' +
300
+ // '</div> ' +
301
+ // '</div> ' +
302
+ // '</div> ' +
303
+ '</div> ' +
304
+ '</div> ';
305
+
306
+ $(main_style_string).appendTo(this.styleOptionsContainer);
307
+ },
308
+
309
+ addMainColorToCreator: function() {
310
+ var main_color_string = '<div class="col-sm-12 color-div" data-id="0" id="main-color" style="margin-bottom: 20px;">' +
311
+ '<div class="row" id="main-color"> ' +
312
+ '<div class="col-sm-6"> ' +
313
+ '<div class="form-group color-group"> ' +
314
+ '<label for="dataset-color">Main variable color</label>' +
315
+ '<input type="text" name="dataset-color" class="form-control"> ' +
316
+ '</div> ' +
317
+ '</div> ' +
318
+ '<div class="col-sm-6"> ' +
319
+ '<div class="form-group transparency-group"> ' +
320
+ '<label for="transparency">Area transparency</label> ' +
321
+ '<input type="range" name="transparency" value="0" step="1" class="form-control"> ' +
322
+ '</div>' +
323
+ '</div>' +
324
+ '</div>' +
325
+ '</div>';
326
+
327
+ var main_color_div = $(main_color_string).appendTo(this.colorOptionsContainer);
328
+ // Set first swatches color
329
+ var default_color = this.minicolors_options.swatches[0];
330
+ main_color_div.find('[name="dataset-color"]').minicolors(this.minicolors_options).val(default_color).change();
331
+ main_color_div.find('.minicolors-input-swatch .minicolors-swatch-color').css("background-color", default_color);
332
+ },
333
+
334
+
335
+ // --------------- Variables handling ---------------
336
+ addVar: function() {
337
+ var last_var_div = this.yContainer.find('.var-div:last');
338
+ var var_id = parseInt(last_var_div.attr('data-id')) + 1;
339
+
340
+ this.addVarToCreator(var_id);
341
+ this.checkMainType();
342
+ this.addStyleToCreator(var_id);
343
+ },
344
+
345
+ addVarToCreator: function(var_id) {
346
+ var var_div_string = '<div class="col-sm-12 var-div" data-id="' + var_id + '" style="margin-top:20px;">'
347
+ + '<div class="row">'
348
+ + '<div class="col-sm-12">'
349
+ + '<h5>Variable ' + var_id + '</h5>'
350
+ + '</div>'
351
+ + '<div class="col-sm-1">'
352
+ + '<button type="button" class="close remove-var-btn" aria-label="Close">'
353
+ + '<span aria-hidden="true">×</span>'
354
+ + '</button>'
355
+ + '</div>'
356
+ + '<div class="form-group col-sm-3">' +
357
+ '<select name="y-axis" class="axis-select form-control">' +
358
+ '<option value="">Choose data</option>' +
359
+ '</select>'
360
+ + '</div>'
361
+ + '<div class="form-group col-sm-3 offset-sm-1">'
362
+ + '<input type="text" name="dataset-label" class="form-control">'
363
+ + '</div>'
364
+ + '<div class="form-group col-sm-3 offset-sm-1">' +
365
+ '<select name="type" class="type-select form-control">' +
366
+ '<option value="line">Line</option>' +
367
+ '<option value="bar">Bar</option>' +
368
+ '</select>'
369
+ + '</div></div></div>';
370
+
371
+ $(var_div_string).appendTo(this.yContainer);
372
+ },
373
+
374
+ addStyleToCreator: function(var_id) {
375
+ var var_style_div_string = '<div class="col-sm-12 var-style-div" data-id="' + var_id + '"></div>';
376
+ $(var_style_div_string).appendTo(this.styleOptionsContainer);
377
+
378
+ this.addColorToCreator(var_id, 0);
379
+ },
380
+
381
+ addColorToCreator: function(var_id, label_num) {
382
+ var label;
383
+ var is_not_var_color = var_id === 0;
384
+ if (is_not_var_color)
385
+ label = 'Label ' + label_num + ' color';
386
+ else
387
+ label = 'Variable ' + var_id + ' color';
388
+
389
+ var color_div_string = '<div class="col-sm-12 color-div" data-id="' + var_id + '" style="margin-bottom: 20px;">' +
390
+ '<div class="row"> ' +
391
+ '<div class="col-sm-6"> ' +
392
+ '<div class="form-group color-group"> ' +
393
+ '<label for="dataset-color">' + label + '</label>' +
394
+ '<input type="text" name="dataset-color" class="form-control"> ' +
395
+ '</div> ' +
396
+ '</div> ' +
397
+ '<div class="col-sm-6"> ' +
398
+ '<div class="form-group transparency-group"> ' +
399
+ '<label for="transparency">Area transparency</label> ' +
400
+ '<input type="range" name="transparency" value="0" step="1" class="form-control"> ' +
401
+ '</div>' +
402
+ '</div>' +
403
+ '</div>' +
404
+ '</div>';
405
+
406
+ var color_div = $(color_div_string).appendTo(this.colorOptionsContainer);
407
+
408
+ // Set a default color
409
+ var swatches = this.minicolors_options.swatches;
410
+ var num = label_num === 0 ? var_id : label_num;
411
+ var default_color = swatches[num % swatches.length];
412
+ color_div.find('[name="dataset-color"]').minicolors(this.minicolors_options).val(default_color).change();
413
+ color_div.find('.minicolors-input-swatch .minicolors-swatch-color').css("background-color", default_color);
414
+ },
415
+
416
+ removeVar: function(e) {
417
+ var target = $(e.target);
418
+
419
+ var var_div = target.closest('.var-div');
420
+ var id = var_div.attr("data-id");
421
+ this.container.find('[data-id="' + id + '"]').remove();
422
+ },
423
+
424
+ checkMainType: function() {
425
+ var main_type = this.yContainer.find('[name="main-type"]').val();
426
+
427
+ if (main_type === 'bar' || main_type === 'line') {
428
+ this.yContainer.find('[name="type"]').show();
429
+ this.styleOptionsContainer.find('#style-barline').show();
430
+ }
431
+ else {
432
+ this.yContainer.find('[name="type"]').hide();
433
+ this.styleOptionsContainer.find('#style-barline').hide();
434
+ this.styleOptionsContainer.find('#style-line').hide();
435
+ }
436
+
437
+ return main_type;
438
+ },
439
+
440
+
441
+ // --------------- Selection callbacks ---------------
442
+ axisSelection: function(e) {
443
+ var target = $(e.target);
444
+
445
+ var select_name = target.attr("name");
446
+
447
+ // Remove previous options
448
+ target.children('option').not('[value=""]').remove();
449
+
450
+ // Different handling for main or second variable
451
+ if (select_name === 'y-axis')
452
+ this.fillYAxisSelect(target);
453
+ else if (select_name === 'x-axis')
454
+ this.fillXAxisSelect(target);
455
+ else
456
+ this.fillXSubSelect(target);
457
+ },
458
+
459
+ fillYAxisSelect: function(select) {
460
+ var options_string = '';
461
+
462
+ // Take models from filters if associated with filter_creator
463
+ var displayed_model_names = this.displayed_model_names;
464
+ if (this.filter_creator !== null) {
465
+ this.filter_creator.find('.top-filter').each(function() {
466
+ var filter_id = $(this).attr("data-id");
467
+ var model = $(this).find('[name="model"]').val();
468
+ if (model !== '') {
469
+ var model_name_to_display = displayed_model_names[model];
470
+ if (typeof model_name_to_display === 'undefined')
471
+ model_name_to_display = model.humanize();
472
+ options_string += '<option value="' + model + '">Filter ' + filter_id + ': ' + model_name_to_display + '</option>';
473
+ }
474
+ });
475
+ }
476
+ else {
477
+ $.each(this.models_data, function(model, attributes) {
478
+ var model_name_to_display = displayed_model_names[model];
479
+ if (typeof model_name_to_display === 'undefined')
480
+ model_name_to_display = model.humanize();
481
+ options_string += '<option value="' + model + '">' + model_name_to_display + '</option>';
482
+ });
483
+ }
484
+
485
+ // Append options to select
486
+ $(options_string).appendTo(select);
487
+ },
488
+
489
+ fillXAxisSelect: function(select) {
490
+ var options_string = '';
491
+ var attributes_aliases = this.attributes_aliases;
492
+
493
+ // Get model data
494
+ var y_vals = [];
495
+ this.yContainer.find('[name="y-axis"]').each(function() {
496
+ var model = $(this).val().split('-')[0];
497
+ var alias = attributes_aliases[model];
498
+ model = (typeof alias === 'undefined') ? model : alias;
499
+ y_vals.push(model.classify());
500
+ });
501
+ var model_data = this.yAxesDataInCommon(y_vals);
502
+
503
+ // Get list of filtered models
504
+ var filtered_models = [];
505
+ if (this.filter_creator !== null) {
506
+ this.filter_creator.find('.top-filter').each(function() {
507
+ var model = $(this).find('[name="model"]').val();
508
+ if (model !== '')
509
+ filtered_models.push(model);
510
+ });
511
+ }
512
+
513
+ var filter_creator = this.filter_creator;
514
+ var displayed_attribute_names = this.displayed_attribute_names[y_vals[0]];
515
+ $.each(model_data, function(idx, str) {
516
+ var key = str.split('-')[0], value = str.split('-')[1];
517
+
518
+ // Create option string for each attribute
519
+ var key_name_to_display = (typeof displayed_attribute_names === 'undefined') ? undefined : displayed_attribute_names[key];
520
+ if (typeof key_name_to_display === 'undefined')
521
+ key_name_to_display = key.humanize();
522
+
523
+ var new_option_string = '<option value="' + key + '-' + value + '">' + key_name_to_display;
524
+ if (value === 'has')
525
+ new_option_string += ' (has relation)';
526
+ if (value === 'ref')
527
+ new_option_string += ' (belongs relation)';
528
+
529
+ // If attribute is a related model that is filtered, copy the option to have filtered or not version
530
+ var alias = attributes_aliases[key];
531
+ var key_model = (typeof alias === 'undefined') ? key : alias;
532
+ if ($.inArray(key_model.classify(), filtered_models) !== -1) {
533
+ new_option_string += '</option>' +
534
+ '<option value="' + key + '-' + value + '-filter">' + key_name_to_display;
535
+
536
+ var filters_model_selects = filter_creator.find('[name="model"]');
537
+ filters_model_selects.each(function() {
538
+ var model = $(this).val();
539
+ if (model === key_model.classify()) {
540
+ var filter_id = $(this).closest('.top-filter').attr("data-id");
541
+ new_option_string += ' (Filter ' + filter_id + ')';
542
+ }
543
+ });
544
+ }
545
+ options_string += new_option_string + '</option>';
546
+ });
547
+
548
+ // Append options to select
549
+ $(options_string).appendTo(select);
550
+ },
551
+
552
+ fillXSubSelect: function(select) {
553
+ var options_string = '';
554
+
555
+ // Get model data
556
+ var x_model = this.xContainer.find('[name="x-axis"]').val().split('-')[0];
557
+ var alias = this.attributes_aliases[x_model];
558
+ x_model = (typeof alias === 'undefined') ? x_model : alias;
559
+ var model_data = this.models_data[x_model.classify()];
560
+
561
+ var plotting_types = ['text', 'numeric', 'boolean', 'datetime'];
562
+ var displayed_attribute_names = this.displayed_attribute_names[x_model.classify()];
563
+ $.each(model_data, function(idx, str) {
564
+ var key = str.split('-')[0], value = str.split('-')[1];
565
+ // Get types that can be used for plotting
566
+ if ($.inArray(value, plotting_types) === -1) return true;
567
+
568
+ var key_name_to_display = (typeof displayed_attribute_names === 'undefined') ? undefined : displayed_attribute_names[key];
569
+ if (typeof key_name_to_display === 'undefined')
570
+ key_name_to_display = key.humanize();
571
+
572
+ // Create option string for each attribute
573
+ options_string += '<option value="' + key + '-' + value + '">' + key_name_to_display + '</option>';
574
+ });
575
+
576
+ // Append options to select
577
+ $(options_string).appendTo(select);
578
+ },
579
+
580
+ yAxesDataInCommon: function(models) {
581
+ var models_data = this.models_data;
582
+
583
+ var first_model_data = models_data[models[0]];
584
+ if (models.length === 1)
585
+ return first_model_data;
586
+
587
+ var final_data = [];
588
+ $.each(models, function(index, model) {
589
+ if (index === 0) return true;
590
+
591
+ $.each(first_model_data, function(idx, str) {
592
+ if ($.inArray(str, models_data[model]) !== -1) final_data.push(str);
593
+ });
594
+ });
595
+
596
+ return final_data;
597
+ },
598
+
599
+ axisSelectionCallback: function(e) {
600
+ var target = $(e.target);
601
+
602
+ var select_name = target.attr("name");
603
+ var attribute = target.val().split('-')[0], attribute_type = target.val().split('-')[1];
604
+ if (select_name === 'y-axis') {
605
+ target.closest('.var-div').find('[name="dataset-label"]').val(attribute);
606
+ this.showXAxisSelect();
607
+ }
608
+ else {
609
+ // Hide if empty value (prompt value)
610
+ if (attribute === '') {
611
+ if (select_name === 'x-axis')
612
+ this.labelOptionsContainer.children().not('#label').hide();
613
+ else
614
+ this.labelOptionsContainer.children().not('#label').not('#label-type-radio-div').remove();
615
+ return;
616
+ }
617
+ this.showLabelOptions(select_name, attribute_type);
618
+ }
619
+ },
620
+
621
+ showXAxisSelect: function() {
622
+ if (this.yContainer.find('[name="y-axis"]').first().val() === '') {
623
+ this.xContainer.find('#x-axis-select-div').hide();
624
+ this.labelOptionsContainer.children().not('#label').remove();
625
+ }
626
+ else this.xContainer.find('#x-axis-select-div').show();
627
+ },
628
+
629
+ showLabelOptions: function(select_name, attribute_type) {
630
+ // Otherwise show and remove previous options
631
+ this.labelOptionsContainer.children().show();
632
+ var is_sub = false;
633
+ if (select_name === 'x-sub' && this.labelOptionsContainer.find('[name="labels-type"]:checked').val() === 'attribute') {
634
+ this.labelOptionsContainer.children().not('#label-type-radio-div').not('#label').remove();
635
+ is_sub = true;
636
+ }
637
+ else
638
+ this.labelOptionsContainer.children().not('#label').remove();
639
+
640
+ // Display according to attribute type
641
+ switch(attribute_type) {
642
+ case 'datetime':
643
+ this.showDatetimeLabelOptions();
644
+ break;
645
+
646
+ case 'numeric':
647
+ this.showNumericLabelTypes(is_sub);
648
+ break;
649
+
650
+ case 'boolean':
651
+ this.showBooleanLabelOptions(is_sub);
652
+ break;
653
+
654
+ case 'text':
655
+ this.showTextLabelTypes(is_sub);
656
+ break;
657
+
658
+ case 'ref':
659
+ this.showRefLabelTypes(is_sub);
660
+ break;
661
+
662
+ case 'has':
663
+ this.showHasLabelTypes(is_sub);
664
+ break;
665
+
666
+ default:
667
+ this.showErrorMessage(is_sub, attribute_type);
668
+ break;
669
+ }
670
+
671
+ // Add options to page and change labels number to display further options
672
+ if (!is_sub)
673
+ this.labelOptionsContainer.find('#label-type-radio-div').find('[type="radio"]:first').click();
674
+ else
675
+ this.labelOptionsContainer.find('#sub-label-type-radio-div').find('[type="radio"]:first').click();
676
+ },
677
+
678
+ showDatetimeLabelOptions: function() {
679
+ this.labelOptionsContainer.find('#sub-label-type-radio-div').remove();
680
+
681
+ // Select input for date range
682
+ var date_range_options = [
683
+ 'Today',
684
+ 'Yesterday',
685
+ 'Last 7 Days',
686
+ 'This Week',
687
+ 'Last Week',
688
+ 'Last 30 Days',
689
+ 'This Month',
690
+ 'Last Month',
691
+ 'Last 365 Days',
692
+ 'This Year',
693
+ 'Last Year',
694
+ 'Fixed Date Range'
695
+ ];
696
+ var date_range_select_string = '<select name="date_range" id="date-range-select" class="form-control">' +
697
+ '<option value="">Choose a date range</option>';
698
+ $.each(date_range_options, function(index, daterange) {
699
+ date_range_select_string += '<option value="' + daterange + '">' + daterange + '</option>';
700
+ });
701
+ date_range_select_string += '</select>';
702
+
703
+ var options_string = '<div class="col-sm-6">'
704
+ + '<div class="form-group">'
705
+ + '<label>Date range</label>'
706
+ + date_range_select_string
707
+ + '</div></div>';
708
+
709
+ // Choose period plot : day, week, month
710
+ options_string += '<div class="col-sm-2">'
711
+ + '<div class="form-group">'
712
+ + '<input type="radio" name="period" value="day" checked="checked" class="form-control">'
713
+ + '<label>Day</label>'
714
+ + '</div></div>';
715
+ options_string += '<div class="col-sm-2">'
716
+ + '<div class="form-group">'
717
+ + '<input type="radio" name="period" value="week" class="form-control">'
718
+ + '<label>Week</label>'
719
+ + '</div></div>';
720
+ options_string += '<div class="col-sm-2">'
721
+ + '<div class="form-group">'
722
+ + '<input type="radio" name="period" value="month" class="form-control">'
723
+ + '<label>Month</label>'
724
+ + '</div></div>';
725
+
726
+ // // Choose date formatting in the labels
727
+ // options_string += form_div_string_start
728
+ // + '<label>Date formatting</label>'
729
+ // + '<input type="text" name="format" value="%Y/%m/%d" class="form-control">'
730
+ // + '</div></div>';
731
+
732
+ $(options_string).appendTo(this.labelOptionsContainer);
733
+
734
+ var parent_div = $('<div class="col-sm-12"></div>').appendTo(this.labelOptionsContainer);
735
+ var parent_div = $('<div class="form-group"></div>').appendTo(parent_div);
736
+
737
+ // Add daterangepicker
738
+ daterangeField(parent_div);
739
+ },
740
+
741
+ showNumericLabelTypes: function(is_sub) {
742
+ var sub = is_sub ? 'sub-' : '';
743
+ var options_string = '<div class="col-sm-12 row" id="' + sub + 'label-type-radio-div">'
744
+ + '<div class="col-sm-4">'
745
+ + '<div class="form-group">'
746
+ + '<input type="radio" name="' + sub + 'labels-type" value="numeric" class="form-control">'
747
+ + '<label>Define labels</label>'
748
+ + '</div></div>';
749
+ options_string += '<div class="col-sm-4">'
750
+ + '<div class="form-group">'
751
+ + '<input type="radio" name="' + sub + 'labels-type" value="number" class="form-control">'
752
+ + '<label>Count</label>'
753
+ + '</div></div>'
754
+ + '</div>';
755
+ $(options_string).appendTo(this.labelOptionsContainer);
756
+ },
757
+
758
+ showBooleanLabelOptions: function() {
759
+ var labels_options_string = '<div class="col-sm-12 label-limit-div">'
760
+ + '<div class="row">'
761
+ + '<div class="col-sm-3">'
762
+ + '<div class="form-group">'
763
+ + '<label>Value</label>'
764
+ + '<input type="text" class="limit-label form-control" name="boolean-true" value="true" disabled="disabled">'
765
+ + '</div></div>'
766
+ + '<div class="col-sm-9">'
767
+ + '<div class="form-group">'
768
+ + '<label>Correspondence</label>'
769
+ + '<input type="text" class="limit-label-corres form-control" name="boolean-true-corres">'
770
+ + '</div></div></div>'
771
+ + '<div class="row">'
772
+ + '<div class="col-sm-3">'
773
+ + '<div class="form-group">'
774
+ + '<label>Value</label>'
775
+ + '<input type="text" class="limit-label form-control" name="boolean-false" value="false" disabled="disabled">'
776
+ + '</div></div>'
777
+ + '<div class="col-sm-9">'
778
+ + '<div class="form-group">'
779
+ + '<label>Correspondence</label>'
780
+ + '<input type="text" class="limit-label-corres form-control" name="boolean-false-corres">'
781
+ + '</div></div></div>'
782
+ + '</div>';
783
+ $(labels_options_string).appendTo(this.labelOptionsContainer);
784
+ },
785
+
786
+ showTextLabelTypes: function(is_sub) {
787
+ var sub = is_sub ? 'sub-' : '';
788
+ var options_string = '<div class="col-sm-12 row" id="' + sub + 'label-type-radio-div">'
789
+ + '<div class="col-sm-4">'
790
+ + '<div class="form-group">'
791
+ + '<input type="radio" name="' + sub + 'labels-type" value="text-auto" class="form-control">'
792
+ + '<label>Auto text labels</label>'
793
+ + '</div></div>';
794
+ options_string += '<div class="col-sm-4">'
795
+ + '<div class="form-group">'
796
+ + '<input type="radio" name="' + sub + 'labels-type" value="text" class="form-control">'
797
+ + '<label>Define labels</label>'
798
+ + '</div></div>'
799
+ + '</div>';
800
+ $(options_string).appendTo(this.labelOptionsContainer);
801
+ },
802
+
803
+ showRefLabelTypes: function(is_sub) {
804
+ var sub = is_sub ? 'sub-' : '';
805
+ var options_string = '<div class="col-sm-12 row" id="' + sub + 'label-type-radio-div">'
806
+ + '<div class="col-sm-4">'
807
+ + '<div class="form-group">'
808
+ + '<input type="radio" name="' + sub + 'labels-type" value="number" class="form-control">'
809
+ + '<label>Count</label>'
810
+ + '</div></div>';
811
+ options_string += '<div class="col-sm-4">'
812
+ + '<div class="form-group">'
813
+ + '<input type="radio" name="' + sub + 'labels-type" value="attribute" class="form-control">'
814
+ + '<label>Sub-attribute</label>'
815
+ + '</div></div>'
816
+ + '</div>';
817
+ $(options_string).appendTo(this.labelOptionsContainer);
818
+ },
819
+
820
+ showHasLabelTypes: function(is_sub) {
821
+ var sub = is_sub ? 'sub-' : '';
822
+ var options_string = '<div class="col-sm-12 row" id="' + sub + 'label-type-radio-div">'
823
+ + '<div class="col-sm-4">'
824
+ + '<div class="form-group">'
825
+ + '<input type="radio" name="' + sub + 'labels-type" value="number" class="form-control">'
826
+ + '<label>Count</label>'
827
+ + '</div></div>';
828
+ options_string += '<div class="col-sm-4">'
829
+ + '<div class="form-group">'
830
+ + '<input type="radio" name="' + sub + 'labels-type" value="attribute" class="form-control">'
831
+ + '<label>Sub-attribute</label>'
832
+ + '</div></div>'
833
+ + '</div>';
834
+ $(options_string).appendTo(this.labelOptionsContainer);
835
+ },
836
+
837
+ showErrorMessage: function(is_sub, type) {
838
+ var sub = is_sub ? 'sub-' : '';
839
+ var options_string = '<div class="col-sm-12" id="' + sub + 'label-type-radio-div">'
840
+ + '<strong>Type ' + type + ' is not handled</strong>'
841
+ + '</div>';
842
+ $(options_string).appendTo(this.labelOptionsContainer);
843
+ },
844
+
845
+ daterangeSelection: function(e) {
846
+ var target = $(e.target);
847
+
848
+ // Change date format
849
+ var label_options_container = this.labelOptionsContainer;
850
+ function cb(start, end) {
851
+ label_options_container.find('#daterange-chart span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
852
+ }
853
+
854
+ switch(target.val()) {
855
+ case 'Today':
856
+ cb(moment(), moment());
857
+ break;
858
+
859
+ case 'Yesterday':
860
+ cb(moment().subtract(1, 'days'), moment().subtract(1, 'days'));
861
+ break;
862
+
863
+ case 'Last 7 Days':
864
+ cb(moment().subtract(6, 'days'), moment());
865
+ break;
866
+
867
+ case 'This Week':
868
+ cb(moment().startOf('week'), moment().endOf('week'));
869
+ break;
870
+
871
+ case 'Last Week':
872
+ cb(moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week'));
873
+ break;
874
+
875
+ case 'Last 30 Days':
876
+ cb(moment().subtract(29, 'days'), moment());
877
+ break;
878
+
879
+ case 'This Month':
880
+ cb(moment().startOf('month'), moment().endOf('month'));
881
+ break;
882
+
883
+ case 'Last Month':
884
+ cb(moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month'));
885
+ break;
886
+
887
+ case 'Last 365 Days':
888
+ cb(moment().subtract(364, 'days'), moment());
889
+ break;
890
+
891
+ case 'This Year':
892
+ cb(moment().startOf('year'), moment().endOf('year'));
893
+ break;
894
+
895
+ case 'Last Year':
896
+ cb(moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year'));
897
+ break;
898
+
899
+ case 'Fixed Date Range':
900
+ default:
901
+ break;
902
+
903
+ }
904
+ },
905
+
906
+ changeLabelTypeCallback: function(e) {
907
+ var target = $(e.target);
908
+
909
+ var value = target.val();
910
+ this.labelOptionsContainer.find('.limit-label').prop("type", value);
911
+
912
+ if (target.attr("name") === 'labels-type') {
913
+ this.labelOptionsContainer.find('#sub-select-div').remove();
914
+ this.labelOptionsContainer.children().not('#label-type-radio-div').not('#label').remove();
915
+ }
916
+ else {
917
+ this.labelOptionsContainer.children().not('#label-type-radio-div').not('#sub-label-type-radio-div').not('#label').remove();
918
+ }
919
+
920
+ switch(value) {
921
+ case 'attribute':
922
+ this.showAttributeLabelOptions();
923
+ break;
924
+
925
+ case 'text-auto':
926
+ this.labelOptionsContainer.children().not('#label-type-radio-div').not('#sub-label-type-radio-div').not('#label').remove();
927
+ break;
928
+
929
+ case 'numeric':
930
+ this.showNumericLabelOptions();
931
+ break;
932
+
933
+ case 'number':
934
+ this.showNumberLabelOptions();
935
+ break;
936
+
937
+ case 'text':
938
+ this.showTextLabelOptions();
939
+ break;
940
+
941
+ default:
942
+ break;
943
+ }
944
+ },
945
+
946
+ showAttributeLabelOptions: function() {
947
+ this.labelOptionsContainer.children().not('#label-type-radio-div').not('#label').remove();
948
+ var select_string = '<div class="col-sm-4" id="sub-select-div">'
949
+ + '<select class="axis-select form-control" name="x-sub">'
950
+ + '<option value="">Choose sub-attribute</option>'
951
+ + '</select></div>';
952
+ $(select_string).appendTo(this.labelOptionsContainer.find('#label-type-radio-div'));
953
+ },
954
+
955
+ showNumericLabelOptions: function() {
956
+ var labels_num_div_string = '<div class="col-sm-12" id="labels-num-div" style="margin-bottom:20px;">'
957
+ + '<div class="form-group">'
958
+ + '<label>Number of labels</label>'
959
+ + '<input type="number" name="labels-num" min="1" value="3" class="form-control">'
960
+ + '</div>'
961
+ + '<div class="row">'
962
+ + '<div class="col-sm-6">'
963
+ + '<button class="pull-right btn btn-primary" id="pluck-labels-btn">Generate values with limit: </button>'
964
+ + '</div>'
965
+ + '<div class="col-sm-6">'
966
+ + '<input type="number" name="pluck-num" min="1" value="3" class="form-control pull-right">'
967
+ + '</div></div></div>';
968
+ $(labels_num_div_string).appendTo(this.labelOptionsContainer);
969
+ this.labelOptionsContainer.find('[name="labels-num"]').change();
970
+ },
971
+
972
+ showNumberLabelOptions: function() {
973
+ var labels_num_div_string = '<div class="col-sm-12" id="labels-num-div" style="margin-bottom:20px;">'
974
+ + '<div class="form-group">'
975
+ + '<label>Number of labels</label>'
976
+ + '<input type="number" name="labels-num" min="1" value="3" class="form-control">'
977
+ + '</div></div>'
978
+ + '<div class="col-sm-12" id="plus-div">'
979
+ + '<div class="form-group">'
980
+ + '<input type="radio" name="plus" value="true" class="form-control" checked="checked">'
981
+ + '<label>+</label>'
982
+ + '</div>'
983
+ + '<div class="form-group">'
984
+ + '<input type="radio" name="plus" value="false" class="form-control">'
985
+ + '<label>Not +</label>'
986
+ + '</div></div>';
987
+ $(labels_num_div_string).appendTo(this.labelOptionsContainer);
988
+ this.labelOptionsContainer.find('[name="labels-num"]').change();
989
+ },
990
+
991
+ showTextLabelOptions: function() {
992
+ var labels_num_div_string = '<div class="col-sm-12" id="labels-num-div" style="margin-bottom:20px;">'
993
+ + '<div class="form-group">'
994
+ + '<label>Number of labels</label>'
995
+ + '<input type="number" name="labels-num" min="1" value="3" class="form-control">'
996
+ + '</div>'
997
+ + '<div class="row">'
998
+ + '<div class="col-sm-6">'
999
+ + '<button class="pull-right btn btn-primary" id="pluck-labels-btn">Generate labels with limit: </button>'
1000
+ + '</div>'
1001
+ + '<div class="col-sm-6">'
1002
+ + '<input type="number" name="pluck-num" min="1" value="30" class="form-control pull-right">'
1003
+ + '</div></div></div>';
1004
+ $(labels_num_div_string).appendTo(this.labelOptionsContainer);
1005
+ this.labelOptionsContainer.find('[name="labels-num"]').change();
1006
+ },
1007
+
1008
+ changeLabelsNumCallback: function() {
1009
+ var low_limit_div = this.labelOptionsContainer.find('#low-limit-div'), labels_num_div = this.labelOptionsContainer.find('#labels-num-div');
1010
+
1011
+ var number = labels_num_div.find('[name="labels-num"]').val(), previous_number = this.labelOptionsContainer.find('.label-limit-div').length;
1012
+ var labels_options_string = '';
1013
+
1014
+ var label_type = this.labelOptionsContainer.find('[name="labels-type"]:checked').val();
1015
+ if (label_type === 'attribute') label_type = this.labelOptionsContainer.find('[name="sub-labels-type"]:checked').val();
1016
+ var label_base = (label_type === 'number') ? 'Limit ' : 'Label ';
1017
+
1018
+ this.labelOptionsContainer.find('.limit-label').each(function() {
1019
+ var id = $(this).attr("name").split('-')[1];
1020
+ if (id !== '0') $(this).siblings('label').text(label_base + id);
1021
+ });
1022
+
1023
+ // Display low limit for first display
1024
+ if (label_type === 'number' && low_limit_div.length === 0) {
1025
+ labels_options_string = '<div class="col-sm-6" id="low-limit-div">'
1026
+ + '<div class="form-group">'
1027
+ + '<label>Low limit</label>'
1028
+ + '<input type="number" class="limit-label form-control" name="label-0" min="0" value="0">'
1029
+ + '</div></div>';
1030
+ $(labels_options_string).insertAfter(labels_num_div);
1031
+ low_limit_div = this.labelOptionsContainer.find('#low-limit-div');
1032
+ }
1033
+
1034
+ // On change of labels number, either remove fields if too many, either add fields
1035
+ if (number >= previous_number) {
1036
+ labels_options_string = '';
1037
+ for (var i = previous_number + 1; i <= number; i++) {
1038
+ if (label_type === 'numeric') {
1039
+ labels_options_string += '<div class="col-sm-12 label-limit-div">'
1040
+ + '<div class="row">'
1041
+ + '<div class="col-sm-3">'
1042
+ + '<div class="form-group">'
1043
+ + '<label>Value ' + i +'</label>'
1044
+ + '<input type="number" class="limit-label form-control" name="label-' + i + '">'
1045
+ + '</div></div>'
1046
+ + '<div class="col-sm-9">'
1047
+ + '<div class="form-group">'
1048
+ + '<label>Correspondence ' + i +'</label>'
1049
+ + '<input type="text" class="limit-label-corres form-control" name="label-corres-' + i + '">'
1050
+ + '</div></div></div></div>';
1051
+ }
1052
+ else {
1053
+ labels_options_string += '<div class="col-sm-6 label-limit-div">'
1054
+ + '<div class="form-group">'
1055
+ + '<label>' + label_base + i +'</label>'
1056
+ + '<input type="' + label_type + '" class="limit-label form-control" name="label-' + i + '" min="0">'
1057
+ + '</div></div>';
1058
+ }
1059
+ }
1060
+
1061
+ if (previous_number === 0) {
1062
+ if (label_type === 'number') $(labels_options_string).insertAfter(low_limit_div);
1063
+ else $(labels_options_string).insertAfter(labels_num_div);
1064
+ }
1065
+ else $(labels_options_string).insertAfter(this.labelOptionsContainer.find('.label-limit-div:last'));
1066
+ }
1067
+ else {
1068
+ for (var i = previous_number; i > number; i--) {
1069
+ this.labelOptionsContainer.find('.label-limit-div:last').remove();
1070
+ }
1071
+ }
1072
+ },
1073
+
1074
+
1075
+ // --------------- Prepare data ---------------
1076
+ getChartData: function() {
1077
+ var chart_data = {};
1078
+
1079
+ // Axes Data
1080
+ this.getAxesData(chart_data);
1081
+
1082
+ // Style Options
1083
+ var style_options = chart_data['style'] = {};
1084
+ this.getStyleData(style_options);
1085
+ this.getColorData(style_options);
1086
+
1087
+ if (this.filter_creator === null)
1088
+ this.addDefaultFilters(chart_data);
1089
+ else
1090
+ chart_data = $.extend(chart_data, {filters: this.filter_creator.data('filterCreator').getFiltersData()});
1091
+
1092
+ return JSON.parse(JSON.stringify(chart_data));
1093
+ },
1094
+
1095
+ getAxesData: function(chart_data) {
1096
+ // Get select fields values
1097
+ var split_x_axis = this.xContainer.find('[name="x-axis"]').val().split('-');
1098
+ var x_val = split_x_axis[0], x_type = split_x_axis[1];
1099
+ var y_vals = [];
1100
+ this.yContainer.find('[name="y-axis"]').each(function() {
1101
+ y_vals.push($(this).val());
1102
+ });
1103
+
1104
+ // Return if x or y missing
1105
+ if (x_val === '' || y_vals.length === 0)
1106
+ return alert('Variable missing.');
1107
+
1108
+ // If type is datetime, prepare date_info
1109
+ chart_data['x_data'] = {};
1110
+ chart_data['x_data']['type'] = x_type;
1111
+ var label_type = this.labelOptionsContainer.find('[name="labels-type"]:checked').val();
1112
+ if (label_type === 'attribute') {
1113
+ var sub_array = this.labelOptionsContainer.find('.axis-select[name="x-sub"]').val().split('-');
1114
+ chart_data['x_data']['sub_attribute'] = sub_array[0];
1115
+ chart_data['x_data']['sub_attribute_from'] = x_type;
1116
+ chart_data['x_data']['type'] = sub_array[1];
1117
+ label_type = this.labelOptionsContainer.find('[name="sub-labels-type"]:checked').val();
1118
+ }
1119
+ chart_data['x_data']['label_type'] = label_type;
1120
+
1121
+ switch(chart_data['x_data']['type']) {
1122
+ case 'datetime':
1123
+ var date_info = chart_data['x_data'];
1124
+ var daterange = this.labelOptionsContainer.find('.daterange-value').text().split(' - ');
1125
+ date_info['start'] = daterange[0];
1126
+ date_info['end'] = daterange[1];
1127
+ date_info['date_range_type'] = this.labelOptionsContainer.find('#date-range-select').val();
1128
+ date_info['period'] = this.labelOptionsContainer.find('[name="period"]:checked').val();
1129
+ // date_info['format'] = label_options_div.find('input[name="format"]').val();
1130
+ break;
1131
+
1132
+ case 'has':
1133
+ case 'ref':
1134
+ case 'text':
1135
+ case 'numeric':
1136
+ if (label_type === 'text-auto') break;
1137
+
1138
+ var labels_num = this.labelOptionsContainer.find('.label-limit-div').length;
1139
+ var labels = chart_data['x_data']['labels'] = [];
1140
+ var labels_corres = chart_data['x_data']['labels-corres'] = [];
1141
+
1142
+ for (var i = 1; i <= labels_num; i++) {
1143
+ if (label_type === 'number') {
1144
+ var low = parseInt(this.labelOptionsContainer.find('[name="label-' + (i-1) + '"]').val()), high = parseInt(this.labelOptionsContainer.find('[name="label-' + i + '"]').val()) - 1;
1145
+ if (low === high)
1146
+ labels.push(low);
1147
+ else
1148
+ labels.push(low + '-' + high);
1149
+ }
1150
+ else if (label_type === 'numeric') {
1151
+ labels.push(this.labelOptionsContainer.find('[name="label-' + i + '"]').val());
1152
+ labels_corres.push(this.labelOptionsContainer.find('[name="label-corres-' + i + '"]').val());
1153
+ }
1154
+ else
1155
+ labels.push(this.labelOptionsContainer.find('[name="label-' + i + '"]').val());
1156
+ }
1157
+
1158
+ if (label_type === 'number') {
1159
+ var plus = this.labelOptionsContainer.find('[name="plus"]:checked').val();
1160
+ if (plus === 'true')
1161
+ labels.push(this.labelOptionsContainer.find('[name="label-' + labels_num + '"]').val() + '+');
1162
+ }
1163
+
1164
+ break;
1165
+
1166
+ case 'boolean':
1167
+ chart_data['x_data']['labels'] = [true, false];
1168
+
1169
+ var true_corres = this.labelOptionsContainer.find('[name="boolean-true-corres"]').val(),
1170
+ false_corres = this.labelOptionsContainer.find('[name="boolean-false-corres"]').val();
1171
+ chart_data['x_data']['labels-corres'] = [true_corres, false_corres];
1172
+ break;
1173
+
1174
+ default:
1175
+ break;
1176
+ }
1177
+ chart_data['y_data'] = y_vals;
1178
+ chart_data['x_data']['attribute'] = x_val;
1179
+ chart_data['x_data']['from_filter'] = (split_x_axis.length === 3);
1180
+
1181
+ // Datasets Labels
1182
+ var datasets_labels = [];
1183
+ this.yContainer.find('[name="dataset-label"]').each(function() {
1184
+ datasets_labels.push($(this).val());
1185
+ });
1186
+ chart_data['datasets_labels'] = datasets_labels;
1187
+
1188
+ // Options
1189
+ chart_data['options'] = null;
1190
+
1191
+ // Types
1192
+ var main_type = this.yContainer.find('[name="main-type"]').val(), type = [];
1193
+ if (main_type === 'bar' || main_type === 'line') {
1194
+ this.yContainer.find('.type-select').each(function() {
1195
+ type.push($(this).val());
1196
+ });
1197
+ }
1198
+ else
1199
+ type.push(main_type);
1200
+ chart_data['types'] = type;
1201
+ },
1202
+
1203
+ getStyleData: function(style_options) {
1204
+ // Title
1205
+ style_options['title'] = this.styleOptionsContainer.find('[name="title"]').val();
1206
+
1207
+ // Legend
1208
+ var legend_options = style_options['legend'] = {};
1209
+ legend_options['display'] = this.styleOptionsContainer.find('[name="legend"]').is(':checked');
1210
+ legend_options['position'] = this.styleOptionsContainer.find('[name="legend-pos"]').val();
1211
+
1212
+ // Grid
1213
+ var grid_options = style_options['grid'] = {};
1214
+ grid_options['x'] = this.styleOptionsContainer.find('[name="x-grid-lines"]').is(':checked');
1215
+ grid_options['y'] = this.styleOptionsContainer.find('[name="y-grid-lines"]').is(':checked');
1216
+
1217
+ // Y Axis
1218
+ var y_axis_options = style_options['y-axis'] = {};
1219
+ y_axis_options['min'] = this.styleOptionsContainer.find('[name="y-axis-min"]').val();
1220
+ y_axis_options['max'] = this.styleOptionsContainer.find('[name="y-axis-max"]').val();
1221
+ y_axis_options['step'] = this.styleOptionsContainer.find('[name="y-axis-step"]').val();
1222
+
1223
+ // Labeling step
1224
+ style_options['labeling-step'] = this.styleOptionsContainer.find('[name="labeling-step"]').val();
1225
+
1226
+ // Stacked
1227
+ style_options['stacked'] = this.styleOptionsContainer.find('[name="stacked"]').is(':checked');
1228
+ },
1229
+
1230
+ getColorData: function(style_options) {
1231
+ // Colors
1232
+ style_options['colors'] = [];
1233
+ this.colorOptionsContainer.find('[name="dataset-color"]').each(function() {
1234
+ style_options['colors'].push($(this).val());
1235
+ });
1236
+
1237
+ // Area transparency
1238
+ style_options['transparencies'] = [];
1239
+ this.colorOptionsContainer.find('[name="transparency"]').each(function() {
1240
+ style_options['transparencies'].push($(this).val());
1241
+ });
1242
+ },
1243
+
1244
+ addDefaultFilters: function(chart_data) {
1245
+ var filters_data = chart_data['filters'] = {};
1246
+ $.each(chart_data['y_data'], function(index, model) {
1247
+ filters_data[model] = {num_records: ''};
1248
+ });
1249
+ },
1250
+
1251
+
1252
+ // --------------- Build chart from data ---------------
1253
+ buildChartFields: function(chart_data) {
1254
+ this.buildYAxes(chart_data);
1255
+ this.buildXAxis(chart_data['x_data']);
1256
+ this.buildLabelOptions(chart_data['x_data'], false);
1257
+ this.buildStyleOptions(chart_data['style']);
1258
+ this.buildColorOptions(chart_data['style']);
1259
+ },
1260
+
1261
+ buildYAxes: function(chart_data) {
1262
+ var yContainer = this.yContainer;
1263
+ yContainer.find('.remove-var-btn').click();
1264
+
1265
+ $.each(chart_data['y_data'], function(index, value) {
1266
+ if (index > 0)
1267
+ yContainer.find('#add-var-btn').click();
1268
+
1269
+ yContainer.find('.var-div:last [name="y-axis"]').focusin().val(value).change();
1270
+ yContainer.find('[name="dataset-label"]:last').val(chart_data['datasets_labels'][index]);
1271
+
1272
+ });
1273
+
1274
+ var main_type = chart_data['types'][0];
1275
+ yContainer.find('[name="main-type"]').val(main_type).change();
1276
+ if (main_type === 'bar' || main_type === 'line') {
1277
+ var idx = 1;
1278
+ yContainer.find('.type-select').not('[name="main-type"]').each(function() {
1279
+ $(this).val(chart_data['types'][idx++]);
1280
+ });
1281
+ }
1282
+ },
1283
+
1284
+ buildXAxis: function(x_data) {
1285
+ var value_string = x_data['attribute'] + '-';
1286
+ if ('sub_attribute' in x_data) {
1287
+ if (x_data['sub_attribute_from'] === 'has')
1288
+ value_string += 'has';
1289
+ else
1290
+ value_string += 'ref';
1291
+ }
1292
+ else
1293
+ value_string += x_data['type'];
1294
+
1295
+ if (x_data['from_filter'] === 'true')
1296
+ value_string += '-filter';
1297
+
1298
+ this.xContainer.find('[name="x-axis"]').focusin().val(value_string).change();
1299
+ },
1300
+
1301
+ buildLabelOptions: function(x_data, is_sub) {
1302
+ if ('sub_attribute' in x_data && !is_sub) {
1303
+ if (x_data['sub_attribute_from'] === 'has')
1304
+ this.buildHasLabelOptions(x_data);
1305
+ else
1306
+ this.buildRefLabelOptions(x_data);
1307
+ }
1308
+
1309
+ switch (x_data['type']) {
1310
+ case 'datetime':
1311
+ this.buildDatetimeLabelOptions(x_data);
1312
+ break;
1313
+
1314
+ case 'numeric':
1315
+ this.buildNumericLabelOptions(x_data);
1316
+ break;
1317
+
1318
+ case 'boolean':
1319
+ this.buildBooleanLabelOptions(x_data);
1320
+ break;
1321
+
1322
+ case 'text':
1323
+ this.buildTextLabelOptions(x_data);
1324
+ break;
1325
+
1326
+ case 'has':
1327
+ this.buildHasLabelOptions(x_data);
1328
+ break;
1329
+
1330
+ case 'ref':
1331
+ this.buildRefLabelOptions(x_data);
1332
+ break;
1333
+
1334
+ default:
1335
+ break;
1336
+
1337
+ }
1338
+ },
1339
+
1340
+ buildDatetimeLabelOptions: function(x_data) {
1341
+ var start = x_data['start'], end = x_data['end'];
1342
+ this.labelOptionsContainer.find('.daterange span').html(start + ' - ' + end);
1343
+ this.labelOptionsContainer.find('#date-range-select').val(x_data['date_range_type']).change();
1344
+ this.labelOptionsContainer.find('[name="period"][value="' + x_data['period'] + '"]').prop('checked', true);
1345
+ // $('input[name="format"]').val(x_data['format']);
1346
+ },
1347
+
1348
+ buildNumericLabelOptions: function(x_data) {
1349
+ var label_options_container = this.labelOptionsContainer;
1350
+
1351
+ var label_type = x_data['label_type'];
1352
+
1353
+ if (label_type === 'number') {
1354
+ label_options_container.find('[type="radio"][value="number"]:last').prop('checked', true).change();
1355
+ var last_idx = x_data['labels'].length - 1;
1356
+ var plus = x_data['labels'][last_idx].split('+');
1357
+ var num_labels = last_idx;
1358
+ if (plus.length === 1) num_labels++;
1359
+
1360
+ label_options_container.find('[name="labels-num"]').val(num_labels).change();
1361
+ $.each(x_data['labels'], function(index, value) {
1362
+ if (index === last_idx) return true;
1363
+ label_options_container.find('[name="label-' + index + '"]:last').val(value.split('-')[0]);
1364
+ });
1365
+ if (plus.length === 2) {
1366
+ label_options_container.find('[name="label-' + last_idx + '"]:last').val(plus[0]);
1367
+ plus = 'true';
1368
+ }
1369
+ else {
1370
+ label_options_container.find('[name="label-' + num_labels + '"]:last').val(x_data['labels'][last_idx].split('-')[1]);
1371
+ plus = 'false';
1372
+ }
1373
+ label_options_container.find('[name="plus"][value="' + plus + '"]').prop('checked', true);
1374
+ }
1375
+ else {
1376
+ $.each(x_data['labels'], function(index, value) {
1377
+ label_options_container.find('[name="label-' + (index+1) + '"]').val(value);
1378
+ label_options_container.find('[name="label-corres-' + (index+1) + '"]').val(x_data['labels-corres'][index]);
1379
+ });
1380
+ }
1381
+ },
1382
+
1383
+ buildBooleanLabelOptions: function(x_data) {
1384
+ this.labelOptionsContainer.find('[name="boolean-true-corres"]').val(x_data['labels-corres'][0]);
1385
+ this.labelOptionsContainer.find('[name="boolean-false-corres"]').val(x_data['labels-corres'][1]);
1386
+ },
1387
+
1388
+ buildTextLabelOptions: function(x_data) {
1389
+ var label_options_container = this.labelOptionsContainer;
1390
+
1391
+ var label_type = x_data['label_type'];
1392
+ if (label_type === 'text') label_options_container.find('[name="labels-type"][value="text"]').prop('checked', true).change();
1393
+
1394
+ if (label_type !== 'text-auto') {
1395
+ label_options_container.find('[name="labels-num"]').val(x_data['labels'].length).change();
1396
+ $.each(x_data['labels'], function(index, value) {
1397
+ label_options_container.find('.limit-label[name="label-' + (index+1) + '"]').val(value);
1398
+ });
1399
+ }
1400
+ },
1401
+
1402
+ buildHasLabelOptions: function(x_data) {
1403
+ var label_options_container = this.labelOptionsContainer;
1404
+
1405
+ var label_type = ('sub_attribute' in x_data) ? 'attribute' : x_data['label_type'];
1406
+ label_options_container.find('[name="labels-type"][value="' + label_type + '"]').prop('checked', true).change();
1407
+
1408
+ if (label_type === 'number') {
1409
+ var last_idx = x_data['labels'].length - 1;
1410
+ var plus = x_data['labels'][last_idx].split('+');
1411
+ var num_labels = last_idx;
1412
+ if (plus.length === 1) num_labels++;
1413
+
1414
+ label_options_container.find('[name="labels-num"]').val(num_labels).change();
1415
+ $.each(x_data['labels'], function(index, value) {
1416
+ label_options_container.find('.limit-label[name="label-' + index + '"]').val(value.split('-')[0]);
1417
+ if (index === last_idx) return true;
1418
+ });
1419
+ if (plus.length === 2) {
1420
+ label_options_container.find('.limit-label[name="label-' + last_idx + '"]').val(plus[0]);
1421
+ plus = 'true';
1422
+ }
1423
+ else {
1424
+ label_options_container.find('.limit-label[name="label-' + num_labels + '"]').val(x_data['labels'][last_idx].split('-')[1]);
1425
+ plus = 'false';
1426
+ }
1427
+ label_options_container.find('[name="plus"][value="' + plus + '"]').prop('checked', true);
1428
+ }
1429
+ else {
1430
+ var sub_attribute_string = x_data['sub_attribute'] + '-' + x_data['type'];
1431
+ label_options_container.find('[name="x-sub"]').focusin().val(sub_attribute_string).change();
1432
+ this.buildLabelOptions(x_data, true);
1433
+ }
1434
+ },
1435
+
1436
+ buildRefLabelOptions: function(x_data) {
1437
+ var label_type = ('sub_attribute' in x_data) ? 'attribute' : x_data['label_type'];
1438
+ this.labelOptionsContainer.find('[name="labels-type"][value="' + label_type + '"]').prop('checked', true).change();
1439
+
1440
+ if (label_type === 'attribute') {
1441
+ var sub_attribute_string = x_data['sub_attribute'] + '-' + x_data['type'];
1442
+ this.labelOptionsContainer.find('[name="x-sub"]').focusin().val(sub_attribute_string).change();
1443
+ this.buildLabelOptions(x_data, true);
1444
+ }
1445
+ },
1446
+
1447
+ buildStyleOptions: function(style_options) {
1448
+ // Title
1449
+ var title = style_options['title'];
1450
+ this.styleOptionsContainer.find('[name="title"]').val(title);
1451
+
1452
+ // Legend options
1453
+ var legend_options = style_options['legend'];
1454
+ this.styleOptionsContainer.find('[name="legend"]').prop('checked', legend_options['display'] === 'true');
1455
+ this.styleOptionsContainer.find('[name="legend-pos"]').val(legend_options['position']);
1456
+
1457
+ // Grid checkboxes
1458
+ var grid_options = style_options['grid'];
1459
+ this.styleOptionsContainer.find('[name="x-grid-lines"]').prop('checked', grid_options['x'] === 'true');
1460
+ this.styleOptionsContainer.find('[name="y-grid-lines"]').prop('checked', grid_options['y'] === 'true');
1461
+
1462
+ // Y Axis options
1463
+ var y_axis_options = style_options['y-axis'];
1464
+ this.styleOptionsContainer.find('[name="y-axis-min"]').val(y_axis_options['min']);
1465
+ this.styleOptionsContainer.find('[name="y-axis-max"]').val(y_axis_options['max']);
1466
+ this.styleOptionsContainer.find('[name="y-axis-step"]').val(y_axis_options['step']);
1467
+
1468
+ // Labeling step number
1469
+ this.styleOptionsContainer.find('[name="labeling-step"]').val(style_options['labeling-step']);
1470
+
1471
+ // Stacked checkbox
1472
+ var stacked = style_options['stacked'] === 'true';
1473
+ this.styleOptionsContainer.find('[name="stacked"]').prop('checked', stacked);
1474
+ },
1475
+
1476
+ buildColorOptions: function(style_options) {
1477
+ // Colors
1478
+ var colors = style_options['colors'], i = 0;
1479
+ this.colorOptionsContainer.find('[name="dataset-color"]').each(function() {
1480
+ $(this).val(colors[i]);
1481
+ $(this).parent().find('.minicolors-input-swatch .minicolors-swatch-color').css("background-color", colors[i++]);
1482
+ });
1483
+
1484
+ // Transparencies
1485
+ var transparencies = style_options['transparencies'];
1486
+ i = 0;
1487
+ this.colorOptionsContainer.find('[name="transparency"]').each(function() {
1488
+ $(this).val(transparencies[i++]);
1489
+ });
1490
+ },
1491
+
1492
+
1493
+ // --------------- Color callback ---------------
1494
+ colorCallback: function() {
1495
+ var labels_num_input = this.labelOptionsContainer.find('[name="labels-num"]'),
1496
+ main_var_color_divs = this.colorOptionsContainer.find('.color-div[data-id="0"]'),
1497
+ x_is_boolean = this.labelOptionsContainer.find('[name="boolean-true"]').length !== 0;
1498
+
1499
+ var main_type = this.yContainer.find('[name="main-type"]').val();
1500
+
1501
+ // No colors if no labels_num (in no boolean case) or if type 1 chart
1502
+ if ((labels_num_input.length === 0 && !x_is_boolean) || main_type === 'bar' || main_type === 'line') {
1503
+ main_var_color_divs.not('#main-color').remove();
1504
+ }
1505
+ // Right number of colors for type 2 chart
1506
+ else {
1507
+ var color_number = x_is_boolean ? 2 : parseInt(labels_num_input.val()), // 2 colors if x is boolean
1508
+ previous_color_number = parseInt(main_var_color_divs.length);
1509
+ var adapt_to_label_type = 0;
1510
+ if ((this.labelOptionsContainer.find('[name="labels-type"][value="number"]').is(':checked')
1511
+ || this.labelOptionsContainer.find('[name="sub-labels-type"][value="number"]').is(':checked'))
1512
+ && this.labelOptionsContainer.find('[name="plus"][value="true"]').is(':checked')) {
1513
+ adapt_to_label_type = 1;
1514
+ }
1515
+
1516
+ if (color_number >= previous_color_number) {
1517
+ for (var i = previous_color_number; i < color_number + adapt_to_label_type; i++) {
1518
+ this.addColorToCreator(0, i + 1);
1519
+ }
1520
+ }
1521
+ else {
1522
+ for (var i = previous_color_number - adapt_to_label_type; i > color_number; i--) {
1523
+ this.colorOptionsContainer.find('.color-div[data-id="0"]:last').remove();
1524
+ }
1525
+ }
1526
+ }
1527
+ }
1528
+
1529
+ };
1530
+
1531
+ $.fn.chartCreator = function(options, callback) {
1532
+ this.each(function(i, _element) {
1533
+ var el = $(_element);
1534
+ if (el.data('chartCreator'))
1535
+ el.data('chartCreator').remove();
1536
+ el.data('chartCreator', new ChartCreator(el, options, callback));
1537
+ });
1538
+ return this;
1539
+ };
1540
+
1541
+ // Creates a daterange field for datetime label options
1542
+ function daterangeField(parent_div) {
1543
+ // Append (empty) daterangepicker
1544
+ var daterange_input_string = '<label>In range</label>'
1545
+ + '<div id="daterange-chart" class="daterange" style="background: #fff; cursor: pointer; padding: 5px 10px; border: 1px solid #ccc; width: 100%">'
1546
+ + '<i class="glyphicon glyphicon-calendar fa fa-calendar"></i>&nbsp;'
1547
+ + '<span class="daterange-value"></span>'
1548
+ + '<b class="caret"></b>'
1549
+ + '</div>';
1550
+ var daterange_input = $(daterange_input_string).appendTo(parent_div);
1551
+
1552
+ // Customize daterangepicker
1553
+ $(function() {
1554
+ // Default start, end
1555
+ var start = moment().subtract(29, 'days');
1556
+ var end = moment();
1557
+
1558
+ // Change date format
1559
+ function cb(start, end) {
1560
+ parent_div.find('#daterange-chart span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
1561
+ }
1562
+
1563
+ // Set as daterangepicker with different defaults
1564
+ daterange_input.daterangepicker({
1565
+ startDate: start,
1566
+ endDate: end,
1567
+ ranges: {
1568
+ 'Today': [moment(), moment()],
1569
+ 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
1570
+ 'Last 7 Days': [moment().subtract(6, 'days'), moment()],
1571
+ 'Last 30 Days': [moment().subtract(29, 'days'), moment()],
1572
+ 'This Month': [moment().startOf('month'), moment().endOf('month')],
1573
+ 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
1574
+ }
1575
+ }, cb);
1576
+
1577
+ cb(start, end);
1578
+ });
1579
+ }
1580
+
1581
+ return ChartCreator;
1582
+ });