diff --git a/agents/stock/workspace/scripts/behive_web.py b/agents/stock/workspace/scripts/behive_web.py index d39a767..ab17347 100644 --- a/agents/stock/workspace/scripts/behive_web.py +++ b/agents/stock/workspace/scripts/behive_web.py @@ -3660,7 +3660,7 @@ def _render_net_worth_chart(series: list[tuple[str, int]], current_net: int | No if solid_d: svg_parts.append(f'') if dashed_d: - svg_parts.append(f'') + svg_parts.append(f'') if point_dots: svg_parts.append(''.join(point_dots)) if has_live: @@ -3729,6 +3729,7 @@ def _render_net_worth_chart(series: list[tuple[str, int]], current_net: int | No '' f'{html.escape(last_label_v)}' '' @@ -9076,13 +9077,33 @@ window.openPinModal = openPinModal; if(td) td.innerHTML=''+sgn(T.daypl)+'원'+(T.dpct!==null?' ('+(T.dpct>=0?'+':'')+T.dpct.toFixed(2)+'%)':'')+''; } }); - // 순자산 차트 오늘(장중) 포인트 값 라벨 실시간 — 점 위치(SVG)는 새로고침 시, 값 라벨만 라이브. + // 순자산 차트 오늘(장중) 포인트 — 값 라벨 + SVG 점·마지막 선분을 1초마다 함께 이동(라벨↔점 불일치 제거). document.querySelectorAll('.net-chart-last[data-rt-nw-owner="'+owner+'"][data-rt-nw-live="1"]').forEach(function(el){ var basenet=parseFloat(el.getAttribute('data-rt-nw-basenet')||'0'); var baseval=parseFloat(el.getAttribute('data-rt-nw-baseval')||'0'); var v=Math.round(baseval+(T.net-basenet)); // 순자산 변동분 = 손익 변동분(baseline·cf는 세션 중 고정) var s=(el.getAttribute('data-rt-nw-pnl')==='1') ? ((v>=0?'+':'−')+Math.abs(v).toLocaleString()+'원') : (v.toLocaleString()+'원'); el.textContent=s+' (장중)'; + // 점 위치도 같은 값으로 재계산 — 서버 렌더와 동일 스케일 y = top + (1 − (v−ylo)/span)·ih. + var ylo=parseFloat(el.getAttribute('data-rt-nw-ylo')); + var span=parseFloat(el.getAttribute('data-rt-nw-span')); + var top=parseFloat(el.getAttribute('data-rt-nw-top')); + var ih=parseFloat(el.getAttribute('data-rt-nw-ih')); + var lastx=parseFloat(el.getAttribute('data-rt-nw-x')); + if([ylo,span,top,ih,lastx].some(isNaN)) return; + var chart=el.closest('.net-chart'); if(!chart) return; + var svg=chart.querySelector('svg.net-chart-svg'); if(!svg) return; + var ny=top+(1-(v-ylo)/span)*ih; + ny=Math.max(top, Math.min(top+ih, ny)); // 렌더 당시 범위 밖이면 차트 가장자리로 클램프(다음 페치가 스케일 재계산) + var nys=ny.toFixed(2); + ['.last-dot','.live-halo','.ath-ring'].forEach(function(sel){ + var c=svg.querySelector(sel); if(c) c.setAttribute('cy', nys); + }); + var al=svg.querySelector('.ath-label'); if(al) al.setAttribute('y', Math.max(ny-14, top+12).toFixed(2)); + var seg=svg.querySelector('.line.dashed.live-seg'); // 마지막(확정점→라이브) 점선 끝점 y 교체 + if(seg){ var d=seg.getAttribute('d')||''; seg.setAttribute('d', d.replace(/L\s*([\d.]+),[\d.]+\s*$/, 'L $1,'+nys)); } + var dots=svg.querySelectorAll('.pt-dot'); // 라이브 점과 같은 x의 pt-dot도 이동 + if(dots.length){ var ld=dots[dots.length-1]; if(Math.abs(parseFloat(ld.getAttribute('cx'))-lastx)<0.5) ld.setAttribute('cy', nys); } }); } // KPI 총합 — owner 탭 scope의 consolidated pane 행만 합산(중복합산 방지). 시세 미수신 종목은 data-rt-px(서버값) fallback.