Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(word-cloud): imageMask选项支持url字符串格式 #1617

Merged
merged 5 commits into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions examples/word-cloud/basic/API.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@

#### imageMask

**可选**, _HTMLImageElement_
**可选**, _HTMLImageElement \| string_

功能描述: 设置一张图片,然后图表就可以根据该图片的形状进行渲染,必须是已加载完成的图片对象
功能描述: 设置一张图片,然后图表就可以根据该图片的形状进行渲染,可以是图片元素实例或者 url 地址和 base64

注意: 词语只渲染在图片的深色部位,浅色的部位(如白色)不渲染词语。当使用图片的 url 地址时,图片的大小不宜过大,不然图片加载时间过长

默认配置: 无

Expand Down Expand Up @@ -76,17 +78,6 @@
| -------- | ----------------------------------- | ---------------------------------------------------- |
| text | _string_ | 文本内容 |
| value | _number_ | 该文本所占权重 |
| font | _string_ | 字体 |
| style | _"normal" \| "italic" \| "oblique"_ | 字体样式 |
| weight | _number \| string_ | 文本粗细 |
| rotate | _number_ | 旋转角度 |
| size | _number_ | 字体大小 |
| padding | _number_ | 一个单词所占的盒子的内边距,值越大单词之间的间隔越大 |
| hasText | _boolean_ | 是否包含文本 |
| width | _number_ | 单词所占盒子的宽度 |
| height | _number_ | 单词所占盒子的高度 |
| x | _number_ | x 轴坐标 |
| y | _number_ | y 轴坐标 |

`markdown:docs/common/color.en.md`

Expand Down
6 changes: 4 additions & 2 deletions examples/word-cloud/basic/API.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@

#### imageMask

**可选**, _HTMLImageElement_
**可选**, _HTMLImageElement \| string_

功能描述: 设置一张图片,然后图表就可以根据该图片的形状进行渲染,必须是已加载完成的图片对象
功能描述: 设置一张图片,然后图表就可以根据该图片的形状进行渲染,可以是图片元素实例或者 url 地址和 base64

注意: 词语只渲染在图片的深色部位,浅色的部位(如白色)不渲染词语。当使用图片的 url 地址时,图片的大小不宜过大,不然图片加载时间过长

默认配置: 无

Expand Down
21 changes: 21 additions & 0 deletions examples/word-cloud/basic/demo/image-mask-base64.ts
Original file line number Diff line number Diff line change
@@ -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',
imageMask:
'data:image/png;base64,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',
wordStyle: {
fontFamily: 'Verdana',
fontSize: [8, 32],
},
});

wordCloud.render();
});
42 changes: 17 additions & 25 deletions examples/word-cloud/basic/demo/image-mask.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
import { WordCloud } from '@antv/g2plot';

const imageMask = new Image();
imageMask.crossOrigin = '';
imageMask.src = 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*07tdTIOmvlYAAAAAAAAAAABkARQnAQ';

// 等待图片加载完成
imageMask.onload = () => {
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/antv-keywords.json')
.then((res) => res.json())
.then((data) => {
const wordCloud = new WordCloud('container', {
data,
// 宽高设置最好根据 imageMask 做调整
width: 600,
height: 400,
wordField: 'name',
weightField: 'value',
imageMask,
wordStyle: {
fontFamily: 'Verdana',
fontSize: [8, 32],
},
});

wordCloud.render();
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',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里赞

wordStyle: {
fontFamily: 'Verdana',
fontSize: [8, 32],
},
});
};

wordCloud.render();
});
8 changes: 8 additions & 0 deletions examples/word-cloud/basic/demo/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
"en": "Word Cloud chart - image mask"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f5c722/afts/img/A*id4CSZIMCtsAAAAAAAAAAABkARQnAQ"
},
{
"filename": "image-mask-base64.ts",
"title": {
"zh": "词云图-图片遮罩-base64",
"en": "Word Cloud chart - image mask base64"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f5c722/afts/img/A*id4CSZIMCtsAAAAAAAAAAABkARQnAQ"
}
]
}
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
"@antv/data-set": "^0.11.5",
"@antv/event-emitter": "^0.1.2",
"@antv/g2": "^4.1.0-beta.7",
"dayjs": "^1.8.34",
"dayjs": "^1.8.36",
"size-sensor": "^1.0.1",
"tslib": "^1.13.0"
},
"devDependencies": {
"@antv/gatsby-theme-antv": "^1.0.0-beta.0",
"@antv/gatsby-theme-antv": "^1.0.0-beta.4",
"@babel/core": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@commitlint/cli": "^8.2.0",
Expand All @@ -76,14 +76,14 @@
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^3.1.0",
"gatsby": "^2.20.22",
"gatsby": "^2.24.63",
"generate-changelog": "^1.8.0",
"gh-pages": "^3.1.0",
"husky": "^4.2.3",
"jest": "^26.0.1",
"jest-electron": "^0.1.7",
"jest-extended": "^0.11.2",
"limit-size": "^0.1.1",
"limit-size": "^0.1.3",
"lint-md-cli": "^0.1.2",
"lint-staged": "^10.0.7",
"npm-run-all": "^4.1.5",
Expand All @@ -93,8 +93,8 @@
"ts-jest": "^25.4.0",
"ts-loader": "^7.0.0",
"typescript": "^3.5.3",
"webpack": "^4.39.2",
"webpack-bundle-analyzer": "^3.4.1",
"webpack": "^4.44.2",
"webpack-bundle-analyzer": "^3.9.0",
"webpack-cli": "^3.3.7",
"webpack-dev-server": "^3.9.0"
},
Expand Down
25 changes: 24 additions & 1 deletion src/plots/word-cloud/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Plot } from '../../core/plot';
import { Adaptor } from '../../core/adaptor';
import { WordCloudOptions } from './types';
import { adaptor } from './adaptor';
import { processImageMask } from './utils';
// 注册的shape
import './shapes/word-cloud';

