[Jifty-commit] r3770 - in jifty/branches/virtual-models: . lib/Jifty/Plugin lib/Jifty/Plugin/Chart lib/Jifty/Plugin/Chart/Renderer lib/Jifty/Plugin/Chart/Renderer/GD lib/Jifty/Web share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit share/web/static/js t t/TestApp-Plugin-Chart/lib/TestApp/Plugin/Chart t/TestApp-Plugin-Chart/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Fri Aug 3 13:01:44 EDT 2007


Author: sterling
Date: Fri Aug  3 13:01:43 2007
New Revision: 3770

Added:
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/PlotKit_Packed-20060807-custom.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/chart_img_behaviour.js
Removed:
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/Base.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/Canvas.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/EasyPlot.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/Layout.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/PlotKit.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/PlotKit_Packed.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/SVG.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/SweetCanvas.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/SweetSVG.js
   jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/dummy.svg
Modified:
   jifty/branches/virtual-models/   (props changed)
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/Chart.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/GD/Graph.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/PlotKit.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Web.pm
   jifty/branches/virtual-models/lib/Jifty/Web/Session.pm
   jifty/branches/virtual-models/share/web/static/js/jifty.js
   jifty/branches/virtual-models/t/13-sessions.t
   jifty/branches/virtual-models/t/TestApp-Plugin-Chart/lib/TestApp/Plugin/Chart/View.pm
   jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/chart.t
   jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/gd_graph.t

Log:
 r8330 at riddle:  andrew | 2007-08-03 11:52:12 -0500
 Mergedown from trunk.
 
  r8303 at riddle:  andrew | 2007-08-02 08:26:56 -0500
  Add explicit hide/show for the error, warning, and canonicalization note divs. This solves some long time ugliness on IE. However, it is not perfect as I am still getting some rendering issues on IE. Does not seem to break anything on FF.
  r8309 at riddle:  andrew | 2007-08-02 08:27:21 -0500
   r8304 at dynpc145 (orig r3760):  jesse | 2007-08-01 14:15:14 -0500
   
   r8305 at dynpc145 (orig r3761):  jesse | 2007-08-01 14:15:32 -0500
    r65037 at pinglin:  jesse | 2007-08-01 15:11:00 -0400
     * clean up load_by_kv
   
   r8306 at dynpc145 (orig r3762):  sartak | 2007-08-01 14:31:06 -0500
    r29755 at caladan:  sartak | 2007-08-01 15:30:21 -0400
    Add failing tests for load_by_kv with chr(0)
   
   r8307 at dynpc145 (orig r3763):  trs | 2007-08-01 21:33:42 -0500
    r25802 at zot:  tom | 2007-08-01 22:33:03 -0400
    *Very* custom packed PlotKit (from svn) that no longer depends on MochiKit exporting functions into the global namespace
    
    Still need to solve the issue of why MochiKit blows up when included in our honkin' JS file...
   
   r8308 at dynpc145 (orig r3764):  trs | 2007-08-02 01:28:00 -0500
    r25809 at zot:  tom | 2007-08-02 02:25:34 -0400
    Don't mess with the data structure if it's already what plotkit expects
   
  
  r8325 at riddle:  andrew | 2007-08-03 11:09:49 -0500
  Making the IMG-based chart renderers capable of handling CSS styling with some added behaviour.
  r8326 at riddle:  andrew | 2007-08-03 11:10:20 -0500
  
  r8328 at riddle:  andrew | 2007-08-03 11:40:04 -0500
  Added a renderer parameter to the chart() method and add per-renderer initialization.
 


Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart.pm	Fri Aug  3 13:01:43 2007
@@ -5,8 +5,9 @@
 use base qw/ Jifty::Plugin Class::Accessor::Fast /;
 
 use Jifty::Plugin::Chart::Web;
+use Scalar::Util qw/ blessed /;
 
-__PACKAGE__->mk_accessors(qw/ renderer /);
+__PACKAGE__->mk_accessors(qw/ renderer renderers /);
 
 =head1 NAME
 
@@ -71,24 +72,52 @@
         @_,
     );
 
-    if ( $args{renderer} !~ /::/ ) {
-        $args{renderer} = __PACKAGE__.'::Renderer::'.$args{renderer};
+    # Create the empty renderers list
+    $self->renderers({});
+
+    # Load the default renderer
+    $self->renderer( $self->init_renderer($args{renderer}) );
+
+    push @Jifty::Web::ISA, 'Jifty::Plugin::Chart::Web';
+}
+
+=head2 init_renderer
+
+  my $renderer = $chart_plugin->init_renderer($renderer_class)
+
+This is a helper method that is used by the API to initialize the renderer class. This is handled automatically so you probably shouldn't use this.
+
+=cut
+
+sub init_renderer {
+    my ($self, $renderer_class) = @_;
+
+    # If it's already an object, just return that
+    if ( blessed($renderer_class)
+            and $renderer_class->isa(__PACKAGE__.'::Renderer') ) {
+        return $renderer_class;
     }
 
-    eval "use $args{renderer}";
-    warn $@ if $@;
-    $self->renderer( $args{renderer} );
-
-    if ( $self->renderer =~ 'PlotKit' ) {
-        # XXX TODO: Why does MochiKit need to be loaded before everything else?
-        Jifty->web->javascript_libs([
-            'MochiKit/MochiKit.js',
-            @{ Jifty->web->javascript_libs },
-            'PlotKit/PlotKit_Packed.js'
-        ]);
+    # Prepend Jifty::Plugin::Chart::Renderer:: if we think we need to
+    if ( $renderer_class !~ /::/ ) {
+        $renderer_class = __PACKAGE__.'::Renderer::'.$renderer_class;
     }
 
-    push @Jifty::Web::ISA, 'Jifty::Plugin::Chart::Web';
+    # Check to see if we already loaded this one
+    my $renderer = $self->renderers->{ $renderer_class };
+    return $renderer if defined $renderer;
+
+    # Tell perl to load the class
+    $renderer_class->require;
+
+    # Initialize the renderer
+    $renderer = $renderer_class->new;
+
+    # Remember it
+    $self->renderers->{ $renderer_class } = $renderer;
+
+    # Return it!
+    return $renderer;
 }
 
 =head1 SEE ALSO

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Dispatcher.pm	Fri Aug  3 13:01:43 2007
@@ -24,11 +24,24 @@
 
     # Unpack the data and then clear it from the session
     my $args = Jifty::YAML::Load( Jifty->web->session->get( $session_id ) );
-    Jifty->web->session->remove( $session_id );
+
+    # XXX if there are a lot of charts, this could asplode
+    #Jifty->web->session->remove( $session_id );
 
     # No data? Act like a 404
     last_rule unless defined $args;
 
+    # Request might override width/height:
+    $args->{width}  = get 'width'  if get 'width';
+    $args->{height} = get 'height' if get 'height';
+
+    # XXX TODO Is there a better way to guess the pixel heights when using CSS
+    # heights initially?
+
+    # Remove 'px' from width/height and set to 400/300 if not in pixels
+    ($args->{width}  =~ s/px$//) or ($args->{width}  = 400);
+    ($args->{height} =~ s/px$//) or ($args->{height} = 300);
+
     # Use the "type" to determine which class to use
     my $class = 'Chart::' . $args->{type};
 
@@ -55,11 +68,24 @@
 
     # Unpack the data and then clear it from the session
     my $args = Jifty::YAML::Load( Jifty->web->session->get( $session_id ) );
-    Jifty->web->session->remove( $session_id );
+
+    # XXX If there are lots of charts, this could asplode
+    #Jifty->web->session->remove( $session_id );
 
     # No data? Act like a 404
     last_rule unless defined $args;
 
+    # Request might override width/height:
+    $args->{width}  = get 'width'  if get 'width';
+    $args->{height} = get 'height' if get 'height';
+
+    # XXX TODO Is there a better way to guess the pixel heights when using CSS
+    # heights initially?
+
+    # Remove 'px' from width/height and set to 400/300 if not in pixels
+    ($args->{width}  =~ s/px$//) or ($args->{width}  = 400);
+    ($args->{height} =~ s/px$//) or ($args->{height} = 300);
+
     # Use the "type" to determine which class to use
     my $class = 'GD::Graph::' . $args->{type};
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer.pm	Fri Aug  3 13:01:43 2007
@@ -20,15 +20,15 @@
   package MyApp::Renderer;
   use base qw/ Jifty::Plugin::Chart::Renderer /;
 
+  sub init {
+      my $self = shift;
+
+      # Handle any required initialization, like required CSS, JS, etc.
+  }
+
   sub render {
       my $self = shift;
-      my %args = (
-          type   => 'points',
-          width  => 400,
-          height => 300,
-          data   => [],
-          @_,
-      );
+      my %args = @_;
 
       # Output your chart
       Jifty->web->out( #{ Output your chart here... } );
@@ -41,6 +41,29 @@
 
 Your renderer implementation must subclass this package and implement the following methods:
 
+=head2 new
+
+This is the constructor. Don't override this directly. Instead implement L</init>.
+
+=cut
+
+sub new {
+    my $class = shift;
+    my $self = bless {}, $class;
+    $self->init;
+    return $self;
+}
+
+=head2 init
+
+  $renderer->init();
+
+This is called by C<new> immediately after constructing the object. Subclasses should implement this method to do any required initialization such as letting Jifty know about required CSS files, JS files, etc.
+
+=cut
+
+sub init {}
+
 =head2 render
 
   Jifty->web->out($renderer->render(%args));
@@ -49,6 +72,10 @@
 
 The C<render> method may either return it's output or print it out using L<Jifty::Web::out>.
 
+=cut
+
+sub render {}
+
 =head1 SEE ALSO
 
 L<Jifty::Plugin::Chart::Web>, L<Jifty::Plugin::Chart::Renderer::Chart>

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/Chart.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/Chart.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/Chart.pm	Fri Aug  3 13:01:43 2007
@@ -16,6 +16,16 @@
 
 =head1 METHODS
 
+=head2 init
+
+Adds the F<chart_img_behaviour.js> script to those loaded.
+
+=cut
+
+sub init {
+    Jifty->web->add_javascript('chart_img_behaviour.js');
+}
+
 =head2 render
 
 Implemented the L<Jifty::Plugin::Chart::Renderer/render> method interface.
@@ -34,8 +44,21 @@
     my $session_id = 'chart_' . $chart_id;
     Jifty->web->session->set( $session_id => Jifty::YAML::Dump(\%args) );
 
+    # Build up the chart tag
+    my $img;
+    $img  = qq{<img};
+    $img .= qq{ src="/chart/chart/$chart_id"};
+    $img .= qq{ class="@{[ join ' ', @{ $args{class} } ]}"};
+
+    my @styles;
+    push @styles, "width:$args{width}"   if defined $args{width};
+    push @styles, "height:$args{height}" if defined $args{height};
+
+    $img .= qq{ style="@{[ join ';', @styles ]}"} if @styles;
+    $img .= qq{/>};
+    
     # Output the <img> tag and include the chart's configuration key
-    Jifty->web->out(qq{<img src="/chart/chart/$chart_id" width="$args{width}" height="$args{height}"/>});
+    Jifty->web->out($img);
 
     # Make sure we don't return anything that will get output
     return;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/GD/Graph.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/GD/Graph.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/GD/Graph.pm	Fri Aug  3 13:01:43 2007
@@ -22,6 +22,16 @@
 
 =head1 METHODS
 
+=head2 init
+
+Adds the F<chart_img_behaviour.js> script to those loaded.
+
+=cut
+
+sub init {
+    Jifty->web->add_javascript('chart_img_behaviour.js');
+}
+
 =head2 render
 
 Renders an IMG tag referring to the L<GD::Graph> image view.
@@ -40,8 +50,21 @@
     my $session_id = 'chart_' . $chart_id;
     Jifty->web->session->set( $session_id => Jifty::YAML::Dump(\%args) );
 
+    # Build up the chart tag
+    my $img;
+    $img  = qq{<img};
+    $img .= qq{ src="/chart/gd_graph/$chart_id"};
+    $img .= qq{ class="@{[ join ' ', @{ $args{class} } ]}"};
+
+    my @styles;
+    push @styles, "width:$args{width}"   if defined $args{width};
+    push @styles, "height:$args{height}" if defined $args{height};
+
+    $img .= qq{ style="@{[ join ';', @styles ]}"} if @styles;
+    $img .= qq{/>};
+
     # Output the <img> tag and include the chart's configuration key
-    Jifty->web->out(qq{<img src="/chart/gd_graph/$chart_id" width="$args{width}" height="$args{height}"/>});
+    Jifty->web->out($img);
 
     # Make sure we don't return anything that will get output
     return;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/PlotKit.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/PlotKit.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Renderer/PlotKit.pm	Fri Aug  3 13:01:43 2007
@@ -16,6 +16,23 @@
 
 =head1 METHODS
 
+=head2 init
+
+Adds the various JavaScript files required to use PlotKit.
+
+=cut
+
+sub init {
+    Jifty->web->add_external_javascript(qw(
+        /static/js/mochikit.noexport.js
+        /static/js/MochiKit/MochiKit.js
+    ));
+    Jifty->web->add_javascript(qw(
+        PlotKit/excanvas.js
+        PlotKit/PlotKit_Packed-20060807-custom.js
+    ));
+}
+
 =head2 render
 
 Implemented the L<Jifty::Plugin::Chart::Renderer/render> method interface.
@@ -87,7 +104,11 @@
         my @ds;
         for ( my $i = 0; $i < @$dataset; $i++ ) {
             # PlotKit can't deal with undefined values
-            push @ds, [ $i, defined $dataset->[$i] ? $dataset->[$i] : '0' ];
+            if ( not ref $dataset->[$i] ) {
+                push @ds, [ $i, defined $dataset->[$i] ? $dataset->[$i] : '0' ];
+            } else {
+                push @ds, $dataset->[$i];
+            }
         }
         push @data, \@ds;
     }

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Web.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Web.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Chart/Web.pm	Fri Aug  3 13:01:43 2007
@@ -3,6 +3,8 @@
 
 package Jifty::Plugin::Chart::Web;
 
+use Scalar::Util qw/ looks_like_number /;
+
 =head1 NAME
 
 Jifty::Plugin::Chart::Web - Base class to add to Jifty::Web's ISA
@@ -55,11 +57,15 @@
 
 =item width
 
-The width, in pixels, the chart should take on the page. Defaults to 400.
+This is the width the chart should take when rendered. This may be a number, indicating the width in pixels. It may also be any value that would be appropriate for the C<width> CSS property.
+
+Defaults to C<undef>, which indicates that the chart will take on whatever size the box it is in will be. See L</CSS FOR CHARTS>.
 
 =item height
 
-The height, in pixels, the chart should take on the page. Defaults to 300.
+This is the height the chart should take when rendered. This may be a number, indicating the height in pixels. It may also be any value that would be appropriate for the C<height> CSS property.
+
+Defaults to C<undef>, which indicates that the chart will take on whatever size the box it is in will be. See L</CSS FOR CHARTS>.
 
 =item data
 
@@ -67,20 +73,29 @@
 
 Defaults to no data (i.e., it must be given if anything useful is to happen).
 
+=item class
+
+This allows you to associated an additional class or classes to the element containing the chart. This can be a string containing on or more class names separated by spaces or an array of class names.
+
+=item renderer
+
+This allows you to use a different renderer than the one configured in F<config.yml>. Give the renderer as a class name, which will be initialized for you.
+
 =back
 
 Here's an example:
 
   <% Jifty->web->chart(
       type   => 'Pie',
-      width  => 400,
-      height => 300,
+      width  => '100%',
+      height => '300px',
       data   => sub {
           [
               [ 2004, 2005, 2006, 2007 ],
               [ 26, 37, 12, 42 ]
           ];
       },
+      class => 'visualizeronimicon',
   ) %>
 
 Be sure to output anything returned by the method (unless it returns undef).
@@ -94,22 +109,51 @@
     # TODO It might be a good idea to make this config.yml-able
     # Setup the defaults
     my %args = (
-        type   => 'points',
-        width  => 400,
-        height => 300,
-        data   => [],
+        renderer => $plugin->renderer,
+        type     => 'points',
+        width    => undef,
+        height   => undef,
+        data     => [],
+        class    => [],
         @_,
     );
 
+    # load the renderer
+    $args{renderer} = $plugin->init_renderer($args{renderer});
+
+    # canonicalize the width/height
+    $args{width}  .= 'px' if looks_like_number($args{width});
+    $args{height} .= 'px' if looks_like_number($args{height});
+
+    # canonicalize the class argument
+    if (not ref $args{class}) {
+        $args{class} = defined $args{class} ? [ $args{class} ] : [];
+    }
+
+    # Add the chart class, which is always present
+    push @{ $args{class} }, 'chart';
+
     # Turn any subs into values returned
     for my $key (keys %args) {
         $args{$key} = $args{$key}->(\%args) if ref $args{$key} eq 'CODE';
     }
 
-    # Call the rendering plugin's render method
-    return $plugin->renderer->render(%args);
+    # Call the rendering class' render method
+    return $args{renderer}->render(%args);
 }
 
+=head1 CSS FOR CHARTS
+
+The chart API allows you to build the charts without explicit pixel widths and heights. In fact, you can not specify C<width> and C<height> and perform the styling in your regular CSS stylesheets by using the "chart" class associated with every chart or by using custom classes with the C<class> argument.
+
+See your renderer class documentation for further details.
+
+=head1 JAVASCRIPT FOR CHARTS
+
+Charts typically require JavaScript to render properly. If the client does not have JavaScript available, the chart may not work or could look very bad. 
+
+If you are using one of the image based renderers like L<Jifty::Plugin::Chart::Renderer::Chart>, it is recommended that you stick with pixel widths if you expect clients with limited or no JavaScript support. 
+
 =head1 SEE ALSO
 
 L<Jifty::Plugin::Chart>, L<Jifty::Plugin::Chart::Renderer>

Modified: jifty/branches/virtual-models/lib/Jifty/Web/Session.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web/Session.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web/Session.pm	Fri Aug  3 13:01:43 2007
@@ -5,6 +5,7 @@
 use base qw/Jifty::Object/;
 use CGI::Cookie ();
 use DateTime ();
+use Storable ();
  
 =head1 NAME
 
@@ -76,42 +77,39 @@
     $self->{cache} = undef;
 }
 
-=head2 load_by_kv key => value OR key, default, callback
+=head2 load_by_kv key => value 
 
 Load up the current session from the given (key, value) pair. If no matching
 session could be found, it will create a new session with the key, value set.
 Be sure that what you're loading by is unique. If you're loading a session
 based on, say, a timestamp, then you're asking for trouble.
 
-The second form is used when you have a complex value. Each value for the
-given key is passed to the callback. The callback should return true if
-there's a match. The default value is used to create a new entry when no
-value was chosen.
-
 =cut
 
 sub load_by_kv {
     my $self = shift;
-    my $k = shift;
-    my $v = shift;
-    my $callback = shift || sub { $_[0] eq $v };
+    my $k    = shift;
+    my $v    = shift;
     my $session_id;
 
     # tried doing this with load_by_cols but it never returned any rows
     my $sessions = Jifty::Model::SessionCollection->new;
-    $sessions->limit(column => 'key_type', value => 'key');
-    $sessions->limit(column => 'data_key', value => $k );
+    $sessions->limit( column => 'key_type', value => 'key' );
+    $sessions->limit( column => 'data_key', value => $k );
 
-    while (my $row = $sessions->next) {
-        my $match = $callback->($row->value);
-        if ($match) {
-            $session_id = $row->session_id;
-            last;
-        }
+    # XXX TODO: we store this data in a storable. so we now want to match on the storable version
+    # It would be so nice if Jifty::DBI could do this for us.
+    $Storable::Deparse = 1;
+    my $value = Storable::nfreeze(\$v);
+
+    $sessions->limit( column => 'value' => value => $value );
+
+    while ( my $row = $sessions->next ) {
+        $session_id = $row->session_id;
+        last;
     }
-
     $self->load($session_id);
-    $self->set($k => $v) if !$session_id;
+    $self->set( $k => $v ) if !$session_id;
 }
 
 sub _get_session_id_from_client {

Added: jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/PlotKit_Packed-20060807-custom.js
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/PlotKit/PlotKit_Packed-20060807-custom.js	Fri Aug  3 13:01:43 2007
@@ -0,0 +1,1592 @@
+/***
+
+    PlotKit.PlotKit 0.9 : PACKED VERSION
+
+    THIS FILE IS AUTOMATICALLY GENERATED.  If creating patches, please
+    diff against the source tree, not this file.
+
+    For more information, <http://www.liquidx.net/plotkit/>.
+    
+    Copyright (c) 2006. Alastair Tse.
+
+***/
+
+try{
+if(typeof (MochiKit.Base)=="undefined"||typeof (MochiKit.DOM)=="undefined"||typeof (MochiKit.Color)=="undefined"||typeof (MochiKit.Format)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format}";
+}
+MochiKit.Base.update(MochiKit.Color.Color.prototype,{asFillColor:function(){
+return this.lighterColorWithLevel(0.3);
+},asStrokeColor:function(){
+return this.darkerColorWithLevel(0.1);
+},asPointColor:function(){
+return this.lighterColorWithLevel(0.1);
+}});
+if(typeof (PlotKit)=="undefined"){
+PlotKit={};
+}
+PlotKit.NAME="PlotKit";
+PlotKit.VERSION="0.8";
+PlotKit.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.toString=function(){
+return this.__repr__();
+};
+if(typeof (PlotKit.Base)=="undefined"){
+PlotKit.Base={};
+}
+PlotKit.Base.NAME="PlotKit.Base";
+PlotKit.Base.VERSION=PlotKit.VERSION;
+PlotKit.Base.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.Base.toString=function(){
+return this.__repr__();
+};
+PlotKit.Base.usingPrototype=function(){
+try{
+return (typeof (Object.extend)=="function");
+}
+catch(e){
+return false;
+}
+};
+MochiKit.Base.update(PlotKit.Base,{roundInterval:function(_1,_2,_3){
+var _4=MochiKit.Format.roundToFixed;
+var _5=_1/_2;
+return parseFloat(_4(_5,_3));
+},collapse:function(_6){
+var m=MochiKit.Base;
+var _8=new Array();
+for(var i=0;i<_6.length;i++){
+_8=m.concat(_8,_6[i]);
+}
+if(PlotKit.Base.usingPrototype()){
+delete _8.extend;
+delete _8.from;
+delete _8.inspect;
+}
+return _8;
+},uniq:function(_10){
+var m=MochiKit.Base;
+if(!m.isArrayLike(_10)||(_10.length<1)){
+return new Array();
+}
+var _11=new Array();
+var _12=_10[0];
+_11.push(_10[0]);
+for(var i=1;i<_10.length;i++){
+if(m.compare(_10[i],_12)!=0){
+_12=_10[i];
+_11.push(_10[i]);
+}
+}
+return _11;
+},colorScheme:function(){
+var mb=MochiKit.Base;
+var mc=MochiKit.Color;
+var _15=["red","orange","yellow","green","cyan","blue","purple","magenta"];
+var _16=function(_17){
+return mc.Color[_17+"Color"]();
+};
+return mb.map(_16,_15);
+},baseDarkPrimaryColors:function(){
+var _18=MochiKit.Color.Color.fromHexString;
+return [_18("#ad3f40"),_18("#ddac2c"),_18("#dfdd0c"),_18("#5276c4"),_18("#739c5a")];
+},basePrimaryColors:function(){
+var _19=MochiKit.Color.Color.fromHexString;
+return [_19("#d24c4d"),_19("#f2b32f"),_19("#ece90e"),_19("#5d83da"),_19("#78a15d")];
+},baseBlueColors:function(){
+var _20=MochiKit.Color.Color.fromHexString;
+return [_20("#4b6b94"),_20("#5d81b4"),_20("#acbad2")];
+},palette:function(_21,_22,_23,_24){
+var _25=MochiKit.Base.isUndefinedOrNull;
+var _26=new Array();
+if(_25(_24)){
+_24=0.1;
+}
+if(_25(_23)){
+_23=0.4;
+}
+if(_25(_22)){
+_22=-0.2;
+}
+var _27=_22;
+while(_27<=_23){
+_26.push(_27);
+_27+=_24;
+}
+var _28=function(_29,_30){
+return _29.lighterColorWithLevel(_30);
+};
+return MochiKit.Base.map(MochiKit.Base.partial(_28,_21),_26);
+},excanvasSupported:function(){
+if(/MSIE/.test(navigator.userAgent)&&!window.opera){
+return true;
+}
+return false;
+},findPosX:function(obj){
+var _32=0;
+if(obj.offsetParent){
+while(obj.offsetParent){
+_32+=obj.offsetLeft;
+obj=obj.offsetParent;
+}
+}else{
+if(obj.x){
+_32+=obj.x;
+}
+}
+return _32;
+},findPosY:function(obj){
+var _33=0;
+if(obj.offsetParent){
+while(obj.offsetParent){
+_33+=obj.offsetTop;
+obj=obj.offsetParent;
+}
+}else{
+if(obj.y){
+_33+=obj.y;
+}
+}
+return _33;
+},isFuncLike:function(obj){
+return (typeof (obj)=="function");
+}});
+PlotKit.Base.map=function(fn,lst){
+if(PlotKit.Base.usingPrototype()){
+var _36=[];
+for(var x in lst){
+if(typeof (lst[x])=="function"){
+continue;
+}
+_36.push(fn(lst[x]));
+}
+return _36;
+}else{
+return MochiKit.Base.map(fn,lst);
+}
+};
+PlotKit.Base.items=function(lst){
+if(PlotKit.Base.usingPrototype()){
+var _38=[];
+for(var x in lst){
+if(typeof (lst[x])=="function"){
+continue;
+}
+_38.push([x,lst[x]]);
+}
+return _38;
+}else{
+return MochiKit.Base.items(lst);
+}
+};
+PlotKit.Base.keys=function(lst){
+if(PlotKit.Base.usingPrototype()){
+var _39=[];
+for(var x in lst){
+if(typeof (lst[x])=="function"){
+continue;
+}
+_39.push(x);
+}
+return _39;
+}else{
+return MochiKit.Base.keys(lst);
+}
+};
+PlotKit.Base.baseColors=function(){
+var _40=MochiKit.Color.Color.fromHexString;
+return [_40("#476fb2"),_40("#be2c2b"),_40("#85b730"),_40("#734a99"),_40("#26a1c5"),_40("#fb8707"),_40("#000000")];
+};
+PlotKit.Base.officeBaseStyle={"axisLineWidth":2,"axisLabelColor":MochiKit.Color.Color.grayColor(),"axisLineColor":MochiKit.Color.Color.whiteColor(),"padding":{top:5,bottom:10,left:30,right:30}};
+MochiKit.Base.update(PlotKit.Base,{officeBlue:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[0]),"backgroundColor":PlotKit.Base.baseColors()[0].lighterColorWithLevel(0.45)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officeRed:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[1]),"backgroundColor":PlotKit.Base.baseColors()[1].lighterColorWithLevel(0.5)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officeGreen:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[2]),"backgroundColor":PlotKit.Base.baseColors()[2].lighterColorWithLevel(0.5)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officePurple:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[3]),"backgroundColor":PlotKit.Base.baseColors()[3].lighterColorWithLevel(0.5)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officeCyan:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[4]),"backgroundColor":PlotKit.Base.baseColors()[4].lighterColorWithLevel(0.5)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officeOrange:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[5]),"backgroundColor":PlotKit.Base.baseColors()[5].lighterColorWithLevel(0.4)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+},officeBlack:function(){
+var r={"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[6],0,0.6),"backgroundColor":PlotKit.Base.baseColors()[6].lighterColorWithLevel(0.9)};
+MochiKit.Base.update(r,PlotKit.Base.officeBaseStyle);
+return r;
+}});
+PlotKit.Base.EXPORT=["baseColors","collapse","colorScheme","findPosX","findPosY","officeBaseStyle","officeBlue","officeRed","officeGreen","officePurple","officeCyan","officeOrange","officeBlack","roundInterval","uniq","isFuncLike","excanvasSupported"];
+PlotKit.Base.EXPORT_OK=[];
+PlotKit.Base.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+PlotKit.Base.__new__();
+MochiKit.Base._exportSymbols(this,PlotKit.Base);
+try{
+if(typeof (PlotKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Base";
+}
+if(typeof (PlotKit.Layout)=="undefined"){
+PlotKit.Layout={};
+}
+PlotKit.Layout.NAME="PlotKit.Layout";
+PlotKit.Layout.VERSION=PlotKit.VERSION;
+PlotKit.Layout.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.Layout.toString=function(){
+return this.__repr__();
+};
+PlotKit.Layout.valid_styles=["bar","line","pie","point"];
+PlotKit.Layout=function(_42,_43){
+this.options={"barWidthFillFraction":0.75,"barOrientation":"vertical","xOriginIsZero":true,"yOriginIsZero":true,"xAxis":null,"yAxis":null,"xTicks":null,"yTicks":null,"xNumberOfTicks":10,"yNumberOfTicks":5,"xTickPrecision":1,"yTickPrecision":1,"pieRadius":0.4};
+this.style=_42;
+MochiKit.Base.update(this.options,_43?_43:{});
+if(!MochiKit.Base.isUndefinedOrNull(this.options.xAxis)){
+this.minxval=this.options.xAxis[0];
+this.maxxval=this.options.xAxis[1];
+this.xscale=this.maxxval-this.minxval;
+}else{
+this.minxval=0;
+this.maxxval=null;
+this.xscale=null;
+}
+if(!MochiKit.Base.isUndefinedOrNull(this.options.yAxis)){
+this.minyval=this.options.yAxis[0];
+this.maxyval=this.options.yAxis[1];
+this.yscale=this.maxyval-this.minyval;
+}else{
+this.minyval=0;
+this.maxyval=null;
+this.yscale=null;
+}
+this.bars=new Array();
+this.points=new Array();
+this.slices=new Array();
+this.xticks=new Array();
+this.yticks=new Array();
+this.datasets=new Array();
+this.minxdelta=0;
+this.xrange=1;
+this.yrange=1;
+this.hitTestCache={x2maxy:null};
+};
+PlotKit.Layout.prototype.addDataset=function(_44,_45){
+this.datasets[_44]=_45;
+};
+PlotKit.Layout.prototype.removeDataset=function(_46,_47){
+delete this.datasets[_46];
+};
+PlotKit.Layout.prototype.addDatasetFromTable=function(_48,_49,_50,_51){
+var _52=MochiKit.Base.isUndefinedOrNull;
+var _53=MochiKit.DOM.scrapeText;
+var _54=MochiKit.Format.strip;
+if(_52(_50)){
+_50=0;
+}
+if(_52(_51)){
+_51=1;
+}
+var _55=_49.tBodies[0].rows;
+var _56=new Array();
+if(!_52(_55)){
+for(var i=0;i<_55.length;i++){
+_56.push([parseFloat(_54(_53(_55[i].cells[_50]))),parseFloat(_54(_53(_55[i].cells[_51])))]);
+}
+this.addDataset(_48,_56);
+return true;
+}
+return false;
+};
+PlotKit.Layout.prototype.evaluate=function(){
+this._evaluateLimits();
+this._evaluateScales();
+if(this.style=="bar"){
+if(this.options.barOrientation=="horizontal"){
+this._evaluateHorizBarCharts();
+}else{
+this._evaluateBarCharts();
+}
+this._evaluateBarTicks();
+}else{
+if(this.style=="line"){
+this._evaluateLineCharts();
+this._evaluateLineTicks();
+}else{
+if(this.style=="pie"){
+this._evaluatePieCharts();
+this._evaluatePieTicks();
+}
+}
+}
+};
+PlotKit.Layout.prototype.hitTest=function(x,y){
+var f=MochiKit.Format.twoDigitFloat;
+if((this.style=="bar")&&this.bars&&(this.bars.length>0)){
+for(var i=0;i<this.bars.length;i++){
+var bar=this.bars[i];
+if((x>=bar.x)&&(x<=bar.x+bar.w)&&(y>=bar.y)&&(y-bar.y<=bar.h)){
+return bar;
+}
+}
+}else{
+if(this.style=="line"){
+if(this.hitTestCache.x2maxy==null){
+this._regenerateHitTestCache();
+}
+var _60=x/this.xscale;
+var _61=this.hitTestCache.xvalues;
+var _62=null;
+var _63=null;
+for(var i=1;i<_61.length;i++){
+if(_61[i]>_60){
+_62=_61[i-1];
+_63=_61[i];
+break;
+}
+}
+if((_62!=null)){
+var _64=this.hitTestCache.x2maxy[_62];
+var _65=this.hitTestCache.x2maxy[_63];
+var _66=(1-y)/this.yscale;
+var _67=(_65-_64)/(_63-_62);
+var _68=_64+_67*(_60-_62);
+if(_68>=_66){
+var obj={xval:_60,yval:_66,xafter:_63,yafter:_65,xbefore:_62,ybefore:_64,yprojected:_68};
+return obj;
+}
+}
+}else{
+if(this.style=="pie"){
+var _69=Math.sqrt((y-0.5)*(y-0.5)+(x-0.5)*(x-0.5));
+if(_69>this.options.pieRadius){
+return null;
+}
+var _70=Math.atan2(y-0.5,x-0.5)-Math.PI/2;
+for(var i=0;i<this.slices.length;i++){
+var _71=this.slices[i];
+if(_71.startAngle<_70&&_71.endAngle>=_70){
+return _71;
+}
+}
+}
+}
+}
+return null;
+};
+PlotKit.Layout.prototype.rectForX=function(x){
+return null;
+};
+PlotKit.Layout.prototype.angleRangeForX=function(x){
+return null;
+};
+PlotKit.Layout.prototype._evaluateLimits=function(){
+var map=PlotKit.Base.map;
+var _73=PlotKit.Base.items;
+var _74=MochiKit.Base.itemgetter;
+var _75=PlotKit.Base.collapse;
+var _76=MochiKit.Base.listMin;
+var _77=MochiKit.Base.listMax;
+var _78=MochiKit.Base.isUndefinedOrNull;
+var all=_75(map(_74(1),_73(this.datasets)));
+if(_78(this.options.xAxis)){
+if(this.options.xOriginIsZero){
+this.minxval=0;
+}else{
+this.minxval=_76(map(parseFloat,map(_74(0),all)));
+}
+this.maxxval=_77(map(parseFloat,map(_74(0),all)));
+}else{
+this.minxval=this.options.xAxis[0];
+this.maxxval=this.options.xAxis[1];
+this.xscale=this.maxval-this.minxval;
+}
+if(_78(this.options.yAxis)){
+if(this.options.yOriginIsZero){
+this.minyval=0;
+}else{
+this.minyval=_76(map(parseFloat,map(_74(1),all)));
+}
+this.maxyval=_77(map(parseFloat,map(_74(1),all)));
+}else{
+this.minyval=this.options.yAxis[0];
+this.maxyval=this.options.yAxis[1];
+this.yscale=this.maxyval-this.minyval;
+}
+};
+PlotKit.Layout.prototype._evaluateScales=function(){
+var _80=MochiKit.Base.isUndefinedOrNull;
+this.xrange=this.maxxval-this.minxval;
+if(this.xrange==0){
+this.xscale=1;
+}else{
+this.xscale=1/this.xrange;
+}
+this.yrange=this.maxyval-this.minyval;
+if(this.yrange==0){
+this.yscale=1;
+}else{
+this.yscale=1/this.yrange;
+}
+};
+PlotKit.Layout.prototype._uniqueXValues=function(){
+var _81=PlotKit.Base.collapse;
+var map=PlotKit.Base.map;
+var _82=PlotKit.Base.uniq;
+var _83=MochiKit.Base.itemgetter;
+var _84=PlotKit.Base.items;
+var _85=map(parseFloat,map(_83(0),_81(map(_83(1),_84(this.datasets)))));
+_85.sort(MochiKit.Base.compare);
+return _82(_85);
+};
+PlotKit.Layout.prototype._evaluateBarCharts=function(){
+var _86=PlotKit.Base.items;
+var _87=_86(this.datasets).length;
+var _88=10000000;
+var _89=this._uniqueXValues();
+for(var i=1;i<_89.length;i++){
+_88=Math.min(Math.abs(_89[i]-_89[i-1]),_88);
+}
+var _90=0;
+var _91=0;
+var _92=0;
+if(_89.length==1){
+_88=1;
+this.xscale=1;
+this.minxval=_89[0];
+_90=1*this.options.barWidthFillFraction;
+_91=_90/_87;
+_92=(1-this.options.barWidthFillFraction)/2;
+}else{
+this.xscale=(1-_88/this.xrange)/this.xrange;
+_90=_88*this.xscale*this.options.barWidthFillFraction;
+_91=_90/_87;
+_92=_88*this.xscale*(1-this.options.barWidthFillFraction)/2;
+}
+this.minxdelta=_88;
+this.bars=new Array();
+var i=0;
+for(var _93 in this.datasets){
+var _94=this.datasets[_93];
+if(PlotKit.Base.isFuncLike(_94)){
+continue;
+}
+for(var j=0;j<_94.length;j++){
+var _96=_94[j];
+var _97={x:((parseFloat(_96[0])-this.minxval)*this.xscale)+(i*_91)+_92,y:1-((parseFloat(_96[1])-this.minyval)*this.yscale),w:_91,h:((parseFloat(_96[1])-this.minyval)*this.yscale),xval:parseFloat(_96[0]),yval:parseFloat(_96[1]),name:_93};
+if((_97.x>=0)&&(_97.x<=1)&&(_97.y>=0)&&(_97.y<=1)){
+this.bars.push(_97);
+}
+}
+i++;
+}
+};
+PlotKit.Layout.prototype._evaluateHorizBarCharts=function(){
+var _98=PlotKit.Base.items;
+var _99=_98(this.datasets).length;
+var _100=10000000;
+var _101=this._uniqueXValues();
+for(var i=1;i<_101.length;i++){
+_100=Math.min(Math.abs(_101[i]-_101[i-1]),_100);
+}
+var _102=0;
+var _103=0;
+var _104=0;
+if(_101.length==1){
+_100=1;
+this.xscale=1;
+this.minxval=_101[0];
+_102=1*this.options.barWidthFillFraction;
+_103=_102/_99;
+_104=(1-this.options.barWidthFillFraction)/2;
+}else{
+this.xscale=(1-_100/this.xrange)/this.xrange;
+_102=_100*this.xscale*this.options.barWidthFillFraction;
+_103=_102/_99;
+_104=_100*this.xscale*(1-this.options.barWidthFillFraction)/2;
+}
+this.minxdelta=_100;
+this.bars=new Array();
+var i=0;
+for(var _105 in this.datasets){
+var _106=this.datasets[_105];
+if(PlotKit.Base.isFuncLike(_106)){
+continue;
+}
+for(var j=0;j<_106.length;j++){
+var item=_106[j];
+var rect={y:((parseFloat(item[0])-this.minxval)*this.xscale)+(i*_103)+_104,x:0,h:_103,w:((parseFloat(item[1])-this.minyval)*this.yscale),xval:parseFloat(item[0]),yval:parseFloat(item[1]),name:_105};
+if(rect.y<=0){
+rect.y=0;
+}
+if(rect.y>=1){
+rect.y=1;
+}
+if((rect.x>=0)&&(rect.x<=1)){
+this.bars.push(rect);
+}
+}
+i++;
+}
+};
+PlotKit.Layout.prototype._evaluateLineCharts=function(){
+var _109=PlotKit.Base.items;
+var _110=_109(this.datasets).length;
+this.points=new Array();
+var i=0;
+for(var _111 in this.datasets){
+var _112=this.datasets[_111];
+if(PlotKit.Base.isFuncLike(_112)){
+continue;
+}
+_112.sort(function(a,b){
+return compare(parseFloat(a[0]),parseFloat(b[0]));
+});
+for(var j=0;j<_112.length;j++){
+var item=_112[j];
+var _115={x:((parseFloat(item[0])-this.minxval)*this.xscale),y:1-((parseFloat(item[1])-this.minyval)*this.yscale),xval:parseFloat(item[0]),yval:parseFloat(item[1]),name:_111};
+if(_115.y<=0){
+_115.y=0;
+}
+if(_115.y>=1){
+_115.y=1;
+}
+if((_115.x>=0)&&(_115.x<=1)){
+this.points.push(_115);
+}
+}
+i++;
+}
+};
+PlotKit.Layout.prototype._evaluatePieCharts=function(){
+var _116=PlotKit.Base.items;
+var sum=MochiKit.Iter.sum;
+var _118=MochiKit.Base.itemgetter;
+var _119=_116(this.datasets).length;
+var _120=_116(this.datasets)[0][1];
+var _121=sum(map(_118(1),_120));
+this.slices=new Array();
+var _122=0;
+for(var i=0;i<_120.length;i++){
+var _123=_120[i][1]/_121;
+var _124=_122*Math.PI*2;
+var _125=(_122+_123)*Math.PI*2;
+var _126={fraction:_123,xval:_120[i][0],yval:_120[i][1],startAngle:_124,endAngle:_125};
+this.slices.push(_126);
+_122+=_123;
+}
+};
+PlotKit.Layout.prototype._evaluateLineTicksForXAxis=function(){
+var _127=MochiKit.Base.isUndefinedOrNull;
+if(this.options.xTicks){
+this.xticks=new Array();
+var _128=function(tick){
+var _130=tick.label;
+if(_127(_130)){
+_130=tick.v.toString();
+}
+var pos=this.xscale*(tick.v-this.minxval);
+if((pos>=0)&&(pos<=1)){
+this.xticks.push([pos,_130]);
+}
+};
+MochiKit.Iter.forEach(this.options.xTicks,MochiKit.Base.bind(_128,this));
+}else{
+if(this.options.xNumberOfTicks){
+var _132=this._uniqueXValues();
+var _133=this.xrange/this.options.xNumberOfTicks;
+var _134=0;
+this.xticks=new Array();
+for(var i=0;i<=_132.length;i++){
+if((_132[i]-this.minxval)>=(_134*_133)){
+var pos=this.xscale*(_132[i]-this.minxval);
+if((pos>1)||(pos<0)){
+continue;
+}
+this.xticks.push([pos,_132[i]]);
+_134++;
+}
+if(_134>this.options.xNumberOfTicks){
+break;
+}
+}
+}
+}
+};
+PlotKit.Layout.prototype._evaluateLineTicksForYAxis=function(){
+var _135=MochiKit.Base.isUndefinedOrNull;
+if(this.options.yTicks){
+this.yticks=new Array();
+var _136=function(tick){
+var _137=tick.label;
+if(_135(_137)){
+_137=tick.v.toString();
+}
+var pos=1-(this.yscale*(tick.v-this.minyval));
+if((pos>=0)&&(pos<=1)){
+this.yticks.push([pos,_137]);
+}
+};
+MochiKit.Iter.forEach(this.options.yTicks,MochiKit.Base.bind(_136,this));
+}else{
+if(this.options.yNumberOfTicks){
+this.yticks=new Array();
+var _138=PlotKit.Base.roundInterval;
+var prec=this.options.yTickPrecision;
+var _140=_138(this.yrange,this.options.yNumberOfTicks,prec);
+for(var i=0;i<=this.options.yNumberOfTicks;i++){
+var yval=this.minyval+(i*_140);
+var pos=1-((yval-this.minyval)*this.yscale);
+if((pos>1)||(pos<0)){
+continue;
+}
+this.yticks.push([pos,MochiKit.Format.roundToFixed(yval,prec)]);
+}
+}
+}
+};
+PlotKit.Layout.prototype._evaluateLineTicks=function(){
+this._evaluateLineTicksForXAxis();
+this._evaluateLineTicksForYAxis();
+};
+PlotKit.Layout.prototype._evaluateBarTicks=function(){
+this._evaluateLineTicks();
+var _142=function(tick){
+return [tick[0]+(this.minxdelta*this.xscale)/2,tick[1]];
+};
+this.xticks=MochiKit.Base.map(MochiKit.Base.bind(_142,this),this.xticks);
+if(this.options.barOrientation=="horizontal"){
+var _143=this.xticks;
+this.xticks=this.yticks;
+this.yticks=_143;
+var _144=function(tick){
+return [1-tick[0],tick[1]];
+};
+this.xticks=MochiKit.Base.map(_144,this.xticks);
+}
+};
+PlotKit.Layout.prototype._evaluatePieTicks=function(){
+var _145=MochiKit.Base.isUndefinedOrNull;
+var _146=MochiKit.Format.numberFormatter("#%");
+this.xticks=new Array();
+if(this.options.xTicks){
+var _147=new Array();
+for(var i=0;i<this.slices.length;i++){
+_147[this.slices[i].xval]=this.slices[i];
+}
+for(var i=0;i<this.options.xTicks.length;i++){
+var tick=this.options.xTicks[i];
+var _148=_147[tick.v];
+var _149=tick.label;
+if(_148){
+if(_145(_149)){
+_149=tick.v.toString();
+}
+_149+=" ("+_146(_148.fraction)+")";
+this.xticks.push([tick.v,_149]);
+}
+}
+}else{
+for(var i=0;i<this.slices.length;i++){
+var _148=this.slices[i];
+var _149=_148.xval+" ("+_146(_148.fraction)+")";
+this.xticks.push([_148.xval,_149]);
+}
+}
+};
+PlotKit.Layout.prototype._regenerateHitTestCache=function(){
+this.hitTestCache.xvalues=this._uniqueXValues();
+this.hitTestCache.xlookup=new Array();
+this.hitTestCache.x2maxy=new Array();
+var _150=MochiKit.Base.listMax;
+var _151=MochiKit.Base.itemgetter;
+var map=MochiKit.Base.map;
+var _152=keys(this.datasets);
+for(var i=0;i<_152.length;i++){
+var _153=this.datasets[_152[i]];
+for(var j=0;j<_153.length;j++){
+var xval=_153[j][0];
+var yval=_153[j][1];
+if(this.hitTestCache.xlookup[xval]){
+this.hitTestCache.xlookup[xval].push([yval,_152[i]]);
+}else{
+this.hitTestCache.xlookup[xval]=[[yval,_152[i]]];
+}
+}
+}
+for(var x in this.hitTestCache.xlookup){
+var _155=this.hitTestCache.xlookup[x];
+this.hitTestCache.x2maxy[x]=_150(map(_151(0),_155));
+}
+};
+PlotKit.LayoutModule={};
+PlotKit.LayoutModule.Layout=PlotKit.Layout;
+PlotKit.LayoutModule.EXPORT=["Layout"];
+PlotKit.LayoutModule.EXPORT_OK=[];
+PlotKit.LayoutModule.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+PlotKit.LayoutModule.__new__();
+MochiKit.Base._exportSymbols(this,PlotKit.LayoutModule);
+try{
+if((typeof (PlotKit.Base)=="undefined")||(typeof (PlotKit.Layout)=="undefined")){
+throw "";
+}
+}
+catch(e){
+throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Base,Layout}";
+}
+if(typeof (PlotKit.CanvasRenderer)=="undefined"){
+PlotKit.CanvasRenderer={};
+}
+PlotKit.CanvasRenderer.NAME="PlotKit.CanvasRenderer";
+PlotKit.CanvasRenderer.VERSION=PlotKit.VERSION;
+PlotKit.CanvasRenderer.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.CanvasRenderer.toString=function(){
+return this.__repr__();
+};
+PlotKit.CanvasRenderer=function(_156,_157,_158){
+if(arguments.length>0){
+this.__init__(_156,_157,_158);
+}
+};
+PlotKit.CanvasRenderer.prototype.__init__=function(_159,_160,_161){
+var _162=MochiKit.Base.isUndefinedOrNull;
+var _163=MochiKit.Color.Color;
+this.options={"drawBackground":true,"backgroundColor":_163.whiteColor(),"padding":{left:30,right:30,top:5,bottom:10},"colorScheme":PlotKit.Base.palette(PlotKit.Base.baseColors()[0]),"strokeColor":_163.whiteColor(),"strokeColorTransform":"asStrokeColor","strokeWidth":0.5,"shouldFill":true,"shouldStroke":true,"drawXAxis":true,"drawYAxis":true,"axisLineColor":_163.blackColor(),"axisLineWidth":0.5,"axisTickSize":3,"axisLabelColor":_163.blackColor(),"axisLabelFont":"Arial","axisLabelFontSize":9,"axisLabelWidth":50,"pieRadius":0.4,"enableEvents":true};
+MochiKit.Base.update(this.options,_161?_161:{});
+this.layout=_160;
+this.element=MochiKit.DOM.getElement(_159);
+this.container=this.element.parentNode;
+this.isIE=PlotKit.Base.excanvasSupported();
+if(this.isIE&&!_162(G_vmlCanvasManager)){
+this.IEDelay=0.5;
+this.maxTries=5;
+this.renderDelay=null;
+this.clearDelay=null;
+this.element=G_vmlCanvasManager.initElement(this.element);
+}
+this.height=this.element.height;
+this.width=this.element.width;
+if(_162(this.element)){
+throw "CanvasRenderer() - passed canvas is not found";
+}
+if(!this.isIE&&!(PlotKit.CanvasRenderer.isSupported(this.element))){
+throw "CanvasRenderer() - Canvas is not supported.";
+}
+if(_162(this.container)||(this.container.nodeName.toLowerCase()!="div")){
+throw "CanvasRenderer() - <canvas> needs to be enclosed in <div>";
+}
+this.xlabels=new Array();
+this.ylabels=new Array();
+this.isFirstRender=true;
+this.area={x:this.options.padding.left,y:this.options.padding.top,w:this.width-this.options.padding.left-this.options.padding.right,h:this.height-this.options.padding.top-this.options.padding.bottom};
+MochiKit.DOM.updateNodeAttributes(this.container,{"style":{"position":"relative","width":this.width+"px"}});
+};
+PlotKit.CanvasRenderer.prototype.render=function(){
+if(this.isIE){
+try{
+if(this.renderDelay){
+this.renderDelay.cancel();
+this.renderDelay=null;
+}
+var _164=this.element.getContext("2d");
+}
+catch(e){
+this.isFirstRender=false;
+if(this.maxTries-->0){
+this.renderDelay=MochiKit.Async.wait(this.IEDelay);
+this.renderDelay.addCallback(MochiKit.Base.bind(this.render,this));
+}
+return;
+}
+}
+if(this.options.drawBackground){
+this._renderBackground();
+}
+if(this.layout.style=="bar"){
+this._renderBarChart();
+this._renderBarAxis();
+}else{
+if(this.layout.style=="pie"){
+this._renderPieChart();
+this._renderPieAxis();
+}else{
+if(this.layout.style=="line"){
+this._renderLineChart();
+this._renderLineAxis();
+}
+}
+}
+};
+PlotKit.CanvasRenderer.prototype._renderBarChartWrap=function(data,_166){
+var _167=this.element.getContext("2d");
+var _168=this.options.colorScheme.length;
+var _169=this.options.colorScheme;
+var _170=MochiKit.Base.keys(this.layout.datasets);
+var _171=_170.length;
+for(var i=0;i<_171;i++){
+var _172=_170[i];
+var _173=_169[i%_168];
+_167.save();
+_167.fillStyle=_173.toRGBString();
+if(this.options.strokeColor){
+_167.strokeStyle=this.options.strokeColor.toRGBString();
+}else{
+if(this.options.strokeColorTransform){
+_167.strokeStyle=_173[this.options.strokeColorTransform]().toRGBString();
+}
+}
+_167.lineWidth=this.options.strokeWidth;
+var _174=function(obj){
+if(obj.name==_172){
+_166(_167,obj);
+}
+};
+MochiKit.Iter.forEach(data,MochiKit.Base.bind(_174,this));
+_167.restore();
+}
+};
+PlotKit.CanvasRenderer.prototype._renderBarChart=function(){
+var bind=MochiKit.Base.bind;
+var _176=function(_177,bar){
+var x=this.area.w*bar.x+this.area.x;
+var y=this.area.h*bar.y+this.area.y;
+var w=this.area.w*bar.w;
+var h=this.area.h*bar.h;
+if((w<1)||(h<1)){
+return;
+}
+if(this.options.shouldFill){
+_177.fillRect(x,y,w,h);
+}
+if(this.options.shouldStroke){
+_177.strokeRect(x,y,w,h);
+}
+};
+this._renderBarChartWrap(this.layout.bars,bind(_176,this));
+};
+PlotKit.CanvasRenderer.prototype._renderLineChart=function(){
+var _180=this.element.getContext("2d");
+var _181=this.options.colorScheme.length;
+var _182=this.options.colorScheme;
+var _183=MochiKit.Base.keys(this.layout.datasets);
+var _184=_183.length;
+var bind=MochiKit.Base.bind;
+var _185=MochiKit.Base.partial;
+for(var i=0;i<_184;i++){
+var _186=_183[i];
+var _187=_182[i%_181];
+var _188=this.options.strokeColorTransform;
+_180.save();
+_180.fillStyle=_187.toRGBString();
+if(this.options.strokeColor){
+_180.strokeStyle=this.options.strokeColor.toRGBString();
+}else{
+if(this.options.strokeColorTransform){
+_180.strokeStyle=_187[_188]().toRGBString();
+}
+}
+_180.lineWidth=this.options.strokeWidth;
+var _189=function(ctx){
+ctx.beginPath();
+ctx.moveTo(this.area.x,this.area.y+this.area.h);
+var _191=function(ctx_,_193){
+if(_193.name==_186){
+ctx_.lineTo(this.area.w*_193.x+this.area.x,this.area.h*_193.y+this.area.y);
+}
+};
+MochiKit.Iter.forEach(this.layout.points,_185(_191,ctx),this);
+ctx.lineTo(this.area.w+this.area.x,this.area.h+this.area.y);
+ctx.lineTo(this.area.x,this.area.y+this.area.h);
+ctx.closePath();
+};
+if(this.options.shouldFill){
+bind(_189,this)(_180);
+_180.fill();
+}
+if(this.options.shouldStroke){
+bind(_189,this)(_180);
+_180.stroke();
+}
+_180.restore();
+}
+};
+PlotKit.CanvasRenderer.prototype._renderPieChart=function(){
+var _194=this.element.getContext("2d");
+var _195=this.options.colorScheme.length;
+var _196=this.layout.slices;
+var _197=this.area.x+this.area.w*0.5;
+var _198=this.area.y+this.area.h*0.5;
+var _199=Math.min(this.area.w*this.options.pieRadius,this.area.h*this.options.pieRadius);
+if(this.isIE){
+_197=parseInt(_197);
+_198=parseInt(_198);
+_199=parseInt(_199);
+}
+for(var i=0;i<_196.length;i++){
+var _200=this.options.colorScheme[i%_195];
+_194.save();
+_194.fillStyle=_200.toRGBString();
+var _201=function(){
+_194.beginPath();
+_194.moveTo(_197,_198);
+_194.arc(_197,_198,_199,_196[i].startAngle-Math.PI/2,_196[i].endAngle-Math.PI/2,false);
+_194.lineTo(_197,_198);
+_194.closePath();
+};
+if(Math.abs(_196[i].startAngle-_196[i].endAngle)>0.001){
+if(this.options.shouldFill){
+_201();
+_194.fill();
+}
+if(this.options.shouldStroke){
+_201();
+_194.lineWidth=this.options.strokeWidth;
+if(this.options.strokeColor){
+_194.strokeStyle=this.options.strokeColor.toRGBString();
+}else{
+if(this.options.strokeColorTransform){
+_194.strokeStyle=_200[this.options.strokeColorTransform]().toRGBString();
+}
+}
+_194.stroke();
+}
+}
+_194.restore();
+}
+};
+PlotKit.CanvasRenderer.prototype._renderBarAxis=function(){
+this._renderAxis();
+};
+PlotKit.CanvasRenderer.prototype._renderLineAxis=function(){
+this._renderAxis();
+};
+PlotKit.CanvasRenderer.prototype._renderAxis=function(){
+if(!this.options.drawXAxis&&!this.options.drawYAxis){
+return;
+}
+var _202=this.element.getContext("2d");
+var _203={"style":{"position":"absolute","fontSize":this.options.axisLabelFontSize+"px","zIndex":10,"color":this.options.axisLabelColor.toRGBString(),"width":this.options.axisLabelWidth+"px","overflow":"hidden"}};
+_202.save();
+_202.strokeStyle=this.options.axisLineColor.toRGBString();
+_202.lineWidth=this.options.axisLineWidth;
+if(this.options.drawYAxis){
+if(this.layout.yticks){
+var _204=function(tick){
+if(typeof (tick)=="function"){
+return;
+}
+var x=this.area.x;
+var y=this.area.y+tick[0]*this.area.h;
+_202.beginPath();
+_202.moveTo(x,y);
+_202.lineTo(x-this.options.axisTickSize,y);
+_202.closePath();
+_202.stroke();
+var _205=MochiKit.DOM.DIV(_203,tick[1]);
+_205.style.top=(y-this.options.axisLabelFontSize)+"px";
+_205.style.left=(x-this.options.padding.left-this.options.axisTickSize)+"px";
+_205.style.textAlign="right";
+_205.style.width=(this.options.padding.left-this.options.axisTickSize*2)+"px";
+MochiKit.DOM.appendChildNodes(this.container,_205);
+this.ylabels.push(_205);
+};
+MochiKit.Iter.forEach(this.layout.yticks,MochiKit.Base.bind(_204,this));
+}
+_202.beginPath();
+_202.moveTo(this.area.x,this.area.y);
+_202.lineTo(this.area.x,this.area.y+this.area.h);
+_202.closePath();
+_202.stroke();
+}
+if(this.options.drawXAxis){
+if(this.layout.xticks){
+var _204=function(tick){
+if(typeof (dataset)=="function"){
+return;
+}
+var x=this.area.x+tick[0]*this.area.w;
+var y=this.area.y+this.area.h;
+_202.beginPath();
+_202.moveTo(x,y);
+_202.lineTo(x,y+this.options.axisTickSize);
+_202.closePath();
+_202.stroke();
+var _206=MochiKit.DOM.DIV(_203,tick[1]);
+_206.style.top=(y+this.options.axisTickSize)+"px";
+_206.style.left=(x-this.options.axisLabelWidth/2)+"px";
+_206.style.textAlign="center";
+_206.style.width=this.options.axisLabelWidth+"px";
+MochiKit.DOM.appendChildNodes(this.container,_206);
+this.xlabels.push(_206);
+};
+MochiKit.Iter.forEach(this.layout.xticks,MochiKit.Base.bind(_204,this));
+}
+_202.beginPath();
+_202.moveTo(this.area.x,this.area.y+this.area.h);
+_202.lineTo(this.area.x+this.area.w,this.area.y+this.area.h);
+_202.closePath();
+_202.stroke();
+}
+_202.restore();
+};
+PlotKit.CanvasRenderer.prototype._renderPieAxis=function(){
+if(!this.options.drawXAxis){
+return;
+}
+if(this.layout.xticks){
+var _207=new Array();
+for(var i=0;i<this.layout.slices.length;i++){
+_207[this.layout.slices[i].xval]=this.layout.slices[i];
+}
+var _208=this.area.x+this.area.w*0.5;
+var _209=this.area.y+this.area.h*0.5;
+var _210=Math.min(this.area.w*this.options.pieRadius,this.area.h*this.options.pieRadius);
+var _211=this.options.axisLabelWidth;
+for(var i=0;i<this.layout.xticks.length;i++){
+var _212=_207[this.layout.xticks[i][0]];
+if(MochiKit.Base.isUndefinedOrNull(_212)){
+continue;
+}
+var _213=(_212.startAngle+_212.endAngle)/2;
+var _214=_213;
+if(_214>Math.PI*2){
+_214=_214-Math.PI*2;
+}else{
+if(_214<0){
+_214=_214+Math.PI*2;
+}
+}
+var _215=_208+Math.sin(_214)*(_210+10);
+var _216=_209-Math.cos(_214)*(_210+10);
+var _217={"position":"absolute","zIndex":11,"width":_211+"px","fontSize":this.options.axisLabelFontSize+"px","overflow":"hidden","color":this.options.axisLabelColor.toHexString()};
+if(_214<=Math.PI*0.5){
+_217["textAlign"]="left";
+_217["verticalAlign"]="top";
+_217["left"]=_215+"px";
+_217["top"]=(_216-this.options.axisLabelFontSize)+"px";
+}else{
+if((_214>Math.PI*0.5)&&(_214<=Math.PI)){
+_217["textAlign"]="left";
+_217["verticalAlign"]="bottom";
+_217["left"]=_215+"px";
+_217["top"]=_216+"px";
+}else{
+if((_214>Math.PI)&&(_214<=Math.PI*1.5)){
+_217["textAlign"]="right";
+_217["verticalAlign"]="bottom";
+_217["left"]=(_215-_211)+"px";
+_217["top"]=_216+"px";
+}else{
+_217["textAlign"]="right";
+_217["verticalAlign"]="bottom";
+_217["left"]=(_215-_211)+"px";
+_217["top"]=(_216-this.options.axisLabelFontSize)+"px";
+}
+}
+}
+var _218=MochiKit.DOM.DIV({"style":_217},this.layout.xticks[i][1]);
+this.xlabels.push(_218);
+MochiKit.DOM.appendChildNodes(this.container,_218);
+}
+}
+};
+PlotKit.CanvasRenderer.prototype._renderBackground=function(){
+var _219=this.element.getContext("2d");
+_219.save();
+_219.fillStyle=this.options.backgroundColor.toRGBString();
+_219.fillRect(0,0,this.width,this.height);
+_219.restore();
+};
+PlotKit.CanvasRenderer.prototype.clear=function(){
+if(this.isIE){
+try{
+if(this.clearDelay){
+this.clearDelay.cancel();
+this.clearDelay=null;
+}
+var _220=this.element.getContext("2d");
+}
+catch(e){
+this.isFirstRender=false;
+this.clearDelay=MochiKit.Async.wait(this.IEDelay);
+this.clearDelay.addCallback(MochiKit.Base.bind(this.clear,this));
+return;
+}
+}
+var _220=this.element.getContext("2d");
+_220.clearRect(0,0,this.width,this.height);
+MochiKit.Iter.forEach(this.xlabels,MochiKit.DOM.removeElement);
+MochiKit.Iter.forEach(this.ylabels,MochiKit.DOM.removeElement);
+this.xlabels=new Array();
+this.ylabels=new Array();
+};
+PlotKit.CanvasRenderer.prototype._initialiseEvents=function(){
+var _221=MochiKit.Signal.connect;
+var bind=MochiKit.Base.bind;
+MochiKit.Signal.registerSignals(this,["onmouseover","onclick","onmouseout","onmousemove"]);
+_221(this.element,"onclick",bind(this.onclick,this));
+};
+PlotKit.CanvasRenderer.prototype._resolveObject=function(e){
+var x=(e.mouse().page.x-PlotKit.Base.findPosX(this.element)-this.area.x)/this.area.w;
+var y=(e.mouse().page.y-PlotKit.Base.findPosY(this.element)-this.area.y)/this.area.h;
+var _223=this.layout.hitTest(x,y);
+if(_223){
+return _223;
+}
+return null;
+};
+PlotKit.CanvasRenderer.prototype._createEventObject=function(_224,e){
+if(_224==null){
+return null;
+}
+e.chart=_224;
+return e;
+};
+PlotKit.CanvasRenderer.prototype.onclick=function(e){
+var _225=this._resolveObject(e);
+var _226=this._createEventObject(_225,e);
+if(_226!=null){
+MochiKit.Signal.signal(this,"onclick",_226);
+}
+};
+PlotKit.CanvasRenderer.prototype.onmouseover=function(e){
+var _227=this._resolveObject(e);
+var _228=this._createEventObject(_227,e);
+if(_228!=null){
+signal(this,"onmouseover",_228);
+}
+};
+PlotKit.CanvasRenderer.prototype.onmouseout=function(e){
+var _229=this._resolveObject(e);
+var _230=this._createEventObject(_229,e);
+if(_230==null){
+signal(this,"onmouseout",e);
+}else{
+signal(this,"onmouseout",_230);
+}
+};
+PlotKit.CanvasRenderer.prototype.onmousemove=function(e){
+var _231=this._resolveObject(e);
+var _232=this._createEventObject(_231,e);
+if((_231==null)&&(this.event_isinside==null)){
+return;
+}
+if((_231!=null)&&(this.event_isinside==null)){
+signal(this,"onmouseover",_232);
+}
+if((_231==null)&&(this.event_isinside!=null)){
+signal(this,"onmouseout",_232);
+}
+if((_231!=null)&&(this.event_isinside!=null)){
+signal(this,"onmousemove",_232);
+}
+this.event_isinside=_231;
+};
+PlotKit.CanvasRenderer.isSupported=function(_233){
+var _234=null;
+try{
+if(MochiKit.Base.isUndefinedOrNull(_233)){
+_234=MochiKit.DOM.CANVAS({});
+}else{
+_234=MochiKit.DOM.getElement(_233);
+}
+var _235=_234.getContext("2d");
+}
+catch(e){
+var ie=navigator.appVersion.match(/MSIE (\d\.\d)/);
+var _237=(navigator.userAgent.toLowerCase().indexOf("opera")!=-1);
+if((!ie)||(ie[1]<6)||(_237)){
+return false;
+}
+return true;
+}
+return true;
+};
+PlotKit.Canvas={};
+PlotKit.Canvas.CanvasRenderer=PlotKit.CanvasRenderer;
+PlotKit.Canvas.EXPORT=["CanvasRenderer"];
+PlotKit.Canvas.EXPORT_OK=["CanvasRenderer"];
+PlotKit.Canvas.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+PlotKit.Canvas.__new__();
+MochiKit.Base._exportSymbols(this,PlotKit.Canvas);
+try{
+if(typeof (PlotKit.CanvasRenderer)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "SweetCanvas depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Layout, Canvas}";
+}
+if(typeof (PlotKit.SweetCanvasRenderer)=="undefined"){
+PlotKit.SweetCanvasRenderer={};
+}
+PlotKit.SweetCanvasRenderer=function(_238,_239,_240){
+if(arguments.length>0){
+this.__init__(_238,_239,_240);
+}
+};
+PlotKit.SweetCanvasRenderer.NAME="PlotKit.SweetCanvasRenderer";
+PlotKit.SweetCanvasRenderer.VERSION=PlotKit.VERSION;
+PlotKit.SweetCanvasRenderer.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.SweetCanvasRenderer.toString=function(){
+return this.__repr__();
+};
+PlotKit.SweetCanvasRenderer.prototype=new PlotKit.CanvasRenderer();
+PlotKit.SweetCanvasRenderer.prototype.constructor=PlotKit.SweetCanvasRenderer;
+PlotKit.SweetCanvasRenderer.__super__=PlotKit.CanvasRenderer.prototype;
+PlotKit.SweetCanvasRenderer.prototype.__init__=function(el,_242,opts){
+var _244=PlotKit.Base.officeBlue();
+MochiKit.Base.update(_244,opts);
+PlotKit.SweetCanvasRenderer.__super__.__init__.call(this,el,_242,_244);
+};
+PlotKit.SweetCanvasRenderer.prototype._renderBarChart=function(){
+var bind=MochiKit.Base.bind;
+var _245=MochiKit.Color.Color.blackColor().colorWithAlpha(0.1).toRGBString();
+var _246=function(_247,x,y,w,h){
+_247.fillStyle=_245;
+_247.fillRect(x-2,y-2,w+4,h+2);
+_247.fillStyle=_245;
+_247.fillRect(x-1,y-1,w+2,h+1);
+};
+var _248=this.options.colorScheme.length;
+var _249=this.options.colorScheme;
+var _250=PlotKit.Base.keys(this.layout.datasets);
+var _251=_250.length;
+var _252=function(name){
+for(var i=0;i<_251;i++){
+if(name==_250[i]){
+return _249[i%_248];
+}
+}
+return _249[0];
+};
+var _254=function(_255,bar){
+var x=this.area.w*bar.x+this.area.x;
+var y=this.area.h*bar.y+this.area.y;
+var w=this.area.w*bar.w;
+var h=this.area.h*bar.h;
+if((w<1)||(h<1)){
+return;
+}
+_255.save();
+_255.shadowBlur=5;
+_255.shadowColor=MochiKit.Color.Color.fromHexString("#888888").toRGBString();
+if(this.isIE){
+_255.save();
+_255.fillStyle="#cccccc";
+_255.fillRect(x-2,y-2,w+4,h+2);
+_255.restore();
+}else{
+_246(_255,x,y,w,h);
+}
+if(this.options.shouldFill){
+_255.fillStyle=_252(bar.name).toRGBString();
+_255.fillRect(x,y,w,h);
+}
+_255.shadowBlur=0;
+_255.strokeStyle=MochiKit.Color.Color.whiteColor().toRGBString();
+_255.lineWidth=2;
+if(this.options.shouldStroke){
+_255.strokeRect(x,y,w,h);
+}
+_255.restore();
+};
+this._renderBarChartWrap(this.layout.bars,MochiKit.Base.bind(_254,this));
+};
+PlotKit.SweetCanvasRenderer.prototype._renderLineChart=function(){
+var _256=this.element.getContext("2d");
+var _257=this.options.colorScheme.length;
+var _258=this.options.colorScheme;
+var _259=PlotKit.Base.keys(this.layout.datasets);
+var _260=_259.length;
+var bind=MochiKit.Base.bind;
+for(var i=0;i<_260;i++){
+var _261=_259[i];
+var _262=_258[i%_257];
+var _263=this.options.strokeColorTransform;
+_256.save();
+var _264=function(ctx){
+ctx.beginPath();
+ctx.moveTo(this.area.x,this.area.y+this.area.h);
+var _265=function(ctx_,_266){
+if(_266.name==_261){
+ctx_.lineTo(this.area.w*_266.x+this.area.x,this.area.h*_266.y+this.area.y);
+}
+};
+MochiKit.Iter.forEach(this.layout.points,MochiKit.Base.partial(_265,ctx),this);
+ctx.lineTo(this.area.w+this.area.x,this.area.h+this.area.y);
+ctx.lineTo(this.area.x,this.area.y+this.area.h);
+ctx.closePath();
+};
+if(this.options.shouldFill){
+_256.save();
+if(this.isIE){
+_256.fillStyle="#cccccc";
+}else{
+_256.fillStyle=MochiKit.Color.Color.blackColor().colorWithAlpha(0.2).toRGBString();
+}
+_256.translate(-1,-2);
+bind(_264,this)(_256);
+if(this.options.shouldFill){
+_256.fill();
+}
+_256.restore();
+}
+_256.shadowBlur=5;
+_256.shadowColor=MochiKit.Color.Color.fromHexString("#888888").toRGBString();
+_256.fillStyle=_262.toRGBString();
+_256.lineWidth=2;
+_256.strokeStyle=MochiKit.Color.Color.whiteColor().toRGBString();
+if(this.options.shouldFill){
+bind(_264,this)(_256);
+_256.fill();
+}
+if(this.options.shouldStroke){
+bind(_264,this)(_256);
+_256.stroke();
+}
+_256.restore();
+}
+};
+PlotKit.SweetCanvasRenderer.prototype._renderPieChart=function(){
+var _267=this.element.getContext("2d");
+var _268=this.options.colorScheme.length;
+var _269=this.layout.slices;
+var _270=this.area.x+this.area.w*0.5;
+var _271=this.area.y+this.area.h*0.5;
+var _272=Math.min(this.area.w*this.options.pieRadius,this.area.h*this.options.pieRadius);
+if(this.isIE){
+_270=parseInt(_270);
+_271=parseInt(_271);
+_272=parseInt(_272);
+}
+if(!this.isIE){
+_267.save();
+var _273=MochiKit.Color.Color.blackColor().colorWithAlpha(0.2);
+_267.fillStyle=_273.toRGBString();
+_267.shadowBlur=5;
+_267.shadowColor=MochiKit.Color.Color.fromHexString("#888888").toRGBString();
+_267.translate(1,1);
+_267.beginPath();
+_267.moveTo(_270,_271);
+_267.arc(_270,_271,_272+2,0,Math.PI*2,false);
+_267.closePath();
+_267.fill();
+_267.restore();
+}
+_267.save();
+_267.strokeStyle=MochiKit.Color.Color.whiteColor().toRGBString();
+_267.lineWidth=2;
+for(var i=0;i<_269.length;i++){
+var _274=this.options.colorScheme[i%_268];
+_267.fillStyle=_274.toRGBString();
+var _275=function(){
+_267.beginPath();
+_267.moveTo(_270,_271);
+_267.arc(_270,_271,_272,_269[i].startAngle-Math.PI/2,_269[i].endAngle-Math.PI/2,false);
+_267.lineTo(_270,_271);
+_267.closePath();
+};
+if(Math.abs(_269[i].startAngle-_269[i].endAngle)>0.0001){
+if(this.options.shouldFill){
+_275();
+_267.fill();
+}
+if(this.options.shouldStroke){
+_275();
+_267.stroke();
+}
+}
+}
+_267.restore();
+};
+PlotKit.SweetCanvasRenderer.prototype._renderBackground=function(){
+var _276=this.element.getContext("2d");
+if(this.layout.style=="bar"||this.layout.style=="line"){
+_276.save();
+_276.fillStyle=this.options.backgroundColor.toRGBString();
+_276.fillRect(this.area.x,this.area.y,this.area.w,this.area.h);
+_276.strokeStyle=this.options.axisLineColor.toRGBString();
+_276.lineWidth=1;
+var _277=this.layout.yticks;
+var _278=false;
+if(this.layout.style=="bar"&&this.layout.options.barOrientation=="horizontal"){
+_277=this.layout.xticks;
+_278=true;
+}
+for(var i=0;i<_277.length;i++){
+var x1=0;
+var y1=0;
+var x2=0;
+var y2=0;
+if(_278){
+x1=_277[i][0]*this.area.w+this.area.x;
+y1=this.area.y;
+x2=x1;
+y2=y1+this.area.h;
+}else{
+x1=this.area.x;
+y1=_277[i][0]*this.area.h+this.area.y;
+x2=x1+this.area.w;
+y2=y1;
+}
+_276.beginPath();
+_276.moveTo(x1,y1);
+_276.lineTo(x2,y2);
+_276.closePath();
+_276.stroke();
+}
+_276.restore();
+}else{
+PlotKit.SweetCanvasRenderer.__super__._renderBackground.call(this);
+}
+};
+PlotKit.SweetCanvas={};
+PlotKit.SweetCanvas.SweetCanvasRenderer=PlotKit.SweetCanvasRenderer;
+PlotKit.SweetCanvas.EXPORT=["SweetCanvasRenderer"];
+PlotKit.SweetCanvas.EXPORT_OK=["SweetCanvasRenderer"];
+PlotKit.SweetCanvas.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+PlotKit.SweetCanvas.__new__();
+MochiKit.Base._exportSymbols(this,PlotKit.SweetCanvas);
+try{
+if(typeof (PlotKit.CanvasRenderer)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "PlotKit.EasyPlot depends on all of PlotKit's components";
+}
+if(typeof (PlotKit.EasyPlot)=="undefined"){
+PlotKit.EasyPlot={};
+}
+PlotKit.EasyPlot.NAME="PlotKit.EasyPlot";
+PlotKit.EasyPlot.VERSION=PlotKit.VERSION;
+PlotKit.EasyPlot.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+PlotKit.EasyPlot.toString=function(){
+return this.__repr__();
+};
+PlotKit.EasyPlot=function(_283,_284,_285,_286){
+this.layout=new PlotKit.Layout(_283,_284);
+this.divElem=_285;
+this.width=parseInt(_285.getAttribute("width"));
+this.height=parseInt(_285.getAttribute("height"));
+this.deferredCount=0;
+if(this.width<1){
+this.width=this.divElem.width?this.divElem.width:300;
+}
+if(this.height<1){
+this.height=this.divElem.height?this.divElem.height:300;
+}
+if(MochiKit.Base.isArrayLike(_286)){
+for(var i=0;i<_286.length;i++){
+if(typeof (_286[i])=="string"){
+this.deferredCount++;
+var d=MochiKit.Async.doSimpleXMLHttpRequest(_286[i]);
+d.addCallback(MochiKit.Base.bind(PlotKit.EasyPlot.onDataLoaded,this));
+}else{
+if(MochiKit.Base.isArrayLike(_286[i])){
+this.layout.addDataset("data-"+i,_286[i]);
+}
+}
+}
+}else{
+if(!MochiKit.Base.isUndefinedOrNull(_286)){
+throw "Passed datasources are not Array like";
+}
+}
+if(PlotKit.CanvasRenderer.isSupported()){
+this.element=MochiKit.DOM.CANVAS({"id":this.divElem.getAttribute("id")+"-canvas","width":this.width,"height":this.height},"");
+this.divElem.appendChild(this.element);
+this.renderer=new PlotKit.SweetCanvasRenderer(this.element,this.layout,_284);
+}else{
+if(PlotKit.SVGRenderer.isSupported()){
+this.element=PlotKit.SVGRenderer.SVG({"id":this.divElem.getAttribute("id")+"-svg","width":this.width,"height":this.height,"version":"1.1","baseProfile":"full"},"");
+this.divElem.appendChild(this.element);
+this.renderer=new PlotKit.SweetSVGRenderer(this.element,this.layout,_284);
+}
+}
+if((this.deferredCount==0)&&(PlotKit.Base.keys(this.layout.datasets).length>0)){
+this.layout.evaluate();
+this.renderer.clear();
+this.renderer.render();
+}
+};
+PlotKit.EasyPlot.onDataLoaded=function(_288){
+var _289=new Array();
+var _290=_288.responseText.split("\n");
+for(var i=0;i<_290.length;i++){
+var _291=MochiKit.Format.strip(_290[i]);
+if((_291.length>1)&&(_291.charAt(0)!="#")){
+_289.push(_291.split(","));
+}
+}
+this.layout.addDataset("data-ajax-"+this.deferredCount,_289);
+this.deferredCount--;
+if((this.deferredCount==0)&&(PlotKit.Base.keys(this.layout.datasets).length>0)){
+this.layout.evaluate();
+this.renderer.clear();
+this.renderer.render();
+}
+};
+PlotKit.EasyPlot.prototype.reload=function(){
+this.layout.evaluate();
+this.renderer.clear();
+this.renderer.render();
+};
+PlotKit.EasyPlotModule={};
+PlotKit.EasyPlotModule.EasyPlot=PlotKit.EasyPlot;
+PlotKit.EasyPlotModule.EXPORT=["EasyPlot"];
+PlotKit.EasyPlotModule.EXPORT_OK=[];
+PlotKit.EasyPlotModule.__new__=function(){
+var m=MochiKit.Base;
+m.nameFunctions(this);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+};
+PlotKit.EasyPlotModule.__new__();
+MochiKit.Base._exportSymbols(this,PlotKit.EasyPlotModule);
+
+

Added: jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/chart_img_behaviour.js
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/share/plugins/Jifty/Plugin/Chart/web/static/js/chart_img_behaviour.js	Fri Aug  3 13:01:43 2007
@@ -0,0 +1,16 @@
+/*
+ * chart_behaviour.js
+ *
+ * Helper to make charts more designer friendly.
+ */
+
+Behaviour.register({
+    'img.chart': function(e) {
+        var dim = Element.getDimensions(e);
+        var url = e.src;
+        url += url.indexOf('?') >= 0 ? '&' : '?';
+        url += 'width=' + dim.width + 'px';
+        url += '&height=' + dim.height + 'px';
+        e.src = url;
+    },
+});

Modified: jifty/branches/virtual-models/share/web/static/js/jifty.js
==============================================================================
--- jifty/branches/virtual-models/share/web/static/js/jifty.js	(original)
+++ jifty/branches/virtual-models/share/web/static/js/jifty.js	Fri Aug  3 13:01:43 2007
@@ -260,11 +260,13 @@
                                     if (field.nodeName == 'error' || field.nodeName == 'warning') {
                                         var err_div = document.getElementById(field.getAttribute("id"));
                                         if (err_div != null) {
+                                            Element.show(err_div);
                                             err_div.innerHTML = field.firstChild.data;
                                         }
                                     } else if (field.nodeName == 'ok') {
                                         var err_div = document.getElementById(field.getAttribute("id"));
                                         if (err_div != null) {
+                                            Element.hide(err_div);
                                             err_div.innerHTML = '';
                                         }
                                     }
@@ -276,6 +278,7 @@
                                     if (field.nodeName == 'canonicalization_note')  {
                                         var note_div= document.getElementById(field.getAttribute("id"));
                                         if (note_div != null) {
+                                            Element.show(note_div);
                                             note_div.innerHTML = field.firstChild.data;
                                         }
                                     }
@@ -714,6 +717,9 @@
 
             Element.addClassName( e, "jifty_enter_handler_attached" );
         }
+    },
+    '.form_field .error, .form_field .warning, .form_field .canonicalization_note': function(e) {
+        Element.hide(e);
     }
 });
 

Modified: jifty/branches/virtual-models/t/13-sessions.t
==============================================================================
--- jifty/branches/virtual-models/t/13-sessions.t	(original)
+++ jifty/branches/virtual-models/t/13-sessions.t	Fri Aug  3 13:01:43 2007
@@ -7,9 +7,9 @@
 
 =cut
 
-use Jifty::Test tests => 31;
+use Jifty::Test tests => 25;
 
-my ($first_id, $second_id, $third_id);
+my ($first_id, $third_id);
 
 {
     my $session = Jifty::Web::Session->new();
@@ -44,7 +44,6 @@
     $session->load_by_kv(user => 'second');
     ok($session->id, "got a session");
     isnt($session->id, $first_id, "NOT same session as before");
-    $second_id = $session->id;
 
     is($session->get('hello'),  undef, "different value gives different session");
     is($session->get('number'), undef, "different value gives different session");
@@ -63,36 +62,30 @@
     is($session->get('number'), '1st', "even though the two sessions have some overlapping keys, the one that matters doesn't overlap");
 }
 
-# the three-arg form
-
+# test null char
 {
     my $session = Jifty::Web::Session->new();
-    $session->load_by_kv('user', 'first', sub { $_[0] =~ /^f/ } );
+    $session->load_by_kv(user => "first\0sneaky!");
     ok($session->id, "got a session");
-    is($session->id, $first_id, "first session again");
-    is($session->get('number'), '1st');
+    isnt($session->id, $first_id, "'first\\0sneaky!' different from 'first'");
+    is($session->get('hello'), undef, "first\\0sneaky has no session data yet");
 }
 
 {
     my $session = Jifty::Web::Session->new();
-    $session->load_by_kv('user', 'third', sub { $_[0] =~ /\b(thi|3)rd\b/ } );
+    $session->load_by_kv(user => "\0third");
     ok($session->id, "got a session");
     $third_id = $session->id;
 
-    isnt($session->id, $first_id,  "not first session");
-    isnt($session->id, $second_id, "not second session");
-    is($session->get('number'), undef);
-    $session->set(number => '3rd');
-    is($session->get('number'), '3rd');
+    $session->set(a => 'apple');
 }
 
 {
     my $session = Jifty::Web::Session->new();
-    $session->load_by_kv('user', 'third', sub { $_[0] =~ /\b(thi|3)rd\b/ } );
+    $session->load_by_kv(user => "\0third");
     ok($session->id, "got a session");
-    isnt($session->id, $first_id,  "not first session");
-    isnt($session->id, $second_id, "not second session");
-    is($session->id,   $third_id, "third session again");
-    is($session->get('number'), '3rd');
+    is($session->id, $third_id, "same session as before");
+
+    is($session->get('a'), 'apple', "'set', destroy, 'get' works");
 }
 

Modified: jifty/branches/virtual-models/t/TestApp-Plugin-Chart/lib/TestApp/Plugin/Chart/View.pm
==============================================================================
--- jifty/branches/virtual-models/t/TestApp-Plugin-Chart/lib/TestApp/Plugin/Chart/View.pm	(original)
+++ jifty/branches/virtual-models/t/TestApp-Plugin-Chart/lib/TestApp/Plugin/Chart/View.pm	Fri Aug  3 13:01:43 2007
@@ -7,8 +7,8 @@
 template '/graphit' => page {
     Jifty->web->chart(
         type   => 'Pie',
-        width  => 400,
-        height => 300,
+        width  => '100%',
+        height => 500,
         data   => sub {
             [
                 [ 2004, 2005, 2006, 2007 ],

Modified: jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/chart.t
==============================================================================
--- jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/chart.t	(original)
+++ jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/chart.t	Fri Aug  3 13:01:43 2007
@@ -33,7 +33,7 @@
 my $mech = Jifty::Test::WWW::Mechanize->new;
 
 $mech->get_ok($url . '/graphit', 'try getting /graphit');
-my $img_match = qr{<img src="(/chart/chart/S\d+)" width="400" height="300"/>};
+my $img_match = qr{<img src="(/chart/chart/S\d+)" };
 $mech->content_like($img_match, 'has an img tag');
 my ($chart_path) = $mech->content =~ $img_match;
 
@@ -53,6 +53,6 @@
 
     is($info->{file_ext}, 'png', 'it is a png file');
     is($info->{width}, 400, 'it is 400 pixels wide');
-    is($info->{height}, 300, 'it is 300 pixels tall');
+    is($info->{height}, 500, 'it is 500 pixels tall');
 };
 

Modified: jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/gd_graph.t
==============================================================================
--- jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/gd_graph.t	(original)
+++ jifty/branches/virtual-models/t/TestApp-Plugin-Chart/t/gd_graph.t	Fri Aug  3 13:01:43 2007
@@ -33,7 +33,7 @@
 my $mech = Jifty::Test::WWW::Mechanize->new;
 
 $mech->get_ok($url . '/graphit', 'try getting /graphit');
-my $img_match = qr{<img src="(/chart/gd_graph/S\d+)" width="400" height="300"/>};
+my $img_match = qr{<img src="(/chart/gd_graph/S\d+)" };
 $mech->content_like($img_match, 'has an img tag');
 my ($chart_path) = $mech->content =~ $img_match;
 
@@ -53,6 +53,6 @@
 
     is($info->{file_ext}, 'png', 'it is a png file');
     is($info->{width}, 400, 'it is 400 pixels wide');
-    is($info->{height}, 300, 'it is 300 pixels tall');
+    is($info->{height}, 500, 'it is 500 pixels tall');
 };
 


More information about the Jifty-commit mailing list