我正试图在javascript中手动编写一个dart演示。我在使用firebug和Chrome中类似的TypeError: this.canvas is undefined
类draw
函数中发现了一个奇怪的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;
答案 0 :(得分:2)
这就是问题所在。
window.requestAnimationFrame(this.draw);
当您将原始draw
方法传递到requestAnimationFrame
时,您会丢失SolarSystem
的上下文。例如,如果您在draw
中尝试此操作,则会返回true。
alert(this === window)
解决方案很简单,使用闭包来更改上下文。
prototype.requestRedraw = function(){
var self = this;
window.requestAnimationFrame(function () {self.draw()});
};
答案 1 :(得分:0)
如果您使用的是ES6,则可以使用箭头功能,它会使您的this
保持在范围内。
window.requestAnimationFrame(() => this.draw());
或者如果您使用的是setInterval
setInterval(() => app.draw(), 10);