Public
Edited
Jun 10, 2023
Importers
Insert cell
Insert cell
Insert cell
{
// Initialize the turtle and the drawing surface
const turtle = new Turtle({
width: 200,
height: 200,
backgroundColor: "#fafafa"
});

// Set the pen color and size, and move the turtle to
// its initial position
turtle.grid().penColor("black").penSize(2);
turtle.moveTo(50, 50);

// Draw a side of the square and turn 90 degrees
for (let k = 0; k <= 4; k = k + 1) {
turtle.forward(100).right(90);
}

// Return the drawing (a canvas element)
return turtle.draw();
}
Insert cell
Insert cell
image = {
const width = 600;
const height = width;
const turtle = new Turtle({ width, height, backgroundColor: "#222" });
turtle.moveTo(width / 2, height / 2);


for (let k = 0; k < 720; k = k + 1) {
turtle
.penColor(colors[k % colors.length])
.segment(k)
.left(59);
}

return turtle.draw();
}
Insert cell
{
const width = 600;
const height = 400;
const t = new Turtle({ width, height, backgroundColor: "#222" });

for (let k = 0; k < height; k = k + 10) {
const r = k;
const dx = _.random(-20, 20);
const dy = _.random(-20, 20);
t.moveTo(width / 2 + dx, height / 2 + dy)
.penColor(colors[k % colors.length])
.circle(k);
}

return t.draw();
}
Insert cell
{
const width = 600;
const height = 400;
const t = new Turtle({ width, height, backgroundColor: "#222" });

t.moveTo(0, height / 2);
for (let x = 0; x < width; x = x + 10) {
t.penColor(colors[x % colors.length])
.moveTo(x, height / 2)
.circle(10000 / x);
}

return t.draw();
}
Insert cell
smiley = {
const width = 250;
const height = 250;
const cx = width / 2;
const cy = height / 2;

const t = new Turtle({ width, height, backgroundColor: "#222" });
t.penColor("yellow").penSize(3);

// Outer circle
t.moveTo(cx, cy).circle(100);

// Mouth (clockwise)
t.moveTo(cx, cy).arc(60, 15, 180 - 15, false);

// Eyes
t.moveTo(cx - 32, cy - 28).circle(5);
t.moveTo(cx + 32, cy - 28).circle(5);

return t.draw();
}
Insert cell
lines = {
const [width, height] = [600, 600];

const turtle = new Turtle({ width, height, backgroundColor: "#222" });
turtle.moveTo(0, 0);

for (let k = 0; k < height; k = k + 10) {
turtle
.penColor(colors[k % colors.length])
.moveTo(0, k)
.lineTo(width - k, 0)
.moveTo(k, height)
.lineTo(width, height - k);
}

return turtle.draw();
}
Insert cell
class Turtle {
/**
*
*/
constructor(options = {}) {
const DEFAULT_OPTIONS = {
width: 600,
height: 600,
gridColor: "#ddd",
backgroundColor: "#fafafa",
x: 300,
y: 300,
angle: 0
};
this.options = { ...DEFAULT_OPTIONS, ...options };

const { x, y, angle, width, height } = this.options;
this.ctx = DOM.context2d(width, height);
this.backgroundColor(this.options.backgroundColor);

this.x = x;
this.y = y;
this.angle = angle;
}

// Move and Draw
forward(distance) {
return this.segment(distance);
}

backward(distance) {
return this.segment(-1 * distance);
}

right(angle) {
return this.rotate(angle);
}

left(angle) {
return this.rotate(-1 * angle);
}

goto(x, y) {
return this.moveTo(x, y);
}

home() {
this.x = this.options.x;
this.y = this.options.y;
this.angle = this.options.angle;
}

circle(radius) {
return this.arc(radius);
}

dot(size = 1) {
return this.circle(1);
}

// Turtle State
position() {
return { x: this.x, y: this.y };
}

// Pen

penColor(color = "black") {
this.ctx.strokeStyle = color;
return this;
}

penSize(lineWidth = 1) {
this.ctx.lineWidth = lineWidth;
return this;
}

// lineCap
// lineJoin
// miterLimit
// getLineDash, setLineDash
// lineDashOffset

// fillColor() {}
// Filling

// reset() {}
// clear() {}
// write() {}

// Debug Mode
/**
* grid - Draws grid lines and tick labels in the canvas area.
*
* By default, lines will be spaced by 50 pixels. The color of the grid
* is controlled by the `gridColor` option.
*
* @param {number} dx - Distance between horizontal grid lines.
* @param {number} dy - Distance between vertical the grid lines.
*/
grid(dx = 50, dy = 50) {
const { width, height, gridColor } = this.options;

// TODO: Restore stroke, fill and font
this.penColor(gridColor);
this.ctx.fillStyle = "#777";
this.ctx.font = "monospace";

_.range(0, width + dx, dx).forEach((x) => {
this.moveTo(x, 0)
.lineTo(x, height)
.text(x, x + 2, 10);
});

_.range(0, height + dy, dy).forEach((y) => {
this.moveTo(0, y)
.lineTo(width, y)
.text(y, 2, y - 3);
});

return this;
}

// Basic drawing

// Primitives

move(distance) {
const rad = this.rad(this.angle);
const x = this.x + distance * Math.cos(rad);
const y = this.y + distance * Math.sin(rad);
this.moveTo(x, y);
return this;
}

moveTo(x, y) {
this.x = x;
this.y = y;
return this;
}

lineTo(x, y) {
this.ctx.beginPath();
this.ctx.moveTo(this.x, this.y);
this.ctx.lineTo(x, y);
this.ctx.stroke();
this.x = x;
this.y = y;
return this;
}

segment(distance) {
const rad = this.rad(this.angle);
const x = this.x + distance * Math.cos(rad);
const y = this.y + distance * Math.sin(rad);
this.lineTo(x, y);
return this;
}

rotate(deg) {
this.angle = this.angle + deg;
return this;
}

arc(radius, startAngle = 0, endAngle = 360, counterclockwise = true) {
this.ctx.beginPath();
this.ctx.arc(
this.x,
this.y,
radius,
this.rad(startAngle),
this.rad(endAngle),
counterclockwise
);
this.ctx.stroke();
return this;
}

backgroundColor(color = "#333") {
const { width, height } = this.options;
this.ctx.fillStyle = color;
this.ctx.fillRect(0, 0, width, height);
return this;
}

// Text
// font
// textAlign
// textbaseline
// direction

// save
// restore
// translate
// rotate
// scale

text(text, x, y) {
this.ctx.fillText(text, x, y);
return this;
}

// Utils
rad(deg) {
return (Math.PI / 180) * deg;
}

// Returns the canvas elements with the drawing
draw() {
return this.ctx.canvas;
}
}
Insert cell
colors =
["#6e40aa","#7140ab","#743fac","#773fad","#7a3fae","#7d3faf","#803eb0","#833eb0","#873eb1","#8a3eb2","#8d3eb2","#903db2","#943db3","#973db3","#9a3db3","#9d3db3","#a13db3","#a43db3","#a73cb3","#aa3cb2","#ae3cb2","#b13cb2","#b43cb1","#b73cb0","#ba3cb0","#be3caf","#c13dae","#c43dad","#c73dac","#ca3dab","#cd3daa","#d03ea9","#d33ea7","#d53ea6","#d83fa4","#db3fa3","#de3fa1","#e040a0","#e3409e","#e5419c","#e8429a","#ea4298","#ed4396","#ef4494","#f14592","#f34590","#f5468e","#f7478c","#f9488a","#fb4987","#fd4a85","#fe4b83","#ff4d80","#ff4e7e","#ff4f7b","#ff5079","#ff5276","#ff5374","#ff5572","#ff566f","#ff586d","#ff596a","#ff5b68","#ff5d65","#ff5e63","#ff6060","#ff625e","#ff645b","#ff6659","#ff6857","#ff6a54","#ff6c52","#ff6e50","#ff704e","#ff724c","#ff744a","#ff7648","#ff7946","#ff7b44","#ff7d42","#ff8040","#ff823e","#ff843d","#ff873b","#ff893a","#ff8c38","#ff8e37","#fe9136","#fd9334","#fb9633","#f99832","#f89b32","#f69d31","#f4a030","#f2a32f","#f0a52f","#eea82f","#ecaa2e","#eaad2e","#e8b02e","#e6b22e","#e4b52e","#e2b72f","#e0ba2f","#debc30","#dbbf30","#d9c131","#d7c432","#d5c633","#d3c934","#d1cb35","#cece36","#ccd038","#cad239","#c8d53b","#c6d73c","#c4d93e","#c2db40","#c0dd42","#bee044","#bce247","#bae449","#b8e64b","#b6e84e","#b5ea51","#b3eb53","#b1ed56","#b0ef59","#adf05a","#aaf159","#a6f159","#a2f258","#9ef258","#9af357","#96f357","#93f457","#8ff457","#8bf457","#87f557","#83f557","#80f558","#7cf658","#78f659","#74f65a","#71f65b","#6df65c","#6af75d","#66f75e","#63f75f","#5ff761","#5cf662","#59f664","#55f665","#52f667","#4ff669","#4cf56a","#49f56c","#46f46e","#43f470","#41f373","#3ef375","#3bf277","#39f279","#37f17c","#34f07e","#32ef80","#30ee83","#2eed85","#2cec88","#2aeb8a","#28ea8d","#27e98f","#25e892","#24e795","#22e597","#21e49a","#20e29d","#1fe19f","#1edfa2","#1ddea4","#1cdca7","#1bdbaa","#1bd9ac","#1ad7af","#1ad5b1","#1ad4b4","#19d2b6","#19d0b8","#19cebb","#19ccbd","#19cabf","#1ac8c1","#1ac6c4","#1ac4c6","#1bc2c8","#1bbfca","#1cbdcc","#1dbbcd","#1db9cf","#1eb6d1","#1fb4d2","#20b2d4","#21afd5","#22add7","#23abd8","#25a8d9","#26a6db","#27a4dc","#29a1dd","#2a9fdd","#2b9cde","#2d9adf","#2e98e0","#3095e0","#3293e1","#3390e1","#358ee1","#378ce1","#3889e1","#3a87e1","#3c84e1","#3d82e1","#3f80e1","#417de0","#437be0","#4479df","#4676df","#4874de","#4a72dd","#4b70dc","#4d6ddb","#4f6bda","#5169d9","#5267d7","#5465d6","#5663d5","#5761d3","#595fd1","#5a5dd0","#5c5bce","#5d59cc","#5f57ca","#6055c8","#6153c6","#6351c4","#6450c2","#654ec0","#664cbe","#674abb","#6849b9","#6a47b7","#6a46b4","#6b44b2","#6c43af","#6d41ad","#6e40aa"]
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more