skip to Main Content

https://stackblitz.com/edit/vitejs-vite-myutvi?file=src%2FApp.jsx

Hello,

I’m currently integrating a custom export functionality. My goal is to add an export button to display “Save as CSV” but the text is rendering as undefined.

import React, { useEffect, useState } from 'react';
import CanvasJSReact from '@canvasjs/react-charts';

const { CanvasJSChart } = CanvasJSReact;

function Chart({ isLoading, data }) {
  // Default chart options setup
  const defaultOptions = {
    animationEnabled: true,
    exportEnabled: true,
    theme: 'dark2',
    // Additional options...
  };

  const [chartOptions, setChartOptions] = useState(defaultOptions);

  useEffect(() => {
    // Conditional logic based on <code>isLoading</code> and <code>data</code>
    if (isLoading) {
      setChartOptions({ ...defaultOptions, /* Loading state */ });
    } else if (data?.length > 0) {
      setChartOptions({ ...defaultOptions, /* Data available state */ });
    } else {
      setChartOptions({ ...defaultOptions, /* No data state */ });
    }
  }, [isLoading, data]);

 
  return (
    <CanvasJSChart
      options={chartOptions}
      onRef={(chart) => {
        if (chart?.get("exportEnabled")) {
          const text = document.createTextNode("Save as CSV");
          const exportCSV = document.createElement("div");
          exportCSV.appendChild(text);
          exportCSV.setAttribute('style', <code>padding: 12px 8px; background-color: ${chart.toolbar.itemBackgroundColor}; color: ${chart.toolbar.fontColor}</code>);
          exportCSV.addEventListener('mouseover', () => {
            exportCSV.setAttribute('style', <code>padding: 12px 8px; background-color: ${chart.toolbar.itemBackgroundColorOnHover}; color: ${chart.toolbar.fontColorOnHover}</code>);
          });
          exportCSV.addEventListener('mouseout', () => {
            exportCSV.setAttribute('style', <code>padding: 12px 8px; background-color: ${chart.toolbar.itemBackgroundColor}; color: ${chart.toolbar.fontColor}</code>);
          });
          chart._toolBar.lastChild.appendChild(exportCSV);
        }
      }}
    />
  );
}

function App() {
  return <div className="App"><Chart isLoading={true} data={[]} /></div>;
}

export default App;

2

Answers


  1. Chosen as BEST ANSWER

    I reported the bug to canvasjs and they fixed the issue in a new release.


  2. This is a tricky one. It seems like the library mutates the DOM of the toolbar elements every time it’s rendered. I’m using a trick to delay the rendering of the export CSV button for 2 seconds to wait for the chart to settle.

    https://stackblitz.com/edit/vitejs-vite-bpwzyk?file=src%2FApp.jsx,src%2FExportCSVButton.jsx

    export default function ExportCSVButton({ chartRef }) {
      const divRef = useRef();
    
      useEffect(() => {
        const timer = setTimeout(() => {
          if (!divRef.current) return;
          divRef.current.innerText = 'Save As CSV';
        }, 2000);
    
        return () => clearTimeout(timer);
      });
    
      return (
        chartRef?._toolBar?.lastChild &&
        createPortal(
          <div
            ref={divRef}
            style={{
              padding: '12px 8px',
              backgroundColor: '#666666',
              color: '#F5F5F5',
            }}
          >
            Save As CSV
          </div>,
          chartRef?._toolBar?.lastChild
        )
      );
    }
    

    Edit: So instead of delay rendering the portal, I will just reset the innerText of the div every time the component re-render (because of parent state change)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search