翻译:疯狂的技术宅原文:https://slicker.me/javascript...
未经允许严禁转载
我曾经用 Python 海龟图形生成过这个图像,并有用 JavaScript 复制它的强烈冲动。
对于那些不熟悉海龟图形的人来说,这是一个使用虚拟“海龟”绘制图形的概念,当海龟四处移动时,它的尾巴会在屏幕上留下痕迹。海龟有几个简单的命令:向前/向后移动 x 步,向左/向右转 x 度等。
所以例如这个序列:
- 前进100步
- 向左转90度
- 前进100步
- 向左转90度
- 前进100步
- 向左转90度
- 前进100步
会画一个正方形。每次移动后,乌龟的位置和方向都会更新,下一步移动将相对于之前的位置。有点类似于Canvas Path(你可以有一系列的 lineTo),但 Path 只能使用笛卡尔坐标(x 和 y)而不是方向(左/右/前/后)。
如果海龟朝北开始,左转 90 度它将指向西。再左 90 度会指向南等。
可以在 Logo(自20世纪60年代)和 Python 中使用海龟图形,但不能在 JavaScript 中使用。
但真的是这样吗?我突然意识到 context.rotate
基本上模仿 “左转/右转”,而 context.translate
与 moveTo/drawTo
结合起来就像“前进/后退”一样。
这绝对不是一种优雅或可扩展的图形编程方式 —— 有点像用蚯蚓绑鞋子:它看起来很酷,但只适用于某些条件。这些只是我的奇怪代码集中的另一个小发明。如果你玩真正的海龟图形,我建议你使用提供这种功能的 JS 库、Python 或 Logo。或者至少先创建移动和旋转海龟的功能,以便使你的代码可读。
我的第一反应是创建一个具有自己的坐标和方向的海龟对象,然后使用 trig
函数计算移动,但是 rotate/translate 解决方案肯定更有趣,并允许我几乎逐行翻译 Python 程序:
首先,让我们看一下 rotate 和 translate 方法的工作原理。他们基本上改变了坐标系:
- rotate 旋转一个角度
- translate 通过向量移动它
It's easiest to see it in an example:
通过下面这个例子中最容易理解:
<html>
<style>
body { background-color: black;}
</style>
<body>
<canvas id='myCanvas' width='800' height='600'></canvas>
<script>
function line(x1, y1, x2, y2) {
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
}
function drawAxles() {
line(-length, 0, length, 0); // x axis
line(length * .9, length * .1, length, 0);
line(length * .9, -length * .1, length, 0);
line(0, -length, 0, length); // y axis
line(-length * .1, length * .9, 0, length);
line(length * .1, length * .9, 0, length);
}
let length = 100;
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
context.strokeStyle = 'white';
drawAxles();
context.translate(length * 3, length);
context.strokeStyle = 'blue';
drawAxles();
context.rotate(Math.PI / 8);
context.strokeStyle = 'red';
drawAxles();
context.translate(3 * length, 0);
context.strokeStyle = 'green';
drawAxles();
</script>
</body>
左上角的白色(半)箭头是 HTML5 Canvas 的标准初始 X(水平)和 Y 轴(垂直)。注意,Y 轴指向下方 —— 与你在学校学到的笛卡尔坐标系相反。
轴的负部分位于屏幕之外。
现在我们用 translate 来向右和向下移动坐标系 —— 也就是这些蓝色箭头。
接下来,我们将坐标系旋转几度并绘制红色箭头。请注意,原点(0, 0)仍然与蓝色原点位于同一位置。
最后,我们将系统在 x 轴上移动并将其绘制为绿色。请注意,上一步的轮换仍然适用。
现在让我们看看原始 Python 代码的 JavaScript 版本:
<html>
<style>
body { background-color: black;}
</style>
<canvas id='myCanvas' width='800' height='600'></canvas>
<body>
<script>
let colors = ['red', 'purple', 'blue', 'green', 'orange', 'yellow'];
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
context.scale(.3, .3);
context.translate(canvas.width, canvas.height);
for (let i = 0; i < 360; i++) {
context.strokeStyle = colors[i % 6];
context.lineWidth = i / 100 + 1;
context.beginPath();
context.moveTo(0, 0);
context.lineTo(0, i);
context.stroke();
context.translate(0, i);
context.rotate(-59 * (2 * Math.PI / 360));
}
</script>
</body>
</canvas>
在第[11]行中,我缩小了图像。否则如果我保留原始的 Python 维度,它将会非常大。
[12] 将“海龟”移到画布的右下角。
[13-22] 绘制螺旋的主循环
[14]通过颜色数组([8])循环
[15]随着螺旋的增长改变线宽。它几乎不可见。
[16-20] 通过 i
步长向前移动海龟。 [16-19] 画线,[20] 移动海龟。所以我们首先绘制线,并在事后更新“海龟”的位置。
当海龟离开中心时,线的长度变长。
[21] 将海龟旋转 59 度。负号只是为了保持螺旋方向。
现在让我们把螺旋旋转一下。只需几行代码就可以改变海龟转动的角度。我使用正弦函数[10]来实现,但如果你不是三角函数的粉丝,也可以使用不同的公式。甚至像 let rotation = counter / speed;
这样简单的东西产生有趣的结果(确保根据自己的喜好调整 [32] 中的速度)。
<html>
<style>
body { background-color: black;}
</style>
<body>
<canvas id='myCanvas' width='800' height='600'></canvas>
<script>
function animate() {
let rotation = (2 * Math.sin(counter / (3.14 * speed)));
context.setTransform(scale, 0, 0, scale, canvas.width / 2, canvas.height / 2);
context.clearRect(-canvas.width / 2, -canvas.height, canvas.width, canvas.height *2);
for (let i = 0; i < 360; i++) {
context.strokeStyle = colors[i % 6];
context.lineWidth = i / 100 + 1;
context.beginPath();
context.moveTo(0, 0);
context.lineTo(0, i);
context.stroke();
context.translate(0, i);
context.rotate((-60 + rotation) * 2 * Math.PI / 360);
}
window.requestAnimationFrame(animate);
counter++;
}
let colors = ['red', 'purple', 'blue', 'green', 'orange', 'yellow'];
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
let counter = 0;
let scale = .3;
let speed = 20;
animate();
</script>
</canvas>
</body>
以下这些参源可以帮你了解更多图形学方面的东西:
Spinning squares - visual effect (25 lines)
Oldschool fire effect (20 lines)
Physics engine - interactive sandbox
Physics engine - silly contraption
Yin Yang with a twist (4 circles and 20 lines)
Image transition effect (16 lines)
Wholla lotta quadratic curves (50 lines)
Your first program in JavaScript: you need 5 minutes and a notepad
本文首发微信公众号:前端先锋
欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章
欢迎继续阅读本专栏其它高赞文章:
- 深入理解Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13个帮你提高开发效率的现代CSS框架
- 快速上手BootstrapVue
- JavaScript引擎是如何工作的?从调用栈到Promise你需要知道的一切
- WebSocket实战:在 Node 和 React 之间进行实时通信
- 关于 Git 的 20 个面试题
- 深入解析 Node.js 的 console.log
- Node.js 究竟是什么?
- 30分钟用Node.js构建一个API服务器
- Javascript的对象拷贝
- 程序员30岁前月薪达不到30K,该何去何从
- 14个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩展插件
- Node.js 多线程完全指南
- 把HTML转成PDF的4个方案及实现
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。