Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ Generated from `dist/index.d.ts` after the package build.
| Export | Kind | Source | JSDoc summary |
|---|---|---|---|
| `AcceleratedDataset` | interface | `./core/types` | Convenience contract for maximum-performance custom datasets. Implement this when a dataset can provide fast exact sample copies, stable viewport sampling, range min/max queries, and renderer-ready min/max buckets. |
| `AppendableDataset` | interface | `./core/types` | Dataset that accepts appended explicit X/Y samples. |
| `AppendableDataset` | interface | `./core/types` | Dataset that accepts appended X/Y samples; implementations may store X values explicitly or use them to seed implicit X spacing. |
| `AttributeSpec` | interface | `./render/types` | Vertex attribute binding for a draw call. |
| `AxisConfig` | interface | `./ui/Chart` | Axis visibility, placement, scale, tick formatting, and title options. |
| `AxisController` | class | `./interaction/AxisController` | Computes axis tick values and labels for a camera. |
Expand Down Expand Up @@ -317,7 +317,7 @@ Generated from `dist/index.d.ts` after the package build.
| `PrecomputedHistogramSeriesConfig` | interface | `./ui/Chart` | Series configuration for `Chart.addHistogram(...)` from precomputed bins. |
| `RangeMinMaxDataset` | interface | `./core/types` | Dataset that can answer min/max Y queries for index ranges. |
| `RangeSampleCopyDataset` | interface | `./core/types` | Optional high-performance extraction capability for datasets that can copy raw samples without going through repeated getX/getY calls. Implement this for very large datasets, implicit-X datasets, or remote/memory-mapped sources. |
| `ReglBackend` | const | `./render/WebGL2Backend` | Deprecated alias for WebGL2Backend. This preserves the pre-native-backend public API. Deprecated: Effective next patch release. Use WebGL2Backend. |
| `ReglBackend` | const | `./render/WebGL2Backend` | Deprecated alias for WebGL2Backend. This preserves the pre-native-backend public API. Deprecated: Use WebGL2Backend; removal target: 0.4.0. |
| `ResolvedChartTheme` | interface | `./ui/theme` | Fully resolved chart theme with concrete RGBA values. |
| `RgbaColor` | type | `./ui/theme` | RGBA color tuple with 0-1 channel values. |
| `RingBuffer` | class | `./core/RingBuffer` | Fixed-capacity sorted XY buffer for explicit X values. |
Expand Down
4 changes: 2 additions & 2 deletions docs/api-reference.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions src/core/SeriesStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class SeriesStore {
/** Append XY, implicit-X, OHLC, or row-array data and request an on-demand render. */
append(data: SeriesAppendData): void;
/**
* @deprecated Effective next patch release. Use `append({ x, y })` instead.
* @deprecated Use `append({ x, y })` instead; removal target: 0.4.0.
*/
append(x: ArrayLike<number>, y: ArrayLike<number>): void;
/** Append data in the supported object, row, or legacy array forms. */
Expand Down Expand Up @@ -326,7 +326,7 @@ export class SeriesStore {
}

/**
* @deprecated Effective next patch release. Use `append({ y })` instead.
* @deprecated Use `append({ y })` instead; removal target: 0.4.0.
*/
appendY(y: ArrayLike<number>): void {
this.appendYArray(y);
Expand All @@ -342,7 +342,7 @@ export class SeriesStore {
}

/**
* @deprecated Effective next patch release. Use `append({ x, open, high, low, close })` instead.
* @deprecated Use `append({ x, open, high, low, close })` instead; removal target: 0.4.0.
*/
appendOhlc(
x: ArrayLike<number>,
Expand Down Expand Up @@ -421,7 +421,7 @@ export class SeriesStore {
}

/**
* @deprecated Effective next patch release. Use `updateLast({ open, high, low, close })` instead.
* @deprecated Use `updateLast({ open, high, low, close })` instead; removal target: 0.4.0.
*/
updateLastOhlc(open: number, high: number, low: number, close: number): boolean {
return this.updateOhlcAt(this.dataset.length - 1, open, high, low, close);
Expand Down
2 changes: 1 addition & 1 deletion src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export interface OhlcDataset extends Dataset {
getClose(index: number): number;
}

/** Dataset that accepts appended explicit X/Y samples. */
/** Dataset that accepts appended X/Y samples; implementations may store X values explicitly or use them to seed implicit X spacing. */
export interface AppendableDataset extends Dataset {
push(x: number, y: number): void;
append(x: ArrayLike<number>, y: ArrayLike<number>): void;
Expand Down
2 changes: 1 addition & 1 deletion src/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export function exportSelectedChartData(
}, options);
}

/** Collect all raw samples from chart series, optionally constrained by options.series and visibleOnly. */
/** Collect raw samples from visible chart series by default; pass visibleOnly: false to include hidden series. */
export function exportAllChartData(chart: Chart, options: ChartDataExportOptions = {}): ChartDataExport {
return collectChartData(chart, { source: "all", bounds: null }, options);
}
Expand Down
1 change: 1 addition & 0 deletions src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ChartOptions } from "./ui/Chart.js";

/** Props for the React chart host component. */
export interface BlazeChartProps {
/** Chart options used at construction time. Changing object identity disposes and recreates the chart; keep stable with useMemo. */
readonly options?: ChartOptions;
readonly className?: string;
readonly style?: React.CSSProperties;
Expand Down
2 changes: 1 addition & 1 deletion src/render/WebGL2Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,6 @@ export class WebGL2Backend implements GpuBackend {

/**
* Deprecated alias for WebGL2Backend. This preserves the pre-native-backend public API.
* @deprecated Effective next patch release. Use WebGL2Backend.
* @deprecated Use WebGL2Backend; removal target: 0.4.0.
*/
export const ReglBackend: typeof WebGL2Backend = WebGL2Backend;
22 changes: 11 additions & 11 deletions src/ui/Annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export interface AnnotationsPlugin extends ChartPlugin {

const SVG_NS = "http://www.w3.org/2000/svg";

function svg<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K] {
function createSvgElement<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K] {
return document.createElementNS(SVG_NS, tag);
}

Expand Down Expand Up @@ -316,7 +316,7 @@ export function annotationsPlugin(options: AnnotationsPluginOptions = {}): Annot
return {
install(chart: ChartPluginContext) {
chartRef = chart;
overlay = svg("svg");
overlay = createSvgElement("svg");
overlay.classList.add(options.className ?? "blazeplot-annotations");
overlay.style.position = "absolute";
overlay.style.inset = "0";
Expand Down Expand Up @@ -420,14 +420,14 @@ function drawAnnotation(
const viewport = chart.getViewport(annotation.yAxis ?? "left");
const xToPx = (x: number): number => ((x - viewport.xMin) / (viewport.xMax - viewport.xMin)) * width;
const yToPx = (y: number): number => ((viewport.yMax - y) / (viewport.yMax - viewport.yMin)) * height;
const group = svg("g");
const group = createSvgElement("g");
if (annotation.className) group.classList.add(annotation.className);

switch (annotation.type) {
case "x-line": {
const x = xToPx(annotation.x);
if (x < 0 || x > width) return;
const line = svg("line");
const line = createSvgElement("line");
line.setAttribute("x1", String(x));
line.setAttribute("x2", String(x));
line.setAttribute("y1", "0");
Expand All @@ -440,7 +440,7 @@ function drawAnnotation(
case "y-line": {
const y = yToPx(annotation.y);
if (y < 0 || y > height) return;
const line = svg("line");
const line = createSvgElement("line");
line.setAttribute("x1", "0");
line.setAttribute("x2", String(width));
line.setAttribute("y1", String(y));
Expand Down Expand Up @@ -500,7 +500,7 @@ function styleStroke(el: SVGElement, color: string, width: number = 1, dash?: st
}

function appendRect(group: SVGGElement, rect: { x: number; y: number; w: number; h: number }, fill: string, stroke?: string, strokeWidth: number = 0): void {
const el = svg("rect");
const el = createSvgElement("rect");
el.setAttribute("x", String(rect.x));
el.setAttribute("y", String(rect.y));
el.setAttribute("width", String(rect.w));
Expand All @@ -518,7 +518,7 @@ function appendMarker(group: SVGGElement, x: number, y: number, radius: number,
const stroke = annotation.strokeColor ?? "rgba(0,0,0,0.35)";
const strokeWidth = annotation.strokeWidth ?? 1;
if (annotation.shape === "diamond") {
const polygon = svg("polygon");
const polygon = createSvgElement("polygon");
polygon.setAttribute("points", `${x},${y - radius} ${x + radius},${y} ${x},${y + radius} ${x - radius},${y}`);
polygon.setAttribute("fill", fill);
polygon.setAttribute("stroke", stroke);
Expand All @@ -529,7 +529,7 @@ function appendMarker(group: SVGGElement, x: number, y: number, radius: number,

if (annotation.shape === "cross") {
for (const [x1, y1, x2, y2] of [[x - radius, y, x + radius, y], [x, y - radius, x, y + radius]] as const) {
const line = svg("line");
const line = createSvgElement("line");
line.setAttribute("x1", String(x1));
line.setAttribute("y1", String(y1));
line.setAttribute("x2", String(x2));
Expand All @@ -540,7 +540,7 @@ function appendMarker(group: SVGGElement, x: number, y: number, radius: number,
return;
}

const circle = svg("circle");
const circle = createSvgElement("circle");
circle.setAttribute("cx", String(x));
circle.setAttribute("cy", String(y));
circle.setAttribute("r", String(radius));
Expand All @@ -553,7 +553,7 @@ function appendMarker(group: SVGGElement, x: number, y: number, radius: number,
function appendStandaloneLabel(group: SVGGElement, annotation: LabelAnnotation, x: number, y: number, defaultColor: string, defaultFont: string): void {
const text = appendText(group, annotation.text, x, y, "start", annotation.color ?? defaultColor, annotation.font ?? defaultFont);
if (annotation.backgroundColor) {
const rect = svg("rect");
const rect = createSvgElement("rect");
rect.setAttribute("x", String(x - 4));
rect.setAttribute("y", String(y - 14));
rect.setAttribute("width", String(Math.max(16, annotation.text.length * 7 + 8)));
Expand All @@ -572,7 +572,7 @@ function appendLabel(group: SVGGElement, label: string | AnnotationLabelOptions
}

function appendText(group: SVGGElement, textValue: string, x: number, y: number, anchor: "start" | "middle" | "end", color: string, font: string): SVGTextElement {
const text = svg("text");
const text = createSvgElement("text");
text.textContent = textValue;
text.setAttribute("x", String(x));
text.setAttribute("y", String(y));
Expand Down
12 changes: 9 additions & 3 deletions src/ui/Crosshair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type CrosshairLabelPlacement = "bottom-right" | "top-right" | "bottom-lef
/** Custom renderer for crosshair pick highlights. */
export type CrosshairHighlightRenderer = (position: CrosshairPosition, container: HTMLElement, chart: Chart) => void;

/** Crosshair position in client and data coordinates. */
/** Crosshair position in data coordinates and plot-relative CSS pixels. */
export interface CrosshairPosition {
readonly dataX: number;
readonly dataY: number;
Expand Down Expand Up @@ -88,6 +88,12 @@ export interface CrosshairPlugin extends ChartPlugin {
subscribe(event: "measurechange" | "measureend", callback: (measurement: RulerMeasurement) => void): () => void;
}

const SVG_NS = "http://www.w3.org/2000/svg";

function createSvgElement<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K] {
return document.createElementNS(SVG_NS, tag);
}

function countSamplesInRange(chart: ChartPluginContext, xMin: number, xMax: number): number {
const viewport = { xMin, xMax, yMin: -Infinity, yMax: Infinity };
let total = 0;
Expand Down Expand Up @@ -394,15 +400,15 @@ export function crosshairPlugin(options: CrosshairPluginOptions = {}): Crosshair
label.style.font = options.labelFont ?? chart.theme.tooltipFont;
label.style.whiteSpace = "nowrap";

rulerSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
rulerSvg = createSvgElement("svg");
rulerSvg.style.position = "absolute";
rulerSvg.style.inset = "0";
rulerSvg.style.width = "100%";
rulerSvg.style.height = "100%";
rulerSvg.style.display = "none";
rulerSvg.style.overflow = "hidden";
rulerSvg.style.zIndex = "1";
rulerLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
rulerLine = createSvgElement("line");
rulerLine.setAttribute("stroke", color);
rulerLine.setAttribute("stroke-width", String(options.width ?? 1));
if (dash) rulerLine.setAttribute("stroke-dasharray", dash);
Expand Down
16 changes: 8 additions & 8 deletions src/ui/Navigator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ interface DragState {

const SVG_NS = "http://www.w3.org/2000/svg";

function svg<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K] {
function createSvgElement<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K] {
return document.createElementNS(SVG_NS, tag);
}

Expand Down Expand Up @@ -169,7 +169,7 @@ export function navigatorPlugin(options: NavigatorPluginOptions = {}): Navigator
overlay.setAttribute("preserveAspectRatio", "none");

while (paths.length < selectedSeries.length) {
const path = svg("path");
const path = createSvgElement("path");
path.setAttribute("fill", "none");
path.setAttribute("vector-effect", "non-scaling-stroke");
overlay.insertBefore(path, windowRect);
Expand Down Expand Up @@ -265,16 +265,16 @@ export function navigatorPlugin(options: NavigatorPluginOptions = {}): Navigator
chart.setLayoutReservation(reservationId, placement === "top" ? { top: height + margin * 2 } : { bottom: height + margin * 2 });
}

overlay = svg("svg");
overlay = createSvgElement("svg");
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.setAttribute("aria-hidden", "true");
overlay.style.display = "block";
windowRect = svg("rect");
leftHandle = svg("rect");
rightHandle = svg("rect");
leftHandleHit = svg("rect");
rightHandleHit = svg("rect");
windowRect = createSvgElement("rect");
leftHandle = createSvgElement("rect");
rightHandle = createSvgElement("rect");
leftHandleHit = createSvgElement("rect");
rightHandleHit = createSvgElement("rect");
for (const handle of [leftHandle, rightHandle]) {
handle.style.cursor = "ew-resize";
handle.style.pointerEvents = "none";
Expand Down
4 changes: 2 additions & 2 deletions src/ui/OverlayUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export function placeFixedWithinViewport(
element: HTMLElement,
clientX: number,
clientY: number,
options: { readonly offsetX: number; readonly offsetY: number; readonly margin?: number },
options: { readonly offsetX: number; readonly offsetY: number; readonly margin?: number; readonly size?: { readonly width: number; readonly height: number } },
): void {
const rect = element.getBoundingClientRect();
const rect = options.size ?? element.getBoundingClientRect();
const margin = options.margin ?? 4;
const doc = element.ownerDocument;
const viewportWidth = Math.max(1, globalThis.innerWidth || doc.documentElement.clientWidth);
Expand Down
18 changes: 9 additions & 9 deletions src/ui/Tooltip.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Chart, ChartHoverState, ChartPickGroup, ChartPickItem, ChartPickMode, ChartPlugin, ChartPluginContext } from "./Chart.js";
import { clamp, createLongPressTouchTracker, createOverlayLayer, createPickMarker, formatCompactNumber, pickAtDataX, rgba, renderPickItems } from "./OverlayUtils.js";
import { createLongPressTouchTracker, createOverlayLayer, createPickMarker, formatCompactNumber, pickAtDataX, placeFixedWithinViewport, renderPickItems, rgba } from "./OverlayUtils.js";

/** Options for the built-in hover tooltip plugin. */
export interface TooltipPluginOptions {
Expand Down Expand Up @@ -50,14 +50,14 @@ interface TooltipPeer {
const tooltipGroups = new Map<string, Set<TooltipPeer>>();

function placeTooltip(container: HTMLElement, state: ChartHoverState, options: TooltipPluginOptions, size: { readonly width: number; readonly height: number }): void {
const margin = 4;
const width = Math.max(1, size.width || 240);
const height = Math.max(1, size.height || 80);
const viewportWidth = Math.max(1, globalThis.innerWidth || container.ownerDocument.documentElement.clientWidth);
const viewportHeight = Math.max(1, globalThis.innerHeight || container.ownerDocument.documentElement.clientHeight);
const x = clamp(state.clientX + (options.offsetX ?? 12), margin, Math.max(margin, viewportWidth - width - margin));
const y = clamp(state.clientY + (options.offsetY ?? 12), margin, Math.max(margin, viewportHeight - height - margin));
container.style.transform = `translate(${x}px, ${y}px)`;
placeFixedWithinViewport(container, state.clientX, state.clientY, {
offsetX: options.offsetX ?? 12,
offsetY: options.offsetY ?? 12,
size: {
width: Math.max(1, size.width || 240),
height: Math.max(1, size.height || 80),
},
});
}

/** Create a plugin that displays picked data values in a tooltip. */
Expand Down