const [startAngle, setStartAngle] = useState<number>(90)
const [endAngle, setEndAngle] = useState<number>(90)
const [delayOverdue, setDelayOverdue] = useState<any>([])
const [dueOverdue, setDueOverdue] = useState<any>([])
const circle1Radius = 100;
const circle2Radius = 80;
const [isCanvas, setIsCanvas] = useState<any>(true)
let size: any = useSize(document.querySelector('#divpie'));
useUpdateEffect(() => {
if (isCanvas) {
pieFn(startAngle)
}
}, [size]);
const { loading: loadMARKET, run: runMARKET } = useRequest(GET_SERVICE_STAGING_OVERDUE_MARKET, {
manual: true,
onSuccess: (list: { error_code: number; data: any; msg: any }) => {
if (list.error_code != 0) {
return
}
const aa = list.data.delayOverdue
aa[0].itemStyle = {
normal: {
borderColor: '#fff',
borderWidth: '2',
shadowColor: '#b3e4f1'
}
}
aa[1].itemStyle = {
normal: {
borderColor: '#fff',
borderWidth: '2',
shadowColor: '#b1a9fd'
}
}
const bb = list.data.dueOverdue
bb[0].itemStyle = {
normal: {
borderColor: '#fff',
borderWidth: '2',
shadowColor: '#f2dac4'
}
}
bb[1].itemStyle = {
normal: {
borderColor: '#fff',
borderWidth: '2',
shadowColor: '#ebd9ad'
}
}
setDueOverdue(list.data.dueOverdue)
setDelayOverdue(list.data.delayOverdue)
const pieChart = calculatePieChartAngles(list.data.dueOverdue);
const pieChartsmall = calculatePieChartAngles(list.data.delayOverdue);
let chpre = parseInt((parseInt(pieChart[0].angle) / 2).toString())
let chpre2 = parseInt((parseInt(pieChartsmall[0].angle) / 2).toString())
setStartAngle(chpre)
setEndAngle(chpre2)
if (list.data.dueOverdue && list.data.dueOverdue[0].value == 0) {
setIsCanvas(false)
} else {
setIsCanvas(true)
pieFn(chpre)
}
}
})
const calculatePieChartAngles = (data) => {
const total = data.reduce((acc, item) => acc + item.value, 0);
return data.map((item, index) => {
const itemPercentage = item.value / total;
const itemAngle = itemPercentage * 360;
return { ...item, angle: itemAngle, key: index };
});
}
const getTwoCenter = (ele: { width: number, height: number }) => {
let CenterX = parseInt((ele['width'] / 4).toString())
let CenterY = parseInt((ele['height'] / 2).toString())
let secondX = parseInt((CenterX * 3).toString())
return {
first: { x: CenterX, y: CenterY },
second: { x: secondX, y: CenterY }
}
}
const calculateTangentPoints = (px:number, py:number, cx:number, cy:number, r:number) => {
let distance = Math.sqrt((px - cx) * (px - cx) + (py - cy) * (py - cy));
let length = Math.sqrt(distance * distance - r * r);
if (distance <= r) {
console.log("输入的数值不在范围内");
return;
}
let ux = (cx - px) / distance;
let uy = (cy - py) / distance;
let angle = Math.asin(r / distance);
let q1x = ux * Math.cos(angle) - uy * Math.sin(angle);
let q1y = ux * Math.sin(angle) + uy * Math.cos(angle);
let q2x = ux * Math.cos(-angle) - uy * Math.sin(-angle);
let q2y = ux * Math.sin(-angle) + uy * Math.cos(-angle);
q1x = q1x * length + px;
q1y = q1y * length + py;
q2x = q2x * length + px;
q2y = q2y * length + py;
return [{ x: q1x, y: q1y }, { x: q2x, y: q2y }]
}
const pieFn = (chpre: any) => {
if (!size['width']) return
let result_center = getTwoCenter(size)
let arr1half: any = chpre > 90 ? 90 : chpre
let arr2half = 360 - arr1half
const arr1Rad = (arr1half * Math.PI) / 180;
const arr2Rad = (arr2half * Math.PI) / 180;
const bottompiex = result_center['first']['x'] + Math.cos(arr1Rad) * circle1Radius;
const bottompiey = result_center['first']['y'] + Math.sin(arr1Rad) * circle1Radius;
const toppiex = result_center['first']['x'] + Math.cos(arr2Rad) * circle1Radius;
const toppiey = result_center['first']['y'] + Math.sin(arr2Rad) * circle1Radius;
let bottompoint:any = calculateTangentPoints(bottompiex, bottompiey, result_center['second']['x'], result_center['second']['y'], circle2Radius)
let toppoint:any = calculateTangentPoints(toppiex, toppiey, result_center['second']['x'], result_center['second']['y'], circle2Radius)
let canvas = document.getElementById('targetcanvas')
canvas.width = size.width
canvas.height = size.height
var ctx = canvas.getContext("2d")
ctx.imageSmoothingEnabled = true
ctx.imageSmoothingQuality = 'high'
ctx.beginPath()
ctx.moveTo(bottompiex, bottompiey)
ctx.lineTo(bottompoint[0]['x'], bottompoint[0]['y'])
ctx.strokeStyle = '#cccccc'
ctx.lineWidth = 1
ctx.fill()
ctx.stroke()
ctx.beginPath()
ctx.moveTo(toppiex, toppiey)
ctx.lineTo(toppoint[1]['x'], toppoint[1]['y'])
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 1
ctx.fill();
ctx.stroke();
}
const option1: ECOption = {
tooltip: {
trigger: 'item',
formatter: (params) => {
const { name, value, percent } = params;
const divcontent = `<div style="padding: 10px 2px;color:black;display:flex;justifyContent:start">
<div>
<div style="padding: 4px 0px;color:#333333">${name}</div>
<div style="padding: 4px 0px;color:#333333"><span style="display:inline-block;width:10px;height:10px;line-height:10px;border-radius:50%;background-color:#7262fd;margin-right:10px"></span>金额:${value}</div>
<div style="padding: 4px 0px;color:#333333"><span style="display:inline-block;width:10px;height:10px;line-height:10px;border-radius:50%;background-color:#45cbf1;margin-right:10px"></span>百分比:${percent}%</div></div>
`
return divcontent;
},
},
legend: false,
color: [
"#45cbf1",
"#7262fd",
],
series: [
{
name: '占比图1',
type: 'pie',
radius: circle1Radius,
startAngle: startAngle,
data: dueOverdue,
minAngle: 3,
emphasis: {
label: {
show: false,
},
scale: 0,
},
label: {
show: false,
position: 'center'
},
}
]
};
const option2: ECOption = {
tooltip: {
trigger: 'item',
formatter: (params) => {
const { name, value, percent } = params;
const divcontent = `<div style="padding: 10px 2px;color:black;display:flex;justifyContent:start">
<div>
<div style="padding: 4px 0px;color:#333333">${name}</div>
<div style="padding: 4px 0px;color:#333333"><span style="display:inline-block;width:10px;height:10px;line-height:10px;border-radius:50%;background-color:#ffb607;margin-right:10px"></span>金额:${value}</div>
<div style="padding: 4px 0px;color:#333333"><span style="display:inline-block;width:10px;height:10px;line-height:10px;border-radius:50%;background-color:#ff860f;margin-right:10px"></span>百分比:${percent}%</div></div>
`
return divcontent;
},
},
color: [
"#ff860f",
"#ffb607",
],
legend: false,
series: [
{
name: '占比图2',
type: 'pie',
radius: circle2Radius,
data: delayOverdue,
startAngle: endAngle,
minAngle: 3,
emphasis: {
label: {
show: false,
},
scale: 0,
},
label: {
show: false,
position: 'center'
},
}
]
};
<div className="desktop_overduePie_con">
<canvas id="targetcanvas" className="isShowCanvas" style={{ opacity: isCanvas ? 1 : 0 }} />
<div id="divpie">
{
isCanvas ? (
<div className="pieCharts_flex">
<div className="pieCharts">
<ReactEChartsCore
echarts={echarts}
option={option1}
theme={"theme_name"}
style={{ width: "100%", height: "240px" }}
/>
</div>
<div className="pieCharts">
<ReactEChartsCore
echarts={echarts}
option={option2}
theme={"theme_name"}
style={{ width: "100%", height: "240px" }}
/>
</div>
</div>
) : (<div style={{ display: 'flex', width: '100%' }} >
<div className="pieCharts" style={{ width: '100%', position: 'relative', }}>
<ReactEChartsCore
echarts={echarts}
option={option1}
theme={"theme_name"}
style={{ width: "100%", height: "240px" }}
/>
</div>
</div>)
}
</div>
</div>