8000 Initial commit - first try of the word wrapping · plotly/plotly.js@53cd362 · GitHub
[go: up one dir, main page]

Skip to content

Commit 53cd362

Browse files
committed
Initial commit - first try of the word wrapping
1 parent d0e1bef commit 53cd362

File tree

6 files changed

+84
-19
lines changed

6 files changed

+84
-19
lines changed

src/components/annotations/draw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
248248
}[options.align] || 'middle'
249249
});
250250

251-
svgTextUtils.convertToTspans(s, gd, drawGraphicalElements);
251+
svgTextUtils.convertToTspans(s, gd, null, drawGraphicalElements);
252252
return s;
253253
}
254254

src/components/legend/draw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ function setupTraceToggle(g, gd) {
496496

497497
function textLayout(s, g, gd, legendObj, aTitle) {
498498
if(legendObj._inHover) s.attr('data-notex', true); // do not process MathJax for unified hover
499-
svgTextUtils.convertToTspans(s, gd, function() {
499+
svgTextUtils.convertToTspans(s, gd, null, function() {
500500
computeTextDimensions(g, gd, legendObj, aTitle);
501501
});
502502
}

src/components/titles/index.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ function draw(gd, titleClass, options) {
5656
var attributes = options.attributes;
5757
var transform = options.transform;
5858
var group = options.containerGroup;
59+
var isAxis = options.isAxis; // Prepare documentation for this
60+
var wrap = options.wrap;
5961

6062
var fullLayout = gd._fullLayout;
6163

@@ -120,6 +122,7 @@ function draw(gd, titleClass, options) {
120122

121123
function drawTitle(titleEl) {
122124
var transformVal;
125+
var convertOptions = null;
123126

124127
if(transform) {
125128
transformVal = '';
@@ -133,6 +136,17 @@ function draw(gd, titleClass, options) {
133136
transformVal = null;
134137
}
135138

139+
if(isAxis && wrap) {
140+
var axName = options.propContainer._name;
141+
var axOut = gd._fullLayout[axName];
142+
143+
convertOptions = {
144+
wrap: wrap,
145+
axisLength: axOut._length,
146+
axisOrientation: axOut._id.substr(0, 1) === 'y' ? 'v' : 'h'
147+
};
148+
}
149+
136150
titleEl.attr('transform', transformVal);
137151

138152
titleEl.style({
@@ -143,13 +157,13 @@ function draw(gd, titleClass, options) {
143157
'font-weight': Plots.fontWeight
144158
})
145159
.attr(attributes)
146-
.call(svgTextUtils.convertToTspans, gd);
160+
.call(svgTextUtils.convertToTspans, gd, convertOptions);
147161

148162
return Plots.previousPromises(gd);
149163
}
150164

151-
function scootTitle(titleElIn) {
152-
var titleGroup = d3.select(titleElIn.node().parentNode);
165+
function scootTitle(titleEl) {
166+
var titleGroup = d3.select(titleEl.node().parentNode);
153167

154168
if(avoid && avoid.selection && avoid.side && txt) {
155169
titleGroup.attr('transform', null);

src/lib/svg_text_utils.js

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,18 @@ function getSize(_selection, _dimension) {
1717

1818
var FIND_TEX = /([^$]*)([$]+[^$]*[$]+)([^$]*)/;
1919

20-
exports.convertToTspans = function(_context, gd, _callback) {
20+
/**
21+
* Converts to <tspan /> SVG element.
22+
* @param {*} _context Context
23+
* @param {*} gd Graph DIV
24+
* @param {*} options All props are needed to wrap.
25+
* [axLength]?: number
26+
* [orientation]?: 'v' | 'h'
27+
* [wrap]?: boolean
28+
* @param {Function} _callback Callback function.
29+
* @returns Modified `_context`.
30+
*/
31+
exports.convertToTspans = function(_context, gd, options, _callback) {
2132
var str = _context.text();
2233

2334
// Until we get tex integrated more fully (so it can be used along with non-tex)
@@ -50,7 +61,7 @@ exports.convertToTspans = function(_context, gd, _callback) {
5061
_context.text('')
5162
.style('white-space', 'pre');
5263

53-
var hasLink = buildSVGText(_context.node(), str);
64+
var hasLink = buildSVGText(_context.node(), str, options);
5465

5566
if(hasLink) {
5667
// at least in Chrome, pointer-events does not seem
@@ -428,24 +439,24 @@ function fromCodePoint(code) {
428439
);
429440
}
430441

431-
/*
432-
* buildSVGText: convert our pseudo-html into SVG tspan elements, and attach these
433-
* to containerNode
442+
/**
443+
* Converts SVG `<tspan />` elements from pseudo-html into, and attach these to `containerNode`.
434444
*
435445
* @param {svg text element} containerNode: the <text> node to insert this text into
436446
* @param {string} str: the pseudo-html string to convert to svg
437-
*
447+
* @param {{ axLength: number, axOrientation: 'v' | 'h', wrap?: boolean }} options
438448
* @returns {bool}: does the result contain any links? We need to handle the text element
439449
* somewhat differently if it does, so just keep track of this when it happens.
440450
*/
441-
function buildSVGText(containerNode, str) {
451+
function buildSVGText(containerNode, str, options) {
442452
/*
443453
* Normalize behavior between IE and others wrt newlines and whitespace:pre
444454
* this combination makes IE barf https://github.com/plotly/plotly.js/issues/746
445455
* Chrome and FF display \n, \r, or \r\n as a space in this mode.
446456
* I feel like at some point we turned these into <br> but currently we don't so
447457
* I'm just going to cement what we do now in Chrome and FF
448458
*/
459+
str = options && options.axOrientation === 'v' ? 'One very long string that is soo long, that<br>I dont get it!' : str;
449460
str = str.replace(NEWLINES, ' ');
450461

451462
var hasLink = false;
@@ -530,7 +541,11 @@ function buildSVGText(containerNode, str) {
530541
}
531542

532543
function addTextNode(node, text) {
533-
node.appendChild(document.createTextNode(text));
544+
return node.appendChild(document.createTextNode(text));
545+
}
546+
547+
function removeTextNode(node, child) {
548+
node.removeChild(child);
534549
}
535550

536551
function exitNode(type) {
@@ -550,16 +565,19 @@ function buildSVGText(containerNode, str) {
550565
currentNode = nodeStack[nodeStack.length - 1].node;
551566
}
552567

553-
var hasLines = BR_TAG.test(str);
568+
var hasBrLines = BR_TAG.test(str);
554569

555-
if(hasLines) newLine();
570+
if(hasBrLines) newLine();
556571
else {
557572
currentNode = containerNode;
558573
nodeStack = [{node: containerNode}];
559574
}
560575

561576
var parts = str.split(SPLIT_TAGS);
562-
for(var i = 0; i < parts.length; i++) {
577+
// eslint-disable-next-line no-console
578+
// options && options.axOrientation === 'v' && console.log(parts);
579+
var i = 0;
580+
for(i; i < parts.length; i++) {
563581
var parti = parts[i];
564582
var match = parti.match(ONE_TAG);
565583
var tagType = match && match[2].toLowerCase();
@@ -568,7 +586,33 @@ function buildSVGText(containerNode, str) {
568586
if(tagType === 'br') {
569587
newLine();
570588
} else if(tagStyle === undefined) {
571-
addTextNode(currentNode, convertEntities(parti));
589+
// addTextNode(currentNode, convertEntities(parti));
590+
591+
if(options && options.axOrientation === 'v') {
592+
if(options.wrap) {
593+
var wordId = 0;
594+
var wordsArray = parti.split(' ');
595+
for(wordId; wordId < wordsArray.length; wordId++) {
596+
var word = wordsArray[wordId];
597+
var preSpace = wordId === 0 ? '' : ' ';
598+
var child = addTextNode(currentNode, convertEntities(preSpace + word));
599+
if(currentNode.getBBox().width > options.axLength) {
600+
removeTextNode(currentNode, child);
601+
newLine();
602+
addTextNode(currentNode, convertEntities(word));
603+
}
604+
// eslint-disable-next-line no-console
605+
// console.log(currentNode.getBBox().width);
606+
}
607+
608+
// eslint-disable-next-line no-console
609+
// options && options.axOrientation === 'v' && console.log(currentNode.getBoundingClientRect().height);
610+
// eslint-disable-next-line no-console
611+
// options && options.axOrientation === 'v' && console.log(currentNode.getBBox().width);
612+
} else {
613+
addTextNode(currentNode, convertEntities(parti));
614+
}
615+
}
572616
} else {
573617
// tag - open or close
574618
if(match[1]) {

src/plots/cartesian/axes.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3464,6 +3464,8 @@ function drawTitle(gd, ax) {
34643464
var axId = ax._id;
34653465
var axLetter = axId.charAt(0);
34663466
var fontSize = ax.title.font.size;
3467+
// var wrap = ax.title.wrap; // TODO: Update documentation and the TypeScript types.
3468+
34673469
var titleStandoff;
34683470

34693471
if(ax.title.hasOwnProperty('standoff')) {
@@ -3536,7 +3538,12 @@ function drawTitle(gd, ax) {
35363538
placeholder: fullLayout._dfltTitle[axLetter],
35373539
avoid: avoid,
35383540
transform: transform,
3539-
attributes: {x: x, y: y, 'text-anchor': 'middle'}
3541+
attributes: {x: x, y: y, 'text-anchor': 'middle'},
3542+
isAxis: true,
3543+
// wrap: wrap
3544+
// HEY! This is for testing only!
3545+
wrap: 'breakword',
3546+
// TODO: options: 'breakword' | 'breakchar' | undefined (default)
35403547
});
35413548
}
35423549

src/traces/table/plot.js

+1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ function populateCellText(cellText, tableControlView, allColumnBlock, gd) {
561561

562562
var renderCallback = d.wrappingNeeded ? wrapTextMaker : updateYPositionMaker;
563563
if(d.needsConvertToTspans) {
564-
svgUtil.convertToTspans(selection, gd, renderCallback(allColumnBlock, element, tableControlView, gd, d));
564+
svgUtil.convertToTspans(selection, gd, null, renderCallback(allColumnBlock, element, tableControlView, gd, d));
565565
} else {
566566
d3.select(element.parentNode)
567567
// basic cell adjustment - compliance with `cellPad`

0 commit comments

Comments
 (0)
0