]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Cartesian axis label cross alignment (#7874)
authorEvert Timberg <evert.timberg+github@gmail.com>
Mon, 12 Oct 2020 14:22:13 +0000 (10:22 -0400)
committerGitHub <noreply@github.com>
Mon, 12 Oct 2020 14:22:13 +0000 (10:22 -0400)
* Refactor Y axis alignment to it's own method
* Label Cross alignment
* Add documentation of new setting
* Update docs with live sample

28 files changed:
docs/docs/axes/cartesian/index.mdx [moved from docs/docs/axes/cartesian/index.md with 71% similarity]
docs/docs/axes/styling.md
src/core/core.scale.js
test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-center.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-center.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-far.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-far.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-near.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-left-near.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-center.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-center.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-far.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-far.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-near.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-right-near.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-center.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-center.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-far.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-far.png [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-near.js [new file with mode: 0644]
test/fixtures/core.scale/crossAlignment/cross-align-top-near.png [new file with mode: 0644]
types/scales/index.d.ts

similarity index 71%
rename from docs/docs/axes/cartesian/index.md
rename to docs/docs/axes/cartesian/index.mdx
index 2fa707cc9c0153a872eda6aa56058cd9294dafc7..2e7cf228074b9e49fed70a08c277f7955f1a4dcf 100644 (file)
@@ -2,6 +2,8 @@
 title: Cartesian Axes
 ---
 
+import { useEffect } from 'react';
+
 Axes that follow a cartesian grid are known as 'Cartesian Axes'. Cartesian axes are used for line, bar, and bubble charts. Four cartesian axes are included in Chart.js by default.
 
 * [linear](./linear.md#linear-cartesian-axis)
@@ -47,6 +49,8 @@ The following options are common to all cartesian axes but do not apply to other
 
 | Name | Type | Default | Description
 | ---- | ---- | ------- | -----------
+| `alignment` | `string` | | `'center'` | The tick alignment along the axis. Can be `'start'`, `'center'`, or `'end'`.
+| `crossAlignment` | `string` | | `'near'` | The tick alignment perpendicular to the axis. Can be `'near'`, `'center'`, or `'far'`. See [Tick Alignment](#tick-alignment)
 | `sampleSize` | `number` | `ticks.length` | The number of ticks to examine when deciding how many labels will fit. Setting a smaller value will be faster, but may be less accurate when there is large variability in label length.
 | `autoSkip` | `boolean` | `true` | If true, automatically calculates how many labels can be shown and hides labels accordingly. Labels will be rotated up to `maxRotation` before skipping any. Turn `autoSkip` off to show all labels no matter what.
 | `autoSkipPadding` | `number` | `0` | Padding between the ticks on the horizontal axis when `autoSkip` is enabled.
@@ -56,6 +60,65 @@ The following options are common to all cartesian axes but do not apply to other
 | `mirror` | `boolean` | `false` | Flips tick labels around axis, displaying the labels inside the chart instead of outside. *Note: Only applicable to vertical scales.*
 | `padding` | `number` | `0` | Padding between the tick label and the axis. When set on a vertical axis, this applies in the horizontal (X) direction. When set on a horizontal axis, this applies in the vertical (Y) direction.
 
+### Tick Alignment
+
+The alignment of ticks is primarily controlled using two settings on the tick configuration object: `alignment` and `crossAlignment`. The `alignment` setting configures how labels align with the tick mark along the axis direction (i.e. horizontal for a horizontal axis and vertical for a vertical axis). The `crossAlignment` setting configures how labels align with the tick mark in the perpendicular direction (i.e. vertical for a horizontal axis and horizontal for a vertical axis). In the example below, the `crossAlignment` setting is used to left align the labels on the Y axis.
+
+```jsx live
+function exampleAlignment() {
+  useEffect(() => {
+    const cfg = {
+      type: 'bar',
+      data: {
+        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+        datasets: [{
+          axis: 'y',
+          label: 'My First Dataset',
+          data: [65, 59, 80, 81, 56, 55, 40],
+          fill: false,
+          backgroundColor: [
+            'rgba(255, 99, 132, 0.2)',
+            'rgba(255, 159, 64, 0.2)',
+            'rgba(255, 205, 86, 0.2)',
+            'rgba(75, 192, 192, 0.2)',
+            'rgba(54, 162, 235, 0.2)',
+            'rgba(153, 102, 255, 0.2)',
+            'rgba(201, 203, 207, 0.2)'
+          ],
+          borderColor: [
+            'rgb(255, 99, 132)',
+            'rgb(255, 159, 64)',
+            'rgb(255, 205, 86)',
+            'rgb(75, 192, 192)',
+            'rgb(54, 162, 235)',
+            'rgb(153, 102, 255)',
+            'rgb(201, 203, 207)'
+          ],
+          borderWidth: 1
+        }]
+      },
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            beginAtZero: true
+          },
+          y: {
+            ticks: {
+              crossAlignment: 'far',
+            }
+          }
+        }
+      }
+    };
+    new Chart(document.getElementById('chartjs-1').getContext('2d'), cfg);
+  });
+  return <div className="chartjs-wrapper"><canvas id="chartjs-1" className="chartjs"></canvas></div>;
+}
+```
+
+**Note:** the `crossAlignment` setting is not used the the tick rotation is not `0`, the axis position is `'center'` or the position is with respect to a data value.
+
 ### Axis ID
 
 The properties `dataset.xAxisID` or `dataset.yAxisID` have to match to `scales` property. This is especially needed if multi-axes charts are used.
index eed36ab4d9492f83ede4f5cd95febf6e9620a8ff..a9c8f1a0b5155c44b0a447a8e86a58e1151f06c9 100644 (file)
@@ -42,7 +42,6 @@ The tick configuration is nested under the scale configuration in the `ticks` ke
 
 | Name | Type | Scriptable | Default | Description
 | ---- | ---- | :-------------------------------: | ------- | -----------
-| `alignment` | `string` | | `'center'` | The tick alignment along the axis. Can be `'start'`, `'center'`, or `'end'`.
 | `callback` | `function` | | | Returns the string representation of the tick value as it should be displayed on the chart. See [callback](../axes/labelling.md#creating-custom-tick-formats).
 | `display` | `boolean` | | `true` | If true, show tick labels.
 | `font` | `Font` | Yes | `defaults.font` | See [Fonts](../general/fonts.md)
index 69a69be7614636084c63c38eeb8d47c9de898625..5dc8d7e2d9c63b3814f5929ba57ae5002063c678 100644 (file)
@@ -63,6 +63,7 @@ defaults.set('scale', {
                minor: {},
                major: {},
                alignment: 'center',
+               crossAlignment: 'near',
        }
 });
 
@@ -1250,56 +1251,59 @@ export default class Scale extends Element {
                const axis = me.axis;
                const options = me.options;
                const {position, ticks: optionTicks} = options;
-               const isMirrored = optionTicks.mirror;
                const isHorizontal = me.isHorizontal();
                const ticks = me.ticks;
-               const tickPadding = optionTicks.padding;
+               const {alignment, crossAlignment, padding} = optionTicks;
                const tl = getTickMarkLength(options.gridLines);
+               const tickAndPadding = tl + padding;
                const rotation = -toRadians(me.labelRotation);
                const items = [];
                let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
                let textBaseline = 'middle';
 
                if (position === 'top') {
-                       y = me.bottom - tl - tickPadding;
+                       y = me.bottom - tickAndPadding;
                        textAlign = me._getXAxisLabelAlignment();
                } else if (position === 'bottom') {
-                       y = me.top + tl + tickPadding;
+                       y = me.top + tickAndPadding;
                        textAlign = me._getXAxisLabelAlignment();
                } else if (position === 'left') {
-                       x = me.right - (isMirrored ? 0 : tl) - tickPadding;
-                       textAlign = isMirrored ? 'left' : 'right';
+                       const ret = this._getYAxisLabelAlignment(tl);
+                       textAlign = ret.textAlign;
+                       x = ret.x;
                } else if (position === 'right') {
-                       x = me.left + (isMirrored ? 0 : tl) + tickPadding;
-                       textAlign = isMirrored ? 'right' : 'left';
+                       const ret = this._getYAxisLabelAlignment(tl);
+                       textAlign = ret.textAlign;
+                       x = ret.x;
                } else if (axis === 'x') {
                        if (position === 'center') {
-                               y = ((chartArea.top + chartArea.bottom) / 2) + tl + tickPadding;
+                               y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding;
                        } else if (isObject(position)) {
                                const positionAxisID = Object.keys(position)[0];
                                const value = position[positionAxisID];
-                               y = me.chart.scales[positionAxisID].getPixelForValue(value) + tl + tickPadding;
+                               y = me.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
                        }
                        textAlign = me._getXAxisLabelAlignment();
                } else if (axis === 'y') {
                        if (position === 'center') {
-                               x = ((chartArea.left + chartArea.right) / 2) - tl - tickPadding;
+                               x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding;
                        } else if (isObject(position)) {
                                const positionAxisID = Object.keys(position)[0];
                                const value = position[positionAxisID];
                                x = me.chart.scales[positionAxisID].getPixelForValue(value);
                        }
-                       textAlign = 'right';
+                       textAlign = this._getYAxisLabelAlignment(tl).textAlign;
                }
 
                if (axis === 'y') {
-                       if (optionTicks.alignment === 'start') {
+                       if (alignment === 'start') {
                                textBaseline = 'top';
-                       } else if (optionTicks.alignment === 'end') {
+                       } else if (alignment === 'end') {
                                textBaseline = 'bottom';
                        }
                }
 
+               const labelSizes = me._getLabelSizes();
                for (i = 0, ilen = ticks.length; i < ilen; ++i) {
                        tick = ticks[i];
                        label = tick.label;
@@ -1308,15 +1312,30 @@ export default class Scale extends Element {
                        font = me._resolveTickFontOptions(i);
                        lineHeight = font.lineHeight;
                        lineCount = isArray(label) ? label.length : 1;
+                       const halfCount = lineCount / 2;
 
                        if (isHorizontal) {
                                x = pixel;
                                if (position === 'top') {
-                                       textOffset = (Math.sin(rotation) * (lineCount / 2) + 0.5) * lineHeight;
-                                       textOffset -= (rotation === 0 ? (lineCount - 0.5) : Math.cos(rotation) * (lineCount / 2)) * lineHeight;
-                               } else {
-                                       textOffset = Math.sin(rotation) * (lineCount / 2) * lineHeight;
-                                       textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * (lineCount / 2)) * lineHeight;
+                                       if (crossAlignment === 'near' || rotation !== 0) {
+                                               textOffset = (Math.sin(rotation) * halfCount + 0.5) * lineHeight;
+                                               textOffset -= (rotation === 0 ? (lineCount - 0.5) : Math.cos(rotation) * halfCount) * lineHeight;
+                                       } else if (crossAlignment === 'center') {
+                                               textOffset = -1 * (labelSizes.highest.height / 2);
+                                               textOffset -= halfCount * lineHeight;
+                                       } else {
+                                               textOffset = (-1 * labelSizes.highest.height) + (0.5 * lineHeight);
+                                       }
+                               } else if (position === 'bottom') {
+                                       if (crossAlignment === 'near' || rotation !== 0) {
+                                               textOffset = Math.sin(rotation) * halfCount * lineHeight;
+                                               textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * halfCount) * lineHeight;
+                                       } else if (crossAlignment === 'center') {
+                                               textOffset = labelSizes.highest.height / 2;
+                                               textOffset -= halfCount * lineHeight;
+                                       } else {
+                                               textOffset = labelSizes.highest.height - ((lineCount - 0.5) * lineHeight);
+                                       }
                                }
                        } else {
                                y = pixel;
@@ -1358,6 +1377,58 @@ export default class Scale extends Element {
                return align;
        }
 
+       _getYAxisLabelAlignment(tl) {
+               const me = this;
+               const {position, ticks} = me.options;
+               const {crossAlignment, mirror, padding} = ticks;
+               const labelSizes = me._getLabelSizes();
+               const tickAndPadding = tl + padding;
+               const widest = labelSizes.widest.width;
+
+               let textAlign;
+               let x;
+
+               if (position === 'left') {
+                       if (mirror) {
+                               textAlign = 'left';
+                               x = me.right - padding;
+                       } else {
+                               x = me.right - tickAndPadding;
+
+                               if (crossAlignment === 'near') {
+                                       textAlign = 'right';
+                               } else if (crossAlignment === 'center') {
+                                       textAlign = 'center';
+                                       x -= (widest / 2);
+                               } else {
+                                       textAlign = 'left';
+                                       x -= widest;
+                               }
+                       }
+               } else if (position === 'right') {
+                       if (mirror) {
+                               textAlign = 'right';
+                               x = me.left + padding;
+                       } else {
+                               x = me.left + tickAndPadding;
+
+                               if (crossAlignment === 'near') {
+                                       textAlign = 'left';
+                               } else if (crossAlignment === 'center') {
+                                       textAlign = 'center';
+                                       x += widest / 2;
+                               } else {
+                                       textAlign = 'right';
+                                       x += widest;
+                               }
+                       }
+               } else {
+                       textAlign = 'right';
+               }
+
+               return {textAlign, x};
+       }
+
        /**
         * @protected
         */
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.js b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.js
new file mode 100644 (file)
index 0000000..5eae388
--- /dev/null
@@ -0,0 +1,29 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       ticks: {
+                                               crossAlignment: 'center',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.png b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.png
new file mode 100644 (file)
index 0000000..b817e5b
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.js b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.js
new file mode 100644 (file)
index 0000000..f7daff2
--- /dev/null
@@ -0,0 +1,29 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       ticks: {
+                                               crossAlignment: 'far',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.png b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.png
new file mode 100644 (file)
index 0000000..6dd7a50
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.js b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.js
new file mode 100644 (file)
index 0000000..69175ba
--- /dev/null
@@ -0,0 +1,29 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       ticks: {
+                                               crossAlignment: 'near',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.png b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.png
new file mode 100644 (file)
index 0000000..a7bfa8d
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-center.js b/test/fixtures/core.scale/crossAlignment/cross-align-left-center.js
new file mode 100644 (file)
index 0000000..d51df0a
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'left',
+                                       ticks: {
+                                               crossAlignment: 'center',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-center.png b/test/fixtures/core.scale/crossAlignment/cross-align-left-center.png
new file mode 100644 (file)
index 0000000..747d704
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-left-center.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-far.js b/test/fixtures/core.scale/crossAlignment/cross-align-left-far.js
new file mode 100644 (file)
index 0000000..0e1232c
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'left',
+                                       ticks: {
+                                               crossAlignment: 'far',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-far.png b/test/fixtures/core.scale/crossAlignment/cross-align-left-far.png
new file mode 100644 (file)
index 0000000..be066d1
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-left-far.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-near.js b/test/fixtures/core.scale/crossAlignment/cross-align-left-near.js
new file mode 100644 (file)
index 0000000..591e92c
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'left',
+                                       ticks: {
+                                               crossAlignment: 'near',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-near.png b/test/fixtures/core.scale/crossAlignment/cross-align-left-near.png
new file mode 100644 (file)
index 0000000..50d27b8
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-left-near.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-center.js b/test/fixtures/core.scale/crossAlignment/cross-align-right-center.js
new file mode 100644 (file)
index 0000000..4e56f15
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'right',
+                                       ticks: {
+                                               crossAlignment: 'center',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-center.png b/test/fixtures/core.scale/crossAlignment/cross-align-right-center.png
new file mode 100644 (file)
index 0000000..baa12cb
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-right-center.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-far.js b/test/fixtures/core.scale/crossAlignment/cross-align-right-far.js
new file mode 100644 (file)
index 0000000..fc7906f
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'right',
+                                       ticks: {
+                                               crossAlignment: 'far',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-far.png b/test/fixtures/core.scale/crossAlignment/cross-align-right-far.png
new file mode 100644 (file)
index 0000000..ae02309
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-right-far.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-near.js b/test/fixtures/core.scale/crossAlignment/cross-align-right-near.js
new file mode 100644 (file)
index 0000000..acdc5bc
--- /dev/null
@@ -0,0 +1,31 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: ['Long long label 1', 'Label2', 'Label3']
+               },
+               options: {
+                       indexAxis: 'y',
+                       legend: false,
+                       title: false,
+                       scales: {
+                               y: {
+                                       position: 'right',
+                                       ticks: {
+                                               crossAlignment: 'near',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-near.png b/test/fixtures/core.scale/crossAlignment/cross-align-right-near.png
new file mode 100644 (file)
index 0000000..d0cd811
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-right-near.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-center.js b/test/fixtures/core.scale/crossAlignment/cross-align-top-center.js
new file mode 100644 (file)
index 0000000..4ed7034
--- /dev/null
@@ -0,0 +1,30 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       position: 'top',
+                                       ticks: {
+                                               crossAlignment: 'center',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-center.png b/test/fixtures/core.scale/crossAlignment/cross-align-top-center.png
new file mode 100644 (file)
index 0000000..4f5eb96
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-top-center.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-far.js b/test/fixtures/core.scale/crossAlignment/cross-align-top-far.js
new file mode 100644 (file)
index 0000000..2d6f8ce
--- /dev/null
@@ -0,0 +1,30 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       position: 'top',
+                                       ticks: {
+                                               crossAlignment: 'far',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-far.png b/test/fixtures/core.scale/crossAlignment/cross-align-top-far.png
new file mode 100644 (file)
index 0000000..ea5c88d
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-top-far.png differ
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-near.js b/test/fixtures/core.scale/crossAlignment/cross-align-top-near.js
new file mode 100644 (file)
index 0000000..e2a9797
--- /dev/null
@@ -0,0 +1,30 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       datasets: [{
+                               data: [1, 2, 3],
+                       }],
+                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+               },
+               options: {
+                       legend: false,
+                       title: false,
+                       scales: {
+                               x: {
+                                       position: 'top',
+                                       ticks: {
+                                               crossAlignment: 'near',
+                                       },
+                               },
+                       }
+               }
+       },
+       options: {
+               spriteText: true,
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-top-near.png b/test/fixtures/core.scale/crossAlignment/cross-align-top-near.png
new file mode 100644 (file)
index 0000000..9321668
Binary files /dev/null and b/test/fixtures/core.scale/crossAlignment/cross-align-top-near.png differ
index fe19273c63a62472584d3893c11cd41ab9fe3724..81e1cce2fbf9eee59bbac41418694e1f7f43bacf 100644 (file)
@@ -143,6 +143,14 @@ export interface ICartesianScaleOptions extends ICoreScaleOptions {
      * @default 0
      */
     autoSkipPadding: number;
+
+    /**
+     * How is the label positioned perpendicular to the axis direction.
+     * This only applies when the rotation is 0 and the axis position is one of "top", "left", "right", or "bottom"
+     * @default 'near'
+     */
+    crossAlignment: 'near' | 'center' | 'far';
+
     /**
      * Distance in pixels to offset the label from the centre point of the tick (in the x direction for the x axis, and the y direction for the y axis). Note: this can cause labels at the edges to be cropped by the edge of the canvas
      * @default 0