如何简化此代码?

时间:2017-01-14 02:01:06

标签: javascript html5 canvas html5-canvas

我刚刚开始学习画布并且到目前为止已经尝试过几次练习,但是我的代码总是太长而且很可能不必要地复杂化。我有以下四叶草图的代码,想知道如何简化它。有什么建议?

提前谢谢!

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();

2 个答案:

答案 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

您的代码的第一个想法是使用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(","));