22
33<!-- -IMPORT org.jetbrains.kotlinx.dataframe.samples.api.Render-->
44
5+ ## HTML rendering
6+
57` DataFrame ` instances can be rendered to HTML.
68Rendering of hierarchical tables in HTML is supported by JS and CSS definitions
79that can be found in project resources.
810
911Dataframes can also be formatted before being converted to HTML.
1012See [ ] ( format.md ) for how to do this.
1113
14+ Besides that, DataFrame provides multiple APIs to customize HTML output.
15+
16+ ### Display images
17+ Values of the ` org.jetbrains.kotlinx.dataframe.datatypes.IMG ` class are rendered as an ` <img> ` tag
18+
19+ <!-- -FUN displayImg-->
20+
21+ ``` kotlin
22+ val htmlData = dataFrameOf(
23+ " kotlinLogo" to columnOf(
24+ IMG (" https://kotlin.github.io/dataframe/images/kotlin-logo.svg" ),
25+ ),
26+ ).toStandaloneHtml()
27+ ```
28+
29+ <!-- -END-->
30+
31+ ### Embed pages
32+
33+ Values of the ` org.jetbrains.kotlinx.dataframe.datatypes.IFRAME ` class are rendered as an ` <iframe> ` tag
34+
35+ <!-- -FUN displayIFrame-->
36+
37+ ``` kotlin
38+ val htmlData = dataFrameOf(
39+ " documentationPages" to columnOf(
40+ IFRAME (
41+ src = " https://kotlin.github.io/dataframe/tohtml.html" ,
42+ width = 850 ,
43+ height = 500 ,
44+ ),
45+ ),
46+ ).toStandaloneHtml()
47+ ```
48+
49+ <!-- -END-->
50+
51+ ### Render clickable links
52+
53+ Values of ` java.net.URL ` are rendered as ` <a> ` tag
54+
55+ <!-- -FUN displayURL-->
56+
57+ ``` kotlin
58+ val htmlData = dataFrameOf(
59+ " documentationPages" to columnOf(
60+ URI (" https://kotlin.github.io/dataframe/format.html" ).toURL(),
61+ URI (" https://kotlin.github.io/dataframe/tohtml.html" ).toURL(),
62+ URI (" https://kotlin.github.io/dataframe/jupyterrendering.html" ).toURL(),
63+ ),
64+ ).toStandaloneHtml()
65+ ```
66+
67+ <!-- -END-->
68+
69+ ### Render any HTML inside a cell
70+
71+ Wrap cell values in custom HTML using ` RenderedContent.media `
72+
73+ <!-- -FUN displayMediaContent-->
74+ <tabs >
75+ <tab title =" Properties " >
76+
77+ ``` kotlin
78+ val htmlData = dataFrameOf(
79+ " documentationPages" to columnOf(
80+ " https://kotlin.github.io/dataframe/format.html" ,
81+ " https://kotlin.github.io/dataframe/tohtml.html" ,
82+ " https://kotlin.github.io/dataframe/jupyterrendering.html" ,
83+ ),
84+ )
85+ .convert { documentationPages }.with {
86+ val uri = URI (it)
87+ RenderedContent .media(""" <a href='$uri '>${uri.path} </a>""" )
88+ }
89+ .toStandaloneHtml()
90+ ```
91+
92+ </tab >
93+ <tab title =" Strings " >
94+
95+ ``` kotlin
96+ val htmlData = dataFrameOf(
97+ " documentationPages" to columnOf(
98+ " https://kotlin.github.io/dataframe/format.html" ,
99+ " https://kotlin.github.io/dataframe/tohtml.html" ,
100+ " https://kotlin.github.io/dataframe/jupyterrendering.html" ,
101+ ),
102+ )
103+ .convert { " documentationPages" <String >() }.with {
104+ val uri = URI (it)
105+ RenderedContent .media(""" <a href='$uri '>${uri.path} </a>""" )
106+ }
107+ .toStandaloneHtml()
108+ ```
109+
110+ </tab ></tabs >
111+ <!-- -END-->
112+
113+ ### Sample data
114+ This dataframe is used in the following examples
115+
116+ <!-- -FUN df-->
117+
118+ ``` kotlin
119+ val df = dataFrameOf(
120+ " name" to columnOf(
121+ " firstName" to columnOf(" Alice" , " Bob" , " Charlie" , " Charlie" , " Bob" , " Alice" , " Charlie" ),
122+ " lastName" to columnOf(" Cooper" , " Dylan" , " Daniels" , " Chaplin" , " Marley" , " Wolf" , " Byrd" ),
123+ ),
124+ " age" to columnOf(15 , 45 , 20 , 40 , 30 , 20 , 30 ),
125+ " city" to columnOf(" London" , " Dubai" , " Moscow" , " Milan" , " Tokyo" , null , " Moscow" ),
126+ " weight" to columnOf(54 , 87 , null , null , 68 , 55 , 90 ),
127+ " isHappy" to columnOf(true , true , false , true , true , false , true ),
128+ )
129+ ```
130+
131+ <!-- -END-->
132+
133+ ### Reusable rendering logic
134+
135+ Generic approach to custom cell rendering. Useful if you want to apply the same rendering to different dataframes.
136+
137+ <!-- -FUN cellRenderer-->
138+
139+ ``` kotlin
140+ class CustomArrayCellRenderer : ChainedCellRenderer (DefaultCellRenderer ) {
141+ override fun maybeContent (value : Any? , configuration : DisplayConfiguration ): RenderedContent ? {
142+ if (value is Boolean ) {
143+ return RenderedContent .text(if (value) " ✓" else " ✗" )
144+ }
145+ // return null to delegate work to parent renderer: DefaultCellRenderer
146+ return null
147+ }
148+
149+ override fun maybeTooltip (value : Any? , configuration : DisplayConfiguration ): String? {
150+ // return null to delegate work to parent renderer: DefaultCellRenderer
151+ return null
152+ }
153+ }
154+
155+ val htmlData = df.toStandaloneHtml(cellRenderer = CustomArrayCellRenderer ())
156+ ```
157+
158+ <!-- -END-->
159+
160+ ### Custom HTML outside the table
161+
162+ The result of ` toHtml ` can be composed with other HTML, CSS, or JS definitions.
163+ Let's build an alternative to displaying all rows in one table: custom pagination across multiple files
164+
165+ <!-- -FUN appendCustomHtml-->
166+
167+ ``` kotlin
168+ val pages = df.duplicateRows(10 ).chunked(20 )
169+ val files = pages.indices.map { i -> File (" page$i .html" ) }
170+ val navLinks = files.mapIndexed { i, file ->
171+ """ <a href="${file.name} ">Page ${i + 1 } </a>"""
172+ }.joinToString(" | " )
173+
174+ pages.forEachIndexed { i, page ->
175+ val output = files[i]
176+ page.toStandaloneHtml().plus(DataFrameHtmlData (body = navLinks))
177+ // uncomment
178+ // .writeHtml(output)
179+ }
180+ ```
181+
182+ <!-- -END-->
183+
184+ ### Custom style and scripts
185+
186+ Let's add a hover effect and click listener for table cells.
187+ See [ init.js] ( https://github.com/Kotlin/dataframe/blob/704200cb86e7bdc07b800a7cfef48de408bd5fe8/core/src/main/resources/init.js ) and [ table.css] ( https://github.com/Kotlin/dataframe/blob/ead4f8666df5cf24e5bf45d245cda3200e150e93/core/src/main/resources/table.css ) for reference.
188+
189+ <!-- -FUN interactiveJs-->
190+
191+ ``` kotlin
192+ val selectCellInteraction = DataFrameHtmlData (
193+ style =
194+ """
195+ td:hover {
196+ background-color: rgba(0, 123, 255, 0.15);
197+ cursor: pointer;
198+ }
199+ """ .trimIndent(),
200+ script =
201+ """
202+ (function() {
203+ let cells = document.querySelectorAll('td');
204+ cells.forEach(function(cell) {
205+ cell.addEventListener('click', function(e) {
206+ let content = cell.textContent;
207+ alert(content);
208+ });
209+ });
210+ })();
211+ """ .trimIndent(),
212+ )
213+
214+ // keep in mind JS script initialization order.
215+ val htmlData = df.toStandaloneHtml().plus(selectCellInteraction)
216+ ```
217+
218+ <!-- -END-->
219+
12220Depending on your environment, there can be different ways to use the result of ` toHtml ` functions.
13221
14222## IntelliJ IDEA
@@ -21,9 +229,10 @@ It can be displayed in the browser and has parameters for customization.
21229<!-- -FUN useRenderingResult-->
22230
23231``` kotlin
24- df.toStandaloneHtml(DisplayConfiguration (rowsLimit = null )).openInBrowser()
25- df.toStandaloneHtml(DisplayConfiguration (rowsLimit = null )).writeHtml(File (" /path/to/file" ))
26- df.toStandaloneHtml(DisplayConfiguration (rowsLimit = null )).writeHtml(Path (" /path/to/file" ))
232+ val configuration = DisplayConfiguration (rowsLimit = null )
233+ df.toStandaloneHtml(configuration).openInBrowser()
234+ df.toStandaloneHtml(configuration).writeHtml(File (" /path/to/file" ))
235+ df.toStandaloneHtml(configuration).writeHtml(Path (" /path/to/file" ))
27236```
28237
29238<!-- -END-->
@@ -35,6 +244,8 @@ which you can use to include additional scripts, elements,
35244or styles at the end of the page or just to merge multiple tables into one HTML snippet.
36245
37246<!-- -FUN composeTables-->
247+ <tabs >
248+ <tab title =" Properties " >
38249
39250``` kotlin
40251val df1 = df.reorderColumnsByName()
@@ -44,6 +255,20 @@ val df3 = df.sortByDesc { age }
44255listOf (df1, df2, df3).fold(DataFrameHtmlData .tableDefinitions()) { acc, df -> acc + df.toHtml() }
45256```
46257
258+ </tab >
259+ <tab title =" Strings " >
260+
261+ ``` kotlin
262+ val df1 = df.reorderColumnsByName()
263+ val df2 = df.sortBy(" age" )
264+ val df3 = df.sortByDesc(" age" )
265+
266+ listOf (df1, df2, df3).fold(DataFrameHtmlData .tableDefinitions()) { acc, df ->
267+ acc + df.toHtml()
268+ }
269+ ```
270+
271+ </tab ></tabs >
47272<!-- -END-->
48273
49274## Jupyter Notebooks
0 commit comments