How to make morris donut chart with ajax json? - javascript

How to make morris donut chart with ajax json ?
this is my code :
$(function() {
$.ajax({
url : 'dashboard/total-data',
}).done(function(data){
initDonut(JSON.parse(data));
console.log(data);
}).fail(function(){
});
var initDonut = function(data){
return Morris.Donut({
element: 'morris-donut-chart',
data: [ data ],
// data: [
// {label: "BMW", value: 4},
// {label: "Mercy", value: 0},
// {label: "Ferrari", value: 0},
// {label: "Toyota", value: 3},
// {label: "Porsche", value: 0},
// {label: "Limosin", value: 0},
// {label: "Lamborgini", value: 3} ],
resize: true,
colors: ['#87d6c6', '#54cdb4','#1ab394', '#54cdb4','#1ab394', '#54cdb4','#1ab394'],
});
} });
Ajax code above return data format like this:
{"BMW":4,"Mercy":0,"Ferrari":0,"Toyota":3,"Porsche":0,"Limosin":0,"Lamborgini":3}
my question,
How to make format data above become like this with javascript?
[ {label: "BMW", value: 4},{label: "Mercy", value: 0},{label: "Ferrari", value: 0},{label: "Toyota", value: 3},{label: "Porsche", value: 0},{label: "Limosin", value: 0},{label: "Lamborgini", value: 3} ]
This is code for show json:
public function total_data()
{
$data['BMW'] = $this->m_dashboard->get_total_product_bmw();
$data['Mercy'] = $this->m_dashboard->get_total_product_mercy();
echo json_encode($data);
$data['Ferrari'] = $this->m_dashboard->get_total_product_ferrari();
$data['Toyota'] = $this->m_dashboard->get_total_product_toyota();
$data['Porsche'] = $this->m_dashboard->get_total_product_porsche();
$data['Limosin'] = $this->m_dashboard->get_total_product_limosin();
$data['Lamborgini'] = $this->m_dashboard->get_total_product_lamborgini();
echo json_encode($data);
}

You need to change code of total-data like below:-
public function total_data()
{
$data[0]['label']= 'BMW';
$data[0]['value']= $this->m_dashboard->get_total_product_bmw();
$data[1]['label']= 'Mercy';
$data[1]['value']= $this->m_dashboard->get_total_product_mercy();
$data[2]['label']= 'Ferrari';
$data[2]['value']= $this->m_dashboard->get_total_product_ferrari();
$data[3]['label']= 'Toyota';
$data[3]['value']= $this->m_dashboard->get_total_product_toyota();
$data[4]['label']= 'Porsche';
$data[4]['value']= $this->m_dashboard->get_total_product_porsche();
$data[5]['label']= 'Limosin';
$data[5]['value']= $this->m_dashboard->get_total_product_limosin();
$data[6]['label']= 'Lamborgini';
$data[6]['value']= $this->m_dashboard->get_total_product_lamborgini();
echo json_encode($data);
}
jQuery code need to be:-
$(function() {
$.ajax({
url : 'dashboard/total-data',
}).done(function(data){
Morris.Donut({
element: 'morris-donut-chart',
data: JSON.parse(data),
resize: true,
colors: ['#87d6c6', '#54cdb4','#1ab394', '#54cdb4','#1ab394', '#54cdb4','#1ab394']
});
}).fail(function(){
});
});
Working at my end:- http://prntscr.com/f6399z

It seems like the question is mostly, how do I get from
{key: foo, key2:bar}
to
[{label: key, value:foo},{label: key2, value:bar}]
I'm a huge fan of libraries like lodash and ramda. If you had Ramda available I would recommend something like:
var input = {
"BMW": 4,
"Mercy": 0,
"Ferrari": 0,
"Toyota": 3,
"Porsche": 0,
"Limosin": 0,
"Lamborgini": 3
}
var expected = [{
label: "BMW",
value: 4
}, {
label: "Mercy",
value: 0
}, {
label: "Ferrari",
value: 0
}, {
label: "Toyota",
value: 3
}, {
label: "Porsche",
value: 0
}, {
label: "Limosin",
value: 0
}, {
label: "Lamborgini",
value: 3
}]
// First thing we want is to group the key and value together
var pairs = R.toPairs(input);
// This gives us something like
// [["BMW",4],["Mercy",0],...]
// This is getting a little far to explain here but Ramda
// curries all it's functions so we can pass the labels
// here and then the pairs later.
var label = R.zipObj(["label", "value"]);
// Here we map the label function over each set of pairs
var output = pairs.map(label);
tape('Same?', t => {
t.deepEqual(expected, output);
t.end();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.min.js"></script>
<script src="https://wzrd.in/standalone/tape#latest"></script>
Otherwise, you could do something in a for loop.
var input = {
"BMW": 4,
"Mercy": 0,
"Ferrari": 0,
"Toyota": 3,
"Porsche": 0,
"Limosin": 0,
"Lamborgini": 3
}
var expected = [{
label: "BMW",
value: 4
}, {
label: "Mercy",
value: 0
}, {
label: "Ferrari",
value: 0
}, {
label: "Toyota",
value: 3
}, {
label: "Porsche",
value: 0
}, {
label: "Limosin",
value: 0
}, {
label: "Lamborgini",
value: 3
}]
var output = [];
for (var k in input) {
output.push({"label": k, "value": input[k]});
}
tape('Same?', t => {
t.deepEqual(expected, output);
t.end();
});
<script src="https://wzrd.in/standalone/tape#latest"></script>

Related

Javascript grouping

How can I add data by grouping with country label and create data array that has 12 index indicating months and containing value of data before grouping.
I need help, how to push and group the data according to the month number. e.x
arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
now i need the results to be like
[
{ label: 'US', data: [10,60,2,0,0,0,0,0,0,0,0,0] },
{ label: 'UK', data: [0,0,0,0,10,0,0,0,0,0,0,0] },
{ label: 'SA', data: [1,0,0,0,0,0,0,0,0,0,0,10] },
{ label: 'CA', data: [70,0,0,0,0,0,0,0,0,0,0,0] },
];
Create a new object by reducing over the array using the labels as object keys, and initialising the property value as an object with a label, and a pre-filled array of zeros. Then update the array with the data at the relevant position.
const arr=[{label:"US",data:"10",monthNumber:1},{label:"US",data:"2",monthNumber:3},{label:"US",data:"60",monthNumber:2},{label:"UK",data:"10",monthNumber:5},{label:"SA",data:"1",monthNumber:1},{label:"CA",data:"70",monthNumber:1},{label:"SA",data:"10",monthNumber:12}];
function grouper(arr) {
// `reduce` over the array passing in an
// empty object as the initial accumulator value
const out = arr.reduce((acc, c) => {
// Destructure the properties from the current
// iterated object
const { label, data, monthNumber } = c;
// If the label doesn't exist as a key on the object
// create it, and assign an object as its value, using
// the label, and adding a pre-filled array of zeros to
// its data property
acc[label] ??= { label, data: new Array(12).fill(0) };
// Update the data array with the data value at the
// appropriate position
acc[label].data[monthNumber - 1] = Number(data);
// Return the accumulator for the next iteration
return acc;
}, {});
// Finally get the array of updated objects
// from the accumulated data
return Object.values(out);
}
console.log(grouper(arr));
Additional documentation
Logical nullish assignment
fill
Object.values
For grouping, you could make use of reduce
const arr = [
{ label: "US", data: "10", monthNumber: 1 },
{ label: "US", data: "2", monthNumber: 3 },
{ label: "US", data: "60", monthNumber: 2 },
{ label: "UK", data: "10", monthNumber: 5 },
{ label: "SA", data: "1", monthNumber: 1 },
{ label: "CA", data: "70", monthNumber: 1 },
{ label: "SA", data: "10", monthNumber: 12 },
]
let res = arr.reduce((acc, { label, monthNumber, data }) => {
if (!acc[label]) acc[label] = Array(12).fill(0)
acc[label][monthNumber - 1] = Number(data)
return acc
}, {})
res = Object.entries(res).map(([label, data]) => ({ label, data }))
console.log(res)
First I have extracted the label from the current array.
After that, I have a loop through those labels, and inside that loop through the array, and created an object with store values of data and label.
please see the comments for a better understanding.
Important thing to notice here is that for the same month number for labels value will be replaced with the last one.
arr = [{
label: 'US',
data: '10',
monthNumber: 1
},
{
label: 'US',
data: '2',
monthNumber: 3
},
{
label: 'US',
data: '60',
monthNumber: 2
},
{
label: 'UK',
data: '10',
monthNumber: 5
},
{
label: 'SA',
data: '1',
monthNumber: 1
},
{
label: 'CA',
data: '70',
monthNumber: 1
},
{
label: 'SA',
data: '10',
monthNumber: 12
},
];
const labels = [];
const result = [];
// extracting unique labels
arr.forEach(item => {
!labels.includes(item.label) && labels.push(item.label);
})
// looping through labels
labels.forEach(label => {
// creating empty object
const object = {};
// creating data array with 12 values by default 0
const data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// loop though array values
arr.forEach(item => {
// checking if current outer label is matching with array label
if (item.label == label) {
// if abive condition true add label key in object with value of current outer label
object["label"] = label;
// updating month value
data[item.monthNumber - 1] = item.data;
}
// adding data in object with key data.
object["data"] = data;
})
// pushing final object in result
result.push(object);
})
//printing final result
console.log(result);
Good starting point will be to group the data by label first.
Then take the values from that to remap the data.
Create a Month array generating a new array with 0 values
Loop through and add the data to the month array based on MonthNumber
const remap = () => {
let arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 }
];
return Object.values(
arr.reduce((acc, v) => {
if (!acc.hasOwnProperty(v.label)) {
acc[v.label] = [];
}
acc[v.label].push(v);
return acc;
}, {})
).map((flatData) => {
const label = Array.isArray(flatData) && flatData.length > 0 ? flatData[0].label : '';
const monthArray = new Array(12).fill(0);
flatData.forEach(({ data, monthNumber }) => {
monthArray[monthNumber] = parseInt(data);
});
return { label, data: monthArray };
});
};
console.log(remap())
Try this solution:
function setupGraph(arr){
data = [];
for (let i = 0; i < arr.length; i++) {
let found = false;
for (let j = 0; j < data.length; j++) {
if (data[j].label === arr[i].label) {
data[j].data[arr[i].monthNumber - 1] = Number(arr[i].data);
found = true;
break;
}
}
if (!found) {
data.push({ label: arr[i].label, data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] });
data[data.length - 1].data[arr[i].monthNumber - 1] = Number(arr[i].data);
}
}
return data;
}
Testing the function:
arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
let result = setupGraph(arr)
console.log(result);
[
{
label: 'US',
data: [
10, 60, 2, 0, 0,
0, 0, 0, 0, 0,
0, 0
]
},
{
label: 'UK',
data: [
0, 0, 0, 0, 10,
0, 0, 0, 0, 0,
0, 0
]
},
{
label: 'SA',
data: [
1, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 10
]
},
{
label: 'CA',
data: [
70, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
]
}
]
const defaultMonthsData = [0,0,0,0,0,0,0,0,0,0,0,0];
const arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
const results = _(arr)
.groupBy("label")
.map((value, label) => {
const monthsData = JSON.parse(JSON.stringify(defaultMonthsData));
return {
label,
data: _.map(value, function(o, index) {
monthsData[o.monthNumber] = parseInt(o.data);
return monthsData
})[0],
}
}).value();
console.log(results)
You can try with this (I'm using lodash 4.13.1). Thanks

Extract array from javascript object

I have below javascript object - (named Division)
I want to extract only SubDivs from the array
I tried : -
const division = [{
Name: "DivName1",
Value: "DivValue1",
SubDivision: {
Name: "SubDiv1",
Value: "SubDiv1"
}
},
{
Name: "DivName2",
Value: "DivValue2",
SubDivision: [{
Name: "SubDiv2",
Value: "SubDiv2"
},
{
Name: "SubDiv3",
Value: "SubDiv3"
}
]
}
]
var subDivs = division.map(x => x.SubDivision);
console.log(subDivs)
But this is not giving me array in format -
[{
Name:"SubDiv1",
Value:"SubDiv1"
},
{
Name:"SubDiv2",
Value:"SubDiv2"
},
{
Name:"SubDiv3",
Value:"SubDiv3"
}]
You can use flatMap for that
const division = [{
Name: "DivName1",
Value: "DivValue1",
SubDivision: [{
Name: "SubDiv1",
Value: "SubDiv1"
}]
},
{
Name: "DivName2",
Value: "DivValue2",
SubDivision: [{
Name: "SubDiv2",
Value: "SubDiv2"
},
{
Name: "SubDiv3",
Value: "SubDiv3"
}
]
}
]
const subdivision = division.flatMap(d => d.SubDivision)
console.log(subdivision)
Given your example, all you need to do is call flat on the mapped array:
var subDivs= division.map(x=>x.SubDivision).flat();
Working example:
const division = [{
Name: "DivName1",
Value: "DivValue1",
SubDivision: [{
Name: "SubDiv1",
Value: "SubDiv1"
}
]},
{
Name: "DivName2",
Value: "DivValue2",
SubDivision: [{
Name: "SubDiv2",
Value: "SubDiv2"
},
{
Name: "SubDiv3",
Value: "SubDiv3"
}
]
}
]
var subDivs= division.map(x=>x.SubDivision).flat();
console.log(subDivs)

How to modify the object and convert to array of objects javascript

How to change object to array of objects in javascript.
How to modify object and get the new aray of objects in javascript
Expected Result should be as input object weeks x 2 times (4 objects in output array)
for each item.
In Expected Output,
group key represents the weeks columns array,
should create a arraylist of each item desc, and interval qty per week
function createObject(obj){
const results = [];
for (var itm of obj.items) {
group: Object.values(obj.options).map((opt, index)=>opt.start+"-"+opt.end)
}
}
var obj = {
options: {
w1: {start:"Jan",end: "1"},
w2: {start:"Feb", end: "1"}
},
intervals: {
t1: {begin: "1", end: "2", totalqty: 2,totalamt: 200},
t2: {begin: "4", end: "7", totalqty: 3, totalamt: 300},
}
items: [
{
name: "s1",
desc: "sample1",
w1: {t1: {qty:0},t2: {qty:1}},
w2: {t1: {qty:1},t2: {qty:2}}
}
{
name: "s2",
desc: "sample2",
w1: {t1: {qty:0},t2: {qty:0}},
w2: {t1: {qty:0},t2: {qty:1}}
}
]
}
Expected Output:
[
{
group:"Jan 1", // represents w1
columns: [
{
col: 'desc',
value: 'sample1' // item.desc
},
{
col: '1-2', // represents t1
value: 0 , // represents t1.qty
},
{
col: '4-7', // represents t2
value: 1 // represents w1.t2.qty
}
]
},
{
group:"Feb 1", // represents w2
columns: [
{
col: 'desc',
value:'sample1'
},
{
col: '1-2', // represents t1
value:1 , // represents t1.qty
},
{
col: '4-7', // represents t2
value:2 ,// represents t2.qty
}
]
},
{
group:"Jan 1",
columns: [
{
col: 'desc',
value:'sample2'
},
{
col: '1-2',
value:0,
},
{
col: '4-7',
value:0
}
]
},
{
group:"Feb 1",
columns: [
{
col: 'desc',
value:'sample2'
},
{
col: '1-2',
value:0 ,
},
{
col: '4-7',
value:1,
}
]
}
]
Please try the below code. It produces the expected result
function createObject(obj){
return obj.items.map((item) => {
return Object.keys(obj.options).map((optKey) => {
const option = obj.options[optKey];
const items = {
'group' : `${option.start} ${option.end}`,
'columns': [{col: 'desc', value: item.desc}]
};
const intervals = item[optKey];
Object.keys(intervals).forEach((interval) => {
items.columns.push({
col: `${obj.intervals[interval].begin}-${obj.intervals[interval].end}`,
value: intervals[interval].qty
})
})
return items;
})
});
}

How to covert object array to Array List using for loop

Hey I am trying to convert object in array list i tried a lot of but i could not convert here is the code that i tried
const dat1 = [];
for (let i = 0; i < topology.length; i++) {
const data = [data1[i]];
dat1.push({
value:data
});
}
Here is the result that i got of value .
const topology = [
{
label: "secondary",
value: 0.10558737933770979
},
{
label: "unclassified",
value: 0.07702637029193307
},
{
label: "residential",
value: 0.05898100977978933
},
{
label: "tertiary",
value: 0.3012573789201084
},
{
label: "primary",
value: 0.44342463442819086
},
{
label: "primary_link",
value: 0.013723227242268547
},
];
and Here is the result that i want value look like in Array form.
const topology = [
{
label: "secondary",
value: [0.10558737933770979]
},
{
label: "unclassified",
value: [0.07702637029193307]
},
{
label: "residential",
value: [0.05898100977978933]
},
{
label: "tertiary",
value: [0.3012573789201084]
},
{
label: "primary",
value: [0.44342463442819086]
},
{
label: "primary_link",
value: [0.01372322724226854]
},
];
You could map the original topology and then just return the value wrapped in an array, like so:
const topology = [
{
label: "secondary",
value: 0.10558737933770979,
},
{
label: "unclassified",
value: 0.07702637029193307,
},
{
label: "residential",
value: 0.05898100977978933,
},
{
label: "tertiary",
value: 0.3012573789201084,
},
{
label: "primary",
value: 0.44342463442819086,
},
{
label: "primary_link",
value: 0.013723227242268547,
},
];
let result = topology.map(({ label, value }) => ({ label, value: [value] }));
console.log(result);
You can also follow your approach, like so:
const data1 = [];
for (let i = 0; i < topology.length; i++) {
const data = [topology[i].value];
data1.push({
label: topology[i].label,
value: data,
});
}
You were very close, just missing getting the value to be wrapped, i.e. you want the "old data", not the current new, so not [data1[i]] but [topology[i].value] and then adding the label to the new object in data1 array.
const topology = [
{
label: "secondary",
value: 0.10558737933770979,
},
{
label: "unclassified",
value: 0.07702637029193307,
},
{
label: "residential",
value: 0.05898100977978933,
},
{
label: "tertiary",
value: 0.3012573789201084,
},
{
label: "primary",
value: 0.44342463442819086,
},
{
label: "primary_link",
value: 0.013723227242268547,
},
];
const data1 = [];
for (let i = 0; i < topology.length; i++) {
const data = [topology[i].value];
data1.push({
label: topology[i].label,
value: data,
});
}
console.log(data1);
You could do something like this:
const changed = topology.map(({ label, value }) => ({
label,
value: [value]
}));
Basically just transforms the original data to wrap the value as an array with a single element.

How to use ternary operator while pushing elements into the array

I am trying to add the objects into the array based on the condition.
My expectation is to add two objects when the condition met but I am getting only the last object getting added (its element is missing).
const country = ‘USA’
citizenArray.push([
{
label: ‘Alex’,
value: ’32’,
},
country === ‘USA’
? ({
label: ‘John’,
value: ’28’,
},
{
label: ‘Miller’,
value: ’40’,
})
: {
label: ‘Marsh’,
value: ’31’,
},
]);
The output I am getting:
[{
label: ‘Alex’,
value: ’32’,
},
{
label: ‘Miller’,
value: ’40’,
}]
Expected:
[{
label: ‘Alex’,
value: ’32’,
},
{
label: ‘John’,
value: ’28’,
},
{
label: ‘Miller’,
value: ’40’,
}]
Could somebody help me point out where I am doing wrong?
Thanks.
In Javascript when you placed comma-separated expressions within parathesis it will execute each(left to right) and will return the result of last.
In your case ({ label: 'John', value: '28',}, { label: 'Miller', value: '40',}) results just the last object { label: ‘Miller’, value: ’40’, } and adds to the array.
To make it work to use an array and then use spread syntax to add them.
const country = 'USA';
const citizenArray = [];
citizenArray.push([{
label: 'Alex',
value: '32',
},
...(country === 'USA' ? [{
label: 'John',
value: '28',
}, {
label: 'Miller',
value: '40',
}] : [{
label: 'Marsh',
value: '31',
}])
]);
console.log(citizenArray);
Just use different logic like so:
const country = "USA";
let citizenArray = [];
citizenArray.push([{ label: "Alex", value: "32" }, ...(country == "USA" ? [{ label: "John", value: "28" }, { label: "Miller", value: "40" }] : [{ label: "Marsh", value: "31" }])]);
console.log(citizenArray);
.as-console-wrapper { max-height: 100% !important; top: auto; }
How about using the Spread ... operator
const myArray = [
...(condition1 ? [item1] : []),
...(condition2 ? [item2] : []),
...(condition3 ? [item3] : []),
];

Categories

Resources