Body Heatmap

An interactive Flutter widget that displays a human body diagram with customizable heatmap visualization. Perfect for fitness apps, health tracking applications, pain tracking tools, or any app that needs body part selection and intensity visualization.

Features

  • 🎯 Interactive Body Diagram - Front and back view of human body with clickable regions
  • 🌑️ Heatmap Visualization - Display intensity levels with customizable colors and opacity
  • πŸ‘† Touch & Hover Support - Responsive interactions with visual feedback
  • 🎨 Fully Customizable - Colors, intensity levels, legend display, and more
  • πŸ“± Responsive Design - Scales to any screen size while maintaining proportions
  • πŸ” Detailed Body Parts - 60+ distinct body regions including head, neck, shoulders, arms, chest, abs, legs, and feet, knees

Use Cases

  • Fitness Apps - Track muscle soreness or workout intensity by body part
  • Health Apps - Monitor pain levels or symptoms across different body regions
  • Physical Therapy - Document patient progress and problem areas
  • Medical Apps - Record injury locations or treatment areas
  • Wellness Apps - Track massage therapy sessions or acupuncture points

Getting Started

Add this to your package's pubspec.yaml file:

dependencies:
  bodyheatmap: ^1.0.0

Then run:

flutter pub get

Usage

Basic Example

import 'package:flutter/material.dart';
import 'package:bodyheatmap/bodyheatmap.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Body Heatmap Example')),
        body: Center(
          child: BodyHeatmap(
            selectedParts: const {
              'front-head': 3,
              'front-chest-left': 2,
              'front-chest-right': 2,
              'front-arm-left': 1,
            },
            baseColor: Colors.red,
            width: 300,
            showLegend: true,
            onPartTap: (part) {
              print('Tapped: $part');
            },
          ),
        ),
      ),
    );
  }
}

Interactive Example with State Management

class InteractiveBodyHeatmap extends StatefulWidget {
  @override
  _InteractiveBodyHeatmapState createState() => _InteractiveBodyHeatmapState();
}

class _InteractiveBodyHeatmapState extends State<InteractiveBodyHeatmap> {
  Map<String, int> selectedParts = {};

  void _handlePartTap(String part) {
    setState(() {
      if (selectedParts.containsKey(part)) {
        // Cycle through intensity levels: 1 -> 2 -> 3 -> remove
        if (selectedParts[part]! >= 3) {
          selectedParts.remove(part);
        } else {
          selectedParts[part] = selectedParts[part]! + 1;
        }
      } else {
        selectedParts[part] = 1;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Pain Tracker')),
      body: Column(
        children: [
          Expanded(
            child: Center(
              child: BodyHeatmap(
                selectedParts: selectedParts,
                baseColor: Colors.orange,
                unselectedColor: Colors.grey[300]!,
                width: 300,
                showLegend: true,
                intensityLevels: 3,
                legendTextStyle: TextStyle(fontSize: 12),
                onPartTap: _handlePartTap,
              ),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(16),
            child: Text(
              'Tap body parts to track pain levels (1-3)',
              style: TextStyle(fontSize: 16),
            ),
          ),
        ],
      ),
    );
  }
}

Parameters

Parameter Type Default Description
selectedParts Map<String, int> required Map of body part IDs to intensity values (1-10)
baseColor Color required Base color for the heatmap visualization
unselectedColor Color Color(0xFFCCCCCC) Color for unselected body parts
width double 300 Width of the widget (height scales proportionally)
showLegend bool false Whether to display the intensity legend
legendTextStyle TextStyle TextStyle(fontSize: 14) Style for legend text
legendAlignment MainAxisAlignment MainAxisAlignment.center Alignment of the legend
intensityLevels int 3 Number of intensity levels (affects opacity steps)
onPartTap Function(String)? null Callback when a body part is tapped

Available Body Parts

The widget recognizes 60+ body part identifiers:

Front View:

  • front-head, front-neck-left, front-neck-right
  • front-shoulder-left, front-shoulder-right
  • front-chest-left, front-chest-right
  • front-arm-left, front-arm-right
  • front-palm-left, front-palm-right
  • front-abs, front-hip-left, front-hip-right
  • front-leg-left, front-leg-right
  • front-knee-left, front-knee-right
  • front-foot-left, front-foot-right

Back View:

  • back-head, back-neck-left, back-neck-right
  • back-shoulder-left, back-shoulder-right
  • back-upper-left, back-upper-right
  • back-mid-left, back-mid-right
  • back-arm-left, back-arm-right
  • back-hand-left, back-hand-right
  • back-butt-left, back-butt-right
  • back-leg-left, back-leg-right

Customization Examples

Fitness App - Muscle Soreness Tracker

BodyHeatmap(
  selectedParts: {
    'front-chest-left': 5,
    'front-chest-right': 5,
    'front-arm-left': 3,
    'front-leg-left': 2,
  },
  baseColor: Colors.deepOrange,
  width: 350,
  showLegend: true,
  intensityLevels: 5,
  onPartTap: (part) => _recordSoreness(part),
)

Medical App - Pain Assessment

BodyHeatmap(
  selectedParts: painData,
  baseColor: Colors.red,
  unselectedColor: Colors.grey[200]!,
  width: 280,
  showLegend: true,
  legendTextStyle: TextStyle(
    fontSize: 14,
    fontWeight: FontWeight.w500,
  ),
  intensityLevels: 10,
  onPartTap: (part) => _assessPain(part),
)

Wellness App - Massage Therapy

BodyHeatmap(
  selectedParts: treatmentAreas,
  baseColor: Colors.blue,
  width: 300,
  showLegend: false,
  onPartTap: (part) => _markTreatmentArea(part),
)

How It Works

The widget uses SVG path data to render an accurate human body diagram. Each body part is a clickable region that:

  1. Responds to hover events (on supported platforms)
  2. Provides visual feedback on tap
  3. Calculates opacity based on intensity values
  4. Normalizes intensity across all selected parts for consistent visualization

The heatmap automatically scales intensity values to create a gradient effect, making it easy to visualize relative differences between body parts.

Contributing

Contributions are welcome! If you find a bug or want to add a feature:

  1. Open an issue describing the bug or feature
  2. Fork the repository
  3. Create a pull request with your changes

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For issues, questions, or suggestions, please file an issue on the GitHub repository.

Libraries

bodyheatmap
Support for doing something awesome.