app
Adom Gantt
Public Made by Adomby adom
Interactive Gantt chart viewer for project timelines, with a table view and an analytics page over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. One click auto-schedules the whole plan so every dependency lines up finish-to-start on working days, skipping weekends and US federal holidays, push
← Commit history
0.30.3: one wheel handler scrolls the whole gantt body, not just task rows
4 files changed
+66−3
docs/BUILD-NOTES.md+36@@ -3,6 +3,42 @@ Decisions taken while building, and the places where the plan and the code disagreed. Newest first. +## Build notes, 2026-08-17 (0.30.3, the whole gantt body scrolls)++The plan scrolled only when the cursor sat over the timeline side of a task row.+Over a phase header, anywhere in the label column, or down in the empty tail, the+wheel did nothing.++**Cause: only one element was ever a scroller.** `.timeline-col` is `overflow:+auto`; `.labels-col` is `overflow: hidden` and merely mirrors the timeline's+`scrollTop` from its scroll event. The label column, the headers, and the tail all+live in `.labels-col` or over it, so a wheel there had no scrollable ancestor+(`.chart-wrap` and `body` are both `overflow: hidden`) and the gesture was+swallowed.++**Fix: one wheel owner for the whole body.** A single handler on `.chart-wrap`,+which wraps both columns and the resizer, drives the timeline's scroll from+wherever the pointer is: `deltaY` to `scrollTop`, `deltaX` (or Shift with a+vertical wheel) to `scrollLeft`, with line and page deltas normalised to pixels so+a mouse and a trackpad move the plan by a comparable amount. It sets exactly the+`scrollTop`/`scrollLeft` the native scroller would, so the axis rows, which live+inside `.timeline-col`, behave on scroll exactly as before.++**The label column is synced in the same tick, not on the timeline's scroll+event.** A programmatic `scrollTop` fires that event late, or not at all in some+engines, so the labels are pulled along right in the wheel handler; leaning on the+event left them a frame behind the bars. The existing scroll-event sync stays for+the other things that scroll the timeline (drag-autoscroll, keyboard row-into-view).++Verified headless: a wheel dispatched over a phase header, a task label, a bar+row, the label tail and the bar tail each scroll the plan by the same 120px and+the label column follows every time; at a fine grain where the axis overflows its+pane, Shift+wheel and a horizontal wheel both scroll sideways by the same amount+over bars AND over headers, while the label column never moves horizontally; the+axis rows stay present and track the content; the page behind never rubber-bands.+Twelve suites green, zero JS errors. The table view is untouched: it scrolls its+own container and is outside `.chart-wrap`.+ ## Build notes, 2026-08-17 (0.30.2, a bar cannot disagree with its lane) The Drone Project lane showed mixed bar colours, some teal, some blue. Not a
gantt.html+27@@ -2519,6 +2519,32 @@ function mountLabelTailroom(){ labelTail.className='tailroom';labelsEl.appendChild(labelTail); timelineEl.addEventListener('scroll',()=>{labelsEl.scrollTop=timelineEl.scrollTop;}); }+function wireChartWheel(){+ const wrap=timelineEl.closest('.chart-wrap')||timelineEl.parentElement;+ if(!wrap)return;+ wrap.addEventListener('wheel',e=>{+ // A dropdown or menu that opens over the chart and scrolls itself keeps its own+ // wheel; nothing like that lives inside .chart-wrap today, but the guard is cheap.+ if(e.target.closest('.cell-list, .dropdown, .sec-list'))return;+ // Line and page deltas become pixels, so a mouse wheel and a trackpad move the+ // plan by a comparable amount and the maths is uniform.+ const unitY=e.deltaMode===1?16:(e.deltaMode===2?timelineEl.clientHeight:1);+ const unitX=e.deltaMode===1?16:(e.deltaMode===2?timelineEl.clientWidth:1);+ let dx=e.deltaX*unitX, dy=e.deltaY*unitY;+ // Shift with a vertical wheel is the standard "scroll sideways" gesture.+ if(e.shiftKey&&dx===0){ dx=dy; dy=0; }+ if(dy)timelineEl.scrollTop+=dy;+ if(dx)timelineEl.scrollLeft+=dx;+ // Sync the label column HERE rather than lean on the timeline's own scroll+ // event: a programmatic scrollTop fires that event late (or not at all in some+ // engines), so the labels have to be pulled along in the same tick the wheel is+ // handled or they lag a frame behind the bars.+ labelsEl.scrollTop=timelineEl.scrollTop;+ // Own the gesture: the label column has no scroll of its own, and the page+ // behind must never rubber-band because the pointer was over a header.+ e.preventDefault();+ },{passive:false});+} // ── Responsive relayout ── // Everything on the timeline is positioned in px derived from COL, so a resize@@ -5662,6 +5688,7 @@ async function init(){ mountTodayLine(); mountBarTailroom(); mountLabelTailroom();+ wireChartWheel(); wireRelayoutObservers(); wireDepRedraw(); wireLabelClicks();
package.json+1−1@@ -2,7 +2,7 @@ "slug": "adom-gantt", "title": "Adom Gantt", "type": "app",- "version": "0.30.2",+ "version": "0.30.3", "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.", "main": "server.js", "bin": {
page.json+2−2@@ -2,7 +2,7 @@ "slug": "adom-gantt", "title": "Adom Gantt", "type": "app",- "version": "0.30.2",+ "version": "0.30.3", "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.", "main": "server.js", "bin": {@@ -63,4 +63,4 @@ "name": "Drew Owens", "email": "[email protected]" }-}+}