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

Process data uri images synchronously #4105

Merged
merged 7 commits into from
Aug 28, 2019
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions src/components/images/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,31 +84,37 @@ module.exports = function draw(gd) {
var img = new Image();
this.img = img;

// If not set, a `tainted canvas` error is thrown
img.setAttribute('crossOrigin', 'anonymous');
img.onerror = errorHandler;
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
if(d.source && d.source.slice(0, 5) === 'data:') {
Copy link
Contributor

Choose a reason for hiding this comment

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

d.source should always be a string at this stage, so you could use:

if(d.source.indexOf('data:') === 0) {
  // ...
}

instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

Copy link
Collaborator

Choose a reason for hiding this comment

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

d.source can be large though, isn't slice(0, 5) going to be a lot faster than indexOf?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good point @alexcjohnson. @etpinard, anything you don't like about slice here?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not obvious to me why slice would be faster than indexOf() === 0. Has anyone tested that out on jsperf before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thinking was that If the string starts with 'data:', then indexOf() would terminate right away. But if not, indexOf() would search the full string and not bail out until it reaches the end, whereas slice never needs to look past the first 5 characters. If the string doesn't start with data:, then I guess it should be a URL which hopefully isn't terribly long. So it might not matter either way.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess in as far as the two options we care about are a short string starting http
and a long string starting data:, indexOf should be fine. The case to worry about would be a long string that doesn't start data:... but we don't expect that and wouldn't care if it's slow.

jsperf shows a win for indexOf https://jsperf.com/slice-vs-indexof-acj but I don't trust it, there's no way it could actually do indexOf in 2 clock cycles, compiler must have turned it into a constant. This isn't happening in a loop so either option is fast enough to be not worth worrying about.

img.src = d.source;
etpinard marked this conversation as resolved.
Show resolved Hide resolved
thisImage.attr('xlink:href', d.source);
resolve();
} else {
// If not set, a `tainted canvas` error is thrown
img.setAttribute('crossOrigin', 'anonymous');
img.onerror = errorHandler;
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;

var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);

var dataURL = canvas.toDataURL('image/png');
var dataURL = canvas.toDataURL('image/png');

thisImage.attr('xlink:href', dataURL);
thisImage.attr('xlink:href', dataURL);

// resolve promise in onload handler instead of on 'load' to support IE11
// see https://github.com/plotly/plotly.js/issues/1685
// for more details
resolve();
};
// resolve promise in onload handler instead of on 'load' to support IE11
// see https://github.com/plotly/plotly.js/issues/1685
// for more details
resolve();
};


thisImage.on('error', errorHandler);
thisImage.on('error', errorHandler);

img.src = d.source;
img.src = d.source;
}

function errorHandler() {
thisImage.remove();
Expand Down