> For the complete documentation index, see [llms.txt](https://docs.buzzy.buzz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buzzy.buzz/the-building-blocks/code-widget-custom-code/examples/fruit-distribution-chart.md).

# Fruit Distribution Chart

This example demonstrates real-time data visualization using Chart.js with automatic updates when underlying data changes.

## Key Features

* **Real-time data visualization** with automatic chart updates
* **Pie chart with percentages** showing data distribution
* **Dynamic data fetching** from related datatables
* **Professional styling** with custom colors and tooltips
* **Responsive design** that adapts to container size
* **Error handling** with graceful fallbacks

## Use Cases

Ideal for applications requiring:

* Real-time dashboards and analytics
* Inventory tracking and distribution
* Survey results visualization
* Sales performance monitoring
* Resource allocation displays
* Any scenario requiring live data charts

## Implementation Overview

This widget uses the **Other Tables Data** pattern, fetching data from a separate "Fruit Counters" datatable. Key implementation features:

* Automatic chart updates when source data changes
* Professional Chart.js pie chart with custom styling
* Percentage calculations in tooltips
* Dynamic color assignment for visual appeal
* Responsive design principles

## Code Example

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Fruit Distribution Chart</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script
      src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.production.min.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js"
      crossorigin
    ></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      const buzzyFrameAPI = new BuzzyFrameAPI();
      let appData = [];
      let dataTableID = null;

      async function initApp() {
        const initData = await buzzyFrameAPI.initialise();

        const { resourceJSON } = initData || {};
        const dataTable = resourceJSON?.children?.find(
          child => child.title === 'Fruit Counters',
        );
        dataTableID = dataTable?._id;

        if (dataTableID) {
          await fetchAndUpdateData();

          buzzyFrameAPI.addMicroappListener({
            microAppID: dataTableID,
            listener: async () => {
              console.log('Data updated, refreshing chart');
              await fetchAndUpdateData();
            },
          });
        }
      }

      async function fetchAndUpdateData() {
        try {
          if (dataTableID) {
            const fruitTableRowData = await buzzyFrameAPI.fetchDataTableRows({
              microAppID: dataTableID,
            });
            appData = fruitTableRowData;

            if (window.updateChart) {
              window.updateChart(appData);
            }
          }
        } catch (error) {
          console.error('Error fetching data:', error);
          if (window.updateChart) {
            window.updateChart([]);
          }
        }
      }

      function App() {
        const { useEffect, useState, useRef } = React;
        const [data, setData] = useState([]);
        const [loading, setLoading] = useState(true);
        const chartRef = useRef(null);
        const canvasRef = useRef(null);

        useEffect(() => {
          window.updateChart = newData => {
            setData(newData);
            setLoading(false);
          };

          if (appData.length > 0) {
            setData(appData);
            setLoading(false);
          }

          return () => {
            window.updateChart = null;
          };
        }, []);

        useEffect(() => {
          if (data.length > 0 && canvasRef.current) {
            const labels = data.map(fruit => fruit['Fruit Type']);
            const counts = data.map(fruit => fruit['Count']);

            const chartData = {
              labels,
              datasets: [
                {
                  data: counts,
                  backgroundColor: [
                    'rgba(255, 99, 132, 0.8)',
                    'rgba(54, 162, 235, 0.8)',
                    'rgba(255, 206, 86, 0.8)',
                    'rgba(75, 192, 192, 0.8)',
                    'rgba(153, 102, 255, 0.8)',
                    'rgba(255, 159, 64, 0.8)',
                  ],
                  borderColor: [
                    'rgba(255, 99, 132, 1)',
                    'rgba(54, 162, 235, 1)',
                    'rgba(255, 206, 86, 1)',
                    'rgba(75, 192, 192, 1)',
                    'rgba(153, 102, 255, 1)',
                    'rgba(255, 159, 64, 1)',
                  ],
                  borderWidth: 1,
                },
              ],
            };

            if (chartRef.current) {
              chartRef.current.destroy();
            }

            const ctx = canvasRef.current.getContext('2d');
            chartRef.current = new Chart(ctx, {
              type: 'pie',
              data: chartData,
              options: {
                responsive: true,
                plugins: {
                  legend: {
                    position: 'top',
                  },
                  tooltip: {
                    callbacks: {
                      label: function (context) {
                        const label = context.label || '';
                        const value = context.raw || 0;
                        const total = context.dataset.data.reduce(
                          (a, b) => a + b,
                          0,
                        );
                        const percentage = ((value / total) * 100).toFixed(1);
                        return label + ': ' + value + ' (' + percentage + '%)';
                      },
                    },
                  },
                },
              },
            });
          }
        }, [data]);

        if (loading)
          return <div className="has-text-centered p-4">Loading...</div>;

        return (
          <div className="container">
            <div className="box has-text-centered">
              <h3 className="title is-4 mb-4">Fruit Distribution</h3>
              <canvas ref={canvasRef}></canvas>
            </div>
          </div>
        );
      }

      initApp().then(() => {
        ReactDOM.render(<App />, document.getElementById('root'));
      });
    </script>
  </body>
</html>
```

## Key Concepts

### Real-time Data Integration

* **Dynamic Data Source**: Fetches data from "Fruit Counters" datatable by name
* **Automatic Updates**: Chart refreshes immediately when source data changes
* **Error Handling**: Graceful fallback when data source is unavailable
* **Resource Discovery**: Finds datatables by title from resourceJSON

### Chart.js Pie Chart Features

* **Percentage Tooltips**: Custom tooltip showing both count and percentage
* **Professional Colors**: Carefully selected color palette for visual appeal
* **Responsive Design**: Chart adapts to container size automatically
* **Legend Positioning**: Top-positioned legend for optimal layout

### Data Processing

* **Field Mapping**: Maps "Fruit Type" and "Count" fields to chart data
* **Dynamic Labels**: Chart labels generated from actual data
* **Color Assignment**: Automatic color assignment for up to 6 categories
* **Total Calculations**: Real-time percentage calculations in tooltips

### Performance Optimization

* **Chart Lifecycle**: Proper chart destruction and recreation for updates
* **Memory Management**: Prevents memory leaks with proper cleanup
* **Efficient Updates**: Only updates when data actually changes
* **Loading States**: User-friendly loading indicators

This example demonstrates how code widgets can create professional data visualizations that update in real-time, perfect for dashboards and analytics applications where data freshness is critical.
