Created
December 2, 2024 23:45
-
-
Save SnowyPainter/22c70cfb00632ea10bbeaa2b31f8f96a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 전역 데이터 저장소 | |
let chartData = []; | |
let svg, x, y, width, height, margin; | |
function initializeChart() { | |
margin = { top: 20, right: 20, bottom: 30, left: 50 }; | |
width = 800 - margin.left - margin.right; | |
height = 400 - margin.top - margin.bottom; | |
// SVG 설정 | |
svg = d3.select("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", `translate(${margin.left},${margin.top})`); | |
// 스케일 초기 설정 | |
x = d3.scaleBand() | |
.range([0, width]) | |
.padding(0.2); | |
y = d3.scaleLinear() | |
.range([height, 0]); | |
// 축 생성 | |
svg.append("g") | |
.attr("class", "x-axis") | |
.attr("transform", `translate(0,${height})`); | |
svg.append("g") | |
.attr("class", "y-axis"); | |
} | |
function updateChart() { | |
const parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S"); | |
chartData.forEach(d => { | |
if (typeof d.timestamp === 'string') { | |
d.timestamp = parseTime(d.timestamp); | |
} | |
}); | |
// 스케일 도메인 업데이트 | |
x.domain(chartData.map(d => d.timestamp)); | |
y.domain([ | |
d3.min(chartData, d => d.low) * 0.999, | |
d3.max(chartData, d => d.high) * 1.001 | |
]).nice(); | |
// 축 업데이트 | |
svg.select(".x-axis") | |
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%H:%M"))); | |
svg.select(".y-axis") | |
.call(d3.axisLeft(y)); | |
// 캔들스틱 업데이트 | |
const candles = svg.selectAll(".candle") | |
.data(chartData, d => d.timestamp); | |
// 새로운 캔들스틱 추가 | |
candles.enter() | |
.append("rect") | |
.attr("class", d => `candle ${d.close > d.open ? 'up' : 'down'}`) | |
.attr("x", d => x(d.timestamp)) | |
.attr("y", d => y(Math.max(d.open, d.close))) | |
.attr("width", x.bandwidth()) | |
.attr("height", d => Math.abs(y(d.open) - y(d.close))); | |
// 기존 캔들스틱 업데이트 | |
candles | |
.attr("class", d => `candle ${d.close > d.open ? 'up' : 'down'}`) | |
.attr("x", d => x(d.timestamp)) | |
.attr("y", d => y(Math.max(d.open, d.close))) | |
.attr("width", x.bandwidth()) | |
.attr("height", d => Math.abs(y(d.open) - y(d.close))); | |
// 오래된 캔들스틱 제거 | |
candles.exit().remove(); | |
// 고가/저가 선 업데이트 | |
const wicks = svg.selectAll(".wick") | |
.data(chartData, d => d.timestamp); | |
// 새로운 선 추가 | |
wicks.enter() | |
.append("line") | |
.attr("class", "wick") | |
.attr("x1", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("x2", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("y1", d => y(d.high)) | |
.attr("y2", d => y(d.low)) | |
.attr("stroke", "black"); | |
// 기존 선 업데이트 | |
wicks | |
.attr("x1", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("x2", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("y1", d => y(d.high)) | |
.attr("y2", d => y(d.low)); | |
// 오래된 선 제거 | |
wicks.exit().remove(); | |
// 예측 포인트 업데이트 | |
const points = svg.selectAll(".prediction-point") | |
.data(chartData.filter(d => d.prediction > 0), d => d.timestamp); | |
// 새로운 포인트 추가 | |
points.enter() | |
.append("circle") | |
.attr("class", d => `prediction-point prediction-${d.prediction}`) | |
.attr("cx", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("cy", d => y(d.close)) | |
.attr("r", 4); | |
// 기존 포인트 업데이트 | |
points | |
.attr("class", d => `prediction-point prediction-${d.prediction}`) | |
.attr("cx", d => x(d.timestamp) + x.bandwidth() / 2) | |
.attr("cy", d => y(d.close)); | |
// 오래된 포인트 제거 | |
points.exit().remove(); | |
} | |
function connectWebSocket() { | |
const ws = new WebSocket('ws://localhost:8000/ws'); | |
ws.onmessage = function(event) { | |
const message = JSON.parse(event.data); | |
if (message.type === "initial") { | |
chartData = message.data; | |
updateChart(); | |
} else if (message.type === "update") { | |
// 새 데이터 추가 및 오래된 데이터 제거 | |
chartData.push(message.data); | |
if (chartData.length > 30) { | |
chartData.shift(); | |
} | |
updateChart(); | |
} | |
}; | |
ws.onclose = function() { | |
// 연결이 끊어지면 3초 후 재연결 시도 | |
setTimeout(connectWebSocket, 3000); | |
}; | |
} | |
// 차트 초기화 및 웹소켓 연결 시작 | |
document.addEventListener('DOMContentLoaded', () => { | |
initializeChart(); | |
connectWebSocket(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment