blob: 9d8c7599fef5fbd168d44693b9461cfedff0146e [file] [log] [blame]
/**
* @module modules/histogram-sk
*
* @description A visual representation of the command name counts totalled by
* commands-sk when a frame is loaded, and a controller for the set of included
* command names in the filter (also in commands-sk).
*
* It's not an indepentent model-view-controller, just a view-controller for a
* model in commands-sk. The main reason it's a seperate module is that it's
* visually self-contained in different element elsewhere on the page, and as
* far as I know commandsSk cannot export two different elements.
*
* Due to the functionality depending on the integration with commands-sk,
* this module is tested in debugger-page-sk_test.ts.
*
* @evt toggle-command-inclusion: Emitted when a row is clicked, indicating it's
* inclusion in the command filter should be toggled.
*/
import { define } from 'elements-sk/define';
import { html } from 'lit-html';
import { ElementDocSk } from '../element-doc-sk/element-doc-sk';
import {
HistogramUpdateEventDetail, HistogramEntry,
HistogramUpdateEvent,
ToggleCommandInclusionEvent,
ToggleCommandInclusionEventDetail,
} from '../events';
export class HistogramSk extends ElementDocSk {
private static template = (ele: HistogramSk) => html`
<details title="A table of the number of occurrences of each command." open>
<summary><b>Histogram</b></summary>
<table>
<tr>
<td title="Occurrences of command in current frame (or single frame skp file).">frame</td>
<td title="Occurrences of command within the current range filter.">range</td>
<td>name</td>
</tr>
${ele._hist.map((item: HistogramEntry) => HistogramSk.rowTemplate(ele, item))}
<tr><td class=countCol>${ele._total()}</td><td><b>Total</b></td></tr>
</table>
</details>`;
private static rowTemplate = (ele: HistogramSk, item: HistogramEntry) => html`
<tr @click=${() => { ele._toggle(item.name); }} id="hist-row-${item.name.toLowerCase()}"
class="${ele._incl.has(item.name.toLowerCase()) ? '' : 'pinkBackground'}">
<td class=countCol>${item.countInFrame}</td>
<td class=countCol>${item.countInRange}</td>
<td>${item.name}</td>
</tr>`;
// counts of command occurrences
private _hist: HistogramEntry[] = [];
// commands which the filter includes
private _incl = new Set<string>();
private _total(): number {
let total = 0;
for (const item of this._hist) {
total += item.countInRange;
}
return total;
}
constructor() {
super(HistogramSk.template);
}
connectedCallback(): void {
super.connectedCallback();
this._render();
this.addDocumentEventListener(HistogramUpdateEvent, (e) => {
const detail = (e as CustomEvent<HistogramUpdateEventDetail>).detail;
// event may update one or both items
if (detail.hist) {
this._hist = detail.hist;
}
if (detail.included) {
this._incl = detail.included;
}
this._render();
});
}
// Toggle the given item in or out of the included set in commands-sk
private _toggle(name: string) {
const lowerName = name.toLowerCase();
// short cut to change our own appearance
if (this._incl.has(lowerName)) {
this._incl.delete(lowerName);
} else {
this._incl.add(lowerName);
}
this._render();
// but make sure to tell the module that actually owns this model
this.dispatchEvent(
new CustomEvent<ToggleCommandInclusionEventDetail>(
ToggleCommandInclusionEvent, {
detail: { name: lowerName },
bubbles: true,
},
),
);
}
}
define('histogram-sk', HistogramSk);