Files
tra-app/src/pages/course/components/chartSix.vue
T

341 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="chart-box" :style="allStyle">
<view class="cont-box">
<view v-for="width in 7" :class="'total-line total-line' + width"></view>
<view v-for="width in 3" :class="`percent-${width * 25}`"></view>
<view class="data-box">
<view class="line-box">
<view v-for="width in 3" :class="`percent-${width * 25}`"></view>
</view>
</view>
</view>
<view class="title" v-if="fromType === 'crs'">
<image class="title-icon" src="@/static/images/course/edit.png" alt=""> </image>
改进建议
</view>
<view class="title" v-if="fromType === 'tra'">
<image class="title-icon icon-tra" src="@/static/images/sparring/den-icon.png" alt=""> </image>
维度分析
</view>
<view class="total-score" v-if="fromType === 'crs'">
<view class="score-num">{{ score }}</view>
<image class="total-score-icon" src="@/static/images/course/score.png" alt=""></image>
</view>
<view v-for="(item,index) in dataList" :class="['score-item', 'score-item'+(index+1)]">
<view class="score-item-name">{{ item.gradeDimensName || item.gradeDimens }}</view>
<view class="score-item-score">{{ item.anlyGrade }}</view>
</view>
</view>
</template>
<script>
export default{
props:{
dataList:{
default:() => [],
type: Array
},
score:{
default: 0,
type: [Number,String]
},
size:{
default: 262,
type: [Number,String]
},
fromType:{
default: 'crs',
type: String
}
},
data(){
return {
}
},
computed:{
dataValue(){
return this.dataList.map(t=>t.anlyGrade)
},
chartWidth(){
return this.size + 'rpx'
},
chartHeight(){
return this.size + 'rpx'
},
styleFive(){
return this.generateHeptagonClipPath()
},
styleFiveResult(){
return this.generateHeptagonDataClipPath()
},
verticesList(){
return this.calculateHeptagonVertices()
},
allStyle(){
let _obj = {
'--styleFive': this.styleFive,
'--styleFiveResult': this.styleFiveResult,
'--chartWidth': this.chartWidth,
'--chartHeight': this.chartHeight,
'--boxSize': this.size + 'rpx'
}
this.verticesList.forEach((t,index)=>{
_obj[`--pointX${index+1}`] = t.x/100
_obj[`--pointY${index+1}`] = t.y/100
// _obj[`--pointX${index+1}`] = t.cssX
// _obj[`--pointY${index+1}`] = t.cssY
})
return _obj
}
},
methods:{
// 正七边形顶点计算函数
calculateHeptagonVertices(radius = 50, angleOffset = 0) {
const sides = 6;
const vertices = [];
const centerX = 50;
const centerY = 50;
// 将角度偏移转换为弧度
const offsetRad = (angleOffset * Math.PI) / 180;
for (let i = 0; i < sides; i++) {
// 计算每个顶点的角度(弧度)
const angle = (2 * Math.PI * i) / sides + offsetRad;
// 计算顶点坐标(百分比)
const x = centerX + radius * Math.cos(angle);
const y = centerY + radius * Math.sin(angle);
// 计算顶点坐标(百分比)
const dataX = centerX + radius * Math.cos(angle) * this.dataValue[i] / 100;
const dataY = centerY + radius * Math.sin(angle) * this.dataValue[i] / 100;
vertices.push({
x: x,
y: y,
cssX: x + '%',
cssY: y + '%',
dataX: dataX + '%',
dataY: dataY + '%'
});
}
return vertices;
},
// 生成CSS clip-path多边形值
generateHeptagonClipPath(radius = 50, angleOffset = 0) {
const vertices = this.calculateHeptagonVertices(radius, angleOffset);
const polygonPoints = vertices.map(v => `${v.cssX} ${v.cssY}`).join(', ');
return `polygon(${polygonPoints})`;
},
// 生成CSS clip-path多边形值
generateHeptagonDataClipPath(radius = 50, angleOffset = 0) {
const vertices = this.calculateHeptagonVertices(radius, angleOffset);
const polygonPoints = vertices.map(v => `${v.dataX} ${v.dataY}`).join(', ');
return `polygon(${polygonPoints})`;
}
}
}
</script>
<style lang="scss" scoped>
.chart-box{
width: 100%;
height: 580rpx;
background:linear-gradient( 270deg, #4a74ff 0%, #6fa7fe 100%);
overflow: hidden;
position: relative;
border-radius: 16rpx;
margin-bottom: 20rpx;
.cont-box{
background-color: #87abfe;
width: var(--chartWidth);
height: var(--chartHeight);
clip-path: var(--styleFive);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-top: 25rpx;
.total-line{
width: 100%;
height: 3rpx;
background: linear-gradient(90deg, #00000000 0% 50%, rgba(255, 255, 255, .3) 50% 100%);
position: absolute;
overflow: hidden;
z-index: 20;
top: 50%;
left: 0%;
&.total-line1{
transform: rotateZ(calc(360deg * 1 / 6));
}
&.total-line2{
transform: rotateZ(calc(360deg * 2 / 6));
}
&.total-line3{
transform: rotateZ(calc(360deg * 3 / 6));
}
&.total-line4{
transform: rotateZ(calc(360deg * 4 / 6));
}
&.total-line5{
transform: rotateZ(calc(360deg * 5 / 6));
}
&.total-line6{
transform: rotateZ(calc(360deg * 6 / 6));
}
}
@for $i from 1 through 3 {
.percent-#{$i*25}{
width: $i * 25%;
height: $i * 25%;
clip-path: var(--styleFive);
background-color: rgba(255, 255, 255, .3);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: (4 - $i) * 2;
&::before{
content: '';
display: block;
width: calc(100% - 10rpx);
height: calc(100% - 10rpx);
background-color: #87abfe;
clip-path: var(--styleFive);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.data-box{
width: 100%;
height: 100%;
clip-path: var(--styleFiveResult);
position: absolute;
background-color: #fff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 12;
overflow: hidden;
.line-box{
display: block;
width: calc(100% - 24rpx);
height: calc(100% - 24rpx);
// background-color: #6691fe;
background-color: #6691fe;
clip-path: var(--styleFiveResult);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 14;
}
@for $i from 1 through 3 {
.percent-#{$i*25}{
background-color: rgba(255, 255, 255, .1);
z-index: (4 - $i) * 2 + 10;
&::before{
background-color: #6692ff;
}
}
}
}
}
.title{
padding: 24rpx;
line-height: 46rpx;
font-size: 32rpx;
color: #fff;
position: relative;
.title-icon {
width: 27rpx;
height: 27rpx;
&.icon-tra{
position: relative;
top: 4rpx;
width: 32rpx;
height: 32rpx;
}
}
}
.total-score{
position: absolute;
right: 30rpx;
top:30rpx;
width: 100rpx;
height: 80rpx;
line-height: 70rpx;
font-size: 30rpx;
color: #fff;
white-space: nowrap;
text-shadow: 0 4px 12px rgba(0, 0, 0, .33);
.score-num{
display: inline-block;
font-size: 60rpx;
line-height: 70rpx;
font-weight: bold;
}
.total-score-icon{
width: 100%;
height: 16rpx;
position: absolute;
bottom:0;
left:0;
}
}
.score-item{
position: absolute;
color: #fff;
width: 120rpx;
text-align: center;
.score-item-name{
font-size: 28rpx;
line-height: 36rpx;
margin-bottom: 4rpx;
}
.score-item-score{
font-size: 38rpx;
line-height: 46rpx;
font-weight: bold;
}
&.score-item1{
left: 50%;
top: 50%;
transform: translate(calc(-50% + var(--boxSize)/2 + 60rpx), -50%);
margin-top: 25rpx;
}
&.score-item2{
left: calc(var(--pointX2) * var(--boxSize));
top: calc(50% + (var(--pointY2) * var(--boxSize) / 2));
transform: translate(calc(-50% + var(--boxSize)/2 + 80rpx), 30rpx);
}
&.score-item3{
left: calc(var(--pointX3) * var(--boxSize));
top: calc(50% + (var(--pointY3) * var(--boxSize) / 2));
transform: translate(calc(-50% + var(--boxSize)/2 + 50rpx), 30rpx);
}
&.score-item4{
left: calc(var(--pointX4) * var(--boxSize));
top: 50% ;
transform: translate(calc(-50% + var(--boxSize)/2 - 10rpx), -50%);
margin-top: 25rpx;
}
&.score-item5{
left: calc(var(--pointX5) * var(--boxSize));
top: calc(50% + (var(--pointY5) * var(--boxSize) / 2));
transform: translate(calc(-50% + var(--boxSize)/2 + 50rpx), calc(-160rpx - 50%));
}
&.score-item6{
left: calc(var(--pointX6) * var(--boxSize));
top: calc(50% + (var(--pointY6) * var(--boxSize) / 2));
transform: translate(calc(-50% + var(--boxSize)/2 + 80rpx), calc(-160rpx - 50%));
}
}
}
</style>