or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

chart-registry.mdcoordinate-grid-charts.mdcore-utilities.mddata-display-widgets.mdfilters.mdindex.mdlegends.mdmixins.mdordinal-specialized-charts.md
tile.json

legends.mddocs/

Legends and Visual Components

Legend components for displaying chart keys and visual guides that help users understand chart data mappings and categories.

Capabilities

Legend

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();

HtmlLegend

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();

Legend Integration Patterns

Automatic Legend Generation

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();

Interactive Legend Behavior

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();

Custom Legend Styling

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>`;
  });

Multi-Chart Legend Coordination

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
  });

Legend Data Structures

LegendItem Interface

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;
}

Dynamic Legend Updates

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);
});

Performance Considerations

SVG vs HTML Legends

SVG Legend (Legend class):

  • Better for simple, static legends
  • Integrates well with SVG-based charts
  • Less flexible styling
  • Good performance with many items

HTML Legend (HtmlLegend class):

  • More flexible styling and layout
  • Better for interactive legends
  • Easier to implement complex interactions
  • May have performance overhead with many items

Legend Optimization

// 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
});

Accessibility

Screen Reader Support

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);
  });

Keyboard Navigation

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();
      }
    });
});

Types

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;