console
const canvas = document.getElementById('canvas')
const lineCanvas = document.createElement('canvas')
const areaCanvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const lineCtx = lineCanvas.getContext('2d')
const areaCtx = areaCanvas.getContext('2d')
const canvasW = canvas.width
const canvasH = canvas.height
areaCanvas.width = lineCanvas.width = canvasW
areaCanvas.height = lineCanvas.height = canvasH
lineCtx.translate(canvasW / 2, canvasH / 2)
ctx.translate(canvasW / 2, canvasH / 2)
areaCtx.translate(canvasW / 2, canvasH / 2)
const baseData = [
{title:'平均血糖'},
{title:'高血糖强度'},
{title:'低血糖强度'},
{title:'变异系数'},
{title:'葡萄糖未达标时间'},
]
const mData = [
{ titleList: ['爱心传递至', '3个城市'], score: 3, fullScore: 5 },
{ titleList: ['帮助了8人'], score: 5, fullScore: 10 },
{ titleList: [`收到5感谢`], score: 5, fullScore: 10 },
{ titleList: ['获得', '15人点赞'], score: 15, fullScore: 15 },
{ titleList: [`可赠送10件闲置`], score: 10, fullScore: 20 }
]
const mCount = baseData.length
const prismW = 200
const mRadius = prismW / 2 / Math.cos(108 / 2 / 180 * Math.PI)
const mAngle = Math.PI * 2 / mCount
const polygonCount = 1
const sAngle = (90 / mCount) / 180 * Math.PI
const rotateAngle = mCount % 2 === 0 ? 0 : (sAngle * (mCount % 4 === 3 ? -1 : 1))
lineCtx.rotate(-rotateAngle)
areaCtx.rotate(-rotateAngle)
const polygonPoints = []
const radarVertex = []
lineCtx.strokeStyle = '#ccc'
areaCtx.lineWidth = 1
drawPolygon()
drawVertexTxt()
function drawPolygon() {
const r = mRadius / polygonCount
let currentRadius = 0
for (let i = 0; i < polygonCount; i++) {
lineCtx.beginPath()
currentRadius = r * (i + 1)
for (let j = 0; j < mCount; j++) {
const x = currentRadius * Math.cos(mAngle * j)
const y = currentRadius * Math.sin(mAngle * j)
if (i === polygonCount - 1) {
polygonPoints.push([x, y])
}
j === 0 ? lineCtx.moveTo(x, y) : lineCtx.lineTo(x, y)
}
lineCtx.closePath()
lineCtx.stroke()
}
for (let i = 0; i < polygonPoints.length; i++) {
lineCtx.moveTo(0, 0)
lineCtx.lineTo(polygonPoints[i][0], polygonPoints[i][1])
}
lineCtx.save();
lineCtx.rotate(90 * Math.PI / 180);
lineCtx.fillText("-0", 0, -20);
lineCtx.stroke()
lineCtx.restore();
}
function drawDiagonal() {
lineCtx.save()
for (let i = 0; i < polygonPoints.length; i++) {
lineCtx.moveTo(0, 0)
lineCtx.lineTo(polygonPoints[i][0], polygonPoints[i][1])
}
lineCtx.stroke()
lineCtx.restore()
}
function drawVertexTxt() {
lineCtx.font = 'normal normal lighter 16px Arial'
lineCtx.fillStyle = '#333'
const topPointIndex = mCount - Math.round(mCount / 4)
for (let i = 0; i < polygonPoints.length; i++) {
lineCtx.save()
lineCtx.translate(polygonPoints[i][0], polygonPoints[i][1])
lineCtx.rotate(rotateAngle)
let indentX = 0
let indentY = 0
if (i === topPointIndex) {
lineCtx.textAlign = 'center'
indentY = -8
} else {
if (polygonPoints[i][0] > 0 && polygonPoints[i][1] >= 0) {
lineCtx.textAlign = 'start'
indentX = 10
} else if (polygonPoints[i][0] < 0) {
lineCtx.textAlign = 'end'
indentX = -10
}
}
if (mCount === 4 && i === 1) {
lineCtx.textAlign = 'center'
indentY = 10
}
lineCtx.fillText(baseData[i].title, indentX, indentY + 0)
lineCtx.restore()
}
}
function drawRadar() {
let score = null
let xList = []
let yList = []
for (let i = 0; i < mCount; i++) {
score = Math.min(baseData[i].score, baseData[i].fullScore)
xList.push(Math.cos(mAngle * i) * score / baseData[i].fullScore)
yList.push(Math.sin(mAngle * i) * score / baseData[i].fullScore)
radarVertex.push([mRadius * xList[i], mRadius * yList[i]])
}
const indentV = 40
areaCtx.beginPath()
for (let i = 0; i < mCount; i++) {
score = Math.min(baseData[i].score, baseData[i].fullScore)
const x = (mRadius + indentV) * xList[i]
const y = (mRadius + indentV) * yList[i]
i === 0 ? areaCtx.moveTo(x, y) : areaCtx.lineTo(x, y)
}
areaCtx.closePath()
areaCtx.clip()
const toAngle = 2 * Math.PI
const canvasMaxSize = Math.max(canvasW, canvasH)
const ltX = -canvasW / 2
const ltY = -canvasH / 2
const rqDraw = currentAngle => {
ctx.clearRect(ltX, ltY, canvasW, canvasH)
areaCtx.clearRect(ltX, ltY, canvasW, canvasH)
areaCtx.beginPath()
for (let i = 0; i < mCount; i++) {
i === 0
? areaCtx.moveTo(radarVertex[i][0], radarVertex[i][1])
: areaCtx.lineTo(radarVertex[i][0], radarVertex[i][1])
}
areaCtx.fillStyle = 'rgba(204,0,0,0.3)'
areaCtx.strokeStyle = 'red'
areaCtx.closePath()
areaCtx.stroke()
areaCtx.fill()
areaCtx.save()
areaCtx.beginPath()
areaCtx.globalCompositeOperation = 'destination-in'
areaCtx.moveTo(0, 0)
areaCtx.arc(0, 0, canvasMaxSize, 0, currentAngle)
areaCtx.closePath()
areaCtx.fillStyle = 'blue'
areaCtx.fill()
areaCtx.restore()
ctx.drawImage(lineCanvas, ltX, ltY)
ctx.drawImage(areaCanvas, ltX, ltY)
if (currentAngle === toAngle) {
}
let newAngle = currentAngle + 0.25
if (newAngle > toAngle) newAngle = toAngle
setTimeout(() => {
rqDraw(newAngle)
}, 16)
}
rqDraw(0)
}
function drawVertexDot() {
ctx.rotate(-rotateAngle)
ctx.fillStyle = '#fe5c5b'
const dotRadius = 4
const len = radarVertex.length
const rqDrawDox = currentDotRadius => {
for (let i = 0; i < len; i++) {
ctx.beginPath()
ctx.arc(radarVertex[i][0], radarVertex[i][1], currentDotRadius, 0, 2 * Math.PI)
ctx.fill()
}
if (currentDotRadius < dotRadius) {
requestAnimationFrame(() => {
rqDrawDox(currentDotRadius + 0.5)
})
}
}
rqDrawDox(1)
}
<canvas id="canvas" width="600" height="500"></canvas>