在 PHP Yii2 中使用 GridStack.js 和 Charts.js 的图表初始化问题

问题描述 投票:0回答:1

我正在尝试使用gridstack.js和chart.js在PHP yii2项目中制作仪表板

我提供了一个下拉按钮,用户可以在其中选择 KPI 图表,所选图表将添加到 gridstack.js 的网格中

问题 1:如果我按增量顺序加载图表:图表 1、图表 2、图表 3...等等,它会在网格中初始化,没有任何问题。但是,如果我选择图表 1 以外的任何随机图表,则所选图表不会被初始化。

问题2:一旦网格被保存,然后加载。因此,如果用户想要向加载的网格再添加一个图表,以便他/她可以更新已保存的网格 => 创建一个新网格并且加载的网格消失。

我100%确定问题出在initializeChart函数上。我根据网上可用的资源尝试了多种方法,但都是徒劳。我尝试过的一些事情是:

  1. 将initializeChart函数和图表数据分开,并根据用户请求调用图表数据。
  2. 我也尝试过在initializeChart函数中使用if else语句、if elseif语句和switch语句

但是一旦我修改了initializeChart函数,甚至没有一个图表被初始化。而目前如果以增量顺序调用它们正在初始化。

下面是我的完整代码。请帮我解决问题。

注意:我删除了一些图表数据以适应限制。所有图表数据都是虚构的,因此您可以复制粘贴任何图表数据并重命名以使其正常工作。

附注任何帮助将不胜感激。预先感谢!


<?php

/** @var yii\web\View $this */

use yii\helpers\Html;

$this->title = 'About';
$this->params['breadcrumbs'][] = $this->title;
?>
<?php
$this->registerJsFile('https://cdn.jsdelivr.net/npm/chart.js', ['position' => \yii\web\View::POS_HEAD]);
?>

<!DOCTYPE html>
<html>

<head>

    <style type="text/css">
        .grid-stack {
            background: lightslategray;
        }

        .grid-stack-item-content {
            text-align: start;
            background-color: whitesmoke;
        }

        .grid-stack-item {
            min-height: 80px;
        }

        .grid-stack-item-removing {
            opacity: 0.8;
            filter: blur(5px);
        }

        #trash {
            background: rgba(255, 0, 0, 0.6);
        }

     
    </style>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">


    <script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>
    <script nomodule="" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/gridstack.min.js"
        integrity="sha512-V4/oQa+3p3Nu7kSK1DLdTvD3+03q/2MMvszJ84JLroRjUvZ82YcplQ7IJX6XiZXuJtESbUBL+gcGF03F5D+n5Q=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-base-impl.min.js"
        integrity="sha512-mhZn+o/RSWCNMh6NpFW4pTDzGcqwhL2xH2RdRHOQ5dnj5HDrlPwMuHZdAwB8ZOXZcIhR6IgzXUh4DuG13PsPDg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-draggable.min.js"
        integrity="sha512-a41HfVO6a33kYNNTiVMwzCOgNo0RLhmEhKm0K1EiBludHHsjXbyUXcs3jMQpLs1mipx3yR2e5aInebX0e3dNTg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-droppable.min.js"
        integrity="sha512-0MXd7MHHvnDPlwTnGHxxPSk83jr3n04ozR/9D7WpKf7fr7kva7/Syfd8Obki4tIx0NOSzkn8wvlR6CrAFPWRWQ=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-element.min.js"
        integrity="sha512-zvWjOI2JNrhq7K/mfZu0zg6wHRd7iWDF5g7cc4QC6ZbGpIXlc6C1bFoDcj9KqQkU2G56x81qq+NQKRVNbDc2LQ=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-gridstack.min.js"
        integrity="sha512-rfwTdhmMbnmMNjp+H46Bfm5bEQOPMDJ8cWKIzP3JyLWCxo9nlrsjqyfGMe3sAocY7JFm3rH13VH2ZJtPj61Gjw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-manager.min.js"
        integrity="sha512-7c2iOKYLmwWFiZ0bdYJ1p8EvDwJFbFBvKTfVgLBCpPlLiXlITMumR/9aymNLEGqfVNzQjg+hJKcATL3PvZhY9A=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-resizable-handle.min.js"
        integrity="sha512-47UKx0R1s2WYC47SoxCO+OC256GghdA8sRVGTOzb4ehV1SnEBFS1+lujNb3bWW5abegJ+yVGKs8V93iqv4E3hg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-resizable.min.js"
        integrity="sha512-qfVbqxjrtBLIYkAVlicMMiLKO9Jl27UpU4YARHuKvKDUzrar97zKlkdpcXNgBtNaXsZ0NQMSwz0vg9Lxs4ezyA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/dd-touch.min.js"
        integrity="sha512-qjqVUYIO1ooxh8d3mhry2CoKxkqekgZU778GJNfD1bZxUlvUrpl/YMjKvzwwhmWPef/eSvbfHJ0Rj3HAZfJarg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/gridstack-all.min.js"
        integrity="sha512-gq8R31XSsOjp58K9qre4n5inuaUuAkz36qmdVx9Y1VpGtzmx06JlnVGLEDMISZH1Kh/M2X4Iip40WPD94kQW2w=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/gridstack-engine.min.js"
        integrity="sha512-wHYVJ9RRSpsxBgtDstxRb35Dlh6zXCxwzU3fTLyD81ltBG/ZJi9x82A9heWjcX6ykZ+ga8EkCFkKymUYhpwT0g=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/gridstack-extra.min.css"
        integrity="sha512-287EQpO1sItRDNvuCUARDlhpQs3qLRCMaidpOKp5BFu6EgcX3XxB92jmTvdXWW57Q9ImHcYqIHKx12EATT3sPA=="
        crossorigin="anonymous" referrerpolicy="no-referrer" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/gridstack.min.css"
        integrity="sha512-RQiZSqRhRB5xAwqOKws34d14fPNaxoy59RNAUl2KXtT+5XfmspdKoNo1C2hR1bunSSLd4wNOz1bYcZjvuzN0hg=="
        crossorigin="anonymous" referrerpolicy="no-referrer" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/types.min.js"
        integrity="sha512-Or1RaobYJlngoRviBZqCv5kO0PbmajRZ+1uPrcWYWkNQPTU/wgg+IQPtIliaPiVh7/qhJv+qK9oZPsaTsMEiUg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/10.0.1/utils.min.js"
        integrity="sha512-C+//7CsrykaET+j6aiHKpZ12zf+POQPB8t6SQ2Q0HOvadZ0vBuBfTT27/w06JhqJfXdntps6dbaLhKQfMPZ+vg=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

