我刚刚开始学习画布并且到目前为止已经尝试过几次练习,但是我的代码总是太长而且很可能不必要地复杂化。我有以下四叶草图的代码,想知道如何简化它。有什么建议?
提前谢谢!
var clover = document.getElementById("clover");
var ctx = clover.getContext("2d");
//style:
ctx.strokeStyle = "#006600";
ctx.lineWidth = 0.3;
ctx.beginPath();
ctx.moveTo(115,80);
ctx.bezierCurveTo(20,100,200,100,235,135);
ctx.stroke();
//First leaf:
ctx.strokeStyle = "black";
ctx.lineWidth = 0.8;
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(55,70);
ctx.quadraticCurveTo(20,100,115,80);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(55,70);
ctx.quadraticCurveTo(40,30,115,80);
ctx.stroke();
ctx.closePath();
ctx.fill();
// Second leaf:
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(80,20,130,50);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(200,40,130,50);
ctx.stroke();
ctx.closePath();
ctx.fill();
// Third leaf:
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(235,60,185,85);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(190,115,185,85);
ctx.stroke();
ctx.closePath();
ctx.fill();
// Fourth leaf:
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(180,135,110,115);
ctx.stroke();
ctx.closePath();
ctx.fill();
ctx.fillStyle = "#7BA32D";
ctx.beginPath();
ctx.moveTo(115,80);
ctx.quadraticCurveTo(60,130,110,115);
ctx.stroke();
ctx.closePath();
ctx.fill();
// lines on the leaves:
ctx.strokeStyle = "#006600";
ctx.lineWidth = 0.3;
ctx.beginPath();
ctx.moveTo(115, 80);
ctx.lineTo(65, 71);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(115, 80);
ctx.lineTo(127, 55);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(115, 80);
ctx.lineTo(175, 85);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(115, 80);
ctx.lineTo(110, 110);
ctx.stroke();
ctx.closePath();
答案 0 :(得分:4)
编写一个或多个执行您重复操作的函数。找出他们需要采取什么参数才能处理稍微不同的情况。然后使用正确的参数调用函数。例如,您的表单代码
ctx.beginPath();
ctx.moveTo(115, 80);
ctx.lineTo(110, 110);
ctx.stroke();
ctx.closePath();
将被写为函数
function line(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
ctx.closePath();
}
并称为
line(115, 80, 110, 110);
答案 1 :(得分:2)
Javascript以其富有表现力的灵活性而闻名,并且可以允许在大多数其他语言中找不到的编码样式。
您的代码的第一个想法是使用Path2D对象来定义绘制命令。它使用与SVG路径命令类似的语法。
但为什么不创建自己的命令列表。
首先让我们找到所有样式并命名它们
var styles = {
dGreen : {
strokeStyle : "#006600",
lineWidth : 0.3,
},
black : {
strokeStyle : "black",
fillStyle : "#7BA32D",
lineWidth : 0.8,
}
}
现在您可以使用命名样式,如果您将属性命名为2D API使用的属性,则很容易设置样式
function setStyle(style){
Object.keys(style).forEach(prop => ctx[prop] = style[prop]);
},
setStyle(styles.black); // sets the style black
如果您想使用当时没有想到的属性,只需设置属性即可完成
styles.black.lineJoin = "round";
setStyle(styles.black); // sets the style black
对于绘图命令,您多次执行相同的操作集。在SVG中,命令是单个字符“M”表示moveto,后跟x,y坐标。
我们也可以这样做。这些命令将是一个字符串,以“,”分隔,然后将其拆分为一个数组。您可以根据需要从数组中移出每个命令。
首先是具有每个命令功能的命令对象。在这种情况下,{0}表示moveTo,“L”表示lineTo。它采用它用来获取坐标的数组。
M
然后使用我们的新命令定义路径移至10,10然后行至100,100
var commands = {
M(array){
ctx.moveTo(array.shift(),array.shift());
},
L(array){
ctx.lineTo(array.shift(),array.shift());
}
}
现在我们只需要解析和解释路径
var path = "M,10,10,L,100,100";
现在您需要做的就是提供命令字符串以绘制您需要的内容。因为您可以定义命令,所以您可以根据需要创建复杂或简单的命令。
以下是我为绘制图像而创建的命令功能和绘图功能
function drawPath(path){
// split the command string into parts
var commandList = path.split(",");
// while there are commands
while(commandList.length > 0){
// use the next command to index the command
// and call the function it names passing the command list so
// it can get the data it needs
commands[commandList.shift()](commandList);
} // do that until there is nothing on the command list
}
您可以将该代码放入单独的库中并忘记它,同时专注于渲染
现在您可以使用自己定制的声明性语言进行渲染
定义样式
// define draw commands
var drawFuncs = {
getN(a,count){ return a.splice(0,count); }, // gets values from array
M(a){ ctx.moveTo(...this.getN(a,2)); }, // move to
C(a){ ctx.bezierCurveTo(...this.getN(a,6)); }, // bezier curve
Q(a){ ctx.quadraticCurveTo(...this.getN(a,4)); },// quad curve
S(){ ctx.stroke(); }, // stroke
P(){ ctx.closePath(); }, // close path
F(){ ctx.fill(); }, // fill
B(){ ctx.beginPath(); }, // begin path
l(a) { // line segment
ctx.beginPath();
ctx.moveTo(...this.getN(a,2));
ctx.lineTo(...this.getN(a,2));
ctx.stroke();
},
St(a){ // set style
var style = styles[a.shift()];
Object.keys(style).forEach(prop=>ctx[prop] = style[prop]);
},
}
// Takes command string and draws what is in it
function draw(shape){
var a = shape.split(",");
while(a.length > 0){
drawFuncs[a.shift()](a);
}
}
创建命令列表并绘制
// define named styles
var styles = {
dGreen : {
strokeStyle : "#006600",
lineWidth : 0.3,
},
black : {
strokeStyle : "black",
fillStyle : "#7BA32D",
lineWidth : 0.8,
}
}
注意:所有代码都是用ES6编写的,需要使用Babel(或类似代码)才能在旧版浏览器上运行。
draw([
"St,dGreen,B,M,115,80,C,20,100,200,100,235,135,S",
"St,black,B,M,55,70,Q,20,100,115,80",
"M,55,70,Q,40,30,115,80",
"M,115,80,Q,80,20,130,50",
"M,115,80,Q,200,40,130,50",
"M,115,80,Q,235,60,185,85",
"M,115,80,Q,190,115,185,85",
"M,115,80,Q,180,135,110,115",
"M,115,80,Q,60,130,110,115,S,P,F",
"St,dGreen",
"l,115,80,65,71",
"l,115,80,127,55",
"l,115,80,175,85",
"l,115,80,110,110",
].join(","));