<gui-chart />
Usage
ts
import config from './config';
const chart = document.createElement('gui-chart');
chart.setConfig({
table: {
cols: [
[1, 2, 3, 4, 5],
[10, 42, 1337, 12, 0],
],
},
xAxis: {},
yAxes: {
y: {},
},
series: [
{
type: 'line',
title: 'Value',
xCol: 0,
yCol: 1,
yAxis: 'y',
},
],
});
parent.appendChild(chart);
import config from './config';
const chart = document.createElement('gui-chart');
chart.setConfig({
table: {
cols: [
[1, 2, 3, 4, 5],
[10, 42, 1337, 12, 0],
],
},
xAxis: {},
yAxes: {
y: {},
},
series: [
{
type: 'line',
title: 'Value',
xCol: 0,
yCol: 1,
yAxis: 'y',
},
],
});
parent.appendChild(chart);
tsx
parent.appendChild(<gui-chart config={config} />);
parent.appendChild(<gui-chart config={config} />);
tsx
<WCWrapper tag="gui-chart" config={config} />
<WCWrapper tag="gui-chart" config={config} />
Config
ts
export interface ChartConfig<K = { [keys: string]: never }> {
table: TableLike;
series: Serie<Extract<keyof K, string>>[];
/**
* The x-axis definition
*/
xAxis: Axis;
/**
* One or more axes that will be used for y-axes.
*
* This is a key-value object for the series to be able
* to refer to them by the 'key' name in `yAxis`
*/
yAxes: {
[name in keyof K]: Ordinate;
};
cursor?: boolean;
/**
* Tooltip position, defaults to 'top-left'
*/
tooltip?: Partial<Tooltip>;
selection?: Partial<SelectionOptions>;
/**
* Delta in milliseconds between two `touchend` event.
*
* If under this threshold the touch event is processed
* as a `dbltap` rather than a `touchend`
*
* Defaults: `500`
*/
dblTapThreshold?: number;
}
export interface ChartConfig<K = { [keys: string]: never }> {
table: TableLike;
series: Serie<Extract<keyof K, string>>[];
/**
* The x-axis definition
*/
xAxis: Axis;
/**
* One or more axes that will be used for y-axes.
*
* This is a key-value object for the series to be able
* to refer to them by the 'key' name in `yAxis`
*/
yAxes: {
[name in keyof K]: Ordinate;
};
cursor?: boolean;
/**
* Tooltip position, defaults to 'top-left'
*/
tooltip?: Partial<Tooltip>;
selection?: Partial<SelectionOptions>;
/**
* Delta in milliseconds between two `touchend` event.
*
* If under this threshold the touch event is processed
* as a `dbltap` rather than a `touchend`
*
* Defaults: `500`
*/
dblTapThreshold?: number;
}
Serie
ts
export interface CustomSerie<K> extends CommonSerie<K> {
type: 'custom';
draw: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale
) => void;
}
export interface LineSerie<K> extends CommonSerie<K> {
type: 'line';
}
export interface StepSerie<K> extends CommonSerie<K> {
type: 'step';
}
export interface BarSerie<K> extends CommonSerie<K> {
type: 'bar';
}
export interface ScatterSerie<K> extends CommonSerie<K> {
type: 'scatter';
}
export interface LineScatterSerie<K> extends CommonSerie<K> {
type: 'line+scatter';
}
export interface AreaSerie<K> extends CommonSerie<K> {
type: 'area';
}
export interface LineAreaSerie<K> extends CommonSerie<K> {
type: 'line+area';
}
export type Serie<K extends string = string> =
| LineSerie<K>
| BarSerie<K>
| ScatterSerie<K>
| LineScatterSerie<K>
| AreaSerie<K>
| LineAreaSerie<K>
| CustomSerie<K>
| StepSerie<K>;
export interface CustomSerie<K> extends CommonSerie<K> {
type: 'custom';
draw: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale
) => void;
}
export interface LineSerie<K> extends CommonSerie<K> {
type: 'line';
}
export interface StepSerie<K> extends CommonSerie<K> {
type: 'step';
}
export interface BarSerie<K> extends CommonSerie<K> {
type: 'bar';
}
export interface ScatterSerie<K> extends CommonSerie<K> {
type: 'scatter';
}
export interface LineScatterSerie<K> extends CommonSerie<K> {
type: 'line+scatter';
}
export interface AreaSerie<K> extends CommonSerie<K> {
type: 'area';
}
export interface LineAreaSerie<K> extends CommonSerie<K> {
type: 'line+area';
}
export type Serie<K extends string = string> =
| LineSerie<K>
| BarSerie<K>
| ScatterSerie<K>
| LineScatterSerie<K>
| AreaSerie<K>
| LineAreaSerie<K>
| CustomSerie<K>
| StepSerie<K>;
Common Serie
ts
export interface CommonSerie<K> extends Partial<SerieOptions> {
/**
* optional offset of the x column in the given table
*
* If undefined, the array index will be used
*/
xCol?: number;
/**
* offset of the y column in the given table
*/
yCol: number;
/**
* must refer to a defined 'key' in `config.yAxes`
* and will be used as the y-axis for this serie
*/
yAxis: K;
/**
* offset of the column in the table to use to read
* lineType values for each x
*/
lineTypeCol?: number;
/**
* offset of the column in the table to use to read
* the line color values for segment
*/
colorCol?: number;
/**
* Optional title used to name the serie.
*/
title?: string;
/**
* A hook to customize canvas drawing.
* This is called before the serie has been drawn.
*/
drawBefore?: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale,
) => void;
/**
* A hook to customize canvas drawing.
* This is called after the serie has been drawn.
*/
drawAfter?: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale,
) => void;
}
export interface CommonSerie<K> extends Partial<SerieOptions> {
/**
* optional offset of the x column in the given table
*
* If undefined, the array index will be used
*/
xCol?: number;
/**
* offset of the y column in the given table
*/
yCol: number;
/**
* must refer to a defined 'key' in `config.yAxes`
* and will be used as the y-axis for this serie
*/
yAxis: K;
/**
* offset of the column in the table to use to read
* lineType values for each x
*/
lineTypeCol?: number;
/**
* offset of the column in the table to use to read
* the line color values for segment
*/
colorCol?: number;
/**
* Optional title used to name the serie.
*/
title?: string;
/**
* A hook to customize canvas drawing.
* This is called before the serie has been drawn.
*/
drawBefore?: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale,
) => void;
/**
* A hook to customize canvas drawing.
* This is called after the serie has been drawn.
*/
drawAfter?: (
ctx: CanvasContext,
serie: SerieWithOptions,
xScale: Scale,
yScale: Scale,
) => void;
}
Misc
ts
export type Scale =
| d3.ScaleLinear<number, number, never>
| d3.ScaleTime<number, number, never>
| d3.ScaleLogarithmic<number, number, never>;
export type Color = string | CanvasGradient | CanvasPattern;
export type SerieType = Serie['type'];
export type ScaleType = Extract<Axis['scale'], string>;
export type SecondOrdinate = 'min' | 'max' | number;
export type AxisPosition = 'left' | 'right';
export type MarkerShape = 'circle' | 'square' | 'triangle';
export type TooltipPosition = 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
export type SerieWithOptions = Serie & SerieOptions;
// we don't care about the type here, it is user-defined
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type SerieData = Serie & SerieOptions & { xValue?: any; yValue?: any; rowIdx: number };
export type SelectionOptions = {
/**
* If a selection is smallr than this value in pixels it will be ignored.
*
* Defaults: `10`
*/
threshold: number;
/**
* - `'vertical'` means only selectable according to y axes
* - `'horizontal'` means only selectable according to x axis
* - `'both'` means selectable on y & x axes
*
* Defaults to 'horizontal'
*/
orientation: 'vertical' | 'horizontal' | 'both';
};
export type Tooltip = {
position: TooltipPosition;
/**
* Called whenever the tooltip should update its content.
*
* *If this is defined, the default tooltip will not display.*
*
* @param data
* @returns
*/
render?: (data: SerieData[]) => void;
};
export type CommonAxis = {
title?: string;
min?: number | Date | core.time | core.Date;
max?: number | Date | core.time | core.Date;
/**
* Formats the ticks on the axis
* See https://d3js.org/d3-format#format
*
* If the `scale` is `'time'` and `format` is `undefined`, the display is defaulting to ISO.
* See https://d3js.org/d3-time-format#utcFormat
*/
format?: string;
/**
* Formats the cursor hover text on the axis
*
* See https://d3js.org/d3-format#format for number values
* See https://d3js.org/d3-time-format#utcFormat for time values in UTC
*/
cursorFormat?: string;
/**
* Zoom ratio
*/
ratio?: number;
/**
* This is called right before rendering the axis onto the chart.
*
* **When defined, no other axis properties will be applied `format`, `ticks`, etc.**
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
hook?: (axis: d3.Axis<any>) => void;
};
export interface LinearAxis extends CommonAxis {
scale?: 'linear';
/**
* If specified, the values are used for ticks rather than the scale’s automatic tick generator.
*
* However, any tick arguments will still be passed to the scale’s tickFormat function if a tick format is not also set.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ticks?: any[];
}
export interface LogAxis extends CommonAxis {
scale: 'log';
/**
* If specified, the values are used for ticks rather than the scale’s automatic tick generator.
*
* However, any tick arguments will still be passed to the scale’s tickFormat function if a tick format is not also set.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ticks?: any[];
}
export interface TimeAxis extends CommonAxis {
scale: 'time';
/**
* Time axis can also leverage `d3.TimeInterval` by specifying for instance `d3.utcHour.every(24)`
*/
ticks?: d3.TimeInterval | (core.time | core.Date | Date | number)[] | null;
}
export type Axis = LinearAxis | LogAxis | TimeAxis;
export type Ordinate = Axis & { position?: AxisPosition };
export type SerieOptions = {
color: string;
width: number;
markerWidth: number;
markerShape: MarkerShape;
markerColor: string;
opacity: number;
fillOpacity: number;
/**
* - `'min'`: draws the area from `yCol` to the bottom
* - `'max'`: draws the area from `yCol` to the top
* - `<number>`: draws the area from `yCol` to the column at offset `<number>`
*/
yCol2: SecondOrdinate;
/**
* Maps the col values (from `colorCol`) to a color definition.
*
* *Returning `null` or `undefined` will make the painting use the default color of the serie*
*
* *Not defining a `colorMapping` will use the value as-is for coloring, meaning the serie's column can contain color codes directly*
*
* @param v the current cell value
* @returns the color used for canvas painting
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
colorMapping?: (v: any) => Color | null | undefined;
};
export type Scale =
| d3.ScaleLinear<number, number, never>
| d3.ScaleTime<number, number, never>
| d3.ScaleLogarithmic<number, number, never>;
export type Color = string | CanvasGradient | CanvasPattern;
export type SerieType = Serie['type'];
export type ScaleType = Extract<Axis['scale'], string>;
export type SecondOrdinate = 'min' | 'max' | number;
export type AxisPosition = 'left' | 'right';
export type MarkerShape = 'circle' | 'square' | 'triangle';
export type TooltipPosition = 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
export type SerieWithOptions = Serie & SerieOptions;
// we don't care about the type here, it is user-defined
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type SerieData = Serie & SerieOptions & { xValue?: any; yValue?: any; rowIdx: number };
export type SelectionOptions = {
/**
* If a selection is smallr than this value in pixels it will be ignored.
*
* Defaults: `10`
*/
threshold: number;
/**
* - `'vertical'` means only selectable according to y axes
* - `'horizontal'` means only selectable according to x axis
* - `'both'` means selectable on y & x axes
*
* Defaults to 'horizontal'
*/
orientation: 'vertical' | 'horizontal' | 'both';
};
export type Tooltip = {
position: TooltipPosition;
/**
* Called whenever the tooltip should update its content.
*
* *If this is defined, the default tooltip will not display.*
*
* @param data
* @returns
*/
render?: (data: SerieData[]) => void;
};
export type CommonAxis = {
title?: string;
min?: number | Date | core.time | core.Date;
max?: number | Date | core.time | core.Date;
/**
* Formats the ticks on the axis
* See https://d3js.org/d3-format#format
*
* If the `scale` is `'time'` and `format` is `undefined`, the display is defaulting to ISO.
* See https://d3js.org/d3-time-format#utcFormat
*/
format?: string;
/**
* Formats the cursor hover text on the axis
*
* See https://d3js.org/d3-format#format for number values
* See https://d3js.org/d3-time-format#utcFormat for time values in UTC
*/
cursorFormat?: string;
/**
* Zoom ratio
*/
ratio?: number;
/**
* This is called right before rendering the axis onto the chart.
*
* **When defined, no other axis properties will be applied `format`, `ticks`, etc.**
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
hook?: (axis: d3.Axis<any>) => void;
};
export interface LinearAxis extends CommonAxis {
scale?: 'linear';
/**
* If specified, the values are used for ticks rather than the scale’s automatic tick generator.
*
* However, any tick arguments will still be passed to the scale’s tickFormat function if a tick format is not also set.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ticks?: any[];
}
export interface LogAxis extends CommonAxis {
scale: 'log';
/**
* If specified, the values are used for ticks rather than the scale’s automatic tick generator.
*
* However, any tick arguments will still be passed to the scale’s tickFormat function if a tick format is not also set.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ticks?: any[];
}
export interface TimeAxis extends CommonAxis {
scale: 'time';
/**
* Time axis can also leverage `d3.TimeInterval` by specifying for instance `d3.utcHour.every(24)`
*/
ticks?: d3.TimeInterval | (core.time | core.Date | Date | number)[] | null;
}
export type Axis = LinearAxis | LogAxis | TimeAxis;
export type Ordinate = Axis & { position?: AxisPosition };
export type SerieOptions = {
color: string;
width: number;
markerWidth: number;
markerShape: MarkerShape;
markerColor: string;
opacity: number;
fillOpacity: number;
/**
* - `'min'`: draws the area from `yCol` to the bottom
* - `'max'`: draws the area from `yCol` to the top
* - `<number>`: draws the area from `yCol` to the column at offset `<number>`
*/
yCol2: SecondOrdinate;
/**
* Maps the col values (from `colorCol`) to a color definition.
*
* *Returning `null` or `undefined` will make the painting use the default color of the serie*
*
* *Not defining a `colorMapping` will use the value as-is for coloring, meaning the serie's column can contain color codes directly*
*
* @param v the current cell value
* @returns the color used for canvas painting
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
colorMapping?: (v: any) => Color | null | undefined;
};