PullMonkey Blog

30 Apr

Open Flash Chart II – fully automated


Just as an attention grabber - we are going after this example in this article:

Keeping up

Ok, seeing that the php versions of open flash chart and open flash chart swf files continually change along with with the API (not saying this is a bad thing), I wanted to come up with an even more abstract solution. The goal is to not have to worry when the swf file is released with the latest set of graphs or changes its API. I simply don't want to worry about this method or that method, or this class or that class.

Feedback

This article will sort of act as a tutorial for those interested in metaprogramming and as a set of instructions for those looking to experiment with the latest version of the OFC II Rails Plugin that I am currently toying with. I would like to hear feedback, but just remember that phase 1 of this release will be very basic, meaning none of the ajaxy stuff. It will come, just not yet.

Let's see what we can get away with

I am already using method_missing() for pretty much everything in the OFC II Rails Plugin that is being used now. But every time new classes are added, I have to sit down and basically convert the php class to ruby - just plain tedious, not really what I had planned when I started all this. Ok, so method_missing() was great, but let me introduce (or possibly reintroduce) you to const_missing(), basically method_missing() but instead of methods, we can create classes or modules or other objects on the fly. This will definitely help when the php version gets a new class. Instead of getting hounded to update the rails version to be 100% like the php version, everything will just work, no updates to code required. Well, we hope ! So check this out:

Here is what we did with method_missing():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

module OFC
  class Base
    def method_missing(method_name, *args, &blk)
      case method_name.to_s
      when /(.*)=/   # i.e., if it is something x_legend=
        # if the user wants to set an instance variable then let them
        # the other args (args[0]) are ignored since it is a set method
        self.instance_variable_set("@#{$1}", args[0])
      when /^set_(.*)/
        # backwards compatible ... the user can still use the same set_y_legend methods if they want
        self.instance_variable_set("@#{$1}", args[0])
      else
          if inst = self.instance_variable_get("@#{method_name}")
            inst
          else
            # if the method/attribute is missing and it is not a set method then hmmmm better let the user know
            super
          end
      end
    end
  end
end

This just basically allows me to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13

  class Foo < OFC::Base
  end

  foo = Foo.new

  foo.some_random_attribute = "Hello"  #=> "Hello"
  foo.some_random_attribute  #=> "Hello"
  foo.some_random_undefined_attribute  #=> Method Missing error (calls super)

  # too be like php, for easier conversion
  foo.set_some_random_attribute("Good Bye")  #=> "Good Bye"
  foo.some_random_attribute  #=> "Good Bye"

Along the same lines, I have created an initialize method that takes any argument hash of variable/value pairs and calls variable=() which is handled by method missing as we saw above:

1
2
3
4
5
6
7
8

  class Foo < OFC::Base
  end

  foo = Foo.new(:x_axis => 5, :min => 10, :max => 90, :steps => 5, :elements => ["one", "two"])
  
  foo.x_axis #=> 5
  foo.min #=> 10

Ok, so on to const_missing() and what we can do with that:

1
2
3
4
5
6

  def OFC.const_missing(const)
    klass = Class.new OFC::Base
    Object.const_set const, klass
    return klass
  end

This says that any undefined (missing) constant of OFC should be defined as a new class that inherits from OFC::Base.

So when we say OFC::Foo, that has not been defined, so we will get back class OFC::Foo < OFC::Base;end; which will give us the initialize() method and method_missing() method from above. Let's see how this works:

1
2
3
4
5
6
7
8
9
10
11

  line = OFC::Line.new(:values => [1,2,3,nil,nil,5,6,7])
  line.values #=> [1,2,3,nil,nil,5,6,7]
  line.some_random_variable = "Hello" #=> "Hello"
  line.some_random_variable #=> "Hello"

  stacked_bar_chart = OFC::BarStack.new
  stacked_bar_chart.values = []
  stacked_bar_chart.values << [2,3,4]
  stacked_bar_chart.values << [5, {"val" => 5, "colour" => "#ff0000"}]
  stacked_bar_chart.keys = [{ "colour" => "#C4D318", "text" => "Kiting", "font-size" => 13 } ...]

So it all sort of came together right there. I've shown you all the code that comes with the Rails Open Flash Chart plugin now. No more definining idividual classes, no more trying to keep up with the never ending php version, and no more late nights converting php to ruby (!). About dang time.

Ok, but this is just the beginning, nothing has been set in stone, so like I said, give me your feedback, what works for you and what does not. And, hopefully, I will have solutions for you or you for me.

Example with new version (test version)

I am using rails 2.3.2, but I don't think it will matter what version you are using.

Create your new rails project

1
2
3
4
5

# create a new rails project 
> pullmonkey$ rails testing_it
#<Bunch of stuff is created ....>
> pullmonkey$ cd testing_it/

Install the plugin from the test branch

Note the -r test in this next step. The new version (test version) I am playing with is under the test branch and -r says what branch to pull from.

Also, you can use git:// instead of http:// below, but depending on your firewall restrictions http:// will probably work out best for you.

1
2
3

> pullmonkey$ ./script/plugin install http://github.com/pullmonkey/open_flash_chart.git -r test
# <Bunch more stuff ...>

Create a controller to play in

1
2
3

> pullmonkey$ ./script/generate controller test_it
# <And more stuff >

Get our assets

