Draw the live price as a dash-dot ray across the plot.
LWC keeps the axis label only. The overlay uses a 14-4-2-4 dash so it does not look like a trendline.
This commit is contained in:
parent
5708150ba3
commit
8108f2dea3
2 changed files with 28 additions and 10 deletions
|
|
@ -206,6 +206,7 @@ class ConfluenceChart {
|
|||
this.priceLines = new Map();
|
||||
this.currentPriceLine = null;
|
||||
this.currentPricePulse = null;
|
||||
this.currentPriceRay = null;
|
||||
this.projectionDiagnostic = null;
|
||||
this.projectionDiagnosticFrame = null;
|
||||
this.animateCurrentPrice = true;
|
||||
|
|
@ -496,6 +497,12 @@ class ConfluenceChart {
|
|||
this.currentPricePulse.className = 'current-price-pulse';
|
||||
this.currentPricePulse.hidden = true;
|
||||
el.appendChild(this.currentPricePulse);
|
||||
const priceMark = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
priceMark.classList.add('current-price-mark');
|
||||
priceMark.setAttribute('aria-hidden', 'true');
|
||||
this.currentPriceRay = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
priceMark.appendChild(this.currentPriceRay);
|
||||
this.overlayLayer.appendChild(priceMark);
|
||||
this.projectionDiagnostic = document.createElement('pre');
|
||||
this.projectionDiagnostic.className = 'projection-diagnostic';
|
||||
this.projectionDiagnostic.hidden = true;
|
||||
|
|
@ -927,7 +934,8 @@ class ConfluenceChart {
|
|||
price,
|
||||
color: '#b7771d',
|
||||
lineWidth: 1,
|
||||
lineStyle: LightweightCharts.LineStyle.Dotted,
|
||||
lineStyle: LightweightCharts.LineStyle.LargeDashed,
|
||||
lineVisible: false,
|
||||
axisLabelVisible: true,
|
||||
title: '',
|
||||
};
|
||||
|
|
@ -939,19 +947,29 @@ class ConfluenceChart {
|
|||
}
|
||||
|
||||
syncCurrentPricePulse() {
|
||||
if (!this.currentPricePulse) return;
|
||||
const show = this.animateCurrentPrice && this.lastCurrentPrice != null;
|
||||
this.currentPricePulse.hidden = !show;
|
||||
this.currentPricePulse.classList.toggle('active', show);
|
||||
if (!show || !this.candles || this.lastCurrentPrice == null || !this.chartEl) return;
|
||||
const showFrame = this.animateCurrentPrice && this.lastCurrentPrice != null;
|
||||
if (this.currentPricePulse) {
|
||||
this.currentPricePulse.hidden = !showFrame;
|
||||
this.currentPricePulse.classList.toggle('active', showFrame);
|
||||
}
|
||||
if (!this.candles || this.lastCurrentPrice == null || !this.chartEl) return;
|
||||
const y = this.candles.priceToCoordinate(this.lastCurrentPrice);
|
||||
const canvas = this.plotCanvas();
|
||||
if (y == null || !canvas) return;
|
||||
const chart = this.chartEl.getBoundingClientRect();
|
||||
const plot = canvas.getBoundingClientRect();
|
||||
this.currentPricePulse.style.left = `${Math.round(plot.right - chart.left)}px`;
|
||||
this.currentPricePulse.style.top = `${Math.round(plot.top - chart.top + y - 10)}px`;
|
||||
this.currentPricePulse.style.width = `${Math.max(40, Math.round(chart.right - plot.right))}px`;
|
||||
const top = Math.round(y);
|
||||
if (showFrame && this.currentPricePulse) {
|
||||
this.currentPricePulse.style.left = `${Math.round(plot.right - chart.left)}px`;
|
||||
this.currentPricePulse.style.top = `${Math.round(plot.top - chart.top + y - 10)}px`;
|
||||
this.currentPricePulse.style.width = `${Math.max(40, Math.round(chart.right - plot.right))}px`;
|
||||
}
|
||||
if (this.currentPriceRay) {
|
||||
this.currentPriceRay.setAttribute('x1', '0');
|
||||
this.currentPriceRay.setAttribute('x2', String(this.overlayLayer?.clientWidth || plot.width));
|
||||
this.currentPriceRay.setAttribute('y1', String(top));
|
||||
this.currentPriceRay.setAttribute('y2', String(top));
|
||||
}
|
||||
}
|
||||
|
||||
setCommentHandlers({ onToggle, onMove, onSelect }) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ main { display:grid; grid-template-columns:minmax(0, 1fr) 300px; gap:16px; }
|
|||
button { border:1px solid var(--line); background:transparent; color:var(--muted); padding:6px 11px; font:inherit; cursor:pointer; }button.active { color:var(--bg); background:var(--accent); border-color:var(--accent); }
|
||||
.chart-head-tools { display:flex; align-items:center; gap:8px; }.undo-btn { display:grid; place-items:center; width:32px; height:28px; padding:0; flex:none; }.undo-btn:disabled { opacity:.35; cursor:default; }.timeframes { display:flex; flex-wrap:wrap; justify-content:flex-end; }.timeframes button+button { border-left:0; }
|
||||
.drawing-tools { min-height:38px; padding:5px 12px; display:flex; align-items:center; gap:9px; border-bottom:1px solid var(--line); color:var(--muted); font-size:10px; }.drawing-tools button,.drawing-tools select,.drawing-tools .line-name { padding:4px 8px; font-size:10px; }.drawing-tools select,.drawing-tools .line-name { background:var(--panel); color:var(--fg); border:1px solid var(--line); }.drawing-tools .line-name { width:130px; font:inherit; }.drawing-tools label { display:flex; gap:4px; align-items:center; }.drawing-tools input { accent-color:var(--accent); }
|
||||
#chart { position:relative; height:calc(100vh - 190px); min-height:420px; touch-action:pan-y; }.chart-preview,.chart-line-bridges,.chart-handles { position:absolute; inset:0; width:100%; height:100%; overflow:hidden; pointer-events:none; }.chart-preview,.chart-line-bridges { z-index:4; }.chart-line-bridges line { stroke-linecap:round; }.chart-handles { z-index:6; }.chart-preview line[hidden],.chart-anchor[hidden],.chart-line-hit[hidden],.chart-line-focus[hidden],.chart-fib-focus[hidden] { display:none; }.chart-line-focus { stroke-linecap:round; pointer-events:none; animation:line-focus .75s ease-out forwards; }.chart-line-hit { fill:none; stroke:transparent; stroke-width:16px; pointer-events:stroke; cursor:move; touch-action:none; }.chart-anchor { stroke:var(--panel); stroke-width:2px; cursor:grab; pointer-events:all; touch-action:none; }.chart-anchor:active { cursor:grabbing; }.chart-tooltip { position:absolute; z-index:5; padding:4px 7px; border:1px solid var(--line); background:var(--panel); color:var(--fg); font-size:10px; white-space:pre-line; pointer-events:none; }.chart-tooltip[hidden] { display:none; }
|
||||
#chart { position:relative; height:calc(100vh - 190px); min-height:420px; touch-action:pan-y; }.chart-preview,.chart-line-bridges,.chart-handles,.current-price-mark { position:absolute; inset:0; width:100%; height:100%; overflow:hidden; pointer-events:none; }.current-price-mark { z-index:4; }.current-price-mark line { stroke:var(--accent); stroke-width:2; stroke-dasharray:14 4 2 4; }.chart-preview,.chart-line-bridges { z-index:4; }.chart-line-bridges line { stroke-linecap:round; }.chart-handles { z-index:6; }.chart-preview line[hidden],.chart-anchor[hidden],.chart-line-hit[hidden],.chart-line-focus[hidden],.chart-fib-focus[hidden] { display:none; }.chart-line-focus { stroke-linecap:round; pointer-events:none; animation:line-focus .75s ease-out forwards; }.chart-line-hit { fill:none; stroke:transparent; stroke-width:16px; pointer-events:stroke; cursor:move; touch-action:none; }.chart-anchor { stroke:var(--panel); stroke-width:2px; cursor:grab; pointer-events:all; touch-action:none; }.chart-anchor:active { cursor:grabbing; }.chart-tooltip { position:absolute; z-index:5; padding:4px 7px; border:1px solid var(--line); background:var(--panel); color:var(--fg); font-size:10px; white-space:pre-line; pointer-events:none; }.chart-tooltip[hidden] { display:none; }
|
||||
.current-price-pulse { position:absolute; z-index:8; height:20px; box-sizing:border-box; border:1px solid var(--accent); opacity:0; pointer-events:none; }.current-price-pulse.active { opacity:1; animation:current-price-frame 1.8s ease-in-out infinite; }@keyframes current-price-frame { 0%,100% { opacity:1; } 50% { opacity:.25; } }
|
||||
.chart-ohlc { position:absolute; top:6px; left:8px; z-index:5; padding:2px 6px; border:1px solid var(--line); background:color-mix(in srgb,var(--panel) 90%,transparent); color:var(--fg); font-size:10px; font-variant-numeric:tabular-nums; pointer-events:none; white-space:nowrap; }.chart-ohlc.up { color:var(--green); }.chart-ohlc.down { color:var(--red); }.chart-ohlc[hidden] { display:none; }
|
||||
.projection-diagnostic { position:absolute; top:8px; left:8px; z-index:9; margin:0; padding:5px 7px; border:1px solid var(--line); background:color-mix(in srgb,var(--panel) 92%,transparent); color:var(--fg); font:9px/1.35 "IBM Plex Mono", monospace; white-space:pre; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue