CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dc

A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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;

docs

chart-registry.md

coordinate-grid-charts.md

core-utilities.md

data-display-widgets.md

filters.md

index.md

legends.md

mixins.md

ordinal-specialized-charts.md

tile.json