website

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

commit c1189d7c3fee2e658b84a191dec28b2bbf8858c2
parent f7b9168c3ad040fae4ab0577aa27a0010f4a31d2
Author: hrryt <harry@mayesfield.uk>
Date:   Fri, 14 Aug 2026 23:07:27 +0100

Add blank plots, right angle

Diffstat:
Msrc/components/graphing/Angle.jsx | 20+++++++++++++++-----
Msrc/components/graphing/Graph.jsx | 142+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/pages/Home.jsx | 19+++++++++++++++----
Msrc/scripts/utils.js | 20++++++++++----------
Msrc/styles/svg.css | 3+--
5 files changed, 118 insertions(+), 86 deletions(-)

diff --git a/src/components/graphing/Angle.jsx b/src/components/graphing/Angle.jsx @@ -1,7 +1,7 @@ import Label from './Label.jsx'; import { useContext } from 'preact/hooks'; import { StrokeWidthContext } from '../../scripts/contexts.js'; -import { getColourClass, getMidpoint, interpolateDistance } from '../../scripts/utils.js'; +import { getColourClass, getMidpoint, interpolateDistance, sumVectors, getVector } from '../../scripts/utils.js'; function getArc(points, radius) { const start = interpolateDistance(points[1], points[0], radius); @@ -9,6 +9,12 @@ function getArc(points, radius) { return [start, end]; } +function RightAngle({ points, radius, colour }) { + const [start, end] = getArc(points, radius); + const midpoint = sumVectors(start, getVector(points[1], end)); + return <polygon points={[points[1], start, midpoint, end]} class={getColourClass(colour)} /> +} + function AngleArc({ points, radius, colour }) { const [start, end] = getArc(points, radius); return <path d={`M ${start} A ${radius} ${radius} 0 0 1 ${end}`} class={getColourClass(colour)} />; @@ -19,12 +25,16 @@ function AngleLabel({ points, radius, colour, children }) { return <Label point={point} colour={colour}>{children}</Label>; } -export default function Angle({ points, radius = 0.5, arcs = 1, label = null, colour = "auto" }) { - const concentricGap = 3 * useContext(StrokeWidthContext); +export default function Angle({ points, right = false, arcs = 1, label = null, colour = "auto" }) { + const strokeWidth = useContext(StrokeWidthContext); + const radius = 10 * strokeWidth; + const concentricGap = 1.5 * strokeWidth; return ( <g> - {Array.from({ length: arcs }).map( - (_, i) => <AngleArc points={points} radius={(1 + i*concentricGap) * radius} colour={colour} /> + {right ? ( + <RightAngle points={points} radius={0.8 * radius} colour={colour} /> + ) : Array.from({ length: arcs }).map( + (_, i) => <AngleArc points={points} radius={(radius + i*concentricGap)} colour={colour} /> )} {label && <AngleLabel points={points} radius={radius} colour={colour}>{label}</AngleLabel>} </g> diff --git a/src/components/graphing/Graph.jsx b/src/components/graphing/Graph.jsx @@ -49,20 +49,24 @@ function AxisTicks({ viewBox }) { ) } -export default function Graph({ children, viewBox, width="300", height="300" }) { +export default function Plot({ children, mode="graph", viewBox, width="300", height="300" }) { + const id = `graph-${Math.floor(1000 * Math.random())}`; const scaleFactor = Math.max(viewBox[2] / width, viewBox[3] / height); const strokeWidth = 2.5 * scaleFactor; const style = ` - text { + g#${id} text { font-size: ${scaleFactor}em; - stroke-width: ${1.6 * strokeWidth}; + stroke-width: ${mode === "graph" ? 1.6 * strokeWidth : 0}; } - path,polygon,line,polyline,circle,ellipse { + g#${id} :is(path,polygon,line,polyline,rect,circle,ellipse) { stroke-width: ${strokeWidth}; } - path#grid { + g#${id} path#grid { stroke-width: ${0.2 * strokeWidth}; } + g#${id} polygon { + fill-opacity: ${mode === "graph" ? 0.5 : 0}; + } `; return ( <svg @@ -70,71 +74,79 @@ export default function Graph({ children, viewBox, width="300", height="300" }) transform="scale(1 -1)" xmlns="http://www.w3.org/2000/svg" > <defs> - <marker - id='arrowhead' - viewBox="0 0 4 4" - refX="0" refY="2" - markerWidth="4" markerHeight="4" - orient="auto" - > - <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" - > - <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 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" - > - <polyline class="marker" points="2,1 5,3 2,5" /> - <polyline class="marker" points="5,1 8,3 5,5" /> - </marker> + <g> + <marker + id='arrowhead' + viewBox="0 0 4 4" + refX="0" refY="2" + markerWidth="4" markerHeight="4" + orient="auto" + > + <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" + > + <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 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" + > + <polyline class="marker" points="2,1 5,3 2,5" /> + <polyline class="marker" points="5,1 8,3 5,5" /> + </marker> + </g> <style> {style} </style> </defs> <StrokeWidthContext value={strokeWidth}> - <Grid viewBox={viewBox} /> - <Axes viewBox={viewBox} /> - <AxisTicks viewBox={viewBox} /> - {children} + <g id={id}> + {mode === "graph" && ( + <g> + <Grid viewBox={viewBox} /> + <Axes viewBox={viewBox} /> + <AxisTicks viewBox={viewBox} /> + </g> + )} + {children} + </g> </StrokeWidthContext> </svg> ); diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx @@ -7,9 +7,11 @@ 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'; +import Label from '../components/graphing/Label.jsx'; export default function Home() { const viewBox = [-5, -4, 8, 8]; + const [A, B, C] = [[1,4], [3,2], [2,1]]; return ( <main> <Window title="Home"> @@ -18,11 +20,20 @@ export default function Home() { <Graph viewBox={viewBox}> <Quadratic a={2} b={1} c={-3} colour="1" viewBox={viewBox} /> <Polygon points={[[1,2], [-1,1], [-4,3]]} label="P" colour="2" /> - <Angle points={[[-4,3], [1,2], [-1,1]]} arcs={2} colour="2" /> <Cubic a={1} b={-3} c={3} d={-1} colour="3" viewBox={viewBox} /> - <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="4" /> + <Line line={{a: -10, b: -9, c: -1}} colour="4" viewBox={viewBox} /> + <Point point={[0,1]} label="Q" colour="5" /> + </Graph> + <Graph mode="blank" viewBox={[0, 0, 5, 5]}> + <Label point={A} position="top">A</Label> + <Label point={B} position="right">B</Label> + <Label point={C} position="bottom">C</Label> + <Segment points={[A, B]} marker="hash" /> + <Segment points={[C, B]} marker="double-feather" /> + <Segment points={[A, C]} /> + <Angle points={[A, B, C]} right={true} /> + <Angle points={[B, C, A]} /> + <Angle points={[C, A, B]} /> </Graph> </div> </Window> diff --git a/src/scripts/utils.js b/src/scripts/utils.js @@ -74,10 +74,6 @@ export function getColourClass(colour) { return `color-${colour}`; } -function sumVectors(arr) { - return arr.reduce((a, b) => a.map((ai, i) => ai + b[i])); -} - function scale(vector, factor) { return vector.map(a => a * factor); } @@ -86,21 +82,25 @@ function sum(arr) { return arr.reduce((a, b) => a + b); } -function normalise(vector, scaleFactor = 1) { - const length = Math.sqrt(sum(vector.map(a => a*a))); - return scale(vector, scaleFactor / length); +export function sumVectors(a, b) { + return a.map((ai, i) => b[i] + ai); } -function getVector(start, end) { +export function getVector(start, end) { return start.map((a, i) => end[i] - a); } +function normalise(vector, scaleFactor = 1) { + const length = Math.sqrt(sum(vector.map(a => a*a))); + return scale(vector, scaleFactor / length); +} + function interpolate(start, end, along) { - return sumVectors([start, scale(getVector(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)]); + return sumVectors(start, normalise(getVector(start, end), distance)); } export function getMidpoint(points) { diff --git a/src/styles/svg.css b/src/styles/svg.css @@ -1,4 +1,4 @@ -path,polygon,line,polyline,circle,ellipse { +path,polygon,line,polyline,rect,circle,ellipse { stroke-linejoin: round; stroke-linecap: round; fill-opacity: 0; @@ -6,7 +6,6 @@ path,polygon,line,polyline,circle,ellipse { } polygon { - fill-opacity: 0.5; stroke: black; fill: black; }