]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add scale.pointLabels.lineHeight and scale.ticks.lineHeight options (#5914)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Thu, 20 Dec 2018 08:56:06 +0000 (17:56 +0900)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 20 Dec 2018 08:56:06 +0000 (09:56 +0100)
24 files changed:
docs/axes/radial/linear.md
docs/axes/styling.md
src/core/core.defaults.js
src/core/core.js
src/core/core.scale.js
src/elements/element.line.js
src/elements/element.point.js
src/elements/element.rectangle.js
src/helpers/helpers.options.js
src/plugins/plugin.legend.js
src/plugins/plugin.title.js
src/scales/scale.radialLinear.js
test/fixtures/controller.radar/point-style.png
test/fixtures/plugin.filler/fill-radar-boundary-origin-spline.png
test/fixtures/plugin.filler/fill-radar-boundary-origin.png
test/specs/controller.radar.tests.js
test/specs/core.controller.tests.js
test/specs/core.scale.tests.js
test/specs/helpers.options.tests.js
test/specs/plugin.legend.tests.js
test/specs/plugin.title.tests.js
test/specs/scale.category.tests.js
test/specs/scale.linear.tests.js
test/specs/scale.radialLinear.tests.js

index d1edd18be54cc3a588f8bb92b3f578c9bac52215..92f1e35b78afb85c315bd0444b2de5c3d87accd5 100644 (file)
@@ -109,3 +109,4 @@ The following options are used to configure the point labels that are shown on t
 | `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family to use when rendering labels.
 | `fontSize` | `Number` | 10 | font size in pixels.
 | `fontStyle` | `String` | `'normal'` | Font style to use when rendering point labels.
+| `lineHeight` | `Number/String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height)).
index 7184bc96faf1e5fcd542aa66c627eef80fd590a2..1f06ca7af4aecd459e403ad05a71a2dc36dd534b 100644 (file)
@@ -35,6 +35,7 @@ The tick configuration is nested under the scale configuration in the `ticks` ke
 | `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
 | `fontSize` | `Number` | `12` | Font size for the tick labels.
 | `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
+| `lineHeight` | `Number/String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height)).
 | `reverse` | `Boolean` | `false` | Reverses order of tick labels.
 | `minor` | `object` | `{}` | Minor ticks configuration. Omitted options are inherited from options above.
 | `major` | `object` | `{}` | Major ticks configuration. Omitted options are inherited from options above.
@@ -50,6 +51,7 @@ The minorTick configuration is nested under the ticks configuration in the `mino
 | `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
 | `fontSize` | `Number` | `12` | Font size for the tick labels.
 | `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
+| `lineHeight` | `Number/String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height)).
 
 ## Major Tick Configuration
 The majorTick configuration is nested under the ticks configuration in the `major` key. It defines options for the major tick marks that are generated by the axis. Omitted options are inherited from `ticks` configuration.
@@ -61,3 +63,4 @@ The majorTick configuration is nested under the ticks configuration in the `majo
 | `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
 | `fontSize` | `Number` | `12` | Font size for the tick labels.
 | `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
+| `lineHeight` | `Number/String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height)).
index 29bb040d4f069535d67301b1e64b5228e7a9686d..4a2bb8e1b40cdb9665036493496bda205f7ce6f7 100644 (file)
@@ -1,6 +1,6 @@
 'use strict';
 
-var helpers = require('../helpers/index');
+var helpers = require('../helpers/helpers.core');
 
 module.exports = {
        /**
index 906b897c6990225aa9f43613818e2f2a92b4a883..8860b9bbcf4c68f255aa32dabbddb1168dd57635 100644 (file)
@@ -19,6 +19,7 @@ defaults._set('global', {
        defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
        defaultFontSize: 12,
        defaultFontStyle: 'normal',
+       defaultLineHeight: 1.2,
        showLines: true,
 
        // Element defaults defined in element extensions
index 5a777e658560684d095f8c5a67cde45f09e610c3..a538b5efa2139962df717055409e83e4c16b1ebb 100644 (file)
@@ -36,9 +36,6 @@ defaults._set('scale', {
                // actual label
                labelString: '',
 
-               // line height
-               lineHeight: 1.2,
-
                // top/bottom padding
                padding: {
                        top: 4,
@@ -99,27 +96,6 @@ function computeTextSize(context, tick, font) {
                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 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
@@ -341,13 +317,13 @@ module.exports = Element.extend({
 
                // 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 tickFont = helpers.options._parseFont(tickOpts);
+               context.font = tickFont.string;
 
                var labelRotation = tickOpts.minRotation || 0;
 
                if (labels.length && me.options.display && me.isHorizontal()) {
-                       var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
+                       var originalLabelWidth = helpers.longestText(context, tickFont.string, labels, me.longestTextCache);
                        var labelWidth = originalLabelWidth;
                        var cosRotation, sinRotation;
 
@@ -400,7 +376,8 @@ module.exports = Element.extend({
                var position = opts.position;
                var isHorizontal = me.isHorizontal();
 
-               var tickFont = parseFontOptions(tickOpts);
+               var parseFont = helpers.options._parseFont;
+               var tickFont = parseFont(tickOpts);
                var tickMarkLength = opts.gridLines.tickMarkLength;
 
                // Width
@@ -420,9 +397,9 @@ module.exports = Element.extend({
 
                // Are we showing a title for the scale?
                if (scaleLabelOpts.display && display) {
-                       var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
+                       var scaleLabelFont = parseFont(scaleLabelOpts);
                        var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
-                       var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
+                       var deltaHeight = scaleLabelFont.lineHeight + scaleLabelPadding.height;
 
                        if (isHorizontal) {
                                minSize.height += deltaHeight;
@@ -433,7 +410,7 @@ module.exports = Element.extend({
 
                // 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 largestTextWidth = helpers.longestText(me.ctx, tickFont.string, labels, me.longestTextCache);
                        var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
                        var lineSpace = tickFont.size * 0.5;
                        var tickPadding = me.options.ticks.padding;
@@ -448,15 +425,14 @@ module.exports = Element.extend({
 
                                // TODO - improve this calculation
                                var labelHeight = (sinRotation * largestTextWidth)
-                                       + (tickFont.size * tallestLabelHeightInLines)
-                                       + (lineSpace * (tallestLabelHeightInLines - 1))
+                                       + (tickFont.lineHeight * tallestLabelHeightInLines)
                                        + 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);
+                               me.ctx.font = tickFont.string;
+                               var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.string);
+                               var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.string);
                                var offsetLeft = me.getPixelForTick(0) - me.left;
                                var offsetRight = me.right - me.getPixelForTick(labels.length - 1);
                                var paddingLeft, paddingRight;
@@ -717,6 +693,7 @@ module.exports = Element.extend({
                var chart = me.chart;
                var context = me.ctx;
                var globalDefaults = defaults.global;
+               var defaultFontColor = globalDefaults.defaultFontColor;
                var optionTicks = options.ticks.minor;
                var optionMajorTicks = options.ticks.major || optionTicks;
                var gridLines = options.gridLines;
@@ -727,18 +704,20 @@ module.exports = Element.extend({
                var isMirrored = optionTicks.mirror;
                var isHorizontal = me.isHorizontal();
 
+               var parseFont = helpers.options._parseFont;
                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 tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, defaultFontColor);
+               var tickFont = parseFont(optionTicks);
+               var lineHeight = tickFont.lineHeight;
+               var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, defaultFontColor);
+               var majorTickFont = parseFont(optionMajorTicks);
                var tickPadding = optionTicks.padding;
                var labelOffset = optionTicks.labelOffset;
 
                var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
 
-               var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
-               var scaleLabelFont = parseFontOptions(scaleLabel);
+               var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, defaultFontColor);
+               var scaleLabelFont = parseFont(scaleLabel);
                var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
                var labelRotationRadians = helpers.toRadians(me.labelRotation);
 
@@ -790,8 +769,8 @@ module.exports = Element.extend({
                        }
 
                        // Common properties
-                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY, textAlign;
-                       var textBaseline = 'middle';
+                       var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY, textOffset, textAlign;
+                       var labelCount = helpers.isArray(label) ? label.length : 1;
                        var lineValue = getPixelForGridLine(me, index, gridLines.offsetGridLines);
 
                        if (isHorizontal) {
@@ -809,13 +788,13 @@ module.exports = Element.extend({
                                if (position === 'top') {
                                        y1 = alignPixel(chart, chartArea.top, axisWidth) + axisWidth / 2;
                                        y2 = chartArea.bottom;
-                                       textBaseline = !isRotated ? 'bottom' : 'middle';
+                                       textOffset = ((!isRotated ? 0.5 : 1) - labelCount) * lineHeight;
                                        textAlign = !isRotated ? 'center' : 'left';
                                        labelY = me.bottom - labelYOffset;
                                } else {
                                        y1 = chartArea.top;
                                        y2 = alignPixel(chart, chartArea.bottom, axisWidth) - axisWidth / 2;
-                                       textBaseline = !isRotated ? 'top' : 'middle';
+                                       textOffset = (!isRotated ? 0.5 : 0) * lineHeight;
                                        textAlign = !isRotated ? 'center' : 'right';
                                        labelY = me.top + labelYOffset;
                                }
@@ -830,6 +809,7 @@ module.exports = Element.extend({
                                tx2 = tickEnd;
                                ty1 = ty2 = y1 = y2 = alignPixel(chart, lineValue, lineWidth);
                                labelY = me.getPixelForTick(index) + labelOffset;
+                               textOffset = (1 - labelCount) * lineHeight / 2;
 
                                if (position === 'left') {
                                        x1 = alignPixel(chart, chartArea.left, axisWidth) + axisWidth / 2;
@@ -862,7 +842,7 @@ module.exports = Element.extend({
                                rotation: -1 * labelRotationRadians,
                                label: label,
                                major: tick.major,
-                               textBaseline: textBaseline,
+                               textOffset: textOffset,
                                textAlign: textAlign
                        });
                });
@@ -902,25 +882,21 @@ module.exports = Element.extend({
                                context.save();
                                context.translate(itemToDraw.labelX, itemToDraw.labelY);
                                context.rotate(itemToDraw.rotation);
-                               context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
+                               context.font = itemToDraw.major ? majorTickFont.string : tickFont.string;
                                context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
-                               context.textBaseline = itemToDraw.textBaseline;
+                               context.textBaseline = 'middle';
                                context.textAlign = itemToDraw.textAlign;
 
                                var label = itemToDraw.label;
+                               var y = itemToDraw.textOffset;
                                if (helpers.isArray(label)) {
-                                       var lineCount = label.length;
-                                       var lineHeight = tickFont.size * 1.5;
-                                       var y = isHorizontal ? 0 : -lineHeight * (lineCount - 1) / 2;
-
-                                       for (var i = 0; i < lineCount; ++i) {
+                                       for (var i = 0; i < label.length; ++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.fillText(label, 0, y);
                                }
                                context.restore();
                        }
@@ -931,7 +907,7 @@ module.exports = Element.extend({
                        var scaleLabelX;
                        var scaleLabelY;
                        var rotation = 0;
-                       var halfLineHeight = parseLineHeight(scaleLabel) / 2;
+                       var halfLineHeight = scaleLabelFont.lineHeight / 2;
 
                        if (isHorizontal) {
                                scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
@@ -953,7 +929,7 @@ module.exports = Element.extend({
                        context.textAlign = 'center';
                        context.textBaseline = 'middle';
                        context.fillStyle = scaleLabelFontColor; // render in correct colour
-                       context.font = scaleLabelFont.font;
+                       context.font = scaleLabelFont.string;
                        context.fillText(scaleLabel.labelString, 0, 0);
                        context.restore();
                }
index 1500d353c96c6ae49426faa8f345bca45dc25ca5..96bb5be383ef7d6e7ba976dffba70801a683454e 100644 (file)
@@ -4,15 +4,15 @@ var defaults = require('../core/core.defaults');
 var Element = require('../core/core.element');
 var helpers = require('../helpers/index');
 
-var globalDefaults = defaults.global;
+var defaultColor = defaults.global.defaultColor;
 
 defaults._set('global', {
        elements: {
                line: {
                        tension: 0.4,
-                       backgroundColor: globalDefaults.defaultColor,
+                       backgroundColor: defaultColor,
                        borderWidth: 3,
-                       borderColor: globalDefaults.defaultColor,
+                       borderColor: defaultColor,
                        borderCapStyle: 'butt',
                        borderDash: [],
                        borderDashOffset: 0.0,
@@ -30,6 +30,7 @@ module.exports = Element.extend({
                var ctx = me._chart.ctx;
                var spanGaps = vm.spanGaps;
                var points = me._children.slice(); // clone array
+               var globalDefaults = defaults.global;
                var globalOptionLineElements = globalDefaults.elements.line;
                var lastDrawnIndex = -1;
                var index, current, previous, currentVM;
index 56eb5796617052f04fc279fe5925e1ce6915bbd8..b7909116a7c03fdd5f12e05cfebacafae8bad75b 100644 (file)
@@ -73,6 +73,8 @@ module.exports = Element.extend({
                var x = vm.x;
                var y = vm.y;
                var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
+               var globalDefaults = defaults.global;
+               var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow
 
                if (vm.skip) {
                        return;
@@ -81,7 +83,7 @@ module.exports = Element.extend({
                // Clipping for Points.
                if (chartArea === undefined || (model.x > chartArea.left - epsilon && chartArea.right + epsilon > model.x && model.y > chartArea.top - epsilon && chartArea.bottom + epsilon > model.y)) {
                        ctx.strokeStyle = vm.borderColor || defaultColor;
-                       ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth);
+                       ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, globalDefaults.elements.point.borderWidth);
                        ctx.fillStyle = vm.backgroundColor || defaultColor;
                        helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
                }
index ef59ac0dd62d5937a08cb59c79982791a3028871..1cb6fbb534fcc82d5095ce4e790018d1b327dd7c 100644 (file)
@@ -3,11 +3,13 @@
 var defaults = require('../core/core.defaults');
 var Element = require('../core/core.element');
 
+var defaultColor = defaults.global.defaultColor;
+
 defaults._set('global', {
        elements: {
                rectangle: {
-                       backgroundColor: defaults.global.defaultColor,
-                       borderColor: defaults.global.defaultColor,
+                       backgroundColor: defaultColor,
+                       borderColor: defaultColor,
                        borderSkipped: 'bottom',
                        borderWidth: 0
                }
index 8e6c0aadfaefbefd42626ed988f9d77a753bac93..0b107e40d84909f52dd00b3da9e1dcf0fe64a705 100644 (file)
@@ -1,7 +1,25 @@
 'use strict';
 
+var defaults = require('../core/core.defaults');
 var helpers = require('./helpers.core');
 
+/**
+ * Converts the given font object into a CSS font string.
+ * @param {Object} font - A font object.
+ * @return {Stringg} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
+ * @private
+ */
+function toFontString(font) {
+       if (!font || helpers.isNullOrUndef(font.size) || helpers.isNullOrUndef(font.family)) {
+               return null;
+       }
+
+       return (font.style ? font.style + ' ' : '')
+               + (font.weight ? font.weight + ' ' : '')
+               + font.size + 'px '
+               + font.family;
+}
+
 /**
  * @alias Chart.helpers.options
  * @namespace
@@ -65,6 +83,30 @@ module.exports = {
                };
        },
 
+       /**
+        * Parses font options and returns the font object.
+        * @param {Object} options - A object that contains font opttons to be parsed.
+        * @return {Object} The font object.
+        * @todo Support font.* options and renamed to toFont().
+        * @private
+        */
+       _parseFont: function(options) {
+               var valueOrDefault = helpers.valueOrDefault;
+               var globalDefaults = defaults.global;
+               var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
+               var font = {
+                       family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),
+                       lineHeight: helpers.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),
+                       size: size,
+                       style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),
+                       weight: null,
+                       string: ''
+               };
+
+               font.string = toFontString(font);
+               return font;
+       },
+
        /**
         * Evaluates the given `inputs` sequentially and returns the first defined value.
         * @param {Array[]} inputs - An array of values, falling back to the last value.
index 8e6b75f65fe01835d5a3ad9e76336ea506c8364b..f11b823ea585c85adc048141af8e528df5a9cd8c 100644 (file)
@@ -211,12 +211,8 @@ var Legend = Element.extend({
 
                var ctx = me.ctx;
 
-               var globalDefault = defaults.global;
-               var valueOrDefault = helpers.valueOrDefault;
-               var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
-               var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
-               var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
-               var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+               var labelFont = helpers.options._parseFont(labelOpts);
+               var fontSize = labelFont.size;
 
                // Reset hit boxes
                var hitboxes = me.legendHitBoxes = [];
@@ -234,7 +230,7 @@ var Legend = Element.extend({
 
                // Increase sizes here
                if (display) {
-                       ctx.font = labelFont;
+                       ctx.font = labelFont.string;
 
                        if (isHorizontal) {
                                // Labels
@@ -323,19 +319,18 @@ var Legend = Element.extend({
                var me = this;
                var opts = me.options;
                var labelOpts = opts.labels;
-               var globalDefault = defaults.global;
-               var lineDefault = globalDefault.elements.line;
+               var globalDefaults = defaults.global;
+               var defaultColor = globalDefaults.defaultColor;
+               var lineDefault = globalDefaults.elements.line;
                var legendWidth = me.width;
                var lineWidths = me.lineWidths;
 
                if (opts.display) {
                        var ctx = me.ctx;
                        var valueOrDefault = helpers.valueOrDefault;
-                       var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
-                       var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
-                       var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
-                       var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
-                       var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+                       var fontColor = valueOrDefault(labelOpts.fontColor, globalDefaults.defaultFontColor);
+                       var labelFont = helpers.options._parseFont(labelOpts);
+                       var fontSize = labelFont.size;
                        var cursor;
 
                        // Canvas setup
@@ -344,7 +339,7 @@ var Legend = Element.extend({
                        ctx.lineWidth = 0.5;
                        ctx.strokeStyle = fontColor; // for strikethrough effect
                        ctx.fillStyle = fontColor; // render in correct colour
-                       ctx.font = labelFont;
+                       ctx.font = labelFont.string;
 
                        var boxWidth = getBoxWidth(labelOpts, fontSize);
                        var hitboxes = me.legendHitBoxes;
@@ -358,13 +353,13 @@ var Legend = Element.extend({
                                // Set the ctx for the box
                                ctx.save();
 
-                               ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
+                               var lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
+                               ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
                                ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
                                ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
                                ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
-                               ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
-                               ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
-                               var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
+                               ctx.lineWidth = lineWidth;
+                               ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
 
                                if (ctx.setLineDash) {
                                        // IE 9 and 10 do not support line dash
@@ -383,7 +378,7 @@ var Legend = Element.extend({
                                        helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
                                } else {
                                        // Draw box as legend symbol
-                                       if (!isLineWidthZero) {
+                                       if (lineWidth !== 0) {
                                                ctx.strokeRect(x, y, boxWidth, fontSize);
                                        }
                                        ctx.fillRect(x, y, boxWidth, fontSize);
index 47588844d4c644137e1fb9068c5294a390f9bdf8..eb09aa0e2030df875ca64c3c433a38be82634789 100644 (file)
@@ -12,7 +12,6 @@ defaults._set('global', {
                display: false,
                fontStyle: 'bold',
                fullWidth: true,
-               lineHeight: 1.2,
                padding: 10,
                position: 'top',
                text: '',
@@ -111,14 +110,12 @@ var Title = Element.extend({
        beforeFit: noop,
        fit: function() {
                var me = this;
-               var valueOrDefault = helpers.valueOrDefault;
                var opts = me.options;
                var display = opts.display;
-               var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize);
                var minSize = me.minSize;
                var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1;
-               var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
-               var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
+               var fontOpts = helpers.options._parseFont(opts);
+               var textSize = display ? (lineCount * fontOpts.lineHeight) + (opts.padding * 2) : 0;
 
                if (me.isHorizontal()) {
                        minSize.width = me.maxWidth; // fill all the width
@@ -146,14 +143,10 @@ var Title = Element.extend({
                var ctx = me.ctx;
                var valueOrDefault = helpers.valueOrDefault;
                var opts = me.options;
-               var globalDefaults = defaults.global;
 
                if (opts.display) {
-                       var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
-                       var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
-                       var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
-                       var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
-                       var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
+                       var fontOpts = helpers.options._parseFont(opts);
+                       var lineHeight = fontOpts.lineHeight;
                        var offset = lineHeight / 2 + opts.padding;
                        var rotation = 0;
                        var top = me.top;
@@ -162,8 +155,8 @@ var Title = Element.extend({
                        var right = me.right;
                        var maxWidth, titleX, titleY;
 
-                       ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
-                       ctx.font = titleFont;
+                       ctx.fillStyle = valueOrDefault(opts.fontColor, defaults.global.defaultFontColor); // render in correct colour
+                       ctx.font = fontOpts.string;
 
                        // Horizontal
                        if (me.isHorizontal()) {
index 4a76a773c40956d30d4cb3e7053b1be8079255a7..f0c38317e8ad5d1b0ac3b94b179b5488ff3e1e02 100644 (file)
@@ -7,8 +7,6 @@ var Ticks = require('../core/core.ticks');
 
 module.exports = function(Chart) {
 
-       var globalDefaults = defaults.global;
-
        var defaultConfig = {
                display: true,
 
@@ -64,42 +62,26 @@ module.exports = function(Chart) {
                return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
        }
 
-       function getPointLabelFontOptions(scale) {
-               var pointLabelOptions = scale.options.pointLabels;
-               var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
-               var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
-               var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
-               var font = helpers.fontString(fontSize, fontStyle, fontFamily);
-
-               return {
-                       size: fontSize,
-                       style: fontStyle,
-                       family: fontFamily,
-                       font: font
-               };
-       }
-
-       function getTickFontSize(scale) {
-               var opts = scale.options;
+       function getTickBackdropHeight(opts) {
                var tickOpts = opts.ticks;
 
                if (tickOpts.display && opts.display) {
-                       return helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+                       return helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize) + tickOpts.backdropPaddingY * 2;
                }
                return 0;
        }
 
-       function measureLabelSize(ctx, fontSize, label) {
+       function measureLabelSize(ctx, lineHeight, label) {
                if (helpers.isArray(label)) {
                        return {
                                w: helpers.longestText(ctx, ctx.font, label),
-                               h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
+                               h: label.length * lineHeight
                        };
                }
 
                return {
                        w: ctx.measureText(label).width,
-                       h: fontSize
+                       h: lineHeight
                };
        }
 
@@ -111,14 +93,14 @@ module.exports = function(Chart) {
                        };
                } else if (angle < min || angle > max) {
                        return {
-                               start: pos - size - 5,
+                               start: pos - size,
                                end: pos
                        };
                }
 
                return {
                        start: pos,
-                       end: pos + size + 5
+                       end: pos + size
                };
        }
 
@@ -154,28 +136,26 @@ module.exports = function(Chart) {
                 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
                 */
 
-               var plFont = getPointLabelFontOptions(scale);
-               var paddingTop = getTickFontSize(scale) / 2;
+               var plFont = helpers.options._parseFont(scale.options.pointLabels);
 
                // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
                // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
-               var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
                var furthestLimits = {
-                       r: scale.width,
                        l: 0,
-                       t: scale.height,
-                       b: 0
+                       r: scale.width,
+                       t: 0,
+                       b: scale.height
                };
                var furthestAngles = {};
                var i, textSize, pointPosition;
 
-               scale.ctx.font = plFont.font;
+               scale.ctx.font = plFont.string;
                scale._pointLabelSizes = [];
 
                var valueCount = getValueCount(scale);
                for (i = 0; i < valueCount; i++) {
-                       pointPosition = scale.getPointPosition(i, largestPossibleRadius);
-                       textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
+                       pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
+                       textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i] || '');
                        scale._pointLabelSizes[i] = textSize;
 
                        // Add quarter circle to make degree 0 mean top of circle
@@ -205,22 +185,7 @@ module.exports = function(Chart) {
                        }
                }
 
-               if (paddingTop && -paddingTop < furthestLimits.t) {
-                       furthestLimits.t = -paddingTop;
-                       furthestAngles.t = 0;
-               }
-
-               scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
-       }
-
-       /**
-        * Helper function to fit a radial linear scale with no point labels
-        */
-       function fit(scale) {
-               var paddingTop = getTickFontSize(scale) / 2;
-               var largestPossibleRadius = Math.min((scale.height - paddingTop) / 2, scale.width / 2);
-               scale.drawingArea = Math.floor(largestPossibleRadius);
-               scale.setCenterPoint(0, 0, paddingTop, 0);
+               scale.setReductions(scale.drawingArea, furthestLimits, furthestAngles);
        }
 
        function getTextAlignForAngle(angle) {
@@ -233,17 +198,17 @@ module.exports = function(Chart) {
                return 'right';
        }
 
-       function fillText(ctx, text, position, fontSize) {
-               if (helpers.isArray(text)) {
-                       var y = position.y;
-                       var spacing = 1.5 * fontSize;
+       function fillText(ctx, text, position, lineHeight) {
+               var y = position.y + lineHeight / 2;
+               var i, ilen;
 
-                       for (var i = 0; i < text.length; ++i) {
+               if (helpers.isArray(text)) {
+                       for (i = 0, ilen = text.length; i < ilen; ++i) {
                                ctx.fillText(text[i], position.x, y);
-                               y += spacing;
+                               y += lineHeight;
                        }
                } else {
-                       ctx.fillText(text, position.x, position.y);
+                       ctx.fillText(text, position.x, y);
                }
        }
 
@@ -263,6 +228,7 @@ module.exports = function(Chart) {
                var pointLabelOpts = opts.pointLabels;
                var lineWidth = helpers.valueOrDefault(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
                var lineColor = helpers.valueOrDefault(angleLineOpts.color, gridLineOpts.color);
+               var tickBackdropHeight = getTickBackdropHeight(opts);
 
                ctx.save();
                ctx.lineWidth = lineWidth;
@@ -275,10 +241,10 @@ module.exports = function(Chart) {
                var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
 
                // Point Label Font
-               var plFont = getPointLabelFontOptions(scale);
+               var plFont = helpers.options._parseFont(pointLabelOpts);
 
-               ctx.font = plFont.font;
-               ctx.textBaseline = 'top';
+               ctx.font = plFont.string;
+               ctx.textBaseline = 'middle';
 
                for (var i = getValueCount(scale) - 1; i >= 0; i--) {
                        if (angleLineOpts.display && lineWidth && lineColor) {
@@ -290,18 +256,19 @@ module.exports = function(Chart) {
                        }
 
                        if (pointLabelOpts.display) {
-                               // Extra 3px out for some label spacing
-                               var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
+                               // Extra pixels out for some label spacing
+                               var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
+                               var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
 
                                // Keep this in loop since we may support array properties here
-                               var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor);
+                               var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, defaults.global.defaultFontColor);
                                ctx.fillStyle = pointLabelFontColor;
 
                                var angleRadians = scale.getIndexAngle(i);
                                var angle = helpers.toDegrees(angleRadians);
                                ctx.textAlign = getTextAlignForAngle(angle);
                                adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
-                               fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
+                               fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.lineHeight);
                        }
                }
                ctx.restore();
@@ -353,17 +320,14 @@ module.exports = function(Chart) {
        var LinearRadialScale = Chart.LinearScaleBase.extend({
                setDimensions: function() {
                        var me = this;
-                       var opts = me.options;
-                       var tickOpts = opts.ticks;
+
                        // Set the unconstrained dimension before label rotation
                        me.width = me.maxWidth;
                        me.height = me.maxHeight;
+                       me.paddingTop = getTickBackdropHeight(me.options) / 2;
                        me.xCenter = Math.floor(me.width / 2);
-                       me.yCenter = Math.floor(me.height / 2);
-
-                       var minSize = helpers.min([me.height, me.width]);
-                       var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
-                       me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
+                       me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
+                       me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
                },
                determineDataLimits: function() {
                        var me = this;
@@ -394,9 +358,10 @@ module.exports = function(Chart) {
                        me.handleTickRangeOptions();
                },
                getTickLimit: function() {
-                       var tickOpts = this.options.ticks;
-                       var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
-                       return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
+                       var opts = this.options;
+                       var tickOpts = opts.ticks;
+                       var tickBackdropHeight = getTickBackdropHeight(opts);
+                       return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / tickBackdropHeight));
                },
                convertTicksToLabels: function() {
                        var me = this;
@@ -410,10 +375,13 @@ module.exports = function(Chart) {
                        return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
                },
                fit: function() {
-                       if (this.options.pointLabels.display) {
-                               fitWithPointLabels(this);
+                       var me = this;
+                       var opts = me.options;
+
+                       if (opts.display && opts.pointLabels.display) {
+                               fitWithPointLabels(me);
                        } else {
-                               fit(this);
+                               me.setCenterPoint(0, 0, 0, 0);
                        }
                },
                /**
@@ -425,7 +393,7 @@ module.exports = function(Chart) {
                        var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
                        var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
                        var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
-                       var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
+                       var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
 
                        radiusReductionLeft = numberOrZero(radiusReductionLeft);
                        radiusReductionRight = numberOrZero(radiusReductionRight);
@@ -442,10 +410,10 @@ module.exports = function(Chart) {
                        var maxRight = me.width - rightMovement - me.drawingArea;
                        var maxLeft = leftMovement + me.drawingArea;
                        var maxTop = topMovement + me.drawingArea;
-                       var maxBottom = me.height - bottomMovement - me.drawingArea;
+                       var maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
 
                        me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
-                       me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top);
+                       me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
                },
 
                getIndexAngle: function(index) {
@@ -507,12 +475,7 @@ module.exports = function(Chart) {
                        if (opts.display) {
                                var ctx = me.ctx;
                                var startAngle = this.getIndexAngle(0);
-
-                               // Tick Font
-                               var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
-                               var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
-                               var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
-                               var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
+                               var tickFont = helpers.options._parseFont(tickOpts);
 
                                if (opts.angleLines.display || opts.pointLabels.display) {
                                        drawPointLabels(me);
@@ -529,8 +492,8 @@ module.exports = function(Chart) {
                                                }
 
                                                if (tickOpts.display) {
-                                                       var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
-                                                       ctx.font = tickLabelFont;
+                                                       var tickFontColor = valueOrDefault(tickOpts.fontColor, defaults.global.defaultFontColor);
+                                                       ctx.font = tickFont.string;
 
                                                        ctx.save();
                                                        ctx.translate(me.xCenter, me.yCenter);
@@ -541,9 +504,9 @@ module.exports = function(Chart) {
                                                                ctx.fillStyle = tickOpts.backdropColor;
                                                                ctx.fillRect(
                                                                        -labelWidth / 2 - tickOpts.backdropPaddingX,
-                                                                       -yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
+                                                                       -yCenterOffset - tickFont.size / 2 - tickOpts.backdropPaddingY,
                                                                        labelWidth + tickOpts.backdropPaddingX * 2,
-                                                                       tickFontSize + tickOpts.backdropPaddingY * 2
+                                                                       tickFont.size + tickOpts.backdropPaddingY * 2
                                                                );
                                                        }
 
index c64bf330755377abdca1aac7fc18d0c94a5269fa..723fdb826472b2dbc18f6de68d96c2a8e9dd7a7c 100644 (file)
Binary files a/test/fixtures/controller.radar/point-style.png and b/test/fixtures/controller.radar/point-style.png differ
index 5896239e98686b193446f4c036873ce533d95e44..bff65ad3c309f813325eae06c3a5d2202d1da717 100644 (file)
Binary files a/test/fixtures/plugin.filler/fill-radar-boundary-origin-spline.png and b/test/fixtures/plugin.filler/fill-radar-boundary-origin-spline.png differ
index 66c6e563a796d1c50039329dafff1e339a841f53..82b1f60478d1e0f83d5900986b43d400d906a1d9 100644 (file)
Binary files a/test/fixtures/plugin.filler/fill-radar-boundary-origin.png and b/test/fixtures/plugin.filler/fill-radar-boundary-origin.png differ
index a013274bb78eefed358d3dcce012221e77d0c897..a911f93020e6d2b53478c402a6ce53ae77e675be 100644 (file)
@@ -131,10 +131,10 @@ describe('Chart.controllers.radar', function() {
                }));
 
                [
-                       {x: 256, y: 256, cppx: 256, cppy: 256, cpnx: 256, cpny: 256},
-                       {x: 256, y: 256, cppx: 256, cppy: 256, cpnx: 256, cpny: 256},
-                       {x: 256, y: 256, cppx: 256, cppy: 256, cpnx: 256, cpny: 256},
-                       {x: 256, y: 256, cppx: 256, cppy: 256, cpnx: 256, cpny: 256},
+                       {x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
+                       {x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
+                       {x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
+                       {x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
                ].forEach(function(expected, i) {
                        expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
                        expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
@@ -158,10 +158,10 @@ describe('Chart.controllers.radar', function() {
                meta.controller.update();
 
                [
-                       {x: 256, y: 117, cppx: 246, cppy: 117, cpnx: 272, cpny: 117},
-                       {x: 464, y: 256, cppx: 464, cppy: 248, cpnx: 464, cpny: 262},
-                       {x: 256, y: 256, cppx: 277, cppy: 256, cpnx: 250, cpny: 256},
-                       {x: 200, y: 256, cppx: 200, cppy: 259, cpnx: 200, cpny: 245},
+                       {x: 256, y: 120, cppx: 246, cppy: 120, cpnx: 272, cpny: 120},
+                       {x: 464, y: 260, cppx: 464, cppy: 252, cpnx: 464, cpny: 266},
+                       {x: 256, y: 260, cppx: 277, cppy: 260, cpnx: 250, cpny: 260},
+                       {x: 200, y: 260, cppx: 200, cppy: 264, cpnx: 200, cpny: 250},
                ].forEach(function(expected, i) {
                        expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
                        expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
@@ -215,10 +215,10 @@ describe('Chart.controllers.radar', function() {
 
                // Since tension is now 0, we don't care about the control points
                [
-                       {x: 256, y: 117},
-                       {x: 464, y: 256},
-                       {x: 256, y: 256},
-                       {x: 200, y: 256},
+                       {x: 256, y: 120},
+                       {x: 464, y: 260},
+                       {x: 256, y: 260},
+                       {x: 200, y: 260},
                ].forEach(function(expected, i) {
                        expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
                        expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
@@ -274,11 +274,11 @@ describe('Chart.controllers.radar', function() {
                }));
 
                expect(meta.data[0]._model.x).toBeCloseToPixel(256);
-               expect(meta.data[0]._model.y).toBeCloseToPixel(117);
+               expect(meta.data[0]._model.y).toBeCloseToPixel(120);
                expect(meta.data[0]._model.controlPointPreviousX).toBeCloseToPixel(241);
-               expect(meta.data[0]._model.controlPointPreviousY).toBeCloseToPixel(117);
+               expect(meta.data[0]._model.controlPointPreviousY).toBeCloseToPixel(120);
                expect(meta.data[0]._model.controlPointNextX).toBeCloseToPixel(281);
-               expect(meta.data[0]._model.controlPointNextY).toBeCloseToPixel(117);
+               expect(meta.data[0]._model.controlPointNextY).toBeCloseToPixel(120);
                expect(meta.data[0]._model).toEqual(jasmine.objectContaining({
                        radius: 2.2,
                        backgroundColor: 'rgb(0, 1, 3)',
index cf9eb30a22bd75410519647f8b794ad866438c4a..443cceace57d9b7b63c840c414880adf963a89db 100644 (file)
@@ -761,16 +761,16 @@ describe('Chart', function() {
                        // then we will reset and see that they moved
                        expect(meta.data[0]._model.y).toBeCloseToPixel(333);
                        expect(meta.data[1]._model.y).toBeCloseToPixel(183);
-                       expect(meta.data[2]._model.y).toBe(32);
-                       expect(meta.data[3]._model.y).toBe(484);
+                       expect(meta.data[2]._model.y).toBeCloseToPixel(32);
+                       expect(meta.data[3]._model.y).toBeCloseToPixel(482);
 
                        chart.reset();
 
                        // For a line chart, the animation state is the bottom
-                       expect(meta.data[0]._model.y).toBe(484);
-                       expect(meta.data[1]._model.y).toBe(484);
-                       expect(meta.data[2]._model.y).toBe(484);
-                       expect(meta.data[3]._model.y).toBe(484);
+                       expect(meta.data[0]._model.y).toBeCloseToPixel(482);
+                       expect(meta.data[1]._model.y).toBeCloseToPixel(482);
+                       expect(meta.data[2]._model.y).toBeCloseToPixel(482);
+                       expect(meta.data[3]._model.y).toBeCloseToPixel(482);
                });
        });
 
index 93545a21797a1e04980c26090a9d1f7a65d6ce5a..175f47403e27a241bbe8f04cd8931ca85301ceaa 100644 (file)
@@ -9,9 +9,6 @@ describe('Core.scale', function() {
                        // actual label
                        labelString: '',
 
-                       // actual label
-                       lineHeight: 1.2,
-
                        // top/bottom padding
                        padding: {
                                top: 4,
index 3188888cb120901d319c4a7d645a954a2390786b..1afbd59bd45a0c4fdc9796e15f01c267bbe813e6 100644 (file)
@@ -4,122 +4,197 @@ describe('Chart.helpers.options', function() {
        var options = Chart.helpers.options;
 
        describe('toLineHeight', function() {
+               var toLineHeight = options.toLineHeight;
+
                it ('should support keyword values', function() {
-                       expect(options.toLineHeight('normal', 16)).toBe(16 * 1.2);
+                       expect(toLineHeight('normal', 16)).toBe(16 * 1.2);
                });
                it ('should support unitless values', function() {
-                       expect(options.toLineHeight(1.4, 16)).toBe(16 * 1.4);
-                       expect(options.toLineHeight('1.4', 16)).toBe(16 * 1.4);
+                       expect(toLineHeight(1.4, 16)).toBe(16 * 1.4);
+                       expect(toLineHeight('1.4', 16)).toBe(16 * 1.4);
                });
                it ('should support length values', function() {
-                       expect(options.toLineHeight('42px', 16)).toBe(42);
-                       expect(options.toLineHeight('1.4em', 16)).toBe(16 * 1.4);
+                       expect(toLineHeight('42px', 16)).toBe(42);
+                       expect(toLineHeight('1.4em', 16)).toBe(16 * 1.4);
                });
                it ('should support percentage values', function() {
-                       expect(options.toLineHeight('140%', 16)).toBe(16 * 1.4);
+                       expect(toLineHeight('140%', 16)).toBe(16 * 1.4);
                });
                it ('should fallback to default (1.2) for invalid values', function() {
-                       expect(options.toLineHeight(null, 16)).toBe(16 * 1.2);
-                       expect(options.toLineHeight(undefined, 16)).toBe(16 * 1.2);
-                       expect(options.toLineHeight('foobar', 16)).toBe(16 * 1.2);
+                       expect(toLineHeight(null, 16)).toBe(16 * 1.2);
+                       expect(toLineHeight(undefined, 16)).toBe(16 * 1.2);
+                       expect(toLineHeight('foobar', 16)).toBe(16 * 1.2);
                });
        });
 
        describe('toPadding', function() {
+               var toPadding = options.toPadding;
+
                it ('should support number values', function() {
-                       expect(options.toPadding(4)).toEqual(
+                       expect(toPadding(4)).toEqual(
                                {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
-                       expect(options.toPadding(4.5)).toEqual(
+                       expect(toPadding(4.5)).toEqual(
                                {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
                });
                it ('should support string values', function() {
-                       expect(options.toPadding('4')).toEqual(
+                       expect(toPadding('4')).toEqual(
                                {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
-                       expect(options.toPadding('4.5')).toEqual(
+                       expect(toPadding('4.5')).toEqual(
                                {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
                });
                it ('should support object values', function() {
-                       expect(options.toPadding({top: 1, right: 2, bottom: 3, left: 4})).toEqual(
+                       expect(toPadding({top: 1, right: 2, bottom: 3, left: 4})).toEqual(
                                {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
-                       expect(options.toPadding({top: 1.5, right: 2.5, bottom: 3.5, left: 4.5})).toEqual(
+                       expect(toPadding({top: 1.5, right: 2.5, bottom: 3.5, left: 4.5})).toEqual(
                                {top: 1.5, right: 2.5, bottom: 3.5, left: 4.5, height: 5, width: 7});
-                       expect(options.toPadding({top: '1', right: '2', bottom: '3', left: '4'})).toEqual(
+                       expect(toPadding({top: '1', right: '2', bottom: '3', left: '4'})).toEqual(
                                {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
                });
                it ('should fallback to 0 for invalid values', function() {
-                       expect(options.toPadding({top: 'foo', right: 'foo', bottom: 'foo', left: 'foo'})).toEqual(
+                       expect(toPadding({top: 'foo', right: 'foo', bottom: 'foo', left: 'foo'})).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(options.toPadding({top: null, right: null, bottom: null, left: null})).toEqual(
+                       expect(toPadding({top: null, right: null, bottom: null, left: null})).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(options.toPadding({})).toEqual(
+                       expect(toPadding({})).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(options.toPadding('foo')).toEqual(
+                       expect(toPadding('foo')).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(options.toPadding(null)).toEqual(
+                       expect(toPadding(null)).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(options.toPadding(undefined)).toEqual(
+                       expect(toPadding(undefined)).toEqual(
                                {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
                });
        });
 
+       describe('_parseFont', function() {
+               var parseFont = options._parseFont;
+
+               it ('should return a font with default values', function() {
+                       var global = Chart.defaults.global;
+
+                       Chart.defaults.global = {
+                               defaultFontFamily: 'foobar',
+                               defaultFontSize: 42,
+                               defaultFontStyle: 'xxxyyy',
+                               defaultLineHeight: 1.5
+                       };
+
+                       expect(parseFont({})).toEqual({
+                               family: 'foobar',
+                               lineHeight: 63,
+                               size: 42,
+                               string: 'xxxyyy 42px foobar',
+                               style: 'xxxyyy',
+                               weight: null
+                       });
+
+                       Chart.defaults.global = global;
+               });
+               it ('should return a font with given values', function() {
+                       expect(parseFont({
+                               fontFamily: 'bla',
+                               lineHeight: 8,
+                               fontSize: 21,
+                               fontStyle: 'zzz'
+                       })).toEqual({
+                               family: 'bla',
+                               lineHeight: 8 * 21,
+                               size: 21,
+                               string: 'zzz 21px bla',
+                               style: 'zzz',
+                               weight: null
+                       });
+               });
+               it('should return null as a font string if fontSize or fontFamily are missing', function() {
+                       var global = Chart.defaults.global;
+
+                       Chart.defaults.global = {};
+
+                       expect(parseFont({
+                               fontStyle: 'italic',
+                               fontSize: 12
+                       }).string).toBeNull();
+                       expect(parseFont({
+                               fontStyle: 'italic',
+                               fontFamily: 'serif'
+                       }).string).toBeNull();
+
+                       Chart.defaults.global = global;
+               });
+               it('fontStyle should be optional for font strings', function() {
+                       var global = Chart.defaults.global;
+
+                       Chart.defaults.global = {};
+
+                       expect(parseFont({
+                               fontSize: 12,
+                               fontFamily: 'serif'
+                       }).string).toBe('12px serif');
+
+                       Chart.defaults.global = global;
+               });
+       });
+
        describe('resolve', function() {
+               var resolve = options.resolve;
+
                it ('should fallback to the first defined input', function() {
-                       expect(options.resolve([42])).toBe(42);
-                       expect(options.resolve([42, 'foo'])).toBe(42);
-                       expect(options.resolve([undefined, 42, 'foo'])).toBe(42);
-                       expect(options.resolve([42, 'foo', undefined])).toBe(42);
-                       expect(options.resolve([undefined])).toBe(undefined);
+                       expect(resolve([42])).toBe(42);
+                       expect(resolve([42, 'foo'])).toBe(42);
+                       expect(resolve([undefined, 42, 'foo'])).toBe(42);
+                       expect(resolve([42, 'foo', undefined])).toBe(42);
+                       expect(resolve([undefined])).toBe(undefined);
                });
                it ('should correctly handle empty values (null, 0, "")', function() {
-                       expect(options.resolve([0, 'foo'])).toBe(0);
-                       expect(options.resolve(['', 'foo'])).toBe('');
-                       expect(options.resolve([null, 'foo'])).toBe(null);
+                       expect(resolve([0, 'foo'])).toBe(0);
+                       expect(resolve(['', 'foo'])).toBe('');
+                       expect(resolve([null, 'foo'])).toBe(null);
                });
                it ('should support indexable options if index is provided', function() {
                        var input = [42, 'foo', 'bar'];
-                       expect(options.resolve([input], undefined, 0)).toBe(42);
-                       expect(options.resolve([input], undefined, 1)).toBe('foo');
-                       expect(options.resolve([input], undefined, 2)).toBe('bar');
+                       expect(resolve([input], undefined, 0)).toBe(42);
+                       expect(resolve([input], undefined, 1)).toBe('foo');
+                       expect(resolve([input], undefined, 2)).toBe('bar');
                });
                it ('should fallback if an indexable option value is undefined', function() {
                        var input = [42, undefined, 'bar'];
-                       expect(options.resolve([input], undefined, 5)).toBe(undefined);
-                       expect(options.resolve([input, 'foo'], undefined, 1)).toBe('foo');
-                       expect(options.resolve([input, 'foo'], undefined, 5)).toBe('foo');
+                       expect(resolve([input], undefined, 5)).toBe(undefined);
+                       expect(resolve([input, 'foo'], undefined, 1)).toBe('foo');
+                       expect(resolve([input, 'foo'], undefined, 5)).toBe('foo');
                });
                it ('should not handle indexable options if index is undefined', function() {
                        var array = [42, 'foo', 'bar'];
-                       expect(options.resolve([array])).toBe(array);
-                       expect(options.resolve([array], undefined, undefined)).toBe(array);
+                       expect(resolve([array])).toBe(array);
+                       expect(resolve([array], undefined, undefined)).toBe(array);
                });
                it ('should support scriptable options if context is provided', function() {
                        var input = function(context) {
                                return context.v * 2;
                        };
-                       expect(options.resolve([42], {v: 42})).toBe(42);
-                       expect(options.resolve([input], {v: 42})).toBe(84);
+                       expect(resolve([42], {v: 42})).toBe(42);
+                       expect(resolve([input], {v: 42})).toBe(84);
                });
                it ('should fallback if a scriptable option returns undefined', function() {
                        var input = function() {};
-                       expect(options.resolve([input], {v: 42})).toBe(undefined);
-                       expect(options.resolve([input, 'foo'], {v: 42})).toBe('foo');
-                       expect(options.resolve([input, undefined, 'foo'], {v: 42})).toBe('foo');
+                       expect(resolve([input], {v: 42})).toBe(undefined);
+                       expect(resolve([input, 'foo'], {v: 42})).toBe('foo');
+                       expect(resolve([input, undefined, 'foo'], {v: 42})).toBe('foo');
                });
                it ('should not handle scriptable options if context is undefined', function() {
                        var input = function(context) {
                                return context.v * 2;
                        };
-                       expect(options.resolve([input])).toBe(input);
-                       expect(options.resolve([input], undefined)).toBe(input);
+                       expect(resolve([input])).toBe(input);
+                       expect(resolve([input], undefined)).toBe(input);
                });
                it ('should handle scriptable and indexable option', function() {
                        var input = function(context) {
                                return [context.v, undefined, 'bar'];
                        };
-                       expect(options.resolve([input, 'foo'], {v: 42}, 0)).toBe(42);
-                       expect(options.resolve([input, 'foo'], {v: 42}, 1)).toBe('foo');
-                       expect(options.resolve([input, 'foo'], {v: 42}, 5)).toBe('foo');
-                       expect(options.resolve([input, ['foo', 'bar']], {v: 42}, 1)).toBe('bar');
+                       expect(resolve([input, 'foo'], {v: 42}, 0)).toBe(42);
+                       expect(resolve([input, 'foo'], {v: 42}, 1)).toBe('foo');
+                       expect(resolve([input, 'foo'], {v: 42}, 5)).toBe('foo');
+                       expect(resolve([input, ['foo', 'bar']], {v: 42}, 1)).toBe('bar');
                });
        });
 });
index 451f7400d5de7c86cab1c5ec284be72dcab3d5ee..fee715bdb1383341c4bc07d52dca4ce0b9f31fa7 100644 (file)
@@ -494,7 +494,7 @@ describe('Legend block tests', function() {
                expect(chart.legend.left).toBeCloseToPixel(0);
                expect(chart.legend.top).toBeCloseToPixel(6);
                expect(chart.legend.width).toBeCloseToPixel(128);
-               expect(chart.legend.height).toBeCloseToPixel(478);
+               expect(chart.legend.height).toBeCloseToPixel(476);
                expect(chart.legend.legendHitBoxes.length).toBe(22);
 
                [
index 28786f05402a125ad7a4bb9f58a8843e47c726b0..4f00ee8925b8f88923703d518c2bcf78cbf104ca 100644 (file)
@@ -8,7 +8,6 @@ describe('Title block tests', function() {
                        fullWidth: true,
                        weight: 2000,
                        fontStyle: 'bold',
-                       lineHeight: 1.2,
                        padding: 10,
                        text: ''
                });
index 0ce39e5b33c3edac00467bca37a20cd493c250d1..7bc6a8a57ad37c92dd85977efd991a89b96d5df0 100644 (file)
@@ -340,8 +340,8 @@ describe('Category scale tests', function() {
                expect(yScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(77);
                expect(yScale.getValueForPixel(77)).toBe(0);
 
-               expect(yScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(439);
-               expect(yScale.getValueForPixel(439)).toBe(4);
+               expect(yScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(437);
+               expect(yScale.getValueForPixel(437)).toBe(4);
        });
 
        it ('should get the correct pixel for a value when vertical and zoomed', function() {
@@ -385,6 +385,6 @@ describe('Category scale tests', function() {
                chart.update();
 
                expect(yScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(107);
-               expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(409);
+               expect(yScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(407);
        });
 });
index 9ec21116e88fd4911ccdc0863a86443965f937f5..ad35e2a4347d283d2ca2845429afbdd48eef0ed3 100644 (file)
@@ -817,9 +817,9 @@ describe('Linear Scale', function() {
                expect(yScale.getPixelForValue(-1, 0, 0)).toBeCloseToPixel(484); // left + paddingLeft
                expect(yScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(258); // halfway*/
 
-               expect(yScale.getValueForPixel(32)).toBe(1);
-               expect(yScale.getValueForPixel(484)).toBe(-1);
-               expect(yScale.getValueForPixel(258)).toBe(0);
+               expect(yScale.getValueForPixel(32)).toBeCloseTo(1, 1e-2);
+               expect(yScale.getValueForPixel(484)).toBeCloseTo(-1, 1e-2);
+               expect(yScale.getValueForPixel(258)).toBeCloseTo(0, 1e-2);
        });
 
        it('should fit correctly', function() {
@@ -865,7 +865,7 @@ describe('Linear Scale', function() {
                expect(xScale.paddingLeft).toBeCloseToPixel(0);
                expect(xScale.paddingRight).toBeCloseToPixel(0);
                expect(xScale.width).toBeCloseToPixel(468 - 6); // minus lineSpace
-               expect(xScale.height).toBeCloseToPixel(28);
+               expect(xScale.height).toBeCloseToPixel(30);
 
                var yScale = chart.scales.yScale0;
                expect(yScale.paddingTop).toBeCloseToPixel(0);
@@ -873,7 +873,7 @@ describe('Linear Scale', function() {
                expect(yScale.paddingLeft).toBeCloseToPixel(0);
                expect(yScale.paddingRight).toBeCloseToPixel(0);
                expect(yScale.width).toBeCloseToPixel(30 + 6); // plus lineSpace
-               expect(yScale.height).toBeCloseToPixel(452);
+               expect(yScale.height).toBeCloseToPixel(450);
 
                // Extra size when scale label showing
                xScale.options.scaleLabel.display = true;
@@ -885,14 +885,14 @@ describe('Linear Scale', function() {
                expect(xScale.paddingLeft).toBeCloseToPixel(0);
                expect(xScale.paddingRight).toBeCloseToPixel(0);
                expect(xScale.width).toBeCloseToPixel(440);
-               expect(xScale.height).toBeCloseToPixel(50);
+               expect(xScale.height).toBeCloseToPixel(53);
 
                expect(yScale.paddingTop).toBeCloseToPixel(0);
                expect(yScale.paddingBottom).toBeCloseToPixel(0);
                expect(yScale.paddingLeft).toBeCloseToPixel(0);
                expect(yScale.paddingRight).toBeCloseToPixel(0);
                expect(yScale.width).toBeCloseToPixel(58);
-               expect(yScale.height).toBeCloseToPixel(430);
+               expect(yScale.height).toBeCloseToPixel(427);
        });
 
        it('should fit correctly when display is turned off', function() {
index 5459eac311f24707d25c8b2fccb3bb64b414e8a8..49ef34b46d6117d429836c1d68f0eda48852c6ab 100644 (file)
@@ -349,9 +349,9 @@ describe('Test the radial linear scale', function() {
                        }
                });
 
-               expect(chart.scale.drawingArea).toBe(232);
+               expect(chart.scale.drawingArea).toBe(227);
                expect(chart.scale.xCenter).toBe(256);
-               expect(chart.scale.yCenter).toBe(279);
+               expect(chart.scale.yCenter).toBe(284);
        });
 
        it('should correctly get the label for a given data index', function() {
@@ -397,16 +397,16 @@ describe('Test the radial linear scale', function() {
                });
 
                expect(chart.scale.getDistanceFromCenterForValue(chart.scale.min)).toBe(0);
-               expect(chart.scale.getDistanceFromCenterForValue(chart.scale.max)).toBe(232);
+               expect(chart.scale.getDistanceFromCenterForValue(chart.scale.max)).toBe(227);
 
                var position = chart.scale.getPointPositionForValue(1, 5);
                expect(position.x).toBeCloseToPixel(270);
-               expect(position.y).toBeCloseToPixel(275);
+               expect(position.y).toBeCloseToPixel(278);
 
                chart.scale.options.ticks.reverse = true;
                chart.update();
 
-               expect(chart.scale.getDistanceFromCenterForValue(chart.scale.min)).toBe(232);
+               expect(chart.scale.getDistanceFromCenterForValue(chart.scale.min)).toBe(227);
                expect(chart.scale.getDistanceFromCenterForValue(chart.scale.max)).toBe(0);
        });