Графики Google перерисовываются медленно при изменении шрифта - PullRequest
1 голос
/ 27 мая 2019

Я использую Google Charts, который перерисовывается каждые 10 секунд.Если я использую шрифт по умолчанию (Arial), перерисовка (да, я вызываю clearChart ()) будет плавной.Если я пытаюсь изменить шрифт на Roboto, выполнив fontName: «Roboto» внутри моих опций, каждый раз, когда диаграммы перерисовываются, они «мерцают», как на диаграмме, скрывается примерно полсекунды (заменяется пустым пробелом) изатем снова появляется.

Я могу повторить ту же проблему на разных ПК и даже из Chrome на Android.

var temperatureOptions = {
    fontName: 'Roboto',
    hAxis: {
        title: 'Time',
        format: 'HH:mm',
    },
    vAxis: {
        title: 'Temperature (℃)',
    },
    colors: ['#7892c2', '#4e6096', '#a52714', '#097138'],
    legend: {
        position: 'top',
    }
};

temperatureChart.clearChart();
temperatureChart.draw(temperatureData, temperatureOptions);

Если я закомментирую "fontName: 'Roboto',",все работает гладко.

Полный HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Extractus</title>
    <link rel="icon" type="image/png" href="/favicon.png">
    <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
    <link href="https://fonts.googleapis.com/css?family=Roboto&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="/style.css?v=201905271">
    <meta charset="utf-8" />
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-12">
                <a href="#" class="button" id="auto">Auto</a>
                <a href="#" class="button" id="overrideOn">Override On</a>
                <a href="#" class="button" id="overrideOff">Override Off</a>
                <a href="#" class="button" id="restart">Restart</a>
            </div>
        </div>
        <div id="stats" style="display:none;">On <span id="onPercentage"></span>% since <span id="onDate"></span></div>
        <div id="spinner" class="lds-css ng-scope">
            <div class="lds-spinner" style="width:100%;height:100%">
                <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
                <span id="spinnerText">Connecting...</span>
            </div>
        </div>
        <div class="chart" id="temperaturechart_div"></div>
        <div class="chart" id="relativehumiditychart_div"></div>
        <div class="chart" id="absolutehumiditychart_div"></div>
        <div class="chart" id="needchart_div"></div>
        <br>
        <div class="row">
            <div class="col-12">
                <table id="table">
                    <thead id="tableHead">
                        <tr>
                            <th rowspan="2">Date</th>
                            <th colspan="4">Inside</th>
                            <th colspan="4">Outside</th>
                            <th rowspan="2">Need</th>
                            <th rowspan="2">Status</th>
                        </tr>
                        <tr>
                            <th>Temp (°C)</th>
                            <th>RH (%)</th>
                            <th>AH (g/m³)</th>
                            <th>DP (°C)</th>
                            <th>Temp (°C)</th>
                            <th>RH (%)</th>
                            <th>AH (g/m³)</th>
                            <th>DP (°C)</th>
                        </tr>
                    </thead>
                    <tbody id="tableBody"></tbody>
                    <tfoot id="tableFooter"></tfoot>
                </table>
            </div>
        </div>
    </div>
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <script src="/lib/signalr/dist/browser/signalr.min.js?v=201905272"></script>
    <!--<script src="/lib/signalr/dist/browser/signalr-protocol-msgpack.min.js?v=201905272"></script>-->
    <script src="/settings?v=201905272"></script>
    <script src="/js/client.min.js?v=201905273" charset="utf-8"></script>
</body>
</html>

И это полный JS:

"use strict";

google.charts.load('current', { packages: ['corechart', 'line'] });
google.charts.setOnLoadCallback(drawLineColors);

var temperatureData;
var relativeHumidityData;
var absoluteHumidityData;
var needData;
var temperatureChart;
var relativeHumidityChart;
var absoluteHumidityChart;
var needChart;
var lastDateSynced = new Date(2019, 1, 1, 0, 0, 0, 0);
var onDate = new Date(2019, 1, 1, 0, 0, 0, 0);
var onCount = 0;
var offCount = 0;
var synced = false;