Expand All @@ -18,7 +19,6 @@ export class WordCloud extends Plot<WordCloudOptions> {
protected getDefaultOptions(): Partial<WordCloudOptions> {
return deepMix({}, super.getDefaultOptions(), {
timeInterval: 2000,
autoFit: true,
tooltip: {
showTitle: false,
showMarkers: false,
Expand All @@ -36,6 +36,29 @@ export class WordCloud extends Plot<WordCloudOptions> {
});
}

/**
* 覆写父类方法,词云图需要加载图片资源,所以需要异步渲染
*/
public render() {
const { imageMask } = this.options;

if (!imageMask) {
// 调用父类渲染函数
super.render();
return;
}

processImageMask(imageMask, (img) => {
this.options = {
...this.options,
imageMask: img || null,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个可以在 adaptor 中处理吗?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1,现在adaptor中的代码都是同步运行的,而图片资源加载需要时间。
2,也可以这样,一开始就正常运行render,等到图片加载完成后,再更新配置选项,重新渲染。但我觉得这种效果不是很好。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

效果主要取决于图表的加载时间,我觉得目前的方式也可以,但文档里面给个建议,URL 方式不要使用过大的图片。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前来看,用base64效果最好。


// 调用父类渲染函数
super.render();
});
}

/**
* 获取 词云图 的适配器
*/
Expand Down
4 changes: 2 additions & 2 deletions src/plots/word-cloud/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export interface WordCloudOptions extends Options {
readonly wordField: string;
/** 词条权重字段 */
readonly weightField: string;
/** 遮罩图片实例 */
readonly imageMask?: HTMLImageElement;
/** 遮罩图片实例,可以是图片 URL 或者 base64 */
readonly imageMask?: HTMLImageElement | string;
/** 最大执行时间 */
readonly timeInterval?: number;
/** 文字样式配置 */
Expand Down
33 changes: 28 additions & 5 deletions src/plots/word-cloud/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Chart, View } from '@antv/g2';
import DataSet from '@antv/data-set';
import { isArray, isFunction, isNumber } from '@antv/util';
import { isArray, isFunction, isNumber, isString } from '@antv/util';
import { Params } from '../../core/adaptor';
import { log, LEVEL, getContainerSize } from '../../utils';
import { WordCloudOptions } from './types';
Expand All @@ -23,7 +23,7 @@ export function transform(params: Params<WordCloudOptions>) {
dv.transform({
type: 'tag-cloud',
fields: [wordField, weightField],
imageMask: getImageMask(imageMask),
imageMask: imageMask as HTMLImageElement,
font: fontFamily,
fontSize: getFontSize(options, range),
fontWeight: fontWeight,
Expand All @@ -43,7 +43,7 @@ export function transform(params: Params<WordCloudOptions>) {
*/
function getSize(params: Params<WordCloudOptions> & { chart: Chart }) {
const { chart, options } = params;
const { autoFit } = options;
const { autoFit = true } = options;
let { width, height } = chart;

// 由于词云图每个词语的坐标都是先通过 DataSet 根据图表宽高计算出来的,
Expand Down Expand Up @@ -105,8 +105,31 @@ function normalPadding(padding: number | number[] | 'auto'): [number, number, nu
return [0, 0, 0, 0];
}

function getImageMask(img: HTMLImageElement) {
return img;
/**
* 处理 imageMask 可能为 url 字符串的情况
* @param img
* @param callback
*/
export function processImageMask(img: HTMLImageElement | string, callback?: (img?: HTMLImageElement) => void) {
if (img instanceof HTMLImageElement) {
callback(img);
return;
}
if (isString(img)) {
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = img;
image.onload = () => {
callback(image);
};
image.onerror = () => {
log(LEVEL.ERROR, false, 'image %s load failed !!!', img);
callback();
};
return;
}
log(LEVEL.WARN, img === undefined, 'the type of imageMask option must be String or HTMLImageElement.');
callback();
}

/**
Expand Down