평범한 노트북에서도 빠른 이유.
트레이딩 화면은 무겁습니다. 긴 히스토리, 멈추지 않는 틱, 한 페이지의 여러 차트. TradeCanvas는 프레임마다 필요한 일만, 메인 스레드에서, 서드파티 코드 없이 합니다. 이 페이지는 그 방법과 아직 개선 중인 부분을 보여 줍니다.
개발 중: 엔진은 실제로 쓰기에 충분히 빠르지만 아직 도달할 속도에는 이르지 않았습니다. 마지막 섹션에 남은 일을 적었습니다.
작은 패키지, 한 방향
각 패키지는 아래 패키지에만 의존합니다. TradeCanvas 밖의 코드는 페이지에서 실행되지 않습니다. 프레임워크 컴포넌트는 React, Vue, Svelte를 peer로 받고, WebGL 렌더러는 차트가 요청할 때만 불러오는 별도 청크입니다.
0 런타임 서드파티 의존성
틱 하나가 지나는 길
피드에서 온 가격이 한 프레임 안에 화면에 닿습니다. 각 단계는 바뀐 부분만 처리합니다.
- 1여러분의 피드
DataAdapterWebSocket, REST, 증권사: 히스토리와 스트림이 있으면 무엇이든. - 2스트림 매니저
StreamManager히스토리를 먼저, 그다음 실시간. 이전 요청의 응답은 버리고, 조용해진 피드는 30초 안에 알아챕니다. - 3틱 집계
TickAggregator틱은 1,000개짜리 링 버퍼에 들어가 해당 타임프레임의 봉으로 합쳐집니다. - 4지표
IndicatorEngine시리즈 처음부터가 아니라 마지막 봉부터 다시 계산합니다. - 5뷰포트
Viewport화면에 보이는 봉만 순회하고, 가격 축도 그 봉들로만 정합니다. - 6렌더 루프
RenderLoop틱이 몇 개 오든 장면은 애니메이션 프레임당 최대 한 번만 그립니다. - 7Canvas 2D 또는 WebGL
RenderEngine캔버스 두 개, WebGL을 켜면 그 아래 GPU 캔버스 하나.
틱 하나는 봉 하나의 비용, 히스토리 전체가 아닙니다
틱이 마지막 봉을 바꾸면 각 지표는 시리즈 전체를 다시 계산하지 않고 그 봉(과 공식이 되돌아보는 몇 개의 봉)부터 이어서 계산합니다. 기억하는 봉이 더 이상 맞지 않으면 전체 재계산으로 돌아가므로 데이터 수정을 놓치지 않습니다.
약 20개 지표는 자체 증분 업데이트를 갖고, 31개는 점 단위로 이어서 계산하는 기반 위에 만들어졌습니다. 다른 지표의 선을 읽는 지표도 이어서 계산합니다.
축소하면 픽셀당 한 열
봉이 1픽셀보다 좁아지면 하나씩 그리는 것은 눈에 보이지 않는 낭비입니다. 캔들, OHLC 바, 하이로, 거래량은 픽셀당 한 열로 그리며, 그 아래 봉들의 첫 시가, 최고가, 최저가, 마지막 종가를 씁니다. 선과 영역은 픽셀당 약 두 점(LTTB)을 유지하고, 지표 선과 밴드는 픽셀 열마다 한 구간을 그립니다.
- 화면 속 봉
- 313
- 픽셀당 봉
- 0.39
- 그린 도형
- 313
봉은 CSS 픽셀의 4분의 1보다 좁아지지 않습니다. 그래서 100만 개 봉을 가진 차트도 끝까지 축소하면 픽셀당 최대 약 4개, 1,600 px 차트에서 약 6,400개를 보여 줍니다. 100만 봉 벤치마크는 나머지를 이동하는 성능을 잽니다.
캔버스 두 개, 그래서 호버는 거의 비용이 없습니다
장면(그리드, 시리즈, 지표, 드로잉, 주문)은 한 캔버스에, 크로스헤어, 범례, 축 라벨, 카운트다운은 그 위의 얇은 캔버스에 있습니다. 마우스를 움직이면 위 캔버스만 다시 그립니다. 데이터가 바뀌면 다음 프레임에 장면을 한 번 그립니다.
전체 크기 캔버스마다 브라우저는 프레임당 한 번 합성을 더 합니다. 그래서 엔진은 캔버스를 적게 유지하고, 2D 전용 그리기용 보조 캔버스는 필요할 때만 둡니다.
다시 쓰지 않고 기록해서 WebGL로
차트는 Canvas 2D 호출로 그립니다. WebGL을 켜면 그 호출이 레코더로 가서 경로, 채우기, 선을 디바이스 픽셀 기준 GPU 명령으로 바꿉니다. GPU가 똑같이 그릴 수 없는 것은 순서를 지키며 Canvas 2D에 남으므로, 어느 쪽이든 그림은 같습니다.
- 경로, 채우기, 선
- 캔들, 거래량, 그리드를 인스턴싱으로
- 시리즈는 Float32Array 하나에 봉당 6개 값, 틱은 끝부분만 다시 씀
- 텍스트
- 이미지와 패턴
- 그림자, 필터, 특수한 클립
- GPU가 받지 못한 첫 단계 이후의 모든 것
renderer: 'auto'는 큰 성능 경고가 없는 컨텍스트를 요청하므로, WebGL을 소프트웨어로 돌리는 기기는 Canvas 2D를 유지합니다.- 한 페이지에서 최대 8개 차트가 WebGL 컨텍스트를 가집니다(
setMaxWebGLCharts). 나머지는 대기열에서 Canvas 2D로 그립니다. - GPU가 컨텍스트를 잃으면 차트는 Canvas 2D로 계속 그리고, 컨텍스트가 돌아오면 WebGL로 다시 구성합니다.
- 캔들은 셰이더와 CPU에서 같은 규칙으로 디바이스 픽셀에 맞춰지므로, 두 렌더러가 같은 픽셀에 그립니다.
저사양 기기를 위해
- 기본은 Canvas 2DWebGL은 더 많은 기기에서 측정될 때까지 선택 사항입니다. 높은 픽셀 비율의 내장 그래픽에서는 그리기가 아니라 브라우저의 합성이 병목입니다.
- 프레임당 한 번의 리사이즈리사이즈 이벤트는 프레임당 한 번으로 묶이고, 크기가 그대로면 아무것도 하지 않습니다.
- 페이지 단위 히스토리과거로 스크롤하면 이전 봉을 500개씩, 한 번에 한 요청만, 실패 후에는 간격을 늘리며 불러옵니다.
- 로딩 깜박임 없음로딩 화면은 200 ms를 기다리므로 빠른 종목 전환에서는 깜박이지 않습니다.
- 작은 다운로드헤드리스 차트는 gzip 기준 176 KB, 전체 위젯은 315 KB, WebGL 렌더러는 쓸 때 18 KB가 더해집니다.
- 제자리에서 갱신되는 시세판bo-grid 시세판은 틱을 프레임당 한 번의 패치로 합치고 바뀐 셀만 다시 그립니다.