website

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

commit 2334d6782239763eee94cc35f3b7c6c77cb6ca2d
parent 86207f0a18ec8d5e2e4f37340126b3528654975a
Author: hrryt <harry@mayesfield.uk>
Date:   Fri, 14 Aug 2026 13:55:12 +0100

Add segment markers, dynamic label spacing, auto colour support

Diffstat:
MTODO.md | 4----
Msrc/components/graphing/Angle.jsx | 2+-
Msrc/components/graphing/Graph.jsx | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/components/graphing/Label.jsx | 7+++++--
Msrc/components/graphing/Point.jsx | 2+-
Msrc/pages/Home.jsx | 4+++-
Asrc/scripts/contexts.js | 3+++
Msrc/scripts/utils.js | 8++++----
Msrc/styles/svg.css | 18++++++++++++------
9 files changed, 84 insertions(+), 35 deletions(-)

diff --git a/TODO.md b/TODO.md @@ -1,16 +1,12 @@ # Fixes - Use KaTeX_Math font outside MathML -- colour="auto" -> no display? # Questions - Improve adding fractions -- i suppose for a > 1 i should actually factorise 2x-2 etc. factorising code gets bigger - Add more questions - Add graphing questions - Find all roots of this quintic (or something) polynomial (repeated root knowledge) - Transformations of shapes and graphs (curves) - - Make text same size for all graph scalings / dynamic axis ticks - - colour classes and points and polygon labels please :D - Drop-down for finer controls - tricky parallel lines / internal angles etc questions - automate allQuestions using file exploration diff --git a/src/components/graphing/Angle.jsx b/src/components/graphing/Angle.jsx @@ -1,5 +1,5 @@ import Label from './Label.jsx'; -import { getColourClass, getMidpoint, interpolate, interpolateDistance } from '../../scripts/utils.js'; +import { getColourClass, getMidpoint, interpolateDistance } from '../../scripts/utils.js'; function getArc(points, radius) { const start = interpolateDistance(points[1], points[0], radius); diff --git a/src/components/graphing/Graph.jsx b/src/components/graphing/Graph.jsx @@ -1,3 +1,4 @@ +import { ScaleFactorContext } from '../../scripts/contexts.js'; import Label from './Label.jsx'; function Grid({ viewBox }) { @@ -24,17 +25,17 @@ function AxisTicks({ every = 1, viewBox }) { {Array.from({ length: width - 1 }).map((_, i) => { const x = i + minX + 1; if (x == 0 || x % every) { return; } - return <Label point={[x, 0]} position="bottom" d={.1}>{x}</Label>; + return <Label point={[x, 0]} position="bottom">{x}</Label>; })} </g> <g> {Array.from({ length: height - 1 }).map((_, i) => { const y = i + minY + 1; if (y == 0 || y % every) { return; } - return <Label point={[0, y]} position="left" d={.1}>{y}</Label>; + return <Label point={[0, y]} position="left">{y}</Label>; })} </g> - <Label point={[0, 0]} position="bottom-left" d={.1}>0</Label> + <Label point={[0, 0]} position="bottom-left">0</Label> </g> ) } @@ -44,6 +45,13 @@ export default function Graph({ children, viewBox, width="300", height="300" }) const style = ` text { font-size: ${scaleFactor}em; + stroke-width: ${4 * scaleFactor}; + } + path,polygon,line,polyline,circle,ellipse { + stroke-width: ${2.5 * scaleFactor}; + } + path#grid { + stroke-width: ${0.5 * scaleFactor}; } `; return ( @@ -63,30 +71,61 @@ export default function Graph({ children, viewBox, width="300", height="300" }) </marker> <marker id="cross" - viewBox="0 0 10 10" - refX="5" refY="5" - markerWidth="5" markerHeight="5" - orient="45" + viewBox="0 0 6 6" + refX="3" refY="3" + markerWidth="6" markerHeight="6" > - <polygon class='marker' points="0,4 0,6 4,6 4,10 6,10 6,6 10,6 10,4 4,4 4,0 6,0 6,4" /> + <line class='marker' x1="1" y1="1" x2="5" y2="5" /> + <line class='marker' x1="1" y1="5" x2="5" y2="1" /> </marker> <marker id="hash" - viewBox="0 0 10 10" - refX="5" refY="5" - markerWidth="5" markerHeight="5" + viewBox="0 0 2 6" + refX="1" refY="3" + markerWidth="2" markerHeight="6" + orient="auto" + > + <line class="marker" x1="1" y1="1" x2="1" y2="5" /> + </marker> + <marker + id="double-hash" + viewBox="0 0 4 6" + refX="2" refY="3" + markerWidth="4" markerHeight="6" + orient="auto" + > + <line class="marker" x1="1" y1="1" x2="1" y2="5" /> + <line class="marker" x1="3" y1="1" x2="3" y2="5" /> + </marker> + <marker + id="feather" + viewBox="0 0 6 6" + refX="5" refY="3" + markerWidth="6" markerHeight="6" + orient="auto" + > + <polyline class="marker" points="2,1 5,3 2,5" /> + </marker> + <marker + id="double-feather" + viewBox="0 0 9 6" + refX="5" refY="3" + markerWidth="9" markerHeight="6" orient="auto" > - <polygon class="marker" points="4,0 4,10 6,10 6,0" /> + <polyline class="marker" points="2,1 5,3 2,5" /> + <polyline class="marker" points="5,1 8,3 5,5" /> </marker> <style> {style} </style> </defs> - <Grid viewBox={viewBox} /> - <Axes viewBox={viewBox} /> - <AxisTicks every={Math.floor(50 * scaleFactor)} viewBox={viewBox} /> - {children} + <ScaleFactorContext value={scaleFactor}> + <Grid viewBox={viewBox} /> + <Axes viewBox={viewBox} /> + <AxisTicks every={Math.floor(50 * scaleFactor)} viewBox={viewBox} /> + {children} + </ScaleFactorContext> </svg> ); } diff --git a/src/components/graphing/Label.jsx b/src/components/graphing/Label.jsx @@ -1,3 +1,5 @@ +import { useContext } from 'preact/hooks'; +import { ScaleFactorContext } from '../../scripts/contexts.js'; import { getColourClass } from '../../scripts/utils.js'; function getPosition(position) { @@ -17,12 +19,13 @@ function getPosition(position) { } } -export default function Label({ point, position='central', colour='auto', d=.15, children }) { +export default function Label({ point, position='central', spacing=3, colour='auto', children }) { const [x, y] = point; const [dominantBaseline, textAnchor, dx, dy] = getPosition(position); + const scaledSpacing = spacing * useContext(ScaleFactorContext); return ( <text - x={x} y={-y} dx={d*dx} dy={-d*dy} transform='scale(1 -1)' + x={x} y={-y} dx={scaledSpacing * dx} dy={scaledSpacing * -dy} transform='scale(1 -1)' dominant-baseline={dominantBaseline} text-anchor={textAnchor} class={getColourClass(colour)} diff --git a/src/components/graphing/Point.jsx b/src/components/graphing/Point.jsx @@ -5,7 +5,7 @@ export default function Point({ point, label=null, colour="auto", position="top" return ( <g> <path marker-start="url(#cross)" d={`M ${point}`} class={getColourClass(colour)}/> - {label && <Label point={point} position={position} d={.3} colour={colour}>{label}</Label>} + {label && <Label point={point} position={position} spacing={10} colour={colour}>{label}</Label>} </g> ); } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx @@ -6,6 +6,7 @@ import Polygon from '../components/graphing/Polygon.jsx'; import Angle from '../components/graphing/Angle.jsx'; import Segment from '../components/graphing/Segment.jsx'; import Line from '../components/graphing/Line.jsx'; +import Point from '../components/graphing/Point.jsx'; export default function Home() { const viewBox = [-5, -4, 8, 8]; @@ -19,8 +20,9 @@ export default function Home() { <Polygon points={[[1,2], [-1,1], [-4,3]]} label="P" colour="2" /> <Angle points={[[-4,3], [1,2], [-1,1]]} double={true} colour="2" /> <Cubic a={1} b={-3} c={3} d={-1} colour="3" viewBox={viewBox} /> - <Segment points={[[0,1], [2,2]]} marker="hash" colour="4" /> <Line line={{a: -10, b: -9, c: -1}} colour="5" viewBox={viewBox} /> + <Segment points={[[0,1], [2,2]]} marker="double-feather" /> + <Point point={[0,1]} label="Q" colour="1" /> </Graph> </div> </Window> diff --git a/src/scripts/contexts.js b/src/scripts/contexts.js @@ -0,0 +1,3 @@ +import { createContext } from 'preact'; + +export const ScaleFactorContext = createContext(null); diff --git a/src/scripts/utils.js b/src/scripts/utils.js @@ -49,10 +49,6 @@ function scale(vector, factor) { return vector.map(a => a * factor); } -export function interpolate(start, end, along) { - return sumVectors([start, scale(getVector(start, end), along)]); -} - function sum(arr) { return arr.reduce((a, b) => a + b); } @@ -66,6 +62,10 @@ function getVector(start, end) { return start.map((a, i) => end[i] - a); } +function interpolate(start, end, along) { + return sumVectors([start, scale(getVector(start, end), along)]); +} + export function interpolateDistance(start, end, distance) { return sumVectors([start, normalise(getVector(start, end), distance)]); } diff --git a/src/styles/svg.css b/src/styles/svg.css @@ -1,34 +1,40 @@ path,polygon,line,polyline,circle,ellipse { - stroke-width: 0.06; stroke-linejoin: round; stroke-linecap: round; fill-opacity: 0; + stroke: black; } polygon { fill-opacity: 0.5; + stroke: black; + fill: black; } path#grid { stroke: black; - stroke-width: 0.01; } path.axis { stroke: black; - stroke-width: 0.08; stroke-linecap: butt; } -polygon.marker { - fill-opacity: 1; +.marker { stroke: context-stroke; fill: context-fill; } +line.marker, polyline.marker { + stroke-width: 1; +} + +polygon.marker { + fill-opacity: 1; +} + text { stroke: white !important; - stroke-width: 0.1; paint-order: stroke; }