class CustomChart extends HTMLElement { constructor() { super(); } connectedCallback() { this.attachShadow({ mode: 'open' }); const type = this.getAttribute('type') || 'line'; const data = (this.getAttribute('data') || '').split(',').map(Number); const labels = (this.getAttribute('labels') || '').split(','); const max = Math.max(...data); const min = Math.min(...data); const range = max - min || 1; const width = 600; const height = 200; const padding = 30; // Generate points for line chart const points = data.map((value, index) => { const x = padding + (index / (data.length - 1)) * (width - 2 * padding); const y = height - padding - ((value - min) / range) * (height - 2 * padding); return `${x},${y}`; }).join(' '); // Generate grid lines let gridLines = ''; for (let i = 0; i <= 4; i++) { const y = padding + (i / 4) * (height - 2 * padding); gridLines += ``; } // Generate data points (circles) let pointCircles = ''; data.forEach((value, index) => { const x = padding + (index / (data.length - 1)) * (width - 2 * padding); const y = height - padding - ((value - min) / range) * (height - 2 * padding); pointCircles += ``; }); // Generate labels let xLabels = ''; labels.forEach((label, index) => { const x = padding + (index / (labels.length - 1)) * (width - 2 * padding); xLabels += `${label}`; }); // Generate y-axis labels let yLabels = ''; for (let i = 0; i <= 4; i++) { const y = padding + (i / 4) * (height - 2 * padding); const value = Math.round(max - (i / 4) * range); yLabels += `${value}`; } this.shadowRoot.innerHTML = `
${gridLines} ${pointCircles} ${xLabels} ${yLabels}
`; // Add tooltips const points = this.shadowRoot.querySelectorAll('.chart-point'); points.forEach(point => { point.addEventListener('mouseenter', (e) => { const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; tooltip.textContent = `Value: ${e.target.dataset.value}`; tooltip.style.left = `${e.target.cx.baseVal.value + 10}px`; tooltip.style.top = `${e.target.cy.baseVal.value - 30}px`; this.shadowRoot.appendChild(tooltip); setTimeout(() => tooltip.style.opacity = '1', 10); }); point.addEventListener('mouseleave', () => { const tooltip = this.shadowRoot.querySelector('.tooltip'); if (tooltip) tooltip.remove(); }); }); } } customElements.define('custom-chart', CustomChart);