Plugin
Mở rộng biểu đồ bằng chỉ báo, công cụ vẽ, loại biểu đồ và lớp phủ tuỳ chỉnh — đăng ký toàn cục hoặc cho từng biểu đồ.
Đăng ký
Có ba cách đăng ký, theo thứ tự ưu tiên: mặc định toàn cục, qua constructor, rồi gọi trực tiếp trên instance.
import { Chart, registerPlugin } from '@tradecanvas/chart'
// 1) Global — every Chart created afterward inherits it
registerPlugin({ kind: 'indicator', plugin: new MyIndicator() })
// 2) Per-chart at construction
const chart = new Chart(el, { plugins: [{ kind: 'overlay', plugin: myHeatmap }] })
// 3) Imperative on an instance
chart.plugins.register({ kind: 'chartType', plugin: myCandles })
chart.plugins.unregister('chartType:my-candles')
chart.plugins.list() Các loại plugin
| Loại | Interface | Vẽ ở |
|---|---|---|
indicator | IndicatorPlugin — calculate() + render() | phủ lên biểu đồ hoặc bảng riêng |
drawing | DrawingPlugin — render() + hitTest() | lớp overlay |
chartType | ChartTypePlugin — createRenderer() + transform() tuỳ chọn | chuỗi chính |
overlay | OverlayPlugin — render(ctx, { viewport, data, theme }) | main / overlay / ui |
Chỉ báo tuỳ chỉnh
Kế thừa IndicatorBase để có sẵn các hàm hỗ trợ vẽ, rồi đăng ký và thêm nó như mọi chỉ báo có sẵn:
import { IndicatorBase, IndicatorValueMap, registerPlugin } from '@tradecanvas/chart'
class DoubleSMA extends IndicatorBase {
descriptor = {
id: 'double-sma', name: 'Double SMA',
placement: 'overlay', defaultConfig: { fast: 10, slow: 30 },
}
calculate(data, config) { /* values = new IndicatorValueMap(); return { values, series } */ }
render(ctx, output, viewport, style) { /* draw lines */ }
}
registerPlugin({ kind: 'indicator', plugin: new DoubleSMA() })
chart.addIndicator('double-sma', { fast: 10, slow: 30 }) Với values, hãy dùng new IndicatorValueMap() thay vì new Map(): nó thay thế trực tiếp
được cho Map nhưng rẻ hơn nhiều lần khi điền từng nến theo thứ tự thời gian, đúng là việc mà mỗi lần
đổi mã hay khung thời gian phải làm trên toàn bộ lịch sử.
Cập nhật trực tiếp nhanh (tuỳ chọn)
Mỗi tick trực tiếp chỉ làm thay đổi nến đang hình thành. Cài đặt update() để chỉ tính lại
các nến từ from trở đi thay vì toàn bộ lịch sử — biểu đồ dùng nó khi có tick và
nến mới, và quay về calculate() khi hàm này không có hoặc trả về null.
Nó phải cho ra đúng các giá trị mà calculate() sẽ cho.
update(data, config, prev, from) {
if (!this.canResume(data, prev, from)) return null // IndicatorBase helper
for (let i = from; i < data.length; i++) {
this.writePoint(prev, data, i, { value: /* recompute bar i */ 0 })
}
return prev
} Công cụ vẽ tuỳ chỉnh
Kế thừa DrawingBase để có sẵn các hàm hỗ trợ (đổi điểm neo ra
pixel, kiểu nét, điểm kéo), mô tả công cụ rồi đăng ký nó. Các cài đặt liệt kê
trong descriptor.options sẽ hiện trong hộp thoại cài đặt của
widget và được lưu cùng hình vẽ.
import { DrawingBase, registerPlugin } from '@tradecanvas/chart'
class TargetLine extends DrawingBase {
descriptor = {
type: 'targetLine', name: 'Target Line', requiredAnchors: 1,
options: { label: { kind: 'text', label: 'Label', default: 'Target' } },
}
render(ctx, state, viewport, selected) { /* tại this.anchorToPixel(state.anchors[0], viewport) */ }
hitTest(point, state, viewport, tolerance) { /* con trỏ có nằm trên nó không? */ return false }
// tuỳ chọn: giá của các đường, để cảnh báo có thể bám theo
priceAt(state) { return [state.anchors[0].price] }
}
registerPlugin({ kind: 'drawing', plugin: new TargetLine() })
chart.setDrawingTool('targetLine') Descriptor còn có thể cho biết công cụ được vẽ ra sao (creation: 'clicks', 'freehand' hoặc 'path', kèm maxAnchors) và hộp thoại có cho chọn màu nền
(fill) hay chữ (text) hay không. Công cụ có thể
di chuyển các điểm kéo không phải điểm neo bằng moveHandle(), và
nhận các nến của biểu đồ qua setDataGetter() khi nó vẽ dựa trên
chúng.
Loại biểu đồ tuỳ chỉnh
Một ChartTypePlugin cung cấp bộ render và một phép biến đổi dữ liệu tuỳ chọn; chuyển sang nó như với một loại có sẵn:
registerPlugin({
kind: 'chartType',
plugin: {
descriptor: { type: 'my-bricks', name: 'My Bricks' },
createRenderer: () => new MyBrickRenderer(),
transform: (raw) => toBricks(raw), // optional
},
})
chart.setChartType('my-bricks') Lớp phủ tuỳ chỉnh
Một OverlayPlugin vẽ mỗi khung hình trên lớp bạn chọn, nhận khung nhìn, dữ liệu và giao diện (theme) hiện tại:
import { overlayScale, registerPlugin } from '@tradecanvas/chart'
registerPlugin({
kind: 'overlay',
plugin: {
descriptor: { id: 'high-marks', name: 'High marks', layer: 'main' },
render(ctx, context) {
const s = overlayScale(context)
ctx.fillStyle = '#f2a93b'
for (let i = s.visible.from; i <= s.visible.to; i++) {
const bar = context.data[i]
ctx.fillRect(s.indexToX(i) - s.barWidth / 2, s.priceToY(bar.high) - 1, s.barWidth, 2)
}
},
},
}) overlayScale(context) đặt mọi thứ đúng chỗ chart vẽ: timeToX / xToTime theo thời gian nến (giữa hai nến và sau nến mới nhất thì theo tỉ lệ), indexToX / xToIndex, priceToY / yToPrice (cả thang log và thang đảo ngược), barWidth, và visible là các nến đang hiện trên màn hình. Muốn chia hàng theo lưới giá thì dùng chart.getPriceStep(): bước giá nhỏ nhất của mã (minTick), đơn vị phân số, hoặc một
đơn vị của số lẻ đang hiển thị. Renderer của chỉ báo và loại chart chỉ nhận viewport; cho chúng, priceToY, barIndexToX, timeToX và các hàm ngược được export sẵn. Các nến là
nến đang vẽ: trên chart Renko hay Kagi là các viên gạch của nó (chart.isTimeAligned() cho biết khi nào
chúng trùng với nến của nguồn dữ liệu).
Overlay có cài đặt riêng (kiểu hiển thị, công tắc) có thể hiện thay đổi ngay, kể cả khi không có tick nào
tới để vẽ lại chart: đặt enabled: false trên plugin để ẩn nó mà vẫn giữ đăng ký, và gọi chart.requestRender() sau khi đổi một trong hai. Nhiều lần gọi trước khung hình kế tiếp chỉ vẽ một khung.
Xem Tham chiếu API để biết đầy đủ chữ ký kiểu của plugin.