目录
6.2 处理传入的 props 图表数据 dataProcessing
效果展示:
1. package.json
{
"peerDependencies": {
"vue": ">=3.0.0",
"echarts": ">=5.2.2",
"echarts-wordcloud": "2.0.0",
"lodash": "^4.17.21"
}
}
2. templete
一定不要忘记设置 存放图表的 容器宽高
<template>
<!-- 外层容器 -->
<div
class="word-cloud-container"
:style="{ ...curStyle?.wrapper?.default }"
>
<!-- 图表容器 -->
<div
ref="chart"
class="word-cloud"
/>
</div>
</template>
<style lang="scss">
.word-cloud-container {
.word-cloud {
width: 100%;
height: 100%;
}
}
</style>
3. import
// 引入 Echarts
import * as echarts from 'echarts';
import { EChartsOption } from 'echarts/types/dist/echarts';
// 引入词云外部插件
import 'echarts-wordcloud';
// 引入 lodash 中的 merge、深克隆
import merge from 'lodash/merge';
import cloneDeep from 'lodash/cloneDeep';
4. 常用配置
shape —— 词云的形状,默认是 circle,可选的参数有 cardioid 、 diamond 、 triangle-forward 、 triangle 、 star
left / top / right / bottom —— 词云的位置,默认是 center center
width / height —— 词云的宽高,默认是 75% 80%
sizeRange —— 词云的文字字号范围,默认是[12, 60] ,词云会根据提供原始数据的 value 对文字的字号进行渲染。以默认值为例, value 最小的渲染为 12px ,最大的渲染为 60px ,中间的值按比例计算相应的数值
rotationRange / rotationStep —— 词云中文字的角度,词云中的文字会随机的在 rotationRange 范围内旋转角度,渲染的梯度就是 rotationStep ,这个值越小,词云里出现的角度种类就越多。如果是45度到135度,可能旋转的角度就是 -90 -45 0 45 90
gridSize —— 词云中每个词的间距
drawOutOfBound —— 是否允许词云在边界外渲染,直接使用默认参数 false 就可以,否则容易造成词重叠
textStyle —— 词云中文字的样式, normal 是初始的样式, emphasis 是鼠标移到文字上的样式
其他的可以参考 Echarts 官方文档中的配置项
5. props、emits
props: {
// 自定义组件样式
cStyle: {
type: Object as PropType<ComponentCustomStyle>,
default: () => ({
// 外层容器
wrapper: {
default: {},
},
}),
},
// echarts原生配置
options: {
type: Object as PropType<EChartsOption>,
default: () => ({}),
required: false,
},
// 传入数组数据 如果不传入数据 会使用默认数据
// 如果 options 设置了 series 属性 则会忽略 data 的数据
data: {
type: Array as PropType<CommonItem[]>,
default: () => ([]),
},
// 别名 及 样式设置
seriesSetting: {
type: Object,
default: () => ({
// 词云文本样式
wordStyle: {
type: Object,
default: () => ({}),
},
// 取 resData 数据中的别名设置
data: {
nameKey: '', // 名称别名
dataKey: '', // 数据别名
},
}),
},
wordCloud: {
type: Object,
default: () => ({}),
},
},
emits: ['com-click'],
6. 实现逻辑
6.1 添加响应式变量
// props 传入的自定义样式
const curStyle = computed(() => props.cStyle);
// 图表元素
const charts = ref<HTMLElement | null>(null);
// 图表实例
let myChart: any = null;
const state = reactive({
// 图表数据
chartData: [] as CommonItem[],
});
6.2 处理传入的 props 图表数据 dataProcessing
/**
* 数据处理
*/
const dataProcessing = () => {
if (props.seriesSetting?.data && props.data) {
// 数据别名
const { nameKey, dataKey } = props.seriesSetting.data;
// 对传入的数组数据进行键值的处理,以符合图表数据的要求
state.chartData = props.data.map((item: CommonItem) => ({
name: item[nameKey] || '--',
value: item[dataKey] || 0,
}));
}
};
6.3 绘制词云图 drawChart
合并 props 传入的数据 及 默认数据
options 中的 series 优先级高于 data
/**
* 绘制图形
*/
const drawChart = () => {
/* 只要是能配置的属性 都需要将传入的数据(props)与默认的数据合并 */
const { color, series } = props.options;
let seriesData: any;
// options 中的 series 优先级最高
if (series) {
seriesData = (series as any).map((item) => merge(
{
type: 'wordCloud',
// 单词之间的间隔大小
gridSize: 12,
// 最小字体和最大字体 必须写一个范围不能直接写每个字的大小
sizeRange: [12, 30],
// 字体旋转角度的范围,水平
rotationRange: [-45, 0, 45, 90],
// 词云形状
shape: 'circle',
width: '80%',
height: '100%',
left: 'center',
top: 'center',
right: null,
bottom: null,
// 词云是否显示完整,超出画布的也显示
drawOutOfBound: false,
textStyle: {
fontWeight: '500',
// 字体随机颜色
color: (params) => (color && color[params.dataIndex]) || defaultOptions.color[params.dataIndex]
|| `rgb(${[Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)].join(',')})`,
},
...props?.wordCloud,
},
item,
));
} else if (props.data && props.seriesSetting?.data) {
// data 的优先级其次
seriesData = merge({
type: 'wordCloud',
// 单词之间的间隔大小
gridSize: 12,
// 最小字体和最大字体 必须写一个范围不能直接写每个字的大小
sizeRange: [12, 30],
// 字体旋转角度的范围,水平
rotationRange: [-45, 0, 45, 90],
// 词云形状
shape: 'circle',
width: '80%',
height: '100%',
left: 'center',
top: 'center',
right: null,
bottom: null,
// 词云是否显示完整,超出画布的也显示
drawOutOfBound: false,
textStyle: {
fontWeight: 'normal',
// 字体随即色
color: (params) => (color && color[params.dataIndex]) || defaultOptions.color[params.dataIndex]
|| `rgb(${[Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)].join(',')})`,
},
data: state.chartData,
},
props?.wordCloud,
props?.seriesSetting?.wordStyle);
}
// 合并默认配置
let option: any = merge(
{
series: seriesData,
},
defaultOptions,
);
// 合并数据
option = merge(option, props.options);
// 画布清除
myChart.clear();
try {
myChart.setOption(option);
} catch (error) {
console.log(error);
}
};
6.4 重新设置图表大小 resize
/**
* 重新设置图表的尺寸
*/
const resize = () => {
nextTick(() => {
myChart.resize();
});
};
6.5 图表初始化操作 onMounted
实例化 echarts 对象
处理传入数据
绘制图表
添加系列点击事件
监听视窗尺寸变化,重置图表尺寸
onMounted(() => {
if (charts.value) {
// 实例化 echarts 对象
myChart = echarts.init(charts.value);
// 处理传入数据
dataProcessing();
// 绘制图表
drawChart();
// 系列点击事件(此组件为点击词)
myChart.on('click', (params: unknown) => {
emit('com-click', params);
});
}
// 监听视窗尺寸变化 重置图表尺寸
window.addEventListener('resize', resize);
});
6.6 图表卸载操作 onUnmounted
移除监听事件
onUnmounted(() => {
// 移除监听事件
window.removeEventListener('resize', resize);
});
6.7 监听 options 变化,重绘词云图
/**
* 监听options、词云样式变化 重绘词云
*/
watch(() => [props.options, props.seriesSetting.wordStyle, props.wordCloud], () => {
drawChart();
},
{
deep: true,
});
6.8 监听 data 变化,重绘词云图
/**
* 监听 data 的变化, 处理数据、重绘词云
*/
watch(() => [props.data, props.seriesSetting.data], () => {
dataProcessing();
drawChart();
},
{
deep: true,
});
6.9 监听自定义样式变化,重绘词云图
/**
* 监听 cStyle 变化
*/
watch(() => [props.cStyle], () => {
nextTick(() => {
myChart.resize();
});
},
{
deep: true,
});
7. 使用示例
单词颜色随机生成,可设置词云形状(数据量大时才行)
<template>
<chart-word-cloud
:options="chartOptions"
:c-style="{
wrapper: {
default: {
height: '300px',
width: '300px',
}
}
}"
>
</chart-word-cloud>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, toRefs } from 'vue';
export default defineComponent({
setup() {
const state = reactive({
chartOptions: {
color: ['#0DE0E8', '#33B897'],
series: [
{
data: [
{ name: 'Sam S Club', value: 1000 },
{ name: 'Macys', value: 6181 },
{ name: 'Amy Schumer', value: 4386 },
{ name: 'Jurassic World', value: 1001 }
]
}
]
}
});
return {
...toRefs(state),
};
},
});
</script>