说明:这个是先画出一个72度菱形,长中长线和短中长线按照一定比例,然后把菱形分层十份,最后再把菱形进行旋转形成五角星,最后显示标签,因为一直对不上所以对标签做了点操作
<template><view class="container"><canvas canvas-id="diamondCanvas" class="canvas":style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas></view>
</template><script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';interface DiamondItem {name: string;value: number;
}@Component
export default class DiamondCanvas extends Vue {private canvasWidth: number = 350;private canvasHeight: number = 350;private scale: number = 40;private longAxis: number = 3;private shortAxis: number = 1.5;private distance: number = 1;private colors: string[] = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF','#FF9F40', '#8AC249', '#EA5F89', '#0D98BA', '#D27D46'];// 新增:定义橙红色边框颜色private borderColor: string = '#FF6B35'; // 橙红色private borderWidth: number = 3; // 线条粗细(默认3px,可按需调整)@Prop({type: Array,default: () => [{ name: '指标1', value: 5 },{ name: '指标2', value: 7 },{ name: '指标3', value: 6 },{ name: '指标4', value: 8 },{ name: '指标5', value: 4 }],validator: (items: DiamondItem[]) =>items.length === 5 && items.every(item =>item.value >= 0 && item.value <= 10 && Number.isInteger(item.value))}) readonly diamondData!: DiamondItem[];mounted() {this.drawDiamondsWithLabels();}@Watch('diamondData', { deep: true })onDiamondDataChange() {this.drawDiamondsWithLabels();}private drawDiamondsWithLabels() {const ctx = wx.createCanvasContext('diamondCanvas', this);ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);const centerX = this.canvasWidth / 2;const centerY = this.canvasHeight / 2;const pivotY = (this.longAxis / 2) * this.scale;const labelRadius = this.scale * 3.2;const initialRotation = -36 * Math.PI / 180;const angleInterval = 72 * Math.PI / 180;for (let i = 0; i < 5; i++) {const diamondAngle = initialRotation + (i * angleInterval);ctx.save();ctx.translate(centerX, centerY);ctx.rotate(diamondAngle);ctx.translate(0, pivotY);this.drawSingleDiamond(ctx, this.diamondData[i].value, this.colors[i]);ctx.restore();const prevIndex = (i - 1 + 5) % 5;const labelAngle = initialRotation + (prevIndex * angleInterval) + Math.PI;ctx.save();ctx.translate(centerX, centerY);const labelX = Math.cos(labelAngle) * labelRadius;const labelY = Math.sin(labelAngle) * labelRadius;ctx.setFontSize(12);ctx.setFillStyle('#333333');ctx.setTextAlign('center');ctx.setTextBaseline('middle');ctx.fillText(this.diamondData[i].name, labelX, labelY - 10);ctx.setFontSize(14);ctx.setFillStyle(this.colors[i]);ctx.fillText(this.diamondData[i].value.toString(), labelX, labelY + 10);ctx.restore();}ctx.draw();}private drawSingleDiamond(ctx: any, value: number, color: string) {const top = { x: 0, y: this.longAxis / 2 };const bottom = { x: 0, y: -this.longAxis / 2 };const right = { x: this.shortAxis / 2, y: top.y - this.distance };const left = { x: -this.shortAxis / 2, y: top.y - this.distance };// 绘制边框 - 使用橙红色ctx.beginPath();ctx.moveTo(top.x * this.scale, -top.y * this.scale);ctx.lineTo(right.x * this.scale, -right.y * this.scale);ctx.lineTo(bottom.x * this.scale, -bottom.y * this.scale);ctx.lineTo(left.x * this.scale, -left.y * this.scale);ctx.closePath();ctx.setStrokeStyle(this.borderColor); // 关键修改:使用橙红色边框ctx.setLineWidth(this.borderWidth); // 关键:设置线条粗细ctx.stroke();// 分段计算(保持不变)const h1 = top.y - right.y;const h2 = right.y - bottom.y;const totalSegments = 10;const ratio = h1 / (h1 + h2);const n1 = Math.max(1, Math.round(totalSegments * ratio));const n2 = totalSegments - n1;const segmentH1 = h1 / n1;const segmentH2 = h2 / n2;// 上半部分绘制(修正边缘衔接)for (let i = 0; i < n1; i++) {// 关键修正:让当前段的y2与下一段的y1完全一致(避免缝隙)const y1 = top.y - i * segmentH1;const y2 = top.y - (i + 1) * segmentH1; // 精确计算,无偏差const width1 = this.shortAxis * ((top.y - y1) / h1);const width2 = this.shortAxis * ((top.y - y2) / h1);const segmentColor = i < value ? color : '#FFFFFF';// 绘制时增加0.5px偏移,抵消抗锯齿导致的白边this.drawDiamondSegment(ctx, y1, y2, width1, width2, segmentColor);}// 下半部分绘制(修正边缘衔接)for (let i = 0; i < n2; i++) {// 关键修正:让当前段的y2与下一段的y1完全一致const y1 = right.y - i * segmentH2;const y2 = right.y - (i + 1) * segmentH2; // 精确计算,无偏差const width1 = this.shortAxis * ((y1 - bottom.y) / h2);const width2 = this.shortAxis * ((y2 - bottom.y) / h2);const segmentColor = (n1 + i) < value ? color : '#FFFFFF';// 绘制时增加0.5px偏移,抵消抗锯齿导致的白边this.drawDiamondSegment(ctx, y1, y2, width1, width2, segmentColor);}}// 绘制单个颜色块(增加偏移抵消白边)private drawDiamondSegment(ctx: any, y1: number, y2: number, width1: number, width2: number, color: string) {ctx.beginPath();// 关键修正:y坐标增加0.5px偏移,避免Canvas抗锯齿产生的白边const offset = 0.5;ctx.moveTo(-width1 / 2 * this.scale, -y1 * this.scale + offset);ctx.lineTo(width1 / 2 * this.scale, -y1 * this.scale + offset);ctx.lineTo(width2 / 2 * this.scale, -y2 * this.scale + offset);ctx.lineTo(-width2 / 2 * this.scale, -y2 * this.scale + offset);ctx.closePath();ctx.setFillStyle(color);ctx.fill();// 确保没有隐藏的线条绘制(如果有stroke()会导致边缘线,这里保持注释)// ctx.stroke(); // 彻底移除线条绘制,避免产生边界线}
}
</script><style scoped>
.container {display: flex;justify-content: center;align-items: center;width: 100%;height: 100vh;
}.canvas {border: 1px solid #eee;background-color: #f9f9f9;
}
</style>