目录
![](https://img.haomeiwen.com/i8850933/a5d5bc51a93c1ee2.png)
效果展示
![](https://img.haomeiwen.com/i8850933/3d635f9cd01ac70e.png)
实现步骤
- 绘制正多边形
- 绘制正多边形中心点到顶点的连线
- 绘制数据所代表的值点
- 绘制数据点连起来的半透明多边形
重点公式
以(x,y)为中心,中心到顶点的距离为a,degree为旋转的角度,正N边形的顶点坐标公式为:
X=a * cos(degree)+x
Y=a * sin(degree)+y
代码展示
class CobwebView:View {
private var paint:Paint = Paint()
private var pointConPath = Path() //值点的连线路径
private var linePaths:ArrayList<Path> = ArrayList()//正多边形的路径集合
private var linePoints:ArrayList<PointF> = ArrayList()//顶点的集合
private var valuePoints:ArrayList<PointF> = ArrayList()//数据点的集合
private var valDatas = ArrayList<CobWebDataBean>()//点的数据
constructor(context: Context) : this(context,null)
constructor(context: Context, attribute: AttributeSet?) : this(context,attribute,0)
constructor(context: Context,attribute: AttributeSet?,style: Int) : super(context,attribute,style){
init()
}
private fun init() {
setLayerType(LAYER_TYPE_SOFTWARE,null)
paint.color = Color.RED
paint.strokeWidth = 2f
paint.style = Paint.Style.STROKE
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
calc()
}
/**
* 设置数据
*/
fun setDatas(datas:ArrayList<CobWebDataBean>){
valDatas = datas
calc()
postInvalidate()
}
/**
* 计算
*/
private fun calc(){
val maxRadius = width / 2
var maxVal = 0f //最大值
//计算出所有值中的最大点
for(cobWebData in valDatas){
if(maxVal < cobWebData.value){
maxVal = cobWebData.value
}
}
//有几个数据画几个正多边形
for(i in 0..valDatas.size){
val radius = maxRadius / valDatas.size * i //计算每个正多边形的顶点到中心点的距离
val path = Path()
for((index,cobWebData) in valDatas.withIndex()){
val degree = 360.0 / valDatas.size * index //计算出当前旋转的角度
val x =
(radius * cos(Math.toRadians(degree))).toFloat()//计算出当前正多边形当前顶点的X
val y =
(radius * sin(Math.toRadians(degree))).toFloat()//计算出当前正多边形当前顶点的Y
//当前正多边形的顶点连线路径
if(index == 0){
path.moveTo(x,y)
}else{
path.lineTo(x, y)
}
if(i == valDatas.size){
//记录最外层正多边形的顶点
linePoints.add(PointF(x,y))
//计算当前值与最大值的比率
val rate = cobWebData.value / maxVal
//根据比率计算出各个点所在的位置
val valX =
(radius * rate * cos(Math.toRadians(degree))).toFloat() //数据所在的X位置
val valY =
(radius * rate * sin(Math.toRadians(degree))).toFloat() //数据所在的Y位置
//将计算出来的值点保存下来
valuePoints.add(PointF(valX,valY))
//各个值点的连线路径
if(index == 0){
pointConPath.moveTo(valX,valY)
}else{
pointConPath.lineTo(valX,valY)
}
}
}
pointConPath.close()
path.close()
linePaths.add(path)
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//将画布的中心点移动至(0,0)点
canvas?.translate((width/2).toFloat(), (height/2).toFloat())
paint.style = Paint.Style.STROKE
paint.color = Color.RED
//画多边形
for(path in linePaths){
canvas?.drawPath(path,paint)
}
//画顶点到中心点的线
for(point in linePoints){
canvas?.drawLine(0f,0f,point.x,point.y,paint)
}
//画值所在的点
paint.style = Paint.Style.FILL
for(point in valuePoints){
canvas?.drawCircle(point.x,point.y,6f,paint)
}
//画所有值点的连线图形
paint.color = Color.parseColor("#30ff0000")
canvas?.drawPath(pointConPath,paint)
}
}
网友评论