💱词云图💱-echarts-wordcloud

5,111 阅读2分钟

写在开头

哈喽啊,各位UU早上好吖!☀

先给大家来个才艺,跳段街舞:ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ (来自沸点的编舞)😆

这两周工作比较忙都没空上来写"水文"😪,好在熬过去了,接下来应该能空闲一些,摸鱼,启动。🐟

今天一早刷到个新闻:

6871b872527ab41d5ca0086603743b5.png

童年的回忆,这是...又能看几个铁壳子打架了?😂 就是不知道女警还...Em...还能不能看。😗

回到正题,本文将分享关于词云图的内容,请诸君按需食用。

下载安装

本次分享的词云图功能小编是通过 echarts-wordcloud 这个包来实现的,它是基于 wordcloud2.js 实现的一个 echarts 第三方扩展包。

如果你项目中没有使用 echarts 的话,单纯想使用词云图功能,那么你可以直接去使用 wordcloud 包即可。

echarts-wordcloud 说明文档:传送门

echarts-wordcloud 其他案例预览:传送门

wordcloud2.js 官网:传送门

npm install echarts@5.4.3
npm install echarts-wordcloud

不知道你注意到没有,小编下载的 echarts 包版本是 5.4.3 ,为什么要写死这个版本呢?

截止到写这篇文章2024年05月24日,echarts 默认通过 npm install 下载的版本是 5.5.0,但用最新版本的 echarts 却渲染不出来词云图,遇到如下报错:

image.png

是新版本的 echarts 还没兼容好❓

小编降级了两个小版本 5.4.35.4.2 倒是都可以使用✅,就先使用低一点的版本吧,问题不大,注意一点就好。

echarts-wordcloud1.x 对应 echarts4.x

echarts-wordcloud2.x 对应 echarts5.x

基本使用

咱们先跟着文档初始化一个基础效果出来玩玩。🤠

<template>
  <div class="container" ref="container"></div>
</template>

<script>
import * as echarts from 'echarts';
import 'echarts-wordcloud';

export default {
  data() {
    return {
      _chart: null,
      _options: {
        series: [
          {
            type: 'wordCloud',
            width: '70%',
            height: '70%',
            left: 'center',
            top: 'center',
            right: null,
            bottom: null,
            // 形状
            shape: 'circle',
            // 文字之间的间距
            gridSize: 0,
            // 字体大小范围
            sizeRange: [5, 18],
            // 文字旋转角度范围
            rotationRange: [-90, 90],
            // 步长, 在[-90, 90]范围内随机旋转,-90/-45/0/45/90
            rotationStep: 45,
            // 是否渲染超出画布的文字
            drawOutOfBound: false,
            // 数据
            data: [],
            // 渲染时有动画效果,如果数据量大的数据,设置该配置能避免长时间空白
            layoutAnimation: true,
            // 自动缩放文本
            shrinkToFit: true,
            // 词云图-全局样式
            textStyle: {},
          },
        ],
      },
    }
  },
  mounted() {
    this.initChart();
  },
  methods: {
    /** @name 初始化 **/
    initChart() {
      this.$nextTick(() => {
        if (this._chart) this._chart.dispose();
        if (this.$refs?.container)
        this._chart = echarts.init(this.$refs?.container);
        if (!this._chart) return;
        this._chart.clear();
        this.setOptions();
      });
    },
    setOptions() {
      if (!this._chart) return;
      const seriesItem = this._data._options.series[0];
      // 数据
      seriesItem.data = [
        {"name":"潮州","value":146765},
        {"name":"惠州","value":112179}
        // ...
      ];
      this._chart.clear();
      this._chart.setOption(this._data._options, { notMerge: true });
    }
  }
}
</script>

<style scoped>
.container {
  width: 600px;
  height: 400px;
  border: 1px solid #ccc;
}
</style>

效果:

image.png

(不圆不方的形状😪)

数据上面就简列了两个,你可以按着格式扩充就行。

🔉如果你在使用中遇到安装是正常的,使用方式也是正确的,但页面就是没有渲染出东西,并且控制台也没有报错。

那你可以看看 DOM 结构,有没有相关的 canvas 元素渲染。 image.png

如果没有,那你可以尝试将导入

import 'echarts-wordcloud';

改成

import 'echarts-wordcloud/dist/echarts-wordcloud.min.js';

或者直接改成 CDN 的形式引入。

这坑很奇怪,不知道为啥,反正小编我踩过了🤢,记录一下。

形状

词云图,通常我们希望的是它能够变化出多种多样的形状,这无疑是咱们最为期待的一项功能。😛

从上述配置中我们可以观察到,词云图的形状可以通过 shape 属性进行设定。根据官方文档的说明,它支持以下几种形状:

  • circle:圆形(默认)。
  • cardioid:心形。
  • diamond:菱形。
  • triangle-forward:三角形向前。
  • triangle:三角形。
  • pentagon:五边形。
  • star:五角星。

不错,还支持挺多形状的,足够满足小编的需求了,开心。😊

然而,当小编开开心心做这个"感觉很简单"功能的时候,就开始要倒大霉了。

主要存在两个问题:

  • 形状不像,如果是容器尺寸适中,数据量也适宜,某些形状还能接受,但是心形看起来简直惨不忍睹。。😓
  • 容器大小变化时,形状完全乱套了。由于小编的业务中,容器尺寸能够随意缩放大小,所以这无疑也是一个问题。
05253.gif

怎么搞呢❓❓❓

echarts-wordcloud 还提供了一个 maskImage 属性,它允许你提供一个图像,它会从绘图文本中排除白色区域的轮廓图像。(就是说会根据你提供的图片进行绘制😮)

但在 wordcloud2.js 文档中并没有这个属性哦,不过应该也能进行扩展,毕竟 echarts-wordcloud 是在它的基础上扩展出来的。

而这个图片,你可以去 iconfont 上随意下载 .png 图片。

