4

我正在尝试用 javascript 手动编写一个飞镖演示。我收到一个奇怪的TypeError: this.canvas is undefined错误,该错误源于使用 firebug 的类中的draw函数和 chrome 中的类似错误。SolarSystem我无法弄清楚为什么会这样。

这是我在 JS Bin 中的代码的链接,因此您可以使用它。 http://jsbin.com/udujep/1/edit

为了后代,这里是完整的 javascript 代码:

var main, fpsAverage, showFps, Point, SolarSystem, PlanetaryBody;
main = function(){
  var solarSystem;
  solarSystem = new SolarSystem(document.getElementById('container'));
  solarSystem.start();
};
showFps = function(fps){
  if (fpsAverage != null) {
    fpsAverage = fps;
  }
  fpsAverage = fps * 0.05 + fpsAverage * 0.95;
  document.getElementById('notes').textContent = Math.round(fpsAverage) + ' fps';
};
Point = (function(){
  Point.displayName = 'Point';
  var prototype = Point.prototype, constructor = Point;
  function Point(x, y){
    var ref$;
    ref$ = [x, y], this.x = ref$[0], this.y = ref$[1];
  }
  return Point;
}());
SolarSystem = (function(){
  SolarSystem.displayName = 'SolarSystem';
  var prototype = SolarSystem.prototype, constructor = SolarSystem;
  prototype.canvas = null;
  prototype.renderTime = null;
  function SolarSystem(canvas){
    this.canvas = canvas;
  }
  prototype.start = function(){
    this.width = this.canvas.parentNode.clientWidth;
    this.height = this.canvas.parentNode.clientWidth;
    this.canvas.width = this.width;
    this._start();
  };
  prototype._start = function(){
    var earth, f, h, g, jupiter;
    this.sun = new PlanetaryBody(this, 'Sun', '#ff2', 14.0);
    this.sun.addPlanet(new PlanetaryBody(this, 'Mercury', 'orange', 0.382, 0.387, 0.241));
    this.sun.addPlanet(new PlanetaryBody(this, 'Venus', 'green', 0.949, 0.723, 0.615));
    earth = new PlanetaryBody(this, 'Earth', '#33f', 1.0, 1.0, 1.0);
    this.sun.addPlanet(earth);
    earth.addPlanet(new PlanetaryBody(this, 'Moon', 'gray', 0.2, 0.14, 0.075));
    this.sun.addPlanet(new PlanetaryBody(this, 'Mars', 'red', 0.532, 1.524, 1.88));
    this.addAsteroidBelt(this.sun, 150);
    f = 0.1;
    h = 1 / 1500.0;
    g = 1 / 72.0;
    jupiter = new PlanetaryBody(this, 'Jupiter', 'gray', 4.0, 5.203, 11.86);
    this.sun.addPlanet(jupiter);
    jupiter.addPlanet(new PlanetaryBody(this, 'Io', 'gray', 3.6 * f, 421 * h, 1.769 * g));
    jupiter.addPlanet(new PlanetaryBody(this, 'Europa', 'gray', 3.1 * f, 671 * h, 3.551 * g));
    jupiter.addPlanet(new PlanetaryBody(this, 'Ganymede', 'gray', 5.3 * f, 1070 * h, 7.154 * g));
    jupiter.addPlanet(new PlanetaryBody(this, 'Callisto', 'gray', 4.8 * f, 1882 * h, 16.689 * g));
    this.requestRedraw();
  };
  prototype.draw = function(){
    var time, context;
    time = Date.now();
    if (this.renderTime != null) {
      showFps(Math.round(1000 / (time - this.renderTime)));
    }
    this.renderTime = time;
    context = this.canvas.getContext('2d');
    this.drawBackground(context);
    this.drawPlanets(context);
    this.requestRedraw();
  };
  prototype.drawBackground = function(context){
    var x$;
    x$ = context;
    x$.fillStyle = 'white';
    x$.rect(0, 0, this.width, this.height);
    x$.fill();
  };
  prototype.drawPlanets = function(context){
    this.sun.draw(context, this.width / 2, this.height / 2);
  };
  prototype.requestRedraw = function(){
    window.requestAnimationFrame(this.draw);
  };
  prototype.addAsteroidBelt = function(body, count){
    var i$, radius;
    for (i$ = 0; i$ < count; ++i$) {
      radius = 2.06 + Math.random() * (3.27 - 2.06);
      body.addPlanet(new PlanetaryBody(this, 'asteroid', '#777', 0.1 * Math.random(), radius, radius * 2));
    }
  };
  prototype.normalizeOrbitRadius = function(r){
    return r * (this.width / 10.0);
  };
  prototype.normalizePlanetSize = function(r){
    return Math.log(r + 1) * (this.width / 100.0);
  };
  return SolarSystem;
}());
PlanetaryBody = (function(){
  PlanetaryBody.displayName = 'PlanetaryBody';
  var prototype = PlanetaryBody.prototype, constructor = PlanetaryBody;
  prototype.planets = [];
  function PlanetaryBody(solarSystem, name, color, bodySize, orbitRadius, orbitPeriod){
    orbitRadius == null && (orbitRadius = 0.0);
    orbitPeriod == null && (orbitPeriod = 0.0);
    this.solarSystem = solarSystem;
    this.name = name;
    this.color = color;
    this.orbitPeriod = orbitPeriod;
    this.bodySize = solarSystem.normalizePlanetSize(bodySize);
    this.orbitRadius = solarSystem.normalizeOrbitRadius(orbitRadius);
    this.orbitSpeed = prototype._calculateSpeed(orbitPeriod);
  }
  prototype.addPlanet = function(planet){
    this.planets.push(planet);
  };
  prototype.draw = function(context, x, y){
    var pos;
    pos = this._calculatePos(x, y);
    this.drawSelf(context, pos.x, pos.y);
    this.drawChildren(context, pos.x, pos.y);
  };
  prototype.drawSelf = function(context, x, y){
    var x$;
    x$ = context;
    x$.save();
    try {
      x$.lineWidth = 0.5;
      x$.fillStyle = this.color;
      x$.strokeStyle = this.color;
      if (this.bodySize >= 2.0) {
        x$.shadowOffsetX = 2;
        x$.shadowOffsetY = 2;
        x$.shadowBlur = 2;
        x$.shadowColor = '#ddd';
      }
      x$.beginPath();
      x$.arc(x, y, this.bodySize, 0, Math.PI * 2, false);
      x$.fill();
      x$.closePath();
      x$.stroke();
      x$.shadowOffsetX = 0;
      x$.shadowOffsetY = 0;
      x$.shadowBlur = 0;
      x$.beginPath();
      x$.arc(x, y, this.bodySize, 0, Math.PI * 2, false);
      x$.fill();
      x$.closePath();
      x$.stroke();
    } finally {
      x$.restore();
    }
  };
  prototype.drawChildren = function(context, x, y){
    var i$, ref$, len$, planet;
    for (i$ = 0, len$ = (ref$ = this.planets).length; i$ < len$; ++i$) {
      planet = ref$[i$];
      planet.draw(context, x, y);
    }
  };
  prototype._calculateSpeed = function(period){
    if (period === 0.0) {
      return 0.0;
    } else {
      return 1 / (60.0 * 24.0 * 2 * period);
    }
  };
  prototype._calculatePos = function(x, y){
    var angle;
    if (this.orbitSpeed === 0.0) {
      return new Point(x, y);
    } else {
      angle = this.solarSystem.renderTime * this.orbitSpeed;
      return new Point(this.orbitRadius * Math.cos(angle) + x, this.orbitRadius * Math.sin(angle) + y);
    }
  };
  return PlanetaryBody;
}());
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.onload = main;
4

2 回答 2

1

问题是这里的这条线。

window.requestAnimationFrame(this.draw);

发生的事情是,当您将原始draw方法传递给requestAnimationFrame您时,您会丢失SolarSystem. 例如,如果您尝试这样做,draw它将返回 true。

alert(this === window)

解决方案很简单,通过使用闭包来更改上下文。

prototype.requestRedraw = function(){
    var self = this;
    window.requestAnimationFrame(function () {self.draw()});
};
于 2012-11-09T06:17:38.267 回答
0

如果你使用 ES6

如果您使用的是 ES6,则可以使用箭头函数,它会保持您this的范围。

window.requestAnimationFrame(() => this.draw());

或者如果您使用 setInterval

setInterval(() => app.draw(), 10);
于 2017-01-16T20:41:57.763 回答