说明:这个是先画出一个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>