uniapp封装小程序雷达图组件实现
效果图:
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封装小程序雷达图组件实现的更多相关文章
- 支付宝小程序日期选择组件datePicker封装
github 地址 https://github.com/iocool/antminDatePicker 最近在做支付宝小程序(以下简称小程序)开发,发现小程序的日期选择组件很不好用,比如安卓和IOS ...
- uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤
uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤 这里以vant-weapp为例 uni-app官方文档介绍引入组件的方法 1. 新建相关目录 根目录下创建 wxcomponen ...
- 【重点突破】—— UniApp微信小程序开发教程学习Three
一.实战 HBuilderX:在微信小程序中运行页面,需要设置->安全 开启微信小程序服务端口,HBuilder工具->设置->配置程序路径 网络请求.模板语法.打开页面.页面传参 ...
- 小程序解决方案 Westore - 组件、纯组件、插件开发
数据流转 先上一张图看清 Westore 怎么解决小程序数据难以管理和维护的问题: 非纯组件的话,可以直接省去 triggerEvent 的过程,直接修改 store.data 并且 update,形 ...
- 微信小程序之自定义组件的应用
小程序支持自定义组件,下面是一个简单的购物车组件,实现的效果如图: 效果图 创建组件 在根目录创建components目录,然后创建计数组件 count 如图: 组件内容 <!--compone ...
- 微信小程序自定义音频组件,自定义滚动条,单曲循环,循环播放
小程序自定义音频组件,带滚动条 摘要:首先自定义音频组件,是因为产品有这样的需求,需要如下样式的 而微信小程序API给我们提供的就是这样的 而且产品需要小程序有后台播放功能,所以我们不考虑小程序的 a ...
- uniapp开发小程序
uniapp开发小程序 uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS.Android.Web(响应式).以及各种小程序(微信/支付宝/百度/头条 ...
- 微信小程序引入ECharts组件
首先打开ECharts网页 https://echarts.apache.org/zh/tutorial.html#%E5%9C%A8%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8 ...
- 原创:WeZRender:微信小程序Canvas增强组件
WeZRender是一个微信小程序Canvas增强组件,基于HTML5 Canvas类库ZRender. 使用 WXML: <canvas style="width: 375px; h ...
随机推荐
- Java | this的本质 和 static的本质
this 在说this之前先说一下,对象创建的过程: 1.分配对象空间,并将对象成员变量初始化. 2.执行属性值的显式初始化. 3.执行构造方法. 4.返回相关的地址给相关的对象. this的本质 ...
- java基础---设计模式(2)
结构型模式 出处:https://blog.csdn.net/zhangerqing/article/details/8239539 一.适配器模式 适配器模式将某个类的接口转换成客户端期望的另一个接 ...
- Emoji.voto,Linkerd 服务网格(service mesh)的示例应用程序
一个微服务应用程序,允许用户为他们最喜欢的表情符号(emoji)投票,并跟踪排行榜上收到的投票.愿最好的 emoji 获胜. 该应用程序由以下 3 个服务组成: emojivoto-web:Web 前 ...
- [刘阳Java]_Spring中IntrospectorCleanupListener的用途【补充】_第16讲
这篇文章不是我自己原创的,但是为了后期的阅读,所以我收录网上的一篇文章.为了尊重作者的版权,转载地址先放上来,大家也可以去访问他的原始文章.http://jadyer.cn/2013/09/24/sp ...
- VS Code 与 ESP32 官方SDK配置
开发基于 ESP XXX 微控制器应用,最简单的环境搭建方案是像 MicroPython.CircuitPython.NanoFramework 等,下载固件,直接开刷:或者基于 Arduino 的开 ...
- DWA局部路径规划算法论文阅读:The Dynamic Window Approach to Collision Avoidance。
DWA(动态窗口)算法是用于局部路径规划的算法,已经在ROS中实现,在move_base堆栈中:http://wiki.ros.org/dwa_local_planner DWA算法第一次提出应该是1 ...
- 如何热更新长缓存的 HTTP 资源
前言 HTTP 缓存时间一直让开发者头疼.时间太短,性能不够好:时间太长,更新不及时.当遇到严重问题需紧急修复时,尽管后端文件可快速替换,但前端文件仍从本地缓存加载,导致更新长时间无法生效. 对于这个 ...
- 「干货」面试官问我如何快速搜索10万个矩形?——我说RBush
「干货」面试官问我如何快速搜索10万个矩形?--我说RBUSH 前言 亲爱的coder们,我又来了,一个喜欢图形的程序员,前几篇文章一直都在教大家怎么画地图.画折线图.画烟花,难道图形就是这样嘛,当 ...
- 微信小程序云开发-数据库-更新数据
一.js文件代码使用.update更新数据 写一个更新数据的函数,函数内使用.update更新数据.一定要通过.doc指定修改哪一条数据. 二.wxml文件修改数据的按钮 在wxml文件中写[修改] ...
- Python自动化测试面试题-Selenium篇
目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...