我正在尝试画这个 flower在 Canvas 中使用循环。我很困惑从哪里开始。我要先画花瓣吗?我要改造它们以获得全部 5 个花瓣吗?这就是我目前所拥有的 500 x 500 Canvas 。
var canvas = document.getElementById('flowerCanvas');
var ctx = canvas.getContext('2d');
var radius = 20;
var petals = 5;
ctx.beginPath();
ctx.arc(250, 250, radius, 0, 2*Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.save();
ctx.translate(250,250);
for(var i = 0; i < 5; i++){
ctx.lineTo(200,0);
ctx.stroke();
}
ctx.restore();
最佳答案
使用Path2D
缓冲复杂路径
您可以使用 Path2D
对象来存储每个花瓣。它具有与 2D 上下文相同的路径功能,因此可以轻松地将代码转换为 2D 路径,然后进行渲染,而无需执行所有路径创建步骤。如果您有大量渲染涉及许多重复路径,这将为您带来一些额外的性能。
创建路径
您可以相对于其旋转点创建花瓣。
function createPetal(length, width){
const path = new Path2D();
// draw outer line
path.moveTo(0,0);
path.lineTo(length * 0.3, -width);
path.lineTo(length * 0.8, -width);
path.lineTo(length, 0);
path.lineTo(length * 0.8, width);
path.lineTo(length * 0.3, width);
// close the path so that it goes back to start
path.closePath();
// create the line down the middle.
path.moveTo(0,0);
path.lineTo(length,0);
return path;
}
注意为此,花瓣必须相对于旋转点绘制。
渲染路径
您现在需要围绕圆绘制几次路径。
// x,y is center
// count number of petals
// startAt is the angle of the first
function drawPetals(x, y, count, startAt, petal){
const step = (Math.PI * 2) / count;
ctx.setTransform(1, 0, 0, 1, x, y); // set center
ctx.rotate(startAt); // set start angle
for(var i = 0; i < count; i+= 1){
ctx.stroke(petal); // draw a petal
ctx.rotate(step); // rotate to the next
}
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
}
把它们放在一起。
现在您需要做的就是创建一个花瓣,然后绘制它们,并在中心添加一个圆圈
// col is the stroke color
// linewidth is the thing to do with lines
// fitScale is how well to fit the space. Less than one to fit the canvas
// petalCount i will let you guess what that does.
function drawFlower(col, lineWidth,fitScale, petalCount) {
ctx.strokeStyle = col;
ctx.lineWidth = lineWidth;
const size = Math.min(ctx.canvas.width, ctx.canvas.height) * fitScale * 0.5;
drawPetals(ctx.canvas.width / 2, ctx.canvas.height / 2, 5, 0, createPetal(size, size * 0.2));
ctx.beginPath();
ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, size*0.15 , 0, Math.PI * 2);
ctx.fillStyle = col;
ctx.fill();
}
上面的代码运行
const ctx = canvas.getContext("2d");
function createPetal(length, width) {
const path = new Path2D();
path.moveTo(0, 0);
path.lineTo(length * 0.3, -width);
path.lineTo(length * 0.8, -width);
path.lineTo(length, 0);
path.lineTo(length * 0.8, width);
path.lineTo(length * 0.3, width);
path.closePath();
path.moveTo(0, 0);
path.lineTo(length, 0);
return path;
}
// x,y is center
// count number of petals
// startAt is the angle of the first
function drawPetals(x, y, count, startAt, petal) {
const step = (Math.PI * 2) / count;
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(startAt);
for (var i = 0; i < count; i += 1) {
ctx.stroke(petal);
ctx.rotate(step);
}
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
}
function drawFlower(col, lineWidth, fitScale, petalCount) {
ctx.strokeStyle = col;
ctx.lineWidth = lineWidth;
const size = Math.min(ctx.canvas.width, ctx.canvas.height) * fitScale * 0.5;
drawPetals(ctx.canvas.width / 2, ctx.canvas.height / 2, 5, 0, createPetal(size, size * 0.2));
ctx.beginPath();
ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, size*0.15 , 0, Math.PI * 2);
ctx.fillStyle = col;
ctx.fill();
}
drawFlower("black",4,0.95,5);
canvas {
border: 2px solid black;
}
<canvas id="canvas" width="500" height="500"></canvas>
对于没有 Path2D
的浏览器
并非所有浏览器都支持 Path2D
。要执行相同的操作,您可以将花瓣的路径存储为数组。由于有几条路径,其中一条是开放的,另一条是封闭的,因此您需要添加一些路径绘制规则。在这种情况下,最后一个点与第一个点相同,路径是闭合的。
// the array holds normalised coords that need to be scaled when drawing
const petal = [
[ [0,0],[0.3,-1],[0.8,-1],[1,0],[0.8,1],[0.3,1],[0,0] ],
[ [0,0],[1,0] ],
]
现在,您不再需要创建花瓣,而是使用一个函数来使用路径绘制花瓣
function drawPetal(path,width,height){
var i = 0;
do{ // loop through paths
const p = path[i];
let j = 0;
ctx.moveTo(p[j][0] * width, p[j ++][1] * height);
while(j < p.length - 1){
ctx.lineTo(p[j][0] * width, p[j ++][1] * height);
}
// is the path closed ?
if(p[j][0] === p[0][0] && p[j][1] === p[0][1]){
ctx.closePath();
}else{
ctx.lineTo(p[j][0] * width,p[j][1] * height)
}
} while(++i < path.length);
}
绘制花朵函数需要更改为使用新的drawPetal
,但方法是相同的,使用当前变换依次旋转绘制每个花瓣。
作为代码示例
const ctx = canvas.getContext("2d");
const petal = [
[
[0, 0],
[0.3, -1],
[0.7, -1],
[1, 0],
[0.7, 1],
[0.3, 1],
[0, 0]
],
[
[0, 0],
[1, 0]
],
];
function drawPetal(path, width, height) {
var i = 0;
do { // loop through paths
const p = path[i];
let j = 0;
ctx.moveTo(p[j][0] * width, p[j++][1] * height);
while (j < p.length - 1) {
ctx.lineTo(p[j][0] * width, p[j++][1] * height);
}
if (p[j][0] === p[0][0] && p[j][1] === p[0][1]) { // is the path closed ?
ctx.closePath();
} else {
ctx.lineTo(p[j][0] * width, p[j][1] * height)
}
} while (++i < path.length);
}
function drawPetals(x, y, count, startAt, petal, width, height) {
const step = (Math.PI * 2) / count;
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.rotate(startAt);
for (var i = 0; i < count; i += 1) {
drawPetal(petal, width, height);
ctx.rotate(step);
}
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
}
function drawFlower(col, lineWidth, fitScale, petalCount) {
ctx.strokeStyle = col;
ctx.lineWidth = lineWidth;
const size = Math.min(ctx.canvas.width, ctx.canvas.height) * fitScale * 0.5;
ctx.beginPath();
drawPetals(ctx.canvas.width / 2, ctx.canvas.height / 2, 5, -Math.PI / 2, petal, size, size * 0.2);
ctx.stroke();
ctx.beginPath();
ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, size * 0.15, 0, Math.PI * 2);
ctx.fillStyle = col;
ctx.fill();
}
drawFlower("black", 4, 0.95, 5);
canvas {
border: 2px solid black;
}
<canvas id="canvas" width="500" height="500"></canvas>
关于javascript - 使用 Canvas 和环画一朵花,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46738188/