From a903ec454d6eb6705ff8e91fd47d015f700fa24f Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 23 Mar 2015 10:59:43 +0100 Subject: [PATCH] moved arrows to baseEdge, gave the straight edge a + 50% length in the physics. --- dist/vis.js | 234 ++++++++---------- examples/network/01_basic_usage.html | 2 +- lib/network/modules/CanvasRenderer.js | 1 - lib/network/modules/components/Edge.js | 120 +-------- .../modules/components/edges/util/baseEdge.js | 106 +++++++- .../components/physics/SpringSolver.js | 5 +- 6 files changed, 223 insertions(+), 245 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index d89d8c54..474eb338 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 4.0.0-SNAPSHOT - * @date 2015-03-20 + * @date 2015-03-23 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -28468,13 +28468,13 @@ return /******/ (function(modules) { // webpackBootstrap drawArrows: { value: function drawArrows(ctx, viaNode) { if (this.options.arrows.from.enabled === true) { - this._drawArrowHead(ctx, "from", viaNode); + this.edgeType.drawArrowHead(ctx, "from", viaNode); } if (this.options.arrows.middle.enabled === true) { - this._drawArrowHead(ctx, "middle", viaNode); + this.edgeType.drawArrowHead(ctx, "middle", viaNode); } if (this.options.arrows.to.enabled === true) { - this._drawArrowHead(ctx, "to", viaNode); + this.edgeType.drawArrowHead(ctx, "to", viaNode); } }, writable: true, @@ -28593,123 +28593,6 @@ return /******/ (function(modules) { // webpackBootstrap writable: true, configurable: true }, - _drawArrowHead: { - - - - /** - * - * @param ctx - * @param position - * @param viaNode - */ - value: function _drawArrowHead(ctx, position, viaNode) { - // set style - ctx.strokeStyle = this.edgeType.getColor(ctx); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this.edgeType.getLineWidth(); - - // set lets - var angle = undefined; - var length = undefined; - var arrowPos = undefined; - var node1 = undefined; - var node2 = undefined; - var guideOffset = undefined; - var scaleFactor = undefined; - - if (position == "from") { - node1 = this.from; - node2 = this.to; - guideOffset = 0.1; - scaleFactor = this.options.arrows.from.scaleFactor; - } else if (position == "to") { - node1 = this.to; - node2 = this.from; - guideOffset = -0.1; - scaleFactor = this.options.arrows.to.scaleFactor; - } else { - node1 = this.to; - node2 = this.from; - scaleFactor = this.options.arrows.middle.scaleFactor; - } - - // if not connected to itself - if (node1 != node2) { - if (position !== "middle") { - // draw arrow head - if (this.options.smooth.enabled == true) { - arrowPos = this.edgeType.findBorderPosition(node1, ctx, { via: viaNode }); - var guidePos = this.edgeType.getPoint(Math.max(0, Math.min(1, arrowPos.t + guideOffset)), viaNode); - angle = Math.atan2(arrowPos.y - guidePos.y, arrowPos.x - guidePos.x); - } else { - angle = Math.atan2(node1.y - node2.y, node1.x - node2.x); - arrowPos = this.edgeType.findBorderPosition(node1, ctx); - } - } else { - angle = Math.atan2(node1.y - node2.y, node1.x - node2.x); - arrowPos = this.edgeType.getPoint(0.6, viaNode); // this is 0.6 to account for the size of the arrow. - } - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * scaleFactor; - ctx.arrow(arrowPos.x, arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); - } else { - // draw circle - var _angle = undefined, - point = undefined; - var x = undefined, - y = undefined; - var radius = this.options.selfReferenceSize; - if (!node1.width) { - node1.resize(ctx); - } - - // get circle coordinates - if (node1.width > node1.height) { - x = node1.x + node1.width * 0.5; - y = node1.y - radius; - } else { - x = node1.x + radius; - y = node1.y - node1.height * 0.5; - } - - - if (position == "from") { - point = this.edgeType.findBorderPosition(x, y, radius, node1, 0.25, 0.6, -1, ctx); - _angle = point.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; - } else if (position == "to") { - point = this.edgeType.findBorderPosition(x, y, radius, node1, 0.6, 0.8, 1, ctx); - _angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI; - } else { - point = this.edgeType.findBorderPosition(x, y, radius, 0.175); - _angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; - } - - // draw the arrowhead - var _length = (10 + 5 * this.options.width) * scaleFactor; - ctx.arrow(point.x, point.y, _angle, _length); - ctx.fill(); - ctx.stroke(); - } - }, - writable: true, - configurable: true - }, - setScale: { - - /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale - */ - value: function setScale(scale) { - this.networkScaleInv = 1 / scale; - }, - writable: true, - configurable: true - }, select: { value: function select() { this.selected = true; @@ -29437,7 +29320,6 @@ return /******/ (function(modules) { // webpackBootstrap findBorderPosition: { value: function findBorderPosition(nearNode, ctx, options) { if (this.from != this.to) { - console.log(1); return this._findBorderPosition(nearNode, ctx, options); } else { return this._findBorderPositionCircle(nearNode, ctx, options); @@ -29682,6 +29564,108 @@ return /******/ (function(modules) { // webpackBootstrap }, writable: true, configurable: true + }, + drawArrowHead: { + + /** + * + * @param ctx + * @param position + * @param viaNode + */ + value: function drawArrowHead(ctx, position, viaNode) { + // set style + ctx.strokeStyle = this.getColor(ctx); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this.getLineWidth(); + + // set lets + var angle = undefined; + var length = undefined; + var arrowPos = undefined; + var node1 = undefined; + var node2 = undefined; + var guideOffset = undefined; + var scaleFactor = undefined; + + if (position == "from") { + node1 = this.from; + node2 = this.to; + guideOffset = 0.1; + scaleFactor = this.options.arrows.from.scaleFactor; + } else if (position == "to") { + node1 = this.to; + node2 = this.from; + guideOffset = -0.1; + scaleFactor = this.options.arrows.to.scaleFactor; + } else { + node1 = this.to; + node2 = this.from; + scaleFactor = this.options.arrows.middle.scaleFactor; + } + + // if not connected to itself + if (node1 != node2) { + if (position !== "middle") { + // draw arrow head + if (this.options.smooth.enabled == true) { + arrowPos = this.findBorderPosition(node1, ctx, { via: viaNode }); + var guidePos = this.getPoint(Math.max(0, Math.min(1, arrowPos.t + guideOffset)), viaNode); + angle = Math.atan2(arrowPos.y - guidePos.y, arrowPos.x - guidePos.x); + } else { + angle = Math.atan2(node1.y - node2.y, node1.x - node2.x); + arrowPos = this.findBorderPosition(node1, ctx); + } + } else { + angle = Math.atan2(node1.y - node2.y, node1.x - node2.x); + arrowPos = this.getPoint(0.6, viaNode); // this is 0.6 to account for the size of the arrow. + } + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * scaleFactor; + ctx.arrow(arrowPos.x, arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); + } else { + // draw circle + var _angle = undefined, + point = undefined; + var x = undefined, + y = undefined; + var radius = this.options.selfReferenceSize; + if (!node1.width) { + node1.resize(ctx); + } + + // get circle coordinates + if (node1.width > node1.height) { + x = node1.x + node1.width * 0.5; + y = node1.y - radius; + } else { + x = node1.x + radius; + y = node1.y - node1.height * 0.5; + } + + + if (position == "from") { + point = this.findBorderPosition(x, y, radius, node1, 0.25, 0.6, -1, ctx); + _angle = point.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; + } else if (position == "to") { + point = this.findBorderPosition(x, y, radius, node1, 0.6, 0.8, 1, ctx); + _angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI; + } else { + point = this.findBorderPosition(x, y, radius, 0.175); + _angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; + } + + // draw the arrowhead + var _length = (10 + 5 * this.options.width) * scaleFactor; + ctx.arrow(point.x, point.y, _angle, _length); + ctx.fill(); + ctx.stroke(); + } + }, + writable: true, + configurable: true } }); @@ -31335,8 +31319,8 @@ return /******/ (function(modules) { // webpackBootstrap if (edge.connected === true) { // only calculate forces if nodes are in the same sector if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) { - edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length; if (edge.edgeType.via !== undefined) { + edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length; var node1 = edge.to; var node2 = edge.edgeType.via; var node3 = edge.from; @@ -31345,6 +31329,9 @@ return /******/ (function(modules) { // webpackBootstrap this._calculateSpringForce(node1, node2, 0.5 * edgeLength); this._calculateSpringForce(node2, node3, 0.5 * edgeLength); } else { + // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use + // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger. + edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length; this._calculateSpringForce(edge.from, edge.to, edgeLength); } } @@ -32579,7 +32566,6 @@ return /******/ (function(modules) { // webpackBootstrap for (var i = 0; i < edgeIndices.length; i++) { edge = edges[edgeIndices[i]]; - edge.setScale(this.body.view.scale); if (edge.connected === true) { edge.draw(ctx); } diff --git a/examples/network/01_basic_usage.html b/examples/network/01_basic_usage.html index 2a83ea75..79400ac4 100644 --- a/examples/network/01_basic_usage.html +++ b/examples/network/01_basic_usage.html @@ -33,7 +33,7 @@ var edges = [ {from: 1, to: 3}, {from: 1, to: 1}, - {from: 1, to: 2,smooth:false, arrows:{from:false, middle:false, to: true}}, + {from: 1, to: 2,smooth:false, arrows:{from:true, middle:true, to: true}}, {from: 2, to: 4}, {from: 2, to: 5} ]; diff --git a/lib/network/modules/CanvasRenderer.js b/lib/network/modules/CanvasRenderer.js index 2076765c..808b2819 100644 --- a/lib/network/modules/CanvasRenderer.js +++ b/lib/network/modules/CanvasRenderer.js @@ -220,7 +220,6 @@ class CanvasRenderer { for (let i = 0; i < edgeIndices.length; i++) { edge = edges[edgeIndices[i]]; - edge.setScale(this.body.view.scale); if (edge.connected === true) { edge.draw(ctx); } diff --git a/lib/network/modules/components/Edge.js b/lib/network/modules/components/Edge.js index d6515298..4f69db8b 100644 --- a/lib/network/modules/components/Edge.js +++ b/lib/network/modules/components/Edge.js @@ -278,9 +278,9 @@ class Edge { } drawArrows(ctx, viaNode) { - if (this.options.arrows.from.enabled === true) {this._drawArrowHead(ctx,'from', viaNode);} - if (this.options.arrows.middle.enabled === true) {this._drawArrowHead(ctx,'middle', viaNode);} - if (this.options.arrows.to.enabled === true) {this._drawArrowHead(ctx,'to', viaNode);} + if (this.options.arrows.from.enabled === true) {this.edgeType.drawArrowHead(ctx,'from', viaNode);} + if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx,'middle', viaNode);} + if (this.options.arrows.to.enabled === true) {this.edgeType.drawArrowHead(ctx,'to', viaNode);} } drawLabel(ctx, viaNode) { @@ -385,120 +385,6 @@ class Edge { } - - /** - * - * @param ctx - * @param position - * @param viaNode - */ - _drawArrowHead(ctx,position,viaNode) { - // set style - ctx.strokeStyle = this.edgeType.getColor(ctx); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this.edgeType.getLineWidth(); - - // set lets - let angle; - let length; - let arrowPos; - let node1; - let node2; - let guideOffset; - let scaleFactor; - - if (position == 'from') { - node1 = this.from; - node2 = this.to; - guideOffset = 0.1; - scaleFactor = this.options.arrows.from.scaleFactor; - } - else if (position == 'to') { - node1 = this.to; - node2 = this.from; - guideOffset = -0.1; - scaleFactor = this.options.arrows.to.scaleFactor; - } - else { - node1 = this.to; - node2 = this.from; - scaleFactor = this.options.arrows.middle.scaleFactor; - } - - // if not connected to itself - if (node1 != node2) { - if (position !== 'middle') { - // draw arrow head - if (this.options.smooth.enabled == true) { - arrowPos = this.edgeType.findBorderPosition(node1, ctx, {via:viaNode}); - let guidePos = this.edgeType.getPoint(Math.max(0.0,Math.min(1.0,arrowPos.t + guideOffset)), viaNode); - angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); - } - else { - angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x)); - arrowPos = this.edgeType.findBorderPosition(node1, ctx); - } - } - else { - angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x)); - arrowPos = this.edgeType.getPoint(0.6, viaNode); // this is 0.6 to account for the size of the arrow. - } - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * scaleFactor; - ctx.arrow(arrowPos.x, arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); - } - else { - // draw circle - let angle, point; - let x, y; - let radius = this.options.selfReferenceSize; - if (!node1.width) { - node1.resize(ctx); - } - - // get circle coordinates - if (node1.width > node1.height) { - x = node1.x + node1.width * 0.5; - y = node1.y - radius; - } - else { - x = node1.x + radius; - y = node1.y - node1.height * 0.5; - } - - - if (position == 'from') { - point = this.edgeType.findBorderPosition(x, y, radius, node1, 0.25, 0.6, -1, ctx); - angle = point.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; - } - else if (position == 'to') { - point = this.edgeType.findBorderPosition(x, y, radius, node1, 0.6, 0.8, 1, ctx); - angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI; - } - else { - point = this.edgeType.findBorderPosition(x,y,radius,0.175); - angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; - } - - // draw the arrowhead - let length = (10 + 5 * this.options.width) * scaleFactor; - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - } - } - - /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale - */ - setScale(scale) { - this.networkScaleInv = 1.0 / scale; - } - select() { this.selected = true; } diff --git a/lib/network/modules/components/edges/util/baseEdge.js b/lib/network/modules/components/edges/util/baseEdge.js index 58feef42..5a39a1df 100644 --- a/lib/network/modules/components/edges/util/baseEdge.js +++ b/lib/network/modules/components/edges/util/baseEdge.js @@ -112,7 +112,6 @@ class BaseEdge { findBorderPosition(nearNode, ctx, options) { if (this.from != this.to) { - console.log(1) return this._findBorderPosition(nearNode, ctx, options); } else { @@ -346,6 +345,111 @@ class BaseEdge { return Math.sqrt(dx * dx + dy * dy); } + + /** + * + * @param ctx + * @param position + * @param viaNode + */ + drawArrowHead(ctx,position,viaNode) { + // set style + ctx.strokeStyle = this.getColor(ctx); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this.getLineWidth(); + + // set lets + let angle; + let length; + let arrowPos; + let node1; + let node2; + let guideOffset; + let scaleFactor; + + if (position == 'from') { + node1 = this.from; + node2 = this.to; + guideOffset = 0.1; + scaleFactor = this.options.arrows.from.scaleFactor; + } + else if (position == 'to') { + node1 = this.to; + node2 = this.from; + guideOffset = -0.1; + scaleFactor = this.options.arrows.to.scaleFactor; + } + else { + node1 = this.to; + node2 = this.from; + scaleFactor = this.options.arrows.middle.scaleFactor; + } + + // if not connected to itself + if (node1 != node2) { + if (position !== 'middle') { + // draw arrow head + if (this.options.smooth.enabled == true) { + arrowPos = this.findBorderPosition(node1, ctx, {via:viaNode}); + let guidePos = this.getPoint(Math.max(0.0,Math.min(1.0,arrowPos.t + guideOffset)), viaNode); + angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); + } + else { + angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x)); + arrowPos = this.findBorderPosition(node1, ctx); + } + } + else { + angle = Math.atan2((node1.y - node2.y), (node1.x - node2.x)); + arrowPos = this.getPoint(0.6, viaNode); // this is 0.6 to account for the size of the arrow. + } + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * scaleFactor; + ctx.arrow(arrowPos.x, arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); + } + else { + // draw circle + let angle, point; + let x, y; + let radius = this.options.selfReferenceSize; + if (!node1.width) { + node1.resize(ctx); + } + + // get circle coordinates + if (node1.width > node1.height) { + x = node1.x + node1.width * 0.5; + y = node1.y - radius; + } + else { + x = node1.x + radius; + y = node1.y - node1.height * 0.5; + } + + + if (position == 'from') { + point = this.findBorderPosition(x, y, radius, node1, 0.25, 0.6, -1, ctx); + angle = point.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; + } + else if (position == 'to') { + point = this.findBorderPosition(x, y, radius, node1, 0.6, 0.8, 1, ctx); + angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI; + } + else { + point = this.findBorderPosition(x,y,radius,0.175); + angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; + } + + // draw the arrowhead + let length = (10 + 5 * this.options.width) * scaleFactor; + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + } + } + } export default BaseEdge; \ No newline at end of file diff --git a/lib/network/modules/components/physics/SpringSolver.js b/lib/network/modules/components/physics/SpringSolver.js index 433fcd61..37befc93 100644 --- a/lib/network/modules/components/physics/SpringSolver.js +++ b/lib/network/modules/components/physics/SpringSolver.js @@ -29,8 +29,8 @@ class SpringSolver { if (edge.connected === true) { // only calculate forces if nodes are in the same sector if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) { - edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length; if (edge.edgeType.via !== undefined) { + edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length; var node1 = edge.to; var node2 = edge.edgeType.via; var node3 = edge.from; @@ -40,6 +40,9 @@ class SpringSolver { this._calculateSpringForce(node2, node3, 0.5 * edgeLength); } else { + // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use + // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger. + edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5: edge.options.length; this._calculateSpringForce(edge.from, edge.to, edgeLength); } }