预期行为
即使内容已放大或缩小,特定日期的工具提示内容也应保持不变。
实际行为
当图表放大并缩小时,同一天的工具提示内容会有所不同。
现场演示,包含重现步骤
https://jsfiddle.net/aveohsdr/8/
Github问题链接
https://github.com/highcharts/highcharts/issues/6241
受影响的浏览器
Firefox / Chrome
描述
检查2016年6月4日的工具提示内容,然后从范围选择器更改日期,即2016年6月1日至2016年6月30日,鼠标悬停至6月4日工具提示,现在工具提示具有不同的内容。我的代码有问题,或者可能是在Highchart的最后,我无法弄清楚是什么。
代码低于
var seriesOptions = [];
$(function() {
var html = '';
var groupingButtons = {
"Day": "day",
"Week": "week",
"Month":"month",
"3M":"quater",
"6M":"half"
};
for (var i in groupingButtons) {
html += '<button class="btn btn-default dateWiseCriteria" data-criteria="' + groupingButtons[i] + '">' + i + '</button>';
}
$('.dateWiseCriteriaContainer').html(html);
var options = {};
$.extend(options, {
units: [
['week', [1]]
]
});
drawAnalyticalStockChart(getSeries(), options);
$(document).on('click', '.dateWiseCriteria', function() {
var options = {};
var criteria = $(this).data('criteria') == 'quater' ? 'month' : $(this).data('criteria');
criteria = $(this).data('criteria') == 'half' ? 'month' : criteria;
var value = $(this).data('criteria') == 'quater' ? 3 : 1;
value = $(this).data('criteria') == 'half' ? 6 : value;
$.extend(options, {
units: [
[criteria, [value]]
]
});
drawAnalyticalStockChart(getSeries(), options);
});
});
function drawAnalyticalStockChart(series, options) {
Highcharts.stockChart('container', {
chart: {
zoomType: 'x',
},
credits: {
enabled: false
},
rangeSelector: {
selected: 4
},
legend: {
enabled: true
},
scrollbar: {
showFull: false
},
xAxis: [{
crosshair: true,
}],
yAxis: [{ // Primary yAxis
type: 'datetime',
dateTimeLabelFormats: { //force all formats to be hour:minute:second
second: '%H:%M:%S',
minute: '%H:%M:%S',
hour: '%H:%M:%S',
day: '%H:%M:%S',
week: '%H:%M:%S',
month: '%H:%M:%S',
year: '%H:%M:%S'
},
labels: {
formatter: function() {
//get the timestamp
var time = this.value;
return _format_date(time, 1);
//now manipulate the timestamp as you wan using data functions
},
style: {
color: Highcharts.getOptions().colors[2]
},
x: 42
},
title: {
text: 'Average Resolution Time',
style: {
color: Highcharts.getOptions().colors[2]
},
margin: 53
},
opposite: true
}, { // Secondary yAxis
gridLineWidth: 0,
title: {
text: 'Cases',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value} Cases',
style: {
color: Highcharts.getOptions().colors[0]
}
},
allowDecimals: false,
opposite: false
}, { // Tertiary yAxis
gridLineWidth: 0,
title: {
text: 'Average Response Time',
style: {
color: Highcharts.getOptions().colors[3]
}
},
labels: {
formatter: function() {
//get the timestamp
var time = this.value;
return _format_date(time, 0, 1);
//now manipulate the timestamp as you wan using data functions
},
style: {
color: Highcharts.getOptions().colors[3]
}
},
type: 'datetime',
dateTimeLabelFormats: { //force all formats to be hour:minute:second
second: '%H:%M:%S',
minute: '%H:%M:%S',
hour: '%H:%M:%S',
day: '%H:%M:%S',
week: '%H:%M:%S',
month: '%H:%M:%S',
year: '%H:%M:%S'
},
}],
tooltip: {
formatter: function() {
var points = this.points;
var groupingFormat = points[0].series.options.dataGrouping.dateTimeLabelFormats[points[0].series.currentDataGrouping.unitName][0];
var headerFormat = '<span style="font-size: 10px">' + Highcharts.dateFormat(groupingFormat, this.x) + '</span><br/>';
var pointFormat = '',
currentYear;
var isAllPointsHaveData = [];
points.forEach(function(point) {
if(point.y > 0) {
isAllPointsHaveData.push(1);
}
});
points.forEach(function(point) {
var name = point.series.name,
part;
var finalValue = point.y;
var showOnTooltip = true;
if (name === 'Current Year') {
currentYear = part = new Date(point.x).getFullYear();
} else if (name === 'Previous Year') {
part = new Date(point.x).getFullYear() - 1
} else if (name === 'Average Response Time') {
finalValue = _format_date(point.y, 0, 1, 1);
part = (typeof currentYear !== 'undefined' ? name + ' ('+currentYear+')' : name );
} else {
finalValue = _format_date(point.y, 1, 1, 1);
part = (typeof currentYear !== 'undefined' ? name + ' ('+currentYear+')' : name );
}
if(!$.isEmptyObject(isAllPointsHaveData)) {
pointFormat += '<span style="color:' + point.color + '">\u25CF</span> <p style="color:' + point.color + '">' + part + '</p>: <b>' + finalValue + ' ' + point.series.tooltipOptions.valueSuffix + '</b><br/>';
}
});
return headerFormat + pointFormat;
},
},
plotOptions: {
series: {
showInNavigator: true,
dataGrouping: {
dateTimeLabelFormats: {
millisecond: ['%A, %b %e, %H:%M:%S.%L', '%A, %b %e, %H:%M:%S.%L', '-%H:%M:%S.%L'],
second: ['%A, %b %e, %H:%M:%S', '%A, %b %e, %H:%M:%S', '-%H:%M:%S'],
minute: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
hour: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
day: ['%A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
week: ['Week from %A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
month: ['%B %Y', '%B', '-%B %Y'],
year: ['%Y', '%Y', '-%Y']
},
enabled: true,
forced: true,
units: options.units,
smoothed: true,
}
}
},
series: getSeries()
});
}
function getSeries() {
seriesOptions = [{
name: 'Previous Year',
type: 'column',
yAxis: 1,
tooltip: {
valueSuffix: ' Case(s)',
},
data: [],
"dataGrouping": {
"approximation": "sum"
},
"color": "#8085E9"
}, {
name: 'Current Year',
type: 'column',
yAxis: 1,
tooltip: {
valueSuffix: ' Case(s)',
},
data: [],
"dataGrouping": {
"approximation": "sum"
},
"color": "#F45B5B"
}, {
name: 'Average Response Time',
type: 'spline',
yAxis: 2,
tooltip: {
valueSuffix: '',
},
data: [],
"dataGrouping": {
approximation: function(arr) {
var groupedData = [];
var xyDataWithTimestamps = [];
var t = this;
this.xData.forEach(function(xd, i) {
xyDataWithTimestamps.push([
xd,
t.yData[i]
]);
});
var groupedDataWithTimestamps = [];
for(var i in arr) {
var arr1 = jQuery.grep(xyDataWithTimestamps, function( a ) {
return a[1] == arr[i];
});
groupedDataWithTimestamps.push([
arr1[0][0],
arr1[0][1]
]);
}
var len = arr.length;
var seconds = [], cases = [];
var finalArrayWithData = [];
for(var i in groupedDataWithTimestamps) {
if(groupedDataWithTimestamps[i][1] > 0) {
var date = _format_date(arr[i], 1, 1, 1, true);
seconds.push((((date.d * 24) * 60) * 60) + ((date.h * 60) * 60) + (date.m * 60));
var arr2 = jQuery.grep(seriesOptions[1].data, function( a ) {
return a[0] == groupedDataWithTimestamps[i][0];
});
cases.push(arr2[0][1]);
finalArrayWithData['s'] = seconds;
finalArrayWithData['cases'] = cases;
}
}
var sumTopS = 0;
var sumBottom = 0;
console.log(finalArrayWithData);
for (var i in finalArrayWithData['cases']) {
if(finalArrayWithData['s'][i] > 0) {
sumTopS += finalArrayWithData['cases'][i] * finalArrayWithData['s'][i];
sumBottom += finalArrayWithData['cases'][i];
}
}
var averageS = 0;
if ($.isNumeric(sumTopS) && sumBottom) {
averageS = Math.round(sumTopS / sumBottom);
}
_dts = Date.UTC(1970, 0, 1, 0, 0, averageS) / 1000;
return _dts;
}
},
"color": "#8BA6C7"
}];
return seriesOptions;
}
function _format_date(ts, d = 0, h = 0, m = 0, getArray = false) {
var date_now = 0;
var label = '';
var date_future = ts * 1000;
var dateArray = [];
// get total seconds between the times
var delta = Math.abs(date_future - date_now) / 1000;
// calculate (and subtract) whole days
var days = Math.floor(delta / 86400);
var finalValue = '';
if (d) {
label = days > 1 ? ' days ' : ' day ';
dateArray['d'] = days;
finalValue += days + label;
}
delta -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(delta / 3600) % 24;
if (h) {
if (d == 0) {
var totalHours = hours + (days * 24);
label = totalHours > 1 ? ' hours ' : ' hour ';
dateArray['h'] = totalHours;
finalValue += totalHours + label;
} else {
label = hours > 1 ? ' hours ' : ' hour ';
dateArray['h'] = hours;
finalValue += hours + label;
}
}
// calculate (and subtract) whole minutes
var minutes = Math.floor(delta / 60) % 60;
delta -= minutes * 60;
if (m) {
label = minutes > 1 ? ' minutes ' : ' minute ';
dateArray['m'] = minutes;
finalValue += minutes + label;
}
if(getArray) {
return dateArray;
}
return finalValue;
}