Plugin System
QFChart supports a flexible plugin system that allows you to add custom interactive tools and extensions to the chart. Plugins can be used to implement drawing tools, custom overlays, or additional UI controls.
registering a Plugin
To use a plugin, you must register it with the chart instance.
import { QFChart, MeasureTool } from "qfchart";
const chart = new QFChart(container, options);
// 1. Create Plugin Instance
const measureTool = new MeasureTool();
// 2. Register Plugin
chart.registerPlugin(measureTool);
Once registered, the plugin will automatically add its button/icon to the chart’s toolbar (if applicable).
Built-in Plugins
Measure Tool
The MeasureTool is a built-in plugin that allows users to measure price and time differences on the chart, similar to TradingView’s measure tool.
- Usage: Click the ruler icon in the toolbar.
- Interaction:
- Click on the chart to start the measurement.
- Move the mouse to drag the measurement box.
- Click again to finish and freeze the measurement.
- Click anywhere else or drag the chart to clear the measurement.
Fibonacci Tool
The FibonacciTool allows users to draw Fibonacci retracement levels on the chart.
- Usage: Click the Fibonacci icon in the toolbar.
- Interaction:
- Click to set the start point (e.g., swing high).
- Move mouse to set the end point (e.g., swing low).
- Click to finish drawing.
- Levels: 0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.
Creating Custom Plugins
You can create your own plugins by extending the AbstractPlugin class or implementing the Plugin interface directly. We recommend extending AbstractPlugin as it provides useful helpers and automatic event cleanup.
The AbstractPlugin Base Class
import { AbstractPlugin, ChartContext } from "qfchart";
export class MyCustomPlugin extends AbstractPlugin {
constructor() {
super({
id: "my-plugin",
name: "My Plugin",
icon: "<svg>...</svg>", // SVG icon for toolbar
});
}
// Lifecycle Hooks
protected onInit(): void {
console.log("Plugin initialized");
// Access chart instance via this.chart
// Access context via this.context
}
protected onActivate(): void {
console.log("Tool activated");
// Add event listeners automatically managed by the base class
this.on("mouse:move", this.handleMouseMove);
}
protected onDeactivate(): void {
console.log("Tool deactivated");
// Event listeners added with this.on() are automatically removed
}
private handleMouseMove = (params: any) => {
// Handle mouse move
};
}
The Chart Context
The ChartContext provides access to the underlying ECharts instance, data, and utility helpers.
export interface ChartContext {
// Core Access
getChart(): echarts.ECharts;
getMarketData(): OHLCV[];
getTimeToIndex(): Map<number, number>;
getOptions(): QFChartOptions;
// Event Bus
events: EventBus;
// Helpers
coordinateConversion: {
pixelToData: (point: { x; y }) => { timeIndex; value } | null;
dataToPixel: (point: { timeIndex; value }) => { x; y } | null;
};
// Interaction Control
disableTools(): void; // To disable other active tools
// Drawing Management
addDrawing(drawing: DrawingElement): void;
removeDrawing(id: string): void;
}
export interface DrawingElement {
id: string;
type: "line" | "fibonacci";
points: DataCoordinate[];
paneIndex?: number;
style?: {
color?: string;
lineWidth?: number;
};
}
Event Bus
The chart exposes an Event Bus via context.events for communication between plugins and the chart core. Standard events include:
mouse:down,mouse:move,mouse:up,mouse:clickchart:resize,chart:dataZoom,chart:updatedplugin:activated,plugin:deactivated
Drawing Events
When using the native drawing system (via addDrawing), the chart emits granular events for interactions with drawing elements:
- Shape Events:
drawing:hover: Mouse over a drawing shape (e.g., line).drawing:mouseout: Mouse out of a drawing shape.drawing:mousedown: Mouse down on a drawing shape.drawing:click: Click on a drawing shape.
- Control Point Events:
drawing:point:hover: Mouse over a control point (start/end).drawing:point:mouseout: Mouse out of a control point.drawing:point:mousedown: Mouse down on a control point.drawing:point:click: Click on a control point.
All drawing events carry a payload identifying the drawing:
{
id: string, // The ID of the drawing
type?: string, // The type of drawing (e.g., "line")
pointIndex?: number // For point events: 0 (start), 1 (end), etc.
}
Coordinate Conversion & Native Drawings
For persistent drawings (lines, shapes that stick to the chart), you should use the addDrawing API instead of manual ZRender management.
- Use ZRender for Interaction: While the user is drawing (dragging mouse), use ZRender graphics (via
chart.getZr()) for smooth, high-performance feedback. - Use Native Drawings for Persistence: Once drawing is finished, convert pixels to data coordinates and call
context.addDrawing().
Example: Creating a Line
// 1. Convert pixels to data coordinates
const start = this.context.coordinateConversion.pixelToData({ x: 100, y: 200 });
const end = this.context.coordinateConversion.pixelToData({ x: 300, y: 400 });
// 2. Add persistent drawing
if (start && end) {
this.context.addDrawing({
id: "my-line-1",
type: "line",
points: [start, end],
style: {
color: "#3b82f6",
lineWidth: 2,
},
});
}