|
@ -0,0 +1,985 @@ |
|
|
|
|
|
|
|
|
|
|
|
let util = require('../../util'); |
|
|
|
|
|
let Hammer = require('../../module/hammer'); |
|
|
|
|
|
let hammerUtil = require('../../hammerUtil'); |
|
|
|
|
|
let locales = require('../locales'); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* clears the toolbar div element of children |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
class ManipulationSystem { |
|
|
|
|
|
constructor(body, canvas, selectionHandler) { |
|
|
|
|
|
this.body = body; |
|
|
|
|
|
this.canvas = canvas; |
|
|
|
|
|
this.selectionHandler = selectionHandler; |
|
|
|
|
|
|
|
|
|
|
|
this.editMode = false; |
|
|
|
|
|
this.manipulationDiv = undefined; |
|
|
|
|
|
this.editModeDiv = undefined; |
|
|
|
|
|
this.closeDiv = undefined; |
|
|
|
|
|
this.boundFunction = undefined; |
|
|
|
|
|
this.manipulationHammers = []; |
|
|
|
|
|
this.cachedFunctions = {}; |
|
|
|
|
|
this.touchTime = 0; |
|
|
|
|
|
this.temporaryIds = {nodes: [], edges:[]}; |
|
|
|
|
|
this.guiEnabled = false; |
|
|
|
|
|
this.selectedControlNode = undefined; |
|
|
|
|
|
|
|
|
|
|
|
this.options = {}; |
|
|
|
|
|
this.defaultOptions = { |
|
|
|
|
|
enabled: false, |
|
|
|
|
|
initiallyVisible: false, |
|
|
|
|
|
locale: 'en', |
|
|
|
|
|
locales: locales, |
|
|
|
|
|
functionality:{ |
|
|
|
|
|
addNode: true, |
|
|
|
|
|
addEdge: true, |
|
|
|
|
|
editNode: true, |
|
|
|
|
|
editEdge: true, |
|
|
|
|
|
deleteNode: true, |
|
|
|
|
|
deleteEdge: true |
|
|
|
|
|
}, |
|
|
|
|
|
handlerFunctions: { |
|
|
|
|
|
addNode: undefined, |
|
|
|
|
|
addEdge: undefined, |
|
|
|
|
|
editNode: undefined, |
|
|
|
|
|
editEdge: undefined, |
|
|
|
|
|
deleteNode: undefined, |
|
|
|
|
|
deleteEdge: undefined |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
util.extend(this.options, this.defaultOptions); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setOptions(options) { |
|
|
|
|
|
if (options !== undefined) { |
|
|
|
|
|
if (typeof options == 'boolean') { |
|
|
|
|
|
this.options.enabled = options; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.options.enabled = true; |
|
|
|
|
|
for (let prop in options) { |
|
|
|
|
|
if (options.hasOwnProperty(prop)) { |
|
|
|
|
|
this.options[prop] = options[prop]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (this.options.initiallyVisible === true) { |
|
|
|
|
|
this.editMode = true; |
|
|
|
|
|
} |
|
|
|
|
|
this.init(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
init() { |
|
|
|
|
|
if (this.options.enabled === true) { |
|
|
|
|
|
// Enable the GUI
|
|
|
|
|
|
this.guiEnabled = true; |
|
|
|
|
|
|
|
|
|
|
|
// remove override
|
|
|
|
|
|
this.selectionHandler.forceSelectEdges = true; |
|
|
|
|
|
|
|
|
|
|
|
this.createWrappers(); |
|
|
|
|
|
if (this.editMode === false) { |
|
|
|
|
|
this.createEditButton(); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.removeManipulationDOM(); |
|
|
|
|
|
|
|
|
|
|
|
// disable the gui
|
|
|
|
|
|
this.guiEnabled = false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createWrappers() { |
|
|
|
|
|
// load the manipulator HTML elements. All styling done in css.
|
|
|
|
|
|
if (this.manipulationDiv === undefined) { |
|
|
|
|
|
this.manipulationDiv = document.createElement('div'); |
|
|
|
|
|
this.manipulationDiv.className = 'network-manipulationDiv'; |
|
|
|
|
|
if (this.editMode === true) { |
|
|
|
|
|
this.manipulationDiv.style.display = "block"; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.manipulationDiv.style.display = "none"; |
|
|
|
|
|
} |
|
|
|
|
|
this.canvas.frame.appendChild(this.manipulationDiv); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.editModeDiv === undefined) { |
|
|
|
|
|
this.editModeDiv = document.createElement('div'); |
|
|
|
|
|
this.editModeDiv.className = 'network-manipulation-editMode'; |
|
|
|
|
|
if (this.editMode === true) { |
|
|
|
|
|
this.editModeDiv.style.display = "none"; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.editModeDiv.style.display = "block"; |
|
|
|
|
|
} |
|
|
|
|
|
this.canvas.frame.appendChild(this.editModeDiv); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.closeDiv === undefined) { |
|
|
|
|
|
this.closeDiv = document.createElement('div'); |
|
|
|
|
|
this.closeDiv.className = 'network-manipulation-closeDiv'; |
|
|
|
|
|
this.closeDiv.style.display = this.manipulationDiv.style.display; |
|
|
|
|
|
this.canvas.frame.appendChild(this.closeDiv); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Create the edit button |
|
|
|
|
|
*/ |
|
|
|
|
|
createEditButton() { |
|
|
|
|
|
// restore everything to it's original state (if applicable)
|
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
// reset the manipulationDOM
|
|
|
|
|
|
this.manipulationDOM = {}; |
|
|
|
|
|
|
|
|
|
|
|
// empty the editModeDiv
|
|
|
|
|
|
util.recursiveDOMDelete(this.editModeDiv); |
|
|
|
|
|
|
|
|
|
|
|
// create the contents for the editMode button
|
|
|
|
|
|
let locale = this.options.locales[this.options.locale]; |
|
|
|
|
|
let button = this.createButton('editMode', 'network-manipulationUI edit editmode', locale['edit']); |
|
|
|
|
|
this.editModeDiv.appendChild(button); |
|
|
|
|
|
|
|
|
|
|
|
// bind a hammer listener to the button, calling the function toggleEditMode.
|
|
|
|
|
|
this.bindHammerToDiv(button, 'toggleEditMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
removeManipulationDOM() { |
|
|
|
|
|
// removes all the bindings and overloads
|
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
// empty the manipulation divs
|
|
|
|
|
|
util.recursiveDOMDelete(this.manipulationDiv); |
|
|
|
|
|
util.recursiveDOMDelete(this.editModeDiv); |
|
|
|
|
|
util.recursiveDOMDelete(this.closeDiv); |
|
|
|
|
|
|
|
|
|
|
|
// remove the manipulation divs
|
|
|
|
|
|
this.canvas.frame.removeChild(this.manipulationDiv); |
|
|
|
|
|
this.canvas.frame.removeChild(this.editModeDiv); |
|
|
|
|
|
this.canvas.frame.removeChild(this.closeDiv); |
|
|
|
|
|
|
|
|
|
|
|
// set the references to undefined
|
|
|
|
|
|
this.manipulationDiv = undefined; |
|
|
|
|
|
this.editModeDiv = undefined; |
|
|
|
|
|
this.closeDiv = undefined; |
|
|
|
|
|
|
|
|
|
|
|
// remove override
|
|
|
|
|
|
this.selectionHandler.forceSelectEdges = false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//clearManipulatorBar() {
|
|
|
|
|
|
// util._recursiveDOMDelete(this.manipulationDiv);
|
|
|
|
|
|
// this.manipulationDOM = {};
|
|
|
|
|
|
// this._cleanManipulatorHammers();
|
|
|
|
|
|
// this._manipulationReleaseOverload();
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_cleanManipulatorHammers() { |
|
|
|
|
|
// _clean hammer bindings
|
|
|
|
|
|
if (this.manipulationHammers.length != 0) { |
|
|
|
|
|
for (let i = 0; i < this.manipulationHammers.length; i++) { |
|
|
|
|
|
this.manipulationHammers[i].destroy(); |
|
|
|
|
|
} |
|
|
|
|
|
this.manipulationHammers = []; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore |
|
|
|
|
|
* these functions to their original functionality, we saved them in this.cachedFunctions. |
|
|
|
|
|
* This function restores these functions to their original function. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_restoreOverloadedFunctions() { |
|
|
|
|
|
for (let functionName in this.cachedFunctions) { |
|
|
|
|
|
if (this.cachedFunctions.hasOwnProperty(functionName)) { |
|
|
|
|
|
this.body.eventListeners[functionName] = this.cachedFunctions[functionName]; |
|
|
|
|
|
delete this.cachedFunctions[functionName]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.cachedFunctions = {}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Enable or disable edit-mode. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
toggleEditMode() { |
|
|
|
|
|
this.editMode = !this.editMode; |
|
|
|
|
|
let toolbar = this.manipulationDiv; |
|
|
|
|
|
let closeDiv = this.closeDiv; |
|
|
|
|
|
let editModeDiv = this.editModeDiv; |
|
|
|
|
|
if (this.editMode === true) { |
|
|
|
|
|
toolbar.style.display = "block"; |
|
|
|
|
|
closeDiv.style.display = "block"; |
|
|
|
|
|
editModeDiv.style.display = "none"; |
|
|
|
|
|
this.bindHammerToDiv(closeDiv, 'toggleEditMode'); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
toolbar.style.display = "none"; |
|
|
|
|
|
closeDiv.style.display = "none"; |
|
|
|
|
|
editModeDiv.style.display = "block"; |
|
|
|
|
|
this.createEditButton(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_clean() { |
|
|
|
|
|
// _clean the divs
|
|
|
|
|
|
if (this.guiEnabled === true) { |
|
|
|
|
|
util.recursiveDOMDelete(this.editModeDiv); |
|
|
|
|
|
util.recursiveDOMDelete(this.manipulationDiv); |
|
|
|
|
|
|
|
|
|
|
|
// removes all the bindings and overloads
|
|
|
|
|
|
this._cleanManipulatorHammers(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// remove temporary nodes and edges
|
|
|
|
|
|
this._cleanupTemporaryNodesAndEdges(); |
|
|
|
|
|
|
|
|
|
|
|
// restore overloaded UI functions
|
|
|
|
|
|
this._restoreOverloadedFunctions(); |
|
|
|
|
|
|
|
|
|
|
|
// remove the boundFunction
|
|
|
|
|
|
if (this.boundFunction !== undefined) { |
|
|
|
|
|
this.body.emitter.off(this.boundFunction.event, this.boundFunction.fn); |
|
|
|
|
|
} |
|
|
|
|
|
this.boundFunction = undefined; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createSeperator(index = 1) { |
|
|
|
|
|
this.manipulationDOM['seperatorLineDiv' + index] = document.createElement('div'); |
|
|
|
|
|
this.manipulationDOM['seperatorLineDiv' + index].className = 'network-seperatorLine'; |
|
|
|
|
|
this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv' + index]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createAddNodeButton(locale) { |
|
|
|
|
|
let button = this.createButton('addNode', 'network-manipulationUI add', locale['addNode']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, 'addNodeMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createAddEdgeButton(locale) { |
|
|
|
|
|
let button = this.createButton('addEdge', 'network-manipulationUI connect', locale['addEdge']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, 'addEdgeMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createEditNodeButton(locale) { |
|
|
|
|
|
let button = this.createButton('editNode', 'network-manipulationUI edit', locale['editNode']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, '_editNode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createEditEdgeButton(locale) { |
|
|
|
|
|
let button = this.createButton('editEdge', 'network-manipulationUI edit', locale['editEdge']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, 'editEdgeMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createDeleteButton(locale) { |
|
|
|
|
|
let button = this.createButton('delete', 'network-manipulationUI delete', locale['del']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, 'deleteSelected'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createBackButton(locale) { |
|
|
|
|
|
let button = this.createButton('back', 'network-manipulationUI back', locale['back']); |
|
|
|
|
|
this.manipulationDiv.appendChild(button); |
|
|
|
|
|
this.bindHammerToDiv(button, 'createManipulatorBar'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createDescription(label) { |
|
|
|
|
|
this.manipulationDiv.appendChild( |
|
|
|
|
|
this.createButton('description', 'network-manipulationUI none', label) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createButton(id, className, label, labelClassName = 'network-manipulationLabel') { |
|
|
|
|
|
this.manipulationDOM[id+"Div"] = document.createElement('div'); |
|
|
|
|
|
this.manipulationDOM[id+"Div"].className = className; |
|
|
|
|
|
this.manipulationDOM[id+"Label"] = document.createElement('div'); |
|
|
|
|
|
this.manipulationDOM[id+"Label"].className = labelClassName; |
|
|
|
|
|
this.manipulationDOM[id+"Label"].innerHTML = label; |
|
|
|
|
|
this.manipulationDOM[id+"Div"].appendChild(this.manipulationDOM[id+'Label']); |
|
|
|
|
|
return this.manipulationDOM[id+"Div"]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
temporaryBind(fn, event) { |
|
|
|
|
|
this.boundFunction = {fn:fn.bind(this), event}; |
|
|
|
|
|
this.body.emitter.on(event, this.boundFunction.fn); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
createManipulatorBar() { |
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
// resume calculation
|
|
|
|
|
|
this.body.emitter.emit("restorePhysics"); |
|
|
|
|
|
|
|
|
|
|
|
// reset global letiables
|
|
|
|
|
|
this.manipulationDOM = {}; |
|
|
|
|
|
|
|
|
|
|
|
let selectedNodeCount = this.selectionHandler._getSelectedNodeCount(); |
|
|
|
|
|
let selectedEdgeCount = this.selectionHandler._getSelectedEdgeCount(); |
|
|
|
|
|
let selectedTotalCount = selectedNodeCount + selectedEdgeCount; |
|
|
|
|
|
let locale = this.options.locales[this.options.locale]; |
|
|
|
|
|
let needSeperator = false; |
|
|
|
|
|
|
|
|
|
|
|
if (this.options.functionality.addNode === true) { |
|
|
|
|
|
this.createAddNodeButton(locale); |
|
|
|
|
|
needSeperator = true; |
|
|
|
|
|
} |
|
|
|
|
|
if (this.options.functionality.addEdge === true) { |
|
|
|
|
|
if (needSeperator === true) {this.createSeperator(1);} else {needSeperator = true;} |
|
|
|
|
|
this.createAddEdgeButton(locale); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (selectedNodeCount === 1 && typeof this.options.handlerFunctions.editNode === 'function' && this.options.functionality.editNode === true) { |
|
|
|
|
|
if (needSeperator === true) {this.createSeperator(2);} else {needSeperator = true;} |
|
|
|
|
|
this.createEditNodeButton(locale); |
|
|
|
|
|
} |
|
|
|
|
|
else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.functionality.editEdge === true) { |
|
|
|
|
|
if (needSeperator === true) {this.createSeperator(3);} else {needSeperator = true;} |
|
|
|
|
|
this.createEditEdgeButton(locale); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// remove buttons
|
|
|
|
|
|
if (selectedTotalCount !== 0) { |
|
|
|
|
|
if (selectedNodeCount === 1 && this.options.functionality.deleteNode === true) { |
|
|
|
|
|
if (needSeperator === true) {this.createSeperator(4);} |
|
|
|
|
|
this.createDeleteButton(locale); |
|
|
|
|
|
} |
|
|
|
|
|
else if (selectedNodeCount === 0 && this.options.functionality.deleteEdge === true) { |
|
|
|
|
|
if (needSeperator === true) {this.createSeperator(4);} |
|
|
|
|
|
this.createDeleteButton(locale); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// bind the close button
|
|
|
|
|
|
this.bindHammerToDiv(this.closeDiv, 'toggleEditMode'); |
|
|
|
|
|
|
|
|
|
|
|
// refresh this bar based on what has been selected
|
|
|
|
|
|
this.temporaryBind(this.createManipulatorBar,'select'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Bind an hammer instance to a DOM element. TODO: remove the double check. |
|
|
|
|
|
* @param domElement |
|
|
|
|
|
* @param funct |
|
|
|
|
|
*/ |
|
|
|
|
|
bindHammerToDiv(domElement, funct) { |
|
|
|
|
|
let hammer = new Hammer(domElement, {}); |
|
|
|
|
|
hammerUtil.onTouch(hammer, this[funct].bind(this)); |
|
|
|
|
|
this.manipulationHammers.push(hammer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Create the toolbar for adding Nodes |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
addNodeMode() { |
|
|
|
|
|
// clear the toolbar
|
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.guiEnabled === true) { |
|
|
|
|
|
let locale = this.options.locales[this.options.locale]; |
|
|
|
|
|
this.manipulationDOM = {}; |
|
|
|
|
|
this.createBackButton(locale); |
|
|
|
|
|
this.createSeperator(); |
|
|
|
|
|
this.createDescription(locale['addDescription']) |
|
|
|
|
|
|
|
|
|
|
|
// bind the close button
|
|
|
|
|
|
this.bindHammerToDiv(this.closeDiv, 'toggleEditMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.temporaryBind(this._addNode,'click'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* create the toolbar to connect nodes |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
addEdgeMode() { |
|
|
|
|
|
// _clean the system
|
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.guiEnabled === true) { |
|
|
|
|
|
let locale = this.options.locales[this.options.locale]; |
|
|
|
|
|
this.manipulationDOM = {}; |
|
|
|
|
|
this.createBackButton(locale); |
|
|
|
|
|
this.createSeperator(); |
|
|
|
|
|
this.createDescription(locale['edgeDescription']); |
|
|
|
|
|
|
|
|
|
|
|
// bind the close button
|
|
|
|
|
|
this.bindHammerToDiv(this.closeDiv, 'toggleEditMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// temporarily overload functions
|
|
|
|
|
|
this.cachedFunctions["onTouch"] = this.body.eventListeners.onTouch; |
|
|
|
|
|
this.cachedFunctions["onDragEnd"] = this.body.eventListeners.onDragEnd; |
|
|
|
|
|
this.cachedFunctions["onHold"] = this.body.eventListeners.onHold; |
|
|
|
|
|
|
|
|
|
|
|
this.body.eventListeners.onTouch = this._handleConnect.bind(this); |
|
|
|
|
|
this.body.eventListeners.onDragEnd = this._finishConnect.bind(this); |
|
|
|
|
|
this.body.eventListeners.onHold = function () {}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* create the toolbar to edit edges |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
editEdgeMode() { |
|
|
|
|
|
// clear the system
|
|
|
|
|
|
this._clean(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.guiEnabled === true) { |
|
|
|
|
|
let locale = this.options.locales[this.options.locale]; |
|
|
|
|
|
this.manipulationDOM = {}; |
|
|
|
|
|
this.createBackButton(locale); |
|
|
|
|
|
this.createSeperator(); |
|
|
|
|
|
this.createDescription(locale['editEdgeDescription']); |
|
|
|
|
|
|
|
|
|
|
|
// bind the close button
|
|
|
|
|
|
this.bindHammerToDiv(this.closeDiv, 'toggleEditMode'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0]; |
|
|
|
|
|
let edge = this.body.edges[this.edgeBeingEditedId]; |
|
|
|
|
|
|
|
|
|
|
|
// create control nodes
|
|
|
|
|
|
let controlNodeFrom = this.body.functions.createNode(this.getTargetNodeProperties(edge.from.x, edge.from.y)); |
|
|
|
|
|
let controlNodeTo = this.body.functions.createNode(this.getTargetNodeProperties(edge.to.x, edge.to.y)); |
|
|
|
|
|
|
|
|
|
|
|
this.temporaryIds.nodes.push(controlNodeFrom.id); |
|
|
|
|
|
this.temporaryIds.nodes.push(controlNodeTo.id); |
|
|
|
|
|
|
|
|
|
|
|
this.body.nodes[controlNodeFrom.id] = controlNodeFrom; |
|
|
|
|
|
this.body.nodeIndices.push(controlNodeFrom.id); |
|
|
|
|
|
this.body.nodes[controlNodeTo.id] = controlNodeTo; |
|
|
|
|
|
this.body.nodeIndices.push(controlNodeTo.id); |
|
|
|
|
|
|
|
|
|
|
|
// temporarily overload functions
|
|
|
|
|
|
this.cachedFunctions['onTouch'] = this.body.eventListeners.onTouch; |
|
|
|
|
|
this.cachedFunctions['onTap'] = this.body.eventListeners.onTap; |
|
|
|
|
|
this.cachedFunctions['onHold'] = this.body.eventListeners.onHold; |
|
|
|
|
|
this.cachedFunctions['onDragStart'] = this.body.eventListeners.onDragStart; |
|
|
|
|
|
this.cachedFunctions['onDrag'] = this.body.eventListeners.onDrag; |
|
|
|
|
|
this.cachedFunctions['onDragEnd'] = this.body.eventListeners.onDragEnd; |
|
|
|
|
|
this.cachedFunctions['onMouseOver'] = this.body.eventListeners.onMouseOver; |
|
|
|
|
|
|
|
|
|
|
|
this.body.eventListeners.onTouch = this._controlNodeTouch.bind(this); |
|
|
|
|
|
this.body.eventListeners.onTap = function() {}; |
|
|
|
|
|
this.body.eventListeners.onHold = function() {}; |
|
|
|
|
|
this.body.eventListeners.onDragStart= this._controlNodeDragStart.bind(this); |
|
|
|
|
|
this.body.eventListeners.onDrag = this._controlNodeDrag.bind(this); |
|
|
|
|
|
this.body.eventListeners.onDragEnd = this._controlNodeDragEnd.bind(this); |
|
|
|
|
|
this.body.eventListeners.onMouseOver= function() {} |
|
|
|
|
|
|
|
|
|
|
|
// create function to position control nodes correctly on movement
|
|
|
|
|
|
let positionControlNodes = (ctx) => { |
|
|
|
|
|
let positions = edge.edgeType.findBorderPositions(ctx); |
|
|
|
|
|
if (controlNodeFrom.selected === false) { |
|
|
|
|
|
controlNodeFrom.x = positions.from.x; |
|
|
|
|
|
controlNodeFrom.y = positions.from.y; |
|
|
|
|
|
} |
|
|
|
|
|
if (controlNodeTo.selected === false) { |
|
|
|
|
|
controlNodeTo.x = positions.to.x; |
|
|
|
|
|
controlNodeTo.y = positions.to.y; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.temporaryBind(positionControlNodes, "beforeDrawing"); |
|
|
|
|
|
|
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_controlNodeTouch(event) { |
|
|
|
|
|
this.lastTouch = this.body.functions.getPointer(event.center); |
|
|
|
|
|
this.lastTouch.translation = util.extend({},this.body.view.translation); // copy the object
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_controlNodeDragStart(event) { |
|
|
|
|
|
let pointer = this.lastTouch; |
|
|
|
|
|
let pointerObj = this.selectionHandler._pointerToPositionObject(pointer); |
|
|
|
|
|
let from = this.body.nodes[this.temporaryIds.nodes[0]]; |
|
|
|
|
|
let to = this.body.nodes[this.temporaryIds.nodes[1]]; |
|
|
|
|
|
let edge = this.body.edges[this.edgeBeingEditedId]; |
|
|
|
|
|
this.selectedControlNode = undefined; |
|
|
|
|
|
|
|
|
|
|
|
let fromSelect = from.isOverlappingWith(pointerObj); |
|
|
|
|
|
let toSelect = to.isOverlappingWith(pointerObj); |
|
|
|
|
|
|
|
|
|
|
|
if (fromSelect === true) { |
|
|
|
|
|
this.selectedControlNode = from; |
|
|
|
|
|
edge.edgeType.from = from; |
|
|
|
|
|
} |
|
|
|
|
|
else if (toSelect === true) { |
|
|
|
|
|
this.selectedControlNode = to; |
|
|
|
|
|
edge.edgeType.to = to; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_controlNodeDrag(event) { |
|
|
|
|
|
this.body.emitter.emit("disablePhysics"); |
|
|
|
|
|
let pointer = this.body.functions.getPointer(event.center); |
|
|
|
|
|
let pos = this.canvas.DOMtoCanvas(pointer); |
|
|
|
|
|
|
|
|
|
|
|
if (this.selectedControlNode !== undefined) { |
|
|
|
|
|
this.selectedControlNode.x = pos.x; |
|
|
|
|
|
this.selectedControlNode.y = pos.y; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// if the drag was not started properly because the click started outside the network div, start it now.
|
|
|
|
|
|
let diffX = pointer.x - this.lastTouch.x; |
|
|
|
|
|
let diffY = pointer.y - this.lastTouch.y; |
|
|
|
|
|
this.body.view.translation = {x:this.lastTouch.translation.x + diffX, y:this.lastTouch.translation.y + diffY}; |
|
|
|
|
|
} |
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_controlNodeDragEnd(event) { |
|
|
|
|
|
let pointer = this.body.functions.getPointer(event.center); |
|
|
|
|
|
let pointerObj = this.selectionHandler._pointerToPositionObject(pointer); |
|
|
|
|
|
let edge = this.body.edges[this.edgeBeingEditedId]; |
|
|
|
|
|
|
|
|
|
|
|
let overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj); |
|
|
|
|
|
let node = undefined; |
|
|
|
|
|
for (let i = overlappingNodeIds.length-1; i >= 0; i--) { |
|
|
|
|
|
if (overlappingNodeIds[i] !== this.selectedControlNode.id) { |
|
|
|
|
|
node = this.body.nodes[overlappingNodeIds[i]]; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// perform the connection
|
|
|
|
|
|
if (node !== undefined && this.selectedControlNode !== undefined) { |
|
|
|
|
|
if (node.isCluster === true) { |
|
|
|
|
|
alert(this.options.locales[this.options.locale]["createEdgeError"]) |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
let from = this.body.nodes[this.temporaryIds.nodes[0]]; |
|
|
|
|
|
if (this.selectedControlNode.id == from.id) { |
|
|
|
|
|
this._editEdge(node.id, edge.to.id); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this._editEdge(edge.from.id, node.id); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
edge.updateEdgeType(); |
|
|
|
|
|
this.body.emitter.emit("restorePhysics"); |
|
|
|
|
|
} |
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
/** |
|
|
|
|
|
* the function bound to the selection event. It checks if you want to connect a cluster and changes the description |
|
|
|
|
|
* to walk the user through the process. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_selectControlNode(event) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* |
|
|
|
|
|
* @param pointer |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_releaseControlNode(pointer) { |
|
|
|
|
|
if (new Date().valueOf() - this.touchTime > 100) { |
|
|
|
|
|
console.log("release") |
|
|
|
|
|
// perform the connection
|
|
|
|
|
|
let node = this.selectionHandler.getNodeAt(pointer); |
|
|
|
|
|
if (node !== undefined) { |
|
|
|
|
|
if (node.isCluster === true) { |
|
|
|
|
|
alert(this.options.locales[this.options.locale]["createEdgeError"]) |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
let edge = this.body.edges[this.edgeBeingEditedId]; |
|
|
|
|
|
|
|
|
|
|
|
let targetNodeId = undefined; |
|
|
|
|
|
if (edge.to.selected === true) { |
|
|
|
|
|
targetNodeId = edge.toId; |
|
|
|
|
|
} |
|
|
|
|
|
else if (edge.from.selected === true) { |
|
|
|
|
|
targetNodeId = edge.fromId; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//this.body.eventListeners.onDrag = this.cachedFunctions["onDrag"];
|
|
|
|
|
|
//this.body.eventListeners.onRelease = this.cachedFunctions["onRelease"];
|
|
|
|
|
|
//delete this.cachedFunctions["onRelease"];
|
|
|
|
|
|
//delete this.cachedFunctions["onDrag"];
|
|
|
|
|
|
////
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
//if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
|
|
|
|
|
|
// this._createEdge(connectFromId, node.id);
|
|
|
|
|
|
//}
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
//this.body.emitter.emit("_redraw");
|
|
|
|
|
|
//let newNode = this.getNodeAt(pointer);
|
|
|
|
|
|
//if (newNode !== undefined) {
|
|
|
|
|
|
// if (this.edgeBeingEditedId.controlNodes.from.selected == true) {
|
|
|
|
|
|
// this.edgeBeingEditedId._restoreControlNodes();
|
|
|
|
|
|
// this._editEdge(newNode.id, this.edgeBeingEditedId.to.id);
|
|
|
|
|
|
// this.edgeBeingEditedId.controlNodes.from.unselect();
|
|
|
|
|
|
// }
|
|
|
|
|
|
// if (this.edgeBeingEditedId.controlNodes.to.selected == true) {
|
|
|
|
|
|
// this.edgeBeingEditedId._restoreControlNodes();
|
|
|
|
|
|
// this._editEdge(this.edgeBeingEditedId.from.id, newNode.id);
|
|
|
|
|
|
// this.edgeBeingEditedId.controlNodes.to.unselect();
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
//else {
|
|
|
|
|
|
// this.edgeBeingEditedId._restoreControlNodes();
|
|
|
|
|
|
//}
|
|
|
|
|
|
this.touchTime = new Date().valueOf(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* the function bound to the selection event. It checks if you want to connect a cluster and changes the description |
|
|
|
|
|
* to walk the user through the process. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_handleConnect(event) { |
|
|
|
|
|
// check to avoid double fireing of this function.
|
|
|
|
|
|
if (new Date().valueOf() - this.touchTime > 100) { |
|
|
|
|
|
let pointer = this.body.functions.getPointer(event.center); |
|
|
|
|
|
let node = this.selectionHandler.getNodeAt(pointer); |
|
|
|
|
|
|
|
|
|
|
|
if (node !== undefined) { |
|
|
|
|
|
if (node.isCluster === true) { |
|
|
|
|
|
alert(this.options.locales[this.options.locale]['createEdgeError']) |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// create a node the temporary line can look at
|
|
|
|
|
|
let targetNode = this.body.functions.createNode(this.getTargetNodeProperties(node.x,node.y)); |
|
|
|
|
|
let targetNodeId = targetNode.id; |
|
|
|
|
|
this.body.nodes[targetNode.id] = targetNode; |
|
|
|
|
|
this.body.nodeIndices.push(targetNode.id); |
|
|
|
|
|
|
|
|
|
|
|
// create a temporary edge
|
|
|
|
|
|
let connectionEdge = this.body.functions.createEdge({ |
|
|
|
|
|
id: "connectionEdge" + util.randomUUID(), |
|
|
|
|
|
from: node.id, |
|
|
|
|
|
to: targetNode.id, |
|
|
|
|
|
physics:false, |
|
|
|
|
|
smooth: { |
|
|
|
|
|
enabled: true, |
|
|
|
|
|
dynamic: false, |
|
|
|
|
|
type: "continuous", |
|
|
|
|
|
roundness: 0.5 |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
this.body.edges[connectionEdge.id] = connectionEdge; |
|
|
|
|
|
this.body.edgeIndices.push(connectionEdge.id); |
|
|
|
|
|
|
|
|
|
|
|
this.temporaryIds.nodes.push(targetNode.id); |
|
|
|
|
|
this.temporaryIds.edges.push(connectionEdge.id); |
|
|
|
|
|
|
|
|
|
|
|
this.cachedFunctions["onDrag"] = this.body.eventListeners.onDrag; |
|
|
|
|
|
this.body.eventListeners.onDrag = (event) => { |
|
|
|
|
|
let pointer = this.body.functions.getPointer(event.center); |
|
|
|
|
|
let targetNode = this.body.nodes[targetNodeId]; |
|
|
|
|
|
targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x); |
|
|
|
|
|
targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y); |
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.touchTime = new Date().valueOf(); |
|
|
|
|
|
|
|
|
|
|
|
// do the original touch events
|
|
|
|
|
|
this.cachedFunctions["onTouch"](event); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_finishConnect(event) { |
|
|
|
|
|
let pointer = this.body.functions.getPointer(event.center); |
|
|
|
|
|
let pointerObj = this.selectionHandler._pointerToPositionObject(pointer); |
|
|
|
|
|
|
|
|
|
|
|
// remember the edge id
|
|
|
|
|
|
let connectFromId = undefined; |
|
|
|
|
|
if (this.temporaryIds.edges[0] !== undefined) { |
|
|
|
|
|
connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//restore the drag function
|
|
|
|
|
|
if (this.cachedFunctions["onDrag"] !== undefined) { |
|
|
|
|
|
this.body.eventListeners.onDrag = this.cachedFunctions["onDrag"]; |
|
|
|
|
|
delete this.cachedFunctions["onDrag"]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// get the overlapping node but NOT the temporary node;
|
|
|
|
|
|
let overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj); |
|
|
|
|
|
let node = undefined; |
|
|
|
|
|
for (let i = overlappingNodeIds.length-1; i >= 0; i--) { |
|
|
|
|
|
if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) !== -1) { |
|
|
|
|
|
node = this.body.nodes[overlappingNodeIds[i]]; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// clean temporary nodes and edges.
|
|
|
|
|
|
this._cleanupTemporaryNodesAndEdges(); |
|
|
|
|
|
|
|
|
|
|
|
// perform the connection
|
|
|
|
|
|
if (node !== undefined) { |
|
|
|
|
|
if (node.isCluster === true) { |
|
|
|
|
|
alert(this.options.locales[this.options.locale]["createEdgeError"]) |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) { |
|
|
|
|
|
this._createEdge(connectFromId, node.id); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.body.emitter.emit("_redraw"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_cleanupTemporaryNodesAndEdges() { |
|
|
|
|
|
// _clean temporary edges
|
|
|
|
|
|
for (let i = 0; i < this.temporaryIds.edges.length; i++) { |
|
|
|
|
|
this.body.edges[this.temporaryIds.edges[i]].disconnect(); |
|
|
|
|
|
delete this.body.edges[this.temporaryIds.edges[i]]; |
|
|
|
|
|
let indexTempEdge = this.body.edgeIndices.indexOf(this.temporaryIds.edges[i]); |
|
|
|
|
|
if (indexTempEdge !== -1) {this.body.edgeIndices.splice(indexTempEdge,1);} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// _clean temporary nodes
|
|
|
|
|
|
for (let i = 0; i < this.temporaryIds.nodes.length; i++) { |
|
|
|
|
|
delete this.body.nodes[this.temporaryIds.nodes[i]]; |
|
|
|
|
|
let indexTempNode = this.body.nodeIndices.indexOf(this.temporaryIds.nodes[i]); |
|
|
|
|
|
if (indexTempNode !== -1) {this.body.nodeIndices.splice(indexTempNode,1);} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.temporaryIds = {nodes: [], edges: []}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Adds a node on the specified location |
|
|
|
|
|
*/ |
|
|
|
|
|
_addNode(clickData) { |
|
|
|
|
|
let defaultData = { |
|
|
|
|
|
id: util.randomUUID(), |
|
|
|
|
|
x: clickData.pointer.canvas.x, |
|
|
|
|
|
y: clickData.pointer.canvas.y, |
|
|
|
|
|
label: "new" |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof this.options.handlerFunctions.addNode === 'function') { |
|
|
|
|
|
if (this.options.handlerFunctions.addNode.length == 2) { |
|
|
|
|
|
this.options.handlerFunctions.addNode(defaultData, (finalizedData) => { |
|
|
|
|
|
this.body.data.nodes.add(finalizedData); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('The function for add does not support two arguments (data,callback)'); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.body.data.nodes.add(defaultData); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* connect two nodes with a new edge. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_createEdge(sourceNodeId, targetNodeId) { |
|
|
|
|
|
let defaultData = {from: sourceNodeId, to: targetNodeId}; |
|
|
|
|
|
if (this.options.handlerFunctions.addEdge) { |
|
|
|
|
|
if (this.options.handlerFunctions.addEdge.length == 2) { |
|
|
|
|
|
this.options.handlerFunctions.addEdge(defaultData, (finalizedData) => { |
|
|
|
|
|
this.body.data.edges.add(finalizedData); |
|
|
|
|
|
this.selectionHandler.unselectAll(); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('The function for connect does not support two arguments (data,callback)'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.body.data.edges.add(defaultData); |
|
|
|
|
|
this.selectionHandler.unselectAll(); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* connect two nodes with a new edge. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_editEdge(sourceNodeId, targetNodeId) { |
|
|
|
|
|
let defaultData = {id: this.edgeBeingEditedId, from: sourceNodeId, to: targetNodeId}; |
|
|
|
|
|
console.log(defaultData) |
|
|
|
|
|
if (this.options.handlerFunctions.editEdge) { |
|
|
|
|
|
if (this.options.handlerFunctions.editEdge.length == 2) { |
|
|
|
|
|
this.options.handlerFunctions.editEdge(defaultData, (finalizedData) => { |
|
|
|
|
|
this.body.data.edges.update(finalizedData); |
|
|
|
|
|
this.selectionHandler.unselectAll(); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('The function for edit does not support two arguments (data, callback)'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.body.data.edges.update(defaultData); |
|
|
|
|
|
this.selectionHandler.unselectAll(); |
|
|
|
|
|
this.createManipulatorBar(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_editNode() { |
|
|
|
|
|
if (this.options.handlerFunctions.edit && this.editMode == true) { |
|
|
|
|
|
let node = this._getSelectedNode(); |
|
|
|
|
|
let data = { |
|
|
|
|
|
id: node.id, |
|
|
|
|
|
label: node.label, |
|
|
|
|
|
group: node.options.group, |
|
|
|
|
|
shape: node.options.shape, |
|
|
|
|
|
color: { |
|
|
|
|
|
background: node.options.color.background, |
|
|
|
|
|
border: node.options.color.border, |
|
|
|
|
|
highlight: { |
|
|
|
|
|
background: node.options.color.highlight.background, |
|
|
|
|
|
border: node.options.color.highlight.border |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
if (this.options.handlerFunctions.edit.length == 2) { |
|
|
|
|
|
let me = this; |
|
|
|
|
|
this.options.handlerFunctions.edit(data, function (finalizedData) { |
|
|
|
|
|
me.body.data.nodes.update(finalizedData); |
|
|
|
|
|
me.createManipulatorBar(); |
|
|
|
|
|
me.moving = true; |
|
|
|
|
|
me.start(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('The function for edit does not support two arguments (data, callback)'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('No edit function has been bound to this button'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* delete everything in the selection |
|
|
|
|
|
* |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
deleteSelected() { |
|
|
|
|
|
let selectedNodes = this.selectionHandler.getSelectedNodes(); |
|
|
|
|
|
let selectedEdges = this.selectionHandler.getSelectedEdges(); |
|
|
|
|
|
let deleteFunction = undefined; |
|
|
|
|
|
if (selectedNodes.length > 0) { |
|
|
|
|
|
for (let i = 0; i < selectedNodes.length; i++) { |
|
|
|
|
|
if (this.body.nodes[selectedNodes[i]].isCluster === true) { |
|
|
|
|
|
alert("You cannot delete a cluster."); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (typeof this.options.handlerFunctions.deleteNode === 'function') { |
|
|
|
|
|
deleteFunction = this.options.handlerFunctions.deleteNode; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (selectedEdges.length > 0) { |
|
|
|
|
|
if (typeof this.options.handlerFunctions.deleteEdge === 'function') { |
|
|
|
|
|
deleteFunction = this.options.handlerFunctions.deleteEdge; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (typeof deleteFunction === 'function') { |
|
|
|
|
|
let data = {nodes: selectedNodes, edges: selectedEdges}; |
|
|
|
|
|
if (deleteFunction.length == 2) { |
|
|
|
|
|
deleteFunction(data, (finalizedData) => { |
|
|
|
|
|
this.body.data.edges.remove(finalizedData.edges); |
|
|
|
|
|
this.body.data.nodes.remove(finalizedData.nodes); |
|
|
|
|
|
this.body.emitter.emit("startSimulation"); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
throw new Error('The function for delete does not support two arguments (data, callback)') |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
this.body.data.edges.remove(selectedEdges); |
|
|
|
|
|
this.body.data.nodes.remove(selectedNodes); |
|
|
|
|
|
this.body.emitter.emit("startSimulation"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getTargetNodeProperties(x,y) { |
|
|
|
|
|
return { |
|
|
|
|
|
id: 'targetNode' + util.randomUUID(), |
|
|
|
|
|
hidden: false, |
|
|
|
|
|
physics: false, |
|
|
|
|
|
shape:'dot', |
|
|
|
|
|
size:6, |
|
|
|
|
|
x:x, |
|
|
|
|
|
y:y, |
|
|
|
|
|
color: {background: '#ff0000', border: '#3c3c3c', highlight: {background: '#07f968'}}, |
|
|
|
|
|
borderWidth: 2, |
|
|
|
|
|
borderWidthSelected: 2 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export default ManipulationSystem; |
|
|
|
|
|
|