手把手教你实现手绘风格图形,HTML实体字符列表

本文详细介绍了如何使用HTML和JavaScript实现手绘风格的图形,包括线段、多边形、矩形和圆的绘制,通过调整贝塞尔曲线控制点实现随机曲线效果,以及填充算法的原理和实现。
摘要由CSDN通过智能技术生成

})

this.rc.rectangle(225, 270, 80, 30, {

fill: ‘red’,

fillweight: 5

})

this.rc.line(200, 150, 150, 80, { roughness: 5 })

this.rc.line(300, 150, 350, 80, { roughness: 2 })

效果如下:d9cd33a374879ad3fc97fab976d453ed.png是不是有点蠢萌,本文的主要内容是带大家手动实现上面的图形,最终效果预览:lxqnsys.com/#/demo/hand…[2]。话不多说,代码见。

线段

万物基于线段,所以先来看线段怎么画,仔细看上图会发现手绘版线段其实是用两根弯曲的线段组成的,曲线可以使用贝塞尔曲线来画,这里使用三次贝塞尔曲线,那么剩下的问题就是求起点、终点、两个控制点的坐标了。贝塞尔曲线可以在这个网站上尝试:cubic-bezier.com/[3]。首先一条线段的起点和终点我们都给它加一点随机值,随机值比如就在[-2,2]之间,也可以把这个范围和线段的长度关联起来,比如线段越长,随机值就越大。

// 直线变曲线

_line (x1, y1, x2, y2) {

let result = []

// 起始点

result[0] = x1 + this.random(-this.offset, this.offset)

result[1] = y1 + this.random(-this.offset, this.offset)

// 终点

result[2] = x2 + this.random(-this.offset, this.offset)

result[3] = y2 + this.random(-this.offset, this.offset)

}

接下来就是两个控制点,我们把控制点限定在线段所在的矩形内:235e938454e6cc22acffa52e196377fe.png

_line (x1, y1, x2, y2) {

let result = []

// 起始点

// …

// 终点

// …

// 两个控制点

let xo = x2 - x1

let yo = y2 - y1

let randomFn = (x) => {

return x > 0 ? this.random(0, x) : this.random(x, 0)

}

result[4] = x1 + randomFn(xo)

result[5] = y1 + randomFn(yo)

result[6] = x1 + randomFn(xo)

result[7] = y1 + randomFn(yo)

return result

}

然后把上面生成的曲线绘制出来:

// 绘制手绘线段

line (x1, y1, x2, y2) {

this.drawDoubleLine(x1, y1, x2, y2)

}

// 绘制两条曲线

drawDoubleLine (x1, y1, x2, y2) {

// 绘制生成的两条曲线

let line1 = this._line(x1, y1, x2, y2)

let line2 = this._line(x1, y1, x2, y2)

this.drawLine(line1)

this.drawLine(line2)

}

// 绘制单条曲线

drawLine (line) {

this.ctx.beginPath()

this.ctx.moveTo(line[0], line[1])

// bezierCurveTo方法前两个点为控制点,第三个点为结束点

this.ctx.bezierCurveTo(line[4], line[5], line[6], line[7], line[2], line[3])

this.ctx.strokeStyle = ‘#000’

this.ctx.stroke()

}

效果如下:5eda5023fe62a10d190c6a6122170ba4.png但是多试几次就会发现偏离太远、弯曲程度过大:f5528e28b39f8c65e39b951719460dcd.png完全不像一个手正常的人能画出来的,去上面的贝塞尔曲线网站上试几次会发现两个控制点离线段越近,曲线弯曲程度越小:00bef49c01a3c6fa63de3f8fda37ec60.png所以我们要找线段附近的点作为控制点,首先随机一个横坐标点,然后可以计算出线段上该横坐标对应的纵坐标点,把该纵坐标点加减一点随机值即可。

_line (x1, y1, x2, y2) {

let result = []

// …

// 两个控制点

let c1 = this.getNearRandomPoint(x1, y1, x2, y2)

let c2 = this.getNearRandomPoint(x1, y1, x2, y2)

result[4] = c1[0]

result[5] = c1[1]

result[6] = c2[0]

result[7] = c2[1]

return result

}

// 计算两个点连成的线段上附近的一个随机点

getNearRandomPoint (x1, y1, x2, y2) {

let xo, yo, rx, ry

// 垂直x轴的线段特殊处理

if (x1 === x2) {

yo = y2 - y1

rx = x1 + this.random(-2, 2)// 在横坐标附近找一个随机点

ry = y1 + yo * this.random(0, 1)// 在线段上找一个随机点

return [rx, ry]

}

xo = x2 - x1

rx = x1 + xo * this.random(0, 1)// 找一个随机的横坐标

ry = ((rx - x1) * (y2 - y1)) / (x2 - x1) + y1// 通过两点式求出直线方程

ry += this.random(-2, 2)// 纵坐标加一点随机值

return [rx, ry]

}

看一下效果:730e3578ee2ef3009d04c0ced345abf8.png当然和Rough.js比起来还是不够好,有兴趣的可以自行去看一下源码,反正笔者是看不懂,控制变量太多,还没有注释。

多边形&矩形


多边形就是把多个点首尾相连起来,遍历顶点调用绘制线段的方法即可:

// 绘制手绘多边形

polygon (points = [], opt = {}) {

if (points.length < 3) {

return

}

let len = points.length

for (let i = 0; i < len - 1; i++) {

this.line(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1])

}

// 首尾相连

this.line(points[len - 1][0], points[len - 1][1], points[0][0], points[0][1])

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值