diff --git a/__tests__/bugs/issue-1754-spec.ts b/__tests__/bugs/issue-1754-spec.ts new file mode 100644 index 0000000000..90b887a2cc --- /dev/null +++ b/__tests__/bugs/issue-1754-spec.ts @@ -0,0 +1,35 @@ +import { TooltipCfg } from '@antv/g2/lib/interface'; +import { WordCloud } from '../../src'; +import { CountryEconomy } from '../data/country-economy'; +import { createDiv } from '../utils/dom'; + +describe('issue 1754', () => { + it('customContent', () => { + const cloud = new WordCloud(createDiv(), { + width: 400, + height: 300, + data: CountryEconomy, + wordField: 'Country', + weightField: 'GDP', + }); + + const data = [ + { + data: { text: 'name', value: 'weight' }, + mappingData: { color: 'red' }, + }, + ]; + const result = + '
  • ' + + '' + + '' + + 'name:weight' + + '' + + '
  • '; + + cloud.render(); + + const customContent = (cloud.chart.getOptions().tooltip as TooltipCfg).customContent; + expect(customContent(undefined, data)).toBe(result); + }); +}); diff --git a/__tests__/unit/plots/word-cloud/color-spec.ts b/__tests__/unit/plots/word-cloud/color-spec.ts new file mode 100644 index 0000000000..9a93fa2d7d --- /dev/null +++ b/__tests__/unit/plots/word-cloud/color-spec.ts @@ -0,0 +1,68 @@ +import { WordCloud } from '../../../../src'; +import { CountryEconomy } from '../../../data/country-economy'; +import { createDiv } from '../../../utils/dom'; + +describe('word-cloud color option', () => { + it('default', () => { + const cloud = new WordCloud(createDiv(), { + width: 400, + height: 300, + data: CountryEconomy, + wordField: 'Country', + weightField: 'GDP', + }); + + cloud.render(); + + const fields = cloud.chart.geometries[0].getGroupFields(); + expect(fields.length).toBe(1); + }); + + it('wordField', () => { + const cloud = new WordCloud(createDiv(), { + width: 400, + height: 300, + data: CountryEconomy, + wordField: 'Country', + weightField: 'GDP', + colorField: 'Country', // wordField 字段值 + }); + + cloud.render(); + + const field = cloud.chart.geometries[0].getGroupFields()[0]; + expect(field).toBe('color'); + }); + + it('weightField', () => { + const cloud = new WordCloud(createDiv(), { + width: 400, + height: 300, + data: CountryEconomy, + wordField: 'Country', + weightField: 'GDP', + colorField: 'GDP', // weightField 字段值 + }); + + cloud.render(); + + const field = cloud.chart.geometries[0].getGroupFields()[0]; + expect(field).toBe('color'); + }); + + it('x', () => { + const cloud = new WordCloud(createDiv(), { + width: 400, + height: 300, + data: CountryEconomy, + wordField: 'Country', + weightField: 'GDP', + colorField: 'x', + }); + + cloud.render(); + + const field = cloud.chart.geometries[0].getGroupFields()[0]; + expect(field).toBe('color'); + }); +}); diff --git a/__tests__/unit/plots/word-cloud/style-spec.ts b/__tests__/unit/plots/word-cloud/style-spec.ts index f3693b49f3..a3ee5bd556 100644 --- a/__tests__/unit/plots/word-cloud/style-spec.ts +++ b/__tests__/unit/plots/word-cloud/style-spec.ts @@ -1,7 +1,7 @@ import { WordCloud } from '../../../../src'; import { CountryEconomy } from '../../../data/country-economy'; import { createDiv } from '../../../utils/dom'; -import { DataItem } from '../../../../src/plots/word-cloud/types'; +import { Tag } from '../../../../src/plots/word-cloud/types'; describe('word-cloud', () => { it('style', () => { @@ -22,7 +22,7 @@ describe('word-cloud', () => { const { data } = cloud.chart.getOptions(); - data.forEach((item: DataItem) => { + data.forEach((item: Tag) => { // DataSet 处理之后会多出两个无用的数据 if (!item.hasText) return; diff --git a/__tests__/unit/utils/transform/word-cloud-spec.ts b/__tests__/unit/utils/transform/word-cloud-spec.ts index ee0955a2df..e088e5c347 100644 --- a/__tests__/unit/utils/transform/word-cloud-spec.ts +++ b/__tests__/unit/utils/transform/word-cloud-spec.ts @@ -1,10 +1,8 @@ import DataSet from '@antv/data-set'; -import { DataItem } from '../../../../src/plots/word-cloud/types'; +import { Tag, Word } 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', @@ -22,11 +20,10 @@ const data = ['Hello', 'world', 'normally', 'you', 'want', 'more', 'words', 'tha return { text: d, value: 5 + Math.random() * 10, - test: 'haha', }; }); -function basicCommon(v: DataItem) { +function basicCommon(v: Tag) { expect(v.hasText).toBe(true); expect(typeof v.text).toBe('string'); expect(typeof v.value).toBe('number'); @@ -52,7 +49,7 @@ describe('word-cloud', () => { delete v.x; delete v.y; } - const result1 = wordCloud(data, options as any); + const result1 = wordCloud(data as Word[], options as any); const result2 = dv.rows; result1.forEach(removeXY); @@ -62,32 +59,32 @@ describe('word-cloud', () => { }); it('default', () => { - const result = wordCloud(data); + const result = wordCloud(data as Word[]); basicCommon(result[0]); }); it('callback', () => { - const common = (row: Row) => { + const common = (row: Word) => { expect(typeof row.text).toBe('string'); expect(typeof row.value).toBe('number'); }; - const font = (row: Row) => { + const font = (row: Word) => { common(row); return 'font-test'; }; - const fontWeight = (row: Row): any => { + const fontWeight = (row: Word): any => { common(row); return 'fontWeight-test'; }; - const fontSize = (row: Row) => { + const fontSize = (row: Word) => { common(row); return 11; }; - const rotate = (row: Row) => { + const rotate = (row: Word) => { common(row); return 22; }; - const padding = (row: Row) => { + const padding = (row: Word) => { common(row); return 33; }; @@ -100,7 +97,7 @@ describe('word-cloud', () => { }; }; - const result = wordCloud(data, { + const result = wordCloud(data as Word[], { font, fontWeight, fontSize, @@ -127,51 +124,30 @@ describe('word-cloud', () => { 'data:image/png;base64,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'; const img = await processImageMask(base64); - const result = wordCloud(data, { imageMask: img }); + const result = wordCloud(data as Word[], { imageMask: img }); basicCommon(result[0]); }); it('spiral is rectangular', () => { - const result = wordCloud(data, { spiral: 'rectangular' }); + const result = wordCloud(data as Word[], { spiral: 'rectangular' }); basicCommon(result[0]); }); }); describe('transform', () => { it('default', () => { - const result = transform(data, { - fields: ['text', 'value'], + const result = transform(data as Word[], { 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'], + const result = transform(data as Word[], { size: [0, 0], imageMask: img, }); @@ -182,8 +158,7 @@ describe('transform', () => { }); it('timeInterval is 0', () => { - const result = transform(data, { - fields: ['text', 'value'], + const result = transform(data as Word[], { size: [800, 800], timeInterval: 0, }); @@ -194,8 +169,7 @@ describe('transform', () => { }); it('padding is 0', () => { - const result = transform(data, { - fields: ['text', 'value'], + const result = transform(data as Word[], { size: [800, 800], padding: 0, }); @@ -203,8 +177,7 @@ describe('transform', () => { }); it('rotate is 0', () => { - const result = transform(data, { - fields: ['text', 'value'], + const result = transform(data as Word[], { size: [800, 800], rotate: 0, }); diff --git a/docs/manual/plots/word-cloud.en.md b/docs/manual/plots/word-cloud.en.md index d9b57fec0f..de02d287d5 100644 --- a/docs/manual/plots/word-cloud.en.md +++ b/docs/manual/plots/word-cloud.en.md @@ -37,6 +37,14 @@ order: 0 默认配置: 无 +#### colorField + +**可选**, _string_ + +功能描述: 根据该字段进行颜色映射 + +默认配置: 无 + #### timeInterval **可选**, _number_ diff --git a/docs/manual/plots/word-cloud.zh.md b/docs/manual/plots/word-cloud.zh.md index f0fa71ae32..a203db6206 100644 --- a/docs/manual/plots/word-cloud.zh.md +++ b/docs/manual/plots/word-cloud.zh.md @@ -2,7 +2,7 @@ title: 词云图 order: 0 --- - + ## 配置属性 ### 图表容器 @@ -37,6 +37,14 @@ order: 0 默认配置: 无 +#### colorField + +**可选**, _string_ + +功能描述: 根据该字段进行颜色映射 + +默认配置: 无 + #### timeInterval **可选**, _number_ diff --git a/examples/word-cloud/basic/API.en.md b/examples/word-cloud/basic/API.en.md index 94342e0924..08b0fa1a56 100644 --- a/examples/word-cloud/basic/API.en.md +++ b/examples/word-cloud/basic/API.en.md @@ -32,6 +32,14 @@ 默认配置: 无 +#### colorField + +**可选**, _string_ + +功能描述: 根据该字段进行颜色映射 + +默认配置: 无 + #### timeInterval **可选**, _number_ diff --git a/examples/word-cloud/basic/API.zh.md b/examples/word-cloud/basic/API.zh.md index c3cf0d0d20..593cf960d1 100644 --- a/examples/word-cloud/basic/API.zh.md +++ b/examples/word-cloud/basic/API.zh.md @@ -32,6 +32,14 @@ 默认配置: 无 +#### colorField + +**可选**, _string_ + +功能描述: 根据该字段进行颜色映射 + +默认配置: 无 + #### timeInterval **可选**, _number_ diff --git a/examples/word-cloud/basic/demo/color-field.ts b/examples/word-cloud/basic/demo/color-field.ts new file mode 100644 index 0000000000..e75cac5c5f --- /dev/null +++ b/examples/word-cloud/basic/demo/color-field.ts @@ -0,0 +1,21 @@ +import { WordCloud } from '@antv/g2plot'; + +fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/antv-keywords.json') + .then((res) => res.json()) + .then((data) => { + const wordCloud = new WordCloud('container', { + data, + width: 600, + height: 400, + wordField: 'name', + weightField: 'value', + colorField: 'value', + imageMask: 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*07tdTIOmvlYAAAAAAAAAAABkARQnAQ', + wordStyle: { + fontFamily: 'Verdana', + fontSize: [8, 32], + }, + }); + + wordCloud.render(); + }); diff --git a/examples/word-cloud/basic/demo/custom-tooltip.ts b/examples/word-cloud/basic/demo/custom-tooltip.ts new file mode 100644 index 0000000000..32a52172e5 --- /dev/null +++ b/examples/word-cloud/basic/demo/custom-tooltip.ts @@ -0,0 +1,32 @@ +import { WordCloud } from '@antv/g2plot'; + +fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/antv-keywords.json') + .then((res) => res.json()) + .then((data) => { + const wordCloud = new WordCloud('container', { + data, + width: 600, + height: 400, + wordField: 'name', + weightField: 'value', + imageMask: 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*07tdTIOmvlYAAAAAAAAAAABkARQnAQ', + wordStyle: { + fontFamily: 'Verdana', + fontSize: [8, 32], + }, + tooltip: { + customContent(_, data) { + if (!data.length) return; + return `

    title

    +
  • + + + ${data[0]?.data.text}:${data[0]?.data.value} + +
  • `; + }, + }, + }); + + wordCloud.render(); + }); diff --git a/examples/word-cloud/basic/demo/meta.json b/examples/word-cloud/basic/demo/meta.json index 1a5a4ff998..bbd91014b6 100644 --- a/examples/word-cloud/basic/demo/meta.json +++ b/examples/word-cloud/basic/demo/meta.json @@ -35,6 +35,22 @@ "en": "Word Cloud chart - image mask base64" }, "screenshot": "https://gw.alipayobjects.com/mdn/rms_d314dd/afts/img/A*qkYyQqFTU4YAAAAAAAAAAAAAARQnAQ" + }, + { + "filename": "custom-tooltip.ts", + "title": { + "zh": "词云图-自定义Tooltip", + "en": "Word Cloud chart - custom tooltip" + }, + "screenshot": "https://gw.alipayobjects.com/mdn/rms_f5c722/afts/img/A*id4CSZIMCtsAAAAAAAAAAABkARQnAQ" + }, + { + "filename": "color-field.ts", + "title": { + "zh": "词云图-colorField", + "en": "Word Cloud chart - colorField" + }, + "screenshot": "https://gw.alipayobjects.com/mdn/rms_f5c722/afts/img/A*id4CSZIMCtsAAAAAAAAAAABkARQnAQ" } ] } diff --git a/package.json b/package.json index 49817888ed..6a38fa5985 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "dependencies": { "@antv/event-emitter": "^0.1.2", - "@antv/g2": "^4.1.0-beta.13", + "@antv/g2": "^4.1.0-beta.14", "d3-hierarchy": "^2.0.0", "dayjs": "^1.8.36", "size-sensor": "^1.0.1", diff --git a/src/plots/word-cloud/adaptor.ts b/src/plots/word-cloud/adaptor.ts index 1879716531..66550f8305 100644 --- a/src/plots/word-cloud/adaptor.ts +++ b/src/plots/word-cloud/adaptor.ts @@ -1,6 +1,8 @@ +import { deepMix } from '@antv/util'; import { Params } from '../../core/adaptor'; import { tooltip, interaction, animation, theme, scale, state } from '../../adaptor/common'; -import { flow, findGeometry } from '../../utils'; +import { flow } from '../../utils'; +import { point } from '../../adaptor/geometries'; import { WordCloudOptions } from './types'; import { transform } from './utils'; @@ -9,25 +11,30 @@ import { transform } from './utils'; * @param params */ function geometry(params: Params): Params { - const { chart } = params; + const { chart, options } = params; + const { colorField, color } = options; const data = transform(params); chart.data(data); - chart.point().position('x*y').shape('word-cloud'); - - return params; -} -/** - * color 配置处理 - * @param params - */ -function color(params: Params): Params { - const { chart, options } = params; - const { wordField, color } = options; - const geometry = findGeometry(chart, 'point'); + const p = deepMix({}, params, { + options: { + xField: 'x', + yField: 'y', + seriesField: colorField && 'color', + point: { + color, + shape: 'word-cloud', + }, + }, + }); + + const { ext } = point(p); + ext.geometry.label(false); - geometry.color(wordField, color); + chart.coordinate().reflect('y'); + chart.axis(false); + chart.legend(false); return params; } @@ -45,58 +52,6 @@ function meta(params: Params): Params { )(params); } -/** - * coord 配置 - * @param params - */ -function coord(params: Params): Params { - const { chart } = params; - - chart.coordinate().reflect('y'); - - return params; -} - -/** - * axis 配置 - * 词云图不显示轴信息 - * @param params - */ -function axis(params: Params): Params { - const { chart } = params; - - chart.axis(false); - - return params; -} - -/** - * label 配置 - * 词云图不显示 label 信息 - * @param params - */ -function label(params: Params): Params { - const { chart } = params; - const geometry = findGeometry(chart, 'point'); - - geometry.label(false); - - return params; -} - -/** - * legend 配置 - * 词云图不显示 legend 信息 - * @param params - */ -function legend(params: Params): Params { - const { chart } = params; - - chart.legend(false); - - return params; -} - /** * 词云图适配器 * @param chart @@ -104,5 +59,5 @@ function legend(params: Params): Params { */ export function adaptor(params: Params) { // flow 的方式处理所有的配置到 G2 API - flow(geometry, meta, coord, axis, label, color, legend, tooltip, interaction, animation, theme, state)(params); + flow(geometry, meta, tooltip, interaction, animation, theme, state)(params); } diff --git a/src/plots/word-cloud/index.ts b/src/plots/word-cloud/index.ts index a5bacdcb27..aefcec7ab5 100644 --- a/src/plots/word-cloud/index.ts +++ b/src/plots/word-cloud/index.ts @@ -1,7 +1,7 @@ import { deepMix } from '@antv/util'; import { Plot } from '../../core/plot'; import { Adaptor } from '../../core/adaptor'; -import { WordCloudOptions } from './types'; +import { Tag, WordCloudOptions } from './types'; import { adaptor } from './adaptor'; import { processImageMask } from './utils'; // 注册的shape @@ -23,6 +23,19 @@ export class WordCloud extends Plot { showTitle: false, showMarkers: false, showCrosshairs: false, + customContent(_, data: { data: Tag; mappingData: { color: string } }[]) { + if (!data.length) return; + // 不完全采用模板字符串,是为了去掉换行符和部分空格, + // 便于测试。 + return ( + '
  • ' + + `` + + '' + + `${data[0]?.data.text}:${data[0]?.data.value}` + + '' + + '
  • ' + ); + }, }, wordStyle: { fontFamily: 'Verdana', @@ -73,8 +86,11 @@ export class WordCloud extends Plot { */ protected triggerResize() { if (!this.chart.destroyed) { - // 当整个词云图图表的宽高信息发生变化时,每个词语的坐标需要重新 - // 需要重新执行 adaptor,执行词云图的布局函数,不然会出现布局错乱,如相邻词语重叠的情况。 + // 这里解决了重渲染时字体变的透明的问题 + this.chart.clear(); + // 当整个词云图图表的宽高信息发生变化时,每个词语的坐标 + // 需要重新执行 adaptor,执行词云图的布局函数,不然会出现布局错乱, + // 如相邻词语重叠的情况。 this.execAdaptor(); // 执行父类的方法 super.triggerResize(); diff --git a/src/plots/word-cloud/shapes/word-cloud.ts b/src/plots/word-cloud/shapes/word-cloud.ts index 41ea50a74d..8e75109fc0 100644 --- a/src/plots/word-cloud/shapes/word-cloud.ts +++ b/src/plots/word-cloud/shapes/word-cloud.ts @@ -1,9 +1,9 @@ import { registerShape, Util } from '@antv/g2'; import { ShapeInfo } from '@antv/g2/lib/interface'; import { IGroup, ShapeAttrs } from '@antv/g2/lib/dependents'; -import { DataItem } from '../types'; +import { Tag } from '../types'; -type Config = ShapeInfo & { data: DataItem }; +type Config = ShapeInfo & { data: Tag }; registerShape('point', 'word-cloud', { draw(cfg: Config, group: IGroup) { @@ -28,14 +28,12 @@ registerShape('point', 'word-cloud', { function getTextAttrs(cfg: Config): ShapeAttrs { return { - ...cfg.defaultStyle, - ...cfg.style, fontSize: cfg.data.size, text: cfg.data.text, textAlign: 'center', fontFamily: cfg.data.font, fontWeight: cfg.data.weight, - fill: cfg.color, + fill: cfg.color || cfg.defaultStyle.stroke, textBaseline: 'alphabetic', }; } diff --git a/src/plots/word-cloud/types.ts b/src/plots/word-cloud/types.ts index 721a85a1ff..08a7568017 100644 --- a/src/plots/word-cloud/types.ts +++ b/src/plots/word-cloud/types.ts @@ -1,16 +1,21 @@ import { ShapeAttrs } from '@antv/g2/lib/dependents'; -import { Options } from '../../types'; +import { Datum, Options } from '../../types'; type FontWeight = ShapeAttrs['fontWeight']; -interface Row { +/** 一个文本信息,wordCloud 内部 */ +export interface Word { /** 文本内容 */ text: string; /** 该文本所占权重 */ value: number; + /** 用于指定颜色字段 */ + color: string | number; + /** 原始数据 */ + datum: Datum; } -export type DataItem = Row & { +export type Tag = Word & { /** 字体 */ font?: string; /** 字体样式 */ @@ -38,16 +43,16 @@ export type DataItem = Row & { /** 词云字体样式 */ interface WordStyle { /** 词云的字体, 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontFamily?: string | ((row: Row) => string); + readonly fontFamily?: string | ((word: Word) => string); /** 设置字体的粗细, 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontWeight?: FontWeight | ((row: Row) => FontWeight); + readonly fontWeight?: FontWeight | ((word: Word) => FontWeight); /** * 每个单词所占的盒子的内边距,默认为 1。 越大单词之间的间隔越大。 * 当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly padding?: number | ((row: Row) => number); + readonly padding?: number | ((word: Word) => number); /** 字体的大小范围,当为函数时,其参数是一个经过处理之后的数据元素的值 */ - readonly fontSize?: [number, number] | ((row: Row) => number); + readonly fontSize?: [number, number] | ((word: Word) => number); /** 旋转的最小角度和最大角度 默认 [0, 90] */ readonly rotation?: [number, number]; /** 旋转实际的步数,越大可能旋转角度越小, 默认是 2 */ @@ -61,6 +66,8 @@ export interface WordCloudOptions extends Options { readonly wordField: string; /** 词条权重字段 */ readonly weightField: string; + /** 根据该字段进行颜色映射 */ + readonly colorField?: string; /** 遮罩图片实例,可以是图片 URL 或者 base64 */ readonly imageMask?: HTMLImageElement | string; /** 最大执行时间 */ diff --git a/src/plots/word-cloud/utils.ts b/src/plots/word-cloud/utils.ts index ddd27fd0ef..f406af4c84 100644 --- a/src/plots/word-cloud/utils.ts +++ b/src/plots/word-cloud/utils.ts @@ -1,17 +1,18 @@ import { Chart, View } from '@antv/g2'; import { isArray, isFunction, isNumber, isString } from '@antv/util'; import { Params } from '../../core/adaptor'; +import { Datum } from '../../types'; import { log, LEVEL, getContainerSize } from '../../utils'; import { wordCloud } from '../../utils/transform/word-cloud'; -import { DataItem, WordCloudOptions } from './types'; +import { Tag, Word, WordCloudOptions } from './types'; /** * 用 DataSet 转换词云图数据 * @param params */ -export function transform(params: Params): DataItem[] { +export function transform(params: Params): Tag[] { const { options } = params; - const { data, imageMask, wordField, weightField, wordStyle, timeInterval } = options; + const { data, imageMask, wordField, weightField, colorField, wordStyle, timeInterval } = options; if (!data || !data.length) { return []; } @@ -19,8 +20,18 @@ export function transform(params: Params): DataItem[] { const arr = data.map((v) => v[weightField]) as number[]; const range = [min(arr), max(arr)] as [number, number]; - return wordCloud(data, { - fields: [wordField, weightField], + // 变换出 text 和 value 字段 + const words = data.map( + (datum: Datum): Word => ({ + text: datum[wordField], + value: datum[weightField], + color: datum[colorField], + datum, // 存一下原始数据 + }) + ); + + // 数据准备在外部做,wordCloud 单纯就是做布局 + return wordCloud(words, { imageMask: imageMask as HTMLImageElement, font: fontFamily, fontSize: getFontSize(options, range), diff --git a/src/utils/transform/word-cloud.ts b/src/utils/transform/word-cloud.ts index e755c85147..8c3644dab7 100644 --- a/src/utils/transform/word-cloud.ts +++ b/src/utils/transform/word-cloud.ts @@ -1,31 +1,21 @@ -import { deepMix, assign, isString } from '@antv/util'; -import { DataItem } from '../../plots/word-cloud/types'; -import { Data } from '../../types'; +import { isNil, assign } from '@antv/util'; +import { Tag, Word } from '../../plots/word-cloud/types'; type FontWeight = number | 'normal' | 'bold' | 'bolder' | 'lighter'; -interface Row { - /** 文本内容 */ - text: string; - /** 该文本所占权重 */ - value: number; -} - export interface Options { - 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); + font?: string | ((row: Word) => string); + fontSize?: number | ((row: Word) => number); + fontWeight?: FontWeight | ((row: Word) => FontWeight); + rotate?: number | ((row: Word) => number); + padding?: number | ((row: Word) => number); spiral?: 'archimedean' | 'rectangular' | ((size: [number, number]) => (t: number) => number[]); timeInterval?: number; imageMask?: HTMLImageElement; } const DEFAULT_OPTIONS: Options = { - fields: ['text', 'value'], // fields to keep font: () => 'serif', padding: 1, size: [500, 500], @@ -39,46 +29,47 @@ const DEFAULT_OPTIONS: Options = { * 根据对应的数据对象,计算每个 * 词语在画布中的渲染位置,并返回 * 计算后的数据对象 + * @param words * @param options */ -export function wordCloud(data: Data, options?: Partial) { +export function wordCloud(words: Word[], options?: Partial): Tag[] { // 混入默认配置 options = assign({} as Options, DEFAULT_OPTIONS, options); - return transform(data, options as Options); + return transform(words, options as Options); } -export function transform(data: Data, options: Options) { - // 深拷贝 - data = deepMix([], data); +/** + * 抛出没有混入默认配置的方法,用于测试。 + * @param words + * @param options + */ +export function transform(words: Word[], options: Options) { + // 布局对象 const layout = tagCloud(); - ['font', 'fontSize', 'fontWeight', 'padding', 'rotate', 'size', 'spiral', 'timeInterval'].forEach((key) => { - if (options[key] !== undefined && options[key] !== null) { + ['font', 'fontSize', 'fontWeight', 'padding', 'rotate', 'size', 'spiral', 'timeInterval'].forEach((key: string) => { + if (!isNil(options[key])) { layout[key](options[key]); } }); - const [text, value] = options.fields; - if (!isString(text) || !isString(value)) { - throw new TypeError('Invalid fields: must be an array with 2 strings (e.g. [ "text", "value" ])!'); - } - const words = data.map((row) => { - row.text = row[text]; - row.value = row[value]; - return row; - }); + layout.words(words); if (options.imageMask) { layout.createMask(options.imageMask); } + const result = layout.start(); const tags: any[] = result._tags; + const bounds = result._bounds || [ { x: 0, y: 0 }, { x: options.size[0], y: options.size[1] }, ]; + tags.forEach((tag) => { tag.x += options.size[0] / 2; tag.y += options.size[1] / 2; }); + const [w, h] = options.size; const hasImage = result.hasImage; tags.push({ @@ -96,7 +87,7 @@ export function transform(data: Data, options: Options) { opacity: 0, }); - return tags as DataItem[]; + return tags; } /*