Intra Forum
    • Категории
    • Последние
    • Метки
    • Популярные
    • Зарегистрироваться
    • Войти
    1. Главная
    2. grinsva
    G
    Не в сети
    • Профиль
    • Подписки 0
    • Подписчики 0
    • Темы 5
    • Сообщения 13
    • Группы 0

    grinsva

    @grinsva

    3
    Репутация
    1
    Просмотры профиля
    13
    Сообщения
    0
    Подписчики
    0
    Подписки
    Регистрация
    Последнее посещение

    grinsva Отписаться Подписаться

    Недавние сообщения grinsva

    • RE: Пример ГРАФИКА на HTML виджете.

      В папку \anyfiles поместить 2 файла с библиотекой

      1. chart.js - код для него можно скачать по ссылке https://cdn.jsdelivr.net/npm/chart.js и вставить в файл
      2. chartjs - plugin-zoom.js - код для него можно скачать по ссылке https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom и вставить в файл
      написал в HTML виджеты
      G
      grinsva
    • RE: Пример ГРАФИКА на HTML виджете.

      Добавил в версию при отсутствии интернета или доступа к внешним ресурсам загружать библиотеки с папки \anyfiles

      <style type="text/css">
        /* ===== Стили для контейнера и canvas ===== */
        #${uuid} {
          height: 100%;
          width: 100%;
          position: relative;
        }
        #${uuid} canvas {
          width: 100% !important;
          height: 100% !important;
          display: block;
        }
      </style>
      
      <div id="${uuid}">
        <canvas id="myChart"></canvas>
        <button id="exportCsvBtn" style="position: absolute; top: 10px; right: 10px; z-index: 20; padding: 6px 12px; background: #5889A5; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 13px;">
          ⬇ CSV
        </button>
      </div>
      
      <script type="text/javascript">
        // ===== Глобальные переменные =====
        let updateTimeout = null;
        let isRendering = false;
        let chartInstance = null;
        let crosshair = null;
        let isSubscribed = false;
      
        // ===== Экспорт данных в CSV (разделитель ";" с BOM) =====
        function exportChartDataToCSV() {
          if (!chartInstance) {
            console.warn('График ещё не создан');
            return;
          }
      
          const datasets = chartInstance.data.datasets;
          if (!datasets || datasets.length === 0) {
            console.warn('Нет данных для экспорта');
            return;
          }
      
          const xValues = new Set();
          datasets.forEach(ds => {
            ds.data.forEach(point => {
              if (point.x !== undefined && point.x !== null) {
                xValues.add(point.x);
              }
            });
          });
      
          const sortedX = Array.from(xValues).sort((a, b) => a - b);
      
          const headers = ['Масса, кг'];
          datasets.forEach(ds => {
            headers.push(ds.label || 'Без названия');
          });
      
          const rows = [];
          sortedX.forEach(x => {
            const row = [x];
            datasets.forEach(ds => {
              const point = ds.data.find(p => p.x === x);
              row.push(point && point.y !== undefined && point.y !== null ? point.y : '');
            });
            rows.push(row);
          });
      
          const csvContent = [
            headers.join(';'),
            ...rows.map(row => row.join(';'))
          ].join('\n');
      
          const bom = '\uFEFF';
          const blob = new Blob([bom + csvContent], { type: 'text/csv;charset=utf-8;' });
          const link = document.createElement('a');
          link.href = URL.createObjectURL(blob);
          link.download = `chart_data_${new Date().toISOString().slice(0,10)}.csv`;
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          URL.revokeObjectURL(link.href);
          console.log('CSV файл успешно скачан (разделитель ";", с BOM)');
        }
      
        // ===== КАСТОМНОЕ ПЕРЕКРЕСТИЕ (с поддержкой изменения размера окна) =====
        function enableCrosshair(chart) {
          if (!chart) return;
      
          // Удаляем старое перекрестие, если есть
          if (crosshair) {
            if (crosshair.vLine) {
              crosshair.vLine.remove();
              crosshair.hLine.remove();
              crosshair.label.remove();
            }
            if (crosshair.resizeHandler) {
              window.removeEventListener('resize', crosshair.resizeHandler);
            }
            if (crosshair.resizeObserver) {
              crosshair.resizeObserver.disconnect();
            }
            crosshair = null;
          }
      
          const canvas = chart.canvas;
          if (!canvas) {
            console.warn('Canvas отсутствует');
            return;
          }
          const container = canvas.parentNode;
          if (!container) {
            console.warn('Контейнер canvas не найден');
            return;
          }
          container.style.position = 'relative';
      
          // Создаём элементы перекрестия
          const vLine = document.createElement('div');
          vLine.style.cssText = `
            position: absolute; top: 0; left: 0;
            height: 100%;
            border-left: 1px dashed rgba(88, 137, 165, 0.7);
            pointer-events: none; display: none;
            z-index: 10;
          `;
          container.appendChild(vLine);
      
          const hLine = document.createElement('div');
          hLine.style.cssText = `
            position: absolute; top: 0; left: 0;
            width: 100%;
            border-top: 1px dashed rgba(88, 137, 165, 0.7);
            pointer-events: none; display: none;
            z-index: 10;
          `;
          container.appendChild(hLine);
      
          const label = document.createElement('div');
          label.style.cssText = `
            position: absolute;
            background: rgba(235,235,235,0.85);
            padding: 2px 8px; border-radius: 4px;
            font-size: 12px; pointer-events: none;
            display: none; white-space: nowrap;
            border: 1px solid #ccc;
            z-index: 11;
          `;
          container.appendChild(label);
      
          crosshair = { vLine, hLine, label };
      
          // Храним относительные координаты (в долях от размера canvas)
          let lastXPercent = -1;
          let lastYPercent = -1;
          let isMouseInside = false;
      
          function updateCrosshairPosition(x, y) {
            if (!crosshair || !crosshair.vLine) return;
      
            const rect = canvas.getBoundingClientRect();
            if (x < 0 || y < 0 || x > rect.width || y > rect.height || !isMouseInside) {
              crosshair.vLine.style.display = 'none';
              crosshair.hLine.style.display = 'none';
              crosshair.label.style.display = 'none';
              return;
            }
            crosshair.vLine.style.display = 'block';
            crosshair.vLine.style.left = x + 'px';
            crosshair.hLine.style.display = 'block';
            crosshair.hLine.style.top = y + 'px';
      
            const xScale = chart.scales.x;
            const yScale = chart.scales.y;
            if (xScale && yScale) {
              const xVal = xScale.getValueForPixel(x);
              const yVal = yScale.getValueForPixel(y);
              if (xVal !== undefined && yVal !== undefined) {
                crosshair.label.style.display = 'block';
                crosshair.label.textContent = `X: ${xVal.toFixed(1)} кг, Y: ${yVal.toFixed(2)} МПа`;
                let lx = x + 10, ly = y - 10;
                if (lx + 200 > rect.width) lx = x - 200;
                if (ly < 0) ly = 0;
                crosshair.label.style.left = lx + 'px';
                crosshair.label.style.top = ly + 'px';
              } else {
                crosshair.label.style.display = 'none';
              }
            }
          }
      
          function onMouseMove(e) {
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            // Сохраняем относительные координаты
            lastXPercent = x / rect.width;
            lastYPercent = y / rect.height;
            isMouseInside = true;
            updateCrosshairPosition(x, y);
          }
      
          function onMouseLeave() {
            isMouseInside = false;
            if (crosshair) {
              crosshair.vLine.style.display = 'none';
              crosshair.hLine.style.display = 'none';
              crosshair.label.style.display = 'none';
            }
          }
      
          // Обработчик изменения размера окна или контейнера
          function onResize() {
            if (isMouseInside && lastXPercent >= 0 && lastYPercent >= 0 && crosshair) {
              // Обновляем размеры canvas
              chart.resize();
              // Даём время на пересчёт размеров
              setTimeout(() => {
                const rect = canvas.getBoundingClientRect();
                const x = lastXPercent * rect.width;
                const y = lastYPercent * rect.height;
                updateCrosshairPosition(x, y);
              }, 30);
            }
          }
      
          canvas.addEventListener('mousemove', onMouseMove);
          canvas.addEventListener('mouseleave', onMouseLeave);
          window.addEventListener('resize', onResize);
      
          // Наблюдатель за изменением размера контейнера (для случаев, когда окно не меняется, а контейнер — да)
          const resizeObserver = new ResizeObserver(() => {
            onResize();
          });
          resizeObserver.observe(container);
      
          // Сохраняем ссылки для очистки
          chart._crosshairHandlers = { onMouseMove, onMouseLeave, onResize };
          crosshair.resizeHandler = onResize;
          crosshair.resizeObserver = resizeObserver;
        }
      
        // ===== ОСНОВНАЯ ФУНКЦИЯ (debounce) =====
        function drawChart(canvasId) {
          if (isRendering) return;
          if (updateTimeout) {
            clearTimeout(updateTimeout);
            updateTimeout = null;
          }
          updateTimeout = setTimeout(() => {
            updateTimeout = null;
            performRender(canvasId);
          }, 150);
        }
      
        // ===== РЕАЛЬНЫЙ РЕНДЕРИНГ =====
        function performRender(canvasId) {
          if (isRendering) return;
          isRendering = true;
      
          try {
            const canvas = document.getElementById(canvasId);
            if (!canvas) { console.warn('Canvas not found'); return; }
            const context = canvas.getContext('2d');
            if (!context) { console.warn('Canvas context missing'); return; }
      
            const dataObj = window.ihapi.deviceValue('local676', 'report_graf_line_points');
            if (!dataObj || !dataObj.items || dataObj.items.length === 0) {
              console.warn('Нет данных');
              return;
            }
      
            const scaleXVal = window.ihapi.deviceValue('local638', 'scale_X');
            const scaleYVal = window.ihapi.deviceValue('local637', 'scale_Y');
            const isScaleX = scaleXVal == true || scaleXVal == 'true';
            const isScaleY = scaleYVal == true || scaleYVal == 'true';
            let mode = 'xy';
            if (isScaleX && !isScaleY) mode = 'x';
            else if (!isScaleX && isScaleY) mode = 'y';
            else if (!isScaleX && !isScaleY) mode = 'none';
      
            let zoomConfig = {
              pan: { enabled: false },
              zoom: { wheel: { enabled: false } }
            };
            if (mode !== 'none') {
              zoomConfig = {
                pan: { enabled: true, mode: mode },
                zoom: { wheel: { enabled: true }, mode: mode },
                limits: {
                  x: { min: dataObj.start, max: dataObj.end },
                  y: { min: dataObj.min, max: dataObj.max }
                }
              };
            }
      
            const datasets = [];
            for (const item of dataObj.items) {
              if (!item.visible) continue;
              const points = item.points.map(p => ({
                x: parseFloat(p.x),
                y: parseFloat(p.y)
              }));
              datasets.push({
                label: item.legend || 'Без названия',
                data: points,
                fill: false,
                borderColor: item.lineColor || '#000000',
                borderWidth: parseInt(item.lineWidth) || 2,
                tension: 0.0,
                pointRadius: 1.0,
                pointStyle: 'circle',
              });
            }
            if (datasets.length === 0) {
              console.warn('Нет видимых линий');
              return;
            }
      
            if (chartInstance) {
              // === ОБНОВЛЕНИЕ ===
              chartInstance.data.datasets = datasets;
              chartInstance.options.scales.x.min = dataObj.start;
              chartInstance.options.scales.x.max = dataObj.end;
              chartInstance.options.scales.y.min = dataObj.min;
              chartInstance.options.scales.y.max = dataObj.max;
              chartInstance.options.plugins.zoom = zoomConfig;
              chartInstance.update();
              console.log('График обновлён (zoom: ' + mode + ')');
            } else {
              // === ПЕРВОЕ СОЗДАНИЕ ГРАФИКА ===
              const config = {
                type: 'line',
                data: { datasets },
                options: {
                  responsive: true,
                  maintainAspectRatio: false,
                  animation: false,
                  scales: {
                    x: {
                      type: 'linear',
                      min: dataObj.start,
                      max: dataObj.end,
                      ticks: {
                        autoSkip: true,
                        maxRotation: 0,
                        callback: (val, index, ticks) =>
                          index === 0 || index === ticks.length - 1 ? null : `${Number(val.toFixed(3))} кг`,
                        color: '#5889A5',
                        font: { size: 12 },
                        maxTicksLimit: 20
                      },
                      grid: { display: true, color: 'rgba(0,0,0,0.1)', lineWidth: 1 },
                      border: { color: '#5889A540', lineWidth: 1 },
                      title: {
                        display: true,
                        text: 'Количество вяжущего (цемент + МД)',
                        color: '#5C7C8F',
                        font: { size: 14 }
                      }
                    },
                    y: {
                      min: dataObj.min,
                      max: dataObj.max,
                      ticks: {
                        callback: (val, index, ticks) =>
                          index === 0 || index === ticks.length - 1 ? null : Number(val.toFixed(3)),
                        color: '#5889A5',
                        font: { size: 12 },
                        maxTicksLimit: 20
                      },
                      grid: { display: true, color: 'rgba(0,0,0,0.1)', lineWidth: 1 },
                      border: { color: '#5889A540', lineWidth: 1 },
                      title: {
                        display: true,
                        text: 'Прочность, МПа',
                        color: '#5C7C8F',
                        font: { size: 14 }
                      }
                    }
                  },
                  plugins: {
                    zoom: zoomConfig,
                    tooltip: {
                      mode: 'nearest',
                      axis: 'x',
                      intersect: false,
                      backgroundColor: '#F0F0F0',
                      titleColor: '#444444',
                      titleFont: { size: 13, weight: 'normal' },
                      bodyColor: '#444444',
                      borderColor: '#CCCCCC',
                      borderWidth: 1,
                      cornerRadius: 2,
                      padding: 5,
                      usePointStyle: true,
                      boxWidth: 5,
                      boxHeight: 5,
                      callbacks: {
                        title: function(tooltipItems) {
                          const x = tooltipItems[0].parsed.x;
                          return `масса: ${x.toFixed(1)} кг`;
                        },
                        label: function(context) {
                          let label = context.dataset.label || '';
                          if (label) label += ': ';
                          if (context.parsed.y !== null) {
                            label += context.parsed.y.toFixed(2) + ' МПа';
                          }
                          return label;
                        },
                        labelPointStyle: function(context) {
                          return { pointStyle: 'circle' };
                        },
                        labelColor: function(context) {
                          return {
                            borderColor: context.dataset.borderColor,
                            backgroundColor: context.dataset.borderColor,
                            borderWidth: 0,
                            borderRadius: 2
                          };
                        }
                      }
                    },
                    legend: {
                      labels: {
                        boxWidth: 7,
                        boxHeight: 7,
                        usePointStyle: true,
                        font: { size: 13 }
                      }
                    }
                  }
                }
              };
      
              chartInstance = new Chart(context, config);
      
              // Принудительная установка размеров
              const container = canvas.parentNode;
              container.style.height = '100%';
              container.style.width = '100%';
              container.style.overflow = 'hidden';
              canvas.style.height = '100%';
              canvas.style.width = '100%';
              canvas.style.display = 'block';
              chartInstance.resize();
      
              // Вызываем enableCrosshair только один раз
              enableCrosshair(chartInstance);
              console.log('График успешно создан (zoom: ' + mode + ')');
      
              if (!isSubscribed) {
                setTimeout(initSubscriptions, 100);
              }
            }
          } catch (err) {
            console.error('Ошибка при рендеринге:', err);
          } finally {
            isRendering = false;
          }
        }
      
        // ===== ЗАГРУЗКА ПЛАГИНА ZOOM =====
        function loadZoomPlugin() {
        // Проверяем, не загружен ли уже плагин (чтобы избежать дублирования)
        if (document.getElementById('chartjs-plugin-zoom')) {
          drawChart('myChart');
          return;
        }
      
        const pluginScript = document.createElement('script');
        pluginScript.id = 'chartjs-plugin-zoom';
        pluginScript.src = 'https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom';
        document.head.appendChild(pluginScript);
      
        pluginScript.addEventListener('load', function () {
          console.log('Плагин zoom загружен');
          drawChart('myChart');
        });
      
        pluginScript.addEventListener('error', function () {
          console.warn('Ошибка загрузки плагина zoom с CDN, пробуем локальную версию');
          const localPlugin = document.createElement('script');
          localPlugin.id = 'chartjs-plugin-zoom';
          localPlugin.src = '/files/chartjs-plugin-zoom.js'; // путь к локальной копии
          document.head.appendChild(localPlugin);
      
          localPlugin.addEventListener('load', function () {
            console.log('Плагин zoom загружен локально');
            drawChart('myChart');
          });
          localPlugin.addEventListener('error', function () {
            console.error('Не удалось загрузить плагин zoom');
          });
        });
      }
      
        // ===== ЗАГРУЗКА ОСНОВНОГО СКРИПТА =====
       function loadScripts() {
        const chartScript = document.getElementById('chart-js');
        if (!chartScript) {
          const script = document.createElement('script');
          script.id = 'chart-js';
          console.log('Текущий хост:', window.location.hostname);
          // Сначала пробуем загрузить с CDN
          script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
          document.head.appendChild(script);
      
          script.addEventListener('load', function () {
            loadZoomPlugin();
          });
      
          script.addEventListener('error', function () {
            console.warn('Ошибка загрузки Chart.js с CDN, пробуем локальную версию');
            // Если CDN недоступен, загружаем локальный файл
            const localScript = document.createElement('script');
            localScript.id = 'chart-js'; // тот же ID, чтобы не дублировать
            localScript.src = '/files/chart.js'; // путь к локальной копии
            document.head.appendChild(localScript);
      
            localScript.addEventListener('load', function () {
              loadZoomPlugin();
            });
            localScript.addEventListener('error', function () {
              console.error('Не удалось загрузить Chart.js ни с CDN, ни локально');
            });
          });
        } else {
          if (!document.getElementById('chartjs-plugin-zoom')) {
            loadZoomPlugin();
          } else {
            drawChart('myChart');
          }
        }
      }
      
        // ===== Подписка на изменения локальных переменных =====
        let prevScaleX = null;
        let prevScaleY = null;
        let prevRecipeData = null;
        let prevFlags = null;
      
        function initSubscriptions() {
          if (isSubscribed) {
            console.warn('Подписка уже создана, пропускаем');
            return;
          }
      
          const myUuid = '${uuid}';
          const subscribeList = [
            'local638_scale_X',
            'local637_scale_Y',
            'local644_new_rec_table_12_3',
            'local669_report_enabledFlags'
          ];
      
          console.log('Вызов initSubscriptions');
      
          prevScaleX = window.ihapi.deviceValue('local638', 'scale_X');
          prevScaleY = window.ihapi.deviceValue('local637', 'scale_Y');
          prevRecipeData = window.ihapi.deviceValue('local644', 'new_rec_table_12_3');
          prevFlags = window.ihapi.deviceValue('local669', 'report_enabledFlags');
      
          window.ihapi.deviceSub(myUuid, subscribeList);
      
          window.ihapi.addEventListener(myUuid, 'data', function(event) {
            const newData = event;
            let hasChanged = false;
      
            subscribeList.forEach(key => {
              if (newData[key] !== undefined) {
                const currentVal = newData[key];
                if (key === 'local638_scale_X' && currentVal !== prevScaleX) {
                  prevScaleX = currentVal;
                  hasChanged = true;
                } else if (key === 'local637_scale_Y' && currentVal !== prevScaleY) {
                  prevScaleY = currentVal;
                  hasChanged = true;
                } else if (key === 'local644_new_rec_table_12_3' &&
                           JSON.stringify(currentVal) !== JSON.stringify(prevRecipeData)) {
                  prevRecipeData = currentVal;
                  hasChanged = true;
                } else if (key === 'local669_report_enabledFlags') {
                  prevFlags = currentVal;
                  hasChanged = true;
                }
              }
            });
      
            if (hasChanged) {
              console.log('Обнаружено изменение локальной переменной, обновляем график');
              drawChart('myChart');
            }
          });
      
          window.ihapi.addEventListener(myUuid, 'destroy', function() {
            window.ihapi.deviceUnsub(myUuid, subscribeList);
            console.log('Отписка от локальных переменных выполнена');
          });
      
          isSubscribed = true;
        }
      
        // ===== ИНИЦИАЛИЗАЦИЯ =====
        console.log('START');
        const scriptExists = document.getElementById('chart-js');
      
        const exportBtn = document.getElementById('exportCsvBtn');
        if (exportBtn) {
          exportBtn.addEventListener('click', exportChartDataToCSV);
        }
      
        if (!scriptExists) {
          loadScripts();
        } else {
          if (!document.getElementById('chartjs-plugin-zoom')) {
            loadZoomPlugin();
          } else {
            drawChart('myChart');
            setTimeout(initSubscriptions, 500);
          }
        }
      </script>
      
      написал в HTML виджеты
      G
      grinsva
    • Пример ГРАФИКА на HTML виджете.

      Была задача реализовать ГРАФИК максимально приближенный по функционалу к Chart_MultiLine_GL. Т.е. возможность масштабирования по осям, всплывающая подсказка, перья.
      Главное условие, что по осям можно произвольные свои переменные вставлять и гибко настраивать визуал.

      Пример как все выглядит:
      cf7fd5a4-793a-43f7-8daf-9a8b26d5c5a0.jpg

      Процесс:

      • создаем контейнер
      • вставляем HTML виджет
      • вставляем код.

      Созданы несколько локальных переменных:

      • переменная с результирующим объектом из точек;

      • 2 переменные для включения/отключения масштабирования по осям;
        738f69e1-103c-4beb-937c-28c009faf55a-image.jpeg

      • переменная с массивом типа [1,1,1,1] для включения отображения или скрытия каких то графиков, т.к. при использовании встроенного функционала при обновлении графика все кривые вновь появляются и надо их снова отключать.
        350b1a56-d6bd-4edd-afc6-9a378a2a0edd-image.jpeg

      Изменение настроечных переменных график отслеживает по подписке.

      Входящие данные для графиков формируются в скрипте визуализации(можно делать каким угодно образом, не обязательно так). В моем случае я формирую такой же объект для графика как в стандартном обработчике и с ним работаю.

      Итоговый код (комментарии есть, если не понятно закидываем в ИИ):

      написал в HTML виджеты
      G
      grinsva
    • RE: Привязка локальных переменных для Графиков в HTML

      Доброго дня.
      Для подписки правильно ли я формирую названия переменных для метода? А то что то не реагируют на действия кнопок.

      const subscribeList = [ // <-- НОВОЕ
        'local638_scale_X', // <-- НОВОЕ
        'local637_scale_Y', // <-- НОВОЕ
        'local644_new_rec_table_12_3', // <-- НОВОЕ
        'local670_report_enabledFlags' // <-- НОВОЕ
      ]; // <-- НОВОЕ
      
      // Получаем начальные значения через deviceValue // <-- НОВОЕ
      prevScaleX = window.ihapi.deviceValue('local638', 'scale_X'); // <-- НОВОЕ
      prevScaleY = window.ihapi.deviceValue('local637', 'scale_Y'); // <-- НОВОЕ
      prevRecipeData = window.ihapi.deviceValue('local644', 'new_rec_table_12_3'); // <-- НОВОЕ
      prevFlags = window.ihapi.deviceValue('local670', 'report_enabledFlags'); // <-- НОВОЕ
      
      // Подписываемся на изменения // <-- НОВОЕ
      window.ihapi.deviceSub(myUuid, subscribeList); // <-- НОВОЕ
      
      написал в HTML виджеты
      G
      grinsva
    • RE: Привязка локальных переменных для Графиков в HTML

      Вопрос решился неправильно локальную переменную указал. в Коде 674, а в реальности 676 должно быть

      написал в HTML виджеты
      G
      grinsva
    • Привязка локальных переменных для Графиков в HTML

      Как правильно привязывать. По документации что то не получается

      Код:
      <style type="text/css"> </style>

      <div id= "${uuid}">'
      <canvas id="myChart"></canvas>
      </div>

      <script type="text/javascript">

      function drawChart(canvasId) {
      const ctx = document.getElementById(canvasId); // .getContext('3d')
      if (!ctx) {
      console.log('canvas contex missing');

      }
       
       let x_arr = [];
       let y_arr = [];
       const points = window.ihapi.deviceValue('local674', 'report_graf_line_points') ;
      
        console.log( 'points' );
        console.log( points );
       points.sort((a, b) => a.x - b.x);
       
       for ( const item of points){
                     x_arr.push(item.x)
                     y_arr.push(item.y)
       }
       
      
       
      
      const labels = x_arr ; //  [2, 4, 6, 8, 10, 12, 14]; ось X
      const data = {
        labels: labels,
        datasets: [{
          label: 'dataset1',
          data: y_arr, //ось Y  [65, 59, 80, 81, 56, 55, 40]
          fill: false,
          borderColor: 'rgb(75, 192, 192)',
          tension: 0.1
        } 
        ]
      }
      
      const myChart = new Chart(ctx, {  
        type: 'line',
        data: data
      });
      

      }

      function loadScript(scriptId) {
      const script = document.createElement('script');
      script.id = scriptId;
      script.src = '/files/chart.min.js'; // /files/chart.min.js https://cdn.jsdelivr.net/npm/chart.js https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.min.js
      // script.async = true;
      document.head.appendChild(script);

      script.addEventListener('load', function() {
        drawChart('myChart');
      });
      
      script.addEventListener('error', function() {
        console.error('/files/chart.min.js loading failed');
        return { err: '/files/chart.min.js loading failed' }
      });
      

      }

      const scriptExists = document.getElementById('chart-js');
      if (!scriptExists) {
      loadScript('chart-js');
      console.log('loadScript( chart-js )');
      } else {
      drawChart('myChart');
      console.log('drawChart( myChart )');
      }

      </script>

      e226fd33-dbb8-4d6d-8c6f-eb574e0be08e-image.jpeg

      В консоли:
      65444dfd-3e44-4df1-93b9-4950328df309-image.jpeg

      написал в HTML виджеты
      G
      grinsva
    • RE: Корявое изображение в Графиках CHART Multiline GL при зумировании по оси Х

      @maksimvershinin у меня так и так через него время получает. Но это не помогало. Пусть решение и затычка каких то проблем, но раз иного нет, то может кому то и поможет.
      NULL, как я понял, обрывает соединительную линию между точками.
      Этим я и воспользовался. для того что красиво смотрелось.

      написал в IntraSCADA
      G
      grinsva
    • RE: Корявое изображение в Графиках CHART Multiline GL при зумировании по оси Х

      grinsva said:

      Когда включаю Зумирование по Х появляются соединения начальных точек с конечными.
      Сперва на обнаружил на версии 5,18 - обновил. То же самое. Без зума по Х - нормально

      9f55bb45-c154-46ec-96c8-850b2d1fd1b4-image.jpeg

      42fec02d-6b0d-404d-84c4-fa62abad882d-image.jpeg

      Эту проблему я исправил - задав последние точки равными NULL

      написал в IntraSCADA
      G
      grinsva
    • RE: Корявое изображение в Графиках CHART Multiline GL при зумировании по оси Х

      Еще когда по p2p подключаюсь и интервал времени больше месяца, то по шкале Х не отображаются дата-время
      da7a1a82-08fc-478b-b78c-f891f20d81f9-image.jpeg

      Время только показывается.
      ce0794e5-ea14-4314-b51c-c4f82cabcd29-image.jpeg

      А когда из сети сервера смотрю. То нормально показывается - только язык Английский
      93831e0d-42e9-4878-8f28-b9302aaa5068-image.jpeg

      написал в IntraSCADA
      G
      grinsva
    • Корявое изображение в Графиках CHART Multiline GL при зумировании по оси Х

      Когда включаю Зумирование по Х появляются соединения начальных точек с конечными.
      Сперва на обнаружил на версии 5,18 - обновил. То же самое. Без зума по Х - нормально

      9f55bb45-c154-46ec-96c8-850b2d1fd1b4-image.jpeg

      42fec02d-6b0d-404d-84c4-fa62abad882d-image.jpeg

      написал в IntraSCADA
      G
      grinsva