This commit is contained in:
Ricky Reusser 2022-12-27 19:02:04 -08:00
parent a215b1ffc9
commit 11c35bad89
71 changed files with 271 additions and 246 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,13 @@
<!DOCTYPE html><html lang="en" dir="ltr"><head><title>Cubic Polynomial ↔︎ Equilateral Triangle</title><meta charset="utf-8"><meta name="application-name" content="Cubic Polynomial ↔︎ Equilateral Triangle">
<!DOCTYPE html><html lang="en" dir="ltr"><head><title>Cubic Roots ↔︎ Equilateral Triangle</title><meta charset="utf-8"><meta name="application-name" content="Cubic Roots ↔︎ Equilateral Triangle">
<meta name="subject" content="An interactive reproduction of a diagram by Freya Holmér">
<meta name="abstract" content="An interactive reproduction of a diagram by Freya Holmér">
<meta name="twitter:title" content="Cubic Polynomial ↔︎ Equilateral Triangle">
<meta name="twitter:title" content="Cubic Roots ↔︎ Equilateral Triangle">
<meta name="description" content="An interactive reproduction of a diagram by Freya Holmér">
<meta name="twitter:description" content="An interactive reproduction of a diagram by Freya Holmér">
<meta name="author" content="Ricky Reusser">
<meta name="twitter:creator" content="Ricky Reusser">
<meta name="twitter:card" content="summary">
<meta property="og:title" content="Cubic Polynomial ↔︎ Equilateral Triangle">
<meta property="og:title" content="Cubic Roots ↔︎ Equilateral Triangle">
<meta property="og:description" content="An interactive reproduction of a diagram by Freya Holmér">
<meta property="article:author" content="Ricky Reusser">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" /></head><body><script src="bundle.js"></script><script src="../nav.bundle.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -6,7 +6,7 @@ const glslify = require('glslify');
const babelify = require('babelify');
const assert = require('assert');
const mkdirp = require('mkdirp');
//const Idyll = require('idyll');
const Idyll = require('idyll');
const path = require('path');
const budo = require('budo');
const brfs = require('brfs');

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Gallery extends React.Component {
render () {

View File

@ -1,5 +1,5 @@
import React from 'react';
import projectsIndex from '../../src/sketches/index.json';
const React = require('react');
const projectsIndex = require('../../src/sketches/index.json');
class ProjectIndex extends React.Component {
render () {

View File

@ -1,5 +1,5 @@
import React from 'react';
import projectsIndex from '../../src/sketches/index.json';
const React = require('react');
const projectsIndex = require('../../src/sketches/index.json');
class Thumbnail extends React.Component {
render () {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Action extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Analytics extends React.PureComponent {
componentDidMount() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Aside extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Boolean extends React.PureComponent {
constructor(props) {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Button extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const V = require('victory');
const d3Arr = require('d3-array');

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
import SyntaxHighlighter from "react-syntax-highlighter/dist/light";
import style from 'react-syntax-highlighter/dist/styles/atom-one-dark';

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const Format = require('d3-format');
class Display extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
const Format = require('d3-format');
const Drag = require('d3-drag');

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
const Latex = require('react-latex-patched');
const select = require('d3-selection').select;

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
import regl from 'regl';
import mat4lookAt from 'gl-mat4/lookAt'
import mat4perspective from 'gl-mat4/perspective'

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
import ReactDOM from 'react-dom';
const stateClasses = [

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Fixed extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Float extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Footer extends React.PureComponent {
render () {

View File

@ -1,5 +1,4 @@
import React from 'react';
const React = require('react');
import ReactDOM from 'react-dom';
import Screen from './utils/screen';

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const PropTypes = require('prop-types');
class EmbeddedGist extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
import classNames from 'classnames';
import resl from 'resl';

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Inline extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Link extends React.PureComponent {
constructor(props) {

View File

@ -1,5 +1,5 @@
import React from 'react';
import classNames from 'classnames';
const React = require('react');
const classNames = require('classnames');
class Menu extends React.Component {
constructor (props) {

View File

@ -1,5 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
class Panel extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
const imageCache = [];

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
let id = 0;

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Range extends React.PureComponent {
constructor(props) {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
class Select extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class Slide extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const Slide = require('./slide');
class Slideshow extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
import InlineSVG from 'react-inlinesvg';
class SVG extends React.PureComponent {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
class TextContainer extends React.PureComponent {
render() {

View File

@ -1,4 +1,4 @@
import React from 'react';
const React = require('react');
const ReactDOM = require('react-dom');
class TextInput extends React.PureComponent {

View File

@ -89,6 +89,7 @@
"util-extend": "^1.0.3"
},
"dependencies": {
"@babel/preset-react": "^7.18.6",
"color-parse": "^1.3.7",
"color-rgba": "^2.1.0",
"color-stringify": "^1.2.1",

View File

@ -21,6 +21,24 @@ const regl = require('regl')({
onDone: require('fail-nicely')(run)
});
const exp = document.createElement('div');
exp.innerHTML = `
A reproduction of a <a href="https://mathstodon.xyz/@acegikmo@mastodon.social/109404591773876307">diagram by Freya Holmér</a> showing the relation between cubic polynomials and an equilateral triangle.
`;
document.body.appendChild(exp);
exp.style.cssText = `
position: absolute;
bottom: 0;
left: 0;
padding: 5px;
pointer-events: none;
background-color: rgb(237 247 255/50%);
width: 450px;
max-width: 100%;
font-family: sans-serif;
line-height: 1.4;
`;
function run (regl) {
let dirty = true;
@ -117,10 +135,10 @@ function run (regl) {
return state.scale * (x - x0) * (x - x1) * (x - x2);
}
function updatePoints () {
function updatePoints (newEvents=true) {
const yInflec = f(state.center);
const [x0, x1, x2] = computeRoots(state);
const { center } = state;
const { center, scale } = state;
poly.vertexAttributes.xy.subdata([...Array(poly.vertexCount).keys()].map(i => {
const x = xScale.invert((i - 1) / (poly.vertexCount - 3) * window.innerWidth);
@ -179,7 +197,7 @@ function run (regl) {
inflectionHandle
];
pointGrp
const join = pointGrp
.selectAll('circle')
.data(handles)
.join(
@ -196,96 +214,104 @@ function run (regl) {
.attr('cx', ({x}) => xScale(x))
.attr('cy', ({y}) => yScale(y)),
exit => exit.remove()
)
.call(d3.drag()
.on('start', function (event) {
event.sourceEvent.stopPropagation();
})
.on('drag', function (event, d) {
event.sourceEvent.stopPropagation();
event.sourceEvent.preventDefault();
const src = event.sourceEvent.touches ? event.sourceEvent.touches[0] : event.sourceEvent;
const x = xScale.invert(src.clientX);
const y = yScale.invert(src.clientY);
switch(d.type) {
case 'root': {
d.x = x;
Object.assign(state, positionCircle(rootHandles.map(({x}) => x)));
);
if (newEvents) {
join.call(
d3.drag()
.on('start', function (event) {
event.sourceEvent.stopPropagation();
})
.on('drag', function (event, d) {
event.sourceEvent.stopPropagation();
event.sourceEvent.preventDefault();
const src = event.sourceEvent.touches ? event.sourceEvent.touches[0] : event.sourceEvent;
const x = xScale.invert(src.clientX);
const y = yScale.invert(src.clientY);
switch(d.type) {
case 'root': {
d.x = x;
Object.assign(state, positionCircle(rootHandles.map(({x}) => x)));
break;
}
case 'extremum': {
const e1 = d;
const e2 = extremaHandles[0] === d ? extremaHandles[1] : extremaHandles[0];
e1.x = x;
e1.y = y;
const r = 0.5 * (e1.y - e2.y);
const p = 0.5 * (e1.x - e2.x);
const x0 = 0.5 * (e1.x + e2.x);
const y0 = 0.5 * (e1.y + e2.y);
const a = -r / (2 * p ** 3);
const b = 0;
const c = 1.5 * r / p;
const dd = y0;
const A = b / a;
const B = c / a;
const C = dd / a;
const Q = Math.min(0, (3 * B - A ** 2) / 9);
const R = (9 * A * B - 27 * C - 2 * A ** 3) / 54;
const D = Math.min(0, Q ** 3 + R ** 2);
const theta = Math.acos(Math.max(-0.99999, Math.min(0.99999, R / (-Q) ** 1.5)));
state.center = x0;
state.radius = 2 * Math.sqrt(-Q);
state.alpha = theta / 3;
state.scale = a;
break;
}
case 'inflection': {
const dx = x - center;
const dy = (y - yInflec) / scale;
const a = 1;
const b = -(x0 + x1 + x2);
const c = x1 * x2 + x0 * x2 + x0 * x1;
const d = -x0 * x1 * x2 + dy;
const A = b / a;
const B = c / a;
const C = d / a;
const Q = Math.min(0, (3 * B - A ** 2) / 9);
const R = (9 * A * B - 27 * C - 2 * A ** 3) / 54;
const D = Math.min(0, Q ** 3 + R ** 2);
const theta = Math.acos(Math.max(-0.99999, Math.min(0.99999, R / (-Q) ** 1.5)));
state.center = x;
state.radius = 2 * Math.sqrt(-Q);
state.alpha = theta / 3;
break;
}
case 'tri':
const dy = y - yScale.invert(state.yOffset);
const dx = x - state.center;
state.alpha = Math.atan2(dy, dx);
break;
}
case 'extremum': {
const e1 = d;
const e2 = extremaHandles[0] === d ? extremaHandles[1] : extremaHandles[0];
e1.x = x;
e1.y = y;
const r = 0.5 * (e1.y - e2.y);
const p = 0.5 * (e1.x - e2.x);
const x0 = 0.5 * (e1.x + e2.x);
const y0 = 0.5 * (e1.y + e2.y);
const a = -r / (2 * p ** 3);
const b = 0;
const c = 1.5 * r / p;
const dd = y0;
const A = b / a;
const B = c / a;
const C = dd / a;
const Q = Math.min(0, (3 * B - A ** 2) / 9);
const R = (9 * A * B - 27 * C - 2 * A ** 3) / 54;
const D = Math.min(0, Q ** 3 + R ** 2);
const theta = Math.acos(Math.max(-0.99999, Math.min(0.99999, R / (-Q) ** 1.5)));
state.center = x0;
state.radius = 2 * Math.sqrt(-Q);
state.alpha = theta / 3;
state.scale = a;
break;
}
case 'inflection': {
const dx = x - center;
const dy = y - yInflec;
const a = 1;
const b = -(x0 + x1 + x2);
const c = x1 * x2 + x0 * x2 + x0 * x1;
const d = -x0 * x1 * x2 + dy;
const A = b / a;
const B = c / a;
const C = d / a;
const Q = Math.min(0, (3 * B - A ** 2) / 9);
const R = (9 * A * B - 27 * C - 2 * A ** 3) / 54;
const D = Math.min(0, Q ** 3 + R ** 2);
const theta = Math.acos(Math.max(-0.99999, Math.min(0.99999, R / (-Q) ** 1.5)));
case 'center':
state.center = x;
state.radius = 2 * Math.sqrt(-Q);
state.alpha = theta / 3;
state.yOffset = yScale(y);
break;
}
case 'tri':
const dy = y - yScale.invert(state.yOffset);
const dx = x - state.center;
state.alpha = Math.atan2(dy, dx);
break;
case 'center':
state.center = x;
state.yOffset = yScale(y);
break;
}
updatePoints();
repaint();
})
);
}
updatePoints(false);
repaint();
})
.on('end', function () {
updatePoints();
repaint();
})
)
}
}
updatePoints();

View File

@ -0,0 +1,6 @@
{
"title": "Cubic Roots ↔︎ Equilateral Triangle",
"description": "An interactive reproduction of a diagram by Freya Holmér",
"order": 3300 ,
"image": "http://rreusser.github.io/src/src/cubic-roots/thumbnail.jpg"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -1,6 +0,0 @@
{
"title": "Cubic Polynomial ↔︎ Equilateral Triangle",
"description": "An interactive reproduction of a diagram by Freya Holmér",
"order": 3300 ,
"image": "http://rreusser.github.io/src/src/polynomial-roots/thumbnail.jpg"
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -923,7 +923,7 @@
"@babel/types" "^7.4.4"
esutils "^2.0.2"
"@babel/preset-react@^7.16.7":
"@babel/preset-react@^7.16.7", "@babel/preset-react@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d"
integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==