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){
                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封装小程序雷达图组件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 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&quo

  • 微信小程序之自定义组件的实现代码(附源码)

    最近在项目开发中,遇到好多雷同的页面样式,就想着可以将常用的功能模块封装成组件,方便在项目中使用和修改,下面就参照微信小程序的文档分步骤写一个微信小程序的组件. 附上效果图: step1:创建文件并申明 与创建微信小程序的页面一样,一个自定义组件也需要json,wxml,wxss,js四个文件. 在项目根目录中创建文件夹,取名为:component,在该目录下继续创建文件夹successModal. 可以在开发工具中右键创建,选择component,默认自动会创建四个文件.如图: 在succes

  • uniapp开发小程序实现全局悬浮按钮的代码

    目录 看效果 须知: 1.uni.getSystemInfoSync()获取手机的信息接口 2.uni.createSelectorQuery().in(this) 3.touchmove滑动事件 取出存储的值 赋值 全局注册组件 看效果 这是一个全局的按钮,可以换成图片,自己写样式,每个页面都有: 须知: 1.uni.getSystemInfoSync()获取手机的信息接口 可以拿到手机屏幕的宽高 2.uni.createSelectorQuery().in(this) uniapp中式没有w

  • 微信小程序时间轴组件的示例代码

    我这里的标题是小程序的时间组件,其实我这里是将他写成了一个页面,当然,如果你有需求,将其做成一个自定义组件也可以~ 这玩意其实没有什么技术难点就是一个小页面,我这里就不赘述了.直接上代码: Remark.wxml: <view class="listview-container margin_bottom"> <block wx:for="{{newList}}" wx:key="index"> <view clas

  • 微信小程序实现跑马灯效果完整代码(附效果图)

    一:功能介绍及讲解 实现的跑马灯(跑马灯里面显示文章的title)的效果,并在右侧有个查看文章的按钮,按钮绑定当前的跑马灯信息的id,点击按钮后根据id跳转到相应的文章详情页: 这里值得注意的点是我用了swiper组件的 bindchange 事件来获取到当前信息的数组下标,实现了动态改变查看按钮绑定信息id值的效果: 如果还有不懂的地方欢迎加入(173683895)微信小程序开发交流群. 二:效果图: 三:完整源码 1.封装成一个组件: <!-- //滚动 --> <template

  • 微信小程序自定义tabBar组件开发详解

    本文实例为大家分享了微信小程序自定义tabBar组件的具体代码,供大家参考,具体内容如下 以下代码保存在github地址 先看一看目录 template文件夹里存放tabbar模板. template/template.wxml <template name="tabBar"> <view class="tabBar"> <block wx:for="{{tabBar}}" wx:for-item="ite

  • 微信小程序日期时分组件(年月日时分)

    本文实例为大家分享了微信小程序日期时分组件的具体代码,供大家参考,具体内容如下 如图所示效果 第一步新建picker组件文件 1,pickerTime.js组件代码内容 // component/pickerTime/pickerTime.js Component({ /** * 组件的属性列表 */ properties: { date: { // 属性名 type: null, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Arra

  • 微信小程序自定义toast组件的方法详解【含动画】

    本文实例讲述了微信小程序自定义toast组件的方法.分享给大家供大家参考,具体如下: 怎么创建就不说了,前面一篇有 微信小程序自定义prompt组件 直接上代码 wxml <!-- components/toast/toast.wxml --> <view class="toast-box {{isShow? 'show':''}}" animation="{{animationData}}"> <view class="to

  • 微信小程序自定义tabbar组件

    本文实例为大家分享了微信小程序自定义tabbar组件的具体代码,供大家参考,具体内容如下 由于项目需求,必须自己写组件: 第一步:在App.json中配置tabBar,自定也组件也必须配置,"custom": true,list里配置所有的tabbar页面. "tabBar": { "custom": true, "color": "red", "selectedColor": &quo

  • 微信小程序自定义地址组件

    本文实例为大家分享了微信小程序自定义地址组件的具体代码,供大家参考,具体内容如下 项目需求 需要调用后台传过来的地址,存储地址时存的是地址的id,所以市面上的地址组件均不符合我的需求,只能自定义一个. 技术选取 picker-view和picker-view-column 核心代码 region.wxml <!--地址选择器--> <view wx:if="{{show}}" class="region-picker" catchtap="

随机推荐