From 9b83e2ca0f0ccb74633b0ce4e60182e6eda6b20c Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Fri, 7 Aug 2015 16:05:10 +0200 Subject: [PATCH] - Fixed dynamic updating of label properties. --- HISTORY.md | 1 + dist/vis.js | 71 ++++++++++--------- lib/network/modules/NodesHandler.js | 2 +- lib/network/modules/components/Node.js | 3 +- .../modules/components/shared/Label.js | 65 +++++++++-------- 5 files changed, 78 insertions(+), 64 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a6147f83..10e9ef66 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,6 +13,7 @@ http://visjs.org - Fixed #1152, updating images now works. - Fixed cleaning up of nodes. - Improved the positioning and CSS of the configurator and the color picker. +- Fixed dynamic updating of label properties. ## 2015-07-27, version 4.7.0 diff --git a/dist/vis.js b/dist/vis.js index 8f0c5fde..2d1ea21a 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -27703,7 +27703,7 @@ return /******/ (function(modules) { // webpackBootstrap } } - // update the shape size in all nodes + // update the font in all nodes if (options.font !== undefined) { _componentsSharedLabel2['default'].parseOptions(this.options.font, options); for (var nodeId in this.body.nodes) { @@ -28216,6 +28216,7 @@ return /******/ (function(modules) { // webpackBootstrap if (!options) { return; } + // basic options if (options.id !== undefined) { this.id = options.id; @@ -28268,8 +28269,8 @@ return /******/ (function(modules) { // webpackBootstrap } } - this.updateShape(currentShape); this.updateLabelModule(); + this.updateShape(currentShape); if (options.hidden !== undefined || options.physics !== undefined) { return true; @@ -28289,6 +28290,7 @@ return /******/ (function(modules) { // webpackBootstrap if (this.options.label === undefined || this.options.label === null) { this.options.label = ''; } + this.labelModule.setOptions(this.options, true); if (this.labelModule.baseSize !== undefined) { this.baseFontSize = this.labelModule.baseSize; @@ -28590,6 +28592,7 @@ return /******/ (function(modules) { // webpackBootstrap this.pointToSelf = false; this.baseSize = undefined; + this.fontOptions = {}; this.setOptions(options); this.size = { top: 0, left: 0, width: 0, height: 0, yLine: 0 }; // could be cached } @@ -28599,16 +28602,20 @@ return /******/ (function(modules) { // webpackBootstrap value: function setOptions(options) { var allowDeletion = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; - this.options = options; + this.nodeOptions = options; + + // We want to keep the font options seperated from the node options. + // The node options have to mirror the globals when they are not overruled. + this.fontOptions = util.deepExtend({}, options.font, true); if (options.label !== undefined) { this.labelDirty = true; } if (options.font !== undefined) { - Label.parseOptions(this.options.font, options, allowDeletion); + Label.parseOptions(this.fontOptions, options, allowDeletion); if (typeof options.font === 'string') { - this.baseSize = this.options.font.size; + this.baseSize = this.fontOptions.size; } else if (typeof options.font === 'object') { if (options.font.size !== undefined) { this.baseSize = options.font.size; @@ -28631,11 +28638,11 @@ return /******/ (function(modules) { // webpackBootstrap var baseline = arguments.length <= 4 || arguments[4] === undefined ? 'middle' : arguments[4]; // if no label, return - if (this.options.label === undefined) return; + if (this.nodeOptions.label === undefined) return; // check if we have to render the label - var viewFontSize = this.options.font.size * this.body.view.scale; - if (this.options.label && viewFontSize < this.options.scaling.label.drawThreshold - 1) return; + var viewFontSize = this.fontOptions.size * this.body.view.scale; + if (this.nodeOptions.label && viewFontSize < this.nodeOptions.scaling.label.drawThreshold - 1) return; // update the size cache if required this.calculateLabelSize(ctx, selected, x, y, baseline); @@ -28654,12 +28661,12 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: '_drawBackground', value: function _drawBackground(ctx) { - if (this.options.font.background !== undefined && this.options.font.background !== "none") { - ctx.fillStyle = this.options.font.background; + if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") { + ctx.fillStyle = this.fontOptions.background; var lineMargin = 2; - switch (this.options.font.align) { + switch (this.fontOptions.align) { case 'middle': ctx.fillRect(-this.size.width * 0.5, -this.size.height * 0.5, this.size.width, this.size.height); break; @@ -28688,11 +28695,11 @@ return /******/ (function(modules) { // webpackBootstrap value: function _drawText(ctx, selected, x, y) { var baseline = arguments.length <= 4 || arguments[4] === undefined ? 'middle' : arguments[4]; - var fontSize = this.options.font.size; + var fontSize = this.fontOptions.size; var viewFontSize = fontSize * this.body.view.scale; // 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.options.scaling.label.maxVisible) { - fontSize = Number(this.options.scaling.label.maxVisible) / this.body.view.scale; + if (viewFontSize >= this.nodeOptions.scaling.label.maxVisible) { + fontSize = Number(this.nodeOptions.scaling.label.maxVisible) / this.body.view.scale; } var yLine = this.size.yLine; @@ -28712,20 +28719,20 @@ return /******/ (function(modules) { // webpackBootstrap x = _setAlignment22[0]; yLine = _setAlignment22[1]; - ctx.font = (selected && this.options.labelHighlightBold ? 'bold ' : '') + fontSize + "px " + this.options.font.face; + ctx.font = (selected && this.nodeOptions.labelHighlightBold ? 'bold ' : '') + fontSize + "px " + this.fontOptions.face; ctx.fillStyle = fontColor; ctx.textAlign = 'center'; // set the strokeWidth - if (this.options.font.strokeWidth > 0) { - ctx.lineWidth = this.options.font.strokeWidth; + if (this.fontOptions.strokeWidth > 0) { + ctx.lineWidth = this.fontOptions.strokeWidth; ctx.strokeStyle = strokeColor; ctx.lineJoin = 'round'; } // draw the text for (var i = 0; i < this.lineCount; i++) { - if (this.options.font.strokeWidth > 0) { + if (this.fontOptions.strokeWidth > 0) { ctx.strokeText(this.lines[i], x, yLine); } ctx.fillText(this.lines[i], x, yLine); @@ -28737,15 +28744,15 @@ return /******/ (function(modules) { // webpackBootstrap value: function _setAlignment(ctx, x, yLine, baseline) { // check for label alignment (for edges) // TODO: make alignment for nodes - if (this.options.font.align !== 'horizontal' && this.pointToSelf === false) { + if (this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) { x = 0; yLine = 0; var lineMargin = 2; - if (this.options.font.align === 'top') { + if (this.fontOptions.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') { + } else if (this.fontOptions.align === 'bottom') { ctx.textBaseline = 'hanging'; yLine += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers } else { @@ -28769,10 +28776,10 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: '_getColor', value: function _getColor(viewFontSize) { - var fontColor = this.options.font.color || '#000000'; - var strokeColor = this.options.font.strokeColor || '#ffffff'; - if (viewFontSize <= this.options.scaling.label.drawThreshold) { - var opacity = Math.max(0, Math.min(1, 1 - (this.options.scaling.label.drawThreshold - viewFontSize))); + var fontColor = this.fontOptions.color || '#000000'; + var strokeColor = this.fontOptions.strokeColor || '#ffffff'; + if (viewFontSize <= this.nodeOptions.scaling.label.drawThreshold) { + var opacity = Math.max(0, Math.min(1, 1 - (this.nodeOptions.scaling.label.drawThreshold - viewFontSize))); fontColor = util.overrideOpacity(fontColor, opacity); strokeColor = util.overrideOpacity(strokeColor, opacity); } @@ -28792,7 +28799,7 @@ return /******/ (function(modules) { // webpackBootstrap var size = { width: this._processLabel(ctx, selected), - height: this.options.font.size * this.lineCount, + height: this.fontOptions.size * this.lineCount, lineCount: this.lineCount }; return size; @@ -28816,12 +28823,12 @@ return /******/ (function(modules) { // webpackBootstrap if (this.labelDirty === true) { this.size.width = this._processLabel(ctx, selected); } - this.size.height = this.options.font.size * this.lineCount; + this.size.height = this.fontOptions.size * this.lineCount; this.size.left = x - this.size.width * 0.5; this.size.top = y - this.size.height * 0.5; - this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.options.font.size; + this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size; if (baseline === "hanging") { - this.size.top += 0.5 * this.options.font.size; + this.size.top += 0.5 * this.fontOptions.size; 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 } @@ -28842,10 +28849,10 @@ return /******/ (function(modules) { // webpackBootstrap var width = 0; var lines = ['']; var lineCount = 0; - if (this.options.label !== undefined) { - lines = String(this.options.label).split('\n'); + if (this.nodeOptions.label !== undefined) { + lines = String(this.nodeOptions.label).split('\n'); lineCount = lines.length; - ctx.font = (selected && this.options.labelHighlightBold ? 'bold ' : '') + this.options.font.size + "px " + this.options.font.face; + ctx.font = (selected && this.nodeOptions.labelHighlightBold ? 'bold ' : '') + this.fontOptions.size + "px " + this.fontOptions.face; width = ctx.measureText(lines[0]).width; for (var i = 1; i < lineCount; i++) { var lineWidth = ctx.measureText(lines[i]).width; diff --git a/lib/network/modules/NodesHandler.js b/lib/network/modules/NodesHandler.js index 69c7a6fe..e2cd6d6c 100644 --- a/lib/network/modules/NodesHandler.js +++ b/lib/network/modules/NodesHandler.js @@ -134,7 +134,7 @@ class NodesHandler { } } - // update the shape size in all nodes + // update the font in all nodes if (options.font !== undefined) { Label.parseOptions(this.options.font, options); for (let nodeId in this.body.nodes) { diff --git a/lib/network/modules/components/Node.js b/lib/network/modules/components/Node.js index 2f2b6e8e..d7554f98 100644 --- a/lib/network/modules/components/Node.js +++ b/lib/network/modules/components/Node.js @@ -147,8 +147,9 @@ class Node { } } - this.updateShape(currentShape); this.updateLabelModule(); + this.updateShape(currentShape); + if (options.hidden !== undefined || options.physics !== undefined) { return true; diff --git a/lib/network/modules/components/shared/Label.js b/lib/network/modules/components/shared/Label.js index 0141bc36..64c0c374 100644 --- a/lib/network/modules/components/shared/Label.js +++ b/lib/network/modules/components/shared/Label.js @@ -6,21 +6,26 @@ class Label { this.pointToSelf = false; this.baseSize = undefined; + this.fontOptions = {}; this.setOptions(options); this.size = {top: 0, left: 0, width: 0, height: 0, yLine: 0}; // could be cached } setOptions(options, allowDeletion = false) { - this.options = options; + this.nodeOptions = options; + + // We want to keep the font options seperated from the node options. + // The node options have to mirror the globals when they are not overruled. + this.fontOptions = util.deepExtend({},options.font, true); if (options.label !== undefined) { this.labelDirty = true; } if (options.font !== undefined) { - Label.parseOptions(this.options.font, options, allowDeletion); + Label.parseOptions(this.fontOptions, options, allowDeletion); if (typeof options.font === 'string') { - this.baseSize = this.options.font.size; + this.baseSize = this.fontOptions.size; } else if (typeof options.font === 'object') { if (options.font.size !== undefined) { @@ -54,12 +59,12 @@ class Label { */ draw(ctx, x, y, selected, baseline = 'middle') { // if no label, return - if (this.options.label === undefined) + if (this.nodeOptions.label === undefined) return; // check if we have to render the label - let viewFontSize = this.options.font.size * this.body.view.scale; - if (this.options.label && viewFontSize < this.options.scaling.label.drawThreshold - 1) + let viewFontSize = this.fontOptions.size * this.body.view.scale; + if (this.nodeOptions.label && viewFontSize < this.nodeOptions.scaling.label.drawThreshold - 1) return; // update the size cache if required @@ -77,12 +82,12 @@ class Label { * @private */ _drawBackground(ctx) { - if (this.options.font.background !== undefined && this.options.font.background !== "none") { - ctx.fillStyle = this.options.font.background; + if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") { + ctx.fillStyle = this.fontOptions.background; let lineMargin = 2; - switch (this.options.font.align) { + switch (this.fontOptions.align) { case 'middle': ctx.fillRect(-this.size.width * 0.5, -this.size.height * 0.5, this.size.width, this.size.height); break; @@ -108,11 +113,11 @@ class Label { * @private */ _drawText(ctx, selected, x, y, baseline = 'middle') { - let fontSize = this.options.font.size; + let fontSize = this.fontOptions.size; let viewFontSize = fontSize * this.body.view.scale; // 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.options.scaling.label.maxVisible) { - fontSize = Number(this.options.scaling.label.maxVisible) / this.body.view.scale; + if (viewFontSize >= this.nodeOptions.scaling.label.maxVisible) { + fontSize = Number(this.nodeOptions.scaling.label.maxVisible) / this.body.view.scale; } let yLine = this.size.yLine; @@ -120,20 +125,20 @@ class Label { [x, yLine] = this._setAlignment(ctx, x, yLine, baseline); // configure context for drawing the text - ctx.font = (selected && this.options.labelHighlightBold ? 'bold ' : '') + fontSize + "px " + this.options.font.face; + ctx.font = (selected && this.nodeOptions.labelHighlightBold ? 'bold ' : '') + fontSize + "px " + this.fontOptions.face; ctx.fillStyle = fontColor; ctx.textAlign = 'center'; // set the strokeWidth - if (this.options.font.strokeWidth > 0) { - ctx.lineWidth = this.options.font.strokeWidth; + if (this.fontOptions.strokeWidth > 0) { + ctx.lineWidth = this.fontOptions.strokeWidth; ctx.strokeStyle = strokeColor; ctx.lineJoin = 'round'; } // draw the text for (let i = 0; i < this.lineCount; i++) { - if (this.options.font.strokeWidth > 0) { + if (this.fontOptions.strokeWidth > 0) { ctx.strokeText(this.lines[i], x, yLine); } ctx.fillText(this.lines[i], x, yLine); @@ -144,16 +149,16 @@ class Label { _setAlignment(ctx, x, yLine, baseline) { // check for label alignment (for edges) // TODO: make alignment for nodes - if (this.options.font.align !== 'horizontal' && this.pointToSelf === false) { + if (this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) { x = 0; yLine = 0; let lineMargin = 2; - if (this.options.font.align === 'top') { + if (this.fontOptions.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') { + else if (this.fontOptions.align === 'bottom') { ctx.textBaseline = 'hanging'; yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers } @@ -177,10 +182,10 @@ class Label { * @private */ _getColor(viewFontSize) { - let fontColor = this.options.font.color || '#000000'; - let strokeColor = this.options.font.strokeColor || '#ffffff'; - if (viewFontSize <= this.options.scaling.label.drawThreshold) { - let opacity = Math.max(0, Math.min(1, 1 - (this.options.scaling.label.drawThreshold - viewFontSize))); + let fontColor = this.fontOptions.color || '#000000'; + let strokeColor = this.fontOptions.strokeColor || '#ffffff'; + if (viewFontSize <= this.nodeOptions.scaling.label.drawThreshold) { + let opacity = Math.max(0, Math.min(1, 1 - (this.nodeOptions.scaling.label.drawThreshold - viewFontSize))); fontColor = util.overrideOpacity(fontColor, opacity); strokeColor = util.overrideOpacity(strokeColor, opacity); } @@ -197,7 +202,7 @@ class Label { getTextSize(ctx, selected = false) { let size = { width: this._processLabel(ctx,selected), - height: this.options.font.size * this.lineCount, + height: this.fontOptions.size * this.lineCount, lineCount: this.lineCount }; return size; @@ -216,12 +221,12 @@ class Label { if (this.labelDirty === true) { this.size.width = this._processLabel(ctx,selected); } - this.size.height = this.options.font.size * this.lineCount; + this.size.height = this.fontOptions.size * this.lineCount; this.size.left = x - this.size.width * 0.5; this.size.top = y - this.size.height * 0.5; - this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.options.font.size; + this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size; if (baseline === "hanging") { - this.size.top += 0.5 * this.options.font.size; + this.size.top += 0.5 * this.fontOptions.size; 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 } @@ -241,10 +246,10 @@ class Label { let width = 0; let lines = ['']; let lineCount = 0; - if (this.options.label !== undefined) { - lines = String(this.options.label).split('\n'); + if (this.nodeOptions.label !== undefined) { + lines = String(this.nodeOptions.label).split('\n'); lineCount = lines.length; - ctx.font = (selected && this.options.labelHighlightBold ? 'bold ' : '') + this.options.font.size + "px " + this.options.font.face; + ctx.font = (selected && this.nodeOptions.labelHighlightBold ? 'bold ' : '') + this.fontOptions.size + "px " + this.fontOptions.face; width = ctx.measureText(lines[0]).width; for (let i = 1; i < lineCount; i++) { let lineWidth = ctx.measureText(lines[i]).width;