我开始使用Canvas API进行图形编程,但我还没有看到任何重用画布代码的设计模式。到目前为止,我只看过使用全局画布对象和单个绘图函数的示例。
我来自Python tkinter背景,其中主要模式是为每个图形对象创建一个类,并将画布上下文传递给构造函数,以便对象可以自己绘制。我正在考虑使用下面的模块模式来实现相同的目标,但是如果有的话,我正在寻找更多的JavaScript方式。
var MyShape = function (ctx) {
// Assign the canvas context along with any other properties,
// then draw the object.
this.ctx = ctx;
this.draw();
}
MyShape.prototype.draw = function () {
// Use this.ctx to access the Canvas API and draw the object.
}
答案 0 :(得分:2)
到目前为止,你有正确的想法。除了你拥有的,我建议你为每个定义的可渲染对象包含一个更新函数。只要有可能这些形状随着时间的推移而移动。
另外,如果您发现自己需要更复杂的形状,我建议您使用已定义的其他形状类来构建复杂的形状。比如笑脸形状,在其绘制功能中,为眼睛和头部使用三个预定义的圆形类,也许只是使用画布上下文来产生微笑。
您可以在一系列绘制调用中从父形状调用每个子形状的绘制函数。
编辑:这是一个小例子,我忘了提及使用引用类型存储形状父级位置的重要性。
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
var thing = new Thing(100, 100, 30, 40);
function Vector(x, y){
this.x = x;
this.y = y;
}
function Rectangle(pos, w, h, color, parent){
//use a vector2 'pos' so that the position of this rectangle matches the position of the parent
//because pos is a reference type
this.pos = pos;
this.w = w;
this.h = h;
this.color = color || '#000';
}
Rectangle.prototype.render = function(){
ctx.fillStyle = this.color;
ctx.fillRect(this.pos.x, this.pos.y, this.w, this.h);
};
function Circle(pos, r, color, parent){
//use a vector2 'pos' so that the position of this circle matches the position of the parent
//because pos is a reference type
this.pos = pos;
this.r = r;
this.color = color || '#000';
}
Circle.prototype.render = function(){
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, this.r, 0, 2 * Math.PI, false);
ctx.fillStyle = this.color;
ctx.fill();
};
function Thing(x, y, w, h){
//create pos reference
this.pos = new Vector(x, y);
//use pos reference
this.rect = new Rectangle(this.pos, w, h, '#00F');
this.circle = new Circle(this.pos, w, '#F00');
//for update() demonstration
this.rotation = 0;
}
Thing.prototype.render = function(){
this.circle.render();
this.rect.render();
};
Thing.prototype.update = function(){
//notice here i only have to modify the values of pos.x and pox.y, this is important
//because if i had added fields x and y to the Thing class, they would not be reference types
//and i could not have moved both the rectangle and the circle if that was the case.
this.pos.x = this.pos.x + Math.cos(this.rotation);
this.pos.y = this.pos.y + Math.sin(this.rotation);
this.rotation += 0.02;
};
function update(){
thing.update();
}
function render(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
thing.render();
}
function main(){
update();
render();
window.requestAnimationFrame(main);
}
main();

#game{
border: 1px solid black;
}

<canvas id="game" width="500px" height="500px"></canvas>
&#13;
答案 1 :(得分:0)
似乎javascript在构建工具,接口(程序),框架库以及什么不是模块化方面的前进方向。
Javascript从来就不是一种链接库类型的语言,它的结构非常偶然,并且没有真正的范围保护机制可以依赖它来解决命名空间冲突,可用性,上下文定位等等。
Javascript依赖于一系列松散的约定,通过普遍使用的投票而不是辩论,量化,修正......标准达成一致。
这是模块化的approch。定义离散组件并将其添加到商定的注册表空间。您可以通过函数创建命名空间,并确保不会超出全局范围。
Node.JS和简单模块
NodeJs是模块化设计的一个示例,其中组件和接口作为模块,可通过简单的required
接口访问。这将加载并将referance返回到所需的模块。
在NodeJS中加载模块的示例
const fileSystem = require("fs");
// use the module
fileSystem.stats("filepath",callbackFunction);
模块需要的所有内容都会在您收到referance时加载并准备好使用,包括子模块,其他依赖项等。编写模块时,您专门导出界面
export.doSomething = (thing) => { // do some to thing
**对于浏览器????? **
对于常规浏览器环境,import
和export
被定义为语言的一部分。不幸的是,尚未被任何浏览器实现。然而,它们可以通过Babel等许多转发器之一获得。
您编写模块导出接口并在您自己的命名空间内保护范围。编写代码时,可以导入所需的模块,并使用返回的模块参考来与其进行交互。
这个模块approch有很多种变化,非常值得研究。
模块作为单身人士
最基本的approch是单身人士。这是一个模块,作为通过脚本标记引用的js文件。它包含一个封装接口的立即调用的匿名函数。它只将命名空间变量公开给全局范围。
const canvasInterface = (function(){
// define private and protected objects
var mycanvasColour = "Black";
// define private functions
function createCanvas(){ ...
}
// define the interface
const canvasStuff = {
clearTheCanvas : function(){
},
}
// return a referance to the interface
return canvasStuff;
}
您将其包含在
中<script src="../mylibs/myCanvasModual.js"></script>
使用它(onload之后)
canvasInterface.clearTheCanvas();
当文件加载时,立即执行该功能,并通过其定义的命名空间使接口可用。您在界面中所做的工作取决于您。
主要的重要方法是仅公开使用模块所需的内容,并且永远不要在模块中包含的全局名称空间中声明任何内容。这将保护您免受全局命名空间冲突的影响,并将内部状态保持在您的控制中(因此是安全的)。
未来看起来不错。
现在Javascript在模块化设计方面有点乱,但模块化的approch正在蓬勃发展,希望在不久的将来,我们可以享受连接我们的应用程序的一致和可靠的方法。