uniapp封裝小程序雷達(dá)圖組件的完整代碼
效果圖:

實(shí)現(xiàn)代碼如下
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 //元素個(gè)數(shù)
const numSlot = 4 //一條線上的總節(jié)點(diǎn)數(shù)
const mW = toRpx(275) //Canvas的寬度
const mCenter = mW / 2 //中心點(diǎn)
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: {
// 初始化雷達(dá)圖,在組件掛載的時(shí)候執(zhí)行
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)
})
},
// 開(kāi)始執(zhí)行繪制
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++) {
// 計(jì)算半徑
let radius = mRadius / numSlot * (i + 1)
if (i === 3) {
canvasCtx.lineWidth = toRpx(4) // 設(shè)置線寬
canvasCtx.beginPath()
canvasCtx.arc(mCenter, mCenter, radius, 0, 2 * Math.PI,) // 開(kāi)始畫(huà)圓
canvasCtx.stroke()
} else {
canvasCtx.lineWidth = toRpx(1)
const space = 60 + 10 * (i+1)
this.drawDashCircle(mCenter, mCenter, radius, space)
}
}
},
// 繪制外邊框圓點(diǎn)
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; //從原點(diǎn)開(kāi)始畫(huà)
while (start <= 2 * Math.PI) {
let end = start + gap
canvasCtx.beginPath() //開(kāi)始一個(gè)新的路徑
canvasCtx.arc(x, y, radius, start, end, false)
start = gap + end
canvasCtx.stroke() //對(duì)當(dāng)前路徑進(jìn)行描邊
}
},
// 繪制連接點(diǎn)
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` //設(shè)置字體
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)
//通過(guò)不同的位置,調(diào)整文本的顯示位置
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` //設(shè)置字體
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)
//通過(guò)不同的位置,調(diào)整文本的顯示位置
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))
}
}
},
//繪制紅色數(shù)據(jù)區(qū)域(數(shù)據(jù)和填充顏色)
drawRegion(mData, color){
canvasCtx.strokeStyle = '#FF6951'
canvasCtx.lineWidth = toRpx(4) // 設(shè)置線寬
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>
要注意的點(diǎn)是,這里是封裝成組件調(diào)用,在初始化的時(shí)候,const query = uni.createSelectorQuery().in(this),要加上in(this),否則會(huì)報(bào)找不到node節(jié)點(diǎn)的錯(cuò)誤信息
export function toRpx(val) {
const res = uni.getSystemInfoSync()
const scaleRate = res.windowWidth / 375
return val * scaleRate
}
在頁(yè)面中調(diào)用
<template>
<!--雷達(dá)圖-->
<radar-chart :radarData="radarData" ref="radarRef"></radar-chart>
</template>
import RadarChart from './components/radar'
export default {
components: {
RadarChart,
},
data() {
return {
radarData:[["聽(tīng)力", 0], ["口語(yǔ)",0], ["語(yǔ)法",0], ["詞匯",0], ["閱讀",0]],
}
},
methods: {
getData() {
// 請(qǐng)求數(shù)據(jù)返回后,調(diào)用組件方法渲染
this.$refs.radarRef.handleDraw(this.radarData)
}
}
}
總結(jié)
到此這篇關(guān)于uniapp封裝小程序雷達(dá)圖組件的文章就介紹到這了,更多相關(guān)uniapp封裝小程序雷達(dá)圖組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
爬蟲(chóng)進(jìn)階-JS自動(dòng)渲染之Scrapy_splash組件的使用
Splash是一個(gè)Javascript渲染服務(wù)。它是一個(gè)實(shí)現(xiàn)了HTTP API的輕量級(jí)瀏覽器,Splash是用Python和Lua語(yǔ)言實(shí)現(xiàn)的,基于Twisted和QT等模塊構(gòu)建,今天重點(diǎn)給大家介紹js Scrapy_splash組件使用教程,一起看看吧2021-09-09
JavaScript其他類(lèi)型的值轉(zhuǎn)換為布爾值的規(guī)則詳解
在JavaScript中,所有的值在邏輯上下文中都會(huì)被轉(zhuǎn)換為布爾類(lèi)型(Boolean),理解這些轉(zhuǎn)換規(guī)則對(duì)開(kāi)發(fā)者來(lái)說(shuō)至關(guān)重要,尤其是在條件判斷、短路運(yùn)算、邏輯非(!)等場(chǎng)景下,正確掌握布爾轉(zhuǎn)換可以避免潛在的bug,本文將詳細(xì)介紹 JavaScript 其他類(lèi)型的值是如何轉(zhuǎn)換為布爾值的2025-04-04
JavaScript如何利用Promise控制并發(fā)請(qǐng)求個(gè)數(shù)
大家都知道js是單線程,并不存在真正的并發(fā),但是由于JavaScript的Event Loop機(jī)制,使得異步函數(shù)調(diào)用有了“并發(fā)”這樣的假象。這篇文章主要給大家介紹了關(guān)于JavaScript如何利用Promise控制并發(fā)請(qǐng)求個(gè)數(shù)的相關(guān)資料,需要的朋友可以參考下2021-05-05
JS實(shí)現(xiàn)同一個(gè)網(wǎng)頁(yè)布局滑動(dòng)門(mén)和TAB選項(xiàng)卡實(shí)例
這篇文章主要介紹了JS實(shí)現(xiàn)同一個(gè)網(wǎng)頁(yè)布局滑動(dòng)門(mén)和TAB選項(xiàng)卡效果,通過(guò)簡(jiǎn)單的自定義切換函數(shù)setTab實(shí)現(xiàn)頁(yè)面元素的遍歷及屬性切換的功能,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
Bootstrap?按鈕下拉菜單的實(shí)現(xiàn)示例
本文主要介紹了Bootstrap?按鈕下拉菜單的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07

