mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
overlay fix scroll cut
This commit is contained in:
parent
2da5b06c2d
commit
7f5b934a64
@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<script src="../dist/iife/spine-webgl.js"></script>
|
<script src="../dist/iife/spine-webgl.js"></script>
|
||||||
|
<!-- <script src="./spine-webgl.js"></script> -->
|
||||||
<title>JS Library Showcase</title>
|
<title>JS Library Showcase</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@ -18,8 +19,8 @@
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
.section {
|
.section {
|
||||||
/* height: 100vh; */
|
/* height: 100lvh; */
|
||||||
height: 1000px;
|
/* height: 800px; */
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -37,14 +38,15 @@
|
|||||||
border: 1px solid salmon;
|
border: 1px solid salmon;
|
||||||
}
|
}
|
||||||
.navigation {
|
.navigation {
|
||||||
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 20px;
|
left: 20px;
|
||||||
top: 50%;
|
bottom: 20px;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
.nav-btn {
|
.nav-btn {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 10px 0;
|
margin: 0px 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: rgba(255, 255, 255, 0.7);
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
border: none;
|
border: none;
|
||||||
@ -56,9 +58,14 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-top, .split-bottom {
|
.split-top {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50%;
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-bottom {
|
||||||
|
width: 100%;
|
||||||
|
/* height: 600px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-top {
|
.split-top {
|
||||||
@ -88,7 +95,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- <span id="fps" style="position: fixed; top: 0; left: 0">FPS</span> -->
|
<span id="fps" style="position: fixed; top: 0; left: 0">FPS</span>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@ -317,10 +324,16 @@ setInterval(() => {
|
|||||||
<div class="split-right" id="section6-element">
|
<div class="split-right" id="section6-element">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="split-bottom">
|
<div class="split-bottom">
|
||||||
<pre><code id="code-display">
|
<pre><code id="code-display">
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/cloud-pot-pma.atlas",
|
||||||
|
skeletonPath: "assets/cloud-pot.skel",
|
||||||
|
animation: 'playing-in-the-rain',
|
||||||
|
},
|
||||||
|
document.getElementById(`section6-element`)
|
||||||
|
);
|
||||||
</code></pre>
|
</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -343,13 +356,53 @@ setInterval(() => {
|
|||||||
|
|
||||||
<div class="split-top split">
|
<div class="split-top split">
|
||||||
<div class="split-left">
|
<div class="split-left">
|
||||||
As a bonus item, you can move you skeleton around just by setting the <code>draggable</code> property to <code>true</code>.
|
You can view the skeleton world origin (green), the root bone position (red), and the bounds rectangle and center (blue) by setting <code>debug</code> to <code>true</code>.
|
||||||
</div>
|
</div>
|
||||||
<div class="split-right" id="section7-element">
|
<div class="split-right" id="section7-element">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="split-bottom">
|
||||||
|
<pre><code id="code-display">
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/owl-pma.atlas",
|
||||||
|
skeletonPath: "assets/owl-pro.skel",
|
||||||
|
animation: 'idle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: document.getElementById(`section7-element`),
|
||||||
|
debug: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
/////////////////////
|
||||||
|
// end section 7 //
|
||||||
|
/////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
/////////////////////
|
||||||
|
// start section 8 //
|
||||||
|
/////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div id="section8" class="section vertical-split">
|
||||||
|
|
||||||
|
<div class="split-top split">
|
||||||
|
<div class="split-left">
|
||||||
|
As a bonus item, you can move you skeleton around just by setting the <code>draggable</code> property to <code>true</code>.
|
||||||
|
</div>
|
||||||
|
<div class="split-right" id="section8-element">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="split-bottom">
|
<div class="split-bottom">
|
||||||
<pre><code id="code-display">
|
<pre><code id="code-display">
|
||||||
overlay.addSkeleton(
|
overlay.addSkeleton(
|
||||||
@ -359,7 +412,7 @@ overlay.addSkeleton(
|
|||||||
animation: 'wings-and-feet',
|
animation: 'wings-and-feet',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
element: document.getElementById(`section7-element`),
|
element: document.getElementById(`section8-element`),
|
||||||
draggable: true,
|
draggable: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -369,7 +422,7 @@ overlay.addSkeleton(
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// end section 7 //
|
// end section 8 //
|
||||||
/////////////////////
|
/////////////////////
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -382,6 +435,7 @@ overlay.addSkeleton(
|
|||||||
<button class="nav-btn" onclick="scrollToSection('section5')">5</button>
|
<button class="nav-btn" onclick="scrollToSection('section5')">5</button>
|
||||||
<button class="nav-btn" onclick="scrollToSection('section6')">6</button>
|
<button class="nav-btn" onclick="scrollToSection('section6')">6</button>
|
||||||
<button class="nav-btn" onclick="scrollToSection('section7')">7</button>
|
<button class="nav-btn" onclick="scrollToSection('section7')">7</button>
|
||||||
|
<button class="nav-btn" onclick="scrollToSection('section8')">8</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -406,147 +460,169 @@ overlay.addSkeleton(
|
|||||||
(async () => {
|
(async () => {
|
||||||
const overlay = new spine.SpineCanvasOverlay();
|
const overlay = new spine.SpineCanvasOverlay();
|
||||||
|
|
||||||
|
// overlay.addSkeleton(
|
||||||
|
// {
|
||||||
|
// atlasPath: "assets/spineboy-pma.atlas",
|
||||||
|
// skeletonPath: "assets/spineboy-pro.skel",
|
||||||
|
// // animation: 'walk',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// mode: "origin",
|
||||||
|
// xAxis: 1,
|
||||||
|
// yAxis: 1,
|
||||||
|
// element: document.querySelectorAll(`#section1-element`)[0],
|
||||||
|
// debug: true
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 1 //
|
||||||
|
/////////////////////
|
||||||
overlay.addSkeleton(
|
overlay.addSkeleton(
|
||||||
{
|
{
|
||||||
atlasPath: "assets/spineboy-pma.atlas",
|
atlasPath: "assets/spineboy-pma.atlas",
|
||||||
skeletonPath: "assets/spineboy-pro.skel",
|
skeletonPath: "assets/spineboy-pro.skel",
|
||||||
// animation: 'walk',
|
animation: 'walk',
|
||||||
|
},
|
||||||
|
document.querySelectorAll(`#section1-element`),
|
||||||
|
);
|
||||||
|
/////////////////////
|
||||||
|
// end section 1 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 2 //
|
||||||
|
/////////////////////
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/spineboy-pma.atlas",
|
||||||
|
skeletonPath: "assets/spineboy-pro.skel",
|
||||||
|
animation: 'run',
|
||||||
|
scale: .25,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
mode: "origin",
|
element: document.getElementById(`section2-element`),
|
||||||
xAxis: .5,
|
mode: 'origin',
|
||||||
yAxis: 1,
|
xAxis: .25,
|
||||||
element: document.querySelectorAll(`#section1-element`)[0]
|
yAxis: .75,
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
/////////////////////
|
||||||
|
// end section 2 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 3 //
|
||||||
|
/////////////////////
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/spineboy-pma.atlas",
|
||||||
|
skeletonPath: "assets/spineboy-pro.skel",
|
||||||
|
animation: 'jump',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: document.getElementById(`section3-element`),
|
||||||
|
mode: 'inside', // default
|
||||||
|
offsetX: 100,
|
||||||
|
offsetY: 50,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
/////////////////////
|
||||||
|
// end section 3 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 4 //
|
||||||
|
/////////////////////
|
||||||
|
const { skeleton, state } = await overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/raptor-pma.atlas",
|
||||||
|
skeletonPath: "assets/raptor-pro.skel",
|
||||||
|
animation: 'walk',
|
||||||
|
},
|
||||||
|
document.getElementById(`section4-element`)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let isRoaring = false;
|
||||||
|
setInterval(() => {
|
||||||
|
const newAnimation = isRoaring ? "walk" : "roar";
|
||||||
|
state.setAnimation(0, newAnimation, true);
|
||||||
|
overlay.recalculateBounds(skeleton);
|
||||||
|
isRoaring = !isRoaring;
|
||||||
|
}, 4000);
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 1 //
|
|
||||||
// /////////////////////
|
|
||||||
// overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/spineboy-pma.atlas",
|
|
||||||
// skeletonPath: "assets/spineboy-pro.skel",
|
|
||||||
// animation: 'walk',
|
|
||||||
// },
|
|
||||||
// document.querySelectorAll(`#section1-element`),
|
|
||||||
// );
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 1 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 2 //
|
|
||||||
// /////////////////////
|
|
||||||
// overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/spineboy-pma.atlas",
|
|
||||||
// skeletonPath: "assets/spineboy-pro.skel",
|
|
||||||
// animation: 'run',
|
|
||||||
// scale: .25,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// element: document.getElementById(`section2-element`),
|
|
||||||
// mode: 'origin',
|
|
||||||
// xAxis: .25,
|
|
||||||
// yAxis: .75,
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 2 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 3 //
|
|
||||||
// /////////////////////
|
|
||||||
// overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/spineboy-pma.atlas",
|
|
||||||
// skeletonPath: "assets/spineboy-pro.skel",
|
|
||||||
// animation: 'jump',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// element: document.getElementById(`section3-element`),
|
|
||||||
// mode: 'inside', // default
|
|
||||||
// offsetX: 100,
|
|
||||||
// offsetY: 50,
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 3 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 4 //
|
|
||||||
// /////////////////////
|
|
||||||
// const { skeleton, state } = await overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/raptor-pma.atlas",
|
|
||||||
// skeletonPath: "assets/raptor-pro.skel",
|
|
||||||
// animation: 'walk',
|
|
||||||
// },
|
|
||||||
// document.getElementById(`section4-element`)
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let isRoaring = false;
|
|
||||||
// setInterval(() => {
|
|
||||||
// const newAnimation = isRoaring ? "walk" : "roar";
|
|
||||||
// state.setAnimation(0, newAnimation, true);
|
|
||||||
// overlay.recalculateBounds(skeleton);
|
|
||||||
// isRoaring = !isRoaring;
|
|
||||||
// }, 4000);
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 4 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 5 //
|
|
||||||
// /////////////////////
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 5 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 6 //
|
|
||||||
// /////////////////////
|
|
||||||
// overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/cloud-pot-pma.atlas",
|
|
||||||
// skeletonPath: "assets/cloud-pot.skel",
|
|
||||||
// animation: 'playing-in-the-rain',
|
|
||||||
// },
|
|
||||||
// document.getElementById(`section6-element`)
|
|
||||||
// );
|
|
||||||
// /////////////////////
|
|
||||||
// // end section 6 //
|
|
||||||
// /////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /////////////////////
|
|
||||||
// // start section 7 //
|
|
||||||
// /////////////////////
|
|
||||||
// overlay.addSkeleton(
|
|
||||||
// {
|
|
||||||
// atlasPath: "assets/celestial-circus-pma.atlas",
|
|
||||||
// skeletonPath: "assets/celestial-circus-pro.skel",
|
|
||||||
// animation: 'wings-and-feet',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// element: document.getElementById(`section7-element`),
|
|
||||||
// draggable: true,
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
// end section 4 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 5 //
|
||||||
|
/////////////////////
|
||||||
|
/////////////////////
|
||||||
|
// end section 5 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 6 //
|
||||||
|
/////////////////////
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/cloud-pot-pma.atlas",
|
||||||
|
skeletonPath: "assets/cloud-pot.skel",
|
||||||
|
animation: 'playing-in-the-rain',
|
||||||
|
},
|
||||||
|
document.getElementById(`section6-element`)
|
||||||
|
);
|
||||||
|
/////////////////////
|
||||||
|
// end section 6 //
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// start section 7 //
|
||||||
|
/////////////////////
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/owl-pma.atlas",
|
||||||
|
skeletonPath: "assets/owl-pro.skel",
|
||||||
|
animation: 'idle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: document.getElementById(`section7-element`),
|
||||||
|
debug: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
//////////////////////
|
||||||
// end section 7 //
|
// end section 7 //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
// start section 8 //
|
||||||
|
/////////////////////
|
||||||
|
overlay.addSkeleton(
|
||||||
|
{
|
||||||
|
atlasPath: "assets/celestial-circus-pma.atlas",
|
||||||
|
skeletonPath: "assets/celestial-circus-pro.skel",
|
||||||
|
animation: 'wings-and-feet',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: document.getElementById(`section8-element`),
|
||||||
|
draggable: true,
|
||||||
|
debug: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
//////////////////////
|
||||||
|
// end section 8 //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -567,6 +643,8 @@ overlay.addSkeleton(
|
|||||||
|
|
||||||
|
|
||||||
function makeDraggable(element) {
|
function makeDraggable(element) {
|
||||||
|
element.style["touch-action"] = "none";
|
||||||
|
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
let startX, startY;
|
let startX, startY;
|
||||||
let originalX, originalY;
|
let originalX, originalY;
|
||||||
@ -626,6 +704,7 @@ overlay.addSkeleton(
|
|||||||
resizeHandle.style["cursor"] = "se-resize";
|
resizeHandle.style["cursor"] = "se-resize";
|
||||||
|
|
||||||
element.style["position"] = "relative";
|
element.style["position"] = "relative";
|
||||||
|
element.style["touch-action"] = "none";
|
||||||
|
|
||||||
let isResizing = false;
|
let isResizing = false;
|
||||||
let startX, startY, startWidth, startHeight, startPaddingLeft, startPaddingRight, startPaddingTop, startPaddingBottom;
|
let startX, startY, startWidth, startHeight, startPaddingLeft, startPaddingRight, startPaddingTop, startPaddingBottom;
|
||||||
@ -662,8 +741,8 @@ overlay.addSkeleton(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// makeDraggable(document.getElementById(`section6-element`));
|
makeDraggable(document.getElementById(`section6-element`));
|
||||||
// makeResizable(document.getElementById(`section6-element`));
|
makeResizable(document.getElementById(`section6-element`));
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -92,7 +92,7 @@ export class Input {
|
|||||||
let deltaY = ev.deltaY;
|
let deltaY = ev.deltaY;
|
||||||
if (ev.deltaMode == WheelEvent.DOM_DELTA_LINE) deltaY *= 8;
|
if (ev.deltaMode == WheelEvent.DOM_DELTA_LINE) deltaY *= 8;
|
||||||
if (ev.deltaMode == WheelEvent.DOM_DELTA_PAGE) deltaY *= 24;
|
if (ev.deltaMode == WheelEvent.DOM_DELTA_PAGE) deltaY *= 24;
|
||||||
this.listeners.map((listener) => { if (listener.wheel) listener.wheel(e.deltaY); });
|
this.listeners.map((listener) => { if (listener.wheel) listener.wheel(ev.deltaY); });
|
||||||
};
|
};
|
||||||
|
|
||||||
element.addEventListener("mousedown", mouseDown, true);
|
element.addEventListener("mousedown", mouseDown, true);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ type UpdateSpineFunction = (canvas: SpineCanvas, delta: number, skeleton: Skelet
|
|||||||
interface OverlayHTMLOptions {
|
interface OverlayHTMLOptions {
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
mode?: OverlayElementMode,
|
mode?: OverlayElementMode,
|
||||||
showBounds?: boolean,
|
debug?: boolean,
|
||||||
offsetX?: number,
|
offsetX?: number,
|
||||||
offsetY?: number,
|
offsetY?: number,
|
||||||
xAxis?: number,
|
xAxis?: number,
|
||||||
@ -80,6 +80,15 @@ export class SpineCanvasOverlay {
|
|||||||
private resizeObserver:ResizeObserver;
|
private resizeObserver:ResizeObserver;
|
||||||
private disposed = false;
|
private disposed = false;
|
||||||
|
|
||||||
|
// how may pixels to add to the bottom (to avoid cut on edge during scrolling)
|
||||||
|
private readonly additionalPixelsBottom = 300;
|
||||||
|
|
||||||
|
// how much the canvas is translated above (to avoid cut on edge during scrolling)
|
||||||
|
private readonly offsetHeight = 100;
|
||||||
|
|
||||||
|
// the actual base translation
|
||||||
|
private offsetHeightDraw: number;
|
||||||
|
|
||||||
/** Constructs a new spine canvas, rendering to the provided HTML canvas. */
|
/** Constructs a new spine canvas, rendering to the provided HTML canvas. */
|
||||||
constructor () {
|
constructor () {
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
@ -87,11 +96,14 @@ export class SpineCanvasOverlay {
|
|||||||
this.canvas.style.position = "absolute";
|
this.canvas.style.position = "absolute";
|
||||||
this.canvas.style.top = "0";
|
this.canvas.style.top = "0";
|
||||||
this.canvas.style.left = "0";
|
this.canvas.style.left = "0";
|
||||||
this.canvas.style.display = "inline";
|
|
||||||
this.canvas.style.setProperty("pointer-events", "none");
|
this.canvas.style.setProperty("pointer-events", "none");
|
||||||
// this.canvas.style.width = "100%";
|
this.offsetHeightDraw = this.offsetHeight;
|
||||||
// this.canvas.style.height = "100%";
|
this.canvas.style.transform =`translate(0px,0px)`;
|
||||||
|
// this.canvas.style.display = "inline";
|
||||||
|
// this.canvas.style.overflow = "hidden"; // useless
|
||||||
|
// this.canvas.style.setProperty("will-change", "transform"); // performance seems to be even worse with this uncommented
|
||||||
this.updateCanvasSize();
|
this.updateCanvasSize();
|
||||||
|
this.scrollHandler();
|
||||||
|
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
this.updateCanvasSize();
|
this.updateCanvasSize();
|
||||||
@ -99,6 +111,9 @@ export class SpineCanvasOverlay {
|
|||||||
});
|
});
|
||||||
this.resizeObserver.observe(document.body);
|
this.resizeObserver.observe(document.body);
|
||||||
|
|
||||||
|
window.addEventListener('scroll', this.scrollHandler);
|
||||||
|
|
||||||
|
|
||||||
this.spineCanvas = new SpineCanvas(this.canvas, { app: this.setupSpineCanvasApp() });
|
this.spineCanvas = new SpineCanvas(this.canvas, { app: this.setupSpineCanvasApp() });
|
||||||
|
|
||||||
this.input = new Input(document.body, false);
|
this.input = new Input(document.body, false);
|
||||||
@ -148,7 +163,7 @@ export class SpineCanvasOverlay {
|
|||||||
list = htmlOptionsList as Array<OverlayHTMLOptions>;
|
list = htmlOptionsList as Array<OverlayHTMLOptions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapList = list.map(({ element, mode: givenMode, showBounds = false, offsetX = 0, offsetY = 0, xAxis = 0, yAxis = 0, draggable = false, }, i) => {
|
const mapList = list.map(({ element, mode: givenMode, debug = false, offsetX = 0, offsetY = 0, xAxis = 0, yAxis = 0, draggable = false, }, i) => {
|
||||||
const mode = givenMode ?? 'inside';
|
const mode = givenMode ?? 'inside';
|
||||||
if (mode == 'inside' && i > 0) {
|
if (mode == 'inside' && i > 0) {
|
||||||
console.warn("inside option works with multiple html elements only if the elements have the same dimension"
|
console.warn("inside option works with multiple html elements only if the elements have the same dimension"
|
||||||
@ -158,7 +173,7 @@ export class SpineCanvasOverlay {
|
|||||||
return {
|
return {
|
||||||
element: element as HTMLElement,
|
element: element as HTMLElement,
|
||||||
mode,
|
mode,
|
||||||
showBounds,
|
debug,
|
||||||
offsetX,
|
offsetX,
|
||||||
offsetY,
|
offsetY,
|
||||||
xAxis,
|
xAxis,
|
||||||
@ -251,15 +266,14 @@ export class SpineCanvasOverlay {
|
|||||||
skeleton.updateWorldTransform(Physics.update);
|
skeleton.updateWorldTransform(Physics.update);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// (document.body.querySelector("#fps")! as HTMLElement).innerText = canvas.time.framesPerSecond.toFixed(2) + " fps";
|
(document.body.querySelector("#fps")! as HTMLElement).innerText = canvas.time.framesPerSecond.toFixed(2) + " fps";
|
||||||
},
|
},
|
||||||
|
|
||||||
render: (canvas: SpineCanvas) => {
|
render: (canvas: SpineCanvas) => {
|
||||||
|
// canvas.clear(1, 0, 0, .1);
|
||||||
let renderer = canvas.renderer;
|
let renderer = canvas.renderer;
|
||||||
renderer.begin();
|
renderer.begin();
|
||||||
|
|
||||||
// console.log(canvas.gl.getParameter(canvas.gl.MAX_RENDERBUFFER_SIZE));
|
|
||||||
|
|
||||||
const devicePixelRatio = window.devicePixelRatio;
|
const devicePixelRatio = window.devicePixelRatio;
|
||||||
const tempVector = new Vector3();
|
const tempVector = new Vector3();
|
||||||
this.skeletonList.forEach(({ skeleton, htmlOptionsList, bounds }) => {
|
this.skeletonList.forEach(({ skeleton, htmlOptionsList, bounds }) => {
|
||||||
@ -268,10 +282,9 @@ export class SpineCanvasOverlay {
|
|||||||
let { x: ax, y: ay, width: aw, height: ah } = bounds;
|
let { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||||
|
|
||||||
htmlOptionsList.forEach((list) => {
|
htmlOptionsList.forEach((list) => {
|
||||||
const { element, mode, showBounds, offsetX, offsetY, xAxis, yAxis, dragX, dragY } = list;
|
const { element, mode, debug, offsetX, offsetY, xAxis, yAxis, dragX, dragY } = list;
|
||||||
const divBounds = element.getBoundingClientRect();
|
const divBounds = element.getBoundingClientRect();
|
||||||
|
divBounds.y += this.offsetHeightDraw;
|
||||||
// console.log(divBounds.x, divBounds.y, divBounds.width, divBounds.height)
|
|
||||||
|
|
||||||
let x = 0, y = 0;
|
let x = 0, y = 0;
|
||||||
if (mode === 'inside') {
|
if (mode === 'inside') {
|
||||||
@ -292,8 +305,10 @@ export class SpineCanvasOverlay {
|
|||||||
const boundsY = (ay + ah / 2) * ratio;
|
const boundsY = (ay + ah / 2) * ratio;
|
||||||
|
|
||||||
// get the center of the div in world coordinate
|
// get the center of the div in world coordinate
|
||||||
const divX = divBounds.x + divBounds.width / 2 + window.scrollX;
|
// const divX = divBounds.x + divBounds.width / 2 + window.scrollX;
|
||||||
const divY = divBounds.y - 1 + divBounds.height / 2 + window.scrollY;
|
// const divY = divBounds.y - 1 + divBounds.height / 2 + window.scrollY;
|
||||||
|
const divX = divBounds.x + divBounds.width / 2;
|
||||||
|
const divY = divBounds.y - 1 + divBounds.height / 2;
|
||||||
this.screenToWorld(tempVector, divX, divY);
|
this.screenToWorld(tempVector, divX, divY);
|
||||||
|
|
||||||
// get vertices offset: calculate the distance between div center and bounds center
|
// get vertices offset: calculate the distance between div center and bounds center
|
||||||
@ -308,8 +323,10 @@ export class SpineCanvasOverlay {
|
|||||||
// TODO: window.devicePixelRatio to manage browser zoom
|
// TODO: window.devicePixelRatio to manage browser zoom
|
||||||
|
|
||||||
// get the center of the div in world coordinate
|
// get the center of the div in world coordinate
|
||||||
const divX = divBounds.x + divBounds.width * xAxis + window.scrollX;
|
// const divX = divBounds.x + divBounds.width * xAxis + window.scrollX;
|
||||||
const divY = divBounds.y + divBounds.height * yAxis + window.scrollY;
|
// const divY = divBounds.y + divBounds.height * yAxis + window.scrollY;
|
||||||
|
const divX = divBounds.x + divBounds.width * xAxis;
|
||||||
|
const divY = divBounds.y + divBounds.height * yAxis;
|
||||||
this.screenToWorld(tempVector, divX, divY);
|
this.screenToWorld(tempVector, divX, divY);
|
||||||
// console.log(tempVector.x, tempVector.y)
|
// console.log(tempVector.x, tempVector.y)
|
||||||
// console.log(window.devicePixelRatio)
|
// console.log(window.devicePixelRatio)
|
||||||
@ -323,9 +340,6 @@ export class SpineCanvasOverlay {
|
|||||||
list.worldOffsetX = x + offsetX + dragX;
|
list.worldOffsetX = x + offsetX + dragX;
|
||||||
list.worldOffsetY = y + offsetY + dragY;
|
list.worldOffsetY = y + offsetY + dragY;
|
||||||
|
|
||||||
console.log(list.worldOffsetY)
|
|
||||||
// console.log("----")
|
|
||||||
|
|
||||||
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
|
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
|
||||||
for (let i = 0; i < size; i+=vertexSize) {
|
for (let i = 0; i < size; i+=vertexSize) {
|
||||||
vertices[i] = vertices[i] + list.worldOffsetX;
|
vertices[i] = vertices[i] + list.worldOffsetX;
|
||||||
@ -334,7 +348,8 @@ export class SpineCanvasOverlay {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// drawing debug stuff
|
// drawing debug stuff
|
||||||
if (showBounds) {
|
if (debug) {
|
||||||
|
// if (true) {
|
||||||
// show bounds and its center
|
// show bounds and its center
|
||||||
renderer.rect(false,
|
renderer.rect(false,
|
||||||
ax * skeleton.scaleX + list.worldOffsetX,
|
ax * skeleton.scaleX + list.worldOffsetX,
|
||||||
@ -378,7 +393,7 @@ export class SpineCanvasOverlay {
|
|||||||
this.input.addListener({
|
this.input.addListener({
|
||||||
down: (x, y, ev) => {
|
down: (x, y, ev) => {
|
||||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||||
tempVectorInput.set(originalEvent.pageX, originalEvent.pageY, 0);
|
tempVectorInput.set(originalEvent.pageX - window.scrollX, originalEvent.pageY - window.scrollY + this.offsetHeightDraw, 0);
|
||||||
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||||
this.skeletonList.forEach(({ htmlOptionsList, bounds, skeleton }) => {
|
this.skeletonList.forEach(({ htmlOptionsList, bounds, skeleton }) => {
|
||||||
htmlOptionsList.forEach((element) => {
|
htmlOptionsList.forEach((element) => {
|
||||||
@ -404,7 +419,7 @@ export class SpineCanvasOverlay {
|
|||||||
},
|
},
|
||||||
dragged: (x, y, ev) => {
|
dragged: (x, y, ev) => {
|
||||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||||
tempVectorInput.set(originalEvent.pageX, originalEvent.pageY, 0);
|
tempVectorInput.set(originalEvent.pageX - window.scrollX, originalEvent.pageY - window.scrollY + this.offsetHeightDraw, 0);
|
||||||
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||||
let dragX = tempVectorInput.x - prevX;
|
let dragX = tempVectorInput.x - prevX;
|
||||||
let dragY = tempVectorInput.y - prevY;
|
let dragY = tempVectorInput.y - prevY;
|
||||||
@ -436,13 +451,40 @@ export class SpineCanvasOverlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resize utilities
|
* Resize/scroll utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private updateCanvasSize() {
|
private updateCanvasSize() {
|
||||||
const pageSize = this.getPageSize();
|
const displayWidth = document.documentElement.clientWidth;
|
||||||
this.canvas.style.width = pageSize.width + "px";
|
const displayHeight = document.documentElement.clientHeight;
|
||||||
this.canvas.style.height = pageSize.height + "px";
|
this.canvas.style.width = displayWidth + "px";
|
||||||
|
this.canvas.style.height = displayHeight + this.additionalPixelsBottom + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
private scrollHandler = () => {
|
||||||
|
const { width, height } = this.getPageSize();
|
||||||
|
|
||||||
|
const scrollPositionX = window.scrollX;
|
||||||
|
const floatingDivWidth = this.canvas.offsetWidth;
|
||||||
|
const maxTranslationX = width - floatingDivWidth;
|
||||||
|
const translationX = Math.min(scrollPositionX, maxTranslationX);
|
||||||
|
|
||||||
|
const scrollPositionY = window.scrollY;
|
||||||
|
const floatingDivHeight = this.canvas.offsetHeight;
|
||||||
|
const maxTranslation = height - floatingDivHeight + this.offsetHeight;
|
||||||
|
const translationY = Math.min(scrollPositionY, maxTranslation) - this.offsetHeight;
|
||||||
|
|
||||||
|
const delta = scrollPositionY - maxTranslation
|
||||||
|
this.offsetHeightDraw = this.offsetHeight;
|
||||||
|
if (delta > 0) {
|
||||||
|
this.offsetHeightDraw += delta + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate should be faster
|
||||||
|
this.canvas.style.transform =`translate(${translationX}px,${translationY}px)`;
|
||||||
|
// this.canvas.style.top = `${this.currentTranslateY}px`;
|
||||||
|
// this.canvas.style.left = `${this.currentTranslateX}px`;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPageSize() {
|
private getPageSize() {
|
||||||
@ -512,7 +554,6 @@ export class SpineCanvasOverlay {
|
|||||||
private screenToWorld(vec: Vector3, x: number, y: number) {
|
private screenToWorld(vec: Vector3, x: number, y: number) {
|
||||||
vec.set(x, y, 0);
|
vec.set(x, y, 0);
|
||||||
this.spineCanvas.renderer.camera.screenToWorld(vec, this.canvas.clientWidth, this.canvas.clientHeight);
|
this.spineCanvas.renderer.camera.screenToWorld(vec, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||||
// console.log(this.canvas.clientWidth, this.canvas.clientHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inside(point: { x: number; y: number }, rectangle: Rectangle): boolean {
|
private inside(point: { x: number; y: number }, rectangle: Rectangle): boolean {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user