</head>

<body>
    <div class="site-about mb-0 pb-0">
       
        <h1>GridStackJs</h1>

        <div class="col-12">

            <div class="btn-group">
                <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"
                    aria-haspopup="true" aria-expanded="false">
                    <ion-icon name="add-circle"></ion-icon>Add KPI
                </button>
                <div class="dropdown-menu">
                    <a class="dropdown-item add-chart" href="#" data-chart="occupancyChart">Occupancy</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="roomsChart">Rooms</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="contractsChart">Contracts</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="employeeChart">Employee</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="revenueChart">Revenue</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="invoicesChart">Invoices</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="paymentChart">Payment</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="visitorsChart">Visitors</a>
                    <a class="dropdown-item add-chart" href="#" data-chart="maintenanceChart">Maintenance</a>
                </div>
            </div>
            <a onclick="saveFullGrid()" class="btn btn-secondary" href="#">Save Full Grid</a>
            <a onclick="loadFullGrid()" class="btn btn-secondary" href="#">Load Full Grid</a>
            <a onclick="clearGrid()" class="btn btn-secondary" href="#">Reset</a>
            <a id="trash" class="btn btn-danger" href="#"><ion-icon name="trash"></ion-icon>Drag here to remove!</a>
            <br /><br />
            <div id="gridCont" class="grid-stack"></div>
            <hr />
            <textarea id="saved-data" style="width: 100%" cols="100" rows="20" readonly="readonly"></textarea>
        </div>
     
        <script type="text/javascript">



            let grid = GridStack.init({
                cellHeight: 70,
                acceptWidgets: true,
                removable: '#trash', // drag-out delete class
                float: true,
            })
            GridStack.setupDragIn('.newWidget', { appendTo: 'body', helper: 'clone' });

            let advanceItems = [
                { id: 'defaultWidget', x: 0, y: 0, w: 5, h: 4, content: '<p class="px-4 mx-4 mt-4 pt-4"><em><b>Add KPIs as per your requirement<br/> from the dropdown-menu</b></em></p>' },
              
            ];
            advanceItems.forEach((n, i) => {
                n.id = String(i);
                n.content = `<button class="btn btn-outline-secondary" onclick="removeWidget(this.parentElement.parentElement)">X</button><br> ${n.content ? n.content : ''}`;
            });
            let advanceItemsFull;

          
            document.addEventListener('DOMContentLoaded', function () {
                document.querySelectorAll('.dropdown-item').forEach(function (item) {
                    item.addEventListener('click', function () {
                        const chartType = this.innerText.toLowerCase();
                        const chartId = chartType + 'Chart';
                        const newChart = `<canvas id="${chartId}"></canvas>`;

                        // Check if the chart already exists in advanceItems
                        const itemContent = advanceItems.find(item => item.content);
                        console.log("NEW CHART ", newChart);
                        console.log("SELECTED item.content", itemContent);
                        const existingChart = advanceItems.find(item => item.content.includes(newChart));

                        if (!existingChart) {
                            // Calculate new x and y coordinates based on existing items
                            const newX = advanceItems.length % 2 === 0 ? 8 : 0; // Alternates between 0 and 8
                            const newY = Math.floor(advanceItems.length / 2) * 2;

                            advanceItems.push({
                                id: chartId, // Add an id property to uniquely identify the chart
                                x: newX,
                                y: newY,
                                w: 6,
                                h: 4,
                                content: newChart,
                            });

                            advanceItems.forEach((n, i) => {
                                n.id = String(i);
                                if (!n.content.includes('removeWidget')) {
                                    n.content = `<button class="btn btn-outline-secondary" onclick="removeWidget(this.parentElement.parentElement)">X</button><br> ${n.content ? n.content : ''}`;
                                }
                            });

                            // Reload the grid to reflect the changes
                            grid.load(advanceItems);
                            const newItem = advanceItems.find(item => item.id === chartId);
                            if (newItem) {
                                initializeChart(newItem.content);
                            }
                            // Initialize the chart outside the grid load callback
                            initializeChart(newChart);
                        }
                    });
                });
            });


            function addEvents(grid, id) {
                let g = id !== undefined ? "grid" + id + " " : "";

                grid
                    .on("added removed change", function (event, items) {
                        let str = "";
                        items.forEach(function (item) {
                            str += " (" + item.x + "," + item.y + " " + item.w + "x" + item.h + ")";
                        });
                        console.log(
                            g + event.type + " " + items.length + " items (x,y w h):" + str
                        );
                    })
                    .on("enable", function (event) {
                        let grid = event.target;
                        console.log(g + "enable");
                    })
                    .on("disable", function (event) {
                        let grid = event.target;
                        console.log(g + "disable");
                    })
                    .on("dragstart", function (event, el) {
                        let n = el.gridstackNode;
                        let x = el.getAttribute("gs-x"); // verify node (easiest) and attr are the same
                        let y = el.getAttribute("gs-y");
                        console.log(
                            g +
                            "dragstart " +
                            (n.content || "") +
                            " pos: (" +
                            n.x +
                            "," +
                            n.y +
                            ") = (" +
                            x +
                            "," +
                            y +
                            ")"
                        );
                    })
                    .on("drag", function (event, el) {
                        let n = el.gridstackNode;
                        let x = el.getAttribute("gs-x"); // verify node (easiest) and attr are the same
                        let y = el.getAttribute("gs-y");
                     })
                    .on("dragstop", function (event, el) {
                        let n = el.gridstackNode;
                        let x = el.getAttribute("gs-x"); // verify node (easiest) and attr are the same
                        let y = el.getAttribute("gs-y");
                        console.log(
                            g +
                            "dragstop " +
                            (n.content || "") +
                            " pos: (" +
                            n.x +
                            "," +
                            n.y +
                            ") = (" +
                            x +
                            "," +
                            y +
                            ")"
                        );
                    })
                    .on("dropped", function (event, previousNode, newNode) {
                        if (previousNode) {
                            console.log(g + "dropped - Removed widget from grid:", previousNode);
                        }
                        if (newNode) {
                            console.log(g + "dropped - Added widget in grid:", newNode);
                        }
                    })
                    .on("resizestart", function (event, el) {
                        let n = el.gridstackNode;
                        let rec = el.getBoundingClientRect();
                        console.log(
                            `${g} resizestart ${n.content || ""} size: (${n.w}x${n.h
                            }) = (${Math.round(rec.width)}x${Math.round(rec.height)})px`
                        );
                    })
                    .on("resize", function (event, el) {
                        let n = el.gridstackNode;
                        let rec = el.getBoundingClientRect();
                        console.log(
                            `${g} resize ${n.content || ""} size: (${n.w}x${n.h}) = (${Math.round(
                                rec.width
                            )}x${Math.round(rec.height)})px`
                        );
                    })
                    .on("resizestop", function (event, el) {
                        let n = el.gridstackNode;
                        let rec = el.getBoundingClientRect();
                        console.log(
                            `${g} resizestop ${n.content || ""} size: (${n.w}x${n.h
                            }) = (${Math.round(rec.width)}x${Math.round(rec.height)})px`
                        );
                    });
            }


            grid.load(advanceItems);
            addEvents(grid);
            GridStack.setupDragIn('.newWidget', { appendTo: 'body', helper: 'clone' });
            initializeChart(advanceItems);

            function initializeChart(chartId) {
                console.log("in the initializeChart function", chartId, typeof (chartId))

                const ctxOccupancy = document.getElementById('occupancyChart');
                new Chart(ctxOccupancy, {
                    type: 'bar',
                    data: {
                        labels: ['Building 1', 'Building 2', 'Building 3', 'Building 4', 'Building 5'],
                        datasets: [
                            {
                                label: 'Employees',
                                data: [50, 30, 45, 25, 60],
                                backgroundColor: 'rgba(75, 192, 192, 0.7)',
                            },
                            {
                                label: 'Contractors',
                                data: [20, 15, 25, 10, 30],
                                backgroundColor: 'rgba(255, 99, 132, 0.7)',
                            },
                            {
                                label: 'Individual Tenants',
                                data: [10, 5, 15, 8, 20],
                                backgroundColor: 'rgba(255, 206, 86, 0.7)',
                            },
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                stacked: true,
                            },
                            y: {
                                stacked: true,
                                beginAtZero: true,
                            }
                        },
                        plugins: {
                            legend: {
                                display: true,
                                position: 'bottom',
                            },
                            title: {
                                display: true,
                                text: 'Occupancy',

                            },
                        },
                        responsive: true,
                        maintainAspectRatio: true,
                        layout: {
                            padding: {
                                top: 20,
                            }
                        }
                    }
                });

          

                const ctxEmployee = document.getElementById('employeeChart');
                new Chart(ctxEmployee, {
                    type: 'bubble',
                    data: {
                        datasets: [
                            {
                                label: 'Employee Distribution',
                                data: [
                                    { x: 1, y: 3, r: 10 },
                                    { x: 2, y: 2, r: 8 },
                                    { x: 3, y: 4, r: 12 },
                                    { x: 4, y: 5, r: 15 },
                                    { x: 5, y: 2, r: 8 },
                                ],
                                backgroundColor: 'rgba(75, 192, 192, 0.7)',
                            },
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                beginAtZero: true,
                            },
                            y: {
                                beginAtZero: true,
                            }
                        },
                        plugins: {
                            legend: {
                                display: true,
                                position: 'bottom',
                            },
                            title: {
                                display: true,
                                text: 'Employee Distribution',
                            },
                        },
                        responsive: true,
                        maintainAspectRatio: true,
                        layout: {
                            padding: {
                                top: 20,
                            }
                        }
                    }
                });

                const ctxRevenue = document.getElementById('revenueChart');
                new Chart(ctxRevenue, {
                    type: 'pie',
                    data: {
                        labels: ['Employees', 'Contractors', 'Individual Tenants'],
                        datasets: [{
                            data: [60, 25, 15],
                            backgroundColor: ['rgba(75, 192, 192, 0.7)', 'rgba(255, 99, 132, 0.7)', 'rgba(255, 206, 86, 0.7)'],
                        }]
                    },
                    options: {
                        plugins: {
                            legend: {
                                display: true,
                                position: 'bottom',
                            },
                            title: {
                                display: true,
                                text: 'Revenue',
                            },
                        },
                        responsive: true,
                        maintainAspectRatio: true,
                        layout: {
                            padding: {
                                top: 20,
                            }
                        }
                    }
                });

            


            }


            grid.on('added removed change', function (e, advanceItems) {
                let str = '';
                advanceItems.forEach(function (item) { str += ' (x,y)=' + item.x + ',' + item.y; });
                // console.log(e.type + ' ' + advanceItems.length + ' advanceItems:' + str);
            });



            function saveFullGrid() {
                try {
                    // Save the positions of the widget (x, y) coordinates and the content of the widgets (HTML content)
                    advanceItemsFull = grid.save(true, true);

                    // Stringify and store the advanceItemsFull object in localStorage
                    localStorage.setItem('gridData', JSON.stringify(advanceItemsFull));

                    console.log("advanceItems after Saving => ", advanceItemsFull);
                    console.log("saveFullGrid  => ", JSON.stringify(advanceItemsFull, null, '  '));
                } catch (error) {
                    console.error('Error saving full grid:', error);
                    // Provide user feedback or handle the error accordingly
                }
            }


            function loadFullGrid() {
                try {
                    if (!advanceItemsFull) {
                        let localStorageGridData = localStorage.getItem("gridData");

                        // Parse the JSON string retrieved from localStorage
                        advanceItemsFull = JSON.parse(localStorageGridData);

                        // Check if parsing was successful and if it has the expected structure
                        if (advanceItemsFull && advanceItemsFull.children) {
                            grid.removeAll();
                            grid.load(advanceItemsFull.children);
                            advanceItemsFull.children.forEach((item) => {
                                initializeChart(item.content);
                            });
                        } else {
                            console.error('Invalid data format in localStorage.');
                        }
                    } else {
                        // Your existing code for the case when advanceItemsFull is already defined
                        grid.removeAll();
                        grid.load(advanceItemsFull.children);
                        advanceItemsFull.children.forEach((item) => {
                            initializeChart(item.content);
                        });
                    }
                } catch (error) {
                    console.error('Error loading full grid:', error);
                    // Provide user feedback or handle the error accordingly
                }
            }


            // Reset function
            function clearGrid() {
                grid.removeAll();
                advanceItems = [
                    { x: 0, y: 0, w: 5, h: 4, content: '<p class="px-4 mx-4 mt-4 pt-4"><em><b>Add KPIs as per your requirement<br/> from the dropdown-menu</b></em></p>' },
                ];
                advanceItems.forEach((n, i) => {
                    n.id = String(i);
                    n.content = `<button class="btn btn-outline-secondary" onclick="removeWidget(this.parentElement.parentElement)">X</button><br> ${n.content ? n.content : ''}`;
                });

                grid.load(advanceItems);
            }

            function removeWidget(el) {
                // TEST removing from DOM first like Angular/React/Vue would do
                console.log("el", el);
                el.remove();
                grid.removeWidget(el, true);
            }

        </script>


     
    </div>
