model-explorer / js /ui /initializerDisplay.js
mr4's picture
Upload 71 files
9bd422a verified
/**
* InitializerDisplay - Displays model initializers (constant tensors / weights)
* Requirements: 7.1, 7.2, 7.3, 7.4, 7.5
*/
class InitializerDisplay {
/**
* @param {string} containerId - ID of the container element
*/
constructor(containerId) {
this._containerId = containerId;
this._container = document.getElementById(containerId);
if (!this._container) {
console.warn(`[InitializerDisplay] Container #${containerId} not found`);
}
}
// ─── Private ──────────────────────────────────────────────────────────────
/**
* Escape HTML special characters.
* @param {string} str
* @returns {string}
*/
_escapeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(String(str)));
return div.innerHTML;
}
/**
* Format a shape array to a readable string.
* @param {Array<number>} shape
* @returns {string}
*/
_formatShape(shape) {
if (!shape || shape.length === 0) return '[]';
return `[${shape.join(', ')}]`;
}
/**
* Resolve a numeric data type to its string name.
* @param {number|string} dataType
* @returns {string}
*/
_resolveDataType(dataType) {
if (typeof dataType === 'string') return dataType;
if (CONFIG && CONFIG.DATA_TYPES && CONFIG.DATA_TYPES[dataType]) {
return CONFIG.DATA_TYPES[dataType];
}
return String(dataType);
}
/**
* Format a byte count to a human-readable string (e.g. "4.2 KB").
* @param {number} bytes
* @returns {string}
*/
_formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
}
/**
* Compute the size label for an initializer.
* Prefer size in bytes; fall back to element count.
* @param {InitializerInfo} init
* @returns {string}
*/
_sizeLabel(init) {
if (init.size && init.size > 0) {
return this._formatBytes(init.size);
}
if (init.elementCount && init.elementCount > 0) {
return `${init.elementCount.toLocaleString()} elements`;
}
// Compute element count from shape if available
if (init.shape && init.shape.length > 0) {
const count = init.shape.reduce((acc, d) => acc * (d || 1), 1);
return `${count.toLocaleString()} elements`;
}
return 'Unknown size';
}
/**
* Build the HTML for a single initializer item.
* @param {InitializerInfo} init
* @returns {string}
*/
_buildItem(init) {
const shape = this._formatShape(init.shape);
const dtype = this._resolveDataType(init.dataType);
const size = this._sizeLabel(init);
return `
<div class="initializer-item border rounded p-2 mb-2 cursor-pointer"
role="button"
tabindex="0"
data-init-name="${this._escapeHtml(init.name)}"
title="Click to highlight in graph"
aria-label="Initializer ${this._escapeHtml(init.name)}">
<div class="fw-medium text-truncate mb-1">${this._escapeHtml(init.name)}</div>
<div class="small text-muted d-flex flex-wrap gap-2">
<span><i class="fas fa-shapes me-1"></i>${this._escapeHtml(shape)}</span>
<span><i class="fas fa-tag me-1"></i>${this._escapeHtml(dtype)}</span>
<span><i class="fas fa-database me-1"></i>${this._escapeHtml(size)}</span>
</div>
</div>`;
}
/**
* Attach click and keyboard handlers to initializer items.
*/
_attachItemHandlers() {
if (!this._container) return;
const items = this._container.querySelectorAll('.initializer-item');
items.forEach((item) => {
const handler = () => {
const name = item.dataset.initName;
if (name && window.EventBus) {
window.EventBus.emit(CONFIG.EVENTS.NODE_SELECTED, { nodeId: name, source: 'initializer' });
}
if (name && window.StateManager) {
window.StateManager.setSelectedNodeId(name);
}
};
item.addEventListener('click', handler);
item.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handler();
}
});
});
}
// ─── Public API ───────────────────────────────────────────────────────────
/**
* Render the initializer list for a parsed model.
* @param {ParsedModel} model
*/
render(model) {
if (!this._container) return;
const initializers = (model && model.initializers)
? model.initializers
: (model && model.graph && model.graph.initializers)
? model.graph.initializers
: [];
if (initializers.length === 0) {
this._container.innerHTML = `
<p class="text-muted">
<i class="fas fa-info-circle me-1"></i>No initializers found in this model.
</p>`;
return;
}
const header = `<p class="text-secondary small mb-2">${initializers.length} initializer${initializers.length !== 1 ? 's' : ''}</p>`;
const items = initializers.map((init) => this._buildItem(init)).join('');
this._container.innerHTML = header + items;
this._attachItemHandlers();
}
/**
* Clear the display.
*/
clear() {
if (!this._container) return;
this._container.innerHTML = '<p class="text-muted">Select a model to view initializers</p>';
}
}
window.InitializerDisplay = InitializerDisplay;