Skip to content

weytani/d3-lwc

Repository files navigation

Salesforce D3.js Chart Component Library

A complete suite of 20 Lightning Web Components (LWC) that wrap D3.js charts for use in Salesforce App Builder, Experience Builder, and Screen Flows. Components are drag-and-drop ready, capable of ingesting raw Salesforce record collections, and intelligently handle aggregation via server-side SOQL GROUP BY (preferred) or client-side JavaScript (fallback).

Screenshots

D3 LWC Charts in Salesforce

App Builder Configuration Panel

Features

  • 20 Chart Types: Bar, Line, Donut, Gauge, Scatter, Histogram, Treemap, Sankey, Force Graph, Choropleth, Area, Stacked Bar, Funnel, Radar, Heatmap, Box Plot, Waterfall, Bullet, Calendar Heatmap, Sparkline Grid
  • Drag-and-Drop Ready: Fully configurable in Lightning App Builder
  • Server-Side Aggregation: GROUP BY queries run in Apex, processing 50K+ records and sending pre-bucketed results to the browser
  • Dual Data Path: Server-preferred when objectApiName is configured; client-side fallback for recordCollection and soqlQuery-only usage
  • Server-Side Analytics: Statistics (mean, median, stdDev) and correlation (Pearson r, linear regression) computed in Apex
  • Configurable Limits: Per-chart recordLimit property in App Builder β€” set your own data ceiling or use smart defaults
  • Responsive: Uses ResizeObserver for adaptive reflow
  • SLDS Styled: Consistent with Salesforce Lightning Design System
  • Theme Support: 4 built-in palettes + custom colors via JSON config
  • 1,790 Tests: Comprehensive Jest test coverage across 31 suites

πŸ“¦ Components

Phase 1

Component Description Key Features
c-d3-gauge Single KPI gauge Zones, thresholds, color coding
c-d3-bar-chart Aggregated bar chart Vertical bars, drill-down, grid
c-d3-donut-chart Part-to-whole Animated slices, center total, legend
c-d3-line-chart Time series Multi-series, date parsing, curve types
c-d3-scatter-plot Correlation Trend line, Pearson coefficient, point sizing
c-d3-histogram Distribution Auto-binning, normal curve overlay, statistics
c-d3-treemap Hierarchical Nested rectangles, zoom/drill, breadcrumbs
c-d3-sankey Flow/process Nodes + links, gradient colors, flow values
c-d3-force-graph Network graph Force simulation, drag, zoom/pan, node sizing
c-d3-choropleth Geographic map US states, world, custom GeoJSON, color scales

Phase 2

Component Description Key Features
c-d3-area-chart Filled time series Stacked areas, gradients, multi-series
c-d3-stacked-bar-chart Multi-series bars Grouped or stacked, series comparison
c-d3-funnel-chart Conversion funnel Stage progression, drop-off rates
c-d3-radar-chart Multi-axis Polygon overlay, category comparison
c-d3-heatmap 2D categorical Color intensity grid, sequential ramps
c-d3-box-plot Distribution stats Quartiles, whiskers, outliers
c-d3-waterfall-chart Bridge/variance Running totals, positive/negative coloring
c-d3-bullet-chart KPI vs target Actual vs target, qualitative ranges
c-d3-calendar-heatmap Daily data grid Year view, day-level color intensity
c-d3-sparkline-grid Small multiples Inline mini-charts, entity comparison, monthly rollup

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        SALESFORCE ORG                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Static Resource β”‚    β”‚         Apex Controller          β”‚  β”‚
β”‚  β”‚   (D3.js v7)     β”‚    β”‚   D3ChartController.cls          β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚   - executeQuery(soql)           β”‚  β”‚
β”‚           β”‚              β”‚   - getAggregatedData(GROUP BY)  β”‚  β”‚
β”‚           β”‚              β”‚   - getStatistics(stats)         β”‚  β”‚
β”‚           β”‚              β”‚   - getCorrelation(Pearson r)    β”‚  β”‚
β”‚           β”‚              β”‚   - with sharing (security)      β”‚  β”‚
β”‚           β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚           β”‚                             β”‚                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                    SHARED LWC MODULES                     β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  β”‚
β”‚  β”‚  β”‚ dataService β”‚  β”‚themeService β”‚  β”‚  chartUtils     β”‚   β”‚  β”‚
β”‚  β”‚  β”‚ -aggregate  β”‚  β”‚ -palettes   β”‚  β”‚  -resize        β”‚   β”‚  β”‚
β”‚  β”‚  β”‚ -validate   β”‚  β”‚ -getColors  β”‚  β”‚  -tooltip       β”‚   β”‚  β”‚
β”‚  β”‚  β”‚ -truncate   β”‚  β”‚             β”‚  β”‚  -formatters    β”‚   β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                             β”‚                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                    CHART COMPONENTS                       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚  β”‚
β”‚  β”‚  β”‚ Gauge β”‚ β”‚ Bar β”‚ β”‚ Donut β”‚ β”‚ Line β”‚ β”‚ Scatter β”‚       β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β” β”‚  β”‚
β”‚  β”‚  β”‚ Histogram β”‚ β”‚ Treemap β”‚ β”‚ Sankey β”‚ β”‚ Force β”‚ β”‚ Map β”‚ β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”˜ β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ Area β”‚ β”‚ Stacked β”‚ β”‚ Funnel β”‚ β”‚ Radar β”‚ β”‚ Heatmap β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚  β”‚
β”‚  β”‚  β”‚ BoxPlot β”‚ β”‚ Waterfall β”‚ β”‚ Bullet β”‚ β”‚ Calendar β”‚       β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Quick Start