1
2
3
4
5
6
7

# first we will get swfobject.js
> pullmonkey$ cp vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js public/javascripts/
# next the open flash chart swf (GET whatever is the latest version), right now that is here: http://teethgrinder.co.uk/open-flash-chart-2/open-flash-chart.swf
> pullmonkey$ cd public/
> pullmonkey$ wget http://teethgrinder.co.uk/open-flash-chart-2/open-flash-chart.swf
> pullmonkey$ cd ..

Edit our controller

Notice here that I just include one of the many examples from the plugin's examples directory. Definitely more to follow.

One thing you will notice about the examples, is that the php code is in the comments, so you can see how I would convert from the php examples to ruby. Please feel free to add your own examples, just fork the project.

1
2
3
4
5
6
7
8
9
10

> pullmonkey$ vi app/controllers/test_it_controller.rb
# mine looks like this:
class TestItController < ApplicationController
  include OFC::Examples::AreaHollow

  def index
    @graph = open_flash_chart_object(600,300, "/test_it/area_hollow")
  end
end

Edit our view

1
2
3
4
5

> pullmonkey$ vi app/views/test_it/index.html.erb
# mine looks like this:
<%= javascript_include_tag 'swfobject' %>
<%= @graph %>

Start 'er up

1
2
3
4
5

> pullmonkey$ ./script/server

# browse to the test_it index
http://localhost:3000/test_it

Our example



8 Responses to “Open Flash Chart II – fully automated”

  1. By Harry Seldon on Apr 30, 2009 | Reply

    Very cool! Thx for this new version of OFC and thx for these explanations.

  2. By Kip on Apr 30, 2009 | Reply

    Charlie, thanks for a very useful plugin. After some messing around I decided I wanted to leverage the ‘get-data’ model of OFC (not just ‘data-file’). This lets me embed the json data in the html output and avoid another request cycle for ofc to fetch the data. Not needed in all situations, but handy in many. My git-patching-fu isn’t great so the very simple addition of one method to open_flash_chart_object.rb OpenFlashChart::Controller is here for anyone interested:

    <filter:code attributes=lang="ruby">
    def open_flash_chart_embedded(width, height, div_name, json_data, use_swfobject=true, base="/", swf_file_name="open-flash-chart.swf")
    <<-HTML
    <div id="#{div_name}"></div>
    <script type="text/javascript">
    swfobject.embedSWF("#{base}#{swf_file_name}", "#{div_name}", "#{width}", "#{height}", "9.0.0", "expressInstall.swf",
    {"get-data":"chartData#{div_name}"});

    function chartData#{div_name}() {
    return "#{json_data.gsub(‘"’,’\"’)}";
    }
    </script>
    HTML
    end
    </filter:code>

    Note this method requires you provide a div_name but it would be trivial to hook it up to the existing div_name generator.

    Cheers, –Kip

  3. By rob on Apr 30, 2009 | Reply

    Hey, first off, incredible work on this plugin. I have used it for numerous projects, and I absolutely love it. I cant thank you enough for your tireless work on this project…

    I have a question that Id normally email you to ask, but I can’t find your email, so I’m settling for a comment.

    I have graphs that occasionally have no data in them, so what Id like to do is display a "NO DATA AVAILABLE" message in the same style as the "LOADING" bubble that appears when the graph first loads….is there any way to achieve this? I’ve been searching high and low for a way to figure it out. Right now, it just display a blank space when no data is available, but Id really like to display a message to the user instead of just a white box.

    Again, thanks for your hard work.
    Best,
    Rob

  4. By Rain on Apr 30, 2009 | Reply

    Hi, Charlie , with test branch plugin installed, I can successfully make my line chart. But there is still an issue that is I CANNOT make the X Axis Labels display?

    Can you make X axis labels display? Any suggestions for this?

    Thanks for the great plugin!

  5. By Nithin Bekal on Sep 18, 2009 | Reply

    Hey, thanks for creating this great plugin. I’ve tried using the older version of this plugin and it worked great. But when I try installing OFC II, I get a “plugin not found” message for either of the URLs that you’ve given.

    Am I doing something wrong there? I used the same procedure for installing the older version and that worked fine.

  6. By charlie on Sep 18, 2009 | Reply

    Hey Nithin,

    Which urls are you trying? I did a quick check of all the clickable links on the page, they all seem to be fine. Are you having problems with a plugin/install?

  7. By Nithin Bekal on Sep 18, 2009 | Reply

    Hi Charlie,

    Yes, I was having a problem with installing the OFC II plugin, but I finally managed to get it to work with this:

    ruby script/plugin install http://github.com/pullmonkey/open_flash_chart.git/

    …with the trailing slash after .git because apparently you need that while installing a plugin on a Windows machine.

    Sorry about commenting on the wrong page. I had this page open in another tab and so ended up leaving the comment here, which probably caused you the confusion about what URLs I was talking about. And thanks again for the great plugin. 🙂

  8. By Leftblank on Sep 20, 2009 | Reply

    Awesome plugin, however, one think I’m failing to see is how I’d make a graph like the one shown here; http://teethgrinder.co.uk/open-flash-chart-2/x-axis-date.php . Since there isnt much of an API I find it hard to figure out how to build it – could someone perhaps enlighten me here?

Sorry, comments for this entry are closed at this time.