let util = require('../../util');
							 | 
						|
								
							 | 
						|
								import NavigationHandler from "./components/NavigationHandler"
							 | 
						|
								import Popup             from "./components/Popup"
							 | 
						|
								
							 | 
						|
								class InteractionHandler {
							 | 
						|
								  constructor(body, canvas, selectionHandler) {
							 | 
						|
								    this.body = body;
							 | 
						|
								    this.canvas = canvas;
							 | 
						|
								    this.selectionHandler = selectionHandler;
							 | 
						|
								    this.navigationHandler = new NavigationHandler(body,canvas);
							 | 
						|
								
							 | 
						|
								    // bind the events from hammer to functions in this object
							 | 
						|
								    this.body.eventListeners.onTap        = this.onTap.bind(this);
							 | 
						|
								    this.body.eventListeners.onTouch      = this.onTouch.bind(this);
							 | 
						|
								    this.body.eventListeners.onDoubleTap  = this.onDoubleTap.bind(this);
							 | 
						|
								    this.body.eventListeners.onHold       = this.onHold.bind(this);
							 | 
						|
								    this.body.eventListeners.onDragStart  = this.onDragStart.bind(this);
							 | 
						|
								    this.body.eventListeners.onDrag       = this.onDrag.bind(this);
							 | 
						|
								    this.body.eventListeners.onDragEnd    = this.onDragEnd.bind(this);
							 | 
						|
								    this.body.eventListeners.onMouseWheel = this.onMouseWheel.bind(this);
							 | 
						|
								    this.body.eventListeners.onPinch      = this.onPinch.bind(this);
							 | 
						|
								    this.body.eventListeners.onMouseMove  = this.onMouseMove.bind(this);
							 | 
						|
								    this.body.eventListeners.onRelease    = this.onRelease.bind(this);
							 | 
						|
								
							 | 
						|
								    this.touchTime = 0;
							 | 
						|
								    this.drag = {};
							 | 
						|
								    this.pinch = {};
							 | 
						|
								    this.hoverObj = {nodes:{},edges:{}};
							 | 
						|
								    this.popup = undefined;
							 | 
						|
								    this.popupObj = undefined;
							 | 
						|
								    this.popupTimer = undefined;
							 | 
						|
								
							 | 
						|
								    this.body.functions.getPointer = this.getPointer.bind(this);
							 | 
						|
								
							 | 
						|
								    this.options = {};
							 | 
						|
								    this.defaultOptions = {
							 | 
						|
								      dragNodes:true,
							 | 
						|
								      dragView: true,
							 | 
						|
								      zoomView: true,
							 | 
						|
								      hoverEnabled: false,
							 | 
						|
								      navigationButtons: false,
							 | 
						|
								      tooltip: {
							 | 
						|
								        delay: 300,
							 | 
						|
								        fontColor: '#000000',
							 | 
						|
								        fontSize: 14, // px
							 | 
						|
								        fontFace: 'verdana',
							 | 
						|
								        color: {
							 | 
						|
								          border: '#666666',
							 | 
						|
								          background: '#FFFFC6'
							 | 
						|
								        }
							 | 
						|
								      },
							 | 
						|
								      keyboard: {
							 | 
						|
								        enabled: false,
							 | 
						|
								        speed: {x: 10, y: 10, zoom: 0.02},
							 | 
						|
								        bindToWindow: true
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    util.extend(this.options,this.defaultOptions);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  setOptions(options) {
							 | 
						|
								    if (options !== undefined) {
							 | 
						|
								      // extend all but the values in fields
							 | 
						|
								      let fields = ['keyboard','tooltip'];
							 | 
						|
								      util.selectiveNotDeepExtend(fields,this.options, options);
							 | 
						|
								
							 | 
						|
								      // merge the keyboard options in.
							 | 
						|
								      util.mergeOptions(this.options, options, 'keyboard');
							 | 
						|
								
							 | 
						|
								      if (options.tooltip) {
							 | 
						|
								        util.extend(this.options.tooltip, options.tooltip);
							 | 
						|
								        if (options.tooltip.color) {
							 | 
						|
								          this.options.tooltip.color = util.parseColor(options.tooltip.color);
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    this.navigationHandler.setOptions(this.options);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Get the pointer location from a touch location
							 | 
						|
								   * @param {{x: Number, y: Number}} touch
							 | 
						|
								   * @return {{x: Number, y: Number}} pointer
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  getPointer(touch) {
							 | 
						|
								    return {
							 | 
						|
								      x: touch.x - util.getAbsoluteLeft(this.canvas.frame.canvas),
							 | 
						|
								      y: touch.y - util.getAbsoluteTop(this.canvas.frame.canvas)
							 | 
						|
								    };
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * On start of a touch gesture, store the pointer
							 | 
						|
								   * @param event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onTouch(event) {
							 | 
						|
								    if (new Date().valueOf() - this.touchTime > 100) {
							 | 
						|
								      this.drag.pointer = this.getPointer(event.center);
							 | 
						|
								      this.drag.pinched = false;
							 | 
						|
								      this.pinch.scale = this.body.view.scale;
							 | 
						|
								      // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
							 | 
						|
								      this.touchTime = new Date().valueOf();
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle tap/click event: select/unselect a node
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onTap(event) {
							 | 
						|
								    let pointer = this.getPointer(event.center);
							 | 
						|
								
							 | 
						|
								    let previouslySelected = this.selectionHandler._getSelectedObjectCount() > 0;
							 | 
						|
								    let selected = this.selectionHandler.selectOnPoint(pointer);
							 | 
						|
								
							 | 
						|
								    if (selected === true || (previouslySelected === true && selected === false)) { // select or unselect
							 | 
						|
								      this.body.emitter.emit('select', this.selectionHandler.getSelection());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    this.selectionHandler._generateClickEvent("click",pointer);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle doubletap event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onDoubleTap(event) {
							 | 
						|
								    let pointer = this.getPointer(event.center);
							 | 
						|
								    this.selectionHandler._generateClickEvent("doubleClick",pointer);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle long tap event: multi select nodes
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onHold(event) {
							 | 
						|
								    let pointer = this.getPointer(event.center);
							 | 
						|
								
							 | 
						|
								    let selectionChanged = this.selectionHandler.selectAdditionalOnPoint(pointer);
							 | 
						|
								
							 | 
						|
								    if (selectionChanged === true) { // select or longpress
							 | 
						|
								      this.body.emitter.emit('select', this.selectionHandler.getSelection());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    this.selectionHandler._generateClickEvent("click",pointer);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle the release of the screen
							 | 
						|
								   *
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onRelease(event) {
							 | 
						|
								    this.body.emitter.emit("release",event)
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * This function is called by onDragStart.
							 | 
						|
								   * It is separated out because we can then overload it for the datamanipulation system.
							 | 
						|
								   *
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onDragStart(event) {
							 | 
						|
								    //in case the touch event was triggered on an external div, do the initial touch now.
							 | 
						|
								    if (this.drag.pointer === undefined) {
							 | 
						|
								      this.onTouch(event);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // note: drag.pointer is set in onTouch to get the initial touch location
							 | 
						|
								    let node = this.selectionHandler.getNodeAt(this.drag.pointer);
							 | 
						|
								
							 | 
						|
								    this.drag.dragging = true;
							 | 
						|
								    this.drag.selection = [];
							 | 
						|
								    this.drag.translation = util.extend({},this.body.view.translation); // copy the object
							 | 
						|
								    this.drag.nodeId = undefined;
							 | 
						|
								
							 | 
						|
								    this.body.emitter.emit("dragStart", {nodeIds: this.selectionHandler.getSelection().nodes});
							 | 
						|
								
							 | 
						|
								    if (node !== undefined && this.options.dragNodes === true) {
							 | 
						|
								      this.drag.nodeId = node.id;
							 | 
						|
								      // select the clicked node if not yet selected
							 | 
						|
								      if (node.isSelected() === false) {
							 | 
						|
								        this.selectionHandler.unselectAll();
							 | 
						|
								        this.selectionHandler.selectObject(node);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      let selection = this.selectionHandler.selectionObj.nodes;
							 | 
						|
								      // create an array with the selected nodes and their original location and status
							 | 
						|
								      for (let nodeId in selection) {
							 | 
						|
								        if (selection.hasOwnProperty(nodeId)) {
							 | 
						|
								          let object = selection[nodeId];
							 | 
						|
								          let s = {
							 | 
						|
								            id: object.id,
							 | 
						|
								            node: object,
							 | 
						|
								
							 | 
						|
								            // store original x, y, xFixed and yFixed, make the node temporarily Fixed
							 | 
						|
								            x: object.x,
							 | 
						|
								            y: object.y,
							 | 
						|
								            xFixed: object.options.fixed.x,
							 | 
						|
								            yFixed: object.options.fixed.y
							 | 
						|
								          };
							 | 
						|
								
							 | 
						|
								          object.options.fixed.x = true;
							 | 
						|
								          object.options.fixed.y = true;
							 | 
						|
								
							 | 
						|
								          this.drag.selection.push(s);
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle drag event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onDrag(event) {
							 | 
						|
								    if (this.drag.pinched === true) {
							 | 
						|
								      return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // remove the focus on node if it is focussed on by the focusOnNode
							 | 
						|
								    this.body.emitter.emit("unlockNode");
							 | 
						|
								
							 | 
						|
								    let pointer = this.getPointer(event.center);
							 | 
						|
								    let selection = this.drag.selection;
							 | 
						|
								    if (selection && selection.length && this.options.dragNodes === true) {
							 | 
						|
								      // calculate delta's and new location
							 | 
						|
								      let deltaX = pointer.x - this.drag.pointer.x;
							 | 
						|
								      let deltaY = pointer.y - this.drag.pointer.y;
							 | 
						|
								
							 | 
						|
								      // update position of all selected nodes
							 | 
						|
								      selection.forEach((selection) => {
							 | 
						|
								        let node = selection.node;
							 | 
						|
								        // only move the node if it was not fixed initially
							 | 
						|
								        if (selection.xFixed === false) {
							 | 
						|
								          node.x = this.canvas._XconvertDOMtoCanvas(this.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
							 | 
						|
								        }
							 | 
						|
								        // only move the node if it was not fixed initially
							 | 
						|
								        if (selection.yFixed === false) {
							 | 
						|
								          node.y = this.canvas._YconvertDOMtoCanvas(this.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
							 | 
						|
								        }
							 | 
						|
								      });
							 | 
						|
								
							 | 
						|
								      // start the simulation of the physics
							 | 
						|
								      this.body.emitter.emit("startSimulation");
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      // move the network
							 | 
						|
								      if (this.options.dragView === true) {
							 | 
						|
								        // if the drag was not started properly because the click started outside the network div, start it now.
							 | 
						|
								        if (this.drag.pointer === undefined) {
							 | 
						|
								          this._handleDragStart(event);
							 | 
						|
								          return;
							 | 
						|
								        }
							 | 
						|
								        let diffX = pointer.x - this.drag.pointer.x;
							 | 
						|
								        let diffY = pointer.y - this.drag.pointer.y;
							 | 
						|
								
							 | 
						|
								        this.body.view.translation = {x:this.drag.translation.x + diffX, y:this.drag.translation.y + diffY};
							 | 
						|
								        this.body.emitter.emit("_redraw");
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * handle drag start event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onDragEnd(event) {
							 | 
						|
								    this.drag.dragging = false;
							 | 
						|
								    let selection = this.drag.selection;
							 | 
						|
								    if (selection && selection.length) {
							 | 
						|
								      selection.forEach(function (s) {
							 | 
						|
								        // restore original xFixed and yFixed
							 | 
						|
								        s.node.options.fixed.x = s.xFixed;
							 | 
						|
								        s.node.options.fixed.y = s.yFixed;
							 | 
						|
								      });
							 | 
						|
								      this.body.emitter.emit("startSimulation");
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      this.body.emitter.emit("_requestRedraw");
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    this.body.emitter.emit("dragEnd", {nodeIds: this.selectionHandler.getSelection().nodes});
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Handle pinch event
							 | 
						|
								   * @param event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onPinch(event) {
							 | 
						|
								    let pointer = this.getPointer(event.center);
							 | 
						|
								
							 | 
						|
								    this.drag.pinched = true;
							 | 
						|
								    if (this.pinch['scale'] === undefined) {
							 | 
						|
								      this.pinch.scale = 1;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // TODO: enabled moving while pinching?
							 | 
						|
								    let scale = this.pinch.scale * event.scale;
							 | 
						|
								    this.zoom(scale, pointer)
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Zoom the network in or out
							 | 
						|
								   * @param {Number} scale a number around 1, and between 0.01 and 10
							 | 
						|
								   * @param {{x: Number, y: Number}} pointer    Position on screen
							 | 
						|
								   * @return {Number} appliedScale    scale is limited within the boundaries
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  zoom(scale, pointer) {
							 | 
						|
								    if (this.options.zoomView === true) {
							 | 
						|
								      let scaleOld = this.body.view.scale;
							 | 
						|
								      if (scale < 0.00001) {
							 | 
						|
								        scale = 0.00001;
							 | 
						|
								      }
							 | 
						|
								      if (scale > 10) {
							 | 
						|
								        scale = 10;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      let preScaleDragPointer = undefined;
							 | 
						|
								      if (this.drag !== undefined) {
							 | 
						|
								        if (this.drag.dragging === true) {
							 | 
						|
								          preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								      // + this.canvas.frame.canvas.clientHeight / 2
							 | 
						|
								      let translation = this.body.view.translation;
							 | 
						|
								
							 | 
						|
								      let scaleFrac = scale / scaleOld;
							 | 
						|
								      let tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
							 | 
						|
								      let ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
							 | 
						|
								
							 | 
						|
								      this.body.view.scale = scale;
							 | 
						|
								      this.body.view.translation = {x:tx, y:ty};
							 | 
						|
								
							 | 
						|
								      if (preScaleDragPointer != undefined) {
							 | 
						|
								        let postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
							 | 
						|
								        this.drag.pointer.x = postScaleDragPointer.x;
							 | 
						|
								        this.drag.pointer.y = postScaleDragPointer.y;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      this.body.emitter.emit("_requestRedraw");
							 | 
						|
								
							 | 
						|
								      if (scaleOld < scale) {
							 | 
						|
								        this.body.emitter.emit("zoom", {direction: "+"});
							 | 
						|
								      }
							 | 
						|
								      else {
							 | 
						|
								        this.body.emitter.emit("zoom", {direction: "-"});
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Event handler for mouse wheel event, used to zoom the timeline
							 | 
						|
								   * See http://adomas.org/javascript-mouse-wheel/
							 | 
						|
								   *     https://github.com/EightMedia/hammer.js/issues/256
							 | 
						|
								   * @param {MouseEvent}  event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onMouseWheel(event) {
							 | 
						|
								    // retrieve delta
							 | 
						|
								    let delta = 0;
							 | 
						|
								    if (event.wheelDelta) { /* IE/Opera. */
							 | 
						|
								      delta = event.wheelDelta / 120;
							 | 
						|
								    } else if (event.detail) { /* Mozilla case. */
							 | 
						|
								      // In Mozilla, sign of delta is different than in IE.
							 | 
						|
								      // Also, delta is multiple of 3.
							 | 
						|
								      delta = -event.detail / 3;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // If delta is nonzero, handle it.
							 | 
						|
								    // Basically, delta is now positive if wheel was scrolled up,
							 | 
						|
								    // and negative, if wheel was scrolled down.
							 | 
						|
								    if (delta !== 0) {
							 | 
						|
								
							 | 
						|
								      // calculate the new scale
							 | 
						|
								      let scale = this.body.view.scale;
							 | 
						|
								      let zoom = delta / 10;
							 | 
						|
								      if (delta < 0) {
							 | 
						|
								        zoom = zoom / (1 - zoom);
							 | 
						|
								      }
							 | 
						|
								      scale *= (1 + zoom);
							 | 
						|
								
							 | 
						|
								      // calculate the pointer location
							 | 
						|
								      let pointer = this.getPointer({x:event.pageX, y:event.pageY});
							 | 
						|
								
							 | 
						|
								      // apply the new scale
							 | 
						|
								      this.zoom(scale, pointer);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Prevent default actions caused by mouse wheel.
							 | 
						|
								    event.preventDefault();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Mouse move handler for checking whether the title moves over a node with a title.
							 | 
						|
								   * @param  {Event} event
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								  onMouseMove(event) {
							 | 
						|
								    let pointer = this.getPointer({x:event.pageX, y:event.pageY});
							 | 
						|
								    let popupVisible = false;
							 | 
						|
								
							 | 
						|
								    // check if the previously selected node is still selected
							 | 
						|
								    if (this.popup !== undefined) {
							 | 
						|
								      if (this.popup.hidden === false) {
							 | 
						|
								        this._checkHidePopup(pointer);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // if the popup was not hidden above
							 | 
						|
								      if (this.popup.hidden === false) {
							 | 
						|
								        popupVisible = true;
							 | 
						|
								        this.popup.setPosition(pointer.x + 3, pointer.y - 5)
							 | 
						|
								        this.popup.show();
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
							 | 
						|
								    if (this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
							 | 
						|
								      this.canvas.frame.focus();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // start a timeout that will check if the mouse is positioned above an element
							 | 
						|
								    if (popupVisible === false) {
							 | 
						|
								      if (this.popupTimer !== undefined) {
							 | 
						|
								        clearInterval(this.popupTimer); // stop any running calculationTimer
							 | 
						|
								        this.popupTimer = undefined;
							 | 
						|
								      }
							 | 
						|
								      if (!this.drag.dragging) {
							 | 
						|
								        this.popupTimer = setTimeout(() => this._checkShowPopup(pointer), this.options.tooltip.delay);
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								    * Adding hover highlights
							 | 
						|
								    */
							 | 
						|
								    if (this.options.hoverEnabled === true) {
							 | 
						|
								      // removing all hover highlights
							 | 
						|
								      for (let edgeId in this.hoverObj.edges) {
							 | 
						|
								        if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
							 | 
						|
								          this.hoverObj.edges[edgeId].hover = false;
							 | 
						|
								          delete this.hoverObj.edges[edgeId];
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // adding hover highlights
							 | 
						|
								      let obj = this.selectionHandler.getNodeAt(pointer);
							 | 
						|
								      if (obj === undefined) {
							 | 
						|
								        obj = this.selectionHandler.getEdgeAt(pointer);
							 | 
						|
								      }
							 | 
						|
								      if (obj != undefined) {
							 | 
						|
								        this.selectionHandler.hoverObject(obj);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // removing all node hover highlights except for the selected one.
							 | 
						|
								      for (let nodeId in this.hoverObj.nodes) {
							 | 
						|
								        if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
							 | 
						|
								          if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj === undefined) {
							 | 
						|
								            this.selectionHandler.blurObject(this.hoverObj.nodes[nodeId]);
							 | 
						|
								            delete this.hoverObj.nodes[nodeId];
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								      this.body.emitter.emit("_requestRedraw");
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Check if there is an element on the given position in the network
							 | 
						|
								   * (a node or edge). If so, and if this element has a title,
							 | 
						|
								   * show a popup window with its title.
							 | 
						|
								   *
							 | 
						|
								   * @param {{x:Number, y:Number}} pointer
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								 _checkShowPopup(pointer) {
							 | 
						|
								    let x = this.canvas._XconvertDOMtoCanvas(pointer.x);
							 | 
						|
								    let y = this.canvas._YconvertDOMtoCanvas(pointer.y);
							 | 
						|
								    let pointerObj = {
							 | 
						|
								      left:   x,
							 | 
						|
								      top:    y,
							 | 
						|
								      right:  x,
							 | 
						|
								      bottom: y
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    let previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
							 | 
						|
								    let nodeUnderCursor = false;
							 | 
						|
								    let popupType = "node";
							 | 
						|
								
							 | 
						|
								    // check if a node is under the cursor.
							 | 
						|
								    if (this.popupObj === undefined) {
							 | 
						|
								      // search the nodes for overlap, select the top one in case of multiple nodes
							 | 
						|
								      let nodeIndices = this.body.nodeIndices;
							 | 
						|
								      let nodes = this.body.nodes;
							 | 
						|
								      let node;
							 | 
						|
								      let overlappingNodes = [];
							 | 
						|
								      for (let i = 0; i < nodeIndices.length; i++) {
							 | 
						|
								        node = nodes[nodeIndices[i]];
							 | 
						|
								        if (node.isOverlappingWith(pointerObj) === true) {
							 | 
						|
								          if (node.getTitle() !== undefined) {
							 | 
						|
								            overlappingNodes.push(nodeIndices[i]);
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      if (overlappingNodes.length > 0) {
							 | 
						|
								        // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
							 | 
						|
								        this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]];
							 | 
						|
								        // if you hover over a node, the title of the edge is not supposed to be shown.
							 | 
						|
								        nodeUnderCursor = true;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (this.popupObj === undefined && nodeUnderCursor === false) {
							 | 
						|
								      // search the edges for overlap
							 | 
						|
								      let edgeIndices = this.body.edgeIndices;
							 | 
						|
								      let edges = this.body.edges;
							 | 
						|
								      let edge;
							 | 
						|
								      let overlappingEdges = [];
							 | 
						|
								      for (let i = 0; i < edgeIndices.length; i++) {
							 | 
						|
								        edge = edges[edgeIndices[i]];
							 | 
						|
								        if (edge.isOverlappingWith(pointerObj) === true) {
							 | 
						|
								          if (edge.connected === true && edge.getTitle() !== undefined) {
							 | 
						|
								            overlappingEdges.push(edgeIndices[i]);
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      if (overlappingEdges.length > 0) {
							 | 
						|
								        this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
							 | 
						|
								        popupType = "edge";
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (this.popupObj !== undefined) {
							 | 
						|
								      // show popup message window
							 | 
						|
								      if (this.popupObj.id !== previousPopupObjId) {
							 | 
						|
								        if (this.popup === undefined) {
							 | 
						|
								          this.popup = new Popup(this.frame, this.options.tooltip);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        this.popup.popupTargetType = popupType;
							 | 
						|
								        this.popup.popupTargetId = this.popupObj.id;
							 | 
						|
								
							 | 
						|
								        // adjust a small offset such that the mouse cursor is located in the
							 | 
						|
								        // bottom left location of the popup, and you can easily move over the
							 | 
						|
								        // popup area
							 | 
						|
								        this.popup.setPosition(pointer.x + 3, pointer.y - 5);
							 | 
						|
								        this.popup.setText(this.popupObj.getTitle());
							 | 
						|
								        this.popup.show();
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      if (this.popup) {
							 | 
						|
								        this.popup.hide();
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Check if the popup must be hidden, which is the case when the mouse is no
							 | 
						|
								   * longer hovering on the object
							 | 
						|
								   * @param {{x:Number, y:Number}} pointer
							 | 
						|
								   * @private
							 | 
						|
								   */
							 | 
						|
								 _checkHidePopup(pointer) {
							 | 
						|
								    let x = this.canvas._XconvertDOMtoCanvas(pointer.x);
							 | 
						|
								    let y = this.canvas._YconvertDOMtoCanvas(pointer.y);
							 | 
						|
								    let pointerObj = {
							 | 
						|
								      left:   x,
							 | 
						|
								      top:    y,
							 | 
						|
								      right:  x,
							 | 
						|
								      bottom: y
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    let stillOnObj = false;
							 | 
						|
								    if (this.popup.popupTargetType === 'node') {
							 | 
						|
								      if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
							 | 
						|
								        stillOnObj = this.body.nodes[this.popup.popupTargetId].isOverlappingWith(pointerObj);
							 | 
						|
								
							 | 
						|
								        // if the mouse is still one the node, we have to check if it is not also on one that is drawn on top of it.
							 | 
						|
								        // we initially only check stillOnObj because this is much faster.
							 | 
						|
								        if (stillOnObj === true) {
							 | 
						|
								          let overNode = this.selectionHandler.getNodeAt(pointer);
							 | 
						|
								          stillOnObj = overNode.id === this.popup.popupTargetId;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								      if (this.selectionHandler.getNodeAt(pointer) === undefined) {
							 | 
						|
								        if (this.body.edges[this.popup.popupTargetId] !== undefined) {
							 | 
						|
								          stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    if (stillOnObj === false) {
							 | 
						|
								      this.popupObj = undefined;
							 | 
						|
								      this.popup.hide();
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								export default InteractionHandler;
							 |