app/src/components/TermVis.js
// NOTE: boundingBoxes is around the text element.
boundingBoxes is around the text element.
boundingBoxes is around the text element .
_computeLayout(terms, xScale, termPadding, termHeight, termMargin, topMargin, boundingBoxes) {
    const layout = terms.map((term, i) => {
      const boundingBox = boundingBoxes && boundingBoxes[term.term];
      let width;
      if (boundingBox) {
        width = Math.ceil(boundingBox.width) + 2 * termPadding;
      } else {
        const termStr = term.term;
        width = termStr.length * 3 + 2 * termPadding; 
      }
      return {
        term: term.term,
        x: xScale(d3.mean(term.timestamps)) - (width / 2),
        y: topMargin,
        width,
        height: termHeight
      };
    });
    if (!boundingBoxes) {
      return layout;
    }
    function collides(box1, box2) {
      if (box2.y >= box1.y && box2.y <= (box1.y + box1.height)) {
        const leftEdgeInside = box2.x >= box1.x && box2.x <= (box1.x + box1.width);
        const rightEdgeInside = (box2.x + box2.width) >= box1.x && (box2.x + box2.width) <= (box1.x + box1.width);
        const leftEdgeLeft = box2.x < box1.x;
        const rightEdgeRight = (box2.x + box2.width) > (box1.x + box1.width);
        if (leftEdgeInside || rightEdgeInside || (leftEdgeLeft && rightEdgeRight)) {
          return true;
        }
      }
      return false;
    }
    layout.map((termBox, i) => {
      for (let j = 0; j < i; j++) {
        const otherTermBox = layout[j];
        if (collides(termBox, otherTermBox)) {
          termBox.y = otherTermBox.y + otherTermBox.height + termMargin;
          j = 0;
        }
      }
    });
    return layout;
  }
_computeLayout ( terms , xScale , termPadding , termHeight , termMargin , topMargin , boundingBoxes ) { const layout = terms . map ( ( term , i ) => { const boundingBox = boundingBoxes && boundingBoxes [ term . term ] ; let width ; if ( boundingBox ) { width = Math . ceil ( boundingBox . width ) + 2 * termPadding ; } else { const termStr = term . term ; width = termStr . length * 3 + 2 * termPadding ; } return { term : term . term , x : xScale ( d3 . mean ( term . timestamps ) ) - ( width / 2 ) , y : topMargin , width , height : termHeight } ; } ) ; if ( ! boundingBoxes ) { return layout ; } function collides ( box1 , box2 ) { if ( box2 . y >= box1 . y && box2 . y <= ( box1 . y + box1 . height ) ) { const leftEdgeInside = box2 . x >= box1 . x && box2 . x <= ( box1 . x + box1 . width ) ; const rightEdgeInside = ( box2 . x + box2 . width ) >= box1 . x && ( box2 . x + box2 . width ) <= ( box1 . x + box1 . width ) ; const leftEdgeLeft = box2 . x < box1 . x ; const rightEdgeRight = ( box2 . x + box2 . width ) > ( box1 . x + box1 . width ) ; if ( leftEdgeInside || rightEdgeInside || ( leftEdgeLeft && rightEdgeRight ) ) { return true ; } } return false ; } layout . map ( ( termBox , i ) => { for ( let j = 0 ; j < i ; j ++ ) { const otherTermBox = layout [ j ] ; if ( collides ( termBox , otherTermBox ) ) { termBox . y = otherTermBox . y + otherTermBox . height + termMargin ; j = 0 ; } } } ) ; return layout ; }
NOTE: boundingBoxes is around the text element.
NOTE : boundingBoxes is around the text element .
// compute x values and width // use bounding box if we have already calculated it // crude approximation for now // within vertical region // within horizontally (more complex due to variable width) // check all the terms that came before it to check if they collide // we need to restart the check loop each time there is a collision since // by moving the box we may have collided with boxes that we have already checked. // we only will adjust y position to avoid collisions, since x encodes time // recheck all boxes to ensure no new collisions as a result of changing position