| `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. Note: AutoSkip does not remove offset 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.
| `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 = offsetGridLines ? scale._allTicks.length : scale.ticks.length;
+ const 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, offsetGridLines);
+ let lineValue = scale.getPixelForTick(validIndex);
let offset;
if (offsetGridLines) {
if (length === 1) {
offset = Math.max(lineValue - start, end - lineValue);
} else if (index === 0) {
- offset = (scale.getPixelForTick(1, offsetGridLines) - lineValue) / 2;
+ offset = (scale.getPixelForTick(1) - lineValue) / 2;
} else {
- offset = (lineValue - scale.getPixelForTick(validIndex - 1, offsetGridLines)) / 2;
+ offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
}
lineValue += validIndex < index ? offset : -offset;
this.min = undefined;
this.max = undefined;
/** @type {Tick[]} */
- this.ticks = this._allTicks = [];
+ this.ticks = [];
/** @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 {position, ticks: {align, padding}} = me.options;
+ const {ticks: {align, padding}, position} = 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), padding);
- me.paddingRight = Math.max((paddingRight - offsetRight + padding) * me.width / (me.width - offsetRight), padding);
+ 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);
} 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, all = false) {
- const ticks = all ? this._allTicks : this.ticks;
+ getPixelForTick(index) {
+ const ticks = 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 = offset ? me._allTicks : me.ticks;
+ const ticks = 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(247);
+ expect(chart.chartArea.right).toBeCloseToPixel(250);
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(247);
+ expect(chart.scales.x.right).toBeCloseToPixel(250);
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(3);
+ expect(chart.chartArea.left).toBeCloseToPixel(0);
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(3);
+ expect(chart.scales.x.left).toBeCloseToPixel(0);
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(247);
+ expect(chart.chartArea.right).toBeCloseToPixel(250);
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(247);
+ expect(chart.scales.x.right).toBeCloseToPixel(250);
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(247);
+ expect(chart.chartArea.right).toBeCloseToPixel(250);
expect(chart.chartArea.top).toBeCloseToPixel(32);
});
expect(chart.chartArea.bottom).toBeCloseToPixel(150);
expect(chart.chartArea.left).toBeCloseToPixel(31);
- expect(chart.chartArea.right).toBeCloseToPixel(297);
+ expect(chart.chartArea.right).toBeCloseToPixel(300);
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(570);
+ expect(xScale.getPixelForValue(4)).toBeCloseToPixel(572);
});
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(509);
+ expect(scale.getPixelForDecimal(1.0)).toBeCloseToPixel(512);
});
['data', 'labels'].forEach(function(source) {