From 028840c837a8d5e347457ef4ea77727fd086ba0a Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Fri, 12 Jan 2018 00:55:51 +0100 Subject: [PATCH] Move utility methods in src/utils.js --- src/plugin.js | 81 ++---------------------------- src/utils.js | 82 ++++++++++++++++++++++++++++++ test/specs/utils.spec.js | 105 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 77 deletions(-) create mode 100644 src/utils.js create mode 100644 test/specs/utils.spec.js diff --git a/src/plugin.js b/src/plugin.js index c14b6a7..70a65ae 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -5,6 +5,7 @@ 'use strict'; import Chart from 'chart.js'; +import utils from './utils.js'; import defaults from './defaults.js'; import positioners from './positioners.js'; @@ -13,79 +14,6 @@ Chart.defaults.global.plugins.datalabels = defaults; var helpers = Chart.helpers; var MODEL_KEY = '$datalabels'; -// @todo move this in Chart.helpers.toTextLines -function toTextLines(inputs) { - var lines = []; - var input; - - inputs = [].concat(inputs); - while (inputs.length) { - input = inputs.pop(); - if (typeof input === 'string') { - lines.unshift.apply(lines, input.split('\n')); - } else if (Array.isArray(input)) { - inputs.push.apply(inputs, input); - } else if (!helpers.isNullOrUndef(inputs)) { - lines.unshift('' + input); - } - } - - return lines; -} - -// @todo move this method in Chart.helpers.canvas.toFont (deprecates helpers.fontString) -// @see https://developer.mozilla.org/en-US/docs/Web/CSS/font -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; -} - -// @todo move this in Chart.helpers.canvas.textSize -// @todo cache calls of measureText if font doesn't change?! -function textSize(ctx, lines, font) { - var items = [].concat(lines); - var ilen = items.length; - var prev = ctx.font; - var width = 0; - var i; - - ctx.font = font.string; - - for (i = 0; i < ilen; ++i) { - width = Math.max(ctx.measureText(items[i]).width, width); - } - - ctx.font = prev; - - return { - height: ilen * font.lineHeight, - width: width - }; -} - -// @todo move this method in Chart.helpers.options.toFont -function parseFont(value) { - var global = Chart.defaults.global; - var size = helpers.valueOrDefault(value.size, global.defaultFontSize); - var font = { - family: helpers.valueOrDefault(value.family, global.defaultFontFamily), - lineHeight: helpers.options.toLineHeight(value.lineHeight, size), - size: size, - style: helpers.valueOrDefault(value.style, global.defaultFontStyle), - weight: helpers.valueOrDefault(value.weight, null), - string: '' - }; - - font.string = toFontString(font); - return font; -} - function coordinates(el, model, rect) { var point = model.positioner(el._view, model.anchor, model.align, model.origin); var vx = point.vx; @@ -96,7 +24,6 @@ function coordinates(el, model, rect) { return {x: point.x, y: point.y}; } - // include borders to the bounding rect var borderWidth = model.borderWidth || 0; var w = (rect.w + borderWidth * 2); @@ -255,12 +182,12 @@ function modelize(el, index, ctx, config, context) { var value = context.dataset.data[index]; var label = helpers.valueOrDefault(helpers.callback(config.formatter, [value, context]), value); - var lines = helpers.isNullOrUndef(label) ? [] : toTextLines(label); + var lines = helpers.isNullOrUndef(label) ? [] : utils.toTextLines(label); if (!lines.length) { return null; } - var font = parseFont(resolve([config.font, {}], context, index)); + var font = utils.parseFont(resolve([config.font, {}], context, index)); var model = { align: resolve([config.align, 'center'], context, index), anchor: resolve([config.anchor, 'center'], context, index), @@ -277,7 +204,7 @@ function modelize(el, index, ctx, config, context) { textAlign: resolve([config.textAlign, 'start'], context, index), origin: getScaleOrigin(el), positioner: getPositioner(el), - size: textSize(ctx, lines, font) + size: utils.textSize(ctx, lines, font) }; return model; diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..e89d00a --- /dev/null +++ b/src/utils.js @@ -0,0 +1,82 @@ +'use strict'; + +import Chart from 'chart.js'; + +var helpers = Chart.helpers; + +var utils = { + // @todo move this in Chart.helpers.toTextLines + toTextLines: function(inputs) { + var lines = []; + var input; + + inputs = [].concat(inputs); + while (inputs.length) { + input = inputs.pop(); + if (typeof input === 'string') { + lines.unshift.apply(lines, input.split('\n')); + } else if (Array.isArray(input)) { + inputs.push.apply(inputs, input); + } else if (!helpers.isNullOrUndef(inputs)) { + lines.unshift('' + input); + } + } + + return lines; + }, + + // @todo move this method in Chart.helpers.canvas.toFont (deprecates helpers.fontString) + // @see https://developer.mozilla.org/en-US/docs/Web/CSS/font + toFontString: function(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; + }, + + // @todo move this in Chart.helpers.canvas.textSize + // @todo cache calls of measureText if font doesn't change?! + textSize: function(ctx, lines, font) { + var items = [].concat(lines); + var ilen = items.length; + var prev = ctx.font; + var width = 0; + var i; + + ctx.font = font.string; + + for (i = 0; i < ilen; ++i) { + width = Math.max(ctx.measureText(items[i]).width, width); + } + + ctx.font = prev; + + return { + height: ilen * font.lineHeight, + width: width + }; + }, + + // @todo move this method in Chart.helpers.options.toFont + parseFont: function(value) { + var global = Chart.defaults.global; + var size = helpers.valueOrDefault(value.size, global.defaultFontSize); + var font = { + family: helpers.valueOrDefault(value.family, global.defaultFontFamily), + lineHeight: helpers.options.toLineHeight(value.lineHeight, size), + size: size, + style: helpers.valueOrDefault(value.style, global.defaultFontStyle), + weight: helpers.valueOrDefault(value.weight, null), + string: '' + }; + + font.string = utils.toFontString(font); + return font; + } +}; + +export default utils; diff --git a/test/specs/utils.spec.js b/test/specs/utils.spec.js new file mode 100644 index 0000000..c0beb0a --- /dev/null +++ b/test/specs/utils.spec.js @@ -0,0 +1,105 @@ +import Chart from 'chart.js'; +import utils from '../../src/utils'; + +describe('utils.js', function() { + describe('toTextLines', function() { + var toTextLines = utils.toTextLines; + + it('should return an array containing the input string', function() { + expect(toTextLines('')).toEqual(['']); + expect(toTextLines('foo')).toEqual(['foo']); + expect(toTextLines('foo bar')).toEqual(['foo bar']); + }); + it('should return an array with converted values', function() { + expect(toTextLines(null)).toEqual(['null']); + expect(toTextLines(undefined)).toEqual(['undefined']); + expect(toTextLines(42)).toEqual(['42']); + expect(toTextLines(true)).toEqual(['true']); + }); + it('should return an array of strings if inputs is an array', function() { + expect(toTextLines([])).toEqual([]); + expect(toTextLines(['foo'])).toEqual(['foo']); + expect(toTextLines(['foo', 'bar'])).toEqual(['foo', 'bar']); + }); + it('should split the input string if it contains \\n', function() { + expect(toTextLines('foo\nbar')).toEqual(['foo', 'bar']); + expect(toTextLines('foo\nbar\nbla')).toEqual(['foo', 'bar', 'bla']); + }); + it('should preserve spaces when splitting strings', function() { + expect(toTextLines('foo \n bar')).toEqual(['foo ', ' bar']); + expect(toTextLines('foo \n bar \n bla')).toEqual(['foo ', ' bar ', ' bla']); + }); + it('should flatten children arrays in the correct order', function() { + expect(toTextLines(['foo', [['bar', 'xxx'], 'bla']])).toEqual(['foo', 'bar', 'xxx', 'bla']); + }); + it('should split strings children in the correct order', function() { + expect(toTextLines(['foo', [['bar\nxxx'], 'bla\nyyy']])).toEqual(['foo', 'bar', 'xxx', 'bla', 'yyy']); + }); + }); + + describe('toFontString', function() { + var toFontString = utils.toFontString; + + it('should return null if the given font is invalid', function() { + expect(toFontString({})).toBeNull(); + expect(toFontString(null)).toBeNull(); + expect(toFontString(undefined)).toBeNull(); + expect(toFontString(42)).toBeNull(); + expect(toFontString('foo')).toBeNull(); + expect(toFontString(new Date())).toBeNull(); + }); + it('should return null if size or family are missing', function() { + expect(toFontString({style: 'italic', weight: 300, size: 12})).toBeNull(); + expect(toFontString({style: 'italic', weight: 300, family: 'serif'})).toBeNull(); + }); + it('should return the string representation of the given font', function() { + expect(toFontString({style: 'italic', weight: 300, size: 12, family: 'serif'})).toBe('italic 300 12px serif'); + }); + it('weigth and style should be optional', function() { + expect(toFontString({size: 12, family: 'serif'})).toBe('12px serif'); + expect(toFontString({style: 'italic', size: 12, family: 'serif'})).toBe('italic 12px serif'); + expect(toFontString({weight: 300, size: 12, family: 'serif'})).toBe('300 12px serif'); + }); + }); + + describe('parseFont', function() { + var parseFont = utils.parseFont; + + it ('should return a font with default values', function() { + var global = Chart.defaults.global; + + Chart.defaults.global = { + defaultFontFamily: 'foobar', + defaultFontSize: 42, + defaultFontStyle: 'xxxyyy' + }; + + expect(parseFont({})).toEqual({ + family: 'foobar', + lineHeight: 50.4, + 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({ + family: 'bla', + lineHeight: 8, + size: 21, + style: 'zzz', + weight: 400 + })).toEqual({ + family: 'bla', + lineHeight: 8 * 21, + size: 21, + string: 'zzz 400 21px bla', + style: 'zzz', + weight: 400 + }); + }); + }); +});