×
文章路径: Flex > C-DRAWS

C-DRAWS画图程序(三):画图核心

发表于3年前(Dec 12, 2014 10:22:45 PM)  阅读 673  评论 0

分类: Flex C-DRAWS

标签: c-draws DrawCanvas CGraphics

一个多月没有更新了,先说几句废话。之前病了一次,导致两周没有更新,然后开发上遇到困难,导致我对C-DRAWS失去了信心。最开始的设想是做个类似Windows画图样的程序,但是要比那个要强大,支持的样式要多,但开发过程中,发现并不是那么容易的一件事。

首先,画图方面,因为想增加线条样式功能,所以设想,用户可以选择实线以及虚线,乃至其他样式的线,但Flex本身不支持虚线的样式(至少现在未发现方便可行的方法),期间我研究过一阵图形算法,使用Bresenham画圆算法画了一种虚线圆,差强人意,还有椭圆,圆角矩形,箭头等暂时为做研究,这是一样耗时的工作,所以我暂时不想花费在上面。

其次,一个难点是剪切,对于图形的剪切,现在我的实现是用画布的颜色填充剪切的区域,这并不是一个好的处理方法,因为当初的设想,画布的颜色并不是固定的,是可以供用户设置的,但用户选择的画布是透明的时候,这种剪切就尴尬了。理想的做法当然是挖掉选中的部分,但是我没有发现可行的api。参考windows画图,我发现他的画图是不允许选择画布颜色的,那他的剪切是不是用画布颜色填充我就不得而知了。
其实本来是想把C-DRAWS当成一个产品来做,毕竟自己并未单独做过累世成熟的产品,但基于以上两点,我只好把C-DRAWS当成一个练习来做了。现在文件操作功能已经完成,画图功能能画矩形和圆,样式工具栏上没有按钮选择,但代码上我已经做了部分实现,可以说框架已经搭好了,所以我不准备再做其他画图功能了。末了我会附上工程源码,有不懂的可以留言问我。

废话讲完,开始今天的内容,这一节的内容主要是完成核心的画图。

上一节我们主要讲了布局,这一节我们先看下工具栏。众所周知,工具栏一般都是有一个选中状态的,实现方法有几种,一种是准备两组图片,一个是选中状态,一个是未选中状态,状态改变时替换相应的图片。还一种是改变按钮背景图片或颜色。在这里我们使用Flex中的Glow特效。

首先,我们看下源码(UtileBox.mxml):




	
		
	
	
	
    
	
		
			
            
		
		
			
            
		
	

看61-65行,定义的glowImage特效会给图片加上一圈蓝色的边框。unglowImage则会移去,这里我们移去边框特效并不是采用unglowImage实现。我们看rectangleDraw()方法,首先我们将graph的鼠标当前状态置换成画矩形的状态,然后对四个工具栏按钮的特效进行清空,再给画矩形的工具栏按钮加上glowImage特效,这样就实现了按钮选中状态。

我们再来看如何绘制矩形。首先我建立了一个CGraphics类,用来扩充系统的Graphics。现在CGraphics类实现了画点,画线,画矩形,画圆的方法,并支持虚线样式。所有的样式我封装到了自定义的Style类里面了。CGraphics还有很多地方要完善,在这里如何画图形的我就不讨论了,大家有兴趣的自己研究扩充。画图方面我是这样设计的,每种图形都是一个AS类,他们又个共同的父类Sketch,Sketch对图形的一些公共属性如,坐标,长宽,样式等做处理,每个图形有单独的实现类,只负责如何画该类图形。如Rectangle类里除构造函数外,只有一个draw方法,即画矩形的方法:this.cgraphics.clear();
this.cgraphics.drawRect(0, 0, width, height, style);

package com.cangzhitao.util
{
	import com.cangzhitao.util.style.Style;
	
	import flash.display.Graphics;
	import flash.geom.Point;
	
	//画图工具,扩充系统的Graphics
	public class CGraphics
	{
		public function CGraphics()
		{
		}

		//系统的Graphics
		private var _graphics:Graphics;
		
		private var _defaultStyle:Style = new Style();

		public function get graphics():Graphics {
			return this._graphics;
		}
		
		public function set graphics(value:Graphics):void {
			this._graphics = value;
		}
		
		//画矩形
		public function drawRect(x:Number, y:Number, width:Number, height:Number, style:Style=null):void {
			if(style==null) {
				style = _defaultStyle;
			}
			//画虚线矩形
			if(Style.DASHED==style.lineStyle) {
				this.lineStyle(style.thickness, style.color, 0);
				this.beginFill(style.fillColor, style.fillAlpha);
				this.graphics.drawRect(x, y, width, height);
				this.endFill();
				
				this.lineStyle(style.thickness, style.color, style.alpha);
				this.graphics.moveTo(x, y);
				this.drawDashedLine(new Point(x, y), new Point(x+width, y), style.solidLength, style.brokenLength);
				this.drawDashedLine(new Point(x+width, y), new Point(x+width, y+height), style.solidLength, style.brokenLength);
				this.drawDashedLine(new Point(x+width, y+height), new Point(x, y+height), style.solidLength, style.brokenLength);
				this.drawDashedLine(new Point(x, y+height), new Point(x, y), style.solidLength, style.brokenLength);
			//实线矩形
			} else {
				this.lineStyle(style.thickness, style.color, style.alpha);
				this.beginFill(style.fillColor, style.fillAlpha);
				this.graphics.drawRect(x, y, width, height);
				this.endFill();
			} 
		}
		
		//画线
		public function lineTo(startX:Number, startY:Number, endX:Number, endY:Number, style:Style=null):void {
			if(style==null) {
				style = _defaultStyle;
			}
			if(Style.DASHED==style.lineStyle) {
				this.drawDashedLine(new Point(startX, startY), new Point(endX, endY), style.solidLength, style.brokenLength);
			} else {
				this.graphics.moveTo(startX, startY);
				this.graphics.lineTo(endX, endY);
			}
		}
		
		
		//画虚线,参数,起始坐标,实线长度,空格长度
		public function drawDashedLine(fP:Point, tP:Point, solidLength:Number=10, brokenLength:Number=3):void {  
             var g:Graphics=this.graphics;  
             if(!fP){  
                 fP=new Point(0,0);  
             }  
             if(!tP){  
                 tP=new Point(0,0);  
             }  
             var lineAngle:Number;  
             lineAngle = Math.atan2(tP.y - fP.y,tP.x - fP.x);  
               
             var xSolidLength:Number=solidLength*Math.cos(lineAngle);  
             var ySolidLength:Number=solidLength*Math.sin(lineAngle);  
               
             var xBrokenLength:Number=brokenLength*Math.cos(lineAngle);  
             var yBrokenLength:Number=brokenLength*Math.sin(lineAngle);  
               
             var forwardFlag:Boolean=true;  
             if(tP.x<fP.x){  
                 forwardFlag=false;  
             }
             var tempP:Point=new Point(fP.x,fP.y);  
             var tempToP:Point=new Point(tP.x,tP.y);  
             var lineType:String="solid";  
             if(fP.x!=tP.x){
	             while(checkIn(tempP.x,tP.x,forwardFlag)){  
	                 g.beginFill(0x555555);  
	                 if(lineType=="solid"){  
	                     tempToP.x=tempP.x+xSolidLength;  
	                     tempToP.y=tempP.y+ySolidLength;
	                     if(!checkIn(tempToP.x,tP.x,forwardFlag)){
	                     	tempToP.x = tP.x;
	                     	tempToP.y = tP.y;
	                     }
	                     g.moveTo(tempP.x, tempP.y);  
	                     g.lineTo(tempToP.x, tempToP.y);   
	                     lineType="space";  
	                 }else{  
	                     tempToP.x=tempP.x+xBrokenLength;  
	                     tempToP.y=tempP.y+yBrokenLength;                      
	                     g.moveTo(tempToP.x, tempToP.y);  
	                     lineType="solid";     
	                 }  
	                 tempP.x=tempToP.x;  
	                 tempP.y=tempToP.y;  
	                 g.endFill();  
	             } 
             }else {
             	if(tP.y < fP.y){
             		forwardFlag=false;  
             	}
             	while(checkIn(tempP.y,tP.y,forwardFlag)){  
	                 g.beginFill(0x555555);  
	                 if(lineType=="solid"){  
	                     tempToP.x=tempP.x+xSolidLength;  
	                     tempToP.y=tempP.y+ySolidLength;  
	                      if(!checkIn(tempToP.y,tP.y,forwardFlag)){
	                     	tempToP.x = tP.x;
	                     	tempToP.y = tP.y;
	                     }
	                     g.moveTo(tempP.x, tempP.y);  
	                     g.lineTo(tempToP.x, tempToP.y);   
	                     lineType="space";  
	                 }else{  
	                     tempToP.x=tempP.x+xBrokenLength;  
	                     tempToP.y=tempP.y+yBrokenLength;                      
	                     g.moveTo(tempToP.x, tempToP.y);  
	                     lineType="solid";     
	                 }  
	                 tempP.x=tempToP.x;  
	                 tempP.y=tempToP.y;  
	                 g.endFill();  
	             } 
             }
         }  
		
		public function clear():void {
			this.graphics.clear();
		}
		
		public function lineStyle(thickness:Number = NaN, color:uint = 0, alpha:Number = 1.0):void {
			this.graphics.lineStyle(thickness, color, alpha);
		}
		
		public function beginFill(color:uint, alpha:Number = 1.0):void {
			
			this.graphics.beginFill(color, alpha);
		}
		
		public function endFill():void {
			this.graphics.endFill();
		}
		
		//判断是否还在开始点和结束点之间 
        private function checkIn(x:Number,toX:Number,forwardFlag:Boolean):Boolean{ 
             var result:Boolean=true;  
             if(forwardFlag){//向前  
                 if(x<toX){  
                 }else{  
                     result=false;  
                 }  
             }else{  
                 if(x>toX){  
                 }else{  
                     result=false;  
                 }  
             }  
             return result;  
        } 
        
        public function drawCircle(x:Number, y:Number, radius:Number, style:Style=null):void {
        	if(style==null) {
        		style = _defaultStyle;
        	}
        	if(Style.DASHED== style.lineStyle) {
        		//填充
				this.lineStyle(style.thickness, style.color, 0);
				this.beginFill(style.fillColor, style.fillAlpha);
				this.graphics.drawCircle(x, y, radius);
				this.endFill();
        		
        		
        		//bresenham画圆
	        	var linkPoints:Array = new Array();
	        	var p:Number;
	        	var rx:Number = 0;
				var ry:Number = radius;
				p = 3 - 2*radius;
				//求1/8圆各点
				while(rx<ry) {
					//判断哪些点需要画进去
					var length:Number = style.solidLength+style.brokenLength;
					if(rx%length<style.solidLength) {
						linkPoints.push(new Point(rx, ry));
					}
					if(p<0) {
						p = p + 4*rx +6;
					} else {
						p = p + 4*(rx-ry) + 10;
						ry -= 1;
					}
					rx += 1;
				}        	
				if(rx == ry) {
					linkPoints.push(new Point(rx, ry)); 
				}
				for(var i:int=0;i<linkPoints.length;i++) {
					var point:Point = linkPoints[i] as Point;
					this.drawPoint(point.x+x,point.y+y,style);
					this.drawPoint(point.x*(-1)+x, point.y+y,style);
					this.drawPoint(point.x*(-1)+x, point.y*(-1)+y,style);
					this.drawPoint(point.x+x, point.y*(-1)+y,style);
					
					this.drawPoint(point.y+x, point.x+y,style);
					this.drawPoint(point.y*(-1)+x, point.x*(-1)+y,style);
					this.drawPoint(point.y+x, point.x*(-1)+y,style);
					this.drawPoint(point.y*(-1)+x, point.x+y,style);
				}
        	} else {
        		this.lineStyle(style.thickness, style.color, style.alpha);
        		this.beginFill(style.fillColor, style.fillAlpha);
        		this.graphics.drawCircle(x, y, radius);
        		this.endFill();
        	}
        }
        
        public function drawPoint(x:Number, y:Number, style:Style=null):void {
        	if(style==null) {
        		style = _defaultStyle;
        	}
        	this.graphics.lineStyle(style.thickness, style.color, style.alpha);
        	this.graphics.moveTo(x-1, y-1);
        	this.graphics.lineTo(x, y);  
        	 /* this.graphics.drawCircle(x, y, 1)  */
        }
	}
}

我们如何通过鼠标操作,来获得图形的相关操作呢?首先我们必须在画布(DrawCanvas)里监听鼠标事件,但鼠标按下时,我们必须记下,当前鼠标的坐标,作为图形的开始位置,然后开始监听鼠标移动事件(注意,鼠标移动事件不能一开始就监听,必须在鼠标按下时才开始添加监听),移动过程中, 记下鼠标的当前位置,作为图形的结束位置,开始画图,因为鼠标移动是个连续的过程,所以这样做的话,画图也会是一个连续的过程,能实时展现出来。

画图就讲到这,很笼统,需要大家结合代码看。下一节我打算结束他,主要讲下复制,粘贴,打开,保存。

发表评论