Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/456.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何简化此代码?_Javascript_Html_Canvas_Html5 Canvas - Fatal编程技术网

Javascript 如何简化此代码?

Javascript 如何简化此代码?,javascript,html,canvas,html5-canvas,Javascript,Html,Canvas,Html5 Canvas,我刚开始学习canvas,到目前为止已经尝试了几个练习,但我的代码总是太长,而且可能不必要地复杂。我有一个四叶三叶草画下面的代码,想知道如何简化它。有什么建议吗 提前谢谢你 var clover = document.getElementById("clover"); var ctx = clover.getContext("2d"); //style: ctx.strokeStyle = "#006600"; ctx.lineWidth = 0.3; ctx.beginPath(); c

我刚开始学习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();

编写一个或多个函数来执行重复的操作。找出他们需要采取哪些参数才能处理略有不同的情况。然后使用正确的参数调用函数。例如,表单的代码

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

编写一个或多个函数来执行重复的操作。找出他们需要采取哪些参数才能处理略有不同的情况。然后使用正确的参数调用函数。例如,表单的代码

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);
表达性语言 Javascript以其表达的灵活性而闻名,并且可以允许大多数其他语言中找不到的编码样式

使用Path2D 代码的第一个想法是使用Path2D对象定义绘图命令。它使用与SVG path命令类似的语法

但是为什么不创建自己的命令列表呢

命名样式 首先,让我们找到所有样式并命名它们

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中,命令是moveto的单个字符M,后跟x,y坐标

我们也可以这样做。命令将是一个字符串,由分隔,然后拆分为一个数组。您可以根据需要从阵列中切换每个命令

首先是对每个命令都有函数的命令对象。在这种情况下,M代表moveTo,L代表lineTo。它获取用于从中获取坐标的数组

var commands = {
    M(array){
        ctx.moveTo(array.shift(),array.shift());
   },
   L(array){
        ctx.lineTo(array.shift(),array.shift());
   }

}
然后用我们的新命令定义一条路径,移动到10,10,然后移动到100100

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,
    }
}
创建命令列表并绘制

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(","));
演示 注意:所有代码都是用ES6编写的,需要Babel或类似的工具才能在传统浏览器上工作

//定义绘图命令 var drawFuncs={ getNa,count{return a.0,count;},//从数组中获取值 Ma{ctx.moveTo…this.getNa,2;},//移动到 Ca{ctx.bezier Curveto…this.getNa,6;},//bezier曲线 Qa{ctx.quadraticCurveTo…this.getNa,4;},//四次曲线 S{ctx.stroke;},//stroke P{ctx.closePath;},//关闭路径 F{ctx.fill;},//fill B{ctx.beginPath;},//开始路径 la{//线段 ctx.beginPath; ctx.moveTo…this.getNa,2; ctx.lineTo…this.getNa,2; ctx.stroke; }, Sta{//集合样式 var style=样式[a.shift]; Object.keystyle.forEachprop=>ctx[prop]=style[prop]; }, } //获取命令字符串并绘制其中的内容 函数拉伸形状{ var a=形状分割,; whilea.length>0{ drawFuncs[a.shift]a; } } //创建画布并添加到DOM var canvas=document.createElementcanvas; 画布宽度=200; 画布高度=200; var ctx=canvas.getContext2d; document.body.appendChildcanvas; //定义命名样式 变量样式={ 绿色:{ strokeStyle:006600, 线宽:0.3, }, 黑色:{ strokeStyle:黑色, 填充样式:7BA32D, 线宽:0.8, } } //全部画出来 ctx.clearRect0,0,canvas.width,canvas.height; 画[ 圣德格林,B,M,115,80,C,201002001035135,S, 圣布莱克,B,M,55,70,Q,20100115,80, M、 55,70,Q,40,30115,80, M、 115,80,Q,80,20130,50,, M、 115,80,Q,200,40130,50, M、 115,80,Q,235,60185,85,, M、 115,80,Q,190115185,85, M、 115,, 80,Q,180135110115, M、 115,80,Q,60130110115,S,P,F, 圣德格林, l、 115,80,65,71,, l、 115,80127,55,, l、 115,80175,85,, l、 115,80110,110,, ].加入,; 表达性语言 Javascript以其表达的灵活性而闻名,并且可以允许大多数其他语言中找不到的编码样式

使用Path2D 代码的第一个想法是使用Path2D对象定义绘图命令。它使用与SVG path命令类似的语法

但是为什么不创建自己的命令列表呢

命名样式 首先,让我们找到所有样式并命名它们

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中,命令是moveto的单个字符M,后跟x,y坐标

我们也可以这样做。命令将是一个字符串,由分隔,然后拆分为一个数组。您可以根据需要从阵列中切换每个命令

首先是对每个命令都有函数的命令对象。在这种情况下,M代表moveTo,L代表lineTo。它获取用于从中获取坐标的数组

var commands = {
    M(array){
        ctx.moveTo(array.shift(),array.shift());
   },
   L(array){
        ctx.lineTo(array.shift(),array.shift());
   }

}
然后用我们的新命令定义一条路径,移动到10,10,然后移动到100100

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,
    }
}
创建命令列表并绘制

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(","));
演示 注意:所有代码都是用ES6编写的,需要Babel或类似的工具才能在传统浏览器上工作

//定义绘图命令 var drawFuncs={ getNa,count{return a.0,count;},//从数组中获取值 Ma{ctx.moveTo…this.getNa,2;},//移动到 Ca{ctx.bezier Curveto…this.getNa,6;},//bezier曲线 Qa{ctx.quadraticCurveTo…this.getNa,4;},//四次曲线 S{ctx.stroke;},//stroke P{ctx.closePath;},//关闭路径 F{ctx.fill;},//fill B{ctx.beginPath;},//开始路径 la{//线段 ctx.beginPath; ctx.moveTo…this.getNa,2; ctx.lineTo…this.getNa,2; ctx.stroke; }, Sta{//集合样式 var style=样式[a.shift]; Object.keystyle.forEachprop=>ctx[prop]=style[prop]; }, } //获取命令字符串并绘制其中的内容 函数拉伸形状{ var a=形状分割,; whilea.length>0{ drawFuncs[a.shift]a; } } //创建画布并添加到DOM var canvas=document.createElementcanvas; 画布宽度=200; 画布高度=200; var ctx=canvas.getContext2d; document.body.appendChildcanvas; //定义命名样式 变量样式={ 绿色:{ strokeStyle:006600, 线宽:0.3, }, 黑色:{ strokeStyle:黑色, 填充样式:7BA32D, 线宽:0.8, } } //全部画出来 ctx.clearRect0,0,canvas.width,canvas.height; 画[ 圣德格林,B,M,115,80,C,201002001035135,S, 圣布莱克,B,M,55,70,Q,20100115,80, M、 55,70,Q,40,30115,80, M、 115,80,Q,80,20130,50,, M、 115,80,Q,200,40130,50, M、 115,80,Q,235,60185,85,, M、 115,80,Q,190115185,85, M、 115,80,Q,180135110115, M、 115,80,Q,60130110115,S,P,F, 圣德格林, l、 115,80,65,71,, l、 115,80127,55,, l、 115,80175,85,, l、 115,80110,110,, ].加入,;
尝试在循环中放置类似的代码块,并从数组或类似对象中获取更改的值。应该没那么难。试着在循环中放置类似的代码块,并从数组或类似的数组中获取更改的值。应该没那么难。不,贝金帕斯必须在那里。没有这张纸条,你的答案会更好。但是,笔划后的closePath是无用的,fill已经在内部执行此closePath,它只是上一个MovedPoint的一行。与其叫它draw,不如叫line-不,beginPath必须在那里。你的a 没有这张纸条,nswer会更好。但是,笔划后的closePath是无用的,fill已经在内部执行此closePath,它只是上一个MovedPoint的一行。与其叫它draw,不如叫line-