diff options
| author | Martin Ridgers <[email protected]> | 2024-11-28 15:07:16 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2024-11-28 15:07:16 +0100 |
| commit | e697b522f2d869f335aa8db074b43362aff1e29a (patch) | |
| tree | 57ecb83feea76bdb3daeff598b062d5e952d433c /src/zenserver/frontend/html | |
| parent | set content type correctly for getchunkrange (#241) (diff) | |
| download | zen-e697b522f2d869f335aa8db074b43362aff1e29a.tar.xz zen-e697b522f2d869f335aa8db074b43362aff1e29a.zip | |
Dashboard CSS fixes and archival of a partial treemap view (#242)
* Input boxes' text was unreadable when using the dark theme
* Change from margins to padding top/bottom - easier to reason about vertical styling.
* A treemap. Not used anywhere and not finished. Submitting so it isn't lost
* Prevent tables' first content columns from collapsing
* Dashboardk .zip archive update
Diffstat (limited to 'src/zenserver/frontend/html')
| -rw-r--r-- | src/zenserver/frontend/html/pages/map.js | 166 | ||||
| -rw-r--r-- | src/zenserver/frontend/html/util/widgets.js | 6 | ||||
| -rw-r--r-- | src/zenserver/frontend/html/zen.css | 28 |
3 files changed, 194 insertions, 6 deletions
diff --git a/src/zenserver/frontend/html/pages/map.js b/src/zenserver/frontend/html/pages/map.js new file mode 100644 index 000000000..58046b255 --- /dev/null +++ b/src/zenserver/frontend/html/pages/map.js @@ -0,0 +1,166 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +"use strict"; + +import { ZenPage } from "./page.js" +import { Friendly } from "../util/friendly.js" +import { ProgressBar } from "../util/widgets.js" +import { create_indexer } from "../indexer/indexer.js" + + +//////////////////////////////////////////////////////////////////////////////// +function squarify(weights, callback, area_threshold=-1) +{ + const rect = [1.0, 1.0]; + for (var start = 0; start < weights.length;) + { + const ri = +(rect[0] >= rect[1]); + + const length = rect[ri]; + var end = start; + var area = 0; + var prev_rd = Infinity; + for (; end < weights.length; ++end) + { + const w = (area + weights[end]) / length; + const r = weights[end] / (w * w); + const rd = Math.abs(1.0 - r); + if (prev_rd < rd) + break; + prev_rd = rd; + area += weights[end]; + } + const v = area / length; + + const tl = [1.0 - rect[0], 1.0 - rect[1]]; + const wh = [undefined, undefined]; + for (var i = start; i < end; ++i) + { + wh[ri ^ 0] = weights[i] / v; + wh[ri ^ 1] = v; + callback(i, tl[0], tl[1], wh[0], wh[1], ri); + tl[ri] += wh[ri]; + } + + start = end; + rect[ri ^ 1] -= v; + + if (rect[0] * rect[1] < area_threshold) + break; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +export class Page extends ZenPage +{ + main() + { + const project = this.get_param("project"); + const oplog = this.get_param("oplog"); + this._indexer = this._load_indexer(project, oplog); + + this.set_title("map"); + + const section = this.add_section(project + " - " + oplog); + this._build(section); + } + + async _load_indexer(project, oplog) + { + const progress_bar = this.add_widget(ProgressBar); + progress_bar.set_progress("indexing"); + var indexer = create_indexer(project, oplog, (...args) => { + progress_bar.set_progress(...args); + }); + indexer = await indexer; + progress_bar.destroy(); + return indexer; + } + + async _build(section) + { + const indexer = await this._indexer; + + var prefix = this.get_param("path", "/"); + if (!prefix.endsWith("/")) + prefix += "/"; + + var total_size = 0; + var branch_size = 0; + const new_nodes = new Object(); + for (var [name, size] of indexer.enum_all()) + { + total_size += size; + if (!name.startsWith(prefix)) + continue; + + branch_size += size; + + name = name.substr(prefix.length); + const slash = name.indexOf("/"); + if (slash != -1) + name = name.substr(0, slash + 1); + + if (new_nodes[name] !== undefined) + new_nodes[name] += size; + else + new_nodes[name] = size; + } + + const sorted_keys = Object.keys(new_nodes).sort((l, r) => { + return new_nodes[r] - new_nodes[l]; + }); + const nodes = new Array(); + for (const name of sorted_keys) + nodes.push(new_nodes[name] / branch_size); + + var stats = Friendly.kib(branch_size); + stats += " / "; + stats += Friendly.kib(total_size); + stats += " ("; + stats += 0|((branch_size * 100) / total_size); + stats += "%)"; + section.tag().text(prefix + " : " + stats); + const treemap = section.tag().id("treemap"); + const canvas = treemap.tag("canvas").inner(); + + const width = canvas.offsetWidth; + var height = window.visualViewport.height; + height -= treemap.inner().getBoundingClientRect().top + window.scrollY; + height -= 50; + + canvas.width = canvas.offsetWidth; + canvas.height = height; + const context = canvas.getContext("2d"); + context.textBaseline = "top"; + context.imageSmoothingEnabled = false; + context.font = "13px sans-serif"; + context.strokeStyle = "#666666"; + + const palette = [ + "#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", + "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", + ]; + + const callback = (i, x, y, w, h, d) => { + const r = function(u,v) { return Math.floor(u * (v - 1e-7)); }; + x = r(x, width); + y = r(y, height); + w = r(w, width); + h = r(h, height); + context.save(); + context.beginPath(); + context.rect(x, y, w, h); + context.clip(); + context.fillStyle = palette[(i * 0x493) % palette.length]; + context.fill(); + context.stroke(); + context.fillStyle = "#000000"; + context.fillText(sorted_keys[i], x + 4, y + 4); + context.restore(); + }; + squarify(nodes, callback, 0.01); + } +} diff --git a/src/zenserver/frontend/html/util/widgets.js b/src/zenserver/frontend/html/util/widgets.js index e567a7a00..78998b7ff 100644 --- a/src/zenserver/frontend/html/util/widgets.js +++ b/src/zenserver/frontend/html/util/widgets.js @@ -60,10 +60,12 @@ export class Table extends Widget var root = parent.tag().classify("zen_table"); super(root); + const column_width = 0 | (100 / column_names.length); + var column_style; if (flags & Table.Flag_FitLeft) column_style = "max-content"; - else if (flags & Table.Flag_BiasLeft) column_style = "2fr"; - else column_style = "1fr"; + else if (flags & Table.Flag_BiasLeft) column_style = `minmax(${column_width * 2}%, 2fr)`; + else column_style = `minmax(${column_width}%, 1fr)`; for (var i = 1; i < column_names.length; ++i) { const style = (flags & Table.Flag_PackRight) ? " auto" : " 1fr"; diff --git a/src/zenserver/frontend/html/zen.css b/src/zenserver/frontend/html/zen.css index c9dc0d83e..532b71571 100644 --- a/src/zenserver/frontend/html/zen.css +++ b/src/zenserver/frontend/html/zen.css @@ -59,6 +59,7 @@ pre { } input { + color: var(--theme_g0); background-color: var(--theme_g3); border: 1px solid var(--theme_g2); } @@ -68,12 +69,14 @@ input { } #container { - max-width: 130em; - min-width: 80em; - margin: auto; + max-width: 130em; + min-width: 80em; + margin: auto; > div { - margin: 1.0em 2.2em 1.5em 2.2em; + margin: 0.0em 2.2em 0.0em 2.2em; + padding-top: 1.0em; + padding-bottom: 1.5em; } } @@ -467,3 +470,20 @@ a { content: "\\"; } } + +/* map ---------------------------------------------------------------------- */ + +html:has(#map) { + height: 100%; + body, #container, #map { + height: 100%; + } +} +#map { + #treemap { + position: relative; + canvas { + width: 100%; + } + } +} |