Milano
Milano

Reputation: 18705

multiple value axis with datetimes

I'm new in AmCharts.js. I want to create a chart with multiple value axis which represents occurences of prices on different websites for one product according to datetime (up to hours or better minutes) (not date).

So I need to draw chart with multiple lines which doesn't depends on each other. So when I one is null value, the value of second line is still drawn.

Every product can have different number of occurences so I can't hardcode colors and another properties of datasets.

One of the best approaches I found is AmStockChart because there can be drawn multiple lines. But there are multiple problems. One of them is that it needs to "compare" one line to another lines so if there is no value for datetime xxx, the value of line2 is not shown for this datetime.

The datetimes can differ (for one line is it 12.01 13:00, for another is it 14:00 etc).

This is my solution which doesn't work correctly since it has to be compared.

The JSON is: {'web_name':[[[year,month,day,hour...],price],[[[year,month....}

<script>
    var lines = [];
    var dataSets = [];

    generateChartData();

    function generateChartData() {
        var google_chart_json = JSON;
        var loopcounter = -1;
        $.each(google_chart_json, function (key, val) {
            var line = [];
            loopcounter = loopcounter + 1;

            $.each(val, function (_, scan) {
                var year = scan[0][0];
                var month = scan[0][1];
                var day = scan[0][2];
                var hour = scan[0][3];
                var minute = scan[0][4];
                var price = scan[1];

                var data = {
                    'date': new Date(year, month - 1, day, hour, minute),
                    'value': price
                };
                line.push(data);
            });
            line.sort(function (lhs, rhs) {
                return lhs.date.getTime() - rhs.date.getTime();
            });

            lines.push([key, line]);
        });
        console.log('LINES');
        console.log(lines);


        $.each(lines, function (_, name_line) {
            var dict = {
                'title': name_line[0],
                "fieldMappings": [{
                    "fromField": "value",
                    "toField": "value"
                }],
                "dataProvider": name_line[1],
                "categoryField": "date"
            };
            dataSets.push(dict);
        });
    }
    console.log(dataSets)
    var chart = AmCharts.makeChart("chartdiv", {
        "allLabels": [
            {
                "text": "Free label",
                "bold": true,
                "x": 20,
                "y": 20
            }
        ],
        categoryAxesSettings: {
            minPeriod: "hh",//(at least that is not grouped)
            groupToPeriods: ["DD", "WW", "MM"]//(Data will be grouped by day,week and month)
        },
        "type": "stock",
        "theme": "light",
        "dataSets": dataSets,

        "panels": [{
            "showCategoryAxis": false,
            "title": "Value",
            "percentHeight": 70,

            "stockGraphs": [{
                "id": "g1",
                "valueField": "value",
                "comparable": true,
                "compareField": "value",
                "balloonText": "[[date]][[title]]:<b>[[value]]</b>",
                "compareGraphBalloonText": "[[title]]:<b>[[value]]</b>"
            }],
            "stockLegend": {
                "periodValueTextComparing": "[[percents.value.close]]%",
                "periodValueTextRegular": "[[value.close]]"
            }
        }],

        {#https://docs.amcharts.com/javascriptcharts/ChartScrollbar#}
        "chartScrollbarSettings": {
            "graph": "g1",
            "color": "#333333"
        },

        "chartCursorSettings": {
            "valueBalloonsEnabled": true,
            "fullWidth": true,
            "cursorAlpha": 0.1,
            "valueLineBalloonEnabled": true,
            "valueLineEnabled": true,
            "valueLineAlpha": 0.5
        },

        "periodSelector": {
            "position": "left",
            "periods": [{
                "period": "MM",
                "selected": true,
                "count": 1,
                "label": "1 month"
            }, {
                "period": "YYYY",
                "count": 1,
                "label": "1 year"
            }, {
                "period": "YTD",
                "label": "YTD"
            }, {
                "period": "MAX",
                "label": "MAX"
            }]
        },

        "dataSetSelector": {
            "position": "left",
        },

        "export": {
            "enabled": true
        }
    });
    chart.panelsSettings.recalculateToPercents = "never";
</script>

When I put the same datetimes for the values, it shows lines. But when each value has different datetime, it shows nothing except the first line:

enter image description here

Another solution (Line chart FiddleJS) has hardcoded lines which I can't do because there are different numbers of them. But the main problem is that they have own value axises.

Could you tell me what what to do in my code to achieve not compared multiple line chart with allowed different datetimes for different values and lines? Or if you know - recommend some type of amchart which can do this all?

Upvotes: 0

Views: 1085

Answers (1)

xorspark
xorspark

Reputation: 16012

The comparison requires that every date/time has to match or it won't show every point, as you noticed. In the AmCharts knowledge base, there's a demo that implements a mini-plugin that syncs the timestamps in your data prior to initializing the chart:

/**
 * amCharts plugin: sync timestamps of the data sets
 * ---------------
 * Will work only if syncDataTimestamps is set to true in chart config
 */
AmCharts.addInitHandler(function(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 (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;
  }

}, ["stock"]);

Just add this before your chart code and set the custom syncDataTimestamps property to true in the top level of your chart config and it will run upon initialization.

Upvotes: 1

Related Questions