Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

210
Views
How to calculate row- and colspans dynamically?

I'm using a table component from a UI framework that generates me the following headers

enter image description here

based on this configuration

(final result)

[
  [
    {
      "title": "Section 1",
      "rowspan": "4",
      "colspan": "1"
    },
    {
      "title": "Section 2",
      "rowspan": "1",
      "colspan": "2"
    },
    {
      "title": "Section 3",
      "rowspan": "1",
      "colspan": "3"
    },
    {
      "title": "Section 4",
      "rowspan": "1",
      "colspan": "1"
    }
  ],
  [
    {
      "title": "Section 2.1",
      "rowspan": "3",
      "colspan": "1"
    },
    {
      "title": "Section 2.2",
      "rowspan": "3",
      "colspan": "1"
    },
    {
      "title": "Section 3.1",
      "rowspan": "3",
      "colspan": "1"
    },
    {
      "title": "Section 3.2",
      "rowspan": "1",
      "colspan": "2"
    },
    {
      "title": "Section 4.1",
      "rowspan": "1",
      "colspan": "1"
    }
  ],
  [
    {
      "title": "Section 3.2.1",
      "rowspan": "2",
      "colspan": "1"
    },
    {
      "title": "Section 3.2.2",
      "rowspan": "2",
      "colspan": "1"
    },
    {
      "title": "Section 4.1.1",
      "rowspan": "1",
      "colspan": "1"
    }
  ],
  [
    {
      "title": "Section 4.1.1.1",
      "rowspan": "1",
      "colspan": "1"
    }
  ]
]

I want to simplify the configuration. There should be just a tree like structure and I want to calculate the row- and colspans dynamically

(starting point)

[
  {
    "title": "Section 1"
  },
  {
    "title": "Section 2",
    "children": [
      {
        "title": "Section 2.1"
      },
      {
        "title": "Section 2.2"
      }
    ]
  },
  {
    "title": "Section 3",
    "children": [
      {
        "title": "Section 3.1"
      },
      {
        "title": "Section 3.2",
        "children": [
          {
            "title": "Section 3.2.1"
          },
          {
            "title": "Section 3.2.2"
          }
        ]
      }
    ]
  },
  {
    "title": "Section 4",
    "children": [
      {
        "title": "Section 4.1",
        "children": [
          {
            "title": "Section 4.1.1",
            "children": [
              {
                "title": "Section 4.1.1.1"
              }
            ]
          }
        ]
      }
    ]
  }
]

I thought about how to map the starting point array to the final result array. These are my assumptions:

  • Traverse the array recursively
  • Calculate the colspan (width) like so
    • if there are no children => 1
    • if there are any children => sum of colspans from all children of the next depth
  • Calculate the rowspan (height)
    • if there are no children => maximum depth from the whole tree - current depth
    • if there are any children => 1

My current approach

const configuredHeaders = [{
    title: "Section 1"
},
{
    title: "Section 2",
    children: [{
            title: "Section 2.1"
        },
        {
            title: "Section 2.2"
        }
    ]
},
{
    title: "Section 3",
    children: [{
            title: "Section 3.1"
        },
        {
            title: "Section 3.2",
            children: [{
                    title: "Section 3.2.1"
                },
                {
                    title: "Section 3.2.2"
                }
            ]
        }
    ]
},
{
    title: "Section 4",
    children: [{
        title: "Section 4.1",
        children: [{
            title: "Section 4.1.1",
            children: [{
                title: "Section 4.1.1.1"
            }]
        }]
    }]
}];

const finalHeaders = [];

traverseColumnHeaders(configuredHeaders, -1); // first depth should start with 0

function traverseColumnHeaders(headers, parentDepth) {
    headers.forEach(header => {
        header.currentDepth = parentDepth + 1;
        
        if (header.children) {
            traverseColumnHeaders(header.children, header.currentDepth);
            
            header.colspan = header.children.reduce((currentSum, child) => currentSum + child.colspan, 0); // sum of child colspans
            header.rowspan = 1;
        } else {
            header.colspan = 1;

            // header.rowspan =     ... maximum depth - header.currentDepth ...
        }

        addHeaderToFinalHeaders(header);
    });
}

function addHeaderToFinalHeaders({ currentDepth, title, rowspan, colspan }) {
    const depthExistsInFinalHeaders = currentDepth in finalHeaders;
    
    if (!depthExistsInFinalHeaders) {
        finalHeaders[currentDepth] = [];
    }

    finalHeaders[currentDepth].push({ title, rowspan, colspan });
}

console.log(finalHeaders);

This one looks quite good to me because I only need to traverse the collection once. But as you can see some rowspan fields are not calculated yet because I don't know the maximum depth at this point.

To solve this I could initialize a global variable, search for the maximum depth like so

(I took the solution from here Getting the depth of a tree data structure in a simpler way for now)

function getMaximumDepth(headers) {
    return getDepth(headers) -1;
};

function getDepth(headers) {
    return 1 + Math.max(0, ...headers.map(({ children = [] }) => getDepth(children)));
}

const maximumDepth = getMaximumDepth(configuredHeaders);

and calculate

header.rowspan = maximumDepth - header.currentDepth

but now I have to traverse the structure twice. Is there a way to optimize my solution?

over 4 years ago · Santiago Trujillo
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!