0

我采用了这个网站的代码,

http://blog.ninjacaptain.com/2010/03/flex-chart-zoom-window/

请注意,网络博客中提到的有关显示数据提示的错误似乎已得到修复(至少从 4.5.1 SDK 开始)。我可以很好地看到数据提示。

该代码运行良好,除了一个问题。我在下面添加了完整的代码,因此您可以复制并粘贴为新的 Flex 应用程序并运行它。

问题只是当用户单击一次而不拖动时,会出现以下错误(确保在应用程序首次运行时单击它):

TypeError: Error #1009: Cannot access a property or method of a null object reference. at mx.charts.chartClasses::CartesianDataCanvas/localToData()[E:\dev\4.5.1\frameworks\projects\charts\src\mx\charts\chartClasses\CartesianDataCanvas.as:580]

有没有办法捕捉用户点击而不像这样拖动并调用一些函数来处理它?或者,有什么方法可以避免这个错误?感谢您的任何意见/建议。

代码是:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx"
           initialize="init()" width="600" height="520">
<fx:Script>
    <![CDATA[
        [Bindable]
        private var profits:Array;
        private var dragStart:Point;
        private var dragEnd:Point;
        private var zooming:Boolean;

        // initializes the data provider with random data
        private function init():void{
            profits = new Array({month: 0, profit: 15});
            for(var i:int=1; i<40; i++)
                profits.push({month: i, profit: Math.round(Math.random()*25-10)+profits[i-1].profit});
        }

        // sets the start point of the zoom window
        private function startDraw(e:MouseEvent):void{
            zooming = true;
            dragStart = new Point(series1.mouseX, series1.mouseY);
        }

        // draws the zoom window as your mouse moves
        private function showDraw(e:MouseEvent):void{
            if(zooming){
                dragEnd = new Point(series1.mouseX, series1.mouseY);

                // finds the top-left and bottom-right ponits of the zoom window
                var TL:Point = new Point();  // top-left point
                var BR:Point = new Point();  // bottom-right point
                if(dragStart.x < dragEnd.x){
                    TL.x = dragStart.x;
                    BR.x = dragEnd.x;
                }
                else{
                    TL.x = dragEnd.x;
                    BR.x = dragStart.x;
                }
                if(dragStart.y < dragEnd.y){
                    TL.y = dragStart.y;
                    BR.y = dragEnd.y;
                }
                else{
                    TL.y = dragEnd.y;
                    BR.y = dragStart.y;
                }

                // prevents the zoom window from going off the canvas
                if(TL.x < 0) TL.x = 0;
                if(BR.x > chartCanvas.width-1) BR.x = chartCanvas.width-1;
                if(TL.y < 0) TL.y = 0;
                if(BR.y > chartCanvas.height-1) BR.y = chartCanvas.height-1;

                // draw the actual zoom window
                chartCanvas.graphics.clear();
                chartCanvas.graphics.lineStyle(1, 0x000000, 0.25);
                chartCanvas.graphics.beginFill(0xd4e3f0,0.5);
                chartCanvas.graphics.drawRect(TL.x, TL.y, BR.x-TL.x, BR.y-TL.y);
                chartCanvas.graphics.endFill();
            }   
        }

        // clears the drawing canvas and sets the new max/mins
        private function finishDraw(e:MouseEvent):void{
            zooming = false;
            chartCanvas.graphics.clear();

            // converts the drag coordinates into axis data points
            var chartValStart:Array = chartCanvas.localToData(dragStart);
            var chartValEnd:Array = chartCanvas.localToData(dragEnd);

            // sets the new maximum and minimum for both axes
            haxis.minimum = (chartValStart[0] < chartValEnd[0]) ? chartValStart[0] : chartValEnd[0];
            haxis.maximum = (chartValStart[0] < chartValEnd[0]) ? chartValEnd[0] : chartValStart[0];
            vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
            vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
        }

        // resets the axis max/mins
        private function resetZoom():void{
            haxis.minimum = NaN; 
            haxis.maximum = NaN; 
            vaxis.minimum = NaN; 
            vaxis.maximum = NaN;
        }   
]]>
</fx:Script>

<s:VGroup>

    <mx:Panel title="Line Chart">
        <mx:LineChart id="chart1" 
                      mouseDown="startDraw(event)" 
                      mouseMove="showDraw(event)" 
                      mouseUp="finishDraw(event)" 
                      width="510">

            <!-- zoom window is drawn here -->
            <mx:annotationElements>
                <mx:CartesianDataCanvas id="chartCanvas"/>
            </mx:annotationElements>

            <mx:horizontalAxis>
                <mx:LinearAxis id="haxis"/>
            </mx:horizontalAxis>

            <mx:verticalAxis>
                <mx:LinearAxis id="vaxis"/>
            </mx:verticalAxis>

            <mx:series>
                <mx:LineSeries filterData="false" id="series1" xField="month" yField="profit" 
                               displayName="Profit" dataProvider="{profits}"/>
            </mx:series>

        </mx:LineChart>
    </mx:Panel>

    <mx:Button label="Reset Zoom" click="resetZoom()" />

</s:VGroup>

</s:Application>

更新:

这是解决方案,以防对其他人有用。我添加了一个 if 语句来检查空的 dragStart 和 dragEnd 值,如下面的答案中所述。此外,我已经删除了 flex 默认放置在线条系列上的阴影,因此如果用户选择的缩放区域太小,则不会出现警告。

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx"
           initialize="init()" width="600" height="520">
<fx:Script>
    <![CDATA[
        [Bindable]
        private var profits:Array;
        private var dragStart:Point;
        private var dragEnd:Point;
        private var zooming:Boolean;

        // initializes the data provider with random data
        private function init():void{
            profits = new Array({month: 0, profit: 15});
            for(var i:int=1; i<40; i++)
                profits.push({month: i, profit: Math.round(Math.random()*25-10)+profits[i-1].profit});
        }

        // sets the start point of the zoom window
        private function startDraw(e:MouseEvent):void{
            zooming = true;
            dragStart = new Point(series1.mouseX, series1.mouseY);
        }

        // draws the zoom window as your mouse moves
        private function showDraw(e:MouseEvent):void{
            if(zooming){
                dragEnd = new Point(series1.mouseX, series1.mouseY);

                // finds the top-left and bottom-right ponits of the zoom window
                var TL:Point = new Point();  // top-left point
                var BR:Point = new Point();  // bottom-right point
                if(dragStart.x < dragEnd.x){
                    TL.x = dragStart.x;
                    BR.x = dragEnd.x;
                }
                else{
                    TL.x = dragEnd.x;
                    BR.x = dragStart.x;
                }
                if(dragStart.y < dragEnd.y){
                    TL.y = dragStart.y;
                    BR.y = dragEnd.y;
                }
                else{
                    TL.y = dragEnd.y;
                    BR.y = dragStart.y;
                }

                // prevents the zoom window from going off the canvas
                if(TL.x < 0) TL.x = 0;
                if(BR.x > chartCanvas.width-1) BR.x = chartCanvas.width-1;
                if(TL.y < 0) TL.y = 0;
                if(BR.y > chartCanvas.height-1) BR.y = chartCanvas.height-1;

                // draw the actual zoom window
                chartCanvas.graphics.clear();
                chartCanvas.graphics.lineStyle(1, 0x000000, 0.25);
                chartCanvas.graphics.beginFill(0xd4e3f0,0.5);
                chartCanvas.graphics.drawRect(TL.x, TL.y, BR.x-TL.x, BR.y-TL.y);
                chartCanvas.graphics.endFill();
            }   
        }

        // clears the drawing canvas and sets the new max/mins
        private function finishDraw(e:MouseEvent):void{
            zooming = false;
            chartCanvas.graphics.clear();
           if (dragStart && dragEnd) {  // Solution to original posted quesion
            // converts the drag coordinates into axis data points
            var chartValStart:Array = chartCanvas.localToData(dragStart);
            var chartValEnd:Array = chartCanvas.localToData(dragEnd);

            // sets the new maximum and minimum for both axes
            haxis.minimum = (chartValStart[0] < chartValEnd[0]) ? chartValStart[0] : chartValEnd[0];
            haxis.maximum = (chartValStart[0] < chartValEnd[0]) ? chartValEnd[0] : chartValStart[0];
            vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
            vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
                       }
                       // reset values for next time
                       dragStart=null;
                       dragEnd=null;
        }

        // resets the axis max/mins
        private function resetZoom():void{
            haxis.minimum = NaN; 
            haxis.maximum = NaN; 
            vaxis.minimum = NaN; 
            vaxis.maximum = NaN;
        }   
]]>
</fx:Script>

<s:VGroup>

    <mx:Panel title="Line Chart">
        <mx:LineChart id="chart1" 
                      mouseDown="startDraw(event)" 
                      mouseMove="showDraw(event)" 
                      mouseUp="finishDraw(event)" 
                      width="510">

            <!-- zoom window is drawn here -->
            <mx:annotationElements>
                <mx:CartesianDataCanvas id="chartCanvas"/>
            </mx:annotationElements>

            <mx:horizontalAxis>
                <mx:LinearAxis id="haxis"/>
            </mx:horizontalAxis>

            <mx:verticalAxis>
                <mx:LinearAxis id="vaxis"/>
            </mx:verticalAxis>

            <mx:series>
                <mx:LineSeries filterData="false" id="series1" xField="month" yField="profit" 
                               displayName="Profit" dataProvider="{profits}"/>
            </mx:series>

            <mx:seriesFilters>
                <fx:Array/>
            </mx:seriesFilters>

        </mx:LineChart>
    </mx:Panel>

    <mx:Button label="Reset Zoom" click="resetZoom()" />

</s:VGroup>

</s:Application>
4

1 回答 1

1

您会收到此错误,因为dragEnd如果用户只是单击鼠标,则永远不会设置该变量。防止这种情况的最简单方法是检查函数null内的值finishDraw

private function finishDraw(e:MouseEvent):void
{
  zooming = false;
  chartCanvas.clear();

  if(dragStart && dragEnd)
  {
    //your stuff here
    //...

  }

  //reset values for next time
  dragStart=null;
  dragEnd=null;
}

这应该避免那里出现任何进一步的1009 错误。请注意,如果我拖动一个很小的缩放窗口然后释放鼠标,我会收到一些警告,因为 Flash 对 DisplayObject 的大小有限制,因此您还应该验证缩放窗口的尺寸。

希望这可以帮助!

于 2012-07-23T20:38:49.940 回答