or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

content-formatting.mdevent-handling.mdindex.mdlabel-positioning.mdlabel-styling.mdmulti-label.mdplugin-integration.md
tile.json

label-positioning.mddocs/

Label Positioning

Advanced positioning system for precise label placement including anchor points, alignment options, offset distances, rotation, and clipping behaviors.

Capabilities

Anchor and Alignment

Control where labels are positioned relative to their associated data elements.

interface PositionOptions {
  /** Anchor point on the data element
   * @default 'center' */
  anchor?: Indexable<Anchor> | Scriptable<Anchor>;
  
  /** Alignment relative to the anchor point
   * @default 'center' */
  align?: Indexable<Align> | Scriptable<Align>;
  
  /** Distance in pixels from the anchor point
   * @default 4 */
  offset?: Indexable<number> | Scriptable<number>;
}

type Anchor = 'center' | 'end' | 'start';
type Align = 'bottom' | 'center' | 'end' | 'left' | 'right' | 'start' | 'top' | number;

Anchor Options:

  • 'center': Center of the data element (default)
  • 'start': Beginning edge of the element
  • 'end': Ending edge of the element

Align Options:

  • Directional: 'top', 'bottom', 'left', 'right'
  • Relative: 'start', 'center', 'end'
  • Angle: Any number representing degrees (0° = right, 90° = bottom, 180° = left, 270° = top)

Usage Examples:

// Labels inside bars at the top
datalabels: {
  anchor: 'end',
  align: 'start'
}

// Labels outside bars
datalabels: {
  anchor: 'end',
  align: 'end',
  offset: 10
}

// Labels at custom angles
datalabels: {
  align: 45, // 45-degree angle
  offset: 15
}

// Dynamic positioning based on value
datalabels: {
  anchor: function(context) {
    const value = context.parsed.y;
    return value < 0 ? 'end' : 'start';
  },
  align: function(context) {
    const value = context.parsed.y;
    return value < 0 ? 'bottom' : 'top';
  }
}

Rotation and Transformation

Rotate labels for better fit and visual appeal.

interface RotationOptions {
  /** Clockwise rotation in degrees
   * @default 0 */
  rotation?: Indexable<number> | Scriptable<number>;
}

Usage Examples:

// Rotate labels 45 degrees
datalabels: {
  rotation: 45
}

// Vertical text
datalabels: {
  rotation: 90
}

// Dynamic rotation based on data
datalabels: {
  rotation: function(context) {
    return context.dataIndex * 30; // Different rotation per data point
  }
}

// Rotate based on chart type
datalabels: {
  rotation: function(context) {
    return context.chart.config.type === 'polarArea' ? 
      context.dataIndex * (360 / context.dataset.data.length) : 0;
  }
}

Clamping and Clipping

Control how labels behave at chart boundaries.

interface ClampingOptions {
  /** Calculate position based on visible element geometry only
   * @default false */
  clamp?: Indexable<boolean> | Scriptable<boolean>;
  
  /** Clip labels to the chart area
   * @default false */
  clip?: Indexable<boolean> | Scriptable<boolean>;
}

Usage Examples:

// Clamp to visible area (useful for partially visible elements)
datalabels: {
  clamp: true,
  anchor: 'end',
  align: 'end'
}

// Clip labels that would extend outside chart
datalabels: {
  clip: true
}

// Conditional clipping
datalabels: {
  clip: function(context) {
    // Only clip for small charts
    return context.chart.width < 400;
  }
}

Chart Type Specific Positioning

Different positioning strategies work better with different chart types.

Bar Charts:

// Inside bars
datalabels: {
  anchor: 'center',
  align: 'center'
}

// On top of bars
datalabels: {
  anchor: 'end',  
  align: 'top',
  offset: 4
}

Line Charts:

// Above data points
datalabels: {
  anchor: 'center',
  align: 'top',
  offset: 8
}

// Rotated labels for dense data
datalabels: {
  anchor: 'center',
  align: 'end',
  rotation: -45,
  offset: 10
}

Pie/Doughnut Charts:

// Inside slices
datalabels: {
  anchor: 'center',
  align: 'center'
}

// Outside slices with lines (requires custom formatter)
datalabels: {
  anchor: 'end',
  align: 'end',
  offset: 20
}

// Radial positioning
datalabels: {
  anchor: 'end',
  align: function(context) {
    // Position based on slice angle
    const angle = (context.parsed / context.dataset.data.reduce((a, b) => a + b)) * 360;
    return angle;
  }
}

Polar Area Charts:

// Radial labels
datalabels: {
  anchor: 'end',
  align: function(context) {
    const dataIndex = context.dataIndex;
    const dataLength = context.dataset.data.length;
    return (dataIndex / dataLength) * 360;
  },
  offset: 15
}

Advanced Positioning Patterns

Complex positioning scenarios using combinations of options.

Stacked Bar Labels:

// Show percentage inside, absolute value outside
datalabels: {
  labels: {
    percentage: {
      anchor: 'center',
      align: 'center',
      formatter: (value, context) => {
        const sum = context.dataset.data.reduce((a, b) => a + b);
        return Math.round((value / sum) * 100) + '%';
      }
    },
    value: {
      anchor: 'end',
      align: 'end',
      offset: 5,
      formatter: (value) => value
    }
  }
}

Responsive Positioning:

// Adjust positioning based on chart size
datalabels: {
  anchor: function(context) {
    return context.chart.width < 500 ? 'center' : 'end';
  },
  align: function(context) {
    return context.chart.width < 500 ? 'center' : 'top';
  },
  offset: function(context) {
    return context.chart.width < 500 ? 0 : 8;
  }
}