# 如何绘制一条优秀的GPA曲线

(1)准备工作

```//
<xyz.rickygao.gpa2.view.GpaLineChartView
android:id="@+id/cv_gpa_line"
android:layout_width="match_parent"
android:layout_height="320dp"
android:background="@color/gpa2_color_secondary"
app:fillColor="@color/gpa2_color_primary"
app:lineColor="@color/gpa2_color_primary_dark"
app:pointColor="@color/gpa2_color_primary_dark" />

//```

(2)绘制思路

• 创建画笔
• 确定上述基准线
• 确定起点，t0，t1… … 终点坐标
• 计算每两点之间三阶贝塞尔曲线路径

(3)代码实现

```//
data class DataWithDetail(val data: Double, val detail: String)
var dataWithDetail: List<DataWithDetail> = emptyList()
//```

```//
val widthStep = contentWidth.toFloat() / (dataWithDetail.size + 1)
//```

```//
val minData = dataWithDetail.minBy(DataWithDetail::data)?.data ?: 0.0
val maxData = dataWithDetail.maxBy(DataWithDetail::data)?.data ?: 1.0
val dataSpan = if (maxData != minData) maxData - minData else 1.0
val minDataExtended = minData - dataSpan / 4F
val maxDataExtended = maxData + dataSpan / 4F
val dataSpanExtended = maxDataExtended - minDataExtended
//```

```//
(0 until dataWithDetail.size).mapTo(pointsX.apply { clear() }) {
paddingLeft + widthStep * (it + 1)
}
//```

```//
dataWithDetail.mapTo(pointsY.apply { clear() }) {
paddingTop + ((1 - ((it.data - minDataExtended) / dataSpanExtended)) * contentHeight).toFloat()
}
//```

```//
var py = (paddingTop + contentHeight).toFloat()
moveTo(0F, py)
//```

```//
val cx = width - widthStep / 2F
//```

```//
drawPath(linePath, linePaint)
//```

```//
fillPath.apply {
reset()
lineTo(width.toFloat(), height.toFloat())
lineTo(0F, height.toFloat())
close()
}
//```

```//
pointPath.apply {
reset()
if (dataWithDetail.isEmpty())
return@apply // no need to draw
(0 until dataWithDetail.size)
.filter { it != selectedIndex }
.forEach {
pointsX[it] - LINE_STROKE / 4F,
pointsY[it] - LINE_STROKE / 4F,
Path.Direction.CCW
)
}
}
//```

（4）细节

```//
(0 until dataWithDetail.size).mapTo(pointsX.apply { clear() })
//```

```//
fillPath.apply {
reset()
lineTo(width.toFloat(), height.toFloat())
lineTo(0F, height.toFloat())
close()
}
//```

```//
var lineColor
get() = linePaint.color
set(value) {
linePaint.color = value
}
//```

## 《微北洋-代码读后感(1)》有108个想法

• 上官轩明说：

多亏画图工具强大，不然就剩一堆代码了0，0