flutter 自定義view 繪製曲線統計圖

__蘇啵曼發表於2019-09-19

在flutter中圖表框架目前相對較少,且不太符合專案需求,本篇文章將介紹如何運用自定義view完成曲線統計圖的繪製,最終效果如圖.

flutter 自定義view 繪製曲線統計圖

繪製背景線條

 /// 畫背景線
  void darwBackgroundLine(Canvas canvas) {
    painter.strokeWidth = 1.2; // 線條寬度
    painter.color = Color(0xffEBECF0);
    for (int i = 0; i < LINE_NUM - 1; i++) {
      // 繪製橫線
      canvas.drawLine(Offset(yTextwidth, i * LINE_SPACE + Y_TEXT_HEIGHT), Offset(width, i * LINE_SPACE + Y_TEXT_HEIGHT), painter);
    }
    painter.strokeWidth = 1.4; // 最後一條線條較粗
    painter.color = Color(0xffC4C6CF);
    // 繪製橫線
    canvas.drawLine(Offset(yTextwidth, (LINE_NUM - 1) * LINE_SPACE + Y_TEXT_HEIGHT),
        Offset(width, (LINE_NUM - 1) * LINE_SPACE + Y_TEXT_HEIGHT), painter);
  }
複製程式碼

繪製文字,X,Y值及標題

 /// 座標抽文字
  void xyText(Canvas canvas) {
    // y軸標題
    textPainter.text = TextSpan(
      text: lineChartBean.yRemindText,
      style: new TextStyle(
        color: Color(0xff303133),
        fontSize: S(20),
      ),
    );
    textPainter.layout();
    textPainter.paint(canvas, Offset(0, 0));

    // y 軸文字
    for (int i = 0; i < LINE_NUM; i++) {
      textPainter.text = TextSpan(
        text: '${(LINE_NUM - i - 1) * 1000}',
        style: new TextStyle(
          color: Colors.black,
          fontSize: S(24),
        ),
      );
      textPainter.layout();
      textPainter.paint(canvas,
          Offset((yTextwidth - textPainter.width) / 2, i * LINE_SPACE - textPainter.height / 2 + Y_TEXT_HEIGHT));
    }

    double xTextWidth = width - yTextwidth;
    var temp = xTextWidth / 4;
    // x 文字
    for (int i = 1; i < 5; i++) {
      textPainter.text = TextSpan(
        text: '$i 月',
        style: new TextStyle(
          color: Colors.black,
          fontSize: 12,
        ),
      );
      textPainter.layout();
      textPainter.paint(
          canvas,
          Offset(yTextwidth + temp * i - temp / 2 - textPainter.width / 2,
              (LINE_NUM - 1) * LINE_SPACE + 6 + Y_TEXT_HEIGHT));
    }
  }
複製程式碼

繪製曲線

在flutter中可以通過Path繪製線條,把已知的四個點連起來,就是基本的折線統計圖,但要繪製出點與點之前平滑過渡的曲線,就需要另外一個方法得到曲線的座標,這個方法就是cos函式.

做之前先回憶一下cos長啥樣.

flutter 自定義view 繪製曲線統計圖

繪製所需要的就是0 ~ 2π 間的曲線.

  /// 獲取曲線路徑
  /// [v1] 第一個Y軸值 [v2] 第二個Y軸值
  /// [index] X軸座標位置
  Path getCurvePath(double v1, double v2, int index, Path path) {
    int clipNum = 30; // 一段曲線被分割繪製的數量,越大麴線越平滑.
    double temp = 1 / clipNum; // 遍歷運算用到的臨時數值
    bool isNegativeNumber; // 是否為負數
    double diff = (v1 - v2).abs(); // 兩點之間的差值
    isNegativeNumber = (v1 - v2) < 0; // 判斷正負
    for (int i = 0; i < clipNum; i++) {
      path.lineTo(
        // x點座標值,x軸不參與cos運算
        getX(temp * i + index.toDouble()),
        // y點座標值
        // 公式 y = cos(v) + 1 , isNegativeNumber 為true時,用到的是π~2π之間的曲線,為false時,用到的是0~π間的曲線.
        // 通過公式運算之後再與實際大小做比相乘得出實際結果,新增到Path
        getY((cos((isNegativeNumber ? pi : 0) + pi * temp * i) + 1) * diff / 2 + (isNegativeNumber ? v1 : v2)));
    }
    // 返回Path
    return path;
  }

  /// 獲取Y軸座標
  double getY(double value) => (MAX_VALUE - value) / MAX_VALUE * (LINE_NUM - 1) * LINE_SPACE + Y_TEXT_HEIGHT;

  /// 獲取X軸座標
  double getX(double index) => yTextwidth + unitWidth / 2 + index * unitWidth;

複製程式碼
// 最後用drawPath完成整段繪製.
canvas.drawPath(path, painter);
複製程式碼

最後

以上為全部內容,如有錯誤請指正.

完整demo地址

相關文章