Как оптимизировать данный фрагмент кода? HTML, JS
let can = document.getElementById("can");
let ctx = can.getContext("2d");
ctx.fillStyle="fff";
function zad1(){
let x = document.getElementById("xpos").value;
let y = document.getElementById("ypos").value;
let red = Math.random() * 256;
let green = Math.random() * 256;
let blue = Math.random() * 256;
console.log(red)
if(document.getElementById("fig").value == "square"){
ctx.beginPath();
ctx.rect(x, y, 50, 50)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")"
ctx.fill();
}
else if(document.getElementById("fig").value == "round"){
ctx.beginPath();
ctx.arc(x, y, 50, 0, Math.PI*2, false)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")"
ctx.fill();
}
else if(document.getElementById("fig").value == "triangle"){
ctx.beginPath();
ctx.moveTo(x, y)
ctx.lineTo(x-50, y)
ctx.lineTo(x-50, y-30)
ctx.lineTo(x, y)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")"
ctx.fill();
}
else if(document.getElementById("fig").value == "car"){
ctx.beginPath();
ctx.rect(x-100, y-30, 120, 20)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(x-70, y-50, 60, 20)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(x,y, 15, 0, Math.PI*2, false)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")"
ctx.fill();
ctx.closePath()
ctx.beginPath();
ctx.arc(x-80,y, 15, 0, Math.PI*2, false)
ctx.stroke();
ctx.fillStyle="rgb("+red+"," + green + "," + blue + ")"
ctx.fill();
ctx.closePath();
}
}
Ответы (2 шт):
Можно по двигаться в таком направлении.
let can = document.getElementById("can");
let ctx = can.getContext("2d");
function beforeDraw(ctx){
ctx.beginPath();
}
function afterDraw(ctx){
ctx.stroke();
ctx.fill();
ctx.closePath();
}
const figureDrawer = {
"square": function (ctx, x, y, x1 = 50, y1 = 50) {
beforeDraw(ctx);
ctx.rect(x, y, x1, y1);
afterDraw(ctx);
},
"round": function (ctx, x, y, radius = 50) {
beforeDraw(ctx);
ctx.arc(x, y, radius, 0, Math.PI*2, false)
afterDraw(ctx);
},
"triangle": function (ctx, x, y) {
beforeDraw(ctx);
ctx.moveTo(x, y)
ctx.lineTo(x-50, y)
ctx.lineTo(x-50, y-30)
ctx.lineTo(x, y)
afterDraw(ctx);
},
"car": function (ctx, x, y){
this["square"](ctx, x-100, y-30, 120, 20);
this["square"](ctx, x-70, y-50, 60, 20);
this["round"](ctx, x, y, 15);
this["round"](ctx, x-80, y, 15);
}
}
function zad1(){
let x = document.getElementById("xpos").value;
let y = document.getElementById("ypos").value;
let figure = document.getElementById("fig").value;
let red = Math.random() * 256;
let green = Math.random() * 256;
let blue = Math.random() * 256;
let color = "rgb("+red+"," + green + "," + blue + ")";
ctx.fillStyle=color;
figureDrawer[figure](ctx, x, y);
}
zad1();
<canvas id="can" width="400" height="400"></canvas>
<input id="fig" value="car">
<input id="xpos" value="100">
<input id="ypos" value="100">
Во-первых, если предстоит рисовать много сложных фигур, важно сразу подготовить набор функций для рисования простых элементов, которые в первую очередь будет удобно вызывать. Например, избавившись от необходимости бесконечно повторять beginPath, closePath, или одинаковые параметры функций (углы 0, 2 * Math.PI для окружностей, эллипсов и пр.).
Если всё же рисуете составную фигуру одним большим блоком кода, хорошо бы разделять пробельными строками каждый beginPath, чтобы легче было в него вникать. + Оставлять комментарии, что конкретно рисует данная часть кода.
Ответы на вопросы про оптимизацию кода, которые на самом деле не про оптимизацию, а про реорганизацию кода, сильно зависят от вкусовщины и настроения. Ну получилось так:
const cnv = {
ctx: document.getElementById('can').getContext('2d'),
clear: function() {
let ctx = this.ctx;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
return this;
},
rect: function (x, y, wid, hei) {
if (hei === undefined) hei = wid;
// передана только одна сторона? Рисуем квадрат.
this.ctx.beginPath();
this.ctx.rect(x, y, wid, hei);
return this;
},
arc: function (cx, cy, r, start = 0, stop = 2 * Math.PI) {
this.ctx.beginPath();
this.ctx.arc(cx, cy, r, start, stop);
return this;
},
triangle: function (x1, y1, x2, y2, x3, y3) {
let ctx = this.ctx;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.lineTo(x1, y1);
return this;
},
fill: function (color) {
if (color) this.ctx.fillStyle = color;
this.ctx.fill();
return this;
},
stroke: function (color) {
if (color) this.ctx.strokeStyle = color;
this.ctx.stroke();
return this;
},
/***/
randColor: function () {
let r = Math.random() * 256 | 0;
let g = Math.random() * 256 | 0;
let b = Math.random() * 256 | 0;
return `rgb(${r},${g},${b})`;
},
};
/***/
let elem = {
xpos: document.getElementById('xpos'),
ypos: document.getElementById('ypos'),
shape: document.getElementById('shape'),
};
draw();
elem.shape.addEventListener('change', draw);
/***/
function draw() {
cnv.clear();
// Из value всегда прилетает строка.
// Если ожидается работа с числами - явно превращайте в число.
let x = Number(elem.xpos.value);
let y = Number(elem.ypos.value);
let shape = elem.shape.value;
let color = cnv.randColor();
switch (shape) {
case 'square':
cnv.rect(x, y, 50).stroke().fill(color);
break;
case 'circle':
cnv.arc(x, y, 50).stroke().fill(color);
break;
case 'triangle':
cnv.triangle(x, y, x - 50, y, x - 50, y - 30).stroke().fill(color);
break;
case 'car':
cnv.rect(x - 100, y - 30, 120, 20).stroke().fill(color); // тело
cnv.rect(x - 70, y - 50, 60, 20).stroke().fill(color); // крыша
cnv.arc(x, y, 15).stroke().fill(color); // правое колесо
cnv.arc(x - 80, y, 15).stroke().fill(color); // левое колесо
break;
}
}
<input id="xpos" value="120">
<input id="ypos" value="60">
<select id="shape">
<option>car</option>
<option>circle</option>
<option>square</option>
<option>triangle</option>
</select>
<button onclick="draw()">New</button>
<canvas id="can"></canvas>
Рисовашки фигур однострочные, и их мало. Для разнообразия оставил в switch. Но тоже хотелось вынести в отдельный объект, примерно как у @AzizUmarov.