inheritance - Sharing getter/setter functions across Javascript code -
the following example based off of mike bostock's reusable charts proposal.
given 2 functions (bar() , pie()) each generate different kind of chart:
function bar() { var width = 720, // default width height = 80; // default height function my() { console.log('bar created: ' + width + ' ' + height); } my.width = function(value) { if (!arguments.length) return width; width = value; return my; }; my.height = function(value) { if (!arguments.length) return height; height = value; return my; }; my.render = function() { my(); return my; }; return my; } function pie() { var width = 720, // default width height = 80; // default height function my() { console.log('pie created: ' + width + ' ' + height); } my.width = function(value) { if (!arguments.length) return width; width = value; return my; }; my.height = function(value) { if (!arguments.length) return height; height = value; return my; }; my.render = function() { my(); return my; }; return my; } i can call these functions via chaining method such:
bar().width(200).render(); // bar created: 200 80 pie().height(300).render(); // pie created 720 300 is there way code these getter , setter methods same? instance, plan on having width() functions in each of these exact same. how can make bar() , pie() functions inherit shared functions width(), height(), render()?
right... thing particular style of instantiating functions , hanging additional methods off of them variables have part of scope of function instantiates returned function (bar or pie). since variables internal , inaccessible outside of scope, there isn't way @ them when extending instance.
before going further, note implementation bit off. first, console.log('bar created: ' + width + ' ' + height);, semantically that's incorrect. that's not it's created, rather that's it's rendered. it's created when call bar().
then, when render chart, instead of bar().width(200).render() you're supposed is, e.g.
var barchart = bar().width(200); d3.select('svg') .append('g') .call(barchart) you don't need render(). instead, body of my() render. but, per mbostocks suggestion, my() should take d3 selection param, in example g element being appended. right of of reusable charts tutorial linked to; re-read , you'll see mean.
finally, in answer actual question. way using d3.rebind. first have create common base class has internal width variable , width() getter/setter, so:
function base() { var width; function my(selection) { console.log('base: ' + width); } my.width = function(value) { if (!arguments.length) return width; width = value; return my; }; return my; } next, want make bar (and pie) extend base, this:
function bar() { var _base = base(); // instantiate _base, has width() method function my(selection) { // in here, if want width, call `_base.width()` // and, if there's shared rendering functionality want // put in base, can run `selection.call(_base)` } d3.rebind(my, _base, 'width'); // make width() function of return my; } the last line, copies width() my can call bar().width(). here's fiddle works.
Comments
Post a Comment