var temperatureOptions = {
    fontName: 'Roboto',
    hAxis: {
        title: 'Time',
        format: 'HH:mm',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    vAxis: {
        title: 'Temperature (°C)',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    colors: ['#7892c2', '#4e6096', '#a52714', '#097138'],
    legend: {
        position: 'top',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    /*tooltip: {
    textStyle: { fontName: 'Noto Sans JP' }
    }*/
};

var relativeHumidityOptions = {
    fontName: 'Roboto',
    hAxis: {
        title: 'Time',
        format: 'HH:mm',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    vAxis: {
        title: 'Rel. Humidity (%)',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    colors: ['#7892c2', '#4e6096'],
    legend: {
        position: 'top',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    /*tooltip: {
    textStyle: { fontName: 'Noto Sans JP' }
    }*/
};

var absoluteHumidityOptions = {
    fontName: 'Roboto',
    hAxis: {
        title: 'Time',
        format: 'HH:mm',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    vAxis: {
        title: 'Abs. Humidity (g/m³)',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    colors: ['#7892c2', '#4e6096'],
    legend: {
        position: 'top',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    /*tooltip: {
    textStyle: { fontName: 'Noto Sans JP' }
    }*/
};

var needOptions = {
    fontName: 'Roboto',
    allowHtml: true,
    hAxis: {
        title: 'Time',
        format: 'HH:mm',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    vAxis: {
        title: 'Need',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    colors: ['#7892c2'],
    seriesType: "line",
    connectSteps: false,
    series: {
        1: {
            type: "steppedArea",
            color: '#FFE666',
            visibleInLegend: false,
            areaOpacity: 0.4,
            isStacked: false,
            enableInteractivity: false,
            lineWidth: 1
        },
        2: {
            type: "steppedArea",
            color: '#00B31E',
            visibleInLegend: false,
            areaOpacity: 0.4,
            isStacked: false,
            enableInteractivity: false,
            lineWidth: 0
        }
    },
    legend: {
        position: 'top',
        //textStyle: { fontName: 'Noto Sans JP' }
    },
    /*tooltip: {
    textStyle: { fontName: 'Noto Sans JP' }
    }*/
};

//var connection = new signalR.HubConnectionBuilder().withUrl("/signalRHub").withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()).build();
var connection = new signalR.HubConnectionBuilder().withUrl("/signalRHub").build();

//Disable send button until connection is established
document.getElementById("auto").disabled = true;
document.getElementById("overrideOn").disabled = true;
document.getElementById("overrideOff").disabled = true;
document.getElementById("restart").disabled = true;

function formatDate(dateObject) {
    var d = new Date(dateObject);
    var day = d.getDate();
    var month = d.getMonth() + 1;
    var year = d.getFullYear();
    var hours = d.getHours();
    var minutes = d.getMinutes();
    var seconds = d.getSeconds();
    if (day < 10) {
        day = "0" + day;
    }
    if (hours < 10) {
        hours = "0" + hours;
    }
    if (minutes < 10) {
        minutes = "0" + minutes;
    }
    if (seconds < 10) {
        seconds = "0" + seconds;
    }
    if (month < 10) {
        month = "0" + month;
    }
    var date = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;

    return date;
};

function round(value, precision) {
    var multiplier = Math.pow(10, precision || 0);
    return (Math.round(value * multiplier) / multiplier).toString();
}

function getTR(d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n, addData, insertRow) {
    var s = true;
    if (iRH < 0) { s = false; iRH = 0 - iRH; }

    var date = new Date(d);
    if (date > lastDateSynced)
        lastDateSynced = date;

    if (addData) {
        if (insertRow) {
            temperatureData.insertRows(0, [
                [date, iT, oT, iDP, oDP]
            ]);
            relativeHumidityData.insertRows(0, [
                [date, iRH, oRH]
            ]);
            absoluteHumidityData.insertRows(0, [
                [date, iAH, oAH]
            ]);
            needData.insertRows(0, [
                [date, n, minimumNeedForOn, maximumNeedForOff]
            ]);
        }
        else {
            temperatureData.addRows([
                [date, iT, oT, iDP, oDP]
            ]);
            relativeHumidityData.addRows([
                [date, iRH, oRH]
            ]);
            absoluteHumidityData.addRows([
                [date, iAH, oAH]
            ]);
            needData.addRows([
                [date, n, minimumNeedForOn, maximumNeedForOff]
            ]);
        }
    }

    var dTD = document.createElement("td");
    dTD.textContent = formatDate(d);
    var iTTD = document.createElement("td");
    iTTD.textContent = round(iT, 1);
    var iRHTD = document.createElement("td");
    iRHTD.textContent = round(iRH, 1);
    var iAHTD = document.createElement("td");
    iAHTD.textContent = round(iAH, 2);
    var iDPTD = document.createElement("td");
    iDPTD.textContent = round(iDP, 1);
    var oTTD = document.createElement("td");
    oTTD.textContent = round(oT, 1);
    var oRHTD = document.createElement("td");
    oRHTD.textContent = round(oRH, 1);
    var oAHTD = document.createElement("td");
    oAHTD.textContent = round(oAH, 2);
    var oDPTD = document.createElement("td");
    oDPTD.textContent = round(oDP, 1);
    var nTD = document.createElement("td");
    nTD.textContent = round(n, 2);
    if (n >= minimumNeedForOn)
        nTD.style.backgroundColor = '#D98880';
    else if (n > maximumNeedForOff)
        nTD.style.backgroundColor = '#F7DC6F';
    else
        nTD.style.backgroundColor = '#7DCEA0';
    var sTD = document.createElement("td");
    if (s)
        sTD.textContent = "on";
    else
        sTD.textContent = "off";

    var tr = document.createElement("tr");
    tr.appendChild(dTD);
    tr.appendChild(iTTD);
    tr.appendChild(iRHTD);
    tr.appendChild(iAHTD);
    tr.appendChild(iDPTD);
    tr.appendChild(oTTD);
    tr.appendChild(oRHTD);
    tr.appendChild(oAHTD);
    tr.appendChild(oDPTD);
    tr.appendChild(nTD);
    tr.appendChild(sTD);

    return tr;
}

connection.on("S", function (d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n) {
    var tr = getTR(d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n, true, true);

    var tableBody = document.getElementById("tableBody");
    tableBody.insertBefore(tr, tableBody.firstChild);

    if (synced) {
        var s = true;
        if (iRH < 0) { s = false; iRH = 0 - iRH; }
        if (s)
            onCount = onCount + 1;
        else
            offCount = offCount + 1;
        document.getElementById('onPercentage').innerText = Math.round((onCount / (onCount + offCount)) * 10000) / 100;
    }

    drawCharts();
});

connection.on("R", function (onD, onC, offC) {
    document.getElementById("spinner").style.display = 'none';
    var x = document.getElementsByClassName("chart");
    var i;
    for (i = 0; i < x.length; i++) {
        x[i].style.display = 'inline-block';
    }

    onDate = new Date(onD);
    onCount = onC;
    offCount = offC;

    document.getElementById('onPercentage').innerText = Math.round((onCount / (onCount + offCount)) * 10000) / 100;
    document.getElementById('onDate').innerText = formatDate(onDate);
    document.getElementById('stats').style.display = 'block';

    synced = true;

    drawCharts();
});

connection.on("L", function (d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n) {
    var tr = getTR(d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n, false, false);
    tr.setAttribute("style", "background-color: #F0E68C");

    var tableHead = document.getElementById("tableHead");
    if (tableHead.children.length === 2)
        tableHead.appendChild(tr);
    else
        tableHead.children[2].replaceWith(tr);
});

connection.on("F", function (d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n) {
    var tr = getTR(d, iT, oT, iRH, oRH, iAH, oAH, iDP, oDP, n, true, false);

    var tableBody = document.getElementById("tableBody");
    tableBody.appendChild(tr);
});

document.getElementById("auto").addEventListener("click", function (event) {
    connection.invoke("Auto", 0).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

document.getElementById("overrideOn").addEventListener("click", function (event) {
    connection.invoke("OverrideOn", 0).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

document.getElementById("overrideOff").addEventListener("click", function (event) {
    connection.invoke("OverrideOff", 0).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

document.getElementById("restart").addEventListener("click", function (event) {
    connection.invoke("Restart", 0).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

async function start() {
    try {
        await connection.start();
        connection.invoke("Sync", lastDateSynced).catch(function (err) {
            return console.error(err.toString());
        });
        document.getElementById("auto").disabled = false;
        document.getElementById("overrideOn").disabled = false;
        document.getElementById("overrideOff").disabled = false;
        document.getElementById("restart").disabled = false;
        document.getElementById("spinnerText").innerText = 'Loading charts...';
    } catch (err) {
        console.log(err);
        setTimeout(() => start(), 5000);
    }
};

connection.onclose(async () => {
    var bodyNode = document.getElementById("tableBody");
    var footerNode = document.getElementById("tableFooter");

    while (bodyNode.children.length > 0) {
        footerNode.insertBefore(bodyNode.lastChild, footerNode.firstChild);
        bodyNode.deleteRow(bodyNode.children.length - 1);
    }

    document.getElementById("auto").disabled = true;
    document.getElementById("overrideOn").disabled = true;
    document.getElementById("overrideOff").disabled = true;
    document.getElementById("restart").disabled = true;
    document.getElementById("spinner").style.display = 'block';
    document.getElementById('stats').style.display = 'none';
    document.getElementById("spinnerText").innerText = 'Reconnecting...';
    synced = false;
    var x = document.getElementsByClassName("chart");
    var i;
    for (i = 0; i < x.length; i++) {
        x[i].style.display = 'none';
    }
    await start();
});

//start();

function clearData() {
    temperatureData = new google.visualization.DataTable();
    relativeHumidityData = new google.visualization.DataTable();
    absoluteHumidityData = new google.visualization.DataTable();
    needData = new google.visualization.DataTable();

    temperatureData.addColumn('date', 'X');
    temperatureData.addColumn('number', 'Inside Temp.');
    temperatureData.addColumn('number', 'Outside Temp.');
    temperatureData.addColumn('number', 'Inside Dew Point');
    temperatureData.addColumn('number', 'Outside Dew Point');

    relativeHumidityData.addColumn('date', 'X');
    relativeHumidityData.addColumn('number', 'Inside Relative Humidity');
    relativeHumidityData.addColumn('number', 'Outside Relative Humidity');

    absoluteHumidityData.addColumn('date', 'X');
    absoluteHumidityData.addColumn('number', 'Inside Absolute Humidity');
    absoluteHumidityData.addColumn('number', 'Outside Absolute Humidity');

    needData.addColumn('date', 'X');
    needData.addColumn('number', 'Need');
    needData.addColumn('number', 'Minimum Need For On');
    needData.addColumn('number', 'Maximum Need For Off');
}

function drawLineColors() {
    clearData();
    temperatureChart = new google.visualization.LineChart(document.getElementById('temperaturechart_div'));
    relativeHumidityChart = new google.visualization.LineChart(document.getElementById('relativehumiditychart_div'));
    absoluteHumidityChart = new google.visualization.LineChart(document.getElementById('absolutehumiditychart_div'));
    needChart = new google.visualization.LineChart(document.getElementById('needchart_div'));
    date_formatter = new google.visualization.DateFormat({
        pattern: "yyyy-MM-dd HH:mm:ss"
    });
    temperature_formatter = new google.visualization.NumberFormat({
        pattern: "#.#°C"
    });
    percentage_formatter = new google.visualization.NumberFormat({
        pattern: '#.#\'%\''
    });
    absoluteHumidity_formatter = new google.visualization.NumberFormat({
        pattern: "#.##g/m³"
    });
    need_formatter = new google.visualization.NumberFormat({
        pattern: "#.##"
    });
    needColor_formatter = new google.visualization.ColorFormat();
    needColor_formatter.addRange(null, 17.0, '#7DCEA0', 'white');
    needColor_formatter.addRange(17.0, 20.5, '#F7DC6F', 'white');
    needColor_formatter.addRange(20.5, null, '#D98880', 'white');
    start();
}

var date_formatter;
var temperature_formatter;
var percentage_formatter;
var absoluteHumidity_formatter;
var need_formatter;
var needColor_formatter;

function drawCharts() {
    date_formatter.format(temperatureData, 0);
    date_formatter.format(relativeHumidityData, 0);
    date_formatter.format(absoluteHumidityData, 0);
    date_formatter.format(needData, 0);

    temperature_formatter.format(temperatureData, 1);
    temperature_formatter.format(temperatureData, 2);
    temperature_formatter.format(temperatureData, 3);
    temperature_formatter.format(temperatureData, 4);

    percentage_formatter.format(relativeHumidityData, 1);
    percentage_formatter.format(relativeHumidityData, 2);

    absoluteHumidity_formatter.format(absoluteHumidityData, 1);
    absoluteHumidity_formatter.format(absoluteHumidityData, 2);

    need_formatter.format(needData, 1);
    needColor_formatter.format(needData, 1);

    temperatureData.sort({ column: 0, desc: true });
    relativeHumidityData.sort({ column: 0, desc: true });
    absoluteHumidityData.sort({ column: 0, desc: true });
    needData.sort({ column: 0, desc: true });

    temperatureChart.clearChart();
    temperatureChart.draw(temperatureData, temperatureOptions);

    relativeHumidityChart.clearChart();
    relativeHumidityChart.draw(relativeHumidityData, relativeHumidityOptions);

    absoluteHumidityChart.clearChart();
    absoluteHumidityChart.draw(absoluteHumidityData, absoluteHumidityOptions);

    needChart.clearChart();
    needChart.draw(needData, needOptions);
}

1 Ответ

1 голос
/ 20 июня 2019

удалить пакет 'line', нужно только 'corechart'

'line' для графиков линий материала -> google.charts.Line
, которые вы не используете.

вы используете классическую или базовую диаграммы -> google.visualization.LineChart

пакет 'line' вызывает мигание,
см. Следующие рабочие фрагменты ...


с 'line' пакетом - мигает

google.charts.load('current', {
  packages: ['corechart', 'line']
}).then(function () {
  var temperatureData;
  var temperatureChart;
  var temperatureOptions = {
      fontName: 'Roboto',
      hAxis: {
          title: 'Time',
          format: 'HH:mm',
      },
      vAxis: {
          title: 'Temperature (℃)',
      },
      colors: ['#7892c2', '#4e6096', '#a52714', '#097138'],
      legend: {
          position: 'top',
      }
  };

  temperatureData = new google.visualization.DataTable();
  temperatureData.addColumn('date', 'X');
  temperatureData.addColumn('number', 'Inside Temp.');
  temperatureData.addColumn('number', 'Outside Temp.');
  temperatureData.addColumn('number', 'Inside Dew Point');
  temperatureData.addColumn('number', 'Outside Dew Point');

  var oneDay = (24 * 60 * 60 * 1000);
  var index = (new Date((new Date()).getTime() - (oneDay * 365.25))).getTime();
  var rowDate = new Date(index);
  temperatureData.addRow([rowDate, Math.floor(Math.random() * 60), Math.floor(Math.random() * 80), Math.floor(Math.random() * 30), Math.floor(Math.random() * 50)]);

  temperatureChart = new google.visualization.LineChart(document.getElementById('temperaturechart_div'));
  google.visualization.events.addListener(temperatureChart, 'ready', function () {
    setTimeout(function () {
      index = index + oneDay;
      rowDate = new Date(index);
      temperatureData.addRow([rowDate, Math.floor(Math.random() * 60), Math.floor(Math.random() * 80), Math.floor(Math.random() * 30), Math.floor(Math.random() * 50)]);
      temperatureChart.clearChart();
      temperatureChart.draw(temperatureData, temperatureOptions);
    }, 3000);
  });
  temperatureChart.draw(temperatureData, temperatureOptions);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div class="chart" id="temperaturechart_div"></div>

без 'line' упаковки - без мерцания

google.charts.load('current', {
  packages: ['corechart']
}).then(function () {
  var temperatureData;
  var temperatureChart;
  var temperatureOptions = {
      fontName: 'Roboto',
      hAxis: {
          title: 'Time',
          format: 'HH:mm',
      },
      vAxis: {
          title: 'Temperature (℃)',
      },
      colors: ['#7892c2', '#4e6096', '#a52714', '#097138'],
      legend: {
          position: 'top',
      }
  };

  temperatureData = new google.visualization.DataTable();
  temperatureData.addColumn('date', 'X');
  temperatureData.addColumn('number', 'Inside Temp.');
  temperatureData.addColumn('number', 'Outside Temp.');
  temperatureData.addColumn('number', 'Inside Dew Point');
  temperatureData.addColumn('number', 'Outside Dew Point');

  var oneDay = (24 * 60 * 60 * 1000);
  var index = (new Date((new Date()).getTime() - (oneDay * 365.25))).getTime();
  var rowDate = new Date(index);
  temperatureData.addRow([rowDate, Math.floor(Math.random() * 60), Math.floor(Math.random() * 80), Math.floor(Math.random() * 30), Math.floor(Math.random() * 50)]);

  temperatureChart = new google.visualization.LineChart(document.getElementById('temperaturechart_div'));
  google.visualization.events.addListener(temperatureChart, 'ready', function () {
    setTimeout(function () {
      index = index + oneDay;
      rowDate = new Date(index);
      temperatureData.addRow([rowDate, Math.floor(Math.random() * 60), Math.floor(Math.random() * 80), Math.floor(Math.random() * 30), Math.floor(Math.random() * 50)]);
      temperatureChart.clearChart();
      temperatureChart.draw(temperatureData, temperatureOptions);
    }, 3000);
  });
  temperatureChart.draw(temperatureData, temperatureOptions);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div class="chart" id="temperaturechart_div"></div>
...