最近在学习鸿蒙App开发,刚好学到画折线图这部分,也有一些第三方库,功能确实很强大,基本都满足一般的需要。本着学习的态度,弄清楚原理,就手动做了demo,以备记录。好了,废话少说,直接上代码。
interface Point {
x:number;
y:number;
}
@Entry
@Component
export struct TestChartPage {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
@State temPoint:Point[] = []
aboutToAppear(): void {
let tempAry:Point[] = []
const count = 10
const maxWidth = ResManager.getScreenWidth() - 60
const offset = maxWidth / (count - 1)
const yArray:number[] = [100,167,226,175,316,280,230,195,163,100]
for (let i = 0;i < count;i++){
let y = yArray[i] / 470 * 200
let mode:Point = {x:offset * i,y:yArray[i]}
tempAry.push(mode)
}
this.temPoint = tempAry
}
private calculateControlPoints(points: Point[], tension: number = 0.5):[Point[],Point[]]{
const cp1: Point[] = [];
const cp2: Point[] = [];
const n = points.length;
const k = tension / 3;
for (let i = 0; i < n; i++) {
const p0 = points[Math.max(0, i - 1)];
const p1 = points[i];
const p2 = points[Math.min(n - 1, i + 1)];
const p3 = points[Math.min(n - 1, i + 2)];
// 计算后向控制点 (CP1)
const cp1x = p1.x + (p2.x - p0.x) * k;
const cp1y = p1.y + (p2.y - p0.y) * k;
cp1.push({ x: cp1x, y: cp1y });
// 计算前向控制点 (CP2)
const cp2x = p2.x - (p3.x - p1.x) * k;
const cp2y = p2.y - (p3.y - p1.y) * k;
cp2.push({ x: cp2x, y: cp2y });
}
return [cp1,cp2]
}
@Builder testMoreView(){
Canvas(this.context)
.backgroundColor(Color.Orange)
.width('100%')
.height(400)
.onReady(() => {
this.context.strokeStyle = '#0078ff';
this.context.lineWidth = 2;
const result = this.calculateControlPoints(this.temPoint)
let path = new Path2D()
this.context.moveTo(this.temPoint[0].x,this.temPoint[0].y)
const cp1:Point[] = result[0]
const cp2:Point[] = result[1]
for (let i = 0; i < this.temPoint.length - 1; i++) {
// 绘制三次贝塞尔曲线
this.context.bezierCurveTo(
cp1[i].x, cp1[i].y, // 当前段起点控制点 (CP1)
cp2[i].x, cp2[i].y, // 当前段终点控制点 (CP2)
this.temPoint[i + 1].x,
this.temPoint[i + 1].y
);
}
this.context.lineTo(this.temPoint[this.temPoint.length - 1].x,400)
this.context.lineTo(this.temPoint[0].x,400)
this.context.lineTo(this.temPoint[0].x,this.temPoint[0].y)
// 创建渐变填充
const gradient = this.context.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(135, 206, 235, 0.3)'); // 半透明蓝色
gradient.addColorStop(0.5, 'rgba(135, 206, 235, 0.5)'); // 完全透明
gradient.addColorStop(1, 'rgba(135, 206, 235, 1)'); // 完全透明
this.context.stroke();
this.context.closePath()
this.context.fillStyle = gradient;
this.context.fill();
})
}
build() {
Column() {
this.testMoreView()
}
.height('100%')
.width('100%')
.padding({left:30,right:30})
}
}
最终的效果图如下:
图2
图3