diff --git a/__tests__/unit/utils/transform/word-cloud-spec.ts b/__tests__/unit/utils/transform/word-cloud-spec.ts index a1f1a5ddf8..ee0955a2df 100644 --- a/__tests__/unit/utils/transform/word-cloud-spec.ts +++ b/__tests__/unit/utils/transform/word-cloud-spec.ts @@ -1,16 +1,22 @@ import DataSet from '@antv/data-set'; -import { DataItem, wordCloud } from '../../../../src/utils/transform/word-cloud'; +import { DataItem } from '../../../../src/plots/word-cloud/types'; +import { processImageMask } from '../../../../src/plots/word-cloud/utils'; +import { wordCloud, transform } from '../../../../src/utils/transform/word-cloud'; + +type Row = Pick; const { View } = DataSet; const options = { type: 'tag-cloud', fields: ['text', 'value'], + font: 'Impact', fontSize: 10, fontWeight: 'bold', + rotate: 90, + padding: 2, size: [800, 800], - padding: 0, + spiral: 'archimedean', timeInterval: 5000, - rotate: 90, }; const data = ['Hello', 'world', 'normally', 'you', 'want', 'more', 'words', 'than', 'this'].map((d) => { return { @@ -20,6 +26,22 @@ const data = ['Hello', 'world', 'normally', 'you', 'want', 'more', 'words', 'tha }; }); +function basicCommon(v: DataItem) { + expect(v.hasText).toBe(true); + expect(typeof v.text).toBe('string'); + expect(typeof v.value).toBe('number'); + expect(typeof v.font).toBe('string'); + expect(typeof v.style).toBe('string'); + expect(typeof v.weight === 'number' || typeof v.weight === 'string').toBe(true); + expect(typeof v.rotate).toBe('number'); + expect(typeof v.size).toBe('number'); + expect(typeof v.padding).toBe('number'); + expect(typeof v.width).toBe('number'); + expect(typeof v.height).toBe('number'); + expect(typeof v.x).toBe('number'); + expect(typeof v.y).toBe('number'); +} + describe('word-cloud', () => { it('with data-set', () => { const dv = new View(); @@ -41,38 +63,31 @@ describe('word-cloud', () => { it('default', () => { const result = wordCloud(data); - const firstRow = result[0]; - - expect(firstRow.hasText).toBe(true); - expect(typeof firstRow.x).toBe('number'); - expect(typeof firstRow.y).toBe('number'); - expect(typeof firstRow.text).toBe('string'); - expect(typeof firstRow.size).toBe('number'); - expect(typeof firstRow.font).toBe('string'); + basicCommon(result[0]); }); it('callback', () => { - const common = (row: DataItem) => { + const common = (row: Row) => { expect(typeof row.text).toBe('string'); expect(typeof row.value).toBe('number'); }; - const font = (row: DataItem) => { + const font = (row: Row) => { common(row); return 'font-test'; }; - const fontWeight = (row: DataItem): any => { + const fontWeight = (row: Row): any => { common(row); return 'fontWeight-test'; }; - const fontSize = (row: DataItem) => { + const fontSize = (row: Row) => { common(row); return 11; }; - const rotate = (row: DataItem) => { + const rotate = (row: Row) => { common(row); return 22; }; - const padding = (row: DataItem) => { + const padding = (row: Row) => { common(row); return 33; }; @@ -94,14 +109,105 @@ describe('word-cloud', () => { spiral, }); const firstRow = result[0]; - expect(firstRow.hasText).toBe(true); - expect(typeof firstRow.x).toBe('number'); - expect(typeof firstRow.y).toBe('number'); - expect(typeof firstRow.text).toBe('string'); + basicCommon(firstRow); expect(firstRow.font).toBe('font-test'); expect(firstRow.weight).toBe('fontWeight-test'); expect(firstRow.size).toBe(11); expect(firstRow.rotate).toBe(22); expect(firstRow.padding).toBe(33); }); + + it('data is empty', () => { + const result = wordCloud([]); + expect(result.length).toBe(2); + }); + + it('image mask', async () => { + const base64 = + 'data:image/png;base64,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'; + + const img = await processImageMask(base64); + const result = wordCloud(data, { imageMask: img }); + basicCommon(result[0]); + }); + + it('spiral is rectangular', () => { + const result = wordCloud(data, { spiral: 'rectangular' }); + basicCommon(result[0]); + }); +}); + +describe('transform', () => { + it('default', () => { + const result = transform(data, { + fields: ['text', 'value'], + size: [800, 800], + }); + basicCommon(result[0]); + }); + + it('error of fields', () => { + expect(() => { + transform(data, { + fields: [null, null], + size: [800, 800], + }); + }).toThrow(); + }); + + it('fields is not exit', () => { + const result = transform(data, { + fields: ['a', 'b'], + size: [800, 800], + }); + + expect(result[0].text).toBe(undefined); + expect(result[0].value).toBe(undefined); + }); + + it('image mask with size is 0', async () => { + const base64 = + 'data:image/png;base64,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'; + + const img = await processImageMask(base64); + const result = transform(data, { + fields: ['text', 'value'], + size: [0, 0], + imageMask: img, + }); + + // 画布大小为 0 时,返回的数组应为空数组,但该实现中, + // 最终会往返回的数组中 push 进两个元素,所以最终长度为 2。 + expect(result.length).toBe(2); + }); + + it('timeInterval is 0', () => { + const result = transform(data, { + fields: ['text', 'value'], + size: [800, 800], + timeInterval: 0, + }); + + // 时间间隔为 0 ,也就是说不给程序运行的时间, + // 所以最终返回的是空数据,只包含两个占位符数据。 + expect(result.length).toBe(2); + }); + + it('padding is 0', () => { + const result = transform(data, { + fields: ['text', 'value'], + size: [800, 800], + padding: 0, + }); + basicCommon(result[0]); + }); + + it('rotate is 0', () => { + const result = transform(data, { + fields: ['text', 'value'], + size: [800, 800], + rotate: 0, + }); + basicCommon(result[0]); + }); }); diff --git a/src/plots/word-cloud/shapes/word-cloud.ts b/src/plots/word-cloud/shapes/word-cloud.ts index 501ccfb22d..41ea50a74d 100644 --- a/src/plots/word-cloud/shapes/word-cloud.ts +++ b/src/plots/word-cloud/shapes/word-cloud.ts @@ -18,7 +18,7 @@ registerShape('point', 'word-cloud', { }, }); const rotate = cfg.data.rotate; - if (rotate) { + if (typeof rotate === 'number') { Util.rotate(shape, (rotate * Math.PI) / 180); } @@ -35,7 +35,7 @@ function getTextAttrs(cfg: Config): ShapeAttrs { textAlign: 'center', fontFamily: cfg.data.font, fontWeight: cfg.data.weight, - fill: cfg.color || cfg.defaultStyle?.stroke, + fill: cfg.color, textBaseline: 'alphabetic', }; } diff --git a/src/plots/word-cloud/types.ts b/src/plots/word-cloud/types.ts index aeb9214400..721a85a1ff 100644 --- a/src/plots/word-cloud/types.ts +++ b/src/plots/word-cloud/types.ts @@ -3,11 +3,14 @@ import { Options } from '../../types'; type FontWeight = ShapeAttrs['fontWeight']; -export interface DataItem { +interface Row { /** 文本内容 */ text: string; /** 该文本所占权重 */ value: number; +} + +export type DataItem = Row & { /** 字体 */ font?: string; /** 字体样式 */ @@ -30,21 +33,21 @@ export interface DataItem { x?: number; /** y 轴坐标 */ y?: number; -} +}; /** 词云字体样式 */ interface WordStyle { /** 词云的字体, 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontFamily?: string | ((row: DataItem) => string); + readonly fontFamily?: string | ((row: Row) => string); /** 设置字体的粗细, 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontWeight?: FontWeight | ((row: DataItem) => FontWeight); + readonly fontWeight?: FontWeight | ((row: Row) => FontWeight); /** * 每个单词所占的盒子的内边距,默认为 1。 越大单词之间的间隔越大。 * 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly padding?: number | ((row: DataItem) => number); + readonly padding?: number | ((row: Row) => number); /** 字体的大小范围,当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontSize?: [number, number] | ((row: DataItem) => number); + readonly fontSize?: [number, number] | ((row: Row) => number); /** 旋转的最小角度和最大角度 默认 [0, 90] */ readonly rotation?: [number, number]; /** 旋转实际的步数,越大可能旋转角度越小, 默认是 2 */ diff --git a/src/plots/word-cloud/utils.ts b/src/plots/word-cloud/utils.ts index 28cdf1e8b5..ddd27fd0ef 100644 --- a/src/plots/word-cloud/utils.ts +++ b/src/plots/word-cloud/utils.ts @@ -208,10 +208,6 @@ function resolveRotate(options: WordCloudOptions) { * @param numbers */ function min(numbers: number[]) { - if (numbers.length === 0) { - throw new Error('min requires at least one data point'); - } - return Math.min(...numbers); } @@ -221,9 +217,5 @@ function min(numbers: number[]) { * @param numbers */ function max(numbers: number[]) { - if (numbers.length === 0) { - throw new Error('min requires at least one data point'); - } - return Math.max(...numbers); } diff --git a/src/utils/transform/word-cloud.ts b/src/utils/transform/word-cloud.ts index 970983cd48..e755c85147 100644 --- a/src/utils/transform/word-cloud.ts +++ b/src/utils/transform/word-cloud.ts @@ -1,9 +1,10 @@ import { deepMix, assign, isString } from '@antv/util'; +import { DataItem } from '../../plots/word-cloud/types'; import { Data } from '../../types'; type FontWeight = number | 'normal' | 'bold' | 'bolder' | 'lighter'; -export interface DataItem { +interface Row { /** 文本内容 */ text: string; /** 该文本所占权重 */ @@ -11,13 +12,13 @@ export interface DataItem { } export interface Options { - fields?: [string, string]; - font?: string | ((row: DataItem) => string); - fontSize?: number | ((row: DataItem) => number); - fontWeight?: FontWeight | ((row: DataItem) => FontWeight); - rotate?: number | ((row: DataItem) => number); - padding?: number | ((row: DataItem) => number); - size?: [number, number]; + fields: [string, string]; + size: [number, number]; + font?: string | ((row: Row) => string); + fontSize?: number | ((row: Row) => number); + fontWeight?: FontWeight | ((row: Row) => FontWeight); + rotate?: number | ((row: Row) => number); + padding?: number | ((row: Row) => number); spiral?: 'archimedean' | 'rectangular' | ((size: [number, number]) => (t: number) => number[]); timeInterval?: number; imageMask?: HTMLImageElement; @@ -40,19 +41,18 @@ const DEFAULT_OPTIONS: Options = { * 计算后的数据对象 * @param options */ -export function wordCloud(data: Data, options?: Options) { - return transform(data, options); +export function wordCloud(data: Data, options?: Partial) { + // 混入默认配置 + options = assign({} as Options, DEFAULT_OPTIONS, options); + return transform(data, options as Options); } -function transform(data: Data, options?: Options) { +export function transform(data: Data, options: Options) { // 深拷贝 data = deepMix([], data); - options = assign({} as Options, DEFAULT_OPTIONS, options); const layout = tagCloud(); ['font', 'fontSize', 'fontWeight', 'padding', 'rotate', 'size', 'spiral', 'timeInterval'].forEach((key) => { - // @ts-ignore - if (options[key]) { - // @ts-ignore + if (options[key] !== undefined && options[key] !== null) { layout[key](options[key]); } }); @@ -96,7 +96,7 @@ function transform(data: Data, options?: Options) { opacity: 0, }); - return tags; + return tags as DataItem[]; } /* @@ -326,24 +326,20 @@ const spirals = { function tagCloud() { let size = [256, 256], - text = cloudText, font = cloudFont, fontSize = cloudFontSize, - fontStyle = cloudFontNormal, fontWeight = cloudFontNormal, rotate = cloudRotate, padding = cloudPadding, spiral = archimedeanSpiral, words: any = [], - timeInterval = Infinity, - random = Math.random, - canvas = cloudCanvas; + timeInterval = Infinity; + const random = Math.random; + const text = cloudText; + const fontStyle = cloudFontNormal; + const canvas = cloudCanvas; const cloud: any = {}; - cloud.canvas = function (_) { - return arguments.length ? ((canvas = functor(_)), cloud) : canvas; - }; - cloud.start = function () { const [width, height] = size; const contextAndRatio = getContext(canvas()), @@ -502,51 +498,39 @@ function tagCloud() { }; cloud.timeInterval = function (_) { - return arguments.length ? ((timeInterval = _ == null ? Infinity : _), cloud) : timeInterval; + timeInterval = _ == null ? Infinity : _; }; cloud.words = function (_) { - return arguments.length ? ((words = _), cloud) : words; + words = _; }; cloud.size = function (_) { - return arguments.length ? ((size = [+_[0], +_[1]]), cloud) : size; + size = [+_[0], +_[1]]; }; cloud.font = function (_) { - return arguments.length ? ((font = functor(_)), cloud) : font; - }; - - cloud.fontStyle = function (_) { - return arguments.length ? ((fontStyle = functor(_)), cloud) : fontStyle; + font = functor(_); }; cloud.fontWeight = function (_) { - return arguments.length ? ((fontWeight = functor(_)), cloud) : fontWeight; + fontWeight = functor(_); }; cloud.rotate = function (_) { - return arguments.length ? ((rotate = functor(_)), cloud) : rotate; - }; - - cloud.text = function (_) { - return arguments.length ? ((text = functor(_)), cloud) : text; + rotate = functor(_); }; cloud.spiral = function (_) { - return arguments.length ? ((spiral = spirals[_] || _), cloud) : spiral; + spiral = spirals[_] || _; }; cloud.fontSize = function (_) { - return arguments.length ? ((fontSize = functor(_)), cloud) : fontSize; + fontSize = functor(_); }; cloud.padding = function (_) { - return arguments.length ? ((padding = functor(_)), cloud) : padding; - }; - - cloud.random = function (_) { - return arguments.length ? ((random = _), cloud) : random; + padding = functor(_); }; return cloud;