Highcharts 范围选择器:更改超出缩放时间范围的日期

Highcharts 范围选择器:更改超出缩放时间范围的日期,highcharts,Highcharts,我构建了一个类似于lazy-loading示例()的图表,但是带有范围选择器的输入字段。 当我放大时,一切都很好。现在,我想通过使用输入字段更改所选范围。 但我无法将输入更改为超出缩放区域的值,尽管我的导航器中有更多可见数据 在setExtremes函数中,我正在进行一些计算: DX.IPFixGraphModule.prototype.setExtremes = function(e) { var fromTime, maxZoom = 30 * 60 * 1000, now

我构建了一个类似于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' }
                );
            }
        }
    };
//处理输入框中的更改
input.onchange=函数(){
var inputValue=input.value,
value=(options.inputDateParser | | Date.parse)(inputValue),
xAxis=chart.xAxis[0],
dataMin=xAxis.dataMin,
dataMax=xAxis.dataMax;
//如果浏览器的Date.parse方法未将该值直接解析为值,
//就像IE中的YYYY-MM-DD一样,尝试用不同的方式解析它
如果(isNaN(值)){
value=inputValue.split('-');
value=Date.UTC(品脱(值[0]),品脱(值[1])-1,品脱(值[2]);
}
如果(!isNaN(值)){
//时区偏移正确(#433)
如果(!defaultOptions.global.useUTC){
value=value+newdate().getTimezoneOffset()*60*1000;
}
//验证极端值。如果超出数据最小值或最大值,请使用
//实际数据极端(#2438)。
if(isMin){
if(值>rangeSelector.maxInput.HCTime){
值=未定义;
}否则如果(值<数据最小值){
值=数据分钟;
}
}否则{
if(值数据最大值){
值=数据最大值;
}
}
//走极端
如果(值!==未定义){
chart.xAxis[0]。setExtremes(
isMin?值:xAxis.min,
isMin?xAxis.max:值,
未定义,
未定义,
{触发器:'rangeSelectorInput'}
);
}
}
};
(代码取自第21126行附近的highstock.src.js)

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

可能的解决办法 我通过在“afterSetExtremes”事件中检查导航器范围来解决这个问题

DX.IPFixGraphModule.prototype.afterSetExtremes=函数(e){
如果(例如触发器=='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;
如果(从时间<最小值){
fromTime=最小值;
}
如果(toTime>maxValue){
toTime=最大值;
}   
this.stockchart.xAxis[0].setextrems(fromTime,toTime);
}否则{
有时,
toTime;
如果(e.min){
fromTime=e.min;
}否则{
fromTime=e.dataMin;
}
fromTime=Math.round(fromTime);
如果(e.max){
toTime=e.max;
}否则{
toTime=e.dataMax;
}
toTime=数学四舍五入(toTime);
this.settings.afterSetExtremes({startTimestamp:fromTime,endTimestamp:toTime});
}
};

或者参阅下面的解决方案并重写该方法。

没有默认的API。通过重写drawInput函数(第二个代码段)扩展Highcharts

您应该注释掉或删除代码的一部分-以下内容后的
if
子句:

//验证极端。如果超出数据最小值或最大值,请使用

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

例如:

$(函数(){
(职能(H){
H.wrap(H.RangeSelector.prototype,'drawInput',函数(继续){
变量名称=参数[1],
merge=H.merge,
createElement=H.createElement,
前缀='highcharts-',
绝对值=‘绝对值’,
PX='PX',
extend=H.extend,
品脱=高品脱,
未定义;
//drawInput:函数(名称){
var rangeSelector=这个,
chart=rangeSelector.chart,
chartStyle=chart.renderer.style,
renderer=chart.renderer,
选项=chart.options.rangeSelector,
defaultOptions=H.getOptions(),
lang=defaultOptions.lang,
div=rangeSelector.div,
isMin=name=='min',
输入,
标签,
日期框,
inputGroup=this.inputGroup;
//创建文本标签
此[name+'Label']=Label=renderer.Label(lang[isMin?'rangeSelectorFrom':'rangeSelectorTo'],此.inputGroup.offset)
艾特先生({
填充:2
})
.css(合并(图表样式、选项、标签样式))
.add(输入组);
inputGroup.offset+=标签宽度+5;
//创建一个SVG标签,显示更新的日期范围和记录,并单击
//引入HTML输入。
此[name+'DateBox']=DateBox=renderer.label(“”,inputGroup.offset)
艾特先生({
填充:2,
宽度:options.inputBoxWidth | | 90,
高度:options.in
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});
}
};
$(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
                }
            }]
        });
    });
});