Thursday, August 25, 2016

HTML5 Canvas DrawImage Artifacts

I'm working on an HTML5 canvas game that requires smooth scrolling of images across the screen. The coordinates of the images are real numbers, not integers. The canvas can handle real number coordinates just fine and antialiases everything to make it look smooth. The problem is that it also sometimes produces some weird artifacts to be drawn.

What do I mean by artifacts? Artifacts are pixels that are drawn that you don't expect. In my case, for example, I have an image that has a significant amount of transparent pixels. When it's drawn at particular locations thin gray lines get drawn in some of the space where it should be transparent. It's not a lot, but it's noticeable.

So what can you do about it? There are a couple things, but they have their disadvantages. For one thing you can convert all of your coordinates to integers. One way to do this is with a little JavaScript trick; binary "or" the value with 0.

var x = 1.67;
x = x | 0; // x is now 1

That eliminates the artifacts because the images are drawn on whole pixel boundaries, so there's no need for the canvas to smooth out the image. The problem is that it makes your animations really choppy, especially if you have a lot of images scrolling next to each other.

Another thing I tried was to use Math.round() instead of just lopping off the fraction. I figured that would reduce the amount of choppiness. Unfortunately it didn't make much of a difference.

var x = 1.67;
x = Math.round(x); // x is now 2

But wait, there's one more. The canvas context has an imageSmoothingEnabled property you can set to true or false. By default it's true. I found that when you set it to false it's basically the same as using Math.round() above. It forces your images to be drawn on whole pixel boundaries. Which also produces choppiness.

context.imageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;

So now we're right back where we started. In the end I decided not to use any of these methods and just stick with the occasional artifact being drawn. It looks crappy, but it only seems to happen at certain screen locations. In my case having smooth animations was far more important than the occasional artifact.

I think in most cases the choppiness wouldn't be such an issue and one of these techniques would work. It's up to you to determine what looks best. I would go with using imageSmoothingEnabled property because then you don't have to add any extra code to convert to an integer. Let the system do the work for you.

Code hard!

Saturday, May 7, 2016

Testing TypeScript Modules with Jasmine

In my previous post I talked about using TypeScript/ES6 modules. I have been thinking about making the transition from namespaces to modules, but there were a few things I needed to work out first. First of all how to load them (native ES6 support isn't widely available at the time of this writing). In the previous post I talked about using a library called Require1k (http://requirejs.org/) as the module loader. As the name suggests it is only 1kb in size yet provides the basics you need for CommonJS module loading. So far it does everything I need.

The next thing I needed to work out was how to package up my application when it was ready for release. In that post I also talked about using WebPack in Node.js to combine and minify the application modules.

The final thing I needed to work out was how to get my Jasmine (http://jasmine.github.io/) unit tests to run against modules. This was giving me a lot of trouble; it's not as easy as you might think. Jasmine was built in such a way that it expects all of your files to be loaded using script tags, then it runs when the page onload event fires. Unfortunately when using a module loader things don't happen that way. The module loader doesn't load your modules until after the page is loaded.

So for the remainder of this post I'll show how I got my Jasmine tests to run using the Require1k module loader. Although I'm using a specific module loader there shouldn't be any problem using the same principles for any other CommonJS module loader library as they most all work the same way.

Creating the Unit Tests


The first thing we need to do is create unit tests. I won't go into how to write Jasmine tests. There are plenty of good examples on their web site. The only difference is that you will need to use import statements to reference the modules you want to test.

For example, say you want to test module1.ts. Then your unit tests might look something like this.

/// <reference path="../scripts/typings/jasmine/jasmine.d.ts" />
import * as Module1 from "./module1";
describe("When testing module1", () =>
{
    it("should be true when something happens", () =>
        expect(Module1.something()).toBeTruthy());
});

First we have a reference to the Jasmine type definition file (because as TS programmers we like to have better tooling and autocompletion). Then we import everything from module1. Then we define the Jasmine specs for the unit tests. It's that simple ;-).

One important thing to point out here: your unit tests are modules too. Once you decide to use modules everything needs to be a module. Our unit tests need to load the modules they test, therefore they have to be modules for the module loader to pick up the imports and load them.

The Bootstrap File


Now we need a bootstrap file. This is the main file that gets things going. We will call this file unit-tests.ts.

declare function require(s: string): void;
 
require("./module1.spec");
require("./module2.spec");
 
jasmine.getEnv().execute();

The first thing we did was to declare the require function. This is the function defined by the Require1k library (or any other library for loading CommonJS modules) to load a module file. Without this we would get errors from the compiler because it doesn't know what "require" is.

Next we use require to load all of the unit test modules. In this case we have unit tests for two different modules.

I like to name my unit test files with the name of the module it's testing and a ".spec.ts" extension. This way you know exactly which module it's for and you know it's a Jasmine test file (Note: unit tests are known as specs in Jasmine).

The last line is necessary to tell Jasmine to start running the tests. As I stated above, Jasmine will look for any unit tests and run them on page load. But since this is all happening after page load we have to explicitly tell it to run again.

You might be asking yourself: why not use import statements to load all of the unit test files? That's a valid question. The unit tests are modules, I said so previously. The answer is: because nothing is being exported from the unit test modules. All they do is define Jasmine specs. Therefore if you tried to import them the TypeScript compiler would see there's nothing being exported and just skip it. Then your unit tests wouldn't load and you would be wondering what's going on (not that I'm speaking from experience or anything like that).

The Host File


The final thing we need to do is set up the host HTML file to run the unit tests. It will have all of the files for jasmine, of course. Then it will need the script tag for Require1k.

<link href="../Content/jasmine/jasmine.css" rel="stylesheet" />
<script src="../Scripts/jasmine/jasmine.js"></script>
<script src="../Scripts/jasmine/jasmine-html.js"></script>
<script src="../Scripts/jasmine/boot.js"></script>
 
<script src="require1k.js" data-main="./unit-tests"></script>

The "data-main" attribute tells Require1k what the main or start file is. In this case unit-tests.js which we created above. This will define the starting point of the module loader. From there it will load the unit test modules which will in turn load the modules they are testing.

Conclusion


The trick to testing external modules with Jasmine is to have a single bootstrap file that loads all of the unit test files and to tell the module loader where to find it. Then the key to making it work is to tell Jasmine to run again after all of the tests and modules have been loaded.

Switching from internal namespaces to external modules in TypeScript requires a whole new way of looking at things and some new ways of doing things that you're not used to. You just have to learn a few new tricks to get it to work across the board from your source code to your unit tests.

I think in the end using modules is the way of the future for TypeScript, and JavaScript. Once ES6 is fully supported by all browsers and able to provide native module loading things will be a lot easier and modular JS will become more popular.

<jmg/>

Wednesday, April 6, 2016

Packaging Web Apps with Node.js

There comes a time when you're at the end of developing your awesome TypeScript/JavaScript web app that you need to think about releasing it into the wild. If you've been using good programming practices you should have split your app into multiple files to make it easier to manage and maintain. Only problem is, it's not a good practice to serve up a ton of files when the user runs your app. The best practice in this scenario is to package up your JavaScript files into one file and only serve that one file.

In this post I will show you how to use TypeScript/ES6's module loading system and Node.js to make it easy to package your web app's files into one file for release while allowing you to develop without packaging. We will use TypeScript's module system to set up file dependencies. Then we will use Require.js to load those modules in the browser. Finally we will use Webpack to package up all of the files into a single JS file and compress it for release.

Prerequisites: I'm assuming you know TypeScript and Node.js basics, but even if you don't you should be able to understand the concepts and use them as a jumping off point to learn more.

The Modules


First of all lets look at how external modules work in TypeScript/ES6. For this example we are going to create three separate TS files, each of which depends on the next one. Two of the files will be modules and the other will be the main application file.

The first file module2.ts exports a class named MyClass2 with a public method getText().

export class MyClass2
{
    public getText(): string
    {
        return "Hello from module 2";
    }
}

Nothing special yet. We just have a class with a method.

The next file is module1.ts. It is a bit more interesting.

import * as module2 from "./module2";
 
export class MyClass1
{
    public getText(): string
    {
        let c = new module2.MyClass2();
        return "Hello from module 1 " + c.getText();
    }
}

At the top of the file we import our module2 module that was defined in module2.ts. Now this file depends on module2.ts. This allows us to use the exported members of module2.ts in module1.ts. This syntax follows the ES6 standard for importing modules.

Next we define the contents of module1. We export a class called MyClass1. In the getText() of this class it creates and instance of MyClass2 from module2 then calls its getText() method and concatenates the messages together.

That's how we do external modules in TypeScript and ES6. Pretty simple, right?

Now we need a main app file for our starting point, which in this case is app.ts.

import {MyClass1} from "./module1";
 
namespace WebpackModules
{
    export class MyApp
    {
        constructor()
        {
            let c1 = new MyClass1();
            var el = document.getElementById('content');
            el.innerText = "MyApp started " + c1.getText();
 
        }
    }
}
 
var app = new WebpackModules.MyApp();

We begin with an import of module1.ts. Now this file depends on module1.ts and by association module2.ts. Notice that the import is a little different from the previous one. Instead of importing everything from module1.ts and assigning a name for the module, we are only importing the MyClass1 class.

Next we wrap the MyApp class in a namespace just because this is what I would do in a real app to keep the global scope clean. If you're not familiar with it, namespace is the new keyword to create internal modules in TypeScript and is equivalent to the old keyword of module.

Inside the namespace we export the main application class, MyApp, so we can use it outside of the namespace. Inside the constructor is where we use the MyClass1 that we imported. We create a new instance of MyClass1, then call getText() on that object and output it to the web page.

The Script Tag


Now we need to set up our web page and get a module loader that can load the modules for us. At this time most browsers don't support the loading of modules using the ES6 specification. Therefore we are going to have to use something else. A well known module loading framework is RequireJS (http://requirejs.org/). So let's use that.

In order to use RequireJS we need to tell the TypeScript compiler which kind of package manager we are using. RequireJS implements the AMD standard so we must tell the TS compiler to use AMD. If you're in Visual Studio you can change it in the project properties. Otherwise change it in the tsconfig.json file ("module": "amd"). The TypeScript compiler will output the correct code that works with the package manager of your choice.

In the html file we only need one script tag that references the require.js file.

<script src="../Scripts/require.js" data-main="app"></script>


Notice that it has a data attribute called data-main. This is where you tell it what file is your entry point. In this case it's app.js, or just app (you don't need to specify the file extension). When the web page is loaded Require will load app.js first, then fulfill all of the imports specified inside the application's modules (module1.js and module2.js).

At this point the application is running and it is loading all the files separately. This great for our development environment. If all our files were packaged up in development it would make it a lot harder to debug.

Packaging the App


When it's time to release the app we need to package it up. For this we will be using a Node package called Webpack. You can easily install it using "npm install webpack -g". Then you can execute it from the command line telling it where your entry point file is and where to save the packaged file.

$ webpack ./src/app.js ./app.package.js


Here we tell it to start with app.js and save the result to app.package.js. Webpack will go through all of the imports just like Require did and load all the dependencies then save all of the code in the correct order in the output file along with any code it needs to bootstrap the app.

At this point you can change the require.js script tag to set data-main="app.package.js" and the application should run. Congrats, you now have a packaged up web application.

One thing to note about using Require, it's a very comprehensive library and therefore not a small file. The minified version is about 85kb. So you're making the user download 85kb just to run your app. If you don't need all of that functionality there is another, much smaller option, Require1k.

Require1k is a minimal library for loading CommonJS modules. If all you want to do is use modules in a web application it's perfect. And, as you can tell from the name, the file is only 1kb. That is a BIG difference. If you can use it instead you probably should.

To use Require1k we will need to change the TS compiler module type option to CommonJS ("module": "commonjs"). Other than that it works exactly the same. The script tag would look like this now:

<script src="require1k.js" data-main="./app"></script>


The only thing that changed was the name of the source file. From here we can use webpack just as we did before and everything should run, but with only 1k of bootstrap code.

Bonus Points: Minification


OK, all of our JS files are packaged up into one file. That's great but it could be better. We could minify the file to make it as small as possible. To do that we can use a Node package called Uglify. Install it using "npm install uglify-js -g".

It's very simple to use. Just point it at the file you want to minify.

$ uglifyjs ./app.package.js -o ./release/app.js -c -m


Use the -o option to specify where to save the minified file to. The -c option tells it to compress. The -m option tells it to mangle names which will rename everything it can to single letter names for more space savings.

Conclusion


Here we have seen how to use external modules in TypeScript/ES6 and how to use Require to load modules in the browser. Then we learned how to use the Node webpack tool to help us package up our TypeScript app for release while keeping them unpackaged for development. Then we seen how to use uglify to compress our application's code.