Flex实现仪表盘控件

时间:2022-01-17 18:08:08

最近,应公司项目要求,研发一套图谱控件。涵盖折线图、棒图、饼图、仪表盘等多种类型图谱。现将仪表控件实现方式与大家分享,本文中不足之处欢迎大家指出,互相学习、共同进步Flex实现仪表盘控件

先来看一下最终效果:

Flex实现仪表盘控件

仪表控件结构上可以分为容器、表盘、指针、标注标签四部组成,之所以这么分是因为我希望表盘、标注、标注标签能够单独的变化,这样就可以通过开发不同样式的表盘、指针、标注标签等,让它们*组合,实现仪表控件的灵活配置。


源码下载


这里的容器指的就是我们的仪表组件名称,其实现代码如下:

protected override function createChildren():void
{
super.createChildren();

// 创建表盘
this._meterBoard = MeterBoardBase.newInstance();
this.addChild(this._meterBoard);

// 创建刻度
this._scaleLabels = ScaleLabelsBase.newInstance();
this._scaleLabels.minValue = this._minValue;
this._scaleLabels.maxValue = this._maxValue;
this.addChild(this._scaleLabels);

// 创建指针
this._indicator = IndicatorBase.newInstance();
this.addChild(this._indicator);

// 初始化动画器
this._animate = new Animate();
this._animate.duration = 1000;
this._animate.addEventListener(EffectEvent.EFFECT_UPDATE, this.onIndicatorUpdate);
}

protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);

if (null != this._meterBoard)
{
this._meterBoard.setActualSize(unscaledWidth, unscaledHeight);
this._meterBoard.x = this._meterBoard.y = 0;
}

if (null != this._indicator)
{
this._indicator.setActualSize(unscaledWidth, unscaledHeight);
this._indicator.x = this._indicator.y = 0;
}

if (null != this._scaleLabels)
{
this._scaleLabels.setActualSize(unscaledWidth, unscaledHeight);
this._scaleLabels.x = this._scaleLabels.y = 0;
}
}
其中我们使用_animate实现仪表盘指针转动的动画效果,确保无论指针的值的跳变量为多少,指针均能在正确的时间旋转到正确的刻度,这里我们设置的是1000毫秒。

接着来我们实现表盘的绘制,这里我们的表盘采用的半圆的形式,指针的旋转角度为0-180度。具体实现代码如下:

protected override function draw(unscaledWidth:Number, unscaledHeight:Number):void
{
this.graphics.clear();

var radius:Number = this.getRadius(unscaledWidth, unscaledHeight);
var ptCenter:Point = this.getCenterPoint(unscaledWidth, unscaledHeight);

// 绘制表盘边框
GeomUtil.drawSector(this.graphics, 0xf7f7f7, ptCenter.x, ptCenter.y, 0, radius * 0.8, -182, 1);
GeomUtil.drawSector(this.graphics, 0x000000, ptCenter.x, ptCenter.y, radius * 0.78, radius * 0.8, -182, 1);
GeomUtil.drawSector(this.graphics, 0x808080, ptCenter.x, ptCenter.y, radius * 0.76, radius * 0.78, -182, 1);

// 绘制表盘样式
var boardStyles:Array = DataParseUtil.parseMeterBoardData(this._boardDatas);
if (DataObjectUtil.arrayValid(boardStyles))
{
for each (var pieData:PieData in boardStyles)
{
GeomUtil.drawSector(this.graphics, pieData.color, ptCenter.x, ptCenter.y, radius * 0.6, radius * 0.7, pieData.angle, pieData.start);
}
}
}

GeomUtil是我定义的一个几乎工具类,用于实现几何图形的画法。GeomUtil中的drawSector方法用于绘制扇形,drawSector(graphics:Graphics, color:uint, x:Number, y:Number, r:Number, R:Number, angle:Number, startA:Number),参数graphics为绘图对象,color表示扇形区域的颜色,x,y为扇形所在圆的圆心坐标,r为扇形内径,R为扇形外径,angle表示扇形跨越的角度,startA是扇形的起始角度。

接着我们实现指针类,其绘制方法如下:

protected override function draw(unscaledWidth:Number, unscaledHeight:Number):void
{
this.graphics.clear();

// 计算指针轴半径及中心点
var radius:Number = unscaledHeight / 12;
var ptCenter:Point = new Point(unscaledWidth / 2, unscaledHeight * 9 / 10);

// 绘制指针
var matrix:Matrix = new Matrix();

// 获得指针的三个顶点坐标
var ptEnd1:Point = Point.polar(radius, GeomUtil.convertToRadians(180 - this._degree - 30));
var ptEnd2:Point = Point.polar(radius, GeomUtil.convertToRadians(180 - this._degree + 30));
var ptEnd3:Point = Point.polar(radius + Math.min(ptCenter.x, ptCenter.y) * 0.68, GeomUtil.convertToRadians(180 - this._degree));
ptEnd1.y = 0 - ptEnd1.y;
ptEnd2.y = 0 - ptEnd2.y;
ptEnd3.y = 0 - ptEnd3.y;
ptEnd1.offset(ptCenter.x, ptCenter.y);
ptEnd2.offset(ptCenter.x, ptCenter.y);
ptEnd3.offset(ptCenter.x, ptCenter.y);

// 绘制指针
this.graphics.lineStyle(1, 0x0698c8, 0.9);
this.graphics.beginFill(0x0698c8, 0.7);
this.graphics.moveTo(ptEnd1.x, ptEnd1.y);
this.graphics.lineTo(ptEnd3.x, ptEnd3.y);
this.graphics.lineTo(ptEnd2.x, ptEnd2.y);
this.graphics.lineTo(ptEnd1.x, ptEnd1.y);
this.graphics.endFill();

var degree:Number = 180 - this._degree;
var offsetHor:Number = Math.cos(GeomUtil.convertToRadians(degree)) * radius / 5;
var offsetVer:Number = Math.sin(GeomUtil.convertToRadians(degree)) * radius / 5;

// 绘制指针轴
matrix = new Matrix();
matrix.createGradientBox(radius * 2, radius * 2, 0, offsetHor, 0 - offsetVer);
matrix.translate(ptCenter.x - radius, ptCenter.y - radius);
this.graphics.lineStyle(1, 0x585858, 0.8);
this.graphics.beginGradientFill(GradientType.RADIAL, [0xfbfbfb, 0x7b7b7b], [1, 1], [0x00, 0xFF], matrix);
this.graphics.drawCircle(ptCenter.x, ptCenter.y, radius);
this.graphics.endFill();
}

好了,我们的仪表控件关于绘制方面的内容就介绍完了。标注标签的实现等就不再一一给出代码了,稍后会给出整个控件的源代码,有兴趣的朋友下载后自己看吧。