Categorize array of objects into a new array - javascript

I have an array and I need to map this array into an array of its children.
var data = [{
name: 'Cars',
content: 'BMW',
value: 2000
},
{
name: 'Cars',
content: 'Fiat',
value: 542
},
{
name: 'Cars',
content: 'Mercedes',
value: 745
},
{
name: 'Cars',
content: 'Toyota',
value: 965
},
{
name: 'Cars',
content: 'Honda',
value: 754
}, {
name: 'Cars',
content: 'VW',
value: 123
},
{
name: 'Cars',
content: 'Ford',
value: 200
},
{
name: 'Fruits',
content: 'Apple',
value: 500
}, {
name: 'Fruits',
content: 'Orange',
value: 769
}, {
name: 'Fruits',
content: 'Banana',
value: 120
}, {
name: 'Fruits',
content: 'Strawberry',
value: 48
}, {
name: 'Fruits',
content: 'Mango',
value: 653
},
{
name: 'Colors',
content: 'Red',
value: 965
}, {
name: 'Colors',
content: 'Black',
value: 931
}, {
name: 'Colors',
content: 'BMW',
value: 423
}, {
name: 'Colors',
content: 'BMW',
value: 964
}, {
name: 'Colors',
content: 'BMW',
value: 436
}
]
The end result what I want must be like this:
[
{
name: "Children Array",
children: [
{
name: "Cars",
children: [
{
name: "BMW",
value: 2000
},
{
name: "Fiat",
value: 542
},
{
...
}
]
},
{
name: "Fruits",
children: [
{
name: 'Apple',
value: 500
},
{
name: 'Orange',
value: 769
},
{
...
}
]
},
{
name: "Colors",
children: [
{
name: 'Red',
value: 965
},
{
...
}
]
}
]
}
]
This is what I did.
var data = [{
name: 'Cars',
content: 'BMW',
value: 2000
},
{
name: 'Cars',
content: 'Fiat',
value: 542
},
{
name: 'Cars',
content: 'Mercedes',
value: 745
},
{
name: 'Cars',
content: 'Toyota',
value: 965
},
{
name: 'Cars',
content: 'Honda',
value: 754
}, {
name: 'Cars',
content: 'VW',
value: 123
},
{
name: 'Cars',
content: 'Ford',
value: 200
},
{
name: 'Fruits',
content: 'Apple',
value: 500
}, {
name: 'Fruits',
content: 'Orange',
value: 769
}, {
name: 'Fruits',
content: 'Banana',
value: 120
}, {
name: 'Fruits',
content: 'Strawberry',
value: 48
}, {
name: 'Fruits',
content: 'Mango',
value: 653
},
{
name: 'Colors',
content: 'Red',
value: 965
}, {
name: 'Colors',
content: 'Black',
value: 931
}, {
name: 'Colors',
content: 'BMW',
value: 423
}, {
name: 'Colors',
content: 'BMW',
value: 964
}, {
name: 'Colors',
content: 'BMW',
value: 436
}
]
const layer1 = _.uniqWith(_.map(data, (item) => {
return item.name
}), _.isEqual)
const newArray = [{
name: 'Children Array',
children: _.map(layer1, (item) => {
return {
name: item,
children: _.map(data, (item) => {
return {
}
})
}
})
}]
console.log(newArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I do not know how to proceed with the second children layer.
Please advice.

You could group the data and give the result the final layout.
var data = [{ name: 'Cars', content: 'BMW', value: 2000 }, { name: 'Cars', content: 'Fiat', value: 542 }, { name: 'Cars', content: 'Mercedes', value: 745 }, { name: 'Cars', content: 'Toyota', value: 965 }, { name: 'Cars', content: 'Honda', value: 754 }, { name: 'Cars', content: 'VW', value: 123 }, { name: 'Cars', content: 'Ford', value: 200 }, { name: 'Fruits', content: 'Apple', value: 500 }, { name: 'Fruits', content: 'Orange', value: 769 }, { name: 'Fruits', content: 'Banana', value: 120 }, { name: 'Fruits', content: 'Strawberry', value: 48 }, { name: 'Fruits', content: 'Mango', value: 653 }, { name: 'Colors', content: 'Red', value: 965 }, { name: 'Colors', content: 'Black', value: 931 }, { name: 'Colors', content: 'BMW', value: 423 }, { name: 'Colors', content: 'BMW', value: 964 }, { name: 'Colors', content: 'BMW', value: 436 }],
result = _(data)
.groupBy('name')
.map((group, name) =>
({ name, children: _.map(group, ({ content: name, value }) => ({ name, value })) }))
.value(),
final = [{ name: "Children Array", children: result }];
console.log(final);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

You can also do that with ES6 only via Object.entries & reduce:
var data = [{ name: 'Cars', content: 'BMW', value: 2000 }, { name: 'Cars', content: 'Fiat', value: 542 }, { name: 'Cars', content: 'Mercedes', value: 745 }, { name: 'Cars', content: 'Toyota', value: 965 }, { name: 'Cars', content: 'Honda', value: 754 }, { name: 'Cars', content: 'VW', value: 123 }, { name: 'Cars', content: 'Ford', value: 200 }, { name: 'Fruits', content: 'Apple', value: 500 }, { name: 'Fruits', content: 'Orange', value: 769 }, { name: 'Fruits', content: 'Banana', value: 120 }, { name: 'Fruits', content: 'Strawberry', value: 48 }, { name: 'Fruits', content: 'Mango', value: 653 }, { name: 'Colors', content: 'Red', value: 965 }, { name: 'Colors', content: 'Black', value: 931 }, { name: 'Colors', content: 'BMW', value: 423 }, { name: 'Colors', content: 'BMW', value: 964 }, { name: 'Colors', content: 'BMW', value: 436 }]
const groupData = (d) => {
let g = Object.entries(d.reduce((r,c)=>(r[c.name]=[...r[c.name]||[], c],r),{}))
return g.reduce((r,c) => (r.children.push(
{name: c[0], children: c[1]}), r),{name: "Children Array", children:[]})}
console.log(groupData(data))
The idea is via the first grouping to get an object with the name groups and after that you simply get the entries on that object and reduce on them to get the final result.
Also you start the main reduce with your predefined object etc.

Related

Convert an array of objects into a nested array of objects with different keys

So i have an array with the below structure. how would i go about converting it to the nested array below.
[
{mainCategory: 'Brand', slug: 'brand', value: 'Brand', label: 'Brand'},
{category: 'Cat1', slug: 'cat1', value: 'Cat1', label: 'Cat1'},
{subCategory: 'SubCat1', slug: 'subcat1', value: 'SubCat1', label: 'SubCat1'},
{mainCategory: 'Type', slug: 'type', value: 'Type', label: 'Type'},
{category: 'Cat2', slug: 'cat2', value: 'Cat2', label: 'Cat2'},
{subCategory: 'SubCat2', slug: 'subcat2', value: 'Cat2', label: 'Cat2'},
]
[
{label: 'Brand', options:
[
{ label: Cat1, value: Cat1 },
{ label: SubCat1, value: SubCat1 }
]
},
{label: 'Type', options:
[
{ label: Cat2, value: Cat2 },
{ label: SubCat2, value: SubCat2 }
]
},
]
Loop over the array elements. If it's a mainCategory object, create a new array element for the result. Otherwise, push the nested object onto the current result element's options array.
const input_data = [
{mainCategory: 'Brand', slug: 'brand', value: 'Brand', label: 'Brand'},
{category: 'Cat1', slug: 'cat1', value: 'Cat1', label: 'Cat1'},
{subCategory: 'SubCat1', slug: 'subcat1', value: 'SubCat1', label: 'SubCat1'},
{mainCategory: 'Type', slug: 'type', value: 'Type', label: 'Type'},
{category: 'Cat2', slug: 'cat2', value: 'Cat2', label: 'Cat2'},
{subCategory: 'SubCat2', slug: 'subcat2', value: 'Cat2', label: 'Cat2'},
];
const result = [];
let current;
input_data.forEach(obj => {
if (obj.mainCategory) {
current = {
label: obj.mainCategory,
options: []
};
result.push(current);
} else {
current.options.push({
label: obj.label,
value: obj.value
});
}
});
console.log(result);

JavaScript map update subarray to all be the same value

I have created a function to put the same quantity in arrange and then to map over to allocated the value for that month, sorry sounds strange when written down.
But ever time I run it the subarray that is being updated displays the same data in all them:
this.calcTest([
{ id: '001', name: 'First', arrOfStuff: [{ period: '2022-01-01', value: 10 },{ period: '2022-02-01', value: 10 }]},
{ id: '002', name: 'Second', arrOfStuff: [{ period: '2022-01-01', value: 11.11 }]},
{ id: '003', name: 'Third', arrOfStuff: [{ period: '2022-01-01', value: 12.12 },{ period: '2022-02-01', value: 9.99 }]},
{ id: '004', name: 'Fourth', arrOfStuff: [{ period: '2022-01-01', value: 13.13 }] }]);
calcTest(d: any) {
const testData = [];
const periods = [
{ period: '2022-01-01', value: '' },
{ period: '2022-02-01', value: '' },
];
d.map((f, indexCheck) => {
let tempArr = f.arrOfStuff;
f.arrOfStuff = periods;
tempArr.map((t) => {
let i = f.arrOfStuff.findIndex((as) => as.period === t.period);
f.arrOfStuff[i].value = t.value;
});
f.check = indexCheck;
testData.push(f);
});
console.log(testData);
}
this results with:
[{ id: '001', name: 'First', arrOfStuff: [{ period: '2022-01-01', value: 13.33 },{ period: '2022-02-01', value: 9.99 }], check: 0},
{ id: '002', name: 'Second', arrOfStuff: [{ period: '2022-01-01', value: 13.33 },{ period: '2022-02-01', value: 9.99 }], check: 1},
{ id: '003', name: 'Third', arrOfStuff: [{ period: '2022-01-01', value: 13.33 },{ period: '2022-02-01', value: 9.99 }], check: 3},
{ id: '004', name: 'Fourth', arrOfStuff: [{ period: '2022-01-01', value: 13.33 },{ period: '2022-02-01', value: 9.99 }], check: 4}]
I would like it to result in:
[{ id: '001', name: 'First', arrOfStuff: [{ period: '2022-01-01', value: 10 },{ period: '2022-02-01', value: 10 }], check: 0},
{ id: '002', name: 'Second', arrOfStuff: [{ period: '2022-01-01', value: 11.11 },{ period: '2022-02-01', value: '' }], check: 1},
{ id: '003', name: 'Third', arrOfStuff: [{ period: '2022-01-01', value: 12.12 },{ period: '2022-02-01', value: 9.99 }], check: 3},
{ id: '004', name: 'Fourth', arrOfStuff: [{ period: '2022-01-01', value: 13.33 },{ period: '2022-02-01', value: '' }], check: 4}]
I solved it with this code:
calcTest(d: any) {
const periods = JSON.stringify([
{ period: '2022-01-01', value: '' },
{ period: '2022-02-01', value: '' },
]);
d.map((f, indexCheck) => {
let tempArr = f.arrOfStuff;
f.arrOfStuff = JSON.parse(periods);
tempArr.map((t) => {
let i = f.arrOfStuff.findIndex((as) => as.period === t.period);
f.arrOfStuff[i].value = t.value;
});
f.check = indexCheck;
});
console.log(d);
}
I have had this problem before and it has something to do with memory allocation so you have to put the object into memory as a string and then parse back out to use as an object.

How to return the array of intersection between two array with Lodash?

I am trying to return the array of all the intersected array elements.
I got 2 arrays.
The array from api and the filter condition array.
Array from api is this
let somethingList = [
{
id: 'PROD108',
name: 'Headsweats Mid Cap',
CustomFields: [
{
name: 'Brand',
value: 'Headsweats',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD109',
name: 'Performance Liberty City Cycling Cap',
CustomFields: [
{
name: 'Brand',
value: 'Performance',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD110',
name: 'Castelli Logo Bandana',
CustomFields: [
{
name: 'Brand',
value: 'Castelli',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD159',
name: 'Performance Classic Sleeveless Jersey',
CustomFields: [
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#4CAF50',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD160',
name: 'Schwinn Evolution IC Sleeveless Jersey',
CustomFields: [
{
name: 'Brand',
value: 'Schwinn',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#2196F3',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD161',
name: 'Performance Elite Short',
CustomFields: [
{
name: 'Brand',
value: 'Performance',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#000000',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD162',
name: 'Andiamo! Padded Cycling Brief',
CustomFields: [
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#808080',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD163',
name: 'Fox Mojave Glove',
CustomFields: [
{
name: 'Brand',
value: 'Fox',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#000000',
},
{
name: 'Test',
value: '0',
},
],
},
];
filter condition array.
let testingFilter = ['Fox', 'Performance'];
What I want to do is if the customfield value of array from api is intersected with testingFilter value
I want to push them into an array and return that new array.
But the code I written don't return an new array, What should I do to return a new array
let filteredProduct = [];
filteredProduct = _.filter(somethingList, (product) => {
if (testingFilter.length === 0) {
return somethingList;
} else {
// Here is the problem
return _.intersection(testingFilter, _.map(product.CustomFields, 'value'));
}
});
Expected Answer array
filteredProduct = [
{
id: 'PROD109',
name: 'Performance Liberty City Cycling Cap',
CustomFields: [
{
name: 'Brand',
value: 'Performance',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD161',
name: 'Performance Elite Short',
CustomFields: [
{
name: 'Brand',
value: 'Performance',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#000000',
},
{
name: 'Test',
value: '0',
},
],
},
{
id: 'PROD163',
name: 'Fox Mojave Glove',
CustomFields: [
{
name: 'Brand',
value: 'Fox',
},
{
name: 'Eco',
value: 'False',
},
{
name: 'Color',
value: '#000000',
},
{
name: 'Test',
value: '0',
},
],
},
]
The following line taken from your code:
_.map(product.CustomFields, 'value')
Here, you get an array of all the values's of the CustomFields, if we check if there is an item from testinFilter present in that array, we can use that as the _filter return statement like so:
let filteredProduct = [];
filteredProduct = _.filter(somethingList, (product) => {
const allCustomFields = _.map(product.CustomFields, 'value');
return allCustomFields.some(r => testingFilter.indexOf(r) >= 0);
});
// We could rewrite the same code as a one-liner without the extra const like so:
let filteredProduct = _.filter(somethingList, (product) => _.map(product.CustomFields, 'value').some(r => testingFilter.indexOf(r) >= 0));
Snippet:
let testingFilter = ['Fox', 'Performance'];
let somethingList = [{id: 'PROD108', name: 'Headsweats Mid Cap', CustomFields: [{name: 'Brand', value: 'Headsweats', }, {name: 'Eco', value: 'False', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD109', name: 'Performance Liberty City Cycling Cap', CustomFields: [{name: 'Brand', value: 'Performance', }, {name: 'Eco', value: 'False', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD110', name: 'Castelli Logo Bandana', CustomFields: [{name: 'Brand', value: 'Castelli', }, {name: 'Eco', value: 'False', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD159', name: 'Performance Classic Sleeveless Jersey', CustomFields: [{name: 'Eco', value: 'False', }, {name: 'Color', value: '#4CAF50', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD160', name: 'Schwinn Evolution IC Sleeveless Jersey', CustomFields: [{name: 'Brand', value: 'Schwinn', }, {name: 'Eco', value: 'False', }, {name: 'Color', value: '#2196F3', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD161', name: 'Performance Elite Short', CustomFields: [{name: 'Brand', value: 'Performance', }, {name: 'Eco', value: 'False', }, {name: 'Color', value: '#000000', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD162', name: 'Andiamo! Padded Cycling Brief', CustomFields: [{name: 'Eco', value: 'False', }, {name: 'Color', value: '#808080', }, {name: 'Test', value: '0', }, ], }, {id: 'PROD163', name: 'Fox Mojave Glove', CustomFields: [{name: 'Brand', value: 'Fox', }, {name: 'Eco', value: 'False', }, {name: 'Color', value: '#000000', }, {name: 'Test', value: '0', }, ], }, ];
let filteredProduct = _.filter(somethingList, (product) => {
const allCustomFields = _.map(product.CustomFields, 'value');
return allCustomFields.some(r => testingFilter.indexOf(r) >= 0);
});
console.log(filteredProduct);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Result:
[
{
"id": "PROD109",
"name": "Performance Liberty City Cycling Cap",
"CustomFields": [
{
"name": "Brand",
"value": "Performance"
},
{
"name": "Eco",
"value": "False"
},
{
"name": "Test",
"value": "0"
}
]
},
{
"id": "PROD161",
"name": "Performance Elite Short",
"CustomFields": [
{
"name": "Brand",
"value": "Performance"
},
{
"name": "Eco",
"value": "False"
},
{
"name": "Color",
"value": "#000000"
},
{
"name": "Test",
"value": "0"
}
]
},
{
"id": "PROD163",
"name": "Fox Mojave Glove",
"CustomFields": [
{
"name": "Brand",
"value": "Fox"
},
{
"name": "Eco",
"value": "False"
},
{
"name": "Color",
"value": "#000000"
},
{
"name": "Test",
"value": "0"
}
]
}
]
You can do:
let somethingList = [ { id: 'PROD108', name: 'Headsweats Mid Cap', CustomFields: [ { name: 'Brand', value: 'Headsweats', }, { name: 'Eco', value: 'False', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD109', name: 'Performance Liberty City Cycling Cap', CustomFields: [ { name: 'Brand', value: 'Performance', }, { name: 'Eco', value: 'False', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD110', name: 'Castelli Logo Bandana', CustomFields: [ { name: 'Brand', value: 'Castelli', }, { name: 'Eco', value: 'False', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD159', name: 'Performance Classic Sleeveless Jersey', CustomFields: [ { name: 'Eco', value: 'False', }, { name: 'Color', value: '#4CAF50', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD160', name: 'Schwinn Evolution IC Sleeveless Jersey', CustomFields: [ { name: 'Brand', value: 'Schwinn', }, { name: 'Eco', value: 'False', }, { name: 'Color', value: '#2196F3', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD161', name: 'Performance Elite Short', CustomFields: [ { name: 'Brand', value: 'Performance', }, { name: 'Eco', value: 'False', }, { name: 'Color', value: '#000000', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD162', name: 'Andiamo! Padded Cycling Brief', CustomFields: [ { name: 'Eco', value: 'False', }, { name: 'Color', value: '#808080', }, { name: 'Test', value: '0', }, ], }, { id: 'PROD163', name: 'Fox Mojave Glove', CustomFields: [ { name: 'Brand', value: 'Fox', }, { name: 'Eco', value: 'False', }, { name: 'Color', value: '#000000', }, { name: 'Test', value: '0', }, ], }, ];
let testingFilter = ['Fox', 'Performance'];
let filteredProducts = somethingList.filter(p =>
Array.from(p.CustomFields.values()) // iterable to array
.map(({value}) => value)
.some(value => testingFilter.includes(value)))
console.log(filteredProducts)

AmCharts - How to expand only first level children on a Force Directed Tree

I'm working on a force directed tree with 3 levels, and currently when I click to expand the second level childrens, the third level is expanded at the same time.
Is there a way to display only the 2nd level children when clicking the 1st level bubbles and display the 3rd level children only when clicking the second level bubbles ?
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4plugins_forceDirected.ForceDirectedTree);
chart.legend = new am4charts.Legend();
var series = chart.series.push(new am4plugins_forceDirected.ForceDirectedSeries());
series.data = [
{
name: 'One',
color: ("#6ab8da"),
children: [{
name: '1',
children: [{
name: 'Blackberry',
value: 1
},
{
name: 'Raspberry',
value: 1
},
{
name: 'Blueberry',
value: 1
},
{
name: 'Strawberry',
value: 1
}
]
},
{
name: '2',
children: [{
name: 'Raisin',
value: 1
},
{
name: 'Prune',
value: 1
}
]
},
{
name: '3',
children: [{
name: 'Coconut',
value: 1
},
{
name: 'Cherry',
value: 1
},
{
name: 'Pomegranate',
value: 1
},
{
name: 'Pineapple',
value: 1
},
{
name: 'Grape',
value: 1
},
{
name: 'Apple',
value: 1
},
{
name: 'Peach',
value: 1
},
{
name: 'Pear',
value: 1
}
]
},
{
name: '4',
children: [{
name: 'Grapefruit',
value: 1
},
{
name: 'Orange',
value: 1
},
{
name: 'Lemon',
value: 1
},
{
name: 'Lime',
value: 1
}
]
}
]
},
{
name: 'Two',
color: ("#6872d9"),
children: [{
name: 'Visites vistuelles'
},
{
name: 'Lorem ipsum'
}
]
},
{
name: 'Three',
color: ("#a267d9"),
children: [{
name: 'Papery/Musty',
children: [{
name: 'Stale',
value: 1
},
{
name: 'Cardboard',
value: 1
},
{
name: 'Papery',
value: 1
},
{
name: 'Woody',
value: 1
},
{
name: 'Moldy/Damp',
value: 1
},
{
name: 'Musty/Dusty',
value: 1
},
{
name: 'Musty/Earthy',
value: 1
},
{
name: 'Animalic',
value: 1
},
{
name: 'Meaty Brothy',
value: 1
},
{
name: 'Phenolic',
value: 1
}
]
},
{
name: 'Chemical',
children: [{
name: 'Bitter',
value: 1
},
{
name: 'Salty',
value: 1
},
{
name: 'Medicinal',
value: 1
},
{
name: 'Petroleum',
value: 1
},
{
name: 'Skunky',
value: 1
},
{
name: 'Rubber',
value: 1
}
]
}
]
},
{
name: 'Four',
color: ("#da66cc"),
children: [{
name: 'Pipe Tobacco',
value: 1
},
{
name: 'Tobacco',
value: 1
},
{
name: 'Burnt',
children: [{
name: 'Acrid',
value: 1
},
{
name: 'Ashy',
value: 1
},
{
name: 'Smoky',
value: 1
},
{
name: 'Brown, Roast',
value: 1
}
]
},
{
name: 'Cereal',
children: [{
name: 'Grain',
value: 1
},
{
name: 'Malt',
value: 1
}
]
}
]
}
];
series.dataFields.linkWith = "linkWith";
series.dataFields.name = "name";
series.dataFields.id = "name";
series.dataFields.value = "value";
series.dataFields.children = "children";
series.dataFields.color = "color";
series.dataFields.collapsed = "on";
series.manyBodyStrength = -30;
series.links.template.distance = 1;
series.links.template.strength = 1;
series.centerStrength = 1.2;
/*series.manyBodyStrength = -50;*/
series.links.template.strength = 1;
series.nodes.template.tooltipText = "{name}";
series.nodes.template.fillOpacity = 1;
series.nodes.template.togglable = true;
series.nodes.template.label.text = "{name}";
series.fontSize = 14;
series.minRadius = 50;
series.maxRadius = 80;
series.maxLevels = 1;
series.nodes.template.label.hideOversized = true;
series.nodes.template.label.truncate = true;
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 600px;
}
<body>
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<script src="//www.amcharts.com/lib/4/plugins/forceDirected.js"></script>
<div id="chartdiv"></div>
</body>
JSFiddle here
Yes, there is a way to change the behavior from expanding all nodes to just the next, immediate level of the node that was clicked.
By default, the expandAll property of ForceDirectedNodes is set to true.
You can set this to false on all of them via
series.nodes.template.expandAll = false;
And that will give you the behavior you're looking for:
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4plugins_forceDirected.ForceDirectedTree);
chart.legend = new am4charts.Legend();
var series = chart.series.push(new am4plugins_forceDirected.ForceDirectedSeries());
series.nodes.template.expandAll = false;
series.data = [
{
name: 'One',
color: ("#6ab8da"),
children: [{
name: '1',
children: [{
name: 'Blackberry',
value: 1
},
{
name: 'Raspberry',
value: 1
},
{
name: 'Blueberry',
value: 1
},
{
name: 'Strawberry',
value: 1
}
]
},
{
name: '2',
children: [{
name: 'Raisin',
value: 1
},
{
name: 'Prune',
value: 1
}
]
},
{
name: '3',
children: [{
name: 'Coconut',
value: 1
},
{
name: 'Cherry',
value: 1
},
{
name: 'Pomegranate',
value: 1
},
{
name: 'Pineapple',
value: 1
},
{
name: 'Grape',
value: 1
},
{
name: 'Apple',
value: 1
},
{
name: 'Peach',
value: 1
},
{
name: 'Pear',
value: 1
}
]
},
{
name: '4',
children: [{
name: 'Grapefruit',
value: 1
},
{
name: 'Orange',
value: 1
},
{
name: 'Lemon',
value: 1
},
{
name: 'Lime',
value: 1
}
]
}
]
},
{
name: 'Two',
color: ("#6872d9"),
children: [{
name: 'Visites vistuelles'
},
{
name: 'Lorem ipsum'
}
]
},
{
name: 'Three',
color: ("#a267d9"),
children: [{
name: 'Papery/Musty',
children: [{
name: 'Stale',
value: 1
},
{
name: 'Cardboard',
value: 1
},
{
name: 'Papery',
value: 1
},
{
name: 'Woody',
value: 1
},
{
name: 'Moldy/Damp',
value: 1
},
{
name: 'Musty/Dusty',
value: 1
},
{
name: 'Musty/Earthy',
value: 1
},
{
name: 'Animalic',
value: 1
},
{
name: 'Meaty Brothy',
value: 1
},
{
name: 'Phenolic',
value: 1
}
]
},
{
name: 'Chemical',
children: [{
name: 'Bitter',
value: 1
},
{
name: 'Salty',
value: 1
},
{
name: 'Medicinal',
value: 1
},
{
name: 'Petroleum',
value: 1
},
{
name: 'Skunky',
value: 1
},
{
name: 'Rubber',
value: 1
}
]
}
]
},
{
name: 'Four',
color: ("#da66cc"),
children: [{
name: 'Pipe Tobacco',
value: 1
},
{
name: 'Tobacco',
value: 1
},
{
name: 'Burnt',
children: [{
name: 'Acrid',
value: 1
},
{
name: 'Ashy',
value: 1
},
{
name: 'Smoky',
value: 1
},
{
name: 'Brown, Roast',
value: 1
}
]
},
{
name: 'Cereal',
children: [{
name: 'Grain',
value: 1
},
{
name: 'Malt',
value: 1
}
]
}
]
}
];
series.dataFields.linkWith = "linkWith";
series.dataFields.name = "name";
series.dataFields.id = "name";
series.dataFields.value = "value";
series.dataFields.children = "children";
series.dataFields.color = "color";
series.dataFields.collapsed = "on";
series.manyBodyStrength = -30;
series.links.template.distance = 1;
series.links.template.strength = 1;
series.centerStrength = 1.2;
/*series.manyBodyStrength = -50;*/
series.links.template.strength = 1;
series.nodes.template.tooltipText = "{name}";
series.nodes.template.fillOpacity = 1;
series.nodes.template.togglable = true;
series.nodes.template.label.text = "{name}";
series.fontSize = 14;
series.minRadius = 50;
series.maxRadius = 80;
series.maxLevels = 1;
series.nodes.template.label.hideOversized = true;
series.nodes.template.label.truncate = true;
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 600px;
}
<body>
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<script src="//www.amcharts.com/lib/4/plugins/forceDirected.js"></script>
<div id="chartdiv"></div>
</body>
jsfiddle fork:
https://jsfiddle.net/notacouch/4wfc2duj/
Hope this helps.

How to group array

I am trying to group similar objects with the same label.
At the moment, this is the the JSON I receive.
const sizes = [{
id: [{
value: '2496',
label: 'XS'
}, {
value: '2499',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3561',
label: 'XS'
}, {
value: '3563',
label: 'S'
}, {
value: '3565',
label: 'L'
}, , {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}]
The result I am trying to achieve is
const sizes = [{
id: [{
value: '2496,3561',
label: 'XS'
}, {
value: '2499,3563',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863,3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3565',
label: 'L'
}, , {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '2866',
label: 37
}],
type: 'Shoe Sizes'
}]
I have tried to achieve this with underscore, but I am only able to group it by just one label, and I need to group it by any kind of label, whether it be XS or 36.
I have tried with reduce below, it is close but I just need to remove the brackets around the value, and turn the value into a string.
EX: value: '2493, 2343'
var group_to_values = sizes.reduce(function (obj, item) {
obj[item.label] = obj[item.label] || [];
obj[item.label].push(item.value);
return obj;
}, {});
var groups = Object.keys(group_to_values).map(function (key) {
return {label: key, value: group_to_values[key]};
});
You could take a hash table for same labels and iterate the outer array and the inner array. If a label is not found, it generates a new entry for the result set.
var sizes = [{ id: [{ value: '2496', label: 'XS' }, { value: '2499', label: 'S' }], type: 'First Size' }, { id: [{ value: '2863', label: 34 }, { value: '2866', label: 36 }], type: 'Shoe Sizes' }, { id: [{ value: '3561', label: 'XS' }, { value: '3563', label: 'S' }, { value: '3565', label: 'L' }, { value: '3567', label: 'XL' }] }, { id: [{ value: '3523', label: 34 }, { value: '2866', label: 36 }], type: 'Shoe Sizes' }],
labels = Object.create(null),
joined = sizes.reduce((r, a) => {
var temp;
a.id.forEach(o => {
if (labels[o.label]) {
labels[o.label].value += ',' + o.value;
return;
}
if (!temp) {
temp = Object.assign({}, a, { id: [] });
r.push(temp);
}
temp.id.push(labels[o.label] = o);
});
return r;
}, []);
console.log(joined);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here you are, the code below would output Array called result, which is data set you desired, the loop is clear so I think it won't be an issue for you to go through it:
const sizes = [{
id: [{
value: '2496',
label: 'XS'
}, {
value: '2499',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3561',
label: 'XS'
}, {
value: '3563',
label: 'S'
}, {
value: '3565',
label: 'L'
}, {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}]
var groupedSizes = {};
for (var current, i=0;i < sizes.length ;i++){
for (var j=0;j < sizes[i]['id'].length;j++) {
current = sizes[i]['id'][j]
if (groupedSizes[current['label']] !== undefined) {
groupedSizes[current['label']].push(current['value'])
} else {
groupedSizes[current['label']] = [current['value']]
}
}
}
var result = []
for (var key in groupedSizes) {
result.push({'id': groupedSizes[key].join(','), 'label': key})
}
console.log(result)

Categories