Highcharts GANTT Chart Tooltip Mouse-over Tracking

2019-04-17 08:08发布

By default, mouse-over tracking in Highcharts tracks to the closest point on the x-axis. This works well for other types of charts, however, with my GANTT chart [ http://jsfiddle.net/2xkfm87e/11/ ], this results in non-intuitive results for end users. In the sample image below, note that the cursor is closest to the first Category 8 segment. However, point 1 of the Category 4 segment is the closest point on the x-axis and this is the tooltip that is rendered. I need to have the tracking be focused on the y-axis instead so that if the cursor is closest to a point on the y-axis, that tooltip is rendered.

Is this possible? Thanks for your help!

enter image description here

  $(function () {
        // Define tasks
        var tasks = [{
            name: 'Category 1',
            intervals: []
        }, {
            name: 'Category 2',
            intervals: [{ // From-To pairs
                from: Date.UTC(2010,5, 21),
                to: Date.UTC(2015, 5, 21),
                label: 'Category 2',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 3',
            intervals: [{ // From-To pairs
                from: Date.UTC(2011,05,16),
                to: Date.UTC(2012,03,21 ),
                label: 'Category 3',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2013,07,09),
                to: Date.UTC(2015,05,22),
                label: 'Category 3',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 4',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,07,18 ),
                to: Date.UTC(2015,05,22),
                label: 'Category 4',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 5',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,06,17),
                to: Date.UTC(2014,04,21),
                label: 'Category 5',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2015,01,22),
                to: Date.UTC(2015,05,22),
                label: 'Category 5',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 6',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,06,17),
                to: Date.UTC(2014,04,21),
                label: 'Category 6',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2015,01,22),
                to: Date.UTC(2015,05,22),
                label: 'Category 6',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 7',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,06,17),
                to: Date.UTC(2014,04,21),
                label: 'Category 7',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2015,01,22),
                to: Date.UTC(2015,05,22),
                label: 'Category 7',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 8',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,06,17),
                to: Date.UTC(2014,04,21),
                label: 'Category 8',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2015,01,22),
                to: Date.UTC(2015,05,22),
                label: 'Category 8',
                tooltip_data: 'this data'
            }]
        }, {
            name: 'Category 9',
            intervals: [{ // From-To pairs
                from: Date.UTC(2013,06,17),
                to: Date.UTC(2014,04,21),
                label: 'Category 9',
                tooltip_data: 'this data'
            }, {
                from: Date.UTC(2015,01,22),
                to: Date.UTC(2015,05,22),
                label: 'Category 9',
                tooltip_data: 'this data'
            }]
        }];

        // re-structure the tasks into line seriesvar series = [];
        var series = [];
        $.each(tasks.reverse(), function(i, task) {
            var item = {
                name: task.name,
                data: []
            };
            $.each(task.intervals, function(j, interval) {
                item.data.push({
                    x: interval.from,
                    y: i,
                    label: interval.label,
                    from: interval.from,
                    to: interval.to,
                    tooltip_data: interval.tooltip_data

                }, {
                    x: interval.to,
                    y: i,
                    from: interval.from,
                    to: interval.to,
                    tooltip_data: interval.tooltip_data
                });

                // add a null value between intervals
                if (task.intervals[j + 1]) {
                    item.data.push(
                        [(interval.to + task.intervals[j + 1].from) / 2, null]
                    );
                }

            });

            series.push(item);
        });

        // restructure the milestones
        /*$.each(milestones, function(i, milestone) {
            var item = Highcharts.extend(milestone, {
                data: [[
                    milestone.time,
                    milestone.task
                ]],
                type: 'scatter'
            });
            series.push(item);
        });
            */

        // create the chart
        var chart = new Highcharts.Chart({
            chart: {
                renderTo: 'container'
            },

            title: {
                text: 'Category History'
            },

            xAxis: {
                type: 'datetime'
            },

            yAxis: {
                min:0,
                max:8,
                categories: ['Category 9',
                             'Category 8',
                             'Category 7',
                             'Category 6',
                             'Category 5',
                             'Category 4',
                             'Category 3',
                             'Category 2',
                             'Category 1'],
                tickInterval: 1,            
                tickPixelInterval: 200,
                labels: {
                    style: {
                        color: '#525151',
                        font: '12px Helvetica',
                        fontWeight: 'bold'
                    }
                },
                startOnTick: false,
                endOnTick: false,
                title: {
                    text: 'Criteria'
                },
                minPadding: 0.2,
                maxPadding: 0.2,
                   fontSize:'15px'

            },

            legend: {
                enabled: false
            },
            tooltip: {
                formatter: function() {
                    return '<b>'+ tasks[this.y].name + '</b><br/>'+this.point.options.tooltip_data +'<br>' +
                        Highcharts.dateFormat('%m-%d-%Y', this.point.options.from)  +
                        ' - ' + Highcharts.dateFormat('%m-%d-%Y', this.point.options.to); 
                }
            },

            plotOptions: {
                line: {
                    lineWidth: 10,
                    marker: {
                        enabled: false
                    },
                    dataLabels: {
                        enabled: true,
                        align: 'left',
                        formatter: function() {
                            return this.point.options && this.point.options.label;
                        }
                    }
                }
            },

            series: series

        });        

  console.log(series);

   });

