1

I am working on some collision detection for value labels in a d3 chart. This is my collision detection algo:

  isOverlap: (firstRect, secondRect) ->

    # Position of bottom-left coordinate of current rect
    x1 = firstRect.left
    y1 = firstRect.top

    # Position of top-right coordinate of current rect
    x2 = firstRect.right
    y2 = firstRect.bottom

    # Position of bottom-left coordinate of second rect
    x3 = secondRect.left
    y3 = secondRect.top

    # Position of top-right coordinate of second rect
    x4 = secondRect.right
    y4 = secondRect.bottom

    # Basic collision detection algorithm comparing two coordinates of the first
    # rectangle to the two coordinates of the second rectangle
    # Check this for full explanation: http://stackoverflow.com/a/32088787/1913389
    #         _________________  x2, y2
    #        |                 |
    #        |                 |
    #        |                 |
    #        |                 |
    # x1, y1 |_________________|

    !(x3 > x2 || y3 > y2 || x1 > x4 || y1 > y4)

Right now I have two dilemmas.

Delimma #1:

One graph isn't as aggressive in its value label collision detection:

enter image description here

As you can see, value labels that are too close overlap because in my code, I remove the point that causes collision, so there is no more comparison between that node and another. This is the code:

  removeOverlappingLabelText: ->
    valueLabelPositions = []
    d3.selectAll('.value-labels text')[0].forEach (t) =>
      currentRect = t.getBoundingClientRect()

      for previousRect, indexOfRect in valueLabelPositions
        isRemoved = false
        if @isOverlap(currentRect, previousRect)
          t.remove()
          isRemoved = true
          valueLabelPositions.splice(indexOfRect, 1)
          break

      if !isRemoved
        valueLabelPositions.push(currentRect)

Dilemma #2

The second graph is too aggressive, as it compares inexistent points that shouldn't be compared again, and it hides too much:

enter image description here

Here is the code:

  removeOverlappingLabelText: ->
    valueLabelPositions = []
    d3.selectAll('.value-labels text')[0].forEach (t) =>
      currentRect = t.getBoundingClientRect()

      for previousRect, indexOfRect in valueLabelPositions
        isRemoved = false
        if @isOverlap(currentRect, previousRect)
          t.remove()
          isRemoved = true
          valueLabelPositions.splice(indexOfRect, 1)
          break

      valueLabelPositions.push(currentRect)

For dilemma #1, that issue happens because we don't add the currentRect if it overlaps with a previous rectangle. And so, if the next currentRect collides with the previous currectRect, it wouldn't know.

The issue with dilemma #2, we add all rectangles to the array, even if the rectangle doesn't collide with visible rectangles. So the code interprets that there is a collision with non-visible rectangles.

I'm not really sure what to do, and would love some help - thanks!

theGreenCabbage
  • 5,197
  • 19
  • 79
  • 169

0 Answers0