|
@ -338,20 +338,27 @@ class Label { |
|
|
if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) |
|
|
if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// This ensures that there will not be HUGE letters on screen
|
|
|
|
|
|
// by setting an upper limit on the visible text size (regardless of zoomLevel)
|
|
|
|
|
|
if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) { |
|
|
|
|
|
viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// update the size cache if required
|
|
|
// update the size cache if required
|
|
|
this.calculateLabelSize(ctx, selected, hover, x, y, baseline); |
|
|
this.calculateLabelSize(ctx, selected, hover, x, y, baseline); |
|
|
|
|
|
this._drawBackground(ctx, this.size.left, this.size.top); |
|
|
|
|
|
this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize); |
|
|
|
|
|
|
|
|
this._drawBackground(ctx); // create the fontfill background
|
|
|
|
|
|
this._drawText(ctx, selected, hover, x, y, baseline); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Draws the label background |
|
|
* Draws the label background |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
|
|
|
* @param {number} x |
|
|
|
|
|
* @param {number} y |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
_drawBackground(ctx) { |
|
|
|
|
|
|
|
|
_drawBackground(ctx, x, y) { |
|
|
if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") { |
|
|
if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") { |
|
|
ctx.fillStyle = this.fontOptions.background; |
|
|
ctx.fillStyle = this.fontOptions.background; |
|
|
|
|
|
|
|
@ -369,11 +376,11 @@ class Label { |
|
|
ctx.fillRect(-this.size.width * 0.5, lineMargin, this.size.width, this.size.height); |
|
|
ctx.fillRect(-this.size.width * 0.5, lineMargin, this.size.width, this.size.height); |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
ctx.fillRect(this.size.left, this.size.top - 0.5*lineMargin, this.size.width, this.size.height); |
|
|
|
|
|
|
|
|
ctx.fillRect(x, y - 0.5*lineMargin, this.size.width, this.size.height); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
ctx.fillRect(this.size.left, this.size.top - 0.5*lineMargin, this.size.width, this.size.height); |
|
|
|
|
|
|
|
|
ctx.fillRect(x, y - 0.5*lineMargin, this.size.width, this.size.height); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -382,49 +389,39 @@ class Label { |
|
|
/** |
|
|
/** |
|
|
* |
|
|
* |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
* @param {boolean} selected |
|
|
|
|
|
* @param {boolean} hover |
|
|
|
|
|
* @param {number} x |
|
|
* @param {number} x |
|
|
* @param {number} y |
|
|
* @param {number} y |
|
|
* @param {string} [baseline='middle'] |
|
|
* @param {string} [baseline='middle'] |
|
|
|
|
|
* @param {number} viewFontSize |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
_drawText(ctx, selected, hover, x, y, baseline = 'middle') { |
|
|
|
|
|
let fontSize = this.fontOptions.size; |
|
|
|
|
|
let viewFontSize = fontSize * this.body.view.scale; |
|
|
|
|
|
|
|
|
_drawText(ctx, x, y, baseline = 'middle', viewFontSize) { |
|
|
|
|
|
|
|
|
// This ensures that there will not be HUGE letters on screen
|
|
|
|
|
|
// by setting an upper limit on the visible text size (regardless of zoomLevel)
|
|
|
|
|
|
if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) { |
|
|
|
|
|
// TODO: Does this actually do anything?
|
|
|
|
|
|
fontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let yLine = this.size.yLine; |
|
|
|
|
|
[x, yLine] = this._setAlignment(ctx, x, yLine, baseline); |
|
|
|
|
|
|
|
|
[x, y] = this._setAlignment(ctx, x, y, baseline); |
|
|
|
|
|
|
|
|
ctx.textAlign = 'left'; |
|
|
ctx.textAlign = 'left'; |
|
|
x = x - this.size.width / 2; // Shift label 1/2-distance to the left
|
|
|
x = x - this.size.width / 2; // Shift label 1/2-distance to the left
|
|
|
if ((this.fontOptions.valign) && (this.size.height > this.size.labelHeight)) { |
|
|
if ((this.fontOptions.valign) && (this.size.height > this.size.labelHeight)) { |
|
|
if (this.fontOptions.valign === 'top') { |
|
|
if (this.fontOptions.valign === 'top') { |
|
|
yLine -= (this.size.height - this.size.labelHeight) / 2; |
|
|
|
|
|
|
|
|
y -= (this.size.height - this.size.labelHeight) / 2; |
|
|
} |
|
|
} |
|
|
if (this.fontOptions.valign === 'bottom') { |
|
|
if (this.fontOptions.valign === 'bottom') { |
|
|
yLine += (this.size.height - this.size.labelHeight) / 2; |
|
|
|
|
|
|
|
|
y += (this.size.height - this.size.labelHeight) / 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// draw the text
|
|
|
// draw the text
|
|
|
for (let i = 0; i < this.lineCount; i++) { |
|
|
for (let i = 0; i < this.lineCount; i++) { |
|
|
if (this.lines[i] && this.lines[i].blocks) { |
|
|
|
|
|
|
|
|
let line = this.lines[i]; |
|
|
|
|
|
if (line && line.blocks) { |
|
|
let width = 0; |
|
|
let width = 0; |
|
|
if (this.isEdgeLabel || this.fontOptions.align === 'center') { |
|
|
if (this.isEdgeLabel || this.fontOptions.align === 'center') { |
|
|
width += (this.size.width - this.lines[i].width) / 2 |
|
|
|
|
|
|
|
|
width += (this.size.width - line.width) / 2 |
|
|
} else if (this.fontOptions.align === 'right') { |
|
|
} else if (this.fontOptions.align === 'right') { |
|
|
width += (this.size.width - this.lines[i].width) |
|
|
|
|
|
|
|
|
width += (this.size.width - line.width) |
|
|
} |
|
|
} |
|
|
for (let j = 0; j < this.lines[i].blocks.length; j++) { |
|
|
|
|
|
let block = this.lines[i].blocks[j]; |
|
|
|
|
|
|
|
|
for (let j = 0; j < line.blocks.length; j++) { |
|
|
|
|
|
let block = line.blocks[j]; |
|
|
ctx.font = block.font; |
|
|
ctx.font = block.font; |
|
|
let [fontColor, strokeColor] = this._getColor(block.color, viewFontSize, block.strokeColor); |
|
|
let [fontColor, strokeColor] = this._getColor(block.color, viewFontSize, block.strokeColor); |
|
|
if (block.strokeWidth > 0) { |
|
|
if (block.strokeWidth > 0) { |
|
@ -435,12 +432,12 @@ class Label { |
|
|
ctx.fillStyle = fontColor; |
|
|
ctx.fillStyle = fontColor; |
|
|
|
|
|
|
|
|
if (block.strokeWidth > 0) { |
|
|
if (block.strokeWidth > 0) { |
|
|
ctx.strokeText(block.text, x + width, yLine + block.vadjust); |
|
|
|
|
|
|
|
|
ctx.strokeText(block.text, x + width, y + block.vadjust); |
|
|
} |
|
|
} |
|
|
ctx.fillText(block.text, x + width, yLine + block.vadjust); |
|
|
|
|
|
|
|
|
ctx.fillText(block.text, x + width, y + block.vadjust); |
|
|
width += block.width; |
|
|
width += block.width; |
|
|
} |
|
|
} |
|
|
yLine += this.lines[i].height; |
|
|
|
|
|
|
|
|
y += line.height; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -449,26 +446,26 @@ class Label { |
|
|
* |
|
|
* |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
* @param {CanvasRenderingContext2D} ctx |
|
|
* @param {number} x |
|
|
* @param {number} x |
|
|
* @param {number} yLine |
|
|
|
|
|
|
|
|
* @param {number} y |
|
|
* @param {string} baseline |
|
|
* @param {string} baseline |
|
|
* @returns {Array.<number>} |
|
|
* @returns {Array.<number>} |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
_setAlignment(ctx, x, yLine, baseline) { |
|
|
|
|
|
|
|
|
_setAlignment(ctx, x, y, baseline) { |
|
|
// check for label alignment (for edges)
|
|
|
// check for label alignment (for edges)
|
|
|
// TODO: make alignment for nodes
|
|
|
// TODO: make alignment for nodes
|
|
|
if (this.isEdgeLabel && this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) { |
|
|
if (this.isEdgeLabel && this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) { |
|
|
x = 0; |
|
|
x = 0; |
|
|
yLine = 0; |
|
|
|
|
|
|
|
|
y = 0; |
|
|
|
|
|
|
|
|
let lineMargin = 2; |
|
|
let lineMargin = 2; |
|
|
if (this.fontOptions.align === 'top') { |
|
|
if (this.fontOptions.align === 'top') { |
|
|
ctx.textBaseline = 'alphabetic'; |
|
|
ctx.textBaseline = 'alphabetic'; |
|
|
yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
|
|
|
|
|
|
|
|
|
y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
|
|
|
} |
|
|
} |
|
|
else if (this.fontOptions.align === 'bottom') { |
|
|
else if (this.fontOptions.align === 'bottom') { |
|
|
ctx.textBaseline = 'hanging'; |
|
|
ctx.textBaseline = 'hanging'; |
|
|
yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
|
|
|
|
|
|
|
|
|
y += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers
|
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
ctx.textBaseline = 'middle'; |
|
|
ctx.textBaseline = 'middle'; |
|
@ -477,7 +474,7 @@ class Label { |
|
|
else { |
|
|
else { |
|
|
ctx.textBaseline = baseline; |
|
|
ctx.textBaseline = baseline; |
|
|
} |
|
|
} |
|
|
return [x,yLine]; |
|
|
|
|
|
|
|
|
return [x,y]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -528,9 +525,7 @@ class Label { |
|
|
* @param {'middle'|'hanging'} [baseline='middle'] |
|
|
* @param {'middle'|'hanging'} [baseline='middle'] |
|
|
*/ |
|
|
*/ |
|
|
calculateLabelSize(ctx, selected, hover, x = 0, y = 0, baseline = 'middle') { |
|
|
calculateLabelSize(ctx, selected, hover, x = 0, y = 0, baseline = 'middle') { |
|
|
if (this.labelDirty === true) { |
|
|
|
|
|
this._processLabel(ctx, selected, hover); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this._processLabel(ctx, selected, hover); |
|
|
this.size.left = x - this.size.width * 0.5; |
|
|
this.size.left = x - this.size.width * 0.5; |
|
|
this.size.top = y - this.size.height * 0.5; |
|
|
this.size.top = y - this.size.height * 0.5; |
|
|
this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size; |
|
|
this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size; |
|
@ -539,7 +534,6 @@ class Label { |
|
|
this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
|
|
|
this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
|
|
|
this.size.yLine += 4; // distance from node
|
|
|
this.size.yLine += 4; // distance from node
|
|
|
} |
|
|
} |
|
|
this.labelDirty = false; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -598,7 +592,7 @@ class Label { |
|
|
* @returns {boolean} |
|
|
* @returns {boolean} |
|
|
*/ |
|
|
*/ |
|
|
differentState(selected, hover) { |
|
|
differentState(selected, hover) { |
|
|
return ((selected !== this.fontOptions.selectedState) && (hover !== this.fontOptions.hoverState)); |
|
|
|
|
|
|
|
|
return ((selected !== this.selectedState) || (hover !== this.hoverState)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -626,6 +620,10 @@ class Label { |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
_processLabel(ctx, selected, hover) { |
|
|
_processLabel(ctx, selected, hover) { |
|
|
|
|
|
|
|
|
|
|
|
if(this.labelDirty === false && !this.differentState(selected,hover)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
let state = this._processLabelText(ctx, selected, hover, this.elementOptions.label); |
|
|
let state = this._processLabelText(ctx, selected, hover, this.elementOptions.label); |
|
|
|
|
|
|
|
|
if ((this.fontOptions.minWdt > 0) && (state.width < this.fontOptions.minWdt)) { |
|
|
if ((this.fontOptions.minWdt > 0) && (state.width < this.fontOptions.minWdt)) { |
|
@ -643,6 +641,8 @@ class Label { |
|
|
this.size.height = state.height; |
|
|
this.size.height = state.height; |
|
|
this.selectedState = selected; |
|
|
this.selectedState = selected; |
|
|
this.hoverState = hover; |
|
|
this.hoverState = hover; |
|
|
|
|
|
|
|
|
|
|
|
this.labelDirty = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|