1

I've run into a problem using Highcharts WordCloud with React when using emoji as the input data. I'm using the highcharts-react-official wrapper. Most of the time the emojis display fine, but occasionally I'm getting TypeError: Cannot convert undefined or null to object during the render.

I've played around with the input data sets to ensure they are non-null, and non-undefined, and also with the arrays of emoji themselves to test whether specific emoji are causing the problem. The result of that testing highlighted a couple of emoji that, at first, caused a problem, but then started behaving correctly again. Sometimes resizing the browser window or adjusting a weighting, or removing an input value would also re-create the error, but I can't pin it down to any particular input value.

From digging a little through the Highcharts WordCloud src code, I think I've narrowed the problem down to the attempted iteration of the keys of animatableAttribs object of the emoji to be rendered, which turn out to be null or undefined when the error occurs. So I figured perhaps the fault was in the attempted animation of that particular emoji, which may explain the difficulty in reproducing the error as the animation, orientation or positioning of the emoji may be slightly different on render or window resize. To test this, I set the animation property of the series to false but the error still occurred.

Can anyone tell me if I'm doing something wrong here, or if emojis just aren't fully supported by Highcharts wordcloud?

Edit It appears that adding text to the emoji, so the input becomes a short line of text with an emoji at the end, prevents the error from occurring. The minimum length of prepended text required seems to be 2 characters. So "to 😃" instead of "😃" works reliably. Empty strings or strings with just white space, with an emoji appended on the end do not work.

I've recreated a codesandbox example here. If you cycle through the emoji array lists by clicking the button, the error will eventually occur. Below is also a stacktrace of the console error in my browser with a ref to the wordcloud src at line 99, also below.

WordCloud.jsx

import React, { useEffect, useState } from "react";
import HighchartsReact from "highcharts-react-official";
import Highcharts from "highcharts";
import addWordcloudModule from "highcharts/modules/wordcloud";

addWordcloudModule(Highcharts);

const WordCloud = ({ data }) => {
  const [chartOptions, setChartOptions] = useState({
    title: {
      text: ""
    },
    series: [
      {
        type: "wordcloud",
        data: [],
        name: "frequency"
      }
    ],
    tooltip: {
      headerFormat:
        '<span style="font-size: 16px"><b>{point.key}</b></span><br>'
    },
    plotOptions: {
      series: {
        minFontSize: 2,
        animation: false
      }
    }
  });

  const updateSeries = (data) => {
    const newSeries = [
      { type: "wordcloud", data: data.data, name: data.name ?? "frequency" }
    ];
    console.log(newSeries);
    setChartOptions({
      ...chartOptions,
      series: newSeries
    });
  };

  useEffect(() => {
    console.log(data);
    if (data) {
      updateSeries(data);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data]);

  return <HighchartsReact highcharts={Highcharts} options={chartOptions} />;
};

export default WordCloud;

App.jsx

import { useState } from "react";
import "./styles.css";
import WordCloud from "./WordCloud";

const emojis = [
  {
    data: [
      {
        name: "😘",
        weight: 176
      },
      {
        name: "🏃🏻‍♀️",
        weight: 1
      },
      {
        name: "🤟",
        weight: 1
      },
      {
        name: "🤙",
        weight: 1
      },
      {
        name: "😣",
        weight: 1
      },
      {
        name: "🚁",
        weight: 1
      },
      {
        name: "😬",
        weight: 1
      },
      {
        name: "🧡",
        weight: 1
      }
    ]
  }
];

export default function App() {
  const [index, setIndex] = useState(0);

  const updateData = () => {
    const newIndex = (index + 1) % emojis.length;
    console.log(newIndex);
    setIndex(newIndex);
  };

  return (
    <div className="App">
      <button onClick={updateData}>Update Data</button>
      <h5>index = {index}</h5>
      <WordCloud data={emojis[index]} />
    </div>
  );
}

console log of error

wordcloud.src

5
  • I investigated this issue, but it was not easy to reproduce - in my case, cycling through the emoji array lists did not yield any errors. However, I was able to reproduce it only when the screen was resized multiple times. The issue appears even with just one character (e.g. the 'x' letter), which suggests it is not particularly related to the emoji. It seems the behavior might be connected to the animation. Could you please confirm that this bug does not occur when animation is set to true in your case?
    – magdalena
    Commented Mar 15, 2023 at 14:24
  • Thanks @magdalena. Yes it occurs regardless of whether the animation flag is set to true or false. The only way I found around it was to increase the length of the rendered string. I agree that it appears to be something to do with the animation as the error behaviour is inconsistent and as you experienced, sometimes due only to resizing the window.
    – Callum
    Commented Mar 16, 2023 at 21:15
  • @magdalena Any update on this Magdalena? My workaround gets a little fiddly when the background color changes due to dark reader for example
    – Callum
    Commented Mar 25, 2023 at 0:13
  • Apologize for the late response. I reported this issue as a bug, which you can track here: github.com/highcharts/highcharts/issues/18740. As a temporary workaround, set the animation to true, for the new series: codesandbox.io/s/stoic-lederberg-jrg6jp
    – magdalena
    Commented Mar 27, 2023 at 16:50
  • Thanks @magdalena appreciate that
    – Callum
    Commented Mar 28, 2023 at 21:22

1 Answer 1

2

I would appreciate a response from the Highcharts gurus as to a proper solution to this problem, but my current workaround is to render the emoji as html by adding the useHTML flag to the dataLabels in plotOptions

plotOptions: {
  series: {
    dataLabels: {
      useHTML: true,
    },
  },
},

and then adding a span of 2 chars on either side of each emoji, styled the same color as the background, so they're not visible. It doesn't seem to work if opacity is set to 0 instead or if there is only 1 char before and after the emoji. It's a horrible hack but it seems to work reliably.

const data = emojiData.map(({emoji, count}) => {
  return {
    name: `<span style="color:white">''</span>` + emoji + `<span style="color:white">''</span>`,
    weight: count,
  };
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.