• BrowserWindow.js

  • ¶
    var Platform = require('./Platform');
    var Log = require('./Log');
    var merge = require('merge');
    
    var requestAnimFrameFps = 60;
    
    if (Platform.isBrowser) {
      window.requestAnimFrame = function() {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) {
          window.setTimeout(callback, 1000 / requestAnimFrameFps);
        };
      }();
    }
    var eventListeners = [];
    function fireEvent(eventType, event) {
      for (var i = 0; i < eventListeners.length; i++) {
        if (eventListeners[i].eventType == eventType) {
          eventListeners[i].handler(event);
        }
      }
    }
    
    function registerEvents(canvas, win) {
      makeMouseDownHandler(canvas, win);
      makeMouseUpHandler(canvas, win);
      makeMouseDraggedHandler(canvas, win);
      makeMouseMovedHandler(canvas, win);
      makeScrollWheelHandler(canvas, win);
      makeTouchDownHandler(canvas, win);
      makeTouchUpHandler(canvas, win);
      makeTouchMoveHandler(canvas, win);
      makeKeyDownHandler(canvas, win);
      makeWindowResizeHandler(canvas, win);
    }
    
    function makeMouseDownHandler(canvas, win) {
      canvas.addEventListener('mousedown', function(e) {
        fireEvent('leftMouseDown', {
          x: (e.offsetX || e.layerX || e.clientX - e.target.offsetLeft) * win.settings.highdpi,
          y: (e.offsetY || e.layerY || e.clientY - e.target.offsetTop) * win.settings.highdpi,
          option: e.altKey,
          shift: e.shiftKey,
          control: e.ctrlKey
        });
      });
    }
    
    function makeMouseUpHandler(canvas, win) {
      canvas.addEventListener('mouseup', function(e) {
        fireEvent('leftMouseUp', {
          x: (e.offsetX || e.layerX || e.clientX - e.target.offsetLeft) * win.settings.highdpi,
          y: (e.offsetY || e.layerY || e.clientY - e.target.offsetTop) * win.settings.highdpi,
          option: e.altKey,
          shift: e.shiftKey,
          control: e.ctrlKey
        });
      });
    }
    
    function makeMouseDraggedHandler(canvas, win) {
      var down = false;
      var px = 0;
      var py = 0;
      canvas.addEventListener('mousedown', function(e) {
        down = true;
        px = (e.offsetX || e.layerX || e.clientX - e.target.offsetLeft) * win.settings.highdpi;
        py = (e.offsetY || e.layerY || e.clientY - e.target.offsetTop) * win.settings.highdpi;
      });
      canvas.addEventListener('mouseup', function(e) {
        down = false;
      });
      canvas.addEventListener('mousemove', function(e) {
        if (down) {
          var x = (e.offsetX || e.layerX || e.clientX - e.target.offsetLeft) * win.settings.highdpi;
          var y = (e.offsetY || e.layerY || e.clientY - e.target.offsetTop) * win.settings.highdpi;
          fireEvent('mouseDragged', {
            x: x,
            y: y,
            dx: x - px,
            dy: y - py,
            option: e.altKey,
            shift: e.shiftKey,
            control: e.ctrlKey
          });
          px = x;
          py = y;
        }
      });
    }
    
    function makeMouseMovedHandler(canvas, win) {
      canvas.addEventListener('mousemove', function(e) {
        fireEvent('mouseMoved', {
          x: (e.offsetX || e.layerX || e.clientX - e.target.offsetLeft) * win.settings.highdpi,
          y: (e.offsetY || e.layerY || e.clientY - e.target.offsetTop) * win.settings.highdpi,
          option: e.altKey,
          shift: e.shiftKey,
          control: e.ctrlKey
        });
      });
    }
    
    function makeScrollWheelHandler(canvas, win) {
      var mousewheelevt = /Firefox/i.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel';
      document.addEventListener(mousewheelevt, function(e) {
        fireEvent('scrollWheel', {
          x: (e.offsetX || e.layerX) * win.settings.highdpi,
          y: (e.offsetY || e.layerY) * win.settings.highdpi,
          dy: e.wheelDelta / 10 || -e.detail / 10,
          option: e.altKey,
          shift: e.shiftKey,
          control: e.ctrlKey
        });
      });
    }
    var lastTouch = null;
    function makeTouchDownHandler(canvas, win) {
      canvas.addEventListener('touchstart', function(e) {
        lastTouch = {
          clientX: e.touches[0].clientX * win.settings.highdpi,
          clientY: e.touches[0].clientY * win.settings.highdpi
        };
        var touches = Array.prototype.slice.call(this, e.touches).map(function(touch) {
          touch.x = touch.clientX * win.settings.highdpi;
          touch.y = touch.clientY * win.settings.highdpi;
          return touch;
        });
        fireEvent('leftMouseDown', {
          x: e.touches[0].clientX * win.settings.highdpi,
          y: e.touches[0].clientY * win.settings.highdpi,
          option: false,
          shift: false,
          control: false,
          touches: touches
        });
      });
    }
    
    function makeTouchUpHandler(canvas, win) {
      canvas.addEventListener('touchend', function(e) {
        var touches = Array.prototype.slice.call(this, e.touches).map(function(touch) {
          touch.x = touch.clientX * win.settings.highdpi;
          touch.y = touch.clientY * win.settings.highdpi;
          return touch;
        });
        fireEvent('leftMouseUp', {
          x: lastTouch ? lastTouch.clientX : 0,
          y: lastTouch ? lastTouch.clientY : 0,
          option: false,
          shift: false,
          control: false,
          touches: touches
        });
        lastTouch = null;
      });
    }
    
    function makeTouchMoveHandler(canvas, win) {
      canvas.addEventListener('touchmove', function(e) {
        e.preventDefault();
        lastTouch = {
          clientX: e.touches[0].clientX * win.settings.highdpi,
          clientY: e.touches[0].clientY * win.settings.highdpi
        };
        var touches = Array.prototype.slice.call(this, e.touches).map(function(touch) {
          touch.x = touch.clientX * win.settings.highdpi;
          touch.y = touch.clientY * win.settings.highdpi;
          return touch;
        });
        fireEvent('mouseDragged', {
          x: e.touches[0].clientX * win.settings.highdpi,
          y: e.touches[0].clientY * win.settings.highdpi,
          option: false,
          shift: false,
          control: false,
          touches: touches
        });
        return false;
      });
    }
    
    function makeKeyDownHandler(canvas, win) {
      var timeout = 0;
      window.addEventListener('keydown', function(e) {
        timeout = setTimeout(function() {
          fireEvent('keyDown', {
            str: '',
            keyCode: e.keyCode,
            option: e.altKey,
            shift: e.shiftKey,
            control: e.ctrlKey
          }, 1);
        });
      });
      window.addEventListener('keypress', function(e) {
        if (timeout) {
          clearTimeout(timeout);
          timeout = 0;
        }
        fireEvent('keyDown', {
          str: String.fromCharCode(e.charCode),
          keyCode: e.keyCode,
          option: e.altKey,
          shift: e.shiftKey,
          control: e.ctrlKey
        });
      });
    }
    
    function makeWindowResizeHandler(canvas, win) {
      window.addEventListener('resize', function(e) {
        var width = window.innerWidth;
        var height = window.innerHeight;
    
        if (win.settings.fullscreen) {
          canvas.width = width * win.settings.highdpi;
          canvas.height = height * win.settings.highdpi;
          canvas.style.width = width + 'px';
          canvas.style.height = height + 'px';
    
          win.width = width * win.settings.highdpi;
          win.height = height * win.settings.highdpi;
        }
    
        fireEvent('resize', { width: width, height: height });
      });
    }
    
    function simpleWindow(obj) {
      var canvas = obj.settings.canvas;
      if (obj.settings.fullscreen) {
        obj.settings.width = window.innerWidth;
        obj.settings.height = window.innerHeight;
      }
      if (!canvas) {
        canvas = document.getElementById('canvas');
      }
      else if (obj.settings.width && obj.settings.height) {
        canvas.width = obj.settings.width;
        canvas.height = obj.settings.height;
      }
      else {
        obj.settings.width = canvas.width;
        obj.settings.height = canvas.height;
      }
      if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.width = obj.settings.width;
        canvas.height = obj.settings.height;
      }
      if (window.devicePixelRatio == 2) {
        if (obj.settings.highdpi == 2) {
          canvas.width = obj.settings.width * 2;
          canvas.height = obj.settings.height * 2;
          canvas.style.width = obj.settings.width + 'px';
          canvas.style.height = obj.settings.height + 'px';
          obj.settings.width = canvas.width;
          obj.settings.height = canvas.height;
        }
      }
      else {
        obj.settings.highdpi = 1;
      }
    
      if (obj.settings.multisample) {
        canvas.msaaEnabled = true;
        canvas.msaaSamples = 2;
      }
    
      obj.width = obj.settings.width;
      obj.height = obj.settings.height;
      obj.canvas = canvas;
      canvas.style.backgroundColor = '#000000';
      function go() {
        if (obj.stencil === undefined)
          obj.stencil = false;
        if (obj.settings.fullscreen) {
          document.body.style.margin = '0';
          document.body.style.padding = '0';
          document.body.style.overflow = 'hidden';
        }
        var gl = null;
        var ctx = null;
        if (obj.settings.type == '3d') {
          try {
            gl = canvas.getContext('experimental-webgl', {
              antialias: true,
              stencil: obj.settings.stencil,
              premultipliedAlpha : obj.settings.premultipliedAlpha,
              preserveDrawingBuffer: obj.settings.preserveDrawingBuffer
            });
          }
          catch (err) {
            Log.error(err.message);
            return;
          }
          if (gl === null) {
            throw 'No WebGL context is available.';
          }
        }else if (obj.settings.type == '2d') {
          ctx = canvas.getContext('2d');
        }
        obj.framerate = function(fps) {
          requestAnimFrameFps = fps;
        };
        obj.on = function(eventType, handler) {
          eventListeners.push({
            eventType: eventType,
            handler: handler
          });
        };
        registerEvents(canvas, obj);
        obj.dispose = function() {
          obj.__disposed = true;
        };
        obj.gl = gl;
        obj.ctx = ctx;
        obj.init();
        function drawloop() {
          if (!obj.__disposed) {
            obj.draw();
            requestAnimFrame(drawloop);
          }
        }
        requestAnimFrame(drawloop);
      }
      if (!canvas.parentNode) {
        if (document.body) {
          document.body.appendChild(canvas);
          go();
        }else {
          window.addEventListener('load', function() {
            document.body.appendChild(canvas);
            go();
          }, false);
        }
      }
      else {
        go();
      }
      return obj;
    }
    
    var BrowserWindow = { simpleWindow: simpleWindow };
    
    module.exports = BrowserWindow;