Displaying JSON results correctly in Morris Chart - javascript

Am using the following code to display MySQL data in a Morris Chart. All works good EXCEPT if I have TWO or more records on the same day, only shows as ONE in the Morris Chart.
PHP File
$mysqli = mysqli_connect($hostname_membership, $username_membership, $password_membership, $database_membership);
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$query = "SELECT id FROM details WHERE MemberStatus = 'Active' AND PaymentStatus NOT REGEXP 'Not'";
$result = mysqli_query($mysqli,$query);
$total_rows = $result->num_rows;
$array = array();
foreach($mysqli->query('SELECT DateAdded, COUNT(*) FROM details GROUP BY DateAdded') as $row) {
$year = date("Y-m-d",strtotime($row['DateAdded']));
array_push($array,array('Year'=>$year, 'Numb'=>$row['COUNT(*)'],'Total'=>$total_rows));
}
echo json_encode($array);
$mysqli->close();
Morris JS
$.getJSON("js/morris.php", function (json) {
Morris.Area({
element: 'morris-area-chart',
data: json,
xkey: 'Year',
xLabelFormat: function (x) {
var IndexToMonth = [ "Jan", "Feb", "Mar", "Apr", "Mar", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
var month = IndexToMonth[ x.getMonth() ];
var year = x.getFullYear();
return month + ' ' + year;
},
xLabels: 'month',
ykeys: ['Numb','Total'],
labels: ['Signups / Renewals','Total Active Members'],
pointSize: 2,
hideHover: 'auto',
resize: true,
dateFormat: function (x) {
var d = new Date(x);
var MyDateString;
d.setDate(d.getDate());
var monthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
return ("0" + d.getDate()).slice(-2) +' '+monthNames[d.getMonth()]+' '+d.getFullYear();
}
});
return false;
});
And my JSON Output is
[{"Year":"2016-10-27","Numb":"1","Total":11},{"Year":"2016-10-28","Numb":"1","Total":11},{"Year":"2016-10-31","Numb":"1","Total":11},{"Year":"2016-11-02","Numb":"1","Total":11},{"Year":"2016-11-05","Numb":"1","Total":11},{"Year":"2016-11-07","Numb":"1","Total":11},{"Year":"2016-11-08","Numb":"1","Total":11},{"Year":"2016-11-09","Numb":"1","Total":11},{"Year":"2016-11-10","Numb":"1","Total":11},{"Year":"2016-11-10","Numb":"1","Total":11},{"Year":"2016-11-16","Numb":"1","Total":11}]
As you can see from above, the JSON output has two identical records
{"Year":"2016-11-10","Numb":"1","Total":11},{"Year":"2016-11-10","Numb":"1","Total":11}
This is what shows as only ONE record on the Morris Chart. In this case, it's only one person signed up on the 10th Nov 16, when in fact it was TWO...
FYI ONLY - TOTAL is just that - TOTAL number of Signups. Whilst I like to have this as a running total, I can't work that out either. So am not to worried about it, not unless there is a simple solution.
What am I missing?

Have come up with a solution - seems to work - so far....
Replaced
SELECT DateAdded, COUNT(*) FROM details GROUP BY DateAdded
with
SELECT DateAdded, COUNT(*) FROM details GROUP BY DATE_FORMAT(DateAdded,"%Y-%m-%d")
Now just working on a running total...

Related

Creating a unique object on years and months based on array of dates

I am trying to create a unique object of years and months based on an array of dates, see what I mean below:
const availableDates = ["26-01-2022", "30-01-2022", "02-03-2022", "16-04-2022", "01-01-2023"]; // This list will be really long, just an example
I want to create a unique object like below using availableDates but having issues trying to figure it out:
const uniqueDates = {
"2022": ["Jan", "Mar", "Apr"],
"2023": ["Jan"]
};
If you have a better way that I achieve this, please let me know!
Thanks in advance
We can use Array.reduce to create the desired map, and using a Set to ensure we only keep a unique set of months for each year.
const availableDates = ["26-01-2022", "30-01-2022", "02-03-2022", "16-04-2022", "01-01-2023", "01-01-2023"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const uniqueDates = availableDates.reduce((acc, dt) => {
let [day, month, year] = dt.split("-");
acc[year] = [...new Set(acc[year] || []).add(months[month - 1])];
return acc;
}, {})
console.log("Unique object:", uniqueDates)
Maybe something like this:
let month = {
"01" : "Jan",
"02" : "Feb",
"03" : "Mar",
"04" : "Apr",
// ...
};
let res = ["26-01-2022", "30-01-2022", "02-03-2022", "16-04-2022", "01-01-2023"].reduce((acc, el) => {
let arr = el.split("-");
if( acc[arr[2]] && !acc[arr[2]].includes(month[arr[1]])){
acc[arr[2]].push(month[arr[1]])
} else if(!acc[el[2]]){
acc[arr[2]] = [month[arr[1]]]
}
return acc;
}, {})
console.log(res)

Store the first and last day of every month of the year javascript

I need to get the first and last day of every month of the year and set it as an array of objects. I tried the following, but got stuck and unable to get the proper results.
module.exports = function () {
let months_names = ["january","february","march","april","may","june", "july","august","september","october","november","december",
];
let current = new Date();
let month = months_names.map(x => {
return months_names.indexOf(x);
});
const test = {
prev_month_first: new Date(current.getFullYear(), month[0], 1) / 1000 | 0,
prev_month_last: new Date(current.getFullYear(), month[0], 0) / 1000 | 0
}
console.log(test);
const months = [
{
jan_start: "",
jan_end: "",
},
{
feb_start: "",
feb_end: "",
},
{
march_start: "",
march_end: "",
},
{
april_start: "",
april_end: "",
},
{
may_start: "",
may_end: "",
},
{
june_start: "",
june_end: "",
},
{
july_start: "",
july_end: "",
},
{
aug_start: "",
aug_end: "",
},
{
sept_start: "",
sept_end: "",
},
{
oct_start: "",
oct_end: "",
},
{
nov_start: "",
nov_end: "",
},
{
dec_start: "",
dec_end: "",
},
];
return months;
};
The console.log(test) prints the timestamps as { prev_month_first: 1577817000, prev_month_last: 1577730600 }, which equivalents to:
GMT: Tuesday, December 31, 2019 6:30:00 PM
Your time zone: Wednesday, January 1, 2020 12:00:00 AM GMT+05:30
and
GMT: Monday, December 30, 2019 6:30:00 PM
Your time zone: Tuesday, December 31, 2019 12:00:00 AM GMT+05:30
respectively (using epoch time convertor).
I am unable to set the timestamps as per this year for each month correctly.
Please help to get me on track with this.
If I understand your question correctly, you could do something like this:
const monthNames = ["january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december"];
const months = monthNames.map((name, i) => ({
[`${name}_start`]: new Date(new Date().getFullYear(), i, 1),
[`${name}_end`]: new Date(new Date().getFullYear(), i + 1, 0)
}))
console.log(months);

How to map values to arrays according to a pre-defined array which contains the last 12 months

I have an array that contains a couple of hundred trades objects like so:
Input:
[{
"trades": {
"model": "Trades_Information"
"fields": {
"orderCloseTime": "2019-03-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderClosePrice": "1.44000",
"orderProfit": "75",
"orderLots": "1.4"
},
[...]
}]
Now I would like to loop all objects and map the results (some calculations included in the loop) to new arrays which will update an Apexchart.
For me the trickie part right now is to get the correct mapping dynamically to the last 12 months since each new array must contain the values in the correct order according to the last 12 months array which I create as follows:
var date = new Date();
var lastMonths = [],
monthNames = ['Dec', 'Nov', 'Oct', 'Sep', 'Aug', 'Jul', 'Jun', 'May', 'Apr', 'Mar', 'Feb', 'Jan'];
for (var i = 0; i < 12; i++) {
lastMonths.push(monthNames[date.getMonth()]);
date.setMonth(date.getMonth() - 1);
}
console.log(lastMonths);
// ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
So I somehow end up with this brief structure:
// Arrays needed for Apexchart
NetPipsMonth = [];
NetProfitMonth = [];
TotalVolumeMonth = [];
TotalTradesMonth = [];
lastMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
// Loop all trades in trades-object
for (var i = 0; i < tradesTotal; i++) {
// Filter all trades by closed ones
closeTime = trades[i].fields.orderCloseTime;
if (closeTime != null) {
// Make some calculations that output one value per new array per trade object
// Push the results to each array in right order according to lastMonths array
// Mapping with `orderCloseTime`
}
}
I don't know how to realize the mapping by orderCloseTime in order to have the results in the right place within the needed arrays.
My ideas/thoughts in human language:
Define the month of the orderCloseTime for each trade and tell JS which spot in the new arrays is March (example above) using the order of lastMonths and increase it by the result of this particular trade's values to end up with the monthly sum after looping all trade objects.
lastMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
NetProfitMonth = [ , , 75 , , ,];
TotalVolumeMonth = [ , , 1.4 , , ... ,];
Maybe create a nested object and populate this while looping to have all values in one main object and build the needed arrays for apexchart out of this main object after looping is finished
Build 12x4 loops for every month containing each calculation and sum the results afterwards to get monthly sums included in 4 arrays (that would end up in a huge amount of code)
Looking forward to your ideas and enjoy the holidays!
I would approach this differently. I keep my months array as in normal order. (Jan first Dec last). That would make the calculations of the other arrays easier. Get the month from date use it as index to fill the arrays. Then calculate the rotation amount from the current month and then rotate your arrays.
var tradesArr = [{
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-03-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}, {
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-04-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}, {
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-03-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}, {
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-05-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}, {
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-11-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}, {
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-12-19T16:20:56",
"orderOpenPrice": "1.40000",
"orderProfit": "75",
"orderLots": "1.4"
}
}
}];
// taken from https://stackoverflow.com/a/1985471/12354911
Array.prototype.rotate = (function() {
var unshift = Array.prototype.unshift,
splice = Array.prototype.splice;
return function(count) {
var len = this.length >>> 0,
count = count >> 0;
unshift.apply(this, splice.call(this, count % len, len));
return this;
};
})();
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; // use this and keep ordering to later.
// since the size is clear create array with size
// fill them with 0 to claculate easier
NetPipsMonth = Array(12).fill(0);
NetProfitMonth = Array(12).fill(0);
TotalVolumeMonth = Array(12).fill(0);
TotalTradesMonth = Array(12).fill(0);
tradesArr.forEach(t => {
const fields = t.trades.fields;
const ix = new Date(fields.orderCloseTime).getMonth(); // zero indexed month
NetProfitMonth[ix] += +fields.orderProfit;
TotalVolumeMonth[ix] += +fields.orderLots;
// continute
});
// assume we are on may and we want may to be last item in the array
// Date().getMonth() gave us 4 (zero indexed)
const rotation = -((12 - 4)-1); // we need to rotate 7 to the right
months.rotate(rotation);
NetProfitMonth.rotate(rotation);
TotalVolumeMonth.rotate(rotation);
console.log(months, NetProfitMonth, TotalVolumeMonth);
You can indeed create the arrays as you suggest. True, it would be more object oriented to group the three values (month, profit, volume) in one object, but as the apexChart expects individual values in arrays, it makes sense to go directly for that structure.
You can use some splice magic to create the months-array.
let tradesTotal = [{
"trades": {
"model": "Trades_Information",
"fields": {
"orderCloseTime": "2019-03-19T16:20:56",
"orderProfit": "75",
"orderLots": "1.4"
},
}
}];
let now = new Date();
now.setDate(32); // go to next month
now.setDate(1); // set to first of next month
now.setUTCHours(0, 0, 0, 0); // clear time
let firstMonth = now.getMonth();
let lastMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
lastMonths.splice(0, 0, ...lastMonths.splice(firstMonth)); // rotate
let netProfitMonth = Array(12).fill(0);
let totalVolumeMonth = Array(12).fill(0);
let clone = new Date(now);
clone.setFullYear(now.getFullYear()-1);
let minDateString = clone.toJSON().slice(0, 10);
for (let {trades: { fields: { orderCloseTime, orderProfit, orderLots }}} of tradesTotal) {
if (orderCloseTime < minDateString) continue; // not in last 12 months: skip
let month = (orderCloseTime.slice(5, 7) - firstMonth + 11) % 12;
netProfitMonth[month] += +orderProfit;
totalVolumeMonth[month] += +orderLots;
}
console.log(...lastMonths);
console.log(...netProfitMonth);
console.log(...totalVolumeMonth);

CultureInfo in JavaScript

In c# I use the below method in order to get the CultureInfo.
System.Globalization.CultureInfo.CurrentCulture.Name // output :en-US
Can any one tell me how can I get the CultureInfo in JavaScript?
Very easy way is to render it into the view, like this:
<script>
var cultureInfo = '#System.Globalization.CultureInfo.CurrentCulture.Name';
</script>
This is razor syntax, if you use classic asp.net, then use:
<script>
var cultureInfo = '<%= System.Globalization.CultureInfo.CurrentCulture.Name %>';
</script>
This is a very old post an is definately in need of an update. All major browsers now support the navigator property. Simply use
var lang = navigator.language
It depends on your goal. If you want the entire website to be treated as the same culture as your server, you can use System.Globalization.CultureInfo.CurrentCulture.Name only and remove the if-then shorthand within the first code snippet. This is not advisable if you have a global website.
Include the following in the bottom of your page:
<input id="currentCulture" type="hidden" value="<%=((Request.UserLanguages != null && Request.UserLanguages.Length > 0) ? new System.Globalization.CultureInfo(Request.UserLanguages.First(), true).Name : System.Globalization.CultureInfo.CurrentCulture.Name) %>" />
Now you can retrieve the culture info specific to the user, within your javascript, using:
$("#currentCulture").val(); //Jquery
document.getElementById("currentCulture").value; //Pure javascript
Within your code behind, any datetime parsing you require, pass in the culture info provider to the parse and tryparse and Convert.ToDateTime functions by using the below:
CultureInfo info = ((Request.UserLanguages != null && Request.UserLanguages.Length > 0) ? new CultureInfo(Request.UserLanguages.First(), true) : System.Globalization.CultureInfo.CurrentCulture);
Note: if you use Jquery UI and have cultures not included by default (such as en-CA or en-GB), you will have to add them. You can retrieve the code here:
https://code.google.com/p/dobo/source/browse/trunk/dobo/Kooboo.CMS/Kooboo.CMS.Web/Scripts/jquery-ui-i18n/?r=7
You can then include it dynamically by following the below example:
$.datepicker.regional['en-CA'] = { "Name": "en-CA", "closeText": "Close", "prevText": "Prev", "nextText": "Next", "currentText": "Today", "monthNames": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""], "monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""], "dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], "dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], "dayNamesMin": ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], "dateFormat": "dd/mm/yy", "firstDay": 0, "isRTL": false };
$(".datepick").datepicker($.datepicker.setDefaults($.datepicker.regional[$("#currentCulture").val()]));

