vis-network
Version:
A dynamic, browser-based visualization library.
137 lines (125 loc) • 3.48 kB
text/typescript
import { CubicBezierEdgeBase } from "./util/cubic-bezier-edge-base";
import {
EdgeFormattingValues,
Label,
EdgeOptions,
Point,
PointT,
SelectiveRequired,
VBody,
VNode
} from "./util/types";
/**
* A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
*/
export class CubicBezierEdge extends CubicBezierEdgeBase<[Point, Point]> {
/**
* Create a new instance.
*
* @param options - The options object of given edge.
* @param body - The body of the network.
* @param labelModule - Label module.
*/
public constructor(options: EdgeOptions, body: VBody, labelModule: Label) {
super(options, body, labelModule);
}
/** @inheritdoc */
protected _line(
ctx: CanvasRenderingContext2D,
values: SelectiveRequired<
EdgeFormattingValues,
| "backgroundColor"
| "backgroundSize"
| "shadowColor"
| "shadowSize"
| "shadowX"
| "shadowY"
>,
viaNodes: [Point, Point]
): void {
// get the coordinates of the support points.
let via1 = viaNodes[0];
let via2 = viaNodes[1];
this._bezierCurve(ctx, values, via1, via2);
}
/**
* Compute the additional points the edge passes through.
*
* @returns Cartesian coordinates of the points the edge passes through.
*/
protected _getViaCoordinates(): [Point, Point] {
const dx = this.from.x - this.to.x;
const dy = this.from.y - this.to.y;
let x1: number;
let y1: number;
let x2: number;
let y2: number;
const 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 }];
}
/** @inheritdoc */
public getViaNode(): [Point, Point] {
return this._getViaCoordinates();
}
/** @inheritdoc */
protected _findBorderPosition(
nearNode: VNode,
ctx: CanvasRenderingContext2D
): PointT {
return this._findBorderPositionBezier(nearNode, ctx);
}
/** @inheritdoc */
protected _getDistanceToEdge(
x1: number,
y1: number,
x2: number,
y2: number,
x3: number,
y3: number,
[via1, via2]: [Point, Point] = this._getViaCoordinates()
): number {
// x3,y3 is the point
return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
}
/** @inheritdoc */
public getPoint(
position: number,
[via1, via2]: [Point, Point] = this._getViaCoordinates()
): Point {
const t = position;
const vec: [number, number, number, number] = [
Math.pow(1 - t, 3),
3 * t * Math.pow(1 - t, 2),
3 * Math.pow(t, 2) * (1 - t),
Math.pow(t, 3)
];
const x =
vec[0] * this.fromPoint.x +
vec[1] * via1.x +
vec[2] * via2.x +
vec[3] * this.toPoint.x;
const y =
vec[0] * this.fromPoint.y +
vec[1] * via1.y +
vec[2] * via2.y +
vec[3] * this.toPoint.y;
return { x: x, y: y };
}
}