javascript - 使用 Canvas 和环画一朵花

标签 javascript html canvas html5-canvas

我正在尝试画这个 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/

相关文章:

javascript - 将 Canvas 分成几 block

javascript - 修改 Canvas 大小时的 html5 Canvas 行为

javascript - "Mongoose mpromise is deprecated"

javascript - 在 while 循环中使用 ajax 调用 url

javascript - PHP/html : instant search function: Can't search for foreign (e. g.Chinese)字符

javascript - 如何 'slideUp' div的剩余部分?

javascript - 如何在 Redux 操作的 Promise 中发出多个 API 请求

javascript - 如何在映射数组时更改最后一个元素的逻辑

php - 如何将多个复选框值传递给 php

eclipse - 三星 Galaxy S4 和 Phonegap 问题