동기화된 두 차트 — syncX
둘 중 아무 차트나 드래그하거나 휠로 확대해 보라 — x축(보는 구간)이 같이 움직인다. syncX(a, b)는 xDomainChange를 서로에게 미러링하는 30줄짜리 헬퍼다, 코어 계약이 아니라 조립이다.
소스
apps/examples/src/cases/sync-x.ts — CI가 타입체크하는 실물이다.
ts
import { PlotBuilder, browserDeps } from "@finchart/dom";
import type { OHLC, Plot } from "@finchart/core";
import { candleSeries, priceFormat, syncX, timeTicks } from "@finchart/core";
import { fixtureCandles } from "./fixture";
import { chartHost } from "./stage";
export const title = "동기화된 두 차트 — syncX";
export const description =
"둘 중 아무 차트나 드래그하거나 휠로 확대해 보라 — x축(보는 구간)이 같이 움직인다. syncX(a, b)는 xDomainChange를 서로에게 미러링하는 30줄짜리 헬퍼다, 코어 계약이 아니라 조립이다.";
function buildChart(
parent: HTMLElement,
name: string,
seed: number,
height: number,
): { plot: Plot; wrapper: HTMLElement } {
const wrapper = document.createElement("div");
parent.append(wrapper);
const label = document.createElement("div");
label.textContent = name;
label.style.cssText = "font-size: 13px; color: #64748b; margin-bottom: 4px";
wrapper.append(label);
const host = chartHost(wrapper, height);
const plot = PlotBuilder.create<OHLC>(browserDeps({ autoSize: true }))
.setSize(wrapper.clientWidth || 900, height)
.setAxis({
x: { ticks: timeTicks({ timeZone: "UTC", locale: "ko" }) },
y: { position: "right", format: priceFormat({ compact: true, locale: "ko" }) },
})
.build(host);
plot.mainPane.addSeries({
series: candleSeries(),
data: fixtureCandles(300, seed),
name,
});
return { plot, wrapper };
}
export function mount(container: HTMLElement): () => void {
const a = buildChart(container, "BTC/KRW", 7, 240);
const b = buildChart(container, "ETH/KRW", 13, 240);
const unsync = syncX(a.plot, b.plot);
return Object.assign(
() => {
unsync();
a.plot.destroy();
b.plot.destroy();
a.wrapper.remove();
b.wrapper.remove();
},
{
requestRender: () => {
a.plot.requestRender();
b.plot.requestRender();
},
},
);
}