Základy JavaScriptu č. 8:Kreslení na plátno

Pamatujete si, když jsme mluvili o HTML a CSS, krátce jsme představili něco, čemu se říká SVG? Umožňuje nám vytvářet krásné obrázky jednoduše pomocí značek HTML. Dnes si představíme něco podobného, ​​co se nazývá canvas, s tím rozdílem, že nám to umožňuje používat javascript k tvorbě grafiky na webových stránkách. A protože místo jednoduchého značkovacího jazyka používá programovací jazyk, je plátno ve srovnání s SVG mnohem flexibilnější a výkonnější.

Plátno

Víme, že SVG má stromovou strukturu DOM a tvar, barva a pozice jsou reprezentovány pomocí HTML tagů. Plátno je však jeden jediný uzel HTML, ale zapouzdřuje prostor na webové stránce, kde můžete pomocí JavaScriptu vytvářet krásná umělecká díla. Tento prostor lze definovat pomocí <canvas> štítek. Zde je příklad, kdy vytvoříme jednoduchý obdélník uvnitř prostoru plátna:

<canvas width="300px" height="200px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  // Define the colour of the rectangle
  context.fillStyle = "red";

  // The first two parameters means that the top left corner of the ractagle is at coordinate (10, 10)
  // The last two parameters define the width and height of the ractangle (width:100px, height:50px)
  context.fillRect(10, 10, 100, 50);
</script>

getContext() metoda se používá pro přístup k rozhraní kreslení, které je jako sada nástrojů, kde jsou uložena vaše digitální pera a tužky. Parametr "2d" znamená dvourozměrnou grafiku. Pokud máte zájem o vytváření trojrozměrné grafiky, měli byste místo toho použít "webgl". Ale my se zatím soustředíme pouze na 2D systém.

Všimněte si také, že na začátku byla definována velikost plátna. Pokud to neuděláte, prvek canvas bude mít výchozí šířku 300 pixelů a výšku 150 pixelů.

Řádky

Obdélník, který jsme právě vytvořili, je plný, vnitřek obdélníku je vyplněný. Co když chceme něco jiného? Je také možné vytvořit obdélník, který je místo toho tažen, pomocí velmi podobné metody strokeRect() . Tato metoda také bere čtyři parametry, první dva definují pozici a poslední dva definují velikost.

<canvas></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  // Define the colour, position and size
  context.strokeStyle = "blue";
  context.strokeRect(10, 10, 100, 50);

  // Define the width of the strok and create a new rectangle
  context.lineWidth = 5;
  context.strokeRect(150, 10, 100, 50);
</script>

Cesty

Možná se teď divíte, že to není tak vzrušující, stejně snadno můžeme vytvářet obdélníky pomocí SVG. Nebojte se, skutečná síla plátna začíná nyní.

Nejprve musíme pochopit, co je to cesta. Cesta je posloupnost čar. Máme například řádek, který začíná od souřadnice (0, 0) do (0, 50), druhý řádek od (0, 50) do (80, 50) a třetí řádek od (80, 50) do ( 80, 100). Tyto tři řádky budou tvořit cestu.

Plátno nám umožňuje udělat něco takového:

<canvas width="500px" height="500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  context.lineWidth = 5;
  context.strokeStyle = "green";

  context.beginPath();

  // The path starts at (10, 10)
  context.moveTo(10, 10);

  // Drawing the path: (10, 10) -> (150, 10) -> (150, 150) -> (10, 150) -> (10,10)
  context.lineTo(150, 10);
  context.lineTo(150, 150);
  context.lineTo(10, 150);
  context.lineTo(10, 10);

  context.stroke();
</script>

Pomocí cest můžeme vytvořit libovolný tvar, jaký chceme. Například následující kód vytvoří trojúhelník:

<canvas width="500px" height="500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  context.beginPath();

  context.fillStyle = "red";

  context.moveTo(200, 10);
  context.lineTo(250, 100);
  context.lineTo(150, 100);
  context.lineTo(200, 10);

  context.fill();
</script>

Křivky

Cesta může být tvořena přímkami a může být také tvořena křivkami. Definovat křivku je však o něco obtížnější.

K definování křivky potřebujeme počáteční bod, cílový bod a kontrolní bod. Křivka neprochází přímo řídicím bodem, ale definuje bod, kterým prochází tečna počátečního a cílového bodu.

