夏天一起用canvas 赏荷花呀

699 阅读5分钟

我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛

前言

绿竹含新粉,红莲落故衣。夏季到了,大家可以一起约上小伙伴去赏荷花啦。但是被封印在上海我,那就只能想想。不过没事,连对象没有都能new一个的这种事情,荷花还不是自己画一个么?😄偶得灵感,用canvas 画一个吧。

知识点

  • 贝塞尔曲线的使用
  • canvas如何得到一个高清的图像: 画布大小(400/400) 设置css样式显示为(200/200),这样就是高清的啦,原理和照片一样,放大就是像素,缩小就是高清的

画花瓣

我们首先实现一片花瓣然后在一步一步的实现另外的花瓣,之后组合形成一朵完成的荷花

创建画布

首先创建画布, 我使用的是react(ts)搭建的项目所以代码的话,带有一些类型的定义

// html中或者组件中
<canvas id='lotus-canvas-container' width='600px' height='400px' ></canvas>
// 获取到画布的对象
const lotus:any = document.getElementById('lotus-canvas-container')
const ctx = lotus.getContext('2d')

画花瓣的轮廓

开始画花瓣的一个大概的轮廓, 我抽离了一个单个函数进行绘画

  1. 花瓣是曲线的,所以用三次贝塞尔曲线bezierCurveTo进行画曲线,进行连接
  2. 其次,花瓣的轮廓边框也是有颜色的,而且还是渐变色,所以我们定义了一个线性渐变createLinearGradient的颜色对画的线进行设置
 const lotusFun = (ctx:any) => {
    // 线的颜色:线性渐变
    const grd=ctx.createLinearGradient(300, 100, 400, 200);
    grd.addColorStop(0, "rgb(221,172,222)");
    grd.addColorStop(1, "white");

    // 绘制花瓣
    ctx.beginPath();
    ctx.moveTo(300, 50);
    // 三次贝塞尔曲线
    ctx.bezierCurveTo(300, 70, 220, 150, 300, 250);
    ctx.bezierCurveTo(320, 280, 400, 300, 430, 230);
    ctx.bezierCurveTo(440, 50, 320, 75, 300, 50);
    ctx.lineWidth = 1 // 线的宽度
    ctx.strokeStyle = grd // 线的颜色
    ctx.stroke()
    ctx.save()
 }

因为背景颜色是白色的,荷花的花瓣也有部分是白色的,所以我把背景颜色调整成了绿色,这样方便查看线条,如下图,就得到了一个花瓣的大概。

image.png

填充颜色

然后花瓣的颜色是渐变的,这个时候,我们给花瓣填充对应的渐变色, 填充的颜色同样使用的渐变颜色,但是用的是放射状的渐变createRadialGradient

    // 线的颜色:线性渐变
    const grd=ctx.createLinearGradient(300, 100, 400, 200);
    grd.addColorStop(0, "rgb(221,172,222)");
    grd.addColorStop(1, "white");

    // 填充的颜色:放射状的渐变
    const grd2=ctx.createRadialGradient(300, 20, 100, 400, 300, 100);
    grd2.addColorStop(0,"#e295c2");
    grd2.addColorStop(1, "white");

    // 绘制花瓣
    ctx.beginPath();
    ctx.moveTo(300, 50);
    // 三次贝塞尔曲线
    ctx.bezierCurveTo(300, 70, 220, 150, 300, 250);
    ctx.bezierCurveTo(320, 280, 400, 300, 430, 230);
    ctx.bezierCurveTo(440, 50, 320, 75, 300, 50);
    ctx.lineWidth = 1 // 线的宽度
    ctx.strokeStyle = grd // 线的颜色
    ctx.fillStyle= grd2 // 绘制花瓣的背景色 填充颜色
    ctx.fill();
    ctx.stroke()
    ctx.save()

如图:

image.png

画花瓣的纹理

花瓣的大致形状就出来了,但是我们还缺少,花瓣上有那种细小的纹理,所以也加上吧。纹理的组成是一条一条的曲线组成,同时也是线性渐变的。 纹理都是从一个点出发的,而且因为花瓣的颜色并不是很均匀的,所以加上阴影来模糊一下颜色。
因为存在很多条,我这边就不写调试的过程了,,所以就直接是封装成了一个数组进行遍历的。

// 线的颜色:线性渐变
    const grd=ctx.createLinearGradient(300, 100, 400, 200);
    grd.addColorStop(0, "rgb(221,172,222)");
    grd.addColorStop(1, "white");

    // 填充的颜色:放射状的渐变
    const grd2=ctx.createRadialGradient(300, 20, 100, 400, 300, 100);
    grd2.addColorStop(0,"#e295c2");
    grd2.addColorStop(1, "white");

    // 纹理线的颜色
    const grd3=ctx.createLinearGradient(300, 50, 400, 250);
    grd3.addColorStop(0, "rgb(217,179,208)");
    grd3.addColorStop(1, "rgb(255,255,255)");

    // 绘制花瓣
    ctx.beginPath();
    ctx.moveTo(300, 50);
    // 三次贝塞尔曲线
    ctx.bezierCurveTo(300, 70, 220, 150, 300, 250);
    ctx.bezierCurveTo(320, 280, 400, 300, 430, 230);
    ctx.bezierCurveTo(440, 50, 320, 75, 300, 50);
    ctx.lineWidth = 1 // 线的宽度
    ctx.shadowOffsetX = 12; // 线条阴影
    ctx.shadowBlur = 2; // 线条阴影
    ctx.shadowColor = grd // 线条阴影颜色
    ctx.strokeStyle = grd // 线的颜色
    ctx.fillStyle= grd2 // 绘制花瓣的背景色 填充颜色
    ctx.fill();
    ctx.stroke()

    const textureNumList: Array<number[]> = [
      [300, 60, 230, 150, 310, 260],
      [300, 70, 240, 150, 320, 265],
      [300, 80, 260, 150, 330, 269],
      [300, 90, 290, 150, 340, 270],
      [300, 90, 330, 150, 350, 275],
      [300, 90, 370, 120, 360, 275],
      [310, 100, 400, 110, 375, 275],
      [320, 100, 410, 84, 390, 270],
      [320, 94, 420, 60, 400, 266],
      [320, 90, 420, 40, 418, 248]
    ]

    // 花瓣的纹理
    textureNumList.forEach((textureNum:number[]) => {
      ctx.beginPath();
      ctx.moveTo(300, 50);
      ctx.bezierCurveTo(textureNum[0], textureNum[1], textureNum[2], textureNum[3], textureNum[4], textureNum[5]);
      ctx.lineWidth = 1 // 线的宽度
      ctx.strokeStyle = grd3 // 线的颜色
      ctx.stroke()
    })

    ctx.save()

如图:

image.png

画完整的荷花(耗时太久)

然后就是重复枯燥无味的工作, 不断调整,不断画线条。

简单说下,最下层的先画, 然后就是线条的不同的勾勒和上色

2天后。。。。。。。

荷花出来了

image.png

画根茎和荷叶(也是费时的工作)

经历了一个小时之后,我放弃了,太难画了,不是线条难画是颜色的深暗还有过度,所以简单画了一个先凑合吧😂😂😂😂, 不要嫌弃

附上代码:

总结

想法是好的,但是勾勒线条还有一些细节,颜色的调整太难了,只能说画出来的型似。