【HarmonyOS】Canves绘制《渐变折线图》

115 阅读3分钟

废话不多说,先把效果图搞上来。代码写的比较烂,想用的自己直接上手改。

image.png

看懂这份代码,基础绘图难不到你。 直接贴代码,主打一个量大管饱。

//绘制几何图形
private settings: RenderingContextSettings = new RenderingContextSettings(true)
//用来创建CanvasRenderingContext2D对象,通过在canvas中调用CanvasRenderingContext2D对象来绘制。
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private xTitles: string[] = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期七'];
private yTitles: number[] = [0, 5, 10, 15, 20];
private dataList: number[] = [10, 13, 2, 7, 8, 17, 3];

//绘制折线
@Builder drawLineLayer() {
  Column({ space: 20 }) {
    Text('折线图-基础功能');
    Canvas(this.context)
      .backgroundColor(0xF5DC62)
      .onReady(() => {
        //父视图width: 300 height: 300
        let marginRight = 10;
        let marginLeft = 30;
        let marginTop = 30;
        let marginBottom = 30;
        let areaWidth = 300.0 - marginLeft - marginRight;
        let areaHeight = 300.0 - marginTop - marginBottom
        let xWidth = areaWidth / (this.xTitles.length);
        let yLabel: number = 300 - 10;
        //绘制x轴
        //数组最大值
        this.context.beginPath()
        var pointValues: Point[] = [];
        for (let index = 0; index < this.xTitles.length; index++) {
          const element = this.xTitles[index];
          let x: number = index * xWidth + marginLeft;
          this.context.font = '24px';
          this.context.textAlign = 'start';
          this.context.strokeText(element, x, yLabel);
          //绘制贝塞尔曲线-造点
          const valueElement = parseFloat(this.dataList[index].toString());
          if (valueElement > 0) {
            const percentValue = valueElement / 20.0;
            const percentY = 300 - marginBottom - percentValue * areaHeight; //valueY
            pointValues.push({ x: x, y: percentY });
          }
        }
        //创建路径
        let valueLinePath = new Path2D();
        if (pointValues.length > 1) {
          this.context.beginPath();
          let point1 = pointValues[0];
          let point2 = pointValues[pointValues.length - 1];
          let point0: Point = { x: point1.x, y: 300 - marginBottom };
          let pointEnd: Point = { x: point2.x, y: 300 - marginBottom };
          pointValues.splice(0, 0, point0);
          pointValues.push(pointEnd);
          valueLinePath.moveTo(point1.x, point1.y)
          for (let index = 0; index < pointValues.length - 3; index++) {
            let p0: Point = pointValues[index];
            let p1: Point = pointValues[index+1];
            let p2: Point = pointValues[index+2];
            let p3: Point = pointValues[index+3];
            this.getControlPointPath(p0, p1, p2, p3, 300 - marginBottom, valueLinePath);
          }
          //路径封闭
          valueLinePath.lineTo(pointValues[pointValues.length - 1].x, pointValues[pointValues.length - 1].y)
          valueLinePath.lineTo(pointValues[0].x, pointValues[0].y)
          this.context.strokeStyle = '#13d8c1';
          this.context.stroke(valueLinePath)
          this.context.fillStyle = "rgb(255,0,0)"

          let gradientLayer = this.context.createLinearGradient(pointValues[0].x, pointValues[0].y, pointValues[pointValues.length - 1].x, pointValues[pointValues.length - 1].y);
          gradientLayer.addColorStop(0.0, '#ff0000')
          gradientLayer.addColorStop(1, '#00ff00')
          this.context.fillStyle = gradientLayer //先给图层填充渐变图层
          // this.context.fillRect(marginLeft, marginTop, areaWidth, areaHeight)
          this.context.fill(valueLinePath, 'evenodd') //对封闭路径进行填充
          //删除造的首尾点
          pointValues.splice(0, 1);
          pointValues.splice(pointValues.length - 1, 1)
          for (let index = 0; index < pointValues.length; index++) {
            const point = pointValues[index];
            this.context.beginPath();
            this.context.arc(point.x, point.y, 3, 0, 6.28);
            this.context.fillStyle = '#F13153'
            this.context.fill();
          }
        }
        //绘制轴线
        let lineY = 300 - marginBottom;
        let axisLinePath = new Path2D();
        axisLinePath.moveTo(marginLeft, lineY);
        axisLinePath.lineTo(marginLeft, marginTop);
        axisLinePath.moveTo(marginLeft, lineY);
        axisLinePath.lineTo(300 - marginRight, lineY);
        axisLinePath.closePath();
        this.context.strokeStyle = '#999999';
        this.context.stroke(axisLinePath)
        //绘制y轴
        let yAxisHeight = areaHeight / (this.yTitles.length - 1);
        for (let index = 0; index < this.yTitles.length; index++) {
          const element = this.yTitles[index];
          let y: number = 300 - index * yAxisHeight - marginBottom;
          this.context.font = '30px #333333';
          this.context.strokeStyle = '#0x333333';
          this.context.textAlign = 'center';
          this.context.strokeText(element.toString(), 15, y);
        }

      })
  }.width(300).height(300)
}
//根据四点获取一个path
private getControlPointPath(p0: Point, p1: Point, p2: Point, p3: Point, maxY: number, path: Path2D) {
  let smooth_value = 0.7;
  var ctrl1_x;
  var ctrl1_y;
  var ctrl2_x;
  var ctrl2_y;
  let xc1 = (p0.x + p0.x) / 2.0;
  let yc1 = (p0.y + p1.y) / 2.0;
  let xc2 = (p1.x + p2.x) / 2.0;
  let yc2 = (p1.y + p2.y) / 2.0;
  let xc3 = (p2.x + p3.x) / 2.0;
  let yc3 = (p2.x + p3.y) / 2.0;
  let len1 = Math.sqrt((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y));
  let len2 = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
  let len3 = Math.sqrt((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y));
  let k1 = len1 / (len1 + len2);
  let k2 = len2 / (len2 + len3);
  let xm1 = xc1 + (xc2 - xc1) * k1;
  let ym1 = yc1 + (yc2 - yc1) * k1;
  let xm2 = xc2 + (xc3 - xc2) * k2;
  let ym2 = yc2 + (yc3 - yc2) * k2;
  ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + p1.x - xm1;
  ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + p1.y - ym1;
  ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + p2.x - xm2;
  ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + p2.y - ym2;
  ctrl1_y = ctrl1_y > maxY ? maxY : ctrl1_y;
  ctrl2_y = ctrl2_y > maxY ? maxY : ctrl2_y;
  path.bezierCurveTo(ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, p2.x, p2.y);
}

嘎嘎嘎,我也是为鸿蒙做贡献的人了。是不是遥遥领先~~~~~