D3.js Datenvisualisierung Beispiele

Umfassende D3.js datenvisualisierung beispiele einschließlich diagramme, karten, animationen und interaktive visualisierungen

💻 D3.js Basis-Diagramme javascript

🟢 simple ⭐⭐

Wesentliche D3.js-diagramme einschließlich balken-, linien-, torten- und streudiagramme mit interaktiven 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 Interaktives Dashboard javascript

🟡 intermediate ⭐⭐⭐⭐

Dynamisches dashboard mit mehreren verknüpften diagrammen, echtzeit-aktualisierungen und interaktiven filtern

⏱️ 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 Geografische Karten javascript

🔴 complex ⭐⭐⭐⭐

Interaktive geografische visualisierungen inklusive weltkarten, choropleth-karten und räumliche datenanalyse

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