蜘蛛网属性图,html5学习笔记陆

By admin in 4858美高梅 on 2019年4月21日

绘图普通直线,先看效果图:

制图普通直线,先看效用图:

原著地址:

率先看望效果图:

4858美高梅 1

4858美高梅 2

废话不多说,先看下效果:

4858美高梅 3

福寿康宁代码如下:

兑当代码如下:

4858美高梅 4参考意义图

那里写图片描述

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF" //最外层canvas颜色
            context.fillRect(0,0,300,300)//最外层canvas区域
            context.beginPath()
            context.fillStyle="#008B8B"//填充颜色
            context.strokeStyle="#FFFF00"//线的颜色
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            for(var i=0;i<30;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.lineTo(dx+x*s,dy+y*s)
            }
            context.closePath()//关闭路径
            context.fill()//填充颜色
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF" //最外层canvas颜色
            context.fillRect(0,0,300,300)//最外层canvas区域
            context.beginPath()
            context.fillStyle="#008B8B"//填充颜色
            context.strokeStyle="#FFFF00"//线的颜色
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            for(var i=0;i<30;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.lineTo(dx+x*s,dy+y*s)
            }
            context.closePath()//关闭路径
            context.fill()//填充颜色
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>

该意义一眼看上去相比较简单,但其关系的知识点还是挺多的。特别是内需读者对android.graphics包下的API有必然的问询。先对关系到的知识点罗列如下,还不是很精晓的读者能够先活动百度做个轻便的翻阅,对延续作品的接头会有比比较大帮扶。

先简要说一下那边须要涉及到的知识点:

 绘制贝塞尔曲线

 绘制贝塞尔曲线

  • Paint、Canvas那八个基础的类必须纯熟。
  • 用作渲染的Shader类及其子类,以及后文中应用的是SweepGradient梯度渲染,用作渐变圆环,必要掌握。
  • canvas.save() & canvas.restore() 的效应与涉及。
  • 由Paint引申的PathEffect、PorterDuffXfermode,已经Matrix等类要有个主导的概念。
  • 图层绘制的有的定义。
  • 脏矩形技能。
  1. 二D绘制基础。
  2. 高级中学基本的三角函数 Sin,Cos。

功效图如下:

功用图如下:

万1您早就主导精通了下面提到到的知识点。OK。那接下去大家就一步一步落成这么些成效。

参照的稿子:

4858美高梅 5

4858美高梅 6

一.环形渐变

可能大家都有回忆,在Api德姆os中提供过2个例子模仿PS做的取色器效果。有意思味的读者可以切切实实查看Api德姆os下的ColorPickerDialog的贯彻。那里咱们参考她的写法,就足以做出3个归纳的环形渐变了。当然ColorPickerDialog中的宗旨代码相当于利用了刚刚所提起的SweepGradient类用作渲染。该类属于Shader的子类,当然其兄弟类还有BitmapShader位图渲染、LinearGradient线性渲染、RadialGradient环形渲染、SweepGradient梯度渲染以及ComposeShader结缘渲染。英特网有一大堆关于他们的介绍,能够做出过多很棒的效率。此处不开始展览。

骨干代码如下:

private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 渐变色环画笔,抗锯齿private final int[] mColors = new int[] { 0xffff0000, 0xffffff00, 0xff00ff00,0xff00ffff,0xff0000ff,0xffff00ff };// 渐变色环颜色Shader s = new SweepGradient(0, 0, mColors, null);mPaint.setShader;mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth;float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f;canvas.save() ;canvas.translate(CENTER_X, CENTER_X);// 移动中心canvas.rotate;canvas.drawOval(new RectF(-r, -r, r, r), mPaint);// 画出色环和中心园canvas.restore();

效益如图1所示:

4858美高梅 7图1

代码疏解:蜘蛛网属性图,html5学习笔记陆。参考功用图上看,颜色是有革命潜移默化(并非线性渐变,这里大家先依照简便的落到实处)为深紫红,而且效果并非为二个整圆。为了计算方便,我们借使该圆环的角度为240度。如图二所示

4858美高梅 8图贰大家已知SweepGradient是3个360度均匀布满的渐变,大家归总设置了五个渐变色:从彩虹色到杏黄,使其均匀布满在圆环上。而绘制圆的时候,大家先将canvas的原点(在android贰D图形系统中其坐标系原点在视图左上角)通过canvas.translate()挪动至了圆环的着力点。在此大家运用canvas.rotate()旋转操作,旋转150度,使其桃红渐变的上马地点处于图片左下方(这上大夫确的领悟应该是这么:由于我们对画布旋转了150度,所以大家在绘制完圆环之后,通过restore()方法又使得画布回归到原来职位,从而达成了将淡红渐变位于左下方的目标)。调治完canvas之后,我们透过canvas.drawOval()将圆绘制上去。最终将画布回归到原来的岗位。此处还选用了canvas.save()canvas.restore()构成操作。简要介绍一下:由于此地大家对画布有运动、旋转操作。为了不变成对接轨绘制的影响,使其复杂度扩展。大家应用save()和restore()的重组来驱动画布回归到它原本的职位。此举有时候会对质量产生一定的熏陶,本文只是step
by
step的贯彻教程,而且此意义并不会强注重于品质,所以品质在此地先放壹边。文末笔者会评释能够优化的点,供大家思量、钻探。在此间调用完restore()的表象正是canvas的原点又重回了视图的左上角。关于现实对canvas.save()canvas.restore()的解说,互连网有一大堆。那里不详细打开。大概能够精通为save()为保存当前canvas状态,restore则为还原上2遍save()的情事。

  1. Android自定义控件
    芝麻信用分雷达图

代码如下:

代码如下:

4858美高梅 ,2.绘制内圆

主导代码如下

paintMiddleCircle.setColor(Color.GRAY);paintInnerCircle.setColor(Color.GRAY);paintMiddleCircle.setStrokeWidth;paintInnerCircle.setStrokeWidth;paintMiddleCircle.setStyle(Paint.Style.STROKE);paintInnerCircle.setStyle(Paint.Style.STROKE);PathEffect effects = new DashPathEffect(new float[]{5,5,5,5},1);paintInnerCircle.setPathEffect;canvas.save() ;canvas.translate(CENTER_X, CENTER_X);canvas.drawCircle(0, 0, CENTER_X * 5 / 8, paintInnerCircle);canvas.drawCircle(0, 0, CENTER_X * 3 / 4, paintMiddleCircle);canvas.restore();

意义如图3所示

4858美高梅 9图3

代码讲授:该功用相比轻松。在那边要求精晓PathEffect及其子类的功力,这里大家采用DashPathEffect绘制虚线。细心的读者还是能够发现,大家应用的绘图圆形的法门不雷同。前边使用的是drawOval绘制椭圆,而在那边使用的是drawCircle直接画圆,效果都同1。具体差异可以和煦体会,二个是框死了画内切椭圆,另贰个是一直画圆。

这里为了珍重上边那篇小说的撰稿人,需求证实一下,上边包车型大巴代码有一部分是参照上边那篇小说的。那里作者就学之后有了友好的知道。做了有个别小改造,然后以和睦的笔触来捋一捋。希望作者的文字对您更有救助,哈哈。
(Pentagon –伍边形)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF"
            context.fillRect(0,0,300,300)
            context.beginPath()
            context.fillStyle="#008B8B"
            context.strokeStyle="#FFFF00"
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            context.moveTo(dx,dy)
            for(var i=0;i<60;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.bezierCurveTo(dx+x*s,dy+y*s-100,dx+x*s+100,dy+y*s,dx+x*s,dy+y*s)//贝塞尔绘制函数
            }
            context.closePath()
            context.fill()
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF"
            context.fillRect(0,0,300,300)
            context.beginPath()
            context.fillStyle="#008B8B"
            context.strokeStyle="#FFFF00"
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            context.moveTo(dx,dy)
            for(var i=0;i<60;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.bezierCurveTo(dx+x*s,dy+y*s-100,dx+x*s+100,dy+y*s,dx+x*s,dy+y*s)//贝塞尔绘制函数
            }
            context.closePath()
            context.fill()
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>

叁.制图帮助线

宗旨代码如下

paintGap1.setColor(Color.WHITE);paintGap2.setColor(Color.WHITE);paintGap1.setStrokeWidth;paintGap2.setStrokeWidth;int a =  (2 * CENTER_X - mPaint.getStrokeWidth;for ( int i=0;i<=60; i++) { canvas.save() ; canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_X); if ( i % 10 == 0 ) { canvas.drawLine( a ,CENTER_X, 2 * CENTER_X, CENTER_X, paintGap2); } else { canvas.drawLine( a ,CENTER_X, 2 * CENTER_X, CENTER_X, paintGap1); } canvas.restore();}

职能如图肆所示

4858美高梅 10图4

代码疏解在上头,大家曾假诺了圆弧的角度为240度。便于总计,大家将该圆弧划分为多少个区,种种区占40度,每种区有十个小间隔,每一种小间隔的角度便是四度。由于圆弧有30度是在水平线以下的,所以大家的轮回规则是上述代码。canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_X);此间由于CENTER_X==CENTER_Y==r,将上述代码修改为canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_Y);可能更易于领会。rotate中参数>0为顺时针旋转,<0为逆时针旋转。

制图思路:

 

 

4.圆环变圆弧

到近期停止,大家画的还只是个渐变圆环,与效果圆弧还有个别差异。上面我们将圆环管理为圆弧。**
大旨代码如下 **

width = MeasureSpec.getSize(widthMeasureSpec);height =  ( ( Math.tan(Math.PI / 6) + 1 ) * width / 2 ) ;Path path = new Path();path.moveTo(CENTER_X, CENTER_X);path.lineTo(0, height);path.lineTo(width, height);path.lineTo(CENTER_X, CENTER_X);path.close();canvas.drawPath(path, paintBg);

效果图5如下

4858美高梅 11图5**
代码讲明:**率先大家须要调节视图的莫斯中国科学技术大学学。在那在此以前大家都以令width==height,保障绘制出三个整圆。以后依附大家的如若圆弧度数240度,其在水平线以下为30度,即PI/陆。由数学公式计算获知,其视图中度为
height = r * tan + r。这还不够,调解完视图的惊人,大家要求将一些杂线,从视图中除去,让其看起来更像是个圆弧。如图陆所示未去杂线的时候4858美高梅 12图6

作者们选取图层相互遮罩的原理。以圆心和视图的四个顶峰,连接成一个三角,能够高达掩盖其与杂线的目标。约等于末端代码的魔法。记住在onDraw时候的2个标准:先画的在画布下方,后画的在画布上方,后画的会覆盖先画的。从而落成图伍的功用。

  1. 计量多个五边形的五个极端的坐标,用 path 连接起来并绘制
  2. 测算要显得的多寡的两个极端的坐标,用 path 连接起来并绘制
  3. 绘制5条射线
  4. 算算Logo和标题的坐标地点,并绘制
  5. 绘图中间的分数

   
 关于精通的html伍的着力知识点就到那里了,终归项目中绝非去行使,出于个人闲来无事有个大约领会.并且都很基本,其实这一个主题的知识点感到没供给开销这么多精力去关爱,这几个时间个人以为花的太多,完全能够找个小demo去探究,那样驱动的去学习效果会更加好,先到此处了,图谋投入到下1阶段别的开销知识点的就学中.

   
 关于驾驭的html5的基本知识点就到这边了,终归项目中从未去选拔,出于个人闲来无事有个大要通晓.并且都很基本,其实那一个宗旨的知识点以为没须要开支这么多精力去关怀,那些时刻个人感到花的太多,完全能够找个小demo去切磋,那样驱动的去学习效果会越来越好,先到那里了,打算投入到下1阶段其余支付知识点的学习中.

伍.文字的绘图

** 主题代码如下**

private static final String[] text = {"950","极好","700","优秀","650","良好","600","中等","550","较差","350","很差","150"};for ( int i=0;i<=12;i++) { canvas.save(); canvas.rotate(-(-120 + 20 * i ), CENTER_X, CENTER_X); canvas.drawText(text[i],CENTER_X - 20 ,CENTER_X * 3 / 16,paintText); canvas.restore();}

效果图7如下

4858美高梅 13图7

** 代码疏解
**我们已知每一种区为40度。从参考意义图上得以看到每隔20度就会有一段文字。大家知道在绘制文字的时候,都以从左往右写的。所以我们在转动画布的时候,初始点须要在原先的底蕴上再加90度,即逆时针旋转120度,然后绘入文字。当然那段绘制的进度供给在绘制三角形之后,不然部分文字会被三角形的遮罩遮盖起来。

第二步:绘制多少个五边形和暗褐伍边形

4858美高梅 14

此间写图片描述

起初化成员变量

private int dataCount = 5;//多边形维度
private float radian = (float) (Math.PI * 2 / dataCount);//每个维度的角度
private float radius;//一条星射线的长度,即是发散的五条线白线
private int centerX;//中心坐标 Y
private int centerY;//中心坐标 X
private String[] titles = {"履约能力", "信用历史", "人脉关系", "行为偏好", "身份特质"};//标题
private int[] icos = {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher};//五个维度的图标
private float[] data = {170, 180, 100, 170, 150};//五个维度的数据值
private float maxValue = 190;//每个维度的最大值
private Paint mPaintText;//绘制文字的画笔
private int radarMargin = 40;//
private int mAlpha;//白色五边形的透明度
private Path mPentagonPath;//记录白色五边形的路径
private Paint mPentagonPaint;//绘制白色五边形的画笔
private Path mDataPath;//记录红色五边形的路径
private Paint mDataPaint;//绘制红色五边形的画笔

构造方法中发轫化的多寡

private void init() {
    mPentagonPaint = new Paint();//初始化白色五边形的画笔
    mPentagonPaint.setAntiAlias(true);//
    mPentagonPaint.setStrokeWidth(5);//
    mPentagonPaint.setColor(Color.WHITE);//
    mPentagonPaint.setStyle(Paint.Style.FILL_AND_STROKE);//

    mDataPaint = new Paint();//初始化红色五边形的画笔
    mDataPaint.setAntiAlias(true);//
    mDataPaint.setStrokeWidth(10);//
    mDataPaint.setColor(Color.RED);//
    mDataPaint.setAlpha(150);//
    mDataPaint.setStyle(Paint.Style.STROKE);//

    mPaintText = new Paint();//初始化文字画笔
    mPaintText.setAntiAlias(true);//
    mPaintText.setTextSize(50);//
    mPaintText.setColor(Color.WHITE);//
    mPaintText.setStyle(Paint.Style.FILL);//

    mPentagonPath = new Path();//初始化白色五边形路径
    mDataPath = new Path();//初始化红色五边形路径
    radius = 80;//星射线的初始值,也是最小的五边形的一条星射线的长度(后期会递增)
    mAlpha = 150;//白色五边形的透明度(后期后递减)
}

开始化数据之后是经过 radius
的长短来测算伍边形两极分化的坐标值,中期通过退换 radius
的值,来实现总计多少个梅红五边形的四个顶峰的值。那里给出一张图,协助掌握。通过图中的八个玉石白三角形就可以求出顶点的坐标了。

4858美高梅 15

这里写图片描述

**右上角的顶峰为第二个点,顺时针总计,position 依次是 0,1,2,三,4
**

public Point getPoint(int position) {
    return getPoint(position, 0, 1);
}

// 参数:position:顶点的位置,radarMargin:边距,percent:星射线长度的百分比,用于计算红色五边形的顶点
public Point getPoint(int position, int radarMargin, float percent) {//以五边形的中心点为坐标原点
    int x = 0;
    int y = 0;
    switch (position) {
        case 0://第一象限,右上角顶点的坐标计算
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
            break;
        case 1://第四象限,右下角顶点的坐标计算
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
            break;
        case 2://第三象限,左下角顶点的坐标计算
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
            break;
        case 3://第二象限,左上角顶点的坐标计算
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
            break;
        case 4:// Y 轴正方向顶点的计算
            x = centerX;
            y = (int) (centerY - (radius + radarMargin) * percent);
            break;
    }
    return new Point(x, y);
}

基本功工作都做足了,那么就开始展览伍边形的绘图了

