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:
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:
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!