HarmonyOS Next 有遮盖的折线图

118 阅读2分钟

最近在学习鸿蒙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})
  }
}

最终的效果图如下:

WechatIMG592.jpg

图2

WechatIMG594.jpg

图3

WechatIMG593.jpg