java线性渐变_图形处理:给 Canvas 文本填充线性渐变

5d1898151c1459bfd877f0a793bc9921.png

作者:凹凸曼 - Barrior

在 Canvas 中对文本填充水平或垂直的线性渐变可以轻易实现,而带角度的渐变就复杂很多;就好像下面这样,假设文本矩形宽为 W, 高为 H, 左上角坐标为 X, Y。

a3e5301b49c56f2c34bd34b87f3fa653.png

猜想与答案

给出两个答案:

64efdfff78c6a0b1e3992119a88be4e6.png

正确答案是图二,因为这样得出来的坐标生成的渐变最紧接文本矩形边界,它的运动轨迹如下动图:

e4d9ac2e8af677c64d947dd60efb7d3f.gif

(图来源:Do you really know CSS linear-gradients)

渐变起点与终点坐标的计算

所以,渐变的起点与终点坐标该怎么计算呢?答:

先求得起点与终点的长度(距离)。

根据长度与文本矩形的中心点坐标分别计算出起点与终点坐标。

线性渐变长度的计算 W3C 给出了一个公式(A 表示角度):

gradientLineLength = abs(W * sin(A)) + abs(H * cos(A))

不过,该公式主要应用于 CSS 的线性渐变设置,即以 12 点钟方向为 0°,顺时针旋转。

而我们需要的是以 3 点钟方向为 0°,逆时针旋转,即公式为:

gradientLineLength = abs(W * cos(A)) + abs(H * sin(A))

// 半长:

halfGradientLineLength = (abs(W * cos(A)) + abs(H * sin(A))) / 2

那么这个公式是怎么来的呢?以下是笔者的求解:

78e21322681b3b952390aca16d3abe77.png

由图可得以下方程组:

559ad81873af4655b3a8dd9f0e764e95.png

因此可推导出:

ccd51312abbba433e0fce9047b596ed1.png

化简后为:

200432492371f45b0daad89d916a7eb1.png

所以 c1 + c2 为:

cfdea5fc1df3f8e1c33717735d31b4fe.png

由三角函数平方公式知:cos(A) * cos(A) = 1 - sin(A) * sin(A), 代入 c1 + c2:

089a4445dcacfb36b2eadfdbeec26331.png

第一步化简后:

e6a34241d2195e70e2517a29f2a2db44.png

最后的结果就是:

b4fa552b85c823beee95d278c772dcd2.png

因为 sin, cos 在函数周期内存在负值(见下面角度对应的三角函数周期图),所以线性渐变的长度需要取绝对值。

至此,我们知道了线性渐变长度,文本矩形的中心点坐标很好算,即:

centerX = X + W / 2

centerY = Y + H / 2

所以,起点与终点的坐标分别为:

startX = centerX - cos(A) * halfGradientLineLength

startY = centerY + sin(A) * halfGradientLineLength

endX = centerX + cos(A) * halfGradientLineLength

endY = centerY - sin(A) * halfGradientLineLength

看看最终效果

5c3b8d37f5f329f0f8d359d226d12b1c.gif

经验注释

进行三角函数计算时,应尽量避免先用 tan, 因为 tan 在其周期内存在无穷值,需要做特定的条件判断,而 sin, cos 没有此类问题,代码书写更为简洁清晰并且不会因疏忽产生错误,见下面三角函数与角度的对应关系周期图。

e2b3cfdd17e46107e8e72bc52ed18dec.png

参阅:

欢迎关注凹凸实验室博客:aotu.io

或者关注凹凸实验室公众号(AOTULabs),不定时推送文章:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值