我采用了这个网站的代码,
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>