UNPKG

vvcomponent

Version:
114 lines (111 loc) 5.95 kB
globalThis.ComponenetError = class extends Error { constructor(message) { super(message); this.name = 'ComponenetError'; } } class aImage extends HTMLElement { errorSvg = (w, h) => `<?xml version="1.0" encoding="UTF-8"?><svg width="${w}" height="${h}" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M44 23.9941C44 22.8896 43.1046 21.9941 42 21.9941C40.8954 21.9941 40 22.8896 40 23.9941H44ZM24 7.99414C25.1046 7.99414 26 7.09871 26 5.99414C26 4.88957 25.1046 3.99414 24 3.99414V7.99414ZM39 39.9941H9V43.9941H39V39.9941ZM8 38.9941V8.99414H4V38.9941H8ZM40 23.9941V38.9941H44V23.9941H40ZM9 7.99414H24V3.99414H9V7.99414ZM9 39.9941C8.44772 39.9941 8 39.5464 8 38.9941H4C4 41.7556 6.23857 43.9941 9 43.9941V39.9941ZM39 43.9941C41.7614 43.9941 44 41.7556 44 38.9941H40C40 39.5464 39.5523 39.9941 39 39.9941V43.9941ZM8 8.99414C8 8.44186 8.44771 7.99414 9 7.99414V3.99414C6.23858 3.99414 4 6.23272 4 8.99414H8Z" fill="#333"/><path d="M6 35L16.6931 25.198C17.4389 24.5143 18.5779 24.4953 19.3461 25.1538L32 36" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M28 31L32.7735 26.2265C33.4772 25.5228 34.5914 25.4436 35.3877 26.0408L42 31" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M33 7L41 15" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M41 7L33 15" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>`; cacheBlob = null; imgUrl = null; constructor() { super(); this.attachShadow({ mode: 'open' }); const config = { attributes: true, childList: true, subtree: true, characterData: true }; const self = this; const callback = function (mutationsList, observer) { self.loadImg(); }; const observer = new MutationObserver(callback); observer.observe(this, config); } async render(w, h, e) { const imgSrc = this.getAttribute('src'); this.imgUrl = imgSrc; let imgDataUrl = null; if (this.cacheBlob) { imgDataUrl = await this.BlobToDataUrl(this.cacheBlob); } const imgAlt = this.getAttribute('alt') || 'Image'; const imgWidth = this.getAttribute('width'); const imgHeight = this.getAttribute('height'); const scale = typeof this.getAttribute('scale') == 'string' ? Number(this.getAttribute('scale')) : this.getAttribute('scale') || 1; const borderRadius = this.getAttribute('border-radius') || 0; const border = this.getAttribute('border') || 0; const borderColor = this.getAttribute('border-color') || '#000'; const borderStyle = this.getAttribute('border-style') || 'solid'; const mode = this.getAttribute('mode') || 'none'; const img = document.createElement('div'); img.setAttribute("alt", imgAlt); img.setAttribute("class", "iftc-image"); img.style.backgroundImage = `url("${imgDataUrl || imgSrc}")`; img.style.backgroundRepeat = 'no-repeat'; img.style.width = `${(imgWidth || w) * scale}px`; img.style.height = `${(imgHeight || h) * scale}px`; img.style.backgroundSize = `${(imgWidth || w) * scale}px ${(imgHeight || h) * scale}px`; img.style.backgroundPosition = 'center center'; img.style.borderRadius = `${borderRadius}px`; img.style.border = `${border}px ${borderStyle} ${borderColor}`; this.shadowRoot.innerHTML = ''; if (e) { img.innerHTML = `<div class="iftc-image-error">${e((imgWidth * scale) || 24, (imgHeight * scale) || 24)}</div>` img.style.backgroundImage = 'url("")'; } if (mode == 'cover') { img.style.backgroundSize = 'cover'; } else if (mode == 'contain') { img.style.backgroundSize = 'contain'; } else if (mode == 'stretch') { img.style.backgroundSize = '100% 100%'; } else if (mode == 'none') { } else { throw new ComponenetError('无效的mode'); } this.shadowRoot.appendChild(img); } loadImg() { const imgSrc = this.getAttribute('src'); if (this.cacheBlob && this.imgUrl == imgSrc) { this.render(this.imgUrl.width, this.imgUrl.height); return; } const img = new Image(); img.src = imgSrc; img.onload = async () => { this.cacheBlob = await this.getImgBlob(); this.render(img.width, img.height) } img.onerror = () => this.render(img.width, img.height, this.errorSvg) } set(name, value) { this.setAttribute(name, value); } get(name) { return this.getAttribute(name); } BlobToDataUrl(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = () => reject(new Error('Failed to read blob')); reader.readAsDataURL(blob); }); } getImgBlob() { return new Promise((resolve, reject) => { const img = new Image(); img.src = this.getAttribute('src'); img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); canvas.toBlob((blob) => { if (blob) resolve(blob); else reject(new Error('Failed to convert image to blob')); }, 'image/png'); } }) } } customElements.define('iftc-image', aImage);