vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

351 lines
10 KiB

/**
* Created by Alex on 3/20/2015.
*/
var util = require("../../../../../util")
class BaseEdge {
constructor(options, body, labelModule) {
this.body = body;
this.labelModule = labelModule;
this.setOptions(options);
this.colorDirty = true;
}
setOptions(options) {
this.options = options;
this.from = this.body.nodes[this.options.from];
this.to = this.body.nodes[this.options.to];
this.id = this.options.id;
}
/**
* Redraw a edge as a line
* Draw this edge in the given canvas
* The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
* @param {CanvasRenderingContext2D} ctx
* @private
*/
drawLine(ctx, selected, hover) {
// set style
ctx.strokeStyle = this.getColor(ctx);
ctx.lineWidth = this.getLineWidth();
let via = undefined;
if (this.from != this.to) {
// draw line
if (this.options.dashes.enabled == true) {
via = this._drawDashedLine(ctx);
}
else {
via = this._line(ctx);
}
}
else {
let x, y;
let radius = this.options.selfReferenceSize;
let node = this.from;
node.resize(ctx);
if (node.shape.width > node.shape.height) {
x = node.x + node.shape.width * 0.5;
y = node.y - radius;
}
else {
x = node.x + radius;
y = node.y - node.shape.height * 0.5;
}
this._circle(ctx, x, y, radius);
}
return via;
}
_drawDashedLine(ctx) {
let via = undefined;
// only firefox and chrome support this method, else we use the legacy one.
if (ctx.setLineDash !== undefined) {
ctx.save();
// configure the dash pattern
var pattern = [0];
if (this.options.dashes.length !== undefined && this.options.dashes.gap !== undefined) {
pattern = [this.options.dashes.length, this.options.dashes.gap];
}
else {
pattern = [5, 5];
}
// set dash settings for chrome or firefox
ctx.setLineDash(pattern);
ctx.lineDashOffset = 0;
// draw the line
via = this._line(ctx);
// restore the dash settings.
ctx.setLineDash([0]);
ctx.lineDashOffset = 0;
ctx.restore();
}
else { // unsupporting smooth lines
// draw dashes line
ctx.beginPath();
ctx.lineCap = 'round';
if (this.options.dashes.altLength !== undefined) //If an alt dash value has been set add to the array this value
{
ctx.dashesLine(this.from.x, this.from.y, this.to.x, this.to.y,
[this.options.dashes.length, this.options.dashes.gap, this.options.dashes.altLength, this.options.dashes.gap]);
}
else if (this.options.dashes.length !== undefined && this.options.dashes.gap !== undefined) //If a dash and gap value has been set add to the array this value
{
ctx.dashesLine(this.from.x, this.from.y, this.to.x, this.to.y,
[this.options.dashes.length, this.options.dashes.gap]);
}
else //If all else fails draw a line
{
ctx.moveTo(this.from.x, this.from.y);
ctx.lineTo(this.to.x, this.to.y);
}
ctx.stroke();
}
return via;
}
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);
}
}
/**
* This function uses binary search to look for the point where the circle crosses the border of the node.
* @param x
* @param y
* @param radius
* @param node
* @param low
* @param high
* @param direction
* @param ctx
* @returns {*}
* @private
*/
_findBorderPositionCircle(node, ctx, options) {
let x = options.x;
let y = options.y;
let low = options.low;
let high = options.high;
let direction = options.direction;
let maxIterations = 10;
let iteration = 0;
let radius = this.options.selfReferenceSize;
let pos, angle, distanceToBorder, distanceToPoint, difference;
let threshold = 0.05;
while (low <= high && iteration < maxIterations) {
let middle = (low + high) * 0.5;
pos = this._pointOnCircle(x,y,radius,middle);
angle = Math.atan2((node.y - pos.y), (node.x - pos.x));
distanceToBorder = node.distanceToBorder(ctx, angle);
distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
difference = distanceToBorder - distanceToPoint;
if (Math.abs(difference) < threshold) {
break; // found
}
else if (difference > 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
if (direction > 0) {
low = middle;
}
else {
high = middle;
}
}
else {
if (direction > 0) {
high = middle;
}
else {
low = middle;
}
}
iteration++;
}
pos.t = middle;
return pos;
}
/**
* Get the line width of the edge. Depends on width and whether one of the
* connected nodes is selected.
* @return {Number} width
* @private
*/
getLineWidth(selected, hover) {
if (selected == true) {
return Math.max(Math.min(this.options.widthSelectionMultiplier * this.options.width, this.options.scaling.max), 0.3 / this.body.view.scale);
}
else {
if (hover == true) {
return Math.max(Math.min(this.options.hoverWidth, this.options.scaling.max), 0.3 / this.body.view.scale);
}
else {
return Math.max(this.options.width, 0.3 / this.body.view.scale);
}
}
}
getColor(ctx) {
var colorObj = this.options.color;
if (colorObj.inherit.enabled === true) {
if (colorObj.inherit.useGradients == true) {
var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
var fromColor, toColor;
fromColor = this.from.options.color.highlight.border;
toColor = this.to.options.color.highlight.border;
if (this.from.selected == false && this.to.selected == false) {
fromColor = util.overrideOpacity(this.from.options.color.border, this.options.color.opacity);
toColor = util.overrideOpacity(this.to.options.color.border, this.options.color.opacity);
}
else if (this.from.selected == true && this.to.selected == false) {
toColor = this.to.options.color.border;
}
else if (this.from.selected == false && this.to.selected == true) {
fromColor = this.from.options.color.border;
}
grd.addColorStop(0, fromColor);
grd.addColorStop(1, toColor);
// -------------------- this returns -------------------- //
return grd;
}
if (this.colorDirty === true) {
if (colorObj.inherit.source == "to") {
colorObj.highlight = this.to.options.color.highlight.border;
colorObj.hover = this.to.options.color.hover.border;
colorObj.color = util.overrideOpacity(this.to.options.color.border, this.options.color.opacity);
}
else { // (this.options.color.inherit.source == "from") {
colorObj.highlight = this.from.options.color.highlight.border;
colorObj.hover = this.from.options.color.hover.border;
colorObj.color = util.overrideOpacity(this.from.options.color.border, this.options.color.opacity);
}
}
}
// if color inherit is on and gradients are used, the function has already returned by now.
this.colorDirty = false;
if (this.selected == true) {
return colorObj.highlight;
}
else if (this.hover == true) {
return colorObj.hover;
}
else {
return colorObj.color;
}
}
/**
* Draw a line from a node to itself, a circle
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x
* @param {Number} y
* @param {Number} radius
* @private
*/
_circle(ctx, x, y, radius) {
// draw a circle
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
ctx.stroke();
}
/**
* 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
* @param {number} x1
* @param {number} y1
* @param {number} x2
* @param {number} y2
* @param {number} x3
* @param {number} y3
* @private
*/
getDistanceToEdge(x1, y1, x2, y2, x3, y3, via) { // x3,y3 is the point
var returnValue = 0;
if (this.from != this.to) {
returnValue = this._getDistanceToEdge(x1, y1, x2, y2, x3, y3, via)
}
else {
var x, y, dx, dy;
var radius = this.options.selfReferenceSize;
var node = this.from;
if (node.width > node.height) {
x = node.x + 0.5 * node.width;
y = node.y - radius;
}
else {
x = node.x + radius;
y = node.y - 0.5 * node.height;
}
dx = x - x3;
dy = y - y3;
returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
}
if (this.labelModule.size.left < x3 &&
this.labelModule.size.left + this.labelModule.size.width > x3 &&
this.labelModule.size.top < y3 &&
this.labelModule.size.top + this.labelModule.size.height > y3) {
return 0;
}
else {
return returnValue;
}
}
_getDistanceToLine(x1, y1, x2, y2, x3, y3) {
var px = x2 - x1;
var py = y2 - y1;
var something = px * px + py * py;
var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
if (u > 1) {
u = 1;
}
else if (u < 0) {
u = 0;
}
var x = x1 + u * px;
var y = y1 + u * py;
var dx = x - x3;
var dy = y - y3;
//# Note: If the actual distance does not matter,
//# if you only want to compare what this function
//# returns to other results of this function, you
//# can just return the squared distance instead
//# (i.e. remove the sqrt) to gain a little performance
return Math.sqrt(dx * dx + dy * dy);
}
}
export default BaseEdge;