A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Legend components for displaying chart keys and visual guides that help users understand chart data mappings and categories.
SVG-based legend component that displays color-coded keys for chart data series or categories.
/**
* Create an SVG-based Legend
* @param {String|node|d3.selection} parent - DOM selector, element, or d3 selection
* @param {String} [chartGroup] - Chart group name for coordinated interactions
*/
class Legend extends BaseMixin {
constructor(parent: string | Element | d3.Selection, chartGroup?: string);
/** Set/get legend items */
legendItems(items?: LegendItem[]): LegendItem[] | Legend;
/** Set/get legend width */
legendWidth(width?: number): number | Legend;
/** Set/get legend item height */
itemHeight(height?: number): number | Legend;
/** Set/get gap between legend items */
gap(gap?: number): number | Legend;
/** Set/get horizontal gap between legend items */
horizontal(horizontal?: boolean): boolean | Legend;
/** Set/get legend text accessor */
legendText(textFunction?: Function): Function | Legend;
/** Set/get maximum items per row */
maxItems(maxItems?: number): number | Legend;
/** Set/get whether legend is autoItemWidth */
autoItemWidth(auto?: boolean): boolean | Legend;
}
/** Factory function for creating Legend instances */
function legend(parent: string | Element | d3.Selection, chartGroup?: string): Legend;Usage Example:
import { Legend } from 'dc';
const chartLegend = new Legend('#legend')
.legendWidth(200)
.itemHeight(20)
.gap(5)
.horizontal(false)
.legendText(d => d.name)
.legendItems([
{ name: 'Series 1', color: '#1f77b4' },
{ name: 'Series 2', color: '#ff7f0e' },
{ name: 'Series 3', color: '#2ca02c' }
]);
chartLegend.render();HTML-based legend component with more flexible styling and interaction capabilities.
/**
* Create an HTML-based Legend
* @param {String|node|d3.selection} parent - DOM selector, element, or d3 selection
* @param {String} [chartGroup] - Chart group name for coordinated interactions
*/
class HtmlLegend extends BaseMixin {
constructor(parent: string | Element | d3.Selection, chartGroup?: string);
/** Set/get legend container element */
container(container?: string | Element | d3.Selection): any | HtmlLegend;
/** Set/get maximum items displayed */
maxItems(maxItems?: number): number | HtmlLegend;
/** Set/get legend item class */
legendItemClass(className?: string): string | HtmlLegend;
/** Set/get highlighted class */
highlightedClass(className?: string): string | HtmlLegend;
/** Set/get hidden class */
hiddenClass(className?: string): string | HtmlLegend;
/** Set/get legend text function */
legendText(textFunction?: Function): Function | HtmlLegend;
/** Set/get whether items are highlightable */
highlightable(highlightable?: boolean): boolean | HtmlLegend;
/** Set/get whether items are hidable */
hidable(hidable?: boolean): boolean | HtmlLegend;
/** Set/get reset button text */
resetText(text?: string): string | HtmlLegend;
/** Set/get legend items */
legendItems(items?: LegendItem[]): LegendItem[] | HtmlLegend;
}
/** Factory function for creating HtmlLegend instances */
function htmlLegend(parent: string | Element | d3.Selection, chartGroup?: string): HtmlLegend;Usage Example:
import { HtmlLegend } from 'dc';
const htmlLegend = new HtmlLegend('#html-legend')
.container('#legend-container')
.maxItems(10)
.legendItemClass('legend-item')
.highlightedClass('highlighted')
.hiddenClass('hidden')
.highlightable(true)
.hidable(true)
.resetText('Reset filters')
.legendText(d => `${d.name} (${d.value})`)
.legendItems([
{ name: 'Category A', value: 150, color: '#FF6B6B' },
{ name: 'Category B', value: 230, color: '#4ECDC4' },
{ name: 'Category C', value: 180, color: '#45B7D1' }
]);
htmlLegend.render();Legends can automatically generate items based on chart data:
import { PieChart, HtmlLegend } from 'dc';
const pie = new PieChart('#pie-chart')
.dimension(categoryDimension)
.group(categoryGroup);
const legend = new HtmlLegend('#legend')
.legendItems(() => {
// Generate legend items from pie chart data
return pie.data().map(d => ({
name: d.key,
value: d.value,
color: pie.getColor(d, 0)
}));
})
.legendText(d => `${d.name}: ${d.value}`);
// Render both chart and legend
pie.render();
legend.render();HTML legends support interactive filtering:
import { BarChart, HtmlLegend } from 'dc';
const chart = new BarChart('#chart')
.dimension(categoryDimension)
.group(categoryGroup);
const legend = new HtmlLegend('#legend')
.dimension(categoryDimension) // Connect to same dimension
.group(categoryGroup)
.highlightable(true)
.hidable(true)
.on('filtered', function(legend, filter) {
// Legend filtering affects connected chart
chart.redraw();
});
chart.render();
legend.render();HTML legends provide flexible styling options:
/* Custom legend styles */
.legend-item {
display: flex;
align-items: center;
padding: 5px;
cursor: pointer;
border-radius: 3px;
margin: 2px 0;
}
.legend-item:hover {
background-color: #f0f0f0;
}
.legend-item.highlighted {
background-color: #e3f2fd;
font-weight: bold;
}
.legend-item.hidden {
opacity: 0.3;
text-decoration: line-through;
}
.legend-item::before {
content: '';
width: 12px;
height: 12px;
margin-right: 8px;
border-radius: 50%;
background-color: var(--item-color);
}const legend = new HtmlLegend('#legend')
.legendItemClass('legend-item')
.highlightedClass('highlighted')
.hiddenClass('hidden')
.legendText(d => {
// Set CSS custom property for color
return `<span style="--item-color: ${d.color}">${d.name}</span>`;
});Coordinate legends across multiple charts:
import { BarChart, LineChart, HtmlLegend } from 'dc';
const barChart = new BarChart('#bar-chart', 'main')
.dimension(categoryDimension)
.group(categoryGroup);
const lineChart = new LineChart('#line-chart', 'main')
.dimension(timeDimension)
.group(timeGroup);
// Single legend coordinating both charts
const legend = new HtmlLegend('#shared-legend', 'main')
.legendItems([
{ name: 'Bar Chart', color: barChart.colors()(0) },
{ name: 'Line Chart', color: lineChart.colors()(0) }
])
.on('filtered', function(legend, filter) {
// Custom logic to coordinate multiple charts
});Standard structure for legend items:
interface LegendItem {
/** Display name for the legend item */
name: string;
/** Color associated with the item */
color: string;
/** Optional numeric value */
value?: number;
/** Optional additional data */
data?: any;
/** Whether item is visible */
visible?: boolean;
/** Whether item is highlighted */
highlighted?: boolean;
}Update legend items based on data changes:
import { HtmlLegend } from 'dc';
const legend = new HtmlLegend('#legend');
function updateLegend(newData) {
const items = newData.map((d, i) => ({
name: d.category,
value: d.total,
color: d3.schemeCategory10[i % 10],
data: d
}));
legend.legendItems(items).redraw();
}
// Update legend when data changes
chart.on('filtered', function() {
const filteredData = chart.group().all();
updateLegend(filteredData);
});SVG Legend (Legend class):
HTML Legend (HtmlLegend class):
// Limit legend items for performance
const legend = new HtmlLegend('#legend')
.maxItems(20) // Cap at 20 items
.legendItems(data.slice(0, 20)); // Pre-filter data
// Use efficient update patterns
legend.on('preRender', function() {
// Batch DOM operations
});
legend.on('postRender', function() {
// Apply final styling after rendering
});Make legends accessible to screen readers:
const legend = new HtmlLegend('#legend')
.legendText(d => `${d.name}, value: ${d.value}`)
.on('postRender', function() {
// Add ARIA labels
d3.select('#legend').selectAll('.legend-item')
.attr('role', 'button')
.attr('aria-label', d => `Filter by ${d.name}`)
.attr('tabindex', 0);
});Enable keyboard navigation for interactive legends:
legend.on('postRender', function() {
d3.select('#legend').selectAll('.legend-item')
.on('keydown', function(event, d) {
if (event.key === 'Enter' || event.key === ' ') {
// Trigger click behavior
d3.select(this).dispatch('click');
event.preventDefault();
}
});
});interface LegendItem {
name: string;
color: string;
value?: number;
data?: any;
visible?: boolean;
highlighted?: boolean;
}
interface Legend extends BaseMixin {
legendItems(items?: LegendItem[]): LegendItem[] | Legend;
legendWidth(width?: number): number | Legend;
itemHeight(height?: number): number | Legend;
gap(gap?: number): number | Legend;
horizontal(horizontal?: boolean): boolean | Legend;
legendText(textFunction?: Function): Function | Legend;
maxItems(maxItems?: number): number | Legend;
autoItemWidth(auto?: boolean): boolean | Legend;
}
interface HtmlLegend extends BaseMixin {
container(container?: string | Element | d3.Selection): any | HtmlLegend;
maxItems(maxItems?: number): number | HtmlLegend;
legendItemClass(className?: string): string | HtmlLegend;
highlightedClass(className?: string): string | HtmlLegend;
hiddenClass(className?: string): string | HtmlLegend;
legendText(textFunction?: Function): Function | HtmlLegend;
highlightable(highlightable?: boolean): boolean | HtmlLegend;
hidable(hidable?: boolean): boolean | HtmlLegend;
resetText(text?: string): string | HtmlLegend;
legendItems(items?: LegendItem[]): LegendItem[] | HtmlLegend;
}
type LegendFactory = (parent: string | Element | d3.Selection, chartGroup?: string) => Legend;
type HtmlLegendFactory = (parent: string | Element | d3.Selection, chartGroup?: string) => HtmlLegend;