mirror of
https://gitlab.com/Anson-Projects/projects.git
synced 2025-06-15 22:46:48 +00:00
make a cute little canvas to draw on and hook it up to some ojs
This commit is contained in:
parent
51c03d9213
commit
7cd96f1997
@ -2,8 +2,7 @@ const kProgressiveAttr = "data-src";
|
|||||||
let categoriesLoaded = false;
|
let categoriesLoaded = false;
|
||||||
|
|
||||||
window.quartoListingCategory = (category) => {
|
window.quartoListingCategory = (category) => {
|
||||||
// category is URI encoded in EJS template for UTF-8 support
|
category = atob(category);
|
||||||
category = decodeURIComponent(atob(category));
|
|
||||||
if (categoriesLoaded) {
|
if (categoriesLoaded) {
|
||||||
activateCategory(category);
|
activateCategory(category);
|
||||||
setCategoryHash(category);
|
setCategoryHash(category);
|
||||||
|
114
posts/2025-05-25-Brachistochrone/index.qmd
Normal file
114
posts/2025-05-25-Brachistochrone/index.qmd
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
title: "Brachistochrone"
|
||||||
|
description: |
|
||||||
|
Lets create a double pendulum in Observable JS!
|
||||||
|
date: 2025-05-09
|
||||||
|
categories:
|
||||||
|
- Observable JS
|
||||||
|
- Code
|
||||||
|
- Math
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text
|
||||||
|
|
||||||
|
:::{.column-screen}
|
||||||
|
```{ojs}
|
||||||
|
//| echo: false
|
||||||
|
|
||||||
|
|
||||||
|
viewof canvas = {
|
||||||
|
const height = 500;
|
||||||
|
const canvas = html`<canvas width=${width} height="${height}" style="border: 1px solid #ccc; cursor: crosshair;"></canvas>`;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let isDrawing = false;
|
||||||
|
let lastX = 0;
|
||||||
|
let lastY = 0;
|
||||||
|
let pathLength = 0;
|
||||||
|
let pathHistory = [{time: Date.now(), length: 0}];
|
||||||
|
|
||||||
|
// Drawing settings
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.lineCap = 'round';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
|
||||||
|
canvas.addEventListener('mousedown', (e) => {
|
||||||
|
if (!isDrawing) {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.arc(300, 100, 5, 0, 2 * Math.PI);
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
ctx.fill();
|
||||||
|
ctx.arc(600, 300, 5, 0, 2 * Math.PI);
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
ctx.fill();
|
||||||
|
pathLength = 0;
|
||||||
|
pathHistory = [{time: Date.now(), length: 0}];
|
||||||
|
canvas.value = {length: pathLength, history: pathHistory};
|
||||||
|
canvas.dispatchEvent(new CustomEvent("input"));
|
||||||
|
}
|
||||||
|
isDrawing = true;
|
||||||
|
[lastX, lastY] = [e.offsetX, e.offsetY];
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('mousemove', (e) => {
|
||||||
|
if (!isDrawing) return;
|
||||||
|
|
||||||
|
// Calculate distance
|
||||||
|
const distance = Math.sqrt(
|
||||||
|
Math.pow(e.offsetX - lastX, 2) +
|
||||||
|
Math.pow(e.offsetY - lastY, 2)
|
||||||
|
);
|
||||||
|
const angle = Math.atan2(e.offsetY - lastY, e.offsetX - lastX)
|
||||||
|
pathLength += distance;
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(lastX, lastY);
|
||||||
|
ctx.lineTo(e.offsetX, e.offsetY);
|
||||||
|
ctx.stroke();
|
||||||
|
[lastX, lastY] = [e.offsetX, e.offsetY];
|
||||||
|
|
||||||
|
// Update value and emit event
|
||||||
|
pathHistory.push({time: Date.now(), length: pathLength});
|
||||||
|
canvas.value = {length: pathLength, history: pathHistory};
|
||||||
|
canvas.dispatchEvent(new CustomEvent("input"));
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('mouseup', () => isDrawing = false);
|
||||||
|
canvas.addEventListener('mouseout', () => isDrawing = false);
|
||||||
|
|
||||||
|
// Initial value
|
||||||
|
canvas.value = {length: 0, history: pathHistory};
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```{ojs}
|
||||||
|
//| echo: false
|
||||||
|
md`Current path length: **${canvas.length?.toFixed(0) || 0} pixels**`
|
||||||
|
```
|
||||||
|
|
||||||
|
```{ojs}
|
||||||
|
//| echo: false
|
||||||
|
import {Plot} from "@observablehq/plot"
|
||||||
|
|
||||||
|
pathChart = Plot.plot({
|
||||||
|
width: width,
|
||||||
|
height: 200,
|
||||||
|
y: {label: "Path Length (pixels)"},
|
||||||
|
x: {label: "Time", type: "time"},
|
||||||
|
marks: [
|
||||||
|
Plot.line(canvas.history || [], {
|
||||||
|
x: "time",
|
||||||
|
y: "length",
|
||||||
|
stroke: "steelblue",
|
||||||
|
strokeWidth: 2
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text This is a bunch of text
|
Loading…
x
Reference in New Issue
Block a user