website

source code for the ttmaths.uk website
Log | Files | Refs | README

commit 749b69a4edecfb5e6724775120eba49d9f37fb03
parent c8d1e72f2d81d3410ee5c18ca800c75453bc8f74
Author: hrryt <harry@mayesfield.uk>
Date:   Tue, 11 Aug 2026 21:16:37 +0100

Add points, make double transformation QnA

Diffstat:
Msrc/components/Equation.jsx | 2+-
Dsrc/components/graphing/CoordinateLabel.jsx | 5-----
Msrc/components/graphing/Cubic.jsx | 6+++---
Msrc/components/graphing/Graph.jsx | 13+++++++++++--
Msrc/components/graphing/Label.jsx | 5+++--
Asrc/components/graphing/Point.jsx | 11+++++++++++
Msrc/components/graphing/Polygon.jsx | 6+++---
Msrc/components/graphing/Quadratic.jsx | 6+++---
Msrc/components/questions/DoubleTransformationQuestion.jsx | 54+++++++++++++++++++++++++++++++++++++++++-------------
Msrc/pages/Home.jsx | 3---
Msrc/scripts/utils.js | 5+++++
Msrc/styles/svg.css | 6+++---
12 files changed, 84 insertions(+), 38 deletions(-)

diff --git a/src/components/Equation.jsx b/src/components/Equation.jsx @@ -8,5 +8,5 @@ export default function Equation({ equation, displayMode = false }) { render(equation, ref.current, { displayMode: displayMode }); }, [equation]); - return <div ref={ref}>{equation}</div>; + return <span ref={ref}>{equation}</span>; } diff --git a/src/components/graphing/CoordinateLabel.jsx b/src/components/graphing/CoordinateLabel.jsx @@ -1,5 +0,0 @@ -import Label from './Label.jsx'; - -export default function CoordinateLabel({ x, y, position = "top" }) { - return <Label x={x} y={y} position={position}>{`(${x},${y})`}</Label>; -} diff --git a/src/components/graphing/Cubic.jsx b/src/components/graphing/Cubic.jsx @@ -1,6 +1,6 @@ -import { getSymmetricBounds } from '../../scripts/utils.js'; +import { getSymmetricBounds, getColourClass } from '../../scripts/utils.js'; -export default function Cubic({ a=1, b=0, c=0, d=0, colour="1", viewBox }) { +export default function Cubic({ a=1, b=0, c=0, d=0, colour="auto", viewBox }) { // https://math.stackexchange.com/questions/3356084/to-construct-a-polynomial-using-b%C3%A9zier-curves // http://graphics.stanford.edu/courses/cs164-09-spring/Handouts/handout19.pdf function g(u, v, w) { return a*u*v*w + b*(v*w + w*u + u*v)/3 + c*(u + v + w)/3 + d; } @@ -11,5 +11,5 @@ export default function Cubic({ a=1, b=0, c=0, d=0, colour="1", viewBox }) { const x2 = 1/3 * i + 2/3 * f; d = `M ${i},${g(i,i,i)} C ${x1},${g(i,i,f)} ${x2},${g(i,f,f)} ${f},${g(f,f,f)}`; - return <path d={d} class={`color-${colour}`} /> + return <path d={d} class={getColourClass(colour)} /> } diff --git a/src/components/graphing/Graph.jsx b/src/components/graphing/Graph.jsx @@ -60,7 +60,16 @@ export default function Graph({ children, viewBox, width="300", height="300" }) markerUnits="strokeWidth" orient="auto" > - <polygon points="0,0 4,2 0,4" id='arrowhead' /> + <polygon class='marker' points="0,0 4,2 0,4" /> + </marker> + <marker + id="cross" + viewBox="0 0 6 6" + refX="3" refY="3" + markerWidth="6" markerHeight="6" + markerUnits="strokeWidth" + > + <polygon class='marker' points="0,1 1,0 3,2 5,0 6,1 4,3 6,5 5,6 3,4 1,6 0,5 2,3" /> </marker> <style> {style} @@ -68,8 +77,8 @@ export default function Graph({ children, viewBox, width="300", height="300" }) </defs> <Grid viewBox={viewBox} /> <Axes viewBox={viewBox} /> - {children} <AxisTicks every={Math.floor(50 * scaleFactor)} viewBox={viewBox} /> + {children} </svg> ); } diff --git a/src/components/graphing/Label.jsx b/src/components/graphing/Label.jsx @@ -1,3 +1,5 @@ +import { getColourClass } from '../../scripts/utils.js'; + function getPosition(position) { switch (position) { case 'central': @@ -17,13 +19,12 @@ function getPosition(position) { export default function Label({ x, y, position='central', colour='auto', d=.15, children }) { const [dominantBaseline, textAnchor, dx, dy] = getPosition(position); - const colourClass = colour == 'auto' ? '' : `color-${colour}`; return ( <text x={x} y={-y} dx={d*dx} dy={-d*dy} transform='scale(1 -1)' dominant-baseline={dominantBaseline} text-anchor={textAnchor} - class={colourClass} + class={getColourClass(colour)} > {children} </text> diff --git a/src/components/graphing/Point.jsx b/src/components/graphing/Point.jsx @@ -0,0 +1,11 @@ +import Label from './Label.jsx'; +import { getColourClass } from '../../scripts/utils.js'; + +export default function Point({ x, y, label=null, colour="auto", position="top" }) { + return ( + <g> + <path marker-start="url(#cross)" d={`M ${x},${y}`} class={getColourClass(colour)}/> + {label && <Label x={x} y={y} position={position} d={.3} colour={colour}>{label}</Label>} + </g> + ); +} diff --git a/src/components/graphing/Polygon.jsx b/src/components/graphing/Polygon.jsx @@ -1,4 +1,5 @@ import Label from './Label.jsx'; +import { getColourClass } from '../../scripts/utils.js'; function getMean(arr) { return arr.reduce((a, b) => a + b) / arr.length; @@ -15,12 +16,11 @@ function PolygonLabel({ children, points, colour }) { return <Label x={x} y={y} colour={colour}>{children}</Label>; } -export default function Polygon({ points, label=null, colour="1" }) { +export default function Polygon({ points, label=null, colour="auto" }) { const pointsString = points.map((point) => point.join(",")).join(" "); - const colourClass = `color-${colour}`; return ( <g> - <polygon points={pointsString} class={colourClass}/> + <polygon points={pointsString} class={getColourClass(colour)}/> {label && <PolygonLabel points={points} colour={colour}>{label}</PolygonLabel>} </g> ); diff --git a/src/components/graphing/Quadratic.jsx b/src/components/graphing/Quadratic.jsx @@ -1,6 +1,6 @@ -import { getSymmetricBounds } from '../../scripts/utils.js'; +import { getSymmetricBounds, getColourClass } from '../../scripts/utils.js'; -export default function Quadratic({ a=1, b=0, c=0, colour="1", viewBox }) { +export default function Quadratic({ a=1, b=0, c=0, colour="auto", viewBox }) { function f(x) { return a*x*x + b*x + c; } const turnX = -b / (2*a); @@ -10,5 +10,5 @@ export default function Quadratic({ a=1, b=0, c=0, colour="1", viewBox }) { const controlY = 2*f(turnX) - endY; const d = `M ${startX},${endY} Q ${turnX},${controlY} ${endX},${endY}`; - return <path d={d} class={`color-${colour}`} />; + return <path d={d} class={getColourClass(colour)} />; } diff --git a/src/components/questions/DoubleTransformationQuestion.jsx b/src/components/questions/DoubleTransformationQuestion.jsx @@ -1,8 +1,9 @@ import { getRandomChoice, getRandomInt } from "../../scripts/utils"; -import CoordinateLabel from "../graphing/CoordinateLabel"; +import Point from "../graphing/Point"; import Polygon from "../graphing/Polygon"; import Graph from "../graphing/Graph"; import Question from "../Question"; +import Equation from "../Equation"; function rotatePoint(point, angle, axis=[0, 0]) { const diff = [point[0] - axis[0], point[1] - axis[1]] @@ -15,29 +16,56 @@ export default function DoubleTransformationQuestion({ seed, showAnswer }) { const viewBox = [-7, -7, 14, 14] const originalShape = [[0, 1], [2, 1], [0, 2]] const axis1 = [getRandomInt(-3, 3, seed++), getRandomInt(-3, 3, seed++)] - const axis2 = [getRandomInt(-3, 3, seed++), getRandomInt(-3, 3, seed++)] - const angle = getRandomChoice([Math.PI/2, Math.PI, 3*Math.PI/2], seed++) + let axis2 = axis1; + while (axis2.every((x, i) => x === axis1[i])) { + axis2 = [getRandomInt(-3, 3, seed++), getRandomInt(-3, 3, seed++)] + } + const angleDegrees = getRandomChoice([90, 180, -90], seed++) + const angle = angleDegrees / 180 * Math.PI // Rotation then translation!. could do other way around if really needed. const midShape = originalShape.map((point) => rotatePoint(point, angle, axis1)) const rotatedAxis = rotatePoint(axis2, angle, axis1) - const translationVector = axis2.map((value, i) => value - rotatedAxis[i]) + const translationVector = axis2.map((value, i) => Math.round(value - rotatedAxis[i])) const endShape = midShape.map((point) => point.map((value, i) => value + translationVector[i])) + let angleDirection = "" + if (angleDegrees !== 180) { + if (angleDegrees < 0) { + angleDirection = "counterclockwise" + } else { + angleDirection = "clockwise" + } + } + + const angleExpression = ( + <span> + <Equation equation={`${Math.abs(angleDegrees)} degree`} /> {angleDirection} + </span> + ) + const question = (<> - <p> - What single transformation..? - </p> + <p>Shape P is rotated {angleExpression} about point Q to form shape R.</p> + <p>Shape R is translated by <Equation equation={`vec(${translationVector[0]}, ${translationVector[1]})`} /> to form shape S.</p> + <p>What single transformation maps shape P onto shape S?</p> + <Graph viewBox={viewBox}> + <Polygon points={originalShape} label="P" colour="1" /> + <Point x={axis1[0]} y={axis1[1]} label="Q" colour="2" /> + </Graph> + </>) + + const answer = (<> + <p>Rotation {angleExpression} about <Equation equation={`(${axis2[0]}, ${axis2[1]})`} />.</p> <Graph viewBox={viewBox}> - <Polygon points={originalShape} label="P" colour="1" /> - <Polygon points={ midShape} label="Q" colour="2" /> - <Polygon points={ endShape} label="R" colour="3" /> - <CoordinateLabel x={axis1[0]} y={axis1[1]} /> - <CoordinateLabel x={axis2[0]} y={axis2[1]} /> + <Polygon points={originalShape} label="P" colour="1" /> + <Point x={axis1[0]} y={axis1[1]} label="Q" colour="2" /> + <Polygon points={ midShape} label="R" colour="3" /> + <Polygon points={ endShape} label="S" colour="4" /> + <Point x={axis2[0]} y={axis2[1]} /> </Graph> </>) - return <Question question={question} answer="" showAnswer={showAnswer} /> + return <Question question={question} answer={answer} showAnswer={showAnswer} /> } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx @@ -3,7 +3,6 @@ import Graph from '../components/graphing/Graph.jsx'; import Quadratic from '../components/graphing/Quadratic.jsx'; import Cubic from '../components/graphing/Cubic.jsx'; import Polygon from '../components/graphing/Polygon.jsx'; -import CoordinateLabel from '../components/graphing/CoordinateLabel.jsx'; export default function Home() { const viewBox = [-5, -4, 8, 8]; @@ -14,9 +13,7 @@ export default function Home() { <div class="field-border kern"> <Graph viewBox={viewBox}> <Quadratic a={2} b={1} c={-3} colour="1" viewBox={viewBox} /> - <CoordinateLabel x={-.25} y={-3.125} position="bottom" /> <Polygon points={[[1,2], [-1,1], [-4,3]]} label="P" colour="2" /> - <CoordinateLabel x={-4} y={3} /> <Cubic a={1} b={-3} c={3} d={-1} colour="3" viewBox={viewBox}/> </Graph> </div> diff --git a/src/scripts/utils.js b/src/scripts/utils.js @@ -35,3 +35,8 @@ export function getSymmetricBounds(midX, viewBox) { const halfWidth = Math.max(midX - minX, minX + width - midX); return [midX - halfWidth, midX + halfWidth]; } + +export function getColourClass(colour) { + if (colour == 'auto') { return ''; } + return `color-${colour}`; +} diff --git a/src/styles/svg.css b/src/styles/svg.css @@ -20,13 +20,13 @@ path.axis { stroke-linecap: butt; } -polygon#arrowhead { +polygon.marker { fill-opacity: 1; } text { - stroke: white; - stroke-width: 0.03; + stroke: white !important; + stroke-width: 0.1; paint-order: stroke; }