SuperAPI AI Directory

openalgo-chart-plugin

General & other

View repository

Updated 10-16 00:06

About this skill

Extend the engine. Everything extensible in this library is a registry entry or a primitive - there is no plugin loader and no core file to edit.

Step 1 - pick the extension point

Answer these in order and stop at the first yes.

Question Build
Does it need its own data, autoscale and price-scale identity? a chart type via registerChartType
Is it a shape the user places with clicks and drags later? a drawing tool via registerDrawingTool
Is it a number computed per bar that should get a pane, legend row and settings? an indicator via registerIndicator
Anything else that draws - band, zone, label, watermark, custom axis marker a primitive via IPrimitive

Default to a primitive. It is the cheapest and most flexible. Reach past it only when the table above says to.

Step 2 - read the contract before writing

Confirm the interface shape against local typings before writing an implementation:

rg -n "interface IPrimitive|interface RendererEntry|interface DrawingTool|interface IndicatorDescriptor" \
  node_modules/openalgo-charts/dist/index.d.ts node_modules/openalgo-charts/dist/draw/index.d.ts

Step 3 - the rules that make it correct

  1. Draw in bitmap pixels. The canvas context is scaled to the device. Multiply every media-px value by ctx.dpr before you draw, or the result blurs and drifts on HiDPI displays. This is the single most common mistake.
  2. Anchor in data space, not pixels. Store { time, price } and convert at draw time. The time axis is gapless, so a pixel anchor slides the moment a session gap collapses or the user zooms.
  3. Pick the right z-order. 'bottom' draws behind the series, 'normal' over it on the base canvas, 'top' on the overlay canvas which repaints on cursor moves. Anything that follows the pointer belongs on 'top'; anything static does not, or you will repaint it on every mouse move.
  4. autoscaleInfo runs every layout pass. Return a cheap precomputed extent; do not scan your data there.
  5. Give hit-testable primitives a stable externalId. Clicks and drags route back to you through it.
  6. Clean up in detached. Timers, subscriptions, cached bitmaps.
  7. Register into the package entry, never a deep path. A deep import creates a second registry Map and your registration becomes invisible to createChart. See bundling-and-tiers.
  8. Register before use. For a chart type, before the addSeries call that names it.
  9. No emojis or icons in drawn text or logs.

Step 4 - minimum viable primitive

import type { IPrimitive, PrimitiveRenderContext } from 'openalgo-charts';

class Band implements IPrimitive {
  constructor(private lo: number, private hi: number) {}
  zOrder() { return 'bottom' as const; }
  draw(g: CanvasRenderingContext2D, ctx: PrimitiveRenderContext) {
    const dpr = ctx.dpr;
    const y1 = ctx.priceScale.priceToY(this.hi) * dpr;
    const y2 = ctx.priceScale.priceToY(this.lo) * dpr;
    g.fillStyle = 'rgba(80,140,255,0.12)';
    g.fillRect(0, y1, ctx.plotWidth * dpr, y2 - y1);
  }
  autoscaleInfo() { return { min: this.lo, max: this.hi }; }
}

chart.addPrimitive(new Band(99, 101), 0);

Confirm every member name against the typings before shipping this shape - the reference file documents the interface, but dist/index.d.ts is authoritative.

Step 5 - test it

The repo's own tests are the pattern to copy. Look at tests/primitives.test.ts, tests/draw-tier.test.ts and tests/chart-types.test.ts for how a canvas-free unit test asserts draw calls and hit-testing. A plugin with no test is not done.

npx vitest run
npx tsc --noEmit

Report the extension point you chose and why, the file you created, and the test that covers it.