change the position of object in array inside other object - javascript

in given data every ingredient have its substitute option while I can
select any substitute option for example if I want to change masala
with its substitute output will change the position of substitute with
it's option and output should be given below
i want to replace masala with normal masala
i have to create a function who replace ingredient with it's substitute and interchange the position of both *
input
const oData = [
{ CurryName: 'Chiken', id: 0 },
{
ingredients: [
{
id: 1,
name: 'onion',
property: { color: 'yellow', Quantity: 'half KG', price: 120 },
subOption: [
{
id: 11,
name: 'redOnion',
property: { color: 'red', Quantity: '1 KG', price: 120 },
},
{
id: 12,
name: 'whiteOnion',
property: { color: 'white', Quantity: '2 KG', price: 120 },
},
],
},
{
id: 2,
name: 'oil',
property: { color: 'green', Quantity: 'half LT', price: 120 },
subOption: [
{
id: 21,
name: 'yellowOil',
property: { color: 'yellow', Quantity: '1 LT', price: 120 },
},
{
id: 22,
name: 'olivoOil',
property: { color: 'golden', Quantity: '2 LT', price: 120 },
},
{
id: 22,
name: 'CastrolOil',
property: { color: 'silk', Quantity: '2 LT', price: 170 },
},
],
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 },
},
],
},
],
},
];
// in given data every ingredient have it's substitute option while i can select any supstitute option for example if i want to change masala with its substitute output will change the position of substitue with it's option and output should be given below
//i want to replace masala with normal masala
const output = [
{ CurryName: 'Chiken', id: 0 },
{
ingredients: [
{
id: 1,
name: 'onion',
property: { color: 'yellow', Quantity: 'half KG', price: 120 },
subOption: [
{
id: 11,
name: 'redOnion',
property: { color: 'red', Quantity: '1 KG', price: 120 },
},
{
id: 12,
name: 'whiteOnion',
property: { color: 'white', Quantity: '2 KG', price: 120 },
},
],
},
{
id: 2,
name: 'oil',
property: { color: 'green', Quantity: 'half LT', price: 120 },
subOption: [
{
id: 21,
name: 'yellowOil',
property: { color: 'yellow', Quantity: '1 LT', price: 120 },
},
{
id: 22,
name: 'olivoOil',
property: { color: 'golden', Quantity: '2 LT', price: 120 },
},
{
id: 22,
name: 'CastrolOil',
property: { color: 'silk', Quantity: '2 LT', price: 170 },
},
],
},
{
id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 },
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
}
],
},
],
},
];
console.log(output)

I suggest that define an element before 'subOption' like 'selectedOption' so you can change it more easily between them
{
selectedOption:{id: 33,
name: 'normalMasala',
property: { color: 'red', Quantity: '5Tspoon', price: 30 }},
subOption: [
{
id: 31,
name: 'garamMasala',
property: { color: 'Garam', Quantity: '2Tspoon', price: 30 },
},
{
id: 32,
name: 'chikenMasala',
property: { color: 'green', Quantity: ' 3Tspoon', price: 30 },
},
{
id: 3,
name: 'masala',
property: { color: 'gray', Quantity: '1Tspoon', price: 30 },
}
],
}
if you able to add 'selectedOption' you can use this code
let temp = oData[1].ingredients[3].subOption[3]
oData[1].ingredients[3].subOption[3].splice(3,1,oData[1].ingredients[3].selectedOption)
oData[1].ingredients[3].selectedOption=temp;

This solution may not be ideal because it changes the original data. But if you don't mind changing the original data, use this.
function swapIngredientMainSub(data, mainID, subID) {
const { ingredients } = data[1];
const targetIndex = ingredients.findIndex(({ id }) => id === mainID);
const { subOption, ...main } = ingredients[targetIndex];
const subIndex = subOption.findIndex(({ id }) => id === subID);
const sub = subOption[subIndex];
subOption[subIndex] = main;
ingredients[targetIndex] = { ...sub, subOption };
}
swapIngredientMainSub(oData, 3, 33);
console.log(JSON.stringify(oData) === JSON.stringify(output)); // true
Option 2:
function swapIngredientMainSub(data, subID) {
const { ingredients } = data[1];
const targetIndex = ingredients.findIndex(({ subOption }) =>
subOption.find(({ id }) => id === subID)
);
const { subOption, ...main } = ingredients[targetIndex];
const subIndex = subOption.findIndex(({ id }) => id === subID);
const sub = subOption[subIndex];
subOption[subIndex] = main;
ingredients[targetIndex] = { ...sub, subOption };
}
swapIngredientMainSub(oData, 33);
console.log(JSON.stringify(oData) === JSON.stringify(output)); // true

I don't know about d3 library that you have included in the tags, but you can use something like this:
const oData = [{
CurryName: 'Chiken',
id: 0
},
{
ingredients: [{
id: 1,
name: 'onion',
property: {
color: 'yellow',
Quantity: 'half KG',
price: 120
},
subOption: [{
id: 11,
name: 'redOnion',
property: {
color: 'red',
Quantity: '1 KG',
price: 120
},
},
{
id: 12,
name: 'whiteOnion',
property: {
color: 'white',
Quantity: '2 KG',
price: 120
},
},
],
},
{
id: 2,
name: 'oil',
property: {
color: 'green',
Quantity: 'half LT',
price: 120
},
subOption: [{
id: 21,
name: 'yellowOil',
property: {
color: 'yellow',
Quantity: '1 LT',
price: 120
},
},
{
id: 22,
name: 'olivoOil',
property: {
color: 'golden',
Quantity: '2 LT',
price: 120
},
},
{
id: 22,
name: 'CastrolOil',
property: {
color: 'silk',
Quantity: '2 LT',
price: 170
},
},
],
},
{
id: 3,
name: 'masala',
property: {
color: 'gray',
Quantity: '1Tspoon',
price: 30
},
subOption: [{
id: 31,
name: 'garamMasala',
property: {
color: 'Garam',
Quantity: '2Tspoon',
price: 30
},
},
{
id: 32,
name: 'chikenMasala',
property: {
color: 'green',
Quantity: ' 3Tspoon',
price: 30
},
},
{
id: 33,
name: 'normalMasala',
property: {
color: 'red',
Quantity: '5Tspoon',
price: 30
},
},
],
},
],
},
];
const selectIngredients = (obj, mainName, subName) => {
obj[1].ingredients.map(ingredient => {
if (ingredient.name === mainName) {
const optionIndex = ingredient.subOption.findIndex(element => element.name === subName);
if (optionIndex !== undefined) {
const {
id,
name,
property
} = ingredient;
ingredient.id = ingredient.subOption[optionIndex].id;
ingredient.name = ingredient.subOption[optionIndex].name;
ingredient.property = ingredient.subOption[optionIndex].property;
ingredient.subOption[optionIndex].id = id;
ingredient.subOption[optionIndex].name = name;
ingredient.subOption[optionIndex].property = property;
}
}
});
return obj;
};
console.log(selectIngredients(oData, "masala", "normalMasala"));

Related

Search array of nested objects with dynamic parameters

I have an array with objects. I'm trying to recursively search through them and create new array with modified key's.
The array:
let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
I've tried using JSON.Stringify but I keep getting not desired result.
function dynamic(obj, ...keyToFind) {
const foundObj = {};
const foundObjArray: any[] = [];
keyToFind.forEach((key) => {
JSON.stringify(obj, (_, nestedValue) => {
if (nestedValue && nestedValue[a]) {
foundObj[key] = nestedValue[a];
}
return nestedValue;
});
foundObjArray.push(foundObj);
});
return foundObjArray;
}
I'm calling this function with N number of parameters:
dynamic(response, 'age', 'work', 'main', 'description', 'type', 'date');
Once it is called I'm trying to construct a new array of objects who will look like:
let foundObjArray = [
{
'age': 33,
'work': 1015,
'main': 'Doctor',
'description': 'Ofto',
'type': 5.6,
'date': '2022-08-30 15:00:00'
},
{
'age': 25,
'work': 101,
'main': 'Software',
'description': 'Programmer',
'type': 0.26,
'date': '2021-01-30 12:00:00'
},
.......
]
A JSON.stringify based approach, as initially intended by the OP, is even a reliable one, in case one wants to target any user-item's first occurring entry regardless of its nesting level/depth where each property's value is not of object or array type itself.
One just needs to come up with an according property specific regex like e.g. for the "work" key ... /"work":(?<value>[^\[{]+?)(?=,"|\})/.
The rest then can be achieved by combined map and reduce tasks, where with each item's mapping a new object is created via reducing an array of property names which has to be provided as the map method's 2nd thisArg parameter.
const response = {
users: [{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
}],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
}, {
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
}],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
}, {
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
}],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
}],
};
function createObjectOfFirstOccurringValuesFromBoundKeyList(item) {
const itemData = JSON.stringify(item);
return this // `this` equals the bound array of property names.
.reduce((result, key) => {
const { value = null } =
RegExp(`"${ key }":(?<value>[^\[{]+?)(?=,"|\})`)
// see ... [https://regex101.com/r/ss6jlt/1]
.exec(itemData)
?.groups ?? {};
if (value !== null) {
Object
.assign(result, { [key]: JSON.parse(value) });
}
return result;
}, {})
}
const listOfFirstPropertyValueItems = response
.users
.map(createObjectOfFirstOccurringValuesFromBoundKeyList, [
'age', 'work', 'main', 'description', 'type', 'date'
]);
console.log({
listOfFirstPropertyValueItems
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
speed_min: 296.76,
speed_max: 297.87,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
speed_min: 96.76,
speed_max: 327.87,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
speed_min: 16.76,
speed_max: 27.87,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
function getMatchedKey(arr, key) {
let matched = arr.filter(x => key.endsWith(x));
if(matched.length > 0) {
return matched[0];
}
}
function getLimitedData(data, requiredKey = []) {
var result = {};
function recurse(cur, prop) {
if (Object(cur) !== cur) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = cur);
} else if (Array.isArray(cur)) {
for (var i = 0, l = cur.length; i < l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = []);
}
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop + "." + p : p);
}
if (isEmpty && prop) {
let matchedKey = getMatchedKey(requiredKey, prop);
matchedKey != undefined && (result[matchedKey] = {});
}
}
}
recurse(data, "");
return result;
}
let keys = ['age', 'work', 'main', 'description', 'type', 'date'];
let output = response.users.map(a => getLimitedData(a, keys));
console.log(output);
you can do like this two by saperating objectFunction and ArrayFunction recursively
let keys = ['age', 'work', 'main', 'description', 'type', 'date'];
let response = {
users: [
{
user_id: 1661871600,
details: {
height: 150,
age: 33,
work: 1015,
school: 10,
degree: 933
},
work: [
{
id: 500,
main: 'Doctor',
description: 'Ofto',
icon: '10d',
},
],
look: {
all: 100,
},
transport: {
speed: 0.62,
max_speed: 349,
},
visibility: 10000,
hair: {
type: 0.26,
},
date: '2022-08-30 15:00:00',
},
{
user_id: 324235256,
details: {
height: 110,
age: 25,
work: 101,
school: 110,
degree: 553
},
work: [
{
id: 500,
main: 'Software',
description: 'Programmer',
icon: '11d',
},
],
look: {
all: 2,
},
transport: {
speed: 1.2,
max_speed: 49,
},
visibility: 221,
hair: {
type: 5.6,
},
date: '2021-01-30 12:00:00',
},
{
user_id: 12353743,
details: {
height: 10,
age: 75,
work: 1,
school: 114,
degree: 3
},
work: [
{
id: 500,
main: 'Pension',
description: 'Architect',
icon: '1d',
},
],
look: {
all: 6,
},
transport: {
speed: 3.2,
max_speed: 29,
},
visibility: 21,
hair: {
type: 1.6,
},
date: '2020-01-30 12:00:00',
},
],
};
// main function
const fun =(ob, k , con)=>{
// recursive object function
const objectFun =(arr)=>{
for(y in arr){
if(typeof arr[y] === "object"){
objectFun(arr[y])
}else if(Array.isArray(arr[y])){
arrayFun(arr[y])
}else if(k.includes(y)){
temp[y] = arr[y]
}}}
// recursive array function
const arrayFun =(xx) =>{
const usersList = ob[xx].map((ar, i)=>{
objectFun(ar)
con.push(temp)
temp ={}
})}
// main access key for in loop
for(x in ob){
var temp = {}
arrayFun(x)
}
return con
}
console.log(fun(response , keys , []))
.as-console-wrapper { min-height: 100%!important; top: 0; }

Get trees closer together

I am using tree layout and I have multiple trees (multiple roots).
How can I get the trees to be packed together and fill the empty space using layout.
Here is an example of my trees:
unpacked trees image
I want them to be more like this:
packed trees image
here is my current layout:
let myDiagram = new go.Diagram("myDiagramDiv",
{
layout: new go.TreeLayout({
treeStyle: go.TreeLayout.StyleLastParents,
arrangement: go.TreeLayout.ArrangementHorizontal,
compaction: go.TreeLayout.CompactionBlock,
// properties for most of the tree:
angle: 90,
layerSpacing: 35,
// properties for the "last parents":
alternateAngle: 90,
alternateLayerSpacing: 35,
alternateAlignment: go.TreeLayout.AlignmentBus,
alternateNodeSpacing: 20,
})
});
#HumanTarget has the right idea. Here's an example:
<script type="module">
import * as go from "../release/go-module.js";
import { ArrangingLayout } from "../extensionsJSM/ArrangingLayout.js";
import { PackedLayout } from "../extensionsJSM/PackedLayout.js";
const $ = go.GraphObject.make;
const myDiagram =
$(go.Diagram, "myDiagramDiv",
{
layout: $(ArrangingLayout,
{
primaryLayout: $(go.TreeLayout, { angle: 90 }),
arrangingLayout: $(PackedLayout, { spacing: 10 }),
})
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, { fill: "white" },
new go.Binding("fill", "color")),
$(go.TextBlock, { margin: 8 },
new go.Binding("text"))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" },
{ key: 5, text: "Epsilon", color: "lightblue" },
{ key: 6, text: "Zeta", color: "orange" },
{ key: 7, text: "Eta", color: "lightgreen" },
{ key: 8, text: "Theta", color: "pink" },
{ key: 9, text: "Iota", color: "lightblue" },
{ key: 10, text: "Kappa", color: "orange" },
{ key: 11, text: "Lambda", color: "lightgreen" },
{ key: 12, text: "Mu", color: "pink" },
{ key: 13, text: "Nu", color: "lightblue" },
{ key: 14, text: "Xi", color: "orange" },
{ key: 15, text: "Omicron", color: "lightgreen" },
{ key: 16, text: "Pi", color: "pink" },
],
[
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 4, to: 5 },
{ from: 4, to: 6 },
{ from: 6, to: 7 },
{ from: 8, to: 9 },
{ from: 9, to: 10 },
{ from: 11, to: 12 },
{ from: 13, to: 14 },
{ from: 13, to: 15 },
{ from: 13, to: 16 },
]);
</script>
Result:
But note that PackedLayout will treat each subtree as occupying a rectangular area, so it won't try to fit subtrees together where one or both of the subtrees has some empty space.

Clearing a selected item in dropdown after selecting item in other dropdown with vue-treeselect

I'm coding about auto select provinces in Thailand, When I choose province A in province dropdown the district dropdown will change to value in province A, and when I change to province B in province dropdown value in district dropdown has changed to district in province B already but the UI of district dropdown still shows district in province A.
I have researched treeselect docs and tried for several days now, and I really can't find a solution :-(
This is UI rightnow
<treeselect
id="province-selected"
v-model="state.provinceSelected"
:options="provinceArr"
placeholder="กรุณาเลือกจังหวัด"
noResultsText="ไม่พบข้อมูล"
data-test="province-input"
:class="{ errorselect: v$.provinceSelected.$errors.length }"
:normalizer="normalizerProvince"
#select="getDistrict"
zIndex="20000"
:clearable="false"
:allowClearingDisabled="true"
/>
The official documentation of VueTreeselect mentions, the select event is Emitted after selecting an option. It has no dependency with the value update. I prefer you to use input event instead of select. Because the documentation states, the input event will be Emitted after value changes. So inside this method you will get the updated value for the first select.
Working Fiddle
Vue.component('treeselect', VueTreeselect.Treeselect)
new Vue({
el: '#app',
data: {
provinceArr: [
{ id: 1, label: 'Province 1', districtArr: [
{ id: 10, label: 'District 01' },
{ id: 11, label: 'District 02' },
{ id: 12, label: 'District 03' },
{ id: 13, label: 'District 04' },
]},
{ id: 2, label: 'Province 2', districtArr: [
{ id: 20, label: 'District 21' },
{ id: 21, label: 'District 22' },
{ id: 22, label: 'District 23' },
{ id: 23, label: 'District 24' },
]},
{ id: 3, label: 'Province 3', districtArr: [
{ id: 30, label: 'District 31' },
{ id: 31, label: 'District 32' },
{ id: 32, label: 'District 33' },
{ id: 33, label: 'District 34' },
] },
{ id: 4, label: 'Province 4', districtArr: [
{ id: 40, label: 'District 41' },
{ id: 41, label: 'District 42' },
{ id: 42, label: 'District 43' },
{ id: 43, label: 'District 44' },
] },
{ id: 5, label: 'Province 5', districtArr: [
{ id: 50, label: 'District 51' },
{ id: 51, label: 'District 52' },
{ id: 52, label: 'District 53' },
{ id: 53, label: 'District 54' },
] },
{ id: 6, label: 'Province 6', districtArr: [
{ id: 60, label: 'District 61' },
{ id: 61, label: 'District 62' },
{ id: 72, label: 'District 73' },
{ id: 73, label: 'District 74' },
] },
],
districtArr: [],
state: {
provinceSelected: null,
districtSelected: null,
},
},
methods: {
getDistrict: function(node, instanceId) {
console.log(this.state.provinceSelected, node, instanceId);
// Some logic to populate districts
this.districtArr = this.provinceArr.find(item => item.id === this.state.provinceSelected).districtArr;
},
onDistrictSelected: function(node, instanceId) {
console.log(this.state.districtSelected)
}
}
})
<!-- include Vue 2.x -->
<script src="https://cdn.jsdelivr.net/npm/vue#^2"></script>
<!-- include vue-treeselect & its styles. you can change the version tag to better suit your needs. -->
<script src="https://cdn.jsdelivr.net/npm/#riophae/vue-treeselect#^0.4.0/dist/vue-treeselect.umd.min.js"></script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/#riophae/vue-treeselect#^0.4.0/dist/vue-treeselect.min.css">
<div id="app">
<div>
<p>Province</p>
<treeselect
id="province-selected"
v-model="state.provinceSelected"
:options="provinceArr"
placeholder="กรุณาเลือกจังหวัด"
noResultsText="ไม่พบข้อมูล"
data-test="province-input"
#input="getDistrict"
zIndex="20000"
:clearable="false"
:allowClearingDisabled="true"
/>
</div>
<div>
<p>District</p>
<treeselect
id="district-selected"
v-model="state.districtSelected"
:options="districtArr"
placeholder="กรุณาเลือกจังหวัด"
noResultsText="ไม่พบข้อมูล"
data-test="district-input"
#input="onDistrictSelected"
zIndex="20000"
:clearable="false"
:allowClearingDisabled="true"
/>
</div>
</div>

stacked bar chart using angular-highchart

var array= [{ name: "LTNS", id: 1, percentage: 60, price: 900000 },
{ name: "NPCS", id: 2, percentage: 30, price: 342000 },
{ name: "MARCOS", id: 3, percentage: 10, price: 600000 }]
Using above array i need build stacked bar chart in angular-highchart and result should be like below.
I am using angular-highchart 7.2.0 version.
I have seen lots reference but nothing is same as above.
I think that you can start from this approach:
var array = [{
name: "LTNS",
id: 1,
percentage: 60,
price: 900000
},
{
name: "NPCS",
id: 2,
percentage: 30,
price: 342000
},
{
name: "MARCOS",
id: 3,
percentage: 10,
price: 600000
}
].reverse();
array.forEach(obj => {
obj.data = [obj.percentage]
})
Highcharts.chart('container', {
chart: {
type: 'bar'
},
plotOptions: {
bar: {
stacking: 'normal',
groupPadding: 0.2
}
},
series: array
});
Demo: https://jsfiddle.net/BlackLabel/d9xrgeka/
If you will face an issue implementing other features, please ask a specific question.

Dynamically filtering an array of objects with n filter criteria

I have an array of objects (data), and I need to filter this array based on filter criteria (criteria) where each criteria can have multiple values.
var data = [
{ ID: 1, Name: "John", Color: "Blue", Location: "Up" },
{ ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
{ ID: 3, Name: "Ahmed", Color: "Orange", Location: "Left" },
{ ID: 4, Name: "Diego", Color: "Pink", Location: "Up" },
{ ID: 5, Name: "Maria", Color: "Black", Location: "Down" },
{ ID: 6, Name: "Gus", Color: "Green", Location: "Up" },
{ ID: 7, Name: "Brian", Color: "Pink", Location: "Left" },
{ ID: 8, Name: "Shelley", Color: "Green", Location: "Right" },
{ ID: 9, Name: "Leonardo", Color: "Blue", Location: "Right" },
{ ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" }
];
var criteria = [
{ Field: "Color", Values: ["Green"] },
{ Field: "Location", Values: ["Up", "Down"] }
];
I need an array of object (filtered) in such a way that
1. each filter criteria is treated as "AND"
2. multiple filter values in a filter field are treated as "OR". So this is how the output should be:
var filtered = [
{ ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
{ ID: 6, Name: "Gus", Color: "Green", Location: "Up" },
{ ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" }
];
You can use Array.every for AND condition and array.indexOf for OR condition.
Note, indexOf is case sensitive. If you want make it case insensitive, you can transform both values to lower case and compare
var data = [
{ ID: 1, Name: "John", Color: "Blue", Location: "Up" },
{ ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
{ ID: 3, Name: "Ahmed", Color: "Orange", Location: "Left" },
{ ID: 4, Name: "Diego", Color: "Pink", Location: "Up" },
{ ID: 5, Name: "Maria", Color: "Black", Location: "Down" },
{ ID: 6, Name: "Gus", Color: "Green", Location: "Up" },
{ ID: 7, Name: "Brian", Color: "Pink", Location: "Left" },
{ ID: 8, Name: "Shelley", Color: "Green", Location: "Right" },
{ ID: 9, Name: "Leonardo", Color: "Blue", Location: "Right" },
{ ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" },
{ ID: 11, Name: "Dummy", Color: ["Green", "Orange"], Location: "Down" }
];
var criteria = [
{ Field: "Color", Values: ["Green"] },
{ Field: "Location", Values: ["Up", "Down"] }
];
var result = data.filter(function(obj){
return criteria.every(function(c){
var value = obj[c.Field];
if(typeof value === 'object') {
return Object.keys(value).some(function(key){
return c.Values.indexOf(value[key]) > -1
})
}
else
return c.Values.indexOf(value) > -1
})
})
console.log(result)
Array.some provides true for any match , and false for every mismatch. We expect a false and then negate it, so that our filter criteria for the original data is correct.
filteredData = data.filter(d =>
!(criteria.some(criterion =>
criterion.Values.indexOf(d[criterion.Field]) === -1
))
)

Categories