I've combined a jquery datepicker widget with jqplot, and am using the values of the datepicker to recreate the plot when something changes.
However, during large date ranges, the labels on the x-axis run together to look very ugly.
Here's it regularly:
Here's it with a large range:
My question is -- is it possible to change the rendering of the axis, so if there is a large range that not every single date shows? Maybe 2 or 3, but always including the beginning date and end date.
Here's my code -- please let me know if you can help!
$(document).ready(function(){
var ajaxDataRenderer = function(url, plot, options) {
var ret = null;
$.ajax({
async: false,
url: url,
type: "GET",
dataType:"json",
data: {metricName: ""},
success: function(data) {
ret = data;
},
error:function (xhr, ajaxOptions, thrownError){
alert(xhr.responseText);
}
});
return ret;
};
//var jsonurl = "reports/reportData.json";
var jsonurl = "tenant/metrics/get.json";
var currentTime = new Date()
var month = currentTime.getMonth() + 1;
var day = currentTime.getDate();
var year = currentTime.getFullYear();
var today = month + "-" + day + "-" + year;
var currentDatePlus = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
var dayPlus = currentDatePlus.getDate()
var monthPlus = currentDatePlus.getMonth() + 1
var yearPlus = currentDatePlus.getFullYear()
var tomorrow = monthPlus + "/" + dayPlus + "/" + yearPlus;
function getLastWeek(){
var today = new Date();
var lastWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7);
return lastWeek ;
}
var lastWeek = getLastWeek();
var lastWeekMonth = lastWeek.getMonth() + 1;
var lastWeekDay = lastWeek.getDate();
var lastWeekYear = lastWeek.getFullYear();
var lastWeekDisplay = lastWeekMonth + "/" + lastWeekDay + "/" + lastWeekYear;
var datepickerBegin = $("#datepicker_start").val();
var datepickerEnd = $("#datepicker_to").val();
$('#applyBtn').click( function() {
// Check to make sure the datepicker isn't empty
if ($("#datepicker_start").val() !== "" && $("#datepicker_to").val() !== "") {
var datepickerBegin = $("#datepicker_start").val();
var datepickerEnd = $("#datepicker_to").val();
//Recreate the plot
var plot2 = $.jqplot('chart2', jsonurl,{
title: "",
dataRenderer: ajaxDataRenderer,
dataRendererOptions: {unusedOptionalUrl: jsonurl},
axes: {
xaxis: {
//'numberTicks' : 7,
min: datepickerBegin,
max: datepickerEnd,
renderer:$.jqplot.DateAxisRenderer,
rendererOptions:{tickRenderer:$.jqplot.CanvasAxisTickRenderer},
tickInterval: '1 day',
tickOptions:{formatString:'%#m/%#d/%Y'
}
//rendererOptions: {sdaTickInterval: [1, 'month']}
},
yaxis: {
label: "MB",
tickOptions:{formatString:'%d '},
// Comment the next line out to allow negative values (and therefore rounded ones)
min: 0
}
},
highlighter: {
show: true,
sizeAdjust: 7.5
}
});
//redraw the plot now.
//plot2.reInitialize({});
plot2.replot({});
}
})
// The default plot
var plot2 = $.jqplot('chart2', jsonurl,{
title: "",
dataRenderer: ajaxDataRenderer,
dataRendererOptions: {unusedOptionalUrl: jsonurl},
axes: {
xaxis: {
//'numberTicks' : 7,
min: lastWeekDisplay,
max: tomorrow,
renderer:$.jqplot.DateAxisRenderer,
rendererOptions:{tickRenderer:$.jqplot.CanvasAxisTickRenderer},
tickInterval: '1 day',
tickOptions:{formatString:'%#m/%#d/%Y'
}
//rendererOptions: {sdaTickInterval: [1, 'month']}
},
yaxis: {
label: "MB",
tickOptions:{formatString:'%d '},
// Comment the next line out to allow negative values (and therefore rounded ones)
min: 0
}
},
highlighter: {
show: true,
sizeAdjust: 7.5
}
});
});
Okay - I've got a better grasp on this issue.
I've limited the tick number using the 'numberTicks' property, so it has a certain number if the date range is over a specificed value.
The only issue left is that, with numberTicks, the intersections aren't always correct (meaning that on the x-axis 10/05/12, the value isn't always placed there when numberTicks is limited.
Related
I want to use anchorBgColor attribute for Real-time Line chart.
Real-time Line chart.
function updateData() {
var t = new Date(),
date =
t.getHours() + ":" + t.getMinutes() + ":" + t.getSeconds(),
val = Math.floor(Math.random() * (7800 - 7200 + 1)) + 7200,
strData = "&label=" + date + "&value=" + val;
// Feed it to chart.
chartRef.feedData(strData);
}
Could you recommend how to change anchorBgColor for this chart?
If you are wanting to have all the points the same color all you have to do is include the anchorBgColor property in the chart object
{
...
dataSource: {
chart: {
...
anchorBgColor: "#26aa5a"
}
}
}
If you want points to change colors as you add them you have manipulate the chart data object and use setJSONData rather than using the feedData method.
<div id="chart-container">FusionCharts will render here</div>
FusionCharts.ready(function() {
var chartObj = new FusionCharts({
type: 'line',
renderAt: 'chart-container',
id: 'myChart',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"theme": "fusion",
"anchorRadius": "6",
"theme": "fusion"
},
"data": []
}
});
chartObj.render();
function pushNewPoint() {
var t = new Date(),
date =
t.getHours() + ":" + t.getMinutes() + ":" + t.getSeconds(),
val = Math.floor(Math.random() * (7800 - 7200 + 1)) + 7200,
randomColor = Math.floor(Math.random()*16777215).toString(16)
newEntry = {
label: date,
value: val,
anchorBgColor: "#" + randomColor
}
chartData = chartObj.getChartData('json')
chartData.data.push(newEntry)
chartObj.setJSONData(chartData)
}
var counter = 0;
var i = setInterval(function(){
pushNewPoint()
counter++;
if(counter === 10) {
clearInterval(i);
}
}, 1000);
});
Example can be seen here
I am trying to include some extra data from my points in the xAxis label of a Highcharts line chart.
I'm creating my points like this. xAxis is 'datetime' type, and I'm using custom tickPositions (this part works fine).
for (row of results) {
var point = {x:Date.parse(row.time), y:row.value, magicNumber:row.ID};
data_series.data.push(point);
chartConfig.xAxis.tickPositions.push(Date.parse(row.time));
}
In the tooltip I'm able to do the following (this works):
tooltip: {
formatter: function() {
return 'ID: ' + this.point.magicNumber + ' Value:' + this.point.y.toFixed(3);
},
},
How do I do the equivalent in the xAxis formatter? Not clear from the docs if this is possible.
xAxis: {
type: 'datetime',
labels: {
rotation: 90,
formatter: function () {
var ID = **What goes here to obtain magicNumber?**
var datetime = new Date(this.value);
return ID.toString() + ' ' + datetime.toISOString();
}
},
tickPositions: []
}
Try this, console.log(this); should give you a hint if my solution doesn't works.
xAxis: {
type: 'datetime',
labels: {
rotation: 90,
formatter: function () {
console.log(this);
var ID = this.chart.series[0].data[this.pos].magicNumber;
var datetime = new Date(this.value);
return ID.toString() + ' ' + datetime.toISOString();
}
},
tickPositions: []
}
Both formatters has different context, so one way out of that is by iterate on every point of your data (inside of the xAxis.labels.formatter function), find the point which has the same x as this.value, and assign it to some variable. It should be enough, but there is a likelihood of a returning empty object, when none of points won't fit to the tick value.
xAxis: {
type: 'datetime',
labels: {
formatter() {
var points = this.chart.userOptions.series[0].data
var sameTimestampPoint = points.filter(p => p.x === this.value)[0]
var magicValue = sameTimestampPoint ? sameTimestampPoint.magicValue : ""
return magicValue + '<br/>' + this.value
}
}
}
Live example: https://jsfiddle.net/2r8z5wny/
I have a problem with a area chart that I have created.
The time in the tooltip does not correspond with the time on the xAxis (se image for example)
The time in the toolstip is right, the xAxis is however shifted two hours behind in time.
Settings for the chart (modified for brevity)
var chart = new Highcharts.Chart({
tooltip: {
dateTimeLabelFormats: {
day:"%A, %b %e, %Y, %H:%M"
},
formatter: function() {
var tt = '',
newDate = new Date(this.key).toLocaleString();
tt = '<b>' + newDate + ':</b> <br/>' + '<b>' + this.series.name + '</b>' + ': ' + this.y;
return tt;
}
},
xAxis: {
type: 'datetime'
}
});
This is how I draw the series:
for (var i = 0; i < newValue.length; i++) {
chart.series[0].addPoint([newValue[i].tValue, newValue[i].value], false, false);
}
newValue[i].tValue is in epoch, for example 1493097600000
In my case setting useUTC to false helped.
Highcharts.setOptions({
global: {
useUTC: false
}
});
I have the datepicker on a modal of twitter bootstrap.
in order to highlight some dates, the datepicker is generated in the 'success'-part as an ajax-call.
I manage to highlight the dates I want to highlight in the current month, which is fine.
But when I toggle to the previous or next month, I would like to make that ajax-call again and render dates to highlight. Below you can see my code:
function nonValidated() {
var date = new Date();
date.addDays(-date.getDate() + 1);
var startDate = [date.getDate().lpad(2), (date.getMonth() + 1).lpad(2), date.getFullYear()].join('/');
var enddate = new Date();
enddate.setDate(date.getDaysInMonth());
var endDate = [enddate.getDate().lpad(2), (enddate.getMonth() + 1).lpad(2), enddate.getFullYear()].join('/');
var depId = $('#serviceSelector').val();
$.ajax({
type: "POST",
url: "/ServiceManagement/GetUnassignedSlots",
data: { "from": startDate, "to": endDate, "depId": depId },
success: function (data) {
$.datepicker.setDefaults(
$.extend(
{ 'dateFormat': 'dd/mm/yy' },
$.datepicker.regional['nl-BE']
)
);
$("#nonValidatedDatepicker").datepicker(
{
inline: true,
beforeShowDay: function (date) {
var theday = date.getDate() + '/' +
(date.getMonth() + 1).lpad(2) + '/' +
date.getFullYear();
return [true, $.inArray(theday, data.result) >= 0 ? "warningDate" : ''];
},
onSelect: function (dateText, inst) {
var dateParts = dateText.split('/');
if (dateParts[0][0] == '0') dateParts[0] = dateParts[0][1];
if (dateParts[1][0] == '0') dateParts[1] = dateParts[1][1];
var newdate = new Date(dateParts[2], dateParts[0]-1, dateParts[1]);
var dayOfWeek = newdate.getDay();
if (dayOfWeek == 0) dayOfWeek = 7;
var weekstart = new Date(newdate.getFullYear(), newdate.getMonth(), newdate.getDate());
weekstart.addDays(-dayOfWeek + 1);
var weekend = new Date(newdate.getFullYear(), newdate.getMonth(), newdate.getDate());
weekend.addDays(7 - dayOfWeek);
$('#SelectWeekDate').val([weekstart.getDate().lpad(2), (weekstart.getMonth() + 1).lpad(2), weekstart.getFullYear()].join('/') + ' - ' + [weekend.getDate().lpad(2), (weekend.getMonth() + 1).lpad(2), weekend.getFullYear()].join('/'));
$('#modalNonValidated').modal('hide');
InitFillPage();
},
onChangeMonthYear: function (year, month, widget) {
}
}
);
},
error: function (data) {
},
statusCode: {
401: function (data) {
//ERROR 401: Unauthenticated
window.location.href = '/Account/Login?ReturnUrl=' + encodeURIComponent(window.location.pathname);
}
}
});
}
anyone an idea how I can combine onchangemonthyear and beforeshowday?
I would split the code that shows the datepicker and the code that makes the ajax call to get the data for the datepicker (the data that determines which days to highlight) into 2 separate functions. You can call the function that makes the ajax call from the function that first shows the datepicker, and again from your onChangeMonthYear function. Also, make sure that the ajax call to get the data is made synchronously (set async: false option) so that the data comes back before your beforeShowDay function runs.
Hope that helps!
I have an issue in that the $.getJSON segment of code works fine and produces a variable called 'zippy'. I need to access 'zippy' under 'series: data' further down in the code.
I have tried a number of things unfortunately I can't make it work. The easiest would be way to 'return data' $.getJSON(jsonUrl,function(zippy) out of the function(zippy) call but I'm lost as to how to make that data available.
$(function() {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var jsonUrl = "http://www.someurl.com/thing.php?callback=?";
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
console.log("++NEED ACCESS HERE FOR ZIPPY++");
console.log(" =============== \r\n");
console.log(" FINAL " + zippy.cpmdata[5].timestamp + " \r\n");
return data;
})()
}]
}
Your problem is that getJSON is asynchronous. What's happening in your code is this:
document.ready is triggered
getJSON is called and registers a callback "function(zippy)"
note that getJSON returns immediately without executing the callback
You try to draw a chart using HighCharts
... several hundred milliseconds later
The browser makes the JSON request
... several hundred milliseconds later
The JSON request returns with data and triggers the
callback to "function(zippy)"
"function(zippy)" is executed
So you see. The problem is not how "function(zippy)" is executed but when it is executed. As such, you cannot execute code that wants to use the return value of the JSON request outside of the callback function. (Actually you can but we'll ignore polling with setTimeout or using synchronous ajax for now)
The solution is to move all the code that you want to run later on inside the callback function:
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
}
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
console.log(" FINAL " + zippy.cpmdata[5].timestamp + " \r\n");
return data;
})()
}]
});
You need to put all of the new Highcharts.Chart({...}) stuff inside the getJSON callback, because you need to wait until the json request completes before creating the chart. See my code comment that says CUT AND PASTE chart = new Highcharts.Chart({...}) STUFF HERE!!!.
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var jsonUrl = "http://www.someurl.com/thing.php?callback=?";
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
// CUT AND PASTE chart = new Highcharts.Chart({...}) STUFF HERE!!!
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
});