2条回答
乱世女痞
2楼-- · 2019-04-17 08:47

It should be already fixed on the master branch: http://jsfiddle.net/2xkfm87e/14/

And fix will be included in the next release. URL to the branch's CDN:

<script src="http://github.highcharts.com/highstock.js"></script>
查看更多
混吃等死
3楼-- · 2019-04-17 08:54

Ok, I got it working. Here are the results for anyone who might follow this path. http://jsfiddle.net/rwsavoy/2xkfm87e/16/ I am still giving credit to @Paweł Fus for this answer because he sent me in the right direction. Thanks Paweł!

Also, this functionality is available as of Highcharts 4.1.5. However, as of this writing, the latest version of Highstocks (2.1.5) does not (From the documentation, Highstocks includes most of Highcharts functionality).

    $(function () {
    /**
     * Highcharts X-range series plugin
     */
    (function (H) {
        var defaultPlotOptions = H.getOptions().plotOptions,
            columnType = H.seriesTypes.column,
            each = H.each;

        defaultPlotOptions.xrange = H.merge(defaultPlotOptions.column, {});
        H.seriesTypes.xrange = H.extendClass(columnType, {
            type: 'xrange',
            parallelArrays: ['x', 'x2', 'y'],
            animate: H.seriesTypes.line.prototype.animate,

            /**
             * Borrow the column series metrics, but with swapped axes. This gives free access
             * to features like groupPadding, grouping, pointWidth etc.
             */  
            getColumnMetrics: function () {
                var metrics,
                    chart = this.chart,
                    swapAxes = function () {
                        each(chart.series, function (s) {
                            var xAxis = s.xAxis;
                            s.xAxis = s.yAxis;
                            s.yAxis = xAxis;
                        });
                    };

                swapAxes();

                this.yAxis.closestPointRange = 1;
                metrics = columnType.prototype.getColumnMetrics.call(this);

                swapAxes();

                return metrics;
            },
            translate: function () {
                columnType.prototype.translate.apply(this, arguments);
                var series = this,
                    xAxis = series.xAxis,
                    yAxis = series.yAxis,
                    metrics = series.columnMetrics;

                H.each(series.points, function (point) {
                    barWidth = xAxis.translate(H.pick(point.x2, point.x + (point.len || 0))) - point.plotX;
                    point.shapeArgs = {
                        x: point.plotX,
                        y: point.plotY + metrics.offset,
                        width: barWidth,
                        height: metrics.width
                    };
                    point.tooltipPos[0] += barWidth / 2;
                    point.tooltipPos[1] -= metrics.width / 2;
                });
            }
        });

        /**
         * Max x2 should be considered in xAxis extremes
         */
        H.wrap(H.Axis.prototype, 'getSeriesExtremes', function (proceed) {
            var axis = this,
                dataMax = Number.MIN_VALUE;

            proceed.call(this);
            if (this.isXAxis) {
                each(this.series, function (series) {
                    each(series.x2Data || [], function (val) {
                        if (val > dataMax) {
                            dataMax = val;
                        }
                    });
                });
                if (dataMax > Number.MIN_VALUE) {
                    axis.dataMax = dataMax;
                }
            }                
        });
    }(Highcharts)); 


var series= [{
   data: [  { 
            name: 'Catergory 1',
            x: Date.UTC(2009,3,15),
            x2: Date.UTC(2015,5,11),
            y:8,        
            tooltip_data:'',
            color:'#f45b5b'     
        } , { 
            name: 'Catergory 2',
            x: Date.UTC(2013,10,12),
            x2: Date.UTC(2014,6,17),
            y:7,        
            tooltip_data:'Catergory 2 A',
            color:'#2b908f'     
        } , { 
            name: 'Catergory 2',
            x: Date.UTC(2014,6,18),
            x2: Date.UTC(2015,5,11),
            y:7,        
            tooltip_data:'',
            color:'#2b908f'     
        } , { 
            name: 'Catergory 3',
            x: Date.UTC(2009,6,21),
            x2: Date.UTC(2015,5,11),
            y:6,        
            tooltip_data:'',
            color:'#e4d354'     
        } , { 
            name: 'Catergory 4',
            x: Date.UTC(2011,8,29),
            x2: Date.UTC(2015,5,11),
            y:5,        
            tooltip_data:'',
            color:'#f15c80'     
        }  , { 
            name: 'Catergory 7',
            x: Date.UTC(2009,3,15),
            x2: Date.UTC(2014,6,17),
            y:2,        
            tooltip_data:'Tooltip Catergory 7 A',
            color:'#90ed7d'     
        } , { 
            name: 'Catergory 7',
            x: Date.UTC(2014,6,18),
            x2: Date.UTC(2015,5,11),
            y:2,        
            tooltip_data:'',
            color:'#90ed7d'     
        } , { 
            name: 'Catergory 8',
            x: Date.UTC(2009,6,16),
            x2: Date.UTC(2015,5,11),
            y:1,        
            tooltip_data:'',
            color:'#434348'     
        } , { 
            name: 'Category 9',
            x: Date.UTC(2009,3,15),
            x2: Date.UTC(2015,5,11),
            y:0,        
            tooltip_data:'',
            color:'#7cb5ec'     
        }] }];


    // THE CHART
    $('#container').highcharts({
        chart: {
            type: 'xrange'
        },
        title: {
            text: 'Category History',
                style: {
                    color: '#525151',
                    font: '20px Helvetica',
                    fontWeight: 'bold'
                }
        },

        xAxis: {
            type: 'datetime',
            dateTimeLabelFormats:{
                month: '%b - %Y'
            }, 
            labels: {
                style: {
                    color: '#525151',
                    font: '12px Helvetica',
                    fontWeight: 'bold'
                }
            },              
            startOnTick: true,
            tickmarkPlacement: 'on',
            tickInterval: 3 * 30 * 24 * 3600 * 1000,
            endOnTick: true,
            minPadding: 0,
            maxPadding: 0,
            gridLineWidth: 1
        },
        yAxis: {
            min:0,
            useHTML: true,
            categories: ['Category 9',
                         'Category 8',
                         'Category 7',
                         'Category 6',
                         'Category 5',
                         'Category 4',
                         'Category 3',
                         'Category 2',
                         'Category 1'],
            tickInterval: 1,            
            tickPixelInterval: 200,
            labels: {
                style: {
                    color: '#525151',
                    font: '12px Helvetica',
                    fontWeight: 'bold'
                }
            },
            startOnTick: false,
            endOnTick: false,
            title: {
                text: 'Criteria',
                style: {
                    color: '#525151',
                    font: '15px Helvetica',
                    fontWeight: 'bold'
                }
            },
            minPadding: 0.2,
            maxPadding: 0.2
        },

        legend: {
            enabled: false
        },
        tooltip: {
            formatter: function() {
                return '<b>'+ this.point.options.name + '</b><br/>' + this.point.options.tooltip_data + '<br>' +
                    Highcharts.dateFormat('%m-%d-%Y', this.point.options.x)  +
                    ' - ' + Highcharts.dateFormat('%m-%d-%Y', this.point.options.x2 )+ '<br>'; 
            }
        },

        plotOptions: {
            series: {
                borderRadius: 5,
                pointWidth: 10,
                colorByPoint: true
            }
        },
        series: series


    });
});
查看更多
登录 后发表回答