diff --git a/spine-ts/spine-player/example/physics.html b/spine-ts/spine-player/example/physics.html index 045a5ae0b..21a52b5a2 100644 --- a/spine-ts/spine-player/example/physics.html +++ b/spine-ts/spine-player/example/physics.html @@ -17,7 +17,7 @@ last = new spine.Vector3(); new spine.SpinePlayer("player", { skeleton: "assets/celestial-circus-pro.skel", - url: "assets/celestial-circus-pma.atlas", + atlas: "assets/celestial-circus-pma.atlas", showControls: true, animation: "swing", success: (player) => { diff --git a/spine-ts/spine-webgl/example/webcomponent.html b/spine-ts/spine-webgl/example/webcomponent.html index a00aad89d..8b0468009 100644 --- a/spine-ts/spine-webgl/example/webcomponent.html +++ b/spine-ts/spine-webgl/example/webcomponent.html @@ -14,6 +14,7 @@ } body { font-family: Arial, sans-serif; + font-size: 16px; } .section { display: flex; @@ -1712,7 +1713,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => { atlas="assets/celestial-circus-pma.atlas" skeleton="assets/celestial-circus-pro.skel" clip - draggable + isdraggable > diff --git a/spine-ts/spine-webgl/src/Input.ts b/spine-ts/spine-webgl/src/Input.ts index f763685dc..4561f49cb 100644 --- a/spine-ts/spine-webgl/src/Input.ts +++ b/spine-ts/spine-webgl/src/Input.ts @@ -36,11 +36,11 @@ export class Input { touch1: Touch | null = null; initialPinchDistance = 0; private listeners = new Array(); - private preventDefault: boolean; + private autoPreventDefault: boolean; - constructor (element: HTMLElement, preventDefault = true) { + constructor (element: HTMLElement, autoPreventDefault = true) { this.element = element; - this.preventDefault = preventDefault; + this.autoPreventDefault = autoPreventDefault; this.setupCallbacks(element); } @@ -48,7 +48,7 @@ export class Input { let mouseDown = (ev: UIEvent) => { if (ev instanceof MouseEvent) { let rect = element.getBoundingClientRect(); - this.mouseX = ev.clientX - rect.left;; + this.mouseX = ev.clientX - rect.left; this.mouseY = ev.clientY - rect.top; this.buttonDown = true; this.listeners.map((listener) => { if (listener.down) listener.down(this.mouseX, this.mouseY, ev); }); @@ -88,7 +88,7 @@ export class Input { } let mouseWheel = (ev: WheelEvent) => { - if (this.preventDefault) ev.preventDefault(); + if (this.autoPreventDefault) ev.preventDefault(); let deltaY = ev.deltaY; if (ev.deltaMode == WheelEvent.DOM_DELTA_LINE) deltaY *= 8; if (ev.deltaMode == WheelEvent.DOM_DELTA_PAGE) deltaY *= 24; @@ -125,8 +125,8 @@ export class Input { this.listeners.map((listener) => { if (listener.zoom) listener.zoom(this.initialPinchDistance, this.initialPinchDistance, ev) }); } } - if (this.preventDefault) ev.preventDefault(); - }, { passive: this.preventDefault }); + if (this.autoPreventDefault) ev.preventDefault(); + }, { passive: false, capture: false }); element.addEventListener("touchmove", (ev: TouchEvent) => { if (this.touch0) { @@ -154,8 +154,8 @@ export class Input { this.listeners.map((listener) => { if (listener.zoom) listener.zoom(this.initialPinchDistance, distance, ev) }); } } - if (this.preventDefault) ev.preventDefault(); - }, { passive: this.preventDefault }); + if (this.autoPreventDefault) ev.preventDefault(); + }, { passive: false, capture: false }); let touchEnd = (ev: TouchEvent) => { if (this.touch0) { @@ -191,9 +191,9 @@ export class Input { } } } - if (this.preventDefault) ev.preventDefault(); + if (this.autoPreventDefault) ev.preventDefault(); }; - element.addEventListener("touchend", touchEnd, false); + element.addEventListener("touchend", touchEnd, { passive: false, capture: false }); element.addEventListener("touchcancel", touchEnd); } diff --git a/spine-ts/spine-webgl/src/SpineWebComponentWidget.ts b/spine-ts/spine-webgl/src/SpineWebComponentWidget.ts index 049f58651..0c79bf384 100644 --- a/spine-ts/spine-webgl/src/SpineWebComponentWidget.ts +++ b/spine-ts/spine-webgl/src/SpineWebComponentWidget.ts @@ -111,7 +111,7 @@ interface WidgetAttributes { offsetY: number width: number height: number - draggable: boolean + isDraggable: boolean debug: boolean identifier: string manualStart: boolean @@ -280,9 +280,9 @@ export class SpineWebComponentWidget extends HTMLElement implements WidgetAttrib /** * If true, the widget is draggable - * Connected to `draggable` attribute. + * Connected to `isdraggable` attribute. */ - public draggable = false; + public isDraggable = false; /** * If true, some convenience elements are drawn to show the skeleton world origin (green), @@ -488,7 +488,7 @@ export class SpineWebComponentWidget extends HTMLElement implements WidgetAttrib skin: { propertyName: "skin", type: "string" }, width: { propertyName: "width", type: "number", defaultValue: -1 }, height: { propertyName: "height", type: "number", defaultValue: -1 }, - draggable: { propertyName: "draggable", type: "boolean" }, + isdraggable: { propertyName: "isDraggable", type: "boolean" }, "x-axis": { propertyName: "xAxis", type: "number" }, "y-axis": { propertyName: "yAxis", type: "number" }, "offset-x": { propertyName: "offsetX", type: "number" }, @@ -505,29 +505,7 @@ export class SpineWebComponentWidget extends HTMLElement implements WidgetAttrib } static get observedAttributes(): string[] { - return [ - "atlas", // atlasPath - "skeleton", // skeletonPath - "scale", // scale - "animation", // animation - "skin", // skin - "fit", // fit - "width", // width - "height", // height - "draggable", // draggable - "mode", // mode - "x-axis", // xAxis - "y-axis", // yAxis - "offset-x", // offsetX - "offset-y", // offsetY - "identifier", // identifier - "debug", // debug - "manual-start", // manualStart - "spinner", // loadingSpinner - "pages", // pages - "offscreen", // offScreenUpdateBehaviour - "clip", // clip - ]; + return Object.keys(SpineWebComponentWidget.attributesDescription); } constructor() { @@ -843,7 +821,6 @@ class SpineWebComponentOverlay extends HTMLElement { public skeletonList = new Array(); private intersectionObserver? : IntersectionObserver; - private resizeObserver:ResizeObserver; private input: Input; // how many pixels to add to the edges to prevent "edge cuttin" on fast scrolling @@ -896,40 +873,61 @@ class SpineWebComponentOverlay extends HTMLElement { const context = new ManagedWebGLRenderingContext(this.canvas, { alpha: true }); this.renderer = new SceneRenderer(this.canvas, context); this.assetManager = new AssetManager(context); - this.input = new Input(this.canvas); + this.input = new Input(this.canvas, false); this.setupRenderingElements(); - this.updateCanvasSize(); - this.zoomHandler(); - - // translateCanvas starts a requestAnimationFrame loop - this.translateCanvas(); - this.overflowLeftSize = this.overflowLeft * document.documentElement.clientWidth; this.overflowTopSize = this.overflowTop * document.documentElement.clientHeight; - // resize and zoom - // TODO: should I use the resize event? - this.resizeObserver = new ResizeObserver(() => { + window.addEventListener('resize', () => { this.updateCanvasSize(); - this.zoomHandler(); + this.zoomHandler(); }); - this.resizeObserver.observe(document.body); - const screen = window.screen; - screen.orientation.onchange = () => { + window.screen.orientation.onchange = () => { this.updateCanvasSize(); // after an orientation change the scrolling changes, but the scroll event does not fire this.scrollHandler(); } window.addEventListener("scroll", this.scrollHandler); - this.scrollHandler(); + + window.onload = () => { + this.updateCanvasSize(); + this.zoomHandler(); + + // translateCanvas starts a requestAnimationFrame loop + this.translateCanvas(); + + this.scrollHandler(); + }; this.input = new Input(document.body, false); this.setupDragUtility(); } + connectedCallback(): void { + this.intersectionObserver = new IntersectionObserver((widgets) => { + widgets.forEach(({ isIntersecting, target, intersectionRatio }) => { + const widget = this.skeletonList.find(w => w.getHTMLElementReference() == target); + if (!widget) return; + + // old browsers do not have isIntersecting + if (isIntersecting === undefined) { + isIntersecting = intersectionRatio > 0; + } + + widget.onScreen = isIntersecting; + if (isIntersecting) { + widget.onScreenFunction(widget); + } + }) + }, { rootMargin: "30px 20px 30px 20px" }); + } + + disconnectedCallback(): void { + } + addWidget(widget: SpineWebComponentWidget) { this.skeletonList.push(widget); this.intersectionObserver!.observe(widget.getHTMLElementReference()); @@ -1028,12 +1026,13 @@ class SpineWebComponentOverlay extends HTMLElement { const devicePixelRatio = window.devicePixelRatio; const tempVector = new Vector3(); this.skeletonList.forEach((widget) => { - const { skeleton, bounds, mode, debug, offsetX, offsetY, xAxis, yAxis, dragX, dragY, fit, loadingSpinner, onScreen, loading, clip, draggable } = widget; + const { skeleton, bounds, mode, debug, offsetX, offsetY, xAxis, yAxis, dragX, dragY, fit, loadingSpinner, onScreen, loading, clip, isDraggable } = widget; if ((!onScreen && dragX === 0 && dragY === 0)) return; const divBounds = widget.getHTMLElementReference().getBoundingClientRect(); - divBounds.x += this.overflowLeftSize; - divBounds.y += this.overflowTopSize; + // need to use left and top, because x and y are not available on older browser + divBounds.x = divBounds.left + this.overflowLeftSize; + divBounds.y = divBounds.top + this.overflowTopSize; let divOriginX = 0; let divOriginY = 0; @@ -1137,8 +1136,8 @@ class SpineWebComponentOverlay extends HTMLElement { } }); - // store the draggable surface to make darg logic easier - if (draggable) { + // store the draggable surface to make drag logic easier + if (isDraggable) { let { x: ax, y: ay, width: aw, height: ah } = bounds!; this.worldToScreen(tempVector, ax * skeleton.scaleX + worldOffsetX, ay * skeleton.scaleY + worldOffsetY); widget.dragBoundsRectangle.x = tempVector.x + window.scrollX; @@ -1211,24 +1210,6 @@ class SpineWebComponentOverlay extends HTMLElement { const transparentWhite = new Color(1, 1, 1, .3); } - connectedCallback(): void { - this.intersectionObserver = new IntersectionObserver((widgets) => { - widgets.forEach(({ isIntersecting, target }) => { - - const widget = this.skeletonList.find(w => w.getHTMLElementReference() == target); - if (!widget) return; - widget.onScreen = isIntersecting; - if (isIntersecting) { - widget.onScreenFunction(widget); - } - }) - }, { rootMargin: "30px 20px 30px 20px" }); - } - - disconnectedCallback(): void { - } - - // TODO: drag is bugged when zoom on browser (just zoom and activare debug to see the drag surface has some offset) private setupDragUtility() { // TODO: we should use document - body might have some margin that offset the click events - Meanwhile I take event pageX/Y const point: Point = { x: 0, y: 0 }; @@ -1246,7 +1227,7 @@ class SpineWebComponentOverlay extends HTMLElement { down: (x, y, ev) => { const input = getInput(ev); this.skeletonList.forEach(widget => { - if (!widget.draggable || (!widget.onScreen && widget.dragX === 0 && widget.dragY === 0)) return; + if (!widget.isDraggable || (!widget.onScreen && widget.dragX === 0 && widget.dragY === 0)) return; if (inside(input, widget.dragBoundsRectangle)) { widget.dragging = true; ev?.preventDefault();