首页 > 其他分享 >vue3 + echarts-wordcloud 绘制词云图表

vue3 + echarts-wordcloud 绘制词云图表

时间:2024-10-19 15:47:19浏览次数:3  
标签:name value wordcloud 词云 maskImage vue3 echarts Math

词云图,是一种文本数据的视觉展示,由词汇组成类似云的彩色图形。

echarts-wordcloud是基于echarts的一个词云库,本篇主要介绍它的使用方法。

安装


npm install echarts
npm install echarts-wordcloud

注意

echarts-wordcloud@2 is for echarts@5

echarts-wordcloud@1 is for echarts@4

引用

import * as echarts from 'echarts';
import 'echarts-wordcloud'

基本配置

  • 字体颜色随机展示

看一下echarts-wordcloud的具体配置,我把他封装成了子组件,具体代码如下:

// ChartWordCloud.vue
 
<template>
	<div id="charts-content"></div>
</template>
 
<script setup lang="ts">
import * as echarts from 'echarts';
import 'echarts-wordcloud';
import { onMounted } from "vue";
// 引入 lodash 中的 merge、深克隆
import merge from 'lodash/merge';
 
 
const props = withDefaults(
	defineProps<{
		options: any
	}>(),
	{},
)
 
 
// 词云图默认属性
const defaultSeries = [{
	type: 'wordCloud',
	/**
	 * 绘制词云的形状, 值为回调函数 或 关键字, 默认 circle
	 *  关键字:
	 * 
	 * circle(圆形)  词的数量不太多的时候,效果不明显,它会趋向于画一个椭圆
	 * cardioid(苹果形或心形曲线)
	 * diamond(菱形 正方形)
	 * triangle-forward(三角形-向前)
	 * triangle(三角形-直立)
	 * pentagon(五边形)
	 * star(星形)
	 */
	shape: 'circle',
	// 保持 maskImage 的纵横比或形状的纵横比为 1:1
	keepAspect: false,
	/**
	 * 词云轮廓图,支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串, 不包含白色区域; 可选选项
	 * shape选项将随着云的形状增长而继续应用
	 * 有形状限制的时候,最好用背景图来实现,而且这个背景图一定要放base64的,不然词云画不出来
	 */
	// maskImage: maskImage,
 
	// 词云整个图表放置的位置 和 尺寸大小
	left: 'center',
	top: 'center',
	width: '100%',
	height: '100%',
	right: null,
	bottom: null,
	// 词云文本大小范围,  默认为最小12像素,最大60像素
	sizeRange: [12, 60],
	// 词云文字旋转范围和步长。 文本将通过旋转在[-90,90]范围内随机旋转步骤45
	// 如果都设置为 0 , 则是水平显示
	rotationRange: [-90, 90],
	rotationStep: 45,
	/**
	 * 词间距, 距离越大,单词之间的间距越大, 单位像素
	 * 这里间距太小的话,会出现大词把小词套住的情况,比如一个大的口字,中间会有比较大的空隙,这时候他会把一些很小的字放在口字里面,这样的话,鼠标就无法选中里面的那个小字
	 */
	gridSize: 8,
	// 设置为true可以使单词部分在画布之外绘制, 允许绘制大于画布大小的单词
	drawOutOfBound: false,
	/**
	 * 布局的时候是否有动画
	 * 注意:禁用时,当单词较多时,将导致UI阻塞。
	 */
	layoutAnimation: true,
	// 这是全局的文字样式,相对应的还可以对每个词设置字体样式
	textStyle: {
		fontFamily: 'sans-serif',
		fontWeight: 'bold',
		// 颜色可以用一个函数来返回字符串
		color: function () {
          // 随机颜色
          return (
            'rgb(' +
            [
              Math.round(Math.random() * 160),
              Math.round(Math.random() * 160),
              Math.round(Math.random() * 160),
            ].join(',') +
            ')'
          )
        },
	},
	// 鼠标hover的特效样式
	emphasis: {
		focus: 'self',
		textStyle: {
			textShadowBlur: 10,
			textShadowColor: '#999'
		}
	},
 
	/**
	 * 词云数据,必须是一个数组,每个数组项必须有name和value属性
	 * 设置单个文本的样式:  textStyle 
	 * 
	 * 例:{
					name: '',
					value: 40,
					textStyle: {
					}
				},
	 */
	data: []
}]
let seriesData = props.options.series;
const series = merge({}, defaultSeries[0], seriesData[0]) // {}表示合并后的新对象,可以传入一个空对象作为初始值
 
function DrawWordCloud() {
	// 词云
	let mychart = echarts.init(document.getElementById("charts-content")) // 可以设置主题色'dark'
	mychart.setOption({
		series: series
	})
}
 
onMounted(() => {
	DrawWordCloud()
})
</script>
 
<style scoped lang="scss"></style>

父组件调用:

<template>
  <div class="bestsellers-container">
    <chart-word-cloud :options="state.chartOptions"></chart-word-cloud>
  </div>
</template>

<script setup lang="ts">
import ChartWordCloud from "./item.vue";
import { onMounted, reactive } from "vue";

const image =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAA1hJREFUeF7tm01W4zAMgCVzkGEWlFwAht2Ukww9CXCSMichs2PgAqEsJhykFs9OnXHT/MhJ7IaYbOC9Opb1WZZk2UGI/MHI9YcvAH0tIEmuTkHKG/W+BPyGJE/V/4QiF0DvQJRnby8Pffs372k52+0SEIv+iX4aOeqvIPkHTk7yLHtK+8hysgCjNAHcMoXlCgQC/HaFkSwu7zRYIA2Z8eQEmCogLrJYAJTitN2uAXHJGEhTkwLE5vmurY8kuVqSlGsA0DPe88lRiBXHKjoBqJlwmHHOeNXgrrPsKbcbjwR5Tz4BPmw2f1dtg2oE4GNA1kByJLo3pqplSfmPQ69Hm1rgpp9aAJ6VN7L1kgAhUpLysYdiLq80QqgFcH528ThwvbsMLlTbWggHAGaqfGl1r5vn7zbxPQAeHF6o2WXLqTrGEoBnR8QeYIiGuyikE6cSwGLxY+2QdIQYpz8ZROnr28t1CSCm2S/DX5GLpNoCopp9Q2BnBRrA+eJSJSFDUk9/5uqv51xFBAOA/MmZbs/KGWJydnFDiGrzEd2DAPcY5fq3/EDcAAByjNQB/t+QRQ4AYrcAwJnv/jojW9xOkCjFGLbATWagtsa4q8L6Lkl1muIxGiDRSgHwWZA8hl5smShEsReIMRs0lSENIEYrMFWhsiIUWTjUW+G9klhMzrC2JhiNL7DqgXsWEIsvUJ7fPpc8OBiZc4FEFUCqp9PxHI1VTL+sDtdlDbuwqLLD2RRKq6bfCmDnD9RFhVmkyLbXr0546wWJOWyU6ta9DeEYN0TYufrghg3r3g3AOPeDBuvi3AFD+YM8oElIoBsjzjq2vFCmul2ddi4B08Enigxs5dkW8IkgsK/HdYbB1uVQhMep5QjOyjtbwIQtoZfyvQFYG6cpWEJv5QcBmAgEJ4dXt6zZUWCCPmGw8oMtwPYJUtJtsEtWzCSnKwcYDYBZDur7gZEvVh/qMKLyowIorWH82+UlhK6NDWfGq20G+4A6oT52keoUx+VDCC4MLwBGjhCDwlwXCG8ARoLQete/SznO714BDHKOIzu7JhjeAfRxjj6c3dEBMJeE1/XuJRPkrDO7TeOnd4FMPkgY5EBRZ5FS0i/9kaUQKecTN06/rm2C+QDXgYVq/wUgFOmpyvkACUbjkux97g4AAAAASUVORK5CYII=";
const maskImage = new Image();
maskImage.src = image;
console.log(maskImage.src, maskImage);

