Voici donc le rendu final de l'API que nous aurons fait dans ce tutoriel :
background_color = "#000";
var maTortue = new Tortue();
maTortue.is_visible = false;
var angle = 0;
const SIDES = 6;
function hexagonSpiral() {
maTortue.pd();
for (var i = 0 ; i < 360 ; i++) {
maTortue.color("hsl("+ (((i % SIDES) * (360 / SIDES))) +",75%,"+Math.round(100*i/360)+"%)");
maTortue.width(i/120 + 1);
maTortue.forward(i);
maTortue.left(Math.floor(360/SIDES) - 1);
}
maTortue.pu();
}
function boucle() {
angle = (angle + 1) % 360;
maTortue.reset();
maTortue.right(angle);
hexagonSpiral();
}
setInterval(boucle, 5);
Remarquez que le < est devenu < car le navigateur web a convertit le symbole pendant le chargement de la page.
Vous aurez donc une erreur en lancant le script tel quel...
Code de l'API téléchargeable :
Sur ce lien.
Code de l'API en clair
class TurtleElement extends HTMLElement {
constructor() {
// On laisse le navigateur comprendre qu'il s'agit d'une balise html
super();
// On recupere le contenu de la balise et on l'efface
var code = this.innerHTML;
this.innerHTML = "";
// On crée un élément canvas
var child = document.createElement("canvas");
child.id = 'screen';
child.height = this.getAttribute("canvas-height") || "400";
child.width = this.getAttribute("canvas-width") || "400";
child.style.display = "block";
this.appendChild(child);
// On crée un élément textarea qui contient le code de départ
child = document.createElement("textarea");
child.value = code;
child.style.height = (this.getAttribute("textarea-height") || "100") + "px";
child.style.width = (this.getAttribute("textarea-width") || "400") + "px";
child.style.resize = "none";
child.style.color = "white";
child.style.backgroundColor = "black";
child.style.fontFamily = "monospace";
child.onkeydown = (event) => {
switch (event.key) {
case "Tab":
var v = child.value, s = child.selectionStart, e = child.selectionEnd;
child.value = v.substring(0, s) + ' ' + v.substring(e);
child.selectionStart = child.selectionEnd = s + 4;
return false;
case "Enter":
if (!event.shiftKey) {
var code = child.value;
child.value = "";
window.eval(code); // Where magic happens
event.preventDefault();
return false;
}
break;
}
};
this.appendChild(child);
}
}
customElements.define("turtle-js", TurtleElement);
// Variables globales
var screen = document.getElementById("screen");
var context = screen.getContext("2d");
var background_color = "#fff";
var tortues = new Array();
// Pour rafraichir l'ecran
function rafraichir() {
context.fillStyle = background_color;
context.fillRect(0, 0, screen.width, screen.height);
for (tortue of tortues) {
if (tortue.show_drawing) {
for (chemins of tortue.all_shapes) {
context.strokeStyle = chemins.color;
context.lineWidth = chemins.width;
context.stroke(chemins);
}
}
if (tortue.isvisible()) {
tortue.blitturtle(tortue.turtle_color);
}
}
}
var taux_de_rafraichissement = setInterval(rafraichir, 1);
function blitOnScreen () {
for (tortue of tortues) {
if (tortue.is_drawing) {
tortue.pu();
tortue.pd();
}
}
}
setInterval(blitOnScreen, 50);
// Nouvel objet :
class CheminTortue extends Path2D {
constructor(old) {
super(old);
if (old !== undefined) {
this.color = old.color;
this.width = old.width
} else {
this.color = "#000";
this.width = 2;
}
}
}
// Notre tortue
class Tortue {
constructor() {
// On définit les centres de l'écran
this.center_x = Math.floor(screen.width / 2);
this.center_y = Math.floor(screen.height / 2);
// On pose la tortue au centre de l'écran
this.x = this.center_x;
this.y = this.center_y;
// Variable d'état
this.is_drawing = false;
this.show_drawing = true;
this.has_moved = false;
this.angle = 0;
this.is_visible = true;
this.turtle_color = "black";
this.turtle_width = 2;
// Chemins à stocker
this.all_shapes = [new CheminTortue()];
tortues.push(this);
}
blitturtle(color) {
context.fillStyle = color;
context.beginPath();
context.moveTo(Math.round(this.x), Math.round(this.y));
context.lineTo(Math.round(this.x - 12 * Math.cos(Math.PI / 6 + Math.PI * (this.angle / 180))), Math.round(this.y + 12 * Math.sin(Math.PI / 6 + Math.PI * (this.angle / 180))));
context.lineTo(Math.round(this.x - 7 * Math.cos(Math.PI * (this.angle / 180))), Math.round(this.y + 7 * Math.sin(Math.PI * (this.angle / 180))));
context.lineTo(Math.round(this.x - 12 * Math.cos(Math.PI * (this.angle / 180) - Math.PI/6)), Math.round(this.y + 12 * Math.sin(Math.PI * (this.angle / 180) - Math.PI / 6)));
context.closePath();
context.fill();
}
showturtle() {
this.is_visible = true;
}
st() { return this.showturtle(); }
hideturtle() {
this.is_visible = false;
}
ht() { return this.hideturtle(); }
isvisible() { return this.is_visible; }
pendown() {
this.new_shape = new CheminTortue();
this.new_shape.color = this.turtle_color;
this.new_shape.width = this.turtle_width;
// Premier point du dessin
this.new_shape.moveTo(Math.round(this.x), Math.round(this.y));
this.is_drawing = true;
this.has_moved = false;
}
// Equivalents
pd() { return this.pendown(); }
down() { return this.pendown(); }
penup() {
// On ferme le chemin
this.new_shape.closePath();
// On ajoute une copie du chemin crée pour éviter les bugs de reference
this.all_shapes.push(new CheminTortue(this.new_shape));
this.is_drawing = false;
this.has_moved = false;
}
// Equivalents
pu() { return this.penup(); }
up() { return this.penup(); }
color(clr) {
if (this.has_moved) {
this.new_shape.closePath();
this.all_shapes.push(new CheminTortue(this.new_shape));
this.new_shape = new CheminTortue();
this.new_shape.moveTo(Math.round(this.x), Math.round(this.y));
}
if (this.is_drawing) {
this.new_shape.color = clr;
}
this.turtle_color = clr;
this.has_moved = false;
}
width(wdt) {
if (this.has_moved) {
this.new_shape.closePath();
this.all_shapes.push(new CheminTortue(this.new_shape));
this.new_shape = new CheminTortue();
this.new_shape.moveTo(Math.round(this.x), Math.round(this.y));
}
if (this.is_drawing) {
this.new_shape.width = Math.floor(wdt);
}
this.turtle_width = wdt;
this.has_moved = false;
}
reset() {
this.clear();
this.color("#000");
this.width(2);
this.x = this.center_x;
this.y = this.center_y;
this.angle = 0;
}
clear() {
if (!this.is_drawing) {
this.pendown();
}
this.penup();
this.all_shapes = [new CheminTortue()];
}
forward(len) {
// On change de position
this.x += len * Math.cos(Math.PI * (this.angle / 180));
this.y -= len * Math.sin(Math.PI * (this.angle / 180));
// On dessine la ligne
if (this.is_drawing) {
this.new_shape.lineTo(Math.round(this.x), Math.round(this.y));
this.has_moved = true;
}
}
// Equivalents et opposés
fd(len) { return this.forward(len); }
backward(len) {
this.angle = 180 + this.angle;
this.forward(len);
this.angle = this.angle - 180;
}
bk(len) { return this.backward(len); }
back(len) { return this.backward(len); }
goto(x, y) {
this.x = x;
this.y = y;
// On dessine la ligne
if (this.is_drawing) {
this.new_shape.lineTo(Math.round(this.x), Math.round(this.y));
this.has_moved = true;
}
}
left(angle) {
// Modulo toujours positif
this.angle = (((this.angle + angle) % 360) + 360) % 360;
}
// Equivalents et opposés
lt(angle) { return this.left(angle); }
right(angle) { return this.left(-angle); }
rt(angle) { return this.left(-angle); }
}