chartjs / chartjs-adapter-luxon

Luxon adapter for Chart.js
MIT License
33 stars 22 forks source link

Import issue with ChartJS 3.8 #60

Open winsmith opened 2 years ago

winsmith commented 2 years ago

After updating from ChartJS 3.7.1 to ChartJS 3.8, any charts that would use the Luxon adapter stopped working. It seems that ChartJS changed the way their modules are exported slightly and the patches that chartjs-adapter-luxon is making don't register any more, at least in my project.

Any charts that use datetimes don't display any more and the console shows this error message:

Uncaught (in promise) Error: This method is not implemented: Check that a complete date adapter is provided.
    at abstract (chart.esm.js:56:62367)
    at DateAdapter.formats (chart.esm.js:56:62543)
    at TimeScale.init (chart.esm.js:56:280572)
    at eval (chart.esm.js:56:148422)
    at each (helpers.segment.js:129:2545)
    at Chart.buildOrUpdateScales (chart.esm.js:56:147793)
    at Chart._updateScales (chart.esm.js:56:152142)
    at Chart.update (chart.esm.js:56:150911)
    at new Chart (chart.esm.js:56:145260)
    at ChartsPremadeAppVersionsComponent.render (app-versions.js:180:1)

My workaround for this right now has been to create a new helper file, chart-js.js, and doing the patching manually by copy/pasting the code from the adapter source. Then I can import the new Chart object from that helper file.

I realise this is probably very hacky, but I don't really have the experience to find out what the actual problem is.

Here's my new import:

import { Chart } from 'ui/utils/chart-js';

And here's my ui/utils/chart-js.js:

import { Chart, registerables, _adapters } from 'chart.js';

import { DateTime } from 'luxon';

const FORMATS = {
  datetime: DateTime.DATETIME_MED_WITH_SECONDS,
  millisecond: 'h:mm:ss.SSS a',
  second: DateTime.TIME_WITH_SECONDS,
  minute: DateTime.TIME_SIMPLE,
  hour: { hour: 'numeric' },
  day: { day: 'numeric', month: 'short' },
  week: 'DD',
  month: { month: 'short', year: 'numeric' },
  quarter: "'Q'q - yyyy",
  year: { year: 'numeric' },
};

_adapters._date.override({
  _id: 'luxon', // DEBUG

  /**
   * @private
   */
  _create: function (time) {
    return DateTime.fromMillis(time, this.options);
  },

  formats: function () {
    return FORMATS;
  },

  parse: function (value, format) {
    const options = this.options;

    if (value === null || typeof value === 'undefined') {
      return null;
    }

    const type = typeof value;
    if (type === 'number') {
      value = this._create(value);
    } else if (type === 'string') {
      if (typeof format === 'string') {
        value = DateTime.fromFormat(value, format, options);
      } else {
        value = DateTime.fromISO(value, options);
      }
    } else if (value instanceof Date) {
      value = DateTime.fromJSDate(value, options);
    } else if (type === 'object' && !(value instanceof DateTime)) {
      value = DateTime.fromObject(value);
    }

    return value.isValid ? value.valueOf() : null;
  },

  format: function (time, format) {
    const datetime = this._create(time);
    return typeof format === 'string'
      ? datetime.toFormat(format, this.options)
      : datetime.toLocaleString(format);
  },

  add: function (time, amount, unit) {
    const args = {};
    args[unit] = amount;
    return this._create(time).plus(args).valueOf();
  },

  diff: function (max, min, unit) {
    return this._create(max).diff(this._create(min)).as(unit).valueOf();
  },

  startOf: function (time, unit, weekday) {
    if (unit === 'isoWeek') {
      weekday = Math.trunc(Math.min(Math.max(0, weekday), 6));
      const dateTime = this._create(time);
      return dateTime
        .minus({ days: (dateTime.weekday - weekday + 7) % 7 })
        .startOf('day')
        .valueOf();
    }
    return unit ? this._create(time).startOf(unit).valueOf() : time;
  },

  endOf: function (time, unit) {
    return this._create(time).endOf(unit).valueOf();
  },
});

Chart.register(...registerables);

export { Chart };
stockiNail commented 2 years ago

@winsmith may I ask you if you can reproduce the issue in codepen?

LeeLenaleee commented 2 years ago

Only thing I can think off by that error is that you dont import the adapter, thats the only way you get that error afaik, when I try it, it seems to work fine: https://codesandbox.io/s/react-typescript-forked-5s45fs?file=/src/App.tsx

iTrooz commented 6 months ago

Is there a reason ChartJS doesn't support native Javascript dates, rather than forcing an adapter ?

benmccann commented 6 months ago

Date has basically no features. Hopefully we can remove date adapters after https://github.com/tc39/proposal-temporal

iTrooz commented 6 months ago

And I assume you need some of these features with ChartJS ? May I ask why, if you also support raw timestamps (that have no features since they are just numbers)

benmccann commented 6 months ago

You can take a look here for everything we need to do: https://github.com/chartjs/chartjs-adapter-luxon/blob/master/src/index.js