Related
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"));
I have a horizontal stacked bars with 3 labels with the same order for the colors. I would like to know how can I reverse the color order for the first label only so that it goes from dark blue to dark red and keep the same color flow for label 2 and 3.
https://jsfiddle.net/samwhite/s9yzuqd5/
var colors = ['#93003a', '#f4777f', '#ffb040', '#a5d5d8', '#00429d'];
var def_color = '#d3d3d3';
let labels = [
"In my organization, more emphasis is placed on quantity of work than on the quality of work",
"My Division/Office/Region is making real, meaningful progress on diversity, inclusion, and opportunity in our workplace",
"In my Division/Office/Region, I am given a fair opportunity to work on visible, career-enhancing assignments"
];
// Construct the chart
let chart = Highcharts.chart('container1_1', {
...
yAxis: {
title: { text: 'Response Rate' },
max: 100,
maxPadding: 0,
labels: {
format: '{value}%'
},
gridLineWidth: 0,
minorGridLineWidth: 0
},
...
xAxis: {
categories: labels,
labels: {
style: {
fontSize: '1em',
color: '#000',
width: 370,
float: 'left'
}
}
},
series: [{
name: 'Strongly Agree',
color: colors[4],
data: []
}, {
name: 'Agree',
color: colors[3],
data: []
}, {
name: 'Neither Agree nor Disagree',
color: colors[2],
data: []
}, {
name: 'Disagree',
color: colors[1],
data: []
}, {
name: 'Strongly Disagree',
color: colors[0],
data: []
}]
});
Added Color on each data set to work in the color scheme needed based on the index
you can see the reference here: https://api.highcharts.com/highcharts/series.bar.data
{
name: tooltip_titles[s],
color: colors[Math.abs(s - 4)],
y: dept_data["102"][4-s]
},
Old - https://jsfiddle.net/jouwsLn0/
New - https://jsfiddle.net/js1bfxe5/1/
series: [{
name: 'Strongly Agree',
color: colors[4],
data: []
}, {
name: 'Agree',
color: colors[3],
data: []
}, {
name: 'Neither Agree nor Disagree',
color: colors[2],
data: []
}, {
name: 'Disagree',
color: colors[1],
data: []
}, {
name: 'Strongly Disagree',
color: colors[0],
data: []
}]
});
$("#filterOrganization").change(function () {
$(this).find("option:selected")
.each(function () {
var optionValue = $(this).text();
let dept_data = data[optionValue];
chart.series.forEach((series, s) => {
console.log(s);
console.log(dept_data["102"][4-s]);
series.setData([
{
name: tooltip_titles[s],
color: colors[Math.abs(s - 4)],
y: dept_data["102"][4-s]
},
{
name: tooltip_titles[s],
color: colors[s],
y: dept_data["104"][4-s]
},
{
name: tooltip_titles[s],
color: colors[s],
y: dept_data["105"][4-s]
}]);
});
});
}).change();
I have a packed bubble chart that works great. I would like to add a title to each of the larger, separated bubbles. The title should always show and I would like it to be the name of the series. I'm using a split series.
The 'name' attribute shows up in the tooltip, but I would like it to always be displayed.
Here is the code to create the bubbles:
Highcharts.chart('bubble-split-chart', {
chart: {
type: 'packedbubble',
animation: false,
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
stops: [
[0, '#15191b'],
[1, '#15191b']
]
},
},
// remove hamburger button
exporting: {
enabled: false
},
// remove chart watermark (highcharts.com)
credits: {
enabled: false
},
title: {
text: '',
enabled: false
},
tooltip: {
useHTML: true,
pointFormat: '<b>{point.name}</b>'
},
plotOptions: {
packedbubble: {
minSize: '1%',
maxSize: '100%',
zMin: 1,
zMax: 400,
layoutAlgorithm: {
enableSimulation: false,
gravitationalConstant: 0.05,
splitSeries: true,
seriesInteraction: false,
dragBetweenSeries: false,
parentNodeLimit: true
}
},
legend: {
enabled: false
}
},
series: [{
name: 'Test',
data: [{
name: "Lorem",
value: 29.4,
color: 'red'
},
{
name: "Ipsum",
value: 34.1,
color: 'blue'
},
{
name: "Dolor",
value: 7.1,
color: 'green'
}],
}, {
name: 'Test 2',
data: [{
name: 'Lorem',
value: 300.1,
color: 'red'
},
{
name: 'Ipsum',
value: 20.7,
color: 'blue'
},
{
name: "Dolor",
value: 97.2,
color: 'green'
}],
}, {
name: 'Test 3',
data: [{
name: "Lorem",
value: 8.2,
color: 'red'
},
{
name: "Ipsum",
value: 9.2,
color: 'blue'
},
{
name: "Dolor",
value: 13.1,
color: 'green'
}],
}]
});
Is this possible? Also, if this is possible, how can I remove the name from the tooltip?
You can add the labels by using annotations or Highcharts.SVGRenderer class.
To remove the series name from tooltip set:
tooltip: {
headerFormat: '',
...
}
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4771/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer
https://api.highcharts.com/highcharts/annotations
https://api.highcharts.com/highcharts/tooltip.headerFormat
First: Thanks for reading, but there is a lot in this, it may be easier to see it in the CodePen examples that are linked at the bottom.
I recently asked a question about how to dynamically create an array for a treemap, and was pointed in the right direction. I have been able to do some simple manipulation to the hash table, but can't figure out how to do the final step.
Currently the treemap has 2 "levels", that was done like this:
var data=[{color:"blue",party:"Democratic",text:"California",value:55},{color:"blue",party:"Democratic",text:"Oregon",value:7},{color:"red",party:"Republican",text:"Texas",value:38},{color:"red",party:"Republican",text:"Georgia",value:16},{color:"grey",party:"Democratic",text:"Arizona",value:11}];
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (hash[curr.color]) {
hash[curr.color].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
} else {
hash[curr.color] = {};
hash[curr.color].children = hash[curr.color].children || [];
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.color].children
});
hash[curr.color].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
return prev;
};
}(Object.create(null)), []);
Now, what I'm trying to do is bring an additional criteria and add another level. For example, under "Republican" and "Democratic" you'd have subcategories for "Likely", "Leaning", and "Tipping" but for "Toss Up" you wouldn't have any of those.
Here is the end result that I'm trying to make:
series: [{
text: "Democratic",
style: { "backgroundColor": "blue" },
children: [{
text: "Likely",
style: { "backgroundColor": "darkblue" },
children: [{
text: "Alabama",
value: 8,
style: { "backgroundColor": "darkblue" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "darkblue" },
}]
}, {
text: "Leaning",
style: { "backgroundColor": "blue" },
children: [{
text: "Florida",
value: 9,
style: { "backgroundColor": "blue" },
}, {
text: "North Carolina",
value: 6,
style: { "backgroundColor": "blue" },
}]
}, {
text: "Tipping",
style: { "backgroundColor": "lightblue" },
children: [{
text: "Utah",
value: 4,
style: { "backgroundColor": "lightblue" },
}, {
text: "Idaho",
value: 5,
style: { "backgroundColor": "lightblue" },
}]
}]
},
{ text: "Republican",
style: { "backgroundColor": "red" },
children: [{
text: "Likely",
style: { "backgroundColor": "darkred" },
children: [{
text: "alabama",
value: 13,
style: { "backgroundColor": "darkred" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "darkred" },
}]
}, {
text: "Leaning",
style: { "backgroundColor": "red" },
children: [{
text: "Florida",
value: 9,
style: { "backgroundColor": "red" },
}, {
text: "North Carolina",
value: 6,
style: { "backgroundColor": "red" },
}]
}, {
text: "Tipping",
style: { "backgroundColor": "lightred" },
children: [{
text: "Utah",
value: 27,
style: { "backgroundColor": "lightred" },
}, {
text: "Idaho",
value: 12,
style: { "backgroundColor": "lightred" },
}]
}]
}, {
text: "Toss Up",
style: { "backgroundColor": "grey" },
children: [{
text: "alabama",
value: 10,
style: { "backgroundColor": "grey" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "grey" },
}]
},
]
};
I have been trying to figure out how to modify the example I was given to do that, but have been failing for hours. I'm not sure what I should be looking up. I think in the Else statement inside the "prev.push" (line 2040 here) is where the adjustment should be happening, but I don't know how to implement it, I also suspect I need to change the whole approach.
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (hash[curr.party]) {
console.log("if: " + curr.party + " " + curr.category);
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
else {
console.log("else: " + curr.party + " " + curr.category);
hash[curr.party] = {};
hash[curr.party].children = hash[curr.party].children || [];
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.party].children // children: [{ text: curr.category, children: [{ }] }]
});
hash[curr.category] = {};
hash[curr.category].children = hash[curr.category].children || [];
console.log("category");
prev.push({
text: curr.category,
style: {
backgroundColor: curr.color
},
children: hash[curr.category].children
});
}
return prev;
};
}(Object.create(null)), []);
To wrap up:
Here is a CodePen of the basic structure of the goal
Here is my current code
Earlier the classification was being done based on color, seeing your data I guess we can do it based on party now. As there is another level added to the tree, we can classify that based on category.
So there are many changes - see demo below:
var data = [{"text":"California","value":55,"color":"#000066","party":"Democratic","compare":1,"category":"Likely"},{"text":"Connecticut","value":7,"color":"#000066","party":"Democratic","compare":1,"category":"Likely"},{"text":"Colorado","value":9,"color":"#3333CC","party":"Democratic","compare":2,"category":"Leaning"},{"text":"Florida","value":29,"color":"#9999FF","party":"Democratic","compare":3,"category":"Tipping"},{"text":"Iowa","value":6,"color":"red","party":"Republican","compare":4,"category":"Likely"},{"text":"Alabama","value":9,"color":"#CC3333","party":"Republican","compare":5,"category":"Leaning"},{"text":"Alaska","value":3,"color":"#FF9999","party":"Republican","compare":6,"category":"Tipping"},{"text":"Arizona","value":11,"color":"#666666","party":"Toss-Up","compare":7,"category":"Toss Up"},{"text":"Texas","value":11,"color":"#666666","party":"Toss-Up","compare":7,"category":"Toss Up"}];
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (!hash[curr.party]) {
hash[curr.party] = {};
hash[curr.party].children = hash[curr.party].children || [];
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.party].children
});
} else if (hash[curr.party] && hash[curr.party][curr.category]) {
hash[curr.party][curr.category].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
if (hash[curr.party] && !hash[curr.party][curr.category]) {
if (curr.category == "Toss Up") {
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
} else {
hash[curr.party][curr.category] = {};
hash[curr.party][curr.category].children = hash[curr.party][curr.category].children || [];
hash[curr.party].children.push({
text: curr.category,
style: {
backgroundColor: curr.color
},
children: hash[curr.party][curr.category].children
});
hash[curr.party][curr.category].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
}
return prev;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper {top: 0;max-height: 100%!important;}
I am currently using GOjs library's new graph which is the swimlane.
My problem is I want to add DIFFERENT styles to each node (like, one node has a bg-color of red, the other is blue, others are green and etc). Anyone knows how to do this?
Any help is greatly appreciated. Or anyone can suggest another library that does my thing.
As you haven't posted your code Ill be working off the swinlane examples (http://www.gojs.net/latest/samples/swimlanes.html).
If you have a look at the documentation for nodes (http://gojs.net/beta/intro/nodes.html) you can see how they are changing the color there.
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Rectangle",
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 5 },
new go.Binding("text", "key"))
);
diagram.model.nodeDataArray = [
{ key: "Alpha", color: "lightblue" }
];
In the swimlane example they have the following relevant code:
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Rectangle",
{ fill: "white", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true }),
$(go.TextBlock, { margin: 5 },
new go.Binding("text", "key")),
// limit dragging of Nodes to stay within the containing Group, defined above
{
dragComputation: stayInGroup,
mouseDrop: function (e, node) { // dropping a copy of some Nodes and Links onto this Node adds them to this Node's Group
if (!e.shift && !e.control) return; // cannot change groups with an unmodified drag-and-drop
var grp = node.containingGroup;
if (grp !== null) {
var ok = grp.addMembers(node.diagram.selection, true);
if (!ok) grp.diagram.currentTool.doCancel();
}
},
layoutConditions: go.Part.LayoutAdded | go.Part.LayoutNodeSized
}
);
myDiagram.model = new go.GraphLinksModel(
[ // node data
{ key: "Lane1", isGroup: true, color: "lightblue" },
{ key: "Lane2", isGroup: true, color: "lightgreen" },
{ key: "Lane3", isGroup: true, color: "lightyellow" },
{ key: "Lane4", isGroup: true, color: "orange" },
{ key: "oneA", group: "Lane1" },
{ key: "oneB", group: "Lane1" },
{ key: "oneC", group: "Lane1" },
{ key: "oneD", group: "Lane1" },
{ key: "twoA", group: "Lane2" },
{ key: "twoB", group: "Lane2" },
{ key: "twoC", group: "Lane2" },
{ key: "twoD", group: "Lane2" },
{ key: "twoE", group: "Lane2" },
{ key: "twoF", group: "Lane2" },
{ key: "twoG", group: "Lane2" },
{ key: "fourA", group: "Lane4" },
{ key: "fourB", group: "Lane4" },
{ key: "fourC", group: "Lane4" },
{ key: "fourD", group: "Lane4" },
],
[ // link data
{ from: "oneA", to: "oneB" },
{ from: "oneA", to: "oneC" },
{ from: "oneB", to: "oneD" },
{ from: "oneC", to: "oneD" },
{ from: "twoA", to: "twoB" },
{ from: "twoA", to: "twoC" },
{ from: "twoA", to: "twoF" },
{ from: "twoB", to: "twoD" },
{ from: "twoC", to: "twoD" },
{ from: "twoD", to: "twoG" },
{ from: "twoE", to: "twoG" },
{ from: "twoF", to: "twoG" },
{ from: "fourA", to: "fourB" },
{ from: "fourB", to: "fourC" },
{ from: "fourC", to: "fourD" }
]);
To allow each node their own fill color you change the line
{ fill: "white", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true }),
to
{ fill: "lightblue", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true },
new go.Binding("fill", "color")),
After making those changes you can then specify what fill colors you want in the node data. Note that I changed the original fill value above to lighblue. Now lightblue will be the default color if you do not specify a color for a node (fourD will be lightblue):
myDiagram.model = new go.GraphLinksModel(
[ // node data
{ key: "Lane1", isGroup: true, color: "lightblue" },
{ key: "Lane2", isGroup: true, color: "lightgreen" },
{ key: "Lane3", isGroup: true, color: "lightyellow" },
{ key: "Lane4", isGroup: true, color: "orange" },
{ key: "oneA", group: "Lane1", color: "green" },
{ key: "oneB", group: "Lane1", color: "red" },
{ key: "oneC", group: "Lane1", color: "yellow" },
{ key: "oneD", group: "Lane1", color: "purple" },
{ key: "twoA", group: "Lane2", color: "orange" },
{ key: "twoB", group: "Lane2", color: "green" },
{ key: "twoC", group: "Lane2", color: "red" },
{ key: "twoD", group: "Lane2", color: "yellow" },
{ key: "twoE", group: "Lane2", color: "purple" },
{ key: "twoF", group: "Lane2", color: "orange" },
{ key: "twoG", group: "Lane2", color: "green" },
{ key: "fourA", group: "Lane4", color: "red" },
{ key: "fourB", group: "Lane4", color: "yellow" },
{ key: "fourC", group: "Lane4", color: "purple" },
{ key: "fourD", group: "Lane4" },
],
[ // link data
{ from: "oneA", to: "oneB" },
{ from: "oneA", to: "oneC" },
{ from: "oneB", to: "oneD" },
{ from: "oneC", to: "oneD" },
{ from: "twoA", to: "twoB" },
{ from: "twoA", to: "twoC" },
{ from: "twoA", to: "twoF" },
{ from: "twoB", to: "twoD" },
{ from: "twoC", to: "twoD" },
{ from: "twoD", to: "twoG" },
{ from: "twoE", to: "twoG" },
{ from: "twoF", to: "twoG" },
{ from: "fourA", to: "fourB" },
{ from: "fourB", to: "fourC" },
{ from: "fourC", to: "fourD" }
]);