效果图:

view

<canvas id="radar-canvas" class="radar-canvas" type="2d"></canvas>

style

.radar-canvas
width 550rpx
height 550rpx
margin 0 auto

script

<script>
import { toRpx } from "@/utils/common" const numCount = 5 //元素个数
const numSlot = 4 //一条线上的总节点数
const mW = toRpx(275) //Canvas的宽度
const mCenter = mW / 2 //中心点
const mAngle = Math.PI * 2 / numCount //角度
const mRadius = mCenter - toRpx(43) //半径(减去的值用于给绘制的文本留空间) let canvas = null // canvas
let canvasCtx = null // canvas context export default {
name: 'RadarChart',
props: {
},
methods: {
// 初始化雷达图,在组件挂载的时候执行
initDrawRadar() {
console.log('init')
const query = uni.createSelectorQuery().in(this)
query.select('#radar-canvas').fields({ node: true, size: true }).exec((res) => {
canvas = res[0].node
canvasCtx = canvas.getContext('2d')
const dpr = uni.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
canvasCtx.scale(dpr, dpr)
})
},
// 开始执行绘制
handleDraw(radarData) {
this.drawEdge()
this.drawLinePoint()
this.drawText(radarData)
this.drawSubText(radarData)
this.drawEdgeDot()
this.drawRegion(radarData, 'rgba(255, 105, 81, 0.4)')
},
// 绘制圆边
drawEdge() {
canvasCtx.strokeStyle = '#EEEEEE'
for (let i = 0; i < numSlot; i++) {
// 计算半径
let radius = mRadius / numSlot * (i + 1)
if (i === 3) {
canvasCtx.lineWidth = toRpx(4) // 设置线宽
canvasCtx.beginPath()
canvasCtx.arc(mCenter, mCenter, radius, 0, 2 * Math.PI,) // 开始画圆
canvasCtx.stroke()
} else {
canvasCtx.lineWidth = toRpx(1)
const space = 60 + 10 * (i+1)
this.drawDashCircle(mCenter, mCenter, radius, space)
}
}
},
// 绘制外边框圆点
drawEdgeDot(x, y) {
canvasCtx.fillStyle = '#EEEEEF'
canvasCtx.beginPath()
for (let k = 0; k < numCount; k++) {
let x = mCenter + mRadius * Math.cos(mAngle * k - Math.PI / 2)
let y = mCenter + mRadius * Math.sin(mAngle * k - Math.PI / 2)
canvasCtx.arc(x, y, toRpx(5), Math.PI * 2, 0, true)
canvasCtx.closePath()
}
canvasCtx.fill()
},
// 绘制虚线圆
drawDashCircle(x, y, radius, space = 100) {
const gap = 2 * Math.PI / space
canvasCtx.lineCap ='square' let start = 0; //从原点开始画
while (start <= 2 * Math.PI) {
let end = start + gap
canvasCtx.beginPath() //开始一个新的路径
canvasCtx.arc(x, y, radius, start, end, false)
start = gap + end
canvasCtx.stroke() //对当前路径进行描边
}
},
// 绘制连接点
drawLinePoint() {
canvasCtx.lineWidth = toRpx(1)
canvasCtx.beginPath()
for (let k = 0; k < numCount; k++) {
let x = mCenter + mRadius * Math.cos(mAngle * k - Math.PI / 2)
let y = mCenter + mRadius * Math.sin(mAngle * k - Math.PI / 2)
canvasCtx.moveTo(mCenter, mCenter)
canvasCtx.lineTo(x, y)
}
canvasCtx.stroke()
},
// 绘制文本信息
drawText(mData) {
canvasCtx.fillStyle = '#222325'
canvasCtx.font = `bold ${toRpx(14)}px PingFangSC-Medium, PingFang SC` //设置字体
for (let n = 0; n < numCount; n++) {
let x = mCenter + mRadius * Math.cos(mAngle * n - Math.PI / 2)
let y = mCenter + mRadius * Math.sin(mAngle * n - Math.PI / 2)
//通过不同的位置,调整文本的显示位置
const text = mData[n][0]
if (n === 0) {
canvasCtx.fillText(text, x - toRpx(12), y - toRpx(30))
}
if (n === 1) {
canvasCtx.fillText(text, x + toRpx(12), y)
}
if (n === 2) {
canvasCtx.fillText(text, x + toRpx(12), y + toRpx(20))
}
if (n === 3) {
canvasCtx.fillText(text, x - toRpx(36), y + toRpx(20))
}
if (n === 4) {
canvasCtx.fillText(text, x - toRpx(40), y)
}
}
},
// 绘制文本信息
drawSubText(mData) {
canvasCtx.fillStyle = '#8D949B'
canvasCtx.font = `${toRpx(11)}px PingFangSC-Medium, PingFang SC` //设置字体
for (let n = 0; n < numCount; n++) {
const x = mCenter + mRadius * Math.cos(mAngle * n - Math.PI / 2)
const y = mCenter + mRadius * Math.sin(mAngle * n - Math.PI / 2)
//通过不同的位置,调整文本的显示位置
const text = `(${mData[n][1]})`
if (n === 0) {
canvasCtx.fillText(text, x - canvasCtx.measureText(text).width / 2, y - toRpx(10))
}
if (n === 1) {
canvasCtx.fillText(text, x + canvasCtx.measureText(text).width, y + toRpx(16))
}
if (n === 2) {
canvasCtx.fillText(text, x + canvasCtx.measureText(text).width - toRpx(4), y + toRpx(40))
}
if (n === 3) {
canvasCtx.fillText(text, x - canvasCtx.measureText(text).width - toRpx(12), y + toRpx(40))
}
if (n === 4) {
canvasCtx.fillText(text, x - canvasCtx.measureText(text).width - toRpx(16), y + toRpx(16))
}
}
},
//绘制红色数据区域(数据和填充颜色)
drawRegion(mData, color){
// 关注公众号《码克吐温》获取完整代码
},
},
mounted() {
this.initDrawRadar()
}
}
</script>

