lukbukkit / chartist-plugin-tooltip

Tooltip plugin for Chartist.js
MIT License
16 stars 13 forks source link

tooltip falls off edges of chart #12

Closed travisfranklin closed 3 years ago

travisfranklin commented 3 years ago

Thanks for keeping this plugin working!

here's the problem I'm running into:

I want to use this plugin on a full-width chart spanning a full browser window, but the tooltip falls off the edges of the screen. Here's a short video example:

https://user-images.githubusercontent.com/25447934/104045840-c403c580-51a4-11eb-8665-7efaca26319e.mp4

description:

Currently, if a chart is full-width, the tooltip can extend beyond the bounds of the chart, and there isn't a way in options to resolve the issue.

potential solutions:

It's possible I've missed something, but Is there currently a way for a user to change or add a css class to the tooltip based on the point index? I could use the classes to shift the tooltip's position in relation to the mouse pointer if it gets close to the beginning or end of the point index.

Alternatively, if there's a way in options to access how tooltip position is calculated, I could probably come up with something that takes into account width of the chart, and adjusts the tooltip's coordinates slightly based on proximity to the extremities.

lukbukkit commented 3 years ago

Thanks for your bug report. This is indeed a problem which isn't easy to solve and why I would recommend to use a better supported charting library like Chart.js or if you're already using React, you could try Recharts.

But if you want to stick to Chartist, I've got an idea. You could create custom point elements as described in the last chapter of the README and assign points at the edges different classes. Then you can create multiple instances of this plugin with different pointClass properties. Finally you can add custom classes to every kind of tooltip using the class property or change the offset using the tooltipOffset property.

plugins: [
  Chartist.plugins.tooltip({
    appendToBody: true,
    pointClass: 'point-left',
    class: 'tooltip-left',
  }),
  Chartist.plugins.tooltip({
    appendToBody: true,
    pointClass: 'point-right'
    class: 'tooltip-right',
  }),
  ...
]

But be aware, that this is just an idea floating around my head, sadly I have not the time to test it. If this idea won't work, the last option would be to implement this feature in the code of this plugin, but I don't know if this is worth your time when there are better libraries out there.

Have a great day, Lukas

travisfranklin commented 3 years ago

Thank you for your speedy reply!

Your idea makes complete sense and sounds plausible to me. I'll implement it tomorrow and let you know how it goes.

travisfranklin commented 3 years ago

Here's the update!

My plugins ended up having 3 instances, one for normal points, one for points near the left edge, and one for points near the right.

plugins: [
    tooltip({
        currency: '$',
        pointClass: 'ct-point',
        appendToBody: true,
    }),
    tooltip({
        currency: '$',
        pointClass: 'ct-point__left',
        appendToBody: true,
        tooltipOffset: {
            x: +100,
            y: -20,
        },
    }),
    tooltip({
        currency: '$',
        pointClass: 'ct-point__right',
        appendToBody: true,
        tooltipOffset: {
            x: -100,
            y: -20,
        },
    }),
],

Then to add the class, I added the update to my draw function:

chart.on('draw', function(data: any) {
    if (data.type === 'point') {
        const rect: any = new Chartist.Svg('rect', {
            'ct:value': data.value.y,
            'ct:meta': data.axisX.ticks[data.index],
            style: `pointer-events: all !important; stroke-width: ${ pointTooltipHoverArea }px;`,
            class: optionalEdgeClass(data.axisX.ticks.length, data.index), // using a method to add additional classes when appropriate
        }, 'ct-point');
        data.element.replace(rect);
    };
});

...

optionalEdgeClass(xTicks: number, index: number) {
    if (index < 2) {
        return 'ct-point__left';
    } else if (index > xTicks - 3) {
        return 'ct-point__right';
    } else {
        return null;
    }
},

Here's a vid of how it ended up. Thanks again for the help!

https://user-images.githubusercontent.com/25447934/104190119-36f98000-53e1-11eb-87aa-bdd98f63e6b3.mp4

lukbukkit commented 3 years ago

Awesome! I'm glad the idea does work. 👍

lukbukkit commented 3 years ago

If you've got any other questions or problems, feel free to create a new issue.