# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.buzzy.buzz/the-building-blocks/code-widget-custom-code/examples/fruit-distribution-chart.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
