Application { backgroundGradientColors: #FFFFFF, #FFFFFF; backgroundAlpha: 1; } AreaChart { gutterLeft: 0; gutterRight: 0; gutterTop: 0; gutterBottom: 0; } .noAxisStyle { showLine: false; showLabels: false; tickPlacement: none; } .mainChartStyle { gutterBottom: 18; gutterLeft: 0; gutterRight: 0; } .canvasContainerStyles { borderThickness: 1; borderColor: #333333; borderStyle: solid; backgroundColor: #FFFFFF; backgroundAlpha: 1; } GridLines { horizontalChangeCount: 1; verticalChangeCount: 2; direction: both; } HDividedBox { borderThickness: 1; borderColor: #CCCCCC; borderStyle: solid; } LinkButton { paddingLeft: 0; paddingRight: 0; paddingTop: 0; paddingBottom: 0; } Button { fillAlphas: 1,1; cornerRadius: 2; } 0 && allowUpdateComplete) { allowUpdateComplete = false; updateBoxFromSlider = true; updateBox(); this.visible = true; } } /** * Simple parsing function to convert the date strings in our dataset to the equivalent Date object. */ private function dateParse(value:String):Date { var dateArray:Array = value.split(' '); var datePart:Array = dateArray[0].split('-'); var hourPart:Array = dateArray[1].split(':'); return new Date(datePart[0], datePart[1] - 1, datePart[2], hourPart[0],hourPart[1]); } /** * Formats a date object from the DateTimeAxis into a label string */ private function formatDateLabel(value:Number, prevValue:Number, axis:DateTimeAxis):String { var dateValue:Date = new Date(); dateValue.setTime(value + ((dateValue.timezoneOffset + 60) * 60 * 1000)); switch(axis.labelUnits) { case "months": return labelMonthFormatter.format(dateValue); break; case "days": return labelDayFormatter.format(dateValue); case "hours": return labelHourFormatter.format(dateValue); case "minutes": return labelMinuteFormatter.format(dateValue); default: return labelDefaultFormatter.format(dateValue); break; } } /*Step 3 */ /** * Called throughout use to update the mainData range of data that is displayed by slicing the * range data to the left and right values. */ private function updateMainData():void { var delta:Number = rightIndicator.x - leftIndicator.x //if (leftIndicator.x > rangeData.length-120){ //mainData.source = detailData.source.slice(0, detailData.length-1); //datetimeaxis.dataUnits = "minutes" //datetimeaxis.interval=5 //chartMouseOut(); //} else { if (delta > 60){ datetimeaxis.dataUnits = "days" } else { datetimeaxis.dataUnits = "hours" } mainData.source = rangeData.source.slice(leftIndicator.x, rightIndicator.x); chartMouseOut(); //} } /** * Called from the slider value changes. It is filtered to only change when the slider calling it * directly. The updateBoxFromSlider value is set to false when the moveSlider function effect is * playing because the box widths have already been set by the dividerRelease calling * updateIndicatorValuesWithEffect. */ private function updateBox():void { if(updateBoxFromSlider) { //setting the box width value to the slider value times the ratio (to decrease //it to the equivalent width percentage //eg. full divided box width = 500, rangeDataRatio = 1/5 would equal 100 for the //proper left box width equal to range index value leftBox.width = slider.values[0] * rangeDataRatio; rightBox.width = dividedBox.width - ( slider.values[1] * rangeDataRatio ); leftIndicator.x = slider.values[0]; rightIndicator.x = slider.values[1]; updateMainData(); } } /** * Updates the range by moving the entire range left or right by a fixed number of units */ private function clickUpdate(value:int):void { leftIndicator.x += value; rightIndicator.x += value; slider.dispatchEvent(new SliderEvent('change')); } /** * Called from the divided box dividerRelease. Calls a Move for the left and right Indicator * x values which has an easing function * applied. */ private function updateIndicatorValuesWithEffect():void { //setting indicator positions to the box width divided by the ratio (to increase //it to the equivalent range value) //eg. left box width = 100, rangeDataRation = 1/5 would equal 500 for the range index value moveSlider(leftIndicator, (leftBox.width / rangeDataRatio), false); moveSlider(rightIndicator, ((dividedBox.width - rightBox.width) / rangeDataRatio), false); } /** * Called from the thumbRelease on the slider instance, as well as creationComplete * to set the initial range values. * Updates the left and right indicator x values without the move effect. */ private function updateIndicatorsQuietly():void { //these two values are mapped 1:1 as the slider values and indicator values equal the rangeData length exactly leftIndicator.x = slider.values[0]; rightIndicator.x = slider.values[1]; } /** * Moves the left and right indicator x values with an easing transition applied. update * dictates whether this should update the divided box range measurements (false if we're calling this * from the divided box release) callbackFunc can be passed to get called when the move is finished. */ private function moveSlider(target:VRule, xTo:Number, update:Boolean, callbackFunc:Function = null, ... rest):void { var moveIndicator:Move = new Move(); moveIndicator.end(); moveIndicator.easingFunction = Cubic.easeOut; moveIndicator.duration = 750; moveIndicator.target = target; moveIndicator.xTo = xTo; moveIndicator.addEventListener(EffectEvent.EFFECT_START, function():void {updateBoxFromSlider = update}); moveIndicator.addEventListener(TweenEvent.TWEEN_UPDATE, function():void { mainData.source = rangeData.source.slice(leftIndicator.x, rightIndicator.x); }); moveIndicator.addEventListener(EffectEvent.EFFECT_END, function():void {updateBoxFromSlider = true; if(callbackFunc != null) callbackFunc.call(this, rest)}); moveIndicator.play(); } /** * Called from range chart or main chart and determines the position of the mouse as well as left * and right indicators (for static comparison when moving) and adds systemManager events * to capture mouse movement. The values set here are used in the moveChart function to calculate * new position differences with start position */ private function setMouseDown(theChart:CartesianChart):void { //don't capture for drag if we're viewing the entire range of data if(!(leftIndicator.x == 0 && rightIndicator.x == rangeData.length)) { mouseXRef = this.mouseX; staticLeftBoundary = leftIndicator.x; staticRightBoundary = rightIndicator.x; if(theChart == mainChart) mainDrag = true; if(theChart == rangeChart) rangeDrag = true; this.systemManager.addEventListener(MouseEvent.MOUSE_MOVE, moveChart); this.systemManager.addEventListener(MouseEvent.MOUSE_UP, stopDragging); } } /** * Called when systemManager receives mouseUp event. Sets the indicators for which range is * being dragged to false, and removes the system manager event listeners for drag movement. */ private function stopDragging(event:MouseEvent):void { if(mainData.length < 2) { if(leftIndicator.x == rangeData.length) { leftIndicator.x = rangeData.length - 5; rightIndicator.x = rangeData.length; } else if(rightIndicator.x == 0) { leftIndicator.x = 0; rightIndicator.x = 5; } updateBox(); } rangeDrag = false; mainDrag = false; this.systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, moveChart); this.systemManager.removeEventListener(MouseEvent.MOUSE_UP, stopDragging); } /** * Determines which chart instance is being dragged, and updates the left and right indicator x values */ private function moveChart(event:MouseEvent):void { if(mainDrag) { leftIndicator.x = staticLeftBoundary + (mouseXRef - this.mouseX) / (mainChartArea.width / mainData.length); rightIndicator.x = staticRightBoundary + (mouseXRef - this.mouseX) / (mainChartArea.width / mainData.length); } else if(rangeDrag) { leftIndicator.x = staticLeftBoundary - (mouseXRef - this.mouseX) / rangeDataRatio; rightIndicator.x = staticRightBoundary - (mouseXRef - this.mouseX) / rangeDataRatio; } } /* Step 4 */ /** * Finds the DateTimeAxis value (the date) of the mouseover position */ private function getChartDataPoint():void { } /** * Called when cursor is moved off of main chart area. Clears any values that are bound * to mouseover position, and clears all * LineSeriesCustomRenderers on the chart that are showing */ private function chartMouseOut():void { if(mainData.length > 2) { for(var i:int = 0; i < mainData.length; i++) { try { mainChart.series[0].getChildAt(i + 1).showRenderer(false); mainChartVolume.series[0].getChildAt(i).showRenderer(false); } catch(e:Error) {}; } _selectedDate = labelSummaryDateFormatter.format(dateParse(mainData.getItemAt(0).date)) + ' - ' + labelSummaryDateFormatter.format(dateParse(mainData.getItemAt(mainData.length - 1).date)); } else { _selectedDate = ''; } } /** * Finds the DateTimeAxis value (the date) of the mouseover position * invertTransform takes a point in stage space (x and y coordinate) and transforms it into the * relative point in data space, giving appropriate values along x axis (first item in return array), * and y axis (second item in return array) */ private function getChartCoordinates(thePos:Point, theChart:CartesianChart):Object { var tmpArray:Array; if(theChart.series[0] != null) { tmpArray = theChart.series[0].dataTransform.invertTransform(thePos.x, thePos.y); return {x:tmpArray[0], y:tmpArray[1]}; } else { return null; } } /** * Updates the date range display to reflect the current position of the divided box drag */ private function setDividerDragDate():void { var tmpLeftIndex:int = leftBox.width / rangeDataRatio; var tmpRightIndex:int = ((dividedBox.width - rightBox.width) / rangeDataRatio) - 1; if(tmpLeftIndex >= 0 && tmpRightIndex <= rangeData.length) { _selectedDate = labelSummaryDateFormatter.format(dateParse(rangeData.getItemAt(tmpLeftIndex).date)) + ' - ' + labelSummaryDateFormatter.format(dateParse(rangeData.getItemAt(tmpRightIndex).date)); } } /*Step 5 */ /** * Prevents rollover or selection effects in the list control */ private function myEasingFunction(t:Number, b:Number, c:Number, d:Number):Number { return 0; } ]]>