Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Web and WebWorks Development

Reply
Highlighted
New Contributor
Posts: 2
Registered: ‎11-03-2013
My Device: Z10 LE
My Carrier: Private
Accepted Solution

Problem with copying from one canvas to another - weird width

Hi all. Firstly, I want to apologize for my english, when I got more time I should spend this time for learning.

 

I make my first html5 game - simple race game on planet Mars. I have trouble with viewport on my mobile device. I created big race map with resolution 6000px x 3000px. Viewport has screen resolution, for example my laptop has full hd resolution so viewport has about full hd resolution. I created two canvases, one for big map and this canvas isn't connected to the DOM, he is like a buffer. Second canvas is a viewport for game and this viewport follows the player. I copy from big canvas to viewport data and this solution runs quite good on different browsers. But I have problem with BlackBerry Z10 viewport. Take a look of example screens:

 

Laptop:

 

Z10:

 

Second screen has a problem with weird scaled width. Coordinates are good, same on two devices. I don't use scale property of canvas, but this is look like a bug on BlackBerry Z10.

 

This is a code which You can use to propagate this bug:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="Description" content="test" />
	<script>
		var meta = document.createElement("meta");
		meta.setAttribute('name','viewport');
		meta.setAttribute('content','initial-scale='+ (1/window.devicePixelRatio) + ',user-scalable=no');
		document.getElementsByTagName('head')[0].appendChild(meta);
    </script>
	<title>test</title>
</head>
<body>
	<canvas id="canvas" style="width: 100%; height: 100%;"></canvas>
	<script>
		var canvas = document.getElementById('canvas');
		canvas.width = window.innerWidth;
		canvas.height = window.innerHeight;
		var ctx = canvas.getContext('2d');
		
		var img  = new Image();
		img.onload = function () {
			var canvas2 = document.createElement('canvas');
			canvas2.width = img.width;
			canvas2.height = img.height;
			var ctx2 = canvas2.getContext('2d');
			ctx2.drawImage(img, 0, 0);
			ctx.drawImage(canvas2, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
		}
		img.src="test.png"; // <---- use big image file
	</script>
</body>
</html>

 

 If "test.png" has a resolution: 4000x2000 everything it's ok, but if resolution is 6000x3000 there is a problem with width of picture, something like scaled to about 5500x3000. 

Maybe Z10's browser has a bug. Has anyone encountered anything like this problem?  I know, there is a technique with map tiles, but i don't have a time for big changes in my game. 

 

Thx for help/discussion.

Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: Problem with copying from one canvas to another - weird width

[ Edited ]

Hi there, I've been digging into this and have found some information but am still not sure why the break occurs. I'll base my discussion on the following code sample I've been using.

 

<!DOCTYPE html>
<html>
<head>
	<title>Canvas</title>
		
	<style type="text/css">
		#easel {
			position: fixed;
			left: 0px; right: 0px; top: 0px; bottom: 0px;
		}
			
		#target {
			width: 100%; height: 100%;
		}
	</style>
</head>
<body>
	<div id="easel">
		<canvas id="target"></canvas>
	</div>
		
	<script type="text/javascript">
		var target, image, source;

		target = {};
		target.canvas = document.querySelector('#target');
		target.context = target.canvas.getContext('2d');
			
		image = document.createElement('img');
		image.addEventListener('load', function () {
			target.canvas.width = window.innerWidth;
			target.canvas.height = window.innerHeight;
				
			/* Only needed if (A) is uncommented below. */
			source = {};
			source.canvas = document.createElement('canvas');
			source.canvas.width = image.width;
			source.canvas.height = image.height;
			source.context = source.canvas.getContext('2d');
			source.context.drawImage(image, 0, 0);
				
			/* Uncomment one of the following. */
			/* (A) */ //target.context.drawImage(source.canvas, 0, 0, target.canvas.width, target.canvas.height, 0, 0, target.canvas.width, target.canvas.height);
			/* (B) */ target.context.drawImage(image, 0, 0, target.canvas.width, target.canvas.height, 0, 0, target.canvas.width, target.canvas.height);
		}, false);
		image.src='img/7335x4598.png';
	</script>
</body>
</html>

If I call drawImage on the image directly, everything is scaled properly.

 

The issue occurs from the process of copying the image to a second (source) canvas and then attempting to draw source to target.

 

So, in the above code, if we comment out (B) and uncomment (A), everything will look okay on your PC but it will be squished horizontally on the BlackBerry 10 device. I have a feeling this is related to window.devicePixelRatio returning 1.0 on the PC and 1.8625 on the device, but I am not exactly sure how to accomodate for this behaviour.

 

Now, the reason it is squished can be seen by modifying (A) to:

 

target.context.drawImage(source.canvas, 0, 0, target.canvas.width, target.canvas.height);

