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

Remove spinner after an export is complete #470

Closed
sashadev-sky opened this issue Dec 5, 2019 · 2 comments · Fixed by #477
Closed

Remove spinner after an export is complete #470

sashadev-sky opened this issue Dec 5, 2019 · 2 comments · Fixed by #477
Labels

Comments

@sashadev-sky
Copy link
Member

sashadev-sky commented Dec 5, 2019

Please note we are preparing to participate in Google Code-in, and have reserved this issue for GCI participants - but we'd love to have your help with another one! Please check out https://code.publiclab.org to see more.

Problem

LDI provides the ability to export multiple images.
Demo it here: https://publiclab.github.io/Leaflet.DistortableImage/examples/select.html
by

  • ctrl + clicking on one or more images.
  • A single toolbar for all of them will appear in the topleft corner.
  • Click the top icon to begin export
  • Open your developer console to see updates on the status

While the export is in progress a spinner icon appears, but it does not yield back to the original export icon after completion.

We would like it to do so.

Solution:

Relevant information:

  • https://github.com/publiclab/Leaflet.DistortableImage/blob/main/src/edit/actions/ExportAction.js - this is the file for the export action. In addHooks we
    • if (edit instanceof L.DistortableImage.Edit) { edit._getExport(); } Single image instances have a handler class L.DistortableImage.Edit that triggers a single image export edit._getExport(); (you can test this one by clicking on any image and hitting the export icon on its attached toolbar). Multiple images have a separate handler L.DistortableCollection.Edit that calls the multiple export function, edit.startExport(), which you demo'd earlier. We check which one to call.
    • if its multiple, follows are method that switch the action's icon to the spinner, and add the loader class to it to animate it's spin via css.
    • Then a call to the multiple export function edit.startExport()

addHooks: function() {
var edit = this._overlay.editing;
if (edit instanceof L.DistortableImage.Edit) { edit._getExport(); }
else {
L.IconUtil.toggleXlink(this._link, 'get_app', 'spinner');
L.IconUtil.toggleTitle(this._link, 'Export Images', 'Loading...');
L.IconUtil.addClassToSvg(this._link, 'loader');
edit.startExport();
}
},
});

startExport: function(opts) {
opts = opts || {};
opts.collection = opts.collection || this._group.generateExportJson();
opts.frequency = opts.frequency || 3000;
opts.scale = opts.scale || 100; // switch it to _getAvgCmPerPixel !
var statusUrl;
var updateInterval;
// this may be overridden to update the UI to show export progress or completion
// eslint-disable-next-line require-jsdoc
function _defaultUpdater(data) {
data = JSON.parse(data);
// optimization: fetch status directly from google storage:
if (statusUrl !== data.status_url && data.status_url.match('.json')) {
statusUrl = data.status_url;
}
if (data.status === 'complete') {
clearInterval(updateInterval);
}
if (data.status === 'complete' && data.jpg !== null) {
alert('Export succeeded. http://export.mapknitter.org/' + data.jpg);
}
// TODO: update to clearInterval when status == "failed" if we update that in this file:
// https://github.com/publiclab/mapknitter-exporter/blob/main/lib/mapknitterExporter.rb
console.log(data);
}
// receives the URL of status.json, and starts running the updater to repeatedly fetch from status.json;
// this may be overridden to integrate with any UI
// eslint-disable-next-line require-jsdoc
function _defaultHandleStatusUrl(data) {
console.log(data);
statusUrl = '//export.mapknitter.org' + data;
opts.updater = opts.updater || _defaultUpdater;
// repeatedly fetch the status.json
updateInterval = setInterval(function intervalUpdater() {
$.ajax(statusUrl + '?' + Date.now(), {// bust cache with timestamp
type: 'GET',
crossDomain: true,
}).done(function(data) {
opts.updater(data);
});
}, opts.frequency);
}
// eslint-disable-next-line require-jsdoc
function _fetchStatusUrl(collection, scale) {
opts.handleStatusUrl = opts.handleStatusUrl || _defaultHandleStatusUrl;
$.ajax({
url: '//export.mapknitter.org/export',
crossDomain: true,
type: 'POST',
data: {
collection: JSON.stringify(collection.images),
scale: scale,
},
success: opts.handleStatusUrl, // this handles the initial response
});
}
_fetchStatusUrl(opts.collection, opts.scale);
},

  • We use SVG icons, with a simple system for rendering the icons in JS dynamically. Follow the pattern of:
# hint - we will want 'get_app' back
 L.IconUtil.toggleXlink(this._link, 'get_app', 'spinner'); 

# toggles the tooltip
 L.IconUtil.toggleTitle(this._link, 'Export Images', 'Loading...'); 

# adds a css spinner class
 L.IconUtil.addClassToSvg(this._link, 'loader'); 

to reverse it.

💬 Get help

If you need any help - here are some options:

Labeled hard because requires a deeper understanding of LDI's moving parts.

@sashadev-sky
Copy link
Member Author

Uploaded to GCI Dashboard

@SidharthBansal
Copy link
Member

Published

jywarren pushed a commit that referenced this issue Dec 14, 2019
* FIX: Remove loading spinner after image export

In the old UI, the spinner would continue spinning after the images have been
exported.

Resolves #470

* FIX: Wrap startExport function inside of a promise

* FIX: Add polyfill for ES6 promises

* FIX: Replace arrow function with normal function

Change was necessary because arrow functions are not supported in ES5.

* FIX: Bind this startExport function

The change was necessary because in the Promise the value of
keyword this gets lost
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants