Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Incompatible with Svelte 5 (pre-release) #158

Open
1 task
anowell opened this issue Apr 28, 2024 · 9 comments
Open
1 task

[Bug]: Incompatible with Svelte 5 (pre-release) #158

anowell opened this issue Apr 28, 2024 · 9 comments
Labels
bug Something isn't working

Comments

@anowell
Copy link

anowell commented Apr 28, 2024

Would you like to work on a fix?

  • Check this if you would like to implement a PR, we are more than happy to help you go through the process.

Current and expected behavior

Importing a chartjs component (e.g. Bar) with Svelte 5 ([email protected]) yields this error message:

Your application, or one of its dependencies, imported from 'svelte/internal', which was a private module used by Svelte 4 components that no longer exists in Svelte 5. It is not intended to be public API. If you're a library author and you used 'svelte/internal' deliberately, please raise an issue on https://github.com/sveltejs/svelte/issues detailing your use case.

I haven't looked any further than simply confirming the import in this library:

import {
SvelteComponent,
bubble,
listen,
current_component,
} from 'svelte/internal';

Reproduction

[did not create shareable repro - merely confirmed svelte/internal is import]

chart.js version

4.4.2

svelte-chartjs version

3.1.5

Possible solution

No response

@anowell anowell added the bug Something isn't working label Apr 28, 2024
@shahedsalehi
Copy link

I just updated my project to svelte [email protected] and I encountered the same issue.

@anowell
Copy link
Author

anowell commented May 7, 2024

I've implemented a fix here: anowell@155042f

It's basically a rewrite of src/util/svelte.ts to work directly with the DOM, and then changes to the base Chart component to setup event listeners more explicitly.

It's certainly a breaking change, and I don't know that it's "correct", but it seems to work, still supports attaching event listeners (tested on the Bar chart storybook story), and I think it cleans them up. And I didn't mean to bump so many devDependencies, but I'm several years removed from the frontend dev tooling ecosystem so might have run a few too many unneeded pnpm commands.

From here, what it would take for this repo/package to support Svelte 5? Is it a new version? Should we wait for Svelte 5 to release? Is there an expectation of Svelte 4 compatibility? Is there some glaring issue with the implementation? Is there some other testing expectation I've completely overlooked? I could put together a PR if the missing pieces are relatively small, or I'm happy to have someone steal whatever they need from my change to put together a better solution.

Fwiw, I'm currently using it in a prototype with no intent to maintain beyond that prototype, so I advise against using my fork for anything beyond experimenting/testing.

@LukePeltier
Copy link

@SauravKanchan is this work planned? Would love to continue to use this library in svelte.

@andupotorac
Copy link

Same issue here, this doesn't work for Svelte 5.

@avi12
Copy link

avi12 commented Oct 23, 2024

Svelte 5 was released, this library doesn't work
For the time being, I'll use Svelte 4, but if this library doesn't support 5, I'll ditch it at some point

@PierrickP
Copy link

@anowell Can you propose a proper PR here (without console.log) ? 🙏

@MarcGodard
Copy link

This project isn't very active. If someone forks and fix, please let this thread know. If its not fixed by next month, I will do it.

@avi12
Copy link

avi12 commented Nov 4, 2024

Following the repository's source code, I managed to replicate the behavior in Svelte 5
TL;DR

<script lang="ts">
  import { BarController, BarElement, CategoryScale, Chart, LinearScale, TimeScale, Tooltip } from "chart.js";

  import "chartjs-adapter-date-fns";

  let elCanvas: HTMLCanvasElement;

  Chart.register(Tooltip, BarElement, BarController, CategoryScale, LinearScale, TimeScale);

  let chart: Chart;

  onMount(() => {
    chart = new Chart(elCanvas, {
      type: "bar",
      data,
      options: {
        scales: {
          y: {
            grace: "5%"
          },
          x: {
            ticks: {
              callback(i) {
                // ...
              },
              color
            }
          }
        },
        plugins: {
          legend: {
            display: false
          },
          tooltip: {
            callbacks: {
              title(tooltipItem) {
                // ...
              }
            }
          }
        },
        animation: false
      }
    });
  });

  const themeInUse = $derived("light");
  const color = $derived(themeInUse === "dark" ? "#fffFFF" : "#1B1B1B");

  $effect(() => {
    if (chart) {
      chart.data = data;
      chart.update();
    }
  });

  $effect(() => {
    if (chart) {
      chart.config.options.scales.x.ticks.color = color;
      chart.config.options.scales.y.ticks.color = color;
      chart.update();
    }
  });

  // https://www.chartjs.org/docs/latest/charts/bar.html
  const data = $derived({
    datasets: [
      {
        data: (() => {
          // ...
          }, []);
        })(),
        backgroundColor: "#1BE7FF"
      }
    ]
  });
</script>

<canvas bind:this={elCanvas}></canvas>

@fev4
Copy link

fev4 commented Nov 5, 2024

took inspiration from @avi12 (thank you btw) and here's a complete working component for <Line/> in Svelte 5 that you can just drop in as a replacement

my hope is that you can use this Line component as a guide to create every other component you might need

in any case, here it is:

<script lang="ts">
  import {
    Chart,
    Tooltip,
    type ChartData,
    type ChartOptions,
  } from 'chart.js';
  import type { HTMLCanvasAttributes } from 'svelte/elements';

  import 'chart.js/auto';
  import 'chartjs-adapter-date-fns';

  interface Props extends HTMLCanvasAttributes {
    data: ChartData<'line', number[], string>;
    options: ChartOptions<'line'>;
  }

  const { data, options, ...rest }: Props = $props();

  Chart.register(Tooltip);

  let canvasElem: HTMLCanvasElement;
  let chart: Chart;

  $effect(() => {
    chart = new Chart(canvasElem, {
      type: 'line',
      data,
      options,
    });

    return () => {
      chart.destroy();
    };
  });

  $effect(() => {
    if (chart) {
      chart.data = data;
      chart.update();
    }
  });
</script>

<canvas bind:this={canvasElem} {...rest}></canvas>

note a couple of things:

  • uses Chart.register() to only register the things I personally need, you might need others
  • doesn't use onMount instead only $effect calls
  • it returns on one of the $effect calls to clean up the chart when doing internal transitions, in order to avoid errors like Uncaught Error: Canvas is already in use. Chart with ID '15' must be destroyed before the canvas with ID '' can be reused.
  • uses typescript to extend the HTMLCanvasAttribute so that users of the Line component can pass props like height, and so on
  • it also uses specific types to the Line chart from chart.js types
  • I'm importing some extensions like chart.js/auto and chartjs-adapter-date-fns, you might not need those
  • it's a very simple implementation but that's mostly why I like it

IMHO svelte-chartjs is not needed anymore as with the simplicity and extensibility Svelte 5 offers, a simple Line component can be created as seen above, svelte-chartjs can still have a place but I believe it would need to offer some other differentiation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

8 participants