To je trochu těžké pochopit. Doporučuji, abyste se nejprve seznámili s nástrojem pero ve Photoshopu nebo s nástrojem cesty v GIMPu. Sdílejí stejný koncept, kromě toho, že když kódujete, musíte si představit, jak křivka vypadá.

Zde je další příklad. Nejprve nakreslíme křivku a poté nakreslíme tečné čáry a kontrolní bod, aby vám to pomohlo pochopit, co se zde děje:

<canvas width="500px" height="500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  context.beginPath();

  // start point = (10, 90)
  context.moveTo(10, 90);

  // control point = (60,10); destination point = (90,90)
  context.quadraticCurveTo(60, 10, 90, 90);

  // destination point tangent
  context.lineTo(60, 10);

  // start point tangent
  context.moveTo(10, 90);
  context.lineTo(60, 10);

  context.closePath();
  context.stroke();
</script>

Někdy chceme, aby tečna počátečního bodu a cílový bod měly různé řídicí body. Toho je také možné dosáhnout pomocí bezierCurveTo() metoda.

<canvas width="500px" height="500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  context.beginPath();

  // start point = (10, 90)
  context.moveTo(10, 90);

  // start control point = (60,10); destination control point = (30,80); destination point = (90,90)
  context.bezierCurveTo(60, 10, 30, 80, 90, 90);

  // destination point tangent
  context.lineTo(30, 80);

  // start point tangent
  context.moveTo(10, 90);
  context.lineTo(60, 10);

  context.closePath();
  context.stroke();
</script>

Texty

Texty mohou být také užitečné při vytváření grafů. Texty můžeme kreslit buď pomocí fillTextstrokeText . Ten pouze vykreslí obrys textů, místo aby jej vyplňoval.

<canvas width="1500px" height="500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  context.font = "28px Georgia";

  context.fillText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 10, 50);

  context.strokeText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 10, 100);
</script>

Poslední dva parametry udávají polohu textu, ale na rozdíl od kreslení tvarů definují souřadnici začátku účaří textu. Baseline je čára, na které text "stojí".

Transformace

Primárně existují tři typy transformací, překlad (translate() ), měřítko (scale() ) a rotace (rotate() ). Pamatujte, že tyto metody je třeba uvést před graf, který chcete transformovat.

Překlad přesune graf z jedné pozice na druhou:

<canvas width="1500px" height="1500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  // Move whatever graph created after to the right for 50px and downward for 100px
  context.translate(50, 100);

  // Create a graph
  context.beginPath();

  context.fillStyle = "red";

  context.moveTo(200, 10);
  context.lineTo(250, 100);
  context.lineTo(150, 100);
  context.lineTo(200, 10);

  context.fill();

</script>

Měřítko zvětší nebo zmenší původní graf:

<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  // Make the graph 2 times wider (along x-axis) 0.5 time shorter (along y-axis)
  context.scale(2, 1/2);

  // Create a graph
  ...

</script>

A nakonec můžeme graf otočit podél osy:

<canvas width="1500px" height="1500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  // Rotate the graph clockwise for 18 degrees. Notice that the rotate() method takes radian instead of degree.
  context.rotate(0.1 * Math.PI);

  // Create a graph
  ...

</script>

Bitmapová grafika

V počítačové grafice existuje něco, co se nazývá vektorová grafika a bitmapová grafika. Všechny grafy, o kterých jsme dosud mluvili, jsou vektorové grafiky. Jejich primární rozdíl je v tom, že bitmapová grafika je tvořena pixely, zatímco vektorová grafika nikoli. Místo toho jsou tvořeny cestami se směrem a velikostí (délkou), jako je vektor.

Někdy je však nutné, abychom do našeho vektorového grafického návrhu vložili nějakou bitmapovou grafiku. Můžeme to udělat pomocí drawImage() metoda.

<canvas width="1500px" height="1500px"></canvas>
<script>
  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");

  let img = document.createElement("img");
  img.src = "cat.jpg";

  img.addEventListener("load", () => {
    context.drawImage(img, 10, 10, 360, 240);
  });
</script>

V tomto příkladu bude obrázek nakreslen na souřadnici (10, 10) o velikosti 360px * 240px.

Potřebujeme přidat posluchač události, protože obrázek se načte po plátně bez něj, takže musíme nechat plátno počkat, až se obrázek načte jako první.