From a82c74f6c6d79f26a814b40a62565c6b924ed78e Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Wed, 14 Jan 2015 11:28:25 +0100 Subject: [PATCH] - Improved edit edge control nodes positions, altered style a little. - Fixed issue #564 by resetting state to initial when no callback is performed in the return function. --- HISTORY.md | 2 + dist/vis.js | 95 +++++++++++++++---------- lib/network/Edge.js | 87 ++++++++++++---------- lib/network/mixins/ManipulationMixin.js | 8 +++ 4 files changed, 118 insertions(+), 74 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 1557f47c..620585b0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,6 +15,8 @@ http://visjs.org - Added label stroke support to Nodes, Edges & Groups as per-object or global settings. Thank you @klmdb! - Reverted patch that made nodes return to 'default' setting if no group was assigned to fix issue #561. The correct way to 'remove' a group from a node is to assign it a different one. - Made the node/edge selected by the popup system the same as selected by the click-to-select system. Thank you @pavlos256! +- Improved edit edge control nodes positions, altered style a little. +- Fixed issue #564 by resetting state to initial when no callback is performed in the return function. ### Timeline diff --git a/dist/vis.js b/dist/vis.js index fef629a6..3b2c716f 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -28425,7 +28425,6 @@ return /******/ (function(modules) { // webpackBootstrap var threshold = 0.2; var node = this.to; if (from == true) { - node = this.from; } @@ -28708,26 +28707,30 @@ return /******/ (function(modules) { // webpackBootstrap var nodeIdFrom = "edgeIdFrom:".concat(this.id); var nodeIdTo = "edgeIdTo:".concat(this.id); var constants = { - nodes:{group:'', radius:8}, + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, physics:{damping:0}, clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} }; this.controlNodes.from = new Node( {id:nodeIdFrom, shape:'dot', - color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}} + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} },{},{},constants); this.controlNodes.to = new Node( {id:nodeIdTo, shape:'dot', - color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}} + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} },{},{},constants); } - if (this.controlNodes.from.selected == false && this.controlNodes.to.selected == false) { - this.controlNodes.positions = this.getControlNodePositions(ctx); + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); this.controlNodes.from.x = this.controlNodes.positions.from.x; this.controlNodes.from.y = this.controlNodes.positions.from.y; + } + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); this.controlNodes.to.x = this.controlNodes.positions.to.x; this.controlNodes.to.y = this.controlNodes.positions.to.y; } @@ -28819,46 +28822,56 @@ return /******/ (function(modules) { // webpackBootstrap * this calculates the position of the control nodes on the edges of the parent nodes. * * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + * @returns {x: *, y: *} */ - Edge.prototype.getControlNodePositions = function(ctx) { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - - var via; - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true) { - via = this.via; - } - else if (this.options.smoothCurves.enabled == true) { - via = this._getViaCoordinates(); + Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - if (this.options.smoothCurves.enabled == true && via.x != null) { - angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x)); - dx = (this.to.x - via.x); - dy = (this.to.y - via.y); - edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; } - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - var xTo,yTo; - if (this.options.smoothCurves.enabled == true && via.x != null) { - xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x; - yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y; + return controlnodeFromPos; + }; + + /** + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + */ + Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); } else { - xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - return {from:{x:xFrom,y:yFrom},to:{x:xTo,y:yTo}}; + return controlnodeToPos; }; module.exports = Edge; @@ -33393,14 +33406,22 @@ return /******/ (function(modules) { // webpackBootstrap this._redraw(); }; + + /** + * + * @param pointer + * @private + */ exports._releaseControlNode = function(pointer) { var newNode = this._getNodeAt(pointer); if (newNode !== null) { if (this.edgeBeingEdited.controlNodes.from.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); this._editEdge(newNode.id, this.edgeBeingEdited.to.id); this.edgeBeingEdited.controlNodes.from.unselect(); } if (this.edgeBeingEdited.controlNodes.to.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); this._editEdge(this.edgeBeingEdited.from.id, newNode.id); this.edgeBeingEdited.controlNodes.to.unselect(); } diff --git a/lib/network/Edge.js b/lib/network/Edge.js index 3de7474a..9e555a05 100644 --- a/lib/network/Edge.js +++ b/lib/network/Edge.js @@ -814,7 +814,6 @@ Edge.prototype._findBorderPosition = function(from,ctx) { var threshold = 0.2; var node = this.to; if (from == true) { - node = this.from; } @@ -1097,26 +1096,30 @@ Edge.prototype._drawControlNodes = function(ctx) { var nodeIdFrom = "edgeIdFrom:".concat(this.id); var nodeIdTo = "edgeIdTo:".concat(this.id); var constants = { - nodes:{group:'', radius:8}, + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, physics:{damping:0}, clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} }; this.controlNodes.from = new Node( {id:nodeIdFrom, shape:'dot', - color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}} + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} },{},{},constants); this.controlNodes.to = new Node( {id:nodeIdTo, shape:'dot', - color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}} + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} },{},{},constants); } - if (this.controlNodes.from.selected == false && this.controlNodes.to.selected == false) { - this.controlNodes.positions = this.getControlNodePositions(ctx); + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); this.controlNodes.from.x = this.controlNodes.positions.from.x; this.controlNodes.from.y = this.controlNodes.positions.from.y; + } + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); this.controlNodes.to.x = this.controlNodes.positions.to.x; this.controlNodes.to.y = this.controlNodes.positions.to.y; } @@ -1208,46 +1211,56 @@ Edge.prototype._restoreControlNodes = function() { * this calculates the position of the control nodes on the edges of the parent nodes. * * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + * @returns {x: *, y: *} */ -Edge.prototype.getControlNodePositions = function(ctx) { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - - var via; - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true) { - via = this.via; +Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); } - else if (this.options.smoothCurves.enabled == true) { - via = this._getViaCoordinates(); + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; } - if (this.options.smoothCurves.enabled == true && via.x != null) { - angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x)); - dx = (this.to.x - via.x); - dy = (this.to.y - via.y); - edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - } - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + return controlnodeFromPos; +}; - var xTo,yTo; - if (this.options.smoothCurves.enabled == true && via.x != null) { - xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x; - yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y; +/** + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + */ +Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); } else { - xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - return {from:{x:xFrom,y:yFrom},to:{x:xTo,y:yTo}}; + return controlnodeToPos; }; module.exports = Edge; \ No newline at end of file diff --git a/lib/network/mixins/ManipulationMixin.js b/lib/network/mixins/ManipulationMixin.js index 184292d8..04471230 100644 --- a/lib/network/mixins/ManipulationMixin.js +++ b/lib/network/mixins/ManipulationMixin.js @@ -403,14 +403,22 @@ exports._controlNodeDrag = function(event) { this._redraw(); }; + +/** + * + * @param pointer + * @private + */ exports._releaseControlNode = function(pointer) { var newNode = this._getNodeAt(pointer); if (newNode !== null) { if (this.edgeBeingEdited.controlNodes.from.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); this._editEdge(newNode.id, this.edgeBeingEdited.to.id); this.edgeBeingEdited.controlNodes.from.unselect(); } if (this.edgeBeingEdited.controlNodes.to.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); this._editEdge(this.edgeBeingEdited.from.id, newNode.id); this.edgeBeingEdited.controlNodes.to.unselect(); }