首页 > 其他分享 >flex 扇形菜单

flex 扇形菜单

时间:2023-08-11 22:32:31浏览次数:42  
标签:flex 圆心角 菜单 angle Number 扇形 var obj Math


在继 auzn经典Flex教程–KingnareStyle皮肤制作简介 后 ,auzn又出品了经典作品–扇形菜单。本文英文


版:Tutorials: Step by Step to Create your Sector Menu 。 下面我们就来做个扇形菜单,首先来看看效果吧:


[PieMenu.swf ]


只要设定好起始位置和总角度,似乎可以画出很多种组合.


Demo | Download Full Project


这样:

这样:

或者这样:

 

菜单的重点是如何画空心弧及过渡动画的控制.

很明显,菜单是由多个空心弧组成的,菜单形成也就是多个空心弧的产生并进行动画过渡的过程,所以我们先从单个空心弧入手.空心弧在过渡动画 中可能是在任意一个角度开始绘制,任意一个角度结束绘制,我们随意取一个状态:

 

 

上图是从-30度起始画图,画到-135度结束,空心弧角度为-105度,内圆半径50,外圆半径100,中心圆坐标(x,y).

 

可以看出这个图形边线由两条直线和两条弧组成,按逆时针为直线P1P2, 弧P2P3, 直线P3P4, 弧P4P1. 只要画好边线再进行填充即可.

 

我们先来计算四个点的坐标:

P1: (x+r*cos(start), y+r*sin(start))

P2: (x+R*cos(start), y+R*sin(start))

P3: (x+r*cos(start+angle), y+r*sin(start+angle))

P4: (x+R*cos(start+angle), y+R*sin(start+angle))

 

接下来的问题就是圆弧的算法了,可以知道,在圆心角小于45度的范围内是可以画出圆弧的.我们把圆弧的圆心角以小于 45 度 为单位 均分,对每个部分进行画弧,这样拼接起来就是完整的圆弧了.

 

目前已经有比较成熟的程序代码了.

修改了Geordi的DrawSector方法(如果知道作者及出处,请留言):

 

//angle为圆心角的大小,startA为起始角度 
//以45度为最大角度值均分,取得可以划分数值 
var n:Number = Math.ceil(Math.abs(angle) / 45); 
//计算每份圆弧的圆心角(均小于45度) 
var angleA:Number=angle / n; 
angleA = angleA * Math.PI / 180; 
startA = startA * Math.PI / 180 
//循环绘制圆弧 
for (var i=1; i <= n; i++) 
{ 
startA += angleA; 
var angleMid1:Number=startA – angleA / 2; 
var bx:Number = x + R / Math.cos(angleA / 2) * Math.cos(angleMid1); 
var by:Number = y + R / Math.cos(angleA / 2) * Math.sin(angleMid1); 
var cx:Number = x + R * Math.cos(startA); 
var cy:Number = y + R * Math.sin(startA); 
sector.graphics.curveTo(bx, by, cx, cy); 
}

如果理解上有些困难,可参见下图:

[tween_with_angle.swf ]

 

切点P就是画曲线方法curveTo的控制点.

 

OK,理论部分结束.我们在Flash cs3中新建Flash文件,在第一帧的动作面版写上如下代码:

 

var sector:Sprite = new Sprite(); 
addChild(sector); 
drawSector(200, 200, 50, 100, -105, -30); 
function drawSector( x:Number, y:Number, r:Number, R:Number, angle:Number, startA:Number) 
{ 
sector.graphics.clear(); 
sector.graphics.lineStyle (1, 0, 1, true); 
sector.graphics.beginFill(0, 0.5); 
if (Math.abs(angle) > 360) 
{ 
angle=360; 
} 
var n:Number = Math.ceil(Math.abs(angle) / 45); 
var angleA:Number=angle / n; 
angleA = angleA * Math.PI / 180; 
startA = startA * Math.PI / 180; 
var startB:Number = startA; 
//起始边 
sector.graphics.moveTo(x + r * Math.cos(startA), y + r * Math.sin(startA)); 
sector.graphics.lineTo(x + R * Math.cos(startA), y + R * Math.sin(startA)); 
//外圆弧 
for (var i=1; i <= n; i++) 
{ 
startA += angleA; 
var angleMid1:Number=startA – angleA / 2; 
var bx:Number = x + R / Math.cos(angleA / 2) * Math.cos(angleMid1); 
var by:Number = y + R / Math.cos(angleA / 2) * Math.sin(angleMid1); 
var cx:Number = x + R * Math.cos(startA); 
var cy:Number = y + R * Math.sin(startA); 
sector.graphics.curveTo(bx, by, cx, cy); 
} 
//内圆起点 
sector.graphics.lineTo(x + r * Math.cos(startA),y + r * Math.sin(startA)); 
//内圆弧 
for (var j = n; j >= 1; j–) 
{ 
startA-= angleA; 
var angleMid2:Number=startA + angleA / 2; 
var bx2:Number=x + r / Math.cos(angleA / 2) * Math.cos(angleMid2); 
var by2:Number=y + r / Math.cos(angleA / 2) * Math.sin(angleMid2); 
var cx2:Number=x + r * Math.cos(startA); 
var cy2:Number=y + r * Math.sin(startA); 
sector.graphics.curveTo(bx2, by2, cx2, cy2); 
} 
//内圆终点 
sector.graphics.lineTo(x + r * Math.cos(startB),y + r * Math.sin(startB)); 
//完成 
sector.graphics.endFill(); 
}

CTRL+ENTER测试(坐标系为笔者自行加入,坐标中心点为(200, 200)).

 

[draw_sector.swf ]

 

这样就可以完成我们的空心弧了.

至此,绘制空心弧完成.

 

接下来我们将介绍如何生成过渡动画.

通过上面的程序可知,只要改变空心弧的起始角度和圆心角角度,就能达到“展开并旋转”这一效果了.

 

首先是展开效果.所谓展开,就是起始角度不变,只改变圆心角角度.以前面的数据为例,起始角度为-30度,圆心角数值由0过渡到-105 度.加入以下代码:

 

import fl.transitions.Tween; 
import fl.transitions.TweenEvent; 
import fl.transitions.easing.Strong; 
var obj:Object = {}; 
obj.angle = 0; 
var tween:Tween=new Tween(obj, “angle”, Strong.easeInOut, 0, -105, 5, true); 
tween.addEventListener(TweenEvent.MOTION_CHANGE, changeHandler); 
function changeHandler(event:TweenEvent):void 
{ 
drawSector(200, 200, 50, 100, obj.angle, -30); 
}

 

使用了Flash CS3内置的Tween类,除此之外还可以用TweenMax 代替.

CTRL+ENTER测试,[tween_with_angle.swf ].

 

可以观查到程序不断的在改变圆心角角度.

展开没问题了,接下来是改变起始角度.这次设定圆心角夹角仍为105度,起始角度75度, 旋转到-30停止.

 

对刚才的展开代码稍加改动,缓部分代码如下:

 

import fl.transitions.Tween; 
import fl.transitions.TweenEvent; 
import fl.transitions.easing.Strong; 
var obj:Object = {}; 
obj.start = 0; 
var tween:Tween=new Tween(obj, “start”, Strong.easeInOut, 75, -30, 5, true); 
tween.addEventListener(TweenEvent.MOTION_CHANGE, changeHandler); 
function changeHandler(event:TweenEvent):void 
{ 
drawSector(200, 200, 50, 100, -105, obj.start); 
}

CTRL+ENTER测试,[tween_with_start.swf ].

 

可以观查到程序不断的在改变起始角度.

 

由上面两个过程,可以推导出子菜单的生成过程:首先起始角度固定,不断变化的只有圆心角,当圆心角达到目标值后,开始改变起始角度,这个时 候圆心角是固定不变的,空心弧此时是在以围绕圆心做旋转运动,起始角度达到目标值后,整个过程结束.

 

但是有一个重要的问题:如果先展开再旋转,两个动画中间的衔接是个问题.那么如何产生比较流畅的动画?我们现在用另一种方法重新分析一下:

 

我们设定圆心角度数值为正值,那么这时起始边应该在结束边的逆时针方向上,起始边逆时针旋转一定的角度 angle(angle>0),此时将其圆心角数值也更新为angle,这样看起来结束边不动,角度在变大.可以模拟展开效果.当圆心角角度达到目 标值后,将圆心角角度固定,而此时起始边继续旋转,最后旋转到目标值,整个过程结束.

 

根据以上分析,我们修改刚才的代码:

 

import fl.transitions.Tween; 
import fl.transitions.TweenEvent; 
import fl.transitions.easing.Strong; 
var obj:Object = {}; 
obj.start = 0; 
obj.angle = 0; 
var tween:Tween; 
//begin:起始角度初始值 
// end:起始角度终止值 
// angle:圆心角绝对值 
function create (begin:Number, end:Number, angle:Number, tweenTime:Number):void 
{ 
var oldStart:Number=0; 
tween=new Tween(obj, “start”, Strong.easeInOut, begin, end, tweenTime, true); 
tween.addEventListener(TweenEvent.MOTION_CHANGE, changeHandler); 
function changeHandler(event:TweenEvent):void 
{ 
if (Math.abs(obj.angle) >= angle) 
{ 
drawSector(200, 200, 50, 100, angle, obj.start); 
} 
else 
{ 
obj.angle = Math.abs(oldStart – obj.start) 
drawSector(200, 200, 50, 100, obj.angle, obj.start); 
} 
} 
} 
//由0开始,起始边转到-135度,动画时间为5秒 
create (0, -135, 105, 5);

CTRL+ENTER测试.[tween_without_filters.swf ].

OK,剩下的工作就是加上合适的滤镜,让菜单看上去更加美观.

 

可以选择BevelFilter及DropShadowFilter增加立体效果.

增加两个方法:

 

function getBevelFilter():BitmapFilter 
{ 
var distance:Number = 6; 
var angleInDegrees:Number = 45; 
var highlightColor:Number = 0xFFFFFF; 
var highlightAlpha:Number = 0.6; 
var shadowColor:Number = 0xFFFFFF; 
var shadowAlpha:Number = 0; 
var blurX:Number = 10; 
var blurY:Number = 10; 
var strength:Number = 0.8; 
var quality:Number = BitmapFilterQuality.LOW; 
var type:String = BitmapFilterType.INNER; 
var knockout:Boolean = false; 
return new BevelFilter(distance,angleInDegrees,highlightColor,highlightAlpha,shadowColor,shadowAlpha,blurX,blurY,strength,quality,type,knockout); 
} 
//获取DropShadow滤镜 
function getDropShadowFilter():BitmapFilter 
{ 
var color:Number = 0×000000; 
var angle:Number = 45; 
var alpha:Number = 0.9; 
var blurX:Number = 5; 
var blurY:Number = 5; 
var distance:Number = 5; 
var strength:Number = 0.9; 
var inner:Boolean = false; 
var knockout:Boolean = false; 
var quality:Number = BitmapFilterQuality.LOW; 
return new DropShadowFilter(distance,angle,color,alpha,blurX,blurY,strength,quality,inner,knockout); 
}

然后给sector设定滤镜.

sector.filters = [getBevelFilter(), getDropShadowFilter()];

最后把create方法中的填充换为更醒目的色彩:

sector.graphics.beginFill(0×0066FF, 0.8);

 

CTRL+ENTER测试,[tween_with_filters.swf ].

 

接下来就是由总角度及菜单数确定各个菜单的起始角度值变化范围及圆心角数值,然后分别“启动”他们的create方法.我们已经把这部分编 写完成了,大家可以在文章尾部的链接下载到所有示例程序源代码.

若要改用到FLEX中,需要替换代码中的Tween类,因为Flash CS3和FLEX中的Tween是不同的.

 

伪代码如下:

 

import mx.effects.Tween; 
import mx.effects.easing.*; 
private var tween:Tween; 
public function create (value:Number ,delta:Number, tweenTime:Number):void 
{ 
//… 
var listener:Object = {}; 
listener.onTweenUpdate = function(val:Object):void 
{ 
//更新圆心角度 
} 
listener.onTweenEnd = function(val:Object):void 
{ 
// 
} 
tween = new Tween(listener, obj.start, value, tweenTime*1000); 
tween.easingFunction = Quadratic.easeInOut; 
}

 

这样就可以应用到FLEX程序中了.

 

OK,菜单的核心部分就讲到这里,希望能对大家有些许帮助.

 

可以在here 下 载全部源文件.

标签:flex,圆心角,菜单,angle,Number,扇形,var,obj,Math
From: https://blog.51cto.com/u_8895844/7053739

相关文章

  • 记录--用css画扇形菜单
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助1、效果图用手机录屏再用小程序转换的gif,可能精度上有点欠缺。2、实现过程1、观察及思考开始编码前我们首先观察展开后的结构:两个四分之一的圆加三个圆形菜单项。文章名为用css画扇形,如上图所示没有任何Java......
  • 移动端布局之flex布局
    什么是flex布局基本含义Flex是FlexibleBox的缩写(注:意思是“灵活的盒子容器”),意为”弹性布局”,是CSS3引入的新的布局模式,用来为盒状模型提供最大的灵活性,它决定了元素如何在页面上排列,使它们能在不同的屏幕尺寸和设备下可预测地展现出来。基本概念采用Flex布局的元素,称为......
  • 【车载测试】CAN协议、CAN- FD协议和FlexRay协议 区别
    【上半场电动化,下半场智能化】一、CAN协议和CAN-FD协议的区别CAN(ControllerAreaNetwork)协议是一种广泛用于汽车和工业控制系统等领域的现场总线协议。CAN-FD(FlexibleDataRate)协议是对CAN协议的扩展,旨在提高CAN总线的数据传输速率和数据量。1.数据速率不同CAN协议是基......
  • 如何保护FlexRay总线免受浪涌静电威胁和损坏?
    FlexRay是一种高速、实时、可靠、具备故障容错能力的总线技术,是继CAN和LIN总线之后的最新研发成果。FlexRay为线控应用(即线控驱动、线控转向、线控制动等)提供了容错和时间确定性性能要求。虽然FlexRay将解决当前高端和未来主流车载网络的挑战,但它不会取代另外两个主要的车载标准CAN......
  • C# chart控件实现扇形图的一种方式
     ///<summary>///绘制扇形图///</summary>///<paramname="count"></param>privatevoidPainAlam(intcount){Hashtableht=newHashtable();//第一次遍历所有警报,存入到哈希表里面,value设置为1。value为已出现报警的次数for(inti=0;i<......
  • C# 开发cad 添加菜单栏下拉子菜单
     [CommandMethod("caidan")]publicvoidShowJingDianMenu(){try{IAcadApplicationapp=Autodesk.AutoCAD.ApplicationServices.Application.AcadApplicationasAcadApplication;if(app==null......
  • Excel实现下拉菜单多选
    Excel实现下拉菜单多选注意事项需要用到VBA宏编程WPS需要商业版才能启用VBA编程,office破解版(仅供学习)可以使用本文所有操作均在office2021上进行 一、(已有可忽略)打开office开发者工具"文件“-->"选项"-->"自定义功能区"-->勾上"开发者工具" 二、设......
  • JSP----jQuery插件ContextMenu生成右键菜单
    讲述三个内容:一:简介二:使用示例三:在jsp中动态生成的代码记录一:简介ContextMenu 译自:http://www.trendskitchens.co.nz/jquery/contextmenu/ ContextMenu是一个轻量级jQuery插件,用于选择性地用自己创建的菜单代替浏览器的默认右键菜单。 特点 1.可以在一个页面中使用多个右......
  • Mybatis-Flex 与 Mybatis-Plus 的一些对比
    为什么要引入Mybatis增强插件从一个业务开发者的角度来看,这种类似的增强框架使用起来很爽。单表情况下不必再把思路从Service切换到Mapper,从业务思维(业务流程)切换到数据库思维(数据库字段,编写),一定程度上减少了代码的开发量。易于维护数据库增改删字段不必再去xml里改,......
  • Mybatis-Flex之基础查询
    1、selectOneById/***selectOneById(id):根据主键查询数据。*/@TestpublicvoidtestSelectOneById(){/***SELECT*FROM`tb_account`WHERE`id`=?*/Accountaccount=accountMapper.selectOneById(10L);......