return lineValue;
}
-module.exports = function(Chart) {
+function computeTextSize(context, tick, font) {
+ return helpers.isArray(tick) ?
+ helpers.longestText(context, font, tick) :
+ context.measureText(tick).width;
+}
- function computeTextSize(context, tick, font) {
- return helpers.isArray(tick) ?
- helpers.longestText(context, font, tick) :
- context.measureText(tick).width;
- }
+function parseFontOptions(options) {
+ var valueOrDefault = helpers.valueOrDefault;
+ var globalDefaults = defaults.global;
+ var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
+ var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
+ var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
+
+ return {
+ size: size,
+ style: style,
+ family: family,
+ font: helpers.fontString(size, style, family)
+ };
+}
- function parseFontOptions(options) {
- var valueOrDefault = helpers.valueOrDefault;
- var globalDefaults = defaults.global;
- var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
- var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
- var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
+function parseLineHeight(options) {
+ return helpers.options.toLineHeight(
+ helpers.valueOrDefault(options.lineHeight, 1.2),
+ helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
+}
+module.exports = Element.extend({
+ /**
+ * Get the padding needed for the scale
+ * @method getPadding
+ * @private
+ * @returns {Padding} the necessary padding
+ */
+ getPadding: function() {
+ var me = this;
return {
- size: size,
- style: style,
- family: family,
- font: helpers.fontString(size, style, family)
+ left: me.paddingLeft || 0,
+ top: me.paddingTop || 0,
+ right: me.paddingRight || 0,
+ bottom: me.paddingBottom || 0
};
- }
+ },
- function parseLineHeight(options) {
- return helpers.options.toLineHeight(
- helpers.valueOrDefault(options.lineHeight, 1.2),
- helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
- }
+ /**
+ * Returns the scale tick objects ({label, major})
+ * @since 2.7
+ */
+ getTicks: function() {
+ return this._ticks;
+ },
- Chart.Scale = Element.extend({
- /**
- * Get the padding needed for the scale
- * @method getPadding
- * @private
- * @returns {Padding} the necessary padding
- */
- getPadding: function() {
- var me = this;
- return {
- left: me.paddingLeft || 0,
- top: me.paddingTop || 0,
- right: me.paddingRight || 0,
- bottom: me.paddingBottom || 0
+ // These methods are ordered by lifecyle. Utilities then follow.
+ // Any function defined here is inherited by all scale types.
+ // Any function can be extended by the scale type
+
+ mergeTicksOptions: function() {
+ var ticks = this.options.ticks;
+ if (ticks.minor === false) {
+ ticks.minor = {
+ display: false
};
- },
-
- /**
- * Returns the scale tick objects ({label, major})
- * @since 2.7
- */
- getTicks: function() {
- return this._ticks;
- },
-
- // These methods are ordered by lifecyle. Utilities then follow.
- // Any function defined here is inherited by all scale types.
- // Any function can be extended by the scale type
-
- mergeTicksOptions: function() {
- var ticks = this.options.ticks;
- if (ticks.minor === false) {
- ticks.minor = {
- display: false
- };
- }
- if (ticks.major === false) {
- ticks.major = {
- display: false
- };
- }
- for (var key in ticks) {
- if (key !== 'major' && key !== 'minor') {
- if (typeof ticks.minor[key] === 'undefined') {
- ticks.minor[key] = ticks[key];
- }
- if (typeof ticks.major[key] === 'undefined') {
- ticks.major[key] = ticks[key];
- }
+ }
+ if (ticks.major === false) {
+ ticks.major = {
+ display: false
+ };
+ }
+ for (var key in ticks) {
+ if (key !== 'major' && key !== 'minor') {
+ if (typeof ticks.minor[key] === 'undefined') {
+ ticks.minor[key] = ticks[key];
}
- }
- },
- beforeUpdate: function() {
- helpers.callback(this.options.beforeUpdate, [this]);
- },
- update: function(maxWidth, maxHeight, margins) {
- var me = this;
- var i, ilen, labels, label, ticks, tick;
-
- // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
- me.beforeUpdate();
-
- // Absorb the master measurements
- me.maxWidth = maxWidth;
- me.maxHeight = maxHeight;
- me.margins = helpers.extend({
- left: 0,
- right: 0,
- top: 0,
- bottom: 0
- }, margins);
- me.longestTextCache = me.longestTextCache || {};
-
- // Dimensions
- me.beforeSetDimensions();
- me.setDimensions();
- me.afterSetDimensions();
-
- // Data min/max
- me.beforeDataLimits();
- me.determineDataLimits();
- me.afterDataLimits();
-
- // Ticks - `this.ticks` is now DEPRECATED!
- // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
- // and must not be accessed directly from outside this class. `this.ticks` being
- // around for long time and not marked as private, we can't change its structure
- // without unexpected breaking changes. If you need to access the scale ticks,
- // use scale.getTicks() instead.
-
- me.beforeBuildTicks();
-
- // New implementations should return an array of objects but for BACKWARD COMPAT,
- // we still support no return (`this.ticks` internally set by calling this method).
- ticks = me.buildTicks() || [];
-
- me.afterBuildTicks();
-
- me.beforeTickToLabelConversion();
-
- // New implementations should return the formatted tick labels but for BACKWARD
- // COMPAT, we still support no return (`this.ticks` internally changed by calling
- // this method and supposed to contain only string values).
- labels = me.convertTicksToLabels(ticks) || me.ticks;
-
- me.afterTickToLabelConversion();
-
- me.ticks = labels; // BACKWARD COMPATIBILITY
-
- // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
-
- // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
- for (i = 0, ilen = labels.length; i < ilen; ++i) {
- label = labels[i];
- tick = ticks[i];
- if (!tick) {
- ticks.push(tick = {
- label: label,
- major: false
- });
- } else {
- tick.label = label;
+ if (typeof ticks.major[key] === 'undefined') {
+ ticks.major[key] = ticks[key];
}
}
+ }
+ },
+ beforeUpdate: function() {
+ helpers.callback(this.options.beforeUpdate, [this]);
+ },
- me._ticks = ticks;
+ update: function(maxWidth, maxHeight, margins) {
+ var me = this;
+ var i, ilen, labels, label, ticks, tick;
- // Tick Rotation
- me.beforeCalculateTickRotation();
- me.calculateTickRotation();
- me.afterCalculateTickRotation();
- // Fit
- me.beforeFit();
- me.fit();
- me.afterFit();
- //
- me.afterUpdate();
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ me.beforeUpdate();
- return me.minSize;
+ // Absorb the master measurements
+ me.maxWidth = maxWidth;
+ me.maxHeight = maxHeight;
+ me.margins = helpers.extend({
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0
+ }, margins);
+ me.longestTextCache = me.longestTextCache || {};
- },
- afterUpdate: function() {
- helpers.callback(this.options.afterUpdate, [this]);
- },
+ // Dimensions
+ me.beforeSetDimensions();
+ me.setDimensions();
+ me.afterSetDimensions();
- //
+ // Data min/max
+ me.beforeDataLimits();
+ me.determineDataLimits();
+ me.afterDataLimits();
- beforeSetDimensions: function() {
- helpers.callback(this.options.beforeSetDimensions, [this]);
- },
- setDimensions: function() {
- var me = this;
- // Set the unconstrained dimension before label rotation
- if (me.isHorizontal()) {
- // Reset position before calculating rotation
- me.width = me.maxWidth;
- me.left = 0;
- me.right = me.width;
- } else {
- me.height = me.maxHeight;
+ // Ticks - `this.ticks` is now DEPRECATED!
+ // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
+ // and must not be accessed directly from outside this class. `this.ticks` being
+ // around for long time and not marked as private, we can't change its structure
+ // without unexpected breaking changes. If you need to access the scale ticks,
+ // use scale.getTicks() instead.
- // Reset position before calculating rotation
- me.top = 0;
- me.bottom = me.height;
+ me.beforeBuildTicks();
+
+ // New implementations should return an array of objects but for BACKWARD COMPAT,
+ // we still support no return (`this.ticks` internally set by calling this method).
+ ticks = me.buildTicks() || [];
+
+ me.afterBuildTicks();
+
+ me.beforeTickToLabelConversion();
+
+ // New implementations should return the formatted tick labels but for BACKWARD
+ // COMPAT, we still support no return (`this.ticks` internally changed by calling
+ // this method and supposed to contain only string values).
+ labels = me.convertTicksToLabels(ticks) || me.ticks;
+
+ me.afterTickToLabelConversion();
+
+ me.ticks = labels; // BACKWARD COMPATIBILITY
+
+ // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
+
+ // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
+ for (i = 0, ilen = labels.length; i < ilen; ++i) {
+ label = labels[i];
+ tick = ticks[i];
+ if (!tick) {
+ ticks.push(tick = {
+ label: label,
+ major: false
+ });
+ } else {
+ tick.label = label;
}
+ }
- // Reset padding
- me.paddingLeft = 0;
- me.paddingTop = 0;
- me.paddingRight = 0;
- me.paddingBottom = 0;
- },
- afterSetDimensions: function() {
- helpers.callback(this.options.afterSetDimensions, [this]);
- },
-
- // Data limits
- beforeDataLimits: function() {
- helpers.callback(this.options.beforeDataLimits, [this]);
- },
- determineDataLimits: helpers.noop,
- afterDataLimits: function() {
- helpers.callback(this.options.afterDataLimits, [this]);
- },
+ me._ticks = ticks;
+ // Tick Rotation
+ me.beforeCalculateTickRotation();
+ me.calculateTickRotation();
+ me.afterCalculateTickRotation();
+ // Fit
+ me.beforeFit();
+ me.fit();
+ me.afterFit();
//
- beforeBuildTicks: function() {
- helpers.callback(this.options.beforeBuildTicks, [this]);
- },
- buildTicks: helpers.noop,
- afterBuildTicks: function() {
- helpers.callback(this.options.afterBuildTicks, [this]);
- },
-
- beforeTickToLabelConversion: function() {
- helpers.callback(this.options.beforeTickToLabelConversion, [this]);
- },
- convertTicksToLabels: function() {
- var me = this;
- // Convert ticks to strings
- var tickOpts = me.options.ticks;
- me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
- },
- afterTickToLabelConversion: function() {
- helpers.callback(this.options.afterTickToLabelConversion, [this]);
- },
+ me.afterUpdate();
- //
+ return me.minSize;
- beforeCalculateTickRotation: function() {
- helpers.callback(this.options.beforeCalculateTickRotation, [this]);
- },
- calculateTickRotation: function() {
- var me = this;
- var context = me.ctx;
- var tickOpts = me.options.ticks;
- var labels = labelsFromTicks(me._ticks);
-
- // Get the width of each grid by calculating the difference
- // between x offsets between 0 and 1.
- var tickFont = parseFontOptions(tickOpts);
- context.font = tickFont.font;
-
- var labelRotation = tickOpts.minRotation || 0;
-
- if (labels.length && me.options.display && me.isHorizontal()) {
- var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
- var labelWidth = originalLabelWidth;
- var cosRotation, sinRotation;
-
- // Allow 3 pixels x2 padding either side for label readability
- var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
-
- // Max label rotation can be set or default to 90 - also act as a loop counter
- while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
- var angleRadians = helpers.toRadians(labelRotation);
- cosRotation = Math.cos(angleRadians);
- sinRotation = Math.sin(angleRadians);
-
- if (sinRotation * originalLabelWidth > me.maxHeight) {
- // go back one step
- labelRotation--;
- break;
- }
+ },
+ afterUpdate: function() {
+ helpers.callback(this.options.afterUpdate, [this]);
+ },
+
+ //
+
+ beforeSetDimensions: function() {
+ helpers.callback(this.options.beforeSetDimensions, [this]);
+ },
+ setDimensions: function() {
+ var me = this;
+ // Set the unconstrained dimension before label rotation
+ if (me.isHorizontal()) {
+ // Reset position before calculating rotation
+ me.width = me.maxWidth;
+ me.left = 0;
+ me.right = me.width;
+ } else {
+ me.height = me.maxHeight;
+
+ // Reset position before calculating rotation
+ me.top = 0;
+ me.bottom = me.height;
+ }
+
+ // Reset padding
+ me.paddingLeft = 0;
+ me.paddingTop = 0;
+ me.paddingRight = 0;
+ me.paddingBottom = 0;
+ },
+ afterSetDimensions: function() {
+ helpers.callback(this.options.afterSetDimensions, [this]);
+ },
+
+ // Data limits
+ beforeDataLimits: function() {
+ helpers.callback(this.options.beforeDataLimits, [this]);
+ },
+ determineDataLimits: helpers.noop,
+ afterDataLimits: function() {
+ helpers.callback(this.options.afterDataLimits, [this]);
+ },
+
+ //
+ beforeBuildTicks: function() {
+ helpers.callback(this.options.beforeBuildTicks, [this]);
+ },
+ buildTicks: helpers.noop,
+ afterBuildTicks: function() {
+ helpers.callback(this.options.afterBuildTicks, [this]);
+ },
+
+ beforeTickToLabelConversion: function() {
+ helpers.callback(this.options.beforeTickToLabelConversion, [this]);
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ // Convert ticks to strings
+ var tickOpts = me.options.ticks;
+ me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
+ },
+ afterTickToLabelConversion: function() {
+ helpers.callback(this.options.afterTickToLabelConversion, [this]);
+ },
- labelRotation++;
- labelWidth = cosRotation * originalLabelWidth;
+ //
+
+ beforeCalculateTickRotation: function() {
+ helpers.callback(this.options.beforeCalculateTickRotation, [this]);
+ },
+ calculateTickRotation: function() {
+ var me = this;
+ var context = me.ctx;
+ var tickOpts = me.options.ticks;
+ var labels = labelsFromTicks(me._ticks);
+
+ // Get the width of each grid by calculating the difference
+ // between x offsets between 0 and 1.
+ var tickFont = parseFontOptions(tickOpts);
+ context.font = tickFont.font;
+
+ var labelRotation = tickOpts.minRotation || 0;
+
+ if (labels.length && me.options.display && me.isHorizontal()) {
+ var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
+ var labelWidth = originalLabelWidth;
+ var cosRotation, sinRotation;
+
+ // Allow 3 pixels x2 padding either side for label readability
+ var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
+
+ // Max label rotation can be set or default to 90 - also act as a loop counter
+ while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
+ var angleRadians = helpers.toRadians(labelRotation);
+ cosRotation = Math.cos(angleRadians);
+ sinRotation = Math.sin(angleRadians);
+
+ if (sinRotation * originalLabelWidth > me.maxHeight) {
+ // go back one step
+ labelRotation--;
+ break;
}
+
+ labelRotation++;
+ labelWidth = cosRotation * originalLabelWidth;
}
+ }
- me.labelRotation = labelRotation;
- },
- afterCalculateTickRotation: function() {
- helpers.callback(this.options.afterCalculateTickRotation, [this]);
- },
+ me.labelRotation = labelRotation;
+ },
+ afterCalculateTickRotation: function() {
+ helpers.callback(this.options.afterCalculateTickRotation, [this]);
+ },
- //
+ //
- beforeFit: function() {
- helpers.callback(this.options.beforeFit, [this]);
- },
- fit: function() {
- var me = this;
- // Reset
- var minSize = me.minSize = {
- width: 0,
- height: 0
- };
+ beforeFit: function() {
+ helpers.callback(this.options.beforeFit, [this]);
+ },
+ fit: function() {
+ var me = this;
+ // Reset
+ var minSize = me.minSize = {
+ width: 0,
+ height: 0
+ };
- var labels = labelsFromTicks(me._ticks);
+ var labels = labelsFromTicks(me._ticks);
- var opts = me.options;
- var tickOpts = opts.ticks;
- var scaleLabelOpts = opts.scaleLabel;
- var gridLineOpts = opts.gridLines;
- var display = opts.display;
- var isHorizontal = me.isHorizontal();
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ var scaleLabelOpts = opts.scaleLabel;
+ var gridLineOpts = opts.gridLines;
+ var display = opts.display;
+ var isHorizontal = me.isHorizontal();
- var tickFont = parseFontOptions(tickOpts);
- var tickMarkLength = opts.gridLines.tickMarkLength;
+ var tickFont = parseFontOptions(tickOpts);
+ var tickMarkLength = opts.gridLines.tickMarkLength;
- // Width
- if (isHorizontal) {
- // subtract the margins to line up with the chartArea if we are a full width scale
- minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
- } else {
- minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
- }
+ // Width
+ if (isHorizontal) {
+ // subtract the margins to line up with the chartArea if we are a full width scale
+ minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
+ } else {
+ minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ }
+
+ // height
+ if (isHorizontal) {
+ minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ } else {
+ minSize.height = me.maxHeight; // fill all the height
+ }
+
+ // Are we showing a title for the scale?
+ if (scaleLabelOpts.display && display) {
+ var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
+ var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
+ var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
- // height
if (isHorizontal) {
- minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ minSize.height += deltaHeight;
} else {
- minSize.height = me.maxHeight; // fill all the height
+ minSize.width += deltaHeight;
}
+ }
- // Are we showing a title for the scale?
- if (scaleLabelOpts.display && display) {
- var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
- var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
- var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
+ // Don't bother fitting the ticks if we are not showing them
+ if (tickOpts.display && display) {
+ var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
+ var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
+ var lineSpace = tickFont.size * 0.5;
+ var tickPadding = me.options.ticks.padding;
- if (isHorizontal) {
- minSize.height += deltaHeight;
+ if (isHorizontal) {
+ // A horizontal axis is more constrained by the height.
+ me.longestLabelWidth = largestTextWidth;
+
+ var angleRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(angleRadians);
+ var sinRotation = Math.sin(angleRadians);
+
+ // TODO - improve this calculation
+ var labelHeight = (sinRotation * largestTextWidth)
+ + (tickFont.size * tallestLabelHeightInLines)
+ + (lineSpace * (tallestLabelHeightInLines - 1))
+ + lineSpace; // padding
+
+ minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+ me.ctx.font = tickFont.font;
+ var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
+ var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
+
+ // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
+ // which means that the right padding is dominated by the font height
+ if (me.labelRotation !== 0) {
+ me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
} else {
- minSize.width += deltaHeight;
+ me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = lastLabelWidth / 2 + 3;
}
- }
-
- // Don't bother fitting the ticks if we are not showing them
- if (tickOpts.display && display) {
- var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
- var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
- var lineSpace = tickFont.size * 0.5;
- var tickPadding = me.options.ticks.padding;
-
- if (isHorizontal) {
- // A horizontal axis is more constrained by the height.
- me.longestLabelWidth = largestTextWidth;
-
- var angleRadians = helpers.toRadians(me.labelRotation);
- var cosRotation = Math.cos(angleRadians);
- var sinRotation = Math.sin(angleRadians);
-
- // TODO - improve this calculation
- var labelHeight = (sinRotation * largestTextWidth)
- + (tickFont.size * tallestLabelHeightInLines)
- + (lineSpace * (tallestLabelHeightInLines - 1))
- + lineSpace; // padding
-
- minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
-
- me.ctx.font = tickFont.font;
- var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
- var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
-
- // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
- // which means that the right padding is dominated by the font height
- if (me.labelRotation !== 0) {
- me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
- me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
- } else {
- me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
- me.paddingRight = lastLabelWidth / 2 + 3;
- }
+ } else {
+ // A vertical axis is more constrained by the width. Labels are the
+ // dominant factor here, so get that length first and account for padding
+ if (tickOpts.mirror) {
+ largestTextWidth = 0;
} else {
- // A vertical axis is more constrained by the width. Labels are the
- // dominant factor here, so get that length first and account for padding
- if (tickOpts.mirror) {
- largestTextWidth = 0;
- } else {
- // use lineSpace for consistency with horizontal axis
- // tickPadding is not implemented for horizontal
- largestTextWidth += tickPadding + lineSpace;
- }
+ // use lineSpace for consistency with horizontal axis
+ // tickPadding is not implemented for horizontal
+ largestTextWidth += tickPadding + lineSpace;
+ }
- minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
+ minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
- me.paddingTop = tickFont.size / 2;
- me.paddingBottom = tickFont.size / 2;
- }
+ me.paddingTop = tickFont.size / 2;
+ me.paddingBottom = tickFont.size / 2;
}
+ }
- me.handleMargins();
-
- me.width = minSize.width;
- me.height = minSize.height;
- },
-
- /**
- * Handle margins and padding interactions
- * @private
- */
- handleMargins: function() {
- var me = this;
- if (me.margins) {
- me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
- me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
- me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
- me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
- }
- },
-
- afterFit: function() {
- helpers.callback(this.options.afterFit, [this]);
- },
-
- // Shared Methods
- isHorizontal: function() {
- return this.options.position === 'top' || this.options.position === 'bottom';
- },
- isFullWidth: function() {
- return (this.options.fullWidth);
- },
-
- // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
- getRightValue: function(rawValue) {
- // Null and undefined values first
- if (helpers.isNullOrUndef(rawValue)) {
- return NaN;
- }
- // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
- if (typeof rawValue === 'number' && !isFinite(rawValue)) {
- return NaN;
- }
- // If it is in fact an object, dive in one more level
- if (rawValue) {
- if (this.isHorizontal()) {
- if (rawValue.x !== undefined) {
- return this.getRightValue(rawValue.x);
- }
- } else if (rawValue.y !== undefined) {
- return this.getRightValue(rawValue.y);
+ me.handleMargins();
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+ },
+
+ /**
+ * Handle margins and padding interactions
+ * @private
+ */
+ handleMargins: function() {
+ var me = this;
+ if (me.margins) {
+ me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
+ me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
+ me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
+ me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
+ }
+ },
+
+ afterFit: function() {
+ helpers.callback(this.options.afterFit, [this]);
+ },
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ },
+ isFullWidth: function() {
+ return (this.options.fullWidth);
+ },
+
+ // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+ getRightValue: function(rawValue) {
+ // Null and undefined values first
+ if (helpers.isNullOrUndef(rawValue)) {
+ return NaN;
+ }
+ // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
+ if (typeof rawValue === 'number' && !isFinite(rawValue)) {
+ return NaN;
+ }
+ // If it is in fact an object, dive in one more level
+ if (rawValue) {
+ if (this.isHorizontal()) {
+ if (rawValue.x !== undefined) {
+ return this.getRightValue(rawValue.x);
}
+ } else if (rawValue.y !== undefined) {
+ return this.getRightValue(rawValue.y);
}
+ }
- // Value is good, return it
- return rawValue;
- },
-
- /**
- * Used to get the value to display in the tooltip for the data at the given index
- * @param index
- * @param datasetIndex
- */
- getLabelForIndex: helpers.noop,
-
- /**
- * Returns the location of the given data point. Value can either be an index or a numerical value
- * The coordinate (0, 0) is at the upper-left corner of the canvas
- * @param value
- * @param index
- * @param datasetIndex
- */
- getPixelForValue: helpers.noop,
-
- /**
- * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
- * The coordinate (0, 0) is at the upper-left corner of the canvas
- * @param pixel
- */
- getValueForPixel: helpers.noop,
-
- /**
- * Returns the location of the tick at the given index
- * The coordinate (0, 0) is at the upper-left corner of the canvas
- */
- getPixelForTick: function(index) {
- var me = this;
- var offset = me.options.offset;
- if (me.isHorizontal()) {
- var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
- var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
- var pixel = (tickWidth * index) + me.paddingLeft;
-
- if (offset) {
- pixel += tickWidth / 2;
- }
+ // Value is good, return it
+ return rawValue;
+ },
- var finalVal = me.left + Math.round(pixel);
- finalVal += me.isFullWidth() ? me.margins.left : 0;
- return finalVal;
- }
- var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
- return me.top + (index * (innerHeight / (me._ticks.length - 1)));
- },
-
- /**
- * Utility for getting the pixel location of a percentage of scale
- * The coordinate (0, 0) is at the upper-left corner of the canvas
- */
- getPixelForDecimal: function(decimal) {
- var me = this;
- if (me.isHorizontal()) {
- var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
- var valueOffset = (innerWidth * decimal) + me.paddingLeft;
-
- var finalVal = me.left + Math.round(valueOffset);
- finalVal += me.isFullWidth() ? me.margins.left : 0;
- return finalVal;
- }
- return me.top + (decimal * me.height);
- },
-
- /**
- * Returns the pixel for the minimum chart value
- * The coordinate (0, 0) is at the upper-left corner of the canvas
- */
- getBasePixel: function() {
- return this.getPixelForValue(this.getBaseValue());
- },
-
- getBaseValue: function() {
- var me = this;
- var min = me.min;
- var max = me.max;
-
- return me.beginAtZero ? 0 :
- min < 0 && max < 0 ? max :
- min > 0 && max > 0 ? min :
- 0;
- },
-
- /**
- * Returns a subset of ticks to be plotted to avoid overlapping labels.
- * @private
- */
- _autoSkip: function(ticks) {
- var skipRatio;
- var me = this;
- var isHorizontal = me.isHorizontal();
- var optionTicks = me.options.ticks.minor;
- var tickCount = ticks.length;
- var labelRotationRadians = helpers.toRadians(me.labelRotation);
- var cosRotation = Math.cos(labelRotationRadians);
- var longestRotatedLabel = me.longestLabelWidth * cosRotation;
- var result = [];
- var i, tick, shouldSkip;
-
- // figure out the maximum number of gridlines to show
- var maxTicks;
- if (optionTicks.maxTicksLimit) {
- maxTicks = optionTicks.maxTicksLimit;
+ /**
+ * Used to get the value to display in the tooltip for the data at the given index
+ * @param index
+ * @param datasetIndex
+ */
+ getLabelForIndex: helpers.noop,
+
+ /**
+ * Returns the location of the given data point. Value can either be an index or a numerical value
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
+ * @param value
+ * @param index
+ * @param datasetIndex
+ */
+ getPixelForValue: helpers.noop,
+
+ /**
+ * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
+ * @param pixel
+ */
+ getValueForPixel: helpers.noop,
+
+ /**
+ * Returns the location of the tick at the given index
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
+ */
+ getPixelForTick: function(index) {
+ var me = this;
+ var offset = me.options.offset;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
+ var pixel = (tickWidth * index) + me.paddingLeft;
+
+ if (offset) {
+ pixel += tickWidth / 2;
}
- if (isHorizontal) {
- skipRatio = false;
+ var finalVal = me.left + Math.round(pixel);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
+ return me.top + (index * (innerHeight / (me._ticks.length - 1)));
+ },
- if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
- skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
- }
+ /**
+ * Utility for getting the pixel location of a percentage of scale
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
+ */
+ getPixelForDecimal: function(decimal) {
+ var me = this;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var valueOffset = (innerWidth * decimal) + me.paddingLeft;
+
+ var finalVal = me.left + Math.round(valueOffset);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ return me.top + (decimal * me.height);
+ },
- // if they defined a max number of optionTicks,
- // increase skipRatio until that number is met
- if (maxTicks && tickCount > maxTicks) {
- skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
- }
- }
+ /**
+ * Returns the pixel for the minimum chart value
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
+ */
+ getBasePixel: function() {
+ return this.getPixelForValue(this.getBaseValue());
+ },
- for (i = 0; i < tickCount; i++) {
- tick = ticks[i];
+ getBaseValue: function() {
+ var me = this;
+ var min = me.min;
+ var max = me.max;
- // Since we always show the last tick,we need may need to hide the last shown one before
- shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
- if (shouldSkip && i !== tickCount - 1) {
- // leave tick in place but make sure it's not displayed (#4635)
- delete tick.label;
- }
- result.push(tick);
+ return me.beginAtZero ? 0 :
+ min < 0 && max < 0 ? max :
+ min > 0 && max > 0 ? min :
+ 0;
+ },
+
+ /**
+ * Returns a subset of ticks to be plotted to avoid overlapping labels.
+ * @private
+ */
+ _autoSkip: function(ticks) {
+ var skipRatio;
+ var me = this;
+ var isHorizontal = me.isHorizontal();
+ var optionTicks = me.options.ticks.minor;
+ var tickCount = ticks.length;
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(labelRotationRadians);
+ var longestRotatedLabel = me.longestLabelWidth * cosRotation;
+ var result = [];
+ var i, tick, shouldSkip;
+
+ // figure out the maximum number of gridlines to show
+ var maxTicks;
+ if (optionTicks.maxTicksLimit) {
+ maxTicks = optionTicks.maxTicksLimit;
+ }
+
+ if (isHorizontal) {
+ skipRatio = false;
+
+ if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
+ skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
}
- return result;
- },
-
- // Actually draw the scale on the canvas
- // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
- draw: function(chartArea) {
- var me = this;
- var options = me.options;
- if (!options.display) {
- return;
+
+ // if they defined a max number of optionTicks,
+ // increase skipRatio until that number is met
+ if (maxTicks && tickCount > maxTicks) {
+ skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
}
+ }
- var context = me.ctx;
- var globalDefaults = defaults.global;
- var optionTicks = options.ticks.minor;
- var optionMajorTicks = options.ticks.major || optionTicks;
- var gridLines = options.gridLines;
- var scaleLabel = options.scaleLabel;
-
- var isRotated = me.labelRotation !== 0;
- var isHorizontal = me.isHorizontal();
-
- var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
- var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
- var tickFont = parseFontOptions(optionTicks);
- var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
- var majorTickFont = parseFontOptions(optionMajorTicks);
-
- var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
-
- var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
- var scaleLabelFont = parseFontOptions(scaleLabel);
- var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
- var labelRotationRadians = helpers.toRadians(me.labelRotation);
-
- var itemsToDraw = [];
-
- var axisWidth = me.options.gridLines.lineWidth;
- var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl;
- var xTickEnd = options.position === 'right' ? me.right + tl : me.right;
- var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
- var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
-
- helpers.each(ticks, function(tick, index) {
- // autoskipper skipped this tick (#4635)
- if (helpers.isNullOrUndef(tick.label)) {
- return;
- }
+ for (i = 0; i < tickCount; i++) {
+ tick = ticks[i];
- var label = tick.label;
- var lineWidth, lineColor, borderDash, borderDashOffset;
- if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
- // Draw the first index specially
- lineWidth = gridLines.zeroLineWidth;
- lineColor = gridLines.zeroLineColor;
- borderDash = gridLines.zeroLineBorderDash;
- borderDashOffset = gridLines.zeroLineBorderDashOffset;
- } else {
- lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
- lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
- borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
- borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
- }
+ // Since we always show the last tick,we need may need to hide the last shown one before
+ shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
+ if (shouldSkip && i !== tickCount - 1) {
+ // leave tick in place but make sure it's not displayed (#4635)
+ delete tick.label;
+ }
+ result.push(tick);
+ }
+ return result;
+ },
- // Common properties
- var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
- var textAlign = 'middle';
- var textBaseline = 'middle';
- var tickPadding = optionTicks.padding;
-
- if (isHorizontal) {
- var labelYOffset = tl + tickPadding;
-
- if (options.position === 'bottom') {
- // bottom
- textBaseline = !isRotated ? 'top' : 'middle';
- textAlign = !isRotated ? 'center' : 'right';
- labelY = me.top + labelYOffset;
- } else {
- // top
- textBaseline = !isRotated ? 'bottom' : 'middle';
- textAlign = !isRotated ? 'center' : 'left';
- labelY = me.bottom - labelYOffset;
- }
+ // Actually draw the scale on the canvas
+ // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
+ draw: function(chartArea) {
+ var me = this;
+ var options = me.options;
+ if (!options.display) {
+ return;
+ }
- var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
- if (xLineValue < me.left) {
- lineColor = 'rgba(0,0,0,0)';
- }
- xLineValue += helpers.aliasPixel(lineWidth);
+ var context = me.ctx;
+ var globalDefaults = defaults.global;
+ var optionTicks = options.ticks.minor;
+ var optionMajorTicks = options.ticks.major || optionTicks;
+ var gridLines = options.gridLines;
+ var scaleLabel = options.scaleLabel;
+
+ var isRotated = me.labelRotation !== 0;
+ var isHorizontal = me.isHorizontal();
+
+ var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
+ var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
+ var tickFont = parseFontOptions(optionTicks);
+ var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
+ var majorTickFont = parseFontOptions(optionMajorTicks);
+
+ var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
+
+ var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
+ var scaleLabelFont = parseFontOptions(scaleLabel);
+ var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
+
+ var itemsToDraw = [];
+
+ var axisWidth = me.options.gridLines.lineWidth;
+ var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl;
+ var xTickEnd = options.position === 'right' ? me.right + tl : me.right;
+ var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
+ var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
+
+ helpers.each(ticks, function(tick, index) {
+ // autoskipper skipped this tick (#4635)
+ if (helpers.isNullOrUndef(tick.label)) {
+ return;
+ }
- labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
+ var label = tick.label;
+ var lineWidth, lineColor, borderDash, borderDashOffset;
+ if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
+ // Draw the first index specially
+ lineWidth = gridLines.zeroLineWidth;
+ lineColor = gridLines.zeroLineColor;
+ borderDash = gridLines.zeroLineBorderDash;
+ borderDashOffset = gridLines.zeroLineBorderDashOffset;
+ } else {
+ lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
+ lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
+ borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
+ borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
+ }
+
+ // Common properties
+ var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
+ var textAlign = 'middle';
+ var textBaseline = 'middle';
+ var tickPadding = optionTicks.padding;
+
+ if (isHorizontal) {
+ var labelYOffset = tl + tickPadding;
- tx1 = tx2 = x1 = x2 = xLineValue;
- ty1 = yTickStart;
- ty2 = yTickEnd;
- y1 = chartArea.top;
- y2 = chartArea.bottom + axisWidth;
+ if (options.position === 'bottom') {
+ // bottom
+ textBaseline = !isRotated ? 'top' : 'middle';
+ textAlign = !isRotated ? 'center' : 'right';
+ labelY = me.top + labelYOffset;
} else {
- var isLeft = options.position === 'left';
- var labelXOffset;
-
- if (optionTicks.mirror) {
- textAlign = isLeft ? 'left' : 'right';
- labelXOffset = tickPadding;
- } else {
- textAlign = isLeft ? 'right' : 'left';
- labelXOffset = tl + tickPadding;
- }
+ // top
+ textBaseline = !isRotated ? 'bottom' : 'middle';
+ textAlign = !isRotated ? 'center' : 'left';
+ labelY = me.bottom - labelYOffset;
+ }
- labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
+ var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
+ if (xLineValue < me.left) {
+ lineColor = 'rgba(0,0,0,0)';
+ }
+ xLineValue += helpers.aliasPixel(lineWidth);
- var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
- if (yLineValue < me.top) {
- lineColor = 'rgba(0,0,0,0)';
- }
- yLineValue += helpers.aliasPixel(lineWidth);
+ labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
- labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
+ tx1 = tx2 = x1 = x2 = xLineValue;
+ ty1 = yTickStart;
+ ty2 = yTickEnd;
+ y1 = chartArea.top;
+ y2 = chartArea.bottom + axisWidth;
+ } else {
+ var isLeft = options.position === 'left';
+ var labelXOffset;
- tx1 = xTickStart;
- tx2 = xTickEnd;
- x1 = chartArea.left;
- x2 = chartArea.right + axisWidth;
- ty1 = ty2 = y1 = y2 = yLineValue;
+ if (optionTicks.mirror) {
+ textAlign = isLeft ? 'left' : 'right';
+ labelXOffset = tickPadding;
+ } else {
+ textAlign = isLeft ? 'right' : 'left';
+ labelXOffset = tl + tickPadding;
}
- itemsToDraw.push({
- tx1: tx1,
- ty1: ty1,
- tx2: tx2,
- ty2: ty2,
- x1: x1,
- y1: y1,
- x2: x2,
- y2: y2,
- labelX: labelX,
- labelY: labelY,
- glWidth: lineWidth,
- glColor: lineColor,
- glBorderDash: borderDash,
- glBorderDashOffset: borderDashOffset,
- rotation: -1 * labelRotationRadians,
- label: label,
- major: tick.major,
- textBaseline: textBaseline,
- textAlign: textAlign
- });
- });
+ labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
- // Draw all of the tick labels, tick marks, and grid lines at the correct places
- helpers.each(itemsToDraw, function(itemToDraw) {
- if (gridLines.display) {
- context.save();
- context.lineWidth = itemToDraw.glWidth;
- context.strokeStyle = itemToDraw.glColor;
- if (context.setLineDash) {
- context.setLineDash(itemToDraw.glBorderDash);
- context.lineDashOffset = itemToDraw.glBorderDashOffset;
- }
+ var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
+ if (yLineValue < me.top) {
+ lineColor = 'rgba(0,0,0,0)';
+ }
+ yLineValue += helpers.aliasPixel(lineWidth);
- context.beginPath();
+ labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
- if (gridLines.drawTicks) {
- context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
- context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
- }
+ tx1 = xTickStart;
+ tx2 = xTickEnd;
+ x1 = chartArea.left;
+ x2 = chartArea.right + axisWidth;
+ ty1 = ty2 = y1 = y2 = yLineValue;
+ }
- if (gridLines.drawOnChartArea) {
- context.moveTo(itemToDraw.x1, itemToDraw.y1);
- context.lineTo(itemToDraw.x2, itemToDraw.y2);
- }
+ itemsToDraw.push({
+ tx1: tx1,
+ ty1: ty1,
+ tx2: tx2,
+ ty2: ty2,
+ x1: x1,
+ y1: y1,
+ x2: x2,
+ y2: y2,
+ labelX: labelX,
+ labelY: labelY,
+ glWidth: lineWidth,
+ glColor: lineColor,
+ glBorderDash: borderDash,
+ glBorderDashOffset: borderDashOffset,
+ rotation: -1 * labelRotationRadians,
+ label: label,
+ major: tick.major,
+ textBaseline: textBaseline,
+ textAlign: textAlign
+ });
+ });
- context.stroke();
- context.restore();
+ // Draw all of the tick labels, tick marks, and grid lines at the correct places
+ helpers.each(itemsToDraw, function(itemToDraw) {
+ if (gridLines.display) {
+ context.save();
+ context.lineWidth = itemToDraw.glWidth;
+ context.strokeStyle = itemToDraw.glColor;
+ if (context.setLineDash) {
+ context.setLineDash(itemToDraw.glBorderDash);
+ context.lineDashOffset = itemToDraw.glBorderDashOffset;
}
- if (optionTicks.display) {
- // Make sure we draw text in the correct color and font
- context.save();
- context.translate(itemToDraw.labelX, itemToDraw.labelY);
- context.rotate(itemToDraw.rotation);
- context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
- context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
- context.textBaseline = itemToDraw.textBaseline;
- context.textAlign = itemToDraw.textAlign;
-
- var label = itemToDraw.label;
- if (helpers.isArray(label)) {
- var lineCount = label.length;
- var lineHeight = tickFont.size * 1.5;
- var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
-
- for (var i = 0; i < lineCount; ++i) {
- // We just make sure the multiline element is a string here..
- context.fillText('' + label[i], 0, y);
- // apply same lineSpacing as calculated @ L#320
- y += lineHeight;
- }
- } else {
- context.fillText(label, 0, 0);
- }
- context.restore();
+ context.beginPath();
+
+ if (gridLines.drawTicks) {
+ context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
+ context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
}
- });
- if (scaleLabel.display) {
- // Draw the scale label
- var scaleLabelX;
- var scaleLabelY;
- var rotation = 0;
- var halfLineHeight = parseLineHeight(scaleLabel) / 2;
-
- if (isHorizontal) {
- scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
- scaleLabelY = options.position === 'bottom'
- ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
- : me.top + halfLineHeight + scaleLabelPadding.top;
- } else {
- var isLeft = options.position === 'left';
- scaleLabelX = isLeft
- ? me.left + halfLineHeight + scaleLabelPadding.top
- : me.right - halfLineHeight - scaleLabelPadding.top;
- scaleLabelY = me.top + ((me.bottom - me.top) / 2);
- rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+ if (gridLines.drawOnChartArea) {
+ context.moveTo(itemToDraw.x1, itemToDraw.y1);
+ context.lineTo(itemToDraw.x2, itemToDraw.y2);
}
- context.save();
- context.translate(scaleLabelX, scaleLabelY);
- context.rotate(rotation);
- context.textAlign = 'center';
- context.textBaseline = 'middle';
- context.fillStyle = scaleLabelFontColor; // render in correct colour
- context.font = scaleLabelFont.font;
- context.fillText(scaleLabel.labelString, 0, 0);
+ context.stroke();
context.restore();
}
- if (gridLines.drawBorder) {
- // Draw the line at the edge of the axis
- context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
- context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
- var x1 = me.left;
- var x2 = me.right + axisWidth;
- var y1 = me.top;
- var y2 = me.bottom + axisWidth;
-
- var aliasPixel = helpers.aliasPixel(context.lineWidth);
- if (isHorizontal) {
- y1 = y2 = options.position === 'top' ? me.bottom : me.top;
- y1 += aliasPixel;
- y2 += aliasPixel;
+ if (optionTicks.display) {
+ // Make sure we draw text in the correct color and font
+ context.save();
+ context.translate(itemToDraw.labelX, itemToDraw.labelY);
+ context.rotate(itemToDraw.rotation);
+ context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
+ context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
+ context.textBaseline = itemToDraw.textBaseline;
+ context.textAlign = itemToDraw.textAlign;
+
+ var label = itemToDraw.label;
+ if (helpers.isArray(label)) {
+ var lineCount = label.length;
+ var lineHeight = tickFont.size * 1.5;
+ var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
+
+ for (var i = 0; i < lineCount; ++i) {
+ // We just make sure the multiline element is a string here..
+ context.fillText('' + label[i], 0, y);
+ // apply same lineSpacing as calculated @ L#320
+ y += lineHeight;
+ }
} else {
- x1 = x2 = options.position === 'left' ? me.right : me.left;
- x1 += aliasPixel;
- x2 += aliasPixel;
+ context.fillText(label, 0, 0);
}
+ context.restore();
+ }
+ });
- context.beginPath();
- context.moveTo(x1, y1);
- context.lineTo(x2, y2);
- context.stroke();
+ if (scaleLabel.display) {
+ // Draw the scale label
+ var scaleLabelX;
+ var scaleLabelY;
+ var rotation = 0;
+ var halfLineHeight = parseLineHeight(scaleLabel) / 2;
+
+ if (isHorizontal) {
+ scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+ scaleLabelY = options.position === 'bottom'
+ ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
+ : me.top + halfLineHeight + scaleLabelPadding.top;
+ } else {
+ var isLeft = options.position === 'left';
+ scaleLabelX = isLeft
+ ? me.left + halfLineHeight + scaleLabelPadding.top
+ : me.right - halfLineHeight - scaleLabelPadding.top;
+ scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+ rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
}
+
+ context.save();
+ context.translate(scaleLabelX, scaleLabelY);
+ context.rotate(rotation);
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+ context.fillStyle = scaleLabelFontColor; // render in correct colour
+ context.font = scaleLabelFont.font;
+ context.fillText(scaleLabel.labelString, 0, 0);
+ context.restore();
}
- });
-};
+
+ if (gridLines.drawBorder) {
+ // Draw the line at the edge of the axis
+ context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
+ context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
+ var x1 = me.left;
+ var x2 = me.right + axisWidth;
+ var y1 = me.top;
+ var y2 = me.bottom + axisWidth;
+
+ var aliasPixel = helpers.aliasPixel(context.lineWidth);
+ if (isHorizontal) {
+ y1 = y2 = options.position === 'top' ? me.bottom : me.top;
+ y1 += aliasPixel;
+ y2 += aliasPixel;
+ } else {
+ x1 = x2 = options.position === 'left' ? me.right : me.left;
+ x1 += aliasPixel;
+ x2 += aliasPixel;
+ }
+
+ context.beginPath();
+ context.moveTo(x1, y1);
+ context.lineTo(x2, y2);
+ context.stroke();
+ }
+ }
+});