PageRenderTime 39ms CodeModel.GetById 17ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/app/scripts/components/VizabiPrototype.js

https://gitlab.com/Webxity/vizabi-prototypes
JavaScript | 370 lines | 273 code | 61 blank | 36 comment | 36 complexity | eec09407095d13340f1ef7aeffa7e9f6 MD5 | raw file
  1(function(window, document) {'use strict';
  2
  3  var noop = angular.noop;
  4
  5  var tools = [
  6    'bar-chart',
  7    'bubble-chart',
  8    'line-chart'
  9  ];
 10
 11  var toolsObject = {
 12    'bar-chart': 'BarChart',
 13    'bubble-chart': 'BubbleChart',
 14    'line-chart': 'LineChart'
 15  };
 16
 17  /**
 18   * Tool decider
 19   * @param tool {String}
 20   * @exception error
 21   */
 22  var tool = function(tool) {
 23    if (tool) {
 24      if (tools.indexOf(tool) === -1) {
 25        error('No built-in tool provider found.');
 26      }
 27      return tool;
 28    }
 29  };
 30
 31  /**
 32   * Throw error
 33   * @param msg {String}
 34   */
 35  var error = function(msg) {
 36    var err = new Error(msg);
 37    return err.stack;
 38  };
 39
 40  /**
 41   * Safe function execution
 42   * @param fn {Function}
 43   */
 44  var safeExec = function(fn) {
 45    fn = fn || function() {};
 46    try {
 47      fn()
 48    } catch (e) {
 49      throw error(e);
 50    }
 51  };
 52
 53  /**
 54   * Todo: Optimize and make it work
 55   * Create custom events
 56   * @param e {Object}
 57   * @param data {Object}
 58   * @returns {CustomEvent|Boolean}
 59   */
 60  var createEvent = function(e, data) {
 61    if (!angular.isObject(e) || !angular.isObject(data)) {
 62      return false;
 63    }
 64
 65    window.addEventListener(e.name, function(e) { console.log(e.detail) });
 66
 67    e.event = new CustomEvent(e.name, {
 68      detail: data
 69    });
 70
 71    window.dispatchEvent(e.event);
 72  };
 73
 74  var switchResponsiveDevices = function() {
 75    document.querySelector('#resize-portrait').addEventListener(
 76      'click',
 77      function() {
 78        this.setScreenSize(this.PORTRAIT);
 79      }.bind(this));
 80
 81    document.querySelector('#resize-landscape').addEventListener(
 82      'click',
 83      function() {
 84        this.setScreenSize(this.LANDSCAPE)
 85      }.bind(this));
 86
 87    document.querySelector('#resize-full').addEventListener(
 88      'click',
 89      function() {
 90        this.setScreenSize(this.FULL);
 91      }.bind(this));
 92
 93    document.querySelector('#enter-fullscreen').addEventListener(
 94      'click',
 95      function() {
 96        if (!stageEl) {
 97          error('Stage is not yet drawn');
 98        }
 99
100        this.settings.fullscreen = true;
101
102        this.setScreenSize(this.FULL);
103
104        if (this.settings.fullscreen === true) {
105          if (stageEl.requestFullscreen) {
106            stageEl.requestFullscreen();
107          } else if (stageEl.msRequestFullscreen) {
108            stageEl.msRequestFullscreen();
109          } else if (stageEl.mozRequestFullScreen) {
110            stageEl.mozRequestFullScreen();
111          } else if (stageEl.webkitRequestFullscreen) {
112            stageEl.webkitRequestFullscreen();
113          }
114        }
115
116      }.bind(this));
117
118    var langEl = document.querySelector('#change-lang');
119
120    langEl.addEventListener(
121      'click',
122      function() {
123        var title = langEl.getAttribute('data-original-title');
124        var langIndex = this.langs.indexOf(title.toLowerCase());
125        if (langIndex !== -1) {
126          this.lang = (this.lang === 'pt') ? 'en' : 'pt';
127          langEl.setAttribute(
128            'data-original-title',
129            this.langs[langIndex].toUpperCase()
130          );
131          this.visualize();
132        }
133      }.bind(this));
134  };
135
136  var listenWindowResize = function() {
137    window.addEventListener('resize', function(e) {
138      if (this.screenType === this.PORTRAIT
139      || this.screenType === this.LANDSCAPE) {
140        return false;
141      }
142      // Todo: Uncomment when fix
143      //this.newEvent(this.eventTypes.RESIZE, e);
144
145      var fullScreen = document.mozFullscreenElement
146        || document.webkitFullscreenElement
147        || document.msFullscreenElement
148        || document.fullscreenElement;
149
150      if (!fullScreen) {
151        this.settings.fullscreen = false;
152      }
153
154      this.setScreenSize(this.FULL);
155    }.bind(this));
156  };
157
158  // Private var for short instance
159  var VP;
160  var htmlID;
161  var containerID;
162  var containerEl;
163  var stageID;
164  var stageEl;
165
166  /**
167   * VizabiPrototype constructor object
168   * @param tool {String} bar-chart/bubble-chart/line-chart
169   * @param id {String} html id attribute
170   * @param options {Object}
171   * @constructor
172   */
173  window.VizabiPrototype = VP = function VizabiPrototype(tool, id, options) {
174    this.PORTRAIT = 'portrait';
175    this.LANDSCAPE = 'landscape';
176    this.FULL = 'full';
177
178    this.tool = tool;
179
180    this.htmlID = htmlID = id;
181
182    this.sliderID = '#slider';
183    this.optionsID = '#options';
184
185    this.options = options;
186
187    this.stateObj = {};
188
189    this.screenType = 'portrait';
190    this.screenSize = this.screenSizes.portrait;
191
192    this.lang = options.language.id || 'en';
193    this.langs = ['en', 'pt'];
194
195    var eventPrefix = 'vp:';
196    this.events = {
197      RESIZE: []
198    };
199    this.eventTypes = {
200      RESIZE: {
201        name: eventPrefix + 'resize',
202        event: noop
203      }
204    };
205
206    switchResponsiveDevices.call(this);
207    listenWindowResize.call(this);
208
209    this.visualize();
210  };
211
212  VP.prototype.render = function() {
213    tool(this.tool);
214
215    //Todo: Find a proper place for this code to execute. Reason is because of Async call by Ajax causes delay in constructor.
216    this.containerID = containerID = '#vp-bar-main';
217    this.stageID = stageID = 'div#vp-bar-stage';
218    this.containerEl = containerEl = document.querySelector(containerID);
219    this.stageEl = stageEl = document.querySelector(stageID);
220    this.stageEl.style.width = this.screenSize.width + 'px';
221    this.stageEl.style.height = this.screenSize.height  + 'px';
222
223    this[toolsObject[this.tool]]();
224    /*safeExec(function() {
225      ;
226    }.bind(this));*/
227    return this;
228  };
229
230  VP.prototype.newEvent = function(name, data) {
231    createEvent.apply(null, arguments);
232  };
233
234  VP.prototype.visualize = function() {
235    async.waterfall([
236      function(fn) {
237        this.queryData(fn);
238      }.bind(this),
239
240      function(data, fn) {
241        this.dataset = data;
242        fn(null);
243      }.bind(this)
244    ], function(err) {
245      if (err) {
246        return error(err);
247      }
248
249      this.render();
250    }.bind(this));
251    return this;
252  };
253
254  VP.prototype.queryData = function(fn) {
255    var options = this.options;
256    var path = 'data/' + this.tool + '/query-en.json';
257    var lang = this.lang;
258
259    if (options.data.reader !== 'local-json') {
260      // remote server
261    } else {
262      path = options.data.path;
263      var ext = '-'+lang+'.json';
264      if (path.indexOf(ext) !== -1) {
265        path = path.replace(ext, '');
266      }
267      path = 'data/' + this.tool + '/' + path + ext;
268    }
269
270    d3.json(path, function(error, json) {
271      if (error) return console.warn(error);
272      fn.apply(null, arguments);
273    }.bind(this));
274  };
275
276  VP.prototype.destroy = function() {
277    var svgNode = document.querySelector(this.htmlID);
278    var sliderNode = document.querySelector(this.sliderID);
279
280    while (svgNode && svgNode.hasChildNodes()) {
281      svgNode.removeChild(svgNode.lastChild);
282    }
283
284    while (sliderNode && sliderNode.hasChildNodes()) {
285      sliderNode.removeChild(sliderNode.lastChild);
286    }
287
288    return this;
289  };
290
291  VP.prototype.reRender = function() {
292    return this.destroy().render();
293  };
294
295  //Changes the OPTIONS sent to constructor obtained from textArea.
296  VP.prototype.stateChanger = function (defaultObj){
297    if (JSON.parse(document.getElementById("stateText").value != '')){
298      try{
299        this.stateObj = JSON.parse(document.getElementById("stateText").value);
300        this.options = this.stateObj;
301        this.reRender();
302      }
303      catch(e)
304      {
305        alert('Please Enter Valid JSON: ' + e);
306      }
307    }
308    else{
309      alert('No input detected, using default options');
310      this.options = defaultObj;
311      this.reRender();
312    }
313  };
314
315  VP.prototype.dataset = [];
316
317  VP.prototype.settings = {
318    fullscreen: false
319  };
320
321  VP.prototype.screenSizes = {
322    portrait: {
323      width: 320,
324      height: 512
325    },
326    landscape: {
327      width: 568,
328      height: 320
329    },
330    full: {}
331  };
332
333  Object.defineProperty(VP.prototype.screenSizes.full, 'width', {
334    get: function() {
335      var width = containerEl.offsetWidth;
336      if (VP.prototype.settings.fullscreen === true) {
337        width -= 70;
338      }
339      return width;
340    },
341    set: function(v) {
342      return v;
343    }
344  });
345
346  Object.defineProperty(VP.prototype.screenSizes.full, 'height', {
347    get: function() {
348      var c = VP.prototype.settings.fullscreen === true ? stageEl : containerEl;
349      return c.offsetHeight - 110;
350    },
351    set: function(v) {
352      return v;
353    }
354  });
355
356  VP.prototype.setScreenSize = function(type) {
357    var size = this.screenSizes[this.PORTRAIT];
358    if (type && this.screenSizes[type]) {
359      size = this.screenSizes[type];
360    }
361
362    this.screenSize = size;
363    this.screenType = type;
364    stageEl.style.width = size.width  + 'px';
365    stageEl.style.height = size.height + 'px';
366
367    this.reRender();
368  };
369
370})(window, document);