1

I'm building a high-level charting API (on top of d3) as a collection of jQuery plugins.

I'd like to namespace the entire project as 'd3charts', but have each plugin in its own file. So, for example, I might have d3charts.histogram.js and d3charts.pie.js. I want the API to look like this:

<script src="jquery.js"></script>

// I don't really have any common functionality yet, this is an empty file
// not sure if this sort of thing is necessary to achieve the API below
<script src="d3charts.js"></script>

// load only the chart types I want to actually use
<script src="d3charts.histogram.js"></script>
<script src="d3charts.pie.js"></script>
<script>
    var foo_data = [ ... ];
    var bar_data = [ ... ];
    $('.foo').d3charts.histogram(foo_data);
    $('.bar').d3charts.pie(bar_data);
</script>

I have individual charts working as regular (non-namespaced) jQuery plugins, see source and pretty display.

What structure do I need in my plugins to make this API work the way I want it to? That means:

// Not this
$('.foo').d3charts().histogram(foo_data);

// Not this either
$.d3charts.pie('.foo', bar_data);

// but chaining should still work:
$('.foo').d3charts.histogram(foo_data).toggleClass('histogramchart');

Other requisite qualities:

  • I can't assume any order that the plugins will be loaded.
  • Ideally, I'd like a solution where I don't need to load an empty namespace "parent" script like d3charts.js.
  • Inside the original (non-namespaced) plugin, I run my code on every element in the selector using the recommended return this.each(). The namespaced plugin should preserve this behavior somehow.

This SO answer seems to be a piece of the puzzle, but I'm not having luck putting the whole picture together.

Thanks for your guidance!

Community
  • 1
  • 1
Idan Gazit
  • 2,500
  • 3
  • 20
  • 24

3 Answers3

3

Each file should check for the existence of jQuery.fn.d3charts, and create it if it doesn't exist; otherwise add to the object.

// Include this in all your files
if (typeof jQuery.fn.d3charts !== "object") {
    jQuery.fn.d3charts = {};
}
// End inclusion

jQuery.fn.d3charts.histogram = function () {

};

This is very strictly checking for an object; if you want to just check for a truthy value (because it's cool and everyone's using || these days), try;

jQuery.fn.d3charts = jQuery.fn.d3charts || { };
Matt
  • 74,352
  • 26
  • 153
  • 180
  • Okay -- this looks sensible and awesome. My next line would be something like return this.each(function() {...}), but now this is histogram, which isn't a jQuery object. What do I do instead for this case? – Idan Gazit Jan 04 '12 at 12:41
  • Removed accepted answer because this solution doesn't actually take me to the goal. – Idan Gazit Jan 04 '12 at 15:25
1

Personally don't like to bloat the jQuery namespace, and as such I prefer to implement it as :

<script>
$.namespace = $.namespace || {};
</script>

Using this method, you can per file then define what needs to be defined, and you end up with something similar as to which I have just posted on jsFiddle for you: jsFiddle example

jc1arke
  • 116
  • 6
0

I haven't been able to track down a solution for doing this, on SO or elsewhere. I get the strong sense that there isn't a solution which hits all of my API desires.

The best solution I found is to package the plugins as jQuery UI widgets. You can see the result at the d3charts github repo.

Idan Gazit
  • 2,500
  • 3
  • 20
  • 24