Skip to content
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

[Enhancement] Export plot as PDF, JPG, or PNG #1164

Merged
merged 43 commits into from
Sep 12, 2016
Merged

Conversation

hudsonfoo
Copy link

@hudsonfoo hudsonfoo commented Sep 1, 2016

  • Changes address original issue?
  • Unit tests included and/or updated with changes?
  • Command line build passes?
  • Changes have been smoke-tested?

For issue #967.

I'm reviewing methods for adding testing, and there are two minor issues left, but I would appreciate a code review. I'm doing my best to make updates the same way you would internally but it may take a few swings to get it right.

Remaining issues are trivial:

  • Bottom of plot gets cut off on export
  • User should be given option to name the file prior to download (?)

David Hudson added 7 commits August 31, 2016 23:03
This will be used for exporting an image of the plot.
Extends PlotController by adding three new scoped methods:
exportPDF, exportPNG, exportJPG.

All three methods use basically the same steps. The HTML node
of the plot is passed through html2canvas which generates a canvas.
From the canvas we export a blob, PNG, or JPG then save the file.
@hudsonfoo hudsonfoo changed the title [Enhancement] Export plot as PDF, JPG, or PNG [Enhancement] Export plot as PDF, JPG, or PNG for issue #967 Sep 1, 2016
@hudsonfoo hudsonfoo changed the title [Enhancement] Export plot as PDF, JPG, or PNG for issue #967 [Enhancement] Export plot as PDF, JPG, or PNG Sep 1, 2016
$scope.exportJPG = function () {
PlotController.prototype.exportJPG(self.$element, 'plot.jpg');
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlotController is exposed as plot in the Angular scope already, so I believe these could be omitted by instead having ng-click="plot.exportPDF()" in the plot template. This would make the code and changeset simpler.

@VWoeltjen
Copy link
Contributor

I'm reviewing methods for adding testing, and there are two minor issues left, but I would appreciate a code review. I'm doing my best to make updates the same way you would internally but it may take a few swings to get it right.

Sure! Left a couple of comments in-line.

Remaining issues are trivial:

  • Bottom of plot gets cut off on export
  • User should be given option to name the file prior to download (?)

I agree that a user-specified name is better UX, but think this can also be deferred (particularly if collecting that input proves non-obvious/non-trivial for some reason); saving as "plot.png" or "plot.pdf" is sufficient to meet the use case. A user can always rename the file after it's downloaded.

@VWoeltjen VWoeltjen self-assigned this Sep 1, 2016
charlesh88 added a commit that referenced this pull request Sep 2, 2016
Fixes #967
WIP to be integrated with work
from hudsonfoo in PR #1164
David Hudson and others added 14 commits September 2, 2016 11:54
Set export functions on the ExportImageService prototype. Insantiated
ExportImageService in the PlotController for better dependcy injection.
Fixes nasa#967
WIP to be integrated with work
from hudsonfoo in PR nasa#1164

(cherry picked from commit ebadad6)
It's worth noting that I changed the .gl-plot position from relative to absolute
in an attempt to match the results to a similar requirement in MCT Table. Setting
to absolute caused no regressions as far as I could tell, but I have not attempted
browsers outside of Chrome.
Buttons temporarily hide until export completes.
I would prefer this be passed in via the bundle, but it continues to fail
saying "Unknown Provider". I have chosen to require them into the module
the old-fashioned way, then allow an injectible dependency to override.
@hudsonfoo
Copy link
Author

@VWoeltjen unit test has been added. I did try to set up dependency injection with html2canvas, jsPDF, and saveAs, which in the end I did successfully, but I am dissatisfied with my method. For whatever reason, adding any of those to the dependencies in plot/bundle.js wind up with "Unknown provider" errors. If you have time for one more code review, all I have left is to make sure the plot never gets cut off at the bottom (almost certainly a CSS issue) and we're good to go.

David Hudson added 3 commits September 8, 2016 11:03
Based on updates from 0457f7b these styles
are no longer necessary and have been removed.
Issue nasa#1164. Based on updates from 0457f7b these styles
are no longer necessary and have been removed.
@hudsonfoo
Copy link
Author

@charlesh88 cool. I cherry-picked 0457f7b and merged.

+1 on moving this to the context menu long-term.

@charlesh88
Copy link
Contributor

@hudsonfoo Hi Hudson: The changes in _plots-main.scss lines 25 - 39 shouldn't be there - we actually want the export buttons to always display when the user is viewing the object directly to aid discoverability. We hide and show them when that object is in a Layout because often it's a smaller size; that's what the work in #1167 was about generalizing. Sorry to have to correct this after the fact; I'm pretty behind on getting our style guide together which should include this info.

Also: a bit nervous about changing .gl-plot from position: relative to absolute, but I assume that was done for the needs of exporting?

@hudsonfoo
Copy link
Author

hudsonfoo commented Sep 9, 2016

@charlesh88 cool no prob. After some additional testing with the new cherry-pick, looks like those styles are no longer required, including the .gl-plot change. I've put the stylesheet back to its original state and fixed a minor typo.

As for style guides, I purchased several hardcopy NASA Graphics Standards manuals awhile back and distributed them throughout my office as a reference point for our own :) Pretty cool.

@@ -84,12 +88,30 @@ define([
]
}
],
"services": [
{
"key": "ExportImageService",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit, but exportImageService would be more consistent with naming conventions used elsewhere. (Same goes for its usage in PlotController; we use UpperCamelCase as a convention to identify constructor functions.)

}
}

ExportImageService.prototype.exportPDF = function (element, filename) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use some brief JSDoc here for this and the other export methods

@hudsonfoo
Copy link
Author

Another good catch @VWoeltjen, thanks.

@@ -54,7 +54,7 @@ define(
* @throws {Error} an error is thrown if WebGL is unavailable.
*/
function GLChart(canvas) {
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
var gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) || canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like to break this up to reduce line length, e.g.

var gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) || 
        canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),

mockSaveAs
);
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the verification of high-level interactions is good here, but would also like to pass in a testElement (don't think there's anything that needs to be mocked, so this could just be some object) to the exportXYZ methods, in order to expect(mockHtml2Canvas).toHaveBeenCalledWith(testElement, { onrendered: jasmine.any(Function) })

Testing of the onrendered callback itself would also be good. In particular, it would be nice to check interactions with the canvas object to make sure exportPNG isn't producing JPGs and so forth.

@charlesh88
Copy link
Contributor

@hudsonfoo Thanks! I'm good to go on this PR with my eval.

@VWoeltjen VWoeltjen added this to the Pratchett milestone Sep 9, 2016
@hudsonfoo
Copy link
Author

@VWoeltjen please see updated tests which look for proper html2canvas call as well as ensuring canvas.toBlob requests the correct image type from the canvas.

@VWoeltjen
Copy link
Contributor

Everything's looking really good, thanks for working on this! Double bonus extra gratitude for including licensing info for the new run-time dependencies.

Reviewer Checklist

  1. Changes appear to address issue? Y
  2. Appropriate unit tests included? Y
  3. Code style and in-line documentation are appropriate? Y
  4. Commit messages meet standards? Y

@VWoeltjen VWoeltjen merged commit e73bb4f into nasa:master Sep 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants