2016-10-02 62 views
1

我們使用AmCharts的股票圖表與多個DataSet通過ajax異步加載。AmCharts股票圖表多個數據集的日期範圍是不正確

不幸的是,它看起來像整個圖表的日期範圍,我的意思是「From」和「To」僅從第一個添加到所有DataSet數組中設置。

試想一下,你有3個數據集的情況和他們每個人都可以有開始和結束日期完全不同:

<script id="data-set-1" type="application/json"> 
     [ 
      {"date": "2016-10-02T10:00:00", "value": 23.8}, 
      {"date": "2016-10-02T10:05:00", "value": 16.8}, 
      {"date": "2016-10-02T10:10:00", "value": 20.5} 
     ] 
</script> 
<!-- This dataset has max end date from all 3 datasets --> 
<script id="data-set-2" type="application/json"> 
     [ 
      {"date": "2016-10-02T10:00:00", "value": 15.2}, 
      {"date": "2016-10-02T10:05:00", "value": 21.4}, 
      {"date": "2016-10-02T10:15:00", "value": 18.1} 
     ] 
</script> 
<!-- This dataset has min start date from all 3 datasets --> 
<script id="data-set-3" type="application/json"> 
     [ 
      {"date": "2016-10-02T09:55:00", "value": 12.4}, 
      {"date": "2016-10-02T10:00:00", "value": 17.7}, 
      {"date": "2016-10-02T10:05:00", "value": 14.6} 
     ] 
</script> 

在上面的例子中可以看出,數據集-2具有從所有3最大結束日期DataSets和data-set-3在所有3個數據集中都有最小開始日期。

最終結果是:

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <title>AmCharts multiple datasets min-max date range issue</title> 
 
    <meta charset="utf-8" /> 
 
    <style type="text/css"> 
 
     #chartdiv { 
 
      width: 100%; 
 
      height: 500px; 
 
     } 
 
    </style> 
 
    <script id="data-set-1" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T10:00:00", "value": 23.8}, 
 
       {"date": "2016-10-02T10:05:00", "value": 16.8}, 
 
       {"date": "2016-10-02T10:10:00", "value": 20.5} 
 
      ] 
 
    </script> 
 
    <!-- This dataset has max end date from all 3 datasets --> 
 
    <script id="data-set-2" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T10:00:00", "value": 15.2}, 
 
       {"date": "2016-10-02T10:05:00", "value": 21.4}, 
 
       {"date": "2016-10-02T10:15:00", "value": 18.1} 
 
      ] 
 
    </script> 
 
    <!-- This dataset has min start date from all 3 datasets --> 
 
    <script id="data-set-3" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T09:55:00", "value": 12.4}, 
 
       {"date": "2016-10-02T10:00:00", "value": 17.7}, 
 
       {"date": "2016-10-02T10:05:00", "value": 14.6} 
 
      ] 
 
    </script> 
 
    <link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" /> 
 
</head> 
 
<body> 
 
    <div id="chartdiv"></div> 
 
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/amcharts.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/serial.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/amstock.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script> 
 
    <script type="text/javascript"> 
 

 
     $(document).ready(function() { 
 
      AmCharts.useUTC = true; // this will prevent adding timezone hours to ech date 
 

 
      var chart = AmCharts.makeChart("chartdiv", { 
 
       "pathToImages": "http://cdn.amcharts.com/lib/3/images/", 
 
       "type": "stock", 
 
       "theme": "light", 
 
       "categoryAxesSettings": { 
 
        "minPeriod": "mm" // precision to minutes 
 
       }, 
 

 
       "dataSets": [], // empty, we will add each based on single sensor 
 

 
       "panels": [{ 
 
        "recalculateToPercents": "never", // show value on scale not percent 
 
        "showCategoryAxis": true, 
 
        "title": "", 
 
        "percentHeight": 70, 
 

 
        "stockGraphs": [{ // generic config for all lines 
 
         "id": "g1", 
 
         "connect": true, // show gaps in data 
 
         "comparable": true, // must be true to disable/enable each dataset 
 
         "compareField": "value", 
 
         "valueField": "value", 
 
         "type": "smoothedLine", 
 
         "lineThickness": 2, 
 
         "bullet": "round" 
 
        }], 
 

 
        "stockLegend": { 
 
         "periodValueTextRegular": "[[value.close]]" // what will be shown at top legend 
 
        } 
 
       }], 
 

 
       "chartScrollbarSettings": { 
 
        "graph": "g1", 
 
        "usePeriod": "10mm", 
 
        "position": "top" 
 
       }, 
 

 
       "chartCursorSettings": { 
 
        "valueBalloonsEnabled": true 
 
       }, 
 

 
       "periodSelector": { 
 
        "fromText": "", 
 
        "toText": "", 
 
        "periodsText": "", 
 
        "position": "top", 
 
        "dateFormat": "YYYY-MM-DD JJ:NN", 
 
        "inputFieldWidth": 150, 
 
        "periods": [{ 
 
         "period": "hh", 
 
         "count": 1, 
 
         "label": "1 H", 
 
         "selected": true 
 
        }, { 
 
         "period": "hh", 
 
         "count": 8, 
 
         "label": "8 H" 
 
        }, { 
 
         "period": "DD", 
 
         "count": 1, 
 
         "label": "1 D" 
 
        }, { 
 
         "period": "DD", 
 
         "count": 10, 
 
         "label": "10 D" 
 
        }, { 
 
         "period": "MM", 
 
         "selected": true, 
 
         "count": 1, 
 
         "label": "1 M" 
 
        }, { 
 
         "period": "YYYY", 
 
         "count": 1, 
 
         "label": "1 Y" 
 
        }, { 
 
         "period": "YTD", 
 
         "label": "YTD" 
 
        }, { 
 
         "period": "MAX", 
 
         "label": "MAX" 
 
        }] 
 

 
       }, 
 

 
       "panelsSettings": { 
 
        "usePrefixes": true 
 
       }, 
 

 
       "export": { 
 
        "enabled": true, 
 
        "exportTitles": true, 
 
        "libs": { 
 
         "path": "http://www.amcharts.com/lib/3/plugins/export/libs/" 
 
        }, 
 
        "position": "bottom-right" 
 
       } 
 
      }); 
 

 
      for (var i = 1; i <= 3; i++) { 
 
       var dataset = new AmCharts.DataSet(); 
 
       dataset.compared = true; 
 
       dataset.title = "DataSet " + i; 
 
       dataset.categoryField = "date"; 
 
       dataset.fieldMappings = JSON.parse('[{"fromField": "value", "toField": "value"}]'); 
 

 
       var data = JSON.parse($("#data-set-" + i).html()); 
 
       dataset.dataProvider = data; 
 
       chart.dataSets.push(dataset); 
 
       chart.validateData(); 
 
      } 
 
     }); 
 
    </script> 
 
</body> 
 
</html>

可以看到,整個圖表被截斷爲時間範圍從數據集-1,圖未示出的日期 - 組 - 2點:

{"date": "2016-10-02T10:15:00", "value": 18.1} 

,也沒有顯示日期設定3點:

{"date": "2016-10-02T09:55:00", "value": 12.4} 

我試圖破解「從」和「到」的投入沒有任何的運氣:

chart.addListener("init", 
    function (e) { 
     //e.chart.startDate = moment("2016-10-01 00:00"); 
     //e.chart.endDate = moment("2016-10-03 00:00"); 
    }); 

任何想法如何,不僅從第一強制圖表來查找從所有數據集的最小和最大的日期,一個添加到數據集的數組?

回答

1

股票圖表將始終使用主選定數據集中日期的範圍,忽略來自比較數據集的數據點,該數據點不適合該範圍。

此外,它會忽略沒有直接時間戳匹配的數據點。

顯而易見的解決方案是通過在主數據集中添加與所比較的數據集中的數據重疊的「空」數據點來同步所有數據集中的數據。

我知道在生成數據的服務器端執行此操作可能會令人沮喪不便和低效。

幸運的是,我們可以實現一個客戶端封裝器來做到這一點。

我在這裏更新您的例子:

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <title>AmCharts multiple datasets min-max date range issue</title> 
 
    <meta charset="utf-8" /> 
 
    <style type="text/css"> 
 
     #chartdiv { 
 
      width: 100%; 
 
      height: 500px; 
 
     } 
 
    </style> 
 
    
 
    <script id="data-set-1" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T10:00:00", "value": 23.8}, 
 
       {"date": "2016-10-02T10:05:00", "value": 16.8}, 
 
       {"date": "2016-10-02T10:10:00", "value": 20.5} 
 
      ] 
 
    </script> 
 
    <!-- This dataset has max end date from all 3 datasets --> 
 
    <script id="data-set-2" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T10:00:00", "value": 15.2}, 
 
       {"date": "2016-10-02T10:05:00", "value": 21.4}, 
 
       {"date": "2016-10-02T10:15:00", "value": 18.1} 
 
      ] 
 
    </script> 
 
    <!-- This dataset has min start date from all 3 datasets --> 
 
    <script id="data-set-3" type="application/json"> 
 
      [ 
 
       {"date": "2016-10-02T09:55:00", "value": 12.4}, 
 
       {"date": "2016-10-02T10:00:00", "value": 17.7}, 
 
       {"date": "2016-10-02T10:05:00", "value": 14.6} 
 
      ] 
 
    </script> 
 
    <link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" /> 
 
</head> 
 
<body> 
 
    <div id="chartdiv"></div> 
 
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/amcharts.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/serial.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/amstock.js"></script> 
 
    <script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script> 
 
    <script type="text/javascript"> 
 
     function syncDataTimestamps(chart) { 
 

 
      // check if plugin is enabled 
 
      if (chart.syncDataTimestamps !== true) 
 
      return; 
 

 
      // go thorugh all data sets and collect all the different timestamps 
 
      var dates = {}; 
 
      for (var i = 0; i < chart.dataSets.length; i++) { 
 
      var ds = chart.dataSets[i]; 
 
      for (var x = 0; x < ds.dataProvider.length; x++) { 
 
       var date = ds.dataProvider[x][ds.categoryField]; 
 
       if (!(date instanceof Date)) 
 
       date = new Date(date); 
 
       if (dates[date.getTime()] === undefined) 
 
       dates[date.getTime()] = {}; 
 
       dates[date.getTime()][i] = ds.dataProvider[x]; 
 
      } 
 
      } 
 
      
 
      // iterate through data sets again and fill in the blanks 
 
      for (var i = 0; i < chart.dataSets.length; i++) { 
 
      var ds = chart.dataSets[i]; 
 
      var dp = []; 
 
      for (var ts in dates) { 
 
       if (!dates.hasOwnProperty(ts)) 
 
       continue; 
 
       var row = dates[ts]; 
 
       if (row[i] === undefined) { 
 
       row[i] = {}; 
 
       var d = new Date(); 
 
       d.setTime(ts); 
 
       row[i][ds.categoryField] = d; 
 
       } 
 
       dp.push(row[i]); 
 
      } 
 
      dp.sort(function(a,b){ 
 
       return new Date(a[ds.categoryField]) - new Date(b[ds.categoryField]); 
 
      }); 
 
      ds.dataProvider = dp; 
 
      } 
 

 
     }; 
 

 
     $(document).ready(function() { 
 
      AmCharts.useUTC = true; // this will prevent adding timezone hours to ech date 
 

 
      var chart = AmCharts.makeChart("chartdiv", { 
 
       "type": "stock", 
 
       "theme": "light", 
 
       "categoryAxesSettings": { 
 
        "minPeriod": "mm" // precision to minutes 
 
       }, 
 

 
       "syncDataTimestamps": true, 
 
       "dataSets": [], // empty, we will add each based on single sensor 
 

 
       "panels": [{ 
 
        "recalculateToPercents": "never", // show value on scale not percent 
 
        "showCategoryAxis": true, 
 
        "title": "", 
 
        "percentHeight": 70, 
 

 
        "stockGraphs": [{ // generic config for all lines 
 
         "id": "g1", 
 
         "connect": true, // show gaps in data 
 
         "comparable": true, // must be true to disable/enable each dataset 
 
         "compareField": "value", 
 
         "valueField": "value", 
 
         "type": "smoothedLine", 
 
         "lineThickness": 2, 
 
         "bullet": "round" 
 
        }], 
 

 
        "stockLegend": { 
 
         "periodValueTextRegular": "[[value.close]]" // what will be shown at top legend 
 
        } 
 
       }], 
 

 
       "chartScrollbarSettings": { 
 
        "graph": "g1", 
 
        "usePeriod": "10mm", 
 
        "position": "top" 
 
       }, 
 

 
       "chartCursorSettings": { 
 
        "valueBalloonsEnabled": true 
 
       }, 
 

 
       "periodSelector": { 
 
        "fromText": "", 
 
        "toText": "", 
 
        "periodsText": "", 
 
        "position": "top", 
 
        "dateFormat": "YYYY-MM-DD JJ:NN", 
 
        "inputFieldWidth": 150, 
 
        "periods": [{ 
 
         "period": "hh", 
 
         "count": 1, 
 
         "label": "1 H", 
 
         "selected": true 
 
        }, { 
 
         "period": "hh", 
 
         "count": 8, 
 
         "label": "8 H" 
 
        }, { 
 
         "period": "DD", 
 
         "count": 1, 
 
         "label": "1 D" 
 
        }, { 
 
         "period": "DD", 
 
         "count": 10, 
 
         "label": "10 D" 
 
        }, { 
 
         "period": "MM", 
 
         "selected": true, 
 
         "count": 1, 
 
         "label": "1 M" 
 
        }, { 
 
         "period": "YYYY", 
 
         "count": 1, 
 
         "label": "1 Y" 
 
        }, { 
 
         "period": "YTD", 
 
         "label": "YTD" 
 
        }, { 
 
         "period": "MAX", 
 
         "label": "MAX" 
 
        }] 
 

 
       }, 
 

 
       "panelsSettings": { 
 
        "usePrefixes": true 
 
       }, 
 

 
       "export": { 
 
        "enabled": true, 
 
        "exportTitles": true, 
 
        "libs": { 
 
         "path": "http://www.amcharts.com/lib/3/plugins/export/libs/" 
 
        }, 
 
        "position": "bottom-right" 
 
       } 
 
      }); 
 

 
      for (var i = 1; i <= 3; i++) { 
 
       var dataset = new AmCharts.DataSet(); 
 
       dataset.compared = true; 
 
       dataset.title = "DataSet " + i; 
 
       dataset.categoryField = "date"; 
 
       dataset.fieldMappings = JSON.parse('[{"fromField": "value", "toField": "value"}]'); 
 

 
       var data = JSON.parse($("#data-set-" + i).html()); 
 
       dataset.dataProvider = data; 
 
       chart.dataSets.push(dataset); 
 
      } 
 

 
      syncDataTimestamps(chart); 
 
      chart.validateData(); 
 
     }); 
 
    </script> 
 
</body> 
 
</html>

請注意,我還搬出了validateData()通話圈外的,所以它被稱爲只有一次,而不是不必要的三倍。

+0

當我們有很多數據時性能又如何? –

+0

我想對於數百或數千個數據點,額外的處理開銷不應有任何明顯的差異。數十或數十萬可能需要更長的時間。但很難估計確切的數字,只需要用您的實際數據來嘗試。 – martynasma

+0

現在還不夠好。我們將在我們的大型創業公司中使用它後,我會更新我的問題或添加其他答案。謝謝。 –