rangeSelector:更改日期超出缩放时间范围

时间:2015-07-14 11:10:05

标签: highcharts

我构建了一个类似于延迟加载示例(http://www.highcharts.com/stock/demo/lazy-loading)的图表,但是具有范围选择器的输入字段。 当我放大一切都很好。现在我想使用输入字段更改所选范围。 但是我无法将输入更改为超出缩放区域的值,尽管我的导航器中有更多数据可见。

在setExtremes函数中,我正在做一些计算:

DX.IPFixGraphModule.prototype.setExtremes = function(e) {
var fromTime,
    maxZoom = 30 * 60 * 1000,
    now = new Date().getTime();
if (e.min) {
    fromTime = e.min;
} else {
    fromTime = e.dataMin;
}
fromTime = Math.round(fromTime);

var diff = now - fromTime;
// -1 month = max 1 week zoom
if (diff >= 2592000000) {
    maxZoom = 7 * 24 * 60 * 60 * 1000;
}
// -1 week = max 12 hour zoom 
else if (diff >= 604800000) {
    maxZoom = 12 * 60 * 60 * 1000;
}

// this refers to axis
// @see http://api.highcharts.com/highstock#Axis.update
this.update({
    minRange: maxZoom
}, false);  

};

但是我在e.min和e.max中收到的值不是原始输入值,而是已经校正到显示的时间范围。

// handle changes in the input boxes
    input.onchange = function () {
        var inputValue = input.value,
            value = (options.inputDateParser || Date.parse)(inputValue),
            xAxis = chart.xAxis[0],
            dataMin = xAxis.dataMin,
            dataMax = xAxis.dataMax;

        // If the value isn't parsed directly to a value by the browser's Date.parse method,
        // like YYYY-MM-DD in IE, try parsing it a different way
        if (isNaN(value)) {
            value = inputValue.split('-');
            value = Date.UTC(pInt(value[0]), pInt(value[1]) - 1, pInt(value[2]));
        }

        if (!isNaN(value)) {

            // Correct for timezone offset (#433)
            if (!defaultOptions.global.useUTC) {
                value = value + new Date().getTimezoneOffset() * 60 * 1000;
            }

            // Validate the extremes. If it goes beyound the data min or max, use the
            // actual data extreme (#2438).
            if (isMin) {
                if (value > rangeSelector.maxInput.HCTime) {
                    value = UNDEFINED;
                } else if (value < dataMin) {
                    value = dataMin;
                }
            } else {
                if (value < rangeSelector.minInput.HCTime) {
                    value = UNDEFINED;
                } else if (value > dataMax) {
                    value = dataMax;
                }
            }

            // Set the extremes
            if (value !== UNDEFINED) {
                chart.xAxis[0].setExtremes(
                    isMin ? value : xAxis.min,
                    isMin ? xAxis.max : value,
                    UNDEFINED,
                    UNDEFINED,
                    { trigger: 'rangeSelectorInput' }
                );
            }
        }
    };

(代码取自第21126行的highstock.src.js)

所以我无法将缩放扩展到当前活动选择之外,但导航器会显示更多数据。 有没有人知道如何设置超出当前缩放时间范围的日期?

可能的解决方案

我通过检查&#34; afterSetExtremes&#34;中的导航器范围来解决它。事件

DX.IPFixGraphModule.prototype.afterSetExtremes = function(e) {
if (e.trigger === 'rangeSelectorInput') {
    var fromValue = this.stockchart.rangeSelector.minInput.value,
        toValue = this.stockchart.rangeSelector.maxInput.value,
        fromTime = parseDateTime(fromValue),
        toTime = parseDateTime(toValue),
        navigatorAxis = this.stockchart.get('navigator-x-axis'),
        maxValue = navigatorAxis.dataMax,
        minValue = navigatorAxis.dataMin;

    if (fromTime < minValue) {
        fromTime = minValue;
    }
    if (toTime > maxValue) {
        toTime = maxValue;
    }   
    this.stockchart.xAxis[0].setExtremes(fromTime, toTime);
} else {
    var fromTime,
        toTime;
    if (e.min) {
        fromTime = e.min;
    } else {
        fromTime = e.dataMin;
    }
    fromTime = Math.round(fromTime);

    if (e.max) {
        toTime = e.max;
    } else {
        toTime = e.dataMax;
    }
    toTime = Math.round(toTime);
    this.settings.afterSetExtremes({startTimestamp: fromTime, endTimestamp: toTime});
}
};

或者查看下面的解决方案并覆盖该方法。

1 个答案:

答案 0 :(得分:1)

没有默认的API。通过覆盖drawInput函数(第二个代码片段)来扩展Highcharts。

您应该注释或删除一部分代码 - if子句:

  

//验证极端情况。如果数据最小或最大,请使用

     

//实际数据极端(#2438)。

示例:http://jsfiddle.net/epL7awo4/1/

$(function () {
    (function (H) {
        H.wrap(H.RangeSelector.prototype, 'drawInput', function (proceed) {
            var name = arguments[1],
                merge = H.merge,
                createElement = H.createElement,
                PREFIX = 'highcharts-',
                ABSOLUTE = 'absolute',
                PX = 'px',
                extend = H.extend,
                pInt = H.pInt,
                UNDEFINED;
            //drawInput: function (name) {
            var rangeSelector = this,
                chart = rangeSelector.chart,
                chartStyle = chart.renderer.style,
                renderer = chart.renderer,
                options = chart.options.rangeSelector,
                defaultOptions = H.getOptions(),
                lang = defaultOptions.lang,
                div = rangeSelector.div,
                isMin = name === 'min',
                input,
                label,
                dateBox,
                inputGroup = this.inputGroup;

            // Create the text label
            this[name + 'Label'] = label = renderer.label(lang[isMin ? 'rangeSelectorFrom' : 'rangeSelectorTo'], this.inputGroup.offset)
                .attr({
                padding: 2
            })
                .css(merge(chartStyle, options.labelStyle))
                .add(inputGroup);
            inputGroup.offset += label.width + 5;

            // Create an SVG label that shows updated date ranges and and records click events that 
            // bring in the HTML input.
            this[name + 'DateBox'] = dateBox = renderer.label('', inputGroup.offset)
                .attr({
                padding: 2,
                width: options.inputBoxWidth || 90,
                height: options.inputBoxHeight || 17,
                stroke: options.inputBoxBorderColor || 'silver',
                    'stroke-width': 1
            })
                .css(merge({
                textAlign: 'center',
                color: '#444'
            }, chartStyle, options.inputStyle))
                .on('click', function () {
                rangeSelector.showInput(name); // If it is already focused, the onfocus event doesn't fire (#3713)
                rangeSelector[name + 'Input'].focus();
            })
                .add(inputGroup);
            inputGroup.offset += dateBox.width + (isMin ? 10 : 0);


            // Create the HTML input element. This is rendered as 1x1 pixel then set to the right size 
            // when focused.
            this[name + 'Input'] = input = createElement('input', {
                name: name,
                className: PREFIX + 'range-selector',
                type: 'text'
            }, extend({
                position: ABSOLUTE,
                border: 0,
                width: '1px', // Chrome needs a pixel to see it
                height: '1px',
                padding: 0,
                textAlign: 'center',
                fontSize: chartStyle.fontSize,
                fontFamily: chartStyle.fontFamily,
                top: chart.plotTop + PX // prevent jump on focus in Firefox
            }, options.inputStyle), div);

            // Blow up the input box
            input.onfocus = function () {
                rangeSelector.showInput(name);
            };
            // Hide away the input box
            input.onblur = function () {
                rangeSelector.hideInput(name);
            };

            // handle changes in the input boxes
            input.onchange = function () {
                var inputValue = input.value,
                    value = (options.inputDateParser || Date.parse)(inputValue),
                    xAxis = chart.xAxis[0],
                    dataMin = xAxis.dataMin,
                    dataMax = xAxis.dataMax;

                // If the value isn't parsed directly to a value by the browser's Date.parse method,
                // like YYYY-MM-DD in IE, try parsing it a different way
                if (isNaN(value)) {
                    value = inputValue.split('-');
                    value = Date.UTC(pInt(value[0]), pInt(value[1]) - 1, pInt(value[2]));
                }

                if (!isNaN(value)) {

                    // Correct for timezone offset (#433)
                    if (!defaultOptions.global.useUTC) {
                        value = value + new Date().getTimezoneOffset() * 60 * 1000;
                    }

                    // Validate the extremes. If it goes beyound the data min or max, use the
                    // actual data extreme (#2438).
                    /* if (isMin) {
                        if (value > rangeSelector.maxInput.HCTime) {
                            value = UNDEFINED;
                        } else if (value < dataMin) {
                            value = dataMin;
                        }
                    } else {
                        if (value < rangeSelector.minInput.HCTime) {
                            value = UNDEFINED;
                        } else if (value > dataMax) {
                            value = dataMax;
                        }
                    }*/

                    // Set the extremes
                    if (value !== UNDEFINED) {
                        chart.xAxis[0].setExtremes(
                        isMin ? value : xAxis.min,
                        isMin ? xAxis.max : value,
                        UNDEFINED,
                        UNDEFINED, {
                            trigger: 'rangeSelectorInput'
                        });
                    }
                }
            };
            //},
        });
    }(Highcharts));


    /**
     * Load new data depending on the selected min and max
     */
    function afterSetExtremes(e) {

        var chart = $('#container').highcharts();

        chart.showLoading('Loading data from server...');
        $.getJSON('http://www.highcharts.com/samples/data/from-sql.php?start=' + Math.round(e.min) +
            '&end=' + Math.round(e.max) + '&callback=?', function (data) {

            chart.series[0].setData(data);
            chart.hideLoading();
        });
    }

    // See source code from the JSONP handler at https://github.com/highslide-software/highcharts.com/blob/master/samples/data/from-sql.php
    $.getJSON('http://www.highcharts.com/samples/data/from-sql.php?callback=?', function (data) {

        // Add a null value for the end date
        data = [].concat(data, [
            [Date.UTC(2011, 9, 14, 19, 59), null, null, null, null]
        ]);

        // create the chart
        $('#container').highcharts('StockChart', {
            chart: {
                type: 'candlestick',
                zoomType: 'x'
            },

            navigator: {
                adaptToUpdatedData: false,
                series: {
                    data: data
                }
            },

            scrollbar: {
                liveRedraw: false
            },

            title: {
                text: 'AAPL history by the minute from 1998 to 2011'
            },

            subtitle: {
                text: 'Displaying 1.7 million data points in Highcharts Stock by async server loading'
            },

            rangeSelector: {
                buttons: [{
                    type: 'hour',
                    count: 1,
                    text: '1h'
                }, {
                    type: 'day',
                    count: 1,
                    text: '1d'
                }, {
                    type: 'month',
                    count: 1,
                    text: '1m'
                }, {
                    type: 'year',
                    count: 1,
                    text: '1y'
                }, {
                    type: 'all',
                    text: 'All'
                }],
                inputEnabled: true,
                selected: 4 // all
            },

            xAxis: {
                events: {
                    afterSetExtremes: afterSetExtremes
                },
                minRange: 3600 * 1000 // one hour
            },

            yAxis: {
                floor: 0
            },

            series: [{
                data: data,
                dataGrouping: {
                    enabled: false
                }
            }]
        });
    });
});