class WompumGrid { constructor(element) { this.gridElement = element; this.gridSize = { columns: parseInt(element.dataset.columns) || 7, rows: parseInt(element.dataset.rows) || 5 }; // Set grid template columns based on data attribute or default this.gridElement.style.gridTemplateColumns = `repeat(${this.gridSize.columns}, 1fr)`; // Initialize color calculator this.colorCalculator = new ColorCalculator(); // Generate sigil from text content if provided const text = element.dataset.text || ''; this.sigil = Sigil.generate(text); this.gridElement.dataset.sigil = JSON.stringify(this.sigil); } // Get sigil digit for a cell based on its position getSigilDigit(position) { if (!this.sigil || !this.sigil.length) return 0; return this.sigil[position % this.sigil.length]; } // Get influences from adjacent cells getInfluences(column, row) { const influences = []; // Check adjacent cells (up, down, left, right) const adjacentPositions = [ [column, row - 1], // up [column, row + 1], // down [column - 1, row], // left [column + 1, row] // right ]; for (const [adjCol, adjRow] of adjacentPositions) { if (adjCol >= 0 && adjCol < this.gridSize.columns && adjRow >= 0 && adjRow < this.gridSize.rows) { const cell = this.gridElement.querySelector( `[data-column="${adjCol}"][data-row="${adjRow}"]` ); if (cell && cell.dataset.sigilDigit) { influences.push(parseInt(cell.dataset.sigilDigit)); } } } return influences; } // Create basic grid cells createGrid() { const totalCells = this.gridSize.columns * this.gridSize.rows; for (let i = 0; i < totalCells; i++) { const cell = document.createElement('div'); const column = i % this.gridSize.columns; const row = Math.floor(i / this.gridSize.columns); cell.className = 'wompum-cell'; cell.setAttribute('data-cell-index', i); cell.setAttribute('data-column', column); cell.setAttribute('data-row', row); // Set sigil digit based on cell position const sigilDigit = this.getSigilDigit(i); cell.setAttribute('data-sigil-digit', sigilDigit); this.gridElement.appendChild(cell); } } applyMetadataDesign() { const cells = this.gridElement.querySelectorAll('.wompum-cell'); cells.forEach(cell => { const column = parseInt(cell.dataset.column); const row = parseInt(cell.dataset.row); const sigilDigit = parseInt(cell.dataset.sigilDigit); // Get influences from adjacent cells const influences = this.getInfluences(column, row); // Calculate and apply color const color = this.colorCalculator.getColor(sigilDigit, influences); cell.style.backgroundColor = color; }); } init() { if (!this.gridElement) return; this.createGrid(); this.applyMetadataDesign(); } } class ArticleGrid extends WompumGrid { constructor(element, metadata) { super(element); this.metadata = metadata; // Generate sigils for each metadata component this.sigils = { narrator: Sigil.generate(metadata.narrator), subject: Sigil.generate(metadata.subject), facilitator: Sigil.generate(metadata.facilitator) }; // Store sigils as data attributes Object.entries(this.sigils).forEach(([key, value]) => { this.gridElement.dataset[`${key}Sigil`] = JSON.stringify(value); }); } getSigilDigit(position, section) { const sigil = this.sigils[section]; if (!sigil || !sigil.length) return 0; return sigil[position % sigil.length]; } createGrid() { const totalCells = this.gridSize.columns * this.gridSize.rows; const narratorColumns = 2; const facilitatorColumns = 2; for (let i = 0; i < totalCells; i++) { const cell = document.createElement('div'); const column = i % this.gridSize.columns; const row = Math.floor(i / this.gridSize.columns); // Determine section based on column position let section; if (column < narratorColumns) section = 'narrator'; else if (column >= this.gridSize.columns - facilitatorColumns) section = 'facilitator'; else section = 'subject'; // Use BEM modifiers for sections cell.className = `wompum-cell wompum-cell--${section}`; cell.setAttribute('data-cell-index', i); cell.setAttribute('data-section', section); cell.setAttribute('data-column', column); cell.setAttribute('data-row', row); // Set sigil digit based on section and position const sigilDigit = this.getSigilDigit(row, section); cell.setAttribute('data-sigil-digit', sigilDigit); this.gridElement.appendChild(cell); } } } class RadialWompumGrid { constructor(element, size = 10) { this.element = element; // Remove .parentElement this.segments = size; this.colorCalculator = new ColorCalculator(); this.sigil = Sigil.generate(this.element.dataset.text || ''); } createSegment(index) { const angle = (360 / this.segments); // Add a small gap by reducing the arc angle const gap = 2; // degrees of gap const startAngle = (index * angle) + (gap / 2); const endAngle = ((index + 1) * angle) - (gap / 2); const outerRadius = 50; const innerRadius = 0; const start = this.polarToCartesian(startAngle, outerRadius); const end = this.polarToCartesian(endAngle, outerRadius); const innerStart = this.polarToCartesian(startAngle, innerRadius); const innerEnd = this.polarToCartesian(endAngle, innerRadius); const largeArcFlag = (angle - gap) > 180 ? 1 : 0; const d = [ `M ${start.x} ${start.y}`, `A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`, `L ${innerEnd.x} ${innerEnd.y}`, `A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${innerStart.x} ${innerStart.y}`, 'Z' ].join(' '); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', d); const sigilDigit = this.getSigilDigit(index); // Pass empty array for influences since we don't need adjacent segments const color = this.colorCalculator.getColor(sigilDigit, []); path.setAttribute('fill', color); return path; } polarToCartesian(angle, radius) { const radian = (angle - 90) * Math.PI / 180.0; return { x: 50 + (radius * Math.cos(radian)), y: 50 + (radius * Math.sin(radian)) }; } getSigilDigit(position) { if (!this.sigil || !this.sigil.length) return 0; return this.sigil[position % this.sigil.length]; } getInfluences(index) { const prev = (index - 1 + this.segments) % this.segments; const next = (index + 1) % this.segments; return [ this.getSigilDigit(prev), this.getSigilDigit(next) ]; } createSVG() { const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('viewBox', '0 0 100 100'); svg.setAttribute('class', 'wompum-radial-grid'); for (let i = 0; i < this.segments; i++) { svg.appendChild(this.createSegment(i)); } return svg; } init() { if (!this.sigil || !this.sigil.length) { console.error('No sigil generated from text:', this.element.getAttribute('data-text')); return; } const svg = this.createSVG(); this.element.insertBefore(svg, this.element.firstChild); } } // Initialize grids document.addEventListener('DOMContentLoaded', () => { // Initialize basic grids document.querySelectorAll('.wompum-grid').forEach(element => { const grid = new WompumGrid(element); grid.init(); }); // Initialize article grids document.querySelectorAll('.wompum-article-grid').forEach(element => { let metadata = {}; try { metadata = JSON.parse(element.dataset.metadata || '{}'); } catch (e) { console.error('Error parsing metadata for article grid:', e); } const grid = new ArticleGrid(element, metadata); grid.init(); }); // Initialize radial grids for profile images document.querySelectorAll('.narrator__container').forEach(element => { const grid = new RadialWompumGrid(element); grid.init(); }); });