From 4f50949a135ae7390bc0cfc0c48e9219ce18b665 Mon Sep 17 00:00:00 2001 From: padams Date: Sat, 16 Aug 2008 20:44:17 +0000 Subject: [PATCH] adding OFC, sparklines, revamped metrics, revamped db, etc. --- includes/open-flash-chart.php | 1634 +++++++++++++++++ includes/sparkline-php-0.2/CHANGES | 22 + includes/sparkline-php-0.2/DESIGN | 27 + includes/sparkline-php-0.2/LICENSE | 29 + includes/sparkline-php-0.2/README | 37 + includes/sparkline-php-0.2/lib/Object.php | 158 ++ includes/sparkline-php-0.2/lib/Sparkline.php | 496 +++++ .../sparkline-php-0.2/lib/Sparkline_Bar.php | 191 ++ .../sparkline-php-0.2/lib/Sparkline_Line.php | 279 +++ .../sparkline-php-0.2/samples/baseball.php | 93 + .../sparkline-php-0.2/samples/deficit.php | 69 + includes/sparkline-php-0.2/samples/filled.php | 69 + .../sparkline-php-0.2/samples/primitives.php | 37 + .../sparkline-php-0.2/samples/stock_chart.php | 93 + .../samples/stock_chart2.php | 126 ++ .../samples/stock_chart3.php | 112 ++ modules/base/classes/entityManager.php | 314 +++- modules/base/dashboardTrendWidget.php | 84 + modules/base/graphPageTypes.php | 3 +- modules/base/logSessionUpdate.php | 1 + modules/base/metrics/clickBrowserTypes.php | 24 +- modules/base/metrics/clickstream.php | 19 +- modules/base/metrics/dashCoreByDay.php | 32 +- modules/base/metrics/dashCoreByMonth.php | 25 +- modules/base/metrics/dashCounts.php | 18 +- modules/base/metrics/dashCountsTraffic.php | 23 +- modules/base/metrics/feedReaderTypesCount.php | 21 +- modules/base/metrics/feedViewsTrend.php | 17 +- modules/base/metrics/latestVisits.php | 48 +- modules/base/metrics/pageTypesCount.php | 29 +- modules/base/metrics/pageViewsByDay.php | 30 +- modules/base/metrics/pageViewsCount.php | 20 +- modules/base/metrics/requestCounts.php | 19 +- modules/base/metrics/requestCountsByDay.php | 29 +- modules/base/metrics/sessionBrowserTypes.php | 19 +- modules/base/metrics/sessionsCount.php | 14 +- modules/base/metrics/topClicks.php | 27 +- modules/base/metrics/topEntryPages.php | 29 +- modules/base/metrics/topExitPages.php | 30 +- modules/base/metrics/topHosts.php | 28 +- modules/base/metrics/topPages.php | 51 +- modules/base/metrics/topReferers.php | 32 +- modules/base/metrics/topReferingAnchors.php | 26 +- modules/base/metrics/topReferingHosts.php | 24 +- modules/base/metrics/topReferingKeywords.php | 25 +- modules/base/metrics/topVisitors.php | 27 +- modules/base/metrics/visitorTypesCount.php | 17 +- modules/base/metrics/visitorsAge.php | 36 +- modules/base/metrics/visitorsList.php | 17 +- .../base/metrics/visitorsUserAgentCount.php | 18 +- .../base/metrics/visitsFromDirectNavCount.php | 28 +- modules/base/metrics/visitsFromFeedsCount.php | 23 +- .../metrics/visitsFromSearchEnginesCount.php | 22 +- modules/base/metrics/visitsFromSitesCount.php | 26 +- modules/base/optionsFlushCache.php | 6 +- modules/base/optionsGeneral.php | 2 +- modules/base/optionsModules.php | 6 +- modules/base/optionsReset.php | 6 +- modules/base/optionsUpdate.php | 6 +- modules/base/passwordResetRequest.php | 6 +- modules/base/reportDashboard.php | 14 +- modules/base/templates/report_dashboard.tpl | 5 +- modules/base/templates/report_visit.tpl | 6 +- modules/base/templates/widget.tpl | 16 + modules/base/templates/wrapper_mediawiki.tpl | 4 +- modules/base/visitorTypesWidget.php | 116 ++ modules/base/widget.php | 110 ++ owa_adminController.php | 9 +- owa_auth.php | 13 +- owa_controller.php | 12 +- owa_coreAPI.php | 344 ++-- owa_db.php | 685 +++++++ owa_entity.php | 116 +- owa_lib.php | 28 + owa_metric.php | 208 ++- owa_template.php | 113 +- owa_view.php | 101 + plugins/db/owa_db_mysql.php | 425 +---- .../ofc-1.9/actionscript/AreaHollow.as | 90 + .../ofc-1.9/actionscript/Background.as | 121 ++ public/includes/ofc-1.9/actionscript/Bar3D.as | 122 ++ .../includes/ofc-1.9/actionscript/BarArrow.as | 110 ++ .../includes/ofc-1.9/actionscript/BarFade.as | 58 + .../ofc-1.9/actionscript/BarGlassStyle.as | 147 ++ .../ofc-1.9/actionscript/BarSketchStyle.as | 90 + .../includes/ofc-1.9/actionscript/BarStyle.as | 238 +++ .../includes/ofc-1.9/actionscript/BarZebra.as | 113 ++ public/includes/ofc-1.9/actionscript/Box.as | 329 ++++ .../ofc-1.9/actionscript/CandleStyle.as | 230 +++ .../ofc-1.9/actionscript/ChartUtil.as | 277 +++ public/includes/ofc-1.9/actionscript/Css.as | 253 +++ .../includes/ofc-1.9/actionscript/ExPoint.as | 27 + .../ofc-1.9/actionscript/FilledBarStyle.as | 57 + .../includes/ofc-1.9/actionscript/HLCStyle.as | 202 ++ .../ofc-1.9/actionscript/InnerBackground.as | 75 + .../ofc-1.9/actionscript/Invisible.as | 68 + public/includes/ofc-1.9/actionscript/Keys.as | 117 ++ .../includes/ofc-1.9/actionscript/LineDot.as | 68 + .../ofc-1.9/actionscript/LineHollow.as | 56 + .../ofc-1.9/actionscript/LineStyle.as | 244 +++ .../includes/ofc-1.9/actionscript/Loading.as | 95 + .../includes/ofc-1.9/actionscript/MinMax.as | 78 + .../ofc-1.9/actionscript/NumberFormat.as | 76 + .../ofc-1.9/actionscript/NumberUtils.as | 93 + .../includes/ofc-1.9/actionscript/Parser.as | 160 ++ .../includes/ofc-1.9/actionscript/PieStyle.as | 384 ++++ public/includes/ofc-1.9/actionscript/Point.as | 63 + .../includes/ofc-1.9/actionscript/PointBar.as | 17 + .../ofc-1.9/actionscript/PointCandle.as | 38 + .../includes/ofc-1.9/actionscript/PointHLC.as | 39 + .../ofc-1.9/actionscript/PointScatter.as | 4 + .../includes/ofc-1.9/actionscript/README.txt | 16 + .../includes/ofc-1.9/actionscript/Scatter.as | 228 +++ public/includes/ofc-1.9/actionscript/Size.as | 11 + .../includes/ofc-1.9/actionscript/Square.as | 19 + .../actionscript/String.prototype.replace.as | 42 + public/includes/ofc-1.9/actionscript/Style.as | 77 + public/includes/ofc-1.9/actionscript/Title.as | 101 + .../includes/ofc-1.9/actionscript/Tooltip.as | 139 ++ .../includes/ofc-1.9/actionscript/Values.as | 184 ++ public/includes/ofc-1.9/actionscript/XAxis.as | 220 +++ .../ofc-1.9/actionscript/XAxisLabels.as | 168 ++ .../ofc-1.9/actionscript/XLabelStyle.as | 48 + .../includes/ofc-1.9/actionscript/XLegend.as | 73 + public/includes/ofc-1.9/actionscript/YAxis.as | 147 ++ .../ofc-1.9/actionscript/YAxisLabels.as | 109 ++ .../ofc-1.9/actionscript/YLabelStyle.as | 72 + .../includes/ofc-1.9/actionscript/YLegend.as | 69 + .../includes/ofc-1.9/actionscript/YTicks.as | 21 + .../caurina/transitions/AuxFunctions.as | 88 + .../caurina/transitions/Equations.as | 692 +++++++ .../caurina/transitions/PropertyInfoObj.as | 68 + .../transitions/SpecialPropertiesDefault.as | 414 +++++ .../caurina/transitions/SpecialProperty.as | 57 + .../transitions/SpecialPropertyModifier.as | 39 + .../transitions/SpecialPropertySplitter.as | 46 + .../caurina/transitions/TweenListObj.as | 210 +++ .../caurina/transitions/Tweener.as | 1047 +++++++++++ .../ofc-1.9/actionscript/open-flash-chart.as | 981 ++++++++++ .../ofc-1.9/actionscript/open-flash-chart.fla | Bin 0 -> 22528 bytes .../actionscript/open-flash-chart.html | 15 + .../ofc-1.9/actionscript/open-flash-chart.swf | Bin 0 -> 64600 bytes .../actionscript/prototype.drawCircle.as | 19 + .../actionscript/prototype.fillCircle.as | 22 + .../ofc-1.9/actionscript/rrectangle.as | 36 + public/includes/ofc-1.9/swfobject.js | 233 +++ wp_plugin.php | 4 +- 147 files changed, 15992 insertions(+), 966 deletions(-) create mode 100755 includes/open-flash-chart.php create mode 100644 includes/sparkline-php-0.2/CHANGES create mode 100644 includes/sparkline-php-0.2/DESIGN create mode 100644 includes/sparkline-php-0.2/LICENSE create mode 100644 includes/sparkline-php-0.2/README create mode 100644 includes/sparkline-php-0.2/lib/Object.php create mode 100644 includes/sparkline-php-0.2/lib/Sparkline.php create mode 100644 includes/sparkline-php-0.2/lib/Sparkline_Bar.php create mode 100644 includes/sparkline-php-0.2/lib/Sparkline_Line.php create mode 100644 includes/sparkline-php-0.2/samples/baseball.php create mode 100644 includes/sparkline-php-0.2/samples/deficit.php create mode 100644 includes/sparkline-php-0.2/samples/filled.php create mode 100644 includes/sparkline-php-0.2/samples/primitives.php create mode 100644 includes/sparkline-php-0.2/samples/stock_chart.php create mode 100644 includes/sparkline-php-0.2/samples/stock_chart2.php create mode 100644 includes/sparkline-php-0.2/samples/stock_chart3.php create mode 100644 modules/base/dashboardTrendWidget.php create mode 100644 modules/base/templates/widget.tpl create mode 100644 modules/base/visitorTypesWidget.php create mode 100644 modules/base/widget.php create mode 100755 public/includes/ofc-1.9/actionscript/AreaHollow.as create mode 100755 public/includes/ofc-1.9/actionscript/Background.as create mode 100755 public/includes/ofc-1.9/actionscript/Bar3D.as create mode 100755 public/includes/ofc-1.9/actionscript/BarArrow.as create mode 100755 public/includes/ofc-1.9/actionscript/BarFade.as create mode 100755 public/includes/ofc-1.9/actionscript/BarGlassStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/BarSketchStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/BarStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/BarZebra.as create mode 100755 public/includes/ofc-1.9/actionscript/Box.as create mode 100755 public/includes/ofc-1.9/actionscript/CandleStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/ChartUtil.as create mode 100755 public/includes/ofc-1.9/actionscript/Css.as create mode 100755 public/includes/ofc-1.9/actionscript/ExPoint.as create mode 100755 public/includes/ofc-1.9/actionscript/FilledBarStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/HLCStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/InnerBackground.as create mode 100755 public/includes/ofc-1.9/actionscript/Invisible.as create mode 100755 public/includes/ofc-1.9/actionscript/Keys.as create mode 100755 public/includes/ofc-1.9/actionscript/LineDot.as create mode 100755 public/includes/ofc-1.9/actionscript/LineHollow.as create mode 100755 public/includes/ofc-1.9/actionscript/LineStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/Loading.as create mode 100755 public/includes/ofc-1.9/actionscript/MinMax.as create mode 100755 public/includes/ofc-1.9/actionscript/NumberFormat.as create mode 100755 public/includes/ofc-1.9/actionscript/NumberUtils.as create mode 100755 public/includes/ofc-1.9/actionscript/Parser.as create mode 100755 public/includes/ofc-1.9/actionscript/PieStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/Point.as create mode 100755 public/includes/ofc-1.9/actionscript/PointBar.as create mode 100755 public/includes/ofc-1.9/actionscript/PointCandle.as create mode 100755 public/includes/ofc-1.9/actionscript/PointHLC.as create mode 100755 public/includes/ofc-1.9/actionscript/PointScatter.as create mode 100755 public/includes/ofc-1.9/actionscript/README.txt create mode 100755 public/includes/ofc-1.9/actionscript/Scatter.as create mode 100755 public/includes/ofc-1.9/actionscript/Size.as create mode 100755 public/includes/ofc-1.9/actionscript/Square.as create mode 100755 public/includes/ofc-1.9/actionscript/String.prototype.replace.as create mode 100755 public/includes/ofc-1.9/actionscript/Style.as create mode 100755 public/includes/ofc-1.9/actionscript/Title.as create mode 100755 public/includes/ofc-1.9/actionscript/Tooltip.as create mode 100755 public/includes/ofc-1.9/actionscript/Values.as create mode 100755 public/includes/ofc-1.9/actionscript/XAxis.as create mode 100755 public/includes/ofc-1.9/actionscript/XAxisLabels.as create mode 100755 public/includes/ofc-1.9/actionscript/XLabelStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/XLegend.as create mode 100755 public/includes/ofc-1.9/actionscript/YAxis.as create mode 100755 public/includes/ofc-1.9/actionscript/YAxisLabels.as create mode 100755 public/includes/ofc-1.9/actionscript/YLabelStyle.as create mode 100755 public/includes/ofc-1.9/actionscript/YLegend.as create mode 100755 public/includes/ofc-1.9/actionscript/YTicks.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/AuxFunctions.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/Equations.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/PropertyInfoObj.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertiesDefault.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialProperty.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertyModifier.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertySplitter.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/TweenListObj.as create mode 100755 public/includes/ofc-1.9/actionscript/caurina/transitions/Tweener.as create mode 100755 public/includes/ofc-1.9/actionscript/open-flash-chart.as create mode 100755 public/includes/ofc-1.9/actionscript/open-flash-chart.fla create mode 100755 public/includes/ofc-1.9/actionscript/open-flash-chart.html create mode 100755 public/includes/ofc-1.9/actionscript/open-flash-chart.swf create mode 100755 public/includes/ofc-1.9/actionscript/prototype.drawCircle.as create mode 100755 public/includes/ofc-1.9/actionscript/prototype.fillCircle.as create mode 100755 public/includes/ofc-1.9/actionscript/rrectangle.as create mode 100755 public/includes/ofc-1.9/swfobject.js diff --git a/includes/open-flash-chart.php b/includes/open-flash-chart.php new file mode 100755 index 000000000..3bde0236d --- /dev/null +++ b/includes/open-flash-chart.php @@ -0,0 +1,1634 @@ +data_sets = array(); + + + $this->data = array(); + $this->links = array(); + $this->width = 250; + $this->height = 200; + $this->js_path = 'js/'; + $this->swf_path = ''; + $this->x_labels = array(); + $this->y_min = ''; + $this->y_max = ''; + $this->x_min = ''; + $this->x_max = ''; + $this->y_steps = ''; + $this->title = ''; + $this->title_style = ''; + $this->occurence = 0; + + $this->x_offset = ''; + + $this->x_tick_size = -1; + + $this->y2_max = ''; + $this->y2_min = ''; + + // GRID styles: + $this->x_axis_colour = ''; + $this->x_axis_3d = ''; + $this->x_grid_colour = ''; + $this->x_axis_steps = 1; + $this->y_axis_colour = ''; + $this->y_grid_colour = ''; + $this->y2_axis_colour = ''; + + // AXIS LABEL styles: + $this->x_label_style = ''; + $this->y_label_style = ''; + $this->y_label_style_right = ''; + + + // AXIS LEGEND styles: + $this->x_legend = ''; + $this->x_legend_size = 20; + $this->x_legend_colour = '#000000'; + + $this->y_legend = ''; + $this->y_legend_right = ''; + //$this->y_legend_size = 20; + //$this->y_legend_colour = '#000000'; + + $this->lines = array(); + $this->line_default['type'] = 'line'; + $this->line_default['values'] = '3,#87421F'; + $this->js_line_default = 'so.addVariable("line","3,#87421F");'; + + $this->bg_colour = ''; + $this->bg_image = ''; + + $this->inner_bg_colour = ''; + $this->inner_bg_colour_2 = ''; + $this->inner_bg_angle = ''; + + // PIE chart ------------ + $this->pie = ''; + $this->pie_values = ''; + $this->pie_colours = ''; + $this->pie_labels = ''; + + $this->tool_tip = ''; + + // which data lines are attached to the + // right Y axis? + $this->y2_lines = array(); + + // Number formatting: + $this->y_format=''; + $this->num_decimals=''; + $this->is_fixed_num_decimals_forced=''; + $this->is_decimal_separator_comma=''; + $this->is_thousand_separator_disabled=''; + + $this->output_type = ''; + + // + // set some default value incase the user forgets + // to set them, so at least they see *something* + // even is it is only the axis and some ticks + // + $this->set_y_min( 0 ); + $this->set_y_max( 20 ); + $this->set_x_axis_steps( 1 ); + $this->y_label_steps( 5 ); + } + + /** + * Set the unique_id to use for the flash object id. + */ + function set_unique_id() + { + $this->unique_id = uniqid(rand(), true); + } + + /** + * Get the flash object ID for the last rendered object. + */ + function get_unique_id() + { + return ($this->unique_id); + } + + /** + * Set the base path for the swfobject.js + * + * @param base_path a string argument. + * The path to the swfobject.js file + */ + function set_js_path($path) + { + $this->js_path = $path; + } + + /** + * Set the base path for the open-flash-chart.swf + * + * @param path a string argument. + * The path to the open-flash-chart.swf file + */ + function set_swf_path($path) + { + $this->swf_path = $path; + } + + /** + * Set the type of output data. + * + * @param type a string argument. + * The type of data. Currently only type is js, or nothing. + */ + function set_output_type($type) + { + $this->output_type = $type; + } + + /** + * returns the next line label for multiple lines. + */ + function next_line() + { + $line_num = ''; + if( count( $this->lines ) > 0 ) + $line_num = '_'. (count( $this->lines )+1); + + return $line_num; + } + + // escape commas (,) + function esc( $text ) + { + // we replace the comma so it is not URL escaped + // if it is, flash just thinks it is a comma + // which is no good if we are splitting the + // string on commas. + $tmp = str_replace( ',', '#comma#', $text ); + //$tmp = utf8_encode( $tmp ); + // now we urlescape all dodgy characters (like & % $ etc..) + return urlencode( $tmp ); + } + + /** + * Format the text to the type of output. + */ + function format_output($function,$values) + { + if($this->output_type == 'js') + { + $tmp = 'so.addVariable("'. $function .'","'. $values . '");'; + } + else + { + $tmp = '&'. $function .'='. $values .'&'; + } + + return $tmp; + } + + /** + * Set the text and style of the title. + * + * @param title a string argument. + * The text of the title. + * @param style a string. + * CSS styling of the title. + */ + function set_title( $title, $style='' ) + { + $this->title = $this->esc( $title ); + if( strlen( $style ) > 0 ) + $this->title_style = $style; + } + + /** + * Set the width of the chart. + * + * @param width an int argument. + * The width of the chart frame. + */ + function set_width( $width ) + { + $this->width = $width; + } + + /** + * Set the height of the chart. + * + * @param height an int argument. + * The height of the chart frame. + */ + function set_height( $height ) + { + $this->height = $height; + } + + /** + * Set the base path of the swfobject. + * + * @param base a string argument. + * The base path of the swfobject. + */ + function set_base( $base='js/' ) + { + $this->base = $base; + } + + // Number formatting: + function set_y_format( $val ) + { + $this->y_format = $val; + } + + function set_num_decimals( $val ) + { + $this->num_decimals = $val; + } + + function set_is_fixed_num_decimals_forced( $val ) + { + $this->is_fixed_num_decimals_forced = $val?'true':'false'; + } + + function set_is_decimal_separator_comma( $val ) + { + $this->is_decimal_separator_comma = $val?'true':'false'; + } + + function set_is_thousand_separator_disabled( $val ) + { + $this->is_thousand_separator_disabled = $val?'true':'false'; + } + + /** + * Set the data for the chart + * @param a an array argument. + * An array of the data to add to the chart. + */ + function set_data( $a ) + { + $this->data[] = implode(',',$a); + } + + // UGH, these evil functions are making me fell ill + function set_links( $links ) + { + // TO DO escape commas: + $this->links[] = implode(',',$links); + } + + // $val is a boolean + function set_x_offset( $val ) + { + $this->x_offset = $val?'true':'false'; + } + + /** + * Set the tooltip to be displayed on each chart item.\n + * \n + * Replaceable tokens that can be used in the string include: \n + * #val# - The actual value of whatever the mouse is over. \n + * #key# - The key string. \n + * \
- New line. \n + * #x_label# - The X label string. \n + * #x_legend# - The X axis legend text. \n + * Default string is: "#x_label#
#val#" \n + * + * @param tip a string argument. + * A formatted string to show as the tooltip. + */ + function set_tool_tip( $tip ) + { + $this->tool_tip = $this->esc( $tip ); + } + + /** + * Set the x axis labels + * + * @param a an array argument. + * An array of the x axis labels. + */ + function set_x_labels( $a ) + { + $tmp = array(); + foreach( $a as $item ) + $tmp[] = $this->esc( $item ); + $this->x_labels = $tmp; + } + + /** + * Set the look and feel of the x axis labels + * + * @param font_size an int argument. + * The font size. + * @param colour a string argument. + * The hex colour value. + * @param orientation an int argument. + * The orientation of the x-axis text. + * 0 - Horizontal + * 1 - Vertical + * 2 - 45 degrees + * @param step an int argument. + * Show the label on every $step label. + * @param grid_colour a string argument. + */ + function set_x_label_style( $size, $colour='', $orientation=0, $step=-1, $grid_colour='' ) + { + $this->x_label_style = $size; + + if( strlen( $colour ) > 0 ) + $this->x_label_style .= ','. $colour; + + if( $orientation > -1 ) + $this->x_label_style .= ','. $orientation; + + if( $step > 0 ) + $this->x_label_style .= ','. $step; + + if( strlen( $grid_colour ) > 0 ) + $this->x_label_style .= ','. $grid_colour; + } + + /** + * Set the background colour. + * @param colour a string argument. + * The hex colour value. + */ + function set_bg_colour( $colour ) + { + $this->bg_colour = $colour; + } + + /** + * Set a background image. + * @param url a string argument. + * The location of the image. + * @param x a string argument. + * The x location of the image. 'Right', 'Left', 'Center' + * @param y a string argument. + * The y location of the image. 'Top', 'Bottom', 'Middle' + */ + function set_bg_image( $url, $x='center', $y='center' ) + { + $this->bg_image = $url; + $this->bg_image_x = $x; + $this->bg_image_y = $y; + } + + /** + * Attach a set of data (a line, area or bar chart) to the right Y axis. + * @param data_number an int argument. + * The numbered order the data was attached using set_data. + */ + function attach_to_y_right_axis( $data_number ) + { + $this->y2_lines[] = $data_number; + } + + /** + * Set the background colour of the grid portion of the chart. + * @param col a string argument. + * The hex colour value of the background. + * @param col2 a string argument. + * The hex colour value of the second colour if you want a gradient. + * @param angle an int argument. + * The angle in degrees to make the gradient. + */ + function set_inner_background( $col, $col2='', $angle=-1 ) + { + $this->inner_bg_colour = $col; + + if( strlen($col2) > 0 ) + $this->inner_bg_colour_2 = $col2; + + if( $angle != -1 ) + $this->inner_bg_angle = $angle; + } + + /** + * Internal function to build the y label style for y and y2 + */ + function _set_y_label_style( $size, $colour ) + { + $tmp = $size; + + if( strlen( $colour ) > 0 ) + $tmp .= ','. $colour; + return $tmp; + } + + /** + * Set the look and feel of the y axis labels + * + * @param font_size an int argument. + * The font size. + * @param colour a string argument. + * The hex colour value. + */ + function set_y_label_style( $size, $colour='' ) + { + $this->y_label_style = $this->_set_y_label_style( $size, $colour ); + } + + /** + * Set the look and feel of the right y axis labels + * + * @param font_size an int argument. + * The font size. + * @param colour a string argument. + * The hex colour value. + */ + function set_y_right_label_style( $size, $colour='' ) + { + $this->y_label_style_right = $this->_set_y_label_style( $size, $colour ); + } + + function set_x_max( $max ) + { + $this->x_max = floatval( $max ); + } + + function set_x_min( $min ) + { + $this->x_min = floatval( $min ); + } + + /** + * Set the maximum value of the y axis. + * + * @param max an float argument. + * The maximum value. + */ + function set_y_max( $max ) + { + $this->y_max = floatval( $max ); + } + + /** + * Set the minimum value of the y axis. + * + * @param min an float argument. + * The minimum value. + */ + function set_y_min( $min ) + { + $this->y_min = floatval( $min ); + } + + /** + * Set the maximum value of the right y axis. + * + * @param max an float argument. + * The maximum value. + */ + function set_y_right_max( $max ) + { + $this->y2_max = floatval($max); + } + + /** + * Set the minimum value of the right y axis. + * + * @param min an float argument. + * The minimum value. + */ + function set_y_right_min( $min ) + { + $this->y2_min = floatval($min); + } + + /** + * Show the y label on every $step label. + * + * @param val an int argument. + * Show the label on every $step label. + */ + function y_label_steps( $val ) + { + $this->y_steps = intval( $val ); + } + + function title( $title, $style='' ) + { + $this->title = $this->esc( $title ); + if( strlen( $style ) > 0 ) + $this->title_style = $style; + } + + /** + * Set the parameters of the x legend. + * + * @param text a string argument. + * The text of the x legend. + * @param font_size an int argument. + * The font size of the x legend text. + * @param colour a string argument + * The hex value of the font colour. + */ + function set_x_legend( $text, $size=-1, $colour='' ) + { + $this->x_legend = $this->esc( $text ); + if( $size > -1 ) + $this->x_legend_size = $size; + + if( strlen( $colour )>0 ) + $this->x_legend_colour = $colour; + } + + /** + * Set the size of the x label ticks. + * + * @param size an int argument. + * The size of the ticks in pixels. + */ + function set_x_tick_size( $size ) + { + if( $size > 0 ) + $this->x_tick_size = $size; + } + + /** + * Set how often you would like to show a tick on the x axis. + * + * @param steps an int argument. + * Show a tick ever $steps. + */ + function set_x_axis_steps( $steps ) + { + if ( $steps > 0 ) + $this->x_axis_steps = $steps; + } + + /** + * Set the depth in pixels of the 3D X axis slab. + * + * @param size an int argument. + * The depth in pixels of the 3D X axis. + */ + function set_x_axis_3d( $size ) + { + if( $size > 0 ) + $this->x_axis_3d = intval($size); + } + + /** + * The private method of building the y legend output. + */ + function _set_y_legend( $text, $size, $colour ) + { + $tmp = $text; + + if( $size > -1 ) + $tmp .= ','. $size; + + if( strlen( $colour )>0 ) + $tmp .= ','. $colour; + + return $tmp; + } + + /** + * Set the parameters of the y legend. + * + * @param text a string argument. + * The text of the y legend. + * @param font_size an int argument. + * The font size of the y legend text. + * @param colour a string argument + * The hex colour value of the font colour. + */ + function set_y_legend( $text, $size=-1, $colour='' ) + { + $this->y_legend = $this->_set_y_legend( $text, $size, $colour ); + } + + /** + * Set the parameters of the right y legend. + * + * @param text a string argument. + * The text of the right y legend. + * @param font_size an int argument. + * The font size of the right y legend text. + * @param colour a string argument + * The hex value of the font colour. + */ + function set_y_right_legend( $text, $size=-1, $colour='' ) + { + $this->y_legend_right = $this->_set_y_legend( $text, $size, $colour ); + } + + /** + * Set the colour of the x axis line and grid. + * + * @param axis a string argument. + * The hex colour value of the x axis line. + * @param grid a string argument. + * The hex colour value of the x axis grid. + */ + function x_axis_colour( $axis, $grid='' ) + { + $this->x_axis_colour = $axis; + $this->x_grid_colour = $grid; + } + + /** + * Set the colour of the y axis line and grid. + * + * @param axis a string argument. + * The hex colour value of the y axis line. + * @param grid a string argument. + * The hex colour value of the y axis grid. + */ + function y_axis_colour( $axis, $grid='' ) + { + $this->y_axis_colour = $axis; + + if( strlen( $grid ) > 0 ) + $this->y_grid_colour = $grid; + } + + /** + * Set the colour of the right y axis line. + * + * @param colour a string argument. + * The hex colour value of the right y axis line. + */ + function y_right_axis_colour( $colour ) + { + $this->y2_axis_colour = $colour; + } + + /** + * Draw a line without markers on values. + * + * @param width an int argument. + * The width of the line in pixels. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label + * @param circles an int argument + * Need to find out. + */ + function line( $width, $colour='', $text='', $size=-1, $circles=-1 ) + { + $type = 'line'. $this->next_line(); + + $description = ''; + if( $width > 0 ) + { + $description .= $width; + $description .= ','. $colour; + } + + if( strlen( $text ) > 0 ) + { + $description.= ','. $text; + $description .= ','. $size; + } + + if( $circles > 0 ) + $description .= ','. $circles; + + $this->lines[$type] = $description; + } + + /** + * Draw a line with solid dot markers on values. + * + * @param width an int argument. + * The width of the line in pixels. + * @param dot_size an int argument. + * Size in pixels of the dot. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function line_dot( $width, $dot_size, $colour, $text='', $font_size='' ) + { + $type = 'line_dot'. $this->next_line(); + + $description = "$width,$colour,$text"; + + if( strlen( $font_size ) > 0 ) + $description .= ",$font_size,$dot_size"; + + $this->lines[$type] = $description; + } + + /** + * Draw a line with hollow dot markers on values. + * + * @param width an int argument. + * The width of the line in pixels. + * @param dot_size an int argument. + * Size in pixels of the dot. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function line_hollow( $width, $dot_size, $colour, $text='', $font_size='' ) + { + $type = 'line_hollow'. $this->next_line(); + + $description = "$width,$colour,$text"; + + if( strlen( $font_size ) > 0 ) + $description .= ",$font_size,$dot_size"; + + $this->lines[$type] = $description; + } + + /** + * Draw an area chart. + * + * @param width an int argument. + * The width of the line in pixels. + * @param dot_size an int argument. + * Size in pixels of the dot. + * @param colour a string argument. + * The hex colour value of the line. + * @param alpha an int argument. + * The percentage of transparency of the fill colour. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + * @param fill_colour a string argument. + * The hex colour value of the fill colour. + */ + function area_hollow( $width, $dot_size, $colour, $alpha, $text='', $font_size='', $fill_colour='' ) + { + $type = 'area_hollow'. $this->next_line(); + + $description = "$width,$dot_size,$colour,$alpha"; + + if( strlen( $text ) > 0 ) + $description .= ",$text,$font_size"; + + if( strlen( $fill_colour ) > 0 ) + $description .= ','. $fill_colour; + + $this->lines[$type] = $description; + } + + /** + * Draw a bar chart. + * + * @param alpha an int argument. + * The percentage of transparency of the bar colour. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function bar( $alpha, $colour='', $text='', $size=-1 ) + { + $type = 'bar'. $this->next_line(); + + $description = $alpha .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + } + + /** + * Draw a bar chart with an outline. + * + * @param alpha an int argument. + * The percentage of transparency of the bar colour. + * @param colour a string argument. + * The hex colour value of the line. + * @param colour_outline a strng argument. + * The hex colour value of the outline. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function bar_filled( $alpha, $colour, $colour_outline, $text='', $size=-1 ) + { + $type = 'filled_bar'. $this->next_line(); + + $description = "$alpha,$colour,$colour_outline,$text,$size"; + + $this->lines[$type] = $description; + } + + function bar_sketch( $alpha, $offset, $colour, $colour_outline, $text='', $size=-1 ) + { + $type = 'bar_sketch'. $this->next_line(); + + $description = "$alpha,$offset,$colour,$colour_outline,$text,$size"; + + $this->lines[$type] = $description; + } + + /** + * Draw a 3D bar chart. + * + * @param alpha an int argument. + * The percentage of transparency of the bar colour. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function bar_3D( $alpha, $colour='', $text='', $size=-1 ) + { + $type = 'bar_3d'. $this->next_line(); + + $description = $alpha .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + } + + /** + * Draw a 3D bar chart that looks like glass. + * + * @param alpha an int argument. + * The percentage of transparency of the bar colour. + * @param colour a string argument. + * The hex colour value of the line. + * @param outline_colour a string argument. + * The hex colour value of the outline. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function bar_glass( $alpha, $colour, $outline_colour, $text='', $size=-1 ) + { + $type = 'bar_glass'. $this->next_line(); + + $description = $alpha .','. $colour .','. $outline_colour .','. $text .','. $size; + + $this->lines[$type] = $description; + } + + /** + * Draw a faded bar chart. + * + * @param alpha an int argument. + * The percentage of transparency of the bar colour. + * @param colour a string argument. + * The hex colour value of the line. + * @param text a string argument. + * The label of the line. + * @param font_size an int argument. + * Font size of the label. + */ + function bar_fade( $alpha, $colour='', $text='', $size=-1 ) + { + $type = 'bar_fade'. $this->next_line(); + + $description = $alpha .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + } + + function candle( $data, $alpha, $line_width, $colour, $text='', $size=-1 ) + { + $type = 'candle'. $this->next_line(); + + $description = $alpha .','. $line_width .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + + $a = array(); + foreach( $data as $can ) + $a[] = $can->toString(); + + $this->data[] = implode(',',$a); + } + + function hlc( $data, $alpha, $line_width, $colour, $text='', $size=-1 ) + { + $type = 'hlc'. $this->next_line(); + + $description = $alpha .','. $line_width .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + + $a = array(); + foreach( $data as $can ) + $a[] = $can->toString(); + + $this->data[] = implode(',',$a); + } + + function scatter( $data, $line_width, $colour, $text='', $size=-1 ) + { + $type = 'scatter'. $this->next_line(); + + $description = $line_width .','. $colour .','. $text .','. $size; + + $this->lines[$type] = $description; + + $a = array(); + foreach( $data as $can ) + $a[] = $can->toString(); + + $this->data[] = implode(',',$a); + } + + + // + // Patch by, Jeremy Miller (14th Nov, 2007) + // + /** + * Draw a pie chart. + * + * @param alpha an int argument. + * The percentage of transparency of the pie colour. + * @param $style a string argument. + * CSS style string + * @param label_colour a string argument. + * The hex colour value of the label. + * @param gradient a boolean argument. + * Use a gradient true or false. + * @param border_size an int argument. + * Size of the border in pixels. + */ + function pie( $alpha, $line_colour, $style, $gradient = true, $border_size = false ) + { + $this->pie = $alpha.','.$line_colour.','.$style; + if( !$gradient ) + { + $this->pie .= ','.!$gradient; + } + if ($border_size) + { + if ($gradient === false) + { + $this->pie .= ','; + } + $this->pie .= ','.$border_size; + } + } + + /** + * Set the values of the pie chart. + * + * @param values an array argument. + * An array of the values for the pie chart. + * @param labels an array argument. + * An array of the labels for the pie pieces. + * @param links an array argument. + * An array of the links to the pie pieces. + */ + function pie_values( $values, $labels=array(), $links=array() ) + { + $this->pie_values = implode(',',$values); + $this->pie_labels = implode(',',$labels); + $this->pie_links = implode(",",$links); + } + + /** + * Set the pie slice colours. + * + * @param colours an array argument. + * The hex colour values of the pie pieces. + */ + function pie_slice_colours( $colours ) + { + $this->pie_colours = implode(',',$colours); + } + + + /** + * Render the output. + */ + function render() + { + $tmp = array(); + + //echo headers_sent() ?'yes':'no'; + if( !headers_sent() ) + header('content-type: text; charset: utf-8'); + + if($this->output_type == 'js') + { + $this->set_unique_id(); + + $tmp[] = '
'; + $tmp[] = ''; + $tmp[] = ''; + } + + return implode("\r\n",$tmp); + } +} + +class line +{ + var $line_width; + var $colour; + var $_key; + var $key; + var $key_size; + // hold the data + var $data; + // extra tool tip info: + var $tips; + + function line( $line_width, $colour ) + { + $this->var = 'line'; + + $this->line_width = $line_width; + $this->colour = $colour; + $this->data = array(); + $this->links = array(); + $this->tips = array(); + $this->_key = false; + } + + + function key( $key, $size ) + { + $this->_key = true; + $this->key = graph::esc( $key ); + $this->key_size = $size; + } + + function add( $data ) + { + $this->data[] = $data; + } + + function add_link( $data, $link ) + { + $this->data[] = $data; + $this->links[] = graph::esc( $link ); + } + + function add_data_tip( $data, $tip ) + { + $this->data[] = $data; + $this->tips[] = graph::esc( $tip ); + } + + function add_data_link_tip( $data, $link, $tip ) + { + $this->data[] = $data; + $this->links[] = graph::esc( $link ); + $this->tips[] = graph::esc( $tip ); + } + + // return the variables for this chart + function _get_variable_list() + { + $values = array(); + $values[] = $this->line_width; + $values[] = $this->colour; + + if( $this->_key ) + { + $values[] = $this->key; + $values[] = $this->key_size; + } + + return $values; + } + + function toString( $output_type, $set_num ) + { + $values = implode( ',', $this->_get_variable_list() ); + + $tmp = array(); + + if( $output_type == 'js' ) + { + $tmp[] = 'so.addVariable("'. $this->var.$set_num .'","'. $values . '");'; + + $tmp[] = 'so.addVariable("values'. $set_num .'","'. implode( ',', $this->data ) .'");'; + + if( count( $this->links ) > 0 ) + $tmp[] = 'so.addVariable("links'. $set_num .'","'. implode( ',', $this->links ) .'");'; + + if( count( $this->tips ) > 0 ) + $tmp[] = 'so.addVariable("tool_tips_set'. $set_num .'","'. implode( ',', $this->tips ) .'");'; + + } + else + { + $tmp[] = '&'. $this->var. $set_num .'='. $values .'&'; + $tmp[] = '&values'. $set_num .'='. implode( ',', $this->data ) .'&'; + + if( count( $this->links ) > 0 ) + $tmp[] = '&links'. $set_num .'='. implode( ',', $this->links ) .'&'; + + if( count( $this->tips ) > 0 ) + $tmp[] = '&tool_tips_set'. $set_num .'='. implode( ',', $this->tips ) .'&'; + } + + return implode( "\r\n", $tmp ); + } +} + +class line_hollow extends line +{ + var $dot_size; + + function line_hollow( $line_width, $dot_size, $colour ) + { + parent::line( $line_width, $colour ); + $this->var = 'line_hollow'; + $this->dot_size = $dot_size; + } + + // return the variables for this chart + function _get_variable_list() + { + $values = array(); + $values[] = $this->line_width; + $values[] = $this->colour; + + if( $this->_key ) + { + $values[] = $this->key; + $values[] = $this->key_size; + } + else + { + $values[] = ''; + $values[] = ''; + } + $values[] = $this->dot_size; + + return $values; + } +} + +class line_dot extends line_hollow +{ + function line_dot( $line_width, $dot_size, $colour ) + { + parent::line_dot( $line_width, $colour ); + $this->var = 'line_dot'; + } +} + +class bar +{ + var $colour; + var $alpha; + var $data; + var $links; + var $_key; + var $key; + var $key_size; + var $var; + // extra tool tip info: + var $tips; + + function bar( $alpha, $colour ) + { + $this->var = 'bar'; + + $this->alpha = $alpha; + $this->colour = $colour; + $this->data = array(); + $this->links = array(); + $this->tips = array(); + $this->_key = false; + } + + function key( $key, $size ) + { + $this->_key = true; + $this->key = graph::esc( $key ); + $this->key_size = $size; + } + + function add( $data ) + { + $this->data[] = $data; + } + + function add_link( $data, $link ) + { + $this->data[] = $data; + $this->links[] = graph::esc( $link ); + } + + function add_data_tip( $data, $tip ) + { + $this->data[] = $data; + $this->tips[] = graph::esc( $tip ); + } + + // return the variables for this + // bar chart + function _get_variable_list() + { + $values = array(); + $values[] = $this->alpha; + $values[] = $this->colour; + + if( $this->_key ) + { + $values[] = $this->key; + $values[] = $this->key_size; + } + + return $values; + } + + function toString( $output_type, $set_num ) + { + $values = implode( ',', $this->_get_variable_list() ); + + $tmp = array(); + + if( $output_type == 'js' ) + { + $tmp[] = 'so.addVariable("'. $this->var.$set_num .'","'. $values . '");'; + + $tmp[] = 'so.addVariable("values'. $set_num .'","'. implode( ',', $this->data ) .'");'; + + if( count( $this->links ) > 0 ) + $tmp[] = 'so.addVariable("links'. $set_num .'","'. implode( ',', $this->links ) .'");'; + + if( count( $this->tips ) > 0 ) + $tmp[] = 'so.addVariable("tool_tips_set'. $set_num .'","'. implode( ',', $this->tips ) .'");'; + + } + else + { + $tmp[] = '&'. $this->var. $set_num .'='. $values .'&'; + $tmp[] = '&values'. $set_num .'='. implode( ',', $this->data ) .'&'; + + if( count( $this->links ) > 0 ) + $tmp[] = '&links'. $set_num .'='. implode( ',', $this->links ) .'&'; + + if( count( $this->tips ) > 0 ) + $tmp[] = '&tool_tips_set'. $set_num .'='. implode( ',', $this->tips ) .'&'; + } + + return implode( "\r\n", $tmp ); + } + +} + +class bar_3d extends bar +{ + function bar_3d( $alpha, $colour ) + { + parent::bar( $alpha, $colour ); + $this->var = 'bar_3d'; + } +} + +class bar_fade extends bar +{ + function bar_fade( $alpha, $colour ) + { + parent::bar( $alpha, $colour ); + $this->var = 'bar_fade'; + } +} + +class bar_outline extends bar +{ + var $outline_colour; + + function bar_outline( $alpha, $colour, $outline_colour ) + { + parent::bar( $alpha, $colour ); + $this->var = 'filled_bar'; + $this->outline_colour = $outline_colour; + } + + // override the base method + function _get_variable_list() + { + $values = array(); + $values[] = $this->alpha; + $values[] = $this->colour; + $values[] = $this->outline_colour; + + if( $this->_key ) + { + $values[] = $this->key; + $values[] = $this->key_size; + } + + return $values; + } +} + +class bar_glass extends bar_outline +{ + function bar_glass( $alpha, $colour, $outline_colour ) + { + parent::bar_outline( $alpha, $colour, $outline_colour ); + $this->var = 'bar_glass'; + } +} + +// +// this has an outline colour and a 'jiggle' parameter +// called offset +// +class bar_sketch extends bar_outline +{ + var $offset; + + function bar_sketch( $alpha, $offset, $colour, $outline_colour ) + { + parent::bar_outline( $alpha, $colour, $outline_colour ); + $this->var = 'bar_sketch'; + $this->offset = $offset; + } + + // override the base method + function _get_variable_list() + { + $values = array(); + $values[] = $this->alpha; + $values[] = $this->offset; + $values[] = $this->colour; + $values[] = $this->outline_colour; + + if( $this->_key ) + { + $values[] = $this->key; + $values[] = $this->key_size; + } + + return $values; + } +} + +class candle +{ + var $out; + + function candle( $high, $open, $close, $low ) + { + $this->out = array(); + $this->out[] = $high; + $this->out[] = $open; + $this->out[] = $close; + $this->out[] = $low; + } + + function toString() + { + return '['. implode( ',', $this->out ) .']'; + } +} + +class hlc +{ + var $out; + + function hlc( $high, $low, $close ) + { + $this->out = array(); + $this->out[] = $high; + $this->out[] = $low; + $this->out[] = $close; + } + + function toString() + { + return '['. implode( ',', $this->out ) .']'; + } +} + +class point +{ + var $out; + + function point( $x, $y, $size_px ) + { + $this->out = array(); + $this->out[] = $x; + $this->out[] = $y; + $this->out[] = $size_px; + } + + function toString() + { + return '['. implode( ',', $this->out ) .']'; + } +} + +?> diff --git a/includes/sparkline-php-0.2/CHANGES b/includes/sparkline-php-0.2/CHANGES new file mode 100644 index 000000000..9aaadcb8a --- /dev/null +++ b/includes/sparkline-php-0.2/CHANGES @@ -0,0 +1,22 @@ +# +# Sparkline PHP Graphing Library +# Copyright 2004 James Byers +# http://sparkline.org +# +# Sparkline is distributed under a BSD License. See LICENSE for details. +# +# $Id: CHANGES,v 1.2 2005/06/02 20:57:51 jbyers Exp $ +# + +2005-06-02 James Byers + + * Version 0.2 released + * Corrected line chart behavior for small data sets [1096890] + * Library will create log file if possible [1163412] + * Fixed error message on bad log file [1096895] + * Corrected bitmask on DEBUG_ALL + * Revised structure of SetFeature + +2004-11-08 James Byers + + * Version 0.1 released diff --git a/includes/sparkline-php-0.2/DESIGN b/includes/sparkline-php-0.2/DESIGN new file mode 100644 index 000000000..9b965574d --- /dev/null +++ b/includes/sparkline-php-0.2/DESIGN @@ -0,0 +1,27 @@ +# +# Sparkline PHP Graphing Library +# Copyright 2004 James Byers +# http://sparkline.org +# +# Sparkline is distributed under a BSD License. See LICENSE for details. +# +# $Id: DESIGN,v 1.3 2004/11/09 07:10:42 jbyers Exp $ +# + +Not much to see. It's 0.1, after all. + +Flow +------------------------------------------------------------------------------ + +Instantiate appropriate Sparkline subclass +Load data, set parameters, all Set* calls +Render + convert coordinates + calculate image size + create image handle + set colors + fill background + draw graph + draw features +Optionally call Draw* functions +Output / OutputFile diff --git a/includes/sparkline-php-0.2/LICENSE b/includes/sparkline-php-0.2/LICENSE new file mode 100644 index 000000000..f25405655 --- /dev/null +++ b/includes/sparkline-php-0.2/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2004 James Byers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of James Byers nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/includes/sparkline-php-0.2/README b/includes/sparkline-php-0.2/README new file mode 100644 index 000000000..f357c9641 --- /dev/null +++ b/includes/sparkline-php-0.2/README @@ -0,0 +1,37 @@ +# +# Sparkline PHP Graphing Library +# Copyright 2004 James Byers +# http://sparkline.org +# +# Sparkline is distributed under a BSD License. See LICENSE for details. +# +# $Id: README,v 1.2 2004/11/09 07:10:42 jbyers Exp $ +# + +Installation: +------------- + +Sparkline does not have any installation requirements. See the +samples directory for usage ideas. + +Requirements: +------------- + +Sparkline requires PHP 4.0.6 or newer and GD 2.0 built as a PHP +module. + +Troubleshooting and Support: +---------------------------- + +See http://sparkline.org for troubleshooting advice and support. + +Bugs, Features: +--------------- + +Please submit bugs to the bug tracker: + + http://sourceforge.net/tracker/?group_id=122936&atid=694962 + +Please submit feature requests to the RFE tracker: + + http://sourceforge.net/tracker/?group_id=122936&atid=694965 diff --git a/includes/sparkline-php-0.2/lib/Object.php b/includes/sparkline-php-0.2/lib/Object.php new file mode 100644 index 000000000..89332c17b --- /dev/null +++ b/includes/sparkline-php-0.2/lib/Object.php @@ -0,0 +1,158 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: Object.php,v 1.8 2005/06/02 21:01:42 jbyers Exp $ + * + */ + +define('DEBUG_NONE', 0); // nothing +define('DEBUG_ERROR', 1); // major errors +define('DEBUG_WARNING', 2); // warnings +define('DEBUG_STATS', 4); // dataset, rendering statistics +define('DEBUG_CALLS', 8); // major function calls +define('DEBUG_SET', 16); // all Set methods +define('DEBUG_DRAW', 32); // all Draw methods +define('DEBUG_ALL', 2047); // everything + +function error_handler($errno, $errstr, $errfile, $errline) { + switch ($errno) { + case E_ERROR: + $message = "ERROR: "; + break; + case E_WARNING: + $message = "WARNING: "; + break; + case E_PARSE: + $message = "PARSE: "; + break; + case E_NOTICE: + $message = "NOTICE: "; + break; + case E_USER_ERROR: + $message = "UERROR: "; + break; + case E_USER_WARNING: + $message = "UWARNING: "; + break; + case E_USER_NOTICE: + $message = "UNOTICE: "; + break; + default: + $message = "UNKNOWN: "; + break; + } // switch + + $message .= "$errstr in $errfile at line $errline\n"; + + if (($errno != E_NOTICE) && // suppress notices + (error_reporting() != 0)) { // respect supressed errors (@) + log_write($message, 'PHP'); + } +} // function error_handler + +function log_write($string, $type = '', $date = false) { + global $LOGFILE; + + if (isset($LOGFILE)) { + if ($date == false) { + $date = time(); + } + + $message = date('d/m/Y:H:i:s', $date) . " $type: $string \n"; + error_log($message, 3, $LOGFILE); + } +} // function log_write + +class Object { + + var $isError; + var $logFile; + var $errorList; + var $debugList; + var $debugLevel; + var $startTime; + + //////////////////////////////////////////////////////////////////////////// + // constructor + // + function Object($catch_errors = true) { + $this->isError = false; + $this->logFile = null; + $this->logDate = ''; + $this->errorList = array(); + $this->debugList = array(); + $this->debugLevel = DEBUG_NONE; + $this->startTime = $this->microTimer(); + + // if ($catch_errors) { + set_error_handler('error_handler'); + //} + } // function Object + + //////////////////////////////////////////////////////////////////////////// + // utility + // + function microTimer() { + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); + } // function microTimer + + //////////////////////////////////////////////////////////////////////////// + // error handling + // + function SetDebugLevel($level, $file = null) { + global $LOGFILE; + + if ($level >= DEBUG_NONE && + $level <= DEBUG_ALL) { + $this->debugLevel = $level; + } + + if ($file != null) { + if ((!file_exists($file) && !touch($file)) || + !is_writable($file)) { + die("error log file '$file' is not writable to the web server user"); + } else { + $this->logFile = $file; + $LOGFILE = $file; + } + } + } // function SetDebugLevel + + function Debug($string, $level = DEBUG_WARNING) { + $this->debugList[] = $string; + if ($this->debugLevel & $level && + $this->logFile != null) { + log_write($string, 'DEBUG'); + } + } // function Debug + + function Error($string) { + $this->isError = true; + $this->errorList[] = $string; + if ($this->debugLevel & DEBUG_ERROR && + $this->logFile != null) { + log_write($string, 'ERROR'); + } + } // function Error + + function GetDebug() { + return $this->debugList; + } // function GetDebug + + function GetError() { + return $this->errorList; + } // function GetError + + function IsError() { + return $this->isError; + } // function IsError + +} // class Object + +?> diff --git a/includes/sparkline-php-0.2/lib/Sparkline.php b/includes/sparkline-php-0.2/lib/Sparkline.php new file mode 100644 index 000000000..b05262764 --- /dev/null +++ b/includes/sparkline-php-0.2/lib/Sparkline.php @@ -0,0 +1,496 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: Sparkline.php,v 1.8 2005/05/02 20:25:47 jbyers Exp $ + * + */ + +define('TEXT_TOP', 1); +define('TEXT_RIGHT', 2); +define('TEXT_BOTTOM', 3); +define('TEXT_LEFT', 4); + +define('FONT_1', 1); +define('FONT_2', 2); +define('FONT_3', 3); +define('FONT_4', 4); +define('FONT_5', 5); + +require_once('Object.php'); + +class Sparkline extends Object { + + var $imageX; + var $imageY; + var $imageHandle; + var $graphAreaPx; + var $graphAreaPt; + var $colorList; + var $colorBackground; + var $lineSize; + + //////////////////////////////////////////////////////////////////////////// + // constructor + // + function Sparkline($catch_errors = true) { + parent::Object($catch_errors); + + $this->colorList = array(); + $this->colorBackground = 'white'; + $this->lineSize = 1; + $this->graphAreaPx = array(array(0, 0), array(0, 0)); // px(L, B), px(R, T) + } // function Sparkline + + //////////////////////////////////////////////////////////////////////////// + // init + // + function Init($x, $y) { + $this->Debug("Sparkline :: Init($x, $y)", DEBUG_CALLS); + + $this->imageX = $x; + $this->imageY = $y; + + // Set functions may have already set graphAreaPx offsets; add image dimensions + // + $this->graphAreaPx = array(array($this->graphAreaPx[0][0], + $this->graphAreaPx[0][1]), + array($this->graphAreaPx[1][0] + $x - 1, + $this->graphAreaPx[1][1] + $y - 1)); + + $this->imageHandle = $this->CreateImageHandle($x, $y); + + // load default colors; set all color handles + // + $this->SetColorDefaults(); + while (list($k, $v) = each($this->colorList)) { + $this->SetColorHandle($k, $this->DrawColorAllocate($k, $this->imageHandle)); + } + reset($this->colorList); + + if ($this->IsError()) { + return false; + } else { + return true; + } + } // function Init + + //////////////////////////////////////////////////////////////////////////// + // color, drawing setup functions + // + function SetColor($name, $r, $g, $b) { + $this->Debug("Sparkline :: SetColor('$name', $r, $g, $b)", DEBUG_SET); + $name = strtolower($name); + $this->colorList[$name] = array('rgb' => array($r, $g, $b)); + } // function SetDecColor + + function SetColorHandle($name, $handle) { + $this->Debug("Sparkline :: SetColorHandle('$name', $handle)", DEBUG_SET); + $name = strtolower($name); + if (array_key_exists($name, $this->colorList)) { + $this->colorList[$name]['handle'] = $handle; + return true; + } else { + return false; + } + } // function SetColorHandle + + function SetColorHex($name, $r, $g, $b) { + $this->Debug("Sparkline :: SetColorHex('$name', $r, $g, $b)", DEBUG_SET); + $this->SetColor($name, hexdec($r), hexdec($g), hexdec($b)); + } // function SetHexColor + + function SetColorHtml($name, $rgb) { + $this->Debug("Sparkline :: SetColorHtml('$name', '$rgb')", DEBUG_SET); + $rgb = trim($rgb, '#'); + $this->SetColor($name, hexdec(substr($rgb, 0, 2)), hexdec(substr($rgb, 2, 2)), hexdec(substr($rgb, 4, 2))); + } // function SetHexColor + + function SetColorBackground($name) { + $this->Debug("Sparkline :: SetColorBackground('$name')", DEBUG_SET); + $this->colorBackground = $name; + } // function SetColorBackground + + function GetColor($name) { + if (array_key_exists($name, $this->colorList)) { + return $this->colorList[$name]['rgb']; + } else { + return false; + } + } // function GetColor + + function GetColorHandle($name) { + $name = strtolower($name); + if (array_key_exists($name, $this->colorList)) { + return $this->colorList[$name]['handle']; + } else { + $this->Debug("Sparkline :: GetColorHandle color '$name' not set", DEBUG_WARNING); + return false; + } + } // function GetColorHandle + + function SetColorDefaults() { + $this->Debug("Sparkline :: SetColorDefaults()", DEBUG_SET); + $colorDefaults = array(array('aqua', '#00FFFF'), + array('black', '#010101'), // TODO failure if 000000? + array('blue', '#0000FF'), + array('fuscia', '#FF00FF'), + array('gray', '#808080'), + array('grey', '#808080'), + array('green', '#008000'), + array('lime', '#00FF00'), + array('maroon', '#800000'), + array('navy', '#000080'), + array('olive', '#808000'), + array('purple', '#800080'), + array('red', '#FF0000'), + array('silver', '#C0C0C0'), + array('teal', '#008080'), + array('white', '#FFFFFF'), + array('yellow', '#FFFF00')); + while (list(, $v) = each($colorDefaults)) { + if (!array_key_exists($v[0], $this->colorList)) { + $this->SetColorHtml($v[0], $v[1]); + } + } + } // function SetColorDefaults + + function SetLineSize($size) { + $this->Debug("Sparkline :: SetLineSize($size)", DEBUG_CALLS); + + $this->lineSize = $size; + } // function SetLineSize + + function GetLineSize() { + return($this->lineSize); + } // function GetLineSize + + function SetPadding($T, $R = null, $B = null, $L = null) { + $this->Debug("Sparkline :: SetPadding($T, $R, $B, $L)", DEBUG_CALLS); + + if (null == $R && + null == $B && + null == $L) { + $this->graphAreaPx = array(array($this->graphAreaPx[0][0] + $T, + $this->graphAreaPx[0][1] + $T), + array($this->graphAreaPx[1][0] - $T, + $this->graphAreaPx[1][1] - $T)); + } else { + $this->graphAreaPx = array(array($this->graphAreaPx[0][0] + $L, + $this->graphAreaPx[0][1] + $B), + array($this->graphAreaPx[1][0] - $R, + $this->graphAreaPx[1][1] - $T)); + } + } // function SetPadding + + //////////////////////////////////////////////////////////////////////////// + // canvas setup + // + function CreateImageHandle($x, $y) { + $this->Debug("Sparkline :: CreateImageHandle($x, $y)", DEBUG_CALLS); + + $handle = @imagecreatetruecolor($x, $y); + if (!is_resource($handle)) { + $handle = imagecreate($x, $y); + $this->Debug('imagecreatetruecolor unavailable', DEBUG_WARNING); + } + + if (!is_resource($handle)) { + $this->Debug('imagecreate unavailable', DEBUG_WARNING); + $this->Error('could not create image; GD imagecreate functions unavailable'); + } + + return $handle; + } // function CreateImageHandle + + //////////////////////////////////////////////////////////////////////////// + // drawing primitives + // + // NB: all drawing primitives use the coordinate system where (0,0) + // corresponds to the bottom left of the image, unlike y-inverted + // PHP gd functions + // + function DrawBackground($handle = false) { + $this->Debug("Sparkline :: DrawBackground()", DEBUG_DRAW); + + if (!$this->IsError()) { + if ($handle === false) $handle = $this->imageHandle; + return $this->DrawRectangleFilled(0, + 0, + imagesx($handle) - 1, + imagesy($handle) - 1, + $this->colorBackground, + $handle); + } + } // function DrawBackground + + function DrawColorAllocate($color, $handle = false) { + $this->Debug("Sparkline :: DrawColorAllocate('$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorRGB = $this->GetColor($color)) { + if ($handle === false) $handle = $this->imageHandle; + return imagecolorallocate($handle, + $colorRGB[0], + $colorRGB[1], + $colorRGB[2]); + } + } // function DrawColorAllocate + + function DrawFill($x, $y, $color, $handle = false) { + $this->Debug("Sparkline :: DrawFill($x, $y, '$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + return imagefill($handle, + $x, + $this->TxGDYToSLY($y, $handle), + $colorHandle); + } + } // function DrawFill + + function DrawLine($x1, $y1, $x2, $y2, $color, $thickness = 1, $handle = false) { + $this->Debug("Sparkline :: DrawLine($x1, $y1, $x2, $y2, '$color', $thickness)", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + + imagesetthickness($handle, $thickness); + $result = imageline($handle, + $x1, + $this->TxGDYToSLY($y1, $handle), + $x2, + $this->TxGDYToSLY($y2, $handle), + $colorHandle); + imagesetthickness($handle, 1); + return $result; + } + } // function DrawLine + + function DrawPoint($x, $y, $color, $handle = false) { + $this->Debug("Sparkline :: DrawPoint($x, $y, '$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + return imagesetpixel($handle, + $x, + $this->TxGDYToSLY($y, $handle), + $colorHandle); + } + } // function DrawPoint + + function DrawRectangle($x1, $y1, $x2, $y2, $color, $handle = false) { + $this->Debug("Sparkline :: DrawRectangle($x1, $y1, $x2, $y2 '$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + return imagerectangle($handle, + $x1, + $this->TxGDYToSLY($y1, $handle), + $x2, + $this->TxGDYToSLY($y2, $handle), + $colorHandle); + } + } // function DrawRectangle + + function DrawRectangleFilled($x1, $y1, $x2, $y2, $color, $handle = false) { + $this->Debug("Sparkline :: DrawRectangleFilled($x1, $y1, $x2, $y2 '$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + // NB: switch y1, y2 post conversion + // + if ($y1 < $y2) { + $yt = $y1; + $y1 = $y2; + $y2 = $yt; + } + + if ($handle === false) $handle = $this->imageHandle; + return imagefilledrectangle($handle, + $x1, + $this->TxGDYToSLY($y1, $handle), + $x2, + $this->TxGDYToSLY($y2, $handle), + $colorHandle); + } + } // function DrawRectangleFilled + + function DrawCircleFilled($x, $y, $diameter, $color, $handle = false) { + $this->Debug("Sparkline :: DrawCircleFilled($x, $y, $diameter, '$color')", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + return imagefilledellipse($handle, + $x, + $this->TxGDYToSLY($y, $handle), + $diameter, + $diameter, + $colorHandle); + } + } // function DrawCircleFilled + + function DrawText($string, $x, $y, $color, $font = FONT_1, $handle = false) { + $this->Debug("Sparkline :: DrawText('$string', $x, $y, '$color', $font)", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + // adjust for font height so x,y corresponds to bottom left of font + // + if ($handle === false) $handle = $this->imageHandle; + return imagestring($handle, + $font, + $x, + $this->TxGDYToSLY($y + imagefontheight($font), $handle), + $string, + $colorHandle); + } + } // function DrawText + + function DrawTextRelative($string, $x, $y, $color, $position, $padding = 2, $font = FONT_1, $handle = false) { + $this->Debug("Sparkline :: DrawTextRelative('$string', $x, $y, '$color', $position, $font, $padding)", DEBUG_DRAW); + + if (!$this->IsError() && + $colorHandle = $this->GetColorHandle($color)) { + if ($handle === false) $handle = $this->imageHandle; + + // rendered text width, height + // + $textHeight = imagefontheight($font); + $textWidth = imagefontwidth($font) * strlen($string); + + // set (pxX, pxY) based on position and point + // + switch($position) { + case TEXT_TOP: + $x = $x - round($textWidth / 2); + $y = $y + $padding; + break; + + case TEXT_RIGHT: + $x = $x + $padding; + $y = $y - round($textHeight / 2); + break; + + case TEXT_BOTTOM: + $x = $x - round($textWidth / 2); + $y = $y - $padding - $textHeight; + break; + + case TEXT_LEFT: + default: + $x = $x - $padding - $textWidth; + $y = $y - round($textHeight / 2); + break; + } + + // truncate bounds based on string size in pixels, image bounds + // order: TRBL + // + $y = min($y, $this->GetImageHeight() - $textHeight); + $x = min($x, $this->GetImageWidth() - $textWidth); + $y = max($y, 0); + $x = max($x, 0); + + return $this->DrawText($string, + $x, + $y, + $color, + $font, + $handle); + } + } // function DrawTextRelative + + function DrawImageCopyResampled($dhandle, $shandle, $dx, $dy, $sx, $sy, $dw, $dh, $sw, $sh) { + $this->Debug("Sparkline :: DrawImageCopyResampled($dhhandle, $shandle, $dx, $dy, $sx, $sy, $dw, $dh, $sw, $sh)", DEBUG_DRAW); + if (!$this->IsError()) { + return imagecopyresampled($dhandle, // dest handle + $shandle, // src handle + $dx, $dy, // dest x, y + $sx, $sy, // src x, y + $dw, $dh, // dest w, h + $sw, $sh); // src w, h + } + } // function DrawImageCopyResampled + + //////////////////////////////////////////////////////////////////////////// + // coordinate system functions + // world coordinates are referenced as points or pt + // graph coordinates are referenced as pixels or px + // sparkline inverts GD Y pixel coordinates; the bottom left of the + // image rendering area is px(0,0) + // all coordinate transformation functions are prefixed with Tx + // all coordinate transformation functions depend on a valid image handle + // and will only return valid results after all Set* calls are performed + // + function TxGDYToSLY($gdY, $handle) { + return imagesy($handle) - 1 - $gdY; + } // function TxGDYToSLY + + function TxPxToPt($pxX, $pxY, $handle) { + // TODO; must occur after data series conversion + } // function TxPxToPt + + function TxPtToPx($ptX, $ptY, $handle) { + // TODO; must occur after data series conversion + } // function TxPtToPx + + function GetGraphWidth() { + return $this->graphAreaPx[1][0] - $this->graphAreaPx[0][0]; + } // function GetGraphWidth + + function GetGraphHeight() { + return $this->graphAreaPx[1][1] - $this->graphAreaPx[0][1]; + } // function GetGraphHeight + + function GetImageWidth() { + return $this->imageX; + } // function GetImageWidth + + function GetImageHeight() { + return $this->imageY; + } // function GetImageHeight + + //////////////////////////////////////////////////////////////////////////// + // image output + // + function Output($file = '') { + + $this->Debug("Sparkline :: Output($file)", DEBUG_CALLS); + + if ($this->IsError()) { + $colorError = imagecolorallocate($this->imageHandle, 0xFF, 0x00, 0x00); + imagestring($this->imageHandle, + 1, + ($this->imageX / 2) - (5 * imagefontwidth(1) / 2), + ($this->imageY / 2) - (imagefontheight(1) / 2), + "ERROR", + $colorError); + } + + if ($file == '') { + header('Content-type: image/png'); + imagepng($this->imageHandle); + } else { + imagepng($this->imageHandle, $file); + } + + $this->Debug('Sparkline :: Output - total execution time: ' . round($this->microTimer() - $this->startTime, 4) . ' seconds', DEBUG_STATS); + } // function Output + + function OutputToFile($file) { + $this->Output($file); + } // function OutputToFile + +} // class Sparkline + +?> diff --git a/includes/sparkline-php-0.2/lib/Sparkline_Bar.php b/includes/sparkline-php-0.2/lib/Sparkline_Bar.php new file mode 100644 index 000000000..4352539bf --- /dev/null +++ b/includes/sparkline-php-0.2/lib/Sparkline_Bar.php @@ -0,0 +1,191 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: Sparkline_Bar.php,v 1.2 2004/11/09 06:18:52 jbyers Exp $ + * + */ + +require_once('Sparkline.php'); + +class Sparkline_Bar extends Sparkline { + + var $dataSeries; + var $dataSeriesStats; + var $dataSeriesConverted; + var $yMin; + var $yMax; + var $barWidth; + var $barSpacing; + var $barColorDefault; + var $barColorUnderscoreDefault; + + //////////////////////////////////////////////////////////////////////////// + // constructor + // + function Sparkline_Bar($catch_errors = true) { + parent::Sparkline($catch_errors); + + $this->dataSeries = array(); + $this->dataSeriesStats = array(); + $this->dataSeriesConverted = array(); + $this->barWidth = 1; + $this->barSpacing = 1; + $this->barColorDefault = 'black'; + $this->barColorUnderscoreDefault = 'black'; + } // function Sparkline + + //////////////////////////////////////////////////////////////////////////// + // color, image property setting + // + function SetBarWidth($value) { + $this->Debug("Sparkline_Bar :: SetBarWidth($value)", DEBUG_SET); + $this->barWidth = $value; + } // function SetBarWidth + + function SetBarSpacing($value) { + $this->Debug("Sparkline_Bar :: SetBarSpacing($value)", DEBUG_SET); + $this->barSpacing = $value; + } // function SetBarSpacing + + function SetBarColorDefault($value) { + $this->Debug("Sparkline_Bar :: SetBarColorDefault($value)", DEBUG_SET); + $this->barColorDefault = $value; + } // function SetBarColorDefault + + function SetBarColorUnderscoreDefault($value) { + $this->Debug("Sparkline_Bar :: SetBarColorUnderscoreDefault($value)", DEBUG_SET); + $this->barColorUnderscoreDefault = $value; + } // function SetBarColorUnderscoreDefault + + //////////////////////////////////////////////////////////////////////////// + // data setting + // + function SetData($x, $y, $color = null, $underscore = false, $series = 1) { + $x = trim($x); + $y = trim($y); + + $this->Debug("Sparkline_Bar :: SetData($x, $y, $series)", DEBUG_SET); + + if (!is_numeric($x) || + !is_numeric($y)) { + $this->Debug("Sparkline_Bar :: SetData rejected values($x, $y) in series $series", DEBUG_WARNING); + return false; + } // if + + if ($color == null) { + $color = $this->barColorDefault; + } + + $this->dataSeries[$series][$x] = array('value' => $y, + 'color' => $color, + 'underscore' => $underscore); + + if (!isset($this->dataSeriesStats[$series]['min']) || + $y < $this->dataSeriesStats[$series]['min']) { + $this->dataSeriesStats[$series]['min'] = $y; + } + + if (!isset($this->dataSeriesStats[$series]['max']) || + abs($y) > $this->dataSeriesStats[$series]['max']) { + $this->dataSeriesStats[$series]['max'] = abs($y); + } + } // function SetData + + function SetYMin($value) { + $this->Debug("Sparkline_Bar :: SetYMin($value)", DEBUG_SET); + $this->yMin = $value; + } + + function SetYMax($value) { + $this->Debug("Sparkline_Bar :: SetYMax($value)", DEBUG_SET); + $this->yMax = $value; + } + + function ConvertDataSeries($series, $xBound, $yBound) { + $this->Debug("Sparkline_Bar :: ConvertDataSeries($series, $xBound, $yBound)", DEBUG_CALLS); + + if (!isset($this->yMin)) { + $this->yMin = $this->dataSeriesStats[$series]['min']; + } + + if (!isset($this->yMax)) { + $this->yMax = $this->dataSeriesStats[$series]['max']; + } + + while (list(, $v) = each($this->dataSeries[$series])) { + $y = floor($v['value'] * ($yBound / (abs($this->yMax) + abs($this->yMin)))); + $this->dataSeriesConverted[$series][] = array('value' => $y, + 'color' => $v['color'], + 'underscore' => $v['underscore']); + + if (!isset($this->dataSeriesStats[$series]['min_converted']) || + $y < $this->dataSeriesStats[$series]['min_converted']) { + $this->dataSeriesStats[$series]['min_converted'] = $y; + } + + if (!isset($this->dataSeriesStats[$series]['max_converted']) || + abs($y) > $this->dataSeriesStats[$series]['max_converted']) { + $this->dataSeriesStats[$series]['max_converted'] = abs($y); + } + } + reset($this->dataSeries[$series]); + + } // function ConvertDataSeries + + function CalculateImageWidth() { + $this->Debug("Sparkline_Bar :: CalculateImageWidth()", DEBUG_CALLS); + + $count = sizeof($this->dataSeries[1]); + return (($count - 1) * $this->barSpacing) + ($count * $this->barWidth); + } // function CalculateImageWidth + + //////////////////////////////////////////////////////////////////////////// + // rendering + // + function Render($y) { + $this->Debug("Sparkline_Bar :: Render($y)", DEBUG_CALLS); + + // calculate size based on sets for init + // + if (!parent::Init($this->CalculateImageWidth(), $y)) { + return false; + } + + // convert based on actual canvas size + // + $this->ConvertDataSeries(1, $this->GetGraphWidth(), $this->GetGraphHeight()); + + // stats debugging + // + $this->Debug('Sparkline_Bar :: Draw' . + ' series: 1 min: ' . $this->dataSeriesStats[1]['min'] . + ' max: ' . $this->dataSeriesStats[1]['max'] . + ' height: ' . $this->GetGraphHeight() . + ' yfactor: ' . ($this->GetGraphHeight() / (abs($this->dataSeriesStats[1]['max']) + abs($this->dataSeriesStats[1]['min'])))); + + $this->DrawBackground(); + + $yAxis = abs(min($this->dataSeriesStats[1]['min_converted'], 0)); + for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]); $i++) { + $this->DrawRectangleFilled($i * ($this->barWidth + $this->barSpacing), + $yAxis, + $i * ($this->barWidth + $this->barSpacing) + $this->barWidth - 1, + $yAxis + $this->dataSeriesConverted[1][$i]['value'], + $this->dataSeriesConverted[1][$i]['color']); + if ($this->dataSeriesConverted[1][$i]['underscore']) { + $this->DrawLine(max(0, $i * ($this->barWidth + $this->barSpacing) - ($this->barSpacing / 2)), + $yAxis, + min($this->GetGraphWidth(), $i * ($this->barWidth + $this->barSpacing) + ($this->barSpacing / 2)), + $yAxis, + $this->barColorUnderscoreDefault); + } + } + } // function Render +} // class Sparkline_Bar + +?> diff --git a/includes/sparkline-php-0.2/lib/Sparkline_Line.php b/includes/sparkline-php-0.2/lib/Sparkline_Line.php new file mode 100644 index 000000000..a7f00ee8a --- /dev/null +++ b/includes/sparkline-php-0.2/lib/Sparkline_Line.php @@ -0,0 +1,279 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: Sparkline_Line.php,v 1.7 2005/01/06 02:40:46 jbyers Exp $ + * + */ + +require_once('Sparkline.php'); + +class Sparkline_Line extends Sparkline { + + var $dataSeries; + var $dataSeriesStats; + var $dataSeriesConverted; + var $yMin; + var $yMax; + var $featurePoint; + + //////////////////////////////////////////////////////////////////////////// + // constructor + // + function Sparkline_Line($catch_errors = true) { + parent::Sparkline($catch_errors); + + $this->dataSeries = array(); + $this->dataSeriesStats = array(); + $this->dataSeriesConverted = array(); + + $this->featurePoint = array(); + } // function Sparkline + + //////////////////////////////////////////////////////////////////////////// + // data setting + // + function SetData($x, $y, $series = 1) { + $x = trim($x); + $y = trim($y); + + $this->Debug("Sparkline_Line :: SetData($x, $y, $series)", DEBUG_SET); + + if (!is_numeric($x) || + !is_numeric($y)) { + $this->Debug("Sparkline_Line :: SetData rejected values($x, $y) in series $series", DEBUG_WARNING); + return false; + } // if + + $this->dataSeries[$series][$x] = $y; + + if (!isset($this->dataSeriesStats[$series]['yMin']) || + $y < $this->dataSeriesStats[$series]['yMin']) { + $this->dataSeriesStats[$series]['yMin'] = $y; + } + + if (!isset($this->dataSeriesStats[$series]['xMin']) || + $x < $this->dataSeriesStats[$series]['xMin']) { + $this->dataSeriesStats[$series]['xMin'] = $x; + } + + if (!isset($this->dataSeriesStats[$series]['yMax']) || + $y > $this->dataSeriesStats[$series]['yMax']) { + $this->dataSeriesStats[$series]['yMax'] = $y; + } + + if (!isset($this->dataSeriesStats[$series]['xMax']) || + $x > $this->dataSeriesStats[$series]['xMax']) { + $this->dataSeriesStats[$series]['xMax'] = $x; + } + } // function SetData + + function SetYMin($value) { + $this->Debug("Sparkline_Line :: SetYMin($value)", DEBUG_SET); + $this->yMin = $value; + } // function SetYMin + + function SetYMax($value) { + $this->Debug("Sparkline_Line :: SetYMax($value)", DEBUG_SET); + $this->yMax = $value; + } // function SetYMin + + function ConvertDataSeries($series, $xBound, $yBound) { + $this->Debug("Sparkline_Line :: ConvertDataSeries($series, $xBound, $yBound)", DEBUG_CALLS); + + if (!isset($this->yMin)) { + $this->yMin = $this->dataSeriesStats[$series]['yMin']; + } + + if (!isset($this->yMin)) { + $this->xMin = $this->dataSeriesStats[$series]['XMin']; + } + + if (!isset($this->yMax)) { + $this->yMax = $this->dataSeriesStats[$series]['yMax'] + ($this->yMin * -1); + } + + if (!isset($this->xMax)) { + $this->xMax = $this->dataSeriesStats[$series]['xMax']; + } + + for ($i = 0; $i < sizeof($this->dataSeries[$series]); $i ++) { + $y = round(($this->dataSeries[$series][$i] + ($this->yMin * -1)) * ($yBound / $this->yMax)); + $x = round($i * $xBound / sizeof($this->dataSeries[$series])); + $this->dataSeriesConverted[$series][] = array($x, $y); + $this->Debug("Sparkline :: ConvertDataSeries series $series value $i ($x, $y)", DEBUG_SET); + } + } // function ConvertDataSeries + + //////////////////////////////////////////////////////////////////////////// + // features + // + function SetFeaturePoint($x, $y, $color, $diameter, $text = '', $position = TEXT_TOP, $font = FONT_1) { + $this->Debug("Sparkline_Line :: SetFeaturePoint($x, $y, '$color', $diameter, '$text')", DEBUG_CALLS); + + $this->featurePoint[] = array('ptX' => $x, + 'ptY' => $y, + 'color' => $color, + 'diameter' => $diameter, + 'text' => $text, + 'textpos' => $position, + 'font' => $font); + } // function SetFeaturePoint + + //////////////////////////////////////////////////////////////////////////// + // low quality rendering + // + function Render($x, $y) { + $this->Debug("Sparkline_Line :: Render($x, $y)", DEBUG_CALLS); + + if (!parent::Init($x, $y)) { + return false; + } + + // convert based on graphAreaPx bounds + // + $this->ConvertDataSeries(1, $this->GetGraphWidth(), $this->GetGraphHeight()); + + // stats debugging + // + $this->Debug('Sparkline_Line :: Draw' . + ' series: 1 min: ' . $this->dataSeriesStats[1]['yMin'] . + ' max: ' . $this->dataSeriesStats[1]['yMax'] . + ' offset: ' . ($this->dataSeriesStats[1]['yMin'] * -1) . + ' height: ' . $this->GetGraphHeight() + 1 . + ' yfactor: ' . ($this->GetGraphHeight() / ($this->dataSeriesStats[1]['yMax'] + ($this->dataSeriesStats[1]['yMin'] * -1)))); + $this->Debug('Sparkline_Line :: Draw' . + ' drawing area:' . + ' (' . $this->graphAreaPx[0][0] . ',' . $this->graphAreaPx[0][1] . '), ' . + ' (' . $this->graphAreaPx[1][0] . ',' . $this->graphAreaPx[1][1] . ')'); + + $this->DrawBackground(); + + // draw graph + // + for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]) - 1; $i++) { + $this->DrawLine($this->dataSeriesConverted[1][$i][0] + $this->graphAreaPx[0][0], + $this->dataSeriesConverted[1][$i][1] + $this->graphAreaPx[0][1], + $this->dataSeriesConverted[1][$i+1][0] + $this->graphAreaPx[0][0], + $this->dataSeriesConverted[1][$i+1][1] + $this->graphAreaPx[0][1], + 'black'); + } + + // draw features + // + while (list(, $v) = each($this->featurePoint)) { + $pxY = round(($v['ptY'] + ($this->yMin * -1)) * ($this->GetGraphHeight() / $this->yMax)); + $pxX = round($v['ptX'] * $this->GetGraphWidth() / $this->dataSeriesStats[1]['xMax']); + + $this->DrawCircleFilled($pxX + $this->graphAreaPx[0][0], + $pxY + $this->graphAreaPx[0][1], + $v['diameter'], + $v['color'], + $this->imageHandle); + $this->DrawTextRelative($v['text'], + $pxX + $this->graphAreaPx[0][0], + $pxY + $this->graphAreaPx[0][1], + $v['color'], + $v['textpos'], + round($v['diameter'] / 2), + $v['font'], + $this->imageHandle); + } + } // function Render + + //////////////////////////////////////////////////////////////////////////// + // high quality rendering + // + function RenderResampled($x, $y) { + $this->Debug("Sparkline_Line :: RenderResampled($x, $y)", DEBUG_CALLS); + + if (!parent::Init($x, $y)) { + return false; + } + + // draw background on standard image in case of resample blit miss + // + $this->DrawBackground($this->imageHandle); + + // convert based on virtual canvas: x based on size of dataset, y scaled proportionately + // if size of data set is small, default to 4X target canvas size + // + $xVC = max(sizeof($this->dataSeries[1]), 4 * $x); + $yVC = floor($xVC * ($this->GetGraphHeight() / $this->GetGraphWidth())); + $this->ConvertDataSeries(1, $xVC, $yVC); + + // stats debugging + // + $this->Debug('Sparkline_Line :: DrawResampled' . + ' series: 1 min: ' . $this->dataSeriesStats[1]['yMin'] . + ' max: ' . $this->dataSeriesStats[1]['yMax'] . + ' offset: ' . ($this->dataSeriesStats[1]['yMin'] * -1) . + ' height: ' . $this->GetGraphHeight() . + ' yfactor: ' . ($this->GetGraphHeight() / ($this->dataSeriesStats[1]['yMax'] + ($this->dataSeriesStats[1]['yMin'] * -1))), DEBUG_STATS); + $this->Debug('Sparkline_Line :: DrawResampled' . + ' drawing area:' . + ' (' . $this->graphAreaPx[0][0] . ',' . $this->graphAreaPx[0][1] . '), ' . + ' (' . $this->graphAreaPx[1][0] . ',' . $this->graphAreaPx[1][1] . ')'); + + // create virtual image + // allocate colors + // draw background, graph + // resample and blit onto original graph + // + $imageVCHandle = $this->CreateImageHandle($xVC, $yVC); + + while (list($k, $v) = each($this->colorList)) { + $this->SetColorHandle($k, $this->DrawColorAllocate($k, $imageVCHandle)); + } + reset($this->colorList); + + $this->DrawBackground($imageVCHandle); + + for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]) - 1; $i++) { + $this->DrawLine($this->dataSeriesConverted[1][$i][0], + $this->dataSeriesConverted[1][$i][1], + $this->dataSeriesConverted[1][$i+1][0], + $this->dataSeriesConverted[1][$i+1][1], + 'black', + $this->GetLineSize(), + $imageVCHandle); + } + + $this->DrawImageCopyResampled($this->imageHandle, + $imageVCHandle, + $this->graphAreaPx[0][0], // dest x + $this->GetImageHeight() - $this->graphAreaPx[1][1], // dest y + 0, 0, // src x, y + $this->GetGraphWidth(), // dest width + $this->GetGraphHeight(), // dest height + $xVC, // src width + $yVC); // src height + + // draw features + // + while (list(, $v) = each($this->featurePoint)) { + $pxY = round(($v['ptY'] + ($this->yMin * -1)) * ($this->GetGraphHeight() / $this->yMax)); + $pxX = round($v['ptX'] * $this->GetGraphWidth() / $this->dataSeriesStats[1]['xMax']); + + $this->DrawCircleFilled($pxX + $this->graphAreaPx[0][0], + $pxY + $this->graphAreaPx[0][1], + $v['diameter'], + $v['color'], + $this->imageHandle); + $this->DrawTextRelative($v['text'], + $pxX + $this->graphAreaPx[0][0], + $pxY + $this->graphAreaPx[0][1], + $v['color'], + $v['textpos'], + round($v['diameter'] / 2), + $v['font'], + $this->imageHandle); + } + } // function RenderResampled +} // class Sparkline_Line + +?> diff --git a/includes/sparkline-php-0.2/samples/baseball.php b/includes/sparkline-php-0.2/samples/baseball.php new file mode 100644 index 000000000..543417aa8 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/baseball.php @@ -0,0 +1,93 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: baseball.php,v 1.8 2004/11/13 18:50:17 jbyers Exp $ + * + * baseball shows a simple whisker graph of two very different postseasons + * + * parameters: t team [yankees|redsox] + * + */ + +// win/loss, home, shutout +// 2004 postseason, source MLB.com +// if anyone has full season data in a workable format, please let me know +// - jbyers@users.sf.net +// +$data['yankees'] = array(0 => array(0, 1, 1), + 1 => array(1, 1, 0), + 2 => array(1, 0, 0), + 3 => array(1, 0, 0), + 4 => array(1, 1, 0), + 5 => array(1, 1, 0), + 6 => array(1, 0, 0), + 7 => array(0, 0, 0), + 8 => array(0, 0, 0), + 9 => array(0, 1, 0), + 10 => array(0, 1, 0)); + +$data['redsox'] = array(0 => array(1, 0, 0), + 1 => array(1, 0, 0), + 2 => array(1, 1, 0), + 3 => array(0, 0, 0), + 4 => array(0, 0, 0), + 5 => array(0, 1, 0), + 6 => array(1, 1, 0), + 7 => array(1, 1, 0), + 8 => array(1, 0, 0), + 9 => array(1, 0, 0), + 10 => array(1, 1, 0), + 11 => array(1, 1, 0), + 12 => array(1, 0, 0), + 13 => array(1, 0, 1)); + +if (!isset($_GET['t']) || + ($_GET['t'] != 'yankees' && + $_GET['t'] != 'redsox')) { + die('bad team name; need ?t=yankees or ?t=redsox'); +} + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Bar.php'); + +$sparkline = new Sparkline_Bar(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +$sparkline->SetBarWidth(1); +$sparkline->SetBarSpacing(2); + +$i = 0; +while (list(, $v) = each($data[$_GET['t']])) { + // set bar color red if shutout + // + $color = 'black'; + if ($v[2]) { + $color = 'red'; + } + + // set bar underscore boolean if home game + // + $underscore = false; + if ($v[1]) { + $underscore = true; + } + + // convert (W, L) to (1, -1) + // + $sparkline->SetData($i, ($v[0] * 2) - 1, $color, $underscore); + $i++; +} +$sparkline->Render(16); // height only for Sparkline_Bar + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/deficit.php b/includes/sparkline-php-0.2/samples/deficit.php new file mode 100644 index 000000000..8d21fe3c3 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/deficit.php @@ -0,0 +1,69 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: deficit.php,v 1.2 2004/11/09 07:05:33 jbyers Exp $ + * + * deficit shows a bar graph of the US deficit + * + */ + +// annual deficit data, 1983-2003 +// source OMB, http://www.whitehouse.gov/omb/budget/fy2004/hist.html +// +$data = array(1983 => -207.802, + 1984 => -185.367, + 1985 => -212.308, + 1986 => -221.215, + 1987 => -149.728, + 1988 => -155.152, + 1989 => -152.456, + 1990 => -221.195, + 1991 => -269.328, + 1992 => -290.376, + 1993 => -255.087, + 1994 => -203.250, + 1995 => -163.972, + 1996 => -107.473, + 1997 => -21.958, + 1998 => 69.213, + 1999 => 125.563, + 2000 => 236.445, + 2001 => 127.299, + 2002 => -157.802, + 2003 => -304.159); + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Bar.php'); + +$sparkline = new Sparkline_Bar(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +$sparkline->SetBarWidth(2); +$sparkline->SetBarSpacing(1); + +while (list($k, $v) = each($data)) { + + // black if positive, red if negative + // + $color = 'black'; + if ($v < 0) { + $color = 'red'; + } + + $sparkline->SetData($k, $v, $color); +} + +$sparkline->Render(16); // height only for Sparkline_Bar + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/filled.php b/includes/sparkline-php-0.2/samples/filled.php new file mode 100644 index 000000000..ba796f4c5 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/filled.php @@ -0,0 +1,69 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: filled.php,v 1.2 2005/06/02 21:00:32 jbyers Exp $ + * + * filled shows deficit data in a simulated filled-line mode + * + */ + +// annual deficit data, 1983-2003 +// source OMB, http://www.whitehouse.gov/omb/budget/fy2004/hist.html +// +$data = array(1983 => -207.802, + 1984 => -185.367, + 1985 => -212.308, + 1986 => -221.215, + 1987 => -149.728, + 1988 => -155.152, + 1989 => -152.456, + 1990 => -221.195, + 1991 => -269.328, + 1992 => -290.376, + 1993 => -255.087, + 1994 => -203.250, + 1995 => -163.972, + 1996 => -107.473, + 1997 => -21.958, + 1998 => 69.213, + 1999 => 125.563, + 2000 => 236.445, + 2001 => 127.299, + 2002 => -157.802, + 2003 => -304.159); + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Bar.php'); + +$sparkline = new Sparkline_Bar(); + +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +$sparkline->SetBarWidth(1); +$sparkline->SetBarSpacing(0); +$sparkline->SetBarColorDefault('blue'); + +$j = 0; +for($i = 1983; $i < sizeof($data) + 1983; $i++) { + + $sparkline->SetData($j++, $data[$i]); + + if (isset($data[$i+1])) { + $sparkline->SetData($j++, ($data[$i] + $data[$i+1]) / 2); + } +} + +$sparkline->Render(10); // height only for Sparkline_Bar + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/primitives.php b/includes/sparkline-php-0.2/samples/primitives.php new file mode 100644 index 000000000..d1b06fbde --- /dev/null +++ b/includes/sparkline-php-0.2/samples/primitives.php @@ -0,0 +1,37 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: primitives.php,v 1.5 2004/11/09 07:05:33 jbyers Exp $ + * + * primitives doesn't draw a sparkline, only exercises the drawing primitives + * + */ + +require_once('../lib/Sparkline.php'); + +$sparkline = new Sparkline(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +// with any Sparkline subclass, Render would be called instead of Init +// +$sparkline->Init(100, 20); + +$sparkline->DrawFill(9, 9, 'white'); +$sparkline->DrawRectangleFilled(1, 9, 98, 18, 'grey'); +$sparkline->DrawLine(0, 0, 19, 19, 'red'); +$sparkline->DrawCircleFilled(49, 9, 10, 'black'); +$sparkline->DrawPoint(96, 17, 'black'); +$sparkline->DrawRectangle(0, 0, 99, 19, 'blue'); +$sparkline->DrawText('test1', 0, 0, 'red', 1); +$sparkline->DrawText('test2', 25, 0, 'olive', 2); +$sparkline->DrawText('test3', 50, 0, 'blue', 3); + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/stock_chart.php b/includes/sparkline-php-0.2/samples/stock_chart.php new file mode 100644 index 000000000..75f68e699 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/stock_chart.php @@ -0,0 +1,93 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: stock_chart.php,v 1.9 2004/11/09 22:32:48 jbyers Exp $ + * + * stock_chart displays an N-year stock chart sparkline based on Yahoo! data + * each data point is the day's closing price + * + * http://ichart.finance.yahoo.com/table.csv?s=MSFT&a=11&b=31&c=1998&d=11&e=31&f=1999&g=d&ignore=.csv + * NB: months are zero-based, any error will cause a 404 + * + * parameters: s ticker symbol + * y number of years [1-5] + * m drawing mode, 1 for pretty + * + */ + +////////////////////////////////////////////////////////////////////////////// +// verify parameters; bad form, but die to text error on failure +// +if (!isset($_GET['s']) || + !eregi('^[a-z\^]{1,5}$', $_GET['s'])) { + die('bad ticker ' . $_GET['s']); +} + +if (!isset($_GET['y']) || + !is_numeric($_GET['y']) || + $_GET['y'] > 5 || + $_GET['y'] < 0) { + die('bad year ' . $_GET['y']); +} + +////////////////////////////////////////////////////////////////////////////// +// load and process data from Yahoo! ichart csv source +// +$m = date('n') - 1; +$d = date('d'); +$y2 = date('Y'); +$y1 = $y2 - $_GET['y']; + +// data sample: +// 0 1 2 3 4 5 6 +// Date,Open,High,Low,Close,Volume,Adj. Close* +// 5-Nov-04,29.21,29.36,29.03,29.31,95337696,29.31 +// +$url = "http://ichart.finance.yahoo.com/table.csv?s=" . $_GET['s'] . "&a=$m&b=$d&c=$y1&d=$m&e=$d&f=$y2&g=d&ignore=.csv"; +if (!$data = @file($url)) { + die('error fetching stock data; verify ticker symbol'); +} + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Line.php'); + +$sparkline = new Sparkline_Line(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +if (isset($_GET['b'])) { + $sparkline->SetColorHtml('background', $_GET['b']); + $sparkline->SetColorBackground('background'); +} + +$data = array_reverse($data); +$i = 0; +while (list(, $v) = each($data)) { + $elements = explode(',', $v); + if (ereg('^[0-9\.]+$', trim($elements[6]))) { + $sparkline->SetData($i, $elements[6]); + $i++; + } +} + +$sparkline->SetYMin(0); + +if (isset($_GET['m']) && + $_GET['m'] == '0') { + $sparkline->Render(100, 15); +} else { + $sparkline->SetLineSize(6); // for renderresampled, linesize is on virtual image + $sparkline->RenderResampled(100, 15); +} + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/stock_chart2.php b/includes/sparkline-php-0.2/samples/stock_chart2.php new file mode 100644 index 000000000..9dfec6cc0 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/stock_chart2.php @@ -0,0 +1,126 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: stock_chart2.php,v 1.2 2004/11/19 07:16:03 jbyers Exp $ + * + * stock_chart2 adds min/max price bounds and an endpoint value label to + * stock_chart + * + * layout inspired by Mariano Belinky's SVG sparklines: + * http://www.interactiva.com.ar/mariano/?pname=sparklines + * + */ + +////////////////////////////////////////////////////////////////////////////// +// verify parameters; bad form, but die to text error on failure +// +if (!isset($_GET['s']) || + !eregi('^[a-z\^]{1,5}$', $_GET['s'])) { + die('bad ticker ' . $_GET['s']); +} + +if (!isset($_GET['y']) || + !is_numeric($_GET['y']) || + $_GET['y'] > 5 || + $_GET['y'] < 0) { + die('bad year ' . $_GET['y']); +} + +////////////////////////////////////////////////////////////////////////////// +// load and process data from Yahoo! ichart csv source +// +$m = date('n') - 1; +$d = date('d'); +$y2 = date('Y'); +$y1 = $y2 - $_GET['y']; + +// data sample: +// 0 1 2 3 4 5 6 +// Date,Open,High,Low,Close,Volume,Adj. Close* +// 5-Nov-04,29.21,29.36,29.03,29.31,95337696,29.31 +// +$url = "http://ichart.finance.yahoo.com/table.csv?s=" . $_GET['s'] . "&a=$m&b=$d&c=$y1&d=$m&e=$d&f=$y2&g=d&ignore=.csv"; +if (!$data = @file($url)) { + die('error fetching stock data; verify ticker symbol'); +} + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Line.php'); + +$sparkline = new Sparkline_Line(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +if (isset($_GET['b'])) { + $sparkline->SetColorHtml('background', $_GET['b']); + $sparkline->SetColorBackground('background'); +} + +$data = array_reverse($data); +$i = 0; +$min = null; +$max = null; +$last = null; +while (list(, $v) = each($data)) { + $elements = explode(',', $v); + $value = @trim($elements[6]); + + if (ereg('^[0-9\.]+$', $value)) { + + $sparkline->SetData($i, $value); + + if (null == $max || + $value >= $max[1]) { + $max = array($i, $value); + } + + if (null == $min || + $value <= $min[1]) { + $min = array($i, $value); + } + + $last = array($i, $value); + + $i++; + } +} + +// set y-bound, min and max extent lines +// +$sparkline->SetYMin(0); +$sparkline->SetPadding(2); // setpadding is additive +$sparkline->SetPadding(imagefontheight(FONT_2), + imagefontwidth(FONT_2) * strlen(" $last[1]"), + 0, //imagefontheight(FONT_2), + 0); +$sparkline->SetFeaturePoint($min[0], $min[1], 'red', 5, $min[1], TEXT_TOP, FONT_2); +$sparkline->SetFeaturePoint($max[0], $max[1], 'green', 5, $max[1], TEXT_TOP, FONT_2); +$sparkline->SetFeaturePoint($last[0], $last[1], 'blue', 5, " $last[1]", TEXT_RIGHT, FONT_2); + +if (isset($_GET['m']) && + $_GET['m'] == '0') { + $sparkline->Render(200, 50); +} else { + $sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image + $sparkline->RenderResampled(200, 50); +} + +// manually add a stock ticker label +// +$sparkline->DrawText(strtoupper($_GET['s']), + $sparkline->GetImageWidth() - (imagefontwidth(FONT_5) * strlen($_GET['s'])), + $sparkline->GetImageHeight() - imagefontheight(FONT_5), + 'black', + FONT_5); + +$sparkline->Output(); + +?> diff --git a/includes/sparkline-php-0.2/samples/stock_chart3.php b/includes/sparkline-php-0.2/samples/stock_chart3.php new file mode 100644 index 000000000..068b03515 --- /dev/null +++ b/includes/sparkline-php-0.2/samples/stock_chart3.php @@ -0,0 +1,112 @@ + + * http://sparkline.org + * + * Sparkline is distributed under a BSD License. See LICENSE for details. + * + * $Id: stock_chart3.php,v 1.1 2004/11/16 06:34:35 jbyers Exp $ + * + * stock_chart3 adds min/max price bounds and an endpoint value label to + * stock_chart, but without text as in stock_chart2 + * + */ + +////////////////////////////////////////////////////////////////////////////// +// verify parameters; bad form, but die to text error on failure +// +if (!isset($_GET['s']) || + !eregi('^[a-z\^]{1,5}$', $_GET['s'])) { + die('bad ticker ' . $_GET['s']); +} + +if (!isset($_GET['y']) || + !is_numeric($_GET['y']) || + $_GET['y'] > 5 || + $_GET['y'] < 0) { + die('bad year ' . $_GET['y']); +} + +////////////////////////////////////////////////////////////////////////////// +// load and process data from Yahoo! ichart csv source +// +$m = date('n') - 1; +$d = date('d'); +$y2 = date('Y'); +$y1 = $y2 - $_GET['y']; + +// data sample: +// 0 1 2 3 4 5 6 +// Date,Open,High,Low,Close,Volume,Adj. Close* +// 5-Nov-04,29.21,29.36,29.03,29.31,95337696,29.31 +// +$url = "http://ichart.finance.yahoo.com/table.csv?s=" . $_GET['s'] . "&a=$m&b=$d&c=$y1&d=$m&e=$d&f=$y2&g=d&ignore=.csv"; +if (!$data = @file($url)) { + die('error fetching stock data; verify ticker symbol'); +} + +////////////////////////////////////////////////////////////////////////////// +// build sparkline using standard flow: +// construct, set, render, output +// +require_once('../lib/Sparkline_Line.php'); + +$sparkline = new Sparkline_Line(); +$sparkline->SetDebugLevel(DEBUG_NONE); +//$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt'); + +if (isset($_GET['b'])) { + $sparkline->SetColorHtml('background', $_GET['b']); + $sparkline->SetColorBackground('background'); +} + +$data = array_reverse($data); +$i = 0; +$min = null; +$max = null; +$last = null; +while (list(, $v) = each($data)) { + $elements = explode(',', $v); + $value = @trim($elements[6]); + + if (ereg('^[0-9\.]+$', $value)) { + + $sparkline->SetData($i, $value); + + if (null == $max || + $value >= $max[1]) { + $max = array($i, $value); + } + + if (null == $min || + $value <= $min[1]) { + $min = array($i, $value); + } + + $last = array($i, $value); + + $i++; + } +} + +// set y-bound, min and max extent lines +// +$sparkline->SetYMin(0); +$sparkline->SetPadding(3); +$sparkline->SetColorHtml('ltgreen', '#00CC00'); +$sparkline->SetFeaturePoint($min[0], $min[1], 'red', 3); +$sparkline->SetFeaturePoint($max[0], $max[1], 'ltgreen', 3); +$sparkline->SetFeaturePoint($last[0], $last[1], 'blue', 3); + +if (isset($_GET['m']) && + $_GET['m'] == '0') { + $sparkline->Render(80, 20); +} else { + $sparkline->SetLineSize(5); // for renderresampled, linesize is on virtual image + $sparkline->RenderResampled(80, 20); +} + +$sparkline->Output(); + +?> diff --git a/modules/base/classes/entityManager.php b/modules/base/classes/entityManager.php index 094a5bb05..eb9a1c632 100644 --- a/modules/base/classes/entityManager.php +++ b/modules/base/classes/entityManager.php @@ -66,39 +66,6 @@ function owa_entityManager($entity_name) { } - function _getProperties() { - - $vars = get_object_vars($this->entity); - - $properties = array(); - - foreach ($vars as $k => $v) { - - $properties[$k] = $v->value; - - } - - return $properties; - } - - function getColumns() { - - $all_cols = get_object_vars($this->entity); - - return array_keys($all_cols); - - } - - /** - * Persist new object - * - */ - function create() { - - return $this->entity->create(); - - } - /** * Create Table * @@ -199,7 +166,15 @@ function renameTable($new_table_name) { return; } - + /** + * Persist new object + * + */ + function create() { + + return $this->entity->create(); + + } /** * Update all properties of an Existing object @@ -224,7 +199,6 @@ function partialUpdate($named_properties, $where) { } - /** * Delete Object * @@ -246,106 +220,306 @@ function getByColumn($col, $value) { } - function find($params = array()) { + /** + * Sets Values/Properties + * @depricated use setProperties() + */ + function setValues($values) { + + return $this->entity->setProperties($values); + + } + + /** + * Sets object attributes + * + * @param unknown_type $array + */ + function setProperties($array) { + + $this->entity->setProperties($array); + return; + } + + function set($name, $value) { + + return $this->entity->$name->value = $value; + } + + function get($name) { - $params['primary_obj'] = $this->entity; + return $this->entity->$name->value; + } + + function _getProperties() { - return $this->db->getObjs($params); + return $this->entity->_getProperties(); } - function query($params) { + function getColumns($return_as_string = false, $as_namespace = '', $table_namespace = false) { - $this->params['primary_obj'] = $this->entity; + return $this->entity->getColumns($return_as_string, $as_namespace, $table_namespace); - if (!empty($params)): - return $this->db->selectQuery(array_merge($this->params, $params)); - else: - return $this->db->selectQuery($this->params); - endif; } + function getColumnsSql($as_namespace = '', $table_namespace = true) { + + return $this->entity->getColumnsSql($as_namespace, $table_namespace); + + } /** - * Sets object attributes - * - * @param unknown_type $array + * + * @depricated */ - function setProperties($array) { + function find($params = array()) { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom(get_class($this->entity), $db->removeNs($this->entity->getTableName())); - $properties = $this->getColumns(); + $values = $this->entity->getColumns(); - foreach ($properties as $k => $v) { + $primary_obj_ns = $db->removeNs(get_class($this->entity)); + + foreach ($values as $k => $v) { + + if (empty($params['related_objs'])): + $db->selectColumn($v); + else: + $db->selectColumn($primary_obj_ns.'.'.$v, $primary_obj_ns.'_'.$v); + endif; + + } + + $db->selectFrom(get_class($this->entity), $ns); + + // add related objects + if(!empty($params['related_objs'])): + + foreach ($params['related_objs'] as $fk => $v_obj) { + + $values = $v_obj->entity->getColumns(); - if (!empty($array[$v])): - $this->entity->$v->value = $array[$v]; - endif; + $ns = $db->removeNs(get_class($v_obj->entity)); + foreach ($values as $k_values => $v_values) { + + $db->selectColumn($ns.'.'.$v_values, $ns.'_'.$v_values); + + } + + $for_key = $primary_obj_ns . '.' . $fk; + $pk = $ns . '.id'; + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, get_class($v_obj->entity), $ns, $for_key, $pk); + } - return; - } - - function setGuid($string) { + endif; - return owa_lib::setStringGuid($string); - } - - function set($name, $value) { + if(!empty($params['constraints'])): + foreach ($params['constraints'] as $k_con => $v_con) { + + if (is_array($v_con)): + $db->where($k_con, $v_con['value'], $v_con['operator']); + else: + $db->where($k_con, $v_con); + endif; + } + endif; + + return $db->getAllRows(); - return $this->entity->$name->value = $value; } /** - * Sets Values/Properties - * @depricated use setProperties() + * + * @depricated */ - function setValues($values) { + function query($params) { - return $this->setProperties($values); + $db = owa_coreAPI::dbSingleton(); - } + $primary_obj_ns = $db->removeNs(get_class($this->entity)); + + if (!empty($params)): + if (!empty($this->params)): + $params = array_merge($this->params, $params); + endif; + endif; - function get($name) { + // construct FROM + $db->selectFrom(get_class($this->entity), $db->removeNs($this->entity->getTableName())); + $db->selectColumn($params['select']); + $pns = $db->removeNs($this->entity->getTableName()); + // add related objects + if(!empty($params['related_objs'])): + + foreach ($params['related_objs'] as $fk => $v_obj) { + + //$values = $v_obj->entity->getColumns(); + + $ns = $db->removeNs(get_class($v_obj->entity)); + + //foreach ($values as $k_values => $v_values) { + + // $db->selectColumn($ns.'.'.$v_values, $ns.'_'.$v_values); + + //} + + $for_key = $primary_obj_ns . '.' . $fk; + $pk = $ns . '.id'; + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, get_class($v_obj->entity), $ns, $for_key, $pk); + + } + + endif; + + + + if(!empty($params['constraints'])): + foreach ($params['constraints'] as $k_con => $v_con) { + + $db->where($k_con, $v_con['value'], $v_con['operator']); + + } + endif; + + // construct GROUP BY + + if(!empty($params['groupby'])): + + if (is_array($params['groupby'])): + + foreach ($params['groupby'] as $groupby) { + + $db->groupBy($groupby); + + } + else: + $db->groupBy($params['groupby']); + endif; + + endif; + + // construct ORDER + + if(!empty($params['orderby'])): + + if (is_array($params['orderby'])): + + foreach ($params['orderby'] as $orderby) { + + $db->groupBy($orderby); + + } + else: + $db->orderBy($params['groupby']); + endif; + + endif; + + if(!empty($params['order'])): + $db->order($params['order']); + endif; + + // construct LIMIT + + if(!empty($params['limit'])): + $db->limit($params['order']); + endif; + + // construct OFFSET + + if(!empty($params['offset'])): + $db->offset($params['offset']); + endif; + + if(!empty($params['result_format'])): + $db->setFormat($params['result_format']); + endif; + + return $db->getAllRows(); + + - return $this->entity->$name->value; } + /** + * + * @depricated + */ function addRelatedObject($foreign_key, $obj) { return $this->params['related_objs'][$foreign_key] = $obj; } + /** + * + * @depricated + */ function addConstraint($col, $value) { return $this->params['constraints'][$col] = $value; } + /** + * + * @depricated + */ function addGroupBy($col) { return $this->params['groupby'][] = $col; } + /** + * + * @depricated + */ function addOrderBy($col) { return $this->params['orderby'][] = $col; } + /** + * + * @depricated + */ function setOrder($flag) { return $this->params['order'] = $flag; } + /** + * + * @depricated + */ function setSelect($string) { return $this->params['select'] = $string; } + + function setGuid($string) { + + return owa_lib::setStringGuid($string); + + } + + function getTableName() { + + return $this->entity->getTableName(); + + } + } ?> \ No newline at end of file diff --git a/modules/base/dashboardTrendWidget.php b/modules/base/dashboardTrendWidget.php new file mode 100644 index 000000000..9f024e4fb --- /dev/null +++ b/modules/base/dashboardTrendWidget.php @@ -0,0 +1,84 @@ +setConstraint('site_id', $this->params['site_id']); + $m->setConstraint('is_browser', 1); + $m->setPeriod($this->params['period']); + $m->setOrder(OWA_SQL_ASCENDING); + $results = $m->generate(); + + if (array_key_exists('format', $this->params)): + $format = $this->params['format']; + else: + $format = 'graph'; + endif; + + $data['title'] = 'Dashboard Trend'; + $data['view'] = 'base.widget'; + $data['y']['label'] = 'Page Views'; + $data['y2']['label'] = 'Visits'; + $data['x']['label'] = 'Day'; + + switch ($format) { + + case 'graph': + + $series = owa_lib::deconstruct_assoc($results); + $data['y']['series'] = $series['page_views']; + $data['y2']['series'] = $series['sessions']; + $data['x']['series'] = owa_lib::makeDateArray($results, "n/j"); + $data['view'] = 'base.areaBarsFlashChart'; + break; + + case 'table': + $data['column_labels'] = array(); + $data['data'] = ''; + $data['view'] = 'base.genericTable'; + break; + + + } + + return $data; + + } +} + + +?> \ No newline at end of file diff --git a/modules/base/graphPageTypes.php b/modules/base/graphPageTypes.php index 48b96881a..aacf16c44 100644 --- a/modules/base/graphPageTypes.php +++ b/modules/base/graphPageTypes.php @@ -51,12 +51,11 @@ function construct($data) { $result = $api->getMetric('base.pageTypesCount',array( - 'result_format' => 'inverted_array', 'constraints' => array('site_id' => $data['site_id']) )); - //$result = owa_lib::deconstruct_assoc($results); + $result = owa_lib::deconstruct_assoc($result); //Graph params diff --git a/modules/base/logSessionUpdate.php b/modules/base/logSessionUpdate.php index 8eac2bee8..ece5016cd 100644 --- a/modules/base/logSessionUpdate.php +++ b/modules/base/logSessionUpdate.php @@ -53,6 +53,7 @@ function action() { // increment number of page views $s->set('num_pageviews', $s->get('num_pageviews') + 1); + print $num; // update timestamp $s->set('last_req', $this->params['last_req']); diff --git a/modules/base/metrics/clickBrowserTypes.php b/modules/base/metrics/clickBrowserTypes.php index 0225a269e..90fbbb8a1 100644 --- a/modules/base/metrics/clickBrowserTypes.php +++ b/modules/base/metrics/clickBrowserTypes.php @@ -40,9 +40,26 @@ function owa_clickBrowserTypes($params = null) { } - function generate() { + function calculate() { - $c = owa_coreAPI::entityFactory('base.click'); + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_click', 'click'); + + $db->selectColumn("count(distinct click.id) as count, + ua.id, + ua.ua as ua, + ua.browser_type"); + $db->join(OWA_SQL_JOIN_LEFT_OUTER,'owa_ua', 'ua', 'ua_id', 'ua.id'); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('ua.browser_type'); + $db->orderBy('count'); + + return $db->getAllRows(); + + /* +$c = owa_coreAPI::entityFactory('base.click'); $ua = owa_coreAPI::entityFactory('base.ua'); @@ -60,7 +77,8 @@ function generate() { $this->params['orderby'] = array('count'); return $c->query($this->params); - + +*/ } diff --git a/modules/base/metrics/clickstream.php b/modules/base/metrics/clickstream.php index d812c528d..fff0d438b 100644 --- a/modules/base/metrics/clickstream.php +++ b/modules/base/metrics/clickstream.php @@ -40,8 +40,22 @@ function owa_clickstream($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_request', 'request'); + $db->selectColumn("*"); + // pass constraints into where clause + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_document', 'document', 'document_id', 'document.id'); + $db->multiWhere($this->getConstraints()); + + + $ret = $db->getAllRows(); + + return $ret; + /* + $r = owa_coreAPI::entityFactory('base.request'); $d = owa_coreAPI::entityFactory('base.document'); @@ -50,7 +64,8 @@ function generate() { $this->setTimePeriod($this->params['period']); return $r->find($this->params); - + +*/ } diff --git a/modules/base/metrics/dashCoreByDay.php b/modules/base/metrics/dashCoreByDay.php index f862f80ee..2cf5a2efe 100644 --- a/modules/base/metrics/dashCoreByDay.php +++ b/modules/base/metrics/dashCoreByDay.php @@ -40,7 +40,33 @@ function owa_dashCoreByDay($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + + $db->selectColumn("session.month, + session.day, + session.year, + count(distinct session.visitor_id) as unique_visitors, + count(session.id) as sessions, + sum(session.num_pageviews) as page_views"); + + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('day'); + $db->groupBy('month'); + $db->orderBy('year'); + $db->orderBy('month'); + $db->orderBy('day'); + + $ret = $db->getAllRows(); + + return $ret; + + +/* $this->params['select'] = "session.month, session.day, @@ -49,7 +75,6 @@ function generate() { count(session.id) as sessions, sum(session.num_pageviews) as page_views "; - $this->params['use_summary'] = true; $this->params['groupby'] = array('day', 'month'); @@ -60,7 +85,8 @@ function generate() { $s = owa_coreAPI::entityFactory('base.session'); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/dashCoreByMonth.php b/modules/base/metrics/dashCoreByMonth.php index 480f19134..8fcd10e55 100644 --- a/modules/base/metrics/dashCoreByMonth.php +++ b/modules/base/metrics/dashCoreByMonth.php @@ -40,7 +40,27 @@ function owa_dashCoreByMonth($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("session.month, + session.day, + session.year, + count(distinct session.visitor_id) as unique_visitors, + count(session.id) as sessions, + sum(session.num_pageviews) as page_views"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('month'); + $db->groupBy('year'); + $db->orderBy('year'); + $db->orderBy('month'); + + return $db->getAllRows(); + + /* $this->params['select'] = "session.month, session.day, @@ -60,7 +80,8 @@ function generate() { $s = owa_coreAPI::entityFactory('base.session'); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/dashCounts.php b/modules/base/metrics/dashCounts.php index a4ff5bbd6..b504ba30d 100644 --- a/modules/base/metrics/dashCounts.php +++ b/modules/base/metrics/dashCounts.php @@ -40,8 +40,23 @@ function owa_dashCounts($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session'); + $db->selectColumn("count(distinct session.visitor_id) as unique_visitors, + sum(session.is_new_visitor) as new_visitor, sum(session.is_repeat_visitor) as repeat_visitor, + count(session.id) as sessions, + sum(session.num_pageviews) as page_views"); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + return $db->getOneRow(); + + /* + $this->params['select'] = "count(distinct session.visitor_id) as unique_visitors, sum(session.is_new_visitor) as new_visitor, sum(session.is_repeat_visitor) as repeat_visitor, count(session.id) as sessions, @@ -55,6 +70,7 @@ function generate() { return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/dashCountsTraffic.php b/modules/base/metrics/dashCountsTraffic.php index 1aef8b47f..323326cea 100644 --- a/modules/base/metrics/dashCountsTraffic.php +++ b/modules/base/metrics/dashCountsTraffic.php @@ -40,8 +40,28 @@ function owa_dashCountsTraffic($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(distinct session.visitor_id) as unique_visitors, + sum(session.is_new_visitor) as new_visitor, sum(session.is_repeat_visitor) as repeat_visitor, + count(session.id) as sessions, + sum(session.num_pageviews) as page_views"); + + $db->selectFrom('owa_session', 'session'); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + + /* + $this->params['select'] = "count(distinct session.visitor_id) as unique_visitors, sum(session.is_new_visitor) as new_visitor, sum(session.is_repeat_visitor) as repeat_visitor, count(session.id) as sessions, @@ -58,6 +78,7 @@ function generate() { $this->params['related_objs'] = array('referer_id' => $ref); return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/feedReaderTypesCount.php b/modules/base/metrics/feedReaderTypesCount.php index 196455640..bf9fa443c 100644 --- a/modules/base/metrics/feedReaderTypesCount.php +++ b/modules/base/metrics/feedReaderTypesCount.php @@ -40,9 +40,23 @@ function owa_feedReaderTypesCount($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_feed_request', 'feed_request'); + $db->selectColumn("count(distinct feed_request.feed_reader_guid) as count, ua.ua as ua, ua.browser_type"); + // pass constraints into where clause + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_ua', 'ua', 'ua_id', 'ua.id'); + $db->multiWhere($this->getConstraints()); + $db->groupBy('ua.browser_type'); + $db->orderBy('count'); + $db->order('DESC'); + + return $db->getOneRow(); - $this->params['select'] = "count(distinct feed_request.feed_reader_guid) as count, + /* +$this->params['select'] = "count(distinct feed_request.feed_reader_guid) as count, ua.ua as ua, ua.browser_type"; @@ -58,7 +72,8 @@ function generate() { $this->params['orderby'] = array('count'); $this->params['order'] = 'desc'; return $f->query($this->params); - + +*/ } diff --git a/modules/base/metrics/feedViewsTrend.php b/modules/base/metrics/feedViewsTrend.php index e46262cfa..2970035dc 100644 --- a/modules/base/metrics/feedViewsTrend.php +++ b/modules/base/metrics/feedViewsTrend.php @@ -40,8 +40,20 @@ function owa_feedViewsTrend($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_feed_request'); + $db->selectColumn("count(id) as fetch_count, count(distinct feed_reader_guid) as reader_count, year, month, day"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + return $db->getAllRows(); + + + /* + $this->params['select'] = "count(id) as fetch_count, count(distinct feed_reader_guid) as reader_count, year, @@ -54,7 +66,8 @@ function generate() { $f = owa_coreAPI::entityFactory('base.feed_request'); return $f->query($this->params); - + +*/ } diff --git a/modules/base/metrics/latestVisits.php b/modules/base/metrics/latestVisits.php index 158761024..d89186b6e 100644 --- a/modules/base/metrics/latestVisits.php +++ b/modules/base/metrics/latestVisits.php @@ -30,31 +30,53 @@ class owa_latestVisits extends owa_metric { - function owa_latestVisits($params = null) { - - $this->params = $params; - - $this->owa_metric(); - - return; + function owa_latestVisits($params) { + + return parent::__construct($params); } - function generate() { + function __construct($params) { + + return parent::__construct($params); + } + + function calculate() { + + $db = owa_coreAPI::dbSingleton(); $s = owa_coreAPI::entityFactory('base.session'); - $h = owa_coreAPI::entityFactory('base.host'); $ua = owa_coreAPI::entityFactory('base.ua'); $d = owa_coreAPI::entityFactory('base.document'); $v = owa_coreAPI::entityFactory('base.visitor'); $r = owa_coreAPI::entityFactory('base.referer'); - $this->params['related_objs'] = array('host_id' => $h, 'ua_id' => $ua, 'first_page_id' => $d, 'visitor_id' => $v, 'referer_id' => $r); - //$related_objs = array('ua_id' => $ua); - $this->setTimePeriod($this->params['period']); - return $s->find($this->params); + $db->selectFrom($s->getTableName()); + + $db->selectColumn($s->getColumnsSql('session_')); + $db->selectColumn($h->getColumnsSql('host_')); + $db->selectColumn($ua->getColumnsSql('ua_')); + $db->selectColumn($d->getColumnsSql('document_')); + $db->selectColumn($v->getColumnsSql('visitor_')); + $db->selectColumn($r->getColumnsSql('referer_')); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, $h->getTableName(), '', 'host_id'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, $ua->getTableName(), '', 'ua_id'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, $d->getTableName(), '', 'first_page_id'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, $v->getTableName(), '', 'visitor_id'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, $r->getTableName(), '', 'referer_id'); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->orderBy('session_timestamp'); + $db->order($this->params['order']); + $db->limit($this->params['limit']); + $db->offset($this->params['offset']); + + $ret = $db->getAllRows(); + return $ret; } diff --git a/modules/base/metrics/pageTypesCount.php b/modules/base/metrics/pageTypesCount.php index 8a1383702..64e7f02d2 100644 --- a/modules/base/metrics/pageTypesCount.php +++ b/modules/base/metrics/pageTypesCount.php @@ -40,8 +40,32 @@ function owa_pageTypesCount($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_request', 'request'); + $db->selectColumn("count(request.id) as count, + document.page_title, + document.page_type, + document.url, + document.id"); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER,'owa_document', 'document', 'document_id', 'document.id'); + $db->groupBy('document.page_type'); + $db->orderBy('count'); + + return $db->getAllRows(); + + + + + /* + + $r = owa_coreAPI::entityFactory('base.request'); $d = owa_coreAPI::entityFactory('base.document'); @@ -61,7 +85,8 @@ function generate() { $this->params['orderby'] = array('count'); return $r->query($this->params); - + +*/ } diff --git a/modules/base/metrics/pageViewsByDay.php b/modules/base/metrics/pageViewsByDay.php index 72cbea8d7..8d2a095b6 100644 --- a/modules/base/metrics/pageViewsByDay.php +++ b/modules/base/metrics/pageViewsByDay.php @@ -40,7 +40,34 @@ function owa_pageViewsByDay($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("sum(session.num_pageviews) as page_views, + session.month, + session.day, + session.year"); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + if (array_key_exists('groupby', $this->params)): + $db->groupBy($this->params['groupby']); + else: + $db->groupBy('session.day'); + endif; + + $db->orderBy('session.year'); + $db->orderBy('session.month'); + $db->orderBy('session.day'); + + + return $db->getAllRows(); + + /* + $s = owa_coreAPI::entityFactory('base.session'); @@ -56,6 +83,7 @@ function generate() { return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/pageViewsCount.php b/modules/base/metrics/pageViewsCount.php index aafff8f37..e6059dae9 100644 --- a/modules/base/metrics/pageViewsCount.php +++ b/modules/base/metrics/pageViewsCount.php @@ -40,7 +40,22 @@ function owa_pageViewsCount($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("sum(session.num_pageviews) as page_views"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + return $db->getOneRow(); + + + + /* + + $s = owa_coreAPI::entityFactory('base.session'); @@ -49,7 +64,8 @@ function generate() { $this->params['select'] = "sum(session.num_pageviews) as page_views"; return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/requestCounts.php b/modules/base/metrics/requestCounts.php index bd575f04a..039e64e97 100644 --- a/modules/base/metrics/requestCounts.php +++ b/modules/base/metrics/requestCounts.php @@ -40,8 +40,24 @@ function owa_requestCounts($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_request', 'request'); + $db->selectColumn("count(distinct request.visitor_id) as unique_visitors, + count(request.session_id) as sessions, + count(request.id) as page_views"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + return $db->getOneRow(); + + + + + /* + $this->params['select'] = "count(distinct request.visitor_id) as unique_visitors, count(request.session_id) as sessions, count(request.id) as page_views"; @@ -53,6 +69,7 @@ function generate() { $r = owa_coreAPI::entityFactory('base.request'); return $r->query($this->params); +*/ } diff --git a/modules/base/metrics/requestCountsByDay.php b/modules/base/metrics/requestCountsByDay.php index 448780d05..debb91013 100644 --- a/modules/base/metrics/requestCountsByDay.php +++ b/modules/base/metrics/requestCountsByDay.php @@ -40,7 +40,33 @@ function owa_requestCountsByDay($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_request', 'request'); + $db->selectColumn("request.month, request.day, request.year, + count(distinct request.visitor_id) as unique_visitors, + count(distinct request.session_id) as sessions, + count(request.id) as page_views"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + if (array_key_exists('groupby', $this->params)): + $db->groupBy($this->params['groupby']); + else: + $db->groupBy('month'); + endif; + + $db->orderBy('year'); + $db->orderBy('month'); + $db->orderBy('day'); + + return $db->getAllRows(); + + + /* + $this->params['select'] = "request.month, request.day, request.year, count(distinct request.visitor_id) as unique_visitors, @@ -54,6 +80,7 @@ function generate() { $r = owa_coreAPI::entityFactory('base.request'); return $r->query($this->params); +*/ } diff --git a/modules/base/metrics/sessionBrowserTypes.php b/modules/base/metrics/sessionBrowserTypes.php index 3db31219b..d5321ca7c 100644 --- a/modules/base/metrics/sessionBrowserTypes.php +++ b/modules/base/metrics/sessionBrowserTypes.php @@ -40,7 +40,21 @@ function owa_sessionBrowserTypes($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("count(distinct session.id) as count, ua.ua as ua, ua.browser_type"); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_ua', 'ua', 'ua_id', 'ua.id'); + $db->groupBy('ua.browser_type'); + $db->orderBy('count'); + + return $db->getAllRows(); + + /* $s = owa_coreAPI::entityFactory('base.session'); @@ -59,7 +73,8 @@ function generate() { $this->params['orderby'] = array('count'); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/sessionsCount.php b/modules/base/metrics/sessionsCount.php index 46f4f1431..afc910985 100644 --- a/modules/base/metrics/sessionsCount.php +++ b/modules/base/metrics/sessionsCount.php @@ -40,16 +40,18 @@ function owa_sessionsCount($params = null) { } - function generate() { + function calculate() { - $this->params['select'] = "count(session.id) as count"; + $db = owa_coreAPI::dbSingleton(); - $this->setTimePeriod($this->params['period']); + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("count(session.id) as count"); - $s = owa_coreAPI::entityFactory('base.session'); + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); - return $s->query($this->params); - + return $db->getOneRow(); + } diff --git a/modules/base/metrics/topClicks.php b/modules/base/metrics/topClicks.php index 9c89ab4f8..a8c5a774a 100644 --- a/modules/base/metrics/topClicks.php +++ b/modules/base/metrics/topClicks.php @@ -40,8 +40,32 @@ function owa_topClicks($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_click'); + $db->selectColumn("count(id) as count, + click_x, + click_y, + page_width, + page_height, + dom_element_x, + dom_element_y, + position"); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('position'); + $db->orderBy('count'); + $db->order('DESC'); + + return $db->getAllRows(); + + + + /* + $this->params['select'] = "count(id) as count, click_x, click_y, @@ -62,6 +86,7 @@ function generate() { return $c->query($this->params); +*/ } diff --git a/modules/base/metrics/topEntryPages.php b/modules/base/metrics/topEntryPages.php index ec7501169..2d9c66a4b 100644 --- a/modules/base/metrics/topEntryPages.php +++ b/modules/base/metrics/topEntryPages.php @@ -40,28 +40,27 @@ function owa_topEntryPages($params = null) { } - function generate() { + function calculate() { - $s = owa_coreAPI::entityFactory('base.session'); + $db = owa_coreAPI::dbSingleton(); - $d = owa_coreAPI::entityFactory('base.document'); - - $this->params['related_objs'] = array('first_page_id' => $d); - - $this->setTimePeriod($this->params['period']); - - $this->params['select'] = "count(session.id) as count, + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("count(session.id) as count, document.page_title, document.page_type, document.url, - document.id"; - - $this->params['groupby'] = array('session.first_page_id'); - - $this->params['orderby'] = array('count'); + document.id"); - return $s->query($this->params); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_document', 'document', 'first_page_id', 'document.id'); + $db->groupBy('session.last_page_id'); + $db->orderBy('count'); + return $db->getAllRows(); + + } diff --git a/modules/base/metrics/topExitPages.php b/modules/base/metrics/topExitPages.php index 60c1402fb..9e865d3c9 100644 --- a/modules/base/metrics/topExitPages.php +++ b/modules/base/metrics/topExitPages.php @@ -40,7 +40,32 @@ function owa_topExitPages($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("count(session.id) as count, + document.page_title, + document.page_type, + document.url, + document.id"); + + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_document', 'document', 'last_page_id', 'document.id'); + $db->groupBy('session.last_page_id'); + $db->orderBy('count'); + + + return $db->getAllRows(); + + + + /* + $s = owa_coreAPI::entityFactory('base.session'); @@ -61,7 +86,8 @@ function generate() { $this->params['orderby'] = array('count'); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/topHosts.php b/modules/base/metrics/topHosts.php index b5f0920b4..ff0d82fef 100644 --- a/modules/base/metrics/topHosts.php +++ b/modules/base/metrics/topHosts.php @@ -40,7 +40,32 @@ function owa_topHosts($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + + $db->selectFrom('owa_session', 'session'); + $db->selectColumn("count(session.host_id) as count, + host.id, + host.host, + host.full_host, + host.ip_address"); + + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_host', 'host', 'host_id', 'host.id'); + $db->groupBy('host.id'); + $db->orderBy('count'); + $db->order('DESC'); + + return $db->getAllRows(); + + + /* + + $this->params['select'] = "count(session.host_id) as count, host.id, @@ -60,6 +85,7 @@ function generate() { return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/topPages.php b/modules/base/metrics/topPages.php index cd1221fca..586c3a347 100644 --- a/modules/base/metrics/topPages.php +++ b/modules/base/metrics/topPages.php @@ -28,37 +28,50 @@ * @since owa 1.0.0 */ -class owa_toppages extends owa_metric { +class owa_topPages extends owa_metric { - function owa_topPages($params = null) { - - $this->params = $params; - - $this->owa_metric(); - - return; + function owa_topPages($params) { + + return $this->__construct($params); } - function generate() { - + function __construct($params) { + + return parent::__construct($params); + } + + + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + $r = owa_coreAPI::entityFactory('base.request'); - $r->addRelatedObject('document_id', owa_coreAPI::entityFactory('base.document')); + $d = owa_coreAPI::entityFactory('base.document'); - $r->setSelect("count(request.document_id) as count, + //$r->addRelatedObject('document_id', owa_coreAPI::entityFactory('base.document')); + $db->selectFrom($r->getTableName(), 'request'); + $db->selectColumn("count(request.document_id) as count, document.page_title, document.page_type, document.url, document.id as document_id"); + - $this->setTimePeriod($this->params['period']); - - $r->addGroupBy('document.id'); - $r->addOrderBy('count'); - $r->setOrder('DESC'); - $r->addConstraint('document.page_type', array('operator' => '!=', 'value' => 'feed')); + //$this->setTimePeriod($this->params['period']); + + $db->where('document.page_type', 'feed', '!='); + + // pass constraints into where clause + $db->multiWhere($this->getConstraints()); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER,$d->getTableName(), 'document', 'document_id', 'document.id'); + $db->groupBy('document.id'); + $db->orderBy('count'); + $db->order('DESC'); + - return $r->query($this->params); + return $db->getAllRows(); } diff --git a/modules/base/metrics/topReferers.php b/modules/base/metrics/topReferers.php index 73bf0867b..329f9028f 100644 --- a/modules/base/metrics/topReferers.php +++ b/modules/base/metrics/topReferers.php @@ -40,8 +40,35 @@ function owa_topReferers($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(referer.id) as count, + sum(session.num_pageviews) as page_views, + url, + page_title, + site_name, + query_terms, + snippet, + refering_anchortext, + is_searchengine"); + + $db->selectFrom('owa_session', 'session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + $db->groupBy('referer.url'); + $db->orderBy('count'); + $db->where('is_searchengine', 1, '!='); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + + + /* + $s = owa_coreAPI::entityFactory('base.session'); $r = owa_coreAPI::entityFactory('base.referer'); @@ -66,7 +93,8 @@ function generate() { $this->params['orderby'] = array('count'); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/topReferingAnchors.php b/modules/base/metrics/topReferingAnchors.php index 02631cf29..fc18b46c4 100644 --- a/modules/base/metrics/topReferingAnchors.php +++ b/modules/base/metrics/topReferingAnchors.php @@ -40,9 +40,30 @@ function owa_topReferingAnchors($params = null) { } - function generate() { + function calculate() { - $this->params['select'] = "count(session.id) as count, referer.refering_anchortext"; + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as count, referer.refering_anchortext"); + + $db->selectFrom('owa_session', 'session'); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + $db->groupBy('referer.refering_anchortext'); + $db->orderBy('count'); + $db->order('DESC'); + $db->where('referer.id', 0, '!='); + $db->where('referer.refering_anchortext', ' ', '!='); + $db->where('referer.is_searchengine', 0); + + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + /* +$this->params['select'] = "count(session.id) as count, referer.refering_anchortext"; $this->setTimePeriod($this->params['period']); @@ -59,6 +80,7 @@ function generate() { $this->params['constraints']['referer.is_searchengine'] = array('operator' => '=', 'value' => 0); return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/topReferingHosts.php b/modules/base/metrics/topReferingHosts.php index 21a2d0370..a3cd40c86 100644 --- a/modules/base/metrics/topReferingHosts.php +++ b/modules/base/metrics/topReferingHosts.php @@ -40,8 +40,29 @@ function owa_topReferingHosts($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as count, referer.site"); + + $db->selectFrom('owa_session', 'session'); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + $db->groupBy('referer.site'); + $db->orderBy('count'); + $db->order('DESC'); + $db->where('referer.id', 0, '!='); + + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + + /* + $this->params['select'] = "count(session.id) as count, referer.site"; $this->setTimePeriod($this->params['period']); @@ -57,6 +78,7 @@ function generate() { $this->params['constraints']['referer.id'] = array('operator' => '!=', 'value' => 0); return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/topReferingKeywords.php b/modules/base/metrics/topReferingKeywords.php index 2f02834e0..4c61f32d2 100644 --- a/modules/base/metrics/topReferingKeywords.php +++ b/modules/base/metrics/topReferingKeywords.php @@ -40,8 +40,28 @@ function owa_topReferingKeywords($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as count, referer.query_terms"); + + $db->selectFrom('owa_session', 'session'); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + $db->groupBy('referer.query_terms'); + $db->orderBy('count'); + $db->order('DESC'); + $db->where('referer.id', 0, '!='); + $db->where('referer.query_terms', ' ', '!='); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + /* + $this->params['select'] = "count(session.id) as count, referer.query_terms"; $this->setTimePeriod($this->params['period']); @@ -58,7 +78,8 @@ function generate() { $this->params['constraints']['referer.query_terms'] = array('operator' => '!=', 'value' => ''); return $s->query($this->params); - + +*/ } diff --git a/modules/base/metrics/topVisitors.php b/modules/base/metrics/topVisitors.php index 7f695e49a..0af7b01e9 100644 --- a/modules/base/metrics/topVisitors.php +++ b/modules/base/metrics/topVisitors.php @@ -40,23 +40,20 @@ function owa_topVisitors($params = null) { } - function generate() { + function calculate() { - $s = owa_coreAPI::entityFactory('base.session'); - - $this->setTimePeriod($this->params['period']); - - $this->params['select'] = "count(visitor_id) as count, - visitor_id as vis_id, - user_name, - user_email"; - - $this->params['groupby'] = array('vis_id'); - - $this->params['orderby'] = array('count'); - - return $s->query($this->params); + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(visitor_id) as count, visitor_id as vis_id, user_name, user_email"); + $db->selectFrom('owa_session'); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('vis_id'); + $db->orderBy('count'); + $ret = $db->getAllRows(); + + return $ret; + } diff --git a/modules/base/metrics/visitorTypesCount.php b/modules/base/metrics/visitorTypesCount.php index b33d2f1ee..4ba68f95b 100644 --- a/modules/base/metrics/visitorTypesCount.php +++ b/modules/base/metrics/visitorTypesCount.php @@ -42,17 +42,16 @@ function owa_visitorTypesCount($params = null) { function generate() { - $this->params['select'] = "sum(is_new_visitor) as new_visitor, - sum(is_repeat_visitor) as repeat_visitor "; + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("sum(is_new_visitor) as new_visitor, sum(is_repeat_visitor) as repeat_visitor"); + $db->selectFrom('owa_session'); - $this->params['use_summary'] = true; - - $this->setTimePeriod($this->params['period']); - - $s = owa_coreAPI::entityFactory('base.session'); - - return $s->query($this->params); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getOneRow(); + return $ret; } diff --git a/modules/base/metrics/visitorsAge.php b/modules/base/metrics/visitorsAge.php index 20938da40..0c35da511 100644 --- a/modules/base/metrics/visitorsAge.php +++ b/modules/base/metrics/visitorsAge.php @@ -40,28 +40,32 @@ function owa_visitorsAge($params = null) { } - function generate() { + function calculate() { - $s = owa_coreAPI::entityFactory('base.session'); - - $v = owa_coreAPI::entityFactory('base.visitor'); - - $this->params['related_objs'] = array('visitor_id' => $v); - - $this->setTimePeriod($this->params['period']); - - $this->params['select'] = "count(distinct session.visitor_id) as count, + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(distinct session.visitor_id) as count, visitor.first_session_year, visitor.first_session_month, visitor.first_session_day, - visitor.first_session_timestamp as timestamp"; - - $this->params['groupby'] = array('visitor.first_session_year', 'visitor.first_session_month', 'visitor.first_session_day'); + visitor.first_session_timestamp as timestamp"); + + $db->selectFrom('owa_session', 'session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_visitor', 'visitor', 'visitor_id', 'visitor.id'); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); - $this->params['orderby'] = array('visitor.first_session_year', 'visitor.first_session_month', 'visitor.first_session_day'); - - return $s->query($this->params); + $db->groupBy('visitor.first_session_year'); + $db->groupBy('visitor.first_session_month'); + $db->groupBy('visitor.first_session_day'); + + $db->orderBy('visitor.first_session_year'); + $db->orderBy('visitor.first_session_month'); + $db->orderBy('visitor.first_session_day'); + $ret = $db->getAllRows(); + + return $ret; + } diff --git a/modules/base/metrics/visitorsList.php b/modules/base/metrics/visitorsList.php index a7971d2ae..7dcddf64d 100644 --- a/modules/base/metrics/visitorsList.php +++ b/modules/base/metrics/visitorsList.php @@ -40,8 +40,22 @@ function owa_visitorsList($params = null) { } - function generate() { + function calculate() { + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("distinct session.visitor_id as visitor_id, visitor.user_name, visitor.user_email"); + $db->selectFrom('owa_session', 'session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_visitor', 'visitor', 'visitor_id', 'visitor.id'); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getAllRows(); + + return $ret; + + + /* + $s = owa_coreAPI::entityFactory('base.session'); $v = owa_coreAPI::entityFactory('base.visitor'); @@ -56,6 +70,7 @@ function generate() { return $s->query($this->params); +*/ } diff --git a/modules/base/metrics/visitorsUserAgentCount.php b/modules/base/metrics/visitorsUserAgentCount.php index 6631e4e26..c0d91a1db 100644 --- a/modules/base/metrics/visitorsUserAgentCount.php +++ b/modules/base/metrics/visitorsUserAgentCount.php @@ -40,9 +40,22 @@ function owa_visitorsUserAgentCount($params = null) { } - function generate() { + function calculate() { - $sql = sprintf(" + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(distinct sessions.session_id) as count, ua.ua as ua, ua.browser_type"); + $db->selectFrom('owa_session', 'sessions'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_ua', 'ua', 'ua_id'); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + $db->groupBy('ua.browser_type'); + + $ret = $db->getOneRow(); + + return $ret; + + /* +$sql = sprintf(" SELECT count(distinct sessions.session_id) as count, ua.ua as ua, @@ -66,6 +79,7 @@ function generate() { ); return $this->db->get_results($sql); +*/ } diff --git a/modules/base/metrics/visitsFromDirectNavCount.php b/modules/base/metrics/visitsFromDirectNavCount.php index 73a2ac3c3..4490638e9 100644 --- a/modules/base/metrics/visitsFromDirectNavCount.php +++ b/modules/base/metrics/visitsFromDirectNavCount.php @@ -40,22 +40,20 @@ function owa_visitsFromDirectNavCount($params = null) { } - function generate() { - - $this->params['select'] = "count(session.id) as count"; - - $this->params['use_summary'] = true; - - $this->setTimePeriod($this->params['period']); - - $s = owa_coreAPI::entityFactory('base.session'); - $ref = owa_coreAPI::entityFactory('base.referer'); - - $this->params['related_objs'] = array('referer_id' => $ref); - $this->params['constraints']['referer_id'] = array('operator' => '=', 'value' => '0'); - $this->params['constraints']['source'] = array('operator' => '=', 'value' => ''); + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as count"); + $db->selectFrom('owa_session', 'session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', '', 'referer_id'); + $db->where('referer.is_searchengine', 0); + $db->where('source', ' '); + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); - return $s->query($this->params); + $ret = $db->getOneRow(); + + return $ret; } diff --git a/modules/base/metrics/visitsFromFeedsCount.php b/modules/base/metrics/visitsFromFeedsCount.php index c86625ca2..8b25c3a32 100644 --- a/modules/base/metrics/visitsFromFeedsCount.php +++ b/modules/base/metrics/visitsFromFeedsCount.php @@ -40,22 +40,21 @@ function owa_visitsFromFeedsCount($params = null) { } - function generate() { + function calculate() { - $this->params['select'] = "count(session.id) as source_count"; + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as source_count"); + $db->selectFrom('base.session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'base.referer', '', 'referer_id'); + $db->where('session.source', 'feed'); + $db->where('referer.is_searchengine', 1, '!='); - $this->params['use_summary'] = true; + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); - $this->setTimePeriod($this->params['period']); + $ret = $db->getOneRow(); - $s = owa_coreAPI::entityFactory('base.session'); - $ref = owa_coreAPI::entityFactory('base.referer'); - - $this->params['related_objs'] = array('referer_id' => $ref); - $this->params['constraints']['session.source'] = 'feed'; - $this->params['constraints']['referer.is_searchengine'] = array('operator' => '!=', 'value' => 1); - - return $s->query($this->params); + return $ret; } diff --git a/modules/base/metrics/visitsFromSearchEnginesCount.php b/modules/base/metrics/visitsFromSearchEnginesCount.php index 98fc19d27..bad45db6e 100644 --- a/modules/base/metrics/visitsFromSearchEnginesCount.php +++ b/modules/base/metrics/visitsFromSearchEnginesCount.php @@ -40,21 +40,21 @@ function owa_visitsFromSearchEnginesCount($params = null) { } - function generate() { + function calculate() { - $this->params['select'] = "count(session.id) as se_count"; + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as se_count"); + $db->selectFrom('owa_session', 'session'); + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', '', 'referer_id'); + $db->where('session.source', 'feed'); + $db->where('referer.is_searchengine', 1); - $this->params['use_summary'] = true; + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); - $this->setTimePeriod($this->params['period']); + $ret = $db->getOneRow(); - $s = owa_coreAPI::entityFactory('base.session'); - $ref = owa_coreAPI::entityFactory('base.referer'); - - $this->params['related_objs'] = array('referer_id' => $ref); - $this->params['constraints']['referer.is_searchengine'] = 1; - - return $s->query($this->params); + return $ret; } diff --git a/modules/base/metrics/visitsFromSitesCount.php b/modules/base/metrics/visitsFromSitesCount.php index 3450d7ebf..ad4ea3910 100644 --- a/modules/base/metrics/visitsFromSitesCount.php +++ b/modules/base/metrics/visitsFromSitesCount.php @@ -42,7 +42,28 @@ function owa_visitsFromSitesCount($params = null) { } - function generate() { + function calculate() { + + $db = owa_coreAPI::dbSingleton(); + $db->selectColumn("count(session.id) as site_count"); + + $db->selectFrom('owa_session', 'session'); + + $db->join(OWA_SQL_JOIN_LEFT_OUTER, 'owa_referer', 'referer', 'referer_id', 'referer.id'); + + $db->where('referer_id', 0, '!='); + $db->where('referer.source', ' '); + $db->where('referer.is_searchengine', 1, '!='); + + // pass constraints set by caller into where clause + $db->multiWhere($this->getConstraints()); + + $ret = $db->getOneRow(); + + return $ret; + + /* + $this->params['select'] = "count(session.id) as site_count"; @@ -59,7 +80,8 @@ function generate() { $this->params['constraints']['source'] = array('operator' => '=', 'value' => ''); return $s->query($this->params); - + +*/ } diff --git a/modules/base/optionsFlushCache.php b/modules/base/optionsFlushCache.php index 3f2765794..7f2217aa1 100644 --- a/modules/base/optionsFlushCache.php +++ b/modules/base/optionsFlushCache.php @@ -16,7 +16,7 @@ // $Id$ // -require_once(OWA_BASE_DIR.'/owa_controller.php'); +require_once(OWA_BASE_DIR.'/owa_adminController.php'); /** * Options Update Controller @@ -30,10 +30,10 @@ * @since owa 1.0.0 */ -class owa_optionsFlushCacheController extends owa_controller { +class owa_optionsFlushCacheController extends owa_adminController { function owa_optionsFlushCacheController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'admin'; return; diff --git a/modules/base/optionsGeneral.php b/modules/base/optionsGeneral.php index e21c7f7dd..acfab3f79 100644 --- a/modules/base/optionsGeneral.php +++ b/modules/base/optionsGeneral.php @@ -79,7 +79,7 @@ class owa_optionsGeneralController extends owa_adminController { var $type = 'options'; function owa_optionsGeneralController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'admin'; return; diff --git a/modules/base/optionsModules.php b/modules/base/optionsModules.php index 0187a475a..45669cb00 100644 --- a/modules/base/optionsModules.php +++ b/modules/base/optionsModules.php @@ -16,7 +16,7 @@ // $Id$ // -require_once(OWA_BASE_CLASSES_DIR.'owa_controller.php'); +require_once(OWA_BASE_CLASSES_DIR.'owa_adminController.php'); require_once(OWA_BASE_CLASSES_DIR.'owa_view.php'); /** @@ -31,10 +31,10 @@ * @since owa 1.0.0 */ -class owa_optionsModulesController extends owa_controller { +class owa_optionsModulesController extends owa_adminController { function owa_optionsModulesController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'admin'; return; diff --git a/modules/base/optionsReset.php b/modules/base/optionsReset.php index e56fcea51..ac44fa0a9 100644 --- a/modules/base/optionsReset.php +++ b/modules/base/optionsReset.php @@ -16,7 +16,7 @@ // $Id$ // -require_once(OWA_BASE_DIR.'/owa_controller.php'); +require_once(OWA_BASE_DIR.'/owa_adminController.php'); /** * Options Reset Controller @@ -30,10 +30,10 @@ * @since owa 1.0.0 */ -class owa_optionsResetController extends owa_controller { +class owa_optionsResetController extends owa_adminController { function owa_optionsResetController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'admin'; return; diff --git a/modules/base/optionsUpdate.php b/modules/base/optionsUpdate.php index 3844072d4..ff3f0a6ce 100644 --- a/modules/base/optionsUpdate.php +++ b/modules/base/optionsUpdate.php @@ -16,7 +16,7 @@ // $Id$ // -require_once(OWA_BASE_DIR.'/owa_controller.php'); +require_once(OWA_BASE_DIR.'/owa_adminController.php'); /** * Options Update Controller @@ -30,10 +30,10 @@ * @since owa 1.0.0 */ -class owa_optionsUpdateController extends owa_controller { +class owa_optionsUpdateController extends owa_adminController { function owa_optionsUpdateController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'admin'; return; diff --git a/modules/base/passwordResetRequest.php b/modules/base/passwordResetRequest.php index f6aedc450..e2c8697a2 100644 --- a/modules/base/passwordResetRequest.php +++ b/modules/base/passwordResetRequest.php @@ -17,7 +17,7 @@ // require_once(OWA_BASE_DIR.'/owa_view.php'); -require_once(OWA_BASE_DIR.'/owa_controller.php'); +require_once(OWA_BASE_DIR.'/owa_adminController.php'); /** * Password Reset Request View @@ -64,10 +64,10 @@ function construct($data) { * @since owa 1.0.0 */ -class owa_passwordResetRequestController extends owa_controller { +class owa_passwordResetRequestController extends owa_adminController { function owa_passwordResetRequestController($params) { - $this->owa_controller($params); + $this->owa_adminController($params); $this->priviledge_level = 'guest'; return; diff --git a/modules/base/reportDashboard.php b/modules/base/reportDashboard.php index 63f3ea283..8cdfd6805 100644 --- a/modules/base/reportDashboard.php +++ b/modules/base/reportDashboard.php @@ -85,14 +85,12 @@ function action() { )); - $data['latest_visits'] = $api->getMetric('base.latestVisits', array( - - 'constraints' => array('site_id' => $this->params['site_id']), - 'limit' => 15, - 'orderby' => array('session.timestamp'), - 'order' => 'DESC' - - )); + // Latest Visits + $lv = $api->metricFactory('base.latestVisits'); + $lv->setConstraint('site_id', $this->params['site_id']); + $lv->setLimit(15); + $lv->setOrder(OWA_SQL_DESCENDING); + $data['latest_visits'] = $lv->generate(); $data['top_pages_data'] = $api->getMetric('base.topPages', array( diff --git a/modules/base/templates/report_dashboard.tpl b/modules/base/templates/report_dashboard.tpl index b6b67d8aa..4a0bec64f 100644 --- a/modules/base/templates/report_dashboard.tpl +++ b/modules/base/templates/report_dashboard.tpl @@ -19,7 +19,8 @@ - + + getWidget('base.dashboardTrendWidget', 'graph', array('height' => 300, 'width' => 900));?> @@ -60,7 +61,7 @@
- Top Referering Web Pages + Top Referring Web Pages
diff --git a/modules/base/templates/report_visit.tpl b/modules/base/templates/report_visit.tpl index cc566f20a..fe84e3dc1 100644 --- a/modules/base/templates/report_visit.tpl +++ b/modules/base/templates/report_visit.tpl @@ -18,10 +18,10 @@ - :: + :: - ()
- + ()
+ diff --git a/modules/base/templates/widget.tpl b/modules/base/templates/widget.tpl new file mode 100644 index 000000000..8887c59a4 --- /dev/null +++ b/modules/base/templates/widget.tpl @@ -0,0 +1,16 @@ +
+ +
+ +ofc($params['width'], $params['height'], $this->makeAbsoluteLink(array('do' => $widget, 'period' => 'last_thirty_days', 'site_id' => $params['site_id'], 'format' => $format), false , $this->config['action_url'])); ?> + +
+ +
+
+ +
+ + \ No newline at end of file diff --git a/modules/base/templates/wrapper_mediawiki.tpl b/modules/base/templates/wrapper_mediawiki.tpl index bb25583ce..2326f4f5c 100644 --- a/modules/base/templates/wrapper_mediawiki.tpl +++ b/modules/base/templates/wrapper_mediawiki.tpl @@ -8,10 +8,10 @@ - + setTemplate('msgs.tpl'));?> - + \ No newline at end of file diff --git a/modules/base/visitorTypesWidget.php b/modules/base/visitorTypesWidget.php new file mode 100644 index 000000000..ba7f66eac --- /dev/null +++ b/modules/base/visitorTypesWidget.php @@ -0,0 +1,116 @@ + + * @copyright Copyright © 2006 Peter Adams + * @license http://www.gnu.org/copyleft/gpl.html GPL v2.0 + * @category owa + * @package owa + * @version $Revision$ + * @since owa 1.0.0 + */ + +class owa_visitorTypesWidgetController extends owa_controller { + + function owa_visitorTypesWidgetController($params) { + + + return owa_visitorTypesWidgetController::__construct($params); + } + + function __construct($params) { + + return parent::__construct($params); + } + + + function action() { + + $data = array(); + + // count from feeds + $f = owa_coreAPI::metricFactory('base.visitsFromFeedsCount'); + $f->setConstraint('site_id', $this->params['site_id']); + $f->setPeriod($this->params['period']); + $data['values']['feeds'] = $f->generate(); + $data['labels']['feeds'] = 'Feeds'; + + // count from search engines + $se = owa_coreAPI::metricFacory('base.visitsFromSearchEnginesCount'); + $se->setConstraint('site_id', $this->params['site_id']); + $se->setPeriod($this->params['period']); + $data['values'][] = $se->generate(); + $data['labels'][] = 'Search Engines'; + + // count from refering web sites + $s = owa_coreAPI::metricFactory('base.visitsFromSitesCount'); + $s->setConstraint('site_id', $this->params['site_id']); + $s->setPeriod($this->params['period']); + $data['values'][] = $se->generate(); + $data['labels'][] = 'Web Sites'; + + // count from refering web sites + $d = owa_coreAPI::metricFactory('base.visitsFromDirectNavCount'); + $d->setConstraint('site_id', $this->params['site_id']); + $d->setPeriod($this->params['period']); + $data['values'][] = $se->generate(); + $data['labels'][] = 'Direct Navigation'; + + // title + $data['title'] = 'Visitor Types'; + + // setup proper view + if (array_key_exists('format', $this->params)): + $format = $this->params['format']; + else: + $format = 'graph'; + endif; + + switch ($format) { + + case 'graph': + + $data['view'] = 'base.pieFlashChart'; + break; + + case 'table': + $data['column_labels'] = array(); + $data['data'] = ''; + $data['view'] = 'base.genericTable'; + break; + + } + + return $data; + + } + + +} + + + +?> \ No newline at end of file diff --git a/modules/base/widget.php b/modules/base/widget.php new file mode 100644 index 000000000..e896b683d --- /dev/null +++ b/modules/base/widget.php @@ -0,0 +1,110 @@ +owa_controller($params); + $this->priviledge_level = 'viewer'; + + } + + function action() { + + $data = array(); + $data['params'] = $this->params; + + // Load the core API + $api = &owa_coreAPI::singleton($this->params); + + $data['widget'] = $this->params['widget']; + $data['format'] = $this->params['format']; + $data['width'] = $this->params['width']; + $data['height'] = $this->params['height']; + + // flag used to pick the right wrapper template + if (array_key_exists('is_external', $this->params)): + $data['is_external'] = $this->params['is_external']; + endif; + $data['view'] = 'base.widget'; + $data['view_method'] = 'delegate'; + + return $data; + } +} + + + + +/** + * Widget View + * + * @author Peter Adams + * @copyright Copyright © 2006 Peter Adams + * @license http://www.gnu.org/copyleft/gpl.html GPL v2.0 + * @category owa + * @package owa + * @version $Revision$ + * @since owa 1.0.0 + */ + +class owa_widgetView extends owa_view { + + function owa_widgetView() { + + $this->owa_view(); + + return; + } + + function construct($data) { + + // load template + + if ($data['is_external'] == true): + $this->t->set_template('wrapper_widget.tpl'); + else: + $this->t->set_template('wrapper_blank.tpl'); + endif; + + if (!array_key_exists('width', $data)): + $data['width'] = 300; + endif; + + if (!array_key_exists('width', $data)): + $data['height'] = 250; + endif; + + $this->body->set_template('widget.tpl'); + $this->body->set('format', $data['format']); + $this->body->set('widget', $data['widget']); + $this->body->set('params', $data['params']); + return; + } + + +} + + +?> \ No newline at end of file diff --git a/owa_adminController.php b/owa_adminController.php index 3a05964e7..32f41b628 100644 --- a/owa_adminController.php +++ b/owa_adminController.php @@ -45,12 +45,15 @@ class owa_adminController extends owa_controller { */ function owa_adminController($params) { - $this->owa_controller($params); - - return; + return parent::__construct($params); } + function __construct($params) { + + return parent::__construct($params); + } + } diff --git a/owa_auth.php b/owa_auth.php index 709880aa3..1a5c4a6d5 100644 --- a/owa_auth.php +++ b/owa_auth.php @@ -204,19 +204,22 @@ function authenticateUser($necessary_role = '') { * * @return object */ - function &get_instance($auth_module = '') { + function &get_instance($plugin = '') { - if (empty($auth_module)): + static $auth_modules; + $auth_mdules = array(); + + if (empty($auth_modules['plugin'])): $c = &owa_coreAPI::configSingleton(); - $auth_module = $c->get('base', 'authentication'); + $plugin = $c->get('base', 'authentication'); endif; // this needs to not be a singleton - $auth = &owa_lib::singleton(OWA_PLUGIN_DIR.'auth'.DIRECTORY_SEPARATOR, 'owa_auth_', $auth_module); + $auth_modules[$plugin] = &owa_lib::singleton(OWA_PLUGIN_DIR.'auth'.DIRECTORY_SEPARATOR, 'owa_auth_', $plugin); - return $auth; + return $auth_modules[$plugin]; } /** diff --git a/owa_controller.php b/owa_controller.php index a35f94df4..cf6810c80 100644 --- a/owa_controller.php +++ b/owa_controller.php @@ -93,14 +93,19 @@ class owa_controller extends owa_base { */ function owa_controller($params) { + return owa_controller::__construct($params); + + } + + function __construct($params) { + $this->owa_base(); $this->params = $params; - // sets the auth module. requires a configuration object. $this->_setAuthModule(); return; - + } /** @@ -129,7 +134,8 @@ function doAction() { endif; //perfrom authentication - // TODO: make the auth module configurable by the controller + // TODO: create authSingleton() to hold an array of auth objects + $auth = &owa_auth::get_instance(); $data = $auth->authenticateUser($this->priviledge_level); diff --git a/owa_coreAPI.php b/owa_coreAPI.php index f3fa6db2a..e61a6affa 100644 --- a/owa_coreAPI.php +++ b/owa_coreAPI.php @@ -140,6 +140,27 @@ function &dbSingleton() { } + function authSingleton() { + + static $auth_modules; + $auth_mdules = array(); + + if (empty($auth_modules['plugin'])): + + $c = &owa_coreAPI::configSingleton(); + $plugin = $c->get('base', 'authentication'); + + endif; + + // this needs to not be a singleton + $auth_modules[$plugin] = &owa_lib::singleton(OWA_PLUGIN_DIR.'auth'.DIRECTORY_SEPARATOR, 'owa_auth_', $plugin); + + return $auth_modules[$plugin]; + + + return; + } + function &configSingleton($params = array()) { static $config; @@ -248,23 +269,7 @@ function _loadModules() { return; } - /** - * Produces Module Classes (module.php) - * - * @return Object module class object - */ - function moduleClassFactory($module) { - - if (!class_exists('owa_module')): - require_once(OWA_BASE_CLASSES_DIR.'owa_module.php'); - endif; - - require_once(OWA_BASE_DIR.'/modules/'.$module.'/module.php'); - - return owa_lib::factory(OWA_BASE_CLASSES_DIR.$module, 'owa_', $module.'Module'); - } - function _loadEntities() { foreach ($this->modules as $k => $module) { @@ -278,57 +283,7 @@ function _loadEntities() { return; } - - - function displayImage($data) { - - header('Content-type: image/gif'); - header('P3P: CP="'.$this->config['p3p_policy'].'"'); - header('Expires: Sat, 22 Apr 1978 02:19:00 GMT'); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - header('Cache-Control: no-store, no-cache, must-revalidate'); - header('Cache-Control: post-check=0, pre-check=0', false); - header('Pragma: no-cache'); - - print owa_coreAPI::displayView($data); - - return; - - } - - - /** - * Displays a View without user authentication. Takes array of data as input - * - * @param array $data - * @param string $viewfile a specific view file to use - * @return string - * - */ - function displayView($data, $viewfile = '') { - - if (empty($viewfile)): - $viewfile = $data['view']; - endif; - - $view = owa_coreAPI::moduleFactory($viewfile, 'View', $params); - - return $view->assembleView($data); - - } - - function displaySubView($data, $viewfile = '') { - - if (empty($viewfile)): - $viewfile = $data['view']; - endif; - - $view = owa_coreAPI::subViewFactory($viewfile); - - return $view->assembleView($data); - } - function moduleRequireOnce($module, $class_dir, $file) { if (!empty($class_dir)): @@ -340,10 +295,10 @@ function moduleRequireOnce($module, $class_dir, $file) { return require_once(OWA_BASE_DIR.'/modules/'.$module.DIRECTORY_SEPARATOR.$class_dir.$file.'.php'); } - function moduleFactory($modulefile, $class_suffix = null, $params = '') { + function moduleFactory($modulefile, $class_suffix = null, $params = '', $class_ns = 'owa_') { list($module, $file) = split("\.", $modulefile); - $class = 'owa_'.$file.$class_suffix; + $class = $class_ns.$file.$class_suffix; // Require class file if class does not already exist if(!class_exists($class)): @@ -359,9 +314,9 @@ function moduleFactory($modulefile, $class_suffix = null, $params = '') { return $obj; } - function moduleGenericFactory($module, $sub_directory, $file, $class_suffix = null, $params = '') { + function moduleGenericFactory($module, $sub_directory, $file, $class_suffix = null, $params = '', $class_ns = 'owa_') { - $class = 'owa_'.$file.$class_suffix; + $class = $class_ns.$file.$class_suffix; // Require class file if class does not already exist if(!class_exists($class)): @@ -373,12 +328,30 @@ function moduleGenericFactory($module, $sub_directory, $file, $class_suffix = nu return $obj; } - function updateFactory($module, $filename) { + /** + * Produces Module Classes (module.php) + * + * @return Object module class object + */ + function moduleClassFactory($module) { + + if (!class_exists('owa_module')): + require_once(OWA_BASE_CLASSES_DIR.'owa_module.php'); + endif; + + require_once(OWA_BASE_DIR.'/modules/'.$module.'/module.php'); + + return owa_lib::factory(OWA_BASE_CLASSES_DIR.$module, 'owa_', $module.'Module'); + + } + + + function updateFactory($module, $filename, $class_ns = 'owa_') { require_once(OWA_BASE_CLASS_DIR.'update.php'); //$obj = owa_coreAPI::moduleGenericFactory($module, 'updates', $filename, '_update'); - $class = 'owa_'.$module.'_'.$filename.'_update'; + $class = $class_ns.$module.'_'.$filename.'_update'; // Require class file if class does not already exist if(!class_exists($class)): @@ -403,9 +376,9 @@ function subViewFactory($subview, $params = array()) { return $subview; } - function &supportClassFactory($module, $class, $params = array()) { + function &supportClassFactory($module, $class, $params = array(),$class_ns = 'owa_') { - $obj = &owa_lib::factory(OWA_BASE_DIR.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.'classes'.DIRECTORY_SEPARATOR, 'owa_', $class, $params); + $obj = &owa_lib::factory(OWA_BASE_DIR.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.'classes'.DIRECTORY_SEPARATOR, $class_ns, $class, $params); $obj->module = $module; return $obj; @@ -447,28 +420,7 @@ function rawEntityFactory($entity_name) { return owa_coreAPI::moduleSpecificFactory($entity_name, 'entities', '', '', false); } - - /** - * Convienence method for generating metrics - * - * @param unknown_type $entity_name - * @return unknown - */ - function getMetric($metric_name, $params) { - - if (!class_exists('owa_metric')): - - require_once(OWA_BASE_CLASSES_DIR.'owa_metric.php'); - - endif; - - $m = owa_coreAPI::moduleSpecificFactory($metric_name, 'metrics', '', $this->params, false); - - $m->applyOverrides($params); - return $m->generate(); - } - /** * Factory for generating graphs * @@ -490,10 +442,10 @@ function graphFactory($graph_name, $params = array()) { * @param array $params * @return unknown */ - function moduleSpecificFactory($modulefile, $class_dir, $class_suffix = null, $params = '', $add_module_name = true) { + function moduleSpecificFactory($modulefile, $class_dir, $class_suffix = null, $params = '', $add_module_name = true, $class_ns = 'owa_') { list($module, $file) = split("\.", $modulefile); - $class = 'owa_'.$file.$class_suffix; + $class = $class_ns.$file.$class_suffix; // Require class file if class does not already exist if(!class_exists($class)): @@ -511,6 +463,57 @@ function moduleSpecificFactory($modulefile, $class_dir, $class_suffix = null, $p } + /** + * Convienence method for generating metrics + * + * @param unknown_type $entity_name + * @return unknown + */ + function getMetric($metric_name, $params) { + + $m = owa_coreAPI::metricFactory($metric_name); + + if (array_key_exists('constraints', $params)): + + foreach ($params['constraints'] as $k => $v) { + + if(is_array($v)): + $m->setConstraint($k, $v[1], $v[0]); + else: + $m->setConstraint($k, $value); + endif; + + } + + unset($params['constraints']); + + endif; + + $m->applyOverrides($params); + + return $m->generate(); + } + + /** + * Convienence method for generating metrics + * + * @param unknown_type $entity_name + * @return unknown + */ + function metricFactory($metric_name) { + + if (!class_exists('owa_metric')): + + require_once(OWA_BASE_CLASSES_DIR.'owa_metric.php'); + + endif; + + return owa_coreAPI::moduleSpecificFactory($metric_name, 'metrics', '', $this->params, false); + + } + + + /** * Returns a consolidated list of admin/options panels from all active modules @@ -588,51 +591,7 @@ function getNavSort($a, $b) { return strnatcmp($a['order'], $b['order']); } - /** - * Strip a URL of certain GET params - * - * @return string - */ - function stripDocumentUrl($url) { - if ($this->config['clean_query_string'] == true): - - if (!empty($this->config['query_string_filters'])): - $filters = str_replace(' ', '', $this->config['query_string_filters']); - $filters = explode(',', $filters); - else: - $filters = array(); - endif; - - // OWA specific params to filter - array_push($filters, $this->config['source_param']); - array_push($filters, $this->config['ns'].$this->config['feed_subscription_id']); - - //print_r($filters); - - foreach ($filters as $filter => $value) { - - $url = preg_replace( - '#\?' . - $value . - '=.*$|&' . - $value . - '=.*$|' . - $value . - '=.*&#msiU', - '', - $url - ); - - } - - endif; - //print $url; - - return $url; - - } - function getActiveModules() { $config = $this->c->config->get('settings'); @@ -772,6 +731,109 @@ function logEvent($event_type, $caller_params = '') { } + function displayImage($data) { + + header('Content-type: image/gif'); + header('P3P: CP="'.$this->config['p3p_policy'].'"'); + header('Expires: Sat, 22 Apr 1978 02:19:00 GMT'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', false); + header('Pragma: no-cache'); + + print owa_coreAPI::displayView($data); + + return; + + } + + + /** + * Displays a View without user authentication. Takes array of data as input + * + * @param array $data + * @param string $viewfile a specific view file to use + * @return string + * + */ + function displayView($data, $viewfile = '') { + + if (empty($viewfile)): + $viewfile = $data['view']; + endif; + + $view = owa_coreAPI::moduleFactory($viewfile, 'View', $params); + + return $view->assembleView($data); + + } + + function displaySubView($data, $viewfile = '') { + + if (empty($viewfile)): + $viewfile = $data['view']; + endif; + + $view = owa_coreAPI::subViewFactory($viewfile); + + return $view->assembleView($data); + + } + + /** + * Strip a URL of certain GET params + * + * @return string + */ + function stripDocumentUrl($url) { + + if ($this->config['clean_query_string'] == true): + + if (!empty($this->config['query_string_filters'])): + $filters = str_replace(' ', '', $this->config['query_string_filters']); + $filters = explode(',', $filters); + else: + $filters = array(); + endif; + + // OWA specific params to filter + array_push($filters, $this->config['source_param']); + array_push($filters, $this->config['ns'].$this->config['feed_subscription_id']); + + //print_r($filters); + + foreach ($filters as $filter => $value) { + + $url = preg_replace( + '#\?' . + $value . + '=.*$|&' . + $value . + '=.*$|' . + $value . + '=.*&#msiU', + '', + $url + ); + + } + + endif; + //print $url; + + return $url; + + } + + function getRequestParam($name) { + + $r = owa_coreAPI::requestContainerSingleton(); + return $r->getParam($name); + + } + + + } ?> \ No newline at end of file diff --git a/owa_db.php b/owa_db.php index d690e5dad..8a07f5707 100644 --- a/owa_db.php +++ b/owa_db.php @@ -108,6 +108,20 @@ class owa_db extends owa_base { */ var $_total_time; + /** + * Storage Array for components of sql queries + * + * @var array + */ + var $_sqlParams = array(); + + /** + * Sql Statement + * + * @var string + */ + var $_sql_statement; + /** * Constructor * @@ -205,6 +219,677 @@ function _timerEnd() { return; } + + function selectColumn($name, $as = '') { + + $this->_sqlParams['select_values'][] = array('name' => $name, 'as' => $as); + + return; + } + + function where($name, $value, $operator = '') { + + if (empty($operator)): + $operator = '='; + endif; + + if (!empty($value)): + + // hack for intentional empty value + if($value == ' '): + $value = ''; + endif; + + $this->_sqlParams['where'][$name] = array('name' => $name, 'value' => $value, 'operator' => $operator); + endif; + + return; + } + + function multiWhere($where_array = array()) { + + if (!empty($where_array)): + + foreach ($where_array as $k => $v) { + if (!empty($v)): + + if (empty($v['operator'])): + $v['operator'] = '='; + endif; + + $this->_sqlParams['where'][$k] = array('name' => $k, 'value' => $v['value'], 'operator' => $v['operator']); + endif; + } + + endif; + } + + function groupBy($col) { + + $this->_sqlParams['groupby'][] = $col; + return; + } + + function orderBy($col) { + + $this->_sqlParams['orderby'][] = $col; + return; + } + + function order($flag) { + + $this->_sqlParams['order'] = $flag; + return; + } + + function limit($value) { + + $this->_sqlParams['limit'] = $value; + return; + } + + function offset($value) { + + $this->_sqlParams['offset'] = $value; + return; + } + + function set($name, $value) { + + $this->_sqlParams['set_values'][] = array('name' => $name, 'value' => $value); + return; + } + + function executeQuery() { + + switch($this->_sqlParams['query_type']) { + + case 'insert': + + return $this->_insertQuery(); + + case 'select': + + return $this->_selectQuery(); + + case 'update': + + return $this->_updateQuery(); + + case 'delete': + + return $this->_deleteQuery(); + + default: + + return $this->_query(); + } + } + + function getAllRows() { + + return $this->_selectQuery(); + } + + function getOneRow() { + + $ret = $this->_selectQuery(); + return $ret[0]; + } + + function _setSql($sql) { + $this->_sql_statement = $sql; + } + + function selectFrom($name, $as = '') { + + //if (empty($as)): + // $as = $this->removeNs($name); + //endif; + + $this->_sqlParams['query_type'] = 'select'; + $this->_sqlParams['from'][$name] = array('name' => $name, 'as' => $as); + return; + } + + function insertInto($table) { + + $this->_sqlParams['query_type'] = 'insert'; + $this->_sqlParams['table'] = $table; + return; + } + + function deleteFrom($table) { + + $this->_sqlParams['query_type'] = 'delete'; + $this->_sqlParams['table'] = $table; + return; + } + + function updateTable($table) { + + $this->_sqlParams['query_type'] = 'update'; + $this->_sqlParams['table'] = $table; + return; + } + + function _insertQuery() { + + $params = $this->_fetchSqlParams('set_values'); + + $count = count($params); + + $i = 0; + + $sql_cols = ''; + $sql_values = ''; + + foreach ($params as $k => $v) { + + $sql_cols .= $v['name']; + $sql_values .= "'".$this->prepare($v['value'])."'"; + + $i++; + + // Add commas + if ($i < $count): + + $sql_cols .= ", "; + $sql_values .= ", "; + + endif; + } + + $this->_setSql(sprintf(OWA_SQL_INSERT_ROW, $this->_sqlParams['table'], $sql_cols, $sql_values)); + + return $this->_query(); + + } + + function _selectQuery() { + + $cols = ''; + $i = 0; + $params = $this->_fetchSqlParams('select_values'); + $count = count($params); + + foreach ($params as $k => $v) { + + $cols .= $v['name']; + + // Add as + if (!empty($v['as'])): + + $cols .= ' as '.$v['as']; + + endif; + + // Add commas + if ($i < $count - 1): + + $cols .= ', '; + + endif; + + $i++; + + } + + $this->_setSql(sprintf("SELECT %s FROM %s %s %s %s %s %s", + $cols, + $this->_makeFromClause(), + $this->_makeWhereClause(), + $this->_makeGroupByClause(), + $this->_makeOrderByClause(), + $this->_makeLimitClause(), + $this->_makeOffsetClause() + )); + return $this->_query(); + + } + + + function _updateQuery() { + + $params = $this->_fetchSqlParams('set_values'); + + $count = count($params); + + $i = 0; + + $sql_cols = ''; + $sql_values = ''; + $set = ''; + + foreach ($params as $k => $v) { + + //$sql_cols = $sql_cols.$key; + //$sql_values = $sql_values."'".$this->prepare($value)."'"; + + // Add commas + if ($i != 0): + + $set .= ', '; + + endif; + + $set .= $v['name'] .' = \'' . $this->prepare($v['value']) . '\''; + + $i++; + } + + $this->_setSql(sprintf(OWA_SQL_UPDATE_ROW, $this->_sqlParams['table'], $set, $this->_makeWhereClause())); + + return $this->_query(); + + + + } + + function _deleteQuery() { + + $this->_setSql(sprintf(OWA_SQL_DELETE_ROW, $this->_sqlParams['table'], $this->_makeWhereClause())); + + return $this->_query(); + } + + function rawQuery($sql) { + + $this->_setSql($sql); + + return $this->_query(); + } + + function _fetchSqlParams($sql_params_name) { + + if (array_key_exists($sql_params_name, $this->_sqlParams)): + if (!empty($this->_sqlParams[$sql_params_name])): + return $this->_sqlParams[$sql_params_name]; + else: + return false; + endif; + else: + return false; + endif; + } + + function _makeWhereClause() { + + $params = $this->_fetchSqlParams('where'); + + if (!empty($params)): + + $count = count($params); + + $i = 0; + + $where = 'WHERE '; + + foreach ($params as $k => $v) { + //print_r($v); + switch (strtolower($v['operator'])) { + case 'between': + + $where .= sprintf("%s BETWEEN '%s' AND '%s'", $v['name'], $v['value']['start'], $v['value']['end']); + break; + default: + $where .= sprintf("%s %s '%s'",$v['name'], $v['operator'], $v['value']); + break; + } + + + + if ($i < $count - 1): + + $where .= " AND "; + + endif; + + $i++; + + + } + + return $where; + + else: + + return; + + endif; + + } + + function join($type, $table, $as, $foreign_key, $primary_key = '') { + + if (empty($primary_key)): + $primary_key = $table.'.id'; + endif; + + + + $this->_sqlParams['joins'][] = array('type' => $type, + 'table' => $table, + 'as' => $as, + 'foreign_key' => $foreign_key, + 'primary_key' => $primary_key); + + } + + function _makeJoinClause() { + + $params = $this->_fetchSqlParams('joins'); + + if (!empty($params)): + + $join_clause = ''; + + foreach ($params as $k => $v) { + + if (!empty($v['as'])): + $join_clause .= sprintf(" %s %s AS %s ON %s = %s", $v['type'], + $v['table'], + $v['as'], + $v['foreign_key'], + $v['primary_key']); + else: + $join_clause .= sprintf(" %s %s ON %s = %s", $v['type'], + $v['table'], $v['foreign_key'], + $v['primary_key']); + endif; + + + + } + + return $join_clause; + + else: + return; + endif; + + } + + function _makeFromClause() { + + $from = ''; + $i = 0; + $params = $this->_fetchSqlParams('from'); + + if(!empty($params)): + + $count = count($params); + + foreach ($params as $k => $v) { + + $from .= $v['name']; + + // Add as + if (!empty($v['as'])): + + $from .= ' as '.$v['as']; + + endif; + + // Add commas + if ($i < $count - 1): + + $from .= ', '; + + endif; + + $i++; + + } + + $from .= $this->_makeJoinClause(); + + return $from; + else: + $this->e->debug("No SQL FROM params set."); + return false; + endif; + + } + + function _makeGroupByClause() { + + $params = $this->_fetchSqlParams('groupby'); + + if (!empty($params)): + + return sprintf("GROUP BY %s", $this->_makeDelimitedValueList($params)); + + else: + return; + endif; + + + } + + function _makeOrderByClause() { + + $params = $this->_fetchSqlParams('orderby'); + + if (!empty($params)): + + $order = $this->_fetchSqlParams('order'); + + if(empty($order)): + $order = 'DESC'; + endif; + + return sprintf("ORDER BY %s %s", $this->_makeDelimitedValueList($params), $order); + + else: + return; + endif; + + + } + + function _makeLimitClause() { + + $param = $this->_fetchSqlParams('limit'); + + if(!empty($param)): + return sprintf("LIMIT %d", $param); + else: + return; + endif; + + } + + function _makeOffsetClause() { + + $param = $this->_fetchSqlParams('offset'); + + if(!empty($param)): + return sprintf("OFFSET %d", $param); + else: + return; + endif; + + } + + function _makeDelimitedValueList($values, $delimiter = ', ') { + + $items = ''; + $i = 0; + $count = count($values); + + if (is_array($values)): + + foreach ($values as $k) { + + $items .= $k; + + // Add commas + if ($i < $count - 1): + + $items .= $delimiter; + + endif; + + $i++; + + } + + else: + + $items = $values; + + endif; + + return $items; + + } + + function _query() { + + switch($this->_sqlParams['query_type']) { + + case 'insert': + + $ret = $this->query($this->_sql_statement); + $this->_sql_statement = ''; + $this->_sqlParams = array(); + return $ret; + break; + case 'select': + + $ret = $this->get_results($this->_sql_statement); + + + $results = $this->_formatResults($ret); + $count = count($results); + + $this->_sql_statement = ''; + $this->_sqlParams = array(); + + //if ($count > 1): + return $results; + //else: + // return $results[0]; + //endif; + + break; + + case 'update': + + $ret = $this->query($this->_sql_statement); + $this->_sql_statement = ''; + $this->_sqlParams = array(); + return $ret; + case 'delete': + + $ret = $this->query($this->_sql_statement); + $this->_sql_statement = ''; + $this->_sqlParams = array(); + return $ret; + } + + } + + function removeNs($string, $ns = '') { + + if (empty($ns)): + $ns = $this->config['ns']; + endif; + + $ns_len = strlen($ns); + return substr($string, $ns_len); + + } + + function setFormat($value) { + + $this->_sqlParams['result_format'] = $value; + return; + } + + function _formatResults($results) { + + switch ($this->_sqlParams['result_format']) { + + case "single_array": + return $results[0]; + break; + case "single_row": + return $results[0]; + break; + case "inverted_array": + return owa_lib::deconstruct_assoc($results); + break; + default: + return $results; + break; + } + + } + + /** + * Drops a table + * + */ + function dropTable($table_name) { + + return $this->query(sprintf(OWA_SQL_DROP_TABLE, $table_name)); + + } + + /** + * Change table type + * + */ + function alterTableType($table_name, $engine) { + + return $this->query(sprintf(OWA_SQL_ALTER_TABLE_TYPE, $table_name, $engine)); + + } + + + /** + * Rename a table + * + */ + function renameTable($table_name, $new_table_name) { + + return $this->query(sprintf(OWA_SQL_RENAME_TABLE, $table_name, $new_table_name)); + + } + + + /** + * Adds new column to table + * + */ + function addColumn($table_name, $column_name, $column_definition) { + + return $this->query(sprintf(OWA_SQL_ADD_COLUMN, $table_name. $column_name, $column_definition)); + + } + + /** + * Drops a column from a table + * + */ + function dropColumn($table_name, $column_name) { + + return $this->query(sprintf(OWA_SQL_DROP_COLUMN, $table_name. $column_name)); + + } + + /** + * Changes the definition of a column + * + */ + function modifyColumn($table_name, $column_name, $column_definition) { + + return $this->query(sprintf(OWA_SQL_MODIFY_COLUMN, $table_name. $column_name, $column_definition)); + + } + } ?> \ No newline at end of file diff --git a/owa_entity.php b/owa_entity.php index 88696c5a1..75f7dd5ed 100644 --- a/owa_entity.php +++ b/owa_entity.php @@ -62,11 +62,39 @@ function _getProperties() { return $properties; } - function getColumns() { + function getColumns($return_as_string = false, $as_namespace = '', $table_namespace = false) { $all_cols = get_object_vars($this); + $table = $this->getTableName(); + $new_cols = array(); - return array_keys($all_cols); + if (!empty($table_namespace)): + $ns = $table.'.'; + endif; + + foreach ($all_cols as $k => $v) { + + if (!empty($as_namespace)): + $as = ' AS '.$as_namespace.$k; + endif; + + $new_cols[] = $ns.$k.$as; + } + + // add implode as string here + + if ($return_as_string == true): + $new_cols = implode(', ', $new_cols); + endif; + + //print_r($new_cols); + return $new_cols; + + } + + function getColumnsSql($as_namespace = '', $table_namespace = true) { + + return $this->getColumns(true, $as_namespace, $table_namespace); } @@ -83,6 +111,7 @@ function setProperties($array) { if (!empty($array[$v])): $this->$v->value = $array[$v]; + //print $this->getTableName().$v.':'.$this->$v->value; endif; } @@ -139,7 +168,7 @@ function create() { $all_cols = $this->getColumns(); - $cols = array(); + $db->insertInto(get_class($this)); // Control loop foreach ($all_cols as $k => $v){ @@ -148,16 +177,15 @@ function create() { if ($this->$v->auto_increment == true): ; else: - $cols[$v] = $this->$v->value; + $db->set($v, $this->get($v)); endif; } // Persist object - $status = $db->save($cols, get_class($this)); + $status = $db->executeQuery(); // Add to Cache - if ($status == true): if ($config->get('base', 'cache_objects') == true): $cache->set(get_class($this), 'id'.$this->id->value, $this); @@ -178,16 +206,32 @@ function update($where = '') { $config = owa_coreAPI::configSingleton(); $cache = owa_coreAPI::cacheSingleton(); + $db->updateTable(get_class($this)); + + // get column list + $all_cols = $this->getColumns(); + + // Control loop + foreach ($all_cols as $k => $v){ + + // drop column is it is marked as auto-incement as DB will take care of that. + if (!empty($this->$v->value)): + $db->set($v, $this->get($v)); + endif; + + } + if(empty($where)): - $constraint = array('id' => $this->id->value); + $id = $this->get('id'); + $db->where('id', $id); + else: - $constraint = array($where => $this->$where->value); + $db->where($where, $this->get($where)); endif; - // Persist object - $status = $db->update($this->_getProperties(), $constraint, get_class($this)); - + $status = $db->executeQuery(); + // Add to Cache if ($status == true): if ($config->get('base', 'cache_objects') == true): @@ -212,17 +256,25 @@ function partialUpdate($named_properties, $where) { $config = owa_coreAPI::configSingleton(); $cache = owa_coreAPI::cacheSingleton(); - $properties = array(); + $db->updateTable(get_class($this)); - foreach ($named_properties as $n) { + foreach ($named_properties as $v) { - $properties[$n] = $this->$n->value; + if (!empty($this->$v->value)): + $db->set($v, $this->get($v)); + endif; } - + if(empty($where)): + $db->where('id', $this->get('id')); + else: + $db->where($where, $this->get($where)); + endif; + // Persist object - $status = $db->update($properties, $where, get_class($this)); + $status = $db->executeQuery(); + // Add to Cache if ($status == true): @@ -240,18 +292,21 @@ function partialUpdate($named_properties, $where) { * Delete Object * */ - function delete($id, $col = '') { + function delete($value = '', $col = 'id') { $db = owa_coreAPI::dbSingleton(); $config = owa_coreAPI::configSingleton(); $cache = owa_coreAPI::cacheSingleton(); - - if (empty($col)): - $col = 'id'; + + $db->deleteFrom(get_class($this)); + + if (empty($value)): + $value = $this->get('id'); endif; - // Persist object - $status = $db->delete($id, $col, get_class($this)); + $db->where($col, $value); + + $status = $db->executeQuery(); // Add to Cache if ($status == true): @@ -294,10 +349,11 @@ function getByColumn($col, $value) { $this->setProperties($cache_obj_properties); else: - - $constraint = array($col => $value); - - $properties = $db->select($this->_getProperties(), $constraint, get_class($this)); + + $db->selectFrom(get_class($this)); + $db->selectColumn('*'); + $db->where($col, $value); + $properties = $db->getOneRow(); if (!empty($properties)): @@ -305,14 +361,18 @@ function getByColumn($col, $value) { if ($config->get('base', 'cache_objects') == true): $cache->set(get_class($this), 'id'.$this->id->value, $this); - endif; + endif; + endif; + endif; return; } - + function getTableName() { + return get_class($this); + } } diff --git a/owa_lib.php b/owa_lib.php index cc5d1a5aa..1e2871bf0 100644 --- a/owa_lib.php +++ b/owa_lib.php @@ -776,7 +776,35 @@ function listDir($start_dir='.') { } + function makeDateArray($result, $format) { + + $timestamps = array(); + + foreach ($result as $row) { + + $timestamps[]= mktime(0,0,0,$row['month'],$row['day'],$row['year']); + + } + + return owa_lib::makeDates($timestamps, $format); + } + function makeDates($timestamps, $format) { + + sort($timestamps); + + $new_dates = array(); + + foreach ($timestamps as $timestamp) { + + $new_dates[] = date($format, $timestamp); + + } + + return $new_dates; + + } + } diff --git a/owa_metric.php b/owa_metric.php index 9e8a10475..4c936b0c0 100644 --- a/owa_metric.php +++ b/owa_metric.php @@ -51,6 +51,8 @@ class owa_metric extends owa_base { * @var array */ var $params = array(); + + var $db; /** * Constructor @@ -58,11 +60,22 @@ class owa_metric extends owa_base { * @access public * @return owa_metric */ - function owa_metric() { + function owa_metric($params = '') { + return $this->__construct($params); + } + + function __construct($params = '') { + + if (!empty($params)): + $this->params = $params; + endif; + //print_r($this->params); // Setup time and query periods $this->time_now = owa_lib::time_now(); - + // create timeperiod constraints + $this->setTimePeriod($this->params['period']); + //print_r($this->params); return; } @@ -76,7 +89,15 @@ function applyOverrides($params = array()) { foreach ($params as $k => $v) { if (!empty($v)): - $this->params[$k] = $v; + if (is_array($v)): + if (!empty($this->params[$k])): + $this->params[$k] = array_merge($this->params[$k], $v); + endif; + else: + $this->params[$k] = $v; + endif; + + endif; } @@ -84,6 +105,17 @@ function applyOverrides($params = array()) { return; } + function makeTimePeriod($period = '') { + + if (!empty($period)): + $this->params['period'] = $period; + $this->setTimePeriod(); + endif; + + return $this->params['constraints']['timestamp']; + + } + function setTimePeriod() { switch ($this->params['period']) { @@ -93,7 +125,7 @@ function setTimePeriod() { $end = mktime(0, 0, 0, $this->time_now['month'], $this->time_now['day'] + 1, $this->time_now['year']); $start = $end - 3600*24; - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); break; @@ -126,21 +158,21 @@ function setTimePeriod() { case "this_week": - $this->params['constraints']['weekofyear'] = $this->time_now['weekofyear']; - $this->params['constraints']['year'] = $this->time_now['year']; + $this->params['constraints']['weekofyear'] = array('operator' => '=', 'value' => $this->time_now['weekofyear']); + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $this->time_now['year']); break; case "this_month": - $this->params['constraints']['month'] = $this->time_now['month']; - $this->params['constraints']['year'] = $this->time_now['year']; + $this->params['constraints']['month'] = array('operator' => '=', 'value' => $this->time_now['month']); + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $this->time_now['year']); break; case "this_year": - $this->params['constraints']['year'] = $this->time_now['year']; + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $this->time_now['year']); break; @@ -149,7 +181,8 @@ function setTimePeriod() { $end = mktime(0, 0, 0, $this->time_now['month'], $this->time_now['day'], $this->time_now['year']); $start = $end - 3600*24; - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -161,7 +194,8 @@ function setTimePeriod() { $start = mktime(23, 59, 59, $this->time_now['month'], $this->time_now['day'], $this->time_now['year']) - 3600*24*$daybound; - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -175,8 +209,10 @@ function setTimePeriod() { break; case "last_year": - - $this->params['constraints']['year'] = $this->time_now['year'] - 1; + + $bound = $this->time_now['year'] - 1; + + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $bound); break; @@ -184,23 +220,26 @@ function setTimePeriod() { $bound = mktime(12, 0, 0, $this->time_now['month'], $this->time_now['day'], $this->time_now['year']) - 3600*24*7; - $this->params['constraints']['day'] = date("d", $bound); - $this->params['constraints']['month'] = date("n", $bound); - $this->params['constraints']['year'] = date("Y", $bound); + $this->params['constraints']['day'] = array('operator' => '=', 'value' => date("d", $bound)); + $this->params['constraints']['month'] = array('operator' => '=', 'value' => date("n", $bound)); + $this->params['constraints']['year'] = array('operator' => '=', 'value' => date("Y", $bound)); break; case "same_week_last_year": - $this->params['constraints']['weekofyear'] = $this->time_now['weekofyear']; - $this->params['constraints']['year'] = $this->time_now['year'] - 1; + $this->params['constraints']['weekofyear'] = array('operator' => '=', 'value' => $this->time_now['weekofyear']); + + $bound = $this->time_now['year'] - 1; + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $bound); break; case "same_month_last_year": - $this->params['constraints']['month'] = $this->time_now['month']; - $this->params['constraints']['year'] = $this->time_now['year'] - 1; + $bound = $this->time_now['year'] - 1; + $this->params['constraints']['month'] = array('operator' => '=', 'value' => $this->time_now['month']); + $this->params['constraints']['year'] = array('operator' => '=', 'value' => $bound); break; @@ -225,7 +264,8 @@ function setTimePeriod() { //$start = $end - 3600*24*29; //$this->params['constraints']['timestamp'] = array('operator' => '>=', 'value' => $bound); - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -236,7 +276,8 @@ function setTimePeriod() { $start = $end - 3600*24; - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -246,7 +287,8 @@ function setTimePeriod() { $start = mktime(0, 0, 0, $this->params['month'], 0, $this->params['year']); - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -255,7 +297,8 @@ function setTimePeriod() { $end = mktime(0, 0, 0, 1, 1, $this->params['year'] + 1); $start = mktime(0, 0, 0, 1, 1, $this->params['year']); - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; @@ -264,13 +307,16 @@ function setTimePeriod() { $start = mktime(0, 0, 0, $this->params['month'], $this->params['day'], $this->params['year']); $end = mktime(0, 0, 0, $this->params['month2'], $this->params['day2'] + 1, $this->params['year2']); - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $start, 'end' => $end); + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); + break; case "time_range": - $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'start' => $this->params['start_time'], 'end' => $this->params['end_time']); + $start = $this->params['start_time']; + $end = $this->params['end_time']; + $this->params['constraints']['timestamp'] = array('operator' => 'BETWEEN', 'value' => array('start' => $start, 'end' => $end)); break; @@ -283,81 +329,57 @@ function setTimePeriod() { } - /** - * Add constraints into SQL where clause - * - * @param array $constraints - * @return string $where - * @access public - */ - function add_constraints($constraints) { - - if (!empty($constraints)): - //print_r($constraints); - $this->e->debug(' CONSTRAINT: '. print_r($constraints, true)); + function setConstraint($name, $value, $operator = '') { - $count = 0; - - foreach ($constraints as $key => $value) { - - if (!empty($value) || $value === 0 || $value === '0' || $value === false): - $count++; - endif; - } - - $i = 0; - - foreach ($constraints as $key => $value) { - - if (!empty($value) || $value === 0 || $value === '0' || $value === false): - $where .= $key . ' = ' . "'$value'"; - $i++; - if ($count != $i): - - $where .= " AND "; - - endif; - - endif; - - } - - if (!empty($where)): - - return $where = ' AND '.$where; - else: - return; - endif; - - else: - - return; - + if (empty($operator)): + $operator = '='; endif; + if (!empty($value)): + $this->params['constraints'][$name] = array('operator' => $operator, 'value' => $value, 'name' => $name); + endif; - + return; + } - /** - * Hook for using summary tables - * - * @param string $table_name - * @return unknown - */ - function setTable($table_name) { + function setLimit($value) { - if ($this->config['use_summary_tables']): - // Set summary table suffix - $table_name = $this->summaryFramework->getTable($table_name, $this->params['period']); + if (!empty($value)): + $this->params['limit'] = $value; endif; + } + + + function getConstraints() { + + return $this->params['constraints']; + } + + function setOffset($value) { - return sprintf("%s%s", - $this->config['ns'], - $table_name); - + if (!empty($value)): + $this->params['offset'] = $value; + endif; + } + + function setFormat($value) { + if (!empty($value)): + $this->params['result_format'] = $value; + endif; } + function setPeriod($value) { + if (!empty($value)): + $this->params['period'] = $value; + endif; + } + + function setOrder($value) { + if (!empty($value)): + $this->params['order'] = $value; + endif; + } /** * Retrieve Result data for a particular metric @@ -383,6 +405,12 @@ function get_metric($params) { return $data; } + function generate() { + + $this->makeTimePeriod(); + return $this->calculate(); + + } } ?> \ No newline at end of file diff --git a/owa_template.php b/owa_template.php index e21cafe22..078aed00f 100644 --- a/owa_template.php +++ b/owa_template.php @@ -116,7 +116,7 @@ function set_template($file = null) { // throw error else: - $this->e->error(sprintf('%s was not found in any template directory.', $file)); + $this->e->err(sprintf('%s was not found in any template directory.', $file)); return false; endif; @@ -480,6 +480,117 @@ function setTemplate($file) { } + function ofc( $width, $height, $url, $use_swfobject = true, $base = '' ) { + + $base = $this->config['public_url'].'includes/ofc-1.9/'; + // + // I think we may use swfobject for all browsers, + // not JUST for IE... + // + //$ie = strstr(getenv('HTTP_USER_AGENT'), 'MSIE'); + + // + // escape the & and stuff: + // + $url = urlencode($url); + + // + // output buffer + // + $out = array(); + + // + // check for http or https: + // + if (isset ($_SERVER['HTTPS'])) + { + if (strtoupper ($_SERVER['HTTPS']) == 'ON') + { + $protocol = 'https'; + } + else + { + $protocol = 'http'; + } + } + else + { + $protocol = 'http'; + } + + // + // if there are more than one charts on the + // page, give each a different ID + // + global $open_flash_chart_seqno; + $obj_id = 'chart'; + $div_name = 'flashcontent'; + + //$out[] = ''; + + if( !isset( $open_flash_chart_seqno ) ) + { + $open_flash_chart_seqno = 1; + $out[] = ''; + } + else + { + $open_flash_chart_seqno++; + $obj_id .= '_'. $open_flash_chart_seqno; + $div_name .= '_'. $open_flash_chart_seqno; + } + + if( $use_swfobject ) + { + // Using library for auto-enabling Flash object on IE, disabled-Javascript proof + $out[] = '
'; + $out[] = ''; + $out[] = ''; + } + + return implode("\n",$out); + } + + function performAction($action, $params) { + + return owa_coreAPI::performAction($action, $params); + + } + + function getWidget($widget, $format, $params = '') { + + if (empty($params)): + $params = array(); + endif; + + $params['widget'] = $widget; + $params['format'] = $format; + + $api = owa_coreAPI::singleton(); + + return $api->performAction('base.widget', $params); + } } diff --git a/owa_view.php b/owa_view.php index fde178ae3..4dfee4309 100644 --- a/owa_view.php +++ b/owa_view.php @@ -360,4 +360,105 @@ function _setLinkState() { } +class owa_areaBarsFlashChartView extends owa_base { + + function owa_areaBarsFlashChartView() { + + return owa_areaBarsFlashChartView::__construct(); + } + + function __construct() { + + return $this->owa_base(); + + } + + function assembleView($data) { + + include_once(OWA_INCLUDE_DIR.'open-flash-chart.php' ); + + $g = new graph(); + //$g->title($data['title'], '{font-size: 20px;}' ); + $g->bg_colour = '#FFFFFF'; + $g->x_axis_colour('#cccccc', '#ffffff'); + $g->y_axis_colour('#cccccc', '#cccccc'); + //$g->set_inner_background( '#FFFFFF', '#', 90 ); + + // y2 series + $g->set_data($data['y']['series']); + $g->bar( 100, '#FF9900', $data['y']['label'], 10 ); + + // y series + $g->set_data($data['y2']['series']); + // width: 2px, dots: 3px, area alpha: 25% ... + $g->area_hollow( 1, 3, 60, '#99CCFF', $data['y2']['label'], 12, '#99CCFF' ); + + + $g->set_x_labels($data['x']['series']); + $g->set_x_label_style( 10, '#000000', 0, 2 ); + $g->set_x_axis_steps( 2 ); + $g->set_x_legend( $data['x']['label'], 12, '#000000' ); + + $g->set_y_min( 0 ); + //$g->set_y_max( 225 ); + + //$g->y_label_steps( 15 ); + //$g->set_y_legend( '', 12, '#C11B01' ); + + return $g->render(); + + } + +} + +class owa_pieFlashChartView extends owa_base { + + function owa_pieFlashChartView() { + + return owa_pieFlashChartView::__construct(); + } + + function __construct() { + + return $this->owa_base(); + + } + + function assembleView($data) { + + include_once(OWA_INCLUDE_DIR.'open-flash-chart.php' ); + + $g = new graph(); + + // + // PIE chart, 60% alpha + // + $g->pie(60,'#505050','{font-size: 12px; color: #404040;'); + // + // pass in two arrays, one of data, the other data labels + // + $g->pie_values($data['values'], $data['labels']); + // + // Colours for each slice, in this case some of the colours + // will be re-used (3 colurs for 5 slices means the last two + // slices will have colours colour[0] and colour[1]): + // + $g->pie_slice_colours( array('#d01f3c','#356aa0','#C79810') ); + + $g->set_tool_tip( '#val#%' ); + + if (array_key_exists('title', $data)): + $g->title($data['title'], '{font-size:18px; color: #d01f3c}' ); + endif; + + return $g->render(); + + } + +} + + + + + ?> \ No newline at end of file diff --git a/plugins/db/owa_db_mysql.php b/plugins/db/owa_db_mysql.php index 15bed0310..f643533a1 100644 --- a/plugins/db/owa_db_mysql.php +++ b/plugins/db/owa_db_mysql.php @@ -41,8 +41,8 @@ define('OWA_SQL_CREATE_TABLE', 'CREATE TABLE %s (%s) %s'); define('OWA_SQL_DROP_TABLE', 'DROP TABLE IF EXISTS %s'); define('OWA_SQL_INSERT_ROW', 'INSERT into %s (%s) VALUES (%s)'); -define('OWA_SQL_UPDATE_ROW', 'UPDATE %s SET %s WHERE %s'); -define('OWA_SQL_DELETE_ROW', "DELETE from %s WHERE %s = '%s'"); +define('OWA_SQL_UPDATE_ROW', 'UPDATE %s SET %s %s'); +define('OWA_SQL_DELETE_ROW', "DELETE from %s %s"); define('OWA_SQL_CREATE_INDEX', 'CREATE INDEX %s ON %s (%s)'); define('OWA_SQL_DROP_INDEX', 'DROP INDEX %s ON %s'); define('OWA_SQL_INDEX', 'INDEX (%s)'); @@ -53,7 +53,12 @@ define('OWA_DTD_TABLE_TYPE_DISK', 'INNODB'); define('OWA_DTD_TABLE_TYPE_MEMORY', 'MEMORY'); define('OWA_SQL_ALTER_TABLE_TYPE', 'ALTER TABLE %s ENGINE = %s'); - +define('OWA_SQL_JOIN_LEFT_OUTER', 'LEFT OUTER JOIN'); +define('OWA_SQL_JOIN_LEFT_INNER', 'LEFT INNER JOIN'); +define('OWA_SQL_JOIN_RIGHT_OUTER', 'RIGHT OUTER JOIN'); +define('OWA_SQL_JOIN_RIGHT_INNER', 'RIGHT INNER JOIN'); +define('OWA_SQL_DESCENDING', 'DESC'); +define('OWA_SQL_ASCENDING', 'ASC'); /** @@ -222,86 +227,6 @@ function prepare($string) { } - /** - * Save Request to database - * - */ - function save($properties, $table) { - - $count = count($properties); - - $i = 0; - - $sql_cols = ''; - $sql_values = ''; - - foreach ($properties as $key => $value) { - - $sql_cols = $sql_cols.$key; - $sql_values = $sql_values."'".$this->prepare($value)."'"; - - $i++; - - // Add commas - if ($i < $count): - - $sql_cols = $sql_cols.", "; - $sql_values = $sql_values.", "; - - endif; - } - - return $this->query(sprintf( - OWA_SQL_INSERT_ROW, - $table, - $sql_cols, - $sql_values) - ); - - } - - function update($properties, $constraints, $table) { - - $count = count($properties); - - $i = 0; - - $sql_cols = ''; - $sql_values = ''; - $set = ''; - - foreach ($properties as $key => $value) { - - //$sql_cols = $sql_cols.$key; - //$sql_values = $sql_values."'".$this->prepare($value)."'"; - - // Add commas - if ($i != 0): - - $set .= ', '; - - endif; - - $set .= $key .' = \'' . $this->prepare($value) . '\''; - - $i++; - } - - $where = owa_lib::addConstraints($constraints); - - return $this->query(sprintf(OWA_SQL_UPDATE_ROW, $table, $set, $where)); - - } - - /** - * Deletes Row from a table - * - */ - function delete($id, $col, $table) { - - return $this->query(sprintf(OWA_SQL_DELETE_ROW, $table, $col, $id)); - - } /** * Creates a new table @@ -361,57 +286,7 @@ function createTable($entity) { } - /** - * Drops a table - * - */ - function dropTable($table_name) { - - return $this->query(sprintf(OWA_SQL_DROP_TABLE, $table_name)); - - } - - /** - * Change table type - * - */ - function alterTableType($table_name, $engine) { - - return $this->query(sprintf(OWA_SQL_ALTER_TABLE_TYPE, $table_name, $engine)); - - } - - - /** - * Rename a table - * - */ - function renameTable($table_name, $new_table_name) { - - return $this->query(sprintf(OWA_SQL_RENAME_TABLE, $table_name, $new_table_name)); - - } - - - /** - * Adds new column to table - * - */ - function addColumn($table_name, $column_name, $column_definition) { - - return $this->query(sprintf(OWA_SQL_ADD_COLUMN, $table_name. $column_name, $column_definition)); - } - - /** - * Drops a column from a table - * - */ - function dropColumn($table_name, $column_name) { - - return $this->query(sprintf(OWA_SQL_DROP_COLUMN, $table_name. $column_name)); - - } /** * Begins a SQL transaction statement @@ -431,292 +306,8 @@ function endTransaction() { return $this->query(OWA_SQL_END_TRANSACTION); } - /** - * Changes the definition of a column - * - */ - function modifyColumn($table_name, $column_name, $column_definition) { - return $this->query(sprintf(OWA_SQL_MODIFY_COLUMN, $table_name. $column_name, $column_definition)); - - } - - - function select($values, $constraints, $table) { - - $cols = ''; - $i = 0; - $count = count($values); - - foreach ($values as $k => $v) { - - $cols .= $k; - - // Add commas - if ($i < $count - 1): - - $cols .= ', '; - - endif; - - $i++; - - } - - $where = owa_lib::addConstraints($constraints); - - return $this->get_row(sprintf("SELECT %s FROM %s WHERE %s", $cols, $table, $where)); - - } - - /** - * Fetches primary and related objects from DB - * - * @param array $params caller params - * @return array - */ - function getObjs($params) { - - // Adds caller params to class var - $this->params = $params; - - // construct COLUMNS - - $cols = $this->makeColumnList($this->params['primary_obj']); - - // add related objects - if(!empty($this->params['related_objs'])): - - foreach ($this->params['related_objs'] as $k => $v) { - - $cols .= ', '.$this->makeColumnList($v->entity); - - } - - endif; - - - return $this->buildSelectStm($cols); - } - function selectQuery($params) { - - // Adds caller params to class var - $this->params = $params; - - return $this->buildSelectStm($this->params['select']); - - - } - - function buildSelectStm($cols) { - - $orderby_stm = ''; - $limit_stm = ''; - $offset_stm = ''; - // construct FROM - - $from = $this->makeFromStm(); - - // construct WHERE - if(!empty($this->params['constraints'])): - $where = 'WHERE '.owa_lib::addConstraints($this->params['constraints']); - endif; - - // construct GROUP BY - - if(!empty($this->params['groupby'])): - - $groupby_stm = $this->makeGroupByStm(); - - endif; - - // construct ORDER - - if(!empty($this->params['orderby'])): - - $orderby_stm = $this->makeOrderByStm(); - - endif; - - // construct LIMIT - - if(!empty($this->params['limit'])): - - $limit_stm = $this->makeLimitStm(); - - endif; - - // construct OFFSET - - if(!empty($this->params['offset'])): - - $offset_stm = $this->makeOffsetStm(); - - endif; - - // Issue query - - $ret = $this->get_results(sprintf("SELECT %s FROM %s %s %s %s %s %s", $cols, $from, $where, $groupby_stm, $orderby_stm, $limit_stm, $offset_stm)); - - // format results - if(!empty($ret)): - - $ret = $this->formatResults($ret); - - endif; - - // clear out params. - $this->params = ''; - - return $ret; - - - } - - function formatResults($results) { - - switch ($this->params['result_format']) { - - case "single_array": - return $results[0]; - break; - case "single_row": - return $results[0]; - break; - case "inverted_array": - return owa_lib::deconstruct_assoc($results); - break; - default: - return $results; - break; - } - - } - - function makeFromStm() { - - // construct FROM - - $primary_obj_ns = $this->removeNs(get_class($this->params['primary_obj'])); - - $from = get_class($this->params['primary_obj']) . ' as ' . $primary_obj_ns; - - // add related objects - if(!empty($this->params['related_objs'])): - - foreach ($this->params['related_objs'] as $k => $v) { - $joinTableNs = $this->removeNs(get_class($v->entity)); - - $from .= ' LEFT OUTER JOIN ' . get_class($v->entity) . ' as ' . $joinTableNs . ' ON ' . $primary_obj_ns . '.' . $k . ' = ' . $joinTableNs . '.id'; - } - - endif; - - return $from; - - } - - function makeGroupByStm() { - - return 'GROUP BY ' . $this->makeDelimitedList($this->params['groupby']); - - } - - function makeOrderByStm() { - - if (empty($this->params['order'])): - $this->params['order'] = 'DESC'; - endif; - - return 'ORDER BY ' . $this->makeDelimitedList($this->params['orderby']). ' '. $this->params['order']; - - } - - function makeLimitStm() { - - return 'LIMIT ' . $this->params['limit']; - - } - - function makeOffsetStm() { - - return 'OFFSET ' . $this->params['offset']; - - } - - function makeColumnList($obj) { - - $values = $obj->getColumns(); - - $ns = $this->removeNs(get_class($obj)); - $cols = ''; - $i = 0; - $count = count($values); - - foreach ($values as $k => $v) { - - if (empty($this->params['related_objs'])): - $cols .= $v; - else: - $cols .= $ns.'.'.$v.' as '.$ns.'_'.$v; - endif; - - // Add commas - if ($i < $count - 1): - - $cols .= ', '; - - endif; - - $i++; - - } - - return $cols; - - } - - function removeNs($string) { - - $ns_len = strlen($this->config['ns']); - return substr($string, $ns_len); - - } - - function makeDelimitedList($values, $delimiter = ', ') { - - $items = ''; - $i = 0; - $count = count($values); - - if (is_array($values)): - - foreach ($values as $k) { - - $items .= $k; - - // Add commas - if ($i < $count - 1): - - $items .= $delimiter; - - endif; - - $i++; - - } - - else: - - $items = $values; - - endif; - - return $items; - - } - } ?> \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/AreaHollow.as b/public/includes/ofc-1.9/actionscript/AreaHollow.as new file mode 100755 index 000000000..152df4219 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/AreaHollow.as @@ -0,0 +1,90 @@ +class AreaHollow extends LineHollow +{ + public var bottom:Number=-1; + public var alpha:Number=50; + private var mc_area:MovieClip + private var fill_colour:Number; + + public function AreaHollow( lv:Object, name:String ) + { + //this.values = values; + this.bgColour = _root.get_background_colour(); + this.name = 'area_hollow'+name; + + var vals:Array = lv[this.name].split(","); + this.line_width = Number( vals[0] ); + this.circle_size = Number( vals[1] ); + this.alpha = Number( vals[2] ); + this.colour = _root.get_colour( vals[3] ); + + if( vals.length > 4 ) + this.key = vals[4]; + + if( vals.length > 5 ) + this.font_size = Number( vals[5] ); + + // patch from Will Henry + if( vals.length > 6 ) + this.fill_colour = _root.get_colour( vals[6] ); + else + this.fill_colour = this.colour; + + // draw the area behine the line: + this.mc_area = _root.createEmptyMovieClip( name+'_area', _root.getNextHighestDepth()); + this.mc = _root.createEmptyMovieClip( name, _root.getNextHighestDepth()); + + this.mc2 = _root.createEmptyMovieClip( name+'_hightlight', _root.getNextHighestDepth()); + this.mc2.lineStyle( 0, 0, 0); + this.mc2.fillCircle( 0, 0, this.circle_size+2, 15, this.colour ); + this.mc2.fillCircle( 0, 0, this.circle_size-this.line_width+2, 15, this.bgColour); + this.mc2._visible = false; + + this.set_values( lv['values'+name].split(",") ); + } + + public function valPos( b:Box, right_axis:Boolean, min:Number ) + { + // we need this to draw the area: + this.bottom = b.getYbottom( right_axis ); + super.valPos( b, right_axis, min ); + } + + public function draw() + { + var colour:Number = 0x000000; + if(this.fill_colour == '') { + this.fill_colour = this.colour; + } + + this.mc_area.clear(); + +// this.mc_area.beginFill( this.colour, this.alpha ); + + this.mc_area.beginFill(this.fill_colour, this.alpha ); + + var pos:Number = 0; + while( this.ExPoints[pos] == null ) + pos++; + + this.mc_area.moveTo( this.ExPoints[pos].x, this.bottom ); + this.mc_area.lineTo( this.ExPoints[pos].x, this.ExPoints[pos].y ); + + var last:Point = null; + for( var i:Number=pos+1; i < this.ExPoints.length; i++ ) + { + if( this.ExPoints[i] != null ) + { + this.mc_area.lineTo( this.ExPoints[i].x, this.ExPoints[i].y ); + last = this.ExPoints[i]; + } + } + + if( last != null ) + this.mc_area.lineTo( last.x, this.bottom ); + + this.mc_area.endFill(); + + // now draw the line + hollow dots + super.draw(); + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Background.as b/public/includes/ofc-1.9/actionscript/Background.as new file mode 100755 index 000000000..515dc57e6 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Background.as @@ -0,0 +1,121 @@ +class Background +{ + private var colour:Number=0; + private var mc:MovieClip; + private var img_mc:MovieClip; + private var img_x; + private var img_y; + + // added by NetVicious, 05 July, 2007 + function positionize( mc:MovieClip, myX, myY, s:Square ) + { + var newX:Number = 0; + var newY:Number = 0; + + if ( isNaN(myX) ) { + myX.toLowerCase() + switch ( myX ) { + case 'center': + newX = (s.width / 2) - (mc._width / 2); + break; + case 'left': + newX = s.left; + break; + case 'right': + newX = s.right - mc._width; + break; + default: + newX = 0; + } + } else if ( myX < 0 ) { + newX = s.right - mc._width - myX; + } else { newX = s.left + myX; } + + if ( isNaN(myY) ) { + myY.toLowerCase(); + switch ( myY ) { + case 'middle': + newY = (s.height / 2) - (mc._height / 2); + break; + case 'top': + newY = s.top; + break; + case 'bottom': + newY = s.bottom - mc._height; + break; + default: + newY = 0; + } + } else if ( myY < 0 ) { + newY = s.bottom - mc._height - myY; + } else { newY = s.top + myY; } + + mc._x = newX; + mc._y = newY; + } + + + function Background( lv:LoadVars ) + { + if( lv.bg_colour != undefined ) + this.colour = _root.get_colour( lv.bg_colour ); + else + this.colour = 0xf8f8d8; // <-- default to Ivory + + this.mc = _root.createEmptyMovieClip( "background", _root.getNextHighestDepth(), 0, 0, Stage.width, Stage.height ); + + if( lv.bg_image != undefined ) + { + this.img_mc = _root.createEmptyMovieClip( "background_img", _root.getNextHighestDepth(), 0, 0, Stage.width, Stage.height ); + //this.img_mc.cacheAsBitmap = true; + //this.img_mc.opaqueBackground = 0xFFFFFF; + // this.img_mc is replaced with the loaded image: + + // added by NetVicious, 05 July, 2007 ++++ + + if( lv.bg_image_x != undefined ) + this.img_x = lv.bg_image_x; + + if( lv.bg_image_y != undefined ) + this.img_y = lv.bg_image_y; + + var ref = this; // This variable it's used for avoid the scope loss + + var loader:MovieClipLoader = new MovieClipLoader(); + loader.addListener({ + onLoadInit: function(mymc:MovieClip) { + ref.positionize( mymc, ref.img_x, ref.img_y, new Square(0, 0, Stage.width, Stage.height) ); + delete loader; + } + }); + + loader.loadClip(lv.bg_image, this.img_mc); + // ++++++++++++++++++++++++++++++++++++++++ + +// loader = new MovieClipLoader() +// //Give us status updates by firing events +// loader.addListener(this) + + //loadMovie(lv.bg_image, this.img_mc ); + } + } + + // the background doesn't 'move' but + // it does re-size: + function move() + { + this.mc.clear(); + this.mc.beginFill( this.colour, 100 ); + this.mc.moveTo( 0, 0 ); + this.mc.lineTo( Stage.width, 0 ); + this.mc.lineTo( Stage.width, Stage.height ); + this.mc.lineTo( 0, Stage.height ); + this.mc.endFill(); + + // do we have an image, and did it load: + if(( this.img_mc != undefined ) and (this.img_mc._width != undefined)) + { + positionize( this.img_mc, this.img_x, this.img_y, new Square(0, 0, Stage.width, Stage.height) ); + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Bar3D.as b/public/includes/ofc-1.9/actionscript/Bar3D.as new file mode 100755 index 000000000..01c35e115 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Bar3D.as @@ -0,0 +1,122 @@ +class Bar3D extends BarStyle +{ + public var is_bar:Boolean = true; + public var outline_colour:Number = 0x000000; + + public function Bar3D( lv:Object, name:String ) + { + this.name = 'bar_3d'+name; + this.parse_bar( lv[this.name] ); + this.set_values( lv['values'+name], lv['links'+name] ); + } + + private function top( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + + mc.lineStyle(0, this.outline_colour, 0); + //set gradient fill + + var lighter:Number = ChartUtil.Lighten( this.colour ); + + var colors:Array = [this.colour,lighter]; + var alphas:Array = [100,100]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:0, y:0, w:w+12, h:12, r:(270/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + + + var y:Number = 0; + if( h<0 ) + y = h; + + mc.moveTo(0, y); + mc.lineTo(w, y); + mc.lineTo(w-12, y+12); + mc.lineTo(-12, y+12); + mc.endFill(); + mc._x = val.x; + mc._y = val.y; + } + + private function front( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + var x:Number = val.x; + var y:Number = val.y; + var rad:Number = 7; + + var lighter:Number = ChartUtil.Lighten( this.colour ); + + // Darken a light color + //var darker:Number = this.colour; + //darker &= 0x7F7F7F; + + var colors:Array = [lighter,this.colour]; + var alphas:Array = [100,100]; + var ratios:Array = [0,127]; + var matrix:Object = { matrixType:"box", x:-12, y:12, w:w-12, h:h+12, r:(90/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + + mc.moveTo(-12, 12); + mc.lineTo(-12, h+12); + mc.lineTo(w-12, h+12); + mc.lineTo(w-12, 12); + mc.endFill(); + } + + private function side( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + var x:Number = val.x; + var y:Number = val.y; + var rad:Number = 7; + + var lighter:Number = ChartUtil.Lighten( this.colour ); + + var colors:Array = [this.colour,lighter]; + var alphas:Array = [100,100]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:w-12, y:0, w:w, h:h+12, r:(270/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + + mc.lineStyle(0, this.outline_colour, 0); + //mc.beginFill(this.colour, 100); + mc.moveTo(w, 0); + mc.lineTo(w, h); + mc.lineTo(w-12, h+12); + mc.lineTo(w-12, 12); + mc.endFill(); + }; + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = this.bar_mcs[i]; + + mc.clear(); + this.top( mc, val ); + this.front( mc, val ); + this.side( mc, val ); + + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 5; + dropShadow.blurY = 5; + dropShadow.distance = 3; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.4; + //mc.filters = [dropShadow]; + + mc._alpha = this.alpha; + mc._alpha_original = this.alpha; // <-- remember our original alpha while tweening + + // this is used in _root.FadeIn and _root.FadeOut + mc.val = val; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/BarArrow.as b/public/includes/ofc-1.9/actionscript/BarArrow.as new file mode 100755 index 000000000..70a043fbb --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/BarArrow.as @@ -0,0 +1,110 @@ +class BarArrow extends BarStyle +{ + public function BarArrow( lv:Object, name:String ) + { + this.name = 'bar_arrow'+name; + // this calls parent obj Style.Style first + this.parse_bar( lv[this.name] ); + this.set_values( lv['values'+name], lv['links'+name], lv['tool_tips_set'+name] ); + } + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = super.draw_bar( val, i ); + + //var mc:MovieClip = this.bar_mcs[i]; + + mc.lineStyle( 2, 0x000000, 100); + + mc.moveTo( val.x+(val.width/2), val.bar_bottom ); + + var steps:Number = Math.floor( 4+Math.random()*4); + var height:Number = (val.bar_bottom-val.y)/steps; + var x:Number; + var y:Number; + + for( var i:Number=1; i=0 && y<0 ) + { + angle += 360; + } + angle += 180; + + var r:Number=20; + + var radian = (angle+20) * Math.PI/180; + var cos:Number = Math.cos(radian); + var sin:Number = Math.sin(radian); + + var x_1 = Math.cos(radian)*r; + var y_1 = Math.sin(radian)*r; + + var radian = (angle-20) * Math.PI/180; + var cos:Number = Math.cos(radian); + var sin:Number = Math.sin(radian); + + var x_2 = Math.cos(radian)*r; + var y_2 = Math.sin(radian)*r; + + mc.lineStyle( 0, 0x0000E0, 100); + //mc.beginFill( 0x0000E0, 100 ); + mc.moveTo( val.x+(val.width/2), val.y ); + mc.lineTo( val.x+(val.width/2)+x_1, val.y+y_1 ); + mc.lineTo( val.x+(val.width/2)+x_2, val.y+y_2 ); + mc.lineTo( val.x+(val.width/2), val.y ); + //mc.endFill(); + + return mc; + } +} diff --git a/public/includes/ofc-1.9/actionscript/BarFade.as b/public/includes/ofc-1.9/actionscript/BarFade.as new file mode 100755 index 000000000..c672f6e4b --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/BarFade.as @@ -0,0 +1,58 @@ +class BarFade extends BarStyle +{ + public function BarFade( lv:Object, name:String ) + { + this.name = 'bar_fade'+name; + // this calls parent obj Style.Style first + this.parse_bar( lv[this.name] ); + this.set_values( lv['values'+name], lv['links'+name], lv['tool_tips_set'+name] ); + } + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = this.bar_mcs[i]; + mc.clear(); + + var top:Number; + var height:Number; + + if(val.bar_bottom 3 ) + this.key = vals[3]; + + if( vals.length > 4 ) + this.font_size = Number( vals[4] ); + + } + + private function glass( mc:MovieClip, val:PointBar ) + { + var x:Number = 3; + var y:Number = x; + var width:Number = (val.width/2)-x; + var height:Number = val.bar_bottom-val.y; + + if( height>0 ) + height -= 4; + else + { + height += 4; + y = -y; + } + + //set gradient fill + var colors:Array = [0xFFFFFF,0xFFFFFF]; + var alphas:Array = [30, 70]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:x, y:y, w:width, h:height, r:(180/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + + + mc.lineStyle(0, 0, 0); + + var rad:Number = 3; + var w:Number = width; + var h:Number = height; + + //this.beginFill(this.shine_colour, 100); + if( h>0 ) + { + mc.moveTo(x+rad, y); + mc.lineTo(x+w, y); + mc.lineTo(x+w, y+h); + mc.lineTo(x+rad, y+h); + mc.curveTo(x, y+h, x, y+h-rad); + mc.lineTo(x, y+rad); + } + else + { + mc.moveTo(x+rad, y); // <-- bottom left + mc.lineTo(x+w, y); // bottom right + mc.lineTo(x+w, y+h); // top right + mc.lineTo(x, y+h); // top left + mc.lineTo(x, y-rad); // bottom left + //mc.curveTo(x, y, x+rad, y); + } + mc.endFill(); + + } + + private function bg( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + var x:Number = val.x; + var y:Number = val.y; + var rad:Number = 7; + + mc.lineStyle(0, this.outline_colour, 100); + mc.beginFill(this.colour, 100); + + if( h>0 ) + { + // bar goes up + mc.moveTo(0+rad, 0); + mc.lineTo(w-rad, 0); + mc.curveTo(w, 0, w, rad); + mc.lineTo(w, h); + mc.lineTo(0, h); + mc.lineTo(0, 0+rad); + mc.curveTo(0, 0, 0+rad, 0); + } + else + { + // bar goes down + mc.moveTo(0+rad, 0); + mc.lineTo(w-rad, 0); + mc.curveTo(w, 0, w, -rad); + mc.lineTo(w, h); + mc.lineTo(0, h); + mc.lineTo(0, 0-rad); + mc.curveTo(0, 0, 0+rad, 0); + } + mc.endFill(); + mc._x = x; + mc._y = y; + }; + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = this.bar_mcs[i]; + + mc.clear(); + + if( val == null ) + return; + + this.bg( mc, val ); + this.glass( mc, val ); + + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 5; + dropShadow.blurY = 5; + dropShadow.distance = 3; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.4; + mc.filters = [dropShadow]; + + mc._alpha = this.alpha; + mc._alpha_original = this.alpha; // <-- remember our original alpha while tweening + + // this is used in _root.FadeIn and _root.FadeOut + //mc.val = val; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/BarSketchStyle.as b/public/includes/ofc-1.9/actionscript/BarSketchStyle.as new file mode 100755 index 000000000..32f3a9136 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/BarSketchStyle.as @@ -0,0 +1,90 @@ +class BarSketchStyle extends FilledBarStyle +{ + private var offset:Number; + + public function BarSketchStyle( lv:Object, name:String ) + { + this.name = 'bar_sketch'+name; + this.parse( lv[this.name] ); + this.set_values( lv['values'+name], lv['links'+name], lv['tool_tips_set'+name] ); + } + + public function parse( val:String ) + { + var vals:Array = val.split(","); + + this.alpha = Number( vals[0] ); + this.offset = Number( vals[1] ); + this.colour = _root.get_colour( vals[2] ); + this.outline_colour = _root.get_colour( vals[3] ); + + if( vals.length > 4 ) + this.key = vals[4]; + + if( vals.length > 5 ) + this.font_size = Number( vals[5] ); + + } + + public function draw_bar( val:PointBar, i:Number ) + { + var top:Number; + var height:Number; + + if(val.bar_bottom 2 ) + this.key = vals[2].replace('#comma#',','); + + if( vals.length > 3 ) + this.font_size = Number( vals[3] ); + + } + + // override Style:set_values + function set_values( vals:String, links:String, tooltips:String ) + { + super.set_values( this.parse_list( vals ) ); + this.set_links( links ); + this.set_tooltips( tooltips ); + this.set_mcs(this.values.length); + } + + private function set_mcs( count:Number ) + { + // delete the old movie clips + // this should be in the deconstructor... + if( this.bar_mcs!=undefined ) + { + for( var i:Number=0; i this.ExPoints[i].x) && (x < this.ExPoints[i].x+this.ExPoints[i].width) ) + { + // mouse is in position 1 + shortest = Math.min( Math.abs( x - this.ExPoints[i].x ), Math.abs( x - (this.ExPoints[i].x+this.ExPoints[i].width) ) ); + ex = this.ExPoints[i]; + break; + } + else + { + // mouse is in position 2 + // get distance to left side and right side + var d1:Number = Math.abs( x - this.ExPoints[i].x ); + var d2:Number = Math.abs( x - (this.ExPoints[i].x+this.ExPoints[i].width) ); + var min:Number = Math.min( d1, d2 ); + if( min < shortest ) + { + shortest = min; + ex = this.ExPoints[i]; + } + } + } + var dy:Number = Math.abs( y - ex.y ); + + return { point:ex, distance_x:shortest, distance_y:dy }; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/BarZebra.as b/public/includes/ofc-1.9/actionscript/BarZebra.as new file mode 100755 index 000000000..2dc603945 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/BarZebra.as @@ -0,0 +1,113 @@ +class BarZebra extends BarStyle +{ + public function BarZebra( val:String, name:String ) + { + super( val, name ); + } + + private function bg( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + var x:Number = val.x; + var y:Number = val.y; + var rad:Number = 10; + + mc.lineStyle( undefined, 0xFFFFFF, 100); + mc.beginFill( 0xFFFFFF, 100); + mc.moveTo(0+rad, 0); + mc.lineTo(w-rad, 0); + mc.curveTo(w, 0, w, rad); + mc.lineTo(w, h); + mc.lineTo(0, h); + mc.lineTo(0, 0+rad); + mc.curveTo(0, 0, 0+rad, 0); + mc.endFill(); + mc._x = x; + mc._y = y; + }; + + private function bg2( mc:MovieClip, val:PointBar ) + { + // + var w:Number = val.width; + var h:Number = val.bar_bottom-val.y; + var x:Number = val.x; + var y:Number = val.y; + var rad:Number = 10; + + mc.lineStyle( undefined, 0xFFFFFF, 100); + mc.beginFill( 0xFF0000, 50); + mc.moveTo(0, 0); + mc.lineTo(w, 20); + mc.lineTo(0, 20); + mc.lineTo(0, 0); + mc.endFill(); + mc._x = x; + mc._y = y; + }; + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = this.bar_mcs[i]; + mc.clear(); + this.bg( mc, val ); + + var mc_o = mc.createEmptyMovieClip('overlay', mc.getNextHighestDepth()); + + this.bg2( mc_o, val ); + + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 5; + dropShadow.blurY = 5; + dropShadow.distance = 3; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.4; + mc.filters = [dropShadow]; + + return; + var top:Number; + var height:Number; + + if(val.bar_bottom right ) + { + new_right -= 1; + // changing the right also changes the item_width: + item_width = (new_right-left) / count; + r = new_right-(item_width/2); + } + right = new_right; + } + + return right; + + } + + // if the left label is truncated, shrink the box until + // it fits onto the screen + function shrink_left( left:Number, right:Number, x_label_width:Number, count:Number ) + { + var pos:Number = 0; + + if( x_label_width != 0 ) + { + var item_width:Number = (right-left) / count; + var pos:Number = left+(item_width/2); + var new_left:Number = left; + + // while the left most label is hanging off the Stage + // move the box.left in one pixel: + while( pos-(x_label_width/2) < 0 ) + { + new_left += 1; + // changing the left also changes the item_width: + item_width = (right-new_left) / count; + pos = new_left+(item_width/2); + } + left = new_left; + } + + return left; + + } + + // + // the bottom point of a bar: + // min=-100 and max=100, use b.zero + // min = 10 and max = 20, use b.bottom + // + function getYbottom( right_axis:Boolean ) + { + var min:Number = this.minmax.min( right_axis ); + return this.getY( Math.max(0,min), right_axis ); + } + + // takes a value and returns the screen Y location + function getY_old( i:Number, right_axis:Boolean ) + { + var steps:Number = this.height/(this.minmax.range( right_axis )); + + // find Y pos for value=zero + var y:Number = this.bottom-(steps*(this.minmax.min( right_axis )*-1)); + + // move up (-Y) to our point (don't forget that y_min will shift it down) + y -= i*steps; + return y; + } + + // takes a value and returns the screen Y location + function getY( i:Number, right_axis:Boolean ) + { + var steps:Number = this.height/(this.minmax.range( right_axis )); + var y:Number = this.bottom; + + // move up (-Y) to our point (don't forget that y_min will shift it down) + return this.bottom-(this.minmax.min( right_axis )-i)*steps*-1; + } + + function width_():Number + { + return this.right-this.left_(); + } + + function left_():Number + { + var padding_left:Number = this.tick_offset; + return this.left+padding_left; + } + + // + // get the x position by value (e.g. what is the x position for -5 ?) + // + function get_x_pos_of_val( i:Number ) + { + var item_width:Number = this.width_() / this.count; + + var pos:Number = i-this.minmax.x_min; + + var tmp = 0; + if( this.x_offset ) + tmp = (item_width/2); + + return this.left_()+tmp+(pos*item_width); + } + + // + // get the x position of the n'th item + // + function get_x_pos( i:Number ) + { + var item_width:Number = this.width_() / this.count; + + var tmp = 0; + if( this.x_offset ) + tmp = (item_width/2); + + return this.left_()+tmp+(i*item_width); + } + + // + // get the position of the n'th X axis tick + // + function get_x_tick_pos( i:Number ) + { + return this.get_x_pos(i) - this.tick_offset; + } + + // + // make a point object using the X position and absolute Y pos + // e.g. x=wednesday, y=20 + // + function make_point( x:Number, y:Number, right_axis:Boolean ) + { + return new Point( + this.get_x_pos( x ), + this.getY( y, right_axis ), + y + ); + } + + // + // make a point object, using the absolute values (e.g. -5,-5 ) + // + function make_point_2( x:Number, y:Number, right_axis:Boolean ) + { + return new Point( + this.get_x_pos_of_val( x ), + this.getY( y, right_axis ), + y + ); + } + + + + function make_point_bar( x:Number, y:Number, right_axis:Boolean, group:Number, group_count:Number ) + { + + var item_width:Number = this.width_() / this.count; + + // the bar(s) have gaps between them: + var bar_set_width:Number = item_width*0.8; + + // get the margin between sets of bars: + var tmp = 0; + if( this.x_offset ) + tmp = item_width; + + var bar_left:Number = this.left_()+(tmp-bar_set_width)/2; + // 1 bar == 100% wide, 2 bars = 50% wide each + var bar_width:Number = bar_set_width/group_count; + + var left:Number = bar_left+(x*item_width); + left += bar_width*group; + + return new PointBar( + left, + this.getY( y, right_axis ), + bar_width-0.001, // <-- hack so bars don't quite touch + this.getYbottom( right_axis ) + ); + } + + function make_point_candle( x:Number, high:Number, open:Number, close:Number, low:Number, right_axis:Boolean, group:Number, group_count:Number ) + { + + var item_width:Number = this.width_() / this.count; + + // the bar(s) have gaps between them: + var bar_set_width:Number = item_width*0.8; + + // get the margin between sets of bars: + var bar_left:Number = this.left_()+((item_width-bar_set_width)/2); + // 1 bar == 100% wide, 2 bars = 50% wide each + var bar_width:Number = bar_set_width/group_count; + + var left:Number = bar_left+(x*item_width); + left += bar_width*group; + + return new PointCandle( + left, + this.getY( high, right_axis ), + this.getY( open, right_axis ), + this.getY( close, right_axis ), + this.getY( low, right_axis ), + high, + bar_width, + open + ); + + } + + function makePointHLC( x:Number, high:Number, close:Number, low:Number, right_axis:Boolean, group:Number, group_count:Number ) + { + + var item_width:Number = this.width_() / this.count; + // the bar(s) have gaps between them: + var bar_set_width:Number = item_width*1; + + // get the margin between sets of bars: + var bar_left:Number = this.left_()+((item_width-bar_set_width)/2); + // 1 bar == 100% wide, 2 bars = 50% wide each + var bar_width:Number = bar_set_width/group_count; + + var left:Number = bar_left+(x*item_width); + left += bar_width*group; + + return new PointHLC( + left, + this.getY( high, right_axis ), + this.getY( close, right_axis ), + this.getY( low, right_axis ), + high, + bar_width, + close + ); + + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/CandleStyle.as b/public/includes/ofc-1.9/actionscript/CandleStyle.as new file mode 100755 index 000000000..c42acca94 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/CandleStyle.as @@ -0,0 +1,230 @@ +class CandleStyle extends BarStyle +{ + public var is_bar:Boolean = true; + + // MovieClip that holds each bar: + private var bar_mcs:Array; + public var name:String; + private var line_width = 3; + + var links:Array; + + public function CandleStyle( lv:Object, name:String ) + { + this.name = 'candle'+name; + // this calls parent obj Style.Style first + this.parse_bar( lv[this.name] ); + //this.set_values( lv['values'+name], lv['links'+name], lv['tool_tips_set'+name] ); + + this.links = new Array(); + } + + public function parse_bar( val:String ) + { + var vals:Array = val.split(","); + + this.alpha = Number( vals[0] ); + this.line_width = Number( vals[1] ); + this.colour = _root.get_colour(vals[2]); + + if( vals.length > 3 ) + this.key = vals[3]; + + if( vals.length > 4 ) + this.font_size = Number( vals[4] ); + + } + + // a group looks like "[1,2,3,4]" + private function parse_group( g:String ) + { + var group:Array = g.split(','); + this.values.push( + { + high: Number( group[0] ), + open: Number( group[1] ), + close: Number( group[2] ), + low: Number( group[3] ) + } + ); + } + + function groups( vals:String ) + { + var groups:Array=new Array(); + var tmp:String = ''; + var start:Boolean = false; + + for( var i=0; ii ) + { + mc._ofc_link = this.links[i]; + mc.onRelease = function ():Void { trace(this._ofc_link); getURL(this._ofc_link); }; + mc.useHandCursor = true; + } + else + mc.useHandCursor = false; + + //mc.onRollOver = ChartUtil.glowIn; + + // this is used in FadeIn and FadeOut + //mc.tool_tip_title = labels[i]; + var tooltip:Object = {x_label:labels[i], value:this.values[i], key:this.key}; + mc.tooltip = tooltip; + + // add the MovieClip to our array: + this.bar_mcs[i] = mc; + } + } + + public function valPos( b:Box, right_axis:Boolean, min:Number, bar_count:Number, bar:Number ) + { + this.ExPoints=Array(); + + var item_width:Number = b.width_() / this.values.length; + + // the bar(s) have gaps between them: + var bar_set_width:Number = item_width*_root._bars_width; + // get the margin between sets of bars: + var bar_left:Number = b.left_()+((item_width-bar_set_width)/2); + // 1 bar == 100% wide, 2 bars = 50% wide each + var bar_width:Number = bar_set_width/bar_count; + + for( var i:Number=0; i < this.values.length; i++) + { + var tmp:PointCandle = b.make_point_candle( + i, + this.values[i].high, + this.values[i].open, + this.values[i].close, + this.values[i].low, + right_axis, + bar, + bar_count + ); + + tmp.make_tooltip( + _root.get_tooltip_string(), + this.key, + this.values[i], + _root.get_x_legend(), + _root.get_x_axis_label(i) + ); + + //var tooltip:Object = {x_label:labels[i], value:this.values[i], key:this.key}; + //mc.tooltip = tooltip; + + this.ExPoints.push( tmp ); + } + } + + public function draw_bar( val:Object, i:Number ) + { + var top:Number; + var height:Number; + var line_width:Number = this.line_width; + + var hollow:Boolean = false; + + if( val.open > val.close ) + { + hollow = true; + var tmp:Number = val.open; + val.open = val.close; + val.close = tmp; + } +/* + if(val.bar_bottom Stage.width ) + _root.tooltip._x = Stage.width - _root.tooltip._width; + + _root.tooltip._y = _root._ymouse-_root.tooltip._height-20; + if( _root.tooltip._y < 0 ) + _root.tooltip._y = 0; + } + if( mc._alpha < 100 ) + { + mc._alpha += 10; + } + else + { + mc._alpha = 100; + // + // we delete mc.onEnterFrame later, + // so the tool tip keeps following the mouse + // + } + }; + } + + static function FadeOut(mc:MovieClip) : Void { + mc.onEnterFrame = function () + { + + if( (mc._alpha-5) > mc._alpha_original ) + { + mc._alpha -= 5; + } + else + { + mc._alpha = mc._alpha_original; + _root.hide_tip( mc ); + delete mc.onEnterFrame; + } + }; + + } + + // + // JG: lighten a colour by splitting it + // into RGB, then adding a bit to each + // value... + // + static function Lighten( col:Number ) : Number + { + var rgb = col; //decimal value for a purple color + var red = (rgb & 16711680) >> 16; //extacts the red channel + var green = (rgb & 65280) >> 8; //extacts the green channel + var blue = rgb & 255; //extacts the blue channel + var p=2; + red += red/p; + if( red > 255 ) + red = 255; + + green += green/p; + if( green > 255 ) + green = 255; + + blue += blue/p; + if( blue > 255 ) + blue = 255; + + return red << 16 | green << 8 | blue; + } + + // JG - I copied this from : + // http://www.actionscript.org/showMovie.php?id=1183 + // + // Rounded rectangle made only with actionscript. + // Code taken and modified from http://www.actionscript-toolbox.com + // w = rectangle width + // h = rectangle height + // rad = rounded corner radius + // x = x start point for rectangle + // y = y start point for rectangle + // + // + // If you have any questions about this script mail me: janiss@cc.lv + // + static function rrectangle( mc:MovieClip, w:Number, h:Number, rad:Number, x:Number, y:Number, stroke:Object, fill:Object) : Void { + // added by JG on 30th May 07 + x = Math.round(x); + y = Math.round(y); + w = Math.round(w); + h = Math.round(h); + // + mc.lineStyle(stroke.width, stroke.color, stroke.alpha); + mc.beginFill(fill.color, fill.alpha); + mc.moveTo(0+rad, 0); + mc.lineTo(w-rad, 0); + mc.curveTo(w, 0, w, rad); + mc.lineTo(w, h-rad); + mc.curveTo(w, h, w-rad, h); + mc.lineTo(0+rad, h); + mc.curveTo(0, h, 0, h-rad); + mc.lineTo(0, 0+rad); + mc.curveTo(0, 0, 0+rad, 0); + mc.endFill(); + mc._x = x; + mc._y = y; + } + + +/* + //import flash.filters.GlowFilter; + static function GlowIn(mc :MovieClip, tooltip_follow:Boolean) : Void + { + var gf:GlowFilter = new flash.filters.GlowFilter(0x356D83, 100, 3, 3, 5, 3, false, false); + mc.filters = [gf]; + mc.onRollOver = function() + { + this.onEnterFrame = function() + { + if( mc.blurX < 20) + { + gf.blurX++; + gf.blurY++; + } + else + { + delete this.onEnterFrame; + } + this.filters = [gf]; + }; + }; +*/ +/* + kText.onRollOut = function() { + + this.onEnterFrame = function() { + + this.filters = [gf]; + if (gf.blurX > 3) { + + gf.blurX--; + gf.blurY--; + + } else { + + delete this.onEnterFrame; + + } + + }; + + }; +*/ + + +/* + +static function hide_tip( owner:Object ) : Void { + if( _root.tooltip._owner == owner ) + removeMovieClip("tooltip"); +} + +static function show_tip( owner:Object, x:Number, y:Number, tip_text:String ) : Void +{ + if( ( _root.tooltip != undefined ) ) + { + if(_root.tooltip._owner==owner) + return; // <-- it's our tooltip and it is showing + else + removeMovieClip("tooltip"); // <-- it is someone elses tootlip - remove it + } + + var tooltip:MovieClip = _root.createEmptyMovieClip( "tooltip", _root.getNextHighestDepth() ); + + // let the tooltip know who owns it, else we get weird race conditions where one + // bar has onRollOver fired, then another has onRollOut and deletes the tooltip + tooltip._owner = owner; + + var cstroke:Object = {width:2, color:0x808080, alpha:100}; + var ccolor:Object = {color:0xf0f0f0, alpha:100}; + + tooltip.createTextField( "txt", _root.getNextHighestDepth(), 5, 5, 100, 100); + tooltip.txt.text = tip_text; + + var fmt:TextFormat = new TextFormat(); + fmt.color = 0x000000; + fmt.font = "Verdana"; + fmt.size = 12; + fmt.align = "right"; + tooltip.txt.setTextFormat(fmt); + tooltip.txt.autoSize="left"; + + rrectangle(tooltip, + tooltip.txt._width+10, + tooltip.txt._height+10, + 6, + ((x+tooltip._width+10) > Stage.width ) ? (Stage.width-tooltip._width-10) : x, + y - tooltip.txt._height, + cstroke, + ccolor); + + // NetVicious, June, 2007 + // create shadow filter + var dropShadow:Object = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 4; + dropShadow.blurY = 4; + dropShadow.distance = 4; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.5; + // apply shadow filter + tooltip.filters = [dropShadow]; + +} + + +static function format( i:Number ) : String { + var s:String = ''; + if( i<0 ) + var num:Array = String(-i).split('.'); + else + var num:Array = String(i).split('.'); + + var x:String = num[0]; + var pos:Number=0; + for(var c:Number = x.length-1;c>-1;c--) + { + if( pos%3==0 && s.length>0 ) + { + s=','+s; + pos=0; + } + pos++; + + s=x.substr(c,1)+s; + } + if( num[1] != undefined ) + s += '.'+ num[1].substr(0,2); + + if( i<0 ) + s = '-'+s; + + return s; +} +*/ +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Css.as b/public/includes/ofc-1.9/actionscript/Css.as new file mode 100755 index 000000000..b0b199e0d --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Css.as @@ -0,0 +1,253 @@ +class Css { + private var text_align:String; + private var font_size:String; + private var text_decoration:String; + private var margin:String; + public var margin_top:Number; + public var margin_bottom:Number; + public var margin_left:Number; + public var margin_right:Number; + + private var padding:String; + public var padding_top:Number=0; + public var padding_bottom:Number=0; + public var padding_left:Number=0; + public var padding_right:Number=0; + + private var font_weight:String; + private var font_style:String; + private var font_family:String; + private var color:String; + private var stop_process:Number; // Flag for disable checking + private var bg_colour:String; + + private var display:String; + + private function trim( txt:String ) + { + var l = 0; var r = txt.length - 1; + while(txt.charAt(l) == ' ' or txt.charAt(l) == "\t" ) l++; + while(txt.charAt(r) == ' ' or txt.charAt(r) == "\t" ) r--; + return txt.substring( l, r+1 ); + } + + private function removeDoubleSpaces( txt:String ) { + var aux:String; + var auxPrev:String; + aux = txt; + do { + auxPrev = aux; + aux.replace(' ',' '); + } while ( auxPrev.length != aux.length ); + return aux; + } + + private function ToNumber(cad:String) { + + cad = cad.replace( 'px', '' ); + + if ( isNaN( Number(cad) ) ) { + return 0; + } else { + return Number(cad); + } + } + + private function getAttribute( txt:String ) { + var arr:Array = txt.split(":"); + if( arr.length==2 ) + { + this.stop_process = 1; + this.set( arr[0], trim(arr[1]) ); + } + } + + public function get( cad:String ) { + switch (cad) { + case "text-align" : return this.text_align; + case "font-size" : return ToNumber(this.font_size); + case "text-decoration" : return this.text_decoration; + case "margin-top" : return this.margin_top; + case "margin-bottom" : return this.margin_bottom; + case "margin-left" : return this.margin_left; + case "margin-right" : return this.margin_right; + case "padding-top" : return this.padding_top; + case "padding-bottom" : return this.padding_bottom; + case "padding-left" : return this.padding_left; + case "padding-right" : return this.padding_right; + case "font-weight" : return ToNumber(this.font_weight); + case "font-style" : return this.font_style; + case "font-family" : return this.font_family; + case "color" : return this.color; + case "background-color" : return this.bg_colour; + case "display" : return this.display; + default : return 0; + } + } + + // FUCKING!! Flash without By reference String parameters on functions + public function set( cad:String, val:String ) + { + cad = trim( cad ); + + switch( cad ) + { + case "text-align" : this.text_align = val; break; + case "font-size" : this.font_size = val; break; + case "text-decoration" : this.text_decoration = val; break; + case "margin": + this.margin = setMargin(val); + break; + case "margin-top" : this.margin_top = ToNumber(val); break; + case "margin-bottom" : this.margin_bottom = ToNumber(val); break; + case "margin-left" : this.margin_left = ToNumber(val); break; + case "margin-right" : this.margin_right = ToNumber(val); break; + + case 'padding': + this.padding = setPadding(val); + break; + + case "padding-top" : this.padding_top = ToNumber(val); break; + case "padding-bottom" : this.padding_bottom = ToNumber(val); break; + case "padding-left" : this.padding_left = ToNumber(val); break; + case "padding-right" : this.padding_right = ToNumber(val); break; + + case "font-weight" : this.font_weight = val; break; + case "font-style" : this.font_style = val; break; + case "font-family" : this.font_family = val; break; + case "color" : this.color = _root.get_colour( val ); break; + case "background-color": + this.bg_colour = _root.get_colour( val); + break; + case "display" : this.display = val; break; + } + } + + + private function setPadding( val:String ) + { + + val = trim( val ); + var arr:Array = val.split(' '); + + switch( arr.length ) + { + + // margin: 30px; + case 1: + this.padding_top = ToNumber(arr[0]); + this.padding_right = ToNumber(arr[0]); + this.padding_bottom = ToNumber(arr[0]); + this.padding_left = ToNumber(arr[0]); + break; + + // margin: 15px 5px; + case 2: + this.padding_top = ToNumber(arr[0]); + this.padding_right = ToNumber(arr[1]); + this.padding_bottom= ToNumber(arr[0]); + this.padding_left = ToNumber(arr[1]); + break; + + // margin: 15px 5px 10px; + case 3: + this.padding_top = ToNumber(arr[0]); + this.padding_right = ToNumber(arr[1]); + this.padding_bottom= ToNumber(arr[2]); + this.padding_left = ToNumber(arr[1]); + break; + + // margin: 1px 2px 3px 4px; + default: + this.padding_top = ToNumber(arr[0]); + this.padding_right = ToNumber(arr[1]); + this.padding_bottom= ToNumber(arr[2]); + this.padding_left = ToNumber(arr[3]); + } + } + + private function setMargin( val:String ) + { + + val = trim( val ); + var arr:Array = val.split(' '); + + switch( arr.length ) + { + + // margin: 30px; + case 1: + this.margin_top = ToNumber(arr[0]); + this.margin_right = ToNumber(arr[0]); + this.margin_bottom= ToNumber(arr[0]); + this.margin_left = ToNumber(arr[0]); + break; + + // margin: 15px 5px; + case 2: + this.margin_top = ToNumber(arr[0]); + this.margin_right = ToNumber(arr[1]); + this.margin_bottom= ToNumber(arr[0]); + this.margin_left = ToNumber(arr[1]); + break; + + // margin: 15px 5px 10px; + case 3: + this.margin_top = ToNumber(arr[0]); + this.margin_right = ToNumber(arr[1]); + this.margin_bottom= ToNumber(arr[2]); + this.margin_left = ToNumber(arr[1]); + break; + + // margin: 1px 2px 3px 4px; + default: + this.margin_top = ToNumber(arr[0]); + this.margin_right = ToNumber(arr[1]); + this.margin_bottom= ToNumber(arr[2]); + this.margin_left = ToNumber(arr[3]); + } + } + + public function clear() { + this.text_align = undefined; + this.font_size = undefined; + this.text_decoration = undefined; + this.margin_top = undefined; + this.margin_bottom = undefined; + this.margin_left = undefined; + this.margin_right = undefined; + this.font_weight = undefined; + this.font_style = undefined; + this.font_family = undefined; + this.color = undefined; + this.display = undefined; + } + + public function Css( txt:String ) + { + // To lower case + txt.toLowerCase(); + + // monk.e.boy: remove the { and } + txt = txt.replace( '{', '' ); + txt = txt.replace( '}', '' ); + + // monk.e.boy: setup some default values. + // does this confilct with 'clear()'? + this.margin_top = 0; + this.margin_bottom = 0; + this.margin_left = 0; + this.margin_right = 0; + + this.color = '#000000'; + + // Splitting by the ; + var arr:Array = txt.split(";"); + + // Checking all the types of css params we accept and writing to internal variables of the object class + for( var i = 0; i < arr.length; i++) + { + getAttribute(arr[i]); + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/ExPoint.as b/public/includes/ofc-1.9/actionscript/ExPoint.as new file mode 100755 index 000000000..5580394ef --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/ExPoint.as @@ -0,0 +1,27 @@ +class ExPoint +{ + public var left:Number=0; // <-- for bars + public var center:Number=0; // <-- for dots + public var y:Number=0; + public var tooltip:String = ""; + + public var bar_width:Number=0; + public var bar_bottom:Number=0; + + public var is_tip:Boolean = false; + + public function ExPoint( left:Number, center:Number, y:Number, width:Number, bar_bottom:Number, tooltip:Number ) + { + this.left = left; + this.center = center; + this.y = y; + this.bar_width = width; + this.bar_bottom = bar_bottom; + this.tooltip = _root.format(tooltip); + } + + public function toString() + { + return "left :"+ this.left; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/FilledBarStyle.as b/public/includes/ofc-1.9/actionscript/FilledBarStyle.as new file mode 100755 index 000000000..a135eaf17 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/FilledBarStyle.as @@ -0,0 +1,57 @@ +class FilledBarStyle extends BarStyle +{ + public var is_bar:Boolean = true; + public var outline_colour:Number = 0x000000; + + public function FilledBarStyle( lv:Object, name:String ) + { + this.name = 'filled_bar'+name; + this.parse( lv[this.name] ); + this.set_values( lv['values'+name], lv['links'+name], lv['tool_tips_set'+name] ); + } + + public function parse( val:String ) + { + var vals:Array = val.split(","); + + this.alpha = Number( vals[0] ); + this.colour = _root.get_colour( vals[1] ); + this.outline_colour = _root.get_colour( vals[2] ); + + if( vals.length > 3 ) + this.key = vals[3]; + + if( vals.length > 4 ) + this.font_size = Number( vals[4] ); + + } + + public function draw_bar( val:PointBar, i:Number ) + { + var mc:MovieClip = super.draw_bar( val, i ); + + var top:Number; + var height:Number; + + if(val.bar_bottom 3 ) + this.key = vals[3]; + + if( vals.length > 4 ) + this.font_size = Number( vals[4] ); + + } + + // a group looks like "[1,2,3]" + private function parse_group( g:String ) + { + var group:Array = g.split(','); + this.values.push( + { + high: Number( group[0] ), + low: Number( group[1] ), + close: Number( group[2] ) + } + ); +// var _h: Number=Number( group[0] ); +// trace ("high=" + _h); + } + + function groups( vals:String ) + { + var groups:Array=new Array(); + var tmp:String = ''; + var start:Boolean = false; + + for( var i=0; ii ) + { + mc._ofc_link = this.links[i]; + mc.onRelease = function ():Void { trace(this._ofc_link); getURL(this._ofc_link); }; + mc.useHandCursor = true; + } + else + mc.useHandCursor = false; + + //mc.onRollOver = ChartUtil.glowIn; + + // this is used in FadeIn and FadeOut + //mc.tool_tip_title = labels[i]; + var tooltip:Object = {x_label:labels[i], value:this.values[i], key:this.key}; + mc.tooltip = tooltip; + + // add the MovieClip to our array: + this.bar_mcs[i] = mc; + } + } + + public function valPos( b:Box, right_axis:Boolean, min:Number, bar_count:Number, bar:Number ) + { + this.ExPoints=Array(); + + var item_width:Number = b.width_() / this.values.length; + + // the bar(s) have gaps between them: + var bar_set_width:Number = item_width*_root._bars_width; + // get the margin between sets of bars: + var bar_left:Number = b.left_()+((item_width-bar_set_width)/2); + // 1 bar == 100% wide, 2 bars = 50% wide each + var bar_width:Number = bar_set_width/bar_count; + + for( var i:Number=0; i < this.values.length; i++) + { + var tmp:PointHLC = b.makePointHLC( + i, + this.values[i].high, + this.values[i].close, + this.values[i].low, + right_axis, + bar, + bar_count + ); + + tmp.make_tooltip( + _root.get_tooltip_string(), + this.key, + this.values[i], + _root.get_x_legend(), + _root.get_x_axis_label(i) + ); + + //var tooltip:Object = {x_label:labels[i], value:this.values[i], key:this.key}; + //mc.tooltip = tooltip; + + this.ExPoints.push( tmp ); + } + } + + public function draw_bar( val:Object, i:Number ) + { + var top:Number; + var line_width:Number = this.line_width; + + var center:Number = val.width/2; + + var mc:MovieClip = this.bar_mcs[i]; + mc.clear(); + mc._alpha = 100; + + // vert line + mc.rect2( center-(line_width/2), 0, line_width, -(val.high-val.low), this.colour, 100 ); + // horizontal line + mc.rect2( center-(line_width/2), val.close-val.high, val.width,line_width, this.colour, 100 ); + // trace ("close" + (val.close)); + // trace ("high" + (val.high)); + // trace ("low" + (val.low)); + // trace ("c-h" + (val.close-val.high)); + // trace ("h-l" + (val.high-val.low)); + // trace ("---------"); + // make an invisible rectangle for the tooltip: + mc.rect2( 0, 0, val.width, val.low-val.high, 0xff0000, 0 ); + + mc._x = val.x; + mc._y = val.high; + + mc._alpha = this.alpha; + mc._alpha_original = this.alpha; // <-- remember our original alpha while tweening + + // this is used in _root.FadeIn and _root.FadeOut + //mc.val = val; + + // we return this MovieClip to FilledBarStyle + return mc; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/InnerBackground.as b/public/includes/ofc-1.9/actionscript/InnerBackground.as new file mode 100755 index 000000000..3262d777b --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/InnerBackground.as @@ -0,0 +1,75 @@ +class InnerBackground +{ + private var colour:Number=0; + private var colour_2:Number=-1; + private var angle:Number = 90; + private var mc:MovieClip; + + function InnerBackground( lv:LoadVars ) + { + if( lv.inner_background == undefined ) + return; + + var vals:Array = lv.inner_background.split(","); + + this.colour = _root.get_colour( vals[0] ); + + trace( this.colour) + + if( vals.length > 1 ) + this.colour_2 = _root.get_colour( vals[1] ); + + if( vals.length > 2 ) + this.angle = Number( vals[2] ); + + this.mc = _root.createEmptyMovieClip( "inner_background", _root.getNextHighestDepth() ); + + // create shadow filter + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 5; + dropShadow.blurY = 5; + dropShadow.distance = 5; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.5; + // apply shadow filter + + // disabled for now... + //this.mc.filters = [dropShadow]; + + } + + function move( box:Box ) + { + if( this.mc == undefined ) + return; + + this.mc.clear(); + this.mc.lineStyle(1, 0xFFFFFF, 0); + + if( this.colour_2 > -1 ) + { + // Gradients: http://www.lukamaras.com/tutorials/actionscript/gradient-colored-movie-background-actionscript.html + var fillType:String = "linear"; + var colors:Array = [this.colour, this.colour_2]; + var alphas:Array = [100, 100]; + var ratios:Array = [0, 255]; + var matrix = {matrixType:"box", x:0, y:0, w:box.width, h:box.height, r:this.angle/180*Math.PI}; + this.mc.beginGradientFill(fillType, colors, alphas, ratios, matrix); + } + else + this.mc.beginFill( this.colour, 100); + + + this.mc.moveTo(0, 0); + this.mc.lineTo(box.width, 0); + this.mc.lineTo(box.width, box.height); + this.mc.lineTo(0, box.height); + this.mc.lineTo(0, 0); + this.mc.endFill(); + + this.mc._x = box.left; + this.mc._y = box.top; + } + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Invisible.as b/public/includes/ofc-1.9/actionscript/Invisible.as new file mode 100755 index 000000000..acc4d8b5e --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Invisible.as @@ -0,0 +1,68 @@ +class Invisible +{ + // + // This is a FILTHY hack. + // + // A flash movie CAN NOT tell when the mouse has left it, + // so we use this invisible layer to do the job for us. + // + // For this to work we need to pass mouse_move events down + // to the bars and lines. + // + private var mc:MovieClip; + + // when we hover over an item, it gives us + // the on_click stuff to deal with (because it + // never gets the click event (see hack above) + private var link:String; + + function Invisible( lv:Object ) + { + this.mc = _root.createEmptyMovieClip( "tooltipX_mouse_out", _root.getNextHighestDepth() ); + + // + // ask _root to remove our tool tip + // + this.mc.onRollOut = function() { + _root.mouse_over( false ); // <-- tell every item we are NOT over it + _root.tooltip_x.hide(); + }; + + this.mc.onMouseMove = _root.mouse_move; + + var tmp = this; + this.mc.onRelease = function() { + trace( 'Click '+tmp.link ); + if( tmp.link != undefined ) + getURL( tmp.link ); + + }; + + this.mc.useHandCursor = false; + } + + function move( b:Box ) + { + this.mc.clear(); + this.mc.rect2( 0, 0, b.width, b.height, 0, 0 ); // <-- set alpha to 50 for debug! + this.mc._x = b.left; + this.mc._y = b.top; + } + + function hitTest( x:Number, y:Number ) + { + return this.mc.hitTest( x, y ); + } + + function use_hand( link:String ) + { + this.mc.useHandCursor = true; + this.link = link; + } + + function use_arrow() + { + this.mc.useHandCursor = false; + this.link = undefined; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Keys.as b/public/includes/ofc-1.9/actionscript/Keys.as new file mode 100755 index 000000000..fe78a53e2 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Keys.as @@ -0,0 +1,117 @@ +class Keys +{ + private var _height:Number = 0; + public var left:Number = 0; + public var top:Number = 0; + + private var count:Number = 0; + private var key_mcs:Array; + + function Keys( left:Number, top:Number, styles:Array ) + { + this.left = left; + this.top = top; + + this.key_mcs = Array(); + var key:Number = 0; + for( var i=0; i 0) and (styles[i].key != '' ) ) + { + this.key_mcs.push( this.make_key( styles[i], key ) ); + key++; + } + } + + this.count = key; + + this.move(); + } + + // + // this should be in the destructor, but + // actionscript does not support them :-( + // + function del() + { + for( var i=0; i Stage.width ) + { + // it is past the edge of the stage, so move it down a line + x = left; + top += this.key_mcs[i]._height; + height += this.key_mcs[i]._height; + } + + this.key_mcs[i]._x = x; + this.key_mcs[i]._y = top; + + // move next key to the left + some padding between keys + x += width + 10; + } + + // Ugly code: + height += this.key_mcs[0]._height; + this._height = height; + } + + function height() + { + return this._height; + } + + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/LineDot.as b/public/includes/ofc-1.9/actionscript/LineDot.as new file mode 100755 index 000000000..862bcfae1 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/LineDot.as @@ -0,0 +1,68 @@ +class LineDot extends LineStyle +{ + public var bgColour:Number=0; + public var mcs:Array; + + public function LineDot( lv:Object, name:String ) + { + this.mcs=[]; + this.values = []; + + this.bgColour = _root.get_background_colour(); + this.name = 'line_dot'+name; + + var vals:Array = lv[this.name].split(","); + + this.line_width = Number( vals[0] ); + this.colour = _root.get_colour( vals[1] ); + + if( vals.length > 2 ) + this.key = vals[2].replace('#comma#',','); + + if( vals.length > 3 ) + this.font_size = Number( vals[3] ); + + if( length( vals ) > 4 ) + this.circle_size = Number( vals[4] ); + + //this.mc2 = _root.createEmptyMovieClip(name, _root.getNextHighestDepth()); + this.mc2.clear(); + this.mc2.lineStyle( 0, 0, 0); + this.mc2.fillCircle( 0, 0, this.circle_size+2, 15, this.bgColour ); + this.mc2.fillCircle( 0, 0, this.circle_size+1, 15, this.colour ); + this.mc2._visible = false; + + // we need to remeber if the mouse + // is over this movie clip + this.mc2._is_over = false; + + this.set_values( lv['values'+name].split(",") ); + this.set_links( lv['links'+name] ); + this.set_tooltips( lv['tool_tips_set'+name] ); + + } + + // delete the left most value + function del() + { + removeMovieClip(this.mcs[0]._name); + this.mcs.shift(); + this.values.shift(); + } + + public function draw() + { + super.draw(); + + if( this.circle_size == 0 ) + return; + + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + var val:Point = this.ExPoints[i]; + this.mc.lineStyle( 0, 0, 0); + this.mc.fillCircle( val.x, val.y, this.circle_size, 15, this.bgColour ); + this.mc.fillCircle( val.x, val.y, this.circle_size-1, 15, this.colour ); + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/LineHollow.as b/public/includes/ofc-1.9/actionscript/LineHollow.as new file mode 100755 index 000000000..893202d41 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/LineHollow.as @@ -0,0 +1,56 @@ +class LineHollow extends LineStyle +{ + public var bgColour:Number=0; + public var mcs:Array; + + public function LineHollow( lv:Object, name:String ) + { + this.mcs=[]; + this.values = []; + + this.bgColour = _root.get_background_colour(); + this.name = 'line_hollow'+name; + + var vals:Array = lv[this.name].split(","); + this.line_width = Number( vals[0] ); + this.colour = _root.get_colour( vals[1] ); + + if( vals.length > 2 ) + this.key = vals[2]; + + if( vals.length > 3 ) + this.font_size = Number( vals[3] ); + + if( length( vals ) > 4 ) + this.circle_size = Number( vals[4] ); + + this.mc2 = _root.createEmptyMovieClip( name+'_hightlight', _root.getNextHighestDepth()); + this.mc2.lineStyle( 0, 0, 0); + this.mc2.fillCircle( 0, 0, this.circle_size+2, 15, this.colour ); + this.mc2.fillCircle( 0, 0, this.circle_size-this.line_width+2, 15, this.bgColour); + this.mc2._visible = false; + // we need to remeber if the mouse + // is over this movie clip + this.mc2._is_over = false; + + this.set_values( lv['values'+name].split(",") ); + this.set_links( lv['links'+name] ); + this.set_tooltips( lv['tool_tips_set'+name] ); + } + + public function draw() + { + super.draw(); + + if( this.circle_size == 0 ) + return; + + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + var val:Point = this.ExPoints[i]; + this.mc.lineStyle( 0, 0, 0); + this.mc.fillCircle( val.x, val.y, this.circle_size, 15, this.colour ); + this.mc.fillCircle( val.x, val.y, this.circle_size-this.line_width, 15, this.bgColour ); + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/LineStyle.as b/public/includes/ofc-1.9/actionscript/LineStyle.as new file mode 100755 index 000000000..c782a2a88 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/LineStyle.as @@ -0,0 +1,244 @@ +import caurina.transitions.Tweener; + +class LineStyle extends Style +{ + private var mc:MovieClip; + private var mc2:MovieClip; + public var name:String; + + public function LineStyle( lv:Object, name:String ) + { + this.name = 'line'+name; + + var vals:Array = lv[this.name].split(","); + this.line_width = Number( vals[0] ); + this.colour = _root.get_colour( vals[1] ); + + if( vals.length > 2 ) + this.key = vals[2].replace('#comma#',','); + + if( vals.length > 3 ) + this.font_size = Number( vals[3] ); + + if( length( vals ) > 4 ) + this.circle_size = Number( vals[4] ); + + this.mc = _root.createEmptyMovieClip(name, _root.getNextHighestDepth()); + this.make_highlight_dot(); + this.set_values( lv['values'+name].split(",") ); + this.set_links( lv['links'+name] ); + this.set_tooltips( lv['tool_tips_set'+name] ); + } + + private function make_highlight_dot() + { + this.mc2 = _root.createEmptyMovieClip('highlight'+name, _root.getNextHighestDepth()); + this.mc2.lineStyle( 0, 0, 0); + this.mc2.fillCircle( 0, 0, 6, 15, 0xFFFFFF ); + this.mc2.fillCircle( 0, 0, 5, 15, this.colour ); + this.mc2._visible = false; + // we need to remeber if the mouse + // is over this movie clip + this.mc2._is_over = false; + } + + public function valPos( b:Box, right_axis:Boolean, min:Number ) + { + this.ExPoints=Array(); + + var x_legend:String = ''; + if( _root._x_legend != undefined ) + + + for( var i:Number=0; i < this.values.length; i++) + { + + if( this.values[i] == 'null' ) + { + this.ExPoints.push( null ); + } + else + { + var tmp:Point = b.make_point( i, Number(this.values[i]), right_axis ); + + tmp.make_tooltip( + _root.get_tooltip_string(), + this.key, + Number(this.values[i]), + _root.get_x_legend(), + _root.get_x_axis_label(i), + this.tooltips[i] + ); + + this.ExPoints.push( tmp ); + } + } + } + + // Draw lines... + public function draw() + { + this.mc.clear(); + this.mc.lineStyle( this.line_width, this.colour, 100); // <-- alpha 0 to 100 + + var first:Boolean = true; + + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + // skip null values + if( this.ExPoints[i] != null ) + { + if( first ) + { + this.mc.moveTo(this.ExPoints[i].x,this.ExPoints[i].y); + first = false; + } + else + this.mc.lineTo(this.ExPoints[i].x,this.ExPoints[i].y); + + } + } + } + + public function highlight_value() + { + var found:Boolean = false; + + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + if( this.ExPoints[i].is_tip ) + { + this.mc2._x = this.ExPoints[i].x; + this.mc2._y = this.ExPoints[i].y; + this.mc2._visible = true; + found = true; + break; + } + } + if( !found ) + this.mc2._visible = false; + } + + private function rollOver() + {} + + public function closest( x:Number, y:Number ) + { + var shortest:Number = Number.MAX_VALUE; + var point:Point = null; + var dx:Number; + + for( var i:Number=0; i < this.ExPoints.length; i++) + { + this.ExPoints[i].is_tip = false; + + dx = Math.abs( x - this.ExPoints[i].x ); + + if( dx < shortest ) + { + shortest = dx; + point = this.ExPoints[i]; + } + } + var dy:Number = Math.abs( y - point.y ); + return { point:point, distance_x:shortest, distance_y:dy }; + } + + // called by AreaHollow, LineHollow + public function make_dot( mc:MovieClip, col:Number, bg:Number, tool_tip_title:String, tool_tip_value:String ) + { + + if( tool_tip_title != undefined ) + mc.tool_tip_title = tool_tip_title; + else + mc.tool_tip_title = ''; + + mc.tool_tip_value = tool_tip_value; + + //mc.onRollOver = _root.circleBig; + + // + // extremely curious syntax, but it works. + // add a roll over function to the MovieClip + // + var ref = mc; + mc.onRollOver = function(){ + ref._width += 4; + ref._height += 4; + _root.show_tip( this, this._x, this._y-20, this.tool_tip_title, this.tool_tip_value ); + }; + + // make the circle shrink and remove tooltip: + mc.onRollOut = function(){ + _root.hide_tip( this ); + ref._width -= 4; + ref._height -= 4; + }; + + mc.lineStyle( 0, bg, 100); + mc.fillCircle( 0, 0, this.circle_size, 15, bg ); + mc.fillCircle( 0, 0, this.circle_size-1, 15, col); + } + + public function move_dot( val:Point, mc:MovieClip ) + { + //trace(val.center); + // Move and fix the dots... + mc._x = val.x; + mc._y = val.y; + } + + public function is_over( x:Number, y:Number ) + { + if( x<0 ) + { + this.mc2._visible = false; + return; + } + + // is the mouse over our highlight dot? + if( this.mc2.hitTest(x,y) ) + { + if( !this.mc2._is_over ) + { + this.mc2._is_over = true; + + var i:Number=0; + for( i=0; i-1;c--) + { + if( pos%3==0 && s.length>0 ) + { + s=','+s; + pos=0; + } + pos++; + + s=x.substr(c,1)+s; + } + if( num[1] != undefined ) { + if (isFixedNumDecimalsForced){ + num[1] += "0000000000000000"; + } + s += '.'+ num[1].substr(0,numDecimals); + } else { + if (isFixedNumDecimalsForced && numDecimals>0){ + num[1] = "0000000000000000"; + s += '.'+ num[1].substr(0,numDecimals); + } + + } + + if( i<0 ) + s = '-'+s; + + if (isThousandSeparatorDisabled){ + s=s.replace (",",""); + } + + if (isDecimalSeparatorComma) { + s = toDecimalSeperatorComma(s); + } + return s; + } + + public static function toDecimalSeperatorComma (value:String){ + return value + .replace(".","|") + .replace(",",".") + .replace("|",",") + } + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Parser.as b/public/includes/ofc-1.9/actionscript/Parser.as new file mode 100755 index 000000000..7cc168d19 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Parser.as @@ -0,0 +1,160 @@ +class Parser { + + //test if undefined or null + public static function isEmptyValue ( value:Object){ + if( value == undefined || value == null ) { + return true; + } else { + return false; + } + } + + + + + // get valid String value from input value + // if value is not defined, return default value + // default value is valid String (cannot be undefined or null) + // in case that isEmptyStringValid is false - take defaultvalue instead of value + public static function getStringValue ( + value:Object, + defaultValue:String , + isEmptyStringValid:Boolean ):String{ + + //defaultValue if not defined - set to empty String + if( Parser.isEmptyValue (defaultValue)) { + defaultValue = ""; + } + + //for undefined / null - return defaultValue + if( Parser.isEmptyValue (value)) { + return defaultValue; + } + + if (!isEmptyStringValid && value.length == 0) { + return defaultValue; + } + + return String(value); + } + + + + + + // get valid Number value from input value + // if value is not defined, return default value + // default value is valid String (cannot be undefined or null) + // in case that isEmptyStringValid is false - take defaultvalue instead of value + public static function getNumberValue ( + value:Object, + defaultValue:Number , + isZeroValueValid:Boolean , + isNegativeValueValid:Boolean + ):Number{ + + //defaultValue if not defined - set to zero + if( Parser.isEmptyValue (defaultValue) + || isNaN(defaultValue) + ) { + defaultValue = 0; + } + + //for undefined / null - return defaultValue + if( Parser.isEmptyValue (value) ) { + return defaultValue; + } + + var numValue = Number(value); + if ( isNaN (numValue) ){ + return defaultValue; + } + + if (!isZeroValueValid && numValue==0) { + return defaultValue; + } + + if (!isNegativeValueValid && numValue<0) { + return defaultValue; + } + + return numValue; + + } + + + + public static function getBooleanValue ( + value:Object, + defaultValue:Boolean + ):Boolean{ + + if( Parser.isEmptyValue (value) ) { + return defaultValue; + } + + var numValue = Number(value); + if ( !isNaN (numValue) ){ + //for numeric value then 0 is false, everything else is true + if (numValue==0) { + return false; + } else { + return true; + } + } + + //parse string falue 'true' -> true; else false + var strValue = Parser.getStringValue (value,"false", false); +//trace ("0------------------" + strValue); + strValue = strValue.toLowerCase(); +//trace ("1------------------" + strValue); + if (strValue.indexOf('true') !=-1){ + return true; + } else { + return false; + } + + } + + + + public static function runTests():Void{ + var notDefinedNum:Number; + trace ("testing Parser.getStringValue..."); + trace("1) stringOK '" + Parser.getStringValue("stringOK","myDefault",true) + "'"); + trace("2) '' '" + Parser.getStringValue("","myDefault",true) + "'"); + trace("3) myDefault '" + Parser.getStringValue("","myDefault",false) + "'"); + trace("4) '' '" + Parser.getStringValue(notDefinedNum) + "'"); + trace("5) 999 '" + Parser.getStringValue(999) + "'"); + + + trace ("testing Parser.getNumberValue..."); + trace("01) 999 '" + Parser.getNumberValue(999,22222222,true,true) + "'"); + trace("02) 999 '" + Parser.getNumberValue("999",22222222,true,true) + "'"); + trace("03) 999 '" + Parser.getNumberValue("999") + "'"); + trace("04) 0 '" + Parser.getNumberValue("abc") + "'"); + trace("05) -1 '" + Parser.getNumberValue("abc",-1) + "'"); + trace("06) -1 '" + Parser.getNumberValue("abc",-1, false, false) + "'"); + trace("07) -1 '" + Parser.getNumberValue(null,-1, false, false) + "'"); + trace("08) 22222222 '" + Parser.getNumberValue(0,22222222) + "'"); + trace("09) 0 '" + Parser.getNumberValue(0,22222222,true) + "'"); + trace("10) 22222222 '" + Parser.getNumberValue(0,22222222,false) + "'"); + trace("11) 22222222 '" + Parser.getNumberValue(0,22222222,false,false) + "'"); + trace("12) 22222222 '" + Parser.getNumberValue(-0.1,22222222,false,false) + "'"); + trace("13) -0.1 '" + Parser.getNumberValue(-0.1,22222222,false,true) + "'"); + trace("13) 22222222 '" + Parser.getNumberValue("-0.1x",22222222,false,true) + "'"); + + trace ("testing Parser.getBooleanValue..."); + trace("true '" + Parser.getBooleanValue("1",false) + "'"); + trace("true '" + Parser.getBooleanValue("-1",false) + "'"); + trace("false '" + Parser.getBooleanValue("0.000",false) + "'"); + trace("false '" + Parser.getBooleanValue("",false) + "'"); + trace("true '" + Parser.getBooleanValue("",true) + "'"); + trace("false '" + Parser.getBooleanValue("false",false) + "'"); + trace("false '" + Parser.getBooleanValue("xxx",false) + "'"); + trace("true '" + Parser.getBooleanValue("true",true) + "'"); + trace("true '" + Parser.getBooleanValue("TRUE",true) + "'"); + trace("true '" + Parser.getBooleanValue(" TRUE ",true) + "'"); + } + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/PieStyle.as b/public/includes/ofc-1.9/actionscript/PieStyle.as new file mode 100755 index 000000000..b3d2a1576 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/PieStyle.as @@ -0,0 +1,384 @@ +import flash.external.ExternalInterface; +import mx.transitions.Tween; +import mx.transitions.easing.*; + +class PieStyle extends Style +{ + var TO_RADIANS:Number = Math.PI/180; + var labels:Array; + var links:Array; + var colours:Array; + + public var values:Array; + + private var pie_mcs:Array; + public var name:String; + + private var gradientFill:String = 'true'; //toggle gradients + private var border_width:Number = 1; + private var label_line:Number; + private var easing:Function; + private var style:Css; + + public function PieStyle( lv:LoadVars, name:String ) + { + this.labels = new Array(); + this.links = new Array(); + this.colours = new Array(); + + this.name = 'pie'+name; + + this.parse( lv['pie'] ); + this.labels = lv['pie_labels'].split(','); + this.links = lv['links'].split(','); + + var tmp:Array; + if( lv.colours != undefined ) + tmp = lv.colours.split(','); + + // allow for both spellings fo colour. + if( lv.colors != undefined ) + tmp = lv.colours.split(','); + + + for( var i:Number=0; i 3 ) + this.gradientFill = vals[3]; + + if( vals.length > 4 ) + this.border_width = vals[4]; + + } + + private function parseVals( val:String ):Array + { + var tmp:Array = Array(); + + var vals:Array = val.split(","); + for( var i:Number=0; i < vals.length; i++ ) + { + tmp.push( vals[i] ); + } + return tmp; + } + + // override Style:set_values + function set_values( v:Array ) + { + super.set_values( v ); + + // make an empty array to hold each bar MovieClip: + this.pie_mcs = new Array( this.values.length ); + + for( var i:Number=0; i < this.values.length; i++ ) + { + var mc:MovieClip = _root.createEmptyMovieClip( this.name+'_'+i, _root.getNextHighestDepth() ); + + mc.onRollOver = function() {ChartUtil.FadeIn(this, true); }; + mc.onRollOut = function() {ChartUtil.FadeOut(this); }; + + if(this.links.length>i) + { + mc._ofc_link = this.links[i]; + mc.onRelease = function ():Void { trace(this._ofc_link); getURL(this._ofc_link); }; + } + + // this is used in FadeIn and FadeOut + var tooltip:Object = {x_label:this.labels[i], value:this.values[i], key:'??'}; + mc.tooltip = tooltip; + + // add the MovieClip to our array: + this.pie_mcs[i] = mc; + } + + this.valPos(); + } + + private function valPos() : Void + { + this.ExPoints = new Array(); + + var total:Number = 0; + var slice_start:Number=0; + for( var i:Number=0; i < this.values.length; i++) + { + total += Number(values[i]); + } + + for( var i:Number=0; i < this.values.length; i++) + { + var slice_percent :Number = Number(this.values[i])*100/total; + + if( slice_percent >= 0 ) + { + this.ExPoints.push( + new ExPoint( + slice_start, // x position of value + 0, // center (not applicable for a bar) + Number(this.values[i]), //y + slice_percent,//width + // min=-100 and max=100, use b.zero + // min = 10 and max = 20, use b.bottom + slice_start, //bar bottom + //ChartUtil.format(slice_percent)+"%"+"\n"+ChartUtil.format(values[i]), //tooltip + //_root.format(slice_percent)+"%"+"\n"+_root.format(values[i]) + slice_percent + //,"#" //link + ) + ); + } + + slice_start += slice_percent; + } + } + + public function draw( top:Number ) : Void + { + this.clear_mcs( Stage.width/2, ((Stage.height-top)/2)+top ); + + //radius for the pie + //var rad:Number = (Stage.width<(Stage.height-top-60)) ? Stage.width/2 : (Stage.height-top-60)/2; + var rad:Number = (Stage.width0 && this.style.get( 'display' ) != 'none' ) + { + this.init_labels(); + + var tfs:Array = Array(); + + // CSS style is NOT none, so create the text field objects + for( var i:Number=0; i < this.ExPoints.length; i++ ) + tfs.push( this.create_label( i, this.labels[i] ) ); + + // + // start off with the radius at 100%, then keep shrinking it untill + // all the labels fit into the Stage. + + // 2007-11-14 modified by veljac99: + // - impproved algorithm for finding radius which reduces number of itterations ( from 24 to 6 - using data-13.txt ) + + + var radMax:Number = rad; // maximum is 100%% + var radMin:Number = rad * 0.1; // minimum is 10% + var radTest:Number = (radMax + radMin) * 0.7; // assume 70% (instead of usual 50%) + labelLineSize = radTest+this.label_line; + + //tollerance - stop caclulations if we are inside acceptable tollerance (here is 2% with minimum 2 points) + var tollerance:Number = radMax * 0.02; + if (tollerance<2) + tollerance=2; //2 percent tollerance but minimum 2 + var iterations:Number=0; // to avoid endless loop - allow only 30 itterations + + var outside:Boolean = false; + do + { + iterations +=1; + + for( var i:Number=0; i < tfs.length; i++ ) + { + var angle:Number = this.ExPoints[i].bar_bottom+this.ExPoints[i].bar_width/2; + outside = outside || this.move_label( tfs[i], labelLineSize, this.pie_mcs[i]._x, this.pie_mcs[i]._y, angle ); + } + + //found? Great. Go out! + if ( (radMax - radMin)<= tollerance || iterations>30 /*30 = max itterationa*/ ){ + rad = radTest; + trace( 'break' ); + trace( "rad: " + rad + " iterations: " + iterations ); + trace('--'); + break; + } + + //not found - adopt and try again + // trace ( "outside: " + outside + + // " [" + radMin + " - " + radMax + "] radTest:" + radTest + // + " iterations: " + iterations + // ); + + + if (outside) { + radMax = radTest; + } else { + radMin = radTest; + } + radTest = (radMax + radMin)/2; + + labelLineSize = radTest+this.label_line; + outside = false; + + }while( true ); + + } //end if( this.labels.length>0 ) + + this.draw_all(rad); + } + + function draw_all(rad:Number) + { + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + //this.draw_bits( rad, this.ExPoints[i], this.pie_mcs[i], , this.labels[i], this.links[i], i ); + this.draw_slice( this.pie_mcs[i], rad, this.colours[i%this.colours.length], this.ExPoints[i].bar_width ); + // draw the line from the slice to the label + if( this.labels.length>0 && this.style.get( 'display' ) != 'none' ) + this.draw_label_line( this.pie_mcs[i], rad, this.label_line, this.ExPoints[i].bar_width ); + + //rotate slice to appropriate place in pie + //pieSlice._rotation = 3.6*value.bar_bottom; + var t:Tween = new Tween( this.pie_mcs[i], "_rotation", this.easing, 0, 3.6*this.ExPoints[i].bar_bottom, 120, false); + } + } + + function clear_mcs( x:Number, y:Number ) + { + for( var i:Number=0; i < this.ExPoints.length; i++ ) + { + var mc:MovieClip = this.pie_mcs[i]; + //the slice to be drawn + mc.clear(); + //move slice to center + mc._x = x; + mc._y = y; + + mc._alpha = this.alpha; + mc._alpha_original = this.alpha; // <-- remember our original alpha while tweening + } + } + + // draw the line from the pie slice to the label + function draw_label_line( pieSlice:MovieClip, rad:Number, tick_size:Number, slice_angle:Number ) + { + //draw line + pieSlice.lineStyle( 1, this.colour, 100 ); + //move to center of arc + pieSlice.moveTo(rad*Math.cos(slice_angle/2*3.6*TO_RADIANS), rad*Math.sin(slice_angle/2*3.6*TO_RADIANS)); + + //final line positions + var lineEnd_x:Number = (rad+tick_size)*Math.cos(slice_angle/2*3.6*TO_RADIANS); + var lineEnd_y:Number = (rad+tick_size)*Math.sin(slice_angle/2*3.6*TO_RADIANS); + pieSlice.lineTo(lineEnd_x, lineEnd_y); + } + + function init_labels() + { + //create legend text field + for( var i:Number=0; i < this.ExPoints.length; i++ ) + if( _root["pie_text_"+i] != undefined ) + _root["pie_text_"+i].removeTextField(); + } + + function create_label( num:Number, label:String ) + { + var tf:TextField = _root.createTextField("pie_text_"+num, _root.getNextHighestDepth(), 0, 0, 10, 10); + + tf.text = label; + // legend_tf._rotation = 3.6*value.bar_bottom; + + var fmt:TextFormat = new TextFormat(); + fmt.color = this.style.get( 'color' ); + fmt.font = "Verdana"; + fmt.size = this.style.get( 'font-size' ); + fmt.align = "center"; + tf.setTextFormat(fmt); + //tf.autoSize = true; + tf.autoSize = "left"; + return tf; + } + + function move_label( tf:TextField, rad:Number, x:Number, y:Number, ang:Number ) + { + //text field position + var legend_x:Number = x+rad*Math.cos((ang)*3.6*TO_RADIANS); + var legend_y:Number = y+rad*Math.sin((ang)*3.6*TO_RADIANS); + + //if legend stands to the right side of the pie + if(legend_x0) && (tf._y>0) && (tf._y+tf._height'+_root.format(val); + } + + this.tooltip = tmp; + } + + function get_tip_pos() + { + return {x:this.x, y:this.y}; + } + + public function toString() + { + return "x :"+ this.x; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/PointBar.as b/public/includes/ofc-1.9/actionscript/PointBar.as new file mode 100755 index 000000000..7c4e98bd8 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/PointBar.as @@ -0,0 +1,17 @@ +class PointBar extends Point +{ + public var width:Number; + public var bar_bottom:Number; + + public function PointBar( x:Number, y:Number, width:Number, bar_bottom:Number ) + { + super( x, y ); + this.width = width; + this.bar_bottom = bar_bottom; + } + + function get_tip_pos() + { + return {x:this.x+(this.width/2), y:this.y}; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/PointCandle.as b/public/includes/ofc-1.9/actionscript/PointCandle.as new file mode 100755 index 000000000..e552b0b36 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/PointCandle.as @@ -0,0 +1,38 @@ +class PointCandle extends Point +{ + public var width:Number; + public var bar_bottom:Number; + public var high:Number; + public var open:Number; + public var close:Number; + public var low:Number; + + public function PointCandle( x:Number, high:Number, open:Number, close:Number, low:Number, tooltip:Number, width:Number ) + { + super( x, high, tooltip ); + + this.width = width; + this.high = high; + this.open = open; + this.close = close; + this.low = low; + } + + public function make_tooltip( tip:String, key:String, val:Object, x_legend:String, x_axis_label:String ) + { + super.make_tooltip( tip, key, val.open, x_legend, x_axis_label ); + + var tmp:String = this.tooltip; + tmp = tmp.replace('#high#',_root.format(val.high)); + tmp = tmp.replace('#open#',_root.format(val.open)); + tmp = tmp.replace('#close#',_root.format(val.close)); + tmp = tmp.replace('#low#',_root.format(val.low)); + + this.tooltip = tmp; + } + + function get_tip_pos() + { + return {x:this.x+(this.width/2), y:this.y}; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/PointHLC.as b/public/includes/ofc-1.9/actionscript/PointHLC.as new file mode 100755 index 000000000..df6c016d8 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/PointHLC.as @@ -0,0 +1,39 @@ +class PointHLC extends Point +{ +// private var numDecimals:Number =5; +// private var isFixedNumDecimalsForced:Boolean =true; +// private var isDecimalSeparatorComma:Boolean =true; + + public var width:Number; + public var bar_bottom:Number; + public var high:Number; + public var close:Number; + public var low:Number; + + public function PointHLC( x:Number, high:Number, close:Number, low:Number, tooltip:Number, width:Number ) + { + super( x, high, tooltip ); + + this.width = width; + this.high = high; + this.close = close; + this.low = low; + } + + public function make_tooltip( tip:String, key:String, val:Object, x_legend:String, x_axis_label:String ) + { + super.make_tooltip( tip, key, val.close, x_legend, x_axis_label ); + + var tmp:String = this.tooltip; + tmp = tmp.replace('#high#',NumberUtils.formatNumber(val.high)); + tmp = tmp.replace('#close#',NumberUtils.formatNumber(val.close)); + tmp = tmp.replace('#low#',NumberUtils.formatNumber(val.low)); + + this.tooltip = tmp; + } + + function get_tip_pos() + { + return {x:this.x+(this.width/2), y:this.y}; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/PointScatter.as b/public/includes/ofc-1.9/actionscript/PointScatter.as new file mode 100755 index 000000000..38e164bd3 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/PointScatter.as @@ -0,0 +1,4 @@ +class PointScatter extends Point +{ + public var size:Number; +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/README.txt b/public/includes/ofc-1.9/actionscript/README.txt new file mode 100755 index 000000000..1971c2228 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/README.txt @@ -0,0 +1,16 @@ +Open Flash Chart, displays data as a chart in flash. +Copyright (C) 2007 John Glazebrook + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Scatter.as b/public/includes/ofc-1.9/actionscript/Scatter.as new file mode 100755 index 000000000..cea9fb7c8 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Scatter.as @@ -0,0 +1,228 @@ +class Scatter extends Style +{ + public var bgColour:Number=0; + private var mc:MovieClip; + private var mc2:MovieClip; + public var name:String; + + public function Scatter( lv:Object, name:String ) + { + this.bgColour = _root.get_background_colour(); + + this.name = 'scatter'+name; + var vals:Array = lv[this.name].split(","); + + this.line_width = Number( vals[0] ); + this.colour = _root.get_colour( vals[1] ); + + if( vals.length > 2 ) + this.key = vals[2]; + + if( vals.length > 3 ) + this.font_size = Number( vals[3] ); + + if( length( vals ) > 4 ) + this.circle_size = Number( vals[4] ); + + this.mc = _root.createEmptyMovieClip(name, _root.getNextHighestDepth()); + this.mc2 = _root.createEmptyMovieClip(name, _root.getNextHighestDepth()); + this.mc2.fillCircle( 0, 0, 7, 15, 0xFFFFFF ); + this.mc2.fillCircle( 0, 0, 5, 15, this.colour ); + this.mc2._visible = false; + + this.set_values( lv['values'+name] ); + } + + // a group looks like "[x,y]" + private function parse_group( g:String ) + { + var group:Array = g.split(','); + this.values.push( + { + x: Number( group[0] ), + y: Number( group[1] ), + size: Number( group[2] ) + } + ); + } + + function groups( vals:String ) + { + var groups:Array=new Array(); + var tmp:String = ''; + var start:Boolean = false; + + for( var i=0; i' ); + + if( lines.length > 1 ) + this.mc.txt_title.text = lines.shift(); + else + this.mc.txt_title.text = ''; + + var fmt:TextFormat = new TextFormat(); + fmt.color = 0x0000F0; + fmt.font = "Verdana"; + // this needs to be an option: + fmt.bold = true; + fmt.size = 12; + fmt.align = "right"; + this.mc.txt_title.setTextFormat(fmt); + this.mc.txt_title.autoSize="left"; + + this.mc.txt._y = this.mc.txt_title._height; + this.mc.txt.text = lines.join( '\n' ); + var fmt2:TextFormat = new TextFormat(); + fmt2.color = 0x000000; + fmt2.font = "Verdana"; + fmt2.size = 12; + fmt2.align = "left"; + this.mc.txt.setTextFormat(fmt2); + this.mc.txt.autoSize="left"; + + var max_width:Number = Math.max( this.mc.txt_title._width, this.mc.txt._width ); + var y_pos:Number = this.mc._y - this.mc.txt_title._height - this.mc.txt._height; + + if( y_pos < 0 ) + { + // the tooltip has drifted off the top of the screen, move it down: + y_pos = this.mc._y + this.mc.txt_title._height + this.mc.txt._height; + } + + var cstroke = {width:2, color:0x808080, alpha:100}; + var ccolor = {color:0xf0f0f0, alpha:100}; + + ChartUtil.rrectangle( + this.mc, + max_width+10, + this.mc.txt_title._height + this.mc.txt._height + 5, + 6, + ((x+max_width+16) > Stage.width ) ? (Stage.width-max_width-16) : x, + y_pos, + cstroke, + ccolor); + + this.mc._visible = true; + var t:Tween = new Tween( this.mc, "_x", Strong.easeOut, old_x, this.mc._x, 10, false ); + var u:Tween = new Tween( this.mc, "_y", Strong.easeOut, old_y, this.mc._y, 10, false ); + } + + public function hide() + { + //this.myTween = new Tween( this.mc, "_alpha", mx.transitions.easing.Regular.easeOut, this.mc._x, x, 10, false ); + var t:Tween = new Tween( this.mc, "_alpha", Regular.easeOut, 100, 0, 20, false); + var tmp = this; + t.onMotionFinished = function() { + tmp.mc._visible = false; + tmp.mc._alpha = 100; + }; + } +/* + public function hide__() + { + this.mc.onEnterFrame = function () + { + this._alpha -= 5; + if( this._alpha < 0 ) + { + this._visible = false; + this._alpha = 100; + delete this.onEnterFrame; + } + }; + } +*/ +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/Values.as b/public/includes/ofc-1.9/actionscript/Values.as new file mode 100755 index 000000000..98cab7534 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/Values.as @@ -0,0 +1,184 @@ +class Values +{ + public var styles:Array; + + private var attach_right:Array; + + public function Values( lv:LoadVars, x_axis_labels:Array ) + { + this.styles = []; + var name:String = ''; + var c:Number=1; + + do + { + if( c>1 ) name = '_'+c; + + if( lv['values'+name ] != undefined ) + { + this.styles[c-1] = this.make_style( lv, name, c ); + + // + // BUG: These need to be fixed at some point: + // + if( lv['candle'+name] != undefined ) + this.styles[c-1].set_values( lv['values'+name], x_axis_labels, lv['links'+name] ); + else if( lv['hlc'+name] != undefined ) + this.styles[c-1].set_values( lv['values'+name], x_axis_labels, lv['links'+name] ); + + } + else + break; // <-- stop loading data + + c++; + } + while( true ); + + + var y2:Boolean = false; + var y2lines:Array; + + // + // some data sets are attached to the right + // Y axis (and min max) + // + this.attach_right = Array(); + + if( lv.show_y2 != undefined ) + if( lv.show_y2 != 'false' ) + if( lv.y2_lines != undefined ) + { + this.attach_right = lv.y2_lines.split(","); + } + } + + + + private function make_style( lv:LoadVars, name:String, c:Number ) + { + if( lv['line'+name] != undefined ) + return new LineStyle(lv,name); + else if( lv['line_dot'+name] != undefined ) + return new LineDot(lv,name); + else if( lv['line_hollow'+name] != undefined ) + return new LineHollow(lv,name); + else if( lv['area_hollow'+name] != undefined ) + return new AreaHollow(lv,name); + else if( lv['bar'+name] != undefined ) + return new BarStyle(lv,name); + else if( lv['filled_bar'+name] != undefined ) + return new FilledBarStyle(lv,name); + else if( lv['bar_glass'+name] != undefined ) + return new BarGlassStyle(lv,name); + else if( lv['bar_fade'+name] != undefined ) + return new BarFade(lv,name); + else if( lv['bar_zebra'+name] != undefined ) + return new BarZebra(lv['bar_zebra'+name],'bar_'+c); + else if( lv['bar_arrow'+name] != undefined ) + return new BarArrow(lv,name); + else if( lv['bar_3d'+name] != undefined ) + return new Bar3D(lv,name); + else if( lv['pie'+name] != undefined ) + return new PieStyle(lv,name); + else if( lv['candle'+name] != undefined ) + return new CandleStyle(lv,name); + else if( lv['scatter'+name] != undefined ) + return new Scatter(lv,name); + else if( lv['hlc'+name] != undefined ) + return new HLCStyle(lv,name); + else if( lv['bar_sketch'+name] != undefined ) + return new BarSketchStyle(lv,name); + + } + + private function parseVal( val:String ):Array + { + var tmp:Array = Array(); + + var vals:Array = val.split(","); + for( var i:Number=0; i < vals.length; i++ ) + { + tmp.push( vals[i] ); + } + return tmp; + } + + public function length() + { + var max:Number = -1; + + for(var i:Number=0; i 4 ) + { + this.alt_axis_step = style[3]; + this.alt_axis_colour = _root.get_colour(style[4]); + } + + // + // this is set later when the chart has more information + // + this.grid_count = 1; + + // tick every X value? + if( steps==undefined ) + this.x_steps = 1; + else + this.x_steps = steps; + + this.mc = _root.createEmptyMovieClip( "x_axis", _root.getNextHighestDepth() ); + + } + + // grid lines, depends on number of values, + // the X Axis labels and X min and X max + function set_grid_count( val:Number ) + { + this.grid_count = val; + } + + function get_grid_count( val:Number ) + { + return this.grid_count; + } + + function move( box:Box ) + { + this.mc.clear(); + + // + // Grid lines + // + for( var i:Number=0; i < this.grid_count; i+=this.x_steps ) + { + if( ( this.alt_axis_step > 1 ) && ( i % this.alt_axis_step == 0 ) ) + { + this.mc.lineStyle(1,this.alt_axis_colour,100); + } + else + { + this.mc.lineStyle(1,this.grid_colour,100); + } + + var x:Number = box.get_x_pos(i); + this.mc.moveTo( x, box.bottom); + this.mc.lineTo( x, box.top); + + this.mc.moveTo( x, box.bottom); + this.mc.lineTo( x, box.top); + } + + if( this.three_d ) + this.three_d_axis( mc, box ); + else + this.two_d_axis( mc, box ); + } + + function three_d_axis( mc:MovieClip, box:Box ) + { + + // for 3D + var h:Number = this.three_d_height; + var offset:Number = 12; + var x_axis_height:Number = h+offset; + + // + // ticks + var item_width:Number = box.width / this.grid_count; + + this.mc.lineStyle(1, this.axis_colour, 100); + var w:Number = 1; + for( var i:Number=0; i < this.grid_count; i+=this.x_steps ) + { + // + // uncommenting beginFill and endFill causes big bugs??! + // + //this.mc.beginFill(this.axis_colour,100); + var pos:Number = box.get_x_tick_pos(i); + + this.mc.moveTo( pos, box.bottom+x_axis_height); + this.mc.lineTo( pos+w, box.bottom+x_axis_height); + this.mc.lineTo( pos+w, box.bottom+x_axis_height+this.tick); + this.mc.lineTo( pos, box.bottom+x_axis_height+this.tick); + this.mc.lineTo( pos, box.bottom+x_axis_height); + //this.mc.endFill(); + } + + + // turn off out lines: + mc.lineStyle(0, 0, 0); + + var lighter:Number = ChartUtil.Lighten( this.axis_colour ); + + // TOP + var colors:Array = [this.axis_colour,lighter]; + var alphas:Array = [100,100]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:box.left-offset, y:box.bottom, w:box.width_(), h:offset, r:(270/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + this.mc.moveTo(box.left,box.bottom); + this.mc.lineTo(box.right,box.bottom); + this.mc.lineTo(box.right-offset,box.bottom+offset); + this.mc.lineTo(box.left-offset,box.bottom+offset); + this.mc.endFill(); + + // front + var colors:Array = [this.axis_colour,lighter]; + var alphas:Array = [100,100]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:box.left-offset, y:box.bottom+offset, w:box.width_(), h:h, r:(270/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + this.mc.moveTo(box.left-offset,box.bottom+offset); + this.mc.lineTo(box.right-offset,box.bottom+offset); + this.mc.lineTo(box.right-offset,box.bottom+offset+h); + this.mc.lineTo(box.left-offset,box.bottom+offset+h); + this.mc.endFill(); + + // right side + var colors:Array = [this.axis_colour,lighter]; + var alphas:Array = [100,100]; + var ratios:Array = [0,255]; + var matrix:Object = { matrixType:"box", x:box.left-offset, y:box.bottom+offset, w:box.width_(), h:h, r:(225/180)*Math.PI }; + mc.beginGradientFill("linear", colors, alphas, ratios, matrix); + this.mc.moveTo(box.right,box.bottom); + this.mc.lineTo(box.right,box.bottom+h); + this.mc.lineTo(box.right-offset,box.bottom+offset+h); + this.mc.lineTo(box.right-offset,box.bottom+offset); + this.mc.endFill(); + + } + + // 2D: + function two_d_axis( mc:MovieClip, box:Box ) + { + // + // ticks + var item_width:Number = box.width / this.grid_count; + var left:Number = box.left+(item_width/2); + // + this.mc.lineStyle(2,this.axis_colour,100); + for( var i:Number=0; i < this.grid_count; i+=this.x_steps ) + { + var pos:Number = box.get_x_tick_pos(i); + this.mc.moveTo( pos, box.bottom ); + this.mc.lineTo( pos, box.bottom+this.tick ); + //this.mc.moveTo(left + (i*item_width),box.bottom); + //this.mc.lineTo(left + (i*item_width),box.bottom+this.tick); + } + + // Axis line: + this.mc.lineStyle(2,this.axis_colour,100); + this.mc.moveTo(box.left,box.bottom); + this.mc.lineTo(box.right,box.bottom); + + } + + function height_() + { + return 2 + this.tick; + } + + function height() + { + if( this.three_d ) + { + // 12 is the size of the slanty + // 3D part of the X axis + return this.three_d_height+12+this.tick; + } + else + return this.tick; + } + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/XAxisLabels.as b/public/includes/ofc-1.9/actionscript/XAxisLabels.as new file mode 100755 index 000000000..a932d1d7a --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/XAxisLabels.as @@ -0,0 +1,168 @@ +class XAxisLabels +{ + private var mcs:Array; + private var style:XLabelStyle; + public var labels:Array; + + function XAxisLabels( lv:LoadVars, style:XLabelStyle, minmax:MinMax ) + { + + this.style = style; + this.labels = []; + this.mcs = Array(); + + if( lv.x_labels != undefined ) + { + var labels:Array = lv.x_labels.split(','); + // what if there are more values than labels? + + for( var i:Number=0; i < labels.length; i++ ) + { + this.add( labels[i].replace('#comma#',',') ); + } + } + else + { + // they *may* have used x_min and x_max to set + // the X Axis labels + if( style.show_labels ) + for( var i:Number=minmax.x_min; i<=minmax.x_max; i++ ) + this.add( _root.format( i ) ); + } + } + + function add( label:String ) + { + this.labels.push( label ); + + if( ( (this.labels.length-1) % style.step ) ==0 ) + this.show_label( label, 'x_label_'+String(this.labels.length) ); + } + + function get( i:Number ) + { + if( i-1 ) + { + this.show_labels = false; + } + } + else + { + this.show_labels = true; + + var tmp:Array = lv.x_label_style.split(','); + if( tmp.length > 0 ) + this.size = tmp[0]; + + if( tmp.length > 1 ) + this.colour = _root.get_colour(tmp[1]); + + if( tmp.length > 2 ) + { + this.vertical = (Number(tmp[2])==1); + this.diag = (Number(tmp[2])==2); + } + + if( tmp.length > 3 ) + if( Number(tmp[3]) > 0 ) + this.step = Number(tmp[3]); + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/XLegend.as b/public/includes/ofc-1.9/actionscript/XLegend.as new file mode 100755 index 000000000..27a27c205 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/XLegend.as @@ -0,0 +1,73 @@ +class XLegend extends Title +{ + + // override the MovieClip name: + private var name:String = 'x_legend'; + public var mc:TextField; + + function XLegend( lv:LoadVars ) + { + if( lv.x_legend == undefined ) + return; + + var tmp:Array = lv.x_legend.split(','); + + var text:String = tmp[0].replace('#comma#',','); + this.size = Number( tmp[1] ); + this.colour = _root.get_colour( tmp[2] ); + + // call our parent (Title) constructor: + // super.build( text ); + + // while no CSS : + this.build( text ); + } + + // remove when this gets CSS + function build( text:String ) + { + this.title = text; + + if( this.mc == undefined ) + this.mc = _root.createTextField( 'title', _root.getNextHighestDepth(), 0, 0, 200, 200 ); + + this.mc.text = this.title; + + var fmt:TextFormat = new TextFormat(); + fmt.color = this.colour; + fmt.font = "Verdana"; + + fmt.size = this.size; + + fmt.align = "center"; + + this.mc.setTextFormat(fmt); + this.mc.autoSize = "left"; + } + + function get_legend() + { + return this.title; + } + + function move() + { + // this will center it in the X + super.move(); + // this will align bottom: + this.mc._y = Stage.height - this.mc._height; + } + + // + // this is only here while title has CSS and x legend does not. + // remove this when we put css in this object + // + function height() + { + // the title may be turned off: + if( this.mc == undefined ) + return 0; + else + return this.mc._height; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/YAxis.as b/public/includes/ofc-1.9/actionscript/YAxis.as new file mode 100755 index 000000000..bfcda4e3c --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/YAxis.as @@ -0,0 +1,147 @@ +class YAxis +{ + private var _width:Number=0; + private var ticks:YTicks; + private var grid_colour:Number; + private var axis_colour:Number; + //private var count:Number; + private var mc:MovieClip; + private var line_width:Number = 2; + + private var min:Number; + private var max:Number; + private var steps:Number; + + private var right:Boolean; + + function YAxis( y_ticks:YTicks, lv:LoadVars, min:Number, max:Number, steps:Number, nr:Number ) + { + // ticks: thin and wide ticks + this.ticks = y_ticks; + + if( lv.y_grid_colour != undefined ) + this.grid_colour = _root.get_colour( lv.y_grid_colour ); + else + this.grid_colour = 0xF5E1AA; + + this.right = (nr==2); + if( !this.right ) + { + if( lv.y_axis_colour != undefined ) + this.axis_colour = _root.get_colour( lv.y_axis_colour ); + else + this.axis_colour = 0x784016; + } + else + { + if( lv.y2_axis_colour != undefined ) + this.axis_colour = _root.get_colour( lv.y2_axis_colour ); + else + this.axis_colour = 0x784016; + } + + //this.count = count; + this.min = min; + this.max = max; + this.steps = steps; + + if( !this.right ) + this.mc = _root.createEmptyMovieClip( "y_axis", _root.getNextHighestDepth() ); + else + this.mc = _root.createEmptyMovieClip( "y_axis2", _root.getNextHighestDepth() ); + + this._width = this.line_width + Math.max( this.ticks.small, this.ticks.big ); + } + + function move( box:Box ) + { + if( this.right ) + { + this._move_right( box ); + } + else + { + this._move_left( box ); + } + } + + function _move_left( box:Box ) + { + // this should be an option: + this.mc.clear(); + + // Grid lines + this.mc.lineStyle(1,this.grid_colour,100); + + // y axel grid lines + var every:Number = (this.max-this.min)/this.steps; + // Set opacity for the first line to 0 (otherwise it overlaps the x-axel line) + // + // Bug? Does this work on graphs with minus values? + // + var i2:Number=0; + for( var i:Number=this.min; i<=this.max; i+=every ) + { + var y:Number = box.getY(i); + if(i2 == 0) + this.mc.lineStyle(1,this.grid_colour,0); + + this.mc.moveTo( box.left, y ); + this.mc.lineTo( box.right, y ); + + if(i2 == 0) + this.mc.lineStyle(1,this.grid_colour,100); + i2 +=1; + } + + + this.mc.lineStyle(this.line_width,this.axis_colour,100); + + this.mc.moveTo( box.left, box.top ); + this.mc.lineTo( box.left, box.bottom ); + + // ticks.. + var every:Number = (this.max-this.min)/this.steps; + for( var i:Number=this.min; i<=this.max; i+=every ) + { + // start at the bottom and work up: + var y:Number = box.getY(i,false); + + this.mc.moveTo( box.left, y ); + if( i % this.ticks.steps == 0 ) + this.mc.lineTo( box.left-this.ticks.big, y ); + else + this.mc.lineTo( box.left-this.ticks.small, y ); + + } + } + + function _move_right( box:Box ) + { + // Create the new axel + this.mc.clear(); + this.mc.lineStyle( this.line_width, this.axis_colour, 100 ); + + this.mc.moveTo( box.right, box.top ); + this.mc.lineTo( box.right, box.bottom ); + + // create new ticks.. + var every:Number = (this.max-this.min)/this.steps; + for( var i:Number=this.min; i<=this.max; i+=every ) + { + // start at the bottom and work up: + var y:Number = box.getY(i); + this.mc.moveTo( box.right, y ); + if( i % this.ticks.steps == 0 ) + this.mc.lineTo( box.right+this.ticks.big, y ); + else + this.mc.lineTo( box.right+this.ticks.small, y ); + } + } + + function width() + { + return this._width; + } + +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/YAxisLabels.as b/public/includes/ofc-1.9/actionscript/YAxisLabels.as new file mode 100755 index 000000000..35fe0ebb5 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/YAxisLabels.as @@ -0,0 +1,109 @@ +class YAxisLabels +{ + public var labels:Array; + private var steps:Number; + private var right:Boolean; + + function YAxisLabels( y_label_style:YLabelStyle, min:Number, max:Number, steps:Number, nr:Number, lv:LoadVars ) + { + this.steps = steps; + this.labels = Array(); + this.right = nr==2; + + var name:String = ''; + + if( !this.right ) + { + // are the Y Labels visible? + if( !y_label_style.show_labels ) + return; + + name = 'y_label_'; + } + else + { + // is the right Y axis enabled? + if( !lv.show_y2 ) + return; + + // are the Y Labels visible? + if( !y_label_style.show_labels ) + return; + + name = 'y_label_2_'; + } + + // labels + var every:Number = (max-min)/this.steps; + var count:Number = 0; + for( var i:Number=min; i<=max; i+=every ) + { + var title:String = _root.format_y_axis_label(i); + + var tmp = { + textfield: this.yAxisLabel( title, name+String(count++), y_label_style, nr ), + value: i + }; + this.labels.push( tmp ); + } + } + + + + function yAxisLabel( title:String, name:String, y_label_style:YLabelStyle ) + { + // does _root already have this textFiled defined? + // this happens when we do an AJAX reload() + // these have to be deleted by hand or else flash goes wonky. + // In an ideal world we would put this code in the object + // distructor method, but I don't think actionscript has these :-( + if( _root[name] != undefined ) + _root[name].removeTextField(); + + //var mc:MovieClip = _root.createEmptyMovieClip( name, _root.getNextHighestDepth() ); + var tf:TextField = _root.createTextField(name, _root.getNextHighestDepth(), 0, 0, 100, 100); + //tf.border = true; + tf.text = title; + var fmt:TextFormat = new TextFormat(); + fmt.color = y_label_style.colour; + fmt.font = "Verdana"; + fmt.size = y_label_style.size; + fmt.align = "right"; + tf.setTextFormat(fmt); + tf.autoSize="right"; + + return tf; + } + + // move y axis labels to the correct x pos + function move( left:Number, box:Box ) + { + var maxWidth:Number = this.width(); + + for( var i=0; i-1 ) + { + this.show_labels = false; + } + } + else + { + var tmp:Array = lv.y_label_style.split(','); + if( tmp.length > 0 ) + this.size = tmp[0]; + + if( tmp.length > 1 ) + this.colour = _root.get_colour(tmp[1]); + } + } + else + { + // if (nr.. + + if( lv.y2_label_style == undefined ) + return; + + // is it CSV? + var comma:Number = lv.y2_label_style.lastIndexOf(','); + + if( comma<0 ) + { + var none:Number = lv.y2_label_style.lastIndexOf('none',0); + if( none>-1 ) + { + this.show_labels = false; + } + } + else + { + var tmp:Array = lv.y2_label_style.split(','); + if( tmp.length > 0 ) + this.size = tmp[0]; + + if( tmp.length > 1 ) + this.colour = _root.get_colour(tmp[1]); + } + + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/YLegend.as b/public/includes/ofc-1.9/actionscript/YLegend.as new file mode 100755 index 000000000..b40ce5d15 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/YLegend.as @@ -0,0 +1,69 @@ +class YLegend +{ + public var mc:TextField = undefined; + + function YLegend( lv:LoadVars, nr:Number ) + { + + if( lv.y_legend == undefined && lv.y2_legend == undefined) + return; + + // parse the data file string: + if(nr == 2) + var tmp:Array = lv.y2_legend.split(','); + else + var tmp:Array = lv.y_legend.split(','); + + var text:String = tmp[0].replace('#comma#',','); + var size:Number = Number( tmp[1] ); + var colour:Number = _root.get_colour( tmp[2] ); + + if(text == undefined) return; + + if(nr == 1) + this.mc = _root.createTextField("y_legend", _root.getNextHighestDepth(), 0, 0, 200, 200); + else + this.mc = _root.createTextField("y2_legend", _root.getNextHighestDepth(), 0, 0, 200, 200); + + + + this.mc.text = text; + // so we can rotate the text + this.mc.embedFonts = true; + + var fmt:TextFormat = new TextFormat(); + fmt.color = colour; + // our embedded font - so we can rotate it + // library->new font, linkage + fmt.font = "Verdana_embed"; + + fmt.size = size; + fmt.align = "center"; + + this.mc.setTextFormat(fmt); + this.mc.autoSize = "left"; + this.mc._rotation = 270; + this.mc.autoSize = "left"; + } + + function move(nr:Number) + { + + if( this.mc == undefined ) + return; + + this.mc._y = (Stage.height/2)+(this.mc._height/2); + if(nr == 2) + this.mc._x = Stage.width-this.mc._width; + else + this.mc._x = 0; + } + + function width() + { + if( this.mc == undefined ) + return 0; + else + return this.mc._width; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/YTicks.as b/public/includes/ofc-1.9/actionscript/YTicks.as new file mode 100755 index 000000000..fb1f7a2c9 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/YTicks.as @@ -0,0 +1,21 @@ +class YTicks +{ + // default tick sizes (small,big,big every step): + public var big:Number = 5; + public var small:Number = 2; + public var steps:Number = 2; + + function YTicks( lv:LoadVars ) + { + if( lv.y_ticks != undefined ) + { + var ticks:Array = lv.y_ticks.split(','); + if( ticks.length == 3 ) + { + this.small = Number(ticks[0]); + this.big = Number(ticks[1]); + this.steps = Number(ticks[2]); + } + } + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/AuxFunctions.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/AuxFunctions.as new file mode 100755 index 000000000..5409580de --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/AuxFunctions.as @@ -0,0 +1,88 @@ +/** + * Generic, auxiliary functions + * + * @author Zeh Fernando + * @version 1.0.0 + */ + +class caurina.transitions.AuxFunctions { + + /** + * Gets the R (xx0000) bits from a number + * + * @param p_num Number Color number (ie, 0xffff00) + * @return Number The R value + */ + public static function numberToR(p_num:Number):Number { + // The initial & is meant to crop numbers bigger than 0xffffff + return (p_num & 0xff0000) >> 16; + } + + /** + * Gets the G (00xx00) bits from a number + * + * @param p_num Number Color number (ie, 0xffff00) + * @return Number The G value + */ + public static function numberToG(p_num:Number):Number { + return (p_num & 0xff00) >> 8; + } + + /** + * Gets the B (0000xx) bits from a number + * + * @param p_num Number Color number (ie, 0xffff00) + * @return Number The B value + */ + public static function numberToB(p_num:Number):Number { + return (p_num & 0xff); + } + + /** + * Checks whether a string is on an array + * + * @param p_string String String to search for + * @param p_array Array Array to be searched + * @return Boolean Whether the array contains the string or not + */ + public static function isInArray(p_string:String, p_array:Array):Boolean { + var l:Number = p_array.length; + for (var i:Number = 0; i < l; i++) { + if (p_array[i] == p_string) return true; + } + return false; + } + + /** + * Returns the number of properties an object has + * + * @param p_object Object Target object with a number of properties + * @return Number Number of total properties the object has + */ + public static function getObjectLength(p_object:Object):Number { + var totalProperties:Number = 0; + for (var pName:String in p_object) totalProperties ++; + return totalProperties; + } + + /* Takes a variable number of objects as parameters and "adds" their properties, form left to right. If a latter object defines a property as null, it will be removed from the final object + * @param args Object(s) A variable number of objects + * @return Object An object with the sum of all paremeters added as properties. + */ + public static function concatObjects(/*objects to concat*/) : Object{ + var finalObject : Object = {}; + var currentObject : Object; + for (var i : Number = 0; i < arguments.length; i++){ + currentObject = arguments[i]; + for (var prop : String in currentObject){ + if (currentObject[prop] == null){ + // delete in case is null + delete finalObject[prop]; + }else{ + finalObject[prop] = currentObject[prop] + } + } + } + return finalObject; + } +} \ No newline at end of file diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/Equations.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/Equations.as new file mode 100755 index 000000000..767fb2a50 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/Equations.as @@ -0,0 +1,692 @@ +/** + * Equations + * Main equations for the Tweener class + * + * @author Zeh Fernando, Nate Chatellier + * @version 1.0.2 + */ + +/* +Disclaimer for Robert Penner's Easing Equations license: + +TERMS OF USE - EASING EQUATIONS + +Open source under the BSD License. + +Copyright © 2001 Robert Penner +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import caurina.transitions.Tweener; + +class caurina.transitions.Equations { + + /** + * There's no constructor. + */ + public function Equations () { + trace ("Equations is a static class and should not be instantiated.") + } + + /** + * Registers all the equations to the Tweener class, so they can be found by the direct string parameters. + * This method doesn't actually have to be used - equations can always be referenced by their full function + * names. But "registering" them make them available as their shorthand string names. + */ + public static function init():Void { + Tweener.registerTransition("easenone", easeNone); + Tweener.registerTransition("linear", easeNone); // mx.transitions.easing.None.easeNone + + Tweener.registerTransition("easeinquad", easeInQuad); // mx.transitions.easing.Regular.easeIn + Tweener.registerTransition("easeoutquad", easeOutQuad); // mx.transitions.easing.Regular.easeOut + Tweener.registerTransition("easeinoutquad", easeInOutQuad); // mx.transitions.easing.Regular.easeInOut + Tweener.registerTransition("easeoutinquad", easeOutInQuad); + + Tweener.registerTransition("easeincubic", easeInCubic); + Tweener.registerTransition("easeoutcubic", easeOutCubic); + Tweener.registerTransition("easeinoutcubic", easeInOutCubic); + Tweener.registerTransition("easeoutincubic", easeOutInCubic); + + Tweener.registerTransition("easeinquart", easeInQuart); + Tweener.registerTransition("easeoutquart", easeOutQuart); + Tweener.registerTransition("easeinoutquart", easeInOutQuart); + Tweener.registerTransition("easeoutinquart", easeOutInQuart); + + Tweener.registerTransition("easeinquint", easeInQuint); + Tweener.registerTransition("easeoutquint", easeOutQuint); + Tweener.registerTransition("easeinoutquint", easeInOutQuint); + Tweener.registerTransition("easeoutinquint", easeOutInQuint); + + Tweener.registerTransition("easeinsine", easeInSine); + Tweener.registerTransition("easeoutsine", easeOutSine); + Tweener.registerTransition("easeinoutsine", easeInOutSine); + Tweener.registerTransition("easeoutinsine", easeOutInSine); + + Tweener.registerTransition("easeincirc", easeInCirc); + Tweener.registerTransition("easeoutcirc", easeOutCirc); + Tweener.registerTransition("easeinoutcirc", easeInOutCirc); + Tweener.registerTransition("easeoutincirc", easeOutInCirc); + + Tweener.registerTransition("easeinexpo", easeInExpo); // mx.transitions.easing.Strong.easeIn + Tweener.registerTransition("easeoutexpo", easeOutExpo); // mx.transitions.easing.Strong.easeOut + Tweener.registerTransition("easeinoutexpo", easeInOutExpo); // mx.transitions.easing.Strong.easeInOut + Tweener.registerTransition("easeoutinexpo", easeOutInExpo); + + Tweener.registerTransition("easeinelastic", easeInElastic); // mx.transitions.easing.Elastic.easeIn + Tweener.registerTransition("easeoutelastic", easeOutElastic); // mx.transitions.easing.Elastic.easeOut + Tweener.registerTransition("easeinoutelastic", easeInOutElastic); // mx.transitions.easing.Elastic.easeInOut + Tweener.registerTransition("easeoutinelastic", easeOutInElastic); + + Tweener.registerTransition("easeinback", easeInBack); // mx.transitions.easing.Back.easeIn + Tweener.registerTransition("easeoutback", easeOutBack); // mx.transitions.easing.Back.easeOut + Tweener.registerTransition("easeinoutback", easeInOutBack); // mx.transitions.easing.Back.easeInOut + Tweener.registerTransition("easeoutinback", easeOutInBack); + + Tweener.registerTransition("easeinbounce", easeInBounce); // mx.transitions.easing.Bounce.easeIn + Tweener.registerTransition("easeoutbounce", easeOutBounce); // mx.transitions.easing.Bounce.easeOut + Tweener.registerTransition("easeinoutbounce", easeInOutBounce); // mx.transitions.easing.Bounce.easeInOut + Tweener.registerTransition("easeoutinbounce", easeOutInBounce); + } + + // ================================================================================================================================== + // TWEENING EQUATIONS functions ----------------------------------------------------------------------------------------------------- + // (the original equations are Robert Penner's work as mentioned on the disclaimer) + + /** + * Easing equation function for a simple linear tweening, with no easing + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeNone (t:Number, b:Number, c:Number, d:Number):Number { + return c*t/d + b; + } + + /** + * Easing equation function for a quadratic (t^2) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInQuad (t:Number, b:Number, c:Number, d:Number):Number { + return c*(t/=d)*t + b; + } + + /** + * Easing equation function for a quadratic (t^2) easing out: decelerating to zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutQuad (t:Number, b:Number, c:Number, d:Number):Number { + return -c *(t/=d)*(t-2) + b; + } + + /** + * Easing equation function for a quadratic (t^2) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutQuad (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + } + + /** + * Easing equation function for a quadratic (t^2) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInQuad (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutQuad (t*2, b, c/2, d); + return easeInQuad((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for a cubic (t^3) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInCubic (t:Number, b:Number, c:Number, d:Number):Number { + return c*(t/=d)*t*t + b; + } + + /** + * Easing equation function for a cubic (t^3) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutCubic (t:Number, b:Number, c:Number, d:Number):Number { + return c*((t=t/d-1)*t*t + 1) + b; + } + + /** + * Easing equation function for a cubic (t^3) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutCubic (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + } + + /** + * Easing equation function for a cubic (t^3) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInCubic (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutCubic (t*2, b, c/2, d); + return easeInCubic((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for a quartic (t^4) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInQuart (t:Number, b:Number, c:Number, d:Number):Number { + return c*(t/=d)*t*t*t + b; + } + + /** + * Easing equation function for a quartic (t^4) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutQuart (t:Number, b:Number, c:Number, d:Number):Number { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + } + + /** + * Easing equation function for a quartic (t^4) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutQuart (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + } + + /** + * Easing equation function for a quartic (t^4) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInQuart (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutQuart (t*2, b, c/2, d); + return easeInQuart((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for a quintic (t^5) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInQuint (t:Number, b:Number, c:Number, d:Number):Number { + return c*(t/=d)*t*t*t*t + b; + } + + /** + * Easing equation function for a quintic (t^5) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutQuint (t:Number, b:Number, c:Number, d:Number):Number { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + } + + /** + * Easing equation function for a quintic (t^5) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutQuint (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + } + + /** + * Easing equation function for a quintic (t^5) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInQuint (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutQuint (t*2, b, c/2, d); + return easeInQuint((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInSine (t:Number, b:Number, c:Number, d:Number):Number { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + } + + /** + * Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutSine (t:Number, b:Number, c:Number, d:Number):Number { + return c * Math.sin(t/d * (Math.PI/2)) + b; + } + + /** + * Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutSine (t:Number, b:Number, c:Number, d:Number):Number { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + } + + /** + * Easing equation function for a sinusoidal (sin(t)) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInSine (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutSine (t*2, b, c/2, d); + return easeInSine((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for an exponential (2^t) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInExpo (t:Number, b:Number, c:Number, d:Number):Number { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b - c * 0.001; + } + + /** + * Easing equation function for an exponential (2^t) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutExpo (t:Number, b:Number, c:Number, d:Number):Number { + return (t==d) ? b+c : c * 1.001 * (-Math.pow(2, -10 * t/d) + 1) + b; + } + + /** + * Easing equation function for an exponential (2^t) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutExpo (t:Number, b:Number, c:Number, d:Number):Number { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b - c * 0.0005; + return c/2 * 1.0005 * (-Math.pow(2, -10 * --t) + 2) + b; + } + + /** + * Easing equation function for an exponential (2^t) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInExpo (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutExpo (t*2, b, c/2, d); + return easeInExpo((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for a circular (sqrt(1-t^2)) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInCirc (t:Number, b:Number, c:Number, d:Number):Number { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + } + + /** + * Easing equation function for a circular (sqrt(1-t^2)) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutCirc (t:Number, b:Number, c:Number, d:Number):Number { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + } + + /** + * Easing equation function for a circular (sqrt(1-t^2)) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutCirc (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + } + + /** + * Easing equation function for a circular (sqrt(1-t^2)) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInCirc (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutCirc (t*2, b, c/2, d); + return easeInCirc((t*2)-d, b+c/2, c/2, d); + } + + /** + * Easing equation function for an elastic (exponentially decaying sine wave) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param a Number Amplitude + * @param p Number Period + * @return Number The correct value + */ + public static function easeInElastic (t:Number, b:Number, c:Number, d:Number, a:Number, p:Number):Number { + var s:Number; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; s=p/4; } + else s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + } + + /** + * Easing equation function for an elastic (exponentially decaying sine wave) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param a Number Amplitude + * @param p Number Period + * @return Number The correct value + */ + public static function easeOutElastic (t:Number, b:Number, c:Number, d:Number, a:Number, p:Number):Number { + var s:Number; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; s=p/4; } + else s = p/(2*Math.PI) * Math.asin (c/a); + return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b); + } + + /** + * Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param a Number Amplitude + * @param p Number Period + * @return Number The correct value + */ + public static function easeInOutElastic (t:Number, b:Number, c:Number, d:Number, a:Number, p:Number):Number { + var s:Number; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (!a || a < Math.abs(c)) { a=c; s=p/4; } + else s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + } + + /** + * Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param a Number Amplitude + * @param p Number Period + * @return Number The correct value + */ + public static function easeOutInElastic (t:Number, b:Number, c:Number, d:Number, a:Number, p:Number):Number { + if (t < d/2) return easeOutElastic (t*2, b, c/2, d, a, p); + return easeInElastic((t*2)-d, b+c/2, c/2, d, a, p); + } + + /** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param s Number Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent) + * @return Number The correct value + */ + public static function easeInBack (t:Number, b:Number, c:Number, d:Number, s:Number):Number { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + } + + /** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param s Number Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent) + * @return Number The correct value + */ + public static function easeOutBack (t:Number, b:Number, c:Number, d:Number, s:Number):Number { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + } + + /** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param s Number Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent) + * @return Number The correct value + */ + public static function easeInOutBack (t:Number, b:Number, c:Number, d:Number, s:Number):Number { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + } + + /** + * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @param s Number Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent) + * @return Number The correct value + */ + public static function easeOutInBack (t:Number, b:Number, c:Number, d:Number, s:Number):Number { + if (t < d/2) return easeOutBack (t*2, b, c/2, d, s); + return easeInBack((t*2)-d, b+c/2, c/2, d, s); + } + + /** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInBounce (t:Number, b:Number, c:Number, d:Number):Number { + return c - easeOutBounce (d-t, 0, c, d) + b; + } + + /** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutBounce (t:Number, b:Number, c:Number, d:Number):Number { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + } + + /** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeInOutBounce (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeInBounce (t*2, 0, c, d) * .5 + b; + else return easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b; + } + + /** + * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: deceleration until halfway, then acceleration + * + * @param t Number Current time (in frames or seconds) + * @param b Number Starting value + * @param c Number Change needed in value + * @param d Number Expected easing duration (in frames or seconds) + * @return Number The correct value + */ + public static function easeOutInBounce (t:Number, b:Number, c:Number, d:Number):Number { + if (t < d/2) return easeOutBounce (t*2, b, c/2, d); + return easeInBounce((t*2)-d, b+c/2, c/2, d); + } + +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/PropertyInfoObj.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/PropertyInfoObj.as new file mode 100755 index 000000000..4466e3b20 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/PropertyInfoObj.as @@ -0,0 +1,68 @@ +/** + * PropertyInfoObj + * An object containing the updating info for a given property (its starting value, and its final value) + * + * @author Zeh Fernando + * @version 1.0.0 + * @private + */ + +class caurina.transitions.PropertyInfoObj { + + public var valueStart :Number; // Starting value of the tweening (null if not started yet) + public var valueComplete :Number; // Final desired value + public var hasModifier :Boolean; // Whether or not it has a modifier function + public var modifierFunction :Function; // Modifier function, if any + public var modifierParameters :Array; // Additional array of modifier parameters + + // ================================================================================================================================== + // CONSTRUCTOR function ------------------------------------------------------------------------------------------------------------- + + /** + * Initializes the basic PropertyInfoObj. + * + * @param p_valueStart Number Starting value of the tweening (null if not started yet) + * @param p_valueComplete Number Final (desired) property value + */ + function PropertyInfoObj(p_valueStart:Number, p_valueComplete:Number, p_modifierFunction:Function, p_modifierParameters:Array) { + valueStart = p_valueStart; + valueComplete = p_valueComplete; + hasModifier = p_modifierFunction != undefined; + modifierFunction = p_modifierFunction; + modifierParameters = p_modifierParameters; + } + + + // ================================================================================================================================== + // OTHER functions ------------------------------------------------------------------------------------------------------------------ + + /** + * Clones this property info and returns the new PropertyInfoObj + * + * @param omitEvents Boolean Whether or not events such as onStart (and its parameters) should be omitted + * @return TweenListObj A copy of this object + */ + public function clone():PropertyInfoObj { + var nProperty:PropertyInfoObj = new PropertyInfoObj(valueStart, valueComplete, modifierFunction, modifierParameters); + return nProperty; + } + + /** + * Returns this object described as a String. + * + * @return String The description of this object. + */ + public function toString():String { + var returnStr:String = "\n[PropertyInfoObj "; + returnStr += "valueStart:" + String(valueStart); + returnStr += ", "; + returnStr += "valueComplete:" + String(valueComplete); + returnStr += ", "; + returnStr += "modifierFunction:" + String(modifierFunction); + returnStr += ", "; + returnStr += "modifierParameters:" + String(modifierParameters); + returnStr += "]\n"; + return returnStr; + } + +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertiesDefault.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertiesDefault.as new file mode 100755 index 000000000..4124cda61 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertiesDefault.as @@ -0,0 +1,414 @@ +/** + * SpecialPropertiesDefault + * List of default special properties (normal and splitter properties) for the Tweener class + * The function names are strange/inverted because it makes for easier debugging (alphabetic order). They're only for internal use (on this class) anyways. + * + * @author Zeh Fernando, Nate Chatellier + * @version 1.0.2 + */ + +import caurina.transitions.Tweener; +import caurina.transitions.AuxFunctions; +import flash.filters.BitmapFilter; +import flash.filters.BlurFilter; + +class caurina.transitions.SpecialPropertiesDefault { + + /** + * There's no constructor. + */ + public function SpecialPropertiesDefault () { + trace ("SpecialProperties is an static class and should not be instantiated.") + } + + /** + * Registers all the special properties to the Tweener class, so the Tweener knows what to do with them. + */ + public static function init():Void { + + // Normal properties + Tweener.registerSpecialProperty("_frame", _frame_get, _frame_set); + Tweener.registerSpecialProperty("_sound_volume", _sound_volume_get, _sound_volume_set); + Tweener.registerSpecialProperty("_sound_pan", _sound_pan_get, _sound_pan_set); + Tweener.registerSpecialProperty("_color_ra", _color_property_get, _color_property_set, ["ra"]); + Tweener.registerSpecialProperty("_color_rb", _color_property_get, _color_property_set, ["rb"]); + Tweener.registerSpecialProperty("_color_ga", _color_property_get, _color_property_set, ["ga"]); + Tweener.registerSpecialProperty("_color_gb", _color_property_get, _color_property_set, ["gb"]); + Tweener.registerSpecialProperty("_color_ba", _color_property_get, _color_property_set, ["ba"]); + Tweener.registerSpecialProperty("_color_bb", _color_property_get, _color_property_set, ["bb"]); + Tweener.registerSpecialProperty("_color_aa", _color_property_get, _color_property_set, ["aa"]); + Tweener.registerSpecialProperty("_color_ab", _color_property_get, _color_property_set, ["ab"]); + Tweener.registerSpecialProperty("_autoAlpha", _autoAlpha_get, _autoAlpha_set); + + // Normal splitter properties + Tweener.registerSpecialPropertySplitter("_color", _color_splitter); + Tweener.registerSpecialPropertySplitter("_colorTransform", _colorTransform_splitter); + + // Scale splitter properties + Tweener.registerSpecialPropertySplitter("_scale", _scale_splitter); + + // Filter tweening properties - BlurFilter + Tweener.registerSpecialProperty("_blur_blurX", _filter_property_get, _filter_property_set, [BlurFilter, "blurX"]); + Tweener.registerSpecialProperty("_blur_blurY", _filter_property_get, _filter_property_set, [BlurFilter, "blurY"]); + Tweener.registerSpecialProperty("_blur_quality", _filter_property_get, _filter_property_set, [BlurFilter, "quality"]); + + // Filter tweening splitter properties + Tweener.registerSpecialPropertySplitter("_filter", _filter_splitter); + + // Bezier modifiers + Tweener.registerSpecialPropertyModifier("_bezier", _bezier_modifier, _bezier_get); + } + + + // ================================================================================================================================== + // PROPERTY GROUPING/SPLITTING functions -------------------------------------------------------------------------------------------- + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _color + + /** + * Splits the _color parameter into specific color variables + * + * @param p_value Number The original _color value + * @return Array An array containing the .name and .value of all new properties + */ + public static function _color_splitter (p_value:Number):Array { + var nArray:Array = new Array(); + if (p_value == null) { + // No parameter passed, so just resets the color + nArray.push({name:"_color_ra", value:100}); + nArray.push({name:"_color_rb", value:0}); + nArray.push({name:"_color_ga", value:100}); + nArray.push({name:"_color_gb", value:0}); + nArray.push({name:"_color_ba", value:100}); + nArray.push({name:"_color_bb", value:0}); + } else { + // A color tinting is passed, so converts it to the object values + nArray.push({name:"_color_ra", value:0}); + nArray.push({name:"_color_rb", value:AuxFunctions.numberToR(p_value)}); + nArray.push({name:"_color_ga", value:0}); + nArray.push({name:"_color_gb", value:AuxFunctions.numberToG(p_value)}); + nArray.push({name:"_color_ba", value:0}); + nArray.push({name:"_color_bb", value:AuxFunctions.numberToB(p_value)}); + } + return nArray; + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _colorTransform + + /** + * Splits the _colorTransform parameter into specific color variables + * + * @param p_value Number The original _colorTransform value + * @return Array An array containing the .name and .value of all new properties + */ + public static function _colorTransform_splitter (p_value:Object):Array { + var nArray:Array = new Array(); + if (p_value == null) { + // No parameter passed, so just resets the color + nArray.push({name:"_color_ra", value:100}); + nArray.push({name:"_color_rb", value:0}); + nArray.push({name:"_color_ga", value:100}); + nArray.push({name:"_color_gb", value:0}); + nArray.push({name:"_color_ba", value:100}); + nArray.push({name:"_color_bb", value:0}); + } else { + // A color tinting is passed, so converts it to the object values + if (p_value.ra != undefined) nArray.push({name:"_color_ra", value:p_value.ra}); + if (p_value.rb != undefined) nArray.push({name:"_color_rb", value:p_value.rb}); + if (p_value.ga != undefined) nArray.push({name:"_color_ba", value:p_value.ba}); + if (p_value.gb != undefined) nArray.push({name:"_color_bb", value:p_value.bb}); + if (p_value.ba != undefined) nArray.push({name:"_color_ga", value:p_value.ga}); + if (p_value.bb != undefined) nArray.push({name:"_color_gb", value:p_value.gb}); + if (p_value.aa != undefined) nArray.push({name:"_color_aa", value:p_value.aa}); + if (p_value.ab != undefined) nArray.push({name:"_color_ab", value:p_value.ab}); + } + return nArray; + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // scale + public static function _scale_splitter(p_value:Number) : Array{ + var nArray:Array = new Array(); + nArray.push({name:"_xscale", value: p_value}); + nArray.push({name:"_yscale", value: p_value}); + return nArray; + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // filters + + /** + * Splits the _filter, _blur, etc parameter into specific filter variables + * + * @param p_value BitmapFilter A BitmapFilter instance + * @return Array An array containing the .name and .value of all new properties + */ + public static function _filter_splitter (p_value:BitmapFilter):Array { + var nArray:Array = new Array(); + if (p_value instanceof BlurFilter) { + nArray.push({name:"_blur_blurX", value:BlurFilter(p_value).blurX}); + nArray.push({name:"_blur_blurY", value:BlurFilter(p_value).blurY}); + nArray.push({name:"_blur_quality", value:BlurFilter(p_value).quality}); + } else { + // ? + trace ("??"); + } + return nArray; + } + + + // ================================================================================================================================== + // NORMAL SPECIAL PROPERTY functions ------------------------------------------------------------------------------------------------ + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _frame + + /** + * Returns the current frame number from the movieclip timeline + * + * @param p_obj Object MovieClip object + * @return Number The current frame + */ + public static function _frame_get (p_obj:Object):Number { + return p_obj._currentFrame; + } + + /** + * Sets the timeline frame + * + * @param p_obj Object MovieClip object + * @param p_value Number New frame number + */ + public static function _frame_set (p_obj:Object, p_value:Number):Void { + p_obj.gotoAndStop(Math.round(p_value)); + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _sound_volume + + /** + * Returns the current sound volume + * + * @param p_obj Object Sound object + * @return Number The current volume + */ + public static function _sound_volume_get (p_obj:Object):Number { + return p_obj.getVolume(); + } + + /** + * Sets the sound volume + * + * @param p_obj Object Sound object + * @param p_value Number New volume + */ + public static function _sound_volume_set (p_obj:Object, p_value:Number):Void { + p_obj.setVolume(p_value); + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _sound_pan + + /** + * Returns the current sound pan + * + * @param p_obj Object Sound object + * @return Number The current pan + */ + public static function _sound_pan_get (p_obj:Object):Number { + return p_obj.getPan(); + } + + /** + * Sets the sound volume + * + * @param p_obj Object Sound object + * @param p_value Number New pan + */ + public static function _sound_pan_set (p_obj:Object, p_value:Number):Void { + p_obj.setPan(p_value); + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _color_* + + /** + * _color_* + * Generic function for the ra/rb/ga/gb/ba/bb/aa/ab components of the colorTransform object + */ + public static function _color_property_get (p_obj:Object, p_parameters:Array):Number { + return (new Color(p_obj)).getTransform()[p_parameters[0]]; + } + public static function _color_property_set (p_obj:Object, p_value:Number, p_parameters:Array):Void { + var cfObj:Object = new Object(); + cfObj[p_parameters[0]] = Math.round(p_value); + (new Color(p_obj)).setTransform(cfObj); + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _autoAlpha + + /** + * Returns the current alpha + * + * @param p_obj Object MovieClip or Textfield object + * @return Number The current alpha + */ + public static function _autoAlpha_get (p_obj:Object):Number { + return p_obj._alpha; + } + + /** + * Sets the current autoAlpha + * + * @param p_obj Object MovieClip or Textfield object + * @param p_value Number New alpha + */ + public static function _autoAlpha_set (p_obj:Object, p_value:Number):Void { + p_obj._alpha = p_value; + p_obj._visible = p_value > 0; + } + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // filters + + /** + * (filters) + * Generic function for the properties of filter objects + */ + public static function _filter_property_get (p_obj:Object, p_parameters:Array):Number { + var f:Array = p_obj.filters; + var i:Number; + var filterClass:Object = p_parameters[0]; + var propertyName:String = p_parameters[1]; + for (i = 0; i < f.length; i++) { + if (f[i] instanceof filterClass) return (f[i][propertyName]); + } + + // No value found for this property - no filter instance found using this class! + // Must return default desired values + var defaultValues:Object; + switch (filterClass) { + case BlurFilter: + defaultValues = {blurX:0, blurY:0, quality:NaN}; + break; + } + // When returning NaN, the Tweener engine sets the starting value as being the same as the final value + // When returning null, the Tweener engine doesn't tween it at all, just setting it to the final value + return defaultValues[propertyName]; + } + + public static function _filter_property_set (p_obj:Object, p_value:Number, p_parameters:Array):Void { + var f:Array = p_obj.filters; + var i:Number; + var filterClass:Object = p_parameters[0]; + var propertyName:String = p_parameters[1]; + for (i = 0; i < f.length; i++) { + if (f[i] instanceof filterClass) { + f[i][propertyName] = p_value; + p_obj.filters = f; + return; + } + } + + // The correct filter class wasn't found - create a new one + if (f == undefined) f = new Array(); + var fi:BitmapFilter; + switch (filterClass) { + case BlurFilter: + fi = new BlurFilter(0, 0); + break; + } + fi[propertyName] = p_value; + f.push(fi); + p_obj.filters = f; + } + + + // ================================================================================================================================== + // SPECIAL PROPERTY MODIFIER functions ---------------------------------------------------------------------------------------------- + + + // ---------------------------------------------------------------------------------------------------------------------------------- + // _bezier + + /** + * Given the parameter object passed to this special property, return an array listing the properties that should be modified, and their parameters + * + * @param p_obj Object Parameter passed to this property + * @return Array Array listing name and parameter of each property + */ + public static function _bezier_modifier (p_obj:Object):Array { + var mList:Array = []; // List of properties to be modified + var pList:Array; // List of parameters passed, normalized as an array + if (p_obj instanceof Array) { + // Complex + pList = p_obj.concat(); + } else { + pList = [p_obj]; + } + + var i:Number; + var istr:String; + var mListObj:Object = {}; // Object describing each property name and parameter + + for (i = 0; i < pList.length; i++) { + for (istr in pList[i]) { + if (mListObj[istr] == undefined) mListObj[istr] = []; + mListObj[istr].push(pList[i][istr]); + } + } + for (istr in mListObj) { + mList.push({name:istr, parameters:mListObj[istr]}); + } + return mList; + } + + /** + * Given tweening specifications (beging, end, t), applies the property parameter to it, returning new t + * + * @param b Number Beginning value of the property + * @param e Number Ending (desired) value of the property + * @param t Number Current t of this tweening (0-1), after applying the easing equation + * @param p Array Array of parameters passed to this specific property + * @return Number New t, with the p parameters applied to it + */ + public static function _bezier_get (b:Number, e:Number, t:Number, p:Array):Number { + // This is based on Robert Penner's code + if (p.length == 1) { + // Simple curve with just one bezier control point + return b + t*(2*(1-t)*(p[0]-b) + t*(e - b)); + } else { + // Array of bezier control points, must find the point between each pair of bezier points + var ip:Number = Math.floor(t * p.length); // Position on the bezier list + var it:Number = (t - (ip * (1 / p.length))) * p.length; // t inside this ip + var p1:Number, p2:Number; + if (ip == 0) { + // First part: belongs to the first control point, find second midpoint + p1 = b; + p2 = (p[0]+p[1])/2; + } else if (ip == p.length - 1) { + // Last part: belongs to the last control point, find first midpoint + p1 = (p[ip-1]+p[ip])/2; + p2 = e; + } else { + // Any middle part: find both midpoints + p1 = (p[ip-1]+p[ip])/2; + p2 = (p[ip]+p[ip+1])/2; + } + return p1+it*(2*(1-it)*(p[ip]-p1) + it*(p2 - p1)); + } + } +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialProperty.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialProperty.as new file mode 100755 index 000000000..a19e66303 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialProperty.as @@ -0,0 +1,57 @@ +/** + * SpecialProperty + * A kind of a getter/setter for special properties + * + * @author Zeh Fernando + * @version 1.0.1 + */ + +class caurina.transitions.SpecialProperty { + + private var parameters:Array; + + /** + * Builds a new special property object. + * + * @param p_getFunction Function Reference to the function used to get the special property value + * @param p_setFunction Function Reference to the function used to set the special property value + * @param p_parameters Array Additional parameters that should be passed to the function when executing (so the same function can apply to different special properties) + */ + public function SpecialProperty (p_getFunction:Function, p_setFunction:Function, p_parameters:Array) { + getValue = p_getFunction; + setValue = p_setFunction; + parameters = p_parameters; + } + + /** + * Empty shell for the function that gets the value. + */ + public function getValue(p_obj:Object, p_parameters:Array):Number { + // This is rewritten + return null; + } + + /** + * Empty shell for the function that sets the value. + */ + public function setValue(p_obj:Object, p_value:Number, p_parameters:Array):Void { + // This is rewritten + } + + /** + * Converts the instance to a string that can be used when trace()ing the object + */ + public function toString():String { + var value:String = ""; + value += "[SpecialProperty "; + value += "getValue:"+getValue.toString(); + value += ", "; + value += "setValue:"+setValue.toString(); + value += ", "; + value += "parameters:"+parameters.toString(); + value += "]"; + return value; + } + + +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertyModifier.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertyModifier.as new file mode 100755 index 000000000..7634cc9c3 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertyModifier.as @@ -0,0 +1,39 @@ +/** + * SpecialPropertyModifier + * A special property which actually acts on other properties + * + * @author Zeh Fernando + * @version 1.0.0 + * @private + */ + +class caurina.transitions.SpecialPropertyModifier { + + public var modifyValues:Function; + public var getValue:Function; + + /** + * Builds a new special property modifier object. + * + * @param p_modifyFunction Function Function that returns the modifider parameters. + */ + public function SpecialPropertyModifier (p_modifyFunction:Function, p_getFunction:Function) { + modifyValues = p_modifyFunction; + getValue = p_getFunction; + } + + /** + * Converts the instance to a string that can be used when trace()ing the object + */ + public function toString():String { + var value:String = ""; + value += "[SpecialPropertyModifier "; + value += "modifyValues:"+modifyValues.toString(); + value += ", "; + value += "getValue:"+getValue.toString(); + value += "]"; + return value; + } + + +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertySplitter.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertySplitter.as new file mode 100755 index 000000000..fcc0e2c01 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/SpecialPropertySplitter.as @@ -0,0 +1,46 @@ +/** + * SpecialPropertySplitter + * A proxy setter for special properties + * + * @author Zeh Fernando + * @version 1.0.0 + */ + +class caurina.transitions.SpecialPropertySplitter { + + public var parameters:Array; + + /** + * Builds a new splitter special propery object. + * + * @param p_splitFunction Function Reference to the function used to split a value + */ + public function SpecialPropertySplitter (p_splitFunction:Function, p_parameters:Array) { + splitValues = p_splitFunction; + parameters = p_parameters; + } + + /** + * Empty shell for the function that receives the value (usually just a Number), and splits it in new property names and values + * Must return an array containing .name and .value + */ + public function splitValues(p_value:Object, p_parameters:Array):Array { + // This is rewritten + return []; + } + + /** + * Converts the instance to a string that can be used when trace()ing the object + */ + public function toString():String { + var value:String = ""; + value += "[SpecialPropertySplitter "; + value += "splitValues:"+splitValues.toString(); + value += ", "; + value += "parameters:"+parameters.toString(); + value += "]"; + return value; + } + + +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/TweenListObj.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/TweenListObj.as new file mode 100755 index 000000000..6c9fbbed7 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/TweenListObj.as @@ -0,0 +1,210 @@ +/** + * The tween list object. Stores all of the properties and information that pertain to individual tweens. + * + * @author Nate Chatellier, Zeh Fernando + * @version 1.0.4 + */ +import caurina.transitions.AuxFunctions; + +class caurina.transitions.TweenListObj { + + public var scope :Object; // Object affected by this tweening + public var properties :Object; // List of properties that are tweened (PropertyInfoObj instances) + // .valueStart :Number // Initial value of the property + // .valueComplete :Number // The value the property should have when completed + public var auxProperties :Object; // Dynamic object containing properties used on this tweening + public var timeStart :Number; // Time when this tweening should start + public var timeComplete :Number; // Time when this tweening should end + public var useFrames :Boolean; // Whether or not to use frames instead of time + public var transition :Function; // Equation to control the transition animation + public var onStart :Function; // Function to be executed on the object when the tween starts (once) + public var onUpdate :Function; // Function to be executed on the object when the tween updates (several times) + public var onComplete :Function; // Function to be executed on the object when the tween completes (once) + public var onOverwrite :Function; // Function to be executed on the object when the tween is overwritten + public var onError :Function; // Function to be executed if an error is thrown when tweener exectues a callback (onComplete, onUpdate etc) + public var onStartParams :Array; // Array of parameters to be passed for the event + public var onUpdateParams :Array; // Array of parameters to be passed for the event + public var onCompleteParams :Array; // Array of parameters to be passed for the event + public var onOverwriteParams :Array; // Array of parameters to be passed for the event + public var rounded :Boolean; // Use rounded values when updating + public var isPaused :Boolean; // Whether or not this tween is paused + public var timePaused :Number; // Time when this tween was paused + public var isCaller :Boolean; // Whether or not this tween is a "caller" tween + public var count :Number; // Number of times this caller should be called + public var timesCalled :Number; // How many times the caller has already been called ("caller" tweens only) + public var waitFrames :Boolean; // Whether or not this caller should wait at least one frame for each call execution ("caller" tweens only) + public var skipUpdates :Number; // How many updates should be skipped (default = 0; 1 = update-skip-update-skip...) + public var updatesSkipped :Number; // How many updates have already been skipped + public var hasStarted :Boolean; // Whether or not this tween has already started + + // ================================================================================================================================== + // CONSTRUCTOR function ------------------------------------------------------------------------------------------------------------- + + /** + * Initializes the basic TweenListObj + * + * @param p_scope Object Object affected by this tweening + * @param p_timeStart Number Time when this tweening should start + * @param p_timeComplete Number Time when this tweening should end + * @param p_useFrames Boolean Whether or not to use frames instead of time + * @param p_transition Function Equation to control the transition animation + */ + function TweenListObj(p_scope:Object, p_timeStart:Number, p_timeComplete:Number, p_useFrames:Boolean, p_transition:Function) { + scope = p_scope; + timeStart = p_timeStart; + timeComplete = p_timeComplete; + useFrames = p_useFrames; + transition = p_transition; + + // Other default information + auxProperties = new Object(); + properties = new Object(); + isPaused = false; + timePaused = undefined; + isCaller = false; + updatesSkipped = 0; + timesCalled = 0; + skipUpdates = 0; + hasStarted = false; + } + + + // ================================================================================================================================== + // OTHER functions ------------------------------------------------------------------------------------------------------------------ + + /** + * Clones this tweening and returns the new TweenListObj + * + * @param omitEvents Boolean Whether or not events such as onStart (and its parameters) should be omitted + * @return TweenListObj A copy of this object + */ + public function clone(omitEvents:Boolean):TweenListObj { + var nTween:TweenListObj = new TweenListObj(scope, timeStart, timeComplete, useFrames, transition); + nTween.properties = new Object(); + for (var pName:String in properties) { + nTween.properties[pName] = properties[pName].clone(); + } + nTween.skipUpdates = skipUpdates; + nTween.updatesSkipped = updatesSkipped; + if (!omitEvents) { + nTween.onStart = onStart; + nTween.onUpdate = onUpdate; + nTween.onComplete = onComplete; + nTween.onOverwrite = onOverwrite; + nTween.onError = onError; + nTween.onStartParams = onStartParams; + nTween.onUpdateParams = onUpdateParams; + nTween.onCompleteParams = onCompleteParams; + nTween.onOverwriteParams = onOverwriteParams; + } + nTween.rounded = rounded; + nTween.isPaused = isPaused; + nTween.timePaused = timePaused; + nTween.isCaller = isCaller; + nTween.count = count; + nTween.timesCalled = timesCalled; + nTween.waitFrames = waitFrames; + nTween.hasStarted = hasStarted; + + return nTween; + } + + /** + * Returns this object described as a String. + * + * @return String The description of this object. + */ + public function toString():String { + var returnStr:String = "\n[TweenListObj "; + returnStr += "scope:" + String(scope); + returnStr += ", properties:"; + var isFirst:Boolean = true; + for (var i:String in properties) { + if (!isFirst) returnStr += ","; + returnStr += "[name:"+properties[i].name; + returnStr += ",valueStart:"+properties[i].valueStart; + returnStr += ",valueComplete:"+properties[i].valueComplete; + returnStr += "]"; + isFirst = false; + } // END FOR + returnStr += ", timeStart:" + String(timeStart); + returnStr += ", timeComplete:" + String(timeComplete); + returnStr += ", useFrames:" + String(useFrames); + returnStr += ", transition:" + String(transition); + + if (skipUpdates) returnStr += ", skipUpdates:" + String(skipUpdates); + if (updatesSkipped) returnStr += ", updatesSkipped:" + String(updatesSkipped); + + if (onStart) returnStr += ", onStart:" + String(onStart); + if (onUpdate) returnStr += ", onUpdate:" + String(onUpdate); + if (onComplete) returnStr += ", onComplete:" + String(onComplete); + if (onOverwrite) returnStr += ", onOverwrite:" + String(onOverwrite); + if (onError) returnStr += ", onError:" + String(onError); + + if (onStartParams) returnStr += ", onStartParams:" + String(onStartParams); + if (onUpdateParams) returnStr += ", onUpdateParams:" + String(onUpdateParams); + if (onCompleteParams) returnStr += ", onCompleteParams:" + String(onCompleteParams); + if (onOverwriteParams) returnStr += ", onOverwriteParams:" + String(onOverwriteParams); + + if (rounded) returnStr += ", rounded:" + String(rounded); + if (isPaused) returnStr += ", isPaused:" + String(isPaused); + if (timePaused) returnStr += ", timePaused:" + String(timePaused); + if (isCaller) returnStr += ", isCaller:" + String(isCaller); + if (count) returnStr += ", count:" + String(count); + if (timesCalled) returnStr += ", timesCalled:" + String(timesCalled); + if (waitFrames) returnStr += ", waitFrames:" + String(waitFrames); + if (hasStarted) returnStr += ", hasStarted:" + String(hasStarted); + + returnStr += "]\n"; + return returnStr; + } + + /** + * Checks if p_obj "inherits" properties from other objects, as set by the "base" property. Will create a new object, leaving others intact. + * o_bj.base can be an object or an array of objects. Properties are collected from the first to the last element of the "base" filed, with higher + * indexes overwritting smaller ones. Does not modify any of the passed objects, but makes a shallow copy of all properties. + * + * @param p_obj Object Object that should be tweened: a movieclip, textfield, etc.. OR an array of objects + * @return Object A new object with all properties from the p_obj and p_obj.base. + */ + + public static function makePropertiesChain(p_obj : Object) : Object{ + // Is this object inheriting properties from another object? + var baseObject : Object = p_obj.base; + if(baseObject){ + // object inherits. Are we inheriting from an object or an array + var chainedObject : Object = {}; + var chain : Object; + if (baseObject instanceof Array){ + // Inheritance chain is the base array + chain = []; + // make a shallow copy + for (var k : Number = 0 ; k< baseObject.length; k++) chain.push(baseObject[k]); + }else{ + // Only one object to be added to the array + chain = [baseObject]; + } + // add the final object to the array, so it's properties are added last + chain.push(p_obj); + var currChainObj : Object; + // Loops through each object adding it's property to the final object + var len : Number = chain.length; + for(var i : Number = 0; i < len ; i ++){ + if(chain[i]["base"]){ + // deal with recursion: watch the order! "parent" base must be concatenated first! + currChainObj = AuxFunctions.concatObjects( makePropertiesChain(chain[i]["base"] ), chain[i]); + }else{ + currChainObj = chain[i] ; + } + chainedObject = AuxFunctions.concatObjects(chainedObject, currChainObj ); + } + if( chainedObject["base"]){ + delete chainedObject["base"]; + } + return chainedObject; + }else{ + // No inheritance, just return the object it self + return p_obj; + } + } +} diff --git a/public/includes/ofc-1.9/actionscript/caurina/transitions/Tweener.as b/public/includes/ofc-1.9/actionscript/caurina/transitions/Tweener.as new file mode 100755 index 000000000..c6e3644b6 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/caurina/transitions/Tweener.as @@ -0,0 +1,1047 @@ +/** + * Tweener + * Transition controller for movieclips, sounds, textfields and other objects + * + * @author Zeh Fernando, Nate Chatellier, Arthur Debert + * @version 1.26.62 + */ + +/* +Licensed under the MIT License + +Copyright (c) 2006-2007 Zeh Fernando and Nate Chatellier + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +http://code.google.com/p/tweener/ +http://code.google.com/p/tweener/wiki/License +*/ + +import caurina.transitions.Equations; +import caurina.transitions.AuxFunctions; +import caurina.transitions.SpecialPropertiesDefault; +import caurina.transitions.SpecialProperty; +import caurina.transitions.SpecialPropertyModifier; +import caurina.transitions.SpecialPropertySplitter; +import caurina.transitions.TweenListObj; +import caurina.transitions.PropertyInfoObj; + +class caurina.transitions.Tweener { + + private static var _engineExists:Boolean = false; // Whether or not the engine is currently running + private static var _inited:Boolean = false; // Whether or not the class has been initiated + private static var _currentTime:Number; // The current time. This is generic for all tweenings for a "time grid" based update + + private static var _tweenList:Array; // List of active tweens + + private static var _timeScale:Number = 1; // Time scale (default = 1) + + private static var _transitionList:Object; // List of "pre-fetched" transition functions + private static var _specialPropertyList:Object; // List of special properties + private static var _specialPropertyModifierList:Object; // List of special property modifiers + private static var _specialPropertySplitterList:Object; // List of special property splitters + + + /** + * There's no constructor. + */ + public function Tweener () { + trace ("Tweener is an static class and should not be instantiated.") + } + + + // ================================================================================================================================== + // TWEENING CONTROL functions ------------------------------------------------------------------------------------------------------- + + /** + * Adds a new tweening + * + * @param (first-n param) Object Object that should be tweened: a movieclip, textfield, etc.. OR an array of objects + * @param (last param) Object Object containing the specified parameters in any order, as well as the properties that should be tweened and their values + * @param .time Number Time in seconds or frames for the tweening to take (defaults 2) + * @param .delay Number Delay time (defaults 0) + * @param .useFrames Boolean Whether to use frames instead of seconds for time control (defaults false) + * @param .transition String/Function Type of transition equation... (defaults to "easeoutexpo") + * @param .onStart Function * Direct property, See the TweenListObj class + * @param .onUpdate Function * Direct property, See the TweenListObj class + * @param .onComplete Function * Direct property, See the TweenListObj class + * @param .onOverwrite Function * Direct property, See the TweenListObj class + * @param .onStartParams Array * Direct property, See the TweenListObj class + * @param .onUpdateParams Array * Direct property, See the TweenListObj class + * @param .onCompleteParams Array * Direct property, See the TweenListObj class + * @param .onOverwriteParams Array * Direct property, See the TweenListObj class + * @param .rounded Boolean * Direct property, See the TweenListObj class + * @param .skipUpdates Number * Direct property, See the TweenListObj class + * @return Boolean TRUE if the tween was successfully added, FALSE if otherwise + */ + public static function addTween ():Boolean { + if (arguments.length < 2 || arguments[0] == undefined) return false; + + var rScopes:Array = new Array(); // List of objects to tween + var i:Number, j:Number, istr:String, jstr:String; + + if (arguments[0] instanceof Array) { + // The first argument is an array + for (i = 0; i _tweenList[i].timeStart && p_timeStart < _tweenList[i].timeComplete) { + // New time should override the old one... + removedLocally = false; + for (pName in _tweenList[i].properties) { + if (p_properties[pName] != undefined) { + // Same object, same property + // Finally, remove this old tweening and use the new one + if (_tweenList[i].onOverwrite != undefined) { + try { + _tweenList[i].onOverwrite.apply(_tweenList[i].scope, _tweenList[i].onOverwriteParams); + } catch(e:Error) { + handleError(_tweenList[i], e, "onOverwrite"); + } + } + _tweenList[i].properties[pName] = undefined; + delete _tweenList[i].properties[pName]; + removedLocally = true; + removed = true; + } + } + if (removedLocally) { + // Verify if this can be deleted + if (AuxFunctions.getObjectLength(_tweenList[i].properties) == 0) removeTweenByIndex(i); + } + } + } + } + + return removed; + } + + /** + * Remove tweenings from a given object from the tweening list + * + * @param p_tween Object Object that must have its tweens removed + * @param (2nd-last params) Object Property(ies) that must be removed + * @return Boolean Whether or not it successfully removed this tweening + */ + public static function removeTweens (p_scope:Object):Boolean { + // Create the property list + var properties:Array = new Array(); + var i:Number; + for (i = 1; i < arguments.length; i++) { + if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]); + } + // Call the affect function on the specified properties + return affectTweens(removeTweenByIndex, p_scope, properties); + } + + /** + * Remove all tweenings from the engine + * + * @return Boolean Whether or not it successfully removed a tweening + */ + public static function removeAllTweens ():Boolean { + var removed:Boolean = false; + var i:Number; + for (i = 0; i < _tweenList.length; i++) { + removeTweenByIndex(i); + removed = true; + } + return removed; + } + + /** + * Pause tweenings from a given object + * + * @param p_scope Object Object that must have its tweens paused + * @param (2nd-last params) Object Property(ies) that must be paused + * @return Boolean Whether or not it successfully paused something + */ + public static function pauseTweens (p_scope:Object):Boolean { + // Create the property list + var properties:Array = new Array(); + var i:Number; + for (i = 1; i < arguments.length; i++) { + if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]); + } + // Call the affect function on the specified properties + return affectTweens(pauseTweenByIndex, p_scope, properties); + } + + /** + * Pause all tweenings on the engine + * + * @return Boolean Whether or not it successfully paused a tweening + */ + public static function pauseAllTweens ():Boolean { + var paused:Boolean = false; + var i:Number; + for (i = 0; i < _tweenList.length; i++) { + pauseTweenByIndex(i); + paused = true; + } + return paused; + } + + /** + * Resume tweenings from a given object + * + * @param p_scope Object Object that must have its tweens resumed + * @param (2nd-last params) Object Property(ies) that must be resumed + * @return Boolean Whether or not it successfully resumed something + */ + public static function resumeTweens (p_scope:Object):Boolean { + // Create the property list + var properties:Array = new Array(); + var i:Number; + for (i = 1; i < arguments.length; i++) { + if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]); + } + // Call the affect function on the specified properties + return affectTweens(resumeTweenByIndex, p_scope, properties); + } + + /** + * Resume all tweenings on the engine + * + * @return Boolean Whether or not it successfully resumed a tweening + */ + public static function resumeAllTweens ():Boolean { + var resumed:Boolean = false; + var i:Number; + for (i = 0; i < _tweenList.length; i++) { + resumeTweenByIndex(i); + resumed = true; + } + return resumed; + } + + /** + * Do some generic action on specific tweenings (pause, resume, remove, more?) + * + * @param p_function Function Function to run on the tweenings that match + * @param p_scope Object Object that must have its tweens affected by the function + * @param p_properties Array Array of strings that must be affected + * @return Boolean Whether or not it successfully affected something + */ + private static function affectTweens (p_affectFunction:Function, p_scope:Object, p_properties:Array):Boolean { + var affected:Boolean = false; + var i:Number; + + if (!_tweenList) return false; + + for (i = 0; i < _tweenList.length; i++) { + if (_tweenList[i].scope == p_scope) { + if (p_properties.length == 0) { + // Can affect everything + p_affectFunction(i); + affected = true; + } else { + // Must check whether this tween must have specific properties affected + var affectedProperties:Array = new Array(); + var j:Number; + for (j = 0; j < p_properties.length; j++) { + if (_tweenList[i].properties[p_properties[j]] != undefined) { + affectedProperties.push(p_properties[j]); + } + } + if (affectedProperties.length > 0) { + // This tween has some properties that need to be affected + var objectProperties:Number = AuxFunctions.getObjectLength(_tweenList[i].properties); + if (objectProperties == affectedProperties.length) { + // The list of properties is the same as all properties, so affect it all + p_affectFunction(i); + affected = true; + } else { + // The properties are mixed, so split the tween and affect only certain specific properties + var slicedTweenIndex:Number = splitTweens(i, affectedProperties); + p_affectFunction(slicedTweenIndex); + affected = true; + } + } + } + } + } + return affected; + } + + /** + * Splits a tweening in two + * + * @param p_tween Number Object that must have its tweens split + * @param p_properties Array Array of strings containing the list of properties that must be separated + * @return Number The index number of the new tween + */ + public static function splitTweens (p_tween:Number, p_properties:Array):Number { + // First, duplicates + var originalTween:TweenListObj = _tweenList[p_tween]; + var newTween:TweenListObj = originalTween.clone(false); + + // Now, removes tweenings where needed + var i:Number; + var pName:String; + + // Removes the specified properties from the old one + for (i = 0; i < p_properties.length; i++) { + pName = p_properties[i]; + if (originalTween.properties[pName] != undefined) { + originalTween.properties[pName] = undefined; + delete originalTween.properties[pName]; + } + } + + // Removes the unspecified properties from the new one + var found:Boolean; + for (pName in newTween.properties) { + found = false; + for (i = 0; i < p_properties.length; i++) { + if (p_properties[i] == pName) { + found = true; + break; + } + } + if (!found) { + newTween.properties[pName] = undefined; + delete newTween.properties[pName]; + } + } + + // If there are empty property lists, a cleanup is done on the next updateTweens() cycle + _tweenList.push(newTween); + return (_tweenList.length - 1); + + } + + + // ================================================================================================================================== + // ENGINE functions ----------------------------------------------------------------------------------------------------------------- + + /** + * Updates all existing tweenings + * + * @return Boolean FALSE if no update was made because there's no tweening (even delayed ones) + */ + private static function updateTweens ():Boolean { + if (_tweenList.length == 0) return false; + var i:Number; + for (i = 0; i < _tweenList.length; i++) { + // Looping throught each Tweening and updating the values accordingly + if (!_tweenList[i].isPaused) { + if (!updateTweenByIndex(i)) removeTweenByIndex(i); + if (_tweenList[i] == null) { + removeTweenByIndex(i, true); + i--; + } + } + } + + return true; + } + + /** + * Remove an specific tweening from the tweening list + * + * @param p_tween Number Index of the tween to be removed on the tweenings list + * @return Boolean Whether or not it successfully removed this tweening + */ + public static function removeTweenByIndex (p_tween:Number, p_finalRemoval:Boolean):Boolean { + _tweenList[p_tween] = null; + if (p_finalRemoval) _tweenList.splice(p_tween, 1); + return true; + } + + /** + * Pauses an specific tween + * + * @param p_tween Number Index of the tween to be paused + * @return Boolean Whether or not it successfully paused this tweening + */ + public static function pauseTweenByIndex (p_tween:Number):Boolean { + var tTweening:Object = _tweenList[p_tween]; // Shortcut to this tweening + if (tTweening == null || tTweening.isPaused) return false; + tTweening.timePaused = _currentTime; + tTweening.isPaused = true; + + return true; + } + + /** + * Resumes an specific tween + * + * @param p_tween Number Index of the tween to be resumed + * @return Boolean Whether or not it successfully resumed this tweening + */ + public static function resumeTweenByIndex (p_tween:Number):Boolean { + var tTweening:Object = _tweenList[p_tween]; // Shortcut to this tweening + if (tTweening == null || !tTweening.isPaused) return false; + tTweening.timeStart += _currentTime - tTweening.timePaused; + tTweening.timeComplete += _currentTime - tTweening.timePaused; + tTweening.timePaused = undefined; + tTweening.isPaused = false; + + return true; + } + + /** + * Updates an specific tween + * + * @param i Number Index (from the tween list) of the tween that should be updated + * @return Boolean FALSE if it's already finished and should be deleted, TRUE if otherwise + */ + private static function updateTweenByIndex (i:Number):Boolean { + + var tTweening:Object = _tweenList[i]; // Shortcut to this tweening + + if (tTweening == null || !tTweening.scope) return false; + + var isOver:Boolean = false; // Whether or not it's over the update time + var mustUpdate:Boolean; // Whether or not it should be updated (skipped if false) + + var nv:Number; // New value for each property + + var t:Number; // current time (frames, seconds) + var b:Number; // beginning value + var c:Number; // change in value + var d:Number; // duration (frames, seconds) + + var pName:String; // Property name, used in loops + + // Shortcut stuff for speed + var tScope:Object; // Current scope + var tProperty:Object; // Property being checked + + if (_currentTime >= tTweening.timeStart) { + // Can already start + + tScope = tTweening.scope; + + if (tTweening.isCaller) { + // It's a 'caller' tween + do { + t = ((tTweening.timeComplete - tTweening.timeStart)/tTweening.count) * (tTweening.timesCalled+1); + b = tTweening.timeStart; + c = tTweening.timeComplete - tTweening.timeStart; + d = tTweening.timeComplete - tTweening.timeStart; + nv = tTweening.transition(t, b, c, d); + + if (_currentTime >= nv) { + if (tTweening.onUpdate != undefined) { + try { + tTweening.onUpdate.apply(tScope, tTweening.onUpdateParams); + } catch(e:Error) { + handleError(tTweening, e, "onUpdate"); + } + } + + tTweening.timesCalled++; + if (tTweening.timesCalled >= tTweening.count) { + isOver = true; + break; + } + if (tTweening.waitFrames) break; + } + + } while (_currentTime >= nv); + } else { + // It's a normal transition tween + + mustUpdate = tTweening.skipUpdates < 1 || tTweening.skipUpdates == undefined || tTweening.updatesSkipped >= tTweening.skipUpdates; + + if (_currentTime >= tTweening.timeComplete) { + isOver = true; + mustUpdate = true; + } + + if (!tTweening.hasStarted) { + // First update, read all default values (for proper filter tweening) + if (tTweening.onStart != undefined) { + try { + tTweening.onStart.apply(tScope, tTweening.onStartParams); + } catch(e:Error) { + handleError(tTweening, e, "onStart"); + } + } + for (pName in tTweening.properties) { + var pv:Number = getPropertyValue (tScope, pName); + tTweening.properties[pName].valueStart = isNaN(pv) ? tTweening.properties[pName].valueComplete : pv; + } + mustUpdate = true; + tTweening.hasStarted = true; + } + + if (mustUpdate) { + for (pName in tTweening.properties) { + tProperty = tTweening.properties[pName]; + + if (isOver) { + // Tweening time has finished, just set it to the final value + nv = tProperty.valueComplete; + } else { + if (tProperty.hasModifier) { + // Modified + t = _currentTime - tTweening.timeStart; + d = tTweening.timeComplete - tTweening.timeStart; + nv = tTweening.transition(t, 0, 1, d); + nv = tProperty.modifierFunction(tProperty.valueStart, tProperty.valueComplete, nv, tProperty.modifierParameters); + } else { + // Normal update + t = _currentTime - tTweening.timeStart; + b = tProperty.valueStart; + c = tProperty.valueComplete - tProperty.valueStart; + d = tTweening.timeComplete - tTweening.timeStart; + nv = tTweening.transition(t, b, c, d); + } + } + + if (tTweening.rounded) nv = Math.round(nv); + setPropertyValue(tScope, pName, nv); + } + + tTweening.updatesSkipped = 0; + + if (tTweening.onUpdate != undefined) { + try { + tTweening.onUpdate.apply(tScope, tTweening.onUpdateParams); + } catch(e:Error) { + handleError(tTweening, e, "onUpdate"); + } + } + } else { + tTweening.updatesSkipped++; + } + } + + if (isOver && tTweening.onComplete != undefined) { + try { + tTweening.onComplete.apply(tScope, tTweening.onCompleteParams); + } catch(e:Error) { + handleError(tTweening, e, "onComplete"); + } + } + + return (!isOver); + } + + // On delay, hasn't started, so return true + return (true); + + } + + /** + * Initiates the Tweener. Should only be ran once + */ + private static function init():Void { + _inited = true; + + // Registers all default equations + _transitionList = new Object(); + Equations.init(); + + // Registers all default special properties + _specialPropertyList = new Object(); + _specialPropertyModifierList = new Object(); + _specialPropertySplitterList = new Object(); + SpecialPropertiesDefault.init(); + } + + /** + * Adds a new function to the available transition list "shortcuts" + * + * @param p_name String Shorthand transition name + * @param p_function Function The proper equation function + */ + public static function registerTransition(p_name:String, p_function:Function): Void { + if (!_inited) init(); + _transitionList[p_name] = p_function; + } + + /** + * Adds a new special property to the available special property list. + * + * @param p_name Name of the "special" property. + * @param p_getFunction Function that gets the value. + * @param p_setFunction Function that sets the value. + */ + public static function registerSpecialProperty(p_name:String, p_getFunction:Function, p_setFunction:Function, p_parameters:Array): Void { + if (!_inited) init(); + var sp:SpecialProperty = new SpecialProperty(p_getFunction, p_setFunction, p_parameters); + _specialPropertyList[p_name] = sp; + } + + /** + * Adds a new special property modifier to the available modifier list. + * + * @param p_name Name of the "special" property modifier. + * @param p_modifyFunction Function that modifies the value. + * @param p_getFunction Function that gets the value. + */ + public static function registerSpecialPropertyModifier(p_name:String, p_modifyFunction:Function, p_getFunction:Function): Void { + if (!_inited) init(); + var spm:SpecialPropertyModifier = new SpecialPropertyModifier(p_modifyFunction, p_getFunction); + _specialPropertyModifierList[p_name] = spm; + } + + /** + * Adds a new special property splitter to the available splitter list. + * + * @param p_name Name of the "special" property splitter. + * @param p_splitFunction Function that splits the value. + */ + public static function registerSpecialPropertySplitter(p_name:String, p_splitFunction:Function, p_parameters:Array): Void { + if (!_inited) init(); + var sps:SpecialPropertySplitter = new SpecialPropertySplitter(p_splitFunction, p_parameters); + _specialPropertySplitterList[p_name] = sps; + } + + /** + * Starts the Tweener class engine. It is supposed to be running every time a tween exists + */ + private static function startEngine():Void { + _engineExists = true; + _tweenList = new Array(); + + var randomDepth:Number = Math.floor(Math.random() * 999999); + var fmc:MovieClip = _root.createEmptyMovieClip(getControllerName(), 31338+randomDepth); + fmc.onEnterFrame = function() { + Tweener.onEnterFrame(); + }; + + updateTime(); + } + + /** + * Stops the Tweener class engine + */ + private static function stopEngine():Void { + _engineExists = false; + _tweenList = null; + _currentTime = 0; + delete _root[getControllerName()].onEnterFrame; + _root[getControllerName()].removeMovieClip(); + } + + /** + * Gets a property value from an object + * + * @param p_obj Object Any given object + * @param p_prop String The property name + * @return Number The value + */ + private static function getPropertyValue(p_obj:Object, p_prop:String):Number { + if (_specialPropertyList[p_prop] != undefined) { + // Special property + return _specialPropertyList[p_prop].getValue(p_obj, _specialPropertyList[p_prop].parameters); + } else { + // Regular property + return p_obj[p_prop]; + } + } + + /** + * Sets the value of an object property + * + * @param p_obj Object Any given object + * @param p_prop String The property name + * @param p_value Number The new value + */ + private static function setPropertyValue(p_obj:Object, p_prop:String, p_value:Number): Void { + if (_specialPropertyList[p_prop] != undefined) { + // Special property + _specialPropertyList[p_prop].setValue(p_obj, p_value, _specialPropertyList[p_prop].parameters); + } else { + // Regular property + p_obj[p_prop] = p_value; + } + } + + /** + * Updates the time to enforce time grid-based updates + */ + public static function updateTime():Void { + _currentTime = getTimer(); + } + + /** + * Ran once every frame. It's the main engine, updates all existing tweenings. + */ + public static function onEnterFrame():Void { + updateTime(); + var hasUpdated:Boolean = false; + hasUpdated = updateTweens(); + if (!hasUpdated) stopEngine(); // There's no tweening to update or wait, so it's better to stop the engine + } + + /** + * Sets the new time scale. + * + * @param p_time Number New time scale (0.5 = slow, 1 = normal, 2 = 2x fast forward, etc) + */ + public static function setTimeScale(p_time:Number):Void { + var i:Number; + + if (isNaN(p_time)) p_time = 1; + if (p_time < 0.00001) p_time = 0.00001; + if (p_time != _timeScale) { + // Multiplies all existing tween times accordingly + for (i = 0; i<_tweenList.length; i++) { + _tweenList[i].timeStart = _currentTime - ((_currentTime - _tweenList[i].timeStart) * _timeScale / p_time); + _tweenList[i].timeComplete = _currentTime - ((_currentTime - _tweenList[i].timeComplete) * _timeScale / p_time); + if (_tweenList[i].timePaused != undefined) _tweenList[i].timePaused = _currentTime - ((_currentTime - _tweenList[i].timePaused) * _timeScale / p_time); + } + // Sets the new timescale value (for new tweenings) + _timeScale = p_time; + } + } + + + // ================================================================================================================================== + // AUXILIARY functions -------------------------------------------------------------------------------------------------------------- + + /** + * Finds whether or not an object has any tweening + * + * @param p_scope Object Target object + * @return Boolean Whether or not there's a tweening occuring on this object (paused, delayed, or active) + */ + public static function isTweening(p_scope:Object):Boolean { + var i:Number; + + for (i = 0; i<_tweenList.length; i++) { + if (_tweenList[i].scope == p_scope) { + return true; + } + } + return false; + } + + /** + * Return an array containing a list of the properties being tweened for this object + * + * @param p_scope Object Target object + * @return Array List of strings with properties being tweened (including delayed or paused) + */ + public static function getTweens(p_scope:Object):Array { + var i:Number; + var pName:String; + var tList:Array = new Array(); + + for (i = 0; i<_tweenList.length; i++) { + if (_tweenList[i].scope == p_scope) { + for (pName in _tweenList[i].properties) tList.push(pName); + } + } + return tList; + } + + /** + * Return the number of properties being tweened for this object + * + * @param p_scope Object Target object + * @return Number Total count of properties being tweened (including delayed or paused) + */ + public static function getTweenCount(p_scope:Object):Number { + var i:Number; + var c:Number = 0; + + for (i = 0; i<_tweenList.length; i++) { + if (_tweenList[i].scope == p_scope) { + c += AuxFunctions.getObjectLength(_tweenList[i].properties); + } + } + return c; + } + + /* Handles errors when Tweener executes any callbacks (onStart, onUpdate, etc) + * If the TweenListObj specifies an onError callback it well get called, passing the Error object and the current scope as parameters. If no onError callback is specified, it will trace a stackTrace. + */ + private static function handleError(pTweening : Object, pError : Error, pCallBackName : String) : Void{ + // do we have an error handler? + if (pTweening.onError != undefined && typeof(pTweening.onError == "function")){ + // yup, there's a handler. Wrap this in a try catch in case the onError throws an error itself. + try{ + pTweening.onError.apply(pTweening.scope, [pTweening.scope, pError]); + }catch (metaError : Error){ + trace("## [Tweener] Error: " + pTweening.scope.toString() + " raised an error while executing the 'onError' handler. Original error:\n " + pError + "\nonError error: " + metaError); + } + }else{ + // if handler is undefied or null trace the error message (allows empty onErro's to ignore errors) + if (pTweening.onError == undefined){ + trace("## [Tweener] Error: " + pTweening.scope.toString() + " raised an error while executing the '" + pCallBackName.toString() + "'handler. \n" + pError ); + } + } + } + + /** + * Return the current tweener version + * + * @return String The number of the current Tweener version + */ + public static function getVersion():String { + return "AS2 1.26.62"; + } + + /** + * Return the name for the controller movieclip + * + * @return String The number of the current Tweener version + */ + public static function getControllerName():String { + return "__tweener_controller__"+Tweener.getVersion(); + } + + + + // ================================================================================================================================== + // DEBUG functions ------------------------------------------------------------------------------------------------------------------ + + public static function debug_getList():String { + var ttl:String = ""; + var i:Number; + var pName:String; + for (i = 0; i<_tweenList.length; i++) { + ttl += "["+i+"] ::\n"; + for (pName in _tweenList[i].properties) { + ttl += " " + pName +" -> " + _tweenList[i].properties[pName].valueComplete + "\n"; + } + } + return ttl; + } +} diff --git a/public/includes/ofc-1.9/actionscript/open-flash-chart.as b/public/includes/ofc-1.9/actionscript/open-flash-chart.as new file mode 100755 index 000000000..4a4990a05 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/open-flash-chart.as @@ -0,0 +1,981 @@ + +// rectangle with rounded corners +//#include "rrectangle.as" +#include "prototype.drawCircle.as" +#include "prototype.fillCircle.as" +#include "String.prototype.replace.as" + +MovieClip.prototype.rect = function( x:Number, y:Number, width:Number, height:Number, colour:Number, alpha:Number ) +{ + + this.beginFill( colour, 100 ); + this.moveTo( x, y ); + this.lineTo( x+width, y ); + this.lineTo( x+width, y+height ); + this.lineTo( x, y+height ); + this.lineTo( x, y ); + this.endFill(); + + this._alpha = alpha; + this._alpha_original = alpha; // <-- remember our original alpha while tweening + +} + +MovieClip.prototype.rect2 = function( x:Number, y:Number, width:Number, height:Number, colour:Number, alpha:Number ) +{ + this.beginFill( colour, alpha ); + this.moveTo( x, y ); + this.lineTo( x+width, y ); + this.lineTo( x+width, y+height ); + this.lineTo( x, y+height ); + this.lineTo( x, y ); + this.endFill(); +} + +function get_colour( col:String ) +{ + if( col.substr(0,2) == '0x' ) + return Number(col); + + if( col.substr(0,1) == '#' ) + return Number( '0x'+col.substr(1,col.length) ); + + if( col.length=6 ) + return Number( '0x'+col ); + + // not recognised as a valid colour, so? + return Number( col ); + +} + +// why isn't this built into flash? +// make a number 1000 = 1,000 +function format( i:Number ) +{ + return NumberUtils.formatNumber (i); +} + +function formatTime( sval:String ) +{ + var val:Number = parseFloat(sval); + var hours:Number = Math.floor(val); + var minutes:Number = Math.round((val - hours) * 60); + var rval:String = "" + hours; + if (rval.length < 2) { + rval = "0" + rval; + } + if (minutes < 10) { + rval = rval + ":0" + minutes; + } else { + rval = rval + ":" + minutes; + } + return rval; +} + +// added by NetVicious June 2007 +function setContextualMenu() +{ + var contextual_menu:ContextMenu = new ContextMenu(); + var About:ContextMenuItem = new ContextMenuItem("About Open Flash Chart..."); + About.onSelect = function(obj, item) { + // Go to project url + getURL("javascript:popup=window.open('http://teethgrinder.co.uk/open-flash-chart/','ofc', 'toolbar=Yes,location=Yes,scrollbars=Yes,menubar=Yes,status=Yes,resizable=Yes,fullscreen=No'); popup.focus()"); + }; + /* + If you want to remove default items of Flash (except conf and about) uncomment this line + contextual_menu.hideBuiltInItems(); + + + createClassObject + _root.menu = contextual_menu; + */ + contextual_menu.customItems.push(About); + + // + // added by J. Vandervort ( 15th Nov 2007 ) + // + var MyPrint:ContextMenuItem = new ContextMenuItem("Print Chart..."); + MyPrint.onSelect = function(obj, item) + { + var pj:PrintJob = new PrintJob(); + if (pj.start()) { + + // save original _root size + var r:Object = { + width: _root._width, + height: _root._height + }; + + // choose scalefactor from larger dimension + if(r.width > r.height){ + var scaleFactor = pj.pageWidth/r.width; + } else { + var scaleFactor = pj.pageWidth/r.height; + } + // do the _root scaling + _root._xscale = (scaleFactor*100) - 1; + _root._yscale = (scaleFactor*100) - 1; + + // add the page to the job and print + if (pj.addPage(0, {xMin:0, xMax:Stage.width, yMin:0, yMax:Stage.height})) { + pj.send(); // print page + } + // set original size back + with(_root){ + _width = r.width; + _height = r.height; + } + } + delete pj; + }; + + contextual_menu.customItems.push(MyPrint); + + //If you want to remove default items of Flash (except conf + // and about) uncomment this line + contextual_menu.hideBuiltInItems(); + + + createClassObject + _root.menu = contextual_menu; +} + +function TxtFormat(size:Number,colour:Number) +{ + var fmt:TextFormat = new TextFormat(); + fmt.color = colour; + fmt.font = "Verdana"; + fmt.size = size; + fmt.align = "center"; + return fmt; +} + + + +function FadeIn() +{ + this.onEnterFrame = function () + { + + _root.show_tip( + this, + this._x, + this._y-20, + this.tooltip + ); + + if( this._alpha < 100 ) + { + this._alpha += 10; + } + else + { + this._alpha = 100; + delete this.onEnterFrame; + } + } +} + +function FadeIn2() +{ + this.onEnterFrame = function () + { + if( this._alpha < 100 ) + { + this._alpha += 10; + } + else + { + this._alpha = 100; + delete this.onEnterFrame; + } + } +} + +function FadeOut() +{ + this.onEnterFrame = function () + { + + if( (this._alpha-5) > this._alpha_original ) + { + this._alpha -= 5; + } + else + { + this._alpha = this._alpha_original; + _root.hide_tip( this ); + delete this.onEnterFrame; + } + } +} + + +function hide_tip( owner:Object ) +{ + if( _root.tooltip._owner == owner ) + removeMovieClip("tooltip"); +} + +function get_x_legend() +{ + if( _root._x_legend != undefined ) + return _root._x_legend.get_legend(); +} + +function get_tooltip_string() +{ + return _root.tool_tip_wrapper; +} + +function get_x_axis_label( i:Number ) +{ + return _root._x_axis_labels.get( i ); +} + +function get_background_colour() +{ + return _root._background.colour; +} + +function format_y_axis_label( val:Number ) +{ + if( _root._y_format != undefined ) + { + var tmp:String = _root._y_format.replace('#val#',_root.format(val)); + tmp = tmp.replace('#val:time#',_root.formatTime(val)); + tmp = tmp.replace('#val:none#',String(val)); + tmp = tmp.replace('#val:number#', NumberUtils.formatNumber (Number(val))); + return tmp; + } + else + return _root.format(val); +} + +function show_tip( owner:Object, x:Number, y:Number, tip_obj:Object ) +{ + if( ( _root.tooltip != undefined ) ) + { + if(_root.tooltip._owner==owner) + return; // <-- it's our tooltip and it is showing + else + removeMovieClip("tooltip"); // <-- it is someone elses tootlip - remove it + } + + var tmp:String; + var lines:Array = []; + // + // Dirty hack. Takes a tool_tip_wrapper, and replaces the #val# with the + // tool_tip text, so noew you can do: "My Val = $#val#%", which turns into: + // "My Val = $12.00%" + // + if( _root.tool_tip_wrapper != undefined ) + { + tmp = _root.tool_tip_wrapper.replace('#val#',tip_obj.value); + tmp = tmp.replace('#key#',tip_obj.key); + tmp = tmp.replace('#x_label#',tip_obj.x_label); + tmp = tmp.replace('#val:time#',formatTime(tip_obj.value)); + + if( _root._x_legend != undefined ) + tmp = tmp.replace('#x_legend#',_root._x_legend.get_legend()); + } + else + { + if( tip_obj.x_label == undefined ) + tmp = tip_obj.value; + else + tmp = tip_obj.x_label+'
'+tip_obj.value; + } + + lines = tmp.split( '
' ); + + var tooltip = _root.createEmptyMovieClip( "tooltip", this.getNextHighestDepth() ); + + // let the tooltip know who owns it, else we get weird race conditions where one + // bar has onRollOver fired, then another has onRollOut and deletes the tooltip + tooltip._owner = owner; + + tooltip.createTextField( "txt_title", tooltip.getNextHighestDepth(), 5, 5, 100, 100); + if( lines.length > 1 ) + tooltip.txt_title.text = lines.shift(); + + var fmt:TextFormat = new TextFormat(); + fmt.color = 0x0000F0; + fmt.font = "Verdana"; + + // this needs to be an option: + fmt.bold = true; + fmt.size = 12; + fmt.align = "right"; + tooltip.txt_title.setTextFormat(fmt); + tooltip.txt_title.autoSize="left"; + + tooltip.createTextField( "txt", tooltip.getNextHighestDepth(), 5, tooltip.txt_title._height, 100, 100); + + tooltip.txt.text = lines.join( '\n' ); + + var fmt2:TextFormat = new TextFormat(); + fmt2.color = 0x000000; + fmt2.font = "Verdana"; + fmt2.size = 12; + fmt2.align = "left"; + tooltip.txt.setTextFormat(fmt2); + tooltip.txt.autoSize="left"; + + var max_width:Number = Math.max( tooltip.txt_title._width, tooltip.txt._width ); + var y_pos:Number = y - tooltip.txt_title._height - tooltip.txt._height; + + if( y_pos < 0 ) + { + // the tooltip has drifted off the top of the screen, move it down: + y_pos = y + tooltip.txt_title._height + tooltip.txt._height; + } + + var cstroke = {width:2, color:0x808080, alpha:100}; + var ccolor = {color:0xf0f0f0, alpha:100}; + + ChartUtil.rrectangle( + tooltip, + max_width+10, + tooltip.txt_title._height + tooltip.txt._height + 5, + 6, + ((x+max_width+16) > Stage.width ) ? (Stage.width-max_width-16) : x, + y_pos, + cstroke, + ccolor); + + // NetVicious, June, 2007 + // create shadow filter + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 4; + dropShadow.blurY = 4; + dropShadow.distance = 4; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.5; + // apply shadow filter + tooltip.filters = [dropShadow]; + +} + +function is_over( link:String ) +{ + _root._inv.use_hand( link ); +} + +function is_out() +{ + _root._inv.use_arrow(); +} + + +function mouse_over( ok:Boolean ) +{ + var x:Number = _root._xmouse; + var y:Number = _root._ymouse; + + if( !ok ) + { + // tell everyone that the mouse is NOT over them + x = -1; + y = -1; + } + + _root.chartValues.mouse_move( x, y ); +} + +// get the closest point from +// each data set. +function get_closest() +{ + var tmp:Array = []; + var style:Style = null; + + for( var i:Number=0; i < _root.chartValues.styles.length; i++) + { + var style:Style = _root.chartValues.styles[i]; + + // push the {ExPoint,distance} object + tmp.push( style.closest( _root._xmouse, _root._ymouse ) ); + } + + //for( var i:Number=0; i < tmp.length; i++ ) + // trace( i +' '+tmp[i].distance_x ); + return tmp; +} + +//_root.onMouseMove = function() +function mouse_move() +{ + if( _root.chartValues == undefined ) + return; + + // is the mouse over the invisible layer? + if( !_root._inv.hitTest(_root._xmouse, _root._ymouse) ) + return; + + // + mouse_over( true ); + + // get closest points from each data set + var closest:Array = _root.get_closest(); + + // find closest point along X axis + var min:Number = Number.MAX_VALUE; + for( var i:Number=0; i < closest.length; i++ ) + min = Math.min( min, closest[i].distance_x ); + + //for( var i:Number=0; i < closest.length; i++ ) + // trace( i +' '+closest[i].distance_x +' '+ closest[i].distance_y ); + + // now select all points that are the same distance + // along the X axis + var xx:Object = {point:null, distance_x:Number.MAX_VALUE, distance_y:Number.MAX_VALUE }; + for( var i:Number=0; i < closest.length; i++ ) + { + if( closest[i].distance_x == min ) + { + // these share the same X position, so choose + // the closest to the mouse in the Y + if( closest[i].distance_y < xx.distance_y ) + xx = closest[i]; + } + } + + _root.tooltip_x.draw( xx.point ); + xx.point.is_tip = true; + + // make the line dot nice and big, does + // nothing for bars + for( var i:Number=0; i < _root.chartValues.styles.length; i++) + _root.chartValues.styles[i].highlight_value(); +} + + + +function hide_oops() +{ + removeMovieClip("oops"); +} + +function oops( text:String ) +{ + if( _root.oops != undefined ) + { + hide_oops(); + } + + var mc:MovieClip = _root.createEmptyMovieClip( "oops", this.getNextHighestDepth() ); + mc.createTextField("txt", this.getNextHighestDepth(), 5, 5, 100, 100 ); + mc.txt.text = text; + + var fmt:TextFormat = new TextFormat(); + fmt.color = 0x000000; + fmt.font = "Verdana"; + fmt.size = 12; + fmt.align = "center"; + mc.txt.setTextFormat(fmt); + mc.txt.autoSize="left"; + + mc.txt.setTextFormat(fmt); + + var cstroke = {width:2, color:0x808080, alpha:100}; + var ccolor = {color:0xf0f0f0, alpha:100}; + + ChartUtil.rrectangle( + mc, + mc.txt._width+10, + mc.txt._height+10, + 6, + (Stage.width/2)-((mc.txt._width+10)/2), + (Stage.height/2)-((mc.txt._height+10)/2), + cstroke, + ccolor); + + var dropShadow = new flash.filters.DropShadowFilter(); + dropShadow.blurX = 4; + dropShadow.blurY = 4; + dropShadow.distance = 4; + dropShadow.angle = 45; + dropShadow.quality = 2; + dropShadow.alpha = 0.5; + // apply shadow filter + //mc.filters = [dropShadow]; +} + +function make_pie() +{ + _root._pie = new PieStyle( this, 'pie' ); + _root._title = new Title( this ); +} + + +function make_chart() +{ + // + // the order that these are built determines their Z order: + // + _root._inner_background = new InnerBackground( this ); + + _root._min_max = new MinMax( this ); + + // should the X Axis fit bar charts + // see Box.as for details + _root._x_offset = true; + if( this.x_offset != undefined ) + _root._x_offset = (this.x_offset!='false'); + + // we build the graph from top to bottom + _root._title = new Title( this ); + _root._x_legend = new XLegend( this ); + _root._y_legend = new YLegend( this , 1); + + if( this.show_y2 ) + _root._y2_legend = new YLegend( this , 2); + + var xTicks = 5; + if( this.x_ticks != undefined ) + xTicks = Number( this.x_ticks ); + + // size, colour + var x_label_style:XLabelStyle = new XLabelStyle( this ); + var y_label_style:YLabelStyle = new YLabelStyle( this, 1 ); + + if( this.show_y2 ) + var y_label_style2:YLabelStyle = new YLabelStyle( this, 2 ); + + + // create X labels and measure the height: + _root._x_axis_labels = new XAxisLabels( this, x_label_style, _root._min_max ); + + var xSteps = 1; + if( this.x_axis_steps != undefined ) + xStep = Number( this.x_axis_steps ); + + _root._x_axis = new XAxis( + xTicks, // <-- tick size + this, + xStep + ); + + _root._y_ticks = new YTicks( this ); + + // format the Y Axis numbers + _root._y_format = null; + if( this.y_format != undefined ) + _root._y_format = this.y_format; + + _root._y_axis_labels = new YAxisLabels( + y_label_style, + _root._min_max.y_min, + _root._min_max.y_max, + _root._y_ticks.steps, + 1, + this + ); + + if( this.show_y2 ) + { + _root._y_axis_labels2 = new YAxisLabels( + y_label_style2, + _root._min_max.y2_min, + _root._min_max.y2_max, + _root._y_ticks.steps, + 2, + this + ); + } + + + _root._y_axis = new YAxis( + _root._y_ticks, + this, + _root._min_max.y_min, + _root._min_max.y_max, + _root._y_ticks.steps, + 1 + ); + + if( this.show_y2 ) + { + _root._y_axis2 = new YAxis( + _root._y_ticks, + this, + _root._min_max.y_min, + _root._min_max.y_max, + _root._y_ticks.steps, + 2 + ); + } + + // The chart values are defined last and are on TOP of every thing else + _root.chartValues = new Values( this, _root._x_axis_labels.labels ); + + // tell the x axis where the grid lines are: + if( _root._min_max.has_x_range ) + { + // the user has specified the X axis min and max + // this is used in scatter charts + _root._x_axis.set_grid_count( + _root._min_max.x_max-_root._min_max.x_min+1 + ); + } + else + { + // the user has not told us how long the X axis + // is, so we figure it out: + _root._x_axis.set_grid_count( + Math.max( _root._x_axis_labels.count(), _root.chartValues.length() ) + ); + } + + _root._keys = new Keys( + (_root._y_legend.width()+_root._y_axis_labels.width()+_root._y_axis.width()), // <-- from left + _root._title.height(), // <-- from top + _root.chartValues.styles ); + + // this is last and floats over everything! + _root.tooltip_x = new Tooltip(); + + // + // HACK!! + // This is an invisible MovieClip that is on top of all + // MovieClips, all it does is detect if the mouse has left + // the flash movie (.swf) and remove the tooltip + // + _root._inv = new Invisible(); + +} + +function LoadVarsOnLoad( success ) +{ + if( !success ) + { + _root.loading.done(); + //_root.oops('Open Flash Chart: Error opening data file URL\n'+_root.data); + _root.oops(_root.data); + return; + } + + // remove loading data... message + if( _root.oops != undefined ) + removeMovieClip("oops"); + + //added by Maik Fox + //complete cleanup, no known side effects yet ;) + for(i in _root) + { + //if i is a movie clip, remove it + if(typeof(_root[i])=='movieclip') + { + removeMovieClip(_root[i]); + } + //delete it so that the garbage collector can collect it + delete i; + } + + _root.css = new Css('margin-top: 30;margin-right: 40;'); + + NumberFormat.getInstance(this); + NumberFormat.getInstanceY2(this); + + // + // Now we build the objects, the order in which we + // build them determins their Z position. + // + _root._background = new Background( this ); + + + // + // if we have a pie chart, we don't build the + // axis, grid and stuff.. + // + if( this.pie != undefined ) + this.make_pie(); + else + this.make_chart(); + + + if( this.tool_tip != undefined ) + { + _root.tool_tip_wrapper = this.tool_tip.replace('#comma#',','); + } + + _root.loading.done(); + _root.move(); +} + +function move() +{ + if( _root._pie != undefined ) + { + _root._background.move(); + _root._title.move(); + _root._pie.draw( _root._title.height() ); + return; + } + + // + // move items that may resize themselves: + // + _root._keys.move(); + + // + // measure the box: + // + var top:Number = _root._title.height()+_root._keys.height(); + var left:Number = _root._y_legend.width()+_root._y_axis_labels.width()+_root._y_axis.width(); + var right:Number = Stage.width; + // do we jiggle the box smaller because the last X Axis label + // is hanging off the end of the screen? + var jiggle:Boolean = true; + + if( _root._y_axis2 != undefined ) + { + right -= _root._y2_legend.width()+_root._y_axis_labels2.width()+_root._y_axis2.width(); + // no need to shrink the box: + jiggle = false; + } + + var bottom:Number = Stage.height-(_root._x_axis_labels.height()+_root._x_legend.height()+_root._x_axis.height()) + + var b:Box = new Box( + top, left, right, bottom, + _root._min_max, // <-- scale everything between min/max + _root._x_axis_labels.first_label_width(), + _root._x_axis_labels.last_label_width(), + _root._x_axis.get_grid_count(), + jiggle, + _root._x_axis.three_d, + _root._x_offset + ); + + + // + // tell everything else to move, the order in + // which we .move() things doesn't matter because + // they allready have their z-order assigned. + // + _root._background.move(); + _root._inner_background.move( b ); + _root._title.move(); + _root._x_legend.move(); + _root._y_legend.move(1); + + + if( _root._y_axis2 != undefined ) + _root._y2_legend.move(2); + + _root._y_axis_labels.move( _root._y_legend.width(), b ); + + // position of second y axel labels.. + if( _root._y_axis2 != undefined ) + _root._y_axis_labels2.move( Stage.width-(_root._y2_legend.width()+_root._y_axis_labels2.width()), b ); + + _root._x_axis.move( b ); + + // move x labels + _root._x_axis_labels.move( + Stage.height-(_root._x_legend.height()+_root._x_axis_labels.height()), // <-- up from the bottom + b ); + + _root._y_axis.move( b , 1); + + if( _root._y_axis2 != undefined ) + _root._y_axis2.move( b ); + + _root.chartValues.move( + b, + _root._min_max.y_min, + _root._min_max.y_max, // <-- scale everything between min/max + _root._min_max.y2_min, + _root._min_max.y2_max + ); + + _root._inv.move( b ); + +} + +// +// test JS to flash coms +// +import flash.external.*; +ExternalInterface.addCallback("set_title", null, setTitle); +function setTitle(str:String):Void +{ + if( _root._title != undefined ) + { + _root._title.build( str ); + _root.move(); + } + // for debuggig: + //_root.oops(str); +} + +ExternalInterface.addCallback("push_value", null, pushValue); +function pushValue( set:Number, val:String, label:String ):Void +{ + if( set<_root.chartValues.length() ) + { + _root.chartValues.styles[set].add( Number( val ), label ); + _root._x_axis_labels.add(label); + // tell the x axis where the grid lines are: + _root._x_axis.set_grid_count( _root.chartValues.length() ); + _root.move(); + } +} + +ExternalInterface.addCallback("delete_value", null, deleteValue); +function deleteValue( set:Number ):Void +{ + if( set<_root.chartValues.length() ) + { + _root.chartValues.styles[0].del(); + _root._x_axis_labels.del(); + // tell the x axis where the grid lines are: + _root._x_axis.set_grid_count( _root.chartValues.length() ); + _root.move(); + } +} + +ExternalInterface.addCallback("show_message", null, show_message); +function show_message( msg:String ):Void +{ + _root.oops(msg); +} + +ExternalInterface.addCallback("hide_message", null, hide_message); +function hide_message():Void +{ + hide_oops(); +} + +ExternalInterface.addCallback("reload", null, reload); +function reload( u:String, show_loading:Boolean ):Void +{ + if( show_loading == undefined ) + show_loading = true; + + if( show_loading ) + { + // inform the user we are reloading data: + _root.loading = new Loading('Loading data...'); + } + + var url:String = ''; + + if( _root.data != undefined ) + url = _root.data; + + if( u != undefined ) + { + if( u.length > 0 ) + { + url = u; + } + } + //setTitle( u ); + + // + // this bit of code has had a patchy history, + // we don't need a new LoadVars object, but + // if we don't delete it, the object holds + // onto the old variabels. So say we load 2 + // data sets, then load 1 data set, we end up + // with one new set and one old set. So we + // *do* need to delete it, just to get rid of + // the old data :-) + // + _root.lv = undefined; + _root.lv = new LoadVars(); + _root.lv.onLoad = LoadVarsOnLoad; + _root.lv.make_chart = make_chart; + _root.lv.make_pie = make_pie; + _root.lv.load(url); + // + // ----- end ----- + // +} + + +// +// +// +// ******************************************************************************** + +_root.loading = new Loading('Loading data...'); + +// so we can rotate text: +this.embedFonts = true; + +_root.chartValues = new Array(); + +// -------------------------------------------------------------+ +// +// tell flash to align top left, and not to scale +// anything (we do that in the code) +// +Stage.align = "LT"; +// +// ----- RESIZE ---- +// +// noScale: now we can pick up resize events +Stage.scaleMode = "noScale"; +// +var stageListener:Object = new Object(); +stageListener.onResize = function() +{ + //trace("w:"+Stage.width+", h:"+Stage.height); + _root.move(); +}; +Stage.addListener(stageListener); +// +// ------ END RESIZE ---- +// +// + +// NetVicious, June 2007 +// Right click menu: +setContextualMenu(); + +// +// LOAD THE DATA +// + +var lv:LoadVars = new LoadVars(); + +//lv.onLoad = function( success ) +lv.onLoad = LoadVarsOnLoad; +lv.make_chart = make_chart; +lv.make_pie = make_pie; + +// from URL +if( _root.data == undefined ) +{ + if( _root.variables == undefined ) + { + // + // We are in the IDE + // + _root.data="C:\\Users\\John\\Documents\\flash\\svn\\data-files\\data-47.txt"; + //_root.data="http://www.stelteronline.de/index.php?option=com_joomleague&func=showStats_GetChartData&p=1"; + lv.load(_root.data); + } + else + { + // + // Load from inline HTML variables + // + _root.LoadVarsOnLoad = LoadVarsOnLoad; + _root.LoadVarsOnLoad( true ); + } +} +else +{ + // + // An external file + // + lv.load(_root.data); +} + +stop(); diff --git a/public/includes/ofc-1.9/actionscript/open-flash-chart.fla b/public/includes/ofc-1.9/actionscript/open-flash-chart.fla new file mode 100755 index 0000000000000000000000000000000000000000..39ae58cc0621deb6bccddc34f9f4869de1f4cff3 GIT binary patch literal 22528 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 + + +open-flash-chart + + + + + + + + + + + diff --git a/public/includes/ofc-1.9/actionscript/open-flash-chart.swf b/public/includes/ofc-1.9/actionscript/open-flash-chart.swf new file mode 100755 index 0000000000000000000000000000000000000000..85b590a28f4a5cea29eefa8c7cad6b551e29de4a GIT binary patch literal 64600 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 HtI>lMRC*G= literal 0 HcmV?d00001 diff --git a/public/includes/ofc-1.9/actionscript/prototype.drawCircle.as b/public/includes/ofc-1.9/actionscript/prototype.drawCircle.as new file mode 100755 index 000000000..654d64180 --- /dev/null +++ b/public/includes/ofc-1.9/actionscript/prototype.drawCircle.as @@ -0,0 +1,19 @@ +MovieClip.prototype.drawCircle = function(x, y, radius, accuracy ) +{ + if (a < 3) a = 3; + var span = Math.PI/accuracy; + var controlRadius = radius/Math.cos(span); + var anchorAngle=0, controlAngle=0; + this.moveTo(x+Math.cos(anchorAngle)*radius, y+Math.sin(anchorAngle)*radius); + for (var i=0; i 7) { + // only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE + deconcept.SWFObject.doPrepUnload = true; + } + if(c) { this.addParam('bgcolor', c); } + var q = quality ? quality : 'high'; + this.addParam('quality', q); + this.setAttribute('useExpressInstall', false); + this.setAttribute('doExpressInstall', false); + var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location; + this.setAttribute('xiRedirectUrl', xir); + this.setAttribute('redirectUrl', ''); + if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); } +} +deconcept.SWFObject.prototype = { + useExpressInstall: function(path) { + this.xiSWFPath = !path ? "expressinstall.swf" : path; + this.setAttribute('useExpressInstall', true); + }, + setAttribute: function(name, value){ + this.attributes[name] = value; + }, + getAttribute: function(name){ + return this.attributes[name]; + }, + addParam: function(name, value){ + this.params[name] = value; + }, + getParams: function(){ + return this.params; + }, + addVariable: function(name, value){ + this.variables[name] = value; + }, + getVariable: function(name){ + return this.variables[name]; + }, + getVariables: function(){ + return this.variables; + }, + getVariablePairs: function(){ + var variablePairs = new Array(); + var key; + var variables = this.getVariables(); + for(key in variables){ + variablePairs[variablePairs.length] = key +"="+ variables[key]; + } + return variablePairs; + }, + getSWFHTML: function() { + var swfNode = ""; + if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture + if (this.getAttribute("doExpressInstall")) { + this.addVariable("MMplayerType", "PlugIn"); + this.setAttribute('swf', this.xiSWFPath); + } + swfNode = ' 0){ swfNode += 'flashvars="'+ pairs +'"'; } + swfNode += '/>'; + } else { // PC IE + if (this.getAttribute("doExpressInstall")) { + this.addVariable("MMplayerType", "ActiveX"); + this.setAttribute('swf', this.xiSWFPath); + } + swfNode = ''; + swfNode += ''; + var params = this.getParams(); + for(var key in params) { + swfNode += ''; + } + var pairs = this.getVariablePairs().join("&"); + if(pairs.length > 0) {swfNode += '';} + swfNode += ""; + } + return swfNode; + }, + write: function(elementId){ + if(this.getAttribute('useExpressInstall')) { + // check to see if we need to do an express install + var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]); + if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) { + this.setAttribute('doExpressInstall', true); + this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl'))); + document.title = document.title.slice(0, 47) + " - Flash Player Installation"; + this.addVariable("MMdoctitle", document.title); + } + } + if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){ + var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId; + n.innerHTML = this.getSWFHTML(); + return true; + }else{ + if(this.getAttribute('redirectUrl') != "") { + document.location.replace(this.getAttribute('redirectUrl')); + } + } + return false; + } +} + +/* ---- detection functions ---- */ +deconcept.SWFObjectUtil.getPlayerVersion = function(){ + var PlayerVersion = new deconcept.PlayerVersion([0,0,0]); + if(navigator.plugins && navigator.mimeTypes.length){ + var x = navigator.plugins["Shockwave Flash"]; + if(x && x.description) { + PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".")); + } + }else if (navigator.userAgent && navigator.userAgent.indexOf("Windows CE") >= 0){ // if Windows CE + var axo = 1; + var counter = 3; + while(axo) { + try { + counter++; + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+ counter); +// document.write("player v: "+ counter); + PlayerVersion = new deconcept.PlayerVersion([counter,0,0]); + } catch (e) { + axo = null; + } + } + } else { // Win IE (non mobile) + // do minor version lookup in IE, but avoid fp6 crashing issues + // see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/ + try{ + var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + }catch(e){ + try { + var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + PlayerVersion = new deconcept.PlayerVersion([6,0,21]); + axo.AllowScriptAccess = "always"; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code) + } catch(e) { + if (PlayerVersion.major == 6) { + return PlayerVersion; + } + } + try { + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + } catch(e) {} + } + if (axo != null) { + PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(",")); + } + } + return PlayerVersion; +} +deconcept.PlayerVersion = function(arrVersion){ + this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0; + this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0; + this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0; +} +deconcept.PlayerVersion.prototype.versionIsValid = function(fv){ + if(this.major < fv.major) return false; + if(this.major > fv.major) return true; + if(this.minor < fv.minor) return false; + if(this.minor > fv.minor) return true; + if(this.rev < fv.rev) return false; + return true; +} +/* ---- get value of query string param ---- */ +deconcept.util = { + getRequestParameter: function(param) { + var q = document.location.search || document.location.hash; + if (param == null) { return q; } + if(q) { + var pairs = q.substring(1).split("&"); + for (var i=0; i < pairs.length; i++) { + if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { + return pairs[i].substring((pairs[i].indexOf("=")+1)); + } + } + } + return ""; + } +} +/* fix for video streaming bug */ +deconcept.SWFObjectUtil.cleanupSWFs = function() { + var objects = document.getElementsByTagName("OBJECT"); + for (var i = objects.length - 1; i >= 0; i--) { + objects[i].style.display = 'none'; + for (var x in objects[i]) { + if (typeof objects[i][x] == 'function') { + objects[i][x] = function(){}; + } + } + } +} +// fixes bug in some fp9 versions see http://blog.deconcept.com/2006/07/28/swfobject-143-released/ +if (deconcept.SWFObject.doPrepUnload) { + if (!deconcept.unloadSet) { + deconcept.SWFObjectUtil.prepUnload = function() { + __flash_unloadHandler = function(){}; + __flash_savedUnloadHandler = function(){}; + window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs); + } + window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload); + deconcept.unloadSet = true; + } +} +/* add document.getElementById if needed (mobile IE < 5) */ +if (!document.getElementById && document.all) { document.getElementById = function(id) { return document.all[id]; }} + +/* add some aliases for ease of use/backwards compatibility */ +var getQueryParamValue = deconcept.util.getRequestParameter; +var FlashObject = deconcept.SWFObject; // for legacy support +var SWFObject = deconcept.SWFObject; diff --git a/wp_plugin.php b/wp_plugin.php index 35d24ad93..905e0285e 100644 --- a/wp_plugin.php +++ b/wp_plugin.php @@ -2,10 +2,10 @@ /* Plugin Name: Open Web Analytics -Plugin URI: http://www.openwebanalytics +Plugin URI: http://www.openwebanalytics.com Description: This plugin enables Wordpress blog owners to use the Open Web Analytics Framework. Author: Peter Adams -Version: v1.1 +Version: v1.2 Author URI: http://www.openwebanalytics.com */