1

我们正在使用来自 AmCharts 的股票图表,其中多个数据集通过 ajax 异步加载。

不幸的是,它看起来像整个图表的日期范围,我的意思是“从”和“到”仅从添加到所有数据集数组的第一个开始设置。

想象一下您有 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>

在上面的示例中,您可以看到 data-set-2 具有所有 3 个 DataSet 的最大结束日期,而 data-set-3 具有所有 3 个 DataSet 的最小开始日期。

最终结果:

<!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>

您可以看到整个图表被截断为从 data-set-1 开始的日期范围,图表没有显示 date-set-2 点:

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

并且也没有显示 date-set-3 点:

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

我试图破解“From”和“To”输入但没有任何运气:

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

任何想法如何强制图表从所有数据集中查找最小和最大日期,而不仅仅是从添加到数据集数组的第一个日期?

4

1 回答 1

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()调用移出循环,因此它只被调用一次,而不是不必要的三次。

于 2016-10-03T06:53:18.023 回答