Nothing fancy to show. But I needed to write some custom javascript to get the scrollbars of wide tabulators to sync with each other. It took some time to figure out, so I wanted to share it:
import pandas as pd
import panel as pn
pn.extension("tabulator")
js = """
<script type="text/javascript">
function $$$(selector, rootNode=document.body) {
const arr = []
const traverser = node => {
// 1. decline all nodes that are not elements
if(node.nodeType !== Node.ELEMENT_NODE) {
return
}
// 2. add the node to the array, if it matches the selector
if(node.matches(selector)) {
arr.push(node)
}
// 3. loop through the children
const children = node.children
if (children.length) {
for(const child of children) {
traverser(child)
}
}
// 4. check for shadow DOM, and loop through it's children
const shadowRoot = node.shadowRoot
if (shadowRoot) {
const shadowChildren = shadowRoot.children
for(const shadowChild of shadowChildren) {
traverser(shadowChild)
}
}
}
traverser(rootNode)
return arr
}
async function sync_scrolling() {
tables = $$$(".sync-table")
const elements = []
for (let i = 0; i < tables.length; i++) {
var e = null
// Wait for the table to appear
while (e === null) {
await new Promise((r) => setTimeout(r, 100))
e = tables[i].shadowRoot.querySelector(
".pnx-tabulator .tabulator-tableholder"
)
}
elements.push(e)
}
var ignore_scroll_events = false
for (let i = 0; i < elements.length; i++) {
elements[i].onscroll = (e) => {
if (ignore_scroll_events) return
ignore_scroll_events = true
for (let j = 0; j < elements.length; j++) {
if (elements[j] == elements[i]) continue
elements[j].scrollLeft = elements[i].scrollLeft
elements[j].scrollTop = elements[i].scrollTop
}
ignore_scroll_events = false
}
}
}
sync_scrolling()
</script>
"""
df = pd.DataFrame(range(10))
pn.Row(
pn.Column(
pn.widgets.Tabulator(df.T, css_classes=["sync-table"]),
pn.widgets.Tabulator(df.T, css_classes=["sync-table"]),
pn.widgets.Tabulator(df.T, css_classes=["sync-table"]),
pn.widgets.Tabulator(df.T, css_classes=["sync-table"]),
pn.pane.HTML(js),
width=200,
)
).servable()