graphieros / vue-data-ui

An open source user-empowering data visualization Vue 3 components library for eloquent data storytelling
https://vue-data-ui.graphieros.com/
MIT License
1.09k stars 51 forks source link

Enhancement Proposal: Customizable Chart Tooltips #20

Closed Adeiko closed 9 months ago

Adeiko commented 9 months ago

Hey there!

First and foremost, I'd like to express my admiration for the quality of the code in this repository. The work accomplished here is impressive, and in my opinion, it deserves even greater recognition.

I'm interested in utilizing some of the charts available in this project. However, the current lack of customization options for tooltips is a significant limitation for my use case. I believe providing a way to customize tooltips could enhance the flexibility and usability of these charts.

Would you be open to considering a pull request that introduces the option to customize tooltips? From my initial review, it appears that most charts rely on a useTooltip(params) function. My proposal is to expose this function, allowing users to customize tooltip content while maintaining the default implementation as the fallback.

I've already implemented a tweaked version of this for my personal use on the heatmap chart and would be thrilled to contribute it back as a standard feature. Please let me know if this is something the project could benefit from, and if so, any specific guidelines or preferences you have for contributions.

graphieros commented 9 months ago

Hey Adeiko !

Thanks for your kind words :)

That's a very good idea. I was thinking about this exact limitation some weeks ago, but did not get to think of the implementation yet.

Feel free to send me a PR with your implementation for custom tooltips, as it would be clearly a win for the project. Most datasets passed in by the user go through some internal mapping. It would make sense to expose formatted datasets. For example, if no colors are provided for given datasets / datapoints, default colors are mapped. Also additional calculations may be mapped, as percentages. The solution should work seamlessly for all charts bearing a tooltip option.

Thanks again for your interest in the project, it means a great deal to me:)

Cheers A.

graphieros commented 9 months ago

After taking a look, the approach would be:

  1. Adding a config tooltip option called customFormat, defaulting to null, which is used as a callback to expose required data to customize tooltip contents

  2. Inside the useTooltip component functions, calling the customFormat if it exists and its return value is of type string; passing in necessary data (seriesIndex (absolute, non dependent on serie segregation), datapoint, the complete dataset series, and maybe the full config object as well), and assign its return value (the user's custom format) to the tooltipContent. If customFormat is null, or its return type is not a string, the default behavior will apply.

  3. Tweaking lib.js #treeShake to add a check for function types

Here would be an example of use, in the client component, in the config passed to the component:

const config = {
  ...
  tooltip: {
    customFormat: ({ datapoint, seriesIndex, series, config }) => {
        return `<div style="color:${datapoint.color}">${datapoint.name}</div>`
      }
  }
}

If this fits what you imagined, I can start working on applying it to all charts with tooltips.

Adeiko commented 9 months ago

Yeah that is more of less what i was thinking. but I didn't mean any imposition for you to work on it, i was happy to do a pr with an attemp.

if it helps, for example AG-Charts (also chart-js I think) uses a similar setup:

export interface AgSeriesTooltipRendererParams<TDatum = any> extends AgChartCallbackParams<TDatum> {
    /** Series title or yName depending on series configuration. */
    readonly title?: string;
    /** Series primary colour, as selected from the active theme, series options or formatter. */
    readonly color?: CssColor;
}
export interface AgChartCallbackParams<TDatum = any> {
    /** The data point associated with the label. */
    datum: TDatum;
    /** The unique identifier of the item. */
    itemId?: string;
    /** The unique identifier of the series. */
    seriesId: string;
}
interface iChartScatterTooltipParams extends iChartScatterSeries, AgSeriesTooltipRendererParams<customTypeOfYourData> {}
export function genTooltipPickExample({ title, datum}: iChartScatterTooltipParams) {
return `<div><div>${title}</div><span>(${datum.value})</span></div>`
}
graphieros commented 9 months ago

It's not a problem, as I said it's something I knew I had to tackle anyway. It's also the right time. I already prototyped it and it works great, so I just need to apply it everywhere, and add ts types. I'll let you know when it's released:)

graphieros commented 9 months ago

Released in v.2.0.6

Docs are updated.

Basically exposed data is the same for all charts (except for VueUiXy which exposes more stuff). Under the tooltip attribute of config objects, a customFormat attribute was added, set by default to null, which results in the default tooltip behaviour. It is to be used in the following fashion:

customFormat: ({ seriesIndex, datapoint, series, config }) => {
  return `<div>${ ... your custom content  }</div>`
}

customFormat must return a string to work. Depending on the chart, typings for datapoint, series and config are specific. All these types were added in the .d.ts file. Thank you very much for pushing the idea, and providing inspiration for tooltip generics :)

Adeiko commented 9 months ago

Hey there! Tried to implement it in the heatmap chart for example:

20240307_135500-chrome

There seems to be a background and border leftover from the 'base' tooltip. The only way to disable the border is also disabling it on the "selected" setting that adds the border to the items. selected.

I think it would be better to if there is a "custom tooltip add a class with only the z-index:2 and position: fixed" and if not add the defaultClass.

graphieros commented 9 months ago

Hey Adeiko,

nice render btw :)

Yeah I only worked on allowing content customization. I'm reopening the issue until I implement headless styles for this mode. Totally forgot about that part.

The css class will be .vue-data-ui-custom-tooltip

I'll keep you posted.

graphieros commented 9 months ago

Released in v.2.0.9

Using customFormat tooltip option makes the tooltip headless. Custom styles can be applied by targeting the following css class:

.vue-data-ui-custom-tooltip