Scaling JavaScript animation without blurring

Hi,

With help some time ago, an AS3 animation (for an eLearning lesson) was ported to JS. Because of the scaling, it displays in browsers as blurry. I think the problem is that the canvas drawing is using 1X1 rectangles, when they should be 8X8. Also, there are mis-matches between canvas size in the JS, CSS, index files. Canvas should be 640X640.

I have tried to fix this but with no success and would appreciate any help getting it sized correctly and displaying clearly.

There are 3 small files (index.html, style.css and src.js) and the link is: http://elearningprojects.com/websample1/index.html

Thank you for any help.

Kind Regards,
writer1

There’s a new CSS property called image-rendering that might solve the problem for you.


image-rendering: optimize-contrast;

It’s designed to help fix such pixel-rendering issues.

So far, the most compatible use that I’ve seen of it is with this:


canvas {
    image-rendering: optimizeSpeed;             // Older versions of FF
    image-rendering: -moz-crisp-edges;          // FF 6.0+
    image-rendering: -webkit-optimize-contrast; // Webkit
                                                //  (Safari now, Chrome soon)
    image-rendering: -o-crisp-edges;            // OS X & Windows Opera (12.02+)
    image-rendering: optimize-contrast;         // Possible future browsers.
    -ms-interpolation-mode: nearest-neighbor;   // IE
}

Hi Paul,

Thank you for your reply. I had found this information earlier and tried it without success.

I suspect that the problem is that the script is using scaling which causes blurring. (I am a beginner and don’t fully understand the script. A few years ago, someone had helped with the script-no longer available to help). I think that it is trying to build the animation with 1X1 rectangles and then scale them up (8X) to the canvas size. Instead, I think that it would solve the scaling/blurring problem if it started with 8X8 rectangles. But, I don’t know how to re-write this to accomplish the change. Also, the canvas size is different in 2 files (style.css and index.html) : 640X640 (correct size) in one and 80X80 in the other. Simply changing these has also not been successful in solving the problem. So, I’m stuck, need some additional help to get it working without blurring.

Any help re-writing to avoid scaling, match up canvas sizes, would be appreciated.

Kind Regards,

writer1

No - the problem in this case is that CSS is being used to stretch the canvas, so the web browser automatically interpolates the image which blurs it.
Do not use CSS to make the canvas bigger. Using CSS to make the width and height bigger is directly causing your problem.

So far as a solution goes, the canvas has a scale command.
Here are a couple of examples that demonstrate how the pixel art can be scaled up without smoothing by applying a custom scale command to the canvas:

Hi Paul,

Thank you for this explanation which narrows down the problem.

I took a look at these examples. But, I’m not sure how to fix the CSS. Currently, it is:

canvas{
border:1px solid black;
height:640px;
width:640px;
}

This seems to be specifying the width and height? So, I’m not sure what to change? (:

writer1

Remove the bloody width and height parts from the CSS. They are badly scaling up the canvas, which is causing your unwanted blurry look.
Instead of using CSS, use a larger canvas in the HTML, and from the JavaScript scale up the context that JavaScript uses on the canvas.

I’m going to bed - good luck :slight_smile:

Thanks, Paul.

Apologies for my not understanding fully. I will try to get it right.

Kind Regards,

writer1

I looked at a few possible solutions, and found that even when using a correct technique, that it leaves out browsers such as Internet Explorer:


ctx.webkitImageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.scale(8, 8);

See demo at http://jsfiddle.net/saviski/pGs4f/12/

So instead of doing that type of thing, it’s time to do it the old-fashioned way. I’ve put together a drawAtScale function instead, which also requires that a buffered work space is used, so that it can then be scaled to whatever size the target canvas is.


    function init() {
        buffer = document.createElement('canvas');
        buffer.width = 80;
        buffer.height = 80;
        bufferCtx = buffer.getContext("2d");
        canvas = document.querySelector("canvas");
        displayCtx = canvas.getContext("2d");
        ...
}


function drawAtScale() {
    var width = buffer.width,
        height = buffer.height,
        xScale = canvas.width / width,
        yScale = canvas.height / height,
        i,
        pixelDataSize = width * height;
    for (i = 0; i < pixelDataSize; i += 1) {
        displayCtx.fillStyle = "rgb(" + px.data[i * 4] + ", " + px.data[i * 4 + 1] + ", " + px.data[i * 4 + 2] + ")";
        displayCtx.fillRect((i % width) * xScale, (i / height | 0) * yScale, xScale, yScale);
    }
}

I’ve also reworked some of it to be clearer, and to allow you to easily change the buffer width and height from 80x80 to any other dimension you might wish to experiment with, or the canvas width and height in the HTML to anything you may desire.

You can see it working in action at http://jsfiddle.net/pmw57/as4UR/

Hi Paul,

Spent the day at it, but not with such an excellent result as you provided above. Impressive!

I tested in FF and IE, and it works in both on the desktop.

When I uploaded it and tried it using Chrome on an Android device, got a blank screen. (Ugh)

Also because it is constantly refreshing, when viewed in FF on an Android device, it stays at full screen even if pinched (it will get smaller while pinched and held, but once you stop pinching/touching the screen, it resumes its full screen display). So, I’ll keep trying to dissect the script, see if I can apply any fixes for these, especially the full screen issue.

Again, thank you very much for your help. Brilliant!

Kind Regards,

writer1

Hi,

I’ve been researching online about cancelling full screen mode and found some script:


function cancelFullscreen() {
  if(document.cancelFullScreen) {
    document.cancelFullScreen();
  } else if(document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
  } else if(document.webkitCancelFullScreen) {
    document.webkitCancelFullScreen();
  }
}

cancelFullscreen();

Tried adding this to the JS, but so far when I view on a mobile FF browser, will not cancel full screen even with this script. I think the constant refreshing keeps causing the window to go to full screen?

I’ll keep trying to find a solution.

OK, adding the following to the HTML seems to solve the full screen problem: :slight_smile:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

Now, I need to figure out how to center the canvas in the middle of the screen on any device? It is currently displaying at 0,0.

Any help appreciated.

writer1

Resolved: :slight_smile:

canvas{
    border:1px solid black;
	position: absolute;
  	top: 50%;
  	left: 50%;
  	margin-left: -320px;
  	margin-top: -320px;
}