返回

用Canvas描绘“鲤鱼跃龙门”:巧妙构思下的视觉盛宴

前端

欢迎踏入一个充满想象力和创造力的数字画布,让我们共同见证一幅壮观的“鲤鱼跃龙门”画卷,它是由神奇的Canvas技术绘制而成。本文将揭开这幅非凡作品背后的奥秘,探索如何巧妙构思和运用代码,将这一中国神话中的经典场景栩栩如生地呈现于屏幕之上。

第一步:铺设数字画布

我们的旅程始于创建Canvas画布,这将成为我们艺术创作的舞台。我们使用JavaScript的<canvas>元素,通过设置宽度和高度来定义画布的尺寸。

const canvas = document.getElementById("my-canvas");
const ctx = canvas.getContext("2d");
canvas.width = 1000;
canvas.height = 600;

第二步:捕捉Canvas元素

接下来,我们获取Canvas元素的上下文,这是一个允许我们与画布交互的对象。通过上下文,我们可以绘制形状、添加颜色并创建动画。

const ctx = canvas.getContext("2d");

第三步:白云朵朵,点缀苍穹

白云是这幅画作的背景,我们使用贝塞尔曲线来绘制它们的柔和形状。我们通过设置颜色、线宽和起始点来创建每个云朵的路径,然后使用fill()方法填充形状。

function drawCloud(x, y, size) {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.bezierCurveTo(x + size / 2, y - size / 2, x + size, y, x + size, y + size / 2);
  ctx.bezierCurveTo(x + size, y + size, x + size / 2, y + size * 1.5, x, y + size * 1.5);
  ctx.bezierCurveTo(x - size / 2, y + size * 1.5, x - size, y + size, x - size, y + size / 2);
  ctx.bezierCurveTo(x - size, y + size / 2, x - size / 2, y, x, y);
  ctx.closePath();
  ctx.fillStyle = "#ffffff";
  ctx.fill();
}

第四步:让白云动起来

为了给画作增添灵动感,我们让白云缓慢移动。我们使用requestAnimationFrame()方法持续更新画布,并在每次刷新中更新白云的位置。

let cloudX = [];
let cloudY = [];
for (let i = 0; i < 10; i++) {
  cloudX.push(Math.random() * canvas.width);
  cloudY.push(Math.random() * canvas.height / 2);
}

function animateClouds() {
  requestAnimationFrame(animateClouds);
  ctx.clearRect(0, 0, canvas.width, canvas.height / 2);
  for (let i = 0; i < 10; i++) {
    cloudX[i] += Math.random() * 2 - 1;
    cloudY[i] += Math.random() * 2 - 1;
    drawCloud(cloudX[i], cloudY[i], 50);
  }
}

animateClouds();

第五步:绘制跃动的鲤鱼

鲤鱼是画作的主角,我们使用圆形和曲线来描绘其流线型的身体。我们设置颜色、填充形状并使用beginPath()closePath()方法创建鱼的轮廓。

function drawFish(x, y, size) {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.quadraticCurveTo(x + size / 4, y - size / 4, x + size / 2, y);
  ctx.quadraticCurveTo(x + size * 3 / 4, y + size / 4, x + size, y);
  ctx.quadraticCurveTo(x + size * 3 / 4, y + size / 2, x + size / 2, y + size);
  ctx.quadraticCurveTo(x + size / 4, y + size * 3 / 4, x, y + size);
  ctx.closePath();
  ctx.fillStyle = "#ff6600";
  ctx.fill();
}

第六步:让鲤鱼游动起来

与白云类似,我们使用动画让鲤鱼在画布上游动。我们不断更新鲤鱼的位置并重新绘制画布。

let fishX = canvas.width / 2;
let fishY = canvas.height * 3 / 4;
let fishSpeed = 2;

function animateFish() {
  requestAnimationFrame(animateFish);
  ctx.clearRect(0, canvas.height / 2, canvas.width, canvas.height / 2);
  fishX += fishSpeed;
  if (fishX > canvas.width || fishX < 0) {
    fishSpeed *= -1;
  }
  drawFish(fishX, fishY, 100);
}

animateFish();

第七步:龙门显现,气宇轩昂

龙门是我们画作的另一焦点,我们使用多边形和曲线来描绘其雄伟的身躯和威严的头部。

function drawDragonGate(x, y, size) {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x + size / 2, y - size / 2);
  ctx.lineTo(x + size, y);
  ctx.lineTo(x + size, y + size / 2);
  ctx.lineTo(x + size / 2, y + size);
  ctx.lineTo(x, y + size);
  ctx.closePath();
  ctx.fillStyle = "#000000";
  ctx.fill();
}

第八步:鲤鱼一跃,化龙登天

在故事的最后,鲤鱼奋力跃过龙门,化身为威严的龙。我们使用椭圆形和曲线来描绘龙的身体和头部,并为其添加颜色和阴影。

function drawDragon(x, y, size) {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.quadraticCurveTo(x + size / 4, y - size / 4, x + size / 2, y);
  ctx.quadraticCurveTo(x + size * 3 / 4, y + size / 4, x + size, y);
  ctx.quadraticCurveTo(x + size * 3 / 4, y + size / 2, x + size / 2, y + size);
  ctx.quadraticCurveTo(x + size / 4, y + size * 3 / 4, x, y + size);
  ctx.closePath();
  ctx.fillStyle = "#000000";
  ctx.fill();
  ctx.beginPath();
  ctx.moveTo(x + size / 2, y + size / 4);
  ctx.quadraticCurveTo(x + size * 3 / 4, y, x + size, y + size / 4);
  ctx.lineTo(x + size, y + size / 2);
  ctx.lineTo(x + size * 3 / 4, y + size * 3 / 4);
  ctx.quadraticCurveTo(x + size / 2, y + size, x + size / 4, y + size * 3 / 4);
  ctx.lineTo(x, y + size / 2);
  ctx.closePath();
  ctx.fillStyle = "#ffffff";
  ctx.fill();
}

第九步:完成之作,气韵生动

最后,我们融合所有元素,呈现出一幅完整的“鲤鱼跃龙门”画卷。白云随风飘动,鲤鱼欢快游弋,龙门巍然耸立,龙身矫健有力,共同描绘了一个充满生命力和意境的场景。

总结

这幅“鲤鱼跃龙门”画作充分展示了Canvas技术在艺术创作中的强大潜力。我们通过巧妙构思、循序渐进地绘制白云、鲤鱼、龙门和龙,最终完成了