1const QUALITY_PRESETS={low:15,medium:30,high:50,ultra:80};class MockImageCanvas extends HTMLElement{constructor(){super(),this.canvas=null,this.ctx=null,this.artworkImg=null,this.frameImg=null,this.overlayImg=null,this.resizeObserver=null,this.isRendering=!1}connectedCallback(){if(this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d",{alpha:!0}),this.appendChild(this.canvas),this.loadAndRender(),!(this.hasAttribute("data-disable-resize-observer")||this.dataset.disableResizeObserver==="true")){let resizeTimeout;this.resizeObserver=new ResizeObserver(()=>{this.isRendering||(resizeTimeout&&cancelAnimationFrame(resizeTimeout),resizeTimeout=requestAnimationFrame(()=>{this.render()}))}),this.resizeObserver.observe(this),this.visibilityObserver=new IntersectionObserver(entries=>{for(const entry of entries)entry.isIntersecting&&this.verifyGeometry()}),this.visibilityObserver.observe(this)}const container=this.closest(".mock-image-container");container&&(this.artworkChangeHandler=()=>this.handleArtworkChange(),container.addEventListener("artwork-changed",this.artworkChangeHandler))}verifyGeometry(){const width=this.offsetWidth;width&&(Math.abs(width-this._renderedForWidth)<1||this.render())}disconnectedCallback(){this.resizeObserver&&this.resizeObserver.disconnect(),this.visibilityObserver&&this.visibilityObserver.disconnect();const container=this.closest(".mock-image-container");container&&this.artworkChangeHandler&&container.removeEventListener("artwork-changed",this.artworkChangeHandler)}async handleArtworkChange(){const container=this.closest(".mock-image-container");if(!container)return;const artworkSrc=container.dataset.artworkSrc;if(artworkSrc)try{this.artworkImg=await this.loadImage(artworkSrc),this.render()}catch(error){console.warn("[MockImageCanvas] Failed to load updated artwork:",error)}}async loadAndRender(){try{const artworkSrc=this.closest(".mock-image-container")?.dataset.artworkSrc||this.dataset.artworkSrc,artworkSrcset=this.dataset.artworkSrcset,frameSrc=this.dataset.frameSrc,frameSrcset=this.dataset.frameSrcset,overlaySrc=this.dataset.overlaySrc,overlaySrcset=this.dataset.overlaySrcset,sizes=this.dataset.sizes,cornersData=this.dataset.corners;if(!artworkSrc||!cornersData)return;try{if(this.corners=JSON.parse(cornersData),!Array.isArray(this.corners)||this.corners.length!==4){this.renderFallback();return}}catch{this.renderFallback();return}const artworkImageSrc=this.selectResponsiveImage(artworkSrc,artworkSrcset,sizes);if(this.artworkImg=await this.loadImage(artworkImageSrc),frameSrc){const frameImageSrc=this.selectResponsiveImage(frameSrc,frameSrcset,sizes);this.frameImg=await this.loadImage(frameImageSrc)}if(overlaySrc){const overlayImageSrc=this.selectResponsiveImage(overlaySrc,overlaySrcset,sizes);this.overlayImg=await this.loadImage(overlayImageSrc)}this.render()}catch{}}selectResponsiveImage(defaultSrc,srcset,sizes){if(!srcset)return defaultSrc;const sources=srcset.split(",").map(source=>{const parts=source.trim().split(" ");return{url:parts[0],width:parseInt(parts[1],10)}}).filter(source=>!isNaN(source.width));if(sources.length===0)return defaultSrc;const containerWidth=this.getBoundingClientRect().width||window.innerWidth,dpr=window.devicePixelRatio||1,targetWidth=containerWidth*dpr;let selectedSource=sources[sources.length-1];for(const source of sources)if(source.width>=targetWidth){selectedSource=source;break}return selectedSource.url}loadImage(src){return new Promise((resolve,reject)=>{const img=new Image;img.onload=()=>resolve(img),img.onerror=e=>reject(e),img.src=src})}render(){if(!(!this.artworkImg||!this.ctx||this.isRendering)){this.isRendering=!0;try{const rect=this.getBoundingClientRect(),width=this.offsetWidth||rect.width,height=this.offsetHeight||rect.height;if(width===0||height===0){this.isRendering=!1;return}this._renderedForWidth=width;const dpr=window.devicePixelRatio||1;this.canvas.width=width*dpr,this.canvas.height=height*dpr,this.canvas.style.width=width+"px",this.canvas.style.height=height+"px",this.ctx.scale(dpr,dpr),this.ctx.clearRect(0,0,width,height);const quality=this.dataset.quality||"medium",subdivisions=QUALITY_PRESETS[quality]||QUALITY_PRESETS.medium;this.drawPerspectiveImage(this.artworkImg,this.corners,width,height,subdivisions),this.overlayImg&&this.drawPerspectiveImage(this.overlayImg,this.corners,width,height,subdivisions),this.frameImg&&(this.ctx.save(),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.ctx.drawImage(this.frameImg,0,0,width,height),this.ctx.restore(
1))}finally{this.isRendering=!1}}}drawPerspectiveImage(img,corners,canvasWidth,canvasHeight,subdivisions){const pixelCorners=corners.map(c=>({x:c.x*canvasWidth,y:c.y*canvasHeight}));this.ctx.save(),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high";for(let row=0;row<subdivisions;row++)for(let col=0;col<subdivisions;col++){const u0=col/subdivisions,u1=(col+1)/subdivisions,v0=row/subdivisions,v1=(row+1)/subdivisions,getPoint=(u,v)=>{const top={x:pixelCorners[0].x*(1-u)+pixelCorners[1].x*u,y:pixelCorners[0].y*(1-u)+pixelCorners[1].y*u},bottom={x:pixelCorners[3].x*(1-u)+pixelCorners[2].x*u,y:pixelCorners[3].y*(1-u)+pixelCorners[2].y*u};return{x:top.x*(1-v)+bottom.x*v,y:top.y*(1-v)+bottom.y*v}},p0=getPoint(u0,v0),p1=getPoint(u1,v0),p3=getPoint(u0,v1),overlap=.5,sx=Math.max(0,u0*img.width-overlap),sy=Math.max(0,v0*img.height-overlap),sw=Math.min(img.width-sx,(u1-u0)*img.width+overlap*2),sh=Math.min(img.height-sy,(v1-v0)*img.height+overlap*2),dx1=p1.x-p0.x,dy1=p1.y-p0.y,dx2=p3.x-p0.x,dy2=p3.y-p0.y,sourceWidth=(u1-u0)*img.width,sourceHeight=(v1-v0)*img.height;this.ctx.save(),this.ctx.transform(dx1/sourceWidth,dy1/sourceWidth,dx2/sourceHeight,dy2/sourceHeight,p0.x,p0.y),this.ctx.drawImage(img,sx,sy,sw,sh,-overlap,-overlap,sourceWidth+overlap*2,sourceHeight+overlap*2),this.ctx.restore()}this.ctx.restore()}}customElements.get("mock-image-canvas")||customElements.define("mock-image-canvas",MockImageCanvas); 2//# sourceMappingURL=/cdn/shop/t/17/assets/mock-image-canvas-renderer.js.map?v=132454567468068375061787745110
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.