90

I have a requirement to plot run history of a task in Highcharts. It needs to show that run history of the tasks as a horizontal bar. There are additional requirements which I've added as an update below. Recently I found out that inverted option is not supported in StockChart and that only navigator & rangeSelector are available in StockChart. Therefore I am using those functions.

So in order to achieve the requirement I created something similar to this jsfiddle example (found somewhere while browsing don't remember the source) and ended up with this plunker link with help from my previous question, thanks to Pawel Fus

Updating question to avoid confusion

Additional requirements:

Show only those tasks which ran in a particular date and time range. In case there are too many runs, such as more than 10 run, then there needs to be a way to display only 10 tasks visibly with a y-axis that is scrollable to show other tasks. plunker link to the problem

Problem explanation of above plunker.

If you check the screenshot below from above plunker, the time range is from 12/12/2014 09:32:26 to 12/12/2014 10:32:26 and there are only 2 tasks that has run m_ARRAYV_SALES_ZIG1_CALL2_VOD__C_OB & m_ZIG2_HCP_MERGE_IB_CN. However I can see another task in between LILLY_C which did not even ran in this date time range. (In actual data there are more than 10 tasks that clutters this chart which does not even fall under this date time range)

Also if you notice at the bottom most right corner time shifted from 09:38 to 19:20. 19:20 is the end time for m_ZIG2_HCP_MERGE_IB_CN task. enter image description here Below is my chart options

    var chart_options = {
            chart: {
                renderTo: 'container',
                height: 600
            },
            title: {
            },
            credits: {
                enabled: false
            },
            xAxis: {
                type: 'datetime',
                gridLineWidth: 1,
                tickInterval: 1 * 3600 * 1000,
                dateTimeLabelFormats: {
                    month: '%b %e, %Y'
                }
            },
            yAxis: {                    
                tickInterval: 1,
                gridLineWidth: 1,
                labels: {
                    formatter: function() {
                        if (tasks[this.value]) {
                            return tasks[this.value].name;
                        }
                    }
                },
                startOnTick: false,
                endOnTick: false,
                title: {
                    text: 'Task'
                }
            },
            rangeSelector: {
                selected: 0,
                buttons: [ {
                    type: "minute",
                    count: 60,
                    text: "1h"
                }, {
                    type: "minute",
                    count: 180,
                    text: "3h"
                }, {
                    type: "minute",
                    count: 300,
                    text: "5h"
                }],
                inputDateFormat: '%m/%d/%Y %H:%M:%S',
                inputEditDateFormat: '%m/%d/%Y %H:%M:%S',
                inputBoxWidth: 120
            },
            navigator: {
                enabled: false
            },
            legend: {
                enabled: false
            },
            tooltip: {
                shared: false,
                formatter: function() {
                    var str = '';
                    str += 'Task: ' + this.series.name + '<br>';
                    str += 'From: ' + Highcharts.dateFormat('%m/%d/%y %H:%M', this.point.from) + '<br>';
                    str += 'To: ' + Highcharts.dateFormat('%m/%d/%y %H:%M', this.point.to) + '<br>';
                    return str;
                }
            },
            plotOptions: {
                line: {
                    lineWidth: 10,
                    marker: {
                        enabled: true
                    },
                    dataLabels: {
                        enabled: true,
                        align: 'left',
                        formatter: function() {
                            return this.point.options && this.point.options.label;
                        }
                    },
                    states:{
                        hover:{
                            lineWidth:10
                        }
                    }
                },
                series: {
                    cursor: 'pointer',
                    point: {
                        events: {
                            click: function () {
                                var query = '{ "task_id": "'+this.task_id+'","start_time": '+this.from+',"exclude_interval": '+opExcludeMinutes+',"size": 10 }';
                                $scope.taskName = this.series.name;
                                $scope.isTaskSelected = false;
                                $scope.operationalReportAgentTaskHistoryServiceRequest(query);
                            }
                        }
                    }
                }
            },
            series: seriesData
        };
Community
  • 1
  • 1
AabinGunz
  • 12,109
  • 54
  • 146
  • 218
  • 6
    Set lineWidth in state hover, example: http://jsfiddle.net/bx2000cb/8/ – Sebastian Bochan Jan 22 '15 at 15:05
  • @SebastianBochan: Thanks that solved my 1st problem. Also if you have seen my plunker you would see that I have given two different point colors for `SUCCESS` and `FAILURE` task runs data, Green and Red respectively, How can I assign the same to line? – AabinGunz Jan 22 '15 at 15:26
  • Honestly I see only yellow point, so let me knw what should I do ? – Sebastian Bochan Jan 23 '15 at 09:55
  • @SebastianBochan: Sorry my bad, when you move the scroll bar to `Dec 4 2014` you'll see a blue line with **green** color point. This indicates task run was `SUCCESS` similarly you can find `FAILURE` task run on 1st data i.e., on `Nov 26 2014`. Currently Yellow point is shown for null data. So these **green** and **red** color should also be applied to corresponding lines. – AabinGunz Jan 23 '15 at 10:31
  • @SebastianBochan: Currently there are 2 problems at hand 1. Need to assign point color to it's line. 2. Highcharts error #15. I have used similar way to create `tasks` data from my server code and then used similar method to create `series` data, not sure where it is failing. – AabinGunz Jan 23 '15 at 16:10
  • 5
    As you know `Highcharts error #15` is for error in sorting your data. You are assigning your data but not in an ascending order. Please check, maybe double check cause I see lots of these problems because the developer fails to find the problem in their somehow sorted data. – Raein Hashemi Jan 25 '15 at 07:43
  • Problem #15 comes also from **duplicated** data points. For example: `000AAA0G0000000000BK` -> have twice the same interval, `from=> 1417023769000, to=> 1417023848000`. And it looks like you have quite a lot of them.. – Paweł Fus Jan 27 '15 at 16:30
  • @Raeen Hashemi and PawełFus: I sorted `start_time` on server and removed duplicate items in js. Now at least Highcharts error is gone. Thanks. Also is there a way to use [yaxis scalable plugin](http://www.highcharts.com/plugin-registry/single/20/Scalable%20Y-Axis) with angularjs and stockchart? I am using latest Highstock version – AabinGunz Jan 28 '15 at 07:00
  • 4
    If you don't try, then you won't know.. – Paweł Fus Jan 28 '15 at 09:15
  • @PawełFus: I tried using this plugin, but I got `Error: Invalid value for attribute height="NaN" in highstock.js:52` – AabinGunz Jan 28 '15 at 09:38
  • jsFiddle/plunker demo? Maybe plugin isn't compatible with angular at all? Unfortunately I don't know that plugin. – Paweł Fus Jan 28 '15 at 10:13
  • @PawełFus: I have updated [plunker](http://plnkr.co/edit/7GRgqk?p=preview) in my question also – AabinGunz Jan 28 '15 at 11:16
  • For me it seems there is small bug in that plugin, in line #45 should be `bBoxHeight = yAxis.height;` – Paweł Fus Jan 28 '15 at 12:06
  • @RaeenHashemi & Pawel Fus: Any idea on why do I get empty tasks (no line in chart) in a timerange, as that time range should only show tasks which has some run in that duration? – AabinGunz Jan 29 '15 at 06:26
  • Actually I think they have some run in those durations. As you can see, the line colors are mostly different from the dot colors. I think you have sorted your data, but the difference between the values of your data is maybe something near milliseconds and your minimum data range is 1 hour. Therefore the lines are maybe overlapped and showing their names. – Raein Hashemi Jan 29 '15 at 07:22
  • 4
    I have no idea what are you guys talking about, is [that plunker](http://plnkr.co/edit/7GRgqk?p=preview) actual one? This questions is a one big mess. I advice to start with reading & understanding code you have for generating chart. Also, I advice to read some tutorials of Highcharts, just to understand how does it work. – Paweł Fus Jan 29 '15 at 10:09
  • 1
    I run this range and see two tasks, no extra whcich you describe. – Sebastian Bochan Jan 30 '15 at 12:48
  • @SebastianBochan: I have a screenshot attached in my question, it show 2 task runs in green and blue color lines, but I can also see `LILLY_C` task label on yAxis which has no run for that range – AabinGunz Jan 30 '15 at 18:38

1 Answers1

6

So after a few hours of digging, I have just found out the culprit (or I really hope so). The problem is your definition of yAxis label formatter:

yAxis: {
  tickInterval: 1,
    gridLineWidth: 1,
    labels: {
    formatter: function() { // THIS IS THE PROBLEM
      if (tasks[this.value]) {
        return tasks[this.value].name;
      }
    }
  },
  startOnTick: false,
    endOnTick: false,
    title: {
    text: 'Task'
  }
},

You don't actually check if you should display the label according to task.intervals (see json.js). A simple update (Plunker) of the formatter seems to work:

  yAxis: {
    tickInterval: 1,
    gridLineWidth: 1,
    labels: {
      formatter: function () {
        console.log("scripts.js - yAxis.labels.formatter", this.value);
        if (tasks[this.value]) {

          //if (tasks[this.value].name === 'LILLY_C') {
            var _xAxis = this.chart.axes[0];
            var _task = tasks[this.value];
            var _show = false;

            // Not optimized for large collections
            for (var _i = 0; _i < _task.intervals.length; _i++) {
              var _int = _task.intervals[_i];
              if (_xAxis.min <= _int.to) {
                _show = true;
              }
            }

            console.log("scripts.js - yAxis.labels.formatter",
              tasks[this.value].name,
              _show,
              _xAxis.min,
              _xAxis.max,
              _task.intervals
            );

            if (_show) {
              return tasks[this.value].name;
            } else {
              return;
            }
          //}

          //return tasks[this.value].name;
        }
      }
    },
    startOnTick: false,
    endOnTick: false,
    title: {
      text: 'Task'
    }
  },

See Plunker for demo.

Meaning of the yAxis labels is: Show label if you see a run in the graph or if there is a run on the right of the graph. Please modify the condition

if (_xAxis.min <= _int.to) {

as you see fit.

Disclaimer: I don't use Highcharts, so this answer tries to explain the problem and not to suggest a Highcharts-way of solving the problem.


Lessons learned:

  • yaxis-plugin.js is irrelevant to the problem.
  • Highstock.js is an open-source library (highstock.src.js). Any debugging is much easier if you debug original source code. Minified code adds unnecessary complexity and guessing. I have downloaded the library and added some console.log() to find out what is going on.
MartyIX
  • 27,828
  • 29
  • 136
  • 207