Interactive behavior system providing hover effects, selection, brushing, and custom interaction patterns.
Interactions that target individual chart elements.
/**
* Highlights elements on hover
* @param options - Highlight interaction options
*/
interaction(type: "elementHighlight", options?: ElementHighlightOptions): Chart;
/**
* Highlights elements by X value
*/
interaction(type: "elementHighlightByX", options?: ElementHighlightByXOptions): Chart;
/**
* Highlights elements by color encoding
*/
interaction(type: "elementHighlightByColor", options?: ElementHighlightByColorOptions): Chart;
/**
* Selects elements on click
*/
interaction(type: "elementSelect", options?: ElementSelectOptions): Chart;
/**
* Selects elements by X value
*/
interaction(type: "elementSelectByX", options?: ElementSelectByXOptions): Chart;
/**
* Selects elements by color encoding
*/
interaction(type: "elementSelectByColor", options?: ElementSelectByColorOptions): Chart;
interface ElementHighlightOptions {
/** Grouping field for related elements */
by?: string;
/** Link highlighting across multiple charts */
link?: boolean;
/** Highlight style */
style?: {
fill?: string;
stroke?: string;
strokeWidth?: number;
opacity?: number;
};
/** Unhighlighted element style */
unselectedStyle?: {
opacity?: number;
fill?: string;
};
}
interface ElementSelectOptions extends ElementHighlightOptions {
/** Allow multiple selection */
multiple?: boolean;
/** Selection behavior */
toggle?: boolean;
/** Callback for selection changes */
onSelect?: (selected: any[]) => void;
}Usage Examples:
// Basic element highlighting
chart
.point()
.data(scatterData)
.encode("x", "height")
.encode("y", "weight")
.encode("color", "gender")
.interaction("elementHighlight", {
style: {
strokeWidth: 3,
stroke: "black"
},
unselectedStyle: {
opacity: 0.3
}
});
// Selection by category
chart
.interval()
.data(salesData)
.encode("x", "category")
.encode("y", "sales")
.interaction("elementSelectByX", {
multiple: true,
onSelect: (selected) => {
console.log("Selected categories:", selected);
}
});
// Linked highlighting across series
chart
.line()
.data(multiSeriesData)
.encode("x", "date")
.encode("y", "value")
.encode("color", "series")
.interaction("elementHighlightByColor", {
link: true,
by: "series"
});Interactions that affect the entire chart or visualization area.
/**
* Adds tooltip functionality
* @param options - Tooltip configuration
*/
interaction(type: "tooltip", options?: TooltipOptions): Chart;
/**
* Adds fisheye lens distortion on hover
* @param options - Fisheye interaction options
*/
interaction(type: "fisheye", options?: FisheyeOptions): Chart;
/**
* Adds chart indexing for temporal data
* @param options - Chart index options
*/
interaction(type: "chartIndex", options?: ChartIndexOptions): Chart;
interface TooltipOptions {
/** Tooltip title */
title?: string | ((data: any) => string);
/** Tooltip items to display */
items?: string[] | ((data: any) => string[]);
/** Tooltip position */
position?: "auto" | "top" | "bottom" | "left" | "right";
/** Share tooltip across multiple elements */
shared?: boolean;
/** Custom tooltip renderer */
render?: (data: any) => HTMLElement | string;
/** Tooltip style */
style?: {
backgroundColor?: string;
border?: string;
borderRadius?: number;
padding?: number;
fontSize?: number;
color?: string;
};
}
interface FisheyeOptions {
/** Distortion strength */
strength?: number;
/** Focus radius */
radius?: number;
/** Animation duration */
duration?: number;
}Usage Examples:
// Custom tooltip
chart
.point()
.data(bubbleData)
.encode("x", "gdp")
.encode("y", "lifeExpectancy")
.encode("size", "population")
.encode("color", "continent")
.interaction("tooltip", {
title: (d) => d.country,
items: ["gdp", "lifeExpectancy", "population"],
position: "auto",
style: {
backgroundColor: "rgba(0,0,0,0.8)",
color: "white",
borderRadius: 4,
padding: 8
}
});
// Fisheye interaction for large datasets
chart
.point()
.data(largeDataset)
.encode("x", "x")
.encode("y", "y")
.interaction("fisheye", {
strength: 2.5,
radius: 100
});
// Chart index for time series
chart
.line()
.data(timeSeriesData)
.encode("x", "date")
.encode("y", "value")
.interaction("chartIndex", {
showCrosshair: true,
snapToData: true
});Brush interactions for selecting regions of data.
/**
* Highlights data within brushed area
*/
interaction(type: "brushHighlight", options?: BrushHighlightOptions): Chart;
/**
* Highlights data within horizontal brush
*/
interaction(type: "brushXHighlight", options?: BrushXHighlightOptions): Chart;
/**
* Highlights data within vertical brush
*/
interaction(type: "brushYHighlight", options?: BrushYHighlightOptions): Chart;
/**
* Filters data within brushed area
*/
interaction(type: "brushFilter", options?: BrushFilterOptions): Chart;
/**
* Filters data within horizontal brush
*/
interaction(type: "brushXFilter", options?: BrushXFilterOptions): Chart;
/**
* Filters data within vertical brush
*/
interaction(type: "brushYFilter", options?: BrushYFilterOptions): Chart;
interface BrushHighlightOptions {
/** Brush area style */
maskStyle?: {
fill?: string;
opacity?: number;
stroke?: string;
strokeWidth?: number;
};
/** Highlighted element style */
highlightStyle?: StyleOptions;
/** Unhighlighted element style */
unselectedStyle?: StyleOptions;
/** Callback for brush events */
onBrush?: (selection: any) => void;
}
interface BrushFilterOptions {
/** Filter behavior */
persistent?: boolean;
/** Animation duration for filter transitions */
duration?: number;
/** Callback for filter changes */
onFilter?: (filtered: any[]) => void;
}Usage Examples:
// 2D brush selection
chart
.point()
.data(scatterData)
.encode("x", "height")
.encode("y", "weight")
.interaction("brushHighlight", {
maskStyle: {
fill: "rgba(0,0,255,0.1)",
stroke: "blue",
strokeWidth: 2
},
onBrush: (selection) => {
console.log("Brushed data:", selection);
}
});
// Horizontal brush for time series
chart
.line()
.data(timeSeriesData)
.encode("x", "date")
.encode("y", "value")
.interaction("brushXFilter", {
persistent: true,
onFilter: (filtered) => {
updateLinkedCharts(filtered);
}
});
// Vertical brush for value filtering
chart
.interval()
.data(histogramData)
.encode("x", "bin")
.encode("y", "count")
.interaction("brushYHighlight", {
highlightStyle: {
fill: "orange",
opacity: 0.8
}
});Interactions that work with chart components like legends and axes.
/**
* Filters data based on legend selection
*/
interaction(type: "legendFilter", options?: LegendFilterOptions): Chart;
/**
* Highlights data based on legend hover
*/
interaction(type: "legendHighlight", options?: LegendHighlightOptions): Chart;
/**
* Filters data based on slider position
*/
interaction(type: "sliderFilter", options?: SliderFilterOptions): Chart;
/**
* Filters data based on scrollbar position
*/
interaction(type: "scrollbarFilter", options?: ScrollbarFilterOptions): Chart;
interface LegendFilterOptions {
/** Allow multiple selection */
multiple?: boolean;
/** Default selected items */
defaultSelected?: string[];
/** Animation duration */
duration?: number;
/** Callback for filter changes */
onFilter?: (selected: string[]) => void;
}
interface LegendHighlightOptions {
/** Highlight style for matching elements */
highlightStyle?: StyleOptions;
/** Style for non-matching elements */
unselectedStyle?: StyleOptions;
}Usage Examples:
// Interactive legend filtering
chart
.point()
.data(categoricalData)
.encode("x", "value1")
.encode("y", "value2")
.encode("color", "category")
.component("legendCategory")
.interaction("legendFilter", {
multiple: true,
defaultSelected: ["A", "B"],
onFilter: (selected) => {
console.log("Active categories:", selected);
}
});
// Legend highlighting
chart
.line()
.data(multiSeriesData)
.encode("x", "x")
.encode("y", "y")
.encode("color", "series")
.component("legendCategory")
.interaction("legendHighlight", {
highlightStyle: {
strokeWidth: 3,
opacity: 1
},
unselectedStyle: {
opacity: 0.2
}
});Domain-specific interactions for specialized visualizations.
/**
* Provides drill-down functionality for treemaps
*/
interaction(type: "treemapDrillDown", options?: TreemapDrillDownOptions): Chart;
/**
* Enables point movement for interactive scatter plots
*/
interaction(type: "elementPointMove", options?: ElementPointMoveOptions): Chart;
/**
* Shows contextual popups on hover
*/
interaction(type: "poptip", options?: PoptipOptions): Chart;
interface TreemapDrillDownOptions {
/** Maximum drill depth */
maxDepth?: number;
/** Animation duration */
duration?: number;
/** Breadcrumb navigation */
showBreadcrumb?: boolean;
/** Callback for navigation events */
onNavigate?: (path: string[]) => void;
}
interface ElementPointMoveOptions {
/** Constrain movement to chart area */
constrain?: boolean;
/** Update data on move */
updateData?: boolean;
/** Callback for position changes */
onMove?: (data: any, position: [number, number]) => void;
}Usage Examples:
// Treemap drill-down
chart
.treemap()
.data(hierarchicalData)
.encode("value", "size")
.encode("color", "category")
.interaction("treemapDrillDown", {
maxDepth: 3,
showBreadcrumb: true,
onNavigate: (path) => {
console.log("Navigation path:", path.join(" > "));
}
});
// Draggable scatter plot points
chart
.point()
.data(editableData)
.encode("x", "x")
.encode("y", "y")
.interaction("elementPointMove", {
updateData: true,
onMove: (data, position) => {
// Update data with new position
data.x = position[0];
data.y = position[1];
console.log("Point moved:", data);
}
});Custom event system for advanced interaction patterns.
/**
* Chart event handling
*/
interface ChartEvents {
/** Element click */
"element:click": (event: ElementEvent) => void;
/** Element hover */
"element:hover": (event: ElementEvent) => void;
/** Chart click */
"plot:click": (event: PlotEvent) => void;
/** Brush start */
"brush:start": (event: BrushEvent) => void;
/** Brush end */
"brush:end": (event: BrushEvent) => void;
/** Legend click */
"legend:click": (event: LegendEvent) => void;
}
interface ElementEvent {
type: string;
data: any;
element: any;
x: number;
y: number;
}
interface PlotEvent {
type: string;
x: number;
y: number;
data: any;
}Custom Event Examples:
// Custom event handling
chart
.point()
.data(data)
.encode("x", "x")
.encode("y", "y")
.on("element:click", (event) => {
console.log("Element clicked:", event.data);
// Custom click behavior
showDetailModal(event.data);
})
.on("plot:click", (event) => {
console.log("Chart clicked at:", event.x, event.y);
// Add new point at click location
addNewDataPoint(event.x, event.y);
});
// Brush event handling
chart
.point()
.data(data)
.encode("x", "x")
.encode("y", "y")
.interaction("brushHighlight")
.on("brush:end", (event) => {
const selectedData = getDataInBrush(event.selection);
updateLinkedVisualization(selectedData);
});Managing interaction state across multiple charts and components.
interface InteractionState {
/** Currently selected elements */
selected: any[];
/** Currently highlighted elements */
highlighted: any[];
/** Active brush selection */
brushSelection?: {
x: [number, number];
y: [number, number];
};
/** Legend filter state */
legendFilters: { [key: string]: boolean };
}
// State management methods
getInteractionState(): InteractionState;
setInteractionState(state: Partial<InteractionState>): Chart;
clearInteractionState(): Chart;State Management Examples:
// Synchronize state across multiple charts
const chart1 = new Chart({ container: "chart1" })
.point()
.data(data)
.interaction("elementSelect");
const chart2 = new Chart({ container: "chart2" })
.interval()
.data(aggregatedData)
.interaction("elementHighlight");
// Sync selection between charts
chart1.on("element:click", (event) => {
const selectedIds = chart1.getInteractionState().selected.map(d => d.id);
chart2.setInteractionState({
highlighted: aggregatedData.filter(d => selectedIds.includes(d.id))
});
});