const state = reactive({
  chartOptions: {
    series: [
      {
        
        gridSize: 20,
        sizeRange: [10, 80], // 控制词语的大小范围

        rotationRange: [0, 0], // 控制词语的旋转角度范围

        rotationStep: 45, // 控制词语旋转的步长
        shape: "circle", // 控制词云图的形状,可选值为 'circle', 'cardioid', 'diamond', 'triangle-forward', 'triangle', 'pentagon', 'star'

        drawOutOfBound: false, // 控制词云图是否允许词语超出绘制区域

        // 布局的时候是否有动画

        layoutAnimation: true,

        // 图的位置

        left: "center",

        top: "center",
        textStyle: {
          fontFamily: "sans-serif",

          // fontWeight: 'bold',

          color: function () {
            return (
              "rgb(" +
              [
                Math.round(Math.random() * 160),

                Math.round(Math.random() * 160),

                Math.round(Math.random() * 160),
              ].join(",") +
              ")"
            );
          },
        },
          emphasis: {

                focus: 'self',

                textStyle: {

                    fontSize: 20 // 点击的词放大

                }

            },


        // 赋值给series里的词云轮廓图maskImage
        data: [
          { name: "互联网服务", value: 1000 },
          { name: "交通运输", value: 850 },
          { name: "公司", value: 800 },
          { name: "军工", value: 600 },
          { name: "医药", value: 900 },
          { name: "商务服务", value: 600 },
          { name: "城乡规划", value: 800 },
          { name: "家政服务", value: 400 },
          { name: "安防", value: 850 },
          { name: "医疗服务", value: 200 },
          { name: "电子科技", value: 8000 },
          { name: "航空航天", value: 1500 },
          { name: "食品饮料", value: 1500 },
          { name: "能源", value: 800 },
          { name: "教育培训", value: 200 },
          { name: "金融", value: 100 },
          { name: "文化娱乐", value: 250 },
          { name: "电力", value: 1200 },
          { name: "石油化工", value: 300 },
          { name: "电子商务", value: 900 },
          { name: "建筑", value: 700 },
          { name: "旅游", value: 550 },
          { name: "环保", value: 750 },
          { name: "地产", value: 1100 },
          { name: "体育", value: 300 },
          { name: "通信", value: 950 },
          { name: "科研", value: 1200 },
          { name: "物流", value: 1300 },
          { name: "咨询", value: 600 },
          { name: "游戏", value: 850 },
          { name: "人力资源", value: 500 },
          { name: "水务", value: 300 },
          { name: "舞蹈艺术", value: 150 },
          { name: "汽车制造", value: 1100 },
          { name: "电影制作", value: 350 },
          { name: "游乐园", value: 250 },
          { name: "新能源", value: 900 },
          { name: "服装设计", value: 400 },
          { name: "采矿", value: 700 },
          { name: "信息安全", value: 800 },
          { name: "化妆品", value: 600 },
          { name: "音乐产业", value: 750 },
          { name: "物联网", value: 1200 },
          { name: "绿色建筑", value: 850 },
          { name: "社交媒体", value: 950 },
          { name: "人工智能", value: 1000 },
          { name: "水产养殖", value: 320 },
          { name: "医学研究", value: 1800 },
          { name: "动物保护", value: 130 },
          { name: "航海", value: 1000 },
        ],
      },
    ],
  },
});

onMounted(() => {});
</script>
<style scoped>
.bestsellers-container {
  height: 38.56rem;
  background: #f0f0f0;
}
#charts-content {
  /* 需要设置宽高后才会显示 */
  width: 100%;
  height: 100%;
}
</style>

以上是效果

  • 字体平行且按预设颜色数组展示
  • 实现字体平行且按预设颜色数组展示的效果,只需将rotationRange都设为0即可,再传入自定义的color数组:
// 父组件
chartOptions: {
      color: ['#FFFFFF', '#FFFFFF', '#FFFFFF', 'rgba(255,255,255,0.7)', 'rgba(255,255,255,0.5)'],
      series: [
        {
          rotationRange: [0, 0],
          gridSize: 45,
          sizeRange: [15, 35],
          data: [...],
        },
      ],
    },

子组件则需要相对应的把将color改为:

color: function (v: any) {
 
   // 根据dataIndex属性作为下标去访问定义的color色系数组
   return `${props.options.color[v.dataIndex]}`
}

背景图插入方式:

background: url('../assets/images/bg-cloud.png') repeat center center / cover;
  • 自定义展示形状

首先要找到一张图片,为了成功率较高,一定要是矢量图,图片可以去iconfont图标库里找

需要把图片转成base64,不然词云画不出来,推荐一个免费转换的网址Base64图片转换

把图片相关的配置项修改一下

const image = 'data:image/png;base64,...'
const maskImage = new Image();
maskImage.src = image
 
// 赋值给series里的词云轮廓图maskImage
maskImage: maskImage,

