Skip to content

Commit cbe95b7

Browse files
authored
feat(data): Intent to ship data.labels.centered
Implementation on data label texts align for bar type Fix #876
1 parent 56c2f99 commit cbe95b7

File tree

5 files changed

+157
-27
lines changed

5 files changed

+157
-27
lines changed

demo/demo.js

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,27 +1703,53 @@ var demos = {
17031703
];
17041704
}
17051705
},
1706-
DataLabel: {
1707-
options: {
1708-
data: {
1709-
columns: [
1710-
["data1", 30, -200, -100, 400, 150, 250],
1711-
["data2", -50, 150, -150, 150, -50, -150],
1712-
["data3", -100, 100, -40, 100, -150, -50]
1713-
],
1714-
groups: [
1715-
["data1", "data2"]
1716-
],
1717-
type: "bar",
1718-
labels: true
1719-
},
1720-
grid: {
1721-
y: {
1722-
lines: [{value: 0}]
1706+
DataLabel: [
1707+
{
1708+
options: {
1709+
data: {
1710+
columns: [
1711+
["data1", 30, -200, -100, 400, 150, 250],
1712+
["data2", -50, 150, -150, 150, -50, -150],
1713+
["data3", -100, 100, -40, 100, -150, -50]
1714+
],
1715+
groups: [
1716+
["data1", "data2"]
1717+
],
1718+
type: "bar",
1719+
labels: true
1720+
},
1721+
grid: {
1722+
y: {
1723+
lines: [{value: 0}]
1724+
}
1725+
}
1726+
}
1727+
},
1728+
{
1729+
options: {
1730+
data: {
1731+
columns: [
1732+
["data1", 230, -200, 400],
1733+
["data2", -250, 350, -170],
1734+
["data3", -123, 100, -240]
1735+
],
1736+
groups: [
1737+
["data1", "data2"]
1738+
],
1739+
type: "bar",
1740+
labels: {
1741+
colors: "white",
1742+
centered: true
1743+
}
1744+
},
1745+
grid: {
1746+
y: {
1747+
lines: [{value: 0}]
1748+
}
17231749
}
17241750
}
17251751
}
1726-
},
1752+
],
17271753
DataLabelColors: [
17281754
{
17291755
options: {
@@ -2532,7 +2558,7 @@ d3.select(".chart_area")
25322558
"01-10-2019 01:00",
25332559
"01-10-2019 01:30",
25342560
"01-10-2019 02:00",
2535-
"01-10-2019 02:30",
2561+
"01-10-2019 02:30",
25362562
"01-10-2019 03:00",
25372563
"01-10-2019 03:30",
25382564
"01-10-2019 04:00",

spec/internals/data-spec.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,51 @@ describe("DATA", () => {
729729
.each(checkXY(expectedTextX[key], expectedTextY[key], "", 4));
730730
});
731731
});
732+
733+
it("set options data.labels.centered=true", () => {
734+
args.data.labels = {
735+
centered: true,
736+
colors: "white"
737+
};
738+
});
739+
740+
it("check for data label text position", () => {
741+
const index = 1;
742+
let j = 0;
743+
const bars = chart.$.bar.bars.filter(d => d.index === index);
744+
const texts = chart.$.text.texts.filter(d => d.index === index).nodes();
745+
746+
bars.each(function(d) {
747+
const barRect = this.getBoundingClientRect();
748+
const textRect = texts[j++].getBoundingClientRect();
749+
750+
expect(
751+
(barRect.height / 2) - (textRect.y - barRect.y)
752+
).to.be.closeTo(textRect.height / 2, 3);
753+
});
754+
});
755+
756+
it("set options axis.rotated=true", () => {
757+
args.axis = {
758+
rotated: true
759+
}
760+
});
761+
762+
it("check for data label text position when is rotated", () => {
763+
const index = 1;
764+
let j = 0;
765+
const bars = chart.$.bar.bars.filter(d => d.index === index);
766+
const texts = chart.$.text.texts.filter(d => d.index === index).nodes();
767+
768+
bars.each(function(d) {
769+
const barRect = this.getBoundingClientRect();
770+
const textRect = texts[j++].getBoundingClientRect();
771+
772+
expect(
773+
(barRect.width / 2) - (textRect.x - barRect.x)
774+
).to.be.closeTo(textRect.width / 2, 3);
775+
});
776+
});
732777
});
733778

734779
describe("for all targets", () => {

src/config/Options.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,8 @@ export default class Options {
560560
* @memberof Options
561561
* @type {Object}
562562
* @property {Boolean} [data.labels=false] Show or hide labels on each data points
563-
* @property {Function} [data.labels.format={}] Set formatter function for data labels.<br>
563+
* @property {Boolean} [data.labels.centered=false] Centerize labels on `bar` shape. (**NOTE:** works only for 'bar' type)
564+
* @property {Function} [data.labels.format] Set formatter function for data labels.<br>
564565
* The formatter function receives 4 arguments such as v, id, i, j and it must return a string that will be shown as the label. The arguments are:<br>
565566
* - `v` is the value of the data point where the label is shown.
566567
* - `id` is the id of the data where the label is shown.
@@ -591,6 +592,9 @@ export default class Options {
591592
* ...
592593
* },
593594
*
595+
* // align text to center of the 'bar' shape (works only for 'bar' type)
596+
* centered: true,
597+
*
594598
* // apply for all label texts
595599
* colors: "red",
596600
*
@@ -1457,7 +1461,7 @@ export default class Options {
14571461
axis_x_categories: [],
14581462

14591463
/**
1460-
* Centerise ticks on category axis.
1464+
* centerize ticks on category axis.
14611465
* @name axis․x․tick․centered
14621466
* @memberof Options
14631467
* @type {Boolean}

src/internals/text.js

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,45 @@ extend(ChartInternal.prototype, {
181181
};
182182
},
183183

184+
/**
185+
* Get centerized text position for bar type data.label.text
186+
* @private
187+
* @param {Object} d Data object
188+
* @param {Array} points Data points position
189+
* @param {HTMLElement} textElement Data label text element
190+
* @returns {Number} Position value
191+
*/
192+
getCenteredTextPos(d, points, textElement) {
193+
const $$ = this;
194+
const config = $$.config;
195+
const isRotated = config.axis_rotated;
196+
197+
if (config.data_labels.centered && $$.isBarType(d)) {
198+
const rect = textElement.getBoundingClientRect();
199+
const isPositive = d.value >= 0;
200+
201+
if (isRotated) {
202+
const w = (
203+
isPositive ?
204+
points[1][1] - points[0][1] :
205+
points[0][1] - points[1][1]
206+
) / 2 + (rect.width / 2);
207+
208+
return isPositive ? -w - 3 : w + 4;
209+
} else {
210+
const h = (
211+
isPositive ?
212+
points[0][1] - points[1][1] :
213+
points[1][1] - points[0][1]
214+
) / 2 + (rect.height / 2);
215+
216+
return isPositive ? h : -h - 4;
217+
}
218+
}
219+
220+
return 0;
221+
},
222+
184223
/**
185224
* Gets the x coordinate of the text
186225
* @private
@@ -192,10 +231,11 @@ extend(ChartInternal.prototype, {
192231
getXForText(points, d, textElement) {
193232
const $$ = this;
194233
const config = $$.config;
234+
const isRotated = config.axis_rotated;
195235
let xPos;
196236
let padding;
197237

198-
if (config.axis_rotated) {
238+
if (isRotated) {
199239
padding = $$.isBarType(d) ? 4 : 6;
200240
xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
201241
} else {
@@ -210,6 +250,10 @@ extend(ChartInternal.prototype, {
210250
}
211251
}
212252

253+
if (isRotated) {
254+
xPos += $$.getCenteredTextPos(d, points, textElement);
255+
}
256+
213257
return xPos + (config.data_labels_position.x || 0);
214258
},
215259

@@ -224,12 +268,14 @@ extend(ChartInternal.prototype, {
224268
getYForText(points, d, textElement) {
225269
const $$ = this;
226270
const config = $$.config;
271+
const isRotated = config.axis_rotated;
227272
const r = config.point_r;
273+
const rect = textElement.getBoundingClientRect();
228274
let baseY = 3;
229275
let yPos;
230276

231-
if (config.axis_rotated) {
232-
yPos = (points[0][0] + points[2][0] + textElement.getBoundingClientRect().height * 0.6) / 2;
277+
if (isRotated) {
278+
yPos = (points[0][0] + points[2][0] + rect.height * 0.6) / 2;
233279
} else {
234280
yPos = points[2][1];
235281

@@ -238,7 +284,7 @@ extend(ChartInternal.prototype, {
238284
}
239285

240286
if (d.value < 0 || (d.value === 0 && !$$.hasPositiveValue)) {
241-
yPos += textElement.getBoundingClientRect().height;
287+
yPos += rect.height;
242288

243289
if ($$.isBarType(d) && $$.isSafari()) {
244290
yPos -= baseY;
@@ -259,8 +305,8 @@ extend(ChartInternal.prototype, {
259305
}
260306

261307
// show labels regardless of the domain if value is null
262-
if (d.value === null && !config.axis_rotated) {
263-
const boxHeight = textElement.getBoundingClientRect().height;
308+
if (d.value === null && !isRotated) {
309+
const boxHeight = rect.height;
264310

265311
if (yPos < boxHeight) {
266312
yPos = boxHeight;
@@ -269,6 +315,10 @@ extend(ChartInternal.prototype, {
269315
}
270316
}
271317

318+
if (!isRotated) {
319+
yPos += $$.getCenteredTextPos(d, points, textElement);
320+
}
321+
272322
return yPos + (config.data_labels_position.y || 0);
273323
}
274324
});

types/options.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,11 @@ export interface Data {
11741174
* - j is the sub index of the data point where the label is shown.
11751175
*/
11761176
labels?: boolean | {
1177+
/**
1178+
* Centerize labels on `bar` shape. (**NOTE:** works only for 'bar' type)
1179+
*/
1180+
centered?: boolean;
1181+
11771182
/**
11781183
* Set label text colors.
11791184
*/

0 commit comments

Comments
 (0)