要注意的点是,这里是封装成组件调用,在初始化的时候,const query = uni.createSelectorQuery().in(this),要加上in(this),否则会报找不到node节点的错误信息

toRpx方法是将数字大小转化为rpx响应式单位大小,方法如下:

export function toRpx(val) {
const res = uni.getSystemInfoSync()
const scaleRate = res.windowWidth / 375
return val * scaleRate
}

在页面中调用

<template>
<!--雷达图-->
<radar-chart :radarData="radarData" ref="radarRef"></radar-chart>
</template> import RadarChart from './components/radar' export default {
components: {
RadarChart,
},
data() {
return {
radarData:[["听力", 0], ["口语",0], ["语法",0], ["词汇",0], ["阅读",0]],
}
},
methods: {
getData() {
// 请求数据返回后,调用组件方法渲染
this.$refs.radarRef.handleDraw(this.radarData)
}
}
}

最后,欢迎关注本人公众号:(码克吐温)及时获取博客内容更新~

uniapp封装小程序雷达图组件实现的更多相关文章

  1. 支付宝小程序日期选择组件datePicker封装

    github 地址 https://github.com/iocool/antminDatePicker 最近在做支付宝小程序(以下简称小程序)开发,发现小程序的日期选择组件很不好用,比如安卓和IOS ...

  2. uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤

    uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤 这里以vant-weapp为例 uni-app官方文档介绍引入组件的方法 1. 新建相关目录 根目录下创建 wxcomponen ...

  3. 【重点突破】—— UniApp微信小程序开发教程学习Three

    一.实战 HBuilderX:在微信小程序中运行页面,需要设置->安全 开启微信小程序服务端口,HBuilder工具->设置->配置程序路径 网络请求.模板语法.打开页面.页面传参 ...

  4. 小程序解决方案 Westore - 组件、纯组件、插件开发

    数据流转 先上一张图看清 Westore 怎么解决小程序数据难以管理和维护的问题: 非纯组件的话,可以直接省去 triggerEvent 的过程,直接修改 store.data 并且 update,形 ...

  5. 微信小程序之自定义组件的应用

    小程序支持自定义组件,下面是一个简单的购物车组件,实现的效果如图: 效果图 创建组件 在根目录创建components目录,然后创建计数组件 count 如图: 组件内容 <!--compone ...

  6. 微信小程序自定义音频组件,自定义滚动条,单曲循环,循环播放

    小程序自定义音频组件,带滚动条 摘要:首先自定义音频组件,是因为产品有这样的需求,需要如下样式的 而微信小程序API给我们提供的就是这样的 而且产品需要小程序有后台播放功能,所以我们不考虑小程序的 a ...

  7. uniapp开发小程序

    uniapp开发小程序 uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS.Android.Web(响应式).以及各种小程序(微信/支付宝/百度/头条 ...

  8. 微信小程序引入ECharts组件

    首先打开ECharts网页 https://echarts.apache.org/zh/tutorial.html#%E5%9C%A8%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8 ...

  9. 原创:WeZRender:微信小程序Canvas增强组件

    WeZRender是一个微信小程序Canvas增强组件,基于HTML5 Canvas类库ZRender. 使用 WXML: <canvas style="width: 375px; h ...

随机推荐

  1. Qt5双缓冲机制与实例

    1. 双缓冲机制 所谓双缓冲机制,是指在绘制控件时,首先将要绘制的内容绘制在一个图片中,再将图片一次性地绘制到控件上. 在早期的Qt版本中,若直接在控件上进行绘制工作,则在控件重绘时会产生闪烁的现象, ...

  2. PyCharm代码区不能编辑的解决办法

    问题: 修改之前的Python代码时发现代码区无法编辑,无意中输入i后又可以编辑了. 解决: 原因是打开了工具中的vim Emulator编辑模式,把vim Emulator前面的勾取消即可.

  3. clickhouse分布式集群

    一.环境准备: 主机 系统 应用 ip ckh-01 centos 8 jdk,zookeeper,clickhouse 192.168.205.190 ckh-02 centos 8 jdk,zoo ...

  4. react-router4 介绍

    react-router 的理解: 1) react 的一个插件库2) 专门用来实现一个 SPA 应用3) 基于 react 的项目基本都会用到此库 SPA  的理解: 1) 单页 Web 应用(si ...

  5. Pytest单元测试框架之FixTure基本使用

    前言: 在单元测试框架中,主要分为:测试固件,测试用例,测试套件,测试执行及测试报告: 测试固件不难理解,也就是我们在执行测试用例前需要做的动作和测试执行后的需要做的事情: 比如在UI自动化测试中,我 ...

  6. 优化 Workerman 检查主进程是否存活的逻辑

    主要新增了判断进程是否为 Workerman 进程的逻辑,从而优化了确定主进程是否存活的准确性 发现问题 年前逛 GitHub 的时候,发现 Workerman 有一个 2017 年打开的 Issue ...

  7. windows下搭建vue开发环境实践

    Vue.js是一套构建用户界面的 "渐进式框架".与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已 ...

  8. 每天五分钟Go - 函数基础

    函数在定义 Go的函数使用func来定义,返回类型支持多个值的返回 func 函数名([参数列]) [返回值类型]{ 方法执行体 } 参数列支持多个参数的声明,同一类型的函数,声明时和变量的声明一样 ...

  9. Matplotlib和Seaborn演示Python可视化

    数据可视化:就是使用图形图表等方式来呈现数据,图形图表能够高效清晰地表达数据包含的信息. Seaborn是基于matplotlib,在matplotlib的基础上进行了更高级的API封装,便于用户可以 ...

  10. 第十五篇 -- QListWidget与QToolButton(界面)

    效果图: 这还只是一个界面,并没有实现相应功能. 先看下这图的构成吧. 工具栏的就是将Action拖上去,这部分前面已经介绍过了,那就看下面这部分的构图. 1.左侧是一个工具箱(ToolBox)组件, ...