Prerequisites

  • Salesforce CLI (sf)
  • Node.js v20+ (v25 has compatibility issues with SF CLI)
  • A Salesforce org with "Enable Local Development" turned on

Installation

# Clone the repository
git clone https://github.com/weytani/d3-lwc.git
cd d3-lwc

# Install dependencies
npm install

# Deploy to your org
sf project deploy start --source-dir force-app -o <your-org-alias>

Running Tests

npm test

Local Development (Hot Reload)

# Use Node 20 for Salesforce CLI compatibility
export PATH="/opt/homebrew/opt/node@20/bin:$PATH"

# Start the Lightning Dev Server
sf lightning dev app -o <your-org-alias>

πŸ“Š Component Usage

Common Properties (All Charts)

Property Type Description
recordCollection Object[] Data from Flow or parent component
soqlQuery String SOQL query (used if recordCollection empty)
objectApiName String SObject API name β€” enables server-side aggregation
filterClause String Optional WHERE clause for server aggregation
recordLimit Integer Max records to process (1–10,000). Leave empty for smart defaults per chart type
height Integer Chart height in pixels
theme String Color theme (Salesforce Standard, Warm, Cool, Vibrant)
advancedConfig String JSON for advanced options

D3 Bar Chart (Server Aggregation)

<!-- Server-side: aggregates across all matching records via SOQL GROUP BY -->
<c-d3-bar-chart
  object-api-name="Opportunity"
  group-by-field="StageName"
  value-field="Amount"
  operation="Sum"
  filter-clause="IsClosed = false"
  height="300"
>
</c-d3-bar-chart>

D3 Bar Chart (Client-Side Fallback)

<!-- Client-side: uses recordCollection from Flow or parent component -->
<c-d3-bar-chart
  record-collection="{records}"
  group-by-field="StageName"
  value-field="Amount"
  operation="Sum"
  height="300"
>
</c-d3-bar-chart>

D3 Line Chart

<c-d3-line-chart
  soql-query="SELECT CloseDate, Amount FROM Opportunity"
  date-field="CloseDate"
  value-field="Amount"
  curve-type="monotone"
  show-points="true"
>
</c-d3-line-chart>

D3 Scatter Plot

<c-d3-scatter-plot
  record-collection="{records}"
  x-field="AnnualRevenue"
  y-field="NumberOfEmployees"
  show-trend-line="true"
>
</c-d3-scatter-plot>

D3 Choropleth (US States)

<c-d3-choropleth
  record-collection="{records}"
  region-field="BillingState"
  value-field="Amount"
  map-type="us-states"
>
</c-d3-choropleth>

Record Limits

Each chart has a default record limit tuned to its visual capacity. Set recordLimit in App Builder to override.

Chart Type Default Limit Why
Aggregation charts (Bar, Donut, Treemap, Funnel, Stacked Bar, Heatmap, Radar) 2,000 Client-side fallback path; server-side GROUP BY has no practical limit
Histogram 10,000 Raw values needed for binning math
Scatter 5,000 SVG sampling kicks in at 500 points
Box Plot 5,000 Raw values needed for quartile math
Sparkline Grid 5,000 Multiple small charts, raw values
Calendar Heatmap 2,000 Daily data points (~5.5 years)
Line, Area, Sankey 1,000 Visual comprehension ceiling
Force Graph 500 O(n log n) simulation cost
Waterfall, Choropleth 500 Sequential/geographic readability
Gauge, Bullet 1 Single value (no recordLimit exposed)

