<div class="wrapper">
<canvas id="canvas" width="100%" height="100%"></canvas>
</div>
body {
margin: 0;
padding: 0;
height: 100vh;
position: relative;
overflow: hidden;
cursor: zoom-in;
}
.wrapper {
position: relative;
}
import {
createArtboard,
mouse,
wheel,
touch,
raf,
sticky,
clickZoom
} from "https://esm.sh/artboard-deluxe";
const canvas = document.getElementById("canvas");
const artboard = createArtboard(
canvas,
[
wheel({
useMomentumScroll: true,
useMomentumZoom: true
}),
mouse(),
touch(),
clickZoom(),
raf()
],
{
initTransform: {
x: window.innerWidth / 2 - 200,
y: window.innerHeight / 2 - 150,
scale: 0.5
},
overscrollBounds: 190
}
);
const plugin = artboard.addPlugin(
sticky({
target: { width: 140, height: 40 },
position: "top-left",
origin: "bottom-left",
keepVisible: true
})
);
artboard.setArtboardSize(800, 600);
function loop(time: number) {
window.requestAnimationFrame(loop);
const { offset, scale, artboardSize } = artboard.loop(time);
if (!artboardSize) {
return;
}
const width = window.innerWidth;
const height = window.innerHeight;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.globalAlpha = 1;
// Clear canvas.
ctx.clearRect(0, 0, width, height);
// Draw a grey background.
ctx.fillStyle = "#bcbcbc";
ctx.fillRect(0, 0, width, height);
// Multiply the current scale with the width and height to get the "actual"
// size of the artboard as it would appear.
const artboardWidth = Math.round(artboardSize!.width * scale);
const artboardHeight = Math.round(artboardSize!.height * scale);
// Draw the artboard.
ctx.fillStyle = "white";
// The offset is always unscaled, so we can keep it like this.
ctx.fillRect(offset.x, offset.y, artboardWidth, artboardHeight);
ctx.strokeStyle = "black";
ctx.lineWidth = 6;
ctx.strokeRect(offset.x, offset.y, artboardWidth, artboardHeight);
const circles = [
"#dc2626",
"#ea580c",
"#eab308",
"#84cc16",
"#14b8a6",
"#0284c7",
"#c026d3",
"#fca5a5"
];
for (let i = 0; i < circles.length; i++) {
ctx.fillStyle = circles[i];
ctx.beginPath();
const p = Math.sin(time / 500 + i * 92);
const ay = Math.cos(time / 900 + i * 324 + Math.sin(time / 3245)) * scale;
const ax = Math.sin(time / 300 + i + Math.cos(time / 2000)) * scale;
const radius = (20 + ((p + 1) / 2) * 50) * scale;
ctx.globalAlpha = (Math.sin(time / 500 + i * 1000) + 1) / 4 + 0.5;
ctx.arc(
offset.x + artboardWidth / 2 + ax * 200,
offset.y + artboardHeight / 2 + ay * 180,
radius,
0,
2 * Math.PI
);
ctx.fill();
}
const zoom =
"Zoom: " +
Math.round(scale * 100)
.toString()
.padStart(3, " ") +
"%";
ctx.globalAlpha = 1;
const stickyRect = plugin.getRect();
ctx.fillStyle = "black";
ctx.fillRect(stickyRect.x, stickyRect.y, stickyRect.width, stickyRect.height);
ctx.font = "20px monospace";
ctx.fillStyle = "white";
ctx.textRendering = "optimizeSpeed";
ctx.fillText(zoom, stickyRect.x + 10, stickyRect.y + 27);
}
window.requestAnimationFrame(loop);
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.