需要注意一点的是,图片内容区部分必须是纯黑色(#000000)的,这点很重要❗❗❗否则可能啥也没渲染出来哦。😗

image.png

具体使用:

<script>
...
import shape from './shape';

export default {
  data() {
    return {
      ...,
      shape: 'circle',
    }
  },
  computed: {
    shapeOptions() {
      return [
        { label: '圆形', value: 'circle' },
        { label: '椭圆', value: 'ellipse' },
        { label: '五角星', value: 'star' },
        { label: '菱形', value: 'diamond' },
        { label: '三角形', value: 'triangleTop' },
        { label: '正方形', value: 'square' },
        { label: '长方形', value: 'rectangle' },
        { label: '箭头', value: 'arrowRight' },
      ];
    }
  },
  methods: {
    ...,
    setOptions() {
      if (!this._chart) return;
      const seriesItem = this._data._options.series[0];
      seriesItem.data = data;
      // 保持maskImage属性的图像横纵比例
      seriesItem.keepAspect = true;
      // 形状
      const shapeConfig = shape[this.shape];
      const maskImage = new Image();
      maskImage.src = shapeConfig.img;
      maskImage.onload = () => {
        seriesItem.maskImage = maskImage;
        this._chart.clear();
        this._chart.setOption(this._data._options, { notMerge: true });
      };
    }
  }
}
</script>

keepAspect 属性能帮咱们保持图像的比例,可以解决容器变化大小时,形状乱套的问题。

keepAspect 属性仅 echarts-wordcloud@2.1.0 版本支持。

通过 iconfont 下载的 .png 图片,还需要将其转成base64才能使用。

下面小编提供了几个形状的 base64 数据,你也可以自己再增加。

shape.js 文件:

/**@name 五角星 **/
const star = {
  shape: 'star',
  img:
    'data:image/png;base64,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',
};

/**@name 菱形 **/
const diamond = {
  shape: 'diamond',
  img:
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAA+tJREFUeF7t3Uly3EAMRFHqzLZPYfvOjpbVUneLQw1AIZFIbhjBHeo/DhtGvW06Sq/AW+npt+3nx/x/qq5DZQC3+L8/wv/atq0kgqoAHuPfb/6SCCoC2ItfFkE1AGfxSyKoBKAlfjkEVQD0xC+FoAKAkfhlELADmIlfAgEzAIv49AhYAVjGp0bACMAjPi0CNgCe8SkRMAFYEZ8OAQuAlfGpEDAAiIhPgyA7gMj4FAgyA0CInx5BVgBI8VMjyAgAMX5aBNkAIMdPiSATgAzx0yHIAiBT/FQIMgDIGD8NAnQAmeOnQIAMgCE+PAJUAEzxoREgAmCMD4sADQBzfEgESAAqxIdDgAKgUnwoBAgAKsaHQRANoHJ8CASRABT/TmDbwn5NjwKg+F/xQ58EEQAU/3v8MASrASj+cfwQBCsBKP51/OUIVgFQ/Pb4SxGsAKD4/fGXIfAGoPjj8Zcg8ASg+PPx3RF4AVB8u/iuCDwAKL59fDcE1gAU3y++CwJLAIrvH98cgRUAxV8X3xSBBQDFXx/fDMEsAMWPi2+CYAaA4sfHn0YwCkDxceJPIRgBoPh48YcR9AJQfNz4Qwh6ACg+fvxuBK0AFD9P/C4ELQAUP1/8ZgRXABQ/b/wmBGcAFD9//EsERwAUnyf+KYI9AIrPF/8QwSsAxeeNv4vgEYDi88f/huAOQPHrxH9CcAfwo+ru2fW6f058u+n/Pr4ChKCOhvf4t3FfPwKFgB/BZ/w9ALdrQsCL4Cn+EQAh4ATwLf4ZACHgQrAb/wqAEHAgOIzfAkAIciM4jd8KQAhyIriM3wNACHIhaIrfC0AIciBojj8CQAiwEXTFHwUgBJgIuuPPABACLARD8WcBCAEGguH4FgCEIBbBVHwrAEIQg2A6viUAIViLwCS+NQAhWIPALL4HACHwRWAa3wuAEPggMI/vCUAIbBG4xPcGIAQ2CNzirwAgBHMIXOOvAiAEYwjc468EIAR9CJbEXw1ACNoQLIsfAUAIzhEsjR8FQAj2ESyPHwlACJ4RhMSPBiAE/xGExUcAUB1BaHwUAFURhMdHAlANAUR8NABVEMDERwTAjgAqPioAVgRw8ZEBsCGAjI8OgAUBbPwMALIjgI6fBUBWBPDxMwHIhiBF/GwAsiBIEz8jAHQEqeJnBYCKIF38zADQEKSMnx0ACoK08RkARCNIHZ8FQBSC9PGZAKxGQBGfDcAqBDTxGQF4I6CKzwrACwFdfGYA1ggo47MDsEJAG78CgFkE1PGrABhFQB+/EoBeBCXiVwPQiqBM/IoArhCUil8VwBGCcvErA3hFUDJ+dQB3BLfz+0bKFY/XzaMrrkHpmf8BZSX6gcDcCB4AAAAASUVORK5CYII=',
};

/**@name 圆形 **/
const circle = {
  shape: 'circle',
  img:
    'data:image/png;base64,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',
};

/**@name 三角形 **/
const triangleTop = {
  shape: 'triangle',
  img:
    'data:image/png;base64,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',
};

/**@name 正方形 **/
const square = {
  shape: function shapeSquare(theta) {
    return Math.min(
      1 / Math.abs(Math.cos(theta)),
      1 / Math.abs(Math.sin(theta)),
    );
  },
  img:
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAq9JREFUeF7tlMENgDAQw2D/oWEDfBIf8Jl3JBrH7Xn0rSZwrm5f+SMBlkuQAAmwnMDy+r0ACbCcwPL6vQAJgAQuTBT4MoHHSz55ARLgy/Py2RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyCcCM1IkEUM/L5RKAGakTCaCel8slADNSJxJAPS+XSwBmpE4kgHpeLpcAzEidSAD1vFwuAZiROpEA6nm5XAIwI3UiAdTzcrkEYEbqRAKo5+VyrwXgX5T4LYFHO37bqoOPCSTAGJUzmADOXcetEmCMyhlMAOeu41YJMEblDCaAc9dxqxuoAHCBGZfSZgAAAABJRU5ErkJggg==',
};

/**@name 长方形 **/
const rectangle = {
  shape: function shapeSquare(theta) {
    return Math.min(
      1 / Math.abs(Math.cos(theta)),
      1 / Math.abs(Math.sin(theta)),
    );
  },
  img:
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAACACAYAAABtCHdKAAAAAXNSR0IArs4c6QAAA09JREFUeF7t2sENw0AMA8Fz53HlNpAevB9OCgihORF6JNc55zk+BAh8KXBfivalr+8m8BdQNItAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAIBRQuQRRBQNDtAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAIBRQuQRRBQNDtAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAIBRQuQRRBQNDtAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAIBRQuQRRBQNDtAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAIBRQuQRRBQNDtAIBBQtABZBAFFswMEAgFFC5BFEFA0O0AgEFC0AFkEAUWzAwQCAUULkEUQUDQ7QCAQULQAWQQBRbMDBAKB33XOeYIgEQSWBVy05dc3eybgomXUgpYFXLTl1zd7JuCiZdSClgVctOXXN3sm4KJl1IKWBVy05dc3eyagaBm1oGUBRVt+fbNnAoqWUQtaFlC05dc3eyagaBm1oGUBRVt+fbNnAoqWUQtaFlC05dc3eybgnyEZtaBlARdt+fXNngm4aBm1oGUBF2359c2eCbhoGbWgZQEXbfn1zZ4JuGgZtaBlARdt+fXNngkoWkYtaFlA0ZZf3+yZgKJl1IKWBRRt+fXNngkoWkYtaFlA0ZZf3+yZgKJl1IKWBRRt+fXNngn4Z0hGLWhZwEVbfn2zZwIuWkYtaFnARVt+fbNnAi5aRi1oWcBFW359s2cCLlpGLWhZwEVbfn2zZwKKllELWhZQtOXXN3smoGgZtaBlAUVbfn2zZwKKllELWhZQtOXXN3sm4He0jFrQsoCLtvz6Zs8EXLSMWtCygIu2/PpmzwRctIxa0LKAi7b8+mbPBFy0jFrQsoCLtvz6Zs8EXLSMWtCywP0C6nLAcP+Cg/oAAAAASUVORK5CYII=',
};

/**@name 椭圆 **/
const ellipse = {
  shape: 'circle',
  img:
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABXNJREFUeF7tnY111DAQhC+VAJWEVBKoBKgEqARSCUklkHG8h85nn2X5Z0fa8Xt59xOdtbvzaSXZsn130hY6AnehvZfzJwEQHAIBIACCRyC4+8oAAiB4BIK7rwwgAIJHILj7ygACIHgEgruvDCAAgkcguPvKAAIgeASCu68MIACCRyC4+8oAAiB4BIK7rwwgAIJHILj7ygACIHgEgrvfagZ43+uKV/sbSv1u8MVL8vm5f5++2vumkKkZABP2Y6/I/Q2xtxLNIPh9Op2eEkjwucqtFgAgNoTGK4Q20VmCPgQDn6uAghUACP2pV/cLi8oL7TAI0LUABkogmAAw0Rlb+ELtR4sbED+ZYPAGwESvtZWXgkEDgwcAJvpj36eXBrGV3wEGZIUfr93e4TONIwGI2tpzQXXJCkcAAOGR4m1QlxuQyOUAw+cjxgp7AiDh1yMMEL713cP6vY3sYQ8AlOq3lwogPOwxRtgagK99ut8+BNrjLoPFrQDAkbnvGtUfQqmBgMa2etsCALX61TIU7QBjg9UQrAEAfT1aPdtx+aJoVvqj1dmgFACI/qvSoLVodnE2KAFAKZ8ToSIIlgKAVq+UzwkArFo8XVwCgMTnFT61bBEEuQBI/DrENyuzIcgBQOLXJX4KwYc50+cAkPhzEeT+PzLBTQhuAaDRPre4udZhnQHOLI5uUwBonp8b3jrKAQCAcLVNAfBHx/XrUDbTysn1BWMA4PCuFm9kRraiYliVjFPKF9sQAKX+ihQtMPWqKxgCoFF/QVQr+snVrCAFAGkf6V9b2xG4OGeQAqDW37bw5t1FFjAA1PfHEN+8xGCwu1TNANDIPxYA5xmBAfA3lv/ytj9E/AwANPiLyUPXDQiAmOLD6+4cAQBQ/x8Tgm42AAB03D8mAN0kAABoABgXgC4DCIC4ADwIgLjiw3MBEFv/t1mAuoC4FCgDxNW+81yDQAHwdpGnLveKSUJ3HEAAxBT/fChYawGCA4AbPeBwsLZYEegWiNp6AHUDscQ/LwYyALQmIBYA58vFDAB1A7EAuFoTCPfVDcSA4OIKoXRZuLJADADOrf88EEj81uqgtiG4uj5weGmYskDbAFy0/rEMgO80I2gTgtEbRYxdHq47gLYHwOStYqZuEAEIMCuwBzC2F5JYHl2lfnP/1j2CdI6gDUgmxZ8aA6Ru60ZRdUNw8wZROQCgjCCoE4LRW8IMXZm7T6CVFwR1QZAlfm4GEASNir8UAHUH/CDM9vmlXUD6O80OOEGYvBnkLXNzxwDDfeg4AQ8Eqx4yWQoA3NfzAf0hyB7sTZm6BgDbpx4Z5wNC0SNithgDjLmrbHAcBNkPg8gxaYsMkNajE0k5US8rs8tzhLcGIB0bPOpkUpnSg1+tfjbgHrOAHM+sWxAIOdG6LrOr8FbdHhlgbMqIRSYCIQ+EQ4Q/EgCrCxkBMwaAoItRnVr8XrOAPLb/l1L38BaLXR4Jv0SMI7qAW/ZYVrgP9pQSHMB5eg3M6qd/LxF7rKw3AMMpZApES92EtXQI392lm2VjAmBs8AgIkB0MDJa4zdkBwSH0S/9KJXpqPDMAc0AACoZFqxAbf0jp2NzT+hydtQIw5pcBYJkCZdLvlsRiqizEtQEb3qNVY6NL5yXO1pQBSvxLM8TUe9uvCZ1+Hn5XYgP1b1oHgDr4DMYJAAYVHG0QAI7BZ6haADCo4GiDAHAMPkPVAoBBBUcbBIBj8BmqFgAMKjjaIAAcg89QtQBgUMHRBgHgGHyGqgUAgwqONggAx+AzVC0AGFRwtEEAOAafoWoBwKCCow0CwDH4DFULAAYVHG0QAI7BZ6haADCo4GiDAHAMPkPVAoBBBUcbBIBj8BmqFgAMKjja8A/UQc8BdlckFQAAAABJRU5ErkJggg==',
};

/**@name 箭头 **/
const arrowRight = {
  shape: 'triangle-forward',
  img:
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABYVJREFUeF7tnd+rTVEQx8e7P9H/QRRF+fWgKA9EEYp4UBRFFA+KeFCUB6J4UMQDUR5oumt1znXPuWutvWbWzF7re17vrJlZ3/mctXcze9+zg/AZWoEdlbvfSUQ/Kn1guaECtQBcIqK7RHTFcA8IXaGABAC7iOg6Ee0honcVuWCpgQJSAHDqfwIEJwz2gZATFZAEIKbwKIDwZGJOWNZQAQ0AYvrHAggNt4NQpQpoAsC5vAkQ3CxNDPZtFNAGIO7iQgDhc5ttIUquAq0A4Hy+BQjO5iYHO30FWgIQd3MngPBSf3uIkFLAAoCY034iOpRKEH/XVcASAN7Z83Aa3NfdJryvU8AagJjXaSLaTUQ/Uaq2CngBgHf9MZwGmCs0ZMATAHHbmCsMDgBvH3OFRhB4PAGWt465gjII3gGI28dcQQmEuQDA28dcQQGCOQEQt4+5giAIcwSAt/899A0wV6iEYa4AYK5QWfi4fO4AYK5QCUIvALAML8JlAXOFAih6AgBzhYLC93YJ+H/rmCtkwtDjCbC89RvhsoD3FdYA0TsAmCskToIRAIgSYK6wAoaRAIjbPx4uC5lXyb7NRgQAc4UlpkcFAHOFoMDoAMS5Ar/ZfKbvw3717gDAQpch31cAAFu/GEO9rwAAVp+MPFfgy8K93i8LAGD7CvP7CgxCt/8HCQCkv+JdzxUAQBqAaMFzBT4N3uYv8W8JAMpq1N37CgCgDIDu5goAYBoAy3MFviz8rXNjtxoA1Gs/6/cVAEA9ALOeKwAAOQBmOVcAALIARG+zmSsAAB0Aolf3cwUAoAsAe3c9VwAA+gDECC7nCgCgHQAc6VN4HtHN/0ECAG0BcDdXAAA2AHBUF3MFAGAHQIz8OFwWTH5fAQDYA2A6VwAAfgDgTJrPFQCALwBiNhfDZUH99xUAgE8Ams0VAIBfAJrMFQCAfwBihgeI6KB0ugBAWlFdf+JzBQCgWzAt72JzBQCgVSJ9vzxX4OcRL9eEAgA16vlYu4+IDk9NBQBMVc5+3e1wAryqSQUA1Khns/ZraBKdlwgPACRUbOeDi87X/S9SIQGAlJK6fl6Hwt+SDgMApBWV98c3eHyjp/IBACqyijh9GL71T0W8rXECADTVneb7dyj8yWnLy1YBgDK9tK2vhTv8D9qBon8A0Erp7eNwwfnu/mrrdABAa8W3xjsViv/LIhUAYKH6Rsxn4bjnmz2zDwCwkb6qfy+ZMgCQVDPtS6R/nw6TbwEA8rWqseT+Pd/knatxorEWAGioutmneP9eMmUAIKnmZl9q/XvJlAGApJoLX0eIaK+Oa1mvAEBWzyb9e8mUAYCMmk379zIpb3gBAPVqNu/f16e88AAApqtp1r+fnvLWlQBgmpqm/ftpKa9eBQDK1HTRvy9LeXtrAJCvppv+fX7KaUsAkNbIXf8+nXK+BQBYr5Xb/n1+edOWAGC1Rq779+my5lsAgM1azaJ/n1/etCUAWGg0m/59uqz5FgCAaHb9+/zypi1HBmC2/ft0WfMtRgWA+/f8hM77fKn6tBwNgC7695IojgRAN/17AFCmAPfv+bh/ULZsDOveT4Au+/eSaPYKQNf9ewAweP8eAAzevwcAg/fvAcDg/XsAMHj/fmQA0L+XrP7M3gtA/164+OxuDn0A9O8VCh9degcA/XvF4ns+AdC/Vy685xMA/ftGxfd2AqB/37Dwnk6AIZ6/N6htVkjrm8Bhnr/PqoaBkRUAwz1/b1DbrJAWAAz5/H1WNQyMWgIw9PP3BrXNCtkCAPTvs0phY6QNAPr3NnXNjqoFAPr32SWwNdQAAP1725oWRZcEAP37Iul9GEsBgP69j3oWZyEBwFEiqvr92uKssUBMgVoAxBKBIxsFAICN7m6iAgA3pbBJ5B/HiF2QrT6M+QAAAABJRU5ErkJggg==',
};

const shape = {
  star,
  diamond,
  circle,
  triangleTop,
  square,
  rectangle,
  ellipse,
  arrowRight,
};

export default shape;

看看通过图片绘制的效果:

05255.gif

好像看着还不错吧?😊 起码形状看起来像那么一回事了。

容器大小变化,图像也不会乱掉了,只是等比例缩小而已,可以自个试试哈。

然而,你以为这就完了❓

⏰当然还没,你发现没有,当形状选择正方形和长方形的时候,这玩意变成圆形了?😬

image.png 0AE05E18.jpg

分析了一下原因,主要还是数据量的问题,由于绘制的图片里面形状过大,数据量又不够,大概是这样子:

image.png

为啥中间有一个圆呢?因为咱们还有一个 shape 属性设置的值是 circle

还记得 maskImage 属性的描述吗?

"它允许你提供一个图像,它会从绘图文本中排除白色区域的轮廓图像。"

原文描述:
A silhouette image which the white area will be excluded from drawing texts.
The shape option will continue to apply as the shape of the cloud to grow.

那么,如何解决这个问题呢?

简单嘛,数据量不够,加数据不就行啦?真是个聪明的小伙!😁

image.png

确实,是能解决的。其实也可以调整一下容器大小(.container)或者配置中的 width/height 属性也可以解决,然而,真就这样子❓

当然不是,💢谁能保证一定有那么多数据量或者尺寸适中呢!!!

这会,细心的你一定发现...了吧💯,如果我们能将上面中间的圆形也变成正方形是不是就可以了呢❓

可惜的是 shape 属性仅支持circle/cardioid/diamond...就是没有正方形和长方形,咋整?

不怕,shape 属性还支持回调函数(callback function)形式,这个特性可以让咱们自定义各种所需的形状。但这需要你有较好的数学和算法能力,反正小编我是没有,俺只能从网上找现成的捡过来用。🙊

关于如何创建形状的计算公式,你可以先从 echarts-wordcloud源码 中模仿。
其中数学计算可以用这个网站辅助:传送门

shape 属性的回调函数形式要如何使用?才能让其支持正方形呢?其实上面已经写过了,可以看看 shape.js 文件,里面每个形状对象(看正方形的对象)还有另外一个属性,就是为此准备的。

setOptions() {
  ...
  const shapeConfig = shape[this.shape];
  // 让shape属性形状也和提供的图像形状对应上,避免少量数据时出现的异常
  seriesItem.shape = shapeConfig.shape;
  const maskImage = new Image();
  ...
}

看效果:

image.png

即使只有少量的数据也能保持图像的形状,这就很棒了!😀

好,到这里,词云图的形状功能相信你已经能得心应手,任何形状都不在话下了,咱们就继续其他功能。🏃

颜色设置

搞定了形状,接下来令人期待的功能肯定就是颜色啦🌈,现在的词云图全是单一的蓝色,显得有些单调,花里胡哨快安排起来。😉

词云图的颜色配置可以分为两种方式:全局设置和单个词语的设置。

全局随机颜色:

_options: {
  series: [
    {
      ...,
      // 全局样式
      textStyle: {
        // 固定一种颜色
        // color: 'red',
        // 随机颜色
        color: function () {
            return 'rgb(' + [
                Math.round(Math.random() * 160),
                Math.round(Math.random() * 160),
                Math.round(Math.random() * 160)
            ].join(',') + ')';
        }
      },
    },
  ],
},
image.png

单个设置:

{ name: "深圳", value: 164910, textStyle: { color: 'red' } },
image.png

而咱们需要完成的效果如下:

05256.gif

配色规则大致是这样子的:设定几个主题,每个主题下有若干个颜色,然后通过计算每项数据的 name 属性的哈希编码,再将其与主题下的颜色对应。

产生的效果就是在同一个主题下,某项数据{name: '橙某人'}对应的颜色永远会是某一个颜色,不会改变。

具体实现:

// utils.js
/**
 * @name 通过字符串的hash得到对应的颜色
 * @param { string } str: 目标字符串
 * @param { string[] } colors: 颜色模版
 * @returns { Array<string> }
 */
export function getStringColor(str, colors = []) {
  if (!str) return colors[0];
  if (!colors || colors.length === 0) return;
  return colors[getBKDRHASH(str) % colors.length];
}

/**
 * @name 字符串hash
 * @param { string } str: 目标字符串
 * @returns { number } 
 * @description BKDRHASH是一种字符哈希算法,可以自行查阅资料
 */
export function getBKDRHASH(str) {
  const seed = 131;
  let hash = 0;
  let charCode = 0;
  let index = 0;
  while ((charCode = str.charCodeAt(index))) {
    hash = (hash * seed + charCode) % Number.MAX_SAFE_INTEGER; // 求余来防止溢出
    index++;
  }
  return hash;
}
<script>
...
import { getStringColor } from './utils';

export default {
  data() {
    return {
      ...,
      themeValue: '1'
    }
  },
  computed: {
    ...,
    themeOptions() {
      return [
        {
          name: '姹紫嫣红', value: '1', color: ['#02E1FD','#7F96FD','#02C0FF','#FF0270','#FFA621','#FEE600','#27F28E','#96F62A','#F98639','#28D5D7','#F4F452','#768EFF'],
        },
        {
          name: '馥郁芬芳', value: '2', color: ['#07EDE9','#FF7D6C','#FFDD71','#81FFC3','#E3A3FC','#F8FFA3','#9286FE','#9AEE8C','#F4F452','#02C0FD','#B598FF','#738CFF'],
        },
        {
          name: '蔚蓝海岸', value: '3', color: ['#94E5FA', '#69CCF0','#9AF1E8','#4AC5DE','#5AA9FF','#4EAFF4','#5BE4C5','#43BBD9','#37CAFF','#70E2FF','#4096F3','#719FFC'],
        },
      ]
    }
  },
  methods: {
    ...,
    setOptions() {
      ...
      seriesItem.data = data.map(item => ({
        ...item,
        textStyle: {
          color: getStringColor(item.name, theme.color)
        }
      }));
      ...
    }
  },
}
</script>

这下就足够花里胡哨了吧,产品经理看了都说好。

0BD81457.jpg

排列方式

接下来要讲的是词云图的排列方式,也就是"文本"的旋转角度问题。

观察上面展示过的词云图,文本的旋转角度📐基本都是-90度、-45度、0度、45度、90度。

这是因为咱们设置了 rotationRange 属性与 rotationStep 属性。

// 文字旋转角度范围 
rotationRange: [-90, 90], 
// 步长, 在[-90, 90]范围内随机旋转,-90/-45/0/45/90 
rotationStep: 45,

而咱们要来做一个如下功能:

05257.gif

具体实现:

<script>
...

/** @name 排列方式 **/
const SORT = {
  horizontal: {
    rotationRange: [0, 0],
    rotationStep: 0,
  },
  diagonal: {
    rotationRange: [-90, 90],
    rotationStep: 7,
  },
  blendHV: {
    rotationRange: [0, 90],
    rotationStep: 90,
  },
  blendHC: {
    rotationRange: [0, 90],
    rotationStep: 45,
  },
};

export default {
  data() {
    return {
      ...,
      sortValue: 'horizontal'
    }
  },
  computed() {
    sortOptions() {
      return [
        { label: '横向', value: 'horizontal' },
        { label: '对角线', value: 'diagonal' },
        { label: '横竖混排', value: 'blendHV' },
        { label: '横切混排', value: 'blendHC' },
      ];
    }
  },
  methods: {
    setOptions() {
      ...,
      // 排列方式
      const sortConfig = SORT[this.sortValue];
      if (sortConfig) {
        seriesItem.rotationRange = sortConfig.rotationRange;
        seriesItem.rotationStep = sortConfig.rotationStep;
      }
      ...
    }
  }
}
</script>

应该不是很难吧,很好理解的啦。😀 😀 😀

  • 横向:所有文本都不旋转。
  • 对角线:理想下是所有文本应该是旋转-45度、45度、135度、-135度,但是好像无法整出来😵。换了一个想法,只要不产生横和竖的角度就行,所以让文本都按7度的步长去随机,这样出来的效果好像也还行。🙈
  • 横竖混排:所有文本都不旋转或者旋转90度。
  • 横切混排:所有文本都不旋转或者旋转45度。

🔉产品经理小要求:文本不要倒着展示。

image.png

字体设置

😀 讲完了比较复杂的功能,接下来就是一些辅助性的小功能了。

比如我们可以设置字体的大小范围、字体类型等。

<script>
export default {
  data() {
    return {
      ...,
      fontRange: {
            min: 12,
            max: 24,
      },
      fontFamilyValue: '微软雅黑'
    }
  },
  computed() {
    fontFamilyOptions() {
      return [
        'Arial',
        'Courier New',
        'Georgia',
        'Helvetica',
        'Impact',
        'times new roman',
        'Trebuchet ms',
        'Verdana',
        '仿宋',
        '华文仿宋',
        '华文宋体',
        '华文楷体',
        '宋体',
        '微软雅黑',
        '黑体',
        '楷体',
        '方正楷体',
        '方正黑体',
        '方正仿宋',
      ].map(item => ({ label: item, value: item }))
    }
  },
  methods: {
    setOptions() {
      ...,
      // 字号范围
      seriesItem.sizeRange = [
        this.widget.fontRange.min,
        this.widget.fontRange.max,
      ];
      // 字体设置
      const fontFamily = this.widget.fontFamily;
      if (fontFamily) {
        seriesItem.textStyle.fontFamily = fontFamily;
      }
      ...
    }
  }
}
</script>
05261.gif

tooltip

_options: {
  tooltip: {
    show: true,
  },
  ...
}
image.png

图片下载

/** @name 导出图片 **/
downloadPicture(name) {
  const base64 = this._chart?.getDataURL({
    type: 'png',
    pixelRatio: 1.5,
    backgroundColor: '#fff',
  });
  const fileName = name + '_' + new Date().getTime();
  const link = document.createElement('a');
  link.download = fileName;
  link.style.display = 'none';
  link.href = base64;
  document.body.appendChild(link);
  link.click();
  URL.revokeObjectURL(link.href);
  document.body.removeChild(link);
}

点击事件

/** @name 初始化图表 **/
initChart() {
  this.$nextTick(() => {
      if (this._chart) this._chart.dispose();
      if (this.$refs?.container) {
        this._chart = echarts.init(this.$refs.container);
      }
      if (!this._chart) return;
      // 尺寸自适应
      addListener(this.$refs.container, this.resizeHandler);
      // 事件绑定
      this._chart.on(
      'click',
          throttle(params => this.handleClick(params), 350, {
            leading: true,
            trailing: false,
          }),
      );
      this._chart.clear();
      this.setOptions();
  });
}

完整源码

传送门 👈👈👈





至此,本篇文章就写完啦,撒花撒花。

image.png

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。