-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Charts to ES6 classes #1561
Charts to ES6 classes #1561
Conversation
I am trying to come up with a guideline on how an ES6 class should look in So far the guidelines look like the following:
Looking for you feedback/suggestions. |
This makes sense. I'll review the Legend class more closely tomorrow. I didn't think about the lack of private members in JS. That's a big change. I guess there is a proposal (with weird hash syntax) which is making its way to browsers, but not fast enough for us. (Same document you linked) I think this is okay. dc.js was intended to be a leaky abstraction, and there are times where it's difficult to implement a special behavior or a workaround because the members are inaccessible. We've been inconsistent about using Personally I would advocate for the most terse accessor syntax possible:
I recognize it's not consistent that the chart is usually I'm open to debate. |
Yes, the lack of private members and no ability to explicitly declare members was something that stumped me. However with the current naming convention, in future, it should be easy to switch to the #s. Totally agree about the usage => functions. I am updating the guidelines. So far the guidelines look like the following:
|
Wait, I thought you were going to use ES6 class member functions instead of initializing all the members in the constructor? I appreciate that this is closer to the original implementation and semantics, but we won't get any of the performance benefits this way (every function gets created every time a class is instantiated) and it's not idiomatic. Are there problems with class members? |
Whoops never mind, I missed a commit there! I see what you are doing now. This looks really nice. 👍 |
After several attempts, Additional learning:
Moving to to other classes now. |
Cool!! We probably don't need That should clear up the first issue, which sounds painful. As for all the functions initialized in the constructor: since none of those depend on the scope, the bigger function definitions could be moved out of the class and be private to the module. They'd just be referenced in the constructor, with less clutter and maybe a little more clarity. I agree about needing a new deprecation logger. I'll think about it. |
Thanks @gordonwoodhull. Just curious, should we make conventions for ordering of member functions (and constructor)? |
Took a shot at moving initializer function as private methods. Currently placed towards end of the class. |
I meant private to the module - at file scope. None of them use They don't really make sense as member functions, for the same reason. And if they are not exported, they won't be visible or cloud up any namespaces. |
And sure, if you see a consistent ordering for class members that works for chart classes, that would be helpful. They are a jumble right now. The categories that come to mind are constructor, getters/setters, public methods, private methods and utilities. (It also helps to make a distinction between truly private methods and internal interfaces like I'll leave it to your judgment what order to put them in. There are good arguments either way. |
Also, looks like you need to rebase - I made a minor doc fix for the crossfilter PR. |
Code has changed a lot, unfortunately rebasing is no longer possible. I have checked the diff, I will just make the corresponding change. |
With respect to method orders, I guess the counterargument is that it's often nice to have helper/utility functions near the public or "internal interface" methods they support, grouping code by functionality rather than what category it's in. E.g. "all of the brushing code", "all of the legendable code", drawing functions, etc. Could this subjective factor be addressed in the guideline? Another consideration is that many of the utility functions don't use |
Makes sense. At this point I will focus on conversion of classes. We can take up reordering of methods later if we feel like it 😄 |
Looking good! 👍 |
I'd declare it like this: const _tweenPie = self => function(b) {
// ... and use it like this: tranNodes.attrTween('d', _tweenPie(this)); |
That looks like a good idea, I will apply similar pattern to sunburst as well. |
Please review the change set. I also needed to explicitly set All test cases pass and tween seem to be working. At top level |
Cool! I'll take a thorough look at all the Yes arrow functions do not have their own |
Thanks @kum-deepak! I took a closer look at the Excellent work - the "real" classes are much clearer than the Crockford-style class-closures we had before. Overall this is very clean. "private methods" of classesPreviously there were free-floating functions inside of the dc.js classes, some of which accessed the current state through the closure, and some which didn't. The functions which don't access the state can be put in the module, as you implemented for the base mixin. (Thanks!) The ones that do access state need to be made members, but I would suggest one small change: since they were previously private, they should have the underscore prefix. This is consistent with "internal" methods like I am thinking of methods like the base mixin's Looks like you already did this for the pie chart's A small point, open to debate: the base mixin's _tweenPieI agree that there needs to be a const _tweenPie = chart => function(b) {
// ...
};
if (tranNodes.attrTween)
tranNodes.attrTween('d', _tweenPie(this)); and it works. I find it simpler than It looks like the same approach could work for the sunburst's I like the parameter name _pvt_onClickThese make my brain hurt. Hopefully they will get a lot better with regular ES6 inheritance and overrides! I did not look deep into every method implementation but I looked at a few dozen of them. Overall I think these changes make the code easier to read. If there are any places where you think the transformation makes the code more complicated, please reach out. |
Thanks @gordonwoodhull! I am prefixing _, whenever I realize the method/member is actually private. I have a sense that there may be a few opposite cases. Once full code has been converted to proper classes, IDE capabilities allow easier refactoring, including renames. I am currently intending to keep all charts working and test cases pass, at least as far I can keep. This is helping me in avoiding errors. The pvt is marker for me to come back. |
That sounds like a great plan. I also like keeping everything running while refactoring. It may end up being more work, measured in characters added/deleted, than making N changes at once. But you don't end up in that state where nothing works and you don't know why. (which I know too well!) |
This is a monumental task you've taken on! It's looking great so far. |
Completed one pass on all charts. Finally came at the other end. Next I will do some Gruntfile changes before hitting mixins. At that stage will make another pass at all the charts. |
Excellent work! The incremental approach makes so much sense for such a complete and thorough change. I took a peek at one of these, the composite chart. I forgot that we were deleting I think you are using Thanks for taking this on, @kum-deepak! |
There are few places where a method is deleted, my current thinking is to either raise an exception or just an error is logged (which I found in some cases). Currently I have put ES6 as a marker for me to revisit. Currently, I have been using a set of regular expressions and some patterns to figure out what all can be relatively safely changed. I am keeping |
I see, deletion is used in the composite chart in order to make sure the wrong implementation of I thought |
Updated the last commit, the automated system removed all of the |
Spoke too soon, bar chart seems yet to be converted. |
Re browserify, just to document this while I'm looking at it, in case anyone comes searching later. In the past we were generating a browserify bundle in order to test that our UMD code worked correctly with that bundler. Looks like we disabled it in beef2c8 about a year ago during a grunt cleanup in support of Karma. Arguably it could still have some use in dc.js 3.0 but I agree it should be removed for dc.js 4.0. Browserify sort of does support ES6 modules (browserify/browserify#1186), but the point of this test was to make sure that our UMD code worked correctly. Rollup will generate our UMD going forward. |
I am releasing 3.1.3 with the canvas scatter plot. @kum-deepak, up to you if you want to pull these changes into the es6 branch or leave that to me. I've also been updating examples every once in a while, so let's sync up when you're done with the current stage of the transformation. |
We can sync examples and specs easily. However, merging any file in src is not going to be trivial at this stage. |
It took a little thought rebasing the scatter canvas code from DCv3 to DCv4, but it's fairly straightforward - a couple of new functions. I'll take care of it when we merge this PR. |
Thanks @gordonwoodhull! |
Learned that stack based charts work quite differently than other charts. Been able to resolve most of it, barring their usage of |
I took a quick run through the examples and tests to see how this is going. I take it you haven't needed to make any breaking changes to the interface so far? I am impressed but also surprised. |
I am surprised as well. I am really thankful to all predecessors who have meticulously written test cases. When anything went wrong at least one of the test cases would fail - making the work easier. So, it has been a slow effort but not frustrating which earlier I was afraid about. |
That's great to hear. It is a ton of work to write and maintain tests, often more work than writing features. TBH this is the main reason so many PRs don't get merged. It's hard to convince people to learn how to write them, and I can't always take the time myself. But they make changes so much safer. I'm sure there will still be glitches, since people use this library in lots of weird ways. But it's very comforting to see the tests and examples continue to run, with almost no changes. |
I think we have reached a stage to merge it to ES6 branch. All tests pass and eslint clean. Time for reviews 😄 We can merge newer examples and other changes at this stage. Also time to plan and start conceptual changes. |
The code looks beautiful! It doesn't fix bugs in itself, but I think having such orderly code will help maintenance a lot going forward.
|
I did notice a few places, notably in cbox-menu and series-chart, where const chart = this; is not strictly necessary. It's not a big deal, but could you do a grep for |
I'm inclined to merge to es6 after dealing with those glitches. We can call it alpha 2! Do you have open ES6 issues/questions which are not commented ES6 in the code? |
src/charts/series-chart.js
Outdated
.brushOn(false); | ||
}); | ||
// ES6: do we add removal function in composite chart? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it's a great idea, it's not really an ES6 issue, so let's deal with it later.
As always, adding features requires thinking carefully about impact, as well as tedious but valuable test-writing.
For now, I don't think chart
is necessary here. (much easier discussion!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, let us drop this.
There is still work before I would suggest to mark another alpha. For me a key benefit merging to ES6 branch brings is that I can work on multiple PRs in parallel. In this instance I had to work quite long in a linear sequence. In particular I want to clean up files in core folder. I will do those as smaller PRs. |
Let me have a look 😄 |
Thanks @kum-deepak. My idea is to bump the version number when I merge to the es6 branch, but not actually release the library to NPM or advertise it until it goes to master. If anyone wants to try out the bleeding edge, they should be able to. Bumping the version number is a precaution in case weird versions of dc.js get out on the web. |
Makes sense. Please do it. |
ok github, yes you are correct, this is merged, but i'm still working on integrating the changes from develop/master, so don't get too excited! |
Hi @kum-deepak, I have merged everything to the es6 branch, including the changes to examples and the canvas scatter plot. Now this PR is really merged!! |
Have been experimenting with multiple approaches so far. At this stage trying to figure out what the final ES6 classes should look like and also how to get there without, potentially, introducing errors.