Как создать диаграммы на моем веб-сайте JavaScript, используя данные из базы данных MySQL. Использование внешнего интерфейса EJS

Я создаю веб-сайт, на котором могу вводить данные о полях для гольфа, а затем анализировать их. Я использую экспресс в своем бэкэнде для маршрутизации на мои страницы ejs. Я также использую базу данных MySQL для хранения данных. При создании диаграмм я использовал файлchart.js из w3schools, что позволило мне создать скрипт внутри html-кода для вставки кода javascript. Но потом понял, что мне придется создать соединение с базой данных в файле ejs (что кажется неэффективным и небезопасным (создание нескольких подключений к БД)). Затем я потратил много времени, создавая функции внутри моего js-файла с базой данных и экспресс-соединения, где я выполняю все остальные запросы. Я закончил просто попыткой сохранить сценарий с веб-сайта в файле ejs, а затем попытаться передать данные из моего файла js в этот файл ejs для отображения. Именно по этой причине я прошу о помощи. Я не могу понять, как передать этот список данных из моего js-файла в мой ejs-файл для использования в скрипте? Пока думаю об этом. Должен быть более эффективный способ сделать это?

EJS-файл, в котором я пытаюсь отобразить график:

<body>
    <div class = "container">
        <div class = "chart">
            <canvas id = "myChart" style = "width:100%;max-width:700px"></canvas>
        </div>
    </div>
    <script src = "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
            const scatterGraphData = JSON.parse(document.getElementById('myChart').dataset.scatterData);
            
            new Chart("myChart", {
                type: "scatter",
                data: {
                    datasets: [{
                        pointRadius: 4,
                        pointBackgroundColor: "rgb(0,0,255)",
                        data: scatterGraphData
                    }]
                },
                options: {
                    legend: { display: false },
                    scales: {
                        xAxes: [{ ticks: { min: 40, max: 160 } }],
                        yAxes: [{ ticks: { min: 6, max: 16 } }],
                    }
                }
            });
        });
        </script>
</body>

Функция, которая вычисляет данные:

async function getChartData() {
    const now = new Date();
    const formattedDate = now.toISOString().split('T')[0];

    connection.query("SELECT * FROM sample WHERE Date = ?", [formattedDate], (error, results) => {
        if (error) {
            console.info("Database Error inside getChartData");
            return;
        }
        if (results.length === 0) {
            // No data found today
            console.info("Entered in the no data found");
            // random test data to see if graph even works
            const defaultData = [
                { x: 50, y: 7 },
                { x: 60, y: 8 },
                { x: 70, y: 8 },
                { x: 80, y: 9 },
                { x: 90, y: 9 },
                { x: 100, y: 9 },
                { x: 110, y: 10 },
                { x: 120, y: 11 },
                { x: 130, y: 14 },
                { x: 140, y: 14 },
                { x: 150, y: 15 }
            ];
            return defaultData;
        }
        // real Data exists to map
        let AveragesList = [];
        let counter = 0;
        const sampleHoles = [2, 12, 16];
        for (const holeid of sampleHoles) {
            const holeRecord = connection.query("SELECT * FROM holes WHERE Id = ?", [results[0][holeid]]);
            const upSlopeData = connection.query("SELECT * FROM upslopespeed WHERE UpSlopeID = ?", [holeRecord[0].UpSlopeSpeedID]);
            const downSlopeData = connection.query("SELECT * FROM downslopespeed WHERE DownSlopeID = ?", [holeRecord[0].DownSlopeSpeedID]);

            const backLeftSpeed = (upSlopeData[0].BackLeft * 2) / (upSlopeData[0].BackLeft + downSlopeData[0].BackLeft);
            const backCentreSpeed = (upSlopeData[0].BackCentre * 2) / (upSlopeData[0].BackCentre + downSlopeData[0].BackCentre);
            const backRightSpeed = (upSlopeData[0].BackRight * 2) / (upSlopeData[0].BackRight + downSlopeData[0].BackRight);

            const AverageSpeed = (backLeftSpeed + backCentreSpeed + backRightSpeed) / 3;
            AveragesList[counter] = AverageSpeed;
            counter++;
        }

        const xyValues = [
            {x:2, y:AveragesList[0]},
            {x:12, y:AveragesList[1]},
            {x:16, y:AveragesList[2]}
          ];

        return xyValues;
    });
}

Это функция, которая вызывается при загрузке страницы:

function DashboardDetermine(req, res) {
    if (req.session.user.isAdmin === 1) {
        // ADMIN
        // get all employees to list on admin dashboard
        connection.query("SELECT * FROM user WHERE admin = 0", async (error, results) => {
            if (error) {
                console.error('Error executing query:', error);
                req.flash('error_msg', 'An error occurred while loading users.');
                res.redirect('/dashboard');
                return;
            }
            const scatterGraphData = await JSON.stringify(getChartData());
            console.info(scatterGraphData);
            // Pass the results to the template
            res.render('dashboardAdmin', { user: results, scatterGraphData });
        });
    } else {
        // EMPLOYEE
        res.render("dashboard");
    }
}

В пустой день функция getChartData() должна просто возвращать фиксированные данные, которые я взял с веб-сайта w3schools в своем примере, просто чтобы устранить источники ошибок. Кажется, данные получаются из вызова getChartData(), но файл JSON из console.info возвращает {}. Из-за этого диаграмма не отображается.

Вот почему мне интересно, переместить ли сценарий точечного графика в этот JS-файл, чтобы функции могли вводить туда данные?

Надеюсь, это не сбивает с толку, большое спасибо за любую помощь!

🤔 А знаете ли вы, что...
JavaScript поддерживает работу с графикой и аудио, что позволяет создавать мультимедийные веб-приложения.


79
1

Ответ:

Решено

Несколько наблюдений, комментариев, а также рабочий код, основанный на прилагаемом вашем коде.

а. Второй аргумент res.render по сути является объектом. После этого он будет доступен в шаблоне как сам объект. Пожалуйста, посмотрите в приведенном ниже коде, как он был передан как объект, точнее, в данном случае как объект массива объектов.

  res.render('index', { graphdata });

б. Продолжая вышеизложенное, нет никаких требований о том, что он должен быть в формате JSON. Форматирование же полностью зависит от контекста, в котором оно будет использоваться в шаблоне. Также обратите внимание, что функция конструктора диаграммы напрямую принимает объект javascript, но обратите внимание, что он должен быть в формате JSON. Это вы можете проверить и подтвердить, назначив массив объектов непосредственно его свойству data.datasets.data.

в. Однако в приведенном ниже коде используется формат JSON. Это стало техническим требованием. Объект, переданный в шаблон, будет доступен как сам объект, который уже упоминался в пункте a, однако доступ к нему в JavaScript в теге «script» потребует немного больше работы. Следующее утверждение выполняет эту работу. В данном конкретном случае он сначала отформатировал JSON и, таким образом, стал доступен в контексте сценариев JavaScript, а затем вернул формат JSON путем анализа. Благодаря этим шагам он стал объектом того же типа, который был передан с сервера. Это один из технических способов сделать объект, передаваемый с сервера, доступным и в контексте сценария. Также обратите внимание на дефис в теге ejs «<%-», он также необходим для получения неэкранированных значений.

const graphdata = JSON.parse('<%- (JSON.stringify(graphdata)) %>');

Рабочий код:

сервер.js

const express = require('express');
const app = express();

app.use(express.static('./'));

app.engine('ejs', require('ejs').__express);
app.set('views', './');
app.set('view engine', 'ejs');

const graphdata = [
  { x: 50, y: 7 },
  { x: 60, y: 8 },
  { x: 70, y: 8 },
  { x: 80, y: 9 },
  { x: 90, y: 9 },
  { x: 100, y: 9 },
  { x: 110, y: 10 },
  { x: 120, y: 11 },
  { x: 130, y: 14 },
  { x: 140, y: 14 },
  { x: 150, y: 15 },
];
console.info(graphdata);
app.get('/', (req, res) => {
  res.render('index', { graphdata });
});

app.listen(3000, () => console.info('L@3000'));

index.ejs

<!DOCTYPE html>
<html>
  <head>
    Chart.js sample - Scatter chart
  </head>
  <body>
    <div class = "container">
      <div class = "chart">
        <canvas id = "myChart" style = "width: 100%; max-width: 700px"></canvas>
      </div>
    </div>
    <script src = "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        const graphdata = JSON.parse('<%- (JSON.stringify(graphdata)) %>');

        new Chart('myChart', {
          type: 'scatter',
          data: {
            datasets: [
              {
                pointRadius: 4,
                pointBackgroundColor: 'rgb(0,0,255)',
                data: graphdata,
              },
            ],
          },
          options: {
            legend: { display: false },
            scales: {
              xAxes: [{ ticks: { min: 40, max: 160 } }],
              yAxes: [{ ticks: { min: 6, max: 16 } }],
            },
          },
        });
      });
    </script>
  </body>
</html>

Выход:

Цитаты:

Доступ к переданной переменной EJS в файле Javascript

Обновление: 11 июля 24 г.