</body>

</html>



<?php
$this->registerJsFile('https://cdn.jsdelivr.net/npm/chart.js', ['position' => \yii\web\View::POS_HEAD]);
?>


javascript php yii2 chart.js gridstack
1个回答
0
投票

我设法解决了图表初始化问题。基本上在我的下面的函数中,我将选定的图表添加到 advanceItems 数组中,并且有一个用于图表初始化的函数。

我为每个图表的初始化创建了单独的函数,并从 advanceItems 数组中的画布元素中提取了所选图表 id,并为所选的每个 canvasElement 调用该函数。下面是有效的更新代码


 document.addEventListener('DOMContentLoaded', function () {
                document.querySelectorAll('.dropdown-item').forEach(function (item) {
                    item.addEventListener('click', function () {
                        const chartType = this.innerText.toLowerCase();
                        const chartId = chartType + 'Chart';
                        // console.log(chartId);
                        // console.log(typeof (chartId));
                        const newChart = `<canvas id="${chartId}"></canvas>`;

                        // Check if the chart already exists in advanceItems
                        const itemContent = advanceItems.find(item => item.content);
                        console.log("NEW CHART ", newChart);
                        console.log("SELECTED item.content", itemContent);
                        const existingChart = advanceItems.find(item => item.content.includes(newChart));

                        if (!existingChart) {
                            // Calculate new x and y coordinates based on existing items
                            const newX = advanceItems.length % 2 === 0 ? 8 : 0; // Alternates between 0 and 8
                            const newY = Math.floor(advanceItems.length / 2) * 2;

                            advanceItems.push({
                                id: chartId, // Add an id property to uniquely identify the chart
                                x: newX,
                                y: newY,
                                w: 6,
                                h: 4,
                                content: newChart,
                            });

                            advanceItems.forEach((n, i) => {
                                n.id = String(i);
                                if (!n.content.includes('removeWidget')) {
                                    n.content = `<button class="btn btn-outline-secondary" onclick="removeWidget(this.parentElement.parentElement)">X</button><br> ${n.content ? n.content : ''}`;
                                }
                            });

                            // Reload the grid to reflect the changes
                            grid.load(advanceItems);


                            // Mapping between chart IDs and initialization functions
                            const chartInitializationMap = {
                                'occupancyChart': initializeOccupancyChart,
                                'roomsChart': initializeRoomsChart,
                                'contractsChart': initializeContractsChart,
                                'employeeChart': initializeEmployeeChart,
                                'revenueChart': initializeRevenueChart,
                                'invoicesChart': initializeInvoicesChart,
                                'paymentChart': initializePaymentChart,
                                'visitorsChart': initializeVisitorsChart,
                                'maintenanceChart': initializeMaintenanceChart,
                            };

                            // Extract canvas elements using regular expression
                            const canvasElements = advanceItems.map(selectedGraph => {
                                const matches = selectedGraph.content.match(/<canvas.*?<\/canvas>/);
                                return matches ? matches[0] : null;
                            }).filter(Boolean);

                            console.log("Canvas elements:", canvasElements);

                            // Call the corresponding initialization functions based on the canvas IDs
                            canvasElements.forEach(canvasElement => {
                                const chartIdMatch = canvasElement.match(/id="([^"]+)"/);
                                if (chartIdMatch) {
                                    const chartId = chartIdMatch[1];
                                    const initializationFunction = chartInitializationMap[chartId];
                                    if (initializationFunction) {
                                        initializationFunction();
                                    }
                                }
                            });




                        }
                    });
                });
            });