🎨 Themes

Four built-in color palettes:

Theme Colors
Salesforce Standard Brand blue, orange, green, red, purple, pink, cyan, lime
Warm Reds, oranges, yellows
Cool Blues, purples, cyans
Vibrant High-contrast mixed colors

Custom colors via advancedConfig:

{
  "customColors": ["#FF5733", "#33FF57", "#3357FF"]
}

πŸ› οΈ Shared Modules

dataService

import {
  validateData,
  prepareData,
  aggregateData,
  CHART_LIMITS,
  OPERATIONS
} from "c/dataService";

const { data, valid, error } = prepareData(records, {
  requiredFields: ["Amount"],
  limit: CHART_LIMITS.HISTOGRAM // or pass a custom limit
});
const chartData = aggregateData(records, "StageName", "Amount", OPERATIONS.SUM);

themeService

import { getColors, createColorScale, THEMES } from "c/themeService";

const colors = getColors("Warm", 5);
const colorScale = createColorScale("Salesforce Standard", categories);

chartUtils

import {
  formatNumber,
  formatCurrency,
  formatPercent,
  createTooltip
} from "c/chartUtils";

formatNumber(1500000); // "1.5M"
formatCurrency(50000); // "$50,000"

πŸ“ Project Structure

d3-lwc/
β”œβ”€β”€ force-app/main/default/
β”‚   β”œβ”€β”€ classes/
β”‚   β”‚   β”œβ”€β”€ D3ChartController.cls
β”‚   β”‚   └── D3ChartControllerTest.cls
β”‚   β”œβ”€β”€ lwc/
β”‚   β”‚   β”œβ”€β”€ d3Lib/              # D3.js loader
β”‚   β”‚   β”œβ”€β”€ dataService/        # Data processing, limits, aggregation
β”‚   β”‚   β”œβ”€β”€ themeService/       # Color palettes + sequential ramps
β”‚   β”‚   β”œβ”€β”€ chartUtils/         # Shared utilities (tooltips, resize, formatting)
β”‚   β”‚   β”œβ”€β”€ d3Gauge/            # Phase 1
β”‚   β”‚   β”œβ”€β”€ d3BarChart/
β”‚   β”‚   β”œβ”€β”€ d3DonutChart/
β”‚   β”‚   β”œβ”€β”€ d3LineChart/
β”‚   β”‚   β”œβ”€β”€ d3ScatterPlot/
β”‚   β”‚   β”œβ”€β”€ d3Histogram/
β”‚   β”‚   β”œβ”€β”€ d3Treemap/
β”‚   β”‚   β”œβ”€β”€ d3Sankey/
β”‚   β”‚   β”œβ”€β”€ d3ForceGraph/
β”‚   β”‚   β”œβ”€β”€ d3Choropleth/
β”‚   β”‚   β”œβ”€β”€ d3AreaChart/        # Phase 2
β”‚   β”‚   β”œβ”€β”€ d3StackedBarChart/
β”‚   β”‚   β”œβ”€β”€ d3FunnelChart/
β”‚   β”‚   β”œβ”€β”€ d3RadarChart/
β”‚   β”‚   β”œβ”€β”€ d3Heatmap/
β”‚   β”‚   β”œβ”€β”€ d3BoxPlot/
β”‚   β”‚   β”œβ”€β”€ d3WaterfallChart/
β”‚   β”‚   β”œβ”€β”€ d3BulletChart/
β”‚   β”‚   β”œβ”€β”€ d3CalendarHeatmap/
β”‚   β”‚   └── d3SparklineGrid/
β”‚   └── staticresources/
β”‚       β”œβ”€β”€ d3.js               # D3.js v7
β”‚       └── usStates.js         # US states GeoJSON
β”œβ”€β”€ jest.config.js
β”œβ”€β”€ package.json
β”œβ”€β”€ PROJECT-SPEC.md
β”œβ”€β”€ IMPLEMENTATION-BLUEPRINT.md
└── README.md

πŸ§ͺ Testing

# Run all tests
npm test

# Run specific component tests
npm test -- --testPathPattern=d3BarChart

# Run with coverage
npm test -- --coverage

Test Coverage: 1,790 tests across 31 suites (includes server-side aggregation path tests)

πŸ“š References

πŸ“„ License

MIT


Built with βš”οΈ by Excalibur

About

D3js.org charts wrapped in LWCs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors