var util = require('../util');
							 | 
						|
								
							 | 
						|
								var ColorPicker = require('./ColorPicker').default;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * The way this works is for all properties of this.possible options, you can supply the property name in any form to list the options.
							 | 
						|
								 * Boolean options are recognised as Boolean
							 | 
						|
								 * Number options should be written as array: [default value, min value, max value, stepsize]
							 | 
						|
								 * Colors should be written as array: ['color', '#ffffff']
							 | 
						|
								 * Strings with should be written as array: [option1, option2, option3, ..]
							 | 
						|
								 *
							 | 
						|
								 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
							 | 
						|
								 */
							 | 
						|
								class Configurator {
							 | 
						|
								  /**
							 | 
						|
								   * @param {Object} parentModule        | the location where parentModule.setOptions() can be called
							 | 
						|
								   * @param {Object} defaultContainer    | the default container of the module
							 | 
						|
								   * @param {Object} configureOptions    | the fully configured and predefined options set found in allOptions.js
							 | 
						|
								   * @param {number} pixelRatio          | canvas pixel ratio
							 | 
						|
								   */
							 | 
						|
								  constructor(parentModule, defaultContainer, configureOptions, pixelRatio = 1) {
							 | 
						|
								    this.parent = parentModule;
							 | 
						|
								    this.changedOptions = [];
							 | 
						|
								    this.container = defaultContainer;
							 | 
						|
								    this.allowCreation = false;
							 | 
						|
								
							 | 
						|
								    this.options = {};
							 | 
						|
								    this.initialized = false;
							 | 
						|
								    this.popupCounter = 0;
							 | 
						|
								    this.defaultOptions = {
							 | 
						|
								      enabled: false,
							 | 
						|
								      filter: true,
							 | 
						|
								      container: undefined,
							 | 
						|
								      showButton: true
							 | 
						|
								    };
							 | 
						|
								    util.extend(this.options, this.defaultOptions);
							 | 
						|
								
							 | 
						|
								    this.configureOptions = configureOptions;
							 | 
						|
								    this.moduleOptions = {};
							 | 
						|
								    this.domElements = [];
							 | 
						|
								    this.popupDiv = {};
							 | 
						|
								    this.popupLimit = 5;
							 | 
						|
								    this.popupHistory = {};
							 | 
						|
								    this.colorPicker = new ColorPicker(pixelRatio);
							 | 
						|
								    this.wrapper = undefined;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * refresh all options.
							 | 
						|
								   * Because all modules parse their options by themselves, we just use their options. We copy them here.
							 | 
						|
								   *
							 | 
						|
								   * @param {Object} options
							 | 
						|
								   */
							 | 
						|
								  setOptions(options) {
							 | 
						|
								    if (options !== undefined) {
							 | 
						|
								      // reset the popup history because the indices may have been changed.
							 | 
						|
								      this.popupHistory = {};
							 | 
						|
								      this._removePopup();
							 | 
						|
								
							 | 
						|
								      let enabled = true;
							 | 
						|
								      if (typeof options === 'string') {
							 | 
						|
								        this.options.filter = options;
							 | 
						|
								      }
							 | 
						|
								      else if (options instanceof Array) {
							 | 
						|
								        this.options.filter = options.join();
							 | 
						|
								      }
							 | 
						|
								      else if (typeof options === 'object') {
							 | 
						|
								        if (options == null) {
							 | 
						|
								          throw new TypeError('options cannot be null');
							 | 
						|
								        }
							 | 
						|
								        if (options.container !== undefined) {
							 | 
						|
								          this.options.container = options.container;
							 | 
						|
								        }
							 | 
						|
								        if (options.filter !== undefined) {
							 | 
						|
								          this.options.filter = options.filter;
							 | 
						|
								        }
							 | 
						|
								        if (options.showButton !== undefined) {
							 | 
						|
								          this.options.showButton = options.showButton;
							 | 
						|
								        }
							 | 
						|
								        if (options.enabled !== undefined) {
							 | 
						|
								          enabled = options.enabled;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								      else if (typeof options === 'boolean') {
							 | 
						|
								        this.options.filter = true;
							 | 
						|
								        enabled = options;
							 | 
						|
								      }
							 | 
						|
								      else if (typeof options === 'function') {
							 | 
						|
								        this.options.filter = options;
							 | 
						|
								        enabled = true;
							 | 
						|
								      }
							 | 
						|
								      if (this.options.filter === false) {
							 | 
						|
								        enabled = false;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      this.options.enabled = enabled;
							 | 
						|
								    }
							 | 
						|
								    this._clean();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   *
							 | 
						|
								   * @param {Object} moduleOptions
							 | 
						|
								   */
							 | 
						|
								  setModuleOptions(moduleOptions) {
							 | 
						|
								    this.moduleOptions = moduleOptions;
							 | 
						|
								    if (this.options.enabled === true) {
							 | 
						|
								      this._clean();
							 | 
						|
								      if (this.options.container !== undefined) {
							 | 
						|
								        this.container = this.options.container;
							 | 
						|
								      }
							 | 
						|
								      this._create();
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Create all DOM elements
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _create() {
							 | 
						|
								    this._clean();
							 | 
						|
								    this.changedOptions = [];
							 | 
						|
								
							 | 
						|
								    let filter = this.options.filter;
							 | 
						|
								    let counter = 0;
							 | 
						|
								    let show = false;
							 | 
						|
								    for (let option in this.configureOptions) {
							 | 
						|
								      if (this.configureOptions.hasOwnProperty(option)) {
							 | 
						|
								        this.allowCreation = false;
							 | 
						|
								        show = false;
							 | 
						|
								        if (typeof filter === 'function') {
							 | 
						|
								          show = filter(option,[]);
							 | 
						|
								          show = show || this._handleObject(this.configureOptions[option], [option], true);
							 | 
						|
								        }
							 | 
						|
								        else if (filter === true || filter.indexOf(option) !== -1) {
							 | 
						|
								          show = true;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (show !== false) {
							 | 
						|
								          this.allowCreation = true;
							 | 
						|
								
							 | 
						|
								          // linebreak between categories
							 | 
						|
								          if (counter > 0) {
							 | 
						|
								            this._makeItem([]);
							 | 
						|
								          }
							 | 
						|
								          // a header for the category
							 | 
						|
								          this._makeHeader(option);
							 | 
						|
								
							 | 
						|
								          // get the sub options
							 | 
						|
								          this._handleObject(this.configureOptions[option], [option]);
							 | 
						|
								        }
							 | 
						|
								        counter++;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    this._makeButton();
							 | 
						|
								    this._push();
							 | 
						|
								    //~ this.colorPicker.insertTo(this.container);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * draw all DOM elements on the screen
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _push() {
							 | 
						|
								    this.wrapper = document.createElement('div');
							 | 
						|
								    this.wrapper.className = 'vis-configuration-wrapper';
							 | 
						|
								    this.container.appendChild(this.wrapper);
							 | 
						|
								    for (var i = 0; i < this.domElements.length; i++) {
							 | 
						|
								      this.wrapper.appendChild(this.domElements[i]);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    this._showPopupIfNeeded()
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * delete all DOM elements
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _clean() {
							 | 
						|
								    for (var i = 0; i < this.domElements.length; i++) {
							 | 
						|
								      this.wrapper.removeChild(this.domElements[i]);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (this.wrapper !== undefined) {
							 | 
						|
								      this.container.removeChild(this.wrapper);
							 | 
						|
								      this.wrapper = undefined;
							 | 
						|
								    }
							 | 
						|
								    this.domElements = [];
							 | 
						|
								
							 | 
						|
								    this._removePopup();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * get the value from the actualOptions if it exists
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @returns {*}
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _getValue(path) {
							 | 
						|
								    let base = this.moduleOptions;
							 | 
						|
								    for (let i = 0; i < path.length; i++) {
							 | 
						|
								      if (base[path[i]] !== undefined) {
							 | 
						|
								        base = base[path[i]];
							 | 
						|
								      }
							 | 
						|
								      else {
							 | 
						|
								        base = undefined;
							 | 
						|
								        break;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    return base;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * all option elements are wrapped in an item
							 | 
						|
								   * @param {Array} path    | where to look for the actual option
							 | 
						|
								   * @param {Array.<Element>} domElements
							 | 
						|
								   * @returns {number}
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeItem(path, ...domElements) {
							 | 
						|
								    if (this.allowCreation === true) {
							 | 
						|
								      let item = document.createElement('div');
							 | 
						|
								      item.className = 'vis-configuration vis-config-item vis-config-s' + path.length;
							 | 
						|
								      domElements.forEach((element) => {
							 | 
						|
								        item.appendChild(element);
							 | 
						|
								      });
							 | 
						|
								      this.domElements.push(item);
							 | 
						|
								      return this.domElements.length;
							 | 
						|
								    }
							 | 
						|
								    return 0;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * header for major subjects
							 | 
						|
								   * @param {string} name
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeHeader(name) {
							 | 
						|
								    let div = document.createElement('div');
							 | 
						|
								    div.className = 'vis-configuration vis-config-header';
							 | 
						|
								    div.innerHTML = name;
							 | 
						|
								    this._makeItem([],div);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a label, if it is an object label, it gets different styling.
							 | 
						|
								   * @param {string} name
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @param {string} objectLabel
							 | 
						|
								   * @returns {HTMLElement}
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeLabel(name, path, objectLabel = false) {
							 | 
						|
								    let div = document.createElement('div');
							 | 
						|
								    div.className = 'vis-configuration vis-config-label vis-config-s' + path.length;
							 | 
						|
								    if (objectLabel === true) {
							 | 
						|
								      div.innerHTML = '<i><b>' + name + ':</b></i>';
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      div.innerHTML = name + ':';
							 | 
						|
								    }
							 | 
						|
								    return div;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a dropdown list for multiple possible string optoins
							 | 
						|
								   * @param {Array.<number>} arr
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeDropdown(arr, value, path) {
							 | 
						|
								    let select = document.createElement('select');
							 | 
						|
								    select.className = 'vis-configuration vis-config-select';
							 | 
						|
								    let selectedValue = 0;
							 | 
						|
								    if (value !== undefined) {
							 | 
						|
								      if (arr.indexOf(value) !== -1) {
							 | 
						|
								        selectedValue = arr.indexOf(value);
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    for (let i = 0; i < arr.length; i++) {
							 | 
						|
								      let option = document.createElement('option');
							 | 
						|
								      option.value = arr[i];
							 | 
						|
								      if (i === selectedValue) {
							 | 
						|
								        option.selected = 'selected';
							 | 
						|
								      }
							 | 
						|
								      option.innerHTML = arr[i];
							 | 
						|
								      select.appendChild(option);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    let me = this;
							 | 
						|
								    select.onchange = function () {me._update(this.value, path);};
							 | 
						|
								
							 | 
						|
								    let label = this._makeLabel(path[path.length-1], path);
							 | 
						|
								    this._makeItem(path, label, select);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a range object for numeric options
							 | 
						|
								   * @param {Array.<number>} arr
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeRange(arr, value, path) {
							 | 
						|
								    let defaultValue = arr[0];
							 | 
						|
								    let min = arr[1];
							 | 
						|
								    let max = arr[2];
							 | 
						|
								    let step = arr[3];
							 | 
						|
								    let range = document.createElement('input');
							 | 
						|
								    range.className = 'vis-configuration vis-config-range';
							 | 
						|
								    try {
							 | 
						|
								      range.type = 'range'; // not supported on IE9
							 | 
						|
								      range.min = min;
							 | 
						|
								      range.max = max;
							 | 
						|
								    }
							 | 
						|
								    // TODO: Add some error handling and remove this lint exception
							 | 
						|
								    catch (err) {}  // eslint-disable-line no-empty
							 | 
						|
								    range.step = step;
							 | 
						|
								
							 | 
						|
								    // set up the popup settings in case they are needed.
							 | 
						|
								    let popupString = '';
							 | 
						|
								    let popupValue = 0;
							 | 
						|
								
							 | 
						|
								    if (value !== undefined) {
							 | 
						|
								      let factor = 1.20;
							 | 
						|
								      if (value < 0 && value * factor < min) {
							 | 
						|
								        range.min = Math.ceil(value * factor);
							 | 
						|
								        popupValue = range.min;
							 | 
						|
								        popupString = 'range increased';
							 | 
						|
								      }
							 | 
						|
								      else if (value / factor < min) {
							 | 
						|
								        range.min = Math.ceil(value / factor);
							 | 
						|
								        popupValue = range.min;
							 | 
						|
								        popupString = 'range increased';
							 | 
						|
								      }
							 | 
						|
								      if (value * factor > max && max !== 1) {
							 | 
						|
								        range.max = Math.ceil(value * factor);
							 | 
						|
								        popupValue = range.max;
							 | 
						|
								        popupString = 'range increased';
							 | 
						|
								      }
							 | 
						|
								      range.value = value;
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      range.value = defaultValue;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    let input = document.createElement('input');
							 | 
						|
								    input.className = 'vis-configuration vis-config-rangeinput';
							 | 
						|
								    input.value = range.value;
							 | 
						|
								
							 | 
						|
								    var me = this;
							 | 
						|
								    range.onchange = function () {input.value = this.value; me._update(Number(this.value), path);};
							 | 
						|
								    range.oninput  = function () {input.value = this.value; };
							 | 
						|
								
							 | 
						|
								    let label = this._makeLabel(path[path.length-1], path);
							 | 
						|
								    let itemIndex = this._makeItem(path, label, range, input);
							 | 
						|
								
							 | 
						|
								    // if a popup is needed AND it has not been shown for this value, show it.
							 | 
						|
								    if (popupString !== '' && this.popupHistory[itemIndex] !== popupValue) {
							 | 
						|
								      this.popupHistory[itemIndex] = popupValue;
							 | 
						|
								      this._setupPopup(popupString, itemIndex);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a button object
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeButton() {
							 | 
						|
								    if (this.options.showButton === true) {
							 | 
						|
								      let generateButton = document.createElement('div');
							 | 
						|
								      generateButton.className = 'vis-configuration vis-config-button';
							 | 
						|
								      generateButton.innerHTML = 'generate options';
							 | 
						|
								      generateButton.onclick =     () => {this._printOptions();};
							 | 
						|
								      generateButton.onmouseover = () => {generateButton.className = 'vis-configuration vis-config-button hover';};
							 | 
						|
								      generateButton.onmouseout =  () => {generateButton.className = 'vis-configuration vis-config-button';};
							 | 
						|
								
							 | 
						|
								      this.optionsContainer = document.createElement('div');
							 | 
						|
								      this.optionsContainer.className = 'vis-configuration vis-config-option-container';
							 | 
						|
								
							 | 
						|
								      this.domElements.push(this.optionsContainer);
							 | 
						|
								      this.domElements.push(generateButton);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * prepare the popup
							 | 
						|
								   * @param {string} string
							 | 
						|
								   * @param {number} index
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _setupPopup(string, index) {
							 | 
						|
								    if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
							 | 
						|
								      let div = document.createElement("div");
							 | 
						|
								      div.id = "vis-configuration-popup";
							 | 
						|
								      div.className = "vis-configuration-popup";
							 | 
						|
								      div.innerHTML = string;
							 | 
						|
								      div.onclick = () => {this._removePopup()};
							 | 
						|
								      this.popupCounter += 1;
							 | 
						|
								      this.popupDiv = {html:div, index:index};
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * remove the popup from the dom
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _removePopup() {
							 | 
						|
								    if (this.popupDiv.html !== undefined) {
							 | 
						|
								      this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
							 | 
						|
								      clearTimeout(this.popupDiv.hideTimeout);
							 | 
						|
								      clearTimeout(this.popupDiv.deleteTimeout);
							 | 
						|
								      this.popupDiv = {};
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Show the popup if it is needed.
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _showPopupIfNeeded() {
							 | 
						|
								    if (this.popupDiv.html !== undefined) {
							 | 
						|
								      let correspondingElement = this.domElements[this.popupDiv.index];
							 | 
						|
								      let rect = correspondingElement.getBoundingClientRect();
							 | 
						|
								      this.popupDiv.html.style.left = rect.left + "px";
							 | 
						|
								      this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
							 | 
						|
								      document.body.appendChild(this.popupDiv.html)
							 | 
						|
								      this.popupDiv.hideTimeout = setTimeout(() => {
							 | 
						|
								        this.popupDiv.html.style.opacity = 0;
							 | 
						|
								      },1500);
							 | 
						|
								      this.popupDiv.deleteTimeout = setTimeout(() => {
							 | 
						|
								        this._removePopup();
							 | 
						|
								      },1800)
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a checkbox for boolean options.
							 | 
						|
								   * @param {number} defaultValue
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeCheckbox(defaultValue, value, path) {
							 | 
						|
								    var checkbox = document.createElement('input');
							 | 
						|
								    checkbox.type = 'checkbox';
							 | 
						|
								    checkbox.className = 'vis-configuration vis-config-checkbox';
							 | 
						|
								    checkbox.checked = defaultValue;
							 | 
						|
								    if (value !== undefined) {
							 | 
						|
								      checkbox.checked = value;
							 | 
						|
								      if (value !== defaultValue) {
							 | 
						|
								        if (typeof defaultValue === 'object') {
							 | 
						|
								          if (value !== defaultValue.enabled) {
							 | 
						|
								            this.changedOptions.push({path:path, value:value});
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								          this.changedOptions.push({path:path, value:value});
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    let me = this;
							 | 
						|
								    checkbox.onchange = function() {me._update(this.checked, path)};
							 | 
						|
								
							 | 
						|
								    let label = this._makeLabel(path[path.length-1], path);
							 | 
						|
								    this._makeItem(path, label, checkbox);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a text input field for string options.
							 | 
						|
								   * @param {number} defaultValue
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeTextInput(defaultValue, value, path) {
							 | 
						|
								    var checkbox = document.createElement('input');
							 | 
						|
								    checkbox.type = 'text';
							 | 
						|
								    checkbox.className = 'vis-configuration vis-config-text';
							 | 
						|
								    checkbox.value = value;
							 | 
						|
								    if (value !== defaultValue) {
							 | 
						|
								      this.changedOptions.push({path:path, value:value});
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    let me = this;
							 | 
						|
								    checkbox.onchange = function() {me._update(this.value, path)};
							 | 
						|
								
							 | 
						|
								    let label = this._makeLabel(path[path.length-1], path);
							 | 
						|
								    this._makeItem(path, label, checkbox);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * make a color field with a color picker for color fields
							 | 
						|
								   * @param {Array.<number>} arr
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _makeColorField(arr, value, path) {
							 | 
						|
								    let defaultColor = arr[1];
							 | 
						|
								    let div = document.createElement('div');
							 | 
						|
								    value = value === undefined ? defaultColor : value;
							 | 
						|
								
							 | 
						|
								    if (value !== 'none') {
							 | 
						|
								      div.className = 'vis-configuration vis-config-colorBlock';
							 | 
						|
								      div.style.backgroundColor = value;
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      div.className = 'vis-configuration vis-config-colorBlock none';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    value = value === undefined ? defaultColor : value;
							 | 
						|
								    div.onclick = () => {
							 | 
						|
								      this._showColorPicker(value,div,path);
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    let label = this._makeLabel(path[path.length-1], path);
							 | 
						|
								    this._makeItem(path,label, div);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * used by the color buttons to call the color picker.
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {HTMLElement} div
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _showColorPicker(value, div, path) {
							 | 
						|
								    // clear the callback from this div
							 | 
						|
								    div.onclick = function() {};
							 | 
						|
								
							 | 
						|
								    this.colorPicker.insertTo(div);
							 | 
						|
								    this.colorPicker.show();
							 | 
						|
								
							 | 
						|
								    this.colorPicker.setColor(value);
							 | 
						|
								    this.colorPicker.setUpdateCallback((color) => {
							 | 
						|
								      let colorString = 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',' + color.a + ')';
							 | 
						|
								      div.style.backgroundColor = colorString;
							 | 
						|
								      this._update(colorString,path);
							 | 
						|
								    });
							 | 
						|
								
							 | 
						|
								    // on close of the colorpicker, restore the callback.
							 | 
						|
								    this.colorPicker.setCloseCallback(() => {
							 | 
						|
								      div.onclick = () => {
							 | 
						|
								        this._showColorPicker(value,div,path);
							 | 
						|
								      };
							 | 
						|
								    });
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * parse an object and draw the correct items
							 | 
						|
								   * @param {Object} obj
							 | 
						|
								   * @param {array} [path=[]]    | where to look for the actual option
							 | 
						|
								   * @param {boolean} [checkOnly=false]
							 | 
						|
								   * @returns {boolean}
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _handleObject(obj, path = [], checkOnly = false) {
							 | 
						|
								    let show = false;
							 | 
						|
								    let filter = this.options.filter;
							 | 
						|
								    let visibleInSet = false;
							 | 
						|
								    for (let subObj in obj) {
							 | 
						|
								      if (obj.hasOwnProperty(subObj)) {
							 | 
						|
								        show = true;
							 | 
						|
								        let item = obj[subObj];
							 | 
						|
								        let newPath = util.copyAndExtendArray(path, subObj);
							 | 
						|
								        if (typeof filter === 'function') {
							 | 
						|
								          show = filter(subObj,path);
							 | 
						|
								
							 | 
						|
								          // if needed we must go deeper into the object.
							 | 
						|
								          if (show === false) {
							 | 
						|
								            if (!(item instanceof Array) && typeof item !== 'string' && typeof item !== 'boolean' && item instanceof Object) {
							 | 
						|
								              this.allowCreation = false;
							 | 
						|
								              show = this._handleObject(item, newPath, true);
							 | 
						|
								              this.allowCreation = checkOnly === false;
							 | 
						|
								            }
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (show !== false) {
							 | 
						|
								          visibleInSet = true;
							 | 
						|
								          let value = this._getValue(newPath);
							 | 
						|
								
							 | 
						|
								          if (item instanceof Array) {
							 | 
						|
								            this._handleArray(item, value, newPath);
							 | 
						|
								          }
							 | 
						|
								          else if (typeof item === 'string') {
							 | 
						|
								            this._makeTextInput(item, value, newPath);
							 | 
						|
								          }
							 | 
						|
								          else if (typeof item === 'boolean') {
							 | 
						|
								            this._makeCheckbox(item, value, newPath);
							 | 
						|
								          }
							 | 
						|
								          else if (item instanceof Object) {
							 | 
						|
								            // collapse the physics options that are not enabled
							 | 
						|
								            let draw = true;
							 | 
						|
								            if (path.indexOf('physics') !== -1) {
							 | 
						|
								              if (this.moduleOptions.physics.solver !== subObj) {
							 | 
						|
								                draw = false;
							 | 
						|
								              }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (draw === true) {
							 | 
						|
								              // initially collapse options with an disabled enabled option.
							 | 
						|
								              if (item.enabled !== undefined) {
							 | 
						|
								                let enabledPath = util.copyAndExtendArray(newPath, 'enabled');
							 | 
						|
								                let enabledValue = this._getValue(enabledPath);
							 | 
						|
								                if (enabledValue === true) {
							 | 
						|
								                  let label = this._makeLabel(subObj, newPath, true);
							 | 
						|
								                  this._makeItem(newPath, label);
							 | 
						|
								                  visibleInSet = this._handleObject(item, newPath) || visibleInSet;
							 | 
						|
								                }
							 | 
						|
								                else {
							 | 
						|
								                  this._makeCheckbox(item, enabledValue, newPath);
							 | 
						|
								                }
							 | 
						|
								              }
							 | 
						|
								              else {
							 | 
						|
								                let label = this._makeLabel(subObj, newPath, true);
							 | 
						|
								                this._makeItem(newPath, label);
							 | 
						|
								                visibleInSet = this._handleObject(item, newPath) || visibleInSet;
							 | 
						|
								              }
							 | 
						|
								            }
							 | 
						|
								          }
							 | 
						|
								          else {
							 | 
						|
								            console.error('dont know how to handle', item, subObj, newPath);
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    return visibleInSet;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle the array type of option
							 | 
						|
								   * @param {Array.<number>} arr
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _handleArray(arr, value, path) {
							 | 
						|
								    if (typeof arr[0] === 'string' && arr[0] === 'color') {
							 | 
						|
								      this._makeColorField(arr, value, path);
							 | 
						|
								      if (arr[1] !== value) {this.changedOptions.push({path:path, value:value});}
							 | 
						|
								    }
							 | 
						|
								    else if (typeof arr[0] === 'string') {
							 | 
						|
								      this._makeDropdown(arr, value, path);
							 | 
						|
								      if (arr[0] !== value) {this.changedOptions.push({path:path, value:value});}
							 | 
						|
								    }
							 | 
						|
								    else if (typeof arr[0] === 'number') {
							 | 
						|
								      this._makeRange(arr, value, path);
							 | 
						|
								      if (arr[0] !== value) {this.changedOptions.push({path:path, value:Number(value)});}
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * called to update the network with the new settings.
							 | 
						|
								   * @param {number} value
							 | 
						|
								   * @param {array} path    | where to look for the actual option
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _update(value, path) {
							 | 
						|
								    let options = this._constructOptions(value,path);
							 | 
						|
								
							 | 
						|
								    if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
							 | 
						|
								      this.parent.body.emitter.emit("configChange", options);
							 | 
						|
								    }
							 | 
						|
								    this.initialized = true;
							 | 
						|
								    this.parent.setOptions(options);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   *
							 | 
						|
								   * @param {string|Boolean} value
							 | 
						|
								   * @param {Array.<string>} path
							 | 
						|
								   * @param {{}} optionsObj
							 | 
						|
								   * @returns {{}}
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _constructOptions(value, path, optionsObj = {}) {
							 | 
						|
								    let pointer = optionsObj;
							 | 
						|
								
							 | 
						|
								    // when dropdown boxes can be string or boolean, we typecast it into correct types
							 | 
						|
								    value = value === 'true'  ? true  : value;
							 | 
						|
								    value = value === 'false' ? false : value;
							 | 
						|
								
							 | 
						|
								    for (let i = 0; i < path.length; i++) {
							 | 
						|
								      if (path[i] !== 'global') {
							 | 
						|
								        if (pointer[path[i]] === undefined) {
							 | 
						|
								          pointer[path[i]] = {};
							 | 
						|
								        }
							 | 
						|
								        if (i !== path.length - 1) {
							 | 
						|
								          pointer = pointer[path[i]];
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								          pointer[path[i]] = value;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    return optionsObj;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  _printOptions() {
							 | 
						|
								    let options = this.getOptions();
							 | 
						|
								    this.optionsContainer.innerHTML = '<pre>var options = ' + JSON.stringify(options, null, 2) + '</pre>';
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   *
							 | 
						|
								   * @returns {{}} options
							 | 
						|
								   */
							 | 
						|
								  getOptions() {
							 | 
						|
								    let options = {};
							 | 
						|
								    for (var i = 0; i < this.changedOptions.length; i++) {
							 | 
						|
								      this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options)
							 | 
						|
								    }
							 | 
						|
								    return options;
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								export default Configurator;
							 |