craftyjs/Crafty — pull request #463 by mildmojo (2013-05-13 08:17:43+00:00)
Title: Add Crafty.viewport.absoluteScale()

### Resolution independence: The problem
I need my games to scale to fit the browser window, or at least select something close from a list of known good resolutions. Unfortunately, Crafty's viewport system is working against me.

### Crafty today
I can't figure out the use case for `Crafty.viewport.scale`. It doesn't work at all for my purposes. Where it applies a cumulative scale factor, I need to apply an absolute scale factor calculated from the window size. Additionally, Crafty resets the canvas transform all by itself when the scene changes or the browser is resized. I need to apply a scale factor that overrides everything else for the lifetime of the game.

### One solution
The existing `Crafty.viewport.scale` method applies the new scale as a multiplier against the old scale. This pull request adds a `Crafty.viewport.absoluteScale` method that sets the scale absolutely, regardless of the old scale. Calling `scale(0.5)` twice results in a scale of 0.25. Calling `absoluteScale(0.5)` twice results in a scale of 0.5. This is useful when scaling the stage in response to browser window resize events.

Unfortunately, this doesn't play nice with viewport panning in a mixed Canvas/DOM setting (see [fiddle](http://jsfiddle.net/JUxyE/2/)). It looks like setting `Crafty.viewport.x = 5` (or panning) moves DOM elements by 5 screen pixels and canvas elements by 5 scaled pixels, causing alignment problems. The viewport system is probably due for rethinking.

### Sample resizing code

Here's some sample code for a Crafty app that can scale the viewport in response to the browser window size ([fiddle here](http://jsfiddle.net/JUxyE/1/)):

```javascript
var Screen = { w: 800, h: 480 };

Crafty.init();
Crafty.canvas.init();

var scaler = function() {
var current = { w: Crafty.viewport.width,
h: Crafty.viewport.height };

// This will reset the scale when it adjusts the canvas element
// dimensions, so do it right before setting the scale we want.
Crafty.viewport.reload();

if ( current.w > current.h ) {
// Landscape, scale to fit height
Crafty.viewport.absoluteScale( current.h / Screen.h );
} else {
// Portrait, scale to fit width
Crafty.viewport.absoluteScale( current.w / Screen.w )
}
};

// Avoid drawing entities before we're ready to scale.
Crafty.removeEvent( Crafty, window, 'resize', Crafty.viewport.reload );

// Adjust scale to fit inside resized window.
Crafty.addEvent( Crafty, window, 'resize', scaler );

// Run the scaler after scene changes, since they reset the scale.
Crafty.bind( 'SceneChange', scaler );
```

### Discussion
Thoughts? Is there a better way to go about this? :dancer: