|
@ -1,5 +1,7 @@ |
|
|
var util = require('../../../../util'); |
|
|
var util = require('../../../../util'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import Label from '../unified/label.js' |
|
|
/** |
|
|
/** |
|
|
* @class Edge |
|
|
* @class Edge |
|
|
* |
|
|
* |
|
@ -33,7 +35,6 @@ class Edge { |
|
|
this.value = undefined; |
|
|
this.value = undefined; |
|
|
this.selected = false; |
|
|
this.selected = false; |
|
|
this.hover = false; |
|
|
this.hover = false; |
|
|
this.labelDimensions = {top: 0, left: 0, width: 0, height: 0, yLine: 0}; // could be cached
|
|
|
|
|
|
this.labelDirty = true; |
|
|
this.labelDirty = true; |
|
|
this.colorDirty = true; |
|
|
this.colorDirty = true; |
|
|
|
|
|
|
|
@ -51,6 +52,8 @@ class Edge { |
|
|
|
|
|
|
|
|
this.connected = false; |
|
|
this.connected = false; |
|
|
|
|
|
|
|
|
|
|
|
this.labelModule = new Label(this.body, this.options); |
|
|
|
|
|
|
|
|
this.setOptions(options, true); |
|
|
this.setOptions(options, true); |
|
|
|
|
|
|
|
|
this.controlNodesEnabled = false; |
|
|
this.controlNodesEnabled = false; |
|
@ -101,12 +104,6 @@ class Edge { |
|
|
if (options.id !== undefined) {this.id = options.id;} |
|
|
if (options.id !== undefined) {this.id = options.id;} |
|
|
if (options.from !== undefined) {this.fromId = options.from;} |
|
|
if (options.from !== undefined) {this.fromId = options.from;} |
|
|
if (options.to !== undefined) {this.toId = options.to;} |
|
|
if (options.to !== undefined) {this.toId = options.to;} |
|
|
|
|
|
|
|
|
if (options.label !== undefined) { |
|
|
|
|
|
this.label = options.label; |
|
|
|
|
|
this.labelDirty = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.title !== undefined) {this.title = options.title;} |
|
|
if (options.title !== undefined) {this.title = options.title;} |
|
|
if (options.value !== undefined) {this.value = options.value;} |
|
|
if (options.value !== undefined) {this.value = options.value;} |
|
|
|
|
|
|
|
@ -142,6 +139,8 @@ class Edge { |
|
|
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; |
|
|
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; |
|
|
|
|
|
|
|
|
this.setupSmoothEdges(doNotEmit); |
|
|
this.setupSmoothEdges(doNotEmit); |
|
|
|
|
|
|
|
|
|
|
|
this.labelModule.setOptions(this.options); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -265,11 +264,14 @@ class Edge { |
|
|
* @param total |
|
|
* @param total |
|
|
*/ |
|
|
*/ |
|
|
setValueRange(min, max, total) { |
|
|
setValueRange(min, max, total) { |
|
|
if (!this.widthFixed && this.value !== undefined) { |
|
|
|
|
|
var scale = this.options.customScalingFunction(min, max, total, this.value); |
|
|
|
|
|
var widthDiff = this.options.widthMax - this.options.widthMin; |
|
|
|
|
|
this.options.width = this.options.widthMin + scale * widthDiff; |
|
|
|
|
|
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; |
|
|
|
|
|
|
|
|
if (this.value !== undefined) { |
|
|
|
|
|
var scale = this.options.scaling.customScalingFunction(min, max, total, this.value); |
|
|
|
|
|
var widthDiff = this.options.scaling.max - this.options.scaling.min; |
|
|
|
|
|
if (this.options.scaling.label.enabled == true) { |
|
|
|
|
|
var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min; |
|
|
|
|
|
this.options.font.size = this.options.scaling.label.min + scale * fontDiff; |
|
|
|
|
|
} |
|
|
|
|
|
this.options.width = this.options.scaling.min + scale * widthDiff; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -304,13 +306,25 @@ class Edge { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
drawLabel(ctx, viaNode) { |
|
|
drawLabel(ctx, viaNode) { |
|
|
if (this.label !== undefined) { |
|
|
|
|
|
|
|
|
if (this.options.label !== undefined) { |
|
|
// set style
|
|
|
// set style
|
|
|
var node1 = this.from; |
|
|
var node1 = this.from; |
|
|
var node2 = this.to; |
|
|
var node2 = this.to; |
|
|
|
|
|
var selected = (this.from.selected || this.to.selected || this.selected); |
|
|
if (node1.id != node2.id) { |
|
|
if (node1.id != node2.id) { |
|
|
var point = this._pointOnEdge(0.5, viaNode); |
|
|
var point = this._pointOnEdge(0.5, viaNode); |
|
|
this._label(ctx, this.label, point.x, point.y); |
|
|
|
|
|
|
|
|
ctx.save(); |
|
|
|
|
|
|
|
|
|
|
|
// if the label has to be rotated:
|
|
|
|
|
|
if (this.options.font.align != "horizontal") { |
|
|
|
|
|
this.labelModule.calculateLabelSize(ctx,selected,point.x,point.y); |
|
|
|
|
|
ctx.translate(point.x, this.labelModule.size.yLine); |
|
|
|
|
|
this._rotateForLabelAlignment(ctx); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// draw the label
|
|
|
|
|
|
this.labelModule.draw(ctx, point.x, point.y, selected); |
|
|
|
|
|
ctx.restore(); |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
var x, y; |
|
|
var x, y; |
|
@ -324,7 +338,8 @@ class Edge { |
|
|
y = node1.y - node1.height * 0.5; |
|
|
y = node1.y - node1.height * 0.5; |
|
|
} |
|
|
} |
|
|
point = this._pointOnCircle(x, y, radius, 0.125); |
|
|
point = this._pointOnCircle(x, y, radius, 0.125); |
|
|
this._label(ctx, this.label, point.x, point.y); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.labelModule.draw(ctx, point.x, point.y, selected); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -378,7 +393,7 @@ class Edge { |
|
|
grd.addColorStop(0, fromColor); |
|
|
grd.addColorStop(0, fromColor); |
|
|
grd.addColorStop(1, toColor); |
|
|
grd.addColorStop(1, toColor); |
|
|
|
|
|
|
|
|
// -------------------- this returns the function -------------------- //
|
|
|
|
|
|
|
|
|
// -------------------- this returns -------------------- //
|
|
|
return grd; |
|
|
return grd; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -726,49 +741,7 @@ class Edge { |
|
|
* @param {Number} y |
|
|
* @param {Number} y |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
_label(ctx, text, x, y) { |
|
|
|
|
|
if (text) { |
|
|
|
|
|
ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + |
|
|
|
|
|
this.options.font.size + "px " + this.options.font.face; |
|
|
|
|
|
var yLine; |
|
|
|
|
|
|
|
|
|
|
|
if (this.labelDirty == true) { |
|
|
|
|
|
var lines = String(text).split('\n'); |
|
|
|
|
|
var lineCount = lines.length; |
|
|
|
|
|
var fontSize = Number(this.options.font.size); |
|
|
|
|
|
yLine = y + (1 - lineCount) * 0.5 * fontSize; |
|
|
|
|
|
|
|
|
|
|
|
var width = ctx.measureText(lines[0]).width; |
|
|
|
|
|
for (var i = 1; i < lineCount; i++) { |
|
|
|
|
|
var lineWidth = ctx.measureText(lines[i]).width; |
|
|
|
|
|
width = lineWidth > width ? lineWidth : width; |
|
|
|
|
|
} |
|
|
|
|
|
var height = this.options.font.size * lineCount; |
|
|
|
|
|
var left = x - width * 0.5; |
|
|
|
|
|
var top = y - height * 0.5; |
|
|
|
|
|
|
|
|
|
|
|
// cache
|
|
|
|
|
|
this.labelDimensions = {top: top, left: left, width: width, height: height, yLine: yLine}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var yLine = this.labelDimensions.yLine; |
|
|
|
|
|
|
|
|
|
|
|
ctx.save(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.options.font.align != "horizontal") { |
|
|
|
|
|
ctx.translate(x, yLine); |
|
|
|
|
|
this._rotateForLabelAlignment(ctx); |
|
|
|
|
|
x = 0; |
|
|
|
|
|
yLine = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this._drawLabelRect(ctx); |
|
|
|
|
|
this._drawLabelText(ctx, x, yLine, lines, lineCount, fontSize); |
|
|
|
|
|
|
|
|
|
|
|
ctx.restore(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -790,83 +763,6 @@ class Edge { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Draws the label rectangle |
|
|
|
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_drawLabelRect(ctx) { |
|
|
|
|
|
if (this.options.font.background !== undefined && this.options.font.background !== "none") { |
|
|
|
|
|
ctx.fillStyle = this.options.font.background; |
|
|
|
|
|
|
|
|
|
|
|
var lineMargin = 2; |
|
|
|
|
|
|
|
|
|
|
|
if (this.options.font.align == 'middle') { |
|
|
|
|
|
ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); |
|
|
|
|
|
} |
|
|
|
|
|
else if (this.options.font.align == 'top') { |
|
|
|
|
|
ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); |
|
|
|
|
|
} |
|
|
|
|
|
else if (this.options.font.align == 'bottom') { |
|
|
|
|
|
ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Draws the label text |
|
|
|
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
|
|
|
* @param {Number} x |
|
|
|
|
|
* @param {Number} yLine |
|
|
|
|
|
* @param {Array} lines |
|
|
|
|
|
* @param {Number} lineCount |
|
|
|
|
|
* @param {Number} fontSize |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
_drawLabelText(ctx, x, yLine, lines, lineCount, fontSize) { |
|
|
|
|
|
// draw text
|
|
|
|
|
|
ctx.fillStyle = this.options.font.color || "black"; |
|
|
|
|
|
ctx.textAlign = "center"; |
|
|
|
|
|
|
|
|
|
|
|
// check for label alignment
|
|
|
|
|
|
if (this.options.font.align != 'horizontal') { |
|
|
|
|
|
var lineMargin = 2; |
|
|
|
|
|
if (this.options.font.align == 'top') { |
|
|
|
|
|
ctx.textBaseline = "alphabetic"; |
|
|
|
|
|
yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
|
|
|
|
|
|
} |
|
|
|
|
|
else if (this.options.font.align == 'bottom') { |
|
|
|
|
|
ctx.textBaseline = "hanging"; |
|
|
|
|
|
yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
|
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
ctx.textBaseline = "middle"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
ctx.textBaseline = "middle"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// check for strokeWidth
|
|
|
|
|
|
if (this.options.font.stroke > 0) { |
|
|
|
|
|
ctx.lineWidth = this.options.font.stroke; |
|
|
|
|
|
ctx.strokeStyle = this.options.font.strokeColor; |
|
|
|
|
|
ctx.lineJoin = 'round'; |
|
|
|
|
|
} |
|
|
|
|
|
for (var i = 0; i < lineCount; i++) { |
|
|
|
|
|
if (this.options.font.stroke > 0) { |
|
|
|
|
|
ctx.strokeText(lines[i], x, yLine); |
|
|
|
|
|
} |
|
|
|
|
|
ctx.fillText(lines[i], x, yLine); |
|
|
|
|
|
yLine += fontSize; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Redraw a edge as a dashes line |
|
|
* Redraw a edge as a dashes line |
|
|
* Draw this edge in the given canvas |
|
|
* Draw this edge in the given canvas |
|
@ -1266,10 +1162,10 @@ class Edge { |
|
|
returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius); |
|
|
returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (this.labelDimensions.left < x3 && |
|
|
|
|
|
this.labelDimensions.left + this.labelDimensions.width > x3 && |
|
|
|
|
|
this.labelDimensions.top < y3 && |
|
|
|
|
|
this.labelDimensions.top + this.labelDimensions.height > y3) { |
|
|
|
|
|
|
|
|
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; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
@ -1337,6 +1233,55 @@ class Edge { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*********************** MOVE THESE FUNCTIONS TO THE MANIPULATION SYSTEM ************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
//*************************************************************************************************//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* This function draws the control nodes for the manipulator. |
|
|
* This function draws the control nodes for the manipulator. |
|
|
* In order to enable this, only set the this.controlNodesEnabled to true. |
|
|
* In order to enable this, only set the this.controlNodesEnabled to true. |
|
|