diff --git a/js/viz/axes/base_axis.js b/js/viz/axes/base_axis.js index 41032e63ef66..52f9a0287a26 100644 --- a/js/viz/axes/base_axis.js +++ b/js/viz/axes/base_axis.js @@ -1815,7 +1815,7 @@ Axis.prototype = { if((wordWrapMode !== "none" || overflowMode !== "none") && displayMode !== "rotate" && overlappingMode !== "rotate" && overlappingMode !== "auto" && textWidth) { if(that._majorTicks.some(tick => tick.labelBBox.width > textWidth)) { that._majorTicks.forEach(tick => { - tick.label && tick.label.setMaxWidth(textWidth, options.label); + tick.label && tick.label.setMaxSize(textWidth, undefined, options.label); }); measureLabels(that._majorTicks); } diff --git a/js/viz/core/renderers/renderer.js b/js/viz/core/renderers/renderer.js index 558c08e7849a..66722051f2ee 100644 --- a/js/viz/core/renderers/renderer.js +++ b/js/viz/core/renderers/renderer.js @@ -750,7 +750,7 @@ function parseMultiline(text) { i = 0, items = []; for(; i < texts.length; i++) { - items.push({ value: texts[i].trim(), height: 0 }); + items.push({ value: texts[i].trim(), height: 0, line: i }); } return items; } @@ -831,7 +831,7 @@ function cloneAndRemoveAttrs(node) { return clone || node; } -function setMaxWidth(maxWidth, options = {}) { +function setMaxSize(maxWidth, maxHeight, options = {}) { var that = this, lines = [], textChanged = false, @@ -843,14 +843,18 @@ function setMaxWidth(maxWidth, options = {}) { ellipsis = that.renderer.text(ELLIPSIS).attr(that._styles).append(that.renderer.root); ellipsisWidth = ellipsis.getBBox().width; - if(that._getElementBBox().width > maxWidth) { + + const { width, height } = that._getElementBBox(); + + if(width > maxWidth || maxHeight && height > maxHeight) { if(maxWidth - ellipsisWidth < 0) { ellipsisMaxWidth = 0; } else { ellipsisMaxWidth -= ellipsisWidth; } - lines = applyOverflowRules(that.element, that._texts, maxWidth, ellipsisMaxWidth, options); + lines = applyOverflowRules(that.element, that._texts, maxWidth, ellipsisMaxWidth, options, maxHeight); + lines = setMaxHeight(lines, ellipsisMaxWidth, options, maxHeight, parseFloat(this._getLineHeight())); this._texts = lines.reduce((texts, line) => { return texts.concat(line.parts); @@ -950,6 +954,19 @@ function getWordBreakIndex(text, maxWidth) { } } +function setEllipsis(text, ellipsisMaxWidth) { + if(text.value.length && text.tspan.parentNode) { + for(let i = text.value.length - 1; i >= 1; i--) { + if(text.startBox + text.tspan.getSubStringLength(0, i) < ellipsisMaxWidth) { + setNewText(text, i, ELLIPSIS); + break; + } else if(i === 1) { + setNewText(text, 0, ELLIPSIS); + } + } + } +} + function wordWrap(text, maxWidth, ellipsisMaxWidth, options) { const wholeText = text.value; let breakIndex; @@ -995,14 +1012,7 @@ function wordWrap(text, maxWidth, ellipsisMaxWidth, options) { if(text.value.length) { if(options.textOverflow === "ellipsis" && text.tspan.getSubStringLength(0, text.value.length) > maxWidth) { - for(let i = text.value.length - 1; i >= 1; i--) { - if(text.startBox + text.tspan.getSubStringLength(0, i) < ellipsisMaxWidth) { - setNewText(text, i, ELLIPSIS); - break; - } else if(i === 1) { - setNewText(text, 0, ELLIPSIS); - } - } + setEllipsis(text, ellipsisMaxWidth); } if(options.textOverflow === "hide" && text.tspan.getSubStringLength(0, text.value.length) > maxWidth) { @@ -1021,6 +1031,54 @@ function wordWrap(text, maxWidth, ellipsisMaxWidth, options) { return [{ commonLength: wholeText.length, parts }].concat(restLines); } +function calculateLineHeight(line, lineHeight) { + return line.parts.reduce((height, text) => { + return Math.max(height, getItemLineHeight(text, lineHeight)); + }, 0); +} + +function setMaxHeight(lines, ellipsisMaxWidth, options, maxHeight, lineHeight) { + if(!isFinite(maxHeight)) { + return lines; + } + const result = lines.reduce(([lines, commonHeight], l, index, arr) => { + const height = calculateLineHeight(l, lineHeight); + commonHeight += height; + if(commonHeight < maxHeight) { + lines.push(l); + } else { + l.parts.forEach(item => { + removeTextSpan(item); + }); + if(options.textOverflow === "ellipsis") { + const prevLine = arr[index - 1]; + if(prevLine) { + const text = prevLine.parts[prevLine.parts.length - 1]; + if(!text.hasEllipsis) { + if(text.endBox < ellipsisMaxWidth) { + setNewText(text, text.value.length, ELLIPSIS); + } else { + setEllipsis(text, ellipsisMaxWidth); + } + } + } + } + } + return [lines, commonHeight]; + }, [[], 0]); + + if(options.textOverflow === "hide" && result[1] > maxHeight) { + result[0].forEach(l => { + l.parts.forEach(item => { + removeTextSpan(item); + }); + }); + return []; + } + + return result[0]; +} + function applyOverflowRules(element, texts, maxWidth, ellipsisMaxWidth, options) { if(!texts) { const textValue = element.textContent; @@ -1030,6 +1088,7 @@ function applyOverflowRules(element, texts, maxWidth, ellipsisMaxWidth, options) texts = [text]; } + return texts.reduce(([lines, startBox, endBox, stop, lineNumber], text) => { const line = lines[lines.length - 1]; if(stop) { @@ -1041,7 +1100,7 @@ function applyOverflowRules(element, texts, maxWidth, ellipsisMaxWidth, options) } else { text.startBox = startBox; if(startBox > ellipsisMaxWidth && options.wordWrap === "none" && options.textOverflow === "ellipsis") { - text.tspan.parentNode.removeChild(text.tspan); + removeTextSpan(text); return [lines, startBox, endBox, stop, lineNumber]; } line.parts.push(text); @@ -1070,11 +1129,14 @@ function setNewText(text, index, insertString = ELLIPSIS) { var newText = text.value.substr(0, index) + insertString; text.value = text.tspan.textContent = newText; text.stroke && (text.stroke.textContent = newText); + if(insertString === ELLIPSIS) { + text.hasEllipsis = true; + } } function removeTextSpan(text) { - text.tspan.parentNode.removeChild(text.tspan); - text.stroke && text.stroke.parentNode.removeChild(text.stroke); + text.tspan.parentNode && text.tspan.parentNode.removeChild(text.tspan); + text.stroke && text.stroke.parentNode && text.stroke.parentNode.removeChild(text.stroke); } function createTextNodes(wrapper, text, isStroked) { @@ -1116,11 +1178,15 @@ function setTextNodeAttribute(item, name, value) { item.stroke && item.stroke.setAttribute(name, value); } +function getItemLineHeight(item, defaultValue) { + return item.inherits ? maxLengthFontSize(item.height, defaultValue) : (item.height || defaultValue); +} + function locateTextNodes(wrapper) { if(!wrapper._texts) return; var items = wrapper._texts, x = wrapper._settings.x, - lineHeight = !isNaN(_parseFloat(wrapper._styles[KEY_FONT_SIZE])) ? wrapper._styles[KEY_FONT_SIZE] : DEFAULT_FONT_SIZE, + lineHeight = wrapper._getLineHeight(), i, ii, item = items[0]; setTextNodeAttribute(item, "x", x); @@ -1129,7 +1195,8 @@ function locateTextNodes(wrapper) { item = items[i]; if(_parseFloat(item.height) >= 0) { setTextNodeAttribute(item, "x", x); - setTextNodeAttribute(item, "dy", item.inherits ? maxLengthFontSize(item.height, lineHeight) : (item.height || lineHeight)); // T177039 + const height = getItemLineHeight(item, lineHeight); + setTextNodeAttribute(item, "dy", height); // T177039 } } } @@ -1674,8 +1741,11 @@ extend(TextSvgElement.prototype, { attr: textAttr, css: textCss, applyEllipsis, - setMaxWidth, - restoreText + setMaxSize, + restoreText, + _getLineHeight() { + return !isNaN(_parseFloat(this._styles[KEY_FONT_SIZE])) ? this._styles[KEY_FONT_SIZE] : DEFAULT_FONT_SIZE; + } }); // TextSvgElement diff --git a/js/viz/core/title.js b/js/viz/core/title.js index 1456203bdabf..3e2925d3c4ab 100644 --- a/js/viz/core/title.js +++ b/js/viz/core/title.js @@ -12,7 +12,7 @@ function hasText(text) { } function processTitleLength(elem, text, width, options) { - elem.attr({ text: text }).setMaxWidth(width, options).textChanged && elem.setTitle(text); + elem.attr({ text }).setMaxSize(width, undefined, options).textChanged && elem.setTitle(text); } function pickMarginValue(value) { diff --git a/js/viz/series/points/label.js b/js/viz/series/points/label.js index acb62189ff7d..4e1e4c76d1fc 100644 --- a/js/viz/series/points/label.js +++ b/js/viz/series/points/label.js @@ -458,7 +458,7 @@ Label.prototype = { const padding = this._background ? 2 * LABEL_BACKGROUND_PADDING_X : 0; let rowCountChanged = false; if(this._text) { - let { rowCount } = this._text.setMaxWidth(maxWidth - padding, this._options); + let { rowCount } = this._text.setMaxSize(maxWidth - padding, undefined, this._options); if(rowCount === 0) { rowCount = 1; } diff --git a/js/viz/tree_map/tree_map.base.js b/js/viz/tree_map/tree_map.base.js index 28d486e02550..d107aa05bc68 100644 --- a/js/viz/tree_map/tree_map.base.js +++ b/js/viz/tree_map/tree_map.base.js @@ -604,7 +604,10 @@ function layoutTextNode(node, params) { if(_isDefined(resolveLabelOverflow)) { if(resolveLabelOverflow === "ellipsis" && fitByHeight) { - text.applyEllipsis(effectiveWidth); + text.setMaxSize(effectiveWidth, undefined, { + wordWrap: "none", + textOverflow: "ellipsis" + }); if(!fitByWidth) { bBox = text.getBBox(); fitByWidth = bBox.width <= effectiveWidth; @@ -612,7 +615,8 @@ function layoutTextNode(node, params) { } } else { fitByWidth = true; - text.setMaxWidth(effectiveWidth, node.isNode() ? { textOverflow: groupLabelOverflow, wordWrap: "none" } : + fitByHeight = true; + text.setMaxSize(effectiveWidth, rect[3] - rect[1] - paddingTopBottom, node.isNode() ? { textOverflow: groupLabelOverflow, wordWrap: "none" } : { textOverflow: tileLabelOverflow, wordWrap: tileLabelWordWrap }); } diff --git a/testing/helpers/vizMocks.js b/testing/helpers/vizMocks.js index 851a218592d3..e95e33b80e4a 100644 --- a/testing/helpers/vizMocks.js +++ b/testing/helpers/vizMocks.js @@ -55,7 +55,7 @@ applyEllipsis: function(maxWidth) { // for text return maxWidth < 50; }, - setMaxWidth: function(maxWidth) { // for text + setMaxSize: function(maxWidth) { // for text return { textChanged: maxWidth < 50 }; }, stopAnimation: function() { diff --git a/testing/tests/DevExpress.viz.core.series/label.tests.js b/testing/tests/DevExpress.viz.core.series/label.tests.js index 184beb47650c..aadc61b308ab 100644 --- a/testing/tests/DevExpress.viz.core.series/label.tests.js +++ b/testing/tests/DevExpress.viz.core.series/label.tests.js @@ -1308,7 +1308,7 @@ QUnit.test("fit without background", function(assert) { var text = this.renderer.text.getCall(0).returnValue; - assert.equal(text.setMaxWidth.args[0][0], 15, "Max width param"); + assert.equal(text.setMaxSize.args[0][0], 15, "Max width param"); }); QUnit.test("fit with background", function(assert) { @@ -1322,7 +1322,7 @@ QUnit.test("fit with background", function(assert) { var text = this.renderer.text.getCall(0).returnValue, background = this.renderer.rect.getCall(0).returnValue; - assert.equal(text.setMaxWidth.args[0][0], 15, "Max width param"); + assert.equal(text.setMaxSize.args[0][0], 15, "Max width param"); assert.strictEqual(background.attr.called, true, "New background rect"); }); @@ -1330,7 +1330,7 @@ QUnit.test("Label's fit. Count of rows changed", function(assert) { this.options.background = { fill: "red" }; const label = this.createAndDrawLabel(); - this.renderer.text.lastCall.returnValue.setMaxWidth = function() { + this.renderer.text.lastCall.returnValue.setMaxSize = function() { return { rowCount: 2 }; }; label.shift(-7, -2); @@ -1342,7 +1342,7 @@ QUnit.test("Label's fit. Count of rows not changed", function(assert) { this.options.background = { fill: "red" }; const label = this.createAndDrawLabel(); - this.renderer.text.lastCall.returnValue.setMaxWidth = function() { + this.renderer.text.lastCall.returnValue.setMaxSize = function() { return { rowCount: 1 }; }; label.shift(-7, -2); @@ -1354,7 +1354,7 @@ QUnit.test("Label's fit. rowCount = 0 ", function(assert) { this.options.background = { fill: "red" }; const label = this.createAndDrawLabel(); - this.renderer.text.lastCall.returnValue.setMaxWidth = function() { + this.renderer.text.lastCall.returnValue.setMaxSize = function() { return { rowCount: 0 }; }; label.shift(-7, -2); diff --git a/testing/tests/DevExpress.viz.core/axisDrawing.tests.js b/testing/tests/DevExpress.viz.core/axisDrawing.tests.js index bbb726f4885a..7ab58590d3d8 100644 --- a/testing/tests/DevExpress.viz.core/axisDrawing.tests.js +++ b/testing/tests/DevExpress.viz.core/axisDrawing.tests.js @@ -2392,13 +2392,13 @@ QUnit.test("Horizontal top. WordWrap != none, textOverflow = none. Labels are wi assert.deepEqual(text1.attr.getCall(1).args[0], { x: 40, y: 30 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 60, y: 30 }); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].textOverflow, "none"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].textOverflow, "none"); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 40 - 3 - 10 / 2, translateY: 30 - 10 - 12 - 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 60 - 6 - 10 / 2, translateY: 30 - 10 - 16 - 4 }, "Text args"); @@ -2450,13 +2450,13 @@ QUnit.test("Horizontal top. WordWrap = none, textOverflow != none. Labels are wi assert.deepEqual(text1.attr.getCall(1).args[0], { x: 40, y: 30 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 60, y: 30 }); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].wordWrap, "none"); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].textOverflow, "ellipsis"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].wordWrap, "none"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].textOverflow, "ellipsis"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].wordWrap, "none"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].textOverflow, "ellipsis"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].wordWrap, "none"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].textOverflow, "ellipsis"); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 40 - 3 - 10 / 2, translateY: 30 - 10 - 12 - 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 60 - 6 - 10 / 2, translateY: 30 - 10 - 16 - 4 }, "Text args"); @@ -2511,13 +2511,13 @@ QUnit.test("Horizontal top. Labels are wider than tick interval (datetime) - set assert.deepEqual(text1.attr.getCall(1).args[0], { x: 40, y: 30 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 60, y: 30 }); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].textOverflow, "none"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].textOverflow, "none"); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 40 - 3 - 10 / 2, translateY: 30 - 10 - 12 - 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 60 - 6 - 10 / 2, translateY: 30 - 10 - 16 - 4 }, "Text args"); @@ -2568,8 +2568,8 @@ QUnit.test("Horizontal top. Labels are narrower than tick interval - do not set assert.deepEqual(text1.attr.getCall(1).args[0], { x: 40, y: 30 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 60, y: 30 }); - assert.deepEqual(text1.stub("setMaxWidth").callCount, 0); - assert.deepEqual(text2.stub("setMaxWidth").callCount, 0); + assert.deepEqual(text1.stub("setMaxSize").callCount, 0); + assert.deepEqual(text2.stub("setMaxSize").callCount, 0); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 40 - 1 - 12 / 2, translateY: 30 - 10 - 6 - 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 60 - 3 - 14 / 2, translateY: 30 - 10 - 8 - 4 }, "Text args"); @@ -2612,8 +2612,8 @@ QUnit.test("Horizontal top. No wordWrap option, no textOverflow option - do not this.axis.draw(this.canvas); // assert - assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxWidth").callCount, 0); - assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxWidth").callCount, 0); + assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxSize").callCount, 0); + assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxSize").callCount, 0); }); QUnit.test("Horizontal top. DisplayMode = rotate - do not set max width", function(assert) { @@ -2653,8 +2653,8 @@ QUnit.test("Horizontal top. DisplayMode = rotate - do not set max width", functi this.axis.draw(this.canvas); // assert - assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxWidth").callCount, 0); - assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxWidth").callCount, 0); + assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxSize").callCount, 0); + assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxSize").callCount, 0); }); QUnit.test("Horizontal top. OverlappingBehavior = rotate - do not set max width", function(assert) { @@ -2694,8 +2694,8 @@ QUnit.test("Horizontal top. OverlappingBehavior = rotate - do not set max width" this.axis.draw(this.canvas); // assert - assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxWidth").callCount, 0); - assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxWidth").callCount, 0); + assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxSize").callCount, 0); + assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxSize").callCount, 0); }); QUnit.test("Horizontal top. OverlappingBehavior = auto - do not set max width", function(assert) { @@ -2735,8 +2735,8 @@ QUnit.test("Horizontal top. OverlappingBehavior = auto - do not set max width", this.axis.draw(this.canvas); // assert - assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxWidth").callCount, 0); - assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxWidth").callCount, 0); + assert.deepEqual(renderer.text.getCall(0).returnValue.stub("setMaxSize").callCount, 0); + assert.deepEqual(renderer.text.getCall(1).returnValue.stub("setMaxSize").callCount, 0); }); QUnit.test("Vertical left. Labels are wider than placeholderSize less than - set max width", function(assert) { @@ -2784,13 +2784,13 @@ QUnit.test("Vertical left. Labels are wider than placeholderSize less than - set assert.deepEqual(text1.attr.getCall(1).args[0], { x: 10, y: 40 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 10, y: 60 }); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text1.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text1.setMaxSize.getCall(0).args[2].textOverflow, "none"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[0], 10); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].wordWrap, "normal"); - assert.deepEqual(text2.setMaxWidth.getCall(0).args[1].textOverflow, "none"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[0], 10); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].wordWrap, "normal"); + assert.deepEqual(text2.setMaxSize.getCall(0).args[2].textOverflow, "none"); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 10 - 10 - (3 + 10), translateY: 40 - 2 - 12 / 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 10 - 10 - (6 + 10), translateY: 60 - 4 - 16 / 2 }, "Text args"); @@ -2841,8 +2841,8 @@ QUnit.test("Vertical left. Labels are shorter than placeholderSize - do not set assert.deepEqual(text1.attr.getCall(1).args[0], { x: 10, y: 40 }); assert.deepEqual(text2.attr.getCall(1).args[0], { x: 10, y: 60 }); - assert.deepEqual(text1.stub("setMaxWidth").callCount, 0); - assert.deepEqual(text2.stub("setMaxWidth").callCount, 0); + assert.deepEqual(text1.stub("setMaxSize").callCount, 0); + assert.deepEqual(text2.stub("setMaxSize").callCount, 0); assert.deepEqual(text1.attr.getCall(2).args[0], { translateX: 10 - 10 - (1 + 12), translateY: 40 - 2 - 6 / 2 }, "Text args"); assert.deepEqual(text2.attr.getCall(2).args[0], { translateX: 10 - 10 - (3 + 14), translateY: 60 - 4 - 8 / 2 }, "Text args"); diff --git a/testing/tests/DevExpress.viz.core/title.tests.js b/testing/tests/DevExpress.viz.core/title.tests.js index aed6b5ccdb2f..7f332baa1daa 100644 --- a/testing/tests/DevExpress.viz.core/title.tests.js +++ b/testing/tests/DevExpress.viz.core/title.tests.js @@ -322,7 +322,7 @@ QUnit.test("Drawing with subtitle", function(assert) { assert.deepEqual(subtitleElement.attr.getCall(1).args[0], { text: "subtitle", y: 0 }); assert.deepEqual(subtitleElement.move.lastCall.args, [0, 8]); - assert.ok(subtitleElement.move.lastCall.calledAfter(titleElement.setMaxWidth.lastCall)); + assert.ok(subtitleElement.move.lastCall.calledAfter(titleElement.setMaxSize.lastCall)); }); QUnit.test("Second Update", function(assert) { @@ -383,8 +383,8 @@ QUnit.test("Length of title greater than canvas width", function(assert) { this.createTitle().draw(this.canvas.width, this.canvas.height); - assert.equal(this.renderer.text.getCall(0).returnValue.setMaxWidth.lastCall.args[0], 770); - assert.equal(this.renderer.text.getCall(1).returnValue.setMaxWidth.lastCall.args[0], 770); + assert.equal(this.renderer.text.getCall(0).returnValue.setMaxSize.lastCall.args[0], 770); + assert.equal(this.renderer.text.getCall(1).returnValue.setMaxSize.lastCall.args[0], 770); }); QUnit.test("Set title if text has big size", function(assert) { diff --git a/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js b/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js index a4e3f2f09033..ca08fbcc9732 100644 --- a/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js +++ b/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js @@ -5775,7 +5775,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal" }); assert.deepEqual(result, { rowCount: 5, textChanged: true }); @@ -5796,7 +5796,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "clip" }); @@ -5815,7 +5815,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "word-break" }); @@ -5832,7 +5832,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "clip" }); @@ -5855,7 +5855,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "ellipsis" }); @@ -5872,7 +5872,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "hide" }); @@ -5886,7 +5886,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal" }); @@ -5907,7 +5907,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "none", textOverflow: "ellipsis" }); @@ -5925,7 +5925,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "ellipsis" }); @@ -5954,7 +5954,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "none", textOverflow: "ellipsis" }); @@ -5964,12 +5964,24 @@ function checkDashStyle(assert, elem, result, style, value) { assert.equal(text.element.childNodes.length, 1); }); + QUnit.test("Complex text. wordWrap: none, text overflow: ellipsis - remove test next to ellipsis. Stroked text", function(assert) { + var text = this.createText().append(this.svg).attr({ x: 35, y: 100, fill: "black", stroke: "black", "stroke-width": 2, text: "longlonglonglonglong longlonglonglonglong" }); + + this.prepareRenderBeforeEllipsis(); + text.setMaxSize(110, undefined, { + wordWrap: "none", + textOverflow: "ellipsis" + }); + + assert.equal(text.element.childNodes.length, 2); + }); + QUnit.test("Complex text. wordWrap: normal, text overflow: ellipsis - wrap word", function(assert) { var text = this.createText().append(this.svg).attr({ x: 35, y: 100, fill: "black", stroke: "black", text: "longlonglonglonglong longlonglonglonglong" }), result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal", textOverflow: "ellipsis" }); @@ -5987,7 +5999,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(110, { + result = text.setMaxSize(110, undefined, { wordWrap: "normal" }); @@ -6009,7 +6021,7 @@ function checkDashStyle(assert, elem, result, style, value) { result; this.prepareRenderBeforeEllipsis(); - result = text.setMaxWidth(1, { + result = text.setMaxSize(1, undefined, { wordWrap: "none", textOverflow: "ellipsis" }); @@ -6020,5 +6032,71 @@ function checkDashStyle(assert, elem, result, style, value) { { x: 35, y: 100, text: "..." } ], { x: 35, y: 100 }); }); + + QUnit.test("Set max height. textOverflow hide", function(assert) { + var text = this.createText().append(this.svg).attr({ + x: 35, y: 100, fill: "black", + text: "There is test text for checking ellipsis with single line" + }); + + this.prepareRenderBeforeEllipsis(); + text.setMaxSize(110, 20, { + wordWrap: "normal", + textOverflow: "hide" + }); + + assert.equal(text.getBBox().height, 0); + }); + + QUnit.test("Set max height. textOverflow ellipsis. multi line text, Last text width less than maxWidth - add ... at the end", function(assert) { + var text = this.createText().append(this.svg).attr({ + x: 35, y: 100, fill: "black", + text: "There\nis\ntest\ntext\nfor checking ellipsis with single line" + }); + + this.prepareRenderBeforeEllipsis(); + text.setMaxSize(110, 25, { + wordWrap: "none", + textOverflow: "ellipsis" + }); + + this.checkTspans(assert, text, [ + { x: 35, y: 100, text: "There" }, + { x: 35, dy: 12, text: "is..." }, + ], { x: 35, y: 100 }); + }); + + QUnit.test("Set max height. textOverflow ellipsis. multi line text, Do not add ... double times", function(assert) { + var text = this.createText().append(this.svg).attr({ + x: 35, y: 100, fill: "black", + text: "Text\nText Text Text Text Text Text\nText" + }); + + this.prepareRenderBeforeEllipsis(); + text.setMaxSize(110, 25, { + wordWrap: "none", + textOverflow: "ellipsis" + }); + + assert.ok(text.element.childNodes[1].textContent.indexOf("...") > 0); + assert.equal(text.element.childNodes[1].textContent.indexOf("......"), -1); + assert.ok(text.getBBox().width <= 110); + }); + + QUnit.test("Set max height. textOverflow ellipsis. Slice text", function(assert) { + var text = this.createText().append(this.svg).attr({ + x: 35, y: 100, fill: "black", + text: "Text\nText Text Text 1\nText" + }); + + this.prepareRenderBeforeEllipsis(); + text.setMaxSize(110, 25, { + wordWrap: "none", + textOverflow: "ellipsis" + }); + + assert.ok(text.element.childNodes[1].textContent.indexOf("...") > 0); + assert.ok(text.getBBox().width <= 110); + }); } })(); diff --git a/testing/tests/DevExpress.viz.treeMap/treeMap.base.tests.js b/testing/tests/DevExpress.viz.treeMap/treeMap.base.tests.js index 12747fd2514d..9fddff3da1c8 100644 --- a/testing/tests/DevExpress.viz.treeMap/treeMap.base.tests.js +++ b/testing/tests/DevExpress.viz.treeMap/treeMap.base.tests.js @@ -3,6 +3,11 @@ var $ = require("jquery"), themeModule = require("viz/themes"), DataSource = require("data/data_source/data_source").DataSource; +var ELLIPSIS_SETTINGS = { + wordWrap: "none", + textOverflow: "ellipsis" +}; + function createDataSource(value) { return new DataSource({ load: function() { @@ -983,8 +988,8 @@ QUnit.test("resolveLabelOverflow changed for tile labels", function(assert) { widget.option("resolveLabelOverflow", "ellipsis"); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); - assert.ok(this.renderer.text.lastCall.returnValue.applyEllipsis.calledOnce); - assert.equal(this.renderer.text.lastCall.returnValue.applyEllipsis.args[0][0], 20); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [20, undefined, ELLIPSIS_SETTINGS]); }); QUnit.test("Passing 'wordWrap' and 'overflow' options to texts for tiles", function(assert) { @@ -1002,8 +1007,8 @@ QUnit.test("Passing 'wordWrap' and 'overflow' options to texts for tiles", funct dataSource: [{ name: "Label", value: 10 }] }); - assert.ok(this.renderer.text.lastCall.returnValue.setMaxWidth.calledOnce); - assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxWidth.lastCall.args, [20, { wordWrap: "wordWrap_1", textOverflow: "overflow_1" }]); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [20, 396, { wordWrap: "wordWrap_1", textOverflow: "overflow_1" }]); }); QUnit.test("Passing 'overflow' option to texts for group", function(assert) { @@ -1020,8 +1025,8 @@ QUnit.test("Passing 'overflow' option to texts for group", function(assert) { dataSource: [{ name: "groupName", items: [{ name: "Label", value: 10 }] }] }); - assert.ok(this.renderer.text.getCall(1).returnValue.setMaxWidth.calledOnce); - assert.deepEqual(this.renderer.text.getCall(1).returnValue.setMaxWidth.lastCall.args, [12, { textOverflow: "overflow_1", wordWrap: "none" }]); + assert.ok(this.renderer.text.getCall(1).returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.getCall(1).returnValue.setMaxSize.lastCall.args, [12, 9, { textOverflow: "overflow_1", wordWrap: "none" }]); }); QUnit.test("Do not hide label if it width is equal to allowed width", function(assert) { @@ -1050,8 +1055,8 @@ QUnit.test("resolveLabelOverflow changed for group labels", function(assert) { widget.option("resolveLabelOverflow", "ellipsis"); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); - assert.ok(this.renderer.text.lastCall.returnValue.applyEllipsis.calledOnce); - assert.equal(this.renderer.text.lastCall.returnValue.applyEllipsis.args[0][0], 12); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [12, undefined, ELLIPSIS_SETTINGS]); }); QUnit.module("labels", environment); @@ -1252,6 +1257,19 @@ QUnit.test("label's height > tile height", function(assert) { dataSource: [{ value: 1, name: "some" }] }); + assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); +}); + +QUnit.test("label's height > tile height. resolveLabelOverflow", function(assert) { + this.renderer.bBoxTemplate = { x: 0, y: 0, width: 4, height: 15 }; + common.createWidget({ + size: { + height: 10 + }, + dataSource: [{ value: 1, name: "some" }], + resolveLabelOverflow: "ellipsis" + }); + assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "hidden"); }); @@ -1262,7 +1280,8 @@ QUnit.test("Hide multiline tile's label", function(assert) { size: { height: 10 }, - dataSource: [{ value: 1, name: "some
second line" }] + dataSource: [{ value: 1, name: "some
second line" }], + resolveLabelOverflow: "ellipsis" }); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "hidden"); @@ -1294,8 +1313,8 @@ QUnit.test("ellipsis label in header", function(assert) { }); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); - assert.ok(this.renderer.text.lastCall.returnValue.applyEllipsis.calledOnce); - assert.equal(this.renderer.text.lastCall.returnValue.applyEllipsis.args[0][0], 12); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [12, undefined, ELLIPSIS_SETTINGS]); }); QUnit.test("ellipsis label in header does not fit in width", function(assert) { @@ -1310,8 +1329,8 @@ QUnit.test("ellipsis label in header does not fit in width", function(assert) { }); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "hidden"); - assert.ok(this.renderer.text.lastCall.returnValue.applyEllipsis.calledOnce); - assert.equal(this.renderer.text.lastCall.returnValue.applyEllipsis.args[0][0], 2); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [2, undefined, ELLIPSIS_SETTINGS]); }); QUnit.test("label in header does not fit in width, but fit after ellipsis", function(assert) { @@ -1328,8 +1347,8 @@ QUnit.test("label in header does not fit in width, but fit after ellipsis", func }); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); - assert.ok(this.renderer.text.lastCall.returnValue.applyEllipsis.calledOnce); - assert.equal(this.renderer.text.lastCall.returnValue.applyEllipsis.args[0][0], 7); + assert.ok(this.renderer.text.lastCall.returnValue.setMaxSize.calledOnce); + assert.deepEqual(this.renderer.text.lastCall.returnValue.setMaxSize.lastCall.args, [7, undefined, ELLIPSIS_SETTINGS]); }); QUnit.test("draw only header labels", function(assert) { @@ -1421,6 +1440,7 @@ QUnit.test("labels with small widget height", function(assert) { size: { height: 17 }, + resolveLabelOverflow: "ellipsis", dataSource: [{ name: 'g', value: 1 }] }); @@ -1474,7 +1494,7 @@ QUnit.test("ellipsis mode, change width from small to big - reapply ellipsis", f }); assert.strictEqual(this.renderer.text.lastCall.returnValue.attr.lastCall.args[0].visibility, "visible"); - assert.equal(this.renderer.text.lastCall.returnValue.stub("applyEllipsis").called, true); + assert.equal(this.renderer.text.lastCall.returnValue.stub("setMaxSize").called, true); }); QUnit.module("'onDrawn' event", $.extend({}, environment, {