From 9ee70d6d48a980fbe006d3d2e02ebae24fbfd83a Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 2 Apr 2016 23:05:48 -0400 Subject: [PATCH] Category scale supports min / max --- src/scales/scale.category.js | 33 +++++++-- test/scale.category.tests.js | 125 +++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 5 deletions(-) diff --git a/src/scales/scale.category.js b/src/scales/scale.category.js index 14b1d74bb..44135ebdb 100644 --- a/src/scales/scale.category.js +++ b/src/scales/scale.category.js @@ -10,7 +10,24 @@ module.exports = function(Chart) { var DatasetScale = Chart.Scale.extend({ buildTicks: function(index) { - this.ticks = this.chart.data.labels; + this.startIndex = 0; + this.endIndex = this.chart.data.labels.length; + var findIndex; + + if (this.options.ticks.min !== undefined) { + // user specified min value + findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.min) + this.startIndex = findIndex !== -1 ? findIndex : this.startIndex; + } + + if (this.options.ticks.max !== undefined) { + // user specified max value + findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.max); + this.endIndex = findIndex !== -1 ? findIndex : this.endIndex; + } + + // If we are viewing some subset of labels, slice the original array + this.ticks = (this.startIndex === 0 && this.endIndex === this.chart.data.labels.length) ? this.chart.data.labels : this.chart.data.labels.slice(this.startIndex, this.endIndex + 1); }, getLabelForIndex: function(index, datasetIndex) { @@ -19,10 +36,13 @@ module.exports = function(Chart) { // Used to get data value locations. Value can either be an index or a numerical value getPixelForValue: function(value, index, datasetIndex, includeOffset) { + // 1 is added because we need the length but we have the indexes + var offsetAmt = Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1); + if (this.isHorizontal()) { var innerWidth = this.width - (this.paddingLeft + this.paddingRight); - var valueWidth = innerWidth / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1); - var widthOffset = (valueWidth * index) + this.paddingLeft; + var valueWidth = innerWidth / offsetAmt; + var widthOffset = (valueWidth * (index - this.startIndex)) + this.paddingLeft; if (this.options.gridLines.offsetGridLines && includeOffset) { widthOffset += (valueWidth / 2); @@ -31,8 +51,8 @@ module.exports = function(Chart) { return this.left + Math.round(widthOffset); } else { var innerHeight = this.height - (this.paddingTop + this.paddingBottom); - var valueHeight = innerHeight / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1); - var heightOffset = (valueHeight * index) + this.paddingTop; + var valueHeight = innerHeight / offsetAmt; + var heightOffset = (valueHeight * (index - this.startIndex)) + this.paddingTop; if (this.options.gridLines.offsetGridLines && includeOffset) { heightOffset += (valueHeight / 2); @@ -40,6 +60,9 @@ module.exports = function(Chart) { return this.top + Math.round(heightOffset); } + }, + getPixelForTick: function(index, includeOffset) { + return this.getPixelForValue(this.ticks[index], index + this.startIndex, null, includeOffset); } }); diff --git a/test/scale.category.tests.js b/test/scale.category.tests.js index dd8e4d762..c59504a8b 100644 --- a/test/scale.category.tests.js +++ b/test/scale.category.tests.js @@ -156,6 +156,68 @@ describe('Category scale tests', function() { expect(scale.getPixelForValue(0, 4, 0, true)).toBe(557); }); + it ('Should get the correct pixel for a value when horizontal and zoomed', function() { + var scaleID = 'myScale'; + + var mockData = { + datasets: [{ + yAxisID: scaleID, + data: [10, 5, 0, 25, 78] + }], + labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last'] + }; + + var mockContext = window.createMockContext(); + var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category')); + config.gridLines.offsetGridLines = true; + config.ticks.min = "tick2"; + config.ticks.max = "tick4"; + + var Constructor = Chart.scaleService.getScaleConstructor('category'); + var scale = new Constructor({ + ctx: mockContext, + options: config, + chart: { + data: mockData + }, + id: scaleID + }); + + var minSize = scale.update(600, 100); + + expect(scale.width).toBe(600); + expect(scale.height).toBe(28); + expect(scale.paddingTop).toBe(0); + expect(scale.paddingBottom).toBe(0); + expect(scale.paddingLeft).toBe(28); + expect(scale.paddingRight).toBe(28); + expect(scale.labelRotation).toBe(0); + + expect(minSize).toEqual({ + width: 600, + height: 28, + }); + + scale.left = 5; + scale.top = 5; + scale.right = 605; + scale.bottom = 33; + + expect(scale.getPixelForValue(0, 1, 0, false)).toBe(33); + expect(scale.getPixelForValue(0, 1, 0, true)).toBe(124); + + expect(scale.getPixelForValue(0, 3, 0, false)).toBe(396); + expect(scale.getPixelForValue(0, 3, 0, true)).toBe(486); + + config.gridLines.offsetGridLines = false; + + expect(scale.getPixelForValue(0, 1, 0, false)).toBe(33); + expect(scale.getPixelForValue(0, 1, 0, true)).toBe(33); + + expect(scale.getPixelForValue(0, 3, 0, false)).toBe(577); + expect(scale.getPixelForValue(0, 3, 0, true)).toBe(577); + }); + it ('should get the correct pixel for a value when vertical', function() { var scaleID = 'myScale'; @@ -215,4 +277,67 @@ describe('Category scale tests', function() { expect(scale.getPixelForValue(0, 4, 0, false)).toBe(199); expect(scale.getPixelForValue(0, 4, 0, true)).toBe(199); }); + + it ('should get the correct pixel for a value when vertical and zoomed', function() { + var scaleID = 'myScale'; + + var mockData = { + datasets: [{ + yAxisID: scaleID, + data: [10, 5, 0, 25, 78] + }], + labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last'] + }; + + var mockContext = window.createMockContext(); + var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category')); + config.gridLines.offsetGridLines = true; + config.ticks.min = "tick2"; + config.ticks.max = "tick4"; + config.position = "left"; + + var Constructor = Chart.scaleService.getScaleConstructor('category'); + var scale = new Constructor({ + ctx: mockContext, + options: config, + chart: { + data: mockData + }, + id: scaleID + }); + + var minSize = scale.update(100, 200); + + expect(scale.width).toBe(70); + expect(scale.height).toBe(200); + expect(scale.paddingTop).toBe(6); + expect(scale.paddingBottom).toBe(6); + expect(scale.paddingLeft).toBe(0); + expect(scale.paddingRight).toBe(0); + expect(scale.labelRotation).toBe(0); + + expect(minSize).toEqual({ + width: 70, + height: 200, + }); + + scale.left = 5; + scale.top = 5; + scale.right = 75; + scale.bottom = 205; + + expect(scale.getPixelForValue(0, 1, 0, false)).toBe(11); + expect(scale.getPixelForValue(0, 1, 0, true)).toBe(42); + + expect(scale.getPixelForValue(0, 3, 0, false)).toBe(136); + expect(scale.getPixelForValue(0, 3, 0, true)).toBe(168); + + config.gridLines.offsetGridLines = false; + + expect(scale.getPixelForValue(0, 1, 0, false)).toBe(11); + expect(scale.getPixelForValue(0, 1, 0, true)).toBe(11); + + expect(scale.getPixelForValue(0, 3, 0, false)).toBe(199); + expect(scale.getPixelForValue(0, 3, 0, true)).toBe(199); + }); }); \ No newline at end of file