Dynamically changing Label in Line chart

I am getting the following JSON object from a webserver in response object:
(JSON Array :[{"JUL":"5"},{"AUG":"7"},{"SEP":"9"},{"OCT":"11"},{"NOV":"13"}, {"DEC":"15"},{"JAN":"17"},{"FEB":"19"},{"MAR":"21"},{"APR":"23"},{"MAY":"25"},{"JUN":"27"}])
I am taking keys of the JSON object in an array
var al_key = [];
//For loop for x axis dispaly.
alert("al_key.length --------->"+al_key.length);
var jsonObj = []; //declare array
for (var i = 0; i < al_key.length; i++) {
jsonObj.push({value: i, text: al_key[i].value});
}
// Add axes
chart.addAxis("x", {min:1, max: 12 ,labels: jsonObj , fixLower: "major", microTicks: true, majorTickStep: 1});
chart.addAxis("y", { min: 0, max: 50, vertical: true, fixLower: "major", fixUpper: "major", includeZero: true });
However, it's not working the way I expect it to. Any suggestions as to where I am getting this wrong? Or alternative ways to display months on the x-axis dynamically? Thanks in advance for any help.
Pasted response as a question edit:
Actually i am getting JSONArray Object which contain single JSONObject which contains values like
//Server side coding..
JSONObject object=new JSONObject();
object.put("JAN":"17");
object.put("FEB":"19");
object.put("MAR":"21");
object.put("APR":"23");
object.put("MAY":"24");
object.put("JUN":"27");
JSONArray arrayObj=new JSONArray();
arrayObj.add(object);
On System.out.println(arrayObj); // our json appears like {"JAN":"17"},{"FEB":"19"},{"MAR":"21"},{"APR":"23"}, //{"MAY":"24"},{"JUN":"27"}];
On jsp:
//Call to the database to fetch the desired value
dojo.xhrGet( { url : "/POC/Action.do",
handleAs : "json",
sync: true,
load : function(response, ioArgs) {
alert("retrived response ------"+response);
for(var i in response)
for(var x in response[i])
output.push(response[i][x]);
alert("Get value to draw line chart---------------------->"+output);
},
error: function(response, ioArgs){
dojo.byId("grid").innerHTML = "An error occurred, with response: " + response;
return response;
},
handleAs: "json" });
the response object contain the return value (JSONArray object);
now this key is need to be displayed in the x axis of the chart. Do i need to again get the key and prepare the json object which is formed in the form said above by you..
In reply to your updated information:
Change the way you send the JSON (based on the limited info available,I am assuming is a Java servlet using the org.jon package)
JSONArray array = new JSONArray();
arrayObj.put (new JSONObject("{'month':'JAN', 'value':'17'}");
// and repeat for the rest of the data
You can use it then in your dojo chart as I wrote below (jsonObj3).
Original comment.
Check at the examples here, specially the part:
labels: [{value: 0, text: "zero"},
{value: 2, text: "two"},
{value: 4, text: "four"}
and add the two series
addSeries("Series A", [1, 2, 3, 4, 5], {stroke: {color: "red"}, fill: "lightpink"}).
addSeries("Series B", [5, 4, 3, 2, 1], {stroke: {color: "blue"}, fill: "lightblue"}).
For the series, the JSON might be
var months = ["JUL","AUG","SEP","OCT","NOV","DEC","JAN","FEB","MAR","APR","MAY","JUN"];
var jsonObj2 = [];
for (var i = 0; i < months.length ; i++) {
jsonObj2.push({value: i, text: months[i]});
}
If you want one single JSON object, try arranging it like this:
var data = [{month: "JUL", value:"5"},
{month: "AUG", value:"7"},
{month: "SEP", value:"9"},
{month: "OCT", value:"11"},
{month: "NOV", value:"13"},
{month: "DEC", value:"15"},
{month: "JAN", value:"17"},
{month: "FEB", value:"19"},
{month: "MAR", value:"21"},
{month: "APR", value:"23"},
{month: "MAY", value:"25"},
{month: "JUN", value:"27"}];
var jsonObj3 = [];
for (var i = 0; i < data.length ; i++) {
jsonObj3.push({value: i, text: data[i].month});
}

Categories