效果图:

实现代码如下

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){
                canvasCtx.strokeStyle = '#FF6951'
                canvasCtx.lineWidth = toRpx(4)  // 设置线宽
                canvasCtx.beginPath()
                for (let m = 0; m < numCount; m  ){
                    let x = mCenter   mRadius * Math.cos(mAngle * m - Math.PI / 2) * mData[m][1] / 100
                    let y = mCenter   mRadius * Math.sin(mAngle * m - Math.PI / 2) * mData[m][1] / 100
                    canvasCtx.lineTo(x, y)
                }
                canvasCtx.closePath()
                canvasCtx.fillStyle = color
                canvasCtx.fill()
                canvasCtx.stroke()
            },
        },
        mounted() {
            this.initDrawRadar()
        }
    }
</script>

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

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封装小程序雷达图组件的文章就介绍到这了,更多相关uniapp封装小程序雷达图组件内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

uniapp封装小程序雷达图组件的完整代码的更多相关文章

  1. 用vue3封装一个符合思维且简单实用的弹出层

    最近新项目中需要一个弹窗组件,所以我就做了一个,下面这篇文章主要给大家介绍了关于如何利用vue3封装一个符合思维且简单实用的弹出层,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  2. uniapp中vuex的应用使用步骤

    Vuex是一个专为Vue.js应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,下面这篇文章主要给大家介绍了关于uniapp中vuex的应用使用,需要的朋友可以参考下

  3. Node.js中对通用模块的封装方法

    这篇文章主要介绍了Node.js中对通用模块的封装方法,封装方法参考了Underscore.js的实现,需要的朋友可以参考下

  4. java封装及四种权限修饰符详解

    这篇文章主要介绍了java封装及四种权限修饰符详解,对属性进行封装,使用户不能直接输入数据,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值

  5. 在vue中如何封装G2图表

    这篇文章主要介绍了在vue中如何封装G2图表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  6. JS样式获取的封装方法实例详解

    这篇文章主要介绍了JS样式获取的封装方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  7. Ajax基础教程之封装(三)

    这篇文章给大家介绍ajax基础教程之封装的知识,本文通过实例给大家详细介绍,非常不错,感兴趣的朋友一起学习吧

  8. JavaScript函数封装的示例详解

    这篇文章主要通过动画的示例来为大家详细介绍一下JavaScript的函数封装,文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下

  9. uniapp打包成微信小程序的详细过程

    微信小程序的出现给我们提供了一种使用应用的新方式和体验,下面这篇文章主要给大家介绍了关于uniapp打包成微信小程序的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下

  10. Flutter Dio二次封装的实现

    这篇文章主要介绍了Flutter Dio二次封装的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部