private void drawPentagon(Canvas canvas) {
    for (int j = 0; j < 3; j++) {//绘制三层白色五边形
        radius += 70;//每一层五边形的星射线增加 70 的长度
        mAlpha -= 30;//每一层五边形的透明度减少 30
        mPentagonPaint.setAlpha(mAlpha);
        for (int i = 0; i < dataCount; i++) {//绘制一层
            if (i == 0) {
                mPentagonPath.moveTo(getPoint(i).x, getPoint(i).y);
            } else {
                mPentagonPath.lineTo(getPoint(i).x, getPoint(i).y);
            }
        }
        mPentagonPath.close();
        canvas.drawPath(mPentagonPath, mPentagonPaint);
    }

    for (int i = 0; i < dataCount; i++) {//绘制红色五边形
        float percent = data[i] / maxValue;//数据值与最大值的百分比
        if (i == 0) {
            mDataPath.moveTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);//通过百分比计算出红色顶点的位置
        } else {
            mDataPath.lineTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);
        }
    }
    mDataPath.close();
    canvas.drawPath(mDataPath, mDataPaint);
}

6.结尾的动效

if ( isSetReferValue ) { float r1 = CENTER_X * 6 / 8 ; canvas.save(); canvas.translate(CENTER_X, CENTER_X); canvas.drawArc(new RectF(-r1, -r1, r1, r1), -210, currentRotateAngle, false, paintMiddleArc); canvas.rotate( - 30 + currentRotateAngle ); Matrix matrix = new Matrix(); matrix.preTranslate(-r1 - bitmapWidth * 3/ 8,-bitmapHeight/2); canvas.drawBitmap(bitmapLocation,matrix,paintBitmap); canvas.restore();}public void setReferValue ( int referValue ,final RotateListener rotateListener) { isSetReferValue = !isSetReferValue ; if ( referValue <= 150 ) { totalRotateAngle = 0f ; } else if ( referValue <= 550 ) { totalRotateAngle = ( referValue - 150 ) * 80 / 400f ; } else if ( referValue <= 700 ) { totalRotateAngle = ( referValue - 550 ) * 120 / 150f + 80 ; } else if ( referValue <= 950 ) { totalRotateAngle = ( referValue - 700 ) * 40 / 250f + 200; } else { totalRotateAngle = 210f ; } rotateAngle = totalRotateAngle / 60 ; new Thread(new Runnable() { @Override public void run() { boolean rotating = true ; float value = 350; while  { try { Thread.sleep; } catch (InterruptedException e) { e.printStackTrace(); } currentRotateAngle += rotateAngle; if ( currentRotateAngle >= totalRotateAngle ) { currentRotateAngle = totalRotateAngle; rotating = false; } if ( null != rotateListener) { if ( currentRotateAngle <= 80 ) { value = 350 + ( currentRotateAngle / 80 ) * 400 ; } else if ( currentRotateAngle <= 200 ) { value = 550 + ( ( currentRotateAngle - 80 )/ 120 ) * 150 ; } else { value = 700 + ( ( currentRotateAngle - 200 ) / 40 ) * 250 ; } rotateListener.rotate(currentRotateAngle,value); } postInvalidate.start(); }

效果图8如下

4858美高梅 16图8

代码批注绘制的代码中。首先大家要打听到绘制圆弧的秘诀为canvas.drawArc(),此处大家要从左下角发轫绘制圆弧,所以我们的前奏旋转角度为-2十度。由于大家那里的原点在圆心。图片要跟随着已知的转动角度打开旋转。大家领悟针对canvas.rotate()办法,当旋转角度>0的时候,是顺时针旋转;<0为逆时针旋转。由于那里我们图片的箭头朝向向右,为了保险图片的通向指向圆心。大家旋转的条条框框为- 30 + currentRotateAngle,保证每便在绘制图形的时候,都以在为(-r一

  • bitmapWidth * 3/
    八,-bitmapHeight/二)这么些职位的时候绘制。最后苏醒canvas。关于在盘算totalRotateAnglecurrentRotateAngle以及
    value的时候,都是些简单的算法。夹杂着大多硬编码,耐心点应该能够读懂,不做过多解释。

兑现的77八8,大约思路应当是那般。

其次步:绘制5条星射线

先来探望这一步的功能图:

4858美高梅 17

此处写图片描述

绘图好伍边形之后 radius 的值已经为最大伍边形的星射线的长短了。

private void drawFiveLine(Canvas canvas) {
    mPentagonPaint.setColor(Color.WHITE);//设置颜色为白色
    mPentagonPaint.setStrokeWidth(2);//设置宽度为2
    for (int i = 0; i < dataCount; i++) {
        canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, mPentagonPaint);//绘制
    }
}

有的难点

  1. 在上文也波及了,参考的效益图,并非是三个平整的渐变。仔细察看的话,在600处有处瞬断的一望可知。化解思路:利用方面讲到过的PorterDuffXfermode,将两段分裂的环形渐变,拼接而成。到达此功用。
  2. 有关优化
  • onDraw()方法中,canvas.save()与canvas.restore()方法多次利用,形成不供给的性质浪费。
  • 在施行箭头转动作效果果的时候,不要求在canvas上每便全体都再度绘制。只必要绘制需求绘制的壹对区域就能够,即脏矩形。在此间也正是箭头所滚动范围内的部分区域圆环。读者能够自动达成。
  1. 关于三十二线程细心的人得以窥见方法setReferValue(),并不曾设想二十多线程的情况。此处只是demo,场景也简单。没做越发管理。有意思味的读者能够活动达成。

其三步:绘制七个标题

先来探望这一步的效能图:

4858美高梅 18

此地写图片描述

在这一步,相对难一些的正是坐标的揣测了。第3个顶峰的坐标经过增加radarMargin
值之后就足以一向运用了,别的顶点还索要通过计量获得。那里实在便是要计算每一个Title 文字左下角的坐标。那么合算坐标的代码是那样的:

private void drawTitle(Canvas canvas) {
    for (int i = 0; i < dataCount; i++) {
        int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
        int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
        int iconHeight = bitmap.getHeight();
        int titleWidth = (int) mPaintText.measureText(titles[i]);
        switch (i) {
            case 1://说明一下为什么是 iconHeight / 2 ,主要是因为这样会比较好看
                y += iconHeight / 2;
                break;
            case 2:
                x -= titleWidth;
                y += iconHeight / 2;
                break;
            case 3:
                x -= titleWidth;
                break;
            case 4:
                x -= titleWidth / 2;
                break;
        }
        canvas.drawText(titles[i], x, y, mPaintText);
    }
}

后记

在此以前一向未曾记录博客的习于旧贯。现在写完两篇,开掘将代码翻译成文不是1件轻便的事。代码在周日就宗旨达成了,小说也是一向拖着到今后才整理出来宣布。要将每2个知识点,能够简单的抒发出来,是比较难的一件业务。落笔成文同面对面与人讲述,会不太雷同。现在要多进步那上头的练习。也指望读者们能够一起来尝试记录。遗留的难点,都不是很难,读者能够自动尝试的去完毕。前日头脑有点疼,就写到此了。

源代码在此下载:

enjoy it!

想即刻领悟最新音信。扫1扫,增添关注微信公众号

4858美高梅 19weixin.jpg

原稿地址:

第5步:绘制图标

先来探视这一步的作用:

4858美高梅 20

此地写图片描述

这一步也是要开始展览坐标的总计,首要的总计出放置Logo左上角的坐标值。这里依然相对轻松一点,不须要利用三角函数。

private void drawIcon(Canvas canvas) {
    for (int i = 0; i < dataCount; i++) {
        int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
        int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
        int iconHeight = bitmap.getHeight();
        int iconWidth = bitmap.getWidth();
        int titleWidth = (int) mPaintText.measureText(titles[i]);
        switch (i) {
            case 0:
                x += (titleWidth - iconWidth) / 2;
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
            case 1:
                x += (titleWidth - iconWidth) / 2;
                y -= (iconHeight / 2 + getTextHeight(titles[i]));
                break;
            case 2:
                x -= titleWidth - (titleWidth - iconWidth) / 2;
                y -= (iconHeight / 2 + getTextHeight(titles[i]));
                break;
            case 3:
                x -= titleWidth - (titleWidth - iconWidth) / 2;
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
            case 4:
                x -= (iconHeight / 2);
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
        }
        canvas.drawBitmap(bitmap, x, y, mPaintText);
    }
}

第伍步:绘制中央点的分数

这一步成功之后就足以博得最后效果了,就是图一的职能:

4858美高梅 21

那里写图片描述

文字的坐标是主导点,那么合算出文字的大幅度和可观就足以从中显示文字了。

private void drawScore(Canvas canvas) {
    mPaintText.setColor(getResources().getColor(R.color.colorAccent));
    int score = 0;
    for (int i = 0; i < data.length; i++) {//累加分数值
        score += data[i];
    }
    String str_score = String.valueOf(score);
    Paint.FontMetrics fm = mPaintText.getFontMetrics();//用于计算文字的高度
    canvas.drawText(str_score, centerX - mPaintText.measureText(str_score) / 2, (centerY + (int) Math.ceil(fm.descent - fm.ascent) / 2), mPaintText);
}

总结

一步步下去,对自定义 view 也有了尤其的掌握。感到须求越多的演练技能一心
hold
住。若是文中有何知识点是不对的要么越来越好的落真实景况势,请及时联系自身实行修改,避防误导旁人。多谢。那么完整的代码是这么的。

/**
 * Created by zone on 2017/4/9.
 */

public class PentagonView extends View {
    private int dataCount = 5;//多边形维度,这里是五边形
    private float radian = (float) (Math.PI * 2 / dataCount);//每个维度的角度
    private float radius;//一条星射线的长度,即是发散的五条线白线
    private int centerX;//中心坐标 Y
    private int centerY;//中心坐标 X
    private String[] titles = {"履约能力", "信用历史", "人脉关系", "行为偏好", "身份特质"};//标题
    private int[] icos = {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher};//五个维度的图标
    private float[] data = {170, 180, 100, 170, 150};//五个维度的数据值
    private float maxValue = 190;//每个维度的最大值
    private Paint mPaintText;//绘制文字的画笔
    private int radarMargin = 40;//
    private int mAlpha;//白色五边形的透明度
    private Path mPentagonPath;//记录白色五边形的路径
    private Paint mPentagonPaint;//绘制白色五边形的画笔
    private Path mDataPath;//记录红色五边形的路径
    private Paint mDataPaint;//绘制红色五边形的画笔


    public PentagonView(Context context) {
        super(context);
        init();
    }

    public PentagonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PentagonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public PentagonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        mPentagonPaint = new Paint();//初始化白色五边形的画笔
        mPentagonPaint.setAntiAlias(true);//
        mPentagonPaint.setStrokeWidth(5);//
        mPentagonPaint.setColor(Color.WHITE);//
        mPentagonPaint.setStyle(Paint.Style.FILL_AND_STROKE);//

        mDataPaint = new Paint();//初始化红色五边形的画笔
        mDataPaint.setAntiAlias(true);//
        mDataPaint.setStrokeWidth(10);//
        mDataPaint.setColor(Color.RED);//
        mDataPaint.setAlpha(150);//
        mDataPaint.setStyle(Paint.Style.STROKE);//

        mPaintText = new Paint();//初始化文字画笔
        mPaintText.setAntiAlias(true);//
        mPaintText.setTextSize(50);//
        mPaintText.setColor(Color.WHITE);//
        mPaintText.setStyle(Paint.Style.FILL);//

        mPentagonPath = new Path();//初始化白色五边形路径
        mDataPath = new Path();//初始化红色五边形路径
        radius = 80;//星射线的初始值,也是最小的五边形的一条星射线的长度(后期会递增)
        mAlpha = 150;//白色五边形的透明度(后期后递减)
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(getResources().getColor(R.color.colorAccent));
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;
        drawPentagon(canvas);//绘制白色五边形和红色五边形
        drawFiveLine(canvas);//绘制五条星射线
        drawTitle(canvas);//绘制五个标题
        drawIcon(canvas);//绘制五个图标
        drawScore(canvas);//绘制中间的分数
    }

    private void drawPentagon(Canvas canvas) {
        for (int j = 0; j < 3; j++) {//绘制三层白色五边形
            radius += 70;//每一层五边形的星射线增加 70 的长度
            mAlpha -= 30;//每一层五边形的透明度减少 30
            mPentagonPaint.setAlpha(mAlpha);
            for (int i = 0; i < dataCount; i++) {//绘制一层
                if (i == 0) {
                    mPentagonPath.moveTo(getPoint(i).x, getPoint(i).y);
                } else {
                    mPentagonPath.lineTo(getPoint(i).x, getPoint(i).y);
                }
            }
            mPentagonPath.close();
            canvas.drawPath(mPentagonPath, mPentagonPaint);
        }

        for (int i = 0; i < dataCount; i++) {//绘制红色五边形
            float percent = data[i] / maxValue;//数据值与最大值的百分比
            if (i == 0) {
                mDataPath.moveTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);//通过百分比计算出红色顶点的位置
            } else {
                mDataPath.lineTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);
            }
        }
        mDataPath.close();
        canvas.drawPath(mDataPath, mDataPaint);
    }

    private void drawFiveLine(Canvas canvas) {
        mPentagonPaint.setColor(Color.WHITE);//设置颜色为白色
        mPentagonPaint.setStrokeWidth(2);//设置宽度为2
        for (int i = 0; i < dataCount; i++) {
            canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, mPentagonPaint);//绘制
        }
    }

    private void drawIcon(Canvas canvas) {
        for (int i = 0; i < dataCount; i++) {
            int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
            int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
            int iconHeight = bitmap.getHeight();
            int iconWidth = bitmap.getWidth();
            int titleWidth = (int) mPaintText.measureText(titles[i]);
            switch (i) {
                case 0:
                    x += (titleWidth - iconWidth) / 2;
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
                case 1:
                    x += (titleWidth - iconWidth) / 2;
                    y -= (iconHeight / 2 + getTextHeight(titles[i]));
                    break;
                case 2:
                    x -= titleWidth - (titleWidth - iconWidth) / 2;
                    y -= (iconHeight / 2 + getTextHeight(titles[i]));
                    break;
                case 3:
                    x -= titleWidth - (titleWidth - iconWidth) / 2;
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
                case 4:
                    x -= (iconHeight / 2);
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
            }
            canvas.drawBitmap(bitmap, x, y, mPaintText);
        }
    }

    private int getTextHeight(String text) {
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        return (int) Math.ceil(fm.descent - fm.ascent);
    }

    private void drawTitle(Canvas canvas) {
        for (int i = 0; i < dataCount; i++) {
            int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
            int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
            int iconHeight = bitmap.getHeight();
            int titleWidth = (int) mPaintText.measureText(titles[i]);
            switch (i) {
                case 1://说明一下为什么是 iconHeight / 2 ,主要是因为这样会比较好看
                    y += iconHeight / 2;
                    break;
                case 2:
                    x -= titleWidth;
                    y += iconHeight / 2;
                    break;
                case 3:
                    x -= titleWidth;
                    break;
                case 4:
                    x -= titleWidth / 2;
                    break;
            }
            canvas.drawText(titles[i], x, y, mPaintText);
        }
    }

    private void drawScore(Canvas canvas) {
        mPaintText.setColor(getResources().getColor(R.color.colorAccent));
        int score = 0;
        for (int i = 0; i < data.length; i++) {//累加分数值
            score += data[i];
        }
        String str_score = String.valueOf(score);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();//用于计算文字的高度
        canvas.drawText(str_score, centerX - mPaintText.measureText(str_score) / 2, (centerY + (int) Math.ceil(fm.descent - fm.ascent) / 2), mPaintText);
    }

    public Point getPoint(int position) {
        return getPoint(position, 0, 1);
    }

// 右上角的顶点为第一个点,顺时针计算,position 依次是 0,1,2,3,4
// 参数:position:顶点的位置,radarMargin:边距,percent:星射线长度的百分比,用于计算红色五边形的顶点
    public Point getPoint(int position, int radarMargin, float percent) {//以五边形的中心点为坐标原点
        int x = 0;
        int y = 0;
        switch (position) {
            case 0://第一象限,右上角顶点的坐标计算
                x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent);
                y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
                break;
            case 1://第四象限,右下角顶点的坐标计算
                x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent);
                y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
                break;
            case 2://第三象限,左下角顶点的坐标计算
                x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent);
                y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
                break;
            case 3://第二象限,左上角顶点的坐标计算
                x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent);
                y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
                break;
            case 4:// Y 轴正方向顶点的计算
                x = centerX;
                y = (int) (centerY - (radius + radarMargin) * percent);
                break;
        }
        return new Point(x, y);
    }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有