标签:name,value,wordcloud,词云,maskImage,vue3,echarts,Math
From: https://blog.csdn.net/lele66688888/article/details/142975250

相关文章

  • Vue3路由
    路由组件通常存放在pages或views文件夹,一般组件通常存放在components文件夹。通过点击导航,视觉效果上“消失”了的路由组件,默认是被卸载掉的,需要的时候再去挂载。1.路由的相关配置1.1路由配置constrouter=createRouter({ history:createWebHistory(), routes:[ ......
  • 如何创建Electron + Vue3项目, 并调用C# dll
    依赖环境当前系统环境为win11,真正上手才知道环境问题才是最大的问题,希望本文能帮你节约时间。本文参考以下资料https://www.electronforge.io/guides/framework-integration/vue-3perplexity.ai和kimi.ai提供其他相关资料nodejs在开发前需要确定你要调用的dll是32位还是64位......
  • 一个基于Vue3开源免费的可快速开发中后台的框架,方便易用,业务没有瓶颈期!(附地址)
    该应用是基于Css媒体查询进行开发,手机、平板、PC均自动适配,增强网站的响应式设计,提高网站的可用性,减少开发成本和维护工作,采用主流技术Vue3、Vite、TypeScript、Gulp、Pinia以及周边的优秀的插件搭建,不用担心自己业务所受框架有限的瓶颈,它方便易用,可通过npm命令安装主程序包,也......
  • Vue3 编写HTTP 请求工具并使用
    编写Http请求首先在vue项目中创建一个api工具包并新建http.js导入axiosimportaxiosfrom'axios';如果没有axios,那么要先下载一个下载axios配置axios默认设置设置了Axios的默认超时时间为5秒。允许跨域请求,通过设置 withCredentials 为 true。设置了POST请......
  • Vue3 - 详细实现移动端H5网页调用摄像头拍照功能,微信公众号网页h5页面打开本地摄像头
    前言PC网站端,请访问这篇文章。在vue3手机移动端开发中,详解H5页面/微信公众号网页调用浏览器摄像头并拍照完整示例,在手机浏览器上开启摄像头并拍照上传服务器或保存到本地功能(实时预览使用图片临时路径或base64数据),切换转换前置摄像头与后置摄像头,vue3手机H5打开摄像......
  • vue3.0 使用Element Plus修改el-table表格的横纵滚动条颜色、宽高等样式
    在Vue3.0和ElementPlus中修改el-table的滚动条样式,可能遇到了样式不生效的问题。这通常是因为ElementPlus使用了自定义的滚动条组件el-scrollbar,而不是浏览器默认的滚动条。因此,需要针对el-scrollbar组件进行样式定制。<stylescoped>/*滚动条整体部分*/......
  • 基于 Python + Vue3!一个轻量级的域名和 SSL 证书监测平台!
    大家好,我是Java陈序员。在企业开发中,由于业务众多,涉及到很多业务域名证书,证书过期由于遗忘常常未能及时续期,导致线上访问异常,给企业带来损失!今天,给大家介绍一个轻量级的域名和SSL证书监测平台,用来解决证书管理困难的问题!关注微信公众号:【Java陈序员】,获取开源项目分享、AI......
  • 10/17 vue3
    主要学习了前端工程化安装了node。js会用vscode导入vite依赖,简单了解了各部分的作用学习了xue的一些语法插值表达式{{}}在里面可以放函数数据名和对象调用的api文本渲染命令比如v-textv-html可以识别文本的html代码都要写在开始标签里属性渲染v-bind:属性名=“数据......
  • vue3中的自定义hooks的使用,以及和mixin的区别
    1、理解hooks的概念:hook本质是一个函数,将setup函数中使用的CompositionAPI进行封装,类似于Vue2中的mixin2、mixin相比hook的缺点:(1)变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护(2)同名属性、同名方法无法融合,可能会导致冲突3、例一:第一步:在src/hooks/index.js文件:imp......
  • 【Vue3】将 Element Plus 引入 Vue3 项目
    前言在Vue3项目中使用ElementPlus可以为项目提供丰富的UI组件和交互体验。下面将介绍如何将ElementPlus引入Vue3项目中。步骤安装ElementPlus首先需要通过npm、yarn或pnpm安装ElementPlus包。可以选择其中一种方式进行安装。#NPM$npminstall......