在 JavaScript 中用海龜圖形概念繪圖

翻譯:瘋狂的技術宅

原文:https://slicker.me/javascript...javascript

未經容許嚴禁轉載html

我曾經用 Python 海龜圖形生成過這個圖像,並有用 JavaScript 複製它的強烈衝動。前端

clipboard.png

對於那些不熟悉海龜圖形的人來講,這是一個使用虛擬「海龜」繪製圖形的概念,當海龜四處移動時,它的尾巴會在屏幕上留下痕跡。海龜有幾個簡單的命令:向前/向後移動 x 步,向左/向右轉 x 度等。java

因此例如這個序列:程序員

  • 前進100步
  • 向左轉90度
  • 前進100步
  • 向左轉90度
  • 前進100步
  • 向左轉90度
  • 前進100步

會畫一個正方形。每次移動後,烏龜的位置和方向都會更新,下一步移動將相對於以前的位置。有點相似於Canvas Path(你能夠有一系列的 lineTo),但 Path 只能使用笛卡爾座標(x 和 y)而不是方向(左/右/前/後)。面試

若是海龜朝北開始,左轉 90 度它將指向西。再左 90 度會指向南等。編程

能夠在 Logo(自20世紀60年代)和 Python 中使用海龜圖形,但不能在 JavaScript 中使用。canvas

但真的是這樣嗎?我忽然意識到 context.rotate 基本上模仿 「左轉/右轉」,而 context.translatemoveTo/drawTo 結合起來就像「前進/後退」同樣。segmentfault

這絕對不是一種優雅或可擴展的圖形編程方式 —— 有點像用蚯蚓綁鞋子:它看起來很酷,但只適用於某些條件。這些只是個人奇怪代碼集中的另外一個小發明。若是你玩真正的海龜圖形,我建議你使用提供這種功能的 JS 庫、Python 或 Logo。或者至少先建立移動和旋轉海龜的功能,以便使你的代碼可讀。數組

個人第一反應是建立一個具備本身的座標和方向的海龜對象,而後使用 trig 函數計算移動,可是 rotate/translate 解決方案確定更有趣,並容許我幾乎逐行翻譯 Python 程序:

首先,讓咱們看一下 rotate 和 translate 方法的工做原理。他們基本上改變了座標系:

  • rotate 旋轉一個角度
  • translate 經過向量移動它

It's easiest to see it in an example:
經過下面這個例子中最容易理解:

clipboard.png

<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>

如下這些參源能夠幫你瞭解更多圖形學方面的東西:

Optical illusion (18 lines)

Spinning squares - visual effect (25 lines)

Oldschool fire effect (20 lines)

Fireworks (60 lines)

Animated fractal (32 lines)

Minesweeper game (100 lines)

Physics engine for beginners

Physics engine - interactive sandbox

Physics engine - silly contraption

Starfield (21 lines)

Yin Yang with a twist (4 circles and 20 lines)

Tile map editor (70 lines)

Sine scroller (30 lines)

Interactive animated sprites

Image transition effect (16 lines)

Wholla lotta quadratic curves (50 lines)

Your first program in JavaScript: you need 5 minutes and a notepad


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索