diff --git a/demo/demo.js b/demo/demo.js
index 18139de69..38540cb25 100644
--- a/demo/demo.js
+++ b/demo/demo.js
@@ -1703,27 +1703,53 @@ var demos = {
];
}
},
- DataLabel: {
- options: {
- data: {
- columns: [
- ["data1", 30, -200, -100, 400, 150, 250],
- ["data2", -50, 150, -150, 150, -50, -150],
- ["data3", -100, 100, -40, 100, -150, -50]
- ],
- groups: [
- ["data1", "data2"]
- ],
- type: "bar",
- labels: true
- },
- grid: {
- y: {
- lines: [{value: 0}]
+ DataLabel: [
+ {
+ options: {
+ data: {
+ columns: [
+ ["data1", 30, -200, -100, 400, 150, 250],
+ ["data2", -50, 150, -150, 150, -50, -150],
+ ["data3", -100, 100, -40, 100, -150, -50]
+ ],
+ groups: [
+ ["data1", "data2"]
+ ],
+ type: "bar",
+ labels: true
+ },
+ grid: {
+ y: {
+ lines: [{value: 0}]
+ }
+ }
+ }
+ },
+ {
+ options: {
+ data: {
+ columns: [
+ ["data1", 230, -200, 400],
+ ["data2", -250, 350, -170],
+ ["data3", -123, 100, -240]
+ ],
+ groups: [
+ ["data1", "data2"]
+ ],
+ type: "bar",
+ labels: {
+ colors: "white",
+ centered: true
+ }
+ },
+ grid: {
+ y: {
+ lines: [{value: 0}]
+ }
}
}
}
- },
+ ],
DataLabelColors: [
{
options: {
@@ -2532,7 +2558,7 @@ d3.select(".chart_area")
"01-10-2019 01:00",
"01-10-2019 01:30",
"01-10-2019 02:00",
- "01-10-2019 02:30",
+ "01-10-2019 02:30",
"01-10-2019 03:00",
"01-10-2019 03:30",
"01-10-2019 04:00",
diff --git a/spec/internals/data-spec.js b/spec/internals/data-spec.js
index 5a5601f3c..c0a966ff0 100644
--- a/spec/internals/data-spec.js
+++ b/spec/internals/data-spec.js
@@ -729,6 +729,51 @@ describe("DATA", () => {
.each(checkXY(expectedTextX[key], expectedTextY[key], "", 4));
});
});
+
+ it("set options data.labels.centered=true", () => {
+ args.data.labels = {
+ centered: true,
+ colors: "white"
+ };
+ });
+
+ it("check for data label text position", () => {
+ const index = 1;
+ let j = 0;
+ const bars = chart.$.bar.bars.filter(d => d.index === index);
+ const texts = chart.$.text.texts.filter(d => d.index === index).nodes();
+
+ bars.each(function(d) {
+ const barRect = this.getBoundingClientRect();
+ const textRect = texts[j++].getBoundingClientRect();
+
+ expect(
+ (barRect.height / 2) - (textRect.y - barRect.y)
+ ).to.be.closeTo(textRect.height / 2, 3);
+ });
+ });
+
+ it("set options axis.rotated=true", () => {
+ args.axis = {
+ rotated: true
+ }
+ });
+
+ it("check for data label text position when is rotated", () => {
+ const index = 1;
+ let j = 0;
+ const bars = chart.$.bar.bars.filter(d => d.index === index);
+ const texts = chart.$.text.texts.filter(d => d.index === index).nodes();
+
+ bars.each(function(d) {
+ const barRect = this.getBoundingClientRect();
+ const textRect = texts[j++].getBoundingClientRect();
+
+ expect(
+ (barRect.width / 2) - (textRect.x - barRect.x)
+ ).to.be.closeTo(textRect.width / 2, 3);
+ });
+ });
});
describe("for all targets", () => {
diff --git a/src/config/Options.js b/src/config/Options.js
index 56322faed..742c8463c 100644
--- a/src/config/Options.js
+++ b/src/config/Options.js
@@ -560,7 +560,8 @@ export default class Options {
* @memberof Options
* @type {Object}
* @property {Boolean} [data.labels=false] Show or hide labels on each data points
- * @property {Function} [data.labels.format={}] Set formatter function for data labels.
+ * @property {Boolean} [data.labels.centered=false] Centerize labels on `bar` shape. (**NOTE:** works only for 'bar' type)
+ * @property {Function} [data.labels.format] Set formatter function for data labels.
* 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:
* - `v` is the value of the data point where the label is shown.
* - `id` is the id of the data where the label is shown.
@@ -591,6 +592,9 @@ export default class Options {
* ...
* },
*
+ * // align text to center of the 'bar' shape (works only for 'bar' type)
+ * centered: true,
+ *
* // apply for all label texts
* colors: "red",
*
@@ -1457,7 +1461,7 @@ export default class Options {
axis_x_categories: [],
/**
- * Centerise ticks on category axis.
+ * centerize ticks on category axis.
* @name axis․x․tick․centered
* @memberof Options
* @type {Boolean}
diff --git a/src/internals/text.js b/src/internals/text.js
index 1723fb2f8..5cbf94e2d 100644
--- a/src/internals/text.js
+++ b/src/internals/text.js
@@ -181,6 +181,45 @@ extend(ChartInternal.prototype, {
};
},
+ /**
+ * Get centerized text position for bar type data.label.text
+ * @private
+ * @param {Object} d Data object
+ * @param {Array} points Data points position
+ * @param {HTMLElement} textElement Data label text element
+ * @returns {Number} Position value
+ */
+ getCenteredTextPos(d, points, textElement) {
+ const $$ = this;
+ const config = $$.config;
+ const isRotated = config.axis_rotated;
+
+ if (config.data_labels.centered && $$.isBarType(d)) {
+ const rect = textElement.getBoundingClientRect();
+ const isPositive = d.value >= 0;
+
+ if (isRotated) {
+ const w = (
+ isPositive ?
+ points[1][1] - points[0][1] :
+ points[0][1] - points[1][1]
+ ) / 2 + (rect.width / 2);
+
+ return isPositive ? -w - 3 : w + 4;
+ } else {
+ const h = (
+ isPositive ?
+ points[0][1] - points[1][1] :
+ points[1][1] - points[0][1]
+ ) / 2 + (rect.height / 2);
+
+ return isPositive ? h : -h - 4;
+ }
+ }
+
+ return 0;
+ },
+
/**
* Gets the x coordinate of the text
* @private
@@ -192,10 +231,11 @@ extend(ChartInternal.prototype, {
getXForText(points, d, textElement) {
const $$ = this;
const config = $$.config;
+ const isRotated = config.axis_rotated;
let xPos;
let padding;
- if (config.axis_rotated) {
+ if (isRotated) {
padding = $$.isBarType(d) ? 4 : 6;
xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
} else {
@@ -210,6 +250,10 @@ extend(ChartInternal.prototype, {
}
}
+ if (isRotated) {
+ xPos += $$.getCenteredTextPos(d, points, textElement);
+ }
+
return xPos + (config.data_labels_position.x || 0);
},
@@ -224,12 +268,14 @@ extend(ChartInternal.prototype, {
getYForText(points, d, textElement) {
const $$ = this;
const config = $$.config;
+ const isRotated = config.axis_rotated;
const r = config.point_r;
+ const rect = textElement.getBoundingClientRect();
let baseY = 3;
let yPos;
- if (config.axis_rotated) {
- yPos = (points[0][0] + points[2][0] + textElement.getBoundingClientRect().height * 0.6) / 2;
+ if (isRotated) {
+ yPos = (points[0][0] + points[2][0] + rect.height * 0.6) / 2;
} else {
yPos = points[2][1];
@@ -238,7 +284,7 @@ extend(ChartInternal.prototype, {
}
if (d.value < 0 || (d.value === 0 && !$$.hasPositiveValue)) {
- yPos += textElement.getBoundingClientRect().height;
+ yPos += rect.height;
if ($$.isBarType(d) && $$.isSafari()) {
yPos -= baseY;
@@ -259,8 +305,8 @@ extend(ChartInternal.prototype, {
}
// show labels regardless of the domain if value is null
- if (d.value === null && !config.axis_rotated) {
- const boxHeight = textElement.getBoundingClientRect().height;
+ if (d.value === null && !isRotated) {
+ const boxHeight = rect.height;
if (yPos < boxHeight) {
yPos = boxHeight;
@@ -269,6 +315,10 @@ extend(ChartInternal.prototype, {
}
}
+ if (!isRotated) {
+ yPos += $$.getCenteredTextPos(d, points, textElement);
+ }
+
return yPos + (config.data_labels_position.y || 0);
}
});
diff --git a/types/options.d.ts b/types/options.d.ts
index c8a3bea11..cfe1f0889 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -1174,6 +1174,11 @@ export interface Data {
* - j is the sub index of the data point where the label is shown.
*/
labels?: boolean | {
+ /**
+ * Centerize labels on `bar` shape. (**NOTE:** works only for 'bar' type)
+ */
+ centered?: boolean;
+
/**
* Set label text colors.
*/