| `drawOnChartArea` | `boolean` | | | `true` | If true, draw lines on the chart area inside the axis lines. This is useful when there are multiple axes and you need to control which grid lines are drawn.
| `drawTicks` | `boolean` | | | `true` | If true, draw lines beside the ticks in the axis area beside the chart.
| `lineWidth` | `number` | Yes | Yes | `1` | Stroke width of grid lines.
-| `offset` | `boolean` | | | `false` | If true, grid lines will be shifted to be between labels. This is set to `true` for a bar chart by default.
+| `offset` | `boolean` | | | `false` | If true, grid lines will be shifted to be between labels. This is set to `true` for a bar chart by default. Note: AutoSkip does not remove offset grid lines.
| `tickBorderDash` | `number[]` | | | | Length and spacing of the tick mark line. If not set, defaults to the grid line `borderDash` value.
| `tickBorderDashOffset` | `number` | Yes | Yes | | Offset for the line dash of the tick mark. If unset, defaults to the grid line `borderDashOffset` value
| `tickColor` | [`Color`](../general/colors.md) | Yes | Yes | | Color of the tick line. If unset, defaults to the grid line color.
* @param {boolean} offsetGridLines
*/
function getPixelForGridLine(scale, index, offsetGridLines) {
- const length = scale.ticks.length;
+ const length = offsetGridLines ? scale._allTicks.length : scale.ticks.length;
const validIndex = Math.min(index, length - 1);
const start = scale._startPixel;
const end = scale._endPixel;
const epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
- let lineValue = scale.getPixelForTick(validIndex);
+ let lineValue = scale.getPixelForTick(validIndex, offsetGridLines);
let offset;
if (offsetGridLines) {
if (length === 1) {
offset = Math.max(lineValue - start, end - lineValue);
} else if (index === 0) {
- offset = (scale.getPixelForTick(1) - lineValue) / 2;
+ offset = (scale.getPixelForTick(1, offsetGridLines) - lineValue) / 2;
} else {
- offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
+ offset = (lineValue - scale.getPixelForTick(validIndex - 1, offsetGridLines)) / 2;
}
lineValue += validIndex < index ? offset : -offset;
this.min = undefined;
this.max = undefined;
/** @type {Tick[]} */
- this.ticks = [];
+ this.ticks = this._allTicks = [];
/** @type {object[]|null} */
this._gridLineItems = null;
/** @type {object[]|null} */
me.afterCalculateLabelRotation();
// Auto-skip
+ me._allTicks = me.ticks;
if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
me.ticks = autoSkip(me, me.ticks);
me._labelSizes = null;
_calculatePadding(first, last, sin, cos) {
const me = this;
- const {ticks: {align, padding}, position} = me.options;
+ const {position, ticks: {align, padding}} = me.options;
const isRotated = me.labelRotation !== 0;
const labelsBelowTicks = position !== 'top' && me.axis === 'x';
}
// Adjust padding taking into account changes in offsets
- me.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * me.width / (me.width - offsetLeft), 0);
- me.paddingRight = Math.max((paddingRight - offsetRight + padding) * me.width / (me.width - offsetRight), 0);
+ me.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * me.width / (me.width - offsetLeft), padding);
+ me.paddingRight = Math.max((paddingRight - offsetRight + padding) * me.width / (me.width - offsetRight), padding);
} else {
let paddingTop = last.height / 2;
let paddingBottom = first.height / 2;
* Returns the location of the tick at the given index
* The coordinate (0, 0) is at the upper-left corner of the canvas
* @param {number} index
+ * @param {boolean} [all] - use ticks before autoSkip
* @return {number}
*/
- getPixelForTick(index) {
- const ticks = this.ticks;
+ getPixelForTick(index, all = false) {
+ const ticks = all ? this._allTicks : this.ticks;
if (index < 0 || index > ticks.length - 1) {
return null;
}
const {grid, position} = options;
const offset = grid.offset;
const isHorizontal = me.isHorizontal();
- const ticks = me.ticks;
+ const ticks = offset ? me._allTicks : me.ticks;
const ticksLength = ticks.length + (offset ? 1 : 0);
const tl = getTickMarkLength(grid);
const items = [];
return value === null ? NaN : me.getPixelForDecimal((value - me._startValue) / me._valueRange);
}
- // Must override base implementation because it calls getPixelForValue
- // and category scale can have duplicate values
- getPixelForTick(index) {
- const me = this;
- const ticks = me.ticks;
- if (index < 0 || index > ticks.length - 1) {
- return null;
- }
- return me.getPixelForValue(ticks[index].value);
- }
-
getValueForPixel(pixel) {
const me = this;
return Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
--- /dev/null
+module.exports = {
+ config: {
+ type: 'bar',
+ data: {
+ labels: ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6', 'Label 7', 'Label 8', 'Label 9', 'Label 10', 'Label 11', 'Label 12'],
+ datasets: [{
+ data: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+ }, {
+ data: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
+ }, {
+ data: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
+ }]
+ },
+ options: {
+ scales: {
+ x: {
+ ticks: {
+ maxRotation: 0
+ },
+ grid: {
+ color: 'red',
+ lineWidth: 1
+ }
+ },
+ y: {
+ display: false
+ }
+ }
+ }
+ },
+ options: {
+ spriteText: true,
+ canvas: {
+ width: 512,
+ height: 256
+ }
+ }
+};
--- /dev/null
+module.exports = {
+ config: {
+ type: 'bar',
+ data: {
+ // labels: [['Label 1', 'Line 2'], ['Label 2', 'Line 2'], ['Label 3', 'Line 2'], ['Label 4', 'Line 2'], ['Label 5', 'Line 2'], ['Label 6', 'Line 2'], ['Label 7', 'Line 2'], ['Label 8', 'Line 2'], ['Label 9', 'Line 2'], ['Label 10', 'Line 2'], ['Label 11', 'Line 2'], ['Label 12', 'Line 2']],
+ labels: ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6', 'Label 7', 'Label 8', 'Label 9', 'Label 10', 'Label 11', 'Label 12'],
+ datasets: [{
+ data: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+ }, {
+ data: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
+ }, {
+ data: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
+ }]
+ },
+ options: {
+ indexAxis: 'y',
+ scales: {
+ y: {
+ grid: {
+ color: 'red',
+ lineWidth: 1
+ }
+ },
+ x: {
+ display: false
+ }
+ }
+ }
+ },
+ options: {
+ spriteText: true,
+ canvas: {
+ width: 128,
+ height: 200
+ }
+ }
+};
expect(chart.chartArea.bottom).toBeCloseToPixel(120);
expect(chart.chartArea.left).toBeCloseToPixel(31);
- expect(chart.chartArea.right).toBeCloseToPixel(250);
+ expect(chart.chartArea.right).toBeCloseToPixel(247);
expect(chart.chartArea.top).toBeCloseToPixel(32);
// Is xScale at the right spot
expect(chart.scales.x.bottom).toBeCloseToPixel(150);
expect(chart.scales.x.left).toBeCloseToPixel(31);
- expect(chart.scales.x.right).toBeCloseToPixel(250);
+ expect(chart.scales.x.right).toBeCloseToPixel(247);
expect(chart.scales.x.top).toBeCloseToPixel(120);
expect(chart.scales.x.labelRotation).toBeCloseTo(0);
});
expect(chart.chartArea.bottom).toBeCloseToPixel(139);
- expect(chart.chartArea.left).toBeCloseToPixel(0);
+ expect(chart.chartArea.left).toBeCloseToPixel(3);
expect(chart.chartArea.right).toBeCloseToPixel(218);
expect(chart.chartArea.top).toBeCloseToPixel(62);
// Is xScale at the right spot
expect(chart.scales.x.bottom).toBeCloseToPixel(62);
- expect(chart.scales.x.left).toBeCloseToPixel(0);
+ expect(chart.scales.x.left).toBeCloseToPixel(3);
expect(chart.scales.x.right).toBeCloseToPixel(218);
expect(chart.scales.x.top).toBeCloseToPixel(32);
expect(chart.scales.x.labelRotation).toBeCloseTo(0);
expect(chart.chartArea.bottom).toBeCloseToPixel(110);
expect(chart.chartArea.left).toBeCloseToPixel(70);
- expect(chart.chartArea.right).toBeCloseToPixel(250);
+ expect(chart.chartArea.right).toBeCloseToPixel(247);
expect(chart.chartArea.top).toBeCloseToPixel(32);
// Is xScale at the right spot
expect(chart.scales.x.bottom).toBeCloseToPixel(150);
expect(chart.scales.x.left).toBeCloseToPixel(70);
- expect(chart.scales.x.right).toBeCloseToPixel(250);
+ expect(chart.scales.x.right).toBeCloseToPixel(247);
expect(chart.scales.x.top).toBeCloseToPixel(110);
expect(chart.scales.x.labelRotation).toBeCloseTo(40, -1);
expect(chart.chartArea.bottom).toBeCloseToPixel(120);
expect(chart.chartArea.left).toBeCloseToPixel(31);
- expect(chart.chartArea.right).toBeCloseToPixel(250);
+ expect(chart.chartArea.right).toBeCloseToPixel(247);
expect(chart.chartArea.top).toBeCloseToPixel(32);
});
expect(chart.chartArea.bottom).toBeCloseToPixel(150);
expect(chart.chartArea.left).toBeCloseToPixel(31);
- expect(chart.chartArea.right).toBeCloseToPixel(300);
+ expect(chart.chartArea.right).toBeCloseToPixel(297);
expect(chart.chartArea.top).toBeCloseToPixel(32);
});
});
var xScale = chart.scales.x;
expect(xScale.getPixelForValue(0)).toBeCloseToPixel(89);
expect(xScale.getPixelForValue(3)).toBeCloseToPixel(451);
- expect(xScale.getPixelForValue(4)).toBeCloseToPixel(572);
+ expect(xScale.getPixelForValue(4)).toBeCloseToPixel(570);
});
it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
});
const scale = chart.scales.x;
expect(scale.getPixelForDecimal(0)).toBeCloseToPixel(29);
- expect(scale.getPixelForDecimal(1.0)).toBeCloseToPixel(512);
+ expect(scale.getPixelForDecimal(1.0)).toBeCloseToPixel(509);
});
['data', 'labels'].forEach(function(source) {