单独的图表功能如下:

  function initializeOccupancyChart(chartContent) {
                // Add your existing chart initialization code here
                // Make sure that this code is executed after the grid is loaded
                // You might also need to modify this function to target the correct chart container
                // based on the chartId.
                console.log("in the initializeOccupancyChart function", chartContent, typeof (chartContent))

                const ctxOccupancy = document.getElementById('occupancyChart');
                new Chart(ctxOccupancy, {
                    type: 'bar',
                    data: {
                        labels: ['Building 1', 'Building 2', 'Building 3', 'Building 4', 'Building 5'],
                        datasets: [
                            {
                                label: 'Employees',
                                data: [50, 30, 45, 25, 60],
                                backgroundColor: 'rgba(75, 192, 192, 0.7)',
                            },
                            {
                                label: 'Contractors',
                                data: [20, 15, 25, 10, 30],
                                backgroundColor: 'rgba(255, 99, 132, 0.7)',
                            },
                            {
                                label: 'Individual Tenants',
                                data: [10, 5, 15, 8, 20],
                                backgroundColor: 'rgba(255, 206, 86, 0.7)',
                            },
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                stacked: true,
                            },
                            y: {
                                stacked: true,
                                beginAtZero: true,
                            }
                        },
                        plugins: {
                            legend: {
                                display: true,
                                position: 'bottom',
                            },
                            title: {
                                display: true,
                                text: 'Occupancy',

                            },
                        },
                        responsive: true,
                        maintainAspectRatio: true,
                        layout: {
                            padding: {
                                top: 20,
                            }
                        }
                    }
                });
            }

            function initializeRoomsChart(chartContent) {
                // Add your existing chart initialization code here
                // Make sure that this code is executed after the grid is loaded
                // You might also need to modify this function to target the correct chart container
                // based on the chartId.
                console.log("in the initializeRoomsChart function", chartContent, typeof (chartContent))

                const ctxRooms = document.getElementById('roomsChart');
                new Chart(ctxRooms, {
                    type: 'bar',
                    data: {
                        labels: ['Building 1', 'Building 2', 'Building 3', 'Building 4', 'Building 5'],
                        datasets: [
                            {
                                label: 'Vacant',
                                data: [10, 5, 8, 3, 12],
                                backgroundColor: 'rgba(255, 99, 132, 0.7)',
                            },
                            {
                                label: 'Allocated to Employees',
                                data: [20, 15, 25, 10, 30],
                                backgroundColor: 'rgba(75, 192, 192, 0.7)',
                            },
                            {
                                label: 'Rented to Contractors',
                                data: [5, 3, 6, 2, 8],
                                backgroundColor: 'rgba(255, 206, 86, 0.7)',
                            },
                            {
                                label: 'Rented to Individual Tenants',
                                data: [15, 7, 12, 5, 18],
                                backgroundColor: 'rgba(0, 123, 255, 0.7)',
                            },
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                stacked: true,
                            },
                            y: {
                                stacked: true,
                                beginAtZero: true,
                            }
                        },
                        plugins: {
                            legend: {
                                display: true,
                                position: 'bottom',
                            },
                            title: {
                                display: true,
                                text: 'Rooms',
                            },
                        },
                        responsive: true,
                        maintainAspectRatio: true,
                        layout: {
                            padding: {
                                top: 20,
                            }
                        }
                    }
                });
            }


© www.soinside.com 2019 - 2024. All rights reserved.