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

fromDataUrl fails on tablet #89

Closed
mathpere opened this issue Feb 7, 2015 · 30 comments
Closed

fromDataUrl fails on tablet #89

mathpere opened this issue Feb 7, 2015 · 30 comments

Comments

@mathpere
Copy link

mathpere commented Feb 7, 2015

Hi,

I use this awesome lib on my current project and I meet some issue with tablet.

First of all, all is working fine on desktop browser (mac non-retina, chrome / firefox).

The problem occured on tablet (nexus 7, android lollipop, Chrome) with fromDataURL: The signature size is shrank on tablet.

Here is a demo: http://jsbin.com/tixuje/2/edit?html,js,output

If you open this link: http://jsbin.com/tixuje/2 on desktop, you will see this one:
Original signature capture

When I open this same link: http://jsbin.com/tixuje/2 on my tablet, I get a shrank signature:
Shrank signature capture

Do you know where does the problem?

@mathpere
Copy link
Author

mathpere commented Feb 7, 2015

After checking, if this can help, the problem doesn't occur on iPad (safari + chrome)

@szimek szimek added the bug label Feb 7, 2015
@szimek
Copy link
Owner

szimek commented Feb 7, 2015

I don't own a tablet with Android, but hopefully I'll be able check it on my friend's Nexus 5 on Monday. Does it also happen if you draw the image on Nexus 7 and then read it back?

@mathpere
Copy link
Author

mathpere commented Feb 7, 2015

I also own a nexus 5: it happens too with it.

@szimek
Copy link
Owner

szimek commented Feb 14, 2015

@mathpere I still haven't tried it out on Nexus 5, but I prepared some tests, tried it out on non-retina and retina Macbooks and it seems to work fine.

Here's the first jsfiddle with image created on non-retina Macbook (devicePixelRatio = 1): http://jsfiddle.net/szimek/tge7vy68. The image is correctly displayed on both Macs.

Here's the first jsfiddle with image created on retina Macbook (devicePixelRatio = 2): http://jsfiddle.net/szimek/4utubzhp/. Again, the image is correctly displayed on both Macs. One thing to notice here, is that the image is actually bigger than the one created on non-retina device, but it's still displayed correctly.

I used this jsfiddle to create those images: http://jsfiddle.net/szimek/u4zmsmbL. If you click "Get data" button, it will open a new window where you can copy the data URL from.

This HiDPI stuff is pretty confusing, so it's still possible that my tests are somehow messed up and it doesn't work correctly after all.

Let me know if it actually helps in any way :)

@mathpere
Copy link
Author

Hi,

Thanks for your support.

I don't know yet how to interpret these tests.

  • I can confirm that for the 2nd test, the image looks stretched on my non-retina macbook pro but looks well on both nexus 5 and 7.

I will probably use intensively signature pad again in the next few days, I will let you know.

@mathpere
Copy link
Author

Hi,

Finally, I fixed my encountered issue by replacing in the fromDataUrl function these lines:

width = this._canvas.width / ratio,
height = this._canvas.height / ratio;

by these lines:

width = this._canvas.width,
height = this._canvas.height;

It seems to work as expected on both Macbook pro non-retina and nexus 7.

@szimek
Copy link
Owner

szimek commented Feb 25, 2015

@mathpere Thanks. I'll try it again, because I think the image in the second test looked ok on a non-retina Mac. Could you fork these 2 tests, change the lines you mentioned and post links to them here? I'll try both mine and your versions then.

@mathpere
Copy link
Author

@pierresh
Copy link
Contributor

pierresh commented Sep 4, 2015

Hello,

For your information, I meet the same problem as @mathpere on an Android Phone (Android 5.0.2) and his solution works perfectly.

Thanks!

@axos88
Copy link

axos88 commented Oct 12, 2015

Hello!

The image halfing happens on my macbook pro retina.
removing the division by the window.devicePixelRatio would fix the issue.

@axos88
Copy link

axos88 commented Oct 12, 2015

If i set the zoom to 50% (which makes the window.devicePixelRation to be 1, it works correctly.

@axos88
Copy link

axos88 commented Oct 12, 2015

If I move the window to an external / non-retina window, the behaviour is fixed (since window.dpr == 1)

@axos88
Copy link

axos88 commented Oct 12, 2015

Why is the division there in the first place?

@PerfectPixel
Copy link
Contributor

I can confirm the issue for iPhone 5 / iPad Air 2 with mobile Safari (newest iOS) as well as Google Nexus 9 with Android 5.1.

The question is, what the ratio scaling was supposed to achieve in the first place:
If you stay on the same device, your canvas size should already match the data. The interesting thing is to decide what to do if you switch from high-dpi to non-high-dpi and vice versa. In these cases the canvas does not match the data dimensions.

I would suggest drawing the images on the canvas as is and give the user optional variables to change width and height.

@szimek szimek added this to the 2.0 milestone Nov 6, 2015
@ben3005
Copy link

ben3005 commented Dec 8, 2015

any news on when this is to be fixed?

the proposed fix from @mathpere seems to do the trick for me.

@szimek
Copy link
Owner

szimek commented Dec 8, 2015

@ben3005 Unfortunately I don't have much time lately and I want to check if the fix doesn't break anything before merging it. I'll try to sort it out by the end of this month.

@axos88
Copy link

axos88 commented Dec 9, 2015

@szimek awesome, thanks! :)

A little christmas present for us, eh?

@ben3005
Copy link

ben3005 commented Dec 10, 2015

@szimek awesome, thanks for letting us know

@szimek
Copy link
Owner

szimek commented Dec 30, 2015

This one is really confusing :/ I created yet another demo (http://jsfiddle.net/szimek/x80q89xd/) which loads an image created on my old non-retina MacBook and the image is displayed correctly on both non-retina (devicePixelRatio = 1) and retina (devicePixelRatio = 2) MacBooks.

I created it simply by doing:

setTimeout(function () {
  console.log(signaturePad.toDataURL());
}, 10000)

and then copying data from the console. I'm not sure how it's different from the sample provided by @mathpere and why it works differently.

Here's a picture of both laptops displaying the same image on the canvas:

img_2093

@szimek
Copy link
Owner

szimek commented Dec 30, 2015

Looks like it's related to the code responsible for scaling the canvas in the demo app. It's present in my jsfiddle and the image is displayed correctly there. If you remove this code (just comment out the line with resizeCanvas(c); in http://jsfiddle.net/szimek/x80q89xd/) then it's broken and displayed exactly like in the original post by @mathpere. I guess if you always have this scaling code there, it will "just work".

@PerfectPixel
Copy link
Contributor

Somehow I get the feeling that it would be best to internalize the canvas in the library as there are a lot of pit falls from not dealing with the canvas element correctly.

Maybe just hook the library to a div container and let the library handle the creation / resize of the canvas.

@szimek
Copy link
Owner

szimek commented Dec 31, 2015

@PerfectPixel You may be right, but the problem is that people want to do really strange stuff with it. E.g. instead of resize event they want to listen to orientationchange, or copy the image before canvas is resized and paste it back after, or somehow handle resizing of canvas element even if the size of the whole window doesn't change and so on.

For now I guess I'll add a section about handling canvas element to the README file, i.e. the following code with some explanation:

function resizeCanvas() {
    var ratio =  Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext("2d").scale(ratio, ratio);
}

window.addEventListener("resize", resizeCanvas);
resizeCanvas();

Maybe this callback function could be added as a configuration option and the code above could be the default. But then some people might want to have some throttling there and I'd have to modify the library again...

@PerfectPixel
Copy link
Contributor

Well in my case the issue is, I changed the scale of the context and then changed the dimensions. Turns out that changing the dimensions after scaling is equivalent to not using canvas.getContext("2d").scale(ratio, ratio); at all.

I'll adjust the code once I get back to work after new year and get back to you with feedback.

@szimek
Copy link
Owner

szimek commented Jan 1, 2016

@PerfectPixel I've added a section about handling high DPI screens to the readme: . It's not much besides what's already in this topic, but it would be awesome if you could read it and let me know if it explains it well and is clear enough.

@PerfectPixel
Copy link
Contributor

@szimek sorry for coming around a little late. I read through the readme, looks good from my perspective. However, I noticed a small pitfall: if you fit your canvas at 100% width or height in the parent container, then you need to scale it down with css. Otherwise your canvas will have 200% implicit width/height on high DPI screens.

We are using the canvas in a bootstrap modal, use the modals width as the canvas width and scale the height proportionately. If we do not scale the canvas with css, it flows out over the side of the modal.

@szimek szimek removed this from the 2.2 milestone Apr 2, 2017
@szimek szimek modified the milestones: 2.3, 2.2 Apr 2, 2017
@rwacker
Copy link

rwacker commented Apr 14, 2017

The scaling solution did not work in my scenario. Applying the scaling fixed the image when loaded using .fromDataURL() but the canvas size doubled. Also the point of input was shifted from where the mouse/finger actually made contact on the signature pad.

I was able to fix the issue by overriding the .fromDataURL() function and removing the pixelRatio logic.

customSignaturePadFromDataURL: function(dataUrl)
{
    var self = this,
	image = new Image(),
	// ratio = window.devicePixelRatio || 1,
	width = this._canvas.width,
	height = this._canvas.height;

	this._reset();
	image.src = dataUrl;
	image.onload = function () {
		self._ctx.drawImage(image, 0, 0, width, height);
	};
	this._isEmpty = false;
}

@szimek szimek modified the milestones: 2.2, 2.3 Apr 14, 2017
@szimek szimek modified the milestones: 2.2, 3.0 May 27, 2017
@chitgoks
Copy link

The same happens with toSvg() when created in mobile. it does not seem to get scaled.

@ShinShil
Copy link

ShinShil commented Mar 15, 2018

When I've changed browser zoom to 75% the fromDataURL become not working - after each draw action on canvas the extra elements have been added - elements duplicate what I have drawn, but their size was if I would drawn it in zoom 100%. @rwacker solution help me.

@demo-igor
Copy link

demo-igor commented Mar 26, 2018

fromDataURL(image, {width: 100, height: 100}
width, height should have canvas size to correct restore
https://github.com/szimek/signature_pad/blob/master/src/signature_pad.ts

@UziTech
Copy link
Collaborator

UziTech commented Jun 8, 2021

I think this was fixed in #253

@UziTech UziTech closed this as completed Jun 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests