Browse Source

added cubic bezier curves.

flowchartTest
Alex de Mulder 9 years ago
parent
commit
700e735336
17 changed files with 896 additions and 453 deletions
  1. +1
    -0
      HISTORY.md
  2. +663
    -370
      dist/vis.js
  3. +9
    -1
      docs/network/edges.html
  4. +7
    -49
      examples/network/edgeStyles/smooth.html
  5. +5
    -1
      examples/network/layout/hierarchicalLayoutUserdefined.html
  6. +3
    -3
      lib/network/modules/Clustering.js
  7. +2
    -1
      lib/network/modules/EdgesHandler.js
  8. +4
    -2
      lib/network/modules/LayoutEngine.js
  9. +1
    -2
      lib/network/modules/NodesHandler.js
  10. +10
    -7
      lib/network/modules/PhysicsEngine.js
  11. +19
    -4
      lib/network/modules/components/Edge.js
  12. +17
    -0
      lib/network/modules/components/Node.js
  13. +91
    -0
      lib/network/modules/components/edges/CubicBezierEdge.js
  14. +8
    -11
      lib/network/modules/components/edges/util/BezierEdgeBase.js
  15. +48
    -0
      lib/network/modules/components/edges/util/CubicBezierEdgeBase.js
  16. +4
    -0
      lib/network/modules/components/nodes/util/NodeBase.js
  17. +4
    -2
      lib/network/options.js

+ 1
- 0
HISTORY.md View File

@ -14,6 +14,7 @@ http://visjs.org
### Network ### Network
- Added moveNode method. - Added moveNode method.
- Added cubic Bezier curves.
## 2015-07-22, version 4.6.0 ## 2015-07-22, version 4.6.0

+ 663
- 370
dist/vis.js
File diff suppressed because it is too large
View File


+ 9
- 1
docs/network/edges.html View File

@ -623,13 +623,21 @@ var options: {
<td>String</td> <td>String</td>
<td><code>'dynamic'</code></td> <td><code>'dynamic'</code></td>
<td>Possible options: <code>'dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', <td>Possible options: <code>'dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal',
'vertical', 'curvedCW', 'curvedCCW'</code>. Take a look at our example 26 to see what these look like
'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'</code>. Take a look at our example 26 to see what these look like
and pick the one that you like best! and pick the one that you like best!
<br><br> <br><br>
When using dynamic, the edges will have an invisible support node guiding the shape. This node is part of the When using dynamic, the edges will have an invisible support node guiding the shape. This node is part of the
physics simulation. physics simulation.
</td> </td>
</tr> </tr>
<tr parent="smooth" class="hidden">
<td class="indent">smooth.forceDirection</td>
<td>String or Boolean</td>
<td><code>false</code></td>
<td>Accepted options: <code>['horizontal', 'vertical', 'none']</code>. This options is only used with the cubicBezier curves. When true, horizontal is chosen, when false,
the direction that is larger (x distance between nodes vs y distance between nodes) is used. If the x distance is larger, horizontal. This is ment to be used with hierarchical layouts.
</td>
</tr>
<tr parent="smooth" class="hidden"> <tr parent="smooth" class="hidden">
<td class="indent">smooth.roundness</td> <td class="indent">smooth.roundness</td>
<td>Number</td> <td>Number</td>

+ 7
- 49
examples/network/edgeStyles/smooth.html View File

@ -33,37 +33,15 @@
<br /> <br /> <br /> <br />
</div> </div>
<p>
Smooth curve type:
<select id="dropdownID" onchange="update();">
<option value="continuous" selected="selected">continuous</option>
<option value="discrete">discrete</option>
<option value="diagonalCross">diagonalCross</option>
<option value="straightCross">straightCross</option>
<option value="horizontal">horizontal</option>
<option value="vertical">vertical</option>
<option value="curvedCW">curvedCW</option>
<option value="curvedCCW">curvedCCW</option>
<option value="dynamic">dynamic</option>
<option value="none">none</option>
</select>
</p>
<p>
Roundness (0..1): <input type="range" min="0" max="1" value="0.5" step="0.05" style="width:200px" id="roundnessSlider" onchange="update();"> <input id="roundnessScreen" style="width:30px;" value="0.5"> <br>(0.5 is max roundness for continuous, 1.0 for the others)
</p>
<div id="mynetwork"></div> <div id="mynetwork"></div>
<script type="text/javascript"> <script type="text/javascript">
var dropdown = document.getElementById("dropdownID");
var roundnessSlider = document.getElementById("roundnessSlider");
var roundnessScreen = document.getElementById("roundnessScreen");
// create an array with nodes // create an array with nodes
var nodes = [ var nodes = [
{id: 1, label: 'Fixed node', x:0, y:0, fixed:true}, {id: 1, label: 'Fixed node', x:0, y:0, fixed:true},
{id: 2, label: 'Drag me', x:150, y:130, physics:false}, {id: 2, label: 'Drag me', x:150, y:130, physics:false},
{id: 3, label: 'Obstacle', x:80, y:-80, fixed:true, mass:5}
{id: 3, label: 'Obstacle', x:80, y:-80, fixed:true, mass:10}
]; ];
// create an array with edges // create an array with edges
@ -79,6 +57,12 @@
}; };
var options = { var options = {
physics:true, physics:true,
configure:function (option, path) {
if (path.indexOf('smooth') !== -1 || option === 'smooth') {
return true;
}
return false;
},
edges: { edges: {
smooth: { smooth: {
type: 'continuous' type: 'continuous'
@ -87,33 +71,7 @@
}; };
var network = new vis.Network(container, data, options); var network = new vis.Network(container, data, options);
function update() {
var type = dropdown.value;
var options;
var roundness = parseFloat(roundnessSlider.value);
roundnessScreen.value = roundness;
if (type === 'none') {
options = {
edges: {
smooth: false
}
};
}
else {
options = {
edges: {
smooth: {
type: type,
roundness: roundness
}
}
};
}
network.setOptions(options);
}
update();
</script> </script>
</body> </body>

+ 5
- 1
examples/network/layout/hierarchicalLayoutUserdefined.html View File

@ -79,7 +79,11 @@
var options = { var options = {
edges: { edges: {
smooth: true
smooth: {
type:'cubicBezier',
forceDirection: (directionInput.value == "UD" || directionInput.value == "DU") ? 'vertical' : 'horizontal',
roundness: 0.4
}
}, },
layout: { layout: {
hierarchical:{ hierarchical:{

+ 3
- 3
lib/network/modules/Clustering.js View File

@ -383,7 +383,7 @@ class ClusterEngine {
// if this is a cluster edge that is fully encompassed in the cluster, we want to delete it // if this is a cluster edge that is fully encompassed in the cluster, we want to delete it
// this check verifies that both of the connected nodes are in this cluster // this check verifies that both of the connected nodes are in this cluster
if (edgeId.substr(0,12) === "clusterEdge:" && childNodesObj[edge.fromId] !== undefined && childNodesObj[edge.toId] !== undefined) { if (edgeId.substr(0,12) === "clusterEdge:" && childNodesObj[edge.fromId] !== undefined && childNodesObj[edge.toId] !== undefined) {
edge.edgeType.cleanup();
edge.cleanup();
// this removes the edge from node.edges, which is why edgeIds is formed // this removes the edge from node.edges, which is why edgeIds is formed
edge.disconnect(); edge.disconnect();
delete childEdgesObj[edgeId]; delete childEdgesObj[edgeId];
@ -538,7 +538,7 @@ class ClusterEngine {
let edge = containedEdges[edgeId]; let edge = containedEdges[edgeId];
// if this edge was a temporary edge and it's connected nodes do not exist anymore, we remove it from the data // if this edge was a temporary edge and it's connected nodes do not exist anymore, we remove it from the data
if (this.body.nodes[edge.fromId] === undefined || this.body.nodes[edge.toId] === undefined || edge.toId == clusterNodeId || edge.fromId == clusterNodeId) { if (this.body.nodes[edge.fromId] === undefined || this.body.nodes[edge.toId] === undefined || edge.toId == clusterNodeId || edge.fromId == clusterNodeId) {
edge.edgeType.cleanup();
edge.cleanup();
// this removes the edge from node.edges, which is why edgeIds is formed // this removes the edge from node.edges, which is why edgeIds is formed
edge.disconnect(); edge.disconnect();
delete this.body.edges[edgeId]; delete this.body.edges[edgeId];
@ -591,7 +591,7 @@ class ClusterEngine {
// actually removing the edges // actually removing the edges
for (let i = 0; i < removeIds.length; i++) { for (let i = 0; i < removeIds.length; i++) {
let edgeId = removeIds[i]; let edgeId = removeIds[i];
this.body.edges[edgeId].edgeType.cleanup();
this.body.edges[edgeId].cleanup();
// this removes the edge from node.edges, which is why edgeIds is formed // this removes the edge from node.edges, which is why edgeIds is formed
this.body.edges[edgeId].disconnect(); this.body.edges[edgeId].disconnect();
delete this.body.edges[edgeId]; delete this.body.edges[edgeId];

+ 2
- 1
lib/network/modules/EdgesHandler.js View File

@ -81,6 +81,7 @@ class EdgesHandler {
smooth: { smooth: {
enabled: true, enabled: true,
type: "dynamic", type: "dynamic",
forceDirection:'none',
roundness: 0.5 roundness: 0.5
}, },
title:undefined, title:undefined,
@ -309,7 +310,7 @@ class EdgesHandler {
var id = ids[i]; var id = ids[i];
var edge = edges[id]; var edge = edges[id];
if (edge !== undefined) { if (edge !== undefined) {
edge.edgeType.cleanup();
edge.cleanup();
edge.disconnect(); edge.disconnect();
delete edges[id]; delete edges[id];
} }

+ 4
- 2
lib/network/modules/LayoutEngine.js View File

@ -126,12 +126,14 @@ class LayoutEngine {
this.optionsBackup.edges = { this.optionsBackup.edges = {
smooth: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled, smooth: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled,
type:allOptions.edges.smooth.type === undefined ? 'dynamic' : allOptions.edges.smooth.type, type:allOptions.edges.smooth.type === undefined ? 'dynamic' : allOptions.edges.smooth.type,
roundness: allOptions.edges.smooth.roundness === undefined ? 0.5 : allOptions.edges.smooth.roundness
roundness: allOptions.edges.smooth.roundness === undefined ? 0.5 : allOptions.edges.smooth.roundness,
forceDirection: allOptions.edges.smooth.forceDirection === undefined ? false : allOptions.edges.smooth.forceDirection
}; };
allOptions.edges.smooth = { allOptions.edges.smooth = {
enabled: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled, enabled: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled,
type:type, type:type,
roundness: allOptions.edges.smooth.roundness === undefined ? 0.5 : allOptions.edges.smooth.roundness
roundness: allOptions.edges.smooth.roundness === undefined ? 0.5 : allOptions.edges.smooth.roundness,
forceDirection: allOptions.edges.smooth.forceDirection === undefined ? false : allOptions.edges.smooth.forceDirection
} }
} }
} }

+ 1
- 2
lib/network/modules/NodesHandler.js View File

@ -433,8 +433,7 @@ class NodesHandler {
*/ */
moveNode(nodeId, x, y) { moveNode(nodeId, x, y) {
if (this.body.nodes[nodeId] !== undefined) { if (this.body.nodes[nodeId] !== undefined) {
this.body.nodes[nodeId].x = Number(x);
this.body.nodes[nodeId].y = Number(y);
this.body.nodes[nodeId].move(Number(x), Number(y));
setTimeout(() => {this.body.emitter.emit("startSimulation")},0); setTimeout(() => {this.body.emitter.emit("startSimulation")},0);
} }
else { else {

+ 10
- 7
lib/network/modules/PhysicsEngine.js View File

@ -399,10 +399,12 @@ class PhysicsEngine {
* @private * @private
*/ */
_performStep(nodeId,maxVelocity) { _performStep(nodeId,maxVelocity) {
var node = this.body.nodes[nodeId];
var timestep = this.options.timestep;
var forces = this.physicsBody.forces;
var velocities = this.physicsBody.velocities;
let node = this.body.nodes[nodeId];
let timestep = this.options.timestep;
let forces = this.physicsBody.forces;
let velocities = this.physicsBody.velocities;
let x = node.x;
let y = node.y;
// store the state so we can revert // store the state so we can revert
this.previousStates[nodeId] = {x:node.x, y:node.y, vx:velocities[nodeId].x, vy:velocities[nodeId].y}; this.previousStates[nodeId] = {x:node.x, y:node.y, vx:velocities[nodeId].x, vy:velocities[nodeId].y};
@ -412,7 +414,7 @@ class PhysicsEngine {
let ax = (forces[nodeId].x - dx) / node.options.mass; // acceleration let ax = (forces[nodeId].x - dx) / node.options.mass; // acceleration
velocities[nodeId].x += ax * timestep; // velocity velocities[nodeId].x += ax * timestep; // velocity
velocities[nodeId].x = (Math.abs(velocities[nodeId].x) > maxVelocity) ? ((velocities[nodeId].x > 0) ? maxVelocity : -maxVelocity) : velocities[nodeId].x; velocities[nodeId].x = (Math.abs(velocities[nodeId].x) > maxVelocity) ? ((velocities[nodeId].x > 0) ? maxVelocity : -maxVelocity) : velocities[nodeId].x;
node.x += velocities[nodeId].x * timestep; // position
x += velocities[nodeId].x * timestep; // position
} }
else { else {
forces[nodeId].x = 0; forces[nodeId].x = 0;
@ -424,14 +426,15 @@ class PhysicsEngine {
let ay = (forces[nodeId].y - dy) / node.options.mass; // acceleration let ay = (forces[nodeId].y - dy) / node.options.mass; // acceleration
velocities[nodeId].y += ay * timestep; // velocity velocities[nodeId].y += ay * timestep; // velocity
velocities[nodeId].y = (Math.abs(velocities[nodeId].y) > maxVelocity) ? ((velocities[nodeId].y > 0) ? maxVelocity : -maxVelocity) : velocities[nodeId].y; velocities[nodeId].y = (Math.abs(velocities[nodeId].y) > maxVelocity) ? ((velocities[nodeId].y > 0) ? maxVelocity : -maxVelocity) : velocities[nodeId].y;
node.y += velocities[nodeId].y * timestep; // position
y += velocities[nodeId].y * timestep; // position
} }
else { else {
forces[nodeId].y = 0; forces[nodeId].y = 0;
velocities[nodeId].y = 0; velocities[nodeId].y = 0;
} }
var totalVelocity = Math.sqrt(Math.pow(velocities[nodeId].x,2) + Math.pow(velocities[nodeId].y,2));
node.move(x,y);
let totalVelocity = Math.sqrt(Math.pow(velocities[nodeId].x,2) + Math.pow(velocities[nodeId].y,2));
return totalVelocity; return totalVelocity;
} }

+ 19
- 4
lib/network/modules/components/Edge.js View File

@ -1,6 +1,7 @@
var util = require('../../../util'); var util = require('../../../util');
import Label from './shared/Label' import Label from './shared/Label'
import CubicBezierEdge from './edges/CubicBezierEdge'
import BezierEdgeDynamic from './edges/BezierEdgeDynamic' import BezierEdgeDynamic from './edges/BezierEdgeDynamic'
import BezierEdgeStatic from './edges/BezierEdgeStatic' import BezierEdgeStatic from './edges/BezierEdgeStatic'
import StraightEdge from './edges/StraightEdge' import StraightEdge from './edges/StraightEdge'
@ -208,13 +209,15 @@ class Edge {
updateEdgeType() { updateEdgeType() {
let dataChanged = false; let dataChanged = false;
let changeInType = true; let changeInType = true;
let smooth = this.options.smooth;
if (this.edgeType !== undefined) { if (this.edgeType !== undefined) {
if (this.edgeType instanceof BezierEdgeDynamic && this.options.smooth.enabled === true && this.options.smooth.type === 'dynamic') {changeInType = false;}
if (this.edgeType instanceof BezierEdgeStatic && this.options.smooth.enabled === true && this.options.smooth.type !== 'dynamic') {changeInType = false;}
if (this.edgeType instanceof StraightEdge && this.options.smooth.enabled === false) {changeInType = false;}
if (this.edgeType instanceof BezierEdgeDynamic && smooth.enabled === true && smooth.type === 'dynamic') {changeInType = false;}
if (this.edgeType instanceof CubicBezierEdge && smooth.enabled === true && smooth.type === 'cubicBezier') {changeInType = false;}
if (this.edgeType instanceof BezierEdgeStatic && smooth.enabled === true && smooth.type !== 'dynamic' && smooth.type !== 'cubicBezier') {changeInType = false;}
if (this.edgeType instanceof StraightEdge && smooth.enabled === false) {changeInType = false;}
if (changeInType === true) { if (changeInType === true) {
dataChanged = this.edgeType.cleanup();
dataChanged = this.cleanup();
} }
} }
@ -224,6 +227,9 @@ class Edge {
dataChanged = true; dataChanged = true;
this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule); this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
} }
else if (this.options.smooth.type === 'cubicBezier') {
this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
}
else { else {
this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule); this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
} }
@ -495,6 +501,15 @@ class Edge {
unselect() { unselect() {
this.selected = false; this.selected = false;
} }
/**
* cleans all required things on delete
* @returns {*}
*/
cleanup() {
return this.edgeType.cleanup();
}
} }
export default Edge; export default Edge;

+ 17
- 0
lib/network/modules/components/Node.js View File

@ -440,7 +440,24 @@ class Node {
); );
} }
/**
* move the node to a new position.
* @param x
* @param y
*/
move(x,y) {
this.x = x;
this.y = y;
this.shape.move(x,y)
}
/**
* clean all required things on delete.
* @returns {*}
*/
cleanup() {
return this.shape.cleanup();
}
} }
export default Node; export default Node;

+ 91
- 0
lib/network/modules/components/edges/CubicBezierEdge.js View File

@ -0,0 +1,91 @@
import CubicBezierEdgeBase from './util/CubicBezierEdgeBase'
class CubicBezierEdge extends CubicBezierEdgeBase {
constructor(options, body, labelModule) {
super(options, body, labelModule);
}
/**
* Draw a line between two nodes
* @param {CanvasRenderingContext2D} ctx
* @private
*/
_line(ctx) {
// get the coordinates of the support points.
let [via1,via2] = this._getViaCoordinates();
let returnValue = [via1,via2];
// start drawing the line.
ctx.beginPath();
ctx.moveTo(this.from.x, this.from.y);
// fallback to normal straight edges
if (via1.x === undefined) {
ctx.lineTo(this.to.x, this.to.y);
returnValue = undefined;
}
else {
ctx.bezierCurveTo(via1.x, via1.y, via2.x, via2.y, this.to.x, this.to.y);
}
// draw shadow if enabled
this.enableShadow(ctx);
ctx.stroke();
this.disableShadow(ctx);
return returnValue;
}
_getViaCoordinates() {
let dx = this.from.x - this.to.x;
let dy = this.from.y - this.to.y;
let x1, y1, x2, y2;
let roundness = this.options.smooth.roundness;;
// horizontal if x > y or if direction is forced or if direction is horizontal
if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === 'horizontal') && this.options.smooth.forceDirection !== 'vertical') {
y1 = this.from.y;
y2 = this.to.y;
x1 = this.from.x - roundness * dx;
x2 = this.to.x + roundness * dx;
}
else {
y1 = this.from.y - roundness * dy;
y2 = this.to.y + roundness * dy;
x1 = this.from.x;
x2 = this.to.x;
}
return [{x: x1, y: y1},{x: x2, y: y2}];
}
_findBorderPosition(nearNode, ctx) {
return this._findBorderPositionBezier(nearNode, ctx);
}
_getDistanceToEdge(x1, y1, x2, y2, x3, y3, [via1, via2] = this._getViaCoordinates()) { // x3,y3 is the point
return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via1, via2);
}
/**
* Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
* @param percentage
* @param via
* @returns {{x: number, y: number}}
* @private
*/
getPoint(percentage, [via1, via2] = this._getViaCoordinates()) {
let t = percentage;
let vec = [];
vec[0] = Math.pow(1 - t, 3);
vec[1] = 3 * t * Math.pow(1 - t, 2);
vec[2] = 3 * Math.pow(t,2) * (1 - t);
vec[3] = Math.pow(t, 3);
let x = vec[0] * this.from.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.to.x;
let y = vec[0] * this.from.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.to.y;
return {x: x, y: y};
}
}
export default CubicBezierEdge;

+ 8
- 11
lib/network/modules/components/edges/util/BezierEdgeBase.js View File

@ -73,18 +73,15 @@ class BezierEdgeBase extends EdgeBase {
* Calculate the distance between a point (x3,y3) and a line segment from * Calculate the distance between a point (x3,y3) and a line segment from
* (x1,y1) to (x2,y2). * (x1,y1) to (x2,y2).
* http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
* @param {number} x1
* @param {number} y1
* @param {number} x2
* @param {number} y2
* @param {number} x3
* @param {number} y3
* @param {number} x1 from x
* @param {number} y1 from y
* @param {number} x2 to x
* @param {number} y2 to y
* @param {number} x3 point to check x
* @param {number} y3 point to check y
* @private * @private
*/ */
_getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) { // x3,y3 is the point _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) { // x3,y3 is the point
let xVia, yVia;
xVia = via.x;
yVia = via.y;
let minDistance = 1e9; let minDistance = 1e9;
let distance; let distance;
let i, t, x, y; let i, t, x, y;
@ -92,8 +89,8 @@ class BezierEdgeBase extends EdgeBase {
let lastY = y1; let lastY = y1;
for (i = 1; i < 10; i++) { for (i = 1; i < 10; i++) {
t = 0.1 * i; t = 0.1 * i;
x = Math.pow(1 - t, 2) * x1 + (2 * t * (1 - t)) * xVia + Math.pow(t, 2) * x2;
y = Math.pow(1 - t, 2) * y1 + (2 * t * (1 - t)) * yVia + Math.pow(t, 2) * y2;
x = Math.pow(1 - t, 2) * x1 + (2 * t * (1 - t)) * via.x + Math.pow(t, 2) * x2;
y = Math.pow(1 - t, 2) * y1 + (2 * t * (1 - t)) * via.y + Math.pow(t, 2) * y2;
if (i > 0) { if (i > 0) {
distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3); distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
minDistance = distance < minDistance ? distance : minDistance; minDistance = distance < minDistance ? distance : minDistance;

+ 48
- 0
lib/network/modules/components/edges/util/CubicBezierEdgeBase.js View File

@ -0,0 +1,48 @@
import BezierEdgeBase from './BezierEdgeBase'
class CubicBezierEdgeBase extends BezierEdgeBase {
constructor(options, body, labelModule) {
super(options, body, labelModule);
}
/**
* Calculate the distance between a point (x3,y3) and a line segment from
* (x1,y1) to (x2,y2).
* http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve
* @param {number} x1 from x
* @param {number} y1 from y
* @param {number} x2 to x
* @param {number} y2 to y
* @param {number} x3 point to check x
* @param {number} y3 point to check y
* @private
*/
_getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via1, via2) { // x3,y3 is the point
let minDistance = 1e9;
let distance;
let i, t, x, y;
let lastX = x1;
let lastY = y1;
let vec = [0,0,0,0]
for (i = 1; i < 10; i++) {
t = 0.1 * i;
vec[0] = Math.pow(1 - t, 3);
vec[1] = 3 * t * Math.pow(1 - t, 2);
vec[2] = 3 * Math.pow(t,2) * (1 - t);
vec[3] = Math.pow(t, 3);
x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
if (i > 0) {
distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
minDistance = distance < minDistance ? distance : minDistance;
}
lastX = x;
lastY = y;
}
return minDistance;
}
}
export default CubicBezierEdgeBase;

+ 4
- 0
lib/network/modules/components/nodes/util/NodeBase.js View File

@ -67,6 +67,10 @@ class NodeBase {
} }
} }
} }
// possible to overload in the shapes.
move(x,y) {}
cleanup() {}
} }
export default NodeBase; export default NodeBase;

+ 4
- 2
lib/network/options.js View File

@ -79,8 +79,9 @@ let allOptions = {
}, },
smooth: { smooth: {
enabled: { boolean }, enabled: { boolean },
type: { string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'] },
type: { string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'] },
roundness: { number }, roundness: { number },
forceDirection: { string: ['horizontal', 'vertical', 'none'], boolean },
__type__: { object, boolean } __type__: { object, boolean }
}, },
title: { string, 'undefined': 'undefined' }, title: { string, 'undefined': 'undefined' },
@ -401,7 +402,8 @@ let configureOptions = {
}, },
smooth: { smooth: {
enabled: true, enabled: true,
type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'],
type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'],
forceDirection: ['horizontal', 'vertical', 'none'],
roundness: [0.5, 0, 1, 0.05] roundness: [0.5, 0, 1, 0.05]
}, },
width: [1, 0, 30, 1] width: [1, 0, 30, 1]

Loading…
Cancel
Save