|
1 | 1 | module TableView
|
| 2 | +using Tables, WebIO, JSExpr, JSON, Dates |
2 | 3 |
|
3 |
| -using WebIO |
4 |
| -using JSExpr |
5 |
| -using JuliaDB |
6 |
| -using DataValues |
| 4 | +function showtable(x; dark = false) |
| 5 | + w = Scope(imports=["https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js", |
| 6 | + "https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css", |
| 7 | + "https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham$(dark ? "-dark" : "").css",]) |
7 | 8 |
|
8 |
| -import JuliaDB: DNDSparse, DNextTable, NextTable |
| 9 | + schema = Tables.schema(x) |
| 10 | + names = schema.names |
| 11 | + types = schema.types |
9 | 12 |
|
10 |
| -function JuliaDB.subtable(t::DNextTable, r) |
11 |
| - table(collect(rows(t)[r]), pkey=t.pkey) |
12 |
| -end |
13 |
| - |
14 |
| -showna(xs) = xs |
15 |
| -function showna(xs::AbstractArray{T}) where {T<:DataValue} |
16 |
| - map(xs) do x |
17 |
| - isnull(x) ? "NA" : get(x) |
18 |
| - end |
19 |
| -end |
20 |
| - |
21 |
| -function showna(xs::Columns) |
22 |
| - rows(map(showna, columns(xs))) |
23 |
| -end |
24 |
| - |
25 |
| -function showtable(t::Union{DNextTable, NextTable}; rows=1:100, colopts=Dict(), kwargs...) |
26 |
| - w = Scope(imports=["https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.34.0/handsontable.full.js", |
27 |
| - "https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.34.0/handsontable.full.css"]) |
28 |
| - |
29 |
| - trunc_rows = max(1, first(rows)):min(length(t), last(rows)) |
30 |
| - subt = JuliaDB.subtable(t, trunc_rows) |
31 |
| - |
32 |
| - headers = colnames(subt) |
33 |
| - cols = [merge(Dict(:data=>n), get(colopts, n, Dict())) for n in headers] |
| 13 | + coldefs = [( |
| 14 | + headerName = n, |
| 15 | + field = n, |
| 16 | + type = types[i] <: Union{Missing, T where T <: Number} ? "numericColumn" : nothing, |
| 17 | + filter = types[i] <: Union{Missing, T where T <: Dates.Date} ? "agDateColumnFilter" : |
| 18 | + types[i] <: Union{Missing, T where T <: Number} ? "agNumberColumnFilter" : nothing |
| 19 | + ) for (i, n) in enumerate(names)] |
34 | 20 |
|
35 | 21 | options = Dict(
|
36 |
| - :data => showna(collect(JuliaDB.rows(subt))), |
37 |
| - :colHeaders => headers, |
38 |
| - :modifyColWidth => @js(w -> w > 300 ? 300 : w), |
39 |
| - :modifyRowHeight => @js(h -> h > 60 ? 50 : h), |
40 |
| - :manualColumnResize => true, |
41 |
| - :manualRowResize => true, |
42 |
| - :columns => cols, |
43 |
| - :width => 800, |
44 |
| - :height => 400, |
| 22 | + :rowData => table2json(x), |
| 23 | + :columnDefs => coldefs, |
| 24 | + :enableSorting => true, |
| 25 | + :enableFilter => true, |
| 26 | + :enableColResize => true, |
| 27 | + :multiSortKey => "ctrl" |
45 | 28 | )
|
46 |
| - if (length(t.pkey) > 0 && t.pkey == [1:length(t.pkey);]) |
47 |
| - options[:fixedColumnsLeft] = length(t.pkey) |
48 |
| - end |
49 | 29 |
|
50 |
| - merge!(options, Dict(kwargs)) |
51 |
| - |
52 |
| - handler = @js function (Handsontable) |
53 |
| - @var sizefix = document.createElement("style"); |
54 |
| - sizefix.textContent = """ |
55 |
| - .htCore td { |
56 |
| - white-space:nowrap |
57 |
| - } |
58 |
| - """ |
59 |
| - this.dom.appendChild(sizefix) |
60 |
| - this.hot = @new Handsontable(this.dom, $options); |
| 30 | + handler = @js function (agGrid) |
| 31 | + gridOptions = $options |
| 32 | + gridOptions.rowData = JSON.parse(gridOptions.rowData) |
| 33 | + this.table = @new agGrid.Grid(this.dom.querySelector("#grid"), gridOptions) |
| 34 | + gridOptions.columnApi.autoSizeColumns($names) |
61 | 35 | end
|
62 | 36 | onimport(w, handler)
|
63 |
| - w.dom = dom"div"() |
| 37 | + w.dom = dom"div#grid"(className = "ag-theme-balham$(dark ? "-dark" : "")", |
| 38 | + style=Dict(:position => "absolute", |
| 39 | + :top => "0", |
| 40 | + :left => "0", |
| 41 | + :width => "100%", |
| 42 | + :height => "100%", |
| 43 | + :minHeight => "200px")) |
64 | 44 | w
|
65 | 45 | end
|
66 | 46 |
|
67 |
| -function showtable(t::Union{DNDSparse, NDSparse}; rows=1:100, colopts=Dict(), kwargs...) |
68 |
| - w = Scope(imports=["https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.34.0/handsontable.full.js", |
69 |
| - "https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.34.0/handsontable.full.css"]) |
70 |
| - data = Observable{Any}(w, "data", []) |
71 |
| - |
72 |
| - trunc_rows = max(1, first(rows)):min(length(t), last(rows)) |
73 |
| - |
74 |
| - ks = keys(t)[trunc_rows] |
75 |
| - vs = values(t)[trunc_rows] |
76 |
| - |
77 |
| - if !isa(keys(t), Columns) |
78 |
| - ks = collect(ks) |
79 |
| - vs = collect(vs) |
| 47 | +# directly write JSON instead of allocating temporary dicts etc |
| 48 | +function table2json(table) |
| 49 | + names = Tables.schema(table).names |
| 50 | + |
| 51 | + io = IOBuffer() |
| 52 | + print(io, '[') |
| 53 | + for row in Tables.rows(table) |
| 54 | + print(io, '{') |
| 55 | + i = 1 |
| 56 | + for col in Tables.eachcolumn(row) |
| 57 | + JSON.print(io, names[i]) |
| 58 | + i += 1 |
| 59 | + print(io, ':') |
| 60 | + if col isa Number |
| 61 | + JSON.print(io, col) |
| 62 | + else |
| 63 | + JSON.print(io, sprint(print, col)) |
| 64 | + end |
| 65 | + print(io, ',') |
| 66 | + end |
| 67 | + skip(io, -1) |
| 68 | + print(io, '}') |
| 69 | + print(io, ',') |
80 | 70 | end
|
| 71 | + skip(io, -1) |
| 72 | + print(io, ']') |
81 | 73 |
|
82 |
| - subt = NDSparse(showna(ks), showna(vs)) |
83 |
| - |
84 |
| - headers = colnames(subt) |
85 |
| - cols = [merge(Dict(:data=>n), get(colopts, n, Dict())) for n in headers] |
86 |
| - |
87 |
| - options = Dict( |
88 |
| - :data => JuliaDB.rows(subt), |
89 |
| - :colHeaders => headers, |
90 |
| - :fixedColumnsLeft => ndims(t), |
91 |
| - :modifyColWidth => @js(w -> w > 300 ? 300 : w), |
92 |
| - :modifyRowHeight => @js(h -> h > 60 ? 50 : h), |
93 |
| - :manualColumnResize => true, |
94 |
| - :manualRowResize => true, |
95 |
| - :columns => cols, |
96 |
| - :width => 800, |
97 |
| - :height => 400, |
98 |
| - ) |
99 |
| - |
100 |
| - merge!(options, Dict(kwargs)) |
101 |
| - |
102 |
| - handler = @js function (Handsontable) |
103 |
| - @var sizefix = document.createElement("style"); |
104 |
| - sizefix.textContent = """ |
105 |
| - .htCore td { |
106 |
| - white-space:nowrap |
107 |
| - } |
108 |
| - """ |
109 |
| - this.dom.appendChild(sizefix) |
110 |
| - this.hot = @new Handsontable(this.dom, $options); |
111 |
| - end |
112 |
| - onimport(w, handler) |
113 |
| - w.dom = dom"div"() |
114 |
| - w |
| 74 | + String(take!(io)) |
| 75 | +end |
115 | 76 | end
|
116 |
| - |
117 |
| -showtable(t; kwargs...) = showtable(table(t); kwargs...) |
118 |
| - |
119 |
| -end # module |
0 commit comments