We start here with the project developed in the previous tutorial about UI development with Laminar. To follow along this tutorial, either use the result of the previous tutorial, or checkout the laminar-end-state branch of the accompanying repo.
If you prefer to look at the end result for this tutorial directly, checkout the scalablytyped-end-state branch instead.
There are no playgrounds in Scribble for this tutorial because it does not support ScalablyTyped. You will need a local project to follow along.
Make sure to install the prerequisites before continuing further.
Set up ScalablyTyped with Chart.js
We set up our new dependencies as follows.
First, we install some npm packages: Chart.js as a regular dependency (with
-S), and its TypeScript type definitions along with the TypeScript compiler—required by ScalablyTyped—as development dependencies (with
project/plugins.sbt, we add a dependency on ScalablyTyped:
build.sbt, we configure ScalablyTyped on our project:
For these changes to take effect, we have to perform the following steps:
- Restart sbt and the
~fastLinkJStask (this will take a while the first time, as ScalablyTyped performs its magic)
npm run devif it was running
- Possibly re-import the project in your IDE of choice
We can now enjoy Chart.js with static types in our Scala.js code.
First, we define the Chart.js configuration that we will use:
At the top, we import the facade types for Chart.js generated by ScalablyTyped:
This gives us access to types like
ChartConfiguration, we provide a number of Chart.js-related options to make our chart look the way we want:
- the type of chart as a bar chart:
type = ChartType.bar,
- two datasets with the labels
"Full price", respectively, and
yaxis’ start value as
In a sense, that is all there is to know about ScalablyTyped. What follows is more about the integration of a third-party “component” into Laminar than anything else.
Rendering the chart
We now amend our
appElement() method to also call a new
The implementation of
renderDataChart() is rather large.
We show it in its entirety first, then we will pick it apart.
We create a Laminar
We give it a
height using Laminar’s
:=, as we did before.
For its actual content, we want Chart.js to take over.
For that, we have to create an instance of
Chart referencing the DOM
In order to bridge the world of Laminar
Elements and Chart.js, we use
That function takes one callback executed when the element is attached to a DOM tree, and one when it is removed.
When the element is mounted, we want to create the instance of
When it is unmounted, we want to call the
destroy() method of Chart.js to release its resources.
mount callback receives a
nodeCtx, which, among other things, gives us a handle to the underlying
We name it
domCanvas, and use it together with the
chartConfig defined above to create an instance of Chart.js’
We store the resulting
chart instance in a local
var optChart: Option[Chart].
We will use it later to update the
chart’s imperative data model when our FRP
In order to achieve that, we use a
dataSignal --> binder.
We give it as an argument to the Laminar
canvasTag element to tie the binder to the canvas lifetime, as you may recall from the Laminar tutorial.
Once the canvas gets mounted, every time the value of
dataSignal changes, the callback is executed.
In the callback, we get access to the
chart: Chart instance and update its data model.
--> binder allows to bridge the FRP world of
dataSignal with the imperative world of Chart.js.
Our application now properly renders the data model as a chart.
When we add or remove data items, the chart is automatically updated, thanks to the connection established by the
dataSignal --> binder.
That concludes our tutorial on ScalablyTyped.