Я пытаюсь использовать графы, чтобы создать многоканальный / многоканальный просмотрщик сигналов, для просмотра, например, цифровых сигналов c. Пример, приведенный здесь, отображает что-то вроде этого:
Очевидно, мне нужно синхронизировать две дорожки (т.е. когда я увеличиваю одну дорожку, другие должны соответственно увеличиваться) - в противном случае, это не очень полезно.
Я подготовил суть с обсуждаемым здесь кодом: https://gist.github.com/sdaau/2d21ff7d88f03118bd5b31fac66d2588; и должно быть возможно отобразить пример через bl.ocks.org (см. также здесь ), или если вы запускаете файлы. html локально в вашем браузере (я тестировал с Firefox 74)
Проблема заключается в следующем:
- Когда данные .csv предоставляются в виде кода в коде JavaScript, синхронные вызовы работают - и проблем нет, синхронизация работает ( см .: test_01_dygraphs_sync_csv. html
- Когда данные .csv предоставляются через удаленные URL-адреса, синхронные вызовы не работают - и синхронизация не работает (см .: test_02_dygraphs_sync_csv. html)
- Когда данные .csv предоставляются через удаленные URL-адреса и код перезаписывается асинхронно - синхронизация выполняется (см .: test_03_dygraphs_async_csv. html)
Причина этого объясняется в Есть ли событие загрузки Dygraph? :
Если вы передаете данные CSV или массив в конструктор Dygraphs , он будет вызываться синхронно. Если вы передадите URL, он будет называться асинхронно.
Однако проблема в том, что мне нужно использовать URL-адреса .csv, но я всегда логически думаю об этом с точки зрения синхронных вызовов; Например:
load_g1();
load_g2();
sync_g1g2();
... который, как показано, нарушает синхронизацию осей; и тип асинхронного вызова, который на самом деле работает с синхронизацией:
function load_g1() {
...
g1.ready(function() {
function load_g2() {
...
g2.ready(function() {
sync_g1g2();
});
}
load_g2();
});
}
... то есть «ад обратного вызова», действительно затрудняет мне управление кодом.
Так Я видел такие вопросы как:
... и, видимо, способ сделать это - использовать Обещания - к сожалению, я не все, кто разбирается в JavaScript, и я не могу сказать, если или как это можно применить к этому коду dygraphs.
Итак, подведем итог: есть ли способ переписать вызовы асинхронной загрузки кода .csv с помощью dygraphs, чтобы в конечном итоге я мог написать что-то вроде этих команд в последовательности (в Initialize () в примере)? :
load_g1();
load_g2();
sync_g1g2();
Для справки, я вставлю код test_03_dygraphs_async_csv.html
ниже:
<!DOCTYPE html>
<link rel="stylesheet" href="http://dygraphs.com/2.1.0/dygraph.css">
<title>Test 03: dygraphs asynchronous (URL .csv -> synchronize() OK)</title>
<style>
#graphdiv1, #graphdiv2 {
display: inline-block;
vertical-align: top;
}
#legend1, #legend2 {
display: inline-block;
vertical-align: top;
}
</style>
<h2>Test 03: dygraphs asynchronous (URL .csv -> synchronize() OK)</h2>
<hr/>
<div id="legend1" style="height:40px;">.</div>
<div id="graphdiv1"
style="width:98%; height:200px;"></div>
<div id="legend2" style="height:40px;">.</div>
<div id="graphdiv2"
style="width:98%; height:200px;"></div>
<script type="text/javascript" src="http://dygraphs.com/2.1.0/dygraph.js"></script>
<script type="text/javascript" src="http://dygraphs.com/2.1.0/extras/synchronizer.js"></script>
<script type="text/javascript">
// http://dygraphs.com/tests/plotters.html
// Darken a color
function darkenColor(colorStr) {
// Defined in dygraph-utils.js
var color = Dygraph.toRGB_(colorStr);
color.r = Math.floor((255 + color.r) / 2);
color.g = Math.floor((255 + color.g) / 2);
color.b = Math.floor((255 + color.b) / 2);
return 'rgb(' + color.r + ',' + color.g + ',' + color.b + ')';
}
// This function draws bars for a single series.
function barChartPlotter(e) {
var ctx = e.drawingContext;
var points = e.points;
var y_bottom = e.dygraph.toDomYCoord(0);
ctx.fillStyle = darkenColor(e.color);
//// Find the minimum separation between x-values. .. fixed
var bar_width = Math.floor(2.0);
// Do the actual plotting.
for (var i = 0; i < points.length; i++) {
var p = points[i];
var center_x = p.canvasx;
ctx.fillRect(center_x - bar_width / 2, p.canvasy,
bar_width, y_bottom - p.canvasy);
ctx.strokeRect(center_x - bar_width / 2, p.canvasy,
bar_width, y_bottom - p.canvasy);
}
}
function legendFormatter(data) {
if (data.x == null) {
// This happens when there's no selection and {legend: 'always'} is set.
return '<br>' + data.series.map(function(series) { return series.dashHTML + ' ' + series.labelHTML }).join('<br>');
}
var html = this.getLabels()[0] + ': ' + data.xHTML;
data.series.forEach(function(series) {
if (!series.isVisible) return;
var labeledData = series.labelHTML + ': ' + series.yHTML;
if (series.isHighlighted) {
labeledData = '<b>' + labeledData + '</b>';
}
html += '<br>' + series.dashHTML + ' ' + labeledData;
});
return html;
}
var g1, g2;
function load_g1() {
g1 = new Dygraph(
document.getElementById("graphdiv1"),
//"x,val1\n" +
//"0,0\n" +
//"18790378,1\n" +
//"19111992,0\n" +
//"20107172,1\n" +
//"21101338,0\n" +
//"183224018,0\n",
"https://gist.githubusercontent.com/sdaau/2d21ff7d88f03118bd5b31fac66d2588/raw/val1_data.csv",
{ // options
animatedZooms: true,
stepPlot: true,
axes: {
x: {
drawGrid: false
},
},
includeZero: true,
legend: 'always',
labelsKMB: true,
labelsDiv: document.getElementById('legend1'),
legendFormatter: legendFormatter,
}
);
// NOTE: SO:26316435 "If you pass CSV data or an array to the Dygraphs constructor, it will be called synchronously. If you pass a URL, it will be called asynchronously."
g1.ready(function() {
load_g2();
});
}
function load_g2() {
g2 = new Dygraph(
document.getElementById("graphdiv2"),
//"x,val2\n" +
//"0,0\n" +
//"18790378,0\n" +
//"19111992,10\n" +
//"20107172,40\n" +
//"21101338,30\n" +
//"22095808,20\n" +
//"23091420,50\n" +
//"24085288,10\n" +
//"25080336,50\n" +
//"26075516,40\n" +
//"27069272,20\n",
"https://gist.githubusercontent.com/sdaau/2d21ff7d88f03118bd5b31fac66d2588/raw/val2_data.csv",
{ // options
//title: 'val2', // no need for title (y axis label) here, if using fixed ("always") legend as separate div - shown there.
animatedZooms: true,
plotter: barChartPlotter,
axes: {
x: {
drawGrid: false
},
},
includeZero: true,
legend: 'always', // needs to be always, if we want the legend fixed, that is, not reparented to canvas, as it is for follow, which might fail with bad values
labelsKMB: true, // seemingly only for y values, not x?
labelsDiv: document.getElementById('legend2'),
legendFormatter: legendFormatter,
}
);
// NOTE: SO:26316435 "If you pass CSV data or an array to the Dygraphs constructor, it will be called synchronously. If you pass a URL, it will be called asynchronously."
g2.ready(function() {
sync_g1g2();
});
}
function sync_g1g2() {
g1.updateOptions({
dateWindow: g2.xAxisExtremes() // ok, works
});
var sync = Dygraph.synchronize(g1, g2, { // options
zoom: true,
selection: true,
range: false, // if you wish to only sync the x-axis.
});
// charts are now synchronized
}
function Initialize(evt) {
load_g1();
}
Initialize();
</script>