前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[译] 使用 DOMMatrix 绘制一个星星

[译] 使用 DOMMatrix 绘制一个星星

作者头像
小弟调调
发布2023-09-24 14:45:16
3270
发布2023-09-24 14:45:16
举报
文章被收录于专栏:埋名

使用 DOMMatrix 绘制一个星星 Drawing a star with DOMMatrix

最近我录制了一集关于 DOMPointDOMMatrix 的 HTTP 203 视频。如果你更喜欢观看视频版本,可以点击这里[1],但是请回到这里获取一些关于我犯了一个愚蠢错误的额外细节,而我几乎没有被发现。

I recently recorded an episode of HTTP 203 on DOMPoint and DOMMatrix. If you'd rather watch the video version, here it is, but come back here for some bonus details on a silly mistake I made, which I almost got away with.

DOMMatrix 允许你对 DOMPoints 应用变换。我发现这些 API 在绘制形状和处理变换结果时非常有用,而不会在 DOM 中引起完整的布局。

DOMMatrix lets you apply transformations to DOMPoints. I find these APIs handy for drawing shapes, and working with the result of transforms without causing full layouts in the DOM.

DOMPoint

这是 DOMPoint

Here's DOMPoint:

代码语言:javascript
复制
const point = new DOMPoint(10, 15); console.log(point.x); // 10 console.log(point.y); // 15 

是的!很令人兴奋,对吧?好的,也许 DOMPoint 单独来看并不那么有趣,所以让我们介绍一下 DOMMatrix

Yeah! Exciting right? Ok, maybe DOMPoint isn't interesting on its own, so let's bring in DOMMatrix:

DOMMatrix

代码语言:javascript
复制
const matrix = new DOMMatrix('translate(10px, 15px)').scale(2); console.log(matrix.a); // 2; 

DOMMatrix 允许你创建一个矩阵,可以选择从 CSS 变换中创建,并对其执行额外的变换操作。每个变换都会创建一个新的 DOMMatrix,但也有其他可以直接修改矩阵的方法[2],比如 scaleSelf()

DOMMatrix lets you create a matrix, optionally from a CSS transform, and perform additional transforms on it. Each transform creates a new DOMMatrix, but there are additional methods that mutate the matrix, such as scaleSelf().

当你结合使用 DOMMatrixDOMPoint 时,事情变得有趣起来:

Things start to get fun when you combine DOMMatrix and `DOMPoint:

代码语言:javascript
复制
const newPoint = matrix.transformPoint(point); 

我曾经在 Squoosh[3] 上使用这个方法来绘制 blob 形状,最近我还用它来绘制一个星星。

I used this to draw the blobs on Squoosh, but even more recently I used it to draw a star.

Drawing a star 绘制一个星星

我需要一个中心点位于确切中心的星星。我可以下载一个星星图案并检查中心点,但为什么不自己绘制呢?星星只是一个有尖角的圆形,对吧?不幸的是,我不能记住这种类型的数学公式,但这并不重要,因为我可以让 DOMMatrix 来帮我完成。

I needed a star where the center was in the exact center. I could download one and check the center point, but why not draw it myself? A star's just a spiky circle right? Unfortunately I can't remember the maths for this type of thing, but that doesn't matter, because I can get DOMMatrix to do it for me.

代码语言:javascript
复制
const createStar = ({ points = 10, x = 0, y = 0, size = 1 }) =>   Array.from({ length: points }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       .transformPoint({ x: 0, y: 0 }),   ); 

我正在使用 Array.from 创建和初始化一个数组。我希望有一种更友好的方式来做这个[4]。

I'm using Array.from to create and initialise an array. I wish there was a friendlier way to do this.

一个典型的星星有 10 个点 - 5 个外部点和 5 个内部点,但我觉得允许其他类型的星星也是不错的。

A typical star has 10 points – 5 outer points and 5 inner points, but I figured it'd be nice to allow other kinds of stars.

矩阵只有设置尺寸和位置的变换,所以它只会返回一堆以 x, y 为坐标的点。

The matrix only has transforms set to apply the size and position, so it's just going to return a bunch of points at x, y.

无论如何,这不会阻止我。我将在下面的 <svg> 元素中绘制它:

Anyway, I'm not going to let that stop me. I'm going to draw it in an <svg> element below:

代码语言:javascript
复制
const starPoints = createStar({ x: 50, y: 50, size: 23 }); const starPath = document.querySelector('.star-path'); starPath.setAttribute(   'd',   // SVG path syntax   `M ${starPoints.map((point) => `${point.x} ${point.y}`).join(', ')} z`, ); 

这是最终的结果:

And here's the result:

嗯,这是十个重叠在一起的点。并不完全是一个星星。好的,下一步:

So, err, that's 10 points on top of each other. Not exactly a star. Ok, next step:

代码语言:javascript
复制
const createStar = ({ points = 10, x = 0, y = 0, size = 1 }) =>   Array.from({ length: points }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       // Here's the new bit!       // 这是新的部分!       .translate(0, -1)       .transformPoint({ x: 0, y: 0 }),   ); 

这是结果:

And the result:

使用滑块在前一个状态和新状态之间进行过渡。我相信你会同意这种互动是值得的。

Use the slider to transition between the previous and new state. I'm sure you'll agree it was worth making this interactive.

好的,现在所有的点仍然重叠在一起。让我们来修复一下:

Ok, so all the points are still on stop of each other. Let's fix that:

代码语言:javascript
复制
const createStar = ({ points = 10, x = 0, y = 0, size = 1 }) =>   Array.from({ length: points }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       // Here's the new bit!       // 这是新的部分!       .rotate((i / points) * 360)       .translate(0, -1)       .transformPoint({ x: 0, y: 0 }),   ); 

我将每个点按照 360 度的一部分进行旋转。因此,第一个点旋转了 0/10 的 360 度,第二个点旋转了 1/10 的 360 度,然后是 2/10,以此类推。

I'm rotating each point by a fraction of 360 degrees. So the first point is rotated 0/10ths of 360 degrees, the second is rotated 1/10th, then 2/10ths and so on.

这是结果:

Here's the result:

现在我们有了一个形状!虽然不是一个星星,但我们正在取得进展。

Now we have a shape! It's not a star, but we're getting somewhere.

为了完成它,将一些点向外移动:

To finish it off, move some of the points outward:

代码语言:javascript
复制
const createStar = ({ points = 10, x = 0, y = 0, size = 1 }) =>   Array.from({ length: points }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       .rotate((i / points) * 360)       // Here's the new bit!       // 这是新的部分!       .translate(0, i % 2 ? -1 : -2)       .transformPoint({ x: 0, y: 0 }),   ); 

这是结果:

Here's the result:

这就是一个星星!

And that's a star!

But then I messed it up 但后来我搞砸了

当我为《HTTP 203》节目准备幻灯片时,我意识到 points 参数不太对。它允许你像这样使用:

As I was getting the slides together for the HTTP 203 episode, I realised that the points argument wasn't quite right. It lets you do something like this:

代码语言:javascript
复制
const starPoints = createStar({ points: 9, x: 50, y: 50, size: 23 }); 

看起来像这样:

Which looks like this:

这...不是一个星星。要创建一个有效的星星,点的数量必须是偶数。此外,到目前为止,我们创建的十个点的形状通常称为“五角星”,所以我改变了 API 以符合这种风格:

Which… isn't a star. The number of points has to be even to create a valid star. Besides, the ten-pointed shape we've been creating so far is typically called a "five-pointed star", so I changed the API to work in that style:

代码语言:javascript
复制
const createStar = ({ points = 5, x = 0, y = 0, size = 1 }) =>   Array.from({ length: points * 2 }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       .rotate((i / points) * 360)       .translate(0, i % 2 ? -1 : -2)       .transformPoint({ x: 0, y: 0 }),   ); 

我快速测试了一下代码,看起来没问题。但是...它还不太对。你能发现我引入的 bug 吗?我直到 Dillon Pentz 在 Twitter 上指出才注意到[5]:

I quickly tested the code, and it looked fine. But… it's not quite right. Can you see the bug I've introduced? I didn't notice it until Dillon Pentz pointed it out on Twitter[5]:

等等...如果数组循环中的索引满足 0 <= i < points * 2,那么通过 points 进行除法如何得到正确的星星呢?这样不是会围绕圆圈旋转两次吗? Wait… If the index in the array from loop is 0 <= i < points * 2, how does it produce the correct star when dividing by points? Doesn't that rotate around the circle twice?

他是对的!我在数组长度中正确地乘以了 points,但在 rotate 中忘记了这样做。我没有注意到它,因为对于奇数点的星星,它创建了一个几乎相同的形状。

And, he's right! I correctly multiply points for the array length, but I forgot to do it for the rotate. I didn't notice it, because for stars with odd-numbered points, it creates a shape that's almost identical.

上面的结果是我想要的。拖动滑块来查看代码实际上是如何工作的。

The above is the result I intended. Drag the slider to see what the code actually does.

这是一个正确的实现:

Here's a correct implementation:

代码语言:javascript
复制
const createStar = ({ points = 5, x = 0, y = 0, size = 1 }) => {   const length = points * 2;    return Array.from({ length }, (_, i) =>     new DOMMatrix()       .translate(x, y)       .scale(size)       .rotate((i / length) * 360)       .translate(0, i % 2 ? -1 : -2)       .transformPoint({ x: 0, y: 0 }),   ); }; 

我想故事的寓意是:不要在最后一刻改变幻灯片。

I guess the moral of the story is: Don't change slides at the last minute.

参考

  1. https://www.youtube.com/watch?v=VdNzD4lhidw&lc=Ugx4NRGM8QtqD5XwbEN4AaABAg
  2. https://drafts.fxtf.org/geometry/#dommatrix
  3. https://squoosh.app/
  4. https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/56
  5. https://twitter.com/Dillon_Pentz/status/1574771164249227271 2
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-09-23 19:41,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JSdig 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • DOMPoint
  • DOMMatrix
  • Drawing a star 绘制一个星星
  • But then I messed it up 但后来我搞砸了
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档