version at bottom
This commit is contained in:
parent
0c7e81d222
commit
777ad4af91
4 changed files with 33 additions and 3 deletions
|
|
@ -8,6 +8,24 @@ decisions behind them in `docs/plan.md`.
|
|||
|
||||
## Fix next
|
||||
|
||||
### Revisit the trendline live-edge bend with painted-pixel evidence
|
||||
|
||||
Production still appears to show a bend where 30m manual lines cross from the
|
||||
last real candle into future whitespace. The deployed code is verified to use
|
||||
one canvas `LineSeries`, retained transparent time-scale points, and canonical
|
||||
source-space prices. Diagnostic values can report unequal historical/future
|
||||
screen slopes when the final candles are sparse, but synthetic browser coverage
|
||||
passes after gap slots are inserted. The transparent-point production fix did
|
||||
not visibly settle the report, so do not add another geometry patch from the
|
||||
current theory.
|
||||
|
||||
Next investigation should compare the painted canvas pixels around the join
|
||||
against the chart API's expected coordinates in the user's production viewport.
|
||||
This is the same class of problem where self-consistent API coordinates once
|
||||
missed a real overlay offset. Capture the asset commit, final three bar times,
|
||||
their logical/x coordinates, the first two future coordinates, canonical line
|
||||
prices, and page-pixel samples from the rendered line before changing code.
|
||||
|
||||
### Deepen freshness telemetry
|
||||
|
||||
The status bar now reports when the browser received its latest snapshot or bar.
|
||||
|
|
|
|||
|
|
@ -233,6 +233,16 @@ createApp({
|
|||
hour: 'numeric', minute: '2-digit', second: '2-digit',
|
||||
}).format(new Date(dataReceivedAt.value));
|
||||
});
|
||||
const build = ref({ commit: '', startedAt: '' });
|
||||
const buildStamp = computed(() => {
|
||||
const commit = (build.value.commit || 'dev').slice(0, 7);
|
||||
if (!build.value.startedAt) return commit;
|
||||
const at = new Date(build.value.startedAt);
|
||||
if (Number.isNaN(at.getTime())) return commit;
|
||||
return `${commit} ${new Intl.DateTimeFormat(undefined, {
|
||||
day: 'numeric', month: 'short', hour: 'numeric', minute: '2-digit',
|
||||
}).format(at)}`;
|
||||
});
|
||||
const quoteChange = computed(() => {
|
||||
if (price.value == null || !(sessionOpen.value > 0)) return null;
|
||||
const points = price.value - sessionOpen.value;
|
||||
|
|
@ -1164,6 +1174,8 @@ createApp({
|
|||
await migrateLegacyToken();
|
||||
await refreshStatus();
|
||||
await refreshComments();
|
||||
const version = await fetch('/api/version').then(response => response.json()).catch(() => ({}));
|
||||
build.value = { commit: version.commit || 'dev', startedAt: version.started_at || '' };
|
||||
connect();
|
||||
timer = setInterval(() => { now.value = Date.now(); refreshStatus(); }, 5000);
|
||||
});
|
||||
|
|
@ -1174,6 +1186,6 @@ createApp({
|
|||
window.removeEventListener('keydown', handleKeydown);
|
||||
});
|
||||
|
||||
return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption };
|
||||
return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, buildStamp, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption };
|
||||
},
|
||||
}).mount('#app');
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
<button v-if="diagnosticMode" class="diag-capture" :disabled="captureBusy" @click="captureDiagnostic">
|
||||
{{ captureBusy ? 'CAPTURING…' : 'CAPTURE DIAGNOSTIC' }}
|
||||
</button>
|
||||
<span class="data-freshness">UPDATED <b>{{ dataUpdatedAt }}</b></span>
|
||||
<span class="data-freshness"><span>BUILD <b>{{ buildStamp }}</b></span><span>UPDATED <b>{{ dataUpdatedAt }}</b></span></span>
|
||||
</div>
|
||||
</section>
|
||||
<aside>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ button { border:1px solid var(--line); background:transparent; color:var(--muted
|
|||
@media (prefers-reduced-motion:reduce) { .current-price-pulse.active { animation:none; } }
|
||||
@keyframes line-focus { 0% { opacity:.85; stroke-width:var(--line-focus-start-width,12px); } 80% { opacity:.85; } 100% { opacity:0; stroke-width:var(--line-focus-width,2px); } }
|
||||
.chart-context-menu { position:absolute; z-index:8; width:165px; padding:4px; border:1px solid var(--line); background:var(--panel); box-shadow:0 5px 18px color-mix(in srgb,var(--fg) 15%,transparent); pointer-events:auto; }.chart-context-menu[hidden] { display:none; }.chart-context-menu button { width:100%; padding:6px 8px; text-align:left; color:var(--fg); font-size:10px; }
|
||||
.statusbar { min-height:34px; display:flex; align-items:center; gap:24px; padding:6px 13px; border-top:1px solid var(--line); color:var(--muted); font-size:10px; }.statusbar b { color:var(--fg); text-transform:uppercase; }.data-freshness { margin-left:auto; white-space:nowrap; }.diag-capture { padding:3px 7px; border-color:var(--accent); color:var(--accent); font-size:9px; white-space:nowrap; }.diag-capture:disabled { opacity:.55; cursor:wait; }
|
||||
.statusbar { min-height:34px; display:flex; align-items:center; gap:24px; padding:6px 13px; border-top:1px solid var(--line); color:var(--muted); font-size:10px; }.statusbar b { color:var(--fg); text-transform:uppercase; }.data-freshness { display:flex; gap:24px; margin-left:auto; white-space:nowrap; }.diag-capture { padding:3px 7px; border-color:var(--accent); color:var(--accent); font-size:9px; white-space:nowrap; }.diag-capture:disabled { opacity:.55; cursor:wait; }
|
||||
aside { padding:16px; }h2 { margin:0 0 12px; color:var(--muted); font-size:11px; text-transform:uppercase; letter-spacing:1.3px; }h2:not(:first-child) { margin-top:30px; }.empty { border-left:2px solid var(--line); padding:10px 12px; color:var(--muted); font-size:11px; }
|
||||
.sidebar-section { margin-top:30px; }.sidebar-section:first-of-type { margin-top:0; }.sidebar-section summary { margin-bottom:12px; color:var(--muted); font-size:11px; text-transform:uppercase; letter-spacing:1.3px; cursor:pointer; user-select:none; }.sidebar-section:not([open]) summary { margin-bottom:0; }
|
||||
.trendline-actions { display:grid; grid-template-columns:auto 1fr auto auto; align-items:center; gap:4px; margin-bottom:7px; }.trendline-actions button { padding:3px 5px; font-size:8px; white-space:nowrap; }.selection-count { color:var(--muted); font-size:8px; text-align:center; white-space:nowrap; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue