fib look and feel tweaks

This commit is contained in:
Chris Amow 2026-08-19 09:33:18 +00:00
parent 1c3a852a03
commit ac2943f248
2 changed files with 60 additions and 2 deletions

View file

@ -140,7 +140,7 @@ class FibLevelsPrimitive {
color,
width,
dashed: !major,
label: `${level.label} ${level.price.toFixed(2)}`,
label: `fib ${level.label} ${level.price.toFixed(2)}`,
});
}
}
@ -218,6 +218,8 @@ class ConfluenceChart {
this.lineHitTarget = null;
this.lineFocus = null;
this.lineFocusTimer = null;
this.fibFocus = null;
this.fibFocusTimer = null;
this.draggingLine = null;
this.lineMoveListener = null;
this.lineUpListener = null;
@ -507,6 +509,10 @@ class ConfluenceChart {
this.lineFocus.classList.add('chart-line-focus');
this.lineFocus.setAttribute('hidden', '');
handles.appendChild(this.lineFocus);
this.fibFocus = document.createElementNS('http://www.w3.org/2000/svg', 'g');
this.fibFocus.classList.add('chart-fib-focus');
this.fibFocus.setAttribute('hidden', '');
handles.appendChild(this.fibFocus);
this.lineHitTarget = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
this.lineHitTarget.classList.add('chart-line-hit');
this.lineHitTarget.setAttribute('hidden', '');
@ -1993,6 +1999,11 @@ class ConfluenceChart {
focusLine(id) {
this.setSelectedLine(id);
const fib = this.fibs.find(item => item.id === id);
if (fib) {
this.focusFib(fib);
return;
}
const level = this.levels.find(value => value.id === id && value.kind === 'manual');
if (!level) return;
if (ConfluenceChart.isFlat(level)) {
@ -2020,6 +2031,52 @@ class ConfluenceChart {
this.lineFocusTimer = setTimeout(() => this.lineFocus.setAttribute('hidden', ''), 800);
}
focusFib(fib) {
if (!this.fibFocus || !this.overlayLayer) return;
this.fibFocus.replaceChildren();
const width = this.overlayLayer.getBoundingClientRect().width;
const originX = this.coordinateAtTime(fib.anchor_t);
const start = originX == null ? 0 : Math.max(0, originX);
const color = fib.color || '#c8992f';
const lineWidth = Math.max(1, Number(fib.line_width) || 2);
this.fibFocus.style.setProperty('--line-focus-start-width', `${lineWidth + 10}px`);
this.fibFocus.style.setProperty('--line-focus-width', `${lineWidth}px`);
const y0 = this.candles.priceToCoordinate(Number(fib.anchor_p));
const endP = Number(fib.anchor_p) + Number(fib.slope || 0)
* (Number(fib.last_t) - Number(fib.anchor_t));
const y1 = this.candles.priceToCoordinate(endP);
if (originX != null && y0 != null && y1 != null) {
const rail = document.createElementNS('http://www.w3.org/2000/svg', 'line');
rail.classList.add('chart-line-focus');
rail.setAttribute('x1', originX);
rail.setAttribute('x2', originX);
rail.setAttribute('y1', y0);
rail.setAttribute('y2', y1);
rail.setAttribute('stroke', color);
this.fibFocus.appendChild(rail);
}
for (const level of ConfluenceChart.fibPrices(fib)) {
const y = this.candles.priceToCoordinate(level.price);
if (y == null) continue;
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.classList.add('chart-line-focus');
line.setAttribute('x1', start);
line.setAttribute('x2', width);
line.setAttribute('y1', y);
line.setAttribute('y2', y);
line.setAttribute('stroke', color);
this.fibFocus.appendChild(line);
}
this.fibFocus.removeAttribute('hidden');
for (const line of this.fibFocus.querySelectorAll('line')) {
line.style.animation = 'none';
void line.getBoundingClientRect();
line.style.animation = '';
}
clearTimeout(this.fibFocusTimer);
this.fibFocusTimer = setTimeout(() => this.fibFocus.setAttribute('hidden', ''), 800);
}
focusComment(id) {
const node = this.commentNodes.get(id);
if (!node) return;
@ -2906,6 +2963,7 @@ class ConfluenceChart {
this.detachPointers('anchor');
this.detachPointers('line');
clearTimeout(this.lineFocusTimer);
clearTimeout(this.fibFocusTimer);
for (const node of this.commentNodes.values()) clearTimeout(node.focusTimer);
if (this.chartEl && this.clickListener) this.chartEl.removeEventListener('click', this.clickListener);
if (this.chartEl && this.contextListener) this.chartEl.removeEventListener('contextmenu', this.contextListener);

View file

@ -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); }
.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] { 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 { 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; }
.current-price-pulse { position:absolute; left:0; right:0; z-index:5; height:3px; transform:translateY(-1.5px); overflow:hidden; opacity:0; background:repeating-linear-gradient(110deg,transparent 0 8px,color-mix(in srgb,var(--accent) 55%,white) 8px 13px,transparent 13px 19px); mask-image:linear-gradient(90deg,transparent 0,#000 8%,#000 100%); pointer-events:none; }.current-price-pulse::after { content:''; position:absolute; top:-2px; bottom:-2px; left:-24%; width:24%; background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--accent) 35%,white),transparent); opacity:.8; }.current-price-pulse.active { opacity:.9; animation:current-price-flow 1.5s linear infinite; }.current-price-pulse.active::after { animation:current-price-scan 2.8s linear infinite; }@keyframes current-price-flow { to { background-position-x:57px; } }@keyframes current-price-scan { to { transform:translateX(520%); } }
.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; }