aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2019-03-10 14:12:00 +0100
committerRobert Jaros <rjaros@finn.pl>2019-03-10 14:12:00 +0100
commitc1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea (patch)
tree9244923c93b6f17d8f58cb94c4a83a2619a42469
parentc13d0441dddf31ef019333fd16378b3fc56003a4 (diff)
downloadkvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.tar.gz
kvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.tar.bz2
kvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.zip
New module with support for drawing charts based on chart.js library.
-rw-r--r--Module.md8
-rw-r--r--build.gradle1
-rw-r--r--kvision-modules/kvision-chart/build.gradle12
-rw-r--r--kvision-modules/kvision-chart/package.json.d/project.info3
-rw-r--r--kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/KVManagerChart.kt38
-rw-r--r--kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Chart.kt129
-rw-r--r--kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt94
-rw-r--r--kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Configuration.kt919
-rw-r--r--kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/js/Chart.kt691
-rw-r--r--kvision-modules/kvision-chart/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt99
-rw-r--r--kvision-modules/kvision-chart/src/test/kotlin/test/pl/treksoft/kvision/chart/ChartCanvasSpec.kt77
-rw-r--r--kvision-modules/kvision-chart/src/test/kotlin/test/pl/treksoft/kvision/chart/ChartSpec.kt81
-rw-r--r--settings.gradle1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Css.kt2
14 files changed, 2154 insertions, 1 deletions
diff --git a/Module.md b/Module.md
index 1835c8f8..efb79929 100644
--- a/Module.md
+++ b/Module.md
@@ -7,6 +7,14 @@ KVision - object oriented Web UI framework for Kotlin/JS.
KVision core classes. This includes base interfaces for all components, CSS enums (for colors, borders,
backgrounds, fonts, text and position) and the main Widget class.
+# Package pl.treksoft.kvision.chart
+
+Full-featured chart component based on chart.js library.
+
+# Package pl.treksoft.kvision.chart.js
+
+Kotlin bindings for chart.js API.
+
# Package pl.treksoft.kvision.data
Base component and container class with data binding support for observable data model.
diff --git a/build.gradle b/build.gradle
index c2610971..ce6e62e1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -167,6 +167,7 @@ dokka {
'kvision-modules/kvision-upload/src/main/kotlin',
'kvision-modules/kvision-handlebars/src/main/kotlin',
'kvision-modules/kvision-i18n/src/main/kotlin',
+ 'kvision-modules/kvision-chart/src/main/kotlin',
'kvision-modules/kvision-remote/src/main/kotlin',
'kvision-modules/kvision-select-remote/src/main/kotlin',
'kvision-modules/kvision-common/src/main/kotlin',
diff --git a/kvision-modules/kvision-chart/build.gradle b/kvision-modules/kvision-chart/build.gradle
new file mode 100644
index 00000000..4d4ba4df
--- /dev/null
+++ b/kvision-modules/kvision-chart/build.gradle
@@ -0,0 +1,12 @@
+apply from: "../shared.gradle"
+
+kotlinFrontend {
+
+ npm {
+ dependency("chart.js", "2.7.3")
+ devDependency("karma", "3.1.4")
+ devDependency("karma-chrome-launcher", "2.2.0")
+ devDependency("qunit", "2.8.0")
+ }
+
+}
diff --git a/kvision-modules/kvision-chart/package.json.d/project.info b/kvision-modules/kvision-chart/package.json.d/project.info
new file mode 100644
index 00000000..4b4a6303
--- /dev/null
+++ b/kvision-modules/kvision-chart/package.json.d/project.info
@@ -0,0 +1,3 @@
+{
+ "description": "KVision Chart module"
+}
diff --git a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/KVManagerChart.kt b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/KVManagerChart.kt
new file mode 100644
index 00000000..73a0f2b9
--- /dev/null
+++ b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/KVManagerChart.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017-present Robert Jaros
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package pl.treksoft.kvision
+
+internal val kVManagerChartInit = KVManagerChart.init()
+
+/**
+ * Internal singleton object which initializes and configures KVision Chart module.
+ */
+@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught")
+internal object KVManagerChart {
+ fun init() {}
+
+ private val chart = try {
+ require("chart.js/dist/Chart.bundle.min.js")
+ } catch (e: Throwable) {
+ }
+
+}
diff --git a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Chart.kt b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Chart.kt
new file mode 100644
index 00000000..4681d9c4
--- /dev/null
+++ b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Chart.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017-present Robert Jaros
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package pl.treksoft.kvision.chart
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.chart.js.Chart.ChartConfiguration
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.Widget
+
+/**
+ * Chart component.
+ *
+ * @constructor
+ * @param configuration chart configuration
+ * @param chartWidth chart width in pixels
+ * @param chartHeight chart height in pixels
+ * @param classes a set of CSS class names
+ */
+open class Chart(
+ configuration: Configuration,
+ chartWidth: Int? = null,
+ chartHeight: Int? = null,
+ classes: Set<String> = setOf()
+) : Widget(classes) {
+
+ /**
+ * Chart configuration.
+ */
+ var configuration
+ get() = chartCanvas.configuration
+ set(value) {
+ chartCanvas.configuration = value
+ }
+
+ internal val chartCanvas: ChartCanvas = ChartCanvas(chartWidth, chartHeight, configuration)
+
+ override fun render(): VNode {
+ return render("div", arrayOf(chartCanvas.renderVNode()))
+ }
+
+ /**
+ * Returns chart configuration in the form of native JS object.
+ */
+ open fun getNativeConfig(): ChartConfiguration? {
+ return chartCanvas.getNativeConfig()
+ }
+
+ /**
+ * Resets the chart.
+ */
+ open fun reset() {
+ chartCanvas.reset()
+ }
+
+ /**
+ * Renders the chart.
+ * @param duration animation duration
+ * @param lazy if true, the animation can be interrupted by other animations
+ */
+ open fun render(duration: Int? = null, lazy: Boolean = false) {
+ chartCanvas.render(duration, lazy)
+ }
+
+ /**
+ * Stops the animation.
+ */
+ open fun stop() {
+ chartCanvas.stop()
+ }
+
+ /**
+ * Resizes the chart to the size of the container.
+ */
+ open fun resizeChart() {
+ chartCanvas.resizeChart()
+ }
+
+ /**
+ * Clears the chart.
+ */
+ open fun clearChart() {
+ chartCanvas.clearChart()
+ }
+
+ /**
+ * Returns a base64 encoded string of the chart in its current state.
+ */
+ open fun toBase64Image(): String? {
+ return chartCanvas.toBase64Image()
+ }
+
+ companion object {
+ /**
+ * DSL builder extension function.
+ *
+ * It takes the same parameters as the constructor of the built component.
+ */
+ fun Container.chart(
+ configuration: Configuration,
+ chartWidth: Int? = null,
+ chartHeight: Int? = null,
+ classes: Set<String> = setOf(),
+ init: (Chart.() -> Unit)? = null
+ ): Chart {
+ val chart = Chart(configuration, chartWidth, chartHeight, classes).apply { init?.invoke(this) }
+ this.add(chart)
+ return chart
+ }
+ }
+}
diff --git a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt
new file mode 100644
index 00000000..09b68633
--- /dev/null
+++ b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-present Robert Jaros
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package pl.treksoft.kvision.chart
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.chart.js.Chart.ChartConfiguration
+import pl.treksoft.kvision.html.Canvas
+import pl.treksoft.kvision.i18n.I18n
+import pl.treksoft.kvision.chart.js.Chart as JsChart
+
+internal class ChartCanvas(
+ canvasWidth: Int? = null,
+ canvasHeight: Int? = null,
+ configuration: Configuration,
+ classes: Set<String> = setOf()
+) :
+ Canvas(canvasWidth, canvasHeight, classes) {
+
+ var configuration: Configuration = configuration
+ set(value) {
+ field = value
+ jsChart?.config = value.toJs(this::translate)
+ jsChart?.update()
+ }
+
+ private var jsChart: JsChart? = null
+
+ override fun render(): VNode {
+ if (lastLanguage != null && lastLanguage != I18n.language) {
+ jsChart?.config = configuration.toJs(this::translate)
+ jsChart?.update()
+ }
+ return render("canvas")
+ }
+
+ override fun afterInsert(node: VNode) {
+ super.afterInsert(node)
+ jsChart =
+ JsChart(this.context2D, configuration.toJs(this::translate))
+ }
+
+ override fun afterDestroy() {
+ jsChart?.destroy()
+ jsChart = null
+ }
+
+ fun getNativeConfig(): ChartConfiguration? {
+ return jsChart?.config
+ }
+
+ fun reset() {
+ jsChart?.reset()
+ }
+
+ fun render(duration: Int? = null, lazy: Boolean = false) {
+ jsChart?.render(duration, lazy)
+ }
+
+ fun stop() {
+ jsChart?.stop()
+ }
+
+ fun resizeChart() {
+ jsChart?.resize()
+ }
+
+ fun clearChart() {
+ jsChart?.clear()
+ }
+
+ fun toBase64Image(): String? {
+ return jsChart?.toBase64Image()
+ }
+
+}
diff --git a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Configuration.kt b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Configuration.kt
new file mode 100644
index 00000000..7b1cddd6
--- /dev/null
+++ b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/Configuration.kt
@@ -0,0 +1,919 @@
+/*
+ * Copyright (c) 2017-present Robert Jaros
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+@file:Suppress("TooManyFunctions")
+
+package pl.treksoft.kvision.chart
+
+import org.w3c.dom.events.MouseEvent
+import pl.treksoft.kvision.chart.js.Chart
+import pl.treksoft.kvision.core.Color
+import pl.treksoft.kvision.core.FontStyle
+import pl.treksoft.kvision.utils.obj
+
+
+/**
+ * Chart types.
+ */
+enum class ChartType(internal val type: String) {
+ LINE("line"),
+ BAR("bar"),
+ HORIZONTALBAR("horizontalBar"),
+ RADAR("radar"),
+ DOUGHNUT("doughnut"),
+ PIE("pie"),
+ POLARAREA("polarArea"),
+ BUBBLE("bubble"),
+ SCATTER("scatter")
+}
+
+/**
+ * Chart interaction modes.
+ */
+enum class InteractionMode(internal val mode: String) {
+ POINT("point"),
+ NEAREST("nearest"),
+ INDEX("index"),
+ DATASET("dataset"),
+ X("x"),
+ Y("y")
+}
+
+/**
+ * Chart animation easings.
+ */
+enum class Eeasing(internal val mode: String) {
+ LINEAR("linear"),
+ EASEINQUAD("easeInQuad"),
+ EASEOUTQUAD("easeOutQuad"),
+ EASEINOUTQUAD("easeInOutQuad"),
+ EASEINCUBIC("easeInCubic"),
+ EASEOUTCUBIC("easeOutCubic"),
+ EASEINOUTCUBIC("easeInOutCubic"),
+ EASEINQUART("easeInQuart"),
+ EASEOUTQUART("easeOutQuart"),
+ EASEINOUTQUART("easeInOutQuart"),
+ EASEINQUINT("easeInQuint"),
+ EASEOUTQUINT("easeOutQuint"),
+ EASEINOUTQUINT("easeInOutQuint"),
+ EASEINSINE("easeInSine"),
+ EASEOUTSINE("easeOutSine"),
+ EASEINOUTSINE("easeInOutSine"),
+ EASEINEXPO("easeInExpo"),
+ EASEOUTEXPO("easeOutExpo"),
+ EASEINOUTEXPO("easeInOutExpo"),
+ EASEINCIRC("easeInCirc"),
+ EASEOUTCIRC("easeOutCirc"),
+ EASEINOUTCIRC("easeInOutCirc"),
+ EASEINELASTIC("easeInElastic"),
+ EASEOUTELASTIC("easeOutElastic"),
+ EASEINOUTELASTIC("easeInOutElastic"),
+ EASEINBACK("easeInBack"),
+ EASEOUTBACK("easeOutBack"),
+ EASEINOUTBACK("easeInOutBack"),
+ EASEINBOUNCE("easeInBounce"),
+ EASEOUTBOUNCE("easeOutBounce"),
+ EASEINOUTBOUNCE("easeInOutBounce")
+}
+
+/**
+ * Chart objects positions.
+ */
+enum class Position(internal val position: String) {
+ TOP("top"),
+ LEFT("left"),
+ RIGHT("right"),
+ BOTTOM("bottom")
+}
+
+/**
+ * Chart tooltip positions.
+ */
+enum class TooltipPosition(internal val mode: String) {
+ AVERAGE("average"),
+ NEAREST("nearest")
+}
+
+/**
+ * Chart point styles.
+ */
+enum class PointStyle(internal val style: String) {
+ CIRCLE("circle"),
+ CROSS("cross"),
+ CROSSROT("crossRot"),
+ DASH("dash"),
+ LINE("line"),
+ RECT("rect"),
+ RECTROUNDED("rectRounded"),
+ RECTROT("rectRot"),
+ START("star"),
+ TRIANGLE("triangle")
+}
+
+/**
+ * Chart interpolation modes.
+ */
+enum class InterpolationMode(internal val mode: String) {
+ DEFAULT("default"),
+ MONOTONE("monotone")
+}
+
+/**
+ * Chart scales.
+ */
+enum class ScalesType(internal val type: String) {
+ CATEGORY("category"),
+ LINEAR("linear"),
+ LOGARITHMIC("logarithmic"),
+ TIME("time"),
+ RADIALLINEAR("radialLinear")
+}
+
+/**
+ * Canvas line end point styles.
+ */
+enum class LineCap(internal val mode: String) {
+ BUTT("butt"),
+ ROUND("round"),
+ SQUARE("square")
+}
+
+/**
+ * Canvas line join styles.
+ */
+enum class LineJoin(internal val mode: String) {
+ BEVEL("bevel"),
+ ROUND("round"),
+ MITER("miter")
+}
+
+/**
+ * Chart hover options.
+ */
+data class HoverOptions(
+ val mode: InteractionMode = InteractionMode.NEAREST,
+ val animationDuration: Int = 400,
+ val intersect: Boolean = true,
+ val axis: String = "x"
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun HoverOptions.toJs(): dynamic {
+ return obj {
+ this.mode = mode.mode
+ this.animationDuration = animationDuration
+ this.intersect = intersect
+ this.axis = axis
+ }
+}
+
+/**
+ * Chart animation options.
+ */
+data class AnimationOptions(
+ val duration: Int = 1000,
+ var easing: Eeasing = Eeasing.EASEOUTQUART,
+ val onProgress: ((obj: Chart.ChartAnimationObject) -> Unit)? = null,
+ val onComplete: ((obj: Chart.ChartAnimationObject) -> Unit)? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun AnimationOptions.toJs(): dynamic {
+ return obj {
+ this.duration = duration
+ this.easing = easing.mode
+ if (onProgress != null) this.onProgress = onProgress
+ if (onComplete != null) this.onComplete = onComplete
+ }
+}
+
+/**
+ * Chart layout padding options.
+ */
+data class LayoutPaddingObject(
+ val top: Int? = null,
+ val right: Int? = null,
+ val bottom: Int? = null,
+ val left: Int? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun LayoutPaddingObject.toJs(): dynamic {
+ return obj {
+ if (top != null) this.top = top
+ if (right != null) this.right = right
+ if (bottom != null) this.bottom = bottom
+ if (left != null) this.left = left
+ }
+}
+
+/**
+ * Chart layout options.
+ */
+data class LayoutOptions(val padding: LayoutPaddingObject)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun LayoutOptions.toJs(): dynamic {
+ return obj {
+ this.padding = padding.toJs()
+ }
+}
+
+/**
+ * Chart legend label options.
+ */
+data class LegendLabelOptions(
+ val boxWidth: Int = 40,
+ val fontSize: Int = 12,
+ val fontStyle: FontStyle? = null,
+ val fontColor: Color? = null,
+ val fontFamily: String? = null,
+ val padding: Int = 10,
+ val generateLabels: ((chart: Any) -> Any)? = null,
+ val filter: ((legendItem: Chart.ChartLegendLabelItem, data: Chart.ChartData) -> Any)? = null,
+ val usePointStyle: Boolean = false
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun LegendLabelOptions.toJs(): dynamic {
+ return obj {
+ this.boxWidth = boxWidth
+ this.fontSize = fontSize
+ if (fontStyle != null) this.fontStyle = fontStyle.name
+ if (fontColor != null) this.fontColor = fontColor.asString()
+ if (fontFamily != null) this.fontFamily = fontFamily
+ this.padding = padding
+ if (generateLabels != null) this.generateLabels = generateLabels
+ if (filter != null) this.filter = filter
+ this.usePointStyle = usePointStyle
+ }
+}
+
+/**
+ * Chart legend options.
+ */
+data class LegendOptions(
+ val display: Boolean = true,
+ val position: Position = Position.TOP,
+ val fullWidth: Boolean = true,
+ val reverse: Boolean = false,
+ val onClick: ((event: MouseEvent, legendItem: Chart.ChartLegendLabelItem) -> Unit)? = null,
+ val onHover: ((event: MouseEvent, legendItem: Chart.ChartLegendLabelItem) -> Unit)? = null,
+ val labels: LegendLabelOptions? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun LegendOptions.toJs(): dynamic {
+ return obj {
+ this.display = display
+ this.position = position.position
+ this.fullWidth = fullWidth
+ this.reverse = reverse
+ if (onClick != null) this.onClick = onClick
+ if (onHover != null) this.onHover = onHover
+ if (labels != null) this.labels = labels.toJs()
+ }
+}
+
+/**
+ * Chart title options.
+ */
+data class TitleOptions(
+ val display: Boolean = false,
+ val position: Position = Position.TOP,
+ val fontSize: Int = 12,
+ val fontStyle: FontStyle? = null,
+ val fontColor: Color? = null,
+ val fontFamily: String? = null,
+ val padding: Int = 10,
+ val lineHeight: String? = null,
+ val text: List<String>? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun TitleOptions.toJs(i18nTranslator: (String) -> (String)): dynamic {
+ return obj {
+ this.display = display
+ this.position = position.position
+ this.fontSize = fontSize
+ if (fontStyle != null) this.fontStyle = fontStyle.name
+ if (fontColor != null) this.fontColor = fontColor.asString()
+ if (fontFamily != null) this.fontFamily = fontFamily
+ this.padding = padding
+ if (lineHeight != null) this.lineHeight = lineHeight
+ if (text != null) this.text = text.map(i18nTranslator).toTypedArray()
+ }
+}
+
+/**
+ * Chart tooltips callbacks.
+ */
+data class TooltipCallback(
+ val beforeTitle: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val title: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val afterTitle: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val beforeBody: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val beforeLabel: ((tooltipItem: Chart.ChartTooltipItem, data: Chart.ChartData) -> dynamic)? = null,
+ val label: ((tooltipItem: Chart.ChartTooltipItem, data: Chart.ChartData) -> dynamic)? = null,
+ val labelColor: ((tooltipItem: Chart.ChartTooltipItem, chart: Chart) -> Chart.ChartTooltipLabelColor)? = null,
+ val labelTextColor: ((tooltipItem: Chart.ChartTooltipItem, chart: Chart) -> String)? = null,
+ val afterLabel: ((tooltipItem: Chart.ChartTooltipItem, data: Chart.ChartData) -> dynamic)? = null,
+ val afterBody: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val beforeFooter: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val footer: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null,
+ val afterFooter: ((item: Array<Chart.ChartTooltipItem>, data: Chart.ChartData) -> dynamic)? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+@Suppress("ComplexMethod")
+fun TooltipCallback.toJs(): dynamic {
+ return obj {
+ if (beforeTitle != null) this.beforeTitle = beforeTitle
+ if (title != null) this.title = title
+ if (afterTitle != null) this.afterTitle = afterTitle
+ if (beforeBody != null) this.beforeBody = beforeBody
+ if (beforeLabel != null) this.beforeLabel = beforeLabel
+ if (label != null) this.label = label
+ if (labelColor != null) this.labelColor = labelColor
+ if (labelTextColor != null) this.labelTextColor = labelTextColor
+ if (afterLabel != null) this.afterLabel = afterLabel
+ if (afterBody != null) this.afterBody = afterBody
+ if (beforeFooter != null) this.beforeFooter = beforeFooter
+ if (footer != null) this.footer = footer
+ if (afterFooter != null) this.afterFooter = afterFooter
+ }
+}
+
+/**
+ * Chart tooltip options.
+ */
+data class TooltipOptions(
+ val enabled: Boolean = true,
+ val custom: ((a: Any) -> Unit)? = null,
+ val mode: InteractionMode = InteractionMode.NEAREST,
+ val intersect: Boolean = true,
+ val position: TooltipPosition = TooltipPosition.AVERAGE,
+ val callbacks: TooltipCallback? = null,
+ val filter: ((item: Chart.ChartTooltipItem, data: Chart.ChartData) -> Boolean)? = null,
+ val itemSort: ((itemA: Chart.ChartTooltipItem, itemB: Chart.ChartTooltipItem) -> Number)? = null,
+ val backgroundColor: Color? = null,
+ val titleFontSize: Int = 12,
+ val titleFontStyle: FontStyle? = null,
+ val titleFontColor: Color? = null,
+ val titleFontFamily: String? = null,
+ val titleSpacing: Int = 2,
+ val titleMarginBottom: Int = 6,
+ val bodyFontSize: Int = 12,
+ val bodyFontStyle: FontStyle? = null,
+ val bodyFontColor: Color? = null,
+ val bodyFontFamily: String? = null,
+ val bodySpacing: Int = 2,
+ val footerFontSize: Int = 12,
+ val footerFontStyle: FontStyle? = null,
+ val footerFontColor: Color? = null,
+ val footerFontFamily: String? = null,
+ val footerSpacing: Int = 2,
+ val footerMarginTop: Int = 6,
+ val xPadding: Int = 6,
+ val yPadding: Int = 6,
+ val caretPadding: Int = 2,
+ val caretSize: Int = 5,
+ val cornerRadius: Int = 6,
+ val multiKeyBackground: Color? = null,
+ val displayColors: Boolean = true,
+ val borderColor: Color? = null,
+ val borderWidth: Int = 0
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+@Suppress("ComplexMethod")
+fun TooltipOptions.toJs(): dynamic {
+ return obj {
+ this.enabled = enabled
+ if (custom != null) this.custom = custom
+ this.mode = mode.mode
+ this.intersect = intersect
+ this.position = position.mode
+ if (callbacks != null) this.callbacks = callbacks.toJs()
+ if (filter != null) this.filter = filter
+ if (itemSort != null) this.itemSort = itemSort
+ if (backgroundColor != null) this.backgroundColor = backgroundColor.asString()
+ this.titleFontSize = titleFontSize
+ if (titleFontStyle != null) this.titleFontStyle = titleFontStyle.name
+ if (titleFontColor != null) this.titleFontColor = titleFontColor.asString()
+ if (titleFontFamily != null) this.titleFontFamily = titleFontFamily
+ this.titleSpacing = titleSpacing
+ this.titleMarginBottom = titleMarginBottom
+ this.bodyFontSize = bodyFontSize
+ if (bodyFontStyle != null) this.bodyFontStyle = bodyFontStyle.name
+ if (bodyFontColor != null) this.bodyFontColor = bodyFontColor.asString()
+ if (bodyFontFamily != null) this.bodyFontFamily = bodyFontFamily
+ this.bodySpacing = bodySpacing
+ this.footerFontSize = footerFontSize
+ if (footerFontStyle != null) this.footerFontStyle = footerFontStyle.name
+ if (footerFontColor != null) this.footerFontColor = footerFontColor.asString()
+ if (footerFontFamily != null) this.footerFontFamily = footerFontFamily
+ this.footerSpacing = footerSpacing
+ this.footerMarginTop = footerMarginTop
+ this.xPadding = xPadding
+ this.yPadding = yPadding
+ this.caretPadding = caretPadding
+ this.caretSize = caretSize
+ this.cornerRadius = cornerRadius
+ if (multiKeyBackground != null) this.multiKeyBackground = multiKeyBackground.asString()
+ this.displayColors = displayColors
+ if (borderColor != null) this.borderColor = borderColor.asString()
+ this.borderWidth = borderWidth
+ }
+}
+
+/**
+ * Chart point options.
+ */
+data class PointOptions(
+ val radius: Int = 3,
+ val pointStyle: PointStyle = PointStyle.CIRCLE,
+ val backgroundColor: Color? = null,
+ val borderWidth: Int = 1,
+ val borderColor: Color? = null,
+ val hitRadius: Int = 1,
+ val hoverRadius: Int = 4,
+ val hoverBorderWidth: Int = 1
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun PointOptions.toJs(): dynamic {
+ return obj {
+ this.radius = radius
+ this.pointStyle = pointStyle.style
+ if (backgroundColor != null) this.backgroundColor = backgroundColor.asString()
+ this.borderWidth = borderWidth
+ if (borderColor != null) this.borderColor = borderColor.asString()
+ this.hitRadius = hitRadius
+ this.hoverRadius = hoverRadius
+ this.hoverBorderWidth = hoverBorderWidth
+ }
+}
+
+/**
+ * Chart line options.
+ */
+data class LineOptions(
+ val cubicInterpolationMode: InterpolationMode = InterpolationMode.DEFAULT,
+ val tension: Double = 0.2,
+ val backgroundColor: Color? = null,
+ val borderWidth: Int = 1,
+ val borderColor: Color? = null,
+ val borderCapStyle: LineCap? = null,
+ val borderDash: List<Any>? = null,
+ val borderDashOffset: Int = 0,
+ val borderJoinStyle: LineJoin? = null,
+ val capBezierPoints: Boolean = true,
+ val fill: Boolean = true,
+ val stepped: Boolean = false
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun LineOptions.toJs(): dynamic {
+ return obj {
+ this.cubicInterpolationMode = cubicInterpolationMode.mode
+ this.tension = tension
+ if (backgroundColor != null) this.backgroundColor = backgroundColor.asString()
+ this.borderWidth = borderWidth
+ if (borderColor != null) this.borderColor = borderColor.asString()
+ if (borderCapStyle != null) this.borderCapStyle = borderCapStyle.mode
+ if (borderDash != null) this.borderDash = borderDash.toTypedArray()
+ this.borderDashOffset = borderDashOffset
+ if (borderJoinStyle != null) this.borderJoinStyle = borderJoinStyle.mode
+ this.capBezierPoints = capBezierPoints
+ this.fill = fill
+ this.stepped = stepped
+ }
+}
+
+/**
+ * Chart arc options.
+ */
+data class ArcOptions(
+ val backgroundColor: Color? = null,
+ val borderColor: Color? = null,
+ val borderWidth: Int = 2
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun ArcOptions.toJs(): dynamic {
+ return obj {
+ if (backgroundColor != null) this.backgroundColor = backgroundColor.asString()
+ if (borderColor != null) this.borderColor = borderColor.asString()
+ this.borderWidth = borderWidth
+ }
+}
+
+/**
+ * Chart rectangle options.
+ */
+data class RectangleOptions(
+ val backgroundColor: Color? = null,
+ val borderColor: Color? = null,
+ val borderWidth: Int = 0,
+ val borderSkipped: Position = Position.BOTTOM
+)
+
+/**
+ * An extension function to convert configuration class to JS object.
+ */
+fun RectangleOptions.toJs(): dynamic {
+ return obj {
+ if (backgroundColor != null) this.backgroundColor = backgroundColor.asString()
+ if (borderColor != null) this.borderColor = borderColor.asString()
+ this.borderWidth = borderWidth
+ this.borderSkipped = borderSkipped.position
+ }
+}
+
+/**
+ * Chart elements options.
+ */
+data class ElementsOptions(
+ val point: PointOptions? = null,
+ val line: LineOptions? = null,
+ val arc: ArcOptions? = null,
+ val rectangle: RectangleOptions? = null
+)
+
+/**
+ * An extension function to convert configuration class to JS object.