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] Weird behavior with labels #368

Open
wolflu05 opened this issue Jan 28, 2023 · 1 comment
Open

[BUG] Weird behavior with labels #368

wolflu05 opened this issue Jan 28, 2023 · 1 comment

Comments

@wolflu05
Copy link

Hello,

I experienced a really weird behavior with my labels and don't know why. Im using this package in combination with chartjs-node-canvas.

Description

The provided example code has three different for loop heads which work/don't work.

  // run only for top=60 => perfect result
  for (let top = 60; top <= 60; top += 5) {

  // run a few values for top more => only a few bad
  for (let top = 40; top < 70; top += 5) {
  
  // run from 0 to 100 in 5er steps => everything bad
  for (let top = 0; top < 100; top += 5) {

The weird part is, that it works if the for loop only runs one iteration. If it runs only a few iterations, it's sometimes correct and if its runs 20 iterations nothing is correct.

Screenshots

Correct:
working

Wrong:
not-working

Look at the placement of the labels. In the correct one, the labels are placed ontop of the bars, in the wrong one they are wrapped somehow.

Steps to reproduce

  1. Create a folder and add the example code provided below
  2. Create a folder next to the index.ts file called a.
  3. Run the file with npx ts-node index.ts and try all 3 for heads. (Remember to remove all files in a/ first to have no conflicts)
  4. Compare the results
Example code

package.json:

{
  "name": "typescript-node",
  "version": "1.0.0",
  "scripts": {},
  "dependencies": {
    "@types/node": "14.14.29",
    "ts-node": "9.1.1",
    "typescript": "4.1.5",
    "chart.js": "^3.9.1",
    "chartjs-node-canvas": "^4.1.6",
    "chartjs-plugin-datalabels": "^2.2.0"
  }
}
import { ChartJSNodeCanvas } from "chartjs-node-canvas";
import { ChartConfiguration } from "chart.js";
import "chartjs-plugin-datalabels"; // to fix types
import { writeFileSync } from "fs";

const abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const srcData = new Array(100)
  .fill(0)
  .map((_, i) => ({ x: abc[i % (abc.length - 1)], y: i }));

(async () => {
  // run only for top=60 => perfect result
  // for (let top = 60; top <= 60; top += 5) {

  // run a few values for top more => only a few bad
  for (let top = 40; top < 70; top += 5) {
  
  // run from 0 to 100 in 5er steps => everything bad
  // for (let top = 0; top < 100; top += 5) {
  
  const sliced = srcData.slice(0, top);

    // import via require as it doesnt work otherwise
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const ChartDataLabels = require("chartjs-plugin-datalabels");

    const scale = 2;
    const chartRenderer = new ChartJSNodeCanvas({
      width: scale * Math.max(400, 40 * sliced.length),
      height: scale * 400,
      chartCallback: async (ChartJS) => {
        ChartJS.register(ChartDataLabels);
      },
    });

    const chart: ChartConfiguration = {
      type: "bar",
      data: {
        labels: sliced.map((x) => x.x),
        datasets: [
          {
            label: "ABC",
            data: sliced.map((x) => x.y * 2),
            backgroundColor: "#f43543",
            datalabels: {
              labels: {
                relative: {
                  align: "end",
                  anchor: "end",
                  color: "#ffffff",
                  offset: scale * 12,
                  font: {
                    size: scale * 10,
                    weight: "bold",
                  },
                  formatter: (_value, ctx) =>
                    `${~~(sliced[ctx.dataIndex].y * 10 ** 3) / 10}%`,
                },
              },
            },
          },
        ],
      },
    };
    const pictureBuffer = await chartRenderer.renderToBuffer(chart);
    writeFileSync(`./a/chart${top}.png`, pictureBuffer);
  }
})();
@wolflu05
Copy link
Author

wolflu05 commented Jan 28, 2023

This must be related to this library, because doing the require in the for loop with some tweeks to fresh require it, everything is working fine.

// https://github.com/hughsk/fresh-require
export const freshRequire: /*NodeJS.Require*/ (id: string) => any = (file) => {
  const resolvedFile = require.resolve(file);
  const temp = require.cache[resolvedFile];
  delete require.cache[resolvedFile];
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const modified = require(resolvedFile);
  require.cache[resolvedFile] = temp;
  return modified;
};

  // run only for top=60 => perfect result
  //for (let top = 45; top <= 45; top += 5) {
  
  // run a few values for top more => only a few bad
  for (let top = 40; top < 70; top += 5) {
  
  // run from 0 to 100 in 5er steps => everything bad
  // for (let top = 0; top < 100; top += 5) {

    // import via require as it doesnt work otherwise
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const ChartDataLabels = freshRequire('chartjs-plugin-datalabels');

    [...]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant