diff --git a/documentation/md/style.md b/documentation/md/style.md index 7af34f45d..67021e512 100644 --- a/documentation/md/style.md +++ b/documentation/md/style.md @@ -256,6 +256,8 @@ Towards the target node, positioned in the middle of the edge: * **`font-style`** : A [CSS font style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style) to be applied to the label text. * **`font-weight`** : A [CSS font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight) to be applied to the label text. * **`text-transform`** : A transformation to apply to the label text; may be `none`, `uppercase`, or `lowercase`. + * **`text-wrap`** : A wrapping style to apply to the label text; may be `none`, `wrap`. + * **`text-max-width`** : The maximum width for wrapped text, applied when **text-wrap** is set to `wrap`. Default to 75 (px). * **`text-opacity`** : The opacity of the label text, including its outline. * **`text-outline-color`** : The colour of the outline around the element's label text. * **`text-outline-opacity`** : The opacity of the outline on label text. diff --git a/src/extensions/renderer.canvas.drawing-label-text.js b/src/extensions/renderer.canvas.drawing-label-text.js index a2bfb177f..c2b6f71e4 100644 --- a/src/extensions/renderer.canvas.drawing-label-text.js +++ b/src/extensions/renderer.canvas.drawing-label-text.js @@ -49,7 +49,7 @@ context.translate(rs.labelX, rs.labelY); context.rotate(theta); - this.drawText(context, edge, 0, 0); // make label offset from the edge a bit + this.drawText(context, edge, 0, 0); context.rotate(-theta); context.translate(-rs.labelX, -rs.labelY); @@ -200,6 +200,29 @@ ctx.fill(); } + function wrapText(context, text, x, y, maxWidth, lineHeight) { + var words = text.split(' '); + var line = ''; + + for(var n = 0; n < words.length; n++) { + var testLine = line + words[n] + ' '; + var metrics = context.measureText(testLine); + var testWidth = metrics.width; + testWidth = testWidth / ((lineHeight - 1) / 7); + if (testWidth > maxWidth && n > 0) { + context.fillText(line, x, y); + line = words[n] + ' '; + y += lineHeight; + } + else { + line = testLine; + } + } + + context.fillText(line, x, y); + } + + // Draw text CanvasRenderer.prototype.drawText = function(context, element, textX, textY) { var style = element._private.style; @@ -326,7 +349,13 @@ context.strokeText(text, textX, textY); } - context.fillText(text, textX, textY); + if (element.isNode() && style['text-wrap'].value == 'wrap') { + var fontSize = style['font-size'].pxValue; + wrapText(context, text, textX, textY, style['text-max-width'].value, fontSize + 1); + } else { + context.fillText(text, textX, textY); + } + this.shadowStyle(context, 'transparent', 0); // reset for next guy } diff --git a/src/style.js b/src/style.js index e02d8fa0e..b22b9d5b6 100644 --- a/src/style.js +++ b/src/style.js @@ -69,6 +69,7 @@ fontWeight: { enums: ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '800', '900', 100, 200, 300, 400, 500, 600, 700, 800, 900] }, textDecoration: { enums: ['none', 'underline', 'overline', 'line-through'] }, textTransform: { enums: ['none', 'uppercase', 'lowercase'] }, + textWrap: { enums: ['none', 'wrap'] }, nodeShape: { enums: ['rectangle', 'roundrectangle', 'ellipse', 'triangle', 'square', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'star'] }, arrowShape: { enums: ['tee', 'triangle', 'triangle-tee', 'triangle-backcurve', 'half-triangle-overshot', 'square', 'circle', 'diamond', 'none'] }, arrowFill: { enums: ['filled', 'hollow'] }, @@ -109,6 +110,9 @@ { name: 'text-border-style', type: t.borderStyle }, // { name: 'text-decoration', type: t.textDecoration }, // not supported in canvas { name: 'text-transform', type: t.textTransform }, + { name: 'text-wrap', type: t.textWrap }, + { name: 'text-max-width', type: t.size }, + // { name: 'text-rotation', type: t.angle }, // TODO disabled b/c rotation breaks bounding boxes { name: 'font-family', type: t.fontFamily }, { name: 'font-style', type: t.fontStyle }, @@ -246,6 +250,7 @@ var color = '#000' || this.containerPropertyAsString('color') || '#000'; var textTransform = 'none' || this.containerPropertyAsString('text-transform') || 'none'; var fontSize = 16 || this.containerPropertyAsString('font-size') || 16; + var textMaxWidth = 75 || this.containerPropertyAsString('text-max-width') || 75; // fill the style with the default stylesheet this @@ -260,6 +265,8 @@ 'text-opacity': 1, 'text-decoration': 'none', 'text-transform': textTransform, + 'text-wrap': 'wrap', + 'text-max-width': textMaxWidth, 'text-background-color': 'none', 'text-background-opacity': 1, 'text-border-width': 0,