D3.js Data Visualization Samples
Comprehensive D3.js data visualization examples including charts, maps, animations, and interactive visualizations
Key Facts
- Category
- Data Visualization
- Items
- 3
- Format Families
- json, image, svg
Sample Overview
Comprehensive D3.js data visualization examples including charts, maps, animations, and interactive visualizations This sample set belongs to Data Visualization and can be used to test related workflows inside Elysia Tools.
💻 D3.js Basic Charts javascript
🟢 simple
⭐⭐
Essential D3.js charts including bar charts, line charts, pie charts, and scatter plots with interactive features
⏱️ 25 min
🏷️ d3, charts, visualization
Prerequisites:
JavaScript, HTML, CSS, D3.js basics
// D3.js Basic Charts Examples
// 1. Bar Chart
// HTML: <div id="bar-chart"></div>
function createBarChart() {
const data = [
{ name: 'Product A', value: 30 },
{ name: 'Product B', value: 80 },
{ name: 'Product C', value: 45 },
{ name: 'Product D', value: 60 },
{ name: 'Product E', value: 20 },
{ name: 'Product F', value: 90 },
{ name: 'Product G', value: 55 }
];
// Set dimensions
const margin = { top: 20, right: 30, bottom: 40, left: 40 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
// Create SVG
const svg = d3.select('#bar-chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Set scales
const x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.nice()
.range([height, 0]);
// Create x-axis
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x))
.selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em')
.attr('transform', 'rotate(-45)');
// Create y-axis
svg.append('g')
.call(d3.axisLeft(y));
// Create bars
const bars = svg.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', d => x(d.name))
.attr('width', x.bandwidth())
.attr('y', d => y(d.value))
.attr('height', d => height - y(d.value))
.attr('fill', '#4e79a7')
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('fill', '#f28e2c');
// Show tooltip
const tooltip = d3.select('body').append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('background', 'rgba(0,0,0,0.8)')
.style('color', 'white')
.style('padding', '8px')
.style('border-radius', '4px')
.style('pointer-events', 'none')
.style('opacity', 0);
tooltip.transition()
.duration(200)
.style('opacity', 1);
tooltip.html(`${d.name}: ${d.value}`)
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 10) + 'px');
})
.on('mouseout', function(d) {
d3.select(this)
.transition()
.duration(200)
.attr('fill', '#4e79a7');
// Remove tooltip
d3.selectAll('.tooltip').remove();
})
.on('mousemove', function(event) {
d3.select('.tooltip')
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 10) + 'px');
});
// Add labels
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 0 - margin.left)
.attr('x', 0 - (height / 2))
.attr('dy', '1em')
.style('text-anchor', 'middle')
.text('Value');
svg.append('text')
.attr('transform', `translate(${width / 2}, ${height + margin.bottom})`)
.style('text-anchor', 'middle')
.text('Product');
}
// 2. Line Chart
// HTML: <div id="line-chart"></div>
function createLineChart() {
const data = [
{ date: new Date(2024, 0, 1), value: 30 },
{ date: new Date(2024, 1, 1), value: 45 },
{ date: new Date(2024, 2, 1), value: 35 },
{ date: new Date(2024, 3, 1), value: 50 },
{ date: new Date(2024, 4, 1), value: 65 },
{ date: new Date(2024, 5, 1), value: 55 },
{ date: new Date(2024, 6, 1), value: 70 },
{ date: new Date(2024, 7, 1), value: 85 },
{ date: new Date(2024, 8, 1), value: 75 },
{ date: new Date(2024, 9, 1), value: 90 },
{ date: new Date(2024, 10, 1), value: 80 },
{ date: new Date(2024, 11, 1), value: 95 }
];
// Set dimensions
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = 600 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
// Create SVG
const svg = d3.select('#line-chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Set scales
const x = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.nice()
.range([height, 0]);
// Create line generator
const line = d3.line()
.x(d => x(d.date))
.y(d => y(d.value))
.curve(d3.curveMonotoneX);
// Add grid lines
svg.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x)
.tickSize(-height)
.tickFormat('')
)
.style('stroke-dasharray', '3,3')
.style('opacity', 0.3);
svg.append('g')
.attr('class', 'grid')
.call(d3.axisLeft(y)
.tickSize(-width)
.tickFormat('')
)
.style('stroke-dasharray', '3,3')
.style('opacity', 0.3);
// Create axes
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
// Create line
svg.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', '#4e79a7')
.attr('stroke-width', 2)
.attr('d', line);
// Create area
const area = d3.area()
.x(d => x(d.date))
.y0(height)
.y1(d => y(d.value))
.curve(d3.curveMonotoneX);
svg.append('path')
.datum(data)
.attr('fill', '#4e79a7')
.attr('opacity', 0.1)
.attr('d', area);
// Add dots
svg.selectAll('.dot')
.data(data)
.enter().append('circle')
.attr('class', 'dot')
.attr('cx', d => x(d.date))
.attr('cy', d => y(d.value))
.attr('r', 4)
.attr('fill', '#4e79a7')
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', 6);
showTooltip(event, `Date: ${d.date.toLocaleDateString()}<br>Value: ${d.value}`);
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(200)
.attr('r', 4);
hideTooltip();
});
}
// 3. Pie Chart
// HTML: <div id="pie-chart"></div>
function createPieChart() {
const data = [
{ label: 'Category A', value: 30, color: '#4e79a7' },
{ label: 'Category B', value: 25, color: '#f28e2c' },
{ label: 'Category C', value: 20, color: '#e15759' },
{ label: 'Category D', value: 15, color: '#76b7b2' },
{ label: 'Category E', value: 10, color: '#59a14f' }
];
// Set dimensions
const width = 400;
const height = 400;
const radius = Math.min(width, height) / 2;
// Create SVG
const svg = d3.select('#pie-chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
// Create pie layout
const pie = d3.pie()
.value(d => d.value)
.sort(null);
// Create arc generator
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);
const arcHover = d3.arc()
.innerRadius(0)
.outerRadius(radius * 1.1);
// Create pie slices
const arcs = svg.selectAll('.arc')
.data(pie(data))
.enter().append('g')
.attr('class', 'arc');
arcs.append('path')
.attr('d', arc)
.attr('fill', d => d.data.color)
.attr('stroke', 'white')
.attr('stroke-width', 2)
.style('cursor', 'pointer')
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('d', arcHover);
showTooltip(event, `${d.data.label}: ${d.data.value} (${d3.format('.1%')(d.value / d3.sum(data, d => d.value))})`);
})
.on('mouseout', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('d', arc);
hideTooltip();
});
// Add labels
arcs.append('text')
.attr('transform', d => `translate(${arc.centroid(d)})`)
.attr('text-anchor', 'middle')
.style('fill', 'white')
.style('font-weight', 'bold')
.style('pointer-events', 'none')
.text(d => d.data.value);
}
// 4. Scatter Plot
// HTML: <div id="scatter-plot"></div>
function createScatterPlot() {
const data = Array.from({ length: 50 }, () => ({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 30 + 5,
category: ['A', 'B', 'C', 'D'][Math.floor(Math.random() * 4)]
}));
// Set dimensions
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
// Create SVG
const svg = d3.select('#scatter-plot')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Set scales
const x = d3.scaleLinear()
.domain([0, 100])
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, 100])
.range([height, 0]);
const size = d3.scaleLinear()
.domain([5, 35])
.range([3, 15]);
// Create axes
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
// Create color scale
const color = d3.scaleOrdinal()
.domain(['A', 'B', 'C', 'D'])
.range(['#4e79a7', '#f28e2c', '#e15759', '#76b7b2']);
// Create dots
svg.selectAll('.dot')
.data(data)
.enter().append('circle')
.attr('class', 'dot')
.attr('cx', d => x(d.x))
.attr('cy', d => y(d.y))
.attr('r', d => size(d.size))
.attr('fill', d => color(d.category))
.attr('opacity', 0.7)
.style('cursor', 'pointer')
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('opacity', 1)
.attr('r', d => size(d.size) * 1.2);
showTooltip(event, `X: ${d.x.toFixed(1)}<br>Y: ${d.y.toFixed(1)}<br>Size: ${d.size.toFixed(1)}<br>Category: ${d.category}`);
})
.on('mouseout', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('opacity', 0.7)
.attr('r', d => size(d.size));
hideTooltip();
});
// Add axis labels
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 0 - margin.left)
.attr('x', 0 - (height / 2))
.attr('dy', '1em')
.style('text-anchor', 'middle')
.text('Y Value');
svg.append('text')
.attr('transform', `translate(${width / 2}, ${height + margin.bottom})`)
.style('text-anchor', 'middle')
.text('X Value');
}
// Utility functions
function showTooltip(event, content) {
const tooltip = d3.select('body').append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('background', 'rgba(0,0,0,0.8)')
.style('color', 'white')
.style('padding', '8px')
.style('border-radius', '4px')
.style('pointer-events', 'none')
.style('font-size', '12px')
.style('opacity', 0);
tooltip.transition()
.duration(200)
.style('opacity', 1);
tooltip.html(content)
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 10) + 'px');
}
function hideTooltip() {
d3.selectAll('.tooltip').remove();
}
// Initialize all charts
document.addEventListener('DOMContentLoaded', function() {
createBarChart();
createLineChart();
createPieChart();
createScatterPlot();
});
💻 D3.js Interactive Dashboard javascript
🟡 intermediate
⭐⭐⭐⭐
Dynamic dashboard with multiple linked charts, real-time updates, and interactive filters
⏱️ 45 min
🏷️ d3, dashboard, interactive, real-time
Prerequisites:
Advanced JavaScript, D3.js, HTML/CSS, Data visualization concepts
// D3.js Interactive Dashboard
// Dashboard Configuration
const dashboardConfig = {
width: 1200,
height: 800,
margin: { top: 20, right: 20, bottom: 40, left: 50 },
colors: ['#4e79a7', '#f28e2c', '#e15759', '#76b7b2', '#59a14f', '#edc949', '#af7aa1', '#ff9da7']
};
// Sample data generator
class DataGenerator {
constructor() {
this.categories = ['Electronics', 'Clothing', 'Books', 'Home', 'Sports'];
this.regions = ['North', 'South', 'East', 'West'];
}
generateSalesData(months = 12) {
const data = [];
const now = new Date();
for (let i = 0; i < months; i++) {
const date = new Date(now.getFullYear(), now.getMonth() - (months - 1 - i), 1);
this.categories.forEach(category => {
data.push({
date: date,
category: category,
sales: Math.floor(Math.random() * 10000) + 1000,
profit: Math.floor(Math.random() * 2000) + 200,
region: this.regions[Math.floor(Math.random() * this.regions.length)]
});
});
}
return data;
}
generateRealTimeData() {
return {
timestamp: new Date(),
value: Math.floor(Math.random() * 100) + 20,
category: this.categories[Math.floor(Math.random() * this.categories.length)],
region: this.regions[Math.floor(Math.random() * this.regions.length)]
};
}
}
// Main Dashboard Class
class InteractiveDashboard {
constructor(containerId) {
this.container = d3.select(containerId);
this.dataGenerator = new DataGenerator();
this.data = this.dataGenerator.generateSalesData();
this.filteredData = this.data;
this.filters = {
category: 'all',
region: 'all',
dateRange: [d3.min(this.data, d => d.date), d3.max(this.data, d => d.date)]
};
this.init();
}
init() {
this.createLayout();
this.createFilters();
this.createKPIs();
this.createCharts();
this.setupEventListeners();
this.startRealTimeUpdates();
}
createLayout() {
// Create dashboard container
this.dashboard = this.container.append('div')
.attr('class', 'dashboard')
.style('font-family', 'Arial, sans-serif')
.style('padding', '20px');
// Create header
this.dashboard.append('h1')
.text('Interactive Sales Dashboard')
.style('text-align', 'center')
.style('margin-bottom', '20px');
// Create filter container
this.filterContainer = this.dashboard.append('div')
.attr('class', 'filters')
.style('margin-bottom', '20px');
// Create KPI container
this.kpiContainer = this.dashboard.append('div')
.attr('class', 'kpis')
.style('display', 'flex')
.style('justify-content', 'space-between')
.style('margin-bottom', '20px');
// Create charts container
this.chartsContainer = this.dashboard.append('div')
.attr('class', 'charts')
.style('display', 'grid')
.style('grid-template-columns', '1fr 1fr')
.style('gap', '20px');
}
createFilters() {
// Category filter
this.filterContainer.append('label')
.text('Category: ')
.style('margin-right', '10px');
const categorySelect = this.filterContainer.append('select')
.attr('id', 'category-filter')
.style('margin-right', '20px');
categorySelect.selectAll('option')
.data(['all', ...this.dataGenerator.categories])
.enter()
.append('option')
.attr('value', d => d)
.text(d => d.charAt(0).toUpperCase() + d.slice(1));
// Region filter
this.filterContainer.append('label')
.text('Region: ')
.style('margin-right', '10px');
const regionSelect = this.filterContainer.append('select')
.attr('id', 'region-filter');
regionSelect.selectAll('option')
.data(['all', ...this.dataGenerator.regions])
.enter()
.append('option')
.attr('value', d => d)
.text(d);
// Date range filter
this.filterContainer.append('label')
.text('Date Range: ')
.style('margin-right', '10px');
const startDateInput = this.filterContainer.append('input')
.attr('type', 'date')
.attr('id', 'start-date')
.style('margin-right', '10px');
const endDateInput = this.filterContainer.append('input')
.attr('type', 'date')
.attr('id', 'end-date');
// Set default date range
const minDate = d3.min(this.data, d => d.date);
const maxDate = d3.max(this.data, d => d.date);
startDateInput.property('value', minDate.toISOString().split('T')[0]);
endDateInput.property('value', maxDate.toISOString().split('T')[0]);
}
createKPIs() {
const kpis = [
{ id: 'total-sales', label: 'Total Sales', value: 0, format: d3.format(',.0f') },
{ id: 'total-profit', label: 'Total Profit', value: 0, format: d3.format(',.0f') },
{ id: 'avg-sale', label: 'Average Sale', value: 0, format: d3.format(',.0f') },
{ id: 'top-category', label: 'Top Category', value: '-', format: d => d }
];
kpis.forEach(kpi => {
const kpiCard = this.kpiContainer.append('div')
.attr('class', 'kpi-card')
.style('background', 'white')
.style('padding', '20px')
.style('border-radius', '8px')
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)')
.style('min-width', '200px');
kpiCard.append('h3')
.text(kpi.label)
.style('margin', '0 0 10px 0')
.style('color', '#666')
.style('font-size', '14px');
kpiCard.append('div')
.attr('id', kpi.id)
.style('font-size', '24px')
.style('font-weight', 'bold')
.style('color', '#333');
this[kpi.id] = kpiCard;
});
}
createCharts() {
this.createSalesTrendChart();
this.createCategoryDistribution();
this.createRegionalPerformance();
this.createRealTimeChart();
}
createSalesTrendChart() {
const chartContainer = this.chartsContainer.append('div')
.attr('class', 'chart')
.style('background', 'white')
.style('padding', '20px')
.style('border-radius', '8px')
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)');
chartContainer.append('h3')
.text('Sales Trend')
.style('margin', '0 0 20px 0');
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = 500 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
const svg = chartContainer.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Set scales
const x = d3.scaleTime()
.domain(d3.extent(this.filteredData, d => d.date))
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, d3.max(this.filteredData, d => d.sales)])
.nice()
.range([height, 0]);
// Create line generator
const line = d3.line()
.x(d => x(d.date))
.y(d => y(d.sales))
.curve(d3.curveMonotoneX);
// Create axes
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
// Create line
svg.append('path')
.datum(this.filteredData)
.attr('fill', 'none')
.attr('stroke', '#4e79a7')
.attr('stroke-width', 2)
.attr('d', line);
this.salesTrendChart = { svg, x, y, line };
}
createCategoryDistribution() {
const chartContainer = this.chartsContainer.append('div')
.attr('class', 'chart')
.style('background', 'white')
.style('padding', '20px')
.style('border-radius', '8px')
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)');
chartContainer.append('h3')
.text('Category Distribution')
.style('margin', '0 0 20px 0');
const width = 500;
const height = 300;
const radius = Math.min(width, height) / 2 - 20;
const svg = chartContainer.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
// Aggregate data by category
const categoryData = d3.rollup(
this.filteredData,
v => d3.sum(v, d => d.sales),
d => d.category
);
const pieData = Array.from(categoryData, ([key, value]) => ({ key, value }));
// Create pie layout
const pie = d3.pie()
.value(d => d.value);
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);
// Create pie slices
const arcs = svg.selectAll('.arc')
.data(pie(pieData))
.enter()
.append('g')
.attr('class', 'arc');
arcs.append('path')
.attr('d', arc)
.attr('fill', (d, i) => dashboardConfig.colors[i])
.attr('stroke', 'white')
.attr('stroke-width', 2);
this.categoryChart = { svg, pie, arc };
}
createRegionalPerformance() {
const chartContainer = this.chartsContainer.append('div')
.attr('class', 'chart')
.style('background', 'white')
.style('padding', '20px')
.style('border-radius', '8px')
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)')
.style('grid-column', '1 / -1');
chartContainer.append('h3')
.text('Regional Performance')
.style('margin', '0 0 20px 0');
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = 1000 - margin.left - margin.right;
const height = 250 - margin.top - margin.bottom;
const svg = chartContainer.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Aggregate data by region
const regionData = d3.rollup(
this.filteredData,
v => d3.sum(v, d => d.sales),
d => d.region
);
const barData = Array.from(regionData, ([key, value]) => ({ key, value }));
// Set scales
const x = d3.scaleBand()
.domain(barData.map(d => d.key))
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.nice()
.range([height, 0]);
// Create bars
svg.selectAll('.bar')
.data(barData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', d => x(d.key))
.attr('width', x.bandwidth())
.attr('y', d => y(d.value))
.attr('height', d => height - y(d.value))
.attr('fill', '#4e79a7');
// Create axes
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
this.regionalChart = { svg, x, y };
}
createRealTimeChart() {
const chartContainer = this.chartsContainer.append('div')
.attr('class', 'chart')
.style('background', 'white')
.style('padding', '20px')
.style('border-radius', '8px')
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)');
chartContainer.append('h3')
.text('Real-time Metrics')
.style('margin', '0 0 20px 0');
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = 500 - margin.left - margin.right;
const height = 200 - margin.top - margin.bottom;
const svg = chartContainer.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Real-time data
this.realTimeData = [];
// Set scales
const x = d3.scaleTime()
.domain([new Date(Date.now() - 60000), new Date()])
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, 100])
.range([height, 0]);
// Create axes
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
// Create line
const line = d3.line()
.x(d => x(d.timestamp))
.y(d => d.value)
.curve(d3.curveMonotoneX);
const path = svg.append('path')
.datum(this.realTimeData)
.attr('fill', 'none')
.attr('stroke', '#f28e2c')
.attr('stroke-width', 2)
.attr('d', line);
this.realTimeChart = { svg, x, y, line, path };
}
setupEventListeners() {
// Category filter
d3.select('#category-filter').on('change', (event) => {
this.filters.category = event.target.value;
this.updateDashboard();
});
// Region filter
d3.select('#region-filter').on('change', (event) => {
this.filters.region = event.target.value;
this.updateDashboard();
});
// Date range filter
d3.select('#start-date').on('change', (event) => {
this.filters.dateRange[0] = new Date(event.target.value);
this.updateDashboard();
});
d3.select('#end-date').on('change', (event) => {
this.filters.dateRange[1] = new Date(event.target.value);
this.updateDashboard();
});
}
updateDashboard() {
// Apply filters
this.filteredData = this.data.filter(d => {
const categoryMatch = this.filters.category === 'all' || d.category === this.filters.category;
const regionMatch = this.filters.region === 'all' || d.region === this.filters.region;
const dateMatch = d.date >= this.filters.dateRange[0] && d.date <= this.filters.dateRange[1];
return categoryMatch && regionMatch && dateMatch;
});
// Update KPIs
this.updateKPIs();
// Update charts
this.updateCharts();
}
updateKPIs() {
const totalSales = d3.sum(this.filteredData, d => d.sales);
const totalProfit = d3.sum(this.filteredData, d => d.profit);
const avgSale = d3.mean(this.filteredData, d => d.sales);
const topCategory = d3.rollup(
this.filteredData,
v => d3.sum(v, d => d.sales),
d => d.category
);
const topCategoryName = Array.from(topCategory.entries())
.sort((a, b) => b[1] - a[1])[0]?.[0] || '-';
// Update KPI displays
d3.select('#total-sales').text(d3.format(',')(totalSales));
d3.select('#total-profit').text(d3.format(',')(totalProfit));
d3.select('#avg-sale').text(d3.format(',')(Math.round(avgSale)));
d3.select('#top-category').text(topCategoryName);
}
updateCharts() {
// Update sales trend chart
if (this.salesTrendChart) {
const { svg, x, y, line } = this.salesTrendChart;
x.domain(d3.extent(this.filteredData, d => d.date));
y.domain([0, d3.max(this.filteredData, d => d.sales)]);
svg.select('.x-axis').remove();
svg.select('.y-axis').remove();
svg.append('g')
.attr('transform', `translate(0,${y.range()[0]})`)
.call(d3.axisBottom(x));
svg.append('g')
.call(d3.axisLeft(y));
svg.select('path')
.datum(this.filteredData)
.transition()
.duration(750)
.attr('d', line);
}
// Update category chart
if (this.categoryChart) {
const { svg, pie, arc } = this.categoryChart;
const categoryData = d3.rollup(
this.filteredData,
v => d3.sum(v, d => d.sales),
d => d.category
);
const pieData = Array.from(categoryData, ([key, value]) => ({ key, value }));
const arcs = svg.selectAll('.arc')
.data(pie(pieData));
arcs.select('path')
.transition()
.duration(750)
.attrTween('d', function(d) {
const interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
}
// Update regional chart
if (this.regionalChart) {
const { svg, x, y } = this.regionalChart;
const regionData = d3.rollup(
this.filteredData,
v => d3.sum(v, d => d.sales),
d => d.region
);
const barData = Array.from(regionData, ([key, value]) => ({ key, value }));
x.domain(barData.map(d => d.key));
y.domain([0, d3.max(barData, d => d.value)]);
const bars = svg.selectAll('.bar')
.data(barData);
bars.transition()
.duration(750)
.attr('y', d => y(d.value))
.attr('height', d => y(0) - y(d.value));
}
}
startRealTimeUpdates() {
setInterval(() => {
const newData = this.dataGenerator.generateRealTimeData();
// Add to real-time data array
this.realTimeData.push(newData);
// Keep only last 60 seconds of data
const oneMinuteAgo = new Date(Date.now() - 60000);
this.realTimeData = this.realTimeData.filter(d => d.timestamp > oneMinuteAgo);
// Update real-time chart
if (this.realTimeChart) {
const { x, y, line, path } = this.realTimeChart;
x.domain([new Date(Date.now() - 60000), new Date()]);
path.datum(this.realTimeData)
.transition()
.duration(200)
.attr('d', line);
}
}, 1000);
}
}
// Initialize dashboard
document.addEventListener('DOMContentLoaded', function() {
const dashboard = new InteractiveDashboard('#dashboard');
});
💻 D3.js Geographic Maps javascript
🔴 complex
⭐⭐⭐⭐
Interactive geographic visualizations including world maps, choropleth maps, and spatial data analysis
⏱️ 50 min
🏷️ d3, maps, geographic, spatial
Prerequisites:
Advanced D3.js, Geographic data concepts, TopoJSON, Projections
// D3.js Geographic Maps and Spatial Visualization
// 1. World Map with Data Points
function createWorldMap() {
const width = 960;
const height = 500;
// Create SVG
const svg = d3.select('#world-map')
.append('svg')
.attr('width', width)
.attr('height', height);
// Create projection
const projection = d3.geoNaturalEarth1()
.scale(width / (2 * Math.PI))
.translate([width / 2, height / 2]);
const path = d3.geoPath().projection(projection);
// Create zoom behavior
const zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', (event) => {
g.attr('transform', event.transform);
});
svg.call(zoom);
const g = svg.append('g');
// Sample data points
const cities = [
{ name: 'New York', lat: 40.7128, lon: -74.0060, population: 8419000, gdp: 1730000 },
{ name: 'London', lat: 51.5074, lon: -0.1278, population: 8982000, gdp: 615000 },
{ name: 'Tokyo', lat: 35.6762, lon: 139.6503, population: 13960000, gdp: 1520000 },
{ name: 'Paris', lat: 48.8566, lon: 2.3522, population: 2161000, gdp: 695000 },
{ name: 'Sydney', lat: -33.8688, lon: 151.2093, population: 5312000, gdp: 387000 },
{ name: 'São Paulo', lat: -23.5505, lon: -46.6333, population: 12330000, gdp: 430000 },
{ name: 'Mumbai', lat: 19.0760, lon: 72.8777, population: 20411000, gdp: 310000 },
{ name: 'Beijing', lat: 39.9042, lon: 116.4074, population: 21540000, gdp: 560000 }
];
// Load world map data
d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json').then(function(world) {
// Draw countries
g.selectAll('.country')
.data(topojson.feature(world, world.objects.countries).features)
.enter().append('path')
.attr('class', 'country')
.attr('d', path)
.attr('fill', '#e0e0e0')
.attr('stroke', '#999')
.attr('stroke-width', 0.5)
.on('mouseover', function(event, d) {
d3.select(this)
.attr('fill', '#c0c0c0');
showTooltip(event, `${d.properties.name}`);
})
.on('mouseout', function() {
d3.select(this)
.attr('fill', '#e0e0e0');
hideTooltip();
});
// Draw cities
const cityCircles = g.selectAll('.city')
.data(cities)
.enter().append('circle')
.attr('class', 'city')
.attr('cx', d => projection([d.lon, d.lat])[0])
.attr('cy', d => projection([d.lon, d.lat])[1])
.attr('r', d => Math.sqrt(d.population / 1000000) * 3)
.attr('fill', '#4e79a7')
.attr('opacity', 0.7)
.attr('stroke', '#fff')
.attr('stroke-width', 1)
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', d => Math.sqrt(d.population / 1000000) * 4)
.attr('opacity', 1);
showTooltip(event, `
<strong>${d.name}</strong><br>
Population: ${d3.format(',')(d.population)}<br>
GDP: $${d3.format(',.0f')(d.gdp)}M
`);
})
.on('mouseout', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', d => Math.sqrt(d.population / 1000000) * 3)
.attr('opacity', 0.7);
hideTooltip();
});
// Add city labels
g.selectAll('.city-label')
.data(cities)
.enter().append('text')
.attr('class', 'city-label')
.attr('x', d => projection([d.lon, d.lat])[0])
.attr('y', d => projection([d.lon, d.lat])[1] - 10)
.attr('text-anchor', 'middle')
.attr('font-size', '10px')
.attr('font-weight', 'bold')
.attr('fill', '#333')
.text(d => d.name);
});
}
// 2. Choropleth Map
function createChoroplethMap() {
const width = 800;
const height = 500;
// Create SVG
const svg = d3.select('#choropleth-map')
.append('svg')
.attr('width', width)
.attr('height', height);
// Create projection for US states
const projection = d3.geoAlbersUsa()
.scale(1000)
.translate([width / 2, height / 2]);
const path = d3.geoPath().projection(projection);
// Sample data for US states
const stateData = {
'California': 39500000,
'Texas': 29100000,
'Florida': 21500000,
'New York': 20200000,
'Pennsylvania': 12900000,
'Illinois': 12600000,
'Ohio': 11700000,
'Georgia': 10700000,
'North Carolina': 10600000,
'Michigan': 10000000
};
// Create color scale
const colorScale = d3.scaleThreshold()
.domain([10000000, 20000000, 30000000, 40000000])
.range(['#fee5d9', '#fcae91', '#fb6a4a', '#de2d26', '#a50f15']);
// Load US states data
d3.json('https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json').then(function(us) {
// Draw states
svg.selectAll('.state')
.data(topojson.feature(us, us.objects.states).features)
.enter().append('path')
.attr('class', 'state')
.attr('d', path)
.attr('fill', d => {
const population = stateData[d.properties.name] || 0;
return colorScale(population);
})
.attr('stroke', '#fff')
.attr('stroke-width', 1)
.on('mouseover', function(event, d) {
d3.select(this)
.attr('stroke', '#333')
.attr('stroke-width', 2);
const population = stateData[d.properties.name] || 0;
showTooltip(event, `
<strong>${d.properties.name}</strong><br>
Population: ${d3.format(',')(population)}
`);
})
.on('mouseout', function() {
d3.select(this)
.attr('stroke', '#fff')
.attr('stroke-width', 1);
hideTooltip();
});
// Create legend
const legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(650, 300)');
legend.append('text')
.attr('x', 0)
.attr('y', -10)
.text('Population')
.style('font-weight', 'bold');
const legendItems = legend.selectAll('.legend-item')
.data(colorScale.range())
.enter().append('g')
.attr('class', 'legend-item')
.attr('transform', (d, i) => `translate(0, ${i * 20})`);
legendItems.append('rect')
.attr('width', 18)
.attr('height', 18)
.attr('fill', d => d);
legendItems.append('text')
.attr('x', 24)
.attr('y', 9)
.attr('dy', '0.35em')
.text((d, i) => {
const thresholds = [10000000, 20000000, 30000000, 40000000];
return i === 0 ? `< ${d3.format(',')(thresholds[0])}` :
i === thresholds.length ? `> ${d3.format(',')(thresholds[thresholds.length - 1])}` :
`${d3.format(',')(thresholds[i-1])} - ${d3.format(',')(thresholds[i])}`;
});
});
}
// 3. Flight Routes Map
function createFlightRoutesMap() {
const width = 1000;
const height = 600;
// Create SVG
const svg = d3.select('#flight-routes-map')
.append('svg')
.attr('width', width)
.attr('height', height);
// Create projection
const projection = d3.geoNaturalEarth1()
.scale(width / (2 * Math.PI))
.translate([width / 2, height / 2]);
const path = d3.geoPath().projection(projection);
// Sample airport data
const airports = [
{ iata: 'JFK', name: 'New York JFK', lat: 40.6413, lon: -73.7781 },
{ iata: 'LAX', name: 'Los Angeles LAX', lat: 33.9425, lon: -118.4081 },
{ iata: 'ORD', name: 'Chicago O\'Hare', lat: 41.9742, lon: -87.9073 },
{ iata: 'DFW', name: 'Dallas DFW', lat: 32.8998, lon: -97.0403 },
{ iata: 'DEN', name: 'Denver DEN', lat: 39.8617, lon: -104.6731 },
{ iata: 'SFO', name: 'San Francisco SFO', lat: 37.6213, lon: -122.3790 },
{ iata: 'SEA', name: 'Seattle SEA', lat: 47.4502, lon: -122.3088 },
{ iata: 'LAS', name: 'Las Vegas LAS', lat: 36.0840, lon: -115.1537 },
{ iata: 'PHX', name: 'Phoenix PHX', lat: 33.4484, lon: -112.0740 },
{ iata: 'IAH', name: 'Houston IAH', lat: 29.9902, lon: -95.3368 }
];
// Sample flight routes
const routes = [
{ from: 'JFK', to: 'LAX', passengers: 45000 },
{ from: 'JFK', to: 'SFO', passengers: 28000 },
{ from: 'LAX', to: 'ORD', passengers: 32000 },
{ from: 'ORD', to: 'DFW', passengers: 35000 },
{ from: 'DFW', to: 'IAH', passengers: 41000 },
{ from: 'SFO', to: 'SEA', passengers: 22000 },
{ from: 'DEN', to: 'LAS', passengers: 18000 },
{ from: 'PHX', to: 'LAX', passengers: 25000 },
{ from: 'SEA', to: 'SFO', passengers: 26000 },
{ from: 'LAS', to: 'PHX', passengers: 20000 }
];
// Load world map
d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json').then(function(world) {
// Draw countries
svg.append('g')
.selectAll('.country')
.data(topojson.feature(world, world.objects.countries).features)
.enter().append('path')
.attr('class', 'country')
.attr('d', path)
.attr('fill', '#f0f0f0')
.attr('stroke', '#ddd')
.attr('stroke-width', 0.5);
// Create route lines
const routeLines = svg.append('g')
.selectAll('.route')
.data(routes)
.enter().append('path')
.attr('class', 'route')
.attr('d', d => {
const from = airports.find(a => a.iata === d.from);
const to = airports.find(a => a.iata === d.to);
const fromPoint = projection([from.lon, from.lat]);
const toPoint = projection([to.lon, to.lat]);
// Create curved path
const midX = (fromPoint[0] + toPoint[0]) / 2;
const midY = (fromPoint[1] + toPoint[1]) / 2 - 100;
return `M ${fromPoint[0]},${fromPoint[1]} Q ${midX},${midY} ${toPoint[0]},${toPoint[1]}`;
})
.attr('fill', 'none')
.attr('stroke', '#4e79a7')
.attr('stroke-width', d => Math.sqrt(d.passengers / 10000))
.attr('opacity', 0.3)
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('opacity', 0.8)
.attr('stroke', '#f28e2c');
const from = airports.find(a => a.iata === d.from);
const to = airports.find(a => a.iata === d.to);
showTooltip(event, `
${from.name} → ${to.name}<br>
Passengers: ${d3.format(',')(d.passengers)}
`);
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(200)
.attr('opacity', 0.3)
.attr('stroke', '#4e79a7');
hideTooltip();
});
// Draw airports
svg.selectAll('.airport')
.data(airports)
.enter().append('circle')
.attr('class', 'airport')
.attr('cx', d => projection([d.lon, d.lat])[0])
.attr('cy', d => projection([d.lon, d.lat])[1])
.attr('r', 4)
.attr('fill', '#e15759')
.attr('stroke', '#fff')
.attr('stroke-width', 2)
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', 6);
showTooltip(event, `
<strong>${d.iata}</strong><br>
${d.name}<br>
Lat: ${d.lat.toFixed(2)}<br>
Lon: ${d.lon.toFixed(2)}
`);
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(200)
.attr('r', 4);
hideTooltip();
});
// Add airport labels
svg.selectAll('.airport-label')
.data(airports)
.enter().append('text')
.attr('class', 'airport-label')
.attr('x', d => projection([d.lon, d.lat])[0])
.attr('y', d => projection([d.lon, d.lat])[1] + 15)
.attr('text-anchor', 'middle')
.attr('font-size', '10px')
.attr('font-weight', 'bold')
.attr('fill', '#333')
.text(d => d.iata);
});
}
// 4. Interactive Heatmap
function createHeatmap() {
const data = [];
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
const hours = Array.from({ length: 24 }, (_, i) => i);
// Generate sample heatmap data
for (let day = 0; day < days.length; day++) {
for (let hour = 0; hour < 24; hour++) {
data.push({
day: days[day],
hour: hour,
value: Math.random() * 100,
dayIndex: day,
hourIndex: hour
});
}
}
const margin = { top: 50, right: 30, bottom: 30, left: 50 };
const width = 800 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
const cellSize = Math.floor(width / 24);
// Create SVG
const svg = d3.select('#heatmap')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Create color scale
const colorScale = d3.scaleSequential(d3.interpolateYlOrRd)
.domain([0, 100]);
// Create cells
svg.selectAll('.cell')
.data(data)
.enter().append('rect')
.attr('class', 'cell')
.attr('x', d => d.hour * cellSize)
.attr('y', d => d.day * cellSize)
.attr('width', cellSize)
.attr('height', cellSize)
.attr('fill', d => colorScale(d.value))
.attr('stroke', '#fff')
.attr('stroke-width', 1)
.on('mouseover', function(event, d) {
d3.select(this)
.attr('stroke', '#333')
.attr('stroke-width', 2);
showTooltip(event, `
<strong>${days[d.dayIndex]} ${String(d.hour).padStart(2, '0')}:00</strong><br>
Activity: ${d.value.toFixed(1)}%
`);
})
.on('mouseout', function() {
d3.select(this)
.attr('stroke', '#fff')
.attr('stroke-width', 1);
hideTooltip();
});
// Add day labels
svg.selectAll('.day-label')
.data(days)
.enter().append('text')
.attr('class', 'day-label')
.attr('x', -10)
.attr('y', (d, i) => i * cellSize + cellSize / 2)
.attr('dy', '0.35em')
.attr('text-anchor', 'end')
.style('font-size', '12px')
.text(d => d);
// Add hour labels
svg.selectAll('.hour-label')
.data(hours)
.enter().append('text')
.attr('class', 'hour-label')
.attr('x', (d, i) => i * cellSize + cellSize / 2)
.attr('y', height + 20)
.attr('text-anchor', 'middle')
.style('font-size', '12px')
.text(d => d);
// Add title
svg.append('text')
.attr('x', width / 2)
.attr('y', -20)
.attr('text-anchor', 'middle')
.style('font-size', '16px')
.style('font-weight', 'bold')
.text('Weekly Activity Heatmap');
}
// Utility functions
function showTooltip(event, content) {
const tooltip = d3.select('body').append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('background', 'rgba(0,0,0,0.8)')
.style('color', 'white')
.style('padding', '10px')
.style('border-radius', '4px')
.style('pointer-events', 'none')
.style('font-size', '12px')
.style('max-width', '200px')
.style('opacity', 0);
tooltip.transition()
.duration(200)
.style('opacity', 1);
tooltip.html(content)
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 10) + 'px');
}
function hideTooltip() {
d3.selectAll('.tooltip').remove();
}
// Initialize all maps
document.addEventListener('DOMContentLoaded', function() {
createWorldMap();
createChoroplethMap();
createFlightRoutesMap();
createHeatmap();
});