chartjs-plugin-datalabels icon indicating copy to clipboard operation
chartjs-plugin-datalabels copied to clipboard

Collision

Open EmilMoe opened this issue 6 years ago • 7 comments

I am using datalabels on my bubble chart, but sometimes the bubbles and datalabels collide. Is there any solution to fix collision or detect when they are overlapping?

I can see that in the path chart > $datalabels > labels > [1] > [..n] > Label > _hitbox > _rect I have this

cx: 434.368
cy: 74.09599999999998
x0: 388.0193671875
x1: 481.7166328125
y0: 58.69599999999998
y1: 90.49599999999998

Should I check if there's something overlapping there?

update

I can see a problem with this approach as the _rect isn't updated until there has been a mouse over.

EmilMoe avatar Jul 05 '18 00:07 EmilMoe

Isn't it the same issue as #49 and #55 but for bubble charts? If not, can you provide a jsfiddle that showcases your issue. Anyway, $datalabels and everything prefixed by _ is private and should not be accessed in production code since it could break without notice in upcoming minor/patch releases.

simonbrunel avatar Jul 05 '18 06:07 simonbrunel

Thanks. Looks like same issues but I see no solutions though. Will try to find the properties from a variable without _ in front, but I don't know if that's possible. Also I need to figure out how to update the labels location.

Will be happy to share a jsfiddle later, but for now it's integrated in a vue component so a lot of extra code around it.

EmilMoe avatar Jul 05 '18 08:07 EmilMoe

I have been looking and seems to be nearly no public API then I can access?

This is how far I am in the code

detectCollisions(context) {
                if (this.hasCheckedForCollisions)
                    return

                let rectangles = []

                context.chart.$datalabels.labels[0].forEach(label => {
                    if (label._hitbox._rect) {
                        rectangles.push(this.getBoundaries(label._hitbox._rect, label.$context.dataset.data[label.$context.dataIndex].r))
                        this.hasCheckedForCollisions = true
                    }
                })

                if (this.hasCheckedForCollisions)
                    this.checkAllRectangles(rectangles)
            },
            getBoundaries(rectangle, importance) {
                return {
                    x: rectangle.x0,
                    y: rectangle.y0,
                    w: rectangle.x1 - rectangle.x0,
                    h: rectangle.y1 - rectangle.y0,
                    i: importance,
                }
            },
            checkAllRectangles(rectangles) {
                rectangles.forEach((r1, i1) => {
                    if (i1 === rectangles.length - 1)
                        return

                    rectangles.forEach((r2, i2) => {
                        if (this.isEqualRectangles(r1, r2))
                            return

                    if (this.isColliding(r1, r2))
                        this.handleCollision(r1, r2)
                    })
                })
            },
            isColliding(rect1, rect2) {
                if (rect1.x < rect2.x + rect2.w &&
                    rect1.x + rect1.w > rect2.x &&
                    rect1.y < rect2.y + rect2.h &&
                    rect1.h + rect1.y > rect2.y)
                    return true

                return false
            },
            isEqualRectangles(rect1, rect2) {
                return rect1.x === rect2.x && rect1.y === rect2.y && rect1.h === rect2.h && rect1.w === rect2.w
            },
            handleCollision(rect1, rect2) {
                console.log(rect1)
                rect1.y = rect1.h + rect2.y
                console.log(rect1)
            }

EmilMoe avatar Jul 06 '18 04:07 EmilMoe

I have been looking and seems to be nearly no public API then I can access?

No because the plugin is still in beta and I don't want to commit on implementation details. I'm currently rewriting the whole layouting part and moved the _hitbox outside the label so your previous implementation will break at the next release.

Anyway, I'm currently looking to introduce a new option to prevent labels to overlap and I'm wondering what is your expected behavior when 2 labels overlap?

simonbrunel avatar Nov 14 '18 21:11 simonbrunel

I have been looking and seems to be nearly no public API then I can access?

No because the plugin is still in beta and I don't want to commit on implementation details. I'm currently rewriting the whole layouting part and moved the _hitbox outside the label so your previous implementation will break at the next release.

Anyway, I'm currently looking to introduce a new option to prevent labels to overlap and I'm wondering what is your expected behavior when 2 labels overlap?

A good solution is what Amcharts does... image

krosskawasaki avatar May 10 '21 21:05 krosskawasaki

I'm having the same issue and while I find generic or D3 solutions (here for example), they are difficult to implement for Chart.js as the algorithms aren't simple.

I'm using a bubble chart and it's becoming an increasingly worse issue while the amount of our data is getting bigger. Do we still have any kind of solution for this?

image

naftis avatar May 13 '22 07:05 naftis

I'm having the same issue and while I find generic or D3 solutions (here for example), they are difficult to implement for Chart.js as the algorithms aren't simple.

I'm using a bubble chart and it's becoming an increasingly worse issue while the amount of our data is getting bigger. Do we still have any kind of solution for this?

image

I switched to apex charts as they are more modern, maybe it's fixed the

EmilMoe avatar May 13 '22 07:05 EmilMoe