sjrd / scalajs-sbt-vite-laminar-chartjs-example

An example of using Scala.js with sbt, Vite, Laminar and Chart.js
Apache License 2.0
88 stars 18 forks source link

Chart Rendering Fails #6

Closed objektwerks closed 11 months ago

objektwerks commented 11 months ago

When running Main in the browser and adding data, the Chart.js chart fails to render.

I mimicked this project ( see: Personal Project ), with updated dependencies and the like. Yet the Chart.js chart still fails to render.

I'm seeing the following 2 runtime errors ( see: Personal Project: App ):

  1. `type` = ChartType.bar // bar is not a registered controller
  2. yAxes = js.Array(new CommonAxe { // invalid scale configuration for yAxes

I'm searching for a fix at this time.

objektwerks commented 11 months ago

Taking a lead from Nikita Gazarov's recent work:

  1. Laminar Weather Chart
  2. Chart

I put together this hack ( see: Personal Project ):

import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

/**
  * Supports ChartType.bar, ChartType.line and ChartType.pie
  */
object Registrar:
  @js.native
  @JSImport("chart.js")
  object Chart extends js.Object:
    def register(components: js.Object*): Unit = js.native

  @js.native
  @JSImport("chart.js")
  object BarController extends js.Object

  @js.native
  @JSImport("chart.js")
  object BarElement extends js.Object

  @js.native
  @JSImport("chart.js")
  object LineController extends js.Object

  @js.native
  @JSImport("chart.js")
  object LineElement extends js.Object

  @js.native
  @JSImport("chart.js")
  object PointElement extends js.Object

  @js.native
  @JSImport("chart.js")
  object PieController extends js.Object

  @js.native
  @JSImport("chart.js")
  object ArcElement extends js.Object

  @js.native
  @JSImport("chart.js")
  object CategoryScale extends js.Object

  @js.native
  @JSImport("chart.js")
  object LinearScale extends js.Object

With the following pre-chart building scenario:

  import scala.scalajs.js.JSConverters.*
  import typings.chartJs.mod.*
  import registrar.Registrar.{
    ArcElement, BarController, BarElement, CategoryScale, LineController, LineElement, LinearScale, PieController, PointElement, Chart => ChartJs
  }

  ChartJs.register(
    ArcElement, BarController, BarElement, CategoryScale, LineController, LineElement, LinearScale, PieController, PointElement
  )

And magically the Chart.js chart renders correctly!

The Registrar, or something like it, would need to accommodate ALL Chart.js registrable components to fully support Chart.js. Again, refer to Nikita's work for more examples.

I added support for setting chart x and y axes labels; but this feature fails with these errors:

  1. Invalid scale configuration for scale: xAxes
  2. Invalid scale configuration for scale: yAxes The ScalablyTyped mapping appears to support pre-version 3 Chart.js mappings for xAxes and yAxes, where a js.Array[ChartXAxe] or js.Array[ChartYAxe] is required. Chart.js versions 3+ require a ChartXAxe or ChartYAxe.

The Invalid scale configuration for scale: xAxes | yAxes error is thrown in the code below:

function mergeScaleConfig(config, options) {
  const chartDefaults = overrides[config.type] || {scales: {}};
  const configScales = options.scales || {};
  const chartIndexAxis = getIndexAxis(config.type, options);
  const scales = Object.create(null);

  // First figure out first scale id's per axis.
  Object.keys(configScales).forEach(id => {
    const scaleConf = configScales[id];
    if (!isObject(scaleConf)) {
      return console.error(`Invalid scale configuration for scale: ${id}`); // Error occurs here!!!
    }
    if (scaleConf._proxy) {
      return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
    }
    const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), defaults.scales[scaleConf.type]);
    const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
    const defaultScaleOptions = chartDefaults.scales || {};
    scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]);
  });