Skip to content

Commit

Permalink
Reduce DPI if canvas is too big to avoid page crash - this happen on …
Browse files Browse the repository at this point in the history
…webpage on mobile with high dpi and missing meta viewport tag with width=device-width.
  • Loading branch information
davidetan committed Jan 23, 2025
1 parent 59d6cf1 commit 95caa33
Showing 1 changed file with 23 additions and 8 deletions.
31 changes: 23 additions & 8 deletions spine-ts/spine-webgl/src/SpineWebComponentWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
// to simplify we just assume that the user wants to load the skeleton at scale 1
// at the current browser zoom level
// this might be problematic for free-scale modes (origin and inside+none)
this.currentScaleDpi = window.devicePixelRatio;
this.currentScaleDpi = this.overlay.getDPR();
// skeleton.scaleX = this.currentScaleDpi;
// skeleton.scaleY = this.currentScaleDpi;

Expand Down Expand Up @@ -2124,7 +2124,7 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
// I'm not sure about this. With mode origin and fit none:
// case 1) If I comment this scale code, the skeleton is never scaled and will be always at the same size and won't change size while zooming
// case 2) Otherwise, the skeleton is loaded always at the same size, but changes size while zooming
const scale = window.devicePixelRatio;
const scale = this.getDPR();
skeleton.scaleX = skeleton.scaleX / widget.currentScaleDpi * scale;
skeleton.scaleY = skeleton.scaleY / widget.currentScaleDpi * scale;
widget.currentScaleDpi = scale;
Expand Down Expand Up @@ -2177,8 +2177,8 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,

private resize (width: number, height: number) {
let canvas = this.canvas;
this.canvas.width = Math.round(this.screenToWorldLength(width));
this.canvas.height = Math.round(this.screenToWorldLength(height));
canvas.width = Math.round(this.screenToWorldLength(width));
canvas.height = Math.round(this.screenToWorldLength(height));
this.renderer.context.gl.viewport(0, 0, canvas.width, canvas.height);
this.renderer.camera.setViewport(canvas.width, canvas.height);
this.renderer.camera.update();
Expand All @@ -2196,11 +2196,13 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
private previousDPR = 0;
private static readonly WIDTH_INCREMENT = 1.15;
private static readonly HEIGHT_INCREMENT = 1.2;
private getScreenSize () {
private static readonly MAX_CANVAS_WIDTH = 7000;
private static readonly MAX_CANVAS_HEIGHT = 7000;
private getScreenSize (): { width: number, height: number} {
let width = window.innerWidth;
let height = window.innerHeight;

const dpr = window.devicePixelRatio;
const dpr = this.getDPR();
if (dpr !== this.previousDPR) {
this.previousDPR = dpr;
this.previousWidth = this.previousWidth === 0 ? width : width * SpineWebComponentOverlay.WIDTH_INCREMENT;
Expand All @@ -2210,12 +2212,25 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
if (height > this.previousHeight) this.previousHeight = height * SpineWebComponentOverlay.HEIGHT_INCREMENT;
}

// if the resulting canvas width/height is too high, scale the DPI
if (this.previousHeight * (1 + this.overflowTop + this.overflowBottom) * dpr > SpineWebComponentOverlay.MAX_CANVAS_HEIGHT ||
this.previousWidth * (1 + this.overflowLeft + this.overflowRight) * dpr > SpineWebComponentOverlay.MAX_CANVAS_WIDTH)
{
this.scaleDPR += .5;
return this.getScreenSize();
}

return {
width: this.previousWidth,
height: this.previousHeight,
}
}

private scaleDPR = 1;
public getDPR() {
return window.devicePixelRatio / this.scaleDPR;
}

/*
* Other utilities
*/
Expand All @@ -2231,10 +2246,10 @@ class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes,
this.renderer.camera.worldToScreen(vec, this.worldToScreenLength(this.renderer.camera.viewportWidth), this.worldToScreenLength(this.renderer.camera.viewportHeight));
}
public screenToWorldLength (length: number) {
return length * window.devicePixelRatio;
return length * this.getDPR();
}
public worldToScreenLength (length: number) {
return length / window.devicePixelRatio;
return length / this.getDPR();
}
}

Expand Down

0 comments on commit 95caa33

Please sign in to comment.