Published
Edited
Feb 1, 2018
1 fork
17 stars
Insert cell
Insert cell
createCanvas = () => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
return { canvas, context };
}
Insert cell
Insert cell
resize = (canvas) => {
// Desired width and height in pixels
const width = 256;
const height = 256;
// Device screen density, e.g. MacBook Pro is @2x
const pixelRatio = window.devicePixelRatio;
// Scale it up by pixel ratio for higher density screens
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
// Set the style to the desired size so that it scales back down
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;

return { width, height, pixelRatio };
}
Insert cell
Insert cell
square = {
// Create the canvas and context
const { canvas, context } = createCanvas();
// Resize the canvas, this returns the new size
const { width, height, pixelRatio } = resize(canvas);

// Scale the 2D context by the pixel ratio so we can work in regular pixels
context.scale(pixelRatio, pixelRatio);

// Fill the canvas with black
context.fillStyle = 'black';
context.fillRect(0, 0, width, height);
// Draw a small square at (50, 50)
context.fillStyle = 'white';
context.fillRect(50, 50, 15, 15);

// Return the canvas so it's visible on screen
return canvas;
}
Insert cell
Insert cell
animatedSquare = {
// Create the canvas and context
const { canvas, context } = createCanvas();
// Resize the canvas, this returns the new size
const { width, height, pixelRatio } = resize(canvas);

function render (time = 0) {
// Request another animation frame, so that the drawing loops continuously
window.requestAnimationFrame(render);

// Convert milliseconds to seconds
time /= 1000;

// Save the context state before scaling
context.save();
// Scale the 2D context by the pixel ratio so we can work in regular pixels
context.scale(pixelRatio, pixelRatio);
// Draw into our canvas context
// Fill the canvas with black
context.fillStyle = 'black';
context.fillRect(0, 0, width, height);

// Draw a small square at (x, 50)
const x = width / 2 + Math.sin(time) * width / 4;
context.fillStyle = 'white';
context.fillRect(x, 50, 15, 15);

// Restore the earlier state, so that the scale is reset to 1 for the next frame
context.restore();
}

// Start the render loop
window.requestAnimationFrame(render);

// Return the canvas so it's visible on screen
return canvas;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
draw = (context, width, height, time = 0) => {
context.fillStyle = 'black';
context.fillRect(0, 0, width, height);

// How much to increase/decrease the radius, in pixels
const radiusOffset = Math.sin(time) * 10;

// Our circle radius
const radius = width * 0.33 + radiusOffset;

// Number of sides in our circle geometry
const steps = 9;
// Let's rotate the circle clockwise slowly
const spin = time * 0.15;

// This lets the context know we are starting to build a polygon
context.beginPath();
// Now we need to define each vertex in our circle geometry
for (let i = 0; i < steps; i++) {
// Find out how far along we are in our circle
const t = i / steps;
// To create a full circle, we multiply `t` by 2PI
// Then we offset the angle by the total spin
const angle = t * Math.PI * 2 + spin;
// Define the coordinates for a unit circle in -1..1 space
const cx = Math.cos(angle) * radius;
const cy = Math.sin(angle) * radius;

// Translate that unit circle into the center of canvas
const x = cx + width / 2;
const y = cy + height / 2;
// Draw a line to this vertex
context.lineTo(x, y);
}

// Now draw the last line to close the shape
context.closePath();
// Once a shape is drawn, we can stroke (or fill) it
context.strokeStyle = 'white';

// We can also specify the thickness of the stroke, in pixels
context.lineWidth = 8;
// Finally, apply the stroke() command to draw the polygon
context.stroke();
}
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more