/** * @module Core * @namespace springroll */ (function() { var ApplicationPlugin = include('springroll.ApplicationPlugin'); var devicePixelRatio = include('devicePixelRatio', false); /** * @class Application */ var plugin = new ApplicationPlugin(100); /** * Dom element (or the window) to attach resize listeners and read the size from * @property {DOMElement|Window|null} _resizeElement * @private * @default null */ var _resizeElement = null; /** * The maximum width of the primary display, compared to the original height. * @property {Number} _maxWidth * @private */ var _maxWidth = 0; /** * The maximum height of the primary display, compared to the original width. * @property {Number} _maxHeight * @private */ var _maxHeight = 0; /** * The original width of the primary display, used to calculate the aspect ratio. * @property {int} _originalWidth * @private */ var _originalWidth = 0; /** * The original height of the primary display, used to calculate the aspect ratio. * @property {int} _originalHeight * @private */ var _originalHeight = 0; /** * A helper object to avoid object creation each resize event. * @property {Object} _resizeHelper * @private */ var _resizeHelper = { width: 0, height: 0, normalWidth: 0, normalHeight: 0 }; /** * The timeout when the window is being resized * @property {springroll.DelayedCall} _windowResizer * @private */ var _windowResizer = null; // Init the animator plugin.setup = function() { var options = this.options; /** * Fired when a resize is called * @event resize * @param {int} width The width of the resize element * @param {int} height The height of the resize element */ /** * If doing uniform resizing, optional parameter to add * a maximum width relative to the original height. This * allows for "title-safe" responsiveness. Must be greater * than the original width of the canvas. * @property {int} options.maxWidth */ options.add('maxWidth', 0); /** * If doing uniform resizing, optional parameter to add * a maximum height relative to the original width. This * allows for "title-safe" responsiveness. Must be greater * than the original height of the canvas. * @property {int} options.maxHeight */ options.add('maxHeight', 0); /** * Whether to resize the displays to the original aspect ratio * @property {Boolean} options.uniformResize * @default true */ options.add('uniformResize', true); /** * If responsive is true, the width and height properties * are adjusted on the `<canvas>` element. It's assumed that * responsive applications will adjust their own elements. * If responsive is false then the style properties are changed. * @property {Boolean} options.responsive * @default false */ options.add('responsive', false, true); /** * The element that the canvas is resized to fit. * @property {DOMElement|String} options.resizeElement * @default 'frame' */ options.add('resizeElement', 'frame', true); /** * Whether to account for devicePixelRatio when rendering game * @property {Boolean} options.enableHiDPI * @default false */ options.add('enableHiDPI', false); options.on('maxWidth', function(value) { _maxWidth = value; }); options.on('maxHeight', function(value) { _maxHeight = value; }); // Handle when a display is added, only do it once // in order to get the main display this.once('displayAdded', function(display) { _originalWidth = display.width; _originalHeight = display.height; if (!_maxWidth) _maxWidth = _originalWidth; if (!_maxHeight) _maxHeight = _originalHeight; }); /** * The current width of the application, in real point values * @property {int} realWidth */ this.realWidth = 0; /** * The current height of the application, in real point values * @property {int} realHeight */ this.realHeight = 0; /** * Fire a resize event with the current width and height of the display * @method triggerResize */ this.triggerResize = function() { if (!_resizeElement) return; // window uses innerWidth, DOM elements clientWidth _resizeHelper.width = (_resizeElement.innerWidth || _resizeElement.clientWidth) | 0; _resizeHelper.height = (_resizeElement.innerHeight || _resizeElement.clientHeight) | 0; this.calculateDisplaySize(_resizeHelper); // round up, as canvases require integer sizes // and canvas should be slightly larger to avoid // a hairline around outside of the canvas var width = this.realWidth = _resizeHelper.width; var height = this.realHeight = _resizeHelper.height; var normalWidth = _resizeHelper.normalWidth; var normalHeight = _resizeHelper.normalHeight; var responsive = this.options.responsive; var enableHiDPI = this.options.enableHiDPI; //resize the displays this.displays.forEach(function(display) { if (responsive) { if (enableHiDPI && devicePixelRatio) { display.canvas.style.width = width + "px"; display.canvas.style.height = height + "px"; width *= devicePixelRatio; height *= devicePixelRatio; } // update the dimensions of the canvas display.resize(width, height); } else { // scale the canvas element display.canvas.style.width = width + "px"; display.canvas.style.height = height + "px"; if (enableHiDPI && devicePixelRatio) { normalWidth *= devicePixelRatio; normalHeight *= devicePixelRatio; } // Update the canvas size for maxWidth and maxHeight display.resize(normalWidth, normalHeight); } }); //send out the resize event this.trigger('resize', (responsive ? width : normalWidth), (responsive ? height : normalHeight)); //redraw all displays this.displays.forEach(function(display) { display.render(0, true); // force renderer }); }; /** * Handle the window resize events * @method onWindowResize * @protected */ this.onWindowResize = function() { // Call the resize once this.triggerResize(); // After a short timeout, call the resize again // this will solve issues where the window doesn't // properly get the "full" resize, like on some mobile // devices when pulling-down/releasing the HUD _windowResizer = this.setTimeout( function() { this.triggerResize(); _windowResizer = null; } .bind(this), 500 ); }; /** * Calculates the resizing of displays. By default, this limits the new size * to the initial aspect ratio of the primary display. Override this function * if you need variable aspect ratios. * @method calculateDisplaySize * @protected * @param {Object} size A size object containing the width and height of the resized container. * The size parameter is also the output of the function, so the size * properties are edited in place. * @param {int} size.width The width of the resized container. * @param {int} size.height The height of the resized container. */ this.calculateDisplaySize = function(size) { if (!_originalHeight || !this.options.uniformResize) return; var maxAspectRatio = _maxWidth / _originalHeight, minAspectRatio = _originalWidth / _maxHeight, originalAspect = _originalWidth / _originalHeight, currentAspect = size.width / size.height; if (currentAspect < minAspectRatio) { //limit to the narrower width size.height = size.width / minAspectRatio; } else if (currentAspect > maxAspectRatio) { //limit to the shorter height size.width = size.height * maxAspectRatio; } // Calculate the unscale, real-sizes currentAspect = size.width / size.height; size.normalWidth = _originalWidth; size.normalHeight = _originalHeight; if (currentAspect > originalAspect) { size.normalWidth = _originalHeight * currentAspect; } else if (currentAspect < originalAspect) { size.normalHeight = _originalWidth / currentAspect; } // round up, as canvases require integer sizes // and canvas should be slightly larger to avoid // a hairline around outside of the canvas size.width = Math.ceil(size.width); size.height = Math.ceil(size.height); size.normalWidth = Math.ceil(size.normalWidth); size.normalHeight = Math.ceil(size.normalHeight); }; // Do an initial resize to make sure everything is positioned correctly this.once('beforeInit', this.triggerResize); }; // Add common filters interaction plugin.preload = function(done) { var options = this.options; // Convert to DOM element options.asDOMElement('resizeElement'); if (options.resizeElement) { _resizeElement = options.resizeElement; this.onWindowResize = this.onWindowResize.bind(this); window.addEventListener("resize", this.onWindowResize); } done(); }; plugin.teardown = function() { if (_windowResizer) { _windowResizer.destroy(); _windowResizer = null; } if (_resizeElement) { window.removeEventListener("resize", this.onWindowResize); } _resizeElement = null; _resizeHelper.width = _resizeHelper.height = _resizeHelper.normalWidth = _resizeHelper.normalHeight = _originalWidth = _originalHeight = _maxHeight = _maxWidth = 0; }; }());