Chart component system including axes, legends, titles, and interactive components for enhancing visualizations.
Components for displaying scales and reference information along chart axes.
/**
* Adds X-axis component to chart
* @param options - X-axis configuration options
*/
component(type: "axisX", options?: AxisXOptions): Chart;
/**
* Adds Y-axis component to chart
* @param options - Y-axis configuration options
*/
component(type: "axisY", options?: AxisYOptions): Chart;
interface AxisXOptions {
/** Show or hide axis title */
title?: string | boolean;
/** Axis title configuration */
titleStyle?: StyleOptions;
/** Show or hide grid lines */
grid?: boolean;
/** Grid line style */
gridStyle?: StyleOptions;
/** Show or hide tick marks */
tick?: boolean;
/** Tick mark configuration */
tickStyle?: StyleOptions;
/** Show or hide axis labels */
label?: boolean;
/** Label configuration */
labelStyle?: StyleOptions;
/** Label formatter function */
labelFormatter?: (value: any) => string;
/** Number of ticks */
tickCount?: number;
/** Specific tick values */
tickValues?: any[];
/** Axis line style */
lineStyle?: StyleOptions;
}
interface AxisYOptions extends AxisXOptions {
/** Position of Y axis: 'left' | 'right' */
position?: "left" | "right";
}Usage Examples:
// Basic axes
chart
.interval()
.data(salesData)
.encode("x", "month")
.encode("y", "revenue")
.component("axisX", { title: "Month" })
.component("axisY", { title: "Revenue ($)" });
// Customized axis with grid
chart
.line()
.data(timeSeriesData)
.encode("x", "date")
.encode("y", "price")
.component("axisX", {
title: "Date",
grid: true,
gridStyle: { stroke: "#f0f0f0", strokeWidth: 1 }
})
.component("axisY", {
title: "Price",
labelFormatter: (d) => `$${d.toFixed(2)}`,
position: "right"
});Components for displaying color, size, and other visual encoding legends.
/**
* Adds categorical legend for discrete color/shape mappings
* @param options - Categorical legend options
*/
component(type: "legendCategory", options?: LegendCategoryOptions): Chart;
/**
* Adds continuous legend for continuous color/size mappings
* @param options - Continuous legend options
*/
component(type: "legendContinuous", options?: LegendContinuousOptions): Chart;
/**
* Adds multiple legends with automatic layout
*/
component(type: "legends", options?: LegendsOptions): Chart;
interface LegendCategoryOptions {
/** Legend title */
title?: string;
/** Legend position */
position?: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
/** Item layout direction */
layout?: "horizontal" | "vertical";
/** Number of columns (for horizontal layout) */
cols?: number;
/** Item spacing */
itemSpacing?: number;
/** Item width */
itemWidth?: number;
/** Item height */
itemHeight?: number;
/** Legend item style */
itemStyle?: StyleOptions;
/** Title style */
titleStyle?: StyleOptions;
/** Label formatter */
labelFormatter?: (value: any) => string;
}
interface LegendContinuousOptions {
/** Legend title */
title?: string;
/** Legend position */
position?: "top" | "bottom" | "left" | "right";
/** Legend width */
width?: number;
/** Legend height */
height?: number;
/** Number of tick marks */
tickCount?: number;
/** Label formatter */
labelFormatter?: (value: any) => string;
/** Title style */
titleStyle?: StyleOptions;
}Usage Examples:
// Categorical color legend
chart
.point()
.data(scatterData)
.encode("x", "height")
.encode("y", "weight")
.encode("color", "gender")
.component("legendCategory", {
title: "Gender",
position: "right",
layout: "vertical"
});
// Continuous color legend for heatmap
chart
.rect()
.data(heatmapData)
.encode("x", "x")
.encode("y", "y")
.encode("color", "value")
.component("legendContinuous", {
title: "Temperature (°C)",
position: "bottom",
width: 300,
labelFormatter: (d) => `${d}°C`
});
// Multiple legends
chart
.point()
.data(bubbleData)
.encode("x", "gdp")
.encode("y", "lifeExpectancy")
.encode("color", "continent")
.encode("size", "population")
.component("legends", {
color: {
title: "Continent",
position: "right"
},
size: {
title: "Population",
position: "bottom"
}
});Components that provide user interaction capabilities.
/**
* Adds horizontal data slider for filtering
* @param options - Horizontal slider options
*/
component(type: "sliderX", options?: SliderXOptions): Chart;
/**
* Adds vertical data slider for filtering
* @param options - Vertical slider options
*/
component(type: "sliderY", options?: SliderYOptions): Chart;
/**
* Adds horizontal scrollbar for panning
* @param options - Horizontal scrollbar options
*/
component(type: "scrollbarX", options?: ScrollbarXOptions): Chart;
/**
* Adds vertical scrollbar for panning
* @param options - Vertical scrollbar options
*/
component(type: "scrollbarY", options?: ScrollbarYOptions): Chart;
interface SliderXOptions {
/** Slider position */
position?: "top" | "bottom";
/** Initial range [start, end] as ratios (0-1) */
range?: [number, number];
/** Slider height */
height?: number;
/** Handle style */
handleStyle?: StyleOptions;
/** Track style */
trackStyle?: StyleOptions;
/** Callback for range changes */
onChange?: (range: [number, number]) => void;
}
interface SliderYOptions {
/** Slider position */
position?: "left" | "right";
/** Initial range [start, end] as ratios (0-1) */
range?: [number, number];
/** Slider width */
width?: number;
/** Handle style */
handleStyle?: StyleOptions;
/** Track style */
trackStyle?: StyleOptions;
/** Callback for range changes */
onChange?: (range: [number, number]) => void;
}Usage Examples:
// Time series with date range slider
chart
.line()
.data(timeSeriesData)
.encode("x", "date")
.encode("y", "value")
.component("sliderX", {
position: "bottom",
range: [0.8, 1.0], // Show last 20% initially
onChange: (range) => {
console.log("Date range changed:", range);
}
});
// Large dataset with vertical range slider
chart
.point()
.data(largeDataset)
.encode("x", "value1")
.encode("y", "value2")
.component("sliderY", {
position: "right",
range: [0, 0.5], // Show bottom half initially
width: 20
});Components for chart titles and annotations.
/**
* Chart title component configuration
*/
interface TitleComponent {
/** Title text */
text: string;
/** Title position */
position?: "top" | "bottom" | "left" | "right";
/** Title alignment */
align?: "start" | "center" | "end";
/** Title style */
style?: TitleStyle;
/** Subtitle text */
subtitle?: string;
/** Subtitle style */
subtitleStyle?: StyleOptions;
}
interface TitleStyle {
/** Font size */
fontSize?: number;
/** Font weight */
fontWeight?: string | number;
/** Font family */
fontFamily?: string;
/** Text color */
fill?: string;
/** Text alignment */
textAlign?: "left" | "center" | "right";
/** Margin around title */
margin?: number | [number, number, number, number];
}Usage Examples:
// Add title via chart specification
const chartSpec = {
type: "view",
children: [
{
type: "interval",
data: salesData,
encode: { x: "month", y: "revenue" }
}
],
title: {
text: "Monthly Revenue Trends",
subtitle: "2023 Sales Performance",
position: "top",
align: "center",
style: {
fontSize: 20,
fontWeight: "bold",
fill: "#333"
}
}
};Comprehensive styling options for all component types.
interface StyleOptions {
/** Fill color */
fill?: string;
/** Stroke color */
stroke?: string;
/** Stroke width */
strokeWidth?: number;
/** Opacity (0-1) */
opacity?: number;
/** Font family */
fontFamily?: string;
/** Font size */
fontSize?: number;
/** Font weight */
fontWeight?: string | number;
/** Text alignment */
textAlign?: "left" | "center" | "right";
/** Line dash pattern */
lineDash?: number[];
/** Border radius */
radius?: number;
/** Padding */
padding?: number | [number, number, number, number];
/** Margin */
margin?: number | [number, number, number, number];
}Components automatically position themselves but can be customized.
// Component positioning
interface ComponentLayout {
/** Automatic layout (default) */
layout?: "auto";
/** Manual positioning */
position?: {
x?: number;
y?: number;
width?: number;
height?: number;
};
/** Z-index for layering */
zIndex?: number;
}Layout Examples:
// Custom positioned legend
chart
.point()
.data(data)
.encode("x", "x")
.encode("y", "y")
.encode("color", "category")
.component("legendCategory", {
position: { x: 50, y: 50, width: 150, height: 100 },
title: "Categories"
});
// Multiple components with z-index
chart
.line()
.data(data)
.encode("x", "date")
.encode("y", "value")
.component("axisX", { zIndex: 1 })
.component("axisY", { zIndex: 1 })
.component("legendCategory", { zIndex: 2 });Components can respond to user interactions.
interface ComponentEvents {
/** Click event */
onClick?: (event: ComponentEvent) => void;
/** Hover event */
onHover?: (event: ComponentEvent) => void;
/** Value change (for interactive components) */
onChange?: (value: any) => void;
}
interface ComponentEvent {
type: string;
target: any;
data?: any;
x?: number;
y?: number;
}Event Examples:
// Interactive legend with click events
chart
.point()
.data(data)
.encode("x", "x")
.encode("y", "y")
.encode("color", "category")
.component("legendCategory", {
title: "Categories",
onClick: (event) => {
console.log("Legend item clicked:", event.data);
// Toggle category visibility
}
});
// Slider with change events
chart
.line()
.data(timeSeriesData)
.encode("x", "date")
.encode("y", "value")
.component("sliderX", {
onChange: (range) => {
// Filter data based on range
const filtered = filterDataByRange(timeSeriesData, range);
chart.update({ data: filtered });
}
});