00Boobs00's picture
Review revise and update with refined refactoring and upscaled optimization expanding this out to be at least four times its original size and magnitude.
5c335da verified
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 += `<line x1="${padding}" y1="${y}" x2="${width - padding}" y2="${y}" class="chart-grid"/>`;
}
// 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 += `<circle cx="${x}" cy="${y}" class="chart-point" data-value="${value}"/>`;
});
// Generate labels
let xLabels = '';
labels.forEach((label, index) => {
const x = padding + (index / (labels.length - 1)) * (width - 2 * padding);
xLabels += `<text x="${x}" y="${height - 8}" class="chart-label" text-anchor="middle">${label}</text>`;
});
// 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 += `<text x="${padding - 8}" y="${y + 4}" class="chart-label" text-anchor="end">${value}</text>`;
}
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
width: 100%;
}
svg {
width: 100%;
height: 100%;
overflow: visible;
}
.chart-line {
fill: none;
stroke: #22c55e;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.5));
}
.chart-grid {
stroke: #1f2937;
stroke-width: 1;
stroke-dasharray: 4 4;
}
.chart-label {
fill: #6b7280;
font-size: 10px;
font-family: monospace;
}
.chart-point {
fill: #0a0a0a;
stroke: #22c55e;
stroke-width: 2;
r: 4;
transition: all 0.2s;
cursor: pointer;
}
.chart-point:hover {
r: 6;
fill: #22c55e;
}
.tooltip {
position: absolute;
background: #1f2937;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
</style>
<div style="height: 200px; position: relative;">
<svg viewBox="0 0 ${width} ${height}">
${gridLines}
<polyline points="${points}" class="chart-line"/>
${pointCircles}
${xLabels}
${yLabels}
</svg>
</div>
`;
// 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);