Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions InfoLogger/public/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ export default class Model extends Observable {
// Model can change very often we protect router with callRateLimiter
// Router limit: 100 calls per 30 seconds max = 30ms, 2 FPS is enough (500ms)
this.observe(callRateLimiter(this.updateRouteOnModelChange.bind(this), 500));

this.zoom = {
level: 1, // Default zoom multiplier, 1 = 100%
min: 0.5,
max: 4,
step: 0.1, // Adds/subtracts 10% to the level
baseFontSize: 0.7, // Default font size in rem at level=1, matches default CSS .logs-container font size
// Row height in rem is fontSize * rowHeightRatio; keep this in sync with CSS variable --row-height
rowHeightRatio: 1.3,
lastScrollTime: 0, // Throttle zoom on scroll event to avoid too many updates, especially on a trackpad
};
}

/**
Expand Down Expand Up @@ -389,4 +400,66 @@ export default class Model extends Observable {
isSecureContext() {
return window.isSecureContext;
}

/**
* Font size in rem units
* @returns {number} - font size in rem units
*/
get fontSize() {
return this.zoom.baseFontSize * this.zoom.level;
}

/**
* Row height in rem units, computed with font size to keep the same ratio across zoom levels
* @returns {number} - row height in rem units
*/
get rowHeightRem() {
return this.fontSize * this.zoom.rowHeightRatio;
}

/**
* Row height in pixels, used for the virtual scroll to know how many logs to render depending on the container size
* @returns {number} - row height in pixels
*/
get rowHeightPx() {
return this.rowHeightRem * parseFloat(getComputedStyle(document.documentElement).fontSize);
}

/**
* Zoom in by increasing zoom level by step, with a maximum of zoom.max
*/
zoomIn() {
this.#setZoomLevel(Math.min(this.zoom.level + this.zoom.step, this.zoom.max));
}

/**
* Zoom out by decreasing zoom level by step, with a minimum of zoom.min
*/
zoomOut() {
this.#setZoomLevel(Math.max(this.zoom.level - this.zoom.step, this.zoom.min));
}

/**
* Reset zoom to base level of 1
*/
resetZoom() {
this.#setZoomLevel(1);
}

/**
* Set zoom level
* @param {number} level - zoom level to set, should be between zoom.min and zoom.max
*/
#setZoomLevel(level) {
// Keep zoom to 2 d.p. to avoid floating-point artifacts (for example 1.2000000000000002)
// This keeps CSS values stable and ensures users can reliably return to default zoom (1)
this.zoom.level = parseFloat(level.toFixed(2));
const root = document.querySelector('.logs-container');
if (root) {
// Keep CSS sizes to 3 d.p. to avoid floating-point artifacts (for example 1.0920000000000002rem)
root.style.setProperty('--log-font-size', `${this.fontSize.toFixed(3)}rem`);
root.style.setProperty('--row-height', `${this.rowHeightRem.toFixed(3)}rem`);
}
this.notify();
}
}
10 changes: 7 additions & 3 deletions InfoLogger/public/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
.table-filters { width: 100%; }

/* logs div */
.logs-container { cursor: default; }
.logs-container {
cursor: default;
--log-font-size: 0.7rem; /* default, overridden by JS zoom */
--row-height: 0.91rem; /* default, overridden by JS zoom */
}
.logs-content { border-top: 1px solid #aaa; }

/* logs tables */
Expand All @@ -35,12 +39,12 @@
.table-logs-content td {}

.table-logs-header td,
.table-logs-content td { font-size: 0.7rem; }
.table-logs-content td { font-size: var(--log-font-size); }

td,
th { max-width: 0; /* allow ellipsis on tables */ vertical-align: top; }

.cell { line-height: 1rem; font-size: 1rem; padding: 0rem 0.2rem; font-weight: 100; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 18px; /* must be sync with rowHeight constant in view */ }
.cell { line-height: var(--row-height); font-size: var(--log-font-size); padding: 0rem 0.2rem; font-weight: 100; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cell-bordered { border-left: 1px solid rgb(170, 170, 170); }

.cell-xs { width: 2rem; }
Expand Down
9 changes: 6 additions & 3 deletions InfoLogger/public/log/Log.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { Observable, RemoteData } from '/js/src/index.js';
import LogFilter from '../logFilter/LogFilter.js';
import { MODE } from '../constants/mode.const.js';
import { TIME_MS } from '../common/Timezone.js';
import { ROW_HEIGHT } from '../constants/visual.const.js';

/**
* Model Log, encapsulate all log management and queries
Expand Down Expand Up @@ -595,8 +594,12 @@ export default class Log extends Observable {
*/
listLogsInViewportOnly() {
return this.list.slice(
Math.floor(this.scrollTop / ROW_HEIGHT),
Math.floor(this.scrollTop / ROW_HEIGHT) + Math.ceil(this.scrollHeight / ROW_HEIGHT) + 1,
Math.floor(this.scrollTop / this.rowHeight),
Math.floor(this.scrollTop / this.rowHeight) + Math.ceil(this.scrollHeight / this.rowHeight) + 1,
);
}

get rowHeight() {
return this.model.rowHeightPx;
}
}
13 changes: 12 additions & 1 deletion InfoLogger/public/log/commandLogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
* or submit itself to any jurisdiction.
*/

import { h, iconPerson, iconMediaPlay, iconMediaStop, iconDataTransferDownload } from '/js/src/index.js';
import { h,
iconPerson,
iconMediaPlay,
iconMediaStop,
iconDataTransferDownload,
iconMagnifyingGlass,
} from '/js/src/index.js';
import { BUTTON } from '../constants/button-states.const.js';
import { MODE } from '../constants/mode.const.js';
import { setBrowserTabTitle } from '../common/utils.js';
Expand Down Expand Up @@ -58,6 +64,11 @@ export default (model) => [
title: 'Go to last log message (ALT + down arrow)',
}, '↓'),
downloadButtonGroup(model.log),
h('button.btn.flex-row', {
onclick: () => model.resetZoom(),
disabled: model.zoom.level === 1,
id: 'reset-zoom-button',
}, h('span', ['Reset ', iconMagnifyingGlass()])),
];

/**
Expand Down
9 changes: 4 additions & 5 deletions InfoLogger/public/log/tableLogsContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { h } from '/js/src/index.js';

import { severityClass } from './severityUtils.js';
import tableColGroup from './tableColGroup.js';
import { ROW_HEIGHT } from './../constants/visual.const.js';

/**
* Main content of ILG - simulates a big table scrolling.
Expand All @@ -34,7 +33,7 @@ export default (model) =>
tableContainerHooks(model),
h('div.tableLogsContentPlaceholder', {
style: {
height: `${model.log.list.length * ROW_HEIGHT}px`,
height: `${model.log.list.length * model.log.rowHeight}px`,
position: 'relative',
},
}, [
Expand All @@ -55,7 +54,7 @@ export default (model) =>
const scrollStyling = (model) => ({
style: {
position: 'absolute',
top: `${model.log.scrollTop - model.log.scrollTop % ROW_HEIGHT}px`,
top: `${model.log.scrollTop - model.log.scrollTop % model.log.rowHeight}px`,
},
});

Expand Down Expand Up @@ -182,7 +181,7 @@ const autoscrollManager = (model, vnode) => {

if (previousLastLogId !== currentLastLogId) {
// scroll at maximum bottom possible
vnode.dom.scrollTo(0, ROW_HEIGHT * model.log.applicationLimit);
vnode.dom.scrollTo(0, model.log.rowHeight * model.log.applicationLimit);
vnode.dom.dataset.lastLogId = currentLastLogId;
}

Expand All @@ -199,7 +198,7 @@ const autoscrollManager = (model, vnode) => {
if (previousSelectedItemId !== currentSelectedItemId && model.log.autoScrollToItem) {
// scroll to an index * height of row, centered
const index = model.log.list.indexOf(model.log.item);
const positionRow = ROW_HEIGHT * index;
const positionRow = model.log.rowHeight * index;
const halfView = model.log.scrollHeight / 2;
vnode.dom.scrollTo(0, positionRow - halfView);
}
Expand Down
40 changes: 39 additions & 1 deletion InfoLogger/public/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,45 @@ import errorComponent from './common/errorComponent.js';
*/
export default (model) => [
notification(model.notification),
h('.flex-column absolute-fill', [
h('.flex-column absolute-fill', {
oncreate: (vnode) => {
const handleWheel = (e) => {
if (!e.ctrlKey) {
return;
}
e.preventDefault();
const now = Date.now();
if (now - model.zoom.lastScrollTime < 50) {
return;
}
model.zoom.lastScrollTime = now;
e.deltaY < 0 ? model.zoomIn() : model.zoomOut();
};

const handleKeyDown = (e) => {
if (!e.ctrlKey) {
return;
}
// Support both '=' and '+' for zooming in, as some keyboards require Shift to type '+'
if (e.key === '=' || e.key === '+') {
e.preventDefault();
model.zoomIn();
} else if (e.key === '-') {
e.preventDefault();
model.zoomOut();
}
};

window.addEventListener('wheel', handleWheel, { passive: false });
window.addEventListener('keydown', handleKeyDown);

vnode.state.cleanup = () => {
window.removeEventListener('wheel', handleWheel);
window.removeEventListener('keydown', handleKeyDown);
};
},
onremove: (vnode) => vnode.state.cleanup(),
}, [
h('.shadow-level2', [
h('header.p1.flex-row.f7', [
h('', commandLogs(model)),
Expand Down
1 change: 1 addition & 0 deletions InfoLogger/test/mocha-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ describe('InfoLogger', function() {
require('./public/log-filter-actions-mocha');
require('./public/live-mode-mocha');
require('./public/query-mode-mocha');
require('./public/zoom.mocha');

after(async () => {
await browser.close();
Expand Down
Loading
Loading