Skip to content

Commit 1d6a2c3

Browse files
authored
fix(text): Fix multiline data labels vertial position
Make vertical multiline text positioned at the middle as default Fix #4062
1 parent 383c0fb commit 1d6a2c3

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

src/ChartInternal/internals/text.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export default {
139139
if (isNumber(value)) {
140140
this.textContent = value;
141141
} else {
142-
setTextValue(node, value);
142+
setTextValue(node, value, undefined, true);
143143
}
144144
});
145145

src/module/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function sanitize(str: string): string {
188188
}
189189

190190
/**
191-
* Set text value. If there's multiline add nodes.
191+
* Set text value. If there're multiline add nodes.
192192
* @param {d3Selection} node Text node
193193
* @param {string} text Text value string
194194
* @param {Array} dy dy value for multilined text

test/internals/text-spec.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,128 @@ describe("TEXT", () => {
551551
});
552552
});
553553

554+
describe("multiline data labels", () => {
555+
beforeAll(() => {
556+
args = {
557+
data: {
558+
columns: [
559+
["data1", 100, 200, 150],
560+
["data2", 80, 120, 90]
561+
],
562+
type: "bar",
563+
labels: {
564+
format: (v) => {
565+
// Return multiline text with newline character
566+
return `Value:\n${v}`;
567+
}
568+
}
569+
}
570+
};
571+
});
572+
573+
it("should render multiline labels with tspan elements", () => {
574+
const textElements = chart.$.main.selectAll(`.${$TEXT.texts} text.${$TEXT.text}`);
575+
576+
expect(textElements.size()).to.be.greaterThan(0);
577+
578+
// Check that multiline labels have tspan elements
579+
textElements.each(function() {
580+
const text = d3Select(this);
581+
const tspans = text.selectAll("tspan");
582+
583+
// Multiline labels should have 2 tspan elements
584+
expect(tspans.size()).to.be.equal(2);
585+
});
586+
});
587+
588+
it("should vertically center multiline labels", () => {
589+
const textElements = chart.$.main.selectAll(`.${$TEXT.texts} text.${$TEXT.text}`);
590+
591+
textElements.each(function() {
592+
const text = d3Select(this);
593+
const tspans = text.selectAll("tspan");
594+
595+
// Check that first tspan has negative dy for centering
596+
// When toMiddle is true, first tspan should have dy = -1 * (lines - 1) = -1em
597+
const firstTspan = tspans.nodes()[0];
598+
const firstDy = d3Select(firstTspan).attr("dy");
599+
600+
expect(firstDy).to.be.equal("-1em");
601+
602+
// Second tspan should have dy = 1em
603+
const secondTspan = tspans.nodes()[1];
604+
const secondDy = d3Select(secondTspan).attr("dy");
605+
606+
expect(secondDy).to.be.equal("1em");
607+
});
608+
});
609+
610+
it("should have correct text content in tspan elements", () => {
611+
const textElements = chart.$.main.selectAll(`.${$TEXT.texts} text.${$TEXT.text}`);
612+
613+
textElements.each(function(d) {
614+
const text = d3Select(this);
615+
const tspans = text.selectAll("tspan");
616+
const nodes = tspans.nodes() as Element[];
617+
const firstLine = nodes[0]?.textContent;
618+
const secondLine = nodes[1]?.textContent;
619+
620+
// First line should be "Value:"
621+
expect(firstLine).to.be.equal("Value:");
622+
623+
// Second line should be the numeric value
624+
expect(secondLine).to.match(/^\d+$/);
625+
});
626+
});
627+
628+
it("set options: three line labels", () => {
629+
args.data.labels.format = (v, id, i) => {
630+
return `Line1:\n${v}\nLine3`;
631+
};
632+
});
633+
634+
it("should render three-line labels with correct vertical centering", () => {
635+
const textElements = chart.$.main.selectAll(`.${$TEXT.texts} text.${$TEXT.text}`);
636+
637+
textElements.each(function() {
638+
const text = d3Select(this);
639+
const tspans = text.selectAll("tspan");
640+
641+
// Three-line labels should have 3 tspan elements
642+
expect(tspans.size()).to.be.equal(3);
643+
644+
// Check dy values for vertical centering
645+
// For 3 lines with toMiddle=true: first dy = -2em, others = 1em
646+
const firstTspan = tspans.nodes()[0];
647+
const firstDy = d3Select(firstTspan).attr("dy");
648+
expect(firstDy).to.be.equal("-2em");
649+
650+
// Second and third tspans should have dy = 1em
651+
const secondTspan = tspans.nodes()[1];
652+
const secondDy = d3Select(secondTspan).attr("dy");
653+
expect(secondDy).to.be.equal("1em");
654+
655+
const thirdTspan = tspans.nodes()[2];
656+
const thirdDy = d3Select(thirdTspan).attr("dy");
657+
expect(thirdDy).to.be.equal("1em");
658+
});
659+
});
660+
661+
it("should set x attribute to 0 for all tspan elements", () => {
662+
const textElements = chart.$.main.selectAll(`.${$TEXT.texts} text.${$TEXT.text}`);
663+
664+
textElements.each(function() {
665+
const text = d3Select(this);
666+
const tspans = text.selectAll("tspan");
667+
668+
tspans.each(function() {
669+
const tspan = d3Select(this);
670+
expect(tspan.attr("x")).to.be.equal("0");
671+
});
672+
});
673+
});
674+
});
675+
554676
describe("on area chart", () => {
555677
beforeAll(() => {
556678
args = {

0 commit comments

Comments
 (0)