diff options
| author | Robert Jaros <rjaros@finn.pl> | 2019-03-10 14:12:00 +0100 |
|---|---|---|
| committer | Robert Jaros <rjaros@finn.pl> | 2019-03-10 14:12:00 +0100 |
| commit | c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea (patch) | |
| tree | 9244923c93b6f17d8f58cb94c4a83a2619a42469 | |
| parent | c13d0441dddf31ef019333fd16378b3fc56003a4 (diff) | |
| download | kvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.tar.gz kvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.tar.bz2 kvision-c1b79ad6549ce8dc3a2398fa1e4a8b34b09eecea.zip | |
New module with support for drawing charts based on chart.js library.
14 files changed, 2154 insertions, 1 deletions
@@ -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. |
