{"version":3,"file":"vis-graph3d.min.mjs","sources":["../../lib/graph3d/Point3d.js","../../lib/graph3d/Point2d.js","../../lib/graph3d/Slider.js","../../lib/graph3d/StepNumber.js","../../lib/graph3d/Camera.js","../../lib/graph3d/Settings.js","../../lib/graph3d/options.js","../../lib/graph3d/Range.js","../../lib/graph3d/Filter.js","../../lib/graph3d/DataGroup.js","../../lib/graph3d/Graph3d.js"],"sourcesContent":["/**\n * @param {number} [x]\n * @param {number} [y]\n * @param {number} [z]\n */\nfunction Point3d(x, y, z) {\n  this.x = x !== undefined ? x : 0;\n  this.y = y !== undefined ? y : 0;\n  this.z = z !== undefined ? z : 0;\n}\n\n/**\n * Subtract the two provided points, returns a-b\n * @param {Point3d} a\n * @param {Point3d} b\n * @returns {Point3d} a-b\n */\nPoint3d.subtract = function (a, b) {\n  const sub = new Point3d();\n  sub.x = a.x - b.x;\n  sub.y = a.y - b.y;\n  sub.z = a.z - b.z;\n  return sub;\n};\n\n/**\n * Add the two provided points, returns a+b\n * @param {Point3d} a\n * @param {Point3d} b\n * @returns {Point3d} a+b\n */\nPoint3d.add = function (a, b) {\n  const sum = new Point3d();\n  sum.x = a.x + b.x;\n  sum.y = a.y + b.y;\n  sum.z = a.z + b.z;\n  return sum;\n};\n\n/**\n * Calculate the average of two 3d points\n * @param {Point3d} a\n * @param {Point3d} b\n * @returns {Point3d} The average, (a+b)/2\n */\nPoint3d.avg = function (a, b) {\n  return new Point3d((a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2);\n};\n\n/**\n * Scale the provided point by a scalar, returns p*c\n * @param {Point3d} p\n * @param {number} c\n * @returns {Point3d} p*c\n */\nPoint3d.scalarProduct = function (p, c) {\n  return new Point3d(p.x * c, p.y * c, p.z * c);\n};\n\n/**\n * Calculate the dot product of the two provided points, returns a.b\n * Documentation: http://en.wikipedia.org/wiki/Dot_product\n * @param {Point3d} a\n * @param {Point3d} b\n * @returns {Point3d} dot product a.b\n */\nPoint3d.dotProduct = function (a, b) {\n  return a.x * b.x + a.y * b.y + a.z * b.z;\n};\n\n/**\n * Calculate the cross product of the two provided points, returns axb\n * Documentation: http://en.wikipedia.org/wiki/Cross_product\n * @param {Point3d} a\n * @param {Point3d} b\n * @returns {Point3d} cross product axb\n */\nPoint3d.crossProduct = function (a, b) {\n  const crossproduct = new Point3d();\n\n  crossproduct.x = a.y * b.z - a.z * b.y;\n  crossproduct.y = a.z * b.x - a.x * b.z;\n  crossproduct.z = a.x * b.y - a.y * b.x;\n\n  return crossproduct;\n};\n\n/**\n * Retrieve the length of the vector (or the distance from this point to the origin\n * @returns {number}  length\n */\nPoint3d.prototype.length = function () {\n  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n};\n\n/**\n * Return a normalized vector pointing in the same direction.\n * @returns {Point3d}  normalized\n */\nPoint3d.prototype.normalize = function () {\n  return Point3d.scalarProduct(this, 1 / this.length());\n};\n\nexport default Point3d;\n","/**\n * @param {number} [x]\n * @param {number} [y]\n */\nfunction Point2d(x, y) {\n  this.x = x !== undefined ? x : 0;\n  this.y = y !== undefined ? y : 0;\n}\n\nexport default Point2d;\n","import * as util from \"vis-util/esnext\";\n\n/**\n * An html slider control with start/stop/prev/next buttons\n * @function Object() { [native code] } Slider\n * @param {Element} container  The element where the slider will be created\n * @param {object} options   Available options:\n *                 {boolean} visible   If true (default) the\n *                           slider is visible.\n */\nfunction Slider(container, options) {\n  if (container === undefined) {\n    throw new Error(\"No container element defined\");\n  }\n  this.container = container;\n  this.visible =\n    options && options.visible != undefined ? options.visible : true;\n\n  if (this.visible) {\n    this.frame = document.createElement(\"DIV\");\n    //this.frame.style.backgroundColor = '#E5E5E5';\n    this.frame.style.width = \"100%\";\n    this.frame.style.position = \"relative\";\n    this.container.appendChild(this.frame);\n\n    this.frame.prev = document.createElement(\"INPUT\");\n    this.frame.prev.type = \"BUTTON\";\n    this.frame.prev.value = \"Prev\";\n    this.frame.appendChild(this.frame.prev);\n\n    this.frame.play = document.createElement(\"INPUT\");\n    this.frame.play.type = \"BUTTON\";\n    this.frame.play.value = \"Play\";\n    this.frame.appendChild(this.frame.play);\n\n    this.frame.next = document.createElement(\"INPUT\");\n    this.frame.next.type = \"BUTTON\";\n    this.frame.next.value = \"Next\";\n    this.frame.appendChild(this.frame.next);\n\n    this.frame.bar = document.createElement(\"INPUT\");\n    this.frame.bar.type = \"BUTTON\";\n    this.frame.bar.style.position = \"absolute\";\n    this.frame.bar.style.border = \"1px solid red\";\n    this.frame.bar.style.width = \"100px\";\n    this.frame.bar.style.height = \"6px\";\n    this.frame.bar.style.borderRadius = \"2px\";\n    this.frame.bar.style.MozBorderRadius = \"2px\";\n    this.frame.bar.style.border = \"1px solid #7F7F7F\";\n    this.frame.bar.style.backgroundColor = \"#E5E5E5\";\n    this.frame.appendChild(this.frame.bar);\n\n    this.frame.slide = document.createElement(\"INPUT\");\n    this.frame.slide.type = \"BUTTON\";\n    this.frame.slide.style.margin = \"0px\";\n    this.frame.slide.value = \" \";\n    this.frame.slide.style.position = \"relative\";\n    this.frame.slide.style.left = \"-100px\";\n    this.frame.appendChild(this.frame.slide);\n\n    // create events\n    const me = this;\n    this.frame.slide.onmousedown = function (event) {\n      me._onMouseDown(event);\n    };\n    this.frame.prev.onclick = function (event) {\n      me.prev(event);\n    };\n    this.frame.play.onclick = function (event) {\n      me.togglePlay(event);\n    };\n    this.frame.next.onclick = function (event) {\n      me.next(event);\n    };\n  }\n\n  this.onChangeCallback = undefined;\n\n  this.values = [];\n  this.index = undefined;\n\n  this.playTimeout = undefined;\n  this.playInterval = 1000; // milliseconds\n  this.playLoop = true;\n}\n\n/**\n * Select the previous index\n */\nSlider.prototype.prev = function () {\n  let index = this.getIndex();\n  if (index > 0) {\n    index--;\n    this.setIndex(index);\n  }\n};\n\n/**\n * Select the next index\n */\nSlider.prototype.next = function () {\n  let index = this.getIndex();\n  if (index < this.values.length - 1) {\n    index++;\n    this.setIndex(index);\n  }\n};\n\n/**\n * Select the next index\n */\nSlider.prototype.playNext = function () {\n  const start = new Date();\n\n  let index = this.getIndex();\n  if (index < this.values.length - 1) {\n    index++;\n    this.setIndex(index);\n  } else if (this.playLoop) {\n    // jump to the start\n    index = 0;\n    this.setIndex(index);\n  }\n\n  const end = new Date();\n  const diff = end - start;\n\n  // calculate how much time it to to set the index and to execute the callback\n  // function.\n  const interval = Math.max(this.playInterval - diff, 0);\n  // document.title = diff // TODO: cleanup\n\n  const me = this;\n  this.playTimeout = setTimeout(function () {\n    me.playNext();\n  }, interval);\n};\n\n/**\n * Toggle start or stop playing\n */\nSlider.prototype.togglePlay = function () {\n  if (this.playTimeout === undefined) {\n    this.play();\n  } else {\n    this.stop();\n  }\n};\n\n/**\n * Start playing\n */\nSlider.prototype.play = function () {\n  // Test whether already playing\n  if (this.playTimeout) return;\n\n  this.playNext();\n\n  if (this.frame) {\n    this.frame.play.value = \"Stop\";\n  }\n};\n\n/**\n * Stop playing\n */\nSlider.prototype.stop = function () {\n  clearInterval(this.playTimeout);\n  this.playTimeout = undefined;\n\n  if (this.frame) {\n    this.frame.play.value = \"Play\";\n  }\n};\n\n/**\n * Set a callback function which will be triggered when the value of the\n * slider bar has changed.\n * @param {Function} callback\n */\nSlider.prototype.setOnChangeCallback = function (callback) {\n  this.onChangeCallback = callback;\n};\n\n/**\n * Set the interval for playing the list\n * @param {number} interval   The interval in milliseconds\n */\nSlider.prototype.setPlayInterval = function (interval) {\n  this.playInterval = interval;\n};\n\n/**\n * Retrieve the current play interval\n * @returns {number} interval   The interval in milliseconds\n */\nSlider.prototype.getPlayInterval = function () {\n  return this.playInterval;\n};\n\n/**\n * Set looping on or off\n * @param {boolean} doLoop  If true, the slider will jump to the start when\n *               the end is passed, and will jump to the end\n *               when the start is passed.\n */\nSlider.prototype.setPlayLoop = function (doLoop) {\n  this.playLoop = doLoop;\n};\n\n/**\n * Execute the onchange callback function\n */\nSlider.prototype.onChange = function () {\n  if (this.onChangeCallback !== undefined) {\n    this.onChangeCallback();\n  }\n};\n\n/**\n * redraw the slider on the correct place\n */\nSlider.prototype.redraw = function () {\n  if (this.frame) {\n    // resize the bar\n    this.frame.bar.style.top =\n      this.frame.clientHeight / 2 - this.frame.bar.offsetHeight / 2 + \"px\";\n    this.frame.bar.style.width =\n      this.frame.clientWidth -\n      this.frame.prev.clientWidth -\n      this.frame.play.clientWidth -\n      this.frame.next.clientWidth -\n      30 +\n      \"px\";\n\n    // position the slider button\n    const left = this.indexToLeft(this.index);\n    this.frame.slide.style.left = left + \"px\";\n  }\n};\n\n/**\n * Set the list with values for the slider\n * @param {Array} values   A javascript array with values (any type)\n */\nSlider.prototype.setValues = function (values) {\n  this.values = values;\n\n  if (this.values.length > 0) this.setIndex(0);\n  else this.index = undefined;\n};\n\n/**\n * Select a value by its index\n * @param {number} index\n */\nSlider.prototype.setIndex = function (index) {\n  if (index < this.values.length) {\n    this.index = index;\n\n    this.redraw();\n    this.onChange();\n  } else {\n    throw new Error(\"Index out of range\");\n  }\n};\n\n/**\n * retrieve the index of the currently selected vaue\n * @returns {number} index\n */\nSlider.prototype.getIndex = function () {\n  return this.index;\n};\n\n/**\n * retrieve the currently selected value\n * @returns {*} value\n */\nSlider.prototype.get = function () {\n  return this.values[this.index];\n};\n\nSlider.prototype._onMouseDown = function (event) {\n  // only react on left mouse button down\n  const leftButtonDown = event.which ? event.which === 1 : event.button === 1;\n  if (!leftButtonDown) return;\n\n  this.startClientX = event.clientX;\n  this.startSlideX = parseFloat(this.frame.slide.style.left);\n\n  this.frame.style.cursor = \"move\";\n\n  // add event listeners to handle moving the contents\n  // we store the function onmousemove and onmouseup in the graph, so we can\n  // remove the eventlisteners lateron in the function mouseUp()\n  const me = this;\n  this.onmousemove = function (event) {\n    me._onMouseMove(event);\n  };\n  this.onmouseup = function (event) {\n    me._onMouseUp(event);\n  };\n  document.addEventListener(\"mousemove\", this.onmousemove);\n  document.addEventListener(\"mouseup\", this.onmouseup);\n  util.preventDefault(event);\n};\n\nSlider.prototype.leftToIndex = function (left) {\n  const width =\n    parseFloat(this.frame.bar.style.width) - this.frame.slide.clientWidth - 10;\n  const x = left - 3;\n\n  let index = Math.round((x / width) * (this.values.length - 1));\n  if (index < 0) index = 0;\n  if (index > this.values.length - 1) index = this.values.length - 1;\n\n  return index;\n};\n\nSlider.prototype.indexToLeft = function (index) {\n  const width =\n    parseFloat(this.frame.bar.style.width) - this.frame.slide.clientWidth - 10;\n\n  const x = (index / (this.values.length - 1)) * width;\n  const left = x + 3;\n\n  return left;\n};\n\nSlider.prototype._onMouseMove = function (event) {\n  const diff = event.clientX - this.startClientX;\n  const x = this.startSlideX + diff;\n\n  const index = this.leftToIndex(x);\n\n  this.setIndex(index);\n\n  util.preventDefault();\n};\n\nSlider.prototype._onMouseUp = function () {\n  this.frame.style.cursor = \"auto\";\n\n  // remove event listeners\n  document.removeEventListener(\"mousemove\", this.onmousemove);\n  document.removeEventListener(\"mouseup\", this.onmouseup);\n\n  util.preventDefault();\n};\n\nexport default Slider;\n","/**\n * The class StepNumber is an iterator for Numbers. You provide a start and end\n * value, and a best step size. StepNumber itself rounds to fixed values and\n * a finds the step that best fits the provided step.\n *\n * If prettyStep is true, the step size is chosen as close as possible to the\n * provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....\n *\n * Example usage:\n *   var step = new StepNumber(0, 10, 2.5, true);\n *   step.start();\n *   while (!step.end()) {\n *   alert(step.getCurrent());\n *   step.next();\n *   }\n *\n * Version: 1.0\n * @param {number} start     The start value\n * @param {number} end     The end value\n * @param {number} step    Optional. Step size. Must be a positive value.\n * @param {boolean} prettyStep Optional. If true, the step size is rounded\n *               To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)\n */\nfunction StepNumber(start, end, step, prettyStep) {\n  // set default values\n  this._start = 0;\n  this._end = 0;\n  this._step = 1;\n  this.prettyStep = true;\n  this.precision = 5;\n\n  this._current = 0;\n  this.setRange(start, end, step, prettyStep);\n}\n\n/**\n * Check for input values, to prevent disasters from happening\n *\n * Source: http://stackoverflow.com/a/1830844\n * @param {string} n\n * @returns {boolean}\n */\nStepNumber.prototype.isNumeric = function (n) {\n  return !isNaN(parseFloat(n)) && isFinite(n);\n};\n\n/**\n * Set a new range: start, end and step.\n * @param {number} start     The start value\n * @param {number} end     The end value\n * @param {number} step    Optional. Step size. Must be a positive value.\n * @param {boolean} prettyStep Optional. If true, the step size is rounded\n *               To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)\n */\nStepNumber.prototype.setRange = function (start, end, step, prettyStep) {\n  if (!this.isNumeric(start)) {\n    throw new Error(\"Parameter 'start' is not numeric; value: \" + start);\n  }\n  if (!this.isNumeric(end)) {\n    throw new Error(\"Parameter 'end' is not numeric; value: \" + start);\n  }\n  if (!this.isNumeric(step)) {\n    throw new Error(\"Parameter 'step' is not numeric; value: \" + start);\n  }\n\n  this._start = start ? start : 0;\n  this._end = end ? end : 0;\n\n  this.setStep(step, prettyStep);\n};\n\n/**\n * Set a new step size\n * @param {number} step    New step size. Must be a positive value\n * @param {boolean} prettyStep Optional. If true, the provided step is rounded\n *               to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)\n */\nStepNumber.prototype.setStep = function (step, prettyStep) {\n  if (step === undefined || step <= 0) return;\n\n  if (prettyStep !== undefined) this.prettyStep = prettyStep;\n\n  if (this.prettyStep === true)\n    this._step = StepNumber.calculatePrettyStep(step);\n  else this._step = step;\n};\n\n/**\n * Calculate a nice step size, closest to the desired step size.\n * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an\n * integer Number. For example 1, 2, 5, 10, 20, 50, etc...\n * @param {number}  step  Desired step size\n * @returns {number}     Nice step size\n */\nStepNumber.calculatePrettyStep = function (step) {\n  const log10 = function (x) {\n    return Math.log(x) / Math.LN10;\n  };\n\n  // try three steps (multiple of 1, 2, or 5\n  const step1 = Math.pow(10, Math.round(log10(step))),\n    step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),\n    step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));\n\n  // choose the best step (closest to minimum step)\n  let prettyStep = step1;\n  if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;\n  if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;\n\n  // for safety\n  if (prettyStep <= 0) {\n    prettyStep = 1;\n  }\n\n  return prettyStep;\n};\n\n/**\n * returns the current value of the step\n * @returns {number} current value\n */\nStepNumber.prototype.getCurrent = function () {\n  return parseFloat(this._current.toPrecision(this.precision));\n};\n\n/**\n * returns the current step size\n * @returns {number} current step size\n */\nStepNumber.prototype.getStep = function () {\n  return this._step;\n};\n\n/**\n * Set the current to its starting value.\n *\n * By default, this will be the largest value smaller than start, which\n * is a multiple of the step size.\n *\n * Parameters checkFirst is optional, default false.\n * If set to true, move the current value one step if smaller than start.\n * @param {boolean} [checkFirst]\n */\nStepNumber.prototype.start = function (checkFirst) {\n  if (checkFirst === undefined) {\n    checkFirst = false;\n  }\n\n  this._current = this._start - (this._start % this._step);\n\n  if (checkFirst) {\n    if (this.getCurrent() < this._start) {\n      this.next();\n    }\n  }\n};\n\n/**\n * Do a step, add the step size to the current value\n */\nStepNumber.prototype.next = function () {\n  this._current += this._step;\n};\n\n/**\n * Returns true whether the end is reached\n * @returns {boolean}  True if the current value has passed the end value.\n */\nStepNumber.prototype.end = function () {\n  return this._current > this._end;\n};\n\nexport default StepNumber;\n","import Point3d from \"./Point3d.js\";\n\n/**\n * The camera is mounted on a (virtual) camera arm. The camera arm can rotate\n * The camera is always looking in the direction of the origin of the arm.\n * This way, the camera always rotates around one fixed point, the location\n * of the camera arm.\n *\n * Documentation:\n * http://en.wikipedia.org/wiki/3D_projection\n * @class Camera\n */\nfunction Camera() {\n  this.armLocation = new Point3d();\n  this.armRotation = {};\n  this.armRotation.horizontal = 0;\n  this.armRotation.vertical = 0;\n  this.armLength = 1.7;\n  this.cameraOffset = new Point3d();\n  this.offsetMultiplier = 0.6;\n\n  this.cameraLocation = new Point3d();\n  this.cameraRotation = new Point3d(0.5 * Math.PI, 0, 0);\n\n  this.calculateCameraOrientation();\n}\n\n/**\n * Set offset camera in camera coordinates\n * @param {number} x offset by camera horisontal\n * @param {number} y offset by camera vertical\n */\nCamera.prototype.setOffset = function (x, y) {\n  const abs = Math.abs,\n    sign = Math.sign,\n    mul = this.offsetMultiplier,\n    border = this.armLength * mul;\n\n  if (abs(x) > border) {\n    x = sign(x) * border;\n  }\n  if (abs(y) > border) {\n    y = sign(y) * border;\n  }\n  this.cameraOffset.x = x;\n  this.cameraOffset.y = y;\n  this.calculateCameraOrientation();\n};\n\n/**\n * Get camera offset by horizontal and vertical\n * @returns {number}\n */\nCamera.prototype.getOffset = function () {\n  return this.cameraOffset;\n};\n\n/**\n * Set the location (origin) of the arm\n * @param {number} x  Normalized value of x\n * @param {number} y  Normalized value of y\n * @param {number} z  Normalized value of z\n */\nCamera.prototype.setArmLocation = function (x, y, z) {\n  this.armLocation.x = x;\n  this.armLocation.y = y;\n  this.armLocation.z = z;\n\n  this.calculateCameraOrientation();\n};\n\n/**\n * Set the rotation of the camera arm\n * @param {number} horizontal   The horizontal rotation, between 0 and 2*PI.\n *                Optional, can be left undefined.\n * @param {number} vertical   The vertical rotation, between 0 and 0.5*PI\n *                if vertical=0.5*PI, the graph is shown from the\n *                top. Optional, can be left undefined.\n */\nCamera.prototype.setArmRotation = function (horizontal, vertical) {\n  if (horizontal !== undefined) {\n    this.armRotation.horizontal = horizontal;\n  }\n\n  if (vertical !== undefined) {\n    this.armRotation.vertical = vertical;\n    if (this.armRotation.vertical < 0) this.armRotation.vertical = 0;\n    if (this.armRotation.vertical > 0.5 * Math.PI)\n      this.armRotation.vertical = 0.5 * Math.PI;\n  }\n\n  if (horizontal !== undefined || vertical !== undefined) {\n    this.calculateCameraOrientation();\n  }\n};\n\n/**\n * Retrieve the current arm rotation\n * @returns {object}   An object with parameters horizontal and vertical\n */\nCamera.prototype.getArmRotation = function () {\n  const rot = {};\n  rot.horizontal = this.armRotation.horizontal;\n  rot.vertical = this.armRotation.vertical;\n\n  return rot;\n};\n\n/**\n * Set the (normalized) length of the camera arm.\n * @param {number} length A length between 0.71 and 5.0\n */\nCamera.prototype.setArmLength = function (length) {\n  if (length === undefined) return;\n\n  this.armLength = length;\n\n  // Radius must be larger than the corner of the graph,\n  // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the\n  // graph\n  if (this.armLength < 0.71) this.armLength = 0.71;\n  if (this.armLength > 5.0) this.armLength = 5.0;\n\n  this.setOffset(this.cameraOffset.x, this.cameraOffset.y);\n  this.calculateCameraOrientation();\n};\n\n/**\n * Retrieve the arm length\n * @returns {number} length\n */\nCamera.prototype.getArmLength = function () {\n  return this.armLength;\n};\n\n/**\n * Retrieve the camera location\n * @returns {Point3d} cameraLocation\n */\nCamera.prototype.getCameraLocation = function () {\n  return this.cameraLocation;\n};\n\n/**\n * Retrieve the camera rotation\n * @returns {Point3d} cameraRotation\n */\nCamera.prototype.getCameraRotation = function () {\n  return this.cameraRotation;\n};\n\n/**\n * Calculate the location and rotation of the camera based on the\n * position and orientation of the camera arm\n */\nCamera.prototype.calculateCameraOrientation = function () {\n  // calculate location of the camera\n  this.cameraLocation.x =\n    this.armLocation.x -\n    this.armLength *\n      Math.sin(this.armRotation.horizontal) *\n      Math.cos(this.armRotation.vertical);\n  this.cameraLocation.y =\n    this.armLocation.y -\n    this.armLength *\n      Math.cos(this.armRotation.horizontal) *\n      Math.cos(this.armRotation.vertical);\n  this.cameraLocation.z =\n    this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical);\n\n  // calculate rotation of the camera\n  this.cameraRotation.x = Math.PI / 2 - this.armRotation.vertical;\n  this.cameraRotation.y = 0;\n  this.cameraRotation.z = -this.armRotation.horizontal;\n\n  const xa = this.cameraRotation.x;\n  const za = this.cameraRotation.z;\n  const dx = this.cameraOffset.x;\n  const dy = this.cameraOffset.y;\n  const sin = Math.sin,\n    cos = Math.cos;\n\n  this.cameraLocation.x =\n    this.cameraLocation.x + dx * cos(za) + dy * -sin(za) * cos(xa);\n  this.cameraLocation.y =\n    this.cameraLocation.y + dx * sin(za) + dy * cos(za) * cos(xa);\n  this.cameraLocation.z = this.cameraLocation.z + dy * sin(xa);\n};\n\nexport default Camera;\n","////////////////////////////////////////////////////////////////////////////////\n// This modules handles the options for Graph3d.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport * as util from \"vis-util/esnext\";\nimport Camera from \"./Camera.js\";\nimport Point3d from \"./Point3d.js\";\n\n// enumerate the available styles\nconst STYLE = {\n  BAR: 0,\n  BARCOLOR: 1,\n  BARSIZE: 2,\n  DOT: 3,\n  DOTLINE: 4,\n  DOTCOLOR: 5,\n  DOTSIZE: 6,\n  GRID: 7,\n  LINE: 8,\n  SURFACE: 9,\n};\n\n// The string representations of the styles\nconst STYLENAME = {\n  dot: STYLE.DOT,\n  \"dot-line\": STYLE.DOTLINE,\n  \"dot-color\": STYLE.DOTCOLOR,\n  \"dot-size\": STYLE.DOTSIZE,\n  line: STYLE.LINE,\n  grid: STYLE.GRID,\n  surface: STYLE.SURFACE,\n  bar: STYLE.BAR,\n  \"bar-color\": STYLE.BARCOLOR,\n  \"bar-size\": STYLE.BARSIZE,\n};\n\n/**\n * Field names in the options hash which are of relevance to the user.\n *\n * Specifically, these are the fields which require no special handling,\n * and can be directly copied over.\n */\nconst OPTIONKEYS = [\n  \"width\",\n  \"height\",\n  \"filterLabel\",\n  \"legendLabel\",\n  \"xLabel\",\n  \"yLabel\",\n  \"zLabel\",\n  \"xValueLabel\",\n  \"yValueLabel\",\n  \"zValueLabel\",\n  \"showXAxis\",\n  \"showYAxis\",\n  \"showZAxis\",\n  \"showGrayBottom\",\n  \"showGrid\",\n  \"showPerspective\",\n  \"showShadow\",\n  \"showSurfaceGrid\",\n  \"keepAspectRatio\",\n  \"rotateAxisLabels\",\n  \"verticalRatio\",\n  \"dotSizeRatio\",\n  \"dotSizeMinFraction\",\n  \"dotSizeMaxFraction\",\n  \"showAnimationControls\",\n  \"animationInterval\",\n  \"animationPreload\",\n  \"animationAutoStart\",\n  \"axisColor\",\n  \"axisFontSize\",\n  \"axisFontType\",\n  \"gridColor\",\n  \"xCenter\",\n  \"yCenter\",\n  \"zoomable\",\n  \"tooltipDelay\",\n  \"ctrlToZoom\",\n];\n\n/**\n * Field names in the options hash which are of relevance to the user.\n *\n * Same as OPTIONKEYS, but internally these fields are stored with\n * prefix 'default' in the name.\n */\nconst PREFIXEDOPTIONKEYS = [\n  \"xBarWidth\",\n  \"yBarWidth\",\n  \"valueMin\",\n  \"valueMax\",\n  \"xMin\",\n  \"xMax\",\n  \"xStep\",\n  \"yMin\",\n  \"yMax\",\n  \"yStep\",\n  \"zMin\",\n  \"zMax\",\n  \"zStep\",\n];\n\n// Placeholder for DEFAULTS reference\nlet DEFAULTS = undefined;\n\n/**\n * Check if given hash is empty.\n *\n * Source: http://stackoverflow.com/a/679937\n * @param {object} obj\n * @returns {boolean}\n */\nfunction isEmpty(obj) {\n  for (const prop in obj) {\n    if (Object.prototype.hasOwnProperty.call(obj, prop)) return false;\n  }\n\n  return true;\n}\n\n/**\n * Make first letter of parameter upper case.\n *\n * Source: http://stackoverflow.com/a/1026087\n * @param {string} str\n * @returns {string}\n */\nfunction capitalize(str) {\n  if (str === undefined || str === \"\" || typeof str != \"string\") {\n    return str;\n  }\n\n  return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Add a prefix to a field name, taking style guide into account\n * @param {string} prefix\n * @param {string} fieldName\n * @returns {string}\n */\nfunction prefixFieldName(prefix, fieldName) {\n  if (prefix === undefined || prefix === \"\") {\n    return fieldName;\n  }\n\n  return prefix + capitalize(fieldName);\n}\n\n/**\n * Forcibly copy fields from src to dst in a controlled manner.\n *\n * A given field in dst will always be overwitten. If this field\n * is undefined or not present in src, the field in dst will\n * be explicitly set to undefined.\n *\n * The intention here is to be able to reset all option fields.\n *\n * Only the fields mentioned in array 'fields' will be handled.\n * @param {object} src\n * @param {object} dst\n * @param {Array<string>} fields array with names of fields to copy\n * @param {string} [prefix] prefix to use for the target fields.\n */\nfunction forceCopy(src, dst, fields, prefix) {\n  let srcKey;\n  let dstKey;\n\n  for (let i = 0; i < fields.length; ++i) {\n    srcKey = fields[i];\n    dstKey = prefixFieldName(prefix, srcKey);\n\n    dst[dstKey] = src[srcKey];\n  }\n}\n\n/**\n * Copy fields from src to dst in a safe and controlled manner.\n *\n * Only the fields mentioned in array 'fields' will be copied over,\n * and only if these are actually defined.\n * @param {object} src\n * @param {object} dst\n * @param {Array<string>} fields array with names of fields to copy\n * @param {string} [prefix] prefix to use for the target fields.\n */\nfunction safeCopy(src, dst, fields, prefix) {\n  let srcKey;\n  let dstKey;\n\n  for (let i = 0; i < fields.length; ++i) {\n    srcKey = fields[i];\n    if (src[srcKey] === undefined) continue;\n\n    dstKey = prefixFieldName(prefix, srcKey);\n\n    dst[dstKey] = src[srcKey];\n  }\n}\n\n/**\n * Initialize dst with the values in src.\n *\n * src is the hash with the default values.\n * A reference DEFAULTS to this hash is stored locally for\n * further handling.\n *\n * For now, dst is assumed to be a Graph3d instance.\n * @param {object} src\n * @param {object} dst\n */\nfunction setDefaults(src, dst) {\n  if (src === undefined || isEmpty(src)) {\n    throw new Error(\"No DEFAULTS passed\");\n  }\n  if (dst === undefined) {\n    throw new Error(\"No dst passed\");\n  }\n\n  // Remember defaults for future reference\n  DEFAULTS = src;\n\n  // Handle the defaults which can be simply copied over\n  forceCopy(src, dst, OPTIONKEYS);\n  forceCopy(src, dst, PREFIXEDOPTIONKEYS, \"default\");\n\n  // Handle the more complex ('special') fields\n  setSpecialSettings(src, dst);\n\n  // Following are internal fields, not part of the user settings\n  dst.margin = 10; // px\n  dst.showTooltip = false;\n  dst.onclick_callback = null;\n  dst.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window?\n}\n\n/**\n *\n * @param {object} options\n * @param {object} dst\n */\nfunction setOptions(options, dst) {\n  if (options === undefined) {\n    return;\n  }\n  if (dst === undefined) {\n    throw new Error(\"No dst passed\");\n  }\n\n  if (DEFAULTS === undefined || isEmpty(DEFAULTS)) {\n    throw new Error(\"DEFAULTS not set for module Settings\");\n  }\n\n  // Handle the parameters which can be simply copied over\n  safeCopy(options, dst, OPTIONKEYS);\n  safeCopy(options, dst, PREFIXEDOPTIONKEYS, \"default\");\n\n  // Handle the more complex ('special') fields\n  setSpecialSettings(options, dst);\n}\n\n/**\n * Special handling for certain parameters\n *\n * 'Special' here means: setting requires more than a simple copy\n * @param {object} src\n * @param {object} dst\n */\nfunction setSpecialSettings(src, dst) {\n  if (src.backgroundColor !== undefined) {\n    setBackgroundColor(src.backgroundColor, dst);\n  }\n\n  setDataColor(src.dataColor, dst);\n  setStyle(src.style, dst);\n  if (src.surfaceColors !== undefined) {\n    console.warn(\n      \"`options.surfaceColors` is deprecated and may be removed in a future \" +\n        \"version. Please use `options.colormap` instead. Note that the `colormap` \" +\n        \"option uses the inverse array ordering (running from vMin to vMax).\",\n    );\n    if (src.colormap !== undefined) {\n      throw new Error(\n        \"The `colormap` and `surfaceColors` options are mutually exclusive.\",\n      );\n    }\n    if (dst.style !== \"surface\") {\n      console.warn(\n        \"Ignoring `surfaceColors` in graph style `\" +\n          dst.style +\n          \"` for \" +\n          \"backward compatibility (only effective in `surface` plots).\",\n      );\n    } else {\n      setSurfaceColor(src.surfaceColors, dst);\n    }\n  } else {\n    setColormap(src.colormap, dst);\n  }\n  setShowLegend(src.showLegend, dst);\n  setCameraPosition(src.cameraPosition, dst);\n\n  // As special fields go, this is an easy one; just a translation of the name.\n  // Can't use this.tooltip directly, because that field exists internally\n  if (src.tooltip !== undefined) {\n    dst.showTooltip = src.tooltip;\n  }\n  if (src.onclick != undefined) {\n    dst.onclick_callback = src.onclick;\n    console.warn(\n      \"`options.onclick` is deprecated and may be removed in a future version.\" +\n        \" Please use `Graph3d.on('click', handler)` instead.\",\n    );\n  }\n\n  if (src.tooltipStyle !== undefined) {\n    util.selectiveDeepExtend([\"tooltipStyle\"], dst, src);\n  }\n}\n\n/**\n * Set the value of setting 'showLegend'\n *\n * This depends on the value of the style fields, so it must be called\n * after the style field has been initialized.\n * @param {boolean} showLegend\n * @param {object} dst\n */\nfunction setShowLegend(showLegend, dst) {\n  if (showLegend === undefined) {\n    // If the default was auto, make a choice for this field\n    const isAutoByDefault = DEFAULTS.showLegend === undefined;\n\n    if (isAutoByDefault) {\n      // these styles default to having legends\n      const isLegendGraphStyle =\n        dst.style === STYLE.DOTCOLOR || dst.style === STYLE.DOTSIZE;\n\n      dst.showLegend = isLegendGraphStyle;\n    } else {\n      // Leave current value as is\n    }\n  } else {\n    dst.showLegend = showLegend;\n  }\n}\n\n/**\n * Retrieve the style index from given styleName\n * @param {string} styleName  Style name such as 'dot', 'grid', 'dot-line'\n * @returns {number} styleNumber Enumeration value representing the style, or -1\n *                when not found\n */\nfunction getStyleNumberByName(styleName) {\n  const number = STYLENAME[styleName];\n\n  if (number === undefined) {\n    return -1;\n  }\n\n  return number;\n}\n\n/**\n * Check if given number is a valid style number.\n * @param {string | number} style\n * @returns {boolean} true if valid, false otherwise\n */\nfunction checkStyleNumber(style) {\n  let valid = false;\n\n  for (const n in STYLE) {\n    if (STYLE[n] === style) {\n      valid = true;\n      break;\n    }\n  }\n\n  return valid;\n}\n\n/**\n *\n * @param {string | number} style\n * @param {object} dst\n */\nfunction setStyle(style, dst) {\n  if (style === undefined) {\n    return; // Nothing to do\n  }\n\n  let styleNumber;\n\n  if (typeof style === \"string\") {\n    styleNumber = getStyleNumberByName(style);\n\n    if (styleNumber === -1) {\n      throw new Error(\"Style '\" + style + \"' is invalid\");\n    }\n  } else {\n    // Do a pedantic check on style number value\n    if (!checkStyleNumber(style)) {\n      throw new Error(\"Style '\" + style + \"' is invalid\");\n    }\n\n    styleNumber = style;\n  }\n\n  dst.style = styleNumber;\n}\n\n/**\n * Set the background styling for the graph\n * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor\n * @param {object} dst\n */\nfunction setBackgroundColor(backgroundColor, dst) {\n  let fill = \"white\";\n  let stroke = \"gray\";\n  let strokeWidth = 1;\n\n  if (typeof backgroundColor === \"string\") {\n    fill = backgroundColor;\n    stroke = \"none\";\n    strokeWidth = 0;\n  } else if (typeof backgroundColor === \"object\") {\n    if (backgroundColor.fill !== undefined) fill = backgroundColor.fill;\n    if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke;\n    if (backgroundColor.strokeWidth !== undefined)\n      strokeWidth = backgroundColor.strokeWidth;\n  } else {\n    throw new Error(\"Unsupported type of backgroundColor\");\n  }\n\n  dst.frame.style.backgroundColor = fill;\n  dst.frame.style.borderColor = stroke;\n  dst.frame.style.borderWidth = strokeWidth + \"px\";\n  dst.frame.style.borderStyle = \"solid\";\n}\n\n/**\n *\n * @param {string | object} dataColor\n * @param {object} dst\n */\nfunction setDataColor(dataColor, dst) {\n  if (dataColor === undefined) {\n    return; // Nothing to do\n  }\n\n  if (dst.dataColor === undefined) {\n    dst.dataColor = {};\n  }\n\n  if (typeof dataColor === \"string\") {\n    dst.dataColor.fill = dataColor;\n    dst.dataColor.stroke = dataColor;\n  } else {\n    if (dataColor.fill) {\n      dst.dataColor.fill = dataColor.fill;\n    }\n    if (dataColor.stroke) {\n      dst.dataColor.stroke = dataColor.stroke;\n    }\n    if (dataColor.strokeWidth !== undefined) {\n      dst.dataColor.strokeWidth = dataColor.strokeWidth;\n    }\n  }\n}\n\n/**\n *\n * @param {object | Array<string>} surfaceColors Either an object that describes the HUE, or an array of HTML hex color codes\n * @param {object} dst\n */\nfunction setSurfaceColor(surfaceColors, dst) {\n  if (surfaceColors === undefined || surfaceColors === true) {\n    return; // Nothing to do\n  }\n  if (surfaceColors === false) {\n    dst.surfaceColors = undefined;\n    return;\n  }\n\n  if (dst.surfaceColors === undefined) {\n    dst.surfaceColors = {};\n  }\n\n  let rgbColors;\n  if (Array.isArray(surfaceColors)) {\n    rgbColors = parseColorArray(surfaceColors);\n  } else if (typeof surfaceColors === \"object\") {\n    rgbColors = parseColorObject(surfaceColors.hue);\n  } else {\n    throw new Error(\"Unsupported type of surfaceColors\");\n  }\n  // for some reason surfaceColors goes from vMax to vMin:\n  rgbColors.reverse();\n  dst.colormap = rgbColors;\n}\n\n/**\n *\n * @param {object | Array<string>} colormap Either an object that describes the HUE, or an array of HTML hex color codes\n * @param {object} dst\n */\nfunction setColormap(colormap, dst) {\n  if (colormap === undefined) {\n    return;\n  }\n\n  let rgbColors;\n  if (Array.isArray(colormap)) {\n    rgbColors = parseColorArray(colormap);\n  } else if (typeof colormap === \"object\") {\n    rgbColors = parseColorObject(colormap.hue);\n  } else if (typeof colormap === \"function\") {\n    rgbColors = colormap;\n  } else {\n    throw new Error(\"Unsupported type of colormap\");\n  }\n  dst.colormap = rgbColors;\n}\n\n/**\n *\n * @param {Array} colormap\n */\nfunction parseColorArray(colormap) {\n  if (colormap.length < 2) {\n    throw new Error(\"Colormap array length must be 2 or above.\");\n  }\n  return colormap.map(function (colorCode) {\n    if (!util.isValidHex(colorCode)) {\n      throw new Error(`Invalid hex color code supplied to colormap.`);\n    }\n    return util.hexToRGB(colorCode);\n  });\n}\n\n/**\n * Converts an object to a certain amount of hex color stops. At which point:\n * the HTML hex color codes is converted into an RGB color object.\n * @param {object} hues\n */\nfunction parseColorObject(hues) {\n  if (hues === undefined) {\n    throw new Error(\"Unsupported type of colormap\");\n  }\n  if (!(hues.saturation >= 0 && hues.saturation <= 100)) {\n    throw new Error(\"Saturation is out of bounds. Expected range is 0-100.\");\n  }\n  if (!(hues.brightness >= 0 && hues.brightness <= 100)) {\n    throw new Error(\"Brightness is out of bounds. Expected range is 0-100.\");\n  }\n  if (!(hues.colorStops >= 2)) {\n    throw new Error(\"colorStops is out of bounds. Expected 2 or above.\");\n  }\n\n  const hueStep = (hues.end - hues.start) / (hues.colorStops - 1);\n\n  const rgbColors = [];\n  for (let i = 0; i < hues.colorStops; ++i) {\n    const hue = ((hues.start + hueStep * i) % 360) / 360;\n    rgbColors.push(\n      util.HSVToRGB(\n        hue < 0 ? hue + 1 : hue,\n        hues.saturation / 100,\n        hues.brightness / 100,\n      ),\n    );\n  }\n  return rgbColors;\n}\n\n/**\n *\n * @param {object} cameraPosition\n * @param {object} dst\n */\nfunction setCameraPosition(cameraPosition, dst) {\n  const camPos = cameraPosition;\n  if (camPos === undefined) {\n    return;\n  }\n\n  if (dst.camera === undefined) {\n    dst.camera = new Camera();\n  }\n\n  dst.camera.setArmRotation(camPos.horizontal, camPos.vertical);\n  dst.camera.setArmLength(camPos.distance);\n}\n\nexport { STYLE, setCameraPosition, setDefaults, setOptions };\n","/**\n * This object contains all possible options. It will check if the types are correct, if required if the option is one\n * of the allowed values.\n *\n * __any__ means that the name of the property does not matter.\n * __type__ is a required field for all objects and contains the allowed types of all objects\n */\nconst string = \"string\";\nconst bool = \"boolean\";\nconst number = \"number\";\nconst object = \"object\"; // should only be in a __type__ property\nconst array = \"array\";\n// Following not used here, but useful for reference\n//let dom      = 'dom';\n//let any      = 'any';\n\nconst colorOptions = {\n  fill: { string },\n  stroke: { string },\n  strokeWidth: { number },\n  __type__: { string, object, undefined: \"undefined\" },\n};\n\nconst surfaceColorsOptions = {\n  hue: {\n    start: { number },\n    end: { number },\n    saturation: { number },\n    brightness: { number },\n    colorStops: { number },\n    __type__: { object },\n  },\n  __type__: { boolean: bool, array, object, undefined: \"undefined\" },\n};\n\nconst colormapOptions = {\n  hue: {\n    start: { number },\n    end: { number },\n    saturation: { number },\n    brightness: { number },\n    colorStops: { number },\n    __type__: { object },\n  },\n  __type__: { array, object, function: \"function\", undefined: \"undefined\" },\n};\n\n/**\n * Order attempted to be alphabetical.\n *   - x/y/z-prefixes ignored in sorting\n *   - __type__ always at end\n *   - globals at end\n */\nconst allOptions = {\n  animationAutoStart: { boolean: bool, undefined: \"undefined\" },\n  animationInterval: { number },\n  animationPreload: { boolean: bool },\n  axisColor: { string },\n  axisFontSize: { number: number },\n  axisFontType: { string: string },\n  backgroundColor: colorOptions,\n  xBarWidth: { number, undefined: \"undefined\" },\n  yBarWidth: { number, undefined: \"undefined\" },\n  cameraPosition: {\n    distance: { number },\n    horizontal: { number },\n    vertical: { number },\n    __type__: { object },\n  },\n  zoomable: { boolean: bool },\n  ctrlToZoom: { boolean: bool },\n  xCenter: { string },\n  yCenter: { string },\n  colormap: colormapOptions,\n  dataColor: colorOptions,\n  dotSizeMinFraction: { number },\n  dotSizeMaxFraction: { number },\n  dotSizeRatio: { number },\n  filterLabel: { string },\n  gridColor: { string },\n  onclick: { function: \"function\" },\n  keepAspectRatio: { boolean: bool },\n  xLabel: { string },\n  yLabel: { string },\n  zLabel: { string },\n  legendLabel: { string },\n  xMin: { number, undefined: \"undefined\" },\n  yMin: { number, undefined: \"undefined\" },\n  zMin: { number, undefined: \"undefined\" },\n  xMax: { number, undefined: \"undefined\" },\n  yMax: { number, undefined: \"undefined\" },\n  zMax: { number, undefined: \"undefined\" },\n  showAnimationControls: { boolean: bool, undefined: \"undefined\" },\n  showGrayBottom: { boolean: bool },\n  showGrid: { boolean: bool },\n  showLegend: { boolean: bool, undefined: \"undefined\" },\n  showPerspective: { boolean: bool },\n  showShadow: { boolean: bool },\n  showSurfaceGrid: { boolean: bool },\n  showXAxis: { boolean: bool },\n  showYAxis: { boolean: bool },\n  showZAxis: { boolean: bool },\n  rotateAxisLabels: { boolean: bool },\n  surfaceColors: surfaceColorsOptions,\n  xStep: { number, undefined: \"undefined\" },\n  yStep: { number, undefined: \"undefined\" },\n  zStep: { number, undefined: \"undefined\" },\n  style: {\n    number, // TODO: either Graph3d.DEFAULT has string, or number allowed in documentation\n    string: [\n      \"bar\",\n      \"bar-color\",\n      \"bar-size\",\n      \"dot\",\n      \"dot-line\",\n      \"dot-color\",\n      \"dot-size\",\n      \"line\",\n      \"grid\",\n      \"surface\",\n    ],\n  },\n  tooltip: { boolean: bool, function: \"function\" },\n  tooltipDelay: { number: number },\n  tooltipStyle: {\n    content: {\n      color: { string },\n      background: { string },\n      border: { string },\n      borderRadius: { string },\n      boxShadow: { string },\n      padding: { string },\n      __type__: { object },\n    },\n    line: {\n      borderLeft: { string },\n      height: { string },\n      width: { string },\n      pointerEvents: { string },\n      __type__: { object },\n    },\n    dot: {\n      border: { string },\n      borderRadius: { string },\n      height: { string },\n      width: { string },\n      pointerEvents: { string },\n      __type__: { object },\n    },\n    __type__: { object },\n  },\n  xValueLabel: { function: \"function\" },\n  yValueLabel: { function: \"function\" },\n  zValueLabel: { function: \"function\" },\n  valueMax: { number, undefined: \"undefined\" },\n  valueMin: { number, undefined: \"undefined\" },\n  verticalRatio: { number },\n\n  //globals :\n  height: { string },\n  width: { string },\n  __type__: { object },\n};\n\nexport { allOptions };\n","/**\n * Helper class to make working with related min and max values easier.\n *\n * The range is inclusive; a given value is considered part of the range if:\n *\n *    this.min <= value <= this.max\n */\nfunction Range() {\n  this.min = undefined;\n  this.max = undefined;\n}\n\n/**\n * Adjust the range so that the passed value fits in it.\n *\n * If the value is outside of the current extremes, adjust\n * the min or max so that the value is within the range.\n * @param {number} value Numeric value to fit in range\n */\nRange.prototype.adjust = function (value) {\n  if (value === undefined) return;\n\n  if (this.min === undefined || this.min > value) {\n    this.min = value;\n  }\n\n  if (this.max === undefined || this.max < value) {\n    this.max = value;\n  }\n};\n\n/**\n * Adjust the current range so that the passed range fits in it.\n * @param {Range} range Range instance to fit in current instance\n */\nRange.prototype.combine = function (range) {\n  this.add(range.min);\n  this.add(range.max);\n};\n\n/**\n * Expand the range by the given value\n *\n * min will be lowered by given value;\n * max will be raised by given value\n *\n * Shrinking by passing a negative value is allowed.\n * @param {number} val Amount by which to expand or shrink current range with\n */\nRange.prototype.expand = function (val) {\n  if (val === undefined) {\n    return;\n  }\n\n  const newMin = this.min - val;\n  const newMax = this.max + val;\n\n  // Note that following allows newMin === newMax.\n  // This should be OK, since method expand() allows this also.\n  if (newMin > newMax) {\n    throw new Error(\"Passed expansion value makes range invalid\");\n  }\n\n  this.min = newMin;\n  this.max = newMax;\n};\n\n/**\n * Determine the full range width of current instance.\n * @returns {num} The calculated width of this range\n */\nRange.prototype.range = function () {\n  return this.max - this.min;\n};\n\n/**\n * Determine the central point of current instance.\n * @returns {number} the value in the middle of min and max\n */\nRange.prototype.center = function () {\n  return (this.min + this.max) / 2;\n};\n\nexport default Range;\n","import { DataView } from \"vis-data/esnext\";\n\n/**\n * @class Filter\n * @param {DataGroup} dataGroup the data group\n * @param {number}  column             The index of the column to be filtered\n * @param {Graph3d} graph              The graph\n */\nfunction Filter(dataGroup, column, graph) {\n  this.dataGroup = dataGroup;\n  this.column = column;\n  this.graph = graph; // the parent graph\n\n  this.index = undefined;\n  this.value = undefined;\n\n  // read all distinct values and select the first one\n  this.values = dataGroup.getDistinctValues(this.column);\n\n  if (this.values.length > 0) {\n    this.selectValue(0);\n  }\n\n  // create an array with the filtered datapoints. this will be loaded afterwards\n  this.dataPoints = [];\n\n  this.loaded = false;\n  this.onLoadCallback = undefined;\n\n  if (graph.animationPreload) {\n    this.loaded = false;\n    this.loadInBackground();\n  } else {\n    this.loaded = true;\n  }\n}\n\n/**\n * Return the label\n * @returns {string} label\n */\nFilter.prototype.isLoaded = function () {\n  return this.loaded;\n};\n\n/**\n * Return the loaded progress\n * @returns {number} percentage between 0 and 100\n */\nFilter.prototype.getLoadedProgress = function () {\n  const len = this.values.length;\n\n  let i = 0;\n  while (this.dataPoints[i]) {\n    i++;\n  }\n\n  return Math.round((i / len) * 100);\n};\n\n/**\n * Return the label\n * @returns {string} label\n */\nFilter.prototype.getLabel = function () {\n  return this.graph.filterLabel;\n};\n\n/**\n * Return the columnIndex of the filter\n * @returns {number} columnIndex\n */\nFilter.prototype.getColumn = function () {\n  return this.column;\n};\n\n/**\n * Return the currently selected value. Returns undefined if there is no selection\n * @returns {*} value\n */\nFilter.prototype.getSelectedValue = function () {\n  if (this.index === undefined) return undefined;\n\n  return this.values[this.index];\n};\n\n/**\n * Retrieve all values of the filter\n * @returns {Array} values\n */\nFilter.prototype.getValues = function () {\n  return this.values;\n};\n\n/**\n * Retrieve one value of the filter\n * @param {number}  index\n * @returns {*} value\n */\nFilter.prototype.getValue = function (index) {\n  if (index >= this.values.length) throw new Error(\"Index out of range\");\n\n  return this.values[index];\n};\n\n/**\n * Retrieve the (filtered) dataPoints for the currently selected filter index\n * @param {number} [index] (optional)\n * @returns {Array} dataPoints\n */\nFilter.prototype._getDataPoints = function (index) {\n  if (index === undefined) index = this.index;\n\n  if (index === undefined) return [];\n\n  let dataPoints;\n  if (this.dataPoints[index]) {\n    dataPoints = this.dataPoints[index];\n  } else {\n    const f = {};\n    f.column = this.column;\n    f.value = this.values[index];\n\n    const dataView = new DataView(this.dataGroup.getDataSet(), {\n      filter: function (item) {\n        return item[f.column] == f.value;\n      },\n    }).get();\n    dataPoints = this.dataGroup._getDataPoints(dataView);\n\n    this.dataPoints[index] = dataPoints;\n  }\n\n  return dataPoints;\n};\n\n/**\n * Set a callback function when the filter is fully loaded.\n * @param {Function} callback\n */\nFilter.prototype.setOnLoadCallback = function (callback) {\n  this.onLoadCallback = callback;\n};\n\n/**\n * Add a value to the list with available values for this filter\n * No double entries will be created.\n * @param {number} index\n */\nFilter.prototype.selectValue = function (index) {\n  if (index >= this.values.length) throw new Error(\"Index out of range\");\n\n  this.index = index;\n  this.value = this.values[index];\n};\n\n/**\n * Load all filtered rows in the background one by one\n * Start this method without providing an index!\n * @param {number} [index]\n */\nFilter.prototype.loadInBackground = function (index) {\n  if (index === undefined) index = 0;\n\n  const frame = this.graph.frame;\n\n  if (index < this.values.length) {\n    // create a progress box\n    if (frame.progress === undefined) {\n      frame.progress = document.createElement(\"DIV\");\n      frame.progress.style.position = \"absolute\";\n      frame.progress.style.color = \"gray\";\n      frame.appendChild(frame.progress);\n    }\n    const progress = this.getLoadedProgress();\n    frame.progress.innerHTML = \"Loading animation... \" + progress + \"%\";\n    // TODO: this is no nice solution...\n    frame.progress.style.bottom = 60 + \"px\"; // TODO: use height of slider\n    frame.progress.style.left = 10 + \"px\";\n\n    const me = this;\n    setTimeout(function () {\n      me.loadInBackground(index + 1);\n    }, 10);\n    this.loaded = false;\n  } else {\n    this.loaded = true;\n\n    // remove the progress box\n    if (frame.progress !== undefined) {\n      frame.removeChild(frame.progress);\n      frame.progress = undefined;\n    }\n\n    if (this.onLoadCallback) this.onLoadCallback();\n  }\n};\n\nexport default Filter;\n","import { DataSet } from \"vis-data/esnext\";\nimport { DataView } from \"vis-data/esnext\";\nimport Range from \"./Range.js\";\nimport Filter from \"./Filter.js\";\nimport { STYLE } from \"./Settings.js\";\nimport Point3d from \"./Point3d.js\";\n\n/**\n * Creates a container for all data of one specific 3D-graph.\n *\n * On construction, the container is totally empty; the data\n * needs to be initialized with method initializeData().\n * Failure to do so will result in the following exception begin thrown\n * on instantiation of Graph3D:\n *\n * Error: Array, DataSet, or DataView expected\n * @function Object() { [native code] } DataGroup\n */\nfunction DataGroup() {\n  this.dataTable = null; // The original data table\n}\n\n/**\n * Initializes the instance from the passed data.\n *\n * Calculates minimum and maximum values and column index values.\n *\n * The graph3d instance is used internally to access the settings for\n * the given instance.\n * TODO: Pass settings only instead.\n * @param {vis.Graph3d}  graph3d Reference to the calling Graph3D instance.\n * @param {Array | DataSet | DataView} rawData The data containing the items for\n *                                             the Graph.\n * @param {number}   style   Style Number\n * @returns {Array.<object>}\n */\nDataGroup.prototype.initializeData = function (graph3d, rawData, style) {\n  if (rawData === undefined) return;\n\n  if (Array.isArray(rawData)) {\n    rawData = new DataSet(rawData);\n  }\n\n  let data;\n  if (rawData instanceof DataSet || rawData instanceof DataView) {\n    data = rawData.get();\n  } else {\n    throw new Error(\"Array, DataSet, or DataView expected\");\n  }\n\n  if (data.length == 0) return;\n\n  this.style = style;\n\n  // unsubscribe from the dataTable\n  if (this.dataSet) {\n    this.dataSet.off(\"*\", this._onChange);\n  }\n\n  this.dataSet = rawData;\n  this.dataTable = data;\n\n  // subscribe to changes in the dataset\n  const me = this;\n  this._onChange = function () {\n    graph3d.setData(me.dataSet);\n  };\n  this.dataSet.on(\"*\", this._onChange);\n\n  // determine the location of x,y,z,value,filter columns\n  this.colX = \"x\";\n  this.colY = \"y\";\n  this.colZ = \"z\";\n\n  const withBars = graph3d.hasBars(style);\n\n  // determine barWidth from data\n  if (withBars) {\n    if (graph3d.defaultXBarWidth !== undefined) {\n      this.xBarWidth = graph3d.defaultXBarWidth;\n    } else {\n      this.xBarWidth = this.getSmallestDifference(data, this.colX) || 1;\n    }\n\n    if (graph3d.defaultYBarWidth !== undefined) {\n      this.yBarWidth = graph3d.defaultYBarWidth;\n    } else {\n      this.yBarWidth = this.getSmallestDifference(data, this.colY) || 1;\n    }\n  }\n\n  // calculate minima and maxima\n  this._initializeRange(data, this.colX, graph3d, withBars);\n  this._initializeRange(data, this.colY, graph3d, withBars);\n  this._initializeRange(data, this.colZ, graph3d, false);\n\n  if (Object.prototype.hasOwnProperty.call(data[0], \"style\")) {\n    this.colValue = \"style\";\n    const valueRange = this.getColumnRange(data, this.colValue);\n    this._setRangeDefaults(\n      valueRange,\n      graph3d.defaultValueMin,\n      graph3d.defaultValueMax,\n    );\n    this.valueRange = valueRange;\n  } else {\n    this.colValue = \"z\";\n    this.valueRange = this.zRange;\n  }\n\n  // Initialize data filter if a filter column is provided\n  const table = this.getDataTable();\n  if (Object.prototype.hasOwnProperty.call(table[0], \"filter\")) {\n    if (this.dataFilter === undefined) {\n      this.dataFilter = new Filter(this, \"filter\", graph3d);\n      this.dataFilter.setOnLoadCallback(function () {\n        graph3d.redraw();\n      });\n    }\n  }\n\n  let dataPoints;\n  if (this.dataFilter) {\n    // apply filtering\n    dataPoints = this.dataFilter._getDataPoints();\n  } else {\n    // no filtering. load all data\n    dataPoints = this._getDataPoints(this.getDataTable());\n  }\n  return dataPoints;\n};\n\n/**\n * Collect the range settings for the given data column.\n *\n * This internal method is intended to make the range\n * initalization more generic.\n *\n * TODO: if/when combined settings per axis defined, get rid of this.\n * @private\n * @param {'x'|'y'|'z'} column  The data column to process\n * @param {vis.Graph3d} graph3d Reference to the calling Graph3D instance;\n *                              required for access to settings\n * @returns {object}\n */\nDataGroup.prototype._collectRangeSettings = function (column, graph3d) {\n  const index = [\"x\", \"y\", \"z\"].indexOf(column);\n\n  if (index == -1) {\n    throw new Error(\"Column '\" + column + \"' invalid\");\n  }\n\n  const upper = column.toUpperCase();\n\n  return {\n    barWidth: this[column + \"BarWidth\"],\n    min: graph3d[\"default\" + upper + \"Min\"],\n    max: graph3d[\"default\" + upper + \"Max\"],\n    step: graph3d[\"default\" + upper + \"Step\"],\n    range_label: column + \"Range\", // Name of instance field to write to\n    step_label: column + \"Step\", // Name of instance field to write to\n  };\n};\n\n/**\n * Initializes the settings per given column.\n *\n * TODO: if/when combined settings per axis defined, rewrite this.\n * @private\n * @param {DataSet | DataView} data     The data containing the items for the Graph\n * @param {'x'|'y'|'z'}        column   The data column to process\n * @param {vis.Graph3d}        graph3d  Reference to the calling Graph3D instance;\n *                                      required for access to settings\n * @param {boolean}            withBars True if initializing for bar graph\n */\nDataGroup.prototype._initializeRange = function (\n  data,\n  column,\n  graph3d,\n  withBars,\n) {\n  const NUMSTEPS = 5;\n  const settings = this._collectRangeSettings(column, graph3d);\n\n  const range = this.getColumnRange(data, column);\n  if (withBars && column != \"z\") {\n    // Safeguard for 'z'; it doesn't have a bar width\n    range.expand(settings.barWidth / 2);\n  }\n\n  this._setRangeDefaults(range, settings.min, settings.max);\n  this[settings.range_label] = range;\n  this[settings.step_label] =\n    settings.step !== undefined ? settings.step : range.range() / NUMSTEPS;\n};\n\n/**\n * Creates a list with all the different values in the data for the given column.\n *\n * If no data passed, use the internal data of this instance.\n * @param {'x'|'y'|'z'}                column The data column to process\n * @param {DataSet|DataView|undefined} data   The data containing the items for the Graph\n * @returns {Array} All distinct values in the given column data, sorted ascending.\n */\nDataGroup.prototype.getDistinctValues = function (column, data) {\n  if (data === undefined) {\n    data = this.dataTable;\n  }\n\n  const values = [];\n\n  for (let i = 0; i < data.length; i++) {\n    const value = data[i][column] || 0;\n    if (values.indexOf(value) === -1) {\n      values.push(value);\n    }\n  }\n\n  return values.sort(function (a, b) {\n    return a - b;\n  });\n};\n\n/**\n * Determine the smallest difference between the values for given\n * column in the passed data set.\n * @param {DataSet|DataView|undefined} data   The data containing the items for the Graph\n * @param {'x'|'y'|'z'}                column The data column to process\n * @returns {number|null} Smallest difference value or\n *                        null, if it can't be determined.\n */\nDataGroup.prototype.getSmallestDifference = function (data, column) {\n  const values = this.getDistinctValues(data, column);\n\n  // Get all the distinct diffs\n  // Array values is assumed to be sorted here\n  let smallest_diff = null;\n\n  for (let i = 1; i < values.length; i++) {\n    const diff = values[i] - values[i - 1];\n\n    if (smallest_diff == null || smallest_diff > diff) {\n      smallest_diff = diff;\n    }\n  }\n\n  return smallest_diff;\n};\n\n/**\n * Get the absolute min/max values for the passed data column.\n * @param {DataSet|DataView|undefined} data   The data containing the items for the Graph\n * @param {'x'|'y'|'z'}                column The data column to process\n * @returns {Range} A Range instance with min/max members properly set.\n */\nDataGroup.prototype.getColumnRange = function (data, column) {\n  const range = new Range();\n\n  // Adjust the range so that it covers all values in the passed data elements.\n  for (let i = 0; i < data.length; i++) {\n    const item = data[i][column];\n    range.adjust(item);\n  }\n\n  return range;\n};\n\n/**\n * Determines the number of rows in the current data.\n * @returns {number}\n */\nDataGroup.prototype.getNumberOfRows = function () {\n  return this.dataTable.length;\n};\n\n/**\n * Set default values for range\n *\n * The default values override the range values, if defined.\n *\n * Because it's possible that only defaultMin or defaultMax is set, it's better\n * to pass in a range already set with the min/max set from the data. Otherwise,\n * it's quite hard to process the min/max properly.\n * @param {vis.Range} range\n * @param {number} [defaultMin]\n * @param {number} [defaultMax]\n * @private\n */\nDataGroup.prototype._setRangeDefaults = function (\n  range,\n  defaultMin,\n  defaultMax,\n) {\n  if (defaultMin !== undefined) {\n    range.min = defaultMin;\n  }\n\n  if (defaultMax !== undefined) {\n    range.max = defaultMax;\n  }\n\n  // This is the original way that the default min/max values were adjusted.\n  // TODO: Perhaps it's better if an error is thrown if the values do not agree.\n  //       But this will change the behaviour.\n  if (range.max <= range.min) range.max = range.min + 1;\n};\n\nDataGroup.prototype.getDataTable = function () {\n  return this.dataTable;\n};\n\nDataGroup.prototype.getDataSet = function () {\n  return this.dataSet;\n};\n\n/**\n * Return all data values as a list of Point3d objects\n * @param {Array.<object>} data\n * @returns {Array.<object>}\n */\nDataGroup.prototype.getDataPoints = function (data) {\n  const dataPoints = [];\n\n  for (let i = 0; i < data.length; i++) {\n    const point = new Point3d();\n    point.x = data[i][this.colX] || 0;\n    point.y = data[i][this.colY] || 0;\n    point.z = data[i][this.colZ] || 0;\n    point.data = data[i];\n    point.value = data[i][this.colValue] || 0;\n\n    const obj = {};\n    obj.point = point;\n    obj.bottom = new Point3d(point.x, point.y, this.zRange.min);\n    obj.trans = undefined;\n    obj.screen = undefined;\n\n    dataPoints.push(obj);\n  }\n\n  return dataPoints;\n};\n\n/**\n * Copy all values from the data table to a matrix.\n *\n * The provided values are supposed to form a grid of (x,y) positions.\n * @param {Array.<object>} data\n * @returns {Array.<object>}\n * @private\n */\nDataGroup.prototype.initDataAsMatrix = function (data) {\n  // TODO: store the created matrix dataPoints in the filters instead of\n  //       reloading each time.\n  let x, y, i, obj;\n\n  // create two lists with all present x and y values\n  const dataX = this.getDistinctValues(this.colX, data);\n  const dataY = this.getDistinctValues(this.colY, data);\n\n  const dataPoints = this.getDataPoints(data);\n\n  // create a grid, a 2d matrix, with all values.\n  const dataMatrix = []; // temporary data matrix\n  for (i = 0; i < dataPoints.length; i++) {\n    obj = dataPoints[i];\n\n    // TODO: implement Array().indexOf() for Internet Explorer\n    const xIndex = dataX.indexOf(obj.point.x);\n    const yIndex = dataY.indexOf(obj.point.y);\n\n    if (dataMatrix[xIndex] === undefined) {\n      dataMatrix[xIndex] = [];\n    }\n\n    dataMatrix[xIndex][yIndex] = obj;\n  }\n\n  // fill in the pointers to the neighbors.\n  for (x = 0; x < dataMatrix.length; x++) {\n    for (y = 0; y < dataMatrix[x].length; y++) {\n      if (dataMatrix[x][y]) {\n        dataMatrix[x][y].pointRight =\n          x < dataMatrix.length - 1 ? dataMatrix[x + 1][y] : undefined;\n        dataMatrix[x][y].pointTop =\n          y < dataMatrix[x].length - 1 ? dataMatrix[x][y + 1] : undefined;\n        dataMatrix[x][y].pointCross =\n          x < dataMatrix.length - 1 && y < dataMatrix[x].length - 1\n            ? dataMatrix[x + 1][y + 1]\n            : undefined;\n      }\n    }\n  }\n\n  return dataPoints;\n};\n\n/**\n * Return common information, if present\n * @returns {string}\n */\nDataGroup.prototype.getInfo = function () {\n  const dataFilter = this.dataFilter;\n  if (!dataFilter) return undefined;\n\n  return dataFilter.getLabel() + \": \" + dataFilter.getSelectedValue();\n};\n\n/**\n * Reload the data\n */\nDataGroup.prototype.reload = function () {\n  if (this.dataTable) {\n    this.setData(this.dataTable);\n  }\n};\n\n/**\n * Filter the data based on the current filter\n * @param   {Array} data\n * @returns {Array} dataPoints Array with point objects which can be drawn on\n *                             screen\n */\nDataGroup.prototype._getDataPoints = function (data) {\n  let dataPoints = [];\n\n  if (this.style === STYLE.GRID || this.style === STYLE.SURFACE) {\n    dataPoints = this.initDataAsMatrix(data);\n  } else {\n    // 'dot', 'dot-line', etc.\n    dataPoints = this.getDataPoints(data);\n\n    if (this.style === STYLE.LINE) {\n      // Add next member points for line drawing\n      for (let i = 0; i < dataPoints.length; i++) {\n        if (i > 0) {\n          dataPoints[i - 1].pointNext = dataPoints[i];\n        }\n      }\n    }\n  }\n\n  return dataPoints;\n};\n\nexport default DataGroup;\n","import Emitter from \"component-emitter\";\nimport * as util from \"vis-util/esnext\";\nimport Point3d from \"./Point3d.js\";\nimport Point2d from \"./Point2d.js\";\nimport Slider from \"./Slider.js\";\nimport StepNumber from \"./StepNumber.js\";\nimport {\n  STYLE,\n  setCameraPosition,\n  setDefaults,\n  setOptions,\n} from \"./Settings.js\";\nimport { VALIDATOR_PRINT_STYLE, Validator } from \"vis-util/esnext\";\nimport { allOptions } from \"./options.js\";\nimport DataGroup from \"./DataGroup.js\";\n\n/// enumerate the available styles\nGraph3d.STYLE = STYLE;\n\n/**\n * Following label is used in the settings to describe values which should be\n * determined by the code while running, from the current data and graph style.\n *\n * Using 'undefined' directly achieves the same thing, but this is more\n * descriptive by describing the intent.\n */\nconst autoByDefault = undefined;\n\n/**\n * Default values for option settings.\n *\n * These are the values used when a Graph3d instance is initialized without\n * custom settings.\n *\n * If a field is not in this list, a default value of 'autoByDefault' is assumed,\n * which is just an alias for 'undefined'.\n */\nGraph3d.DEFAULTS = {\n  width: \"400px\",\n  height: \"400px\",\n  filterLabel: \"time\",\n  legendLabel: \"value\",\n  xLabel: \"x\",\n  yLabel: \"y\",\n  zLabel: \"z\",\n  xValueLabel: function (v) {\n    return v;\n  },\n  yValueLabel: function (v) {\n    return v;\n  },\n  zValueLabel: function (v) {\n    return v;\n  },\n  showXAxis: true,\n  showYAxis: true,\n  showZAxis: true,\n  showGrayBottom: false,\n  showGrid: true,\n  showPerspective: true,\n  showShadow: false,\n  showSurfaceGrid: true,\n  keepAspectRatio: true,\n  rotateAxisLabels: true,\n  verticalRatio: 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube'\n\n  dotSizeRatio: 0.02, // size of the dots as a fraction of the graph width\n  dotSizeMinFraction: 0.5, // size of min-value dot as a fraction of dotSizeRatio\n  dotSizeMaxFraction: 2.5, // size of max-value dot as a fraction of dotSizeRatio\n\n  showAnimationControls: autoByDefault,\n  animationInterval: 1000, // milliseconds\n  animationPreload: false,\n  animationAutoStart: autoByDefault,\n\n  axisFontSize: 14,\n  axisFontType: \"arial\",\n  axisColor: \"#4D4D4D\",\n  gridColor: \"#D3D3D3\",\n  xCenter: \"55%\",\n  yCenter: \"50%\",\n\n  style: Graph3d.STYLE.DOT,\n  tooltip: false,\n  tooltipDelay: 300, // milliseconds\n\n  tooltipStyle: {\n    content: {\n      padding: \"10px\",\n      border: \"1px solid #4d4d4d\",\n      color: \"#1a1a1a\",\n      background: \"rgba(255,255,255,0.7)\",\n      borderRadius: \"2px\",\n      boxShadow: \"5px 5px 10px rgba(128,128,128,0.5)\",\n    },\n    line: {\n      height: \"40px\",\n      width: \"0\",\n      borderLeft: \"1px solid #4d4d4d\",\n      pointerEvents: \"none\",\n    },\n    dot: {\n      height: \"0\",\n      width: \"0\",\n      border: \"5px solid #4d4d4d\",\n      borderRadius: \"5px\",\n      pointerEvents: \"none\",\n    },\n  },\n\n  dataColor: {\n    fill: \"#7DC1FF\",\n    stroke: \"#3267D2\",\n    strokeWidth: 1, // px\n  },\n\n  surfaceColors: autoByDefault,\n  colormap: autoByDefault,\n\n  cameraPosition: {\n    horizontal: 1.0,\n    vertical: 0.5,\n    distance: 1.7,\n  },\n\n  zoomable: true,\n  ctrlToZoom: false,\n\n  /*\n  The following fields are 'auto by default', see above.\n */\n  showLegend: autoByDefault, // determined by graph style\n  backgroundColor: autoByDefault,\n\n  xBarWidth: autoByDefault,\n  yBarWidth: autoByDefault,\n  valueMin: autoByDefault,\n  valueMax: autoByDefault,\n  xMin: autoByDefault,\n  xMax: autoByDefault,\n  xStep: autoByDefault,\n  yMin: autoByDefault,\n  yMax: autoByDefault,\n  yStep: autoByDefault,\n  zMin: autoByDefault,\n  zMax: autoByDefault,\n  zStep: autoByDefault,\n};\n\n// -----------------------------------------------------------------------------\n// Class Graph3d\n// -----------------------------------------------------------------------------\n\n/**\n * Graph3d displays data in 3d.\n *\n * Graph3d is developed in javascript as a Google Visualization Chart.\n * @function Object() { [native code] } Graph3d\n * @param {Element} container   The DOM element in which the Graph3d will\n *                              be created. Normally a div element.\n * @param {DataSet | DataView | Array} [data]\n * @param {object} [options]\n */\nfunction Graph3d(container, data, options) {\n  if (!(this instanceof Graph3d)) {\n    throw new SyntaxError(\"Constructor must be called with the new operator\");\n  }\n\n  // create variables and set default values\n  this.containerElement = container;\n\n  this.dataGroup = new DataGroup();\n  this.dataPoints = null; // The table with point objects\n\n  // create a frame and canvas\n  this.create();\n\n  setDefaults(Graph3d.DEFAULTS, this);\n\n  // the column indexes\n  this.colX = undefined;\n  this.colY = undefined;\n  this.colZ = undefined;\n  this.colValue = undefined;\n\n  // TODO: customize axis range\n\n  // apply options (also when undefined)\n  this.setOptions(options);\n\n  // apply data\n  this.setData(data);\n}\n\n// Extend Graph3d with an Emitter mixin\nEmitter(Graph3d.prototype);\n\n/**\n * Calculate the scaling values, dependent on the range in x, y, and z direction\n */\nGraph3d.prototype._setScale = function () {\n  this.scale = new Point3d(\n    1 / this.xRange.range(),\n    1 / this.yRange.range(),\n    1 / this.zRange.range(),\n  );\n\n  // keep aspect ration between x and y scale if desired\n  if (this.keepAspectRatio) {\n    if (this.scale.x < this.scale.y) {\n      //noinspection JSSuspiciousNameCombination\n      this.scale.y = this.scale.x;\n    } else {\n      //noinspection JSSuspiciousNameCombination\n      this.scale.x = this.scale.y;\n    }\n  }\n\n  // scale the vertical axis\n  this.scale.z *= this.verticalRatio;\n  // TODO: can this be automated? verticalRatio?\n\n  // determine scale for (optional) value\n  if (this.valueRange !== undefined) {\n    this.scale.value = 1 / this.valueRange.range();\n  }\n\n  // position the camera arm\n  const xCenter = this.xRange.center() * this.scale.x;\n  const yCenter = this.yRange.center() * this.scale.y;\n  const zCenter = this.zRange.center() * this.scale.z;\n  this.camera.setArmLocation(xCenter, yCenter, zCenter);\n};\n\n/**\n * Convert a 3D location to a 2D location on screen\n * Source: ttp://en.wikipedia.org/wiki/3D_projection\n * @param   {Point3d} point3d  A 3D point with parameters x, y, z\n * @returns {Point2d} point2d  A 2D point with parameters x, y\n */\nGraph3d.prototype._convert3Dto2D = function (point3d) {\n  const translation = this._convertPointToTranslation(point3d);\n  return this._convertTranslationToScreen(translation);\n};\n\n/**\n * Convert a 3D location its translation seen from the camera\n * Source: http://en.wikipedia.org/wiki/3D_projection\n * @param   {Point3d} point3d     A 3D point with parameters x, y, z\n * @returns {Point3d} translation A 3D point with parameters x, y, z This is\n *                                the translation of the point, seen from the\n *                                camera.\n */\nGraph3d.prototype._convertPointToTranslation = function (point3d) {\n  const cameraLocation = this.camera.getCameraLocation(),\n    cameraRotation = this.camera.getCameraRotation(),\n    ax = point3d.x * this.scale.x,\n    ay = point3d.y * this.scale.y,\n    az = point3d.z * this.scale.z,\n    cx = cameraLocation.x,\n    cy = cameraLocation.y,\n    cz = cameraLocation.z,\n    // calculate angles\n    sinTx = Math.sin(cameraRotation.x),\n    cosTx = Math.cos(cameraRotation.x),\n    sinTy = Math.sin(cameraRotation.y),\n    cosTy = Math.cos(cameraRotation.y),\n    sinTz = Math.sin(cameraRotation.z),\n    cosTz = Math.cos(cameraRotation.z),\n    // calculate translation\n    dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz),\n    dy =\n      sinTx *\n        (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) +\n      cosTx * (cosTz * (ay - cy) - sinTz * (ax - cx)),\n    dz =\n      cosTx *\n        (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) -\n      sinTx * (cosTz * (ay - cy) - sinTz * (ax - cx));\n\n  return new Point3d(dx, dy, dz);\n};\n\n/**\n * Convert a translation point to a point on the screen\n * @param   {Point3d} translation A 3D point with parameters x, y, z This is\n *                                the translation of the point, seen from the\n *                                camera.\n * @returns {Point2d} point2d     A 2D point with parameters x, y\n */\nGraph3d.prototype._convertTranslationToScreen = function (translation) {\n  const ex = this.eye.x,\n    ey = this.eye.y,\n    ez = this.eye.z,\n    dx = translation.x,\n    dy = translation.y,\n    dz = translation.z;\n\n  // calculate position on screen from translation\n  let bx;\n  let by;\n  if (this.showPerspective) {\n    bx = (dx - ex) * (ez / dz);\n    by = (dy - ey) * (ez / dz);\n  } else {\n    bx = dx * -(ez / this.camera.getArmLength());\n    by = dy * -(ez / this.camera.getArmLength());\n  }\n\n  // shift and scale the point to the center of the screen\n  // use the width of the graph to scale both horizontally and vertically.\n  return new Point2d(\n    this.currentXCenter + bx * this.frame.canvas.clientWidth,\n    this.currentYCenter - by * this.frame.canvas.clientWidth,\n  );\n};\n\n/**\n * Calculate the translations and screen positions of all points\n * @param {Array.<Point3d>} points\n * @private\n */\nGraph3d.prototype._calcTranslations = function (points) {\n  for (let i = 0; i < points.length; i++) {\n    const point = points[i];\n    point.trans = this._convertPointToTranslation(point.point);\n    point.screen = this._convertTranslationToScreen(point.trans);\n\n    // calculate the translation of the point at the bottom (needed for sorting)\n    const transBottom = this._convertPointToTranslation(point.bottom);\n    point.dist = this.showPerspective ? transBottom.length() : -transBottom.z;\n  }\n\n  // sort the points on depth of their (x,y) position (not on z)\n  const sortDepth = function (a, b) {\n    return b.dist - a.dist;\n  };\n  points.sort(sortDepth);\n};\n\n/**\n * Transfer min/max values to the Graph3d instance.\n */\nGraph3d.prototype._initializeRanges = function () {\n  // TODO: later on, all min/maxes of all datagroups will be combined here\n  const dg = this.dataGroup;\n  this.xRange = dg.xRange;\n  this.yRange = dg.yRange;\n  this.zRange = dg.zRange;\n  this.valueRange = dg.valueRange;\n\n  // Values currently needed but which need to be sorted out for\n  // the multiple graph case.\n  this.xStep = dg.xStep;\n  this.yStep = dg.yStep;\n  this.zStep = dg.zStep;\n  this.xBarWidth = dg.xBarWidth;\n  this.yBarWidth = dg.yBarWidth;\n  this.colX = dg.colX;\n  this.colY = dg.colY;\n  this.colZ = dg.colZ;\n  this.colValue = dg.colValue;\n\n  // set the scale dependent on the ranges.\n  this._setScale();\n};\n\n/**\n * Return all data values as a list of Point3d objects\n * @param {vis.DataSet} data\n * @returns {Array.<object>}\n */\nGraph3d.prototype.getDataPoints = function (data) {\n  const dataPoints = [];\n\n  for (let i = 0; i < data.length; i++) {\n    const point = new Point3d();\n    point.x = data[i][this.colX] || 0;\n    point.y = data[i][this.colY] || 0;\n    point.z = data[i][this.colZ] || 0;\n    point.data = data[i];\n    point.value = data[i][this.colValue] || 0;\n\n    const obj = {};\n    obj.point = point;\n    obj.bottom = new Point3d(point.x, point.y, this.zRange.min);\n    obj.trans = undefined;\n    obj.screen = undefined;\n\n    dataPoints.push(obj);\n  }\n\n  return dataPoints;\n};\n\n/**\n * Filter the data based on the current filter\n * @param   {Array} data\n * @returns {Array} dataPoints Array with point objects which can be drawn on\n *                             screen\n */\nGraph3d.prototype._getDataPoints = function (data) {\n  // TODO: store the created matrix dataPoints in the filters instead of\n  //       reloading each time.\n  let x, y, i, obj;\n\n  let dataPoints = [];\n\n  if (\n    this.style === Graph3d.STYLE.GRID ||\n    this.style === Graph3d.STYLE.SURFACE\n  ) {\n    // copy all values from the data table to a matrix\n    // the provided values are supposed to form a grid of (x,y) positions\n\n    // create two lists with all present x and y values\n    const dataX = this.dataGroup.getDistinctValues(this.colX, data);\n    const dataY = this.dataGroup.getDistinctValues(this.colY, data);\n\n    dataPoints = this.getDataPoints(data);\n\n    // create a grid, a 2d matrix, with all values.\n    const dataMatrix = []; // temporary data matrix\n    for (i = 0; i < dataPoints.length; i++) {\n      obj = dataPoints[i];\n\n      // TODO: implement Array().indexOf() for Internet Explorer\n      const xIndex = dataX.indexOf(obj.point.x);\n      const yIndex = dataY.indexOf(obj.point.y);\n\n      if (dataMatrix[xIndex] === undefined) {\n        dataMatrix[xIndex] = [];\n      }\n\n      dataMatrix[xIndex][yIndex] = obj;\n    }\n\n    // fill in the pointers to the neighbors.\n    for (x = 0; x < dataMatrix.length; x++) {\n      for (y = 0; y < dataMatrix[x].length; y++) {\n        if (dataMatrix[x][y]) {\n          dataMatrix[x][y].pointRight =\n            x < dataMatrix.length - 1 ? dataMatrix[x + 1][y] : undefined;\n          dataMatrix[x][y].pointTop =\n            y < dataMatrix[x].length - 1 ? dataMatrix[x][y + 1] : undefined;\n          dataMatrix[x][y].pointCross =\n            x < dataMatrix.length - 1 && y < dataMatrix[x].length - 1\n              ? dataMatrix[x + 1][y + 1]\n              : undefined;\n        }\n      }\n    }\n  } else {\n    // 'dot', 'dot-line', etc.\n    dataPoints = this.getDataPoints(data);\n\n    if (this.style === Graph3d.STYLE.LINE) {\n      // Add next member points for line drawing\n      for (i = 0; i < dataPoints.length; i++) {\n        if (i > 0) {\n          dataPoints[i - 1].pointNext = dataPoints[i];\n        }\n      }\n    }\n  }\n\n  return dataPoints;\n};\n\n/**\n * Create the main frame for the Graph3d.\n *\n * This function is executed once when a Graph3d object is created. The frame\n * contains a canvas, and this canvas contains all objects like the axis and\n * nodes.\n */\nGraph3d.prototype.create = function () {\n  // remove all elements from the container element.\n  while (this.containerElement.hasChildNodes()) {\n    this.containerElement.removeChild(this.containerElement.firstChild);\n  }\n\n  this.frame = document.createElement(\"div\");\n  this.frame.style.position = \"relative\";\n  this.frame.style.overflow = \"hidden\";\n\n  // create the graph canvas (HTML canvas element)\n  this.frame.canvas = document.createElement(\"canvas\");\n  this.frame.canvas.style.position = \"relative\";\n  this.frame.appendChild(this.frame.canvas);\n  //if (!this.frame.canvas.getContext) {\n  {\n    const noCanvas = document.createElement(\"DIV\");\n    noCanvas.style.color = \"red\";\n    noCanvas.style.fontWeight = \"bold\";\n    noCanvas.style.padding = \"10px\";\n    noCanvas.innerHTML = \"Error: your browser does not support HTML canvas\";\n    this.frame.canvas.appendChild(noCanvas);\n  }\n\n  this.frame.filter = document.createElement(\"div\");\n  this.frame.filter.style.position = \"absolute\";\n  this.frame.filter.style.bottom = \"0px\";\n  this.frame.filter.style.left = \"0px\";\n  this.frame.filter.style.width = \"100%\";\n  this.frame.appendChild(this.frame.filter);\n\n  // add event listeners to handle moving and zooming the contents\n  const me = this;\n  const onmousedown = function (event) {\n    me._onMouseDown(event);\n  };\n  const ontouchstart = function (event) {\n    me._onTouchStart(event);\n  };\n  const onmousewheel = function (event) {\n    me._onWheel(event);\n  };\n  const ontooltip = function (event) {\n    me._onTooltip(event);\n  };\n  const onclick = function (event) {\n    me._onClick(event);\n  };\n  // TODO: these events are never cleaned up... can give a 'memory leakage'\n\n  this.frame.canvas.addEventListener(\"mousedown\", onmousedown);\n  this.frame.canvas.addEventListener(\"touchstart\", ontouchstart);\n  this.frame.canvas.addEventListener(\"mousewheel\", onmousewheel);\n  this.frame.canvas.addEventListener(\"mousemove\", ontooltip);\n  this.frame.canvas.addEventListener(\"click\", onclick);\n\n  // add the new graph to the container element\n  this.containerElement.appendChild(this.frame);\n};\n\n/**\n * Set a new size for the graph\n * @param {number} width\n * @param {number} height\n * @private\n */\nGraph3d.prototype._setSize = function (width, height) {\n  this.frame.style.width = width;\n  this.frame.style.height = height;\n\n  this._resizeCanvas();\n};\n\n/**\n * Resize the canvas to the current size of the frame\n */\nGraph3d.prototype._resizeCanvas = function () {\n  this.frame.canvas.style.width = \"100%\";\n  this.frame.canvas.style.height = \"100%\";\n\n  this.frame.canvas.width = this.frame.canvas.clientWidth;\n  this.frame.canvas.height = this.frame.canvas.clientHeight;\n\n  // adjust with for margin\n  this.frame.filter.style.width = this.frame.canvas.clientWidth - 2 * 10 + \"px\";\n};\n\n/**\n * Start playing the animation, if requested and filter present. Only applicable\n * when animation data is available.\n */\nGraph3d.prototype.animationStart = function () {\n  // start animation when option is true\n  if (!this.animationAutoStart || !this.dataGroup.dataFilter) return;\n\n  if (!this.frame.filter || !this.frame.filter.slider)\n    throw new Error(\"No animation available\");\n\n  this.frame.filter.slider.play();\n};\n\n/**\n * Stop animation\n */\nGraph3d.prototype.animationStop = function () {\n  if (!this.frame.filter || !this.frame.filter.slider) return;\n\n  this.frame.filter.slider.stop();\n};\n\n/**\n * Resize the center position based on the current values in this.xCenter\n * and this.yCenter (which are strings with a percentage or a value\n * in pixels). The center positions are the variables this.currentXCenter\n * and this.currentYCenter\n */\nGraph3d.prototype._resizeCenter = function () {\n  // calculate the horizontal center position\n  if (this.xCenter.charAt(this.xCenter.length - 1) === \"%\") {\n    this.currentXCenter =\n      (parseFloat(this.xCenter) / 100) * this.frame.canvas.clientWidth;\n  } else {\n    this.currentXCenter = parseFloat(this.xCenter); // supposed to be in px\n  }\n\n  // calculate the vertical center position\n  if (this.yCenter.charAt(this.yCenter.length - 1) === \"%\") {\n    this.currentYCenter =\n      (parseFloat(this.yCenter) / 100) *\n      (this.frame.canvas.clientHeight - this.frame.filter.clientHeight);\n  } else {\n    this.currentYCenter = parseFloat(this.yCenter); // supposed to be in px\n  }\n};\n\n/**\n * Retrieve the current camera rotation\n * @returns {object} An object with parameters horizontal, vertical, and\n *                   distance\n */\nGraph3d.prototype.getCameraPosition = function () {\n  const pos = this.camera.getArmRotation();\n  pos.distance = this.camera.getArmLength();\n  return pos;\n};\n\n/**\n * Load data into the 3D Graph\n * @param {vis.DataSet} data\n * @private\n */\nGraph3d.prototype._readData = function (data) {\n  // read the data\n  this.dataPoints = this.dataGroup.initializeData(this, data, this.style);\n\n  this._initializeRanges();\n  this._redrawFilter();\n};\n\n/**\n * Replace the dataset of the Graph3d\n * @param {Array | DataSet | DataView} data\n */\nGraph3d.prototype.setData = function (data) {\n  if (data === undefined || data === null) return;\n\n  this._readData(data);\n  this.redraw();\n  this.animationStart();\n};\n\n/**\n * Update the options. Options will be merged with current options\n * @param {object} options\n */\nGraph3d.prototype.setOptions = function (options) {\n  if (options === undefined) return;\n\n  const errorFound = Validator.validate(options, allOptions);\n  if (errorFound === true) {\n    console.error(\n      \"%cErrors have been found in the supplied options object.\",\n      VALIDATOR_PRINT_STYLE,\n    );\n  }\n\n  this.animationStop();\n\n  setOptions(options, this);\n  this.setPointDrawingMethod();\n  this._setSize(this.width, this.height);\n  this.setAxisLabelMethod();\n\n  this.setData(this.dataGroup.getDataTable());\n  this.animationStart();\n};\n\n/**\n * Determine which point drawing method to use for the current graph style.\n */\nGraph3d.prototype.setPointDrawingMethod = function () {\n  let method = undefined;\n\n  switch (this.style) {\n    case Graph3d.STYLE.BAR:\n      method = this._redrawBarGraphPoint;\n      break;\n    case Graph3d.STYLE.BARCOLOR:\n      method = this._redrawBarColorGraphPoint;\n      break;\n    case Graph3d.STYLE.BARSIZE:\n      method = this._redrawBarSizeGraphPoint;\n      break;\n    case Graph3d.STYLE.DOT:\n      method = this._redrawDotGraphPoint;\n      break;\n    case Graph3d.STYLE.DOTLINE:\n      method = this._redrawDotLineGraphPoint;\n      break;\n    case Graph3d.STYLE.DOTCOLOR:\n      method = this._redrawDotColorGraphPoint;\n      break;\n    case Graph3d.STYLE.DOTSIZE:\n      method = this._redrawDotSizeGraphPoint;\n      break;\n    case Graph3d.STYLE.SURFACE:\n      method = this._redrawSurfaceGraphPoint;\n      break;\n    case Graph3d.STYLE.GRID:\n      method = this._redrawGridGraphPoint;\n      break;\n    case Graph3d.STYLE.LINE:\n      method = this._redrawLineGraphPoint;\n      break;\n    default:\n      throw new Error(\n        \"Can not determine point drawing method \" +\n          \"for graph style '\" +\n          this.style +\n          \"'\",\n      );\n  }\n\n  this._pointDrawingMethod = method;\n};\n\n/**\n * Determine which functions to use to draw axis labels.\n */\nGraph3d.prototype.setAxisLabelMethod = function () {\n  if (this.rotateAxisLabels) {\n    this._drawAxisLabelX = this.drawAxisLabelXRotate;\n    this._drawAxisLabelY = this.drawAxisLabelYRotate;\n    this._drawAxisLabelZ = this.drawAxisLabelZRotate;\n  } else {\n    this._drawAxisLabelX = this.drawAxisLabelX;\n    this._drawAxisLabelY = this.drawAxisLabelY;\n    this._drawAxisLabelZ = this.drawAxisLabelZ;\n  }\n};\n\n/**\n * Redraw the Graph.\n */\nGraph3d.prototype.redraw = function () {\n  if (this.dataPoints === undefined) {\n    throw new Error(\"Graph data not initialized\");\n  }\n\n  this._resizeCanvas();\n  this._resizeCenter();\n  this._redrawSlider();\n  this._redrawClear();\n  this._redrawAxis();\n\n  this._redrawDataGraph();\n\n  this._redrawInfo();\n  this._redrawLegend();\n};\n\n/**\n * Get drawing context without exposing canvas\n * @returns {CanvasRenderingContext2D}\n * @private\n */\nGraph3d.prototype._getContext = function () {\n  const canvas = this.frame.canvas;\n  const ctx = canvas.getContext(\"2d\");\n\n  ctx.lineJoin = \"round\";\n  ctx.lineCap = \"round\";\n\n  return ctx;\n};\n\n/**\n * Clear the canvas before redrawing\n */\nGraph3d.prototype._redrawClear = function () {\n  const canvas = this.frame.canvas;\n  const ctx = canvas.getContext(\"2d\");\n\n  ctx.clearRect(0, 0, canvas.width, canvas.height);\n};\n\nGraph3d.prototype._dotSize = function () {\n  return this.frame.clientWidth * this.dotSizeRatio;\n};\n\n/**\n * Get legend width\n * @returns {*}\n * @private\n */\nGraph3d.prototype._getLegendWidth = function () {\n  let width;\n\n  if (this.style === Graph3d.STYLE.DOTSIZE) {\n    const dotSize = this._dotSize();\n    //width =  dotSize / 2 + dotSize * 2;\n    width = dotSize * this.dotSizeMaxFraction;\n  } else if (this.style === Graph3d.STYLE.BARSIZE) {\n    width = this.xBarWidth;\n  } else {\n    width = 20;\n  }\n  return width;\n};\n\n/**\n * Redraw the legend based on size, dot color, or surface height\n */\nGraph3d.prototype._redrawLegend = function () {\n  //Return without drawing anything, if no legend is specified\n  if (this.showLegend !== true) {\n    return;\n  }\n\n  // Do not draw legend when graph style does not support\n  if (\n    this.style === Graph3d.STYLE.LINE ||\n    this.style === Graph3d.STYLE.BARSIZE //TODO add legend support for BARSIZE\n  ) {\n    return;\n  }\n\n  // Legend types - size and color. Determine if size legend.\n  const isSizeLegend =\n    this.style === Graph3d.STYLE.BARSIZE ||\n    this.style === Graph3d.STYLE.DOTSIZE;\n\n  // Legend is either tracking z values or style values. This flag if false means use z values.\n  const isValueLegend =\n    this.style === Graph3d.STYLE.DOTSIZE ||\n    this.style === Graph3d.STYLE.DOTCOLOR ||\n    this.style === Graph3d.STYLE.SURFACE ||\n    this.style === Graph3d.STYLE.BARCOLOR;\n\n  const height = Math.max(this.frame.clientHeight * 0.25, 100);\n  const top = this.margin;\n  const width = this._getLegendWidth(); // px - overwritten by size legend\n  const right = this.frame.clientWidth - this.margin;\n  const left = right - width;\n  const bottom = top + height;\n\n  const ctx = this._getContext();\n  ctx.lineWidth = 1;\n  ctx.font = \"14px arial\"; // TODO: put in options\n\n  if (isSizeLegend === false) {\n    // draw the color bar\n    const ymin = 0;\n    const ymax = height; // Todo: make height customizable\n    let y;\n\n    for (y = ymin; y < ymax; y++) {\n      // Need (1 - x) because y runs from top to bottom:\n      const f = 1 - (y - ymin) / (ymax - ymin);\n      const color = this._colormap(f, 1);\n\n      ctx.strokeStyle = color;\n      ctx.beginPath();\n      ctx.moveTo(left, top + y);\n      ctx.lineTo(right, top + y);\n      ctx.stroke();\n    }\n    ctx.strokeStyle = this.axisColor;\n    ctx.strokeRect(left, top, width, height);\n  } else {\n    // draw the size legend box\n    let widthMin;\n    if (this.style === Graph3d.STYLE.DOTSIZE) {\n      // Get the proportion to max and min right\n      widthMin = width * (this.dotSizeMinFraction / this.dotSizeMaxFraction);\n    } else if (this.style === Graph3d.STYLE.BARSIZE) {\n      //widthMin = this.xBarWidth * 0.2 this is wrong - barwidth measures in terms of xvalues\n    }\n    ctx.strokeStyle = this.axisColor;\n    ctx.fillStyle = this.dataColor.fill;\n    ctx.beginPath();\n    ctx.moveTo(left, top);\n    ctx.lineTo(right, top);\n    ctx.lineTo(left + widthMin, bottom);\n    ctx.lineTo(left, bottom);\n    ctx.closePath();\n    ctx.fill();\n    ctx.stroke();\n  }\n\n  // print value text along the legend edge\n  const gridLineLen = 5; // px\n\n  const legendMin = isValueLegend ? this.valueRange.min : this.zRange.min;\n  const legendMax = isValueLegend ? this.valueRange.max : this.zRange.max;\n  const step = new StepNumber(\n    legendMin,\n    legendMax,\n    (legendMax - legendMin) / 5,\n    true,\n  );\n  step.start(true);\n\n  while (!step.end()) {\n    const y =\n      bottom -\n      ((step.getCurrent() - legendMin) / (legendMax - legendMin)) * height;\n    const from = new Point2d(left - gridLineLen, y);\n    const to = new Point2d(left, y);\n    this._line(ctx, from, to);\n\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y);\n\n    step.next();\n  }\n\n  ctx.textAlign = \"right\";\n  ctx.textBaseline = \"top\";\n  const label = this.legendLabel;\n  ctx.fillText(label, right, bottom + this.margin);\n};\n\n/**\n * Redraw the filter\n */\nGraph3d.prototype._redrawFilter = function () {\n  const dataFilter = this.dataGroup.dataFilter;\n  const filter = this.frame.filter;\n  filter.innerHTML = \"\";\n\n  if (!dataFilter) {\n    filter.slider = undefined;\n    return;\n  }\n\n  const options = {\n    visible: this.showAnimationControls,\n  };\n  const slider = new Slider(filter, options);\n  filter.slider = slider;\n\n  // TODO: css here is not nice here...\n  filter.style.padding = \"10px\";\n  //this.frame.filter.style.backgroundColor = '#EFEFEF';\n\n  slider.setValues(dataFilter.values);\n  slider.setPlayInterval(this.animationInterval);\n\n  // create an event handler\n  const me = this;\n  const onchange = function () {\n    const dataFilter = me.dataGroup.dataFilter;\n    const index = slider.getIndex();\n\n    dataFilter.selectValue(index);\n    me.dataPoints = dataFilter._getDataPoints();\n\n    me.redraw();\n  };\n\n  slider.setOnChangeCallback(onchange);\n};\n\n/**\n * Redraw the slider\n */\nGraph3d.prototype._redrawSlider = function () {\n  if (this.frame.filter.slider !== undefined) {\n    this.frame.filter.slider.redraw();\n  }\n};\n\n/**\n * Redraw common information\n */\nGraph3d.prototype._redrawInfo = function () {\n  const info = this.dataGroup.getInfo();\n  if (info === undefined) return;\n\n  const ctx = this._getContext();\n\n  ctx.font = \"14px arial\"; // TODO: put in options\n  ctx.lineStyle = \"gray\";\n  ctx.fillStyle = \"gray\";\n  ctx.textAlign = \"left\";\n  ctx.textBaseline = \"top\";\n\n  const x = this.margin;\n  const y = this.margin;\n  ctx.fillText(info, x, y);\n};\n\n/**\n * Draw a line between 2d points 'from' and 'to'.\n *\n * If stroke style specified, set that as well.\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point2d} from\n * @param {vis.Point2d} to\n * @param {string} [strokeStyle]\n * @private\n */\nGraph3d.prototype._line = function (ctx, from, to, strokeStyle) {\n  if (strokeStyle !== undefined) {\n    ctx.strokeStyle = strokeStyle;\n  }\n\n  ctx.beginPath();\n  ctx.moveTo(from.x, from.y);\n  ctx.lineTo(to.x, to.y);\n  ctx.stroke();\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} armAngle\n * @param {number} [yMargin]\n */\nGraph3d.prototype.drawAxisLabelX = function (\n  ctx,\n  point3d,\n  text,\n  armAngle,\n  yMargin,\n) {\n  if (yMargin === undefined) {\n    yMargin = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n\n  if (Math.cos(armAngle * 2) > 0) {\n    ctx.textAlign = \"center\";\n    ctx.textBaseline = \"top\";\n    point2d.y += yMargin;\n  } else if (Math.sin(armAngle * 2) < 0) {\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n  } else {\n    ctx.textAlign = \"left\";\n    ctx.textBaseline = \"middle\";\n  }\n\n  ctx.fillStyle = this.axisColor;\n  ctx.fillText(text, point2d.x, point2d.y);\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} armAngle\n * @param {number} [yMargin]\n */\nGraph3d.prototype.drawAxisLabelY = function (\n  ctx,\n  point3d,\n  text,\n  armAngle,\n  yMargin,\n) {\n  if (yMargin === undefined) {\n    yMargin = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n\n  if (Math.cos(armAngle * 2) < 0) {\n    ctx.textAlign = \"center\";\n    ctx.textBaseline = \"top\";\n    point2d.y += yMargin;\n  } else if (Math.sin(armAngle * 2) > 0) {\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n  } else {\n    ctx.textAlign = \"left\";\n    ctx.textBaseline = \"middle\";\n  }\n\n  ctx.fillStyle = this.axisColor;\n  ctx.fillText(text, point2d.x, point2d.y);\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} [offset]\n */\nGraph3d.prototype.drawAxisLabelZ = function (ctx, point3d, text, offset) {\n  if (offset === undefined) {\n    offset = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n  ctx.textAlign = \"right\";\n  ctx.textBaseline = \"middle\";\n  ctx.fillStyle = this.axisColor;\n  ctx.fillText(text, point2d.x - offset, point2d.y);\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} armAngle\n * @param {number} [yMargin]\n */\nGraph3d.prototype.drawAxisLabelXRotate = function (\n  ctx,\n  point3d,\n  text,\n  armAngle,\n  yMargin,\n) {\n  if (yMargin === undefined) {\n    yMargin = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n  if (Math.cos(armAngle * 2) > 0) {\n    ctx.save();\n    ctx.translate(point2d.x, point2d.y);\n    ctx.rotate(-Math.PI / 2);\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, 0, 0);\n    ctx.restore();\n  } else if (Math.sin(armAngle * 2) < 0) {\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, point2d.x, point2d.y);\n  } else {\n    ctx.textAlign = \"left\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, point2d.x, point2d.y);\n  }\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} armAngle\n * @param {number} [yMargin]\n */\nGraph3d.prototype.drawAxisLabelYRotate = function (\n  ctx,\n  point3d,\n  text,\n  armAngle,\n  yMargin,\n) {\n  if (yMargin === undefined) {\n    yMargin = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n  if (Math.cos(armAngle * 2) < 0) {\n    ctx.save();\n    ctx.translate(point2d.x, point2d.y);\n    ctx.rotate(-Math.PI / 2);\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, 0, 0);\n    ctx.restore();\n  } else if (Math.sin(armAngle * 2) > 0) {\n    ctx.textAlign = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, point2d.x, point2d.y);\n  } else {\n    ctx.textAlign = \"left\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = this.axisColor;\n    ctx.fillText(text, point2d.x, point2d.y);\n  }\n};\n\n/**\n *\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point3d} point3d\n * @param {string} text\n * @param {number} [offset]\n */\nGraph3d.prototype.drawAxisLabelZRotate = function (ctx, point3d, text, offset) {\n  if (offset === undefined) {\n    offset = 0;\n  }\n\n  const point2d = this._convert3Dto2D(point3d);\n  ctx.textAlign = \"right\";\n  ctx.textBaseline = \"middle\";\n  ctx.fillStyle = this.axisColor;\n  ctx.fillText(text, point2d.x - offset, point2d.y);\n};\n\n/**\n \n \n /**\n Draw a line between 2d points 'from' and 'to'.\n \n If stroke style specified, set that as well.\n * @param {CanvasRenderingContext2D} ctx\n * @param {vis.Point2d} from\n * @param {vis.Point2d} to\n * @param {string} [strokeStyle]\n * @private\n */\nGraph3d.prototype._line3d = function (ctx, from, to, strokeStyle) {\n  const from2d = this._convert3Dto2D(from);\n  const to2d = this._convert3Dto2D(to);\n\n  this._line(ctx, from2d, to2d, strokeStyle);\n};\n\n/**\n * Redraw the axis\n */\nGraph3d.prototype._redrawAxis = function () {\n  const ctx = this._getContext();\n  let from,\n    to,\n    step,\n    prettyStep,\n    text,\n    xText,\n    yText,\n    zText,\n    offset,\n    xOffset,\n    yOffset;\n\n  // TODO: get the actual rendered style of the containerElement\n  //ctx.font = this.containerElement.style.font;\n  //ctx.font = 24 / this.camera.getArmLength() + 'px arial';\n  ctx.font =\n    this.axisFontSize / this.camera.getArmLength() + \"px \" + this.axisFontType;\n\n  // calculate the length for the short grid lines\n  const gridLenX = 0.025 / this.scale.x;\n  const gridLenY = 0.025 / this.scale.y;\n  const textMargin = 5 / this.camera.getArmLength(); // px\n  const armAngle = this.camera.getArmRotation().horizontal;\n  const armVector = new Point2d(Math.cos(armAngle), Math.sin(armAngle));\n\n  const xRange = this.xRange;\n  const yRange = this.yRange;\n  const zRange = this.zRange;\n  let point3d;\n\n  // draw x-grid lines\n  ctx.lineWidth = 1;\n  prettyStep = this.defaultXStep === undefined;\n  step = new StepNumber(xRange.min, xRange.max, this.xStep, prettyStep);\n  step.start(true);\n\n  while (!step.end()) {\n    const x = step.getCurrent();\n\n    if (this.showGrid) {\n      from = new Point3d(x, yRange.min, zRange.min);\n      to = new Point3d(x, yRange.max, zRange.min);\n      this._line3d(ctx, from, to, this.gridColor);\n    } else if (this.showXAxis) {\n      from = new Point3d(x, yRange.min, zRange.min);\n      to = new Point3d(x, yRange.min + gridLenX, zRange.min);\n      this._line3d(ctx, from, to, this.axisColor);\n\n      from = new Point3d(x, yRange.max, zRange.min);\n      to = new Point3d(x, yRange.max - gridLenX, zRange.min);\n      this._line3d(ctx, from, to, this.axisColor);\n    }\n\n    if (this.showXAxis) {\n      yText = armVector.x > 0 ? yRange.min : yRange.max;\n      point3d = new Point3d(x, yText, zRange.min);\n      const msg = \"  \" + this.xValueLabel(x) + \"  \";\n      this._drawAxisLabelX.call(this, ctx, point3d, msg, armAngle, textMargin);\n    }\n\n    step.next();\n  }\n\n  // draw y-grid lines\n  ctx.lineWidth = 1;\n  prettyStep = this.defaultYStep === undefined;\n  step = new StepNumber(yRange.min, yRange.max, this.yStep, prettyStep);\n  step.start(true);\n\n  while (!step.end()) {\n    const y = step.getCurrent();\n\n    if (this.showGrid) {\n      from = new Point3d(xRange.min, y, zRange.min);\n      to = new Point3d(xRange.max, y, zRange.min);\n      this._line3d(ctx, from, to, this.gridColor);\n    } else if (this.showYAxis) {\n      from = new Point3d(xRange.min, y, zRange.min);\n      to = new Point3d(xRange.min + gridLenY, y, zRange.min);\n      this._line3d(ctx, from, to, this.axisColor);\n\n      from = new Point3d(xRange.max, y, zRange.min);\n      to = new Point3d(xRange.max - gridLenY, y, zRange.min);\n      this._line3d(ctx, from, to, this.axisColor);\n    }\n\n    if (this.showYAxis) {\n      xText = armVector.y > 0 ? xRange.min : xRange.max;\n      point3d = new Point3d(xText, y, zRange.min);\n      const msg = \"  \" + this.yValueLabel(y) + \"  \";\n      this._drawAxisLabelY.call(this, ctx, point3d, msg, armAngle, textMargin);\n    }\n\n    step.next();\n  }\n\n  // draw z-grid lines and axis\n  if (this.showZAxis) {\n    ctx.lineWidth = 1;\n    prettyStep = this.defaultZStep === undefined;\n    step = new StepNumber(zRange.min, zRange.max, this.zStep, prettyStep);\n    step.start(true);\n\n    xText = armVector.x > 0 ? xRange.min : xRange.max;\n    yText = armVector.y < 0 ? yRange.min : yRange.max;\n\n    while (!step.end()) {\n      const z = step.getCurrent();\n\n      // TODO: make z-grid lines really 3d?\n      const from3d = new Point3d(xText, yText, z);\n      const from2d = this._convert3Dto2D(from3d);\n      to = new Point2d(from2d.x - textMargin, from2d.y);\n      this._line(ctx, from2d, to, this.axisColor);\n\n      const msg = this.zValueLabel(z) + \" \";\n      this._drawAxisLabelZ.call(this, ctx, from3d, msg, 5);\n\n      step.next();\n    }\n\n    ctx.lineWidth = 1;\n    from = new Point3d(xText, yText, zRange.min);\n    to = new Point3d(xText, yText, zRange.max);\n    this._line3d(ctx, from, to, this.axisColor);\n  }\n\n  // draw x-axis\n  if (this.showXAxis) {\n    let xMin2d;\n    let xMax2d;\n    ctx.lineWidth = 1;\n\n    // line at yMin\n    xMin2d = new Point3d(xRange.min, yRange.min, zRange.min);\n    xMax2d = new Point3d(xRange.max, yRange.min, zRange.min);\n    this._line3d(ctx, xMin2d, xMax2d, this.axisColor);\n    // line at ymax\n    xMin2d = new Point3d(xRange.min, yRange.max, zRange.min);\n    xMax2d = new Point3d(xRange.max, yRange.max, zRange.min);\n    this._line3d(ctx, xMin2d, xMax2d, this.axisColor);\n  }\n\n  // draw y-axis\n  if (this.showYAxis) {\n    ctx.lineWidth = 1;\n    // line at xMin\n    from = new Point3d(xRange.min, yRange.min, zRange.min);\n    to = new Point3d(xRange.min, yRange.max, zRange.min);\n    this._line3d(ctx, from, to, this.axisColor);\n    // line at xMax\n    from = new Point3d(xRange.max, yRange.min, zRange.min);\n    to = new Point3d(xRange.max, yRange.max, zRange.min);\n    this._line3d(ctx, from, to, this.axisColor);\n  }\n\n  // draw x-label\n  const xLabel = this.xLabel;\n  if (xLabel.length > 0 && this.showXAxis) {\n    yOffset = 0.1 / this.scale.y;\n    xText = (xRange.max + 3 * xRange.min) / 4;\n    yText = armVector.x > 0 ? yRange.min - yOffset : yRange.max + yOffset;\n    text = new Point3d(xText, yText, zRange.min);\n    this.drawAxisLabelX(ctx, text, xLabel, armAngle);\n  }\n\n  // draw y-label\n  const yLabel = this.yLabel;\n  if (yLabel.length > 0 && this.showYAxis) {\n    xOffset = 0.1 / this.scale.x;\n    xText = armVector.y > 0 ? xRange.min - xOffset : xRange.max + xOffset;\n    yText = (yRange.max + 3 * yRange.min) / 4;\n    text = new Point3d(xText, yText, zRange.min);\n\n    this.drawAxisLabelY(ctx, text, yLabel, armAngle);\n  }\n\n  // draw z-label\n  const zLabel = this.zLabel;\n  if (zLabel.length > 0 && this.showZAxis) {\n    offset = 30; // pixels.  // TODO: relate to the max width of the values on the z axis?\n    xText = armVector.x > 0 ? xRange.min : xRange.max;\n    yText = armVector.y < 0 ? yRange.min : yRange.max;\n    zText = (zRange.max + 3 * zRange.min) / 4;\n    text = new Point3d(xText, yText, zText);\n\n    this.drawAxisLabelZ(ctx, text, zLabel, offset);\n  }\n};\n\n/**\n *\n * @param {vis.Point3d} point\n * @returns {*}\n * @private\n */\nGraph3d.prototype._getStrokeWidth = function (point) {\n  if (point !== undefined) {\n    if (this.showPerspective) {\n      return (1 / -point.trans.z) * this.dataColor.strokeWidth;\n    } else {\n      return (\n        -(this.eye.z / this.camera.getArmLength()) * this.dataColor.strokeWidth\n      );\n    }\n  }\n\n  return this.dataColor.strokeWidth;\n};\n\n// -----------------------------------------------------------------------------\n// Drawing primitives for the graphs\n// -----------------------------------------------------------------------------\n\n/**\n * Draw a bar element in the view with the given properties.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @param {number} xWidth\n * @param {number} yWidth\n * @param {string} color\n * @param {string} borderColor\n * @private\n */\nGraph3d.prototype._redrawBar = function (\n  ctx,\n  point,\n  xWidth,\n  yWidth,\n  color,\n  borderColor,\n) {\n  let surface;\n\n  // calculate all corner points\n  const me = this;\n  const point3d = point.point;\n  const zMin = this.zRange.min;\n  const top = [\n    { point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z) },\n    { point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z) },\n    { point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z) },\n    { point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z) },\n  ];\n  const bottom = [\n    { point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, zMin) },\n    { point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, zMin) },\n    { point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, zMin) },\n    { point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, zMin) },\n  ];\n\n  // calculate screen location of the points\n  top.forEach(function (obj) {\n    obj.screen = me._convert3Dto2D(obj.point);\n  });\n  bottom.forEach(function (obj) {\n    obj.screen = me._convert3Dto2D(obj.point);\n  });\n\n  // create five sides, calculate both corner points and center points\n  const surfaces = [\n    { corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point) },\n    {\n      corners: [top[0], top[1], bottom[1], bottom[0]],\n      center: Point3d.avg(bottom[1].point, bottom[0].point),\n    },\n    {\n      corners: [top[1], top[2], bottom[2], bottom[1]],\n      center: Point3d.avg(bottom[2].point, bottom[1].point),\n    },\n    {\n      corners: [top[2], top[3], bottom[3], bottom[2]],\n      center: Point3d.avg(bottom[3].point, bottom[2].point),\n    },\n    {\n      corners: [top[3], top[0], bottom[0], bottom[3]],\n      center: Point3d.avg(bottom[0].point, bottom[3].point),\n    },\n  ];\n  point.surfaces = surfaces;\n\n  // calculate the distance of each of the surface centers to the camera\n  for (let j = 0; j < surfaces.length; j++) {\n    surface = surfaces[j];\n    const transCenter = this._convertPointToTranslation(surface.center);\n    surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z;\n    // TODO: this dept calculation doesn't work 100% of the cases due to perspective,\n    //     but the current solution is fast/simple and works in 99.9% of all cases\n    //     the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})\n  }\n\n  // order the surfaces by their (translated) depth\n  surfaces.sort(function (a, b) {\n    const diff = b.dist - a.dist;\n    if (diff) return diff;\n\n    // if equal depth, sort the top surface last\n    if (a.corners === top) return 1;\n    if (b.corners === top) return -1;\n\n    // both are equal\n    return 0;\n  });\n\n  // draw the ordered surfaces\n  ctx.lineWidth = this._getStrokeWidth(point);\n  ctx.strokeStyle = borderColor;\n  ctx.fillStyle = color;\n  // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside\n  for (let j = 2; j < surfaces.length; j++) {\n    surface = surfaces[j];\n    this._polygon(ctx, surface.corners);\n  }\n};\n\n/**\n * Draw a polygon using the passed points and fill it with the passed style and stroke.\n * @param {CanvasRenderingContext2D} ctx\n * @param {Array.<vis.Point3d>} points      an array of points.\n * @param {string} [fillStyle] the fill style to set\n * @param {string} [strokeStyle] the stroke style to set\n */\nGraph3d.prototype._polygon = function (ctx, points, fillStyle, strokeStyle) {\n  if (points.length < 2) {\n    return;\n  }\n\n  if (fillStyle !== undefined) {\n    ctx.fillStyle = fillStyle;\n  }\n  if (strokeStyle !== undefined) {\n    ctx.strokeStyle = strokeStyle;\n  }\n  ctx.beginPath();\n  ctx.moveTo(points[0].screen.x, points[0].screen.y);\n\n  for (let i = 1; i < points.length; ++i) {\n    const point = points[i];\n    ctx.lineTo(point.screen.x, point.screen.y);\n  }\n\n  ctx.closePath();\n  ctx.fill();\n  ctx.stroke(); // TODO: only draw stroke when strokeWidth > 0\n};\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @param {string} color\n * @param {string} borderColor\n * @param {number} [size]\n * @private\n */\nGraph3d.prototype._drawCircle = function (\n  ctx,\n  point,\n  color,\n  borderColor,\n  size,\n) {\n  const radius = this._calcRadius(point, size);\n\n  ctx.lineWidth = this._getStrokeWidth(point);\n  ctx.strokeStyle = borderColor;\n  ctx.fillStyle = color;\n  ctx.beginPath();\n  ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI * 2, true);\n  ctx.fill();\n  ctx.stroke();\n};\n\n/**\n * Determine the colors for the 'regular' graph styles.\n * @param {object} point\n * @returns {{fill, border}}\n * @private\n */\nGraph3d.prototype._getColorsRegular = function (point) {\n  const f = (point.point.value - this.valueRange.min) * this.scale.value;\n  const color = this._colormap(f, 1);\n  const borderColor = this._colormap(f, 0.8);\n  return {\n    fill: color,\n    border: borderColor,\n  };\n};\n\n/**\n * Get the colors for the 'color' graph styles.\n * These styles are currently: 'bar-color' and 'dot-color'\n * Color may be set as a string representation of HTML color, like #ff00ff,\n * or calculated from a number, for example, distance from this point\n * The first option is useful when we have some pre-given legend, to which we have to adjust ourselves\n * The second option is useful when we are interested in automatically setting the color, from some value,\n * using some color scale\n * @param {object} point\n * @returns {{fill: *, border: *}}\n * @private\n */\nGraph3d.prototype._getColorsColor = function (point) {\n  // calculate the color based on the value\n  let color, borderColor, pointStyle;\n  if (point && point.point && point.point.data && point.point.data.style) {\n    pointStyle = point.point.data.style;\n  }\n  if (\n    pointStyle &&\n    typeof pointStyle === \"object\" &&\n    pointStyle.fill &&\n    pointStyle.stroke\n  ) {\n    return {\n      fill: pointStyle.fill,\n      border: pointStyle.stroke,\n    };\n  }\n\n  if (typeof point.point.value === \"string\") {\n    color = point.point.value;\n    borderColor = point.point.value;\n  } else {\n    const f = (point.point.value - this.valueRange.min) * this.scale.value;\n    color = this._colormap(f, 1);\n    borderColor = this._colormap(f, 0.8);\n  }\n  return {\n    fill: color,\n    border: borderColor,\n  };\n};\n\n/**\n * Get the colors for the 'size' graph styles.\n * These styles are currently: 'bar-size' and 'dot-size'\n * @returns {{fill: *, border: (string|colorOptions.stroke|{string, undefined}|string|colorOptions.stroke|{string}|*)}}\n * @private\n */\nGraph3d.prototype._getColorsSize = function () {\n  return {\n    fill: this.dataColor.fill,\n    border: this.dataColor.stroke,\n  };\n};\n\n/**\n * Determine the color corresponding to a given value on the color scale.\n * @param {number} [x] the data value to be mapped running from 0 to 1\n * @param {number} [v] scale factor between 0 and 1 for the color brightness\n * @returns {string}\n * @private\n */\nGraph3d.prototype._colormap = function (x, v = 1) {\n  let r, g, b, a;\n  const colormap = this.colormap;\n  if (Array.isArray(colormap)) {\n    const maxIndex = colormap.length - 1;\n    const startIndex = Math.max(Math.floor(x * maxIndex), 0);\n    const endIndex = Math.min(startIndex + 1, maxIndex);\n    const innerRatio = x * maxIndex - startIndex;\n    const min = colormap[startIndex];\n    const max = colormap[endIndex];\n    r = min.r + innerRatio * (max.r - min.r);\n    g = min.g + innerRatio * (max.g - min.g);\n    b = min.b + innerRatio * (max.b - min.b);\n  } else if (typeof colormap === \"function\") {\n    ({ r, g, b, a } = colormap(x));\n  } else {\n    const hue = (1 - x) * 240;\n    ({ r, g, b } = util.HSVToRGB(hue / 360, 1, 1));\n  }\n  if (typeof a === \"number\" && !Number.isNaN(a)) {\n    return `RGBA(${Math.round(r * v)}, ${Math.round(g * v)}, ${Math.round(\n      b * v,\n    )}, ${a})`;\n  } else {\n    return `RGB(${Math.round(r * v)}, ${Math.round(g * v)}, ${Math.round(\n      b * v,\n    )})`;\n  }\n};\n\n/**\n * Determine the size of a point on-screen, as determined by the\n * distance to the camera.\n * @param {object} point\n * @param {number} [size] the size that needs to be translated to screen coordinates.\n *             optional; if not passed, use the default point size.\n * @returns {number}\n * @private\n */\nGraph3d.prototype._calcRadius = function (point, size) {\n  if (size === undefined) {\n    size = this._dotSize();\n  }\n\n  let radius;\n  if (this.showPerspective) {\n    radius = size / -point.trans.z;\n  } else {\n    radius = size * -(this.eye.z / this.camera.getArmLength());\n  }\n  if (radius < 0) {\n    radius = 0;\n  }\n\n  return radius;\n};\n\n// -----------------------------------------------------------------------------\n// Methods for drawing points per graph style.\n// -----------------------------------------------------------------------------\n\n/**\n * Draw single datapoint for graph style 'bar'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawBarGraphPoint = function (ctx, point) {\n  const xWidth = this.xBarWidth / 2;\n  const yWidth = this.yBarWidth / 2;\n  const colors = this._getColorsRegular(point);\n\n  this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);\n};\n\n/**\n * Draw single datapoint for graph style 'bar-color'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawBarColorGraphPoint = function (ctx, point) {\n  const xWidth = this.xBarWidth / 2;\n  const yWidth = this.yBarWidth / 2;\n  const colors = this._getColorsColor(point);\n\n  this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);\n};\n\n/**\n * Draw single datapoint for graph style 'bar-size'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawBarSizeGraphPoint = function (ctx, point) {\n  // calculate size for the bar\n  const fraction =\n    (point.point.value - this.valueRange.min) / this.valueRange.range();\n  const xWidth = (this.xBarWidth / 2) * (fraction * 0.8 + 0.2);\n  const yWidth = (this.yBarWidth / 2) * (fraction * 0.8 + 0.2);\n\n  const colors = this._getColorsSize();\n\n  this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);\n};\n\n/**\n * Draw single datapoint for graph style 'dot'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawDotGraphPoint = function (ctx, point) {\n  const colors = this._getColorsRegular(point);\n\n  this._drawCircle(ctx, point, colors.fill, colors.border);\n};\n\n/**\n * Draw single datapoint for graph style 'dot-line'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawDotLineGraphPoint = function (ctx, point) {\n  // draw a vertical line from the XY-plane to the graph value\n  const from = this._convert3Dto2D(point.bottom);\n  ctx.lineWidth = 1;\n  this._line(ctx, from, point.screen, this.gridColor);\n\n  this._redrawDotGraphPoint(ctx, point);\n};\n\n/**\n * Draw single datapoint for graph style 'dot-color'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawDotColorGraphPoint = function (ctx, point) {\n  const colors = this._getColorsColor(point);\n\n  this._drawCircle(ctx, point, colors.fill, colors.border);\n};\n\n/**\n * Draw single datapoint for graph style 'dot-size'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawDotSizeGraphPoint = function (ctx, point) {\n  const dotSize = this._dotSize();\n  const fraction =\n    (point.point.value - this.valueRange.min) / this.valueRange.range();\n\n  const sizeMin = dotSize * this.dotSizeMinFraction;\n  const sizeRange = dotSize * this.dotSizeMaxFraction - sizeMin;\n  const size = sizeMin + sizeRange * fraction;\n\n  const colors = this._getColorsSize();\n\n  this._drawCircle(ctx, point, colors.fill, colors.border, size);\n};\n\n/**\n * Draw single datapoint for graph style 'surface'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawSurfaceGraphPoint = function (ctx, point) {\n  const right = point.pointRight;\n  const top = point.pointTop;\n  const cross = point.pointCross;\n\n  if (\n    point === undefined ||\n    right === undefined ||\n    top === undefined ||\n    cross === undefined\n  ) {\n    return;\n  }\n\n  let topSideVisible = true;\n  let fillStyle;\n  let strokeStyle;\n  let cosViewAngle;\n\n  if (this.showGrayBottom || this.showShadow) {\n    // calculate the cross product of the two vectors from center\n    // to left and right, in order to know whether we are looking at the\n    // bottom or at the top side. We can also use the cross product\n    // for calculating light intensity\n    const aDiff = Point3d.subtract(cross.trans, point.trans);\n    const bDiff = Point3d.subtract(top.trans, right.trans);\n    const surfaceNormal = Point3d.crossProduct(aDiff, bDiff);\n\n    if (this.showPerspective) {\n      const surfacePosition = Point3d.avg(\n        Point3d.avg(point.trans, cross.trans),\n        Point3d.avg(right.trans, top.trans),\n      );\n      // This corresponds to diffuse lighting with light source at (0, 0, 0).\n      // More generally, we would need `surfacePosition - lightPosition`:\n      cosViewAngle = -Point3d.dotProduct(\n        surfaceNormal.normalize(),\n        surfacePosition.normalize(),\n      );\n    } else {\n      cosViewAngle = surfaceNormal.z / surfaceNormal.length();\n    }\n    topSideVisible = cosViewAngle > 0;\n  }\n\n  if (topSideVisible || !this.showGrayBottom) {\n    const vAvg =\n      (point.point.value +\n        right.point.value +\n        top.point.value +\n        cross.point.value) /\n      4;\n    const ratio = (vAvg - this.valueRange.min) * this.scale.value;\n    // lighting factor. TODO: let user specify lighting model as function(?)\n    const v = this.showShadow ? (1 + cosViewAngle) / 2 : 1;\n    fillStyle = this._colormap(ratio, v);\n  } else {\n    fillStyle = \"gray\";\n  }\n\n  if (this.showSurfaceGrid) {\n    strokeStyle = this.axisColor; // TODO: should be customizable\n  } else {\n    strokeStyle = fillStyle;\n  }\n\n  ctx.lineWidth = this._getStrokeWidth(point);\n  // TODO: only draw stroke when strokeWidth > 0\n\n  const points = [point, right, cross, top];\n  this._polygon(ctx, points, fillStyle, strokeStyle);\n};\n\n/**\n * Helper method for _redrawGridGraphPoint()\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} from\n * @param {object} to\n * @private\n */\nGraph3d.prototype._drawGridLine = function (ctx, from, to) {\n  if (from === undefined || to === undefined) {\n    return;\n  }\n\n  const vAvg = (from.point.value + to.point.value) / 2;\n  const f = (vAvg - this.valueRange.min) * this.scale.value;\n\n  ctx.lineWidth = this._getStrokeWidth(from) * 2;\n  ctx.strokeStyle = this._colormap(f, 1);\n  this._line(ctx, from.screen, to.screen);\n};\n\n/**\n * Draw single datapoint for graph style 'Grid'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawGridGraphPoint = function (ctx, point) {\n  this._drawGridLine(ctx, point, point.pointRight);\n  this._drawGridLine(ctx, point, point.pointTop);\n};\n\n/**\n * Draw single datapoint for graph style 'line'.\n * @param {CanvasRenderingContext2D} ctx\n * @param {object} point\n * @private\n */\nGraph3d.prototype._redrawLineGraphPoint = function (ctx, point) {\n  if (point.pointNext === undefined) {\n    return;\n  }\n\n  ctx.lineWidth = this._getStrokeWidth(point);\n  ctx.strokeStyle = this.dataColor.stroke;\n\n  this._line(ctx, point.screen, point.pointNext.screen);\n};\n\n/**\n * Draw all datapoints for currently selected graph style.\n *\n */\nGraph3d.prototype._redrawDataGraph = function () {\n  const ctx = this._getContext();\n  let i;\n\n  if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception?\n\n  this._calcTranslations(this.dataPoints);\n\n  for (i = 0; i < this.dataPoints.length; i++) {\n    const point = this.dataPoints[i];\n\n    // Using call() ensures that the correct context is used\n    this._pointDrawingMethod.call(this, ctx, point);\n  }\n};\n\n// -----------------------------------------------------------------------------\n// End methods for drawing points per graph style.\n// -----------------------------------------------------------------------------\n\n/**\n * Store startX, startY and startOffset for mouse operations\n * @param {Event}     event     The event that occurred\n */\nGraph3d.prototype._storeMousePosition = function (event) {\n  // get mouse position (different code for IE and all other browsers)\n  this.startMouseX = getMouseX(event);\n  this.startMouseY = getMouseY(event);\n\n  this._startCameraOffset = this.camera.getOffset();\n};\n\n/**\n * Start a moving operation inside the provided parent element\n * @param {Event}     event     The event that occurred (required for\n *                  retrieving the  mouse position)\n */\nGraph3d.prototype._onMouseDown = function (event) {\n  event = event || window.event;\n\n  // check if mouse is still down (may be up when focus is lost for example\n  // in an iframe)\n  if (this.leftButtonDown) {\n    this._onMouseUp(event);\n  }\n\n  // only react on left mouse button down\n  this.leftButtonDown = event.which ? event.which === 1 : event.button === 1;\n  if (!this.leftButtonDown && !this.touchDown) return;\n\n  this._storeMousePosition(event);\n\n  this.startStart = new Date(this.start);\n  this.startEnd = new Date(this.end);\n  this.startArmRotation = this.camera.getArmRotation();\n\n  this.frame.style.cursor = \"move\";\n\n  // add event listeners to handle moving the contents\n  // we store the function onmousemove and onmouseup in the graph, so we can\n  // remove the eventlisteners lateron in the function mouseUp()\n  const me = this;\n  this.onmousemove = function (event) {\n    me._onMouseMove(event);\n  };\n  this.onmouseup = function (event) {\n    me._onMouseUp(event);\n  };\n  document.addEventListener(\"mousemove\", me.onmousemove);\n  document.addEventListener(\"mouseup\", me.onmouseup);\n  util.preventDefault(event);\n};\n\n/**\n * Perform moving operating.\n * This function activated from within the funcion Graph.mouseDown().\n * @param {Event}   event  Well, eehh, the event\n */\nGraph3d.prototype._onMouseMove = function (event) {\n  this.moving = true;\n  event = event || window.event;\n\n  // calculate change in mouse position\n  const diffX = parseFloat(getMouseX(event)) - this.startMouseX;\n  const diffY = parseFloat(getMouseY(event)) - this.startMouseY;\n\n  // move with ctrl or rotate by other\n  if (event && event.ctrlKey === true) {\n    // calculate change in mouse position\n    const scaleX = this.frame.clientWidth * 0.5;\n    const scaleY = this.frame.clientHeight * 0.5;\n\n    const offXNew =\n      (this._startCameraOffset.x || 0) -\n      (diffX / scaleX) * this.camera.armLength * 0.8;\n    const offYNew =\n      (this._startCameraOffset.y || 0) +\n      (diffY / scaleY) * this.camera.armLength * 0.8;\n\n    this.camera.setOffset(offXNew, offYNew);\n    this._storeMousePosition(event);\n  } else {\n    let horizontalNew = this.startArmRotation.horizontal + diffX / 200;\n    let verticalNew = this.startArmRotation.vertical + diffY / 200;\n\n    const snapAngle = 4; // degrees\n    const snapValue = Math.sin((snapAngle / 360) * 2 * Math.PI);\n\n    // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc...\n    // the -0.001 is to take care that the vertical axis is always drawn at the left front corner\n    if (Math.abs(Math.sin(horizontalNew)) < snapValue) {\n      horizontalNew = Math.round(horizontalNew / Math.PI) * Math.PI - 0.001;\n    }\n    if (Math.abs(Math.cos(horizontalNew)) < snapValue) {\n      horizontalNew =\n        (Math.round(horizontalNew / Math.PI - 0.5) + 0.5) * Math.PI - 0.001;\n    }\n\n    // snap vertically to nice angles\n    if (Math.abs(Math.sin(verticalNew)) < snapValue) {\n      verticalNew = Math.round(verticalNew / Math.PI) * Math.PI;\n    }\n    if (Math.abs(Math.cos(verticalNew)) < snapValue) {\n      verticalNew = (Math.round(verticalNew / Math.PI - 0.5) + 0.5) * Math.PI;\n    }\n    this.camera.setArmRotation(horizontalNew, verticalNew);\n  }\n\n  this.redraw();\n\n  // fire a cameraPositionChange event\n  const parameters = this.getCameraPosition();\n  this.emit(\"cameraPositionChange\", parameters);\n\n  util.preventDefault(event);\n};\n\n/**\n * Stop moving operating.\n * This function activated from within the funcion Graph.mouseDown().\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onMouseUp = function (event) {\n  this.frame.style.cursor = \"auto\";\n  this.leftButtonDown = false;\n\n  // remove event listeners here\n  document.removeEventListener(\"mousemove\", this.onmousemove);\n  document.removeEventListener(\"mouseup\", this.onmouseup);\n\n  util.preventDefault(event);\n};\n\n/**\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onClick = function (event) {\n  // NOTE: onclick_callback is deprecated and may be removed in a future version.\n  if (!this.onclick_callback && !this.hasListeners(\"click\")) return;\n  if (!this.moving) {\n    const boundingRect = this.frame.getBoundingClientRect();\n    const mouseX = getMouseX(event) - boundingRect.left;\n    const mouseY = getMouseY(event) - boundingRect.top;\n    const dataPoint = this._dataPointFromXY(mouseX, mouseY);\n    if (dataPoint) {\n      if (this.onclick_callback) this.onclick_callback(dataPoint.point.data);\n      this.emit(\"click\", dataPoint.point.data);\n    }\n  } else {\n    // disable onclick callback, if it came immediately after rotate/pan\n    this.moving = false;\n  }\n  util.preventDefault(event);\n};\n\n/**\n * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point\n * @param {Event}  event   A mouse move event\n */\nGraph3d.prototype._onTooltip = function (event) {\n  const delay = this.tooltipDelay; // ms\n  const boundingRect = this.frame.getBoundingClientRect();\n  const mouseX = getMouseX(event) - boundingRect.left;\n  const mouseY = getMouseY(event) - boundingRect.top;\n\n  if (!this.showTooltip) {\n    return;\n  }\n\n  if (this.tooltipTimeout) {\n    clearTimeout(this.tooltipTimeout);\n  }\n\n  // (delayed) display of a tooltip only if no mouse button is down\n  if (this.leftButtonDown) {\n    this._hideTooltip();\n    return;\n  }\n\n  if (this.tooltip && this.tooltip.dataPoint) {\n    // tooltip is currently visible\n    const dataPoint = this._dataPointFromXY(mouseX, mouseY);\n    if (dataPoint !== this.tooltip.dataPoint) {\n      // datapoint changed\n      if (dataPoint) {\n        this._showTooltip(dataPoint);\n      } else {\n        this._hideTooltip();\n      }\n    }\n  } else {\n    // tooltip is currently not visible\n    const me = this;\n    this.tooltipTimeout = setTimeout(function () {\n      me.tooltipTimeout = null;\n\n      // show a tooltip if we have a data point\n      const dataPoint = me._dataPointFromXY(mouseX, mouseY);\n      if (dataPoint) {\n        me._showTooltip(dataPoint);\n      }\n    }, delay);\n  }\n};\n\n/**\n * Event handler for touchstart event on mobile devices\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onTouchStart = function (event) {\n  this.touchDown = true;\n\n  const me = this;\n  this.ontouchmove = function (event) {\n    me._onTouchMove(event);\n  };\n  this.ontouchend = function (event) {\n    me._onTouchEnd(event);\n  };\n  document.addEventListener(\"touchmove\", me.ontouchmove);\n  document.addEventListener(\"touchend\", me.ontouchend);\n\n  this._onMouseDown(event);\n};\n\n/**\n * Event handler for touchmove event on mobile devices\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onTouchMove = function (event) {\n  this._onMouseMove(event);\n};\n\n/**\n * Event handler for touchend event on mobile devices\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onTouchEnd = function (event) {\n  this.touchDown = false;\n\n  document.removeEventListener(\"touchmove\", this.ontouchmove);\n  document.removeEventListener(\"touchend\", this.ontouchend);\n\n  this._onMouseUp(event);\n};\n\n/**\n * Event handler for mouse wheel event, used to zoom the graph\n * Code from http://adomas.org/javascript-mouse-wheel/\n * @param {Event}  event   The event\n */\nGraph3d.prototype._onWheel = function (event) {\n  if (!event) /* For IE. */ event = window.event;\n  if (this.zoomable && (!this.ctrlToZoom || event.ctrlKey)) {\n    // retrieve delta\n    let delta = 0;\n    if (event.wheelDelta) {\n      /* IE/Opera. */\n      delta = event.wheelDelta / 120;\n    } else if (event.detail) {\n      /* Mozilla case. */\n      // In Mozilla, sign of delta is different than in IE.\n      // Also, delta is multiple of 3.\n      delta = -event.detail / 3;\n    }\n\n    // If delta is nonzero, handle it.\n    // Basically, delta is now positive if wheel was scrolled up,\n    // and negative, if wheel was scrolled down.\n    if (delta) {\n      const oldLength = this.camera.getArmLength();\n      const newLength = oldLength * (1 - delta / 10);\n\n      this.camera.setArmLength(newLength);\n      this.redraw();\n\n      this._hideTooltip();\n    }\n\n    // fire a cameraPositionChange event\n    const parameters = this.getCameraPosition();\n    this.emit(\"cameraPositionChange\", parameters);\n\n    // Prevent default actions caused by mouse wheel.\n    // That might be ugly, but we handle scrolls somehow\n    // anyway, so don't bother here..\n    util.preventDefault(event);\n  }\n};\n\n/**\n * Test whether a point lies inside given 2D triangle\n * @param   {vis.Point2d}   point\n * @param   {vis.Point2d[]} triangle\n * @returns {boolean}   true if given point lies inside or on the edge of the\n *                      triangle, false otherwise\n * @private\n */\nGraph3d.prototype._insideTriangle = function (point, triangle) {\n  const a = triangle[0],\n    b = triangle[1],\n    c = triangle[2];\n\n  /**\n   *\n   * @param {number} x\n   * @returns {number}\n   */\n  function sign(x) {\n    return x > 0 ? 1 : x < 0 ? -1 : 0;\n  }\n\n  const as = sign(\n    (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x),\n  );\n  const bs = sign(\n    (c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x),\n  );\n  const cs = sign(\n    (a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x),\n  );\n\n  // each of the three signs must be either equal to each other or zero\n  return (\n    (as == 0 || bs == 0 || as == bs) &&\n    (bs == 0 || cs == 0 || bs == cs) &&\n    (as == 0 || cs == 0 || as == cs)\n  );\n};\n\n/**\n * Find a data point close to given screen position (x, y)\n * @param   {number} x\n * @param   {number} y\n * @returns {object | null} The closest data point or null if not close to any\n *                          data point\n * @private\n */\nGraph3d.prototype._dataPointFromXY = function (x, y) {\n  const distMax = 100; // px\n  const center = new Point2d(x, y);\n  let i,\n    dataPoint = null,\n    closestDataPoint = null,\n    closestDist = null;\n\n  if (\n    this.style === Graph3d.STYLE.BAR ||\n    this.style === Graph3d.STYLE.BARCOLOR ||\n    this.style === Graph3d.STYLE.BARSIZE\n  ) {\n    // the data points are ordered from far away to closest\n    for (i = this.dataPoints.length - 1; i >= 0; i--) {\n      dataPoint = this.dataPoints[i];\n      const surfaces = dataPoint.surfaces;\n      if (surfaces) {\n        for (let s = surfaces.length - 1; s >= 0; s--) {\n          // split each surface in two triangles, and see if the center point is inside one of these\n          const surface = surfaces[s];\n          const corners = surface.corners;\n          const triangle1 = [\n            corners[0].screen,\n            corners[1].screen,\n            corners[2].screen,\n          ];\n          const triangle2 = [\n            corners[2].screen,\n            corners[3].screen,\n            corners[0].screen,\n          ];\n          if (\n            this._insideTriangle(center, triangle1) ||\n            this._insideTriangle(center, triangle2)\n          ) {\n            // return immediately at the first hit\n            return dataPoint;\n          }\n        }\n      }\n    }\n  } else {\n    // find the closest data point, using distance to the center of the point on 2d screen\n    for (i = 0; i < this.dataPoints.length; i++) {\n      dataPoint = this.dataPoints[i];\n      const point = dataPoint.screen;\n      if (point) {\n        const distX = Math.abs(x - point.x);\n        const distY = Math.abs(y - point.y);\n        const dist = Math.sqrt(distX * distX + distY * distY);\n\n        if ((closestDist === null || dist < closestDist) && dist < distMax) {\n          closestDist = dist;\n          closestDataPoint = dataPoint;\n        }\n      }\n    }\n  }\n\n  return closestDataPoint;\n};\n\n/**\n * Determine if the given style has bars\n * @param   {number} style the style to check\n * @returns {boolean} true if bar style, false otherwise\n */\nGraph3d.prototype.hasBars = function (style) {\n  return (\n    style == Graph3d.STYLE.BAR ||\n    style == Graph3d.STYLE.BARCOLOR ||\n    style == Graph3d.STYLE.BARSIZE\n  );\n};\n\n/**\n * Display a tooltip for given data point\n * @param {object} dataPoint\n * @private\n */\nGraph3d.prototype._showTooltip = function (dataPoint) {\n  let content, line, dot;\n\n  if (!this.tooltip) {\n    content = document.createElement(\"div\");\n    Object.assign(content.style, {}, this.tooltipStyle.content);\n    content.style.position = \"absolute\";\n\n    line = document.createElement(\"div\");\n    Object.assign(line.style, {}, this.tooltipStyle.line);\n    line.style.position = \"absolute\";\n\n    dot = document.createElement(\"div\");\n    Object.assign(dot.style, {}, this.tooltipStyle.dot);\n    dot.style.position = \"absolute\";\n\n    this.tooltip = {\n      dataPoint: null,\n      dom: {\n        content: content,\n        line: line,\n        dot: dot,\n      },\n    };\n  } else {\n    content = this.tooltip.dom.content;\n    line = this.tooltip.dom.line;\n    dot = this.tooltip.dom.dot;\n  }\n\n  this._hideTooltip();\n\n  this.tooltip.dataPoint = dataPoint;\n  if (typeof this.showTooltip === \"function\") {\n    content.innerHTML = this.showTooltip(dataPoint.point);\n  } else {\n    content.innerHTML =\n      \"<table>\" +\n      \"<tr><td>\" +\n      this.xLabel +\n      \":</td><td>\" +\n      dataPoint.point.x +\n      \"</td></tr>\" +\n      \"<tr><td>\" +\n      this.yLabel +\n      \":</td><td>\" +\n      dataPoint.point.y +\n      \"</td></tr>\" +\n      \"<tr><td>\" +\n      this.zLabel +\n      \":</td><td>\" +\n      dataPoint.point.z +\n      \"</td></tr>\" +\n      \"</table>\";\n  }\n\n  content.style.left = \"0\";\n  content.style.top = \"0\";\n  this.frame.appendChild(content);\n  this.frame.appendChild(line);\n  this.frame.appendChild(dot);\n\n  // calculate sizes\n  const contentWidth = content.offsetWidth;\n  const contentHeight = content.offsetHeight;\n  const lineHeight = line.offsetHeight;\n  const dotWidth = dot.offsetWidth;\n  const dotHeight = dot.offsetHeight;\n\n  let left = dataPoint.screen.x - contentWidth / 2;\n  left = Math.min(\n    Math.max(left, 10),\n    this.frame.clientWidth - 10 - contentWidth,\n  );\n\n  line.style.left = dataPoint.screen.x + \"px\";\n  line.style.top = dataPoint.screen.y - lineHeight + \"px\";\n  content.style.left = left + \"px\";\n  content.style.top = dataPoint.screen.y - lineHeight - contentHeight + \"px\";\n  dot.style.left = dataPoint.screen.x - dotWidth / 2 + \"px\";\n  dot.style.top = dataPoint.screen.y - dotHeight / 2 + \"px\";\n};\n\n/**\n * Hide the tooltip when displayed\n * @private\n */\nGraph3d.prototype._hideTooltip = function () {\n  if (this.tooltip) {\n    this.tooltip.dataPoint = null;\n\n    for (const prop in this.tooltip.dom) {\n      if (Object.prototype.hasOwnProperty.call(this.tooltip.dom, prop)) {\n        const elem = this.tooltip.dom[prop];\n        if (elem && elem.parentNode) {\n          elem.parentNode.removeChild(elem);\n        }\n      }\n    }\n  }\n};\n\n/**--------------------------------------------------------------------------**/\n\n/**\n * Get the horizontal mouse position from a mouse event\n * @param   {Event}  event\n * @returns {number} mouse x\n */\nfunction getMouseX(event) {\n  if (\"clientX\" in event) return event.clientX;\n  return (event.targetTouches[0] && event.targetTouches[0].clientX) || 0;\n}\n\n/**\n * Get the vertical mouse position from a mouse event\n * @param   {Event}  event\n * @returns {number} mouse y\n */\nfunction getMouseY(event) {\n  if (\"clientY\" in event) return event.clientY;\n  return (event.targetTouches[0] && event.targetTouches[0].clientY) || 0;\n}\n\n// -----------------------------------------------------------------------------\n//  Public methods for specific settings\n// -----------------------------------------------------------------------------\n\n/**\n * Set the rotation and distance of the camera\n * @param {object}  pos            An object with the camera position\n * @param {number} [pos.horizontal] The horizontal rotation, between 0 and 2*PI.\n *                                 Optional, can be left undefined.\n * @param {number} [pos.vertical]  The vertical rotation, between 0 and 0.5*PI.\n *                                 if vertical=0.5*PI, the graph is shown from\n *                                 the top. Optional, can be left undefined.\n * @param {number} [pos.distance]  The (normalized) distance of the camera to the\n *                                 center of the graph, a value between 0.71 and\n *                                 5.0. Optional, can be left undefined.\n */\nGraph3d.prototype.setCameraPosition = function (pos) {\n  setCameraPosition(pos, this);\n  this.redraw();\n};\n\n/**\n * Set a new size for the graph\n * @param {string} width  Width in pixels or percentage (for example '800px'\n *                        or '50%')\n * @param {string} height Height in pixels or percentage  (for example '400px'\n *                        or '30%')\n */\nGraph3d.prototype.setSize = function (width, height) {\n  this._setSize(width, height);\n  this.redraw();\n};\n\n// -----------------------------------------------------------------------------\n//  End public methods for specific settings\n// -----------------------------------------------------------------------------\n\nexport default Graph3d;\n"],"names":["Point3d","x","y","z","this","undefined","Point2d","Slider","container","options","Error","visible","frame","document","createElement","style","width","position","appendChild","prev","type","value","play","next","bar","border","height","borderRadius","MozBorderRadius","backgroundColor","slide","margin","left","me","onmousedown","event","_onMouseDown","onclick","togglePlay","onChangeCallback","values","index","playTimeout","playInterval","playLoop","StepNumber","start","end","step","prettyStep","_start","_end","_step","precision","_current","setRange","Camera","armLocation","armRotation","horizontal","vertical","armLength","cameraOffset","offsetMultiplier","cameraLocation","cameraRotation","Math","PI","calculateCameraOrientation","subtract","a","b","sub","add","sum","avg","scalarProduct","p","c","dotProduct","crossProduct","crossproduct","prototype","length","sqrt","normalize","getIndex","setIndex","playNext","Date","diff","interval","max","setTimeout","stop","clearInterval","setOnChangeCallback","callback","setPlayInterval","getPlayInterval","setPlayLoop","doLoop","onChange","redraw","top","clientHeight","offsetHeight","clientWidth","indexToLeft","setValues","get","which","button","startClientX","clientX","startSlideX","parseFloat","cursor","onmousemove","_onMouseMove","onmouseup","_onMouseUp","addEventListener","util","preventDefault","leftToIndex","round","removeEventListener","isNumeric","n","isNaN","isFinite","setStep","calculatePrettyStep","log10","log","LN10","step1","pow","step2","step5","abs","getCurrent","toPrecision","getStep","checkFirst","setOffset","sign","mul","getOffset","setArmLocation","setArmRotation","getArmRotation","rot","setArmLength","getArmLength","getCameraLocation","getCameraRotation","sin","cos","xa","za","dx","dy","STYLE","BAR","BARCOLOR","BARSIZE","DOT","DOTLINE","DOTCOLOR","DOTSIZE","GRID","LINE","SURFACE","STYLENAME","dot","line","grid","surface","OPTIONKEYS","PREFIXEDOPTIONKEYS","DEFAULTS","isEmpty","obj","prop","Object","hasOwnProperty","call","prefixFieldName","prefix","fieldName","str","charAt","toUpperCase","slice","forceCopy","src","dst","fields","srcKey","dstKey","i","safeCopy","setSpecialSettings","fill","stroke","strokeWidth","borderColor","borderWidth","borderStyle","setBackgroundColor","dataColor","setDataColor","styleNumber","styleName","number","getStyleNumberByName","valid","checkStyleNumber","setStyle","surfaceColors","console","warn","colormap","rgbColors","Array","isArray","parseColorArray","parseColorObject","hue","reverse","setSurfaceColor","setColormap","showLegend","isLegendGraphStyle","setShowLegend","setCameraPosition","cameraPosition","tooltip","showTooltip","onclick_callback","tooltipStyle","selectiveDeepExtend","map","colorCode","isValidHex","hexToRGB","hues","saturation","brightness","colorStops","hueStep","push","HSVToRGB","camPos","camera","distance","string","bool","object","array","colorOptions","__type__","allOptions","animationAutoStart","boolean","animationInterval","animationPreload","axisColor","axisFontSize","axisFontType","xBarWidth","yBarWidth","zoomable","ctrlToZoom","xCenter","yCenter","function","dotSizeMinFraction","dotSizeMaxFraction","dotSizeRatio","filterLabel","gridColor","keepAspectRatio","xLabel","yLabel","zLabel","legendLabel","xMin","yMin","zMin","xMax","yMax","zMax","showAnimationControls","showGrayBottom","showGrid","showPerspective","showShadow","showSurfaceGrid","showXAxis","showYAxis","showZAxis","rotateAxisLabels","xStep","yStep","zStep","tooltipDelay","content","color","background","boxShadow","padding","borderLeft","pointerEvents","xValueLabel","yValueLabel","zValueLabel","valueMax","valueMin","verticalRatio","Range","min","Filter","dataGroup","column","graph","getDistinctValues","selectValue","dataPoints","loaded","onLoadCallback","loadInBackground","DataGroup","dataTable","adjust","combine","range","expand","val","newMin","newMax","center","isLoaded","getLoadedProgress","len","getLabel","getColumn","getSelectedValue","getValues","getValue","_getDataPoints","f","dataView","DataView","getDataSet","filter","item","setOnLoadCallback","progress","innerHTML","bottom","removeChild","initializeData","graph3d","rawData","data","DataSet","dataSet","off","_onChange","setData","on","colX","colY","colZ","withBars","hasBars","defaultXBarWidth","getSmallestDifference","defaultYBarWidth","_initializeRange","colValue","valueRange","getColumnRange","_setRangeDefaults","defaultValueMin","defaultValueMax","zRange","table","getDataTable","dataFilter","_collectRangeSettings","indexOf","upper","barWidth","range_label","step_label","settings","sort","smallest_diff","getNumberOfRows","defaultMin","defaultMax","getDataPoints","point","trans","screen","initDataAsMatrix","dataX","dataY","dataMatrix","xIndex","yIndex","pointRight","pointTop","pointCross","getInfo","reload","pointNext","Graph3d","autoByDefault","SyntaxError","containerElement","create","eye","setDefaults","setOptions","getMouseX","targetTouches","getMouseY","clientY","v","Emitter","_setScale","scale","xRange","yRange","zCenter","_convert3Dto2D","point3d","translation","_convertPointToTranslation","_convertTranslationToScreen","ax","ay","az","cx","cy","cz","sinTx","cosTx","sinTy","cosTy","sinTz","cosTz","ex","ey","ez","dz","bx","by","currentXCenter","canvas","currentYCenter","_calcTranslations","points","transBottom","dist","_initializeRanges","dg","hasChildNodes","firstChild","overflow","noCanvas","fontWeight","_onTouchStart","_onWheel","_onTooltip","_onClick","_setSize","_resizeCanvas","animationStart","slider","animationStop","_resizeCenter","getCameraPosition","pos","_readData","_redrawFilter","Validator","validate","error","VALIDATOR_PRINT_STYLE","setPointDrawingMethod","setAxisLabelMethod","method","_redrawBarGraphPoint","_redrawBarColorGraphPoint","_redrawBarSizeGraphPoint","_redrawDotGraphPoint","_redrawDotLineGraphPoint","_redrawDotColorGraphPoint","_redrawDotSizeGraphPoint","_redrawSurfaceGraphPoint","_redrawGridGraphPoint","_redrawLineGraphPoint","_pointDrawingMethod","_drawAxisLabelX","drawAxisLabelXRotate","_drawAxisLabelY","drawAxisLabelYRotate","_drawAxisLabelZ","drawAxisLabelZRotate","drawAxisLabelX","drawAxisLabelY","drawAxisLabelZ","_redrawSlider","_redrawClear","_redrawAxis","_redrawDataGraph","_redrawInfo","_redrawLegend","_getContext","ctx","getContext","lineJoin","lineCap","clearRect","_dotSize","_getLegendWidth","isSizeLegend","isValueLegend","right","lineWidth","font","ymin","ymax","_colormap","strokeStyle","beginPath","moveTo","lineTo","strokeRect","widthMin","fillStyle","closePath","legendMin","legendMax","from","to","_line","textAlign","textBaseline","fillText","label","info","lineStyle","text","armAngle","yMargin","point2d","offset","save","translate","rotate","restore","_line3d","from2d","to2d","xText","yText","zText","xOffset","yOffset","gridLenX","gridLenY","textMargin","armVector","defaultXStep","msg","defaultYStep","defaultZStep","from3d","xMin2d","xMax2d","_getStrokeWidth","_redrawBar","xWidth","yWidth","forEach","surfaces","corners","j","transCenter","_polygon","_drawCircle","size","radius","_calcRadius","arc","_getColorsRegular","_getColorsColor","pointStyle","_getColorsSize","r","g","maxIndex","startIndex","floor","endIndex","innerRatio","Number","colors","fraction","dotSize","sizeMin","cross","cosViewAngle","topSideVisible","aDiff","bDiff","surfaceNormal","surfacePosition","ratio","_drawGridLine","_storeMousePosition","startMouseX","startMouseY","_startCameraOffset","window","leftButtonDown","touchDown","startStart","startEnd","startArmRotation","moving","diffX","diffY","ctrlKey","scaleX","scaleY","offXNew","offYNew","horizontalNew","verticalNew","snapAngle","snapValue","parameters","emit","hasListeners","boundingRect","getBoundingClientRect","mouseX","mouseY","dataPoint","_dataPointFromXY","delay","tooltipTimeout","clearTimeout","_hideTooltip","_showTooltip","ontouchmove","_onTouchMove","ontouchend","_onTouchEnd","delta","wheelDelta","detail","newLength","_insideTriangle","triangle","as","bs","cs","closestDataPoint","closestDist","s","triangle1","triangle2","distX","distY","dom","assign","contentWidth","offsetWidth","contentHeight","lineHeight","dotWidth","dotHeight","elem","parentNode","setSize"],"mappings":"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"}