`
rundog
  • 浏览: 7003 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
最近访客 更多访客>>
社区版块
存档分类

重新编译charts.swf,显示charts上面的值,增加右键菜单

阅读更多
   在ext3.0中,增加了flash图表的部分,可以让报表更加的赏心悦目。但是其中也有些缺憾,比如stackbar,columnbar 等,里面的值不能直接显示在相应的位置,必须鼠标移动到上面才行。本以为有什么机关咱不知道,但是在yahoo的论坛上,yui的开发人员明确的回答,yui-chart没有这样的功能,咱就只能自己动手了。
   ext3.0中的charts.swf用的是yui-chart,我试验了两个版本2.6和2.8,2.8无法显示。2.6比较好的兼容了。到这里下载2.6的源码http://yuilibrary.com/downloads/。解压缩后,取出其中的chart目录。
   再说说编译工具的问题吧,为了解决能调试的问题,找了很多的工具,但是现在还是没有能解决,目前只能是黑盒修改,也就是说无法跟踪调试,只能自己在里面写点信息,然后显示出来,看看是否达到了目的。我用的是flex3.0。其实用flashdevelop也可以的。
   用flex3.0新建一个as的工程,然后将chart目录下的文件拷贝到该目录一下,或者应用chart目录。修改build.xml的输出路径(output)和编译工具的路径(flexbin),其他的可以不管.
   对于stackbar 和columnbar,显示值的位置是不同的,因为一个是横向的柱子,一个是纵向的柱子,对于横向的,值是显示在bar里面的,纵向的,值是显示在bar上面的。下面分别就针对这两种类型的bar,进行说明,原理差不多。带中文备注的是增加的.
   打开单元com.yahoo.astra.fl.charts.series.ColumnSeries.as找到draw方法
override protected function draw():void
		{
			super.draw();
			
			//if we don't have data, let's get out of here
			if(!this.dataProvider)
			{
				return;
			}
			
			//grab the axes
			var cartesianChart:CartesianChart = this.chart as CartesianChart;
			var valueAxis:IOriginAxis = cartesianChart.verticalAxis as IOriginAxis;
			var otherAxis:IAxis = cartesianChart.horizontalAxis;
			var verticalAxisTitle:IAxis=cartesianChart.verticalAxis;//获取X轴的相关信息
			if(!valueAxis)
			{
				throw new Error("To use a ColumnSeries object, the vertical axis of the chart it appears within must be an IOriginAxis.");
				return;
			}
			
			var allSeriesOfType:Array = ChartUtil.findSeriesOfType(this, cartesianChart);
			var markerSizes:Array = [];
			var totalMarkerSize:Number = this.calculateTotalMarkerSize(otherAxis, markerSizes);
			var seriesIndex:int = allSeriesOfType.indexOf(this);
			var markerSize:Number = markerSizes[seriesIndex] as Number;
			var xOffset:Number = this.calculateXOffset(valueAxis, otherAxis, markerSizes, totalMarkerSize, allSeriesOfType);
			
			var startValues:Array = [];
			var endValues:Array = [];
			var itemCount:int = this.length;
			for(var i:int = 0; i < itemCount; i++)
			{
				var originValue:Object = this.calculateOriginValue(i, valueAxis, allSeriesOfType);
				var originPosition:Number = valueAxis.valueToLocal(originValue);
				
				var position:Point = IChart(this.chart).itemToPosition(this, i);
				var value:Object=IChart(this.chart).itemToAxisValue(this,i,verticalAxisTitle,false);//根据X轴来获取当前柱子的值
				var marker:DisplayObject = this.markers[i] as DisplayObject;
				
				marker.x = position.x + xOffset;
				
				marker.width = markerSize;
				
				var caption:TextField=new TextField ();//创建一个TextField,也可以用Label等代替
				caption.y=-20;//这里的x,y是相对于柱子来说的,所以要显示在上面,必须为负值
				caption.x=-10;				
				caption.text=String(value);//显示值				
				UIComponent(marker).addChild(caption);//增加这个对象					
					
				//if we have a bad position, don't display the marker
				if(isNaN(position.x) || isNaN(position.y))
				{
					this.invalidateMarker(ISeriesItemRenderer(marker));
				}
				else if(this.isMarkerInvalid(ISeriesItemRenderer(marker)))
				{
					//initialize the marker to the origin
					marker.y = originPosition;
					marker.height = 0;
				
					if(marker is UIComponent) 
					{
						(marker as UIComponent).drawNow();
					}
					this.validateMarker(ISeriesItemRenderer(marker));
				}
				
				//stupid Flash UIComponent rounding!
				position.y = Math.round(position.y);
				originPosition = Math.round(originPosition);
				
				var calculatedHeight:Number = originPosition - position.y;
				if(calculatedHeight < 0)
				{
					calculatedHeight = Math.abs(calculatedHeight);
					position.y = Math.round(originPosition);
					//always put the marker on the origin
					marker.y = position.y;
				}
				
				startValues.push(marker.y, marker.height);
				endValues.push(position.y, calculatedHeight);
			}
			
			//handle animating all the markers in one fell swoop.
			if(this._animation)
			{
				this._animation.removeEventListener(AnimationEvent.UPDATE, tweenUpdateHandler);
				this._animation.removeEventListener(AnimationEvent.COMPLETE, tweenUpdateHandler);
				this._animation = null;
			}
			
			//don't animate on livepreview!
			if(this.isLivePreview || !this.getStyleValue("animationEnabled"))
			{
				this.drawMarkers(endValues);
			}
			else
			{
				var animationDuration:int = this.getStyleValue("animationDuration") as int;
				var animationEasingFunction:Function = this.getStyleValue("animationEasingFunction") as Function;
				
				this._animation = new Animation(animationDuration, startValues, endValues);
				this._animation.addEventListener(AnimationEvent.UPDATE, tweenUpdateHandler);
				this._animation.addEventListener(AnimationEvent.COMPLETE, tweenUpdateHandler);
				this._animation.easingFunction = animationEasingFunction;
			}
		}


     打开单元com.yahoo.astra.fl.charts.series.BarSeries.as找到draw方法
override protected function draw():void
		{
			super.draw();
			
			this.graphics.clear();
			
			//if we don't have data, let's get out of here
			if(!this.dataProvider)
			{
				return;
			}
			
			this.graphics.lineStyle(1, 0x0000ff);
			
			//grab the axes
			var cartesianChart:CartesianChart = this.chart as CartesianChart;
			var valueAxis:IOriginAxis = cartesianChart.horizontalAxis as IOriginAxis;
			var otherAxis:IAxis = cartesianChart.verticalAxis;
			var horizontalAxis:IAxis=cartesianChart.horizontalAxis;//获取Y轴的信息
			if(!valueAxis)
			{
				throw new Error("To use a BarSeries object, the horizontal axis of the chart it appears within must be an IOriginAxis.");
				return;
			}
			
			var markerSizes:Array = [];
			var allSeriesOfType:Array = ChartUtil.findSeriesOfType(this, this.chart as IChart);
			var totalMarkerSize:Number = this.calculateTotalMarkerSize(otherAxis, markerSizes);
			var seriesIndex:int = allSeriesOfType.indexOf(this);
			
			var markerSize:Number = markerSizes[seriesIndex] as Number;
			var yOffset:Number = this.calculateYOffset(valueAxis, otherAxis, markerSizes, totalMarkerSize, allSeriesOfType);
			
			var startValues:Array = [];
			var endValues:Array = [];
			var itemCount:int = this.length;
			for(var i:int = 0; i < itemCount; i++)
			{
				var originValue:Object = this.calculateOriginValue(i, valueAxis, allSeriesOfType);
				var originPosition:Number = valueAxis.valueToLocal(originValue);
				var value:Object=IChart(this.chart).itemToAxisValue(this,i,horizontalAxis,false);//根据Y轴信息来获取值
				var position:Point = IChart(this.chart).itemToPosition(this, i);
				var marker:DisplayObject = this.markers[i] as DisplayObject;
				
				marker.y = position.y + yOffset;
				marker.height = markerSize;
				
				var caption:TextField=new TextField ();//创建一个对象
				caption.y=1;
				caption.x=position.x/2;//显示在柱子的中间				
				caption.text=String(value);//显示值
				UIComponent(marker).addChild(caption);//加入对象	
				
				//if we have a bad position, don't display the marker
				if(isNaN(position.x) || isNaN(position.y))
				{
					this.invalidateMarker(ISeriesItemRenderer(marker));
				}
				else if(this.isMarkerInvalid(ISeriesItemRenderer(marker)))
				{
					//initialize the marker to the origin
					marker.x = originPosition;
					marker.width = 0;
				
					if(marker is UIComponent) 
					{
						(marker as UIComponent).drawNow();
					}
					this.validateMarker(ISeriesItemRenderer(marker));
				}
				
				//stupid Flash UIComponent rounding!
				position.x = Math.round(position.x);
				originPosition = Math.round(originPosition);
				
				var calculatedWidth:Number = originPosition - position.x;
				if(calculatedWidth < 0)
				{
					calculatedWidth = Math.abs(calculatedWidth);
					position.x = Math.round(originPosition);
					//always put the marker on the origin
					marker.x = position.x;
				}
				
				startValues.push(marker.x, marker.width);
				endValues.push(position.x, calculatedWidth);
			}
			
			//handle animating all the markers in one fell swoop.
			if(this._animation)
			{
				this._animation.removeEventListener(AnimationEvent.UPDATE, tweenUpdateHandler);
				this._animation.removeEventListener(AnimationEvent.COMPLETE, tweenUpdateHandler);
				this._animation = null;
			}
			
			//don't animate on livepreview!
			if(this.isLivePreview || !this.getStyleValue("animationEnabled"))
			{
				this.drawMarkers(endValues);
			}
			else
			{
				var animationDuration:int = this.getStyleValue("animationDuration") as int;
				var animationEasingFunction:Function = this.getStyleValue("animationEasingFunction") as Function;
				
				this._animation = new Animation(animationDuration, startValues, endValues);
				this._animation.addEventListener(AnimationEvent.UPDATE, tweenUpdateHandler);
				this._animation.addEventListener(AnimationEvent.COMPLETE, tweenUpdateHandler);
				this._animation.easingFunction = animationEasingFunction;
			}
		}


    增加右键菜单的功能是因为我想在鼠标移动到某个柱子上面,可以有相应的交互。其实用EXT的menu也可以实现,但是会有响应的问题,也就是说会发生点击不准,响应失败的问题,而用flash的右键,则不会产生这种问题,而且更加的好看。响应的修改方法如下:
    打开Charts.as.
    首先在flash中增加方法,可以接受JS传来的右键菜单名:找到方法initializeComponent,在其中加入
    //custom          ExternalInterface.addCallback("setMenuInfo",setMenuInfo)
实现setMenuInfo方法
public function setMenuInfo(value:String):void{			
			var info:Object = JSON.decode(value as String);
			_menuInfo=info;
		}

    增加Charts的本地变量_menuInfo
protected var _menuInfo:Object;
		
		public function get MenuInfo():Object{
			return this._menuInfo;
		}

    这样flash就能接受菜单信息了。接受到菜单信息后,就可以建立菜单了。建立菜单我是安排在数据显示的时候,因为想这种只是针对series的右键菜单,必须在Series中生成,而且是针对每个Series创建。
    com.yahoo.astra.fl.series.Series.as是ColumnSeries和BarSeries的基类,所以在这里就可以解决掉问题。
    加入菜单对象
private var _menuInfo:Object; 
		
		public function get menuInfo():Object{
			return this._menuInfo;
		}
		
		public function set menuInfo(value:Object):void{
			this._menuInfo=value;
			build_right_click_menu();
		}
                private function onContextMenuHandler(event:ContextMenuEvent):void
		{
		}
		
		private function build_right_click_menu(): void {
			//本函数主要的难点在于鼠标对象的获取									
			var cm:ContextMenu = new ContextMenu();
			cm.addEventListener(ContextMenuEvent.MENU_SELECT, onContextMenuHandler);
			cm.hideBuiltInItems();			
			var items:Array=this._menuInfo.items as Array;
			for (var i:int=0;i<items.length;i++){
				var item:String=items[i];
					
				var fs:ContextMenuItem = new ContextMenuItem(item);								
				fs.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,function doSomething(e:ContextMenuEvent):void {
	                                //获取当前Series不能用this,用如下方法,可以获取当前的Series
					var ser:Series=Series(e.contextMenuOwner);

                                       //获取当前菜单序号				
					var index:int=-1;
					for (var j:int=0;j<(ser._menuInfo.items as Array).length;j++){
						if (ser._menuInfo.items[j]==ContextMenuItem(e.currentTarget).caption)
							index=j; 
					}		
					if(ExternalInterface.available){			
						var param:String=JSON.encode(_lastItem);//将对象编码为字符串							
                             					ExternalInterface.call("executeFlashMenu",param,index);
					}////执行JS函数
				});
				cm.customItems.push( fs );
			}
			// OFC CREDITS
			
			this.contextMenu = cm;
		}

    private var _lastItem:Object;//鼠标当前停留的item对象,利用以下方法进行获取
protected function markerRollOverHandler(event:MouseEvent):void
		{
			var itemRenderer:ISeriesItemRenderer = ISeriesItemRenderer(event.currentTarget);
			var index:int = this.itemRendererToIndex(itemRenderer);
			var item:Object = this.dataProvider[index];						
			_lastItem=item;
			var rollOver:ChartEvent = new ChartEvent(ChartEvent.ITEM_ROLL_OVER, index, item, itemRenderer, this);
			this.dispatchEvent(rollOver);
		}

    在Charts的setDataProvider方法中加入
public function setDataProvider(value:Array):void
		{
			var dataProvider:Array = [];
			var seriesCount:int = value.length;
			var seriesStyles:Array = [];
			for(var i:int = 0; i < seriesCount; i++)
			{
				var dataFromJavaScript:Object = value[i];
				var currentData:ISeries = this.chart.dataProvider[i] as ISeries;
				var seriesType:Class = SeriesSerializer.shortNameToSeriesType(dataFromJavaScript.type ? dataFromJavaScript.type : this.type);
				
				var series:ISeries;
				if(currentData && getDefinitionByName(getQualifiedClassName(currentData)) == seriesType)
				{
					//reuse the series if possible because we want animation
					series = SeriesSerializer.readSeries(dataFromJavaScript, currentData);
				}
				else
				{
					series = SeriesSerializer.readSeries(dataFromJavaScript);
				}
				dataProvider[i] = series;				
				series.menuInfo=this._menuInfo;//将菜单信息赋值给每个柱子对象
			
				//this is where we parse the individual series styles, and we convert them
				//to the format the chart actually expects.
				//we fill in with defaults for styles that have not been specified
				if(dataFromJavaScript.style)
				{
					seriesStyles.push(dataFromJavaScript.style);
				}
				else seriesStyles.push(null);
			}


EXT的JS修改如下
重载Ext.chart.StackedBarChart 的refresh方法,
refresh : function(){
		if (this.store==undefined)
		{
			return ;
		}
        var styleChanged = false;
        // convert the store data into something YUI charts can understand
        var data = [], rs = this.store.data.items;
        for(var j = 0, len = rs.length; j < len; j++){
            data[j] = rs[j].data;
        }
		var Number=40;
		//this.setHeight(Number*rs.length); 
        //make a copy of the series definitions so that we aren't
        //editing them directly.
        var dataProvider = [];
        var seriesCount = 0;
        var currentSeries = null;
        var i = 0;
        if(this.series){
            seriesCount = this.series.length;
            for(i = 0; i < seriesCount; i++){
                currentSeries = this.series[i];
                var clonedSeries = {};
                for(var prop in currentSeries){
                    if(prop == "style" && currentSeries.style !== null){
                        clonedSeries.style = Ext.encode(currentSeries.style);
                        styleChanged = true;
                        //we don't want to modify the styles again next time
                        //so null out the style property.
                        // this causes issues
                        // currentSeries.style = null;
                    } else{
                        clonedSeries[prop] = currentSeries[prop];
                    }
                }
                dataProvider.push(clonedSeries);
            }
        }else {

		}
        if(seriesCount > 0){
            for(i = 0; i < seriesCount; i++){
                currentSeries = dataProvider[i];
                if(!currentSeries.type){
                    currentSeries.type = this.type;
                }
                currentSeries.dataProvider = data;
            }
        } else{
            dataProvider.push({type: this.type, dataProvider: data});
        }
		if (this.menuTitles!='')//增加menuTitles属性
		{
			this.swf.setMenuInfo(this.menuTitles);//调用flash的setMenuInfo方法
		}
		try{
			this.swf.setDataProvider(dataProvider);
		}catch(e){
		}					
    }

          //增加属性
          menuTitles:'',
          setMenuInfo:function(infoStr){  //设置菜单值
		this.menuTitles=infoStr;		
	}

  增加函数 ,可以由点中flash右键菜单的时候调用
  function executeFlashMenu(dataItem,itemIndex){}
 
  组织菜单对象,然后传入至flash
       
var items=new Array();
	for (var i=0;i<menuInfo.items.length ;i++ )
	{
		items.push(menuInfo.items[i].text);
	}
	var menus=new Object();
	menus.items=items;
	stackedBarChart.setMenuInfo(Ext.util.JSON.encode(menus));
       
2
0
分享到:
评论
4 楼 grzrt 2012-03-08  
不错,学习下
3 楼 sunjilu05 2010-09-24  
好强!学习中!
2 楼 vishare 2010-09-10  
终于找到我想要了的...谢谢分享
1 楼 yanxianggt 2010-05-18  
楼主可有方法改变Y轴坐标的起始值

每次都从0开始,造成图形的变化趋势太小

根本没有使用价值

相关推荐

Global site tag (gtag.js) - Google Analytics