├── .gitignore
├── .idea
└── copyright
│ ├── LetsPlot.xml
│ └── profiles_settings.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android_demo.gif
├── build.gradle.kts
├── demo
├── android-plot-view
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ └── demo
│ │ │ └── plot
│ │ │ └── view
│ │ │ ├── DensityPlotDemoActivity.kt
│ │ │ ├── PlotGirdDemoActivity.kt
│ │ │ ├── ResizingWithFitContainerSizePolicyDemoActivity.kt
│ │ │ └── ResizingWithFixedPlotSizePolicyDemoActivity.kt
│ │ └── res
│ │ ├── drawable
│ │ └── ic_launcher_foreground.xml
│ │ ├── layout
│ │ └── activity_another.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ └── values
│ │ ├── ic_launcher_background.xml
│ │ └── strings.xml
├── android-svg-view
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ └── demo
│ │ │ └── svg
│ │ │ └── view
│ │ │ ├── MainActivity.kt
│ │ │ ├── SvgReferenceFixedSize.kt
│ │ │ └── SvgReferenceWrapContent.kt
│ │ └── res
│ │ ├── drawable
│ │ └── ic_launcher_foreground.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ └── values
│ │ ├── ic_launcher_background.xml
│ │ └── strings.xml
├── plot
│ ├── compose-android-median
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ └── demo
│ │ │ │ └── plot
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── ui
│ │ │ │ ├── DemoDropdownMenu.kt
│ │ │ │ └── DemoRadioGroup.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ └── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── strings.xml
│ ├── compose-android-min
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ └── demo
│ │ │ │ ├── plot
│ │ │ │ └── MainActivity.kt
│ │ │ │ └── util
│ │ │ │ └── SandboxPanel.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ └── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── strings.xml
│ ├── compose-android-redraw
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── jniLibs
│ │ │ ├── arm64-v8a
│ │ │ │ └── libskiko-android-arm64.so
│ │ │ └── x86_64
│ │ │ │ └── libskiko-android-x64.so
│ │ │ ├── kotlin
│ │ │ └── demo
│ │ │ │ └── letsPlot
│ │ │ │ └── composeAndroidMin
│ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ └── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── strings.xml
│ ├── compose-desktop
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── demo
│ │ │ ├── plot
│ │ │ ├── median
│ │ │ │ ├── AppMain.kt
│ │ │ │ └── ui
│ │ │ │ │ └── DemoList.kt
│ │ │ ├── minimal
│ │ │ │ ├── DensityCompose.kt
│ │ │ │ ├── MultiplePlotSizeLayoutCompose.kt
│ │ │ │ ├── MultiplePlotWeightLayoutCompose.kt
│ │ │ │ ├── PieCompose.kt
│ │ │ │ ├── PlotGridCompose.kt
│ │ │ │ └── Recomposition.kt
│ │ │ ├── redraw
│ │ │ │ └── FastRedrawApp.kt
│ │ │ └── various
│ │ │ │ ├── HyperlinkCompose.kt
│ │ │ │ ├── StrokeDashCompose.kt
│ │ │ │ └── ToolbarCompose.kt
│ │ │ └── util
│ │ │ └── SandboxPanel.kt
│ ├── shared
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ ├── demoData
│ │ │ ├── AutoMpg.kt
│ │ │ ├── Iris.kt
│ │ │ └── Raster.kt
│ │ │ └── plotSpec
│ │ │ ├── AutoSpec.kt
│ │ │ ├── BarPlotSpec.kt
│ │ │ ├── CurveSpec.kt
│ │ │ ├── DensitySpec.kt
│ │ │ ├── FacetWrapSpec.kt
│ │ │ ├── HyperlinkSpec.kt
│ │ │ ├── LabelSpec.kt
│ │ │ ├── MarginalLayersFacetsSpec.kt
│ │ │ ├── MarkdownSpec.kt
│ │ │ ├── PerfSpec.kt
│ │ │ ├── PieSpec.kt
│ │ │ ├── PlotDemoSpec.kt
│ │ │ ├── PlotGridSpec.kt
│ │ │ ├── PolarHeatmapSpec.kt
│ │ │ ├── RasterSpec.kt
│ │ │ ├── StrokeDashSpec.kt
│ │ │ ├── SuperscriptExponentNotationSpec.kt
│ │ │ ├── ThemeOptionsSpec.kt
│ │ │ ├── TooltipAnchorSpec.kt
│ │ │ ├── VariadicPathSpec.kt
│ │ │ └── ViolinSpec.kt
│ └── swing
│ │ ├── build.gradle.kts
│ │ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── demo
│ │ ├── plot
│ │ ├── defaultViewer
│ │ │ └── DensityViewer.kt
│ │ └── various
│ │ │ ├── BarPlot.kt
│ │ │ ├── Curve.kt
│ │ │ ├── Density.kt
│ │ │ ├── FacetWrap.kt
│ │ │ ├── Hyperlink.kt
│ │ │ ├── Label.kt
│ │ │ ├── MarginalLayersFacets.kt
│ │ │ ├── Markdown.kt
│ │ │ ├── Pie.kt
│ │ │ ├── PlotGrid.kt
│ │ │ ├── PolarHeatmap.kt
│ │ │ ├── Raster.kt
│ │ │ ├── SuperscriptExponentNotation.kt
│ │ │ ├── ThemeOptions.kt
│ │ │ ├── TooltipAnchor.kt
│ │ │ ├── VariadicPath.kt
│ │ │ └── Violin.kt
│ │ └── util
│ │ └── PlotSpecsDemoWindow.kt
└── svg
│ ├── android-svg-compose
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ └── demo
│ │ │ ├── plot
│ │ │ └── MainActivity.kt
│ │ │ └── util
│ │ │ └── SandboxPanel.kt
│ │ └── res
│ │ ├── drawable
│ │ └── ic_launcher_foreground.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ └── values
│ │ ├── ic_launcher_background.xml
│ │ └── strings.xml
│ ├── compose-desktop
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── demo
│ │ └── svg
│ │ └── AppMain.kt
│ ├── shared
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── demo
│ │ └── svgModel
│ │ ├── ClipPathSvgModel.kt
│ │ ├── OpacityDemoModel.kt
│ │ ├── ReferenceSvgModel.kt
│ │ ├── SvgDsl.kt
│ │ └── SvgImageElementModel.kt
│ └── swing
│ ├── build.gradle.kts
│ └── src
│ └── main
│ └── kotlin
│ └── demo
│ └── svg
│ ├── ClipPathSvgDemo.kt
│ ├── OpacityDemo.kt
│ ├── ReferenceSvgDemo.kt
│ ├── SuperscriptExponentNotationDemo.kt
│ ├── SvgImageElementDemo.kt
│ ├── TextJustificationDemo.kt
│ ├── TextLabelDemo.kt
│ ├── TooltipBoxDemo.kt
│ └── utils
│ ├── DemoBase.kt
│ └── DemoWindow.kt
├── devdocs
├── DEVELOPMENT.md
├── PUBLISHING.md
└── RELEASE.md
├── future_changes.md
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img-2.png
├── img.png
├── lets-plot-compose
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── org
│ │ └── jetbrains
│ │ └── letsPlot
│ │ └── skia
│ │ └── compose
│ │ ├── PlotPanel.kt
│ │ └── android
│ │ ├── ColorRect.kt
│ │ ├── PlotComponentProvider.kt
│ │ └── PlotViewContainer.kt
│ ├── commonMain
│ └── kotlin
│ │ └── org
│ │ └── jetbrains
│ │ └── letsPlot
│ │ └── skia
│ │ └── compose
│ │ ├── PlotPanel.kt
│ │ └── util
│ │ └── NaiveLogger.kt
│ └── desktopMain
│ └── kotlin
│ └── org
│ └── jetbrains
│ └── letsPlot
│ └── skia
│ └── compose
│ ├── PlotFigureModel.kt
│ ├── PlotPanel.kt
│ ├── PlotToolbar.kt
│ └── desktop
│ ├── DebouncedRunner.kt
│ └── PlotContainer.kt
├── lets-plot-swing-skia
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── org
│ └── jetbrains
│ └── letsPlot
│ └── skia
│ └── swing
│ ├── AwtAppEnv.kt
│ ├── FigureEx.kt
│ ├── PlotComponentProviderSkiaSwing.kt
│ ├── PlotPanelSkiaSwing.kt
│ └── PlotViewerWindowSkia.kt
├── local.properties.template
├── platf-skia-awt
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── org
│ └── jetbrains
│ └── letsPlot
│ └── skia
│ └── awt
│ ├── builderHW
│ ├── FigureToSkiaAwt.kt
│ ├── MonolithicSkiaAwt.kt
│ └── Util.kt
│ └── view
│ ├── SvgPanel.kt
│ └── SvgSkikoViewAwt.kt
├── platf-skia
├── build.gradle.kts
└── src
│ ├── androidInstrumentedTest
│ ├── AndroidManifest.xml
│ ├── kotlin
│ │ └── org
│ │ │ └── jetbrains
│ │ │ └── letsPlot
│ │ │ └── android
│ │ │ └── canvas
│ │ │ ├── ContextClipTest.kt
│ │ │ ├── ContextPath2dTest.kt
│ │ │ ├── ImageComparer.kt
│ │ │ └── Utils.kt
│ └── resources
│ │ ├── arc_transform_after_restore.bmp
│ │ ├── bezier_curve_inside_path.bmp
│ │ ├── circle_fill.bmp
│ │ ├── circle_fill_stroke.bmp
│ │ ├── circle_stroke.bmp
│ │ ├── clip_after_transform.bmp
│ │ ├── clip_and_fill.bmp
│ │ ├── clip_before_transform.bmp
│ │ ├── clip_path.bmp
│ │ ├── clip_restore.bmp
│ │ ├── ellipse.bmp
│ │ ├── ellipse_inside_path.bmp
│ │ ├── ellipse_inside_path_diff.bmp
│ │ ├── multi_path_fill.bmp
│ │ ├── multi_path_stroke.bmp
│ │ ├── nested_translates.bmp
│ │ ├── path_transform_on_build.bmp
│ │ ├── rotated_ellipse.bmp
│ │ ├── rounded_rect_with_curves.bmp
│ │ ├── sheared_circular_arc.bmp
│ │ ├── sheared_ellipse.bmp
│ │ ├── simple_bezier_curve.bmp
│ │ ├── simple_clip_path.bmp
│ │ ├── text_skew_transform.bmp
│ │ ├── zigzag_fill.bmp
│ │ └── zigzag_stroke.bmp
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── org
│ │ └── jetbrains
│ │ └── letsPlot
│ │ ├── android
│ │ └── canvas
│ │ │ ├── AndroidAnimationTimerPeer.kt
│ │ │ ├── AndroidCanvas.kt
│ │ │ ├── AndroidContext2d.kt
│ │ │ ├── AndroidMouseEventMapper.kt
│ │ │ ├── CanvasView.kt
│ │ │ ├── SizeConverter.kt
│ │ │ └── Utils.kt
│ │ └── skia
│ │ └── android
│ │ └── view
│ │ └── SvgCanvasView.kt
│ ├── commonMain
│ └── kotlin
│ │ └── org
│ │ └── jetbrains
│ │ └── letsPlot
│ │ └── skia
│ │ ├── builderLW
│ │ ├── CompositeFigureEventDispatcher.kt
│ │ ├── FigureToViewModel.kt
│ │ ├── MonolithicSkiaLW.kt
│ │ └── ViewModel.kt
│ │ ├── mapping
│ │ └── svg
│ │ │ ├── DebugOptions.kt
│ │ │ ├── FontManager.kt
│ │ │ ├── SkiaTargetPeer.kt
│ │ │ ├── SvgElementMapper.kt
│ │ │ ├── SvgGElementMapper.kt
│ │ │ ├── SvgImageElementMapper.kt
│ │ │ ├── SvgNodeMapper.kt
│ │ │ ├── SvgNodeMapperFactory.kt
│ │ │ ├── SvgSkiaPeer.kt
│ │ │ ├── SvgStyleElementMapper.kt
│ │ │ ├── SvgSvgElementMapper.kt
│ │ │ ├── SvgTextElementMapper.kt
│ │ │ ├── SvgTransformParser.kt
│ │ │ ├── SvgUtils.kt
│ │ │ └── attr
│ │ │ ├── SvgAttrMapping.kt
│ │ │ ├── SvgCircleAttrMapping.kt
│ │ │ ├── SvgEllipseAttrMapping.kt
│ │ │ ├── SvgGAttrMapping.kt
│ │ │ ├── SvgImageAttrMapping.kt
│ │ │ ├── SvgLineAttrMapping.kt
│ │ │ ├── SvgPathAttrMapping.kt
│ │ │ ├── SvgRectAttrMapping.kt
│ │ │ ├── SvgShapeMapping.kt
│ │ │ ├── SvgSvgAttrMapping.kt
│ │ │ ├── SvgTSpanElementAttrMapping.kt
│ │ │ └── SvgTextElementAttrMapping.kt
│ │ ├── shape
│ │ ├── Circle.kt
│ │ ├── Colors.kt
│ │ ├── ComputedProperty.kt
│ │ ├── Container.kt
│ │ ├── Element.kt
│ │ ├── Ellipse.kt
│ │ ├── Figure.kt
│ │ ├── Group.kt
│ │ ├── Image.kt
│ │ ├── Line.kt
│ │ ├── Node.kt
│ │ ├── Pane.kt
│ │ ├── Path.kt
│ │ ├── Rectangle.kt
│ │ ├── TSpan.kt
│ │ ├── Text.kt
│ │ ├── Util.kt
│ │ └── VisualProperty.kt
│ │ └── view
│ │ ├── SkikoViewEventDispatcher.kt
│ │ └── SvgSkikoView.kt
│ └── jvmTest
│ └── kotlin
│ └── org
│ └── jetbrains
│ └── letsPlot
│ └── skia
│ └── shape
│ ├── HierarchyTest.kt
│ ├── PropertiesSynchronizationTest.kt
│ ├── SvgComplianceTest.kt
│ └── SvgDocUtil.kt
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | # share copyright profiles
3 | !.idea/copyright
4 |
5 | *.iml
6 | *.so
7 | .gradle
8 | .DS_Store
9 | **/build
10 | **/out
11 | demo-android-app/src/main/jniLibs/arm64-v8a/org/*
12 | demo-android-app/src/main/jniLibs/arm64-v8a/META-INF/*
13 | demo-android-app/src/main/jniLibs/x86_64/org/*
14 | demo-android-app/src/main/jniLibs/x86_64/META-INF/*
15 | /kotlin-js-store/yarn.lock
16 |
17 | local.properties
18 | skiko-jni-libs.zip
19 |
20 | .maven-publish-dev-repo/*
--------------------------------------------------------------------------------
/.idea/copyright/LetsPlot.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 JetBrains
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/android_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/android_demo.gif
--------------------------------------------------------------------------------
/demo/android-plot-view/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("com.android.application")
9 | }
10 |
11 | android {
12 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
13 | namespace = "demo.plot.view"
14 |
15 | defaultConfig {
16 | applicationId = "demo.plot.view"
17 |
18 | minSdk = (findProperty("android.minSdk") as String).toInt()
19 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
20 |
21 | versionCode = 1
22 | versionName = "1.0"
23 |
24 | ndk {
25 | abiFilters += listOf("x86_64", "arm64-v8a")
26 | }
27 | }
28 |
29 | buildTypes {
30 | debug {
31 | isDebuggable = true
32 | }
33 | }
34 |
35 | compileOptions {
36 | sourceCompatibility = JavaVersion.VERSION_11
37 | targetCompatibility = JavaVersion.VERSION_11
38 | }
39 |
40 | kotlin {
41 | jvmToolchain(11)
42 | }
43 | }
44 |
45 | val letsPlotVersion = extra["letsPlot.version"] as String
46 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
47 |
48 | dependencies {
49 | implementation(project(":platf-skia"))
50 | implementation(project(":demo-plot-shared"))
51 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:${letsPlotKotlinVersion}")
52 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
53 | implementation("org.jetbrains.lets-plot:canvas:${letsPlotVersion}")
54 | implementation("org.jetbrains.lets-plot:plot-raster:$letsPlotVersion")
55 | }
56 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/kotlin/demo/plot/view/DensityPlotDemoActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import org.jetbrains.letsPlot.android.canvas.CanvasView
12 | import org.jetbrains.letsPlot.core.util.sizing.SizingPolicy
13 | import org.jetbrains.letsPlot.intern.toSpec
14 | import org.jetbrains.letsPlot.raster.builder.MonolithicCanvas
15 | import plotSpec.DensitySpec
16 |
17 | class DensityPlotDemoActivity : Activity() {
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 |
21 | val plotFigure = DensitySpec().createFigure()
22 |
23 | setContentView(
24 | CanvasView(this).apply {
25 | figure = MonolithicCanvas.buildPlotFigureFromRawSpec(
26 | rawSpec = plotFigure.toSpec(),
27 | sizingPolicy = SizingPolicy.fitContainerSize(false),
28 | computationMessagesHandler = {}
29 | )
30 | setBackgroundColor(Color.GREEN)
31 | }
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/kotlin/demo/plot/view/PlotGirdDemoActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import org.jetbrains.letsPlot.android.canvas.CanvasView
12 | import org.jetbrains.letsPlot.core.util.sizing.SizingPolicy
13 | import org.jetbrains.letsPlot.intern.toSpec
14 | import org.jetbrains.letsPlot.raster.builder.MonolithicCanvas
15 | import plotSpec.PlotGridSpec
16 |
17 | class PlotGirdDemoActivity : Activity() {
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 |
21 | val plotFigure = PlotGridSpec().createFigure()
22 |
23 | setContentView(
24 | CanvasView(this).apply {
25 | figure = MonolithicCanvas.buildPlotFigureFromRawSpec(
26 | rawSpec = plotFigure.toSpec(),
27 | sizingPolicy = SizingPolicy.fitContainerSize(false),
28 | computationMessagesHandler = {}
29 | )
30 | setBackgroundColor(Color.GREEN)
31 | }
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/kotlin/demo/plot/view/ResizingWithFitContainerSizePolicyDemoActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import demo.plot.view.ResizingWithFixedPlotSizePolicyDemoActivity.Companion.setupResizableCanvas
12 | import org.jetbrains.letsPlot.android.canvas.CanvasView
13 | import org.jetbrains.letsPlot.core.util.sizing.SizingPolicy
14 | import org.jetbrains.letsPlot.intern.toSpec
15 | import org.jetbrains.letsPlot.raster.builder.MonolithicCanvas
16 | import plotSpec.DensitySpec
17 |
18 | class ResizingWithFitContainerSizePolicyDemoActivity: Activity() {
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | val plotFigure = DensitySpec().createFigure()
22 |
23 | val view = CanvasView(this).apply {
24 | figure = MonolithicCanvas.buildPlotFigureFromRawSpec(
25 | rawSpec = plotFigure.toSpec(),
26 | sizingPolicy = SizingPolicy.fitContainerSize(false),
27 | computationMessagesHandler = {}
28 | )
29 | setBackgroundColor(Color.GREEN)
30 | }
31 |
32 |
33 |
34 | setupResizableCanvas(view)
35 | }
36 | }
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/kotlin/demo/plot/view/ResizingWithFixedPlotSizePolicyDemoActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import android.widget.FrameLayout
12 | import org.jetbrains.letsPlot.android.canvas.CanvasView
13 | import org.jetbrains.letsPlot.core.util.sizing.SizingPolicy
14 | import org.jetbrains.letsPlot.intern.toSpec
15 | import org.jetbrains.letsPlot.raster.builder.MonolithicCanvas
16 | import plotSpec.DensitySpec
17 | import java.util.*
18 |
19 | class ResizingWithFixedPlotSizePolicyDemoActivity: Activity() {
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | val plotFigure = DensitySpec().createFigure()
23 |
24 | val view = CanvasView(this).apply {
25 | figure = MonolithicCanvas.buildPlotFigureFromRawSpec(
26 | rawSpec = plotFigure.toSpec(),
27 | sizingPolicy = SizingPolicy.keepFigureDefaultSize(),
28 | computationMessagesHandler = {}
29 | )
30 | setBackgroundColor(Color.GREEN)
31 | }
32 |
33 | setupResizableCanvas(view)
34 | }
35 |
36 | companion object {
37 | fun Activity.setupResizableCanvas(view: CanvasView) {
38 | setContentView(view)
39 | val resizeTask = object : TimerTask() {
40 | var width = 500
41 | var height = 500
42 | var dv = 2
43 |
44 | override fun run() {
45 | runOnUiThread {
46 | if (width < 500 || width > 1000) {
47 | dv *= -1
48 | }
49 |
50 | width += dv
51 | height += dv
52 |
53 | view.layoutParams = FrameLayout.LayoutParams(width, height)
54 | }
55 | }
56 | }
57 | Timer().schedule(resizeTask, 0, 10)
58 | }
59 |
60 | }
61 | }
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/layout/activity_another.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/android-plot-view/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SVG to Canvas Mapping Demo
3 |
4 |
--------------------------------------------------------------------------------
/demo/android-svg-view/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("com.android.application")
9 | }
10 |
11 | android {
12 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
13 | namespace = "demo.svg.view"
14 |
15 | defaultConfig {
16 | applicationId = "demo.svg.view"
17 |
18 | minSdk = (findProperty("android.minSdk") as String).toInt()
19 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
20 |
21 | versionCode = 1
22 | versionName = "1.0"
23 | }
24 |
25 | buildTypes {
26 | debug {
27 | isDebuggable = true
28 | }
29 | }
30 |
31 | compileOptions {
32 | sourceCompatibility = JavaVersion.VERSION_11
33 | targetCompatibility = JavaVersion.VERSION_11
34 | }
35 |
36 | kotlin {
37 | jvmToolchain(11)
38 | }
39 | }
40 |
41 | val letsPlotVersion = extra["letsPlot.version"] as String
42 |
43 | dependencies {
44 | implementation(project(":platf-skia"))
45 | implementation(project(":demo-svg-shared"))
46 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
47 | implementation("org.jetbrains.lets-plot:canvas:${letsPlotVersion}")
48 | implementation("org.jetbrains.lets-plot:plot-raster:$letsPlotVersion")
49 | }
50 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/kotlin/demo/svg/view/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import android.view.ViewGroup
12 | import android.widget.Button
13 | import android.widget.LinearLayout
14 | import demo.svgModel.ClipPathSvgModel
15 | import demo.svgModel.ReferenceSvgModel
16 | import demo.svgModel.SvgImageElementModel
17 | import org.jetbrains.letsPlot.android.canvas.CanvasView
18 | import org.jetbrains.letsPlot.raster.view.SvgCanvasFigure
19 |
20 | class MainActivity : Activity() {
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 |
24 | val layout = LinearLayout(this)
25 | layout.orientation = LinearLayout.VERTICAL
26 | layout.layoutParams =
27 | LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
28 | setContentView(layout, layout.layoutParams)
29 |
30 | layout.addView(Button(this).apply {
31 | text = "Back"
32 | setOnClickListener {
33 | println("Back button clicked")
34 | }
35 | })
36 | // Svg pictures A, B, C
37 | layout.addView(
38 | CanvasView(this).apply {
39 | figure = SvgCanvasFigure(ReferenceSvgModel.createModel())
40 | setBackgroundColor(Color.GREEN)
41 | }
42 | )
43 |
44 | layout.addView(
45 | CanvasView(this).apply {
46 | figure = SvgCanvasFigure(SvgImageElementModel.createModel())
47 | setBackgroundColor(Color.RED)
48 | }
49 | )
50 |
51 | layout.addView(
52 | CanvasView(this).apply {
53 | figure = SvgCanvasFigure(ClipPathSvgModel.createModel())
54 | setBackgroundColor(Color.BLUE)
55 | }
56 | )
57 | }
58 | }
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/kotlin/demo/svg/view/SvgReferenceFixedSize.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import android.view.ViewGroup
12 | import demo.svgModel.ReferenceSvgModel
13 | import org.jetbrains.letsPlot.android.canvas.CanvasView
14 | import org.jetbrains.letsPlot.raster.view.SvgCanvasFigure
15 |
16 | class SvgReferenceFixedSize : Activity() {
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 |
20 | setContentView(
21 | CanvasView(this).apply {
22 | figure = SvgCanvasFigure(ReferenceSvgModel.createModel())
23 | setBackgroundColor(Color.BLUE)
24 | },
25 | ViewGroup.LayoutParams(500, 500)
26 | )
27 | }
28 | }
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/kotlin/demo/svg/view/SvgReferenceWrapContent.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg.view
7 |
8 | import android.app.Activity
9 | import android.graphics.Color
10 | import android.os.Bundle
11 | import android.view.ViewGroup
12 | import android.widget.LinearLayout
13 | import demo.svgModel.ReferenceSvgModel
14 | import org.jetbrains.letsPlot.android.canvas.CanvasView
15 | import org.jetbrains.letsPlot.raster.view.SvgCanvasFigure
16 |
17 | class SvgReferenceWrapContent : Activity() {
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 |
21 | setContentView(
22 | CanvasView(this).apply {
23 | figure = SvgCanvasFigure(ReferenceSvgModel.createModel())
24 | setBackgroundColor(Color.BLUE)
25 | },
26 | LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
27 | )
28 | }
29 | }
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/android-svg-view/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SVG to Canvas Mapping Demo
3 |
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("org.jetbrains.compose")
9 | id("com.android.application")
10 | kotlin("plugin.compose")
11 | }
12 |
13 |
14 | android {
15 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
16 | namespace = "demo.plot.CanvasDemo"
17 |
18 | buildFeatures {
19 | compose = true
20 | }
21 |
22 | defaultConfig {
23 | applicationId = "demo.plot.CanvasDemo"
24 |
25 | minSdk = (findProperty("android.minSdk") as String).toInt()
26 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
27 |
28 | versionCode = 1
29 | versionName = "1.0"
30 | }
31 |
32 | buildTypes {
33 | debug {
34 | isDebuggable = true
35 | }
36 | }
37 |
38 | compileOptions {
39 | sourceCompatibility = JavaVersion.VERSION_11
40 | targetCompatibility = JavaVersion.VERSION_11
41 | }
42 |
43 | kotlin {
44 | jvmToolchain(11)
45 | }
46 | }
47 |
48 | val composeVersion = extra["compose.version"] as String
49 | val androidxActivityCompose = extra["androidx.activity.compose"] as String
50 | val letsPlotVersion = extra["letsPlot.version"] as String
51 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
52 |
53 | dependencies {
54 | implementation(compose.runtime)
55 | implementation(compose.foundation)
56 | implementation(compose.material)
57 | implementation(compose.ui)
58 | implementation("androidx.activity:activity-compose:$androidxActivityCompose")
59 |
60 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
61 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
62 | implementation("org.jetbrains.lets-plot:canvas:${letsPlotVersion}")
63 | implementation("org.jetbrains.lets-plot:plot-raster:${letsPlotVersion}")
64 |
65 | implementation(project(":lets-plot-compose"))
66 | implementation(project(":demo-plot-shared"))
67 |
68 | implementation("org.slf4j:slf4j-api:2.0.9")
69 | implementation("com.github.tony19:logback-android:3.0.0")
70 | }
71 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/kotlin/demo/plot/ui/DemoDropdownMenu.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.ui
7 |
8 | import androidx.compose.foundation.layout.Box
9 | import androidx.compose.material.*
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.MutableState
12 | import androidx.compose.runtime.mutableStateOf
13 | import androidx.compose.runtime.remember
14 |
15 |
16 | @Suppress("FunctionName")
17 | @Composable
18 | fun DemoDropdownMenu(
19 | options: List,
20 | selectedIndex: MutableState
21 | ) {
22 | val expanded = remember { (mutableStateOf(false)) }
23 |
24 | Box() {
25 | @OptIn(ExperimentalMaterialApi::class)
26 | ExposedDropdownMenuBox(
27 | expanded = expanded.value,
28 | onExpandedChange = {
29 | expanded.value = !expanded.value
30 | },
31 | // modifier = Modifier.height(40.dp).width(40.dp)
32 | ) {
33 | TextField(
34 | value = options[selectedIndex.value],
35 | onValueChange = {},
36 | readOnly = true,
37 | trailingIcon = {
38 | @OptIn(ExperimentalMaterialApi::class)
39 | ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded.value)
40 | }
41 | )
42 |
43 | @OptIn(ExperimentalMaterialApi::class)
44 | ExposedDropdownMenu(
45 | expanded = expanded.value,
46 | onDismissRequest = { expanded.value = false }
47 | ) {
48 | options.forEachIndexed { index, name ->
49 | DropdownMenuItem(
50 | onClick = {
51 | selectedIndex.value = index
52 | expanded.value = false
53 | }
54 | ) {
55 | Text(text = name)
56 | }
57 | }
58 | }
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-median/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Plot Rendering Demo (median)
3 |
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("org.jetbrains.compose")
9 | id("com.android.application")
10 | kotlin("plugin.compose")
11 | }
12 |
13 |
14 | android {
15 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
16 | namespace = "demo.plot.CanvasDemo"
17 |
18 | buildFeatures {
19 | compose = true
20 | }
21 |
22 | defaultConfig {
23 | applicationId = "demo.plot.CanvasDemo"
24 |
25 | minSdk = (findProperty("android.minSdk") as String).toInt()
26 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
27 |
28 | versionCode = 1
29 | versionName = "1.0"
30 | }
31 |
32 | buildTypes {
33 | debug {
34 | isDebuggable = true
35 | }
36 | }
37 |
38 | compileOptions {
39 | sourceCompatibility = JavaVersion.VERSION_11
40 | targetCompatibility = JavaVersion.VERSION_11
41 | }
42 |
43 | kotlin {
44 | jvmToolchain(11)
45 | }
46 | }
47 |
48 | val composeVersion = extra["compose.version"] as String
49 | val androidxActivityCompose = extra["androidx.activity.compose"] as String
50 | val letsPlotVersion = extra["letsPlot.version"] as String
51 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
52 |
53 | dependencies {
54 | implementation(compose.runtime)
55 | implementation(compose.foundation)
56 | implementation(compose.material)
57 | implementation(compose.ui)
58 | implementation("androidx.activity:activity-compose:$androidxActivityCompose")
59 |
60 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
61 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
62 | implementation("org.jetbrains.lets-plot:canvas:$letsPlotVersion")
63 | implementation("org.jetbrains.lets-plot:plot-raster:$letsPlotVersion")
64 |
65 | implementation(project(":lets-plot-compose"))
66 | implementation(project(":demo-plot-shared"))
67 |
68 | implementation("org.slf4j:slf4j-api:2.0.9")
69 | implementation("com.github.tony19:logback-android:3.0.0")
70 | }
71 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-min/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Plot Rendering Demo (min)
3 |
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("org.jetbrains.compose")
9 | id("com.android.application")
10 | kotlin("plugin.compose")
11 | }
12 |
13 |
14 | android {
15 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
16 | namespace = "demo.letsPlot"
17 |
18 | buildFeatures {
19 | compose = true
20 | }
21 |
22 | defaultConfig {
23 | applicationId = "demo.letsPlot.composeMinDemo"
24 |
25 | minSdk = (findProperty("android.minSdk") as String).toInt()
26 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
27 |
28 | versionCode = 1
29 | versionName = "1.0"
30 | }
31 |
32 | buildTypes {
33 | getByName("release") {
34 | signingConfig = signingConfigs.getByName("debug")
35 | }
36 | debug {
37 | isDebuggable = true
38 | }
39 | }
40 |
41 | compileOptions {
42 | sourceCompatibility = JavaVersion.VERSION_11
43 | targetCompatibility = JavaVersion.VERSION_11
44 | }
45 |
46 | kotlin {
47 | jvmToolchain(11)
48 | }
49 | }
50 |
51 | val composeVersion = extra["compose.version"] as String
52 | val androidxActivityCompose = extra["androidx.activity.compose"] as String
53 | val letsPlotVersion = extra["letsPlot.version"] as String
54 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
55 |
56 | dependencies {
57 | implementation(compose.runtime)
58 | implementation(compose.foundation)
59 | implementation(compose.material)
60 | implementation(compose.ui)
61 | implementation("androidx.activity:activity-compose:$androidxActivityCompose")
62 |
63 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
64 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
65 |
66 | implementation("org.jetbrains.lets-plot:canvas:${letsPlotVersion}")
67 | implementation("org.jetbrains.lets-plot:plot-raster:${letsPlotVersion}")
68 |
69 | implementation(project(":lets-plot-compose"))
70 | implementation(project(":demo-plot-shared"))
71 |
72 | implementation("org.slf4j:slf4j-api:2.0.9")
73 | implementation("com.github.tony19:logback-android:3.0.0")
74 | }
75 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/jniLibs/arm64-v8a/libskiko-android-arm64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/demo/plot/compose-android-redraw/src/main/jniLibs/arm64-v8a/libskiko-android-arm64.so
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/jniLibs/x86_64/libskiko-android-x64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/demo/plot/compose-android-redraw/src/main/jniLibs/x86_64/libskiko-android-x64.so
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-android-redraw/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Plot Redraw Demo
3 |
4 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | // kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
3 | kotlin("jvm")
4 | kotlin("plugin.compose")
5 | id("org.jetbrains.compose")
6 | }
7 |
8 | val letsPlotVersion = extra["letsPlot.version"] as String
9 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
10 |
11 | dependencies {
12 | implementation(compose.desktop.currentOs)
13 |
14 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
15 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
16 | implementation("org.jetbrains.lets-plot:platf-awt:$letsPlotVersion")
17 |
18 | implementation(project(":lets-plot-compose"))
19 | implementation(project(":demo-plot-shared"))
20 |
21 | implementation("org.slf4j:slf4j-simple:2.0.9") // Enable logging to console
22 | }
23 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/median/ui/DemoList.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.median.ui
7 |
8 | import androidx.compose.foundation.layout.*
9 | import androidx.compose.foundation.selection.selectable
10 | import androidx.compose.material.RadioButton
11 | import androidx.compose.material.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.runtime.MutableState
14 | import androidx.compose.ui.Alignment
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.unit.dp
17 |
18 |
19 | @Suppress("FunctionName")
20 | @Composable
21 | fun DemoList(
22 | options: List,
23 | selectedIndex: MutableState
24 | ) {
25 | Box() {
26 | Column(
27 | modifier = Modifier
28 | .width(IntrinsicSize.Max)
29 | ) {
30 | options.forEachIndexed { index, name ->
31 |
32 | Row(
33 | verticalAlignment = Alignment.CenterVertically,
34 | modifier = Modifier
35 | .fillMaxWidth()
36 | .height(24.dp)
37 | .selectable(
38 | selected = selectedIndex.value == index,
39 | onClick = { selectedIndex.value = index }
40 | )
41 | ) {
42 | RadioButton(
43 | onClick = { selectedIndex.value = index },
44 | selected = index == selectedIndex.value,
45 | )
46 | Text(name)
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/DensityCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.material.MaterialTheme
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Window
15 | import androidx.compose.ui.window.application
16 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
17 | import plotSpec.DensitySpec
18 |
19 | fun main() = application {
20 | Window(onCloseRequest = ::exitApplication, title = "Density Plot (Compose Desktop)") {
21 | MaterialTheme {
22 | Column(
23 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
24 | ) {
25 |
26 | PlotPanel(
27 | figure = DensitySpec().createFigure(),
28 | modifier = Modifier.fillMaxSize()
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/MultiplePlotSizeLayoutCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 | import androidx.compose.foundation.layout.*
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 | import androidx.compose.ui.window.Window
13 | import androidx.compose.ui.window.application
14 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
15 | import plotSpec.DensitySpec
16 |
17 | fun main() = application {
18 | Window(onCloseRequest = ::exitApplication, title = "Multiple Plot Size Layout (Compose Desktop)") {
19 | MaterialTheme {
20 | Column(
21 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
22 | ) {
23 |
24 | PlotPanel(
25 | figure = DensitySpec().createFigure(),
26 | modifier = Modifier.height(100.dp).width(100.dp)
27 | ) { computationMessages ->
28 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
29 | }
30 |
31 | PlotPanel(
32 | figure = DensitySpec().createFigure(),
33 | modifier = Modifier.height(100.dp).width(100.dp)
34 | ) { computationMessages ->
35 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
36 | }
37 | }
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/MultiplePlotWeightLayoutCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.material.MaterialTheme
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Window
15 | import androidx.compose.ui.window.application
16 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
17 | import plotSpec.DensitySpec
18 |
19 | fun main() = application {
20 | Window(onCloseRequest = ::exitApplication, title = "Multiple Plot Weight Layout (Compose Desktop)") {
21 | MaterialTheme {
22 | Column(
23 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
24 | ) {
25 |
26 | PlotPanel(
27 | figure = DensitySpec().createFigure(),
28 | modifier = Modifier.weight(1f)
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 |
33 | PlotPanel(
34 | figure = DensitySpec().createFigure(),
35 | modifier = Modifier.weight(1f)
36 | ) { computationMessages ->
37 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
38 | }
39 | }
40 | }
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/PieCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.material.MaterialTheme
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Window
15 | import androidx.compose.ui.window.application
16 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
17 | import plotSpec.PieSpec
18 |
19 | fun main() = application {
20 | Window(onCloseRequest = ::exitApplication, title = "Pie Plot (Compose Desktop)") {
21 | MaterialTheme {
22 | Column(
23 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
24 | ) {
25 |
26 | PlotPanel(
27 | figure = PieSpec().createFigure(),
28 | modifier = Modifier.fillMaxSize()
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/PlotGridCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.material.MaterialTheme
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Window
15 | import androidx.compose.ui.window.application
16 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
17 | import plotSpec.PlotGridSpec
18 |
19 | fun main() = application {
20 | Window(onCloseRequest = ::exitApplication, title = "Plot Grid (Compose Desktop)") {
21 | MaterialTheme {
22 | Column(
23 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
24 | ) {
25 |
26 | PlotPanel(
27 | figure = PlotGridSpec().createFigure(),
28 | modifier = Modifier.fillMaxSize()
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 | }
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/minimal/Recomposition.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.minimal
7 |
8 |
9 | import androidx.compose.foundation.layout.Column
10 | import androidx.compose.foundation.layout.fillMaxSize
11 | import androidx.compose.foundation.layout.padding
12 | import androidx.compose.material.Button
13 | import androidx.compose.material.MaterialTheme
14 | import androidx.compose.material.Text
15 | import androidx.compose.runtime.getValue
16 | import androidx.compose.runtime.mutableStateOf
17 | import androidx.compose.runtime.remember
18 | import androidx.compose.runtime.setValue
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.unit.dp
21 | import androidx.compose.ui.window.Window
22 | import androidx.compose.ui.window.application
23 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
24 | import plotSpec.DensitySpec
25 |
26 |
27 | // Enable logging to see recompositions:
28 | // org.jetbrains.letsPlot.skia.compose.util.NaiveLoggerKt.ENABLED
29 | fun main() = application {
30 | Window(onCloseRequest = ::exitApplication, title = "Density Plot (Compose Desktop)") {
31 | var counter by remember { mutableStateOf(0) }
32 |
33 | MaterialTheme {
34 | Column(
35 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
36 | ) {
37 | Button(onClick = { counter++ }) {
38 | Text("Click me! (already clicked $counter times)")
39 | }
40 |
41 | PlotPanel(
42 | figure = DensitySpec().createFigure(),
43 | modifier = Modifier.fillMaxSize()
44 | ) { computationMessages ->
45 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/various/HyperlinkCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import androidx.compose.foundation.layout.*
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 | import androidx.compose.ui.window.Window
13 | import androidx.compose.ui.window.application
14 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
15 | import plotSpec.HyperlinkSpec
16 |
17 | @OptIn(ExperimentalLayoutApi::class)
18 | fun main() = application {
19 | Window(onCloseRequest = ::exitApplication, title = "Hyperlink (Compose Desktop)") {
20 | MaterialTheme {
21 | FlowRow(
22 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
23 | ) {
24 | HyperlinkSpec().createFigureList().forEach { figure ->
25 | Column {
26 | PlotPanel(
27 | figure = figure,
28 | modifier = Modifier.size(610.dp)
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 | }
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/various/StrokeDashCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import androidx.compose.foundation.layout.*
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 | import androidx.compose.ui.window.Window
13 | import androidx.compose.ui.window.application
14 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
15 | import plotSpec.StrokeDashSpec
16 |
17 | @OptIn(ExperimentalLayoutApi::class)
18 | fun main() = application {
19 | Window(onCloseRequest = ::exitApplication, title = "StrokeDash (Compose Desktop)") {
20 | MaterialTheme {
21 | FlowRow(
22 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
23 | ) {
24 | StrokeDashSpec().createFigureList().forEach { figure ->
25 | Column {
26 | PlotPanel(
27 | figure = figure,
28 | modifier = Modifier.size(610.dp)
29 | ) { computationMessages ->
30 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
31 | }
32 | }
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/plot/various/ToolbarCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import androidx.compose.foundation.layout.*
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 | import androidx.compose.ui.window.Window
13 | import androidx.compose.ui.window.application
14 | import org.jetbrains.letsPlot.interact.ggtb
15 | import org.jetbrains.letsPlot.intern.Plot
16 | import org.jetbrains.letsPlot.skia.compose.PlotPanel
17 | import plotSpec.AutoSpec
18 |
19 |
20 | @OptIn(ExperimentalLayoutApi::class)
21 | fun main() = application {
22 | Window(onCloseRequest = ::exitApplication, title = "ggtb() (Compose Desktop)") {
23 | MaterialTheme {
24 | FlowRow(
25 | modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp, end = 10.dp, bottom = 10.dp),
26 | ) {
27 | AutoSpec().createFigureList().forEach { figure ->
28 | Column {
29 | PlotPanel(
30 | figure = (figure as Plot) + ggtb(),
31 | modifier = Modifier.fillMaxSize()
32 | ) { computationMessages ->
33 | computationMessages.forEach { println("[DEMO APP MESSAGE] $it") }
34 | }
35 | }
36 | }
37 | }
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/demo/plot/compose-desktop/src/main/kotlin/demo/util/SandboxPanel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.util
7 |
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.DisposableEffect
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.awt.NoOpUpdate
12 | import androidx.compose.ui.awt.SwingPanel
13 | import androidx.compose.ui.layout.onGloballyPositioned
14 | import androidx.compose.ui.platform.LocalDensity
15 | import java.awt.Color
16 | import java.awt.Component
17 | import java.awt.Rectangle
18 | import javax.swing.JPanel
19 |
20 | @Suppress("FunctionName")
21 | @Composable
22 | fun SandboxPanel(
23 | color: Color,
24 | modifier: Modifier,
25 |
26 | ) {
27 | val provider = SandboxPanelProvider(color)
28 |
29 | val factory: () -> Component = provider.factory
30 |
31 | DisposableEffect(factory) {
32 | onDispose {
33 | println("onDispose $this")
34 | }
35 | }
36 |
37 | val density = LocalDensity.current.density
38 | val modifier1 = modifier.onGloballyPositioned { coordinates ->
39 | val size = coordinates.size
40 | val width = size.width / density
41 | val height = size.height / density
42 |
43 | println("onGloballyPositioned $size density: $density")
44 | provider.onGloballyPositioned(width / 2, height / 2)
45 | }
46 | SwingPanel(
47 | background = androidx.compose.ui.graphics.Color.White,
48 | factory = factory,
49 | modifier = modifier1,
50 | update = NoOpUpdate
51 | )
52 | }
53 |
54 | private class SandboxPanelProvider(color: Color) {
55 | private val container = JPanel().apply {
56 | isOpaque = true
57 | background = color
58 | layout = null
59 | }
60 |
61 | val factory: () -> Component = { container }
62 |
63 | fun onGloballyPositioned(w: Float, h: Float) {
64 | container.removeAll() // ToDo: dispose
65 | container.add(
66 | JPanel().also {
67 | it.bounds = Rectangle(0, 0, w.toInt(), h.toInt())
68 | it.isOpaque = true
69 | it.background = Color.YELLOW
70 | }
71 | )
72 | }
73 | }
--------------------------------------------------------------------------------
/demo/plot/shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("jvm")
8 | }
9 |
10 | val letsPlotVersion = extra["letsPlot.version"] as String
11 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
12 |
13 | dependencies {
14 | compileOnly("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
15 |
16 | compileOnly("org.jetbrains.lets-plot:commons:$letsPlotVersion")
17 | compileOnly("org.jetbrains.lets-plot:datamodel:$letsPlotVersion")
18 |
19 | testImplementation(kotlin("test"))
20 | }
21 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/demoData/Raster.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demoData
7 |
8 | object Raster {
9 | @Suppress("FunctionName")
10 | fun rasterData_Blue(): Map> {
11 | val x = ArrayList()
12 | val y = ArrayList()
13 | val fill = ArrayList()
14 | val alpha = ArrayList()
15 |
16 | val width = 3
17 | val height = 3
18 | for (col in 0 until width) {
19 | for (row in 0 until height) {
20 | x.add(col.toDouble())
21 | y.add(row.toDouble())
22 | fill.add(col.toDouble())
23 | alpha.add(row.toDouble())
24 | }
25 | }
26 |
27 | @Suppress("DuplicatedCode")
28 | val map = HashMap>()
29 | map["x"] = x
30 | map["y"] = y
31 | map["fill"] = fill
32 | map["alpha"] = alpha
33 | return map
34 | }
35 |
36 | @Suppress("FunctionName")
37 | fun rasterData_RGB(): Map> {
38 | // R | G | B alpha = 1
39 | // R | G | B alpha = 0.5
40 | // .5 | 1 | .5 <-- gray, alpha
41 |
42 | val fillInt = intArrayOf(0xFF0000, 0xFF00, 0xFF, 0xFF0000, 0xFF00, 0xFF, 0x7F0000, 0x7F00, 0x7F)
43 |
44 | val fill = ArrayList()
45 | for (i in fillInt) {
46 | fill.add(i.toDouble())
47 | }
48 |
49 | val alpha = listOf(1.0, 1.0, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5)
50 | val x = listOf(0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0)
51 | val y = listOf(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0)
52 |
53 | val map = HashMap>()
54 | map["x"] = x
55 | map["y"] = y
56 | map["fill"] = fill
57 | map["alpha"] = alpha
58 | return map
59 | }
60 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/AutoSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import demoData.AutoMpg
9 | import org.jetbrains.letsPlot.Figure
10 | import org.jetbrains.letsPlot.geom.geomLabel
11 | import org.jetbrains.letsPlot.geom.geomPoint
12 | import org.jetbrains.letsPlot.letsPlot
13 |
14 | class AutoSpec : PlotDemoSpec {
15 | override fun createFigureList(): List {
16 | return listOf(
17 | scatter()
18 | )
19 | }
20 |
21 | fun scatter(): Figure {
22 | return letsPlot(AutoMpg.map()) + geomPoint {
23 | x = "engine horsepower"
24 | y = "miles per gallon"
25 | color = "origin of car"
26 | } + geomLabel(
27 | checkOverlap = true,
28 | ) {
29 | x = "engine horsepower"
30 | y = "miles per gallon"
31 | color = "origin of car"
32 | label = "vehicle name"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/BarPlotSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.asDiscrete
10 | import org.jetbrains.letsPlot.geom.geomBar
11 | import org.jetbrains.letsPlot.letsPlot
12 | import org.jetbrains.letsPlot.scale.scaleFillDiscrete
13 | import org.jetbrains.letsPlot.scale.scaleFillHue
14 |
15 | class BarPlotSpec : PlotDemoSpec {
16 |
17 | override fun createFigureList(): List {
18 | val basic = letsPlot(DATA) +
19 | geomBar(alpha = 0.5) {
20 | x = "time"
21 | color = "time"
22 | fill = "time"
23 | }
24 |
25 | // ToDo: this doesn't work the same way as in the same demo in LP.
26 | val fancy = letsPlot(DATA) +
27 | geomBar {
28 | x = "time"
29 | fill = asDiscrete("..count..")
30 | } + scaleFillHue()
31 |
32 | return listOf(
33 | basic,
34 | fancy,
35 | fancyWithWidth(0.5),
36 | fancyWithWidth(5.0),
37 | )
38 | }
39 |
40 | private fun fancyWithWidth(w: Double): Figure {
41 | return letsPlot(DATA) +
42 | geomBar(width = w) {
43 | x = "time"
44 | fill = "..count.."
45 | } + scaleFillDiscrete()
46 | }
47 |
48 | companion object {
49 | val DATA = mapOf(
50 | "time" to listOf("Lunch", "Lunch", "Dinner", "Dinner", "Dinner")
51 | )
52 | }
53 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/CurveSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.extras.arrow
10 | import org.jetbrains.letsPlot.geom.geomCurve
11 | import org.jetbrains.letsPlot.intern.Plot
12 | import org.jetbrains.letsPlot.label.ggtitle
13 | import org.jetbrains.letsPlot.letsPlot
14 | import org.jetbrains.letsPlot.scale.xlim
15 |
16 | class CurveSpec : PlotDemoSpec {
17 |
18 | override fun createFigureList(): List {
19 |
20 | fun curvePlot(curvature: Double, angle: Int, ncp: Int = 0): Plot {
21 | val data = mapOf(
22 | "x" to listOf(-10),
23 | "y" to listOf(1),
24 | "xend" to listOf(10),
25 | "yend" to listOf(-1),
26 | )
27 |
28 | return letsPlot(data) { x = "x"; y = "y"; xend = "xend"; yend = "yend" } +
29 | geomCurve(curvature = curvature, angle = angle, ncp = ncp, arrow = arrow(ends = "both")) +
30 | xlim(listOf(-15, 15)) +
31 | ggtitle("curvature = $curvature, angle=$angle, ncp=$ncp")
32 | }
33 |
34 | return listOf(
35 | curvePlot(curvature = 0.5, angle = 0, ncp = 5),
36 | curvePlot(curvature = 0.5, angle = 90, ncp = 1),
37 | curvePlot(curvature = 0.5, angle = 45, ncp = 5),
38 | curvePlot(curvature = -1.0, angle = 45, ncp = 5),
39 | curvePlot(curvature = 0.7, angle = 30, ncp = 5),
40 | curvePlot(curvature = -0.7, angle = 30, ncp = 5),
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/DensitySpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import demoData.AutoMpg
9 | import demoData.Iris
10 | import org.jetbrains.letsPlot.Figure
11 | import org.jetbrains.letsPlot.coord.coordFixed
12 | import org.jetbrains.letsPlot.geom.geomDensity
13 | import org.jetbrains.letsPlot.letsPlot
14 |
15 | class DensitySpec : PlotDemoSpec {
16 | override fun createFigure(): Figure {
17 | val rand = java.util.Random()
18 | val n = 200
19 | val xs = List(n) { rand.nextGaussian() }
20 | val data = mapOf(
21 | "x" to xs,
22 | "w" to xs.map { if (it < 0.0) 2.0 else 0.5 }
23 | )
24 |
25 | return letsPlot(data) + geomDensity(color = "black", size = 1.2) {
26 | x = "x"
27 | }
28 | }
29 |
30 | override fun createFigureList(): List {
31 | val sepalLength = letsPlot(Iris.map()) +
32 | geomDensity(alpha = 0.7) {
33 | x = "sepal length (cm)"
34 | color = "sepal width (cm)"
35 | fill = "target"
36 | }
37 |
38 | val sepalLengthCoordFixed = letsPlot(Iris.map()) +
39 | geomDensity(alpha = 0.7) {
40 | x = "sepal length (cm)"
41 | color = "sepal width (cm)"
42 | fill = "target"
43 | } + coordFixed()
44 |
45 | val withQuantileAes = letsPlot(AutoMpg.map()) +
46 | geomDensity(alpha = 0.7, size = 2) {
47 | x = "miles per gallon"
48 | group = "number of cylinders"
49 | color = "..quantile.."
50 | }
51 |
52 | val withQuantileLines = letsPlot(Iris.map()) +
53 | geomDensity(
54 | color = "black",
55 | quantiles = listOf(0, 0.02, 0.1, 0.5, 0.9, 0.98, 1),
56 | quantileLines = true
57 | ) {
58 | x = "sepal length (cm)"
59 | group = "target"
60 | fill = "..quantile.."
61 | }
62 |
63 | return listOf(
64 | sepalLength,
65 | sepalLengthCoordFixed,
66 | withQuantileAes,
67 | withQuantileLines
68 | )
69 | }
70 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/FacetWrapSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import demoData.AutoMpg
9 | import org.jetbrains.letsPlot.Figure
10 | import org.jetbrains.letsPlot.facet.facetWrap
11 | import org.jetbrains.letsPlot.geom.geomPoint
12 | import org.jetbrains.letsPlot.intern.Plot
13 | import org.jetbrains.letsPlot.letsPlot
14 | import org.jetbrains.letsPlot.themes.themeGrey
15 |
16 | class FacetWrapSpec : PlotDemoSpec {
17 |
18 | override fun createFigureList(): List {
19 | val oneFacetDef = commonSpecs() + facetWrap(facets = "number of cylinders", format = "{d} cyl")
20 | val oneFacet3cols = commonSpecs() + facetWrap(facets = "number of cylinders", ncol = 3, format = "{d} cyl")
21 | val oneFacet4rows =
22 | commonSpecs() + facetWrap(facets = "number of cylinders", ncol = 4, dir = "v", format = "{d} cyl")
23 | val twoFacets = commonSpecs() + facetWrap(
24 | facets = listOf("origin of car", "number of cylinders"),
25 | ncol = 5,
26 | format = listOf(null, "{d} cyl")
27 | )
28 | val twoFacetsCylindersOrderDesc = commonSpecs() + facetWrap(
29 | facets = listOf("origin of car", "number of cylinders"),
30 | ncol = 5,
31 | order = listOf(null, -1),
32 | format = listOf(null, "{d} cyl")
33 | )
34 |
35 | return listOf(
36 | oneFacetDef,
37 | oneFacet3cols,
38 | oneFacet4rows,
39 | twoFacets,
40 | twoFacetsCylindersOrderDesc,
41 | )
42 | }
43 |
44 | private fun commonSpecs(): Plot {
45 | return letsPlot(AutoMpg.map()) {
46 | x = "engine horsepower"
47 | y = "miles per gallon"
48 | color = "origin of car"
49 | } + geomPoint() + themeGrey()
50 | }
51 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/LabelSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.geomLabel
10 | import org.jetbrains.letsPlot.letsPlot
11 |
12 | class LabelSpec : PlotDemoSpec {
13 | override fun createFigureList(): List {
14 | val fonts = run {
15 | val families = listOf(
16 | "Arial",
17 | "Calibri",
18 | "Garamond",
19 | "Geneva",
20 | "Georgia",
21 | "Helvetica",
22 | "Lucida Grande",
23 | "Rockwell",
24 | "Times New Roman",
25 | "Verdana",
26 | "sans-serif",
27 | "serif",
28 | "monospace"
29 | )
30 | letsPlot() + geomLabel {
31 | y = families.indices
32 | label = families
33 | family = families
34 | }
35 | }
36 |
37 | return listOf(fonts)
38 | }
39 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/MarkdownSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import demoData.AutoMpg
9 | import org.jetbrains.letsPlot.Figure
10 | import org.jetbrains.letsPlot.geom.geomPoint
11 | import org.jetbrains.letsPlot.label.labs
12 | import org.jetbrains.letsPlot.letsPlot
13 | import org.jetbrains.letsPlot.scale.scaleColorManual
14 | import org.jetbrains.letsPlot.themes.elementMarkdown
15 | import org.jetbrains.letsPlot.themes.elementText
16 | import org.jetbrains.letsPlot.themes.theme
17 |
18 | class MarkdownSpec : PlotDemoSpec {
19 | override fun createFigureList(): List {
20 | return listOf(
21 | mpg()
22 | )
23 | }
24 |
25 | fun mpg(): Figure {
26 | return letsPlot(AutoMpg.map()) +
27 | geomPoint(size=8) { x="engine displacement (cu. inches)"; y="miles per gallon"; color="number of cylinders" } +
28 | scaleColorManual(listOf("#66c2a5", "#fc8d62", "#8da0cb"), guide="none") +
29 |
30 | // Enable Markdown in all titles
31 | theme(title=elementMarkdown()) +
32 |
33 | // Adjust style of title and subtitle
34 | theme(plotTitle=elementText(size=30, family="Georgia", hjust=0.5),
35 | plotSubtitle=elementText(family="Georgia", hjust=0.5)) +
36 |
37 | labs(
38 |
39 | // Span styling, mixing style and emphasis
40 | title=
41 | """**4**, """ +
42 | """**6** and """ +
43 | """**8** cylinders""",
44 |
45 | // Simple emphasis
46 | subtitle="**City milage** *vs* **displacement**",
47 |
48 | // multiline caption, multiline style span, links
49 | caption="" +
50 | "Powered by Lets-Plot. \n" +
51 | "Visit the issue tracker for feedback." +
52 | "",
53 |
54 | // Axis titles
55 | x="Displacement (***inches***)",
56 | y="Miles per gallon (***cty***)"
57 | )
58 |
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/PerfSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.geomPoint
10 | import org.jetbrains.letsPlot.intern.Plot
11 | import org.jetbrains.letsPlot.letsPlot
12 | import org.jetbrains.letsPlot.sampling.samplingNone
13 | import kotlin.random.Random
14 |
15 | class PerfSpec : PlotDemoSpec {
16 |
17 | private fun points(): Plot {
18 | val rand = Random(12)
19 | val n = 25_000
20 |
21 | val data = mapOf(
22 | "x" to List(n) { rand.nextDouble() },
23 | "y" to List(n) { rand.nextDouble() },
24 | "col" to List(n) { rand.nextDouble() },
25 | )
26 |
27 | return letsPlot(data) + geomPoint(size = 8, alpha = 0.3, sampling = samplingNone) {
28 | x = "x"
29 | y = "y"
30 | color = "col"
31 | }
32 | }
33 |
34 | override fun createFigureList(): List {
35 | return listOf(points())
36 | }
37 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/PieSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.Stat
10 | import org.jetbrains.letsPlot.geom.geomPie
11 | import org.jetbrains.letsPlot.letsPlot
12 |
13 | class PieSpec : PlotDemoSpec {
14 | override fun createFigureList(): List {
15 | return listOf(
16 | simplePie(),
17 | multiPie()
18 | )
19 | }
20 |
21 | private fun multiPie(): Figure {
22 |
23 | val data = mapOf(
24 | "x" to listOf("a", "a", "a", "a", "a", "b", "b", "c", "c", "c"),
25 | "y" to listOf(1, 1, 1, 1, 1, 2, 2, 1.5, 1.5, 1.5),
26 | "s" to listOf(3, 1, 2, 1, 4, 1, 3, 3, 3, 1),
27 | "n" to listOf("a", "b", "a", "c", "a", "a", "b", "c", "a", "b")
28 | )
29 | return letsPlot(data) +
30 | geomPie(size = 10, hole=0.3) {
31 | x = "x"
32 | y = "y"
33 | slice = "s"
34 | fill = "n"
35 | }
36 | }
37 |
38 | private fun simplePie(): Figure {
39 | val data = mapOf(
40 | "name" to listOf('a', 'b', 'c', 'd', 'b'),
41 | "value" to listOf(40, 90, 10, 50, 20)
42 | )
43 | return letsPlot(data) +
44 | geomPie(stat = Stat.identity, size = 0.7, sizeUnit = "x") {
45 | slice = "value"
46 | fill = "name"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/PlotDemoSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 |
10 | interface PlotDemoSpec {
11 | fun createFigure(): Figure {
12 | return createFigureList().first()
13 | }
14 |
15 | fun createFigureList(): List
16 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/PolarHeatmapSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.coord.coordPolar
10 | import org.jetbrains.letsPlot.geom.geomTile
11 | import org.jetbrains.letsPlot.ggplot
12 | import org.jetbrains.letsPlot.label.ggtitle
13 | import org.jetbrains.letsPlot.scale.scaleBrewer
14 | import org.jetbrains.letsPlot.themes.elementBlank
15 | import org.jetbrains.letsPlot.themes.theme
16 | import kotlin.math.PI
17 | import kotlin.math.cos
18 | import kotlin.math.sin
19 |
20 | class PolarHeatmapSpec : PlotDemoSpec {
21 | override fun createFigureList(): List {
22 | return listOf(
23 | polarHeatmap()
24 | )
25 | }
26 |
27 | private fun polarHeatmap(): Figure {
28 | val maxR = 100
29 | val stepsR = 4 * maxR
30 | val maxTheta = 2 * PI
31 | val stepsTheta = 200
32 | val dataFunction: (Double, Double) -> Double = { x, y -> sin(x * 7) + cos(y / 11) }
33 |
34 | fun linspace(start: Double, stop: Double, num: Int): List {
35 | if (num <= 0) return emptyList()
36 | if (num == 1) return listOf(start)
37 | val step = (stop - start) / (num - 1)
38 | return List(num) { start + it * step }
39 | }
40 |
41 | fun simpleMeshgrid(xs: List, ys: List): Pair>, List>> {
42 | return Pair(
43 | List(ys.size) { xs },
44 | ys.map { y -> List(xs.size) { y } }
45 | )
46 | }
47 |
48 | fun getData(xs: List, ys: List, f: (Double, Double) -> Double): Map> {
49 | val zs = (xs zip ys).map { p -> f(p.first, p.second) }
50 | return mapOf("x" to xs, "y" to ys, "z" to zs)
51 | }
52 |
53 | val (gridR, gridTheta) = simpleMeshgrid(
54 | linspace(0.0, maxR.toDouble(), stepsR),
55 | linspace(0.0, maxTheta.toDouble(), stepsTheta)
56 | )
57 |
58 | val dataMap = getData(gridTheta.flatten(), gridR.flatten(), dataFunction)
59 |
60 | val p = ggplot(dataMap) +
61 | geomTile(size = 1) { x = "x"; y = "y"; color = "z"; fill = "z" } +
62 | scaleBrewer(listOf("color", "fill"), palette = "Spectral", direction = -1) +
63 | theme(axisTitle = elementBlank())
64 |
65 | return p + coordPolar() + ggtitle("Cartesian Heatmap")
66 | }
67 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/RasterSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import demoData.Raster.rasterData_Blue
9 | import demoData.Raster.rasterData_RGB
10 | import org.jetbrains.letsPlot.Figure
11 | import org.jetbrains.letsPlot.geom.geomRaster
12 | import org.jetbrains.letsPlot.letsPlot
13 | import org.jetbrains.letsPlot.scale.scaleFillIdentity
14 |
15 | class RasterSpec : PlotDemoSpec {
16 |
17 | override fun createFigureList(): List {
18 | return listOf(
19 | rasterPlot(rasterData_Blue(), scaleFillIdentity = false),
20 | rasterPlot(rasterData_RGB(), scaleFillIdentity = true)
21 | )
22 | }
23 |
24 | private fun rasterPlot(data: Map<*, *>, scaleFillIdentity: Boolean): Figure {
25 | var plot = letsPlot(data) +
26 | geomRaster {
27 | x = "x"
28 | y = "y"
29 | fill = "fill"
30 | alpha = "alpha"
31 | }
32 |
33 | if (scaleFillIdentity) {
34 | plot += scaleFillIdentity()
35 | }
36 |
37 | return plot
38 | }
39 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/StrokeDashSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.geomSegment
10 | import org.jetbrains.letsPlot.ggplot
11 |
12 | class StrokeDashSpec : PlotDemoSpec {
13 | override fun createFigureList(): List {
14 | return listOf(
15 | ggplot()
16 | + geomSegment(x=0, y=20, xend = 100, yend=20, linetype = listOf(5, listOf(10, 5)))
17 | + geomSegment(x=0, y=10, xend = 100, yend=10, linetype = listOf(0, listOf(10, 5)))
18 | + geomSegment(x=0, y=0, xend = 100, yend=0),
19 | )
20 | }
21 | }
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/SuperscriptExponentNotationSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.geomPoint
10 | import org.jetbrains.letsPlot.label.ggtitle
11 | import org.jetbrains.letsPlot.letsPlot
12 | import org.jetbrains.letsPlot.themes.theme
13 | import kotlin.math.pow
14 |
15 | class SuperscriptExponentNotationSpec : PlotDemoSpec {
16 | override fun createFigureList(): List {
17 | return listOf(
18 | simple()
19 | )
20 | }
21 |
22 | private fun simple(): Figure {
23 | val xs: List = (-10..10).map(Int::toDouble).toList()
24 | val f: (Double) -> Double = { it * 10.0.pow(-5) }
25 | val data = mapOf("x" to xs, "y" to xs.map(f))
26 | return letsPlot(data) {
27 | x = "x"; y = "y"
28 | } + geomPoint() + ggtitle("No transform") + theme(exponentFormat = "pow")
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/demo/plot/shared/src/main/kotlin/plotSpec/VariadicPathSpec.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package plotSpec
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.geom.geomPath
10 | import org.jetbrains.letsPlot.label.ggtitle
11 | import org.jetbrains.letsPlot.letsPlot
12 |
13 | class VariadicPathSpec : PlotDemoSpec {
14 | override fun createFigureList(): List {
15 | return listOf(
16 | variadicPathPlot()
17 | )
18 | }
19 |
20 | private fun variadicPathPlot(): Figure {
21 | val data = mapOf(
22 | "x" to listOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ),
23 | "y" to listOf(0.0, 5.0, 0.0, 10.0, 0.0, 5.0, 0.0, 5.0, 0.0 ),
24 | "g" to listOf(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0 ),
25 | "c" to listOf(1.0, 17.0, 4.0, 8.0, 3.0, 15.0, 15.0, 2.0, 9.0 ),
26 | "s" to listOf(10.0, 10.0, 10.0, 8.0, 3.0, 9.0, 15.0, 12.0, 9.0),
27 | )
28 | return letsPlot(data) + geomPath() { x = "x"; y = "y"; size = "s"; color = "c" } + ggtitle("Variadic Path")
29 | }
30 | }
--------------------------------------------------------------------------------
/demo/plot/swing/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("jvm")
3 | }
4 |
5 | val osName = System.getProperty("os.name")!!
6 | val hostOs = when {
7 | osName == "Mac OS X" -> "macos"
8 | osName.startsWith("Win") -> "windows"
9 | osName.startsWith("Linux") -> "linux"
10 | else -> error("Unsupported OS: $osName")
11 | }
12 |
13 | var hostArch = when (val osArch = System.getProperty("os.arch")) {
14 | "x86_64", "amd64" -> "x64"
15 | "aarch64" -> "arm64"
16 | else -> error("Unsupported arch: $osArch")
17 | }
18 |
19 | val skikoVersion = extra["skiko.version"] as String
20 | val letsPlotVersion = extra["letsPlot.version"] as String
21 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
22 |
23 | dependencies {
24 | implementation("org.jetbrains.skiko:skiko:$skikoVersion")
25 | implementation("org.jetbrains.skiko:skiko-awt-runtime-$hostOs-$hostArch:$skikoVersion")
26 |
27 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
28 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
29 | implementation("org.jetbrains.lets-plot:platf-awt:$letsPlotVersion")
30 |
31 | implementation(project(":lets-plot-swing-skia"))
32 | implementation(project(":demo-plot-shared"))
33 |
34 | implementation("org.slf4j:slf4j-simple:2.0.9") // Enable logging to console
35 | }
36 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/defaultViewer/DensityViewer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.defaultViewer
7 |
8 | import org.jetbrains.letsPlot.skia.swing.PlotViewerWindowSkia
9 | import plotSpec.DensitySpec
10 |
11 | fun main() {
12 | with(DensitySpec()) {
13 | PlotViewerWindowSkia(
14 | "Density plot",
15 | createFigure(),
16 | null,
17 | preserveAspectRatio = false
18 | ).open()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/BarPlot.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.BarPlotSpec
10 |
11 | fun main() {
12 | with(BarPlotSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Bar-plot",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Curve.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.CurveSpec
10 |
11 | fun main() {
12 | with(CurveSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Curve",
15 | createFigureList(),
16 | maxCol = 2
17 | ).open()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Density.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.DensitySpec
10 |
11 | fun main() {
12 | with(DensitySpec()) {
13 | PlotSpecsDemoWindow(
14 | "Density plot",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/FacetWrap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.FacetWrapSpec
10 |
11 | fun main() {
12 | with(FacetWrapSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Facet Wrap",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Hyperlink.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.HyperlinkSpec
10 |
11 | fun main() {
12 | with(HyperlinkSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Hyperlink",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Label.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.LabelSpec
10 |
11 | fun main() {
12 | with(LabelSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Labels",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/MarginalLayersFacets.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.MarginalLayersFacetsSpec
10 |
11 | fun main() {
12 | with(MarginalLayersFacetsSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Marginal Layers",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Markdown.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.MarkdownSpec
10 |
11 | fun main() {
12 | with(MarkdownSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Markdown",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Pie.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.PieSpec
10 |
11 | fun main() {
12 | with(PieSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Pie-plot",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/PlotGrid.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.PlotGridSpec
10 |
11 | fun main() {
12 | with(PlotGridSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Plot grid",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/PolarHeatmap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.PolarHeatmapSpec
10 |
11 | fun main() {
12 | with(PolarHeatmapSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Polar heatmap",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Raster.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.RasterSpec
10 |
11 | fun main() {
12 | with(RasterSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Raster",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/SuperscriptExponentNotation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.SuperscriptExponentNotationSpec
10 |
11 | fun main() {
12 | with(SuperscriptExponentNotationSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Superscript exponent notation",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/ThemeOptions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.ThemeOptionsSpec
10 |
11 | fun main() {
12 | with(ThemeOptionsSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Theme options",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/TooltipAnchor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.TooltipAnchorSpec
10 |
11 | fun main() {
12 | with(TooltipAnchorSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Tooltip Anchor",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/VariadicPath.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.VariadicPathSpec
10 |
11 | fun main() {
12 | with(VariadicPathSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Variadic Path",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/plot/various/Violin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.plot.various
7 |
8 | import demo.util.PlotSpecsDemoWindow
9 | import plotSpec.ViolinSpec
10 |
11 | fun main() {
12 | with(ViolinSpec()) {
13 | PlotSpecsDemoWindow(
14 | "Violin",
15 | createFigureList(),
16 | ).open()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/plot/swing/src/main/kotlin/demo/util/PlotSpecsDemoWindow.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.util
7 |
8 | import org.jetbrains.letsPlot.Figure
9 | import org.jetbrains.letsPlot.skia.swing.createComponent
10 | import java.awt.Color
11 | import java.awt.Dimension
12 | import java.awt.GridLayout
13 | import javax.swing.*
14 | import kotlin.math.min
15 |
16 | internal class PlotSpecsDemoWindow(
17 | title: String,
18 | private val figures: List,
19 | maxCol: Int = 3,
20 | private val plotSize: Dimension? = null,
21 | background: Color = Color.WHITE,
22 | ) : JFrame("$title (Skia Swing)") {
23 | private val rootPanel: JPanel
24 |
25 | init {
26 | defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
27 |
28 | rootPanel = JPanel()
29 | rootPanel.layout = GridLayout(0, min(maxCol, figures.size))
30 | rootPanel.background = background
31 | rootPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
32 |
33 | if (plotSize == null) {
34 | contentPane.add(rootPanel)
35 | } else {
36 | // Fixed plot size
37 | val scrollPane = JScrollPane(
38 | rootPanel,
39 | ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
40 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
41 |
42 | )
43 | contentPane.add(scrollPane)
44 | }
45 | }
46 |
47 | fun open() {
48 | SwingUtilities.invokeLater {
49 | createWindowContent()
50 |
51 | pack()
52 | setLocationRelativeTo(null) // move to the screen center
53 | isVisible = true
54 | }
55 | }
56 |
57 | private fun createWindowContent() {
58 | val preferredSizeFromPlot = (plotSize == null)
59 | val components = figures.map { figure ->
60 | val figureComponent = figure.createComponent(
61 | preferredSizeFromPlot = preferredSizeFromPlot
62 | ) { messages ->
63 | for (message in messages) {
64 | println("[Demo Plot Viewer] $message")
65 | }
66 | }
67 |
68 | plotSize?.let {
69 | figureComponent.preferredSize = it
70 | }
71 |
72 | figureComponent
73 | }
74 |
75 | components.forEach { rootPanel.add(it) }
76 | }
77 | }
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("android")
8 | id("org.jetbrains.compose")
9 | id("com.android.application")
10 | kotlin("plugin.compose")
11 | }
12 |
13 |
14 | android {
15 | compileSdk = (findProperty("android.compileSdk") as String).toInt()
16 | namespace = "demo.plot.CanvasDemo"
17 |
18 | buildFeatures {
19 | compose = true
20 | }
21 |
22 | defaultConfig {
23 | applicationId = "demo.plot.CanvasDemo"
24 |
25 | minSdk = (findProperty("android.minSdk") as String).toInt()
26 | targetSdk = (findProperty("android.targetSdk") as String).toInt()
27 |
28 | versionCode = 1
29 | versionName = "1.0"
30 | }
31 |
32 | buildTypes {
33 | debug {
34 | isDebuggable = true
35 | }
36 | }
37 |
38 | compileOptions {
39 | sourceCompatibility = JavaVersion.VERSION_11
40 | targetCompatibility = JavaVersion.VERSION_11
41 | }
42 |
43 | kotlin {
44 | jvmToolchain(11)
45 | }
46 | }
47 |
48 | val composeVersion = extra["compose.version"] as String
49 | val androidxActivityCompose = extra["androidx.activity.compose"] as String
50 | val letsPlotVersion = extra["letsPlot.version"] as String
51 | val letsPlotKotlinVersion = extra["letsPlotKotlin.version"] as String
52 |
53 | dependencies {
54 | implementation(compose.runtime)
55 | implementation(compose.foundation)
56 | implementation(compose.material)
57 | implementation(compose.ui)
58 | implementation("androidx.activity:activity-compose:$androidxActivityCompose")
59 |
60 | implementation("org.jetbrains.lets-plot:lets-plot-kotlin-kernel:$letsPlotKotlinVersion")
61 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
62 | implementation("org.jetbrains.lets-plot:canvas:$letsPlotVersion")
63 | implementation("org.jetbrains.lets-plot:plot-raster:$letsPlotVersion")
64 |
65 | implementation(project(":lets-plot-compose"))
66 | implementation(project(":demo-plot-shared"))
67 |
68 | implementation("org.slf4j:slf4j-api:2.0.9")
69 | implementation("com.github.tony19:logback-android:3.0.0")
70 | }
71 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3C3F41
4 |
--------------------------------------------------------------------------------
/demo/svg/android-svg-compose/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Plot Rendering Demo (min)
3 |
4 |
--------------------------------------------------------------------------------
/demo/svg/compose-desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | //import org.jetbrains.compose.desktop.application.dsl.TargetFormat
2 |
3 | plugins {
4 | // kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
5 | kotlin("jvm")
6 | kotlin("plugin.compose")
7 | id("org.jetbrains.compose")
8 | }
9 |
10 | val letsPlotVersion = extra["letsPlot.version"] as String
11 |
12 | dependencies {
13 | implementation(compose.desktop.currentOs)
14 |
15 | implementation(project(":platf-skia"))
16 | implementation(project(":platf-skia-awt"))
17 |
18 | implementation(project(":demo-svg-shared"))
19 |
20 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
21 | }
22 |
--------------------------------------------------------------------------------
/demo/svg/shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023. JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | plugins {
7 | kotlin("jvm")
8 | }
9 |
10 | val kotlinLoggingVersion = extra["kotlinLogging.version"] as String
11 | val letsPlotVersion = extra["letsPlot.version"] as String
12 |
13 | dependencies {
14 | implementation("io.github.microutils:kotlin-logging-jvm:$kotlinLoggingVersion")
15 |
16 | compileOnly("org.jetbrains.lets-plot:commons:$letsPlotVersion")
17 | compileOnly("org.jetbrains.lets-plot:datamodel:$letsPlotVersion")
18 |
19 | testImplementation(kotlin("test"))
20 | }
21 |
--------------------------------------------------------------------------------
/demo/svg/shared/src/main/kotlin/demo/svgModel/OpacityDemoModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svgModel
7 |
8 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgColors
9 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgNode
10 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgSvgElement
11 |
12 | object OpacityDemoModel {
13 | fun createModel() = SvgSvgElement(width = 600.0, height = 400.0).apply {
14 | var i = 0
15 | fun SvgNode.row(text: String, opacity: Double? = null, strokeOpacity: Double? = null, fillOpacity: Double? = null) {
16 | val x = 200.0
17 | val size = 60.0
18 | val strokeWidth = 15.0
19 | val vMargin = 30.0
20 | val hMargin = 10.0
21 | val y = 40 + i * (size + vMargin)
22 | i++
23 |
24 | rect(x, y, size, size, SvgColors.CRIMSON, SvgColors.STEEL_BLUE, strokeWidth) {
25 | opacity?.let { setAttribute("opacity", it.toString()) }
26 | strokeOpacity?.let { setAttribute("stroke-opacity", it.toString()) }
27 | fillOpacity?.let { setAttribute("fill-opacity", it.toString()) }
28 | }
29 | text(text, x = x + size + hMargin, y = y + size / 2)
30 | }
31 |
32 | g {
33 | row("opacity=0.5", opacity = 0.5)
34 | row("fill/stroke-opacity=0.5", fillOpacity = 0.5, strokeOpacity = 0.5)
35 | row("fill-opacity=0.5", fillOpacity = 0.5)
36 | row("stroke-opacity=0.5", strokeOpacity = 0.5)
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/demo/svg/swing/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("jvm")
3 | }
4 |
5 | val skikoVersion = extra["skiko.version"] as String
6 | val letsPlotVersion = extra["letsPlot.version"] as String
7 |
8 | val osName = System.getProperty("os.name")!!
9 | val hostOs = when {
10 | osName == "Mac OS X" -> "macos"
11 | osName.startsWith("Win") -> "windows"
12 | osName.startsWith("Linux") -> "linux"
13 | else -> error("Unsupported OS: $osName")
14 | }
15 |
16 | var hostArch = when (val osArch = System.getProperty("os.arch")) {
17 | "x86_64", "amd64" -> "x64"
18 | "aarch64" -> "arm64"
19 | else -> error("Unsupported arch: $osArch")
20 | }
21 |
22 | val host = "${hostOs}-${hostArch}"
23 |
24 |
25 | dependencies {
26 | implementation("org.jetbrains.skiko:skiko:$skikoVersion")
27 | implementation("org.jetbrains.skiko:skiko-awt-runtime-$hostOs-$hostArch:$skikoVersion")
28 |
29 | implementation(project(":platf-skia"))
30 | implementation(project(":platf-skia-awt"))
31 |
32 | implementation(project(":demo-svg-shared"))
33 |
34 | implementation("org.jetbrains.lets-plot:lets-plot-common:$letsPlotVersion")
35 | }
36 |
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/ClipPathSvgDemo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg
7 |
8 | import demo.svg.utils.DemoWindow
9 | import demo.svgModel.ClipPathSvgModel
10 |
11 | fun main() {
12 | DemoWindow("SVG with clip-path", listOf(ClipPathSvgModel.createModel())).open()
13 | }
14 |
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/OpacityDemo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg
7 |
8 | import demo.svg.utils.DemoWindow
9 | import demo.svgModel.OpacityDemoModel
10 |
11 | fun main() {
12 | DemoWindow("Opacity Demo", listOf(OpacityDemoModel.createModel())).open()
13 | }
14 |
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/ReferenceSvgDemo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg
7 |
8 | import demo.svg.utils.DemoWindow
9 | import demo.svgModel.ReferenceSvgModel
10 |
11 | fun main() {
12 | DemoWindow("Reference SVG", listOf(ReferenceSvgModel.createModel())).open()
13 | }
14 |
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/SvgImageElementDemo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg
7 |
8 | import demo.svg.utils.DemoWindow
9 | import demo.svgModel.SvgImageElementModel
10 |
11 | fun main() {
12 | DemoWindow("SvgImage demo", listOf(SvgImageElementModel.createModel())).open()
13 | }
14 |
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/utils/DemoBase.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg.utils
7 |
8 | import org.jetbrains.letsPlot.commons.geometry.DoubleRectangle
9 | import org.jetbrains.letsPlot.commons.geometry.DoubleVector
10 | import org.jetbrains.letsPlot.core.plot.base.render.svg.GroupComponent
11 | import org.jetbrains.letsPlot.core.plot.builder.presentation.Style
12 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgColors
13 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgCssResource
14 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgRectElement
15 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgSvgElement
16 |
17 | internal abstract class DemoBase(
18 | private val demoInnerSize: DoubleVector
19 | ) {
20 | protected open val cssStyle: String = Style.generateCSS(Style.default(), plotId = null, decorationLayerId = null)
21 |
22 | private val demoOuterSize = demoInnerSize.add(PADDING.mul(2.0))
23 |
24 | fun createSvgRoots(demoGroups: List): List {
25 | return demoGroups.map {
26 | it.moveTo(PADDING)
27 | val svgRoot = createSvgRoot()
28 | svgRoot.children().add(it.rootGroup)
29 | svgRoot
30 | }
31 | }
32 |
33 | private fun createSvgRoot(): SvgSvgElement {
34 | val svg = SvgSvgElement()
35 | svg.width().set(demoOuterSize.x)
36 | svg.height().set(demoOuterSize.y)
37 | svg.addClass(Style.PLOT_CONTAINER)
38 |
39 | svg.setStyle(object : SvgCssResource {
40 | override fun css(): String = cssStyle
41 | })
42 |
43 | val viewport = DoubleRectangle(PADDING, demoInnerSize)
44 | val viewportRect = SvgRectElement(viewport)
45 | viewportRect.stroke().set(SvgColors.LIGHT_BLUE)
46 | viewportRect.fill().set(SvgColors.NONE)
47 | svg.children().add(viewportRect)
48 |
49 | return svg
50 | }
51 |
52 | companion object {
53 | private val PADDING = DoubleVector(20.0, 20.0)
54 | }
55 | }
--------------------------------------------------------------------------------
/demo/svg/swing/src/main/kotlin/demo/svg/utils/DemoWindow.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package demo.svg.utils
7 |
8 | import org.jetbrains.letsPlot.datamodel.svg.dom.SvgSvgElement
9 | import org.jetbrains.letsPlot.skia.awt.view.SvgPanel
10 | import java.awt.Color
11 | import java.awt.GridLayout
12 | import javax.swing.*
13 | import kotlin.math.min
14 |
15 | internal class DemoWindow(
16 | title: String,
17 | private val svgRoots: List,
18 | private val maxCol: Int = 2,
19 | ) : JFrame("$title (Skia Swing)") {
20 | private val rootPanel: JPanel
21 |
22 | init {
23 | defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
24 |
25 | rootPanel = JPanel()
26 | rootPanel.layout = GridLayout(0, min(maxCol, svgRoots.size))
27 | // rootPanel.background = Color.WHITE
28 | rootPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
29 |
30 |
31 | // Fixed plot size
32 | val scrollPane = JScrollPane(
33 | rootPanel,
34 | ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
35 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
36 |
37 | )
38 | contentPane.add(scrollPane)
39 | }
40 |
41 | fun open() {
42 | SwingUtilities.invokeLater {
43 | createWindowContent()
44 |
45 | pack()
46 | setLocationRelativeTo(null) // move to the screen center
47 | isVisible = true
48 | }
49 | }
50 |
51 | private fun createWindowContent() {
52 | for (svgRoot in svgRoots) {
53 | rootPanel.add(createSvgPanel(svgRoot))
54 | }
55 | }
56 |
57 | private fun createSvgPanel(svgRoot: SvgSvgElement): JComponent {
58 | val component = SvgPanel(svgRoot)
59 | component.border = BorderFactory.createLineBorder(Color.ORANGE, 1)
60 | return component
61 | }
62 | }
--------------------------------------------------------------------------------
/devdocs/PUBLISHING.md:
--------------------------------------------------------------------------------
1 | ### Publishing to local Maven Repository
2 |
3 | > **Note**: our custom local Maven repository is located at `/.maven-publish-dev-repo`.
4 |
5 | > **Note**: set **version** to "0.0.0-SNAPSHOT".
6 |
7 | `./gradlew publishAllPublicationsToMavenLocalRepository`
8 |
9 |
10 | ### Publishing to Sonatype Maven Repository
11 |
12 | > **Note**: When publishing a "Release" version to Sonatype, PGP signature is required.
13 | >
14 | > See: https://central.sonatype.org/pages/working-with-pgp-signatures.html
15 |
16 |
17 | #### Credentials
18 |
19 | In the `local.properties` file add the following properties:
20 | ```properties
21 | sonatype.username=
22 | sonatype.password=
23 | ```
24 |
25 | #### SNAPSHOT version
26 |
27 | Specify "x.y.z-SNAPSHOT" version in `build.gradle.kts` file.
28 |
29 | `./gradlew publishAllPublicationsToSonatypeRepository`
30 |
31 | > You can find published SNAPSHOT artifacts here https://oss.sonatype.org/index.html#view-repositories;snapshots~browsestorage \
32 | > In the "Browse Storage" tab enter ‘Path lookup’: org/jetbrains/lets-plot
33 |
34 |
35 | #### "Release" version
36 |
37 | a) Specify RELEASE or PRE-RELEASE (i.e. "x.y.z-alpha1", "x.y.z-rc1" etc.) version in `build.gradle.kts` file.
38 |
39 | b) Upload to the Nexus staging repository:
40 |
41 | `./gradlew publishAllPublicationsToSonatypeRepository`
42 |
43 | > Check artifacts are uploaded to staging repository:
44 | >
45 | > https://oss.sonatype.org/index.html#stagingRepositories
46 | >
47 | > Should see repository: "orgjetbrainslets-plot-NNNN" (where NNNN is a number)
48 | > with profile: "org.jetbrains.lets-plot".
49 |
50 | c) Publish all artifacts to "Releases" repository (from the staging):
51 |
52 | `./gradlew findSonatypeStagingRepository closeAndReleaseSonatypeStagingRepository`
53 |
54 | > Check artifacts are uploaded to Nexus Releases repository:
55 | >
56 | > https://oss.sonatype.org/index.html#view-repositories;releases~browsestorage
57 | >
58 | > In the "Browse Storage" tab enter ‘Path lookup’: org/jetbrains/lets-plot
59 |
--------------------------------------------------------------------------------
/devdocs/RELEASE.md:
--------------------------------------------------------------------------------
1 | ## Releasing the Project
2 |
3 | ### Make Version
4 |
5 | ##### 1. Update Documentation
6 |
7 | - Update CHANGELOG.md
8 | - Update the "Dependencies" section in README.md
9 |
10 | ##### 2. Set release version
11 |
12 | - remove _"-SNAPSHOT"_ qualifier (the 'version' property in the root 'build.gradle.kts').
13 |
14 | ##### 3. Build and release artifacts to Sonatype repository / Maven Central
15 |
16 | Make sure that JNI libraries in the `skiko-jni-libs` directory are up-to-date and match the version of the `Skiko` library used in the `Compose Multiplatform`. Refer [DEVELOPMENT.md](DEVELOPMENT.md) for details.
17 |
18 | - `./gradlew clean`
19 | - `./gradlew build`
20 | - `./gradlew packageSkikoJniLibs`
21 | - `./gradlew publishAllPublicationsToSonatypeRepository`
22 | - `./gradlew findSonatypeStagingRepository closeAndReleaseSonatypeStagingRepository`
23 |
24 | > **Note**: For more details see [PUBLISHING.md](PUBLISHING.md).
25 |
26 | ##### 4. Prepare to the next dev cycle
27 |
28 | - Increment the version and add _"-SNAPSHOT"_ qualifier (the 'version' property in the root 'build.gradle.kts')
29 | - Push all to git and add the version git tag:
30 | - `git add --all && git commit -m "Release vX.X.X" && git push`
31 | - `git tag vX.X.X && git push --tags`
32 |
33 | ### Add the GitHub Release:
34 |
35 | * Open the link: https://github.com/JetBrains/lets-plot-skia/releases/new
36 | * Fill `Tag version` and `Release title` with the released version: "vX.X.X"
37 | * Fill the description field - copy from the CHANGELOG.md
38 | * **Attach the artifacts:**
39 | - `skiko-jni-libs.zip` from the project root
40 |
41 |
42 | ### Update Dependant Projects
43 |
44 | - Update the version of the `lets-plot-skia` dependency in the [lets-plot-compose-demos](https://github.com/JetBrains/lets-plot-compose-demos) project.
45 |
--------------------------------------------------------------------------------
/future_changes.md:
--------------------------------------------------------------------------------
1 | ## [2.2.1] - 2025-mm-dd
2 |
3 | ### Compatibility
4 |
5 | - [Android](https://developer.android.com/compose) **temporarily not supported due to [SKIKO-761](https://youtrack.jetbrains.com/issue/SKIKO-761).**
6 | - [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform) 1.7.0-1.7.3
7 | - [Skiko](https://github.com/JetBrains/skiko) 0.8.15 and 0.8.18
8 | - [Lets-Plot Kotlin API](https://github.com/JetBrains/lets-plot-kotlin) 4.10.0
9 | - [Lets-Plot Multiplatform](https://github.com/JetBrains/lets-plot) 4.6.2
10 |
11 | ### Added
12 |
13 | ### Changed
14 |
15 | ### Fixed
16 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #Gradle
2 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
3 |
4 | #Kotlin
5 | kotlin.code.style=official
6 |
7 | #MPP
8 | kotlin.mpp.stability.nowarn=true
9 | kotlin.mpp.enableCInteropCommonization=true
10 | kotlin.mpp.androidSourceSetLayoutVersion=2
11 |
12 | #Compose
13 | org.jetbrains.compose.experimental.uikit.enabled=true
14 | kotlin.native.cacheKind=none
15 |
16 | #Android
17 | android.useAndroidX=true
18 | android.compileSdk=34
19 | android.targetSdk=34
20 | android.minSdk=24
21 |
22 | #Versions
23 | # KMP is not compatible with AGP 8.3 yet.
24 | agp.version=8.2.2
25 |
26 | kotlin.version=2.1.0
27 | compose.version=1.7.3
28 | skiko.version=0.8.18
29 |
30 | androidx.activity.compose=1.8.2
31 |
32 | letsPlot.version=4.6.3-SNAPSHOT
33 | letsPlotKotlin.version=4.10.0
34 |
35 | nexusStaging.version=0.30.0
36 | nexusPublish.version=1.3.0
37 |
38 | kotlinLogging.version=2.0.5
39 | assertj.version=3.12.2
40 |
41 | #------- SKIKO -------
42 | # skiko v0.7.93 and higher doens't work on Android:
43 | # java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aarch64_ldadd4_relax" referenced by ".../lib/arm64-v8a/libskiko-android-arm64.so"
44 | # or
45 | # java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZN4sksg4NodeD2Ev" referenced by ".../lib/x86_64/libskiko-android-x64.so"
46 | # see https://github.com/JetBrains/skiko/issues/761
47 |
48 | # Skiko version should be compatible with Compose version
49 | # Check skiko in the Compose version here (change the version in the URL if needed):
50 | # https://repo1.maven.org/maven2/org/jetbrains/compose/ui/ui-desktop/1.6.10/ui-desktop-1.6.10.pom
51 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/img-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/img-2.png
--------------------------------------------------------------------------------
/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JetBrains/lets-plot-skia/22d4bc33aabe7693aa1ee46bc1f1dad1932fb546/img.png
--------------------------------------------------------------------------------
/lets-plot-compose/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/lets-plot-compose/src/androidMain/kotlin/org/jetbrains/letsPlot/skia/compose/PlotPanel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose
7 |
8 | import androidx.compose.runtime.*
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.viewinterop.AndroidView
11 | import org.jetbrains.letsPlot.Figure
12 | import org.jetbrains.letsPlot.skia.compose.android.PlotComponentProvider
13 | import org.jetbrains.letsPlot.skia.compose.android.PlotViewContainer
14 | import org.jetbrains.letsPlot.skia.compose.util.NaiveLogger
15 |
16 | private val LOG = NaiveLogger("PlotPanel")
17 |
18 | @Suppress("FunctionName")
19 | @Composable
20 | actual fun PlotPanel(
21 | figure: Figure,
22 | preserveAspectRatio: Boolean,
23 | modifier: Modifier,
24 | computationMessagesHandler: (List) -> Unit
25 | ) {
26 | LOG.print { "Recompose PlotPanel() preserveAspectRatio: $preserveAspectRatio " }
27 |
28 | val provider by remember {
29 | mutableStateOf(
30 | PlotComponentProvider(
31 | computationMessagesHandler
32 | )
33 | )
34 | }
35 |
36 | DisposableEffect(provider) {
37 | onDispose {
38 | LOG.print { "DisposableEffect preserveAspectRatio: ${provider.plotViewContainer?.preserveAspectRatio} " }
39 | provider.dispose()
40 | }
41 | }
42 |
43 | AndroidView(
44 | factory = provider.factory,
45 | modifier = modifier,
46 | update = { plotViewContainer ->
47 | plotViewContainer as PlotViewContainer
48 | LOG.print { "UPDATE PlotViewContainer preserveAspectRatio ${plotViewContainer.preserveAspectRatio} -> $preserveAspectRatio" }
49 |
50 | plotViewContainer.figure = figure
51 | plotViewContainer.preserveAspectRatio = preserveAspectRatio
52 | }
53 | )
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/lets-plot-compose/src/androidMain/kotlin/org/jetbrains/letsPlot/skia/compose/android/ColorRect.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose.android
7 |
8 | import android.graphics.Canvas
9 | import android.graphics.ColorFilter
10 | import android.graphics.Paint
11 | import android.graphics.PixelFormat
12 | import android.graphics.drawable.Drawable
13 |
14 | internal class ColorRect(val color: Int) : Drawable() {
15 | override fun draw(canvas: Canvas) {
16 | canvas.drawRect(
17 | canvas.clipBounds,
18 | Paint().also { it.color = color }
19 | )
20 | }
21 |
22 | override fun setAlpha(alpha: Int) {
23 | }
24 |
25 | override fun setColorFilter(colorFilter: ColorFilter?) {
26 | }
27 |
28 | override fun getOpacity(): Int {
29 | return PixelFormat.OPAQUE
30 | }
31 | }
--------------------------------------------------------------------------------
/lets-plot-compose/src/androidMain/kotlin/org/jetbrains/letsPlot/skia/compose/android/PlotComponentProvider.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose.android
7 |
8 | import android.content.Context
9 | import android.view.View
10 | import org.jetbrains.letsPlot.skia.compose.util.NaiveLogger
11 |
12 | private val LOG = NaiveLogger("PlotComponentProvider")
13 |
14 | internal class PlotComponentProvider(
15 | private val computationMessagesHandler: ((List) -> Unit)
16 | ) {
17 | var plotViewContainer: PlotViewContainer? = null
18 |
19 | val factory: (Context) -> View = { ctx ->
20 | check(plotViewContainer == null) { "An attempt to reuse a single-use view factory." }
21 | PlotViewContainer(
22 | ctx,
23 | computationMessagesHandler
24 | ).also {
25 | plotViewContainer = it
26 | }
27 | }
28 |
29 | fun dispose() {
30 | LOG.print("dispose PlotComponentProvider preserveAspectRatio: ${plotViewContainer?.preserveAspectRatio}")
31 | plotViewContainer?.disposePlotView()
32 | plotViewContainer = null
33 | }
34 | }
35 |
36 |
37 |
--------------------------------------------------------------------------------
/lets-plot-compose/src/commonMain/kotlin/org/jetbrains/letsPlot/skia/compose/PlotPanel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose
7 |
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import org.jetbrains.letsPlot.Figure
11 |
12 |
13 | @Suppress("FunctionName")
14 | @Composable
15 | expect fun PlotPanel(
16 | figure: Figure,
17 | preserveAspectRatio: Boolean = false,
18 | modifier: Modifier,
19 | computationMessagesHandler: (List) -> Unit
20 | )
--------------------------------------------------------------------------------
/lets-plot-compose/src/commonMain/kotlin/org/jetbrains/letsPlot/skia/compose/util/NaiveLogger.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose.util
7 |
8 | private const val ENABLED = false
9 |
10 | class NaiveLogger(val key: String) {
11 | fun print(s: String) {
12 | if (ENABLED) {
13 | println("[$key] $s")
14 | }
15 | }
16 |
17 | fun print(message: () -> String) {
18 | if (ENABLED) {
19 | print(message())
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/lets-plot-compose/src/desktopMain/kotlin/org/jetbrains/letsPlot/skia/compose/PlotFigureModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 JetBrains s.r.o.
3 | * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4 | */
5 |
6 | package org.jetbrains.letsPlot.skia.compose
7 |
8 | import org.jetbrains.letsPlot.core.interact.event.ToolEventDispatcher
9 | import org.jetbrains.letsPlot.core.plot.builder.interact.FigureImplicitInteractionSpecs
10 | import org.jetbrains.letsPlot.core.plot.builder.interact.tools.FigureModel
11 |
12 | class PlotFigureModel(
13 | val onUpdateView: (Map?) -> Unit
14 | ) : FigureModel {
15 | private var toolEventCallback: ((Map) -> Unit)? = null
16 |
17 | var toolEventDispatcher: ToolEventDispatcher? = null
18 | set(value) {
19 | // De-activate and re-activate ongoing interactions when replacing the dispatcher.
20 | val wereInteractions = field?.deactivateAllSilently() ?: emptyMap()
21 | field = value
22 | value?.let { newDispatcher ->
23 | newDispatcher.initToolEventCallback { event -> toolEventCallback?.invoke(event) }
24 |
25 | // reactivate interactions in new plot component
26 | wereInteractions.forEach { (origin, interactionSpecList) ->
27 | newDispatcher.activateInteractions(origin, interactionSpecList)
28 | }
29 | }
30 | }
31 |
32 | init {
33 | toolEventDispatcher?.initToolEventCallback { event -> toolEventCallback?.invoke(event) }
34 | }
35 |
36 | override fun onToolEvent(callback: (Map) -> Unit) {
37 | toolEventCallback = callback
38 |
39 | // Make snsure that 'implicit' interaction activated.
40 | deactivateInteractions(origin = ToolEventDispatcher.ORIGIN_FIGURE_IMPLICIT)
41 | activateInteractions(
42 | origin = ToolEventDispatcher.ORIGIN_FIGURE_IMPLICIT,
43 | interactionSpecList = FigureImplicitInteractionSpecs.LIST
44 | )
45 |
46 | }
47 | override fun activateInteractions(origin: String, interactionSpecList: List