title: Return Optimized x coordinates to normalize/maximize area for an array of rectangles with defined y positions
body: <p>I've included a code snippet that hopefully should sum things up nicely and is represented in a sort of 'Fill in the blanks' kind of state.</p>
  
  <p>If it helps to understand the origin of the problem by seeing it in a larger context, what I'm ultimately doing is showing a daily view schedule on calendar on a phone, probably similar to how the calendar on your phone works.  When events begin to overlap in time, represented by the vertical y axis here I want to be able to optimize the width and positioning of those events, not overlapping them and not hiding more than I have to for the content - but when there are too many being able to indicate things are hidden.</p>
  
  <p>I'm not looking for any CSS/HTML based solutions despite the sample being in javascript - the DOM structure is more or less set in stone, just looking for an algorithm that might do what I'm looking for, if it's in C++, TurboPascal, Assembly, Java, whatever doesn't really matter.  In my example expected results the more complex the scenario the results are more like rough estimates, and it comes across in the demo as well when rendering my expected results - I don't even really have a terrific method for doing the math in my head once things start getting weird.</p>
  
  <p>The objective is to fill in the function <code>optimizeLeftAndRightXStartPointsForNormalizedRectangleAreaWithoutOverlapping = (rectangles,minimumArea,minimumWidth,xMin,xMax)=&gt;{}</code></p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>// Let's say I have an array like this of rectangles where they have set y coordinates
  // Some constraints on how this array comes out: it will besorted by the yTop property as shown below, but with no secondary sort criteria.
  // The rectangles difference between yBottom and yTop is always at least 15, in other words this array won't contain any rectangles less than 15 in height
  
  const rectanglesYcoordinatesOnlyExample1 = [
  {"rectangle_id":"b22d","yTop":0,"yBottom":60},
  {"rectangle_id":"8938","yTop":60,"yBottom":120},
  {"rectangle_id":"e78a","yTop":60,"yBottom":120},
  {"rectangle_id":"81ed","yTop":207,"yBottom":222},
  {"rectangle_id":"b446","yTop":207,"yBottom":222},
  {"rectangle_id":"ebd3","yTop":207,"yBottom":222},
  {"rectangle_id":"2caf","yTop":208,"yBottom":223},
  {"rectangle_id":"e623","yTop":227,"yBottom":242},
  {"rectangle_id":"e6a3","yTop":270,"yBottom":320},
  {"rectangle_id":"e613","yTop":272,"yBottom":460},
  {"rectangle_id":"c2d1","yTop":272,"yBottom":290},
  {"rectangle_id":"e64d","yTop":274,"yBottom":300},
  {"rectangle_id":"b653","yTop":276,"yBottom":310},
  {"rectangle_id":"e323","yTop":276,"yBottom":310},
  {"rectangle_id":"fca3","yTop":300,"yBottom":315}
  ]
  
  // I want to get a result sort of like this, explanations provided, although I'm not sure if my internal calculations in my head are 100% on the further I go.  
  
  // And I want to a run a function like so:
  // optimizeLeftAndRightXStartPointsForNormalizedRectangleAreaWithoutOverlapping(rectanglesYcoordinatesOnlyExample1,(33.3 * 15),10,0,100);  
  // I will make this call later but I need to hoist my expected results here to enable the mocking to work for now at the point of the function definiton for my example. (see below)
  // like so I'd get a result something like this, but I start becoming less certain of what the correct result should be the more I go into fringe stuff.
  
  const expectedResultMoreOrLessForExample1 = [
  {"rectangle_id":"b22d","leftX":0,"rightX":100,"yTop":0,"yBottom":60},
  {"rectangle_id":"8938","leftX":0,"rightX":50,"yTop":60,"yBottom":120},
  {"rectangle_id":"e78a","leftX":50,"rightX":100,"yTop":60,"yBottom":120},
  {"rectangle_id":"81ed","leftX":0,"rightX":33.3,"yTop":207,"yBottom":222}, // Three rectangles side by side with minimum Area ["81ed","b446","ebd3"] from this point
  {"rectangle_id":"b446","leftX":33.3,"rightX":66.6,"yTop":207,"yBottom":222},
  {"rectangle_id":"ebd3","isMax":true,"leftX":66.7,"rightX":100,"yTop":207,"yBottom":222},  // has isMax property because there would be an overlap if it tried the next result, and it can't take area away from the other rectangles
  // This rectangle gets thrown out because it would be there are 3 other rectangles in that area each with the minimum area (33.3 * 15);
  // {"rectangle_id":"2caf","yTop":208,"yBottom":223}, This one gets thrown out from the result the time being because there are too many rectangles in one area of vertical space.
  {"rectangle_id":"e623","yTop":227,"yBottom":242,"leftX":0,"rightX":100},
  {"rectangle_id":"e6a3","leftX":0,"rightX":25,"yTop":270,"yBottom":320},
  {"rectangle_id":"e613","leftX":25,"rightX":35,"yTop":272,"yBottom":460},
  {"rectangle_id":"c2d1","leftX":71.28,"rightX":100,"yTop":272,"yBottom":290},  // fill the remaining space since optimizing to max area would take 99% 
  {"rectangle_id":"e64d","leftX":35,"rightX":61.28,"yTop":274,"yBottom":300},
  {"rectangle_id":"b653","yTop":276,"yBottom":940,"leftX":61.28,rightX:71.28},
  {"rectangle_id":"fca3","leftX":35,"rightX":61.28,"yTop":300,"yBottom":315}
  ]
  
  // the function name is really long to reflect what it is what I want to do.  Don't normally make functions this intense
  
  const optimizeLeftAndRightXStartPointsForNormalizedRectangleAreaWithoutOverlapping = (rectangles,minimumArea,minimumWidth,xMin,xMax)=&gt;{
   // TODO : fill in the optimization function.
   // Code I'm looking for would be swapped in here if you wanted to make changes to demo it do it here
   if(rectangles === rectanglesYcoordinatesOnlyExample1 &amp;&amp; minimumArea === (33.3 * 15) &amp;&amp; minimumWidth === 10 &amp;&amp; xMin === 0 &amp;&amp; xMax === 100){  // Just handling the example
    return expectedResultMoreOrLessForExample1;
   } else {
    console.log('I only know how to handle example 1, as computed by a human, poorly.  fill in the function and replace the block with working stuff');
    return [];
   }
  }
  
  
  const displayResults = (completedRectangleList) =&gt; {
   const rectangleColors = ['cyan','magenta','green','yellow','orange']
   completedRectangleList.forEach((rectangle,index) =&gt;{
     let newRectangle = document.createElement('div');
     newRectangle.style.position = 'absolute';
     newRectangle.style.height = rectangle.yBottom - rectangle.yTop + 'px';
      newRectangle.style.top = rectangle.yTop + 'px';
      newRectangle.style.left = parseInt(rectangle.leftX)+'%';
      newRectangle.style.width = rectangle.rightX - rectangle.leftX + "%";
      newRectangle.style.backgroundColor = rectangleColors[index % rectangleColors.length];
      newRectangle.innerHTML = rectangle.rectangle_id;
      if(rectangle.isMax){
       newRectangle.innerHTML += '- more hidden';
      }
    document.body.appendChild(newRectangle);
  })
  }
  // I am calling this function with minimum Area of 33.3 * 15, because it represents 3 min height rectangles taking up a third of the minX,maxX values, which are 0 &amp; 100, representing a percentage value ultimately
  let resultForExample1 = optimizeLeftAndRightXStartPointsForNormalizedRectangleAreaWithoutOverlapping(rectanglesYcoordinatesOnlyExample1,(33.3 * 15),10,0,100);
  displayResults(resultForExample1);</code></pre>
  </div>
  </div>
  </p>
  
  <p>As far as what I've tried, I start something then I kind of think of fringe cases and things get a little haywire.  Even in the expected results I've calculated in my head I think my own humanized calculations are a little off, so when evaluating this issue and looking at my expectedResult and then the rendering of it, it's a little off.  Hopefully the intent and meaning behind the <code>optimizeLeftAndRightXStartPointsForNormalizedRectangleAreaWithoutOverlapping()</code> is more or less clear.  </p>
  
  <p>I'm still working on potential approaches, but in the meantime seeking out the wisdom of the crowd until it comes to me.  I'm curious as to the solution, but I haven't discovered the right track.</p>