扇形图比例封装
扇形图主要依靠CanvasRenderingContext2D的arc接口来实现。
封装:
// 扇形图子组件
@Component
export struct CustomPieChart {
// 获取上下文
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// 饼图数据
@Prop picChartElements: PicChartElement[] = [
new PicChartElement('A', 10.00),
new PicChartElement('B', 10.00),
new PicChartElement('C', 10.00),
new PicChartElement('D', 10.00),
new PicChartElement('E', 10.00)
]
// 圆半径
@State circle_radius: number = 60
// 单位
@State unit: string = ""
// 总资产
@Prop money: string = ''
// 颜色数组
@Prop colors: string[] = [
"#3c6ef5", "#76a0ff", "#79d4fe", "#926cfd", "#ae5dba",
"#c67cd3", "#c43f5e", "#f4a994", "#fe6833", "#efd796"
]
/**
* 计算并绘制饼图
*/
private drawPieChart(): void {
// 计算总数
let total = 0
this.picChartElements.forEach((value) => {
total += value.quantity
})
// 初始化弧线的起始弧度
let startAngle = -0.5 * Math.PI
// 为每个扇形计算角度和颜色
this.picChartElements.forEach((value, index) => {
const percent = value.quantity / total
value.percent = percent
value.beginAngle = startAngle
value.endAngle = startAngle + (percent * 2 * Math.PI)
value.color = this.colors[index % this.colors.length]
// 更新起始角度为当前扇形的结束角度
startAngle = value.endAngle
})
// 重置画布并绘制饼图
this.context.reset()
this.picChartElements.forEach((item) => {
// 开始新的路径
this.context.beginPath()
// 移动到圆心
this.context.moveTo(this.circle_radius, this.circle_radius)
// 绘制扇形弧线
this.context.arc(
this.circle_radius,
this.circle_radius,
this.circle_radius,
item.beginAngle,
item.endAngle
)
// 闭合路径回到圆心
this.context.closePath()
// 设置填充颜色并填充
this.context.fillStyle = item.color
this.context.fill()
})
}
aboutToAppear() {
this.drawPieChart()
}
build() {
Row({ space: 10 }) {
// 饼图区域
Stack() {
Canvas(this.context)
.height('100%')
.width('100%')
.onReady(() => {
this.drawPieChart()
})
// 中心圆和总资产显示
Stack() {
Circle({ width: this.circle_radius * 2 - 15, height: this.circle_radius * 2 - 15 })
.stroke('#FFFFFF')
.fill('#FFFFFF')
Text(this.money + '\n总资产')
.textAlign(TextAlign.Center)
.maxLines(-1)
.width('100%')
.height('100%')
}
.width(this.circle_radius * 2 - 15)
.height(this.circle_radius * 2 - 15)
}
.width(this.circle_radius * 2)
.height(this.circle_radius * 2)
// 间距
Blank()
.layoutWeight(1)
// 图例区域
Column() {
ForEach(this.picChartElements, (item: PicChartElement) => {
Row({ space: 10 }) {
// 颜色标识
Divider()
.vertical(true)
.height(10)
.strokeWidth(5)
.color(item.color)
// 文本和数值
Row() {
Text(item.element)
.fontSize(12)
.textAlign(TextAlign.Start)
.layoutWeight(1)
Text(item.quantity + this.unit)
.fontSize(12)
.textAlign(TextAlign.End)
}
.layoutWeight(1)
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.height(30)
.alignItems(VerticalAlign.Center)
})
}
.width(130)
}
.width('100%')
.padding({ left: 20, right: 20 })
}
}
/**
* 饼图元素数据类
*/
export class PicChartElement {
element: Resource | string // 显示文本
quantity: number // 数量
percent: number = 0 // 百分比
beginAngle: number = 0 // 弧线的起始弧度
endAngle: number = 0 // 弧线的终止弧度
color: string // 颜色
constructor(element: Resource | string, quantity: number, color: string = '') {
this.element = element
this.quantity = quantity
this.color = color
}
}
使用:
@Entry
@Component
struct Page {
@State message: string = 'Hello World';
build() {
Column() {
CustomPieChart({
picChartElements: [
new PicChartElement('A', 10.00),
new PicChartElement('B', 10.00),
new PicChartElement('C', 10.00),
],
money: '¥ 10,000.00',
unit: '万',
colors: [
"#c67cd3", "#c43f5e", "#f4a994", "#fe6833", "#efd796"
],
})
}
.width('100%')
.height('100%')
}
}