Chartjs-plugin-datalabels: Collision

Created on 5 Jul 2018  路  4Comments  路  Source: chartjs/chartjs-plugin-datalabels

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.

enhancement

Most helpful comment

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?

All 4 comments

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.

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.

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)
            }

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?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aldipower picture aldipower  路  7Comments

dgambin picture dgambin  路  5Comments

timdiggins picture timdiggins  路  8Comments

sidv93 picture sidv93  路  3Comments

dannyBies picture dannyBies  路  5Comments