feat: 선물 차트 마커 UI 개선 및 동일 타점 세로 스택

마커 라벨 2배 확대, Y축 뒤집기 버튼 추가, 같은 시각 마커를 좌우 대신 위아래로 표시한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dsyoon
2026-06-09 21:12:06 +09:00
parent a6e0d4081a
commit 281f4cfa25
23 changed files with 1603 additions and 1302 deletions

View File

@@ -157,11 +157,11 @@
el.textContent = `타점 ${currentLegIdx + 1} / ${total}`;
}
const MARKER_FONT = "bold 12px Malgun Gothic, Arial, sans-serif";
const MARKER_FONT = "bold 24px Malgun Gothic, Arial, sans-serif";
const SIM_START_COLOR = "#7b1fa2";
const ARROW_HALF = 6;
const ARROW_HEIGHT = 8;
const LABEL_OFFSET_X = 8;
const ARROW_HALF = 12;
const ARROW_HEIGHT = 16;
const LABEL_OFFSET_X = 16;
function markerSuffix(signalType) {
if (signalType === "pullback") return "*";
@@ -186,7 +186,7 @@
ctx.font = MARKER_FONT;
const lx = x + LABEL_OFFSET_X;
ctx.textBaseline = "middle";
ctx.lineWidth = 2;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, lx, labelY);
@@ -223,8 +223,8 @@
ctx.font = MARKER_FONT;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
const labelY = lineY - ARROW_HEIGHT - 6;
ctx.lineWidth = 2;
const labelY = lineY - ARROW_HEIGHT - 12;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, x, labelY);
@@ -234,7 +234,7 @@
ctx.textBaseline = "alphabetic";
}
const LABEL_GAP = 12;
const LABEL_GAP = 24;
function drawMarkers(u, buys, sells) {
if (!showMarkers) return;
@@ -295,7 +295,7 @@
const opts = {
width: document.getElementById("overview").clientWidth,
height: 480,
padding: [28, 10, 28, 10],
padding: [40, 10, 40, 10],
scales: { x: { time: true } },
axes: [
{ gap: 6 },
@@ -375,7 +375,7 @@
const sm = DATA.sim_start_marker;
if (sm.time >= t0 && sm.time <= t1) markers.push({
time: sm.time, position: "aboveBar",
color: SIM_START_COLOR, shape: "arrowDown", size: 3,
color: SIM_START_COLOR, shape: "arrowDown", size: 6,
text: sm.label || "거래시작",
});
}
@@ -385,7 +385,7 @@
time: m.time, position: "belowBar",
color: m.signal_type === "breakout" ? "#ef6c00"
: m.signal_type === "div_bull" ? "#7b1fa2" : "#2e7d32",
shape: "arrowUp", size: 5,
shape: "arrowUp", size: 10,
text: "B" + m.marker_id + markerSuffix(m.signal_type),
});
});
@@ -393,7 +393,7 @@
if (m.time >= t0 && m.time <= t1) markers.push({
time: m.time, position: "aboveBar",
color: m.signal_type === "div_bear" ? "#7b1fa2" : "#c62828",
shape: "arrowDown", size: 5,
shape: "arrowDown", size: 10,
text: "S" + m.marker_id + markerSuffix(m.signal_type),
});
});

File diff suppressed because one or more lines are too long

View File

@@ -157,11 +157,11 @@
el.textContent = `타점 ${currentLegIdx + 1} / ${total}`;
}
const MARKER_FONT = "bold 12px Malgun Gothic, Arial, sans-serif";
const MARKER_FONT = "bold 24px Malgun Gothic, Arial, sans-serif";
const SIM_START_COLOR = "#7b1fa2";
const ARROW_HALF = 6;
const ARROW_HEIGHT = 8;
const LABEL_OFFSET_X = 8;
const ARROW_HALF = 12;
const ARROW_HEIGHT = 16;
const LABEL_OFFSET_X = 16;
function markerSuffix(signalType) {
if (signalType === "pullback") return "*";
@@ -186,7 +186,7 @@
ctx.font = MARKER_FONT;
const lx = x + LABEL_OFFSET_X;
ctx.textBaseline = "middle";
ctx.lineWidth = 2;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, lx, labelY);
@@ -223,8 +223,8 @@
ctx.font = MARKER_FONT;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
const labelY = lineY - ARROW_HEIGHT - 6;
ctx.lineWidth = 2;
const labelY = lineY - ARROW_HEIGHT - 12;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, x, labelY);
@@ -234,7 +234,7 @@
ctx.textBaseline = "alphabetic";
}
const LABEL_GAP = 12;
const LABEL_GAP = 24;
function drawMarkers(u, buys, sells) {
if (!showMarkers) return;
@@ -295,7 +295,7 @@
const opts = {
width: document.getElementById("overview").clientWidth,
height: 480,
padding: [28, 10, 28, 10],
padding: [40, 10, 40, 10],
scales: { x: { time: true } },
axes: [
{ gap: 6 },
@@ -375,7 +375,7 @@
const sm = DATA.sim_start_marker;
if (sm.time >= t0 && sm.time <= t1) markers.push({
time: sm.time, position: "aboveBar",
color: SIM_START_COLOR, shape: "arrowDown", size: 3,
color: SIM_START_COLOR, shape: "arrowDown", size: 6,
text: sm.label || "거래시작",
});
}
@@ -385,7 +385,7 @@
time: m.time, position: "belowBar",
color: m.signal_type === "breakout" ? "#ef6c00"
: m.signal_type === "div_bull" ? "#7b1fa2" : "#2e7d32",
shape: "arrowUp", size: 5,
shape: "arrowUp", size: 10,
text: "B" + m.marker_id + markerSuffix(m.signal_type),
});
});
@@ -393,7 +393,7 @@
if (m.time >= t0 && m.time <= t1) markers.push({
time: m.time, position: "aboveBar",
color: m.signal_type === "div_bear" ? "#7b1fa2" : "#c62828",
shape: "arrowDown", size: 5,
shape: "arrowDown", size: 10,
text: "S" + m.marker_id + markerSuffix(m.signal_type),
});
});

File diff suppressed because one or more lines are too long

View File

@@ -157,11 +157,11 @@
el.textContent = `타점 ${currentLegIdx + 1} / ${total}`;
}
const MARKER_FONT = "bold 12px Malgun Gothic, Arial, sans-serif";
const MARKER_FONT = "bold 24px Malgun Gothic, Arial, sans-serif";
const SIM_START_COLOR = "#7b1fa2";
const ARROW_HALF = 6;
const ARROW_HEIGHT = 8;
const LABEL_OFFSET_X = 8;
const ARROW_HALF = 12;
const ARROW_HEIGHT = 16;
const LABEL_OFFSET_X = 16;
function markerSuffix(signalType) {
if (signalType === "pullback") return "*";
@@ -186,7 +186,7 @@
ctx.font = MARKER_FONT;
const lx = x + LABEL_OFFSET_X;
ctx.textBaseline = "middle";
ctx.lineWidth = 2;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, lx, labelY);
@@ -223,8 +223,8 @@
ctx.font = MARKER_FONT;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
const labelY = lineY - ARROW_HEIGHT - 6;
ctx.lineWidth = 2;
const labelY = lineY - ARROW_HEIGHT - 12;
ctx.lineWidth = 4;
ctx.lineJoin = "round";
ctx.strokeStyle = "rgba(255,255,255,0.95)";
ctx.strokeText(label, x, labelY);
@@ -234,7 +234,7 @@
ctx.textBaseline = "alphabetic";
}
const LABEL_GAP = 12;
const LABEL_GAP = 24;
function drawMarkers(u, buys, sells) {
if (!showMarkers) return;
@@ -295,7 +295,7 @@
const opts = {
width: document.getElementById("overview").clientWidth,
height: 480,
padding: [28, 10, 28, 10],
padding: [40, 10, 40, 10],
scales: { x: { time: true } },
axes: [
{ gap: 6 },
@@ -375,7 +375,7 @@
const sm = DATA.sim_start_marker;
if (sm.time >= t0 && sm.time <= t1) markers.push({
time: sm.time, position: "aboveBar",
color: SIM_START_COLOR, shape: "arrowDown", size: 3,
color: SIM_START_COLOR, shape: "arrowDown", size: 6,
text: sm.label || "거래시작",
});
}
@@ -385,7 +385,7 @@
time: m.time, position: "belowBar",
color: m.signal_type === "breakout" ? "#ef6c00"
: m.signal_type === "div_bull" ? "#7b1fa2" : "#2e7d32",
shape: "arrowUp", size: 5,
shape: "arrowUp", size: 10,
text: "B" + m.marker_id + markerSuffix(m.signal_type),
});
});
@@ -393,7 +393,7 @@
if (m.time >= t0 && m.time <= t1) markers.push({
time: m.time, position: "aboveBar",
color: m.signal_type === "div_bear" ? "#7b1fa2" : "#c62828",
shape: "arrowDown", size: 5,
shape: "arrowDown", size: 10,
text: "S" + m.marker_id + markerSuffix(m.signal_type),
});
});

File diff suppressed because one or more lines are too long