diff --git a/docs/network/nodes.html b/docs/network/nodes.html index 7e4788ee67..f16c543545 100644 --- a/docs/network/nodes.html +++ b/docs/network/nodes.html @@ -439,6 +439,8 @@

Options

drawExternalLabel() { ctx.drawSomeTextOutsideOfTheNode(); }, + // node dimensions defined by node drawing + nodeDimensions: { width, height }, }; } diff --git a/examples/network/nodeStyles/shapes.html b/examples/network/nodeStyles/shapes.html index e167f836f8..76cf7c3ebc 100644 --- a/examples/network/nodeStyles/shapes.html +++ b/examples/network/nodeStyles/shapes.html @@ -54,29 +54,113 @@ shape: 'custom', ctxRenderer: ({ ctx, x, y, state: { selected, hover }, style }) => { const r = style.size; + const drawNode = () => { + ctx.beginPath(); + const sides = 6; + const a = (Math.PI * 2) / sides; + ctx.moveTo(x , y + r); + for (let i = 1; i < sides; i++) { + ctx.lineTo(x + r * Math.sin(a * i), y + r * Math.cos(a * i)); + } + ctx.closePath(); + ctx.save(); + ctx.fillStyle = 'red'; + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.font = "normal 12px sans-serif"; + ctx.fillStyle = 'black'; + ctx.fillText('custom shape', x - r + 10, y, 2 * r - 20); + } + return { + drawNode, + nodeDimensions: { width: 2*r, height: 2*r } + } + } + + }, + { + id: 37, + label: 'FIELD---my value', + shape: 'custom', + group: 'a', + ctxRenderer: ({ ctx, x, y, state: { selected, hover }, style, label }) => { + const splittedLabel = label.split('---') + ctx.save(); + ctx.restore(); + const labelText = splittedLabel[0] + const valueText = splittedLabel[1] + const r = 5 + + const labelWidth = ctx.measureText(labelText).width; + const valueWidth = ctx.measureText(valueText).width; + + const wPadding = 10 + const hPadding = 10 + const w = 200 + const h = 60 + const drawNode = () => { + const r2d = Math.PI / 180; + if (w - 2 * r < 0) { + r = w / 2; + } //ensure that the radius isn't too large for x + if (h - 2 * r < 0) { + r = h / 2; + } //ensure that the radius isn't too large for y + + const top = y - h / 2 + const left = x - w / 2 + + ctx.lineWidth = 2; ctx.beginPath(); - const sides = 6; - const a = (Math.PI * 2) / sides; - ctx.moveTo(x , y + r); - for (let i = 1; i < sides; i++) { - ctx.lineTo(x + r * Math.sin(a * i), y + r * Math.cos(a * i)); - } + ctx.moveTo(left + r, top); + ctx.lineTo(left + w - r, top); + ctx.arc(left + w - r, top + r, r, r2d * 270, r2d * 360, false); + ctx.lineTo(left + w, top + h - r); + ctx.arc(left + w - r, top + h - r, r, 0, r2d * 90, false); + ctx.lineTo(left + r, top + h); + ctx.arc(left + r, top + h - r, r, r2d * 90, r2d * 180, false); + ctx.lineTo(left, top + r); + ctx.arc(left + r, top + r, r, r2d * 180, r2d * 270, false); ctx.closePath(); ctx.save(); - ctx.fillStyle = 'red'; + ctx.fillStyle = style.color || '#56CCF2'; ctx.fill(); + ctx.strokeStyle = '#FFFFFF'; ctx.stroke(); - ctx.restore(); - + + // label text ctx.font = "normal 12px sans-serif"; + ctx.fillStyle = 'grey'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + const textHeight1 = 12 + ctx.fillText(labelText, left + w / 2, top + textHeight1 + hPadding, w); + + // value text + ctx.font = "bold 14px sans-serif"; ctx.fillStyle = 'black'; - ctx.fillText('custom shape', x - r + 10, y, 2 * r - 20); + const textHeight2 = 12 + + ctx.fillText(valueText, left + w / 2, top + h / 2 + hPadding, w); + + } + + ctx.save(); + ctx.restore(); + return { + drawNode, + nodeDimensions: { width:w, height: h } + } + } - }, + }, ]; edges = [ + {from: 1, to: 37, arrows: { to: { enabled: true}}} ]; // create a network diff --git a/lib/network/modules/components/nodes/shapes/CustomShape.js b/lib/network/modules/components/nodes/shapes/CustomShape.js index 3ca9f909be..06ecd9b78f 100644 --- a/lib/network/modules/components/nodes/shapes/CustomShape.js +++ b/lib/network/modules/components/nodes/shapes/CustomShape.js @@ -62,6 +62,11 @@ class CustomShape extends ShapeBase { }; } + if (drawLater.nodeDimensions) { + this.customSizeWidth = drawLater.nodeDimensions.width; + this.customSizeHeight = drawLater.nodeDimensions.height; + } + return drawLater; } diff --git a/lib/network/modules/components/nodes/util/ShapeBase.js b/lib/network/modules/components/nodes/util/ShapeBase.js index 648c4b670d..87fd1401d5 100644 --- a/lib/network/modules/components/nodes/util/ShapeBase.js +++ b/lib/network/modules/components/nodes/util/ShapeBase.js @@ -27,9 +27,9 @@ class ShapeBase extends NodeBase { if (this.needsRefresh(selected, hover)) { this.labelModule.getTextSize(ctx, selected, hover); const size = 2 * values.size; - this.width = size; - this.height = size; - this.radius = 0.5*this.width; + this.width = this.customSizeWidth ?? size; + this.height = this.customSizeHeight ?? size; + this.radius = 0.5 * this.width; } } @@ -58,9 +58,11 @@ class ShapeBase extends NodeBase { if (this.options.icon !== undefined) { if (this.options.icon.code !== undefined) { - ctx.font = (selected ? "bold " : "") - + (this.height / 2) + "px " - + (this.options.icon.face || 'FontAwesome'); + ctx.font = + (selected ? "bold " : "") + + this.height / 2 + + "px " + + (this.options.icon.face || "FontAwesome"); ctx.fillStyle = this.options.icon.color || "black"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; @@ -73,14 +75,7 @@ class ShapeBase extends NodeBase { if (this.options.label !== undefined) { // Need to call following here in order to ensure value for // `this.labelModule.size.height`. - this.labelModule.calculateLabelSize( - ctx, - selected, - hover, - x, - y, - 'hanging' - ); + this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, 'hanging'); const yLabel = y + 0.5 * this.height + 0.5 * this.labelModule.size.height; this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');