From 85f478ae1d4aed6251f1823953ebb641194bba6b Mon Sep 17 00:00:00 2001 From: efim Date: Wed, 7 Jun 2023 19:11:19 +0000 Subject: [PATCH] feat: static bar of fixed version from article https://www.scala-js.org/doc/tutorial/scalablytyped.html --- build.sbt | 5 +- package-lock.json | 83 +++++++++++++++- package.json | 5 + project/plugins.sbt | 1 + .../sunshine/chartexample/App.scala | 97 ++++++++++++++----- 5 files changed, 165 insertions(+), 26 deletions(-) diff --git a/build.sbt b/build.sbt index 21534e8..fd97e59 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,8 @@ import org.scalajs.linker.interface.ModuleSplitStyle -lazy val productPreviewCardComponent = project.in(file(".")) +lazy val chartExample = project.in(file(".")) .enablePlugins(ScalaJSPlugin) // Enable the Scala.js plugin in this project + .enablePlugins(ScalablyTypedConverterExternalNpmPlugin) .settings( scalaVersion := "3.3.0", @@ -20,7 +21,7 @@ lazy val productPreviewCardComponent = project.in(file(".")) .withModuleSplitStyle( ModuleSplitStyle.SmallModulesFor(List("livechart"))) }, - + externalNpm := baseDirectory.value, /* Depend on the scalajs-dom library. * It provides static types for the browser DOM APIs. */ diff --git a/package-lock.json b/package-lock.json index 8481766..d5c2fb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,22 @@ { - "name": "product-preview-card-component", + "name": "chart-integration-example", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "product-preview-card-component", + "name": "chart-integration-example", "version": "0.0.0", + "dependencies": { + "chart.js": "^2.9.4" + }, "devDependencies": { "@scala-js/vite-plugin-scalajs": "^1.0.0", + "@types/chart.js": "^2.9.29", "autoprefixer": "^10.4.14", "postcss": "^8.4.23", "tailwindcss": "^3.3.2", + "typescript": "^5.1.3", "vite": "^4.3.0" } }, @@ -477,6 +482,15 @@ "vite": "^4.1.4" } }, + "node_modules/@types/chart.js": { + "version": "2.9.29", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.29.tgz", + "integrity": "sha512-WOZMitUU3gHDM0oQsCsVivX+oDsIki93szcTmmUPBm39cCvAELBjokjSDVOoA3xiIEbb+jp17z/3S2tIqruwOQ==", + "dev": true, + "dependencies": { + "moment": "^2.10.2" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -629,6 +643,32 @@ } ] }, + "node_modules/chart.js": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", + "dependencies": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "node_modules/chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "dependencies": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "node_modules/chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "dependencies": { + "color-name": "^1.0.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -668,6 +708,24 @@ "node": ">= 6" } }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1019,6 +1077,14 @@ "node": "*" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -1508,6 +1574,19 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/typescript": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", diff --git a/package.json b/package.json index 0c519be..cbaca97 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,14 @@ }, "devDependencies": { "@scala-js/vite-plugin-scalajs": "^1.0.0", + "@types/chart.js": "^2.9.29", "autoprefixer": "^10.4.14", "postcss": "^8.4.23", "tailwindcss": "^3.3.2", + "typescript": "^5.1.3", "vite": "^4.3.0" + }, + "dependencies": { + "chart.js": "^2.9.4" } } diff --git a/project/plugins.sbt b/project/plugins.sbt index 5c16d20..f1ed5a5 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +1,2 @@ addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.1") +addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta41") diff --git a/src/main/scala/industries/sunshine/chartexample/App.scala b/src/main/scala/industries/sunshine/chartexample/App.scala index 2c805f1..ce3e981 100644 --- a/src/main/scala/industries/sunshine/chartexample/App.scala +++ b/src/main/scala/industries/sunshine/chartexample/App.scala @@ -1,4 +1,4 @@ -package industries.sunshine.productpreviewcard +package industries.sunshine.chartexample import scala.scalajs.js import scala.scalajs.js.annotation.* @@ -17,29 +17,82 @@ def App(): Unit = object Main { def appElement(): Element = div( - className := "w-screen h-screen bg-green-200", - a( - href := "https://vitejs.dev", - target := "_blank", - img(src := "/vite.svg", className := "logo", alt := "Vite logo") - ), - a( - href := "https://developer.mozilla.org/en-US/docs/Web/JavaScript", - target := "_blank", - "link to JS logo" - ), - h1("Hello Laminar!"), - counterButton(), - p(className := "read-the-docs", "Click on the Vite logo to learn more") + className := "w-screen h-screen bg-green-100", + renderDataChart(), ) - def counterButton(): Element = { - val counter = Var(0) - button( - tpe := "button", - "count is ", - child.text <-- counter, - onClick --> { event => counter.update(c => c + 1) } + def renderDataChart(): Element = { + import scala.scalajs.js.JSConverters.* + import typings.chartJs.mod.* + + var optChart: Option[Chart] = None + + canvasTag( + className := "border-4 border-purple-500", + // Regular properties of the canvas + width := "100%", + height := "200px", + + // onMountUnmount callback to bridge the Laminar world and the Chart.js world + onMountUnmountCallback( + // on mount, create the `Chart` instance and store it in optChart + mount = { nodeCtx => + val domCanvas: dom.HTMLCanvasElement = nodeCtx.thisNode.ref + val chart = Chart.apply.newInstance2(domCanvas, chartConfig) + println("on mounting chart") + optChart = Some(chart) + }, + // on unmount, destroy the `Chart` instance + unmount = { thisNode => + for (chart <- optChart) + chart.destroy() + optChart = None + } + ), + + // Bridge the FRP world of dataSignal to the imperative world of the `chart.data` + // dataSignal --> { data => + // for (chart <- optChart) { + // chart.data.labels = data.map(_.label).toJSArray + // chart.data.datasets.get(0).data = data.map(_.price).toJSArray + // chart.data.datasets.get(1).data = data.map(_.fullPrice).toJSArray + // chart.update() + // } + // }, ) } + + val chartConfig = { + import typings.chartJs.mod.* + new ChartConfiguration { + `type` = ChartType.bar + data = new ChartData { + labels = js.Array("one", "two", "al", "la", "yo") + datasets = js.Array( + new ChartDataSets { + label = "Price" + borderWidth = 1 + backgroundColor = "green" + data = js.Array(1,2,3,4,5) + }, + new ChartDataSets { + label = "Full price" + borderWidth = 1 + backgroundColor = "blue" + data = js.Array(5,5,5,5,5) + } + ) + } + options = new ChartOptions { + scales = new ChartScales { + yAxes = js.Array(new CommonAxe { + ticks = new TickOptions { + beginAtZero = true + } + }) + } + } + } + } + }