JavaScript原型继承和html画布 [英] JavaScript prototype inheritance and html canvas
问题描述
我是一名Ruby开发人员,他最终决定认真学习JavaScript。所以我购买了一些书籍,我开始潜入,但当我试图理解原型继承时,我很快陷入困境......
I'm a Ruby developer who finally decided to learn JavaScript seriously. So I purchased some books and I started to dive in, but I got stuck quickly when I tried to understand prototypal inheritance...
本书的一个例子是下列。
给定一个Shape,其原型有一个draw方法,以及两个子形状:一个Triangle和一个Rectangle,它继承自Shape;
One of the examples of the book is the following. Given a Shape which prototype has a draw method, and two child shapes: a Triangle and a Rectangle which prototype inherit from Shape;
- 当我在Triangle和Rectangle实例上调用draw函数时,该方法将正确绘制它们。
- 当我添加第二个方法来显示他们的名字时,每个实例都会正确记录它。
在我添加第三种填充形状的方法之前,一切都是完全可以理解的......只有最后一种方法才能填满。无论我打电话给哪一个。为什么?画布中有什么特别之处吗?
Everything was understandable perfectly until I added a third method to fill the shapes... And only the last one get filled. no matter which one I call. Why? Is there something special in canvas?
以下是练习的代码:
function Point(x, y) {
this.x = x;
this.y = y;
}
function Shape() {
this.points = [];
this.init();
}
Shape.prototype = {
constructor: Shape,
init: function() {
if (this.context === undefined) {
Shape.prototype.context = document.getElementById('canvas').getContext('2d');
};
if (this.name === undefined) {
Shape.prototype.name = 'generic shape'
}
},
draw: function() {
var i, ctx = this.context;
ctx.strokeStyle = 'rgb(0,0,255)';
ctx.beginPath();
ctx.moveTo(this.points[0].x, this.points[0].y);
for (i = 1; i < this.points.length; i++) {
ctx.lineTo(this.points[i].x, this.points[i].y);
}
ctx.closePath();
ctx.stroke();
},
fill: function(color) {
var ctx = this.context;
ctx.fillStyle = color;
ctx.fill();
},
say_name: function() {
console.log('Hello my name is ' + this.name)
}
};
function Triangle(a, b, c) {
this.points = [a, b, c];
this.name = 'Triangle'
this.context = document.getElementById('canvas').getContext('2d');
}
function Rectangle(side_a, side_b) {
var p = new Point(200, 200);
this.points = [
p,
new Point(p.x + side_a, p.y), // top right
new Point(p.x + side_a, p.y + side_b), // bottom right
new Point(p.x, p.y + side_b) // bottom left
];
this.name = 'Rectangle'
this.context = document.getElementById('canvas').getContext('2d');
}
(function() {
var s = new Shape();
Triangle.prototype = s;
Rectangle.prototype = s;
})();
function testTriangle() {
var p1 = new Point(100, 100);
var p2 = new Point(300, 100);
var p3 = new Point(200, 0);
return new Triangle(p1, p2, p3);
}
function testRectangle() {
return new Rectangle(100, 100);
}
function make_me_crazy() {
var t = testTriangle();
var r = testRectangle();
t.draw();
r.draw();
t.say_name();
r.say_name();
t.fill('red');
}
make_me_crazy();
<canvas height='600' width='800' id='canvas' />
谢谢!
更多详情:
- 为什么函数
say_name
完全正常工作我希望说:'我是一个三角'或'我是一个矩形'而且从来没有'我是一个通用的形状',但是fill
函数填充矩形,尽管我在三角形实例上调用它?当人们正确回答翻转两个绘制函数调用时,我会更好地指定以下内容。问题不在于形状的颜色,而在于 context 指针。为什么只填充最后一个形状?如果我在调用fill
之前添加更多形状,则只会填充最后一个。这意味着我在做画布时做错了。我认为它是我绘制形状的地方,但它看起来更像是最后一个活跃的形状 - 如何修复该代码以使其正常工作填充我想要的形状我想要?我的意思是。如果我想要一个接收特定形状实例并填充它的函数怎么办?
- 有没有办法访问包含在画布中的绘图?
- Why the function
say_name
is working exactly I expect saying: 'I am a triangle' or 'I am a rectangle' and never 'I am a generic shape', but thefill
function fills the rectangle despite I'm calling it on a triangle instance? As people rightly answered to flip the two draw functions calls, I would specify better the following. The problem is not about the color of a shape, but the context pointer. why only the last shape is filled? If I add more shapes before callingfill
only the last one get filled. This means I'm doing something wrong referring to the canvas. I supposed it was "the place where I draw shapes" but it seems more like "the last active shape" - How can I fix that code to make it working correctly filling the shape I want whenever I want? I mean. what if I want to have a function which receive an instance of a particular shape and fills it?
- Is there any way to access a the draws contained into a canvas?
推荐答案
问题的核心是上下文 - 你的形状共享单画布的上下文,因此在对象之间来回翻转并不是直截了当的。相反,将您的操作顺序视为一次处理单个形状,并在完成前者时仅转移到下一个形状。
The core of the problem is the context - your shapes are sharing the single context of the canvas, and therefore it is not straight-forward to flip back and forth between objects. Instead, think of your order-of-operations as handling a single shape at a time and only moving on to the next one when you are done with the former.
注意 make_me_crazy
函数中的调用顺序:
Note the order of calls in the make_me_crazy
function:
function Point(x, y) {
this.x = x;
this.y = y;
}
function Shape() {
this.points = [];
this.init();
}
Shape.prototype = {
constructor: Shape,
init: function(){
if (this.context === undefined) {
Shape.prototype.context = document.getElementById('canvas').getContext('2d');
};
if(this.name === undefined){
Shape.prototype.name = 'generic shape'
}
},
draw: function(){
var i, ctx = this.context;
ctx.strokeStyle = 'rgb(0,0,255)';
ctx.beginPath();
ctx.moveTo(this.points[0].x, this.points[0].y);
for (i = 1; i<this.points.length; i++) {
ctx.lineTo(this.points[i].x, this.points[i].y);
}
ctx.closePath();
ctx.stroke();
},
fill: function(color){
var ctx = this.context;
ctx.fillStyle = color;
ctx.fill();
},
say_name: function(){console.log('Hello my name is '+ this.name)}
};
function Triangle(a,b,c){
this.points = [a, b, c];
this.name = 'Triangle'
this.context = document.getElementById('canvas').getContext('2d');
}
function Rectangle(side_a, side_b){
var p = new Point(200, 200);
this.points = [
p,
new Point(p.x + side_a, p.y),// top right
new Point(p.x + side_a, p.y + side_b), // bottom right
new Point(p.x, p.y + side_b)// bottom left
];
this.name = 'Rectangle'
this.context = document.getElementById('canvas').getContext('2d');
}
(function(){
var s = new Shape();
Triangle.prototype = s;
Rectangle.prototype = s;
})();
function testTriangle(){
var p1 = new Point(100, 100);
var p2 = new Point(300, 100);
var p3 = new Point(200, 0);
return new Triangle(p1, p2, p3);
}
function testRectangle(){
return new Rectangle(100, 100);
}
function make_me_crazy(){
var t = testTriangle();
t.say_name();
t.draw();
t.fill('red');
var r = testRectangle();
r.draw();
r.say_name();
}
make_me_crazy();
<canvas height='600' width='800' id='canvas'></canvas>
这篇关于JavaScript原型继承和html画布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!