If you do this, you will notice that there is a lot of extra white space that seems to be squishing everything in; thus when we actually use this canvas to get data from, our image has already been squished. Image attached.

 

 

IMG_00000007.png

 

 

The light blue border was added to show the actual dimensions of the screen; the target canvas takes up 100% of the screen. As you can see, the process of copying to the source canvas has introduced a lot of white space for some reason.

 

The squish issue then (from what I can tell) is originating from this code section.

 

			/* Only needed if (A) is uncommented below. */
			source = {};
			source.canvas = document.createElement('canvas');
			source.canvas.width = image.width;
			source.canvas.height = image.height;
			source.context = source.canvas.getContext('2d');
			source.context.drawImage(image, 0, 0);

 

It is either in the way the canvas dimensions are being assigned (maybe we need to manually account for the devicePixelRatio) or in how the drawImage call is being used (again, maybe something needs to be accounted for.) What that something is, I don't know just yet.

 

 

In your scenario then, is it at all possible to simply use the image as the source for your drawImage call? (i.e. avoid drawing it to the 2nd canvas and using that canvas as the source altogether.)


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: Problem with copying from one canvas to another - weird width

[ Edited ]

I believe I have found it (it is scaling properly in my case anyways) and it was related to the difference in window.devicePixelRatio reported by the PC (1.0) and the device (1.8625).

 

Here is the code that works for me (note the source canvas adjustment, and then the modification to the drawImage call to use the modified source canvas dimensions.

 

<!DOCTYPE html>
<html>
<head>
	<title>Canvas</title>
		
	<style type="text/css">
		#easel {
			position: fixed;
			left: 0px; right: 0px; top: 0px; bottom: 0px;
			overflow: scroll;
		}
			
		#target {
			width: 100%; height: 100%;
		}
	</style>
</head>
<body>
	<div id="easel">
		<canvas id="target"></canvas>
	</div>
		
	<script type="text/javascript">
		var target, image, source;

		target = {};
		target.canvas = document.querySelector('#target');
		target.context = target.canvas.getContext('2d');
			
		image = document.createElement('img');
		image.addEventListener('load', function () {
			target.canvas.width = window.innerWidth;
			target.canvas.height = window.innerHeight;
				
			/* Only needed if (A) is uncommented below. */
			source = {};
			source.canvas = document.createElement('canvas');
			source.canvas.width = image.width * (1.0 / window.devicePixelRatio);
			source.canvas.height = image.height * (1.0 / window.devicePixelRatio);
			source.context = source.canvas.getContext('2d');
			source.context.drawImage(image, 0, 0, image.width, image.height, 0, 0, source.canvas.width, source.canvas.height);
				
			/* Uncomment one of the following. */
			/* (A) */ target.context.drawImage(source.canvas, 0, 0, target.canvas.width, target.canvas.height, 0, 0, target.canvas.width, target.canvas.height);
			/* (B) */ // target.context.drawImage(image, 0, 0, target.canvas.width, target.canvas.height, 0, 0, target.canvas.width, target.canvas.height);
		}, false);
		image.src='img/7335x4598.png';
	</script>
</body>
</html>

 


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.
New Contributor
Posts: 2
Registered: ‎11-03-2013
My Device: Z10 LE
My Carrier: Private

Re: Problem with copying from one canvas to another - weird width

Thx Eric for your time and help. Well I just shrunk the image to the 4000x2000 and it works. This weekend i'll try your modification, but i'm use this code in <head> section:

 

<script>
		var meta = document.createElement("meta");
		meta.setAttribute('name','viewport');
		meta.setAttribute('content','initial-scale='+ (1/window.devicePixelRatio) + ',user-scalable=no');
		document.getElementsByTagName('head')[0].appendChild(meta);
    </script>

 so maybe this is not correct solution for me.

 

I searched a lot for solution and I found the posts in which people describe similar problems with iPhone. Example: http://stackoverflow.com/questions/12554947/mobile-safari-renders-img-src-dataimage-jpegbase64-scale... or https://github.com/blueimp/JavaScript-Load-Image/issues/13

 

They call this problem subsampling and I think it's a webkit problem in retina's display.

Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: Problem with copying from one canvas to another - weird width

[ Edited ]

I just tested and the changes I noted work with the viewport modification as well.

The only difference is that more content is displayed in the canvas because it is now being stretched to a larger viewport (~1280x720) as opposed to the base, reference resolution (~640x320).

Don't quote me on that last number but it is something around there. Reference resolutions are weird :-) The in-depth explanation is here:

http://supportforums.blackberry.com/t5/Web-and-WebWorks-Development/How-to-set-up-the-viewport-for-a...

 

The main thing is that with the noted changes, you should be able to get an un-skewed image across all devices, regardless of what window.devicePixelRatio returns.


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.