mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Changes to make the widget more dynamic while changing attributes. See now webcomponent-gui.html.
This commit is contained in:
parent
a34b8273b3
commit
e9a07bd6b9
BIN
spine-ts/spine-webgl/example/assets/checker.png
Normal file
BIN
spine-ts/spine-webgl/example/assets/checker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 B |
@ -1,274 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="../dist/iife/spine-webgl.js"></script>
|
||||
<!-- <script src="./spine-webgl.min.js"></script> -->
|
||||
<title>JS Library Showcase</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.section {
|
||||
/* height: 100lvh; */
|
||||
/* height: 800px; */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
background-color: #3498db;
|
||||
}
|
||||
.split {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
.split-left, .split-right {
|
||||
width: 50%;
|
||||
min-height: 50%;
|
||||
padding: 1rem;
|
||||
margin: 1rem;
|
||||
border: 1px solid salmon;
|
||||
}
|
||||
.split-nosize {
|
||||
border: 1px solid salmon;
|
||||
}
|
||||
.split-size {
|
||||
padding: 1rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
.navigation {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
left: 20px;
|
||||
bottom: 20px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.nav-btn {
|
||||
display: block;
|
||||
margin: 0px 5px;
|
||||
padding: 10px;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vertical-split {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.high-page {
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.split-top {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.split-bottom {
|
||||
width: 100%;
|
||||
/* height: 600px; */
|
||||
}
|
||||
|
||||
.split-bottom {
|
||||
background-color: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.split-bottom pre {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.split-bottom code {
|
||||
font-family: 'Consolas', 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.skin-grid {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: space-evenly;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.skin-grid-element {
|
||||
border: 1px solid #ccc;
|
||||
width: 150px;
|
||||
aspect-ratio: 3 / 3;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function escapeHTMLandInject(text) {
|
||||
const escaped = text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
document.currentScript.parentElement.innerHTML = escaped;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 8 //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section1" class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
<div class="split-top split">
|
||||
<!-- <div class="split-left">
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
scale="3"
|
||||
fit="none"
|
||||
clip="true"
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
scale="1.5"
|
||||
fit="none"
|
||||
clip="true"
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
scale="1"
|
||||
fit="none"
|
||||
clip="true"
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/cloud-pot-pma.atlas"
|
||||
skeleton="assets/cloud-pot.skel"
|
||||
animation="playing-in-the-rain"
|
||||
scale="0.5"
|
||||
fit="none"
|
||||
clip="true"
|
||||
></spine-widget>
|
||||
</div> -->
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
identifier="celeste"
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
draggable="true"
|
||||
animation="swing"
|
||||
></spine-widget>
|
||||
|
||||
<script>
|
||||
(async () => {
|
||||
const celeste = spine.getSpineWidget("celeste");
|
||||
await celeste.loadingPromise;
|
||||
celeste.state.setAnimation(0, "swing", true);
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
identifier="celeste"
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="swing"
|
||||
fit="contain"
|
||||
debug="true"
|
||||
clip="true"
|
||||
draggable="true"
|
||||
></spine-widget>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>
|
||||
escapeHTMLandInject(`
|
||||
...`);
|
||||
</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 8 //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!-- <div class="navigation">
|
||||
<button class="nav-btn" onclick="scrollToSection('section1')">1</button>
|
||||
<button class="nav-btn" onclick="scrollToSection('section2')">2</button>
|
||||
<button class="nav-btn" onclick="scrollToSection('section3')">3</button>
|
||||
<button class="nav-btn" onclick="scrollToSection('section4')">4</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('section7')">7</button>
|
||||
<button class="nav-btn" onclick="scrollToSection('section8')">8</button>
|
||||
</div> -->
|
||||
|
||||
<script>
|
||||
// function scrollToSection(id) {
|
||||
// document.getElementById(id).scrollIntoView({ behavior: 'smooth' });
|
||||
// }
|
||||
|
||||
// let sections = document.querySelectorAll('.section');
|
||||
// let currentSection = 0;
|
||||
|
||||
// window.addEventListener('wheel', (e) => {
|
||||
// if (e.deltaY > 0 && currentSection < sections.length - 1) {
|
||||
// currentSection++;
|
||||
// } else if (e.deltaY < 0 && currentSection > 0) {
|
||||
// currentSection--;
|
||||
// }
|
||||
// sections[currentSection].scrollIntoView({ behavior: 'smooth' });
|
||||
// });
|
||||
</script>
|
||||
|
||||
<script>
|
||||
//////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////
|
||||
// Drag utility
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
352
spine-ts/spine-webgl/example/webcomponent-gui.html
Normal file
352
spine-ts/spine-webgl/example/webcomponent-gui.html
Normal file
@ -0,0 +1,352 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19.2/dist/lil-gui.umd.min.js"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/lil-gui@0.19.2/dist/lil-gui.min.css" rel="stylesheet">
|
||||
<script src="../dist/iife/spine-webgl.js"></script>
|
||||
<title>Webcomponent GUI</title>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #3498db;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
.left-column {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin: 20px;
|
||||
background: url("assets/checker.png")
|
||||
}
|
||||
.right-column {
|
||||
width: 300px;
|
||||
overflow-y: auto;
|
||||
display: flex; /* Enables Flexbox layout */
|
||||
justify-content: center; /* Horizontally centers content */
|
||||
}
|
||||
#lil {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="left-column">
|
||||
<spine-widget
|
||||
identifier="boi"
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
auto-recalculate-bounds
|
||||
debug
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="right-column">
|
||||
<div id="lil"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
(async () => {
|
||||
const boi = spine.getSpineWidget("boi");
|
||||
let { skeleton } = await boi.loadingPromise;
|
||||
|
||||
const animations = skeleton.data.animations.map(({ name }) => name);
|
||||
animations.push("none");
|
||||
|
||||
const skins = skeleton.data.skins.map(({ name }) => name);
|
||||
|
||||
const gui = new lil.GUI({ container: document.getElementById('lil'), autoPlace: false, width: "100%" });
|
||||
|
||||
const refillAnimations = () => {
|
||||
const animations = skeleton.data.animations.map(({ name }) => name);
|
||||
animations.push("none");
|
||||
const animationController = getController("animation");
|
||||
animationController.options(animations).setValue(animations[animations.length - 1]);
|
||||
}
|
||||
|
||||
const refillSkins = () => {
|
||||
const skins = skeleton.data.skins.map(({ name }) => name);
|
||||
const skinController = getController("skin");
|
||||
skinController.options(skins).setValue(skins[0]);
|
||||
}
|
||||
|
||||
const refillBounds = () => {
|
||||
getController("boundsX").setValue(boi.bounds.x);
|
||||
getController("boundsY").setValue(boi.bounds.y);
|
||||
getController("boundsWidth").setValue(boi.bounds.width);
|
||||
getController("boundsHeight").setValue(boi.bounds.height);
|
||||
}
|
||||
|
||||
const myObject = {
|
||||
isDraggable: false,
|
||||
debug: true,
|
||||
clip: false,
|
||||
animation: "none",
|
||||
skin: "default",
|
||||
padLeft: 0,
|
||||
padRight: 0,
|
||||
padBottom: 0,
|
||||
padTop: 0,
|
||||
customBounds: false,
|
||||
autoRecalculateBounds: true,
|
||||
fit: "contain",
|
||||
mode: "inside",
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
xAxis: boi.xAxis,
|
||||
yAxis: boi.yAxis,
|
||||
offsetX: boi.offsetX,
|
||||
offsetY: boi.offsetY,
|
||||
skeletonPath: boi.skeletonPath,
|
||||
atlasPath: boi.atlasPath,
|
||||
boundsX: boi.bounds.x,
|
||||
boundsY: boi.bounds.y,
|
||||
boundsWidth: boi.bounds.width,
|
||||
boundsHeight: boi.bounds.height,
|
||||
async reload() {
|
||||
const { atlas: atlasPath, skeleton: skeletonPath } = gui.save().folders.Assets.controllers;
|
||||
boi.atlasPath = atlasPath;
|
||||
boi.skeletonPath = skeletonPath;
|
||||
boi.start();
|
||||
|
||||
await boi.loadingPromise;
|
||||
skeleton = boi.skeleton;
|
||||
|
||||
refillAnimations();
|
||||
refillSkins();
|
||||
refillBounds();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const assetFolder = gui.addFolder( 'Assets' );
|
||||
assetFolder.add( myObject, 'skeletonPath' ).name( 'skeleton' );
|
||||
assetFolder.add( myObject, 'atlasPath' ).name( 'atlas' );
|
||||
assetFolder.add( myObject, 'reload' ).name( 'Reload Widget' );
|
||||
|
||||
gui
|
||||
.add(myObject, 'animation', animations)
|
||||
.name( 'animation' )
|
||||
.onChange(value => {
|
||||
if (value === "none") {
|
||||
boi.removeAttribute("animation")
|
||||
} else {
|
||||
boi.setAttribute("animation", value)
|
||||
}
|
||||
refillBounds();
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'skin', skins)
|
||||
.name( 'skin' )
|
||||
.onChange(value => {
|
||||
if (value === "none") {
|
||||
boi.removeAttribute("skin")
|
||||
} else {
|
||||
boi.setAttribute("skin", value)
|
||||
}
|
||||
refillBounds();
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'fit', ["fill", "width", "height", "contain", "cover", "none", "scaleDown"])
|
||||
.name( 'fit' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("fit", value)
|
||||
|
||||
if (value === "none") {
|
||||
getController("scaleX").enable();
|
||||
getController("scaleY").enable();
|
||||
} else {
|
||||
getController("scaleX").disable();
|
||||
getController("scaleY").disable();
|
||||
}
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'mode', ["inside", "origin"])
|
||||
.name( 'mode' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("mode", value)
|
||||
|
||||
if (value === "origin") {
|
||||
getController("fit").disable();
|
||||
disableFolder("Bounds");
|
||||
disableFolder("Padding");
|
||||
getController("scaleX").enable();
|
||||
getController("scaleY").enable();
|
||||
} else {
|
||||
getController("fit").enable();
|
||||
enableFolder("Bounds");
|
||||
enableFolder("Padding");
|
||||
if (myObject.fit !== "none") {
|
||||
getController("scaleX").disable();
|
||||
getController("scaleY").disable();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'scaleX').min(-20).max(20).step(0.01)
|
||||
.name( 'scale-x' )
|
||||
.onChange(value => {
|
||||
boi.skeleton.scaleX = value;
|
||||
})
|
||||
.disable();
|
||||
|
||||
gui
|
||||
.add(myObject, 'scaleY').min(-20).max(20).step(0.01)
|
||||
.name( 'scale-y' )
|
||||
.onChange(value => {
|
||||
boi.skeleton.scaleY = value;
|
||||
})
|
||||
.disable();
|
||||
|
||||
gui
|
||||
.add(myObject, 'isDraggable')
|
||||
.name( 'isdraggable' )
|
||||
.onChange(value => {
|
||||
if (value) boi.setAttribute("isdraggable", '')
|
||||
else boi.removeAttribute("isdraggable");
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'debug')
|
||||
.name( 'debug' )
|
||||
.onChange(value => {
|
||||
if (value) boi.setAttribute("debug", '')
|
||||
else boi.removeAttribute("debug");
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'clip')
|
||||
.name( 'clip' )
|
||||
.onChange(value => {
|
||||
if (value) boi.setAttribute("clip", '')
|
||||
else boi.removeAttribute("clip");
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'xAxis').min(-1).max(1).step(0.01)
|
||||
.name( 'x-axis' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("x-axis", value)
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'yAxis').min(-1).max(1).step(0.01)
|
||||
.name( 'y-axis' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("y-axis", value)
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'offsetX').min(-500).max(500).step(0.1)
|
||||
.name( 'offset-x' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("offset-x", value)
|
||||
});
|
||||
|
||||
gui
|
||||
.add(myObject, 'offsetY').min(-500).max(500).step(0.1)
|
||||
.name( 'offset-y' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("offset-y", value)
|
||||
});
|
||||
|
||||
const paddingFolder = gui.addFolder( 'Padding' );
|
||||
paddingFolder
|
||||
.add(myObject, 'padLeft').min(0).max(1).step(0.01)
|
||||
.name( 'pad-left' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("pad-left", value)
|
||||
});
|
||||
|
||||
paddingFolder
|
||||
.add(myObject, 'padTop').min(0).max(1).step(0.01)
|
||||
.name( 'pad-top' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("pad-top", value)
|
||||
});
|
||||
|
||||
paddingFolder
|
||||
.add(myObject, 'padRight').min(0).max(1).step(0.01)
|
||||
.name( 'pad-right' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("pad-right", value)
|
||||
});
|
||||
|
||||
paddingFolder
|
||||
.add(myObject, 'padBottom').min(0).max(1).step(0.01)
|
||||
.name( 'pad-bottom' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("pad-bottom", value)
|
||||
});
|
||||
|
||||
|
||||
const boundsFolder = gui.addFolder( 'Bounds' );
|
||||
boundsFolder
|
||||
.add(myObject, 'autoRecalculateBounds')
|
||||
.name( 'auto-recalculate-bounds' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("auto-recalculate-bounds", value)
|
||||
});
|
||||
|
||||
boundsFolder
|
||||
.add(myObject, 'boundsX').min(-500).max(500).step(0.01)
|
||||
.name( 'bounds-x' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("bounds-x", value)
|
||||
});
|
||||
|
||||
boundsFolder
|
||||
.add(myObject, 'boundsY').min(-500).max(500).step(0.01)
|
||||
.name( 'bounds-y' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("bounds-y", value)
|
||||
});
|
||||
|
||||
boundsFolder
|
||||
.add(myObject, 'boundsWidth').min(0).max(500).step(0.01)
|
||||
.name( 'bounds-width' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("bounds-width", value)
|
||||
});
|
||||
|
||||
boundsFolder
|
||||
.add(myObject, 'boundsHeight').min(0).max(500).step(0.01)
|
||||
.name( 'bounds-height' )
|
||||
.onChange(value => {
|
||||
boi.setAttribute("bounds-height", value)
|
||||
});
|
||||
|
||||
const controllers = gui.controllersRecursive();
|
||||
const getController = (propertyName) => controllers.find(({ property }) => property === propertyName);
|
||||
|
||||
const folders = gui.foldersRecursive();
|
||||
const getFolder = (folderName) => folders.find(({ _title }) => _title === folderName);
|
||||
const disableFolder = (folderName) => getFolder(folderName).controllers.forEach(c => c.disable());
|
||||
const enableFolder = (folderName) => getFolder(folderName).controllers.forEach(c => c.enable());
|
||||
|
||||
setInterval(() => {
|
||||
if (myObject.fit === "none" || myObject.mode === "origin") return;
|
||||
getController("scaleX").setValue(skeleton.scaleX);
|
||||
getController("scaleY").setValue(skeleton.scaleY);
|
||||
}, 100)
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="../dist/iife/spine-webgl.js"></script>
|
||||
<!-- <script src="./spine-webgl.min.js"></script> -->
|
||||
<title>JS Library Showcase</title>
|
||||
<title>Webcomponent Tutorial</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
@ -131,11 +131,11 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 0 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section0" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -172,17 +172,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 0 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 1 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section1" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="full-width">
|
||||
|
||||
@ -252,17 +252,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 1 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 2 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section2" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -270,12 +270,27 @@
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
height="200"
|
||||
width="200"
|
||||
height="150"
|
||||
width="150"
|
||||
></spine-widget>
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
style="
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 1px solid red;
|
||||
border-radius: 10px;
|
||||
box-shadow: -5px 5px 3px rgba(255, 0, 0, 0.3);
|
||||
"
|
||||
></spine-widget>
|
||||
</div>
|
||||
<div class="split-right">
|
||||
If you want to manually size the Spine widget, specify the attributes <code>width</code> and <code>height</code> in pixels (without the px unit).
|
||||
<br>
|
||||
<br>
|
||||
If you prefer you can style the component using the <code>style</code> attribute. There you have more styling options.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -284,13 +299,28 @@
|
||||
<pre><code id="code-display">
|
||||
<script>
|
||||
escapeHTMLandInject(`
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
height="200"
|
||||
width="200"
|
||||
></spine-widget>`)
|
||||
<div>
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
height="150"
|
||||
width="150"
|
||||
></spine-widget>
|
||||
|
||||
<spine-widget
|
||||
atlas="assets/spineboy-pma.atlas"
|
||||
skeleton="assets/spineboy-pro.skel"
|
||||
animation="walk"
|
||||
style="
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 1px solid red;
|
||||
border-radius: 10px;
|
||||
box-shadow: -5px 5px 3px rgba(255, 0, 0, 0.3);
|
||||
"
|
||||
></spine-widget>
|
||||
</div>`)
|
||||
</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
@ -298,17 +328,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 2 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 3 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section3" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -350,17 +380,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 3 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 4 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section4" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -395,17 +425,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 4 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 5 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section5" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -448,17 +478,73 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 5 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
You can customize the bounds, for example to focus on certain details of your animation.
|
||||
<br>
|
||||
<br>
|
||||
The <code>bounds-x</code>, <code>bounds-y</code>, <code>bounds-width</code> and <code>bounds-height</code> allows to define custom bounds.
|
||||
<br>
|
||||
<br>
|
||||
In this example we're zooming in into Celeste's face. You probably want to use <code>clip</code> in this case to avoid the skeleton overflow.
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
bounds-x="-155"
|
||||
bounds-y="650"
|
||||
bounds-width="300"
|
||||
bounds-height="350"
|
||||
clip
|
||||
></spine-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>escapeHTMLandInject(`
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
bounds-x="-155"
|
||||
bounds-y="650"
|
||||
bounds-width="300"
|
||||
bounds-height="350"
|
||||
clip
|
||||
></spine-widget>`);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 6 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section6" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -526,17 +612,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 6 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 7 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section7" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
<div class="split high-page" style="flex-direction: column;">
|
||||
<div class="split-nosize full-width" style="width: 80%; padding: 1em;">
|
||||
Moving the div will move the skeleton origin.
|
||||
@ -570,17 +656,17 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 7 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 8 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section8" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -613,7 +699,7 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 8 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
@ -621,10 +707,10 @@
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 9 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section9" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -686,16 +772,16 @@
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 9 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 10 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section10" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -924,16 +1010,16 @@
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 10 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 11 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section11" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -1187,16 +1273,16 @@
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 11 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 12 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section12" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -1309,16 +1395,16 @@ skins.forEach((skin, i) => {
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 12 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 13 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section13" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -1402,16 +1488,16 @@ skins.forEach((skin, i) => {
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 13 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 14 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section14" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -1497,16 +1583,16 @@ function loadPageDragon(pageIndex) {
|
||||
</div>
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 14 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 15 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section15" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -1600,16 +1686,16 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 15 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 16 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section16" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split" style="width: 100%; flex-direction: column;">
|
||||
|
||||
@ -1705,16 +1791,16 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 16 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 17 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
<div id="section17" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-left" style="width: 80%; box-sizing: border-box;">
|
||||
More examples for <code>clip</code> attribute.
|
||||
@ -1854,17 +1940,17 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 17 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 18 //
|
||||
// start section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section18" class="section vertical-split">
|
||||
<div class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
@ -1897,63 +1983,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 18 //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// start section 19 //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
<div id="section19" class="section vertical-split">
|
||||
|
||||
<div class="split-top split">
|
||||
<div class="split-left">
|
||||
You can customize the bounds, for example to focus on certain details of your animation.
|
||||
<br>
|
||||
<br>
|
||||
The <code>bounds-x</code>, <code>bounds-y</code>, <code>bounds-width</code> and <code>bounds-height</code> allows to define custom bounds.
|
||||
<br>
|
||||
<br>
|
||||
In this example we're zooming in into Celeste's face. You probably want to use <code>clip</code> in this case to avoid the skeleton overflow.
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
bounds-x="-155"
|
||||
bounds-y="650"
|
||||
bounds-width="300"
|
||||
bounds-height="350"
|
||||
clip
|
||||
></spine-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-bottom">
|
||||
<pre><code id="code-display">
|
||||
<script>escapeHTMLandInject(`
|
||||
<spine-widget
|
||||
atlas="assets/celestial-circus-pma.atlas"
|
||||
skeleton="assets/celestial-circus-pro.skel"
|
||||
animation="wings-and-feet"
|
||||
bounds-x="-155"
|
||||
bounds-y="650"
|
||||
bounds-width="300"
|
||||
bounds-height="350"
|
||||
clip
|
||||
></spine-widget>`);</script>
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
/////////////////////
|
||||
// end section 19 //
|
||||
// end section //
|
||||
/////////////////////
|
||||
-->
|
||||
|
||||
@ -65,7 +65,7 @@ interface Rectangle extends Point {
|
||||
type BeforeAfterUpdateSpineWidgetFunction = (skeleton: Skeleton, state: AnimationState) => void;
|
||||
type UpdateSpineWidgetFunction = (delta: number, skeleton: Skeleton, state: AnimationState) => void;
|
||||
|
||||
type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
|
||||
export type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
|
||||
function isOffScreenUpdateBehaviourType (value: string | null): value is OffScreenUpdateBehaviourType {
|
||||
return (
|
||||
value === "pause" ||
|
||||
@ -74,7 +74,7 @@ function isOffScreenUpdateBehaviourType (value: string | null): value is OffScre
|
||||
);
|
||||
}
|
||||
|
||||
type ModeType = "inside" | "origin";
|
||||
export type ModeType = "inside" | "origin";
|
||||
function isModeType (value: string | null): value is ModeType {
|
||||
return (
|
||||
value === "inside" ||
|
||||
@ -82,7 +82,7 @@ function isModeType (value: string | null): value is ModeType {
|
||||
);
|
||||
}
|
||||
|
||||
type FitType = "fill" | "width" | "height" | "contain" | "cover" | "none" | "scaleDown";
|
||||
export type FitType = "fill" | "width" | "height" | "contain" | "cover" | "none" | "scaleDown";
|
||||
function isFitType (value: string | null): value is FitType {
|
||||
return (
|
||||
value === "fill" ||
|
||||
@ -95,7 +95,7 @@ function isFitType (value: string | null): value is FitType {
|
||||
);
|
||||
}
|
||||
|
||||
type AttributeTypes = "string" | "number" | "boolean" | "string-number" | "fitType" | "modeType" | "offScreenUpdateBehaviourType";
|
||||
export type AttributeTypes = "string" | "number" | "boolean" | "string-number" | "fitType" | "modeType" | "offScreenUpdateBehaviourType";
|
||||
|
||||
// The properties that map to widget attributes
|
||||
interface WidgetAttributes {
|
||||
@ -183,7 +183,8 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
public skeletonPath?: string;
|
||||
|
||||
/**
|
||||
* The scale when loading the skeleton data. Default: 1
|
||||
* The scale passed to the Skeleton Loader. SkeletonData values will be scaled accordingly.
|
||||
* Default: 1
|
||||
* Connected to `scale` attribute.
|
||||
*/
|
||||
public scale = 1;
|
||||
@ -196,6 +197,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
return this._animation;
|
||||
}
|
||||
public set animation (value: string | undefined) {
|
||||
if (value === "") value = undefined;
|
||||
this._animation = value;
|
||||
this.initWidget();
|
||||
}
|
||||
@ -296,7 +298,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
* Use `setBounds` to set you desired bounds. Bounding Box might be useful to determine the bounds to be used.
|
||||
* If the skeleton overflow the element container consider setting {@link clip} to `true`.
|
||||
*/
|
||||
public bounds: Rectangle = { x: 0, y: 0, width: 0, height: 0 };
|
||||
public bounds: Rectangle = { x: 0, y: 0, width: -1, height: -1 };
|
||||
|
||||
/**
|
||||
* The x of the bounds in Spine world coordinates
|
||||
@ -329,6 +331,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
}
|
||||
set boundsWidth(value: number) {
|
||||
this.bounds.width = value;
|
||||
if (value <= 0) this.initWidget(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,6 +343,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
}
|
||||
set boundsHeight(value: number) {
|
||||
this.bounds.height = value;
|
||||
if (value <= 0) this.initWidget(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -575,7 +579,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
atlas: { propertyName: "atlasPath", type: "string" },
|
||||
skeleton: { propertyName: "skeletonPath", type: "string" },
|
||||
scale: { propertyName: "scale", type: "number" },
|
||||
animation: { propertyName: "animation", type: "string" },
|
||||
animation: { propertyName: "animation", type: "string", defaultValue: undefined },
|
||||
skin: { propertyName: "skin", type: "string" },
|
||||
width: { propertyName: "width", type: "number", defaultValue: -1 },
|
||||
height: { propertyName: "height", type: "number", defaultValue: -1 },
|
||||
@ -590,8 +594,8 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
"pad-bottom": { propertyName: "padBottom", type: "number" },
|
||||
"bounds-x": { propertyName: "boundsX", type: "number" },
|
||||
"bounds-y": { propertyName: "boundsY", type: "number" },
|
||||
"bounds-width": { propertyName: "boundsWidth", type: "number" },
|
||||
"bounds-height": { propertyName: "boundsHeight", type: "number" },
|
||||
"bounds-width": { propertyName: "boundsWidth", type: "number", defaultValue: -1 },
|
||||
"bounds-height": { propertyName: "boundsHeight", type: "number", defaultValue: -1 },
|
||||
"auto-recalculate-bounds": { propertyName: "autoRecalculateBounds", type: "boolean" },
|
||||
identifier: { propertyName: "identifier", type: "string" },
|
||||
debug: { propertyName: "debug", type: "boolean" },
|
||||
@ -615,7 +619,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
|
||||
this.debugDragDiv = document.createElement("div");
|
||||
this.debugDragDiv.style.position = "absolute";
|
||||
this.debugDragDiv.style.backgroundColor = "rgba(0, 1, 1, 0.3)";
|
||||
this.debugDragDiv.style.backgroundColor = "rgba(255, 0, 0, .3)";
|
||||
this.debugDragDiv.style.setProperty("pointer-events", "none");
|
||||
}
|
||||
|
||||
@ -650,28 +654,28 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
|
||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||
const { type, propertyName, defaultValue } = SpineWebComponentWidget.attributesDescription[name];
|
||||
const val = SpineWebComponentWidget.castValue(type, newValue, defaultValue ?? this[propertyName]);
|
||||
const val = SpineWebComponentWidget.castValue(type, newValue, defaultValue);
|
||||
(this as any)[propertyName] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the widget. Starting the widget means to load the assets currently set into
|
||||
* {@link atlasPath} and {@link skeletonPath}.
|
||||
* {@link atlasPath} and {@link skeletonPath}. If start is invoked when the widget is already started,
|
||||
* the skeleton, state, skin and animation will be reset.
|
||||
*/
|
||||
public start () {
|
||||
if (this.started) {
|
||||
console.warn("If you want to start again the widget, first reset it");
|
||||
this.skeleton = undefined;
|
||||
this.state = undefined;
|
||||
this._skin = undefined;
|
||||
this._animation = undefined;
|
||||
this.bounds.width = -1;
|
||||
this.bounds.height = -1;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
if (!this.loadingPromise) {
|
||||
this.loadingPromise = customElements.whenDefined("spine-overlay").then(() => this.loadSkeleton());
|
||||
}
|
||||
|
||||
this.loadingPromise.then(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.loadingPromise = customElements.whenDefined("spine-overlay").then(() => this.loadSkeleton());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -700,7 +704,7 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
* @returns The `HTMLElement` where the widget is hosted.
|
||||
*/
|
||||
public getHTMLElementReference (): HTMLElement {
|
||||
return this.width <= 0 || this.width <= 0
|
||||
return (this.width <= 0 || this.width <= 0) && !this.getAttribute("style")
|
||||
? this.parentElement!
|
||||
: this;
|
||||
}
|
||||
@ -769,16 +773,24 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
// skeleton.scaleY = this.currentScaleDpi;
|
||||
|
||||
// the bounds are calculated the first time, if no custom bound is provided
|
||||
this.initWidget(this.bounds.width === 0 || this.bounds.height === 0);
|
||||
this.initWidget(this.bounds.width <= 0 || this.bounds.height <= 0);
|
||||
|
||||
this.loading = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
private initWidget (forceRecalculate = false) {
|
||||
const { skeleton, state, animation, skin } = this;
|
||||
|
||||
if (skin) skeleton?.setSkinByName(skin);
|
||||
if (animation) state?.setAnimation(0, animation, true);
|
||||
if (skin) {
|
||||
skeleton?.setSkinByName(skin);
|
||||
skeleton?.setSlotsToSetupPose();
|
||||
}
|
||||
if (animation) {
|
||||
state?.setAnimation(0, animation, true);
|
||||
} else {
|
||||
state?.setEmptyAnimation(0);
|
||||
}
|
||||
|
||||
if (forceRecalculate || this.autoRecalculateBounds) this.recalculateBounds();
|
||||
}
|
||||
@ -800,8 +812,11 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
display: inline-block;
|
||||
width: ${width};
|
||||
height: ${height};
|
||||
// background-color: red;
|
||||
}
|
||||
|
||||
:host(.debug-background-color) {
|
||||
background-color: rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
@ -848,13 +863,15 @@ export class SpineWebComponentWidget extends HTMLElement implements Disposable,
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
skeleton.getBounds(offset, size, tempArray, renderer.skeletonRenderer.getSkeletonClipping());
|
||||
|
||||
if (!isNaN(offset.x) && !isNaN(offset.y) && !isNaN(size.x) && !isNaN(size.y)) {
|
||||
if (!isNaN(offset.x) && !isNaN(offset.y) && !isNaN(size.x) && !isNaN(size.y) &&
|
||||
!isNaN(minX) && !isNaN(minY) && !isNaN(maxX) && !isNaN(maxY)) {
|
||||
minX = Math.min(offset.x, minX);
|
||||
maxX = Math.max(offset.x + size.x, maxX);
|
||||
minY = Math.min(offset.y, minY);
|
||||
maxY = Math.max(offset.y + size.y, maxY);
|
||||
} else
|
||||
console.error("Animation bounds are invalid: " + animation.name);
|
||||
} else {
|
||||
return { x: 0, y: 0, width: -1, height: -1 };
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@ -1161,7 +1178,8 @@ class SpineWebComponentOverlay extends HTMLElement implements Disposable {
|
||||
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();
|
||||
const elementRef = widget.getHTMLElementReference();
|
||||
const divBounds = elementRef.getBoundingClientRect();
|
||||
// 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;
|
||||
@ -1203,6 +1221,7 @@ class SpineWebComponentOverlay extends HTMLElement implements Disposable {
|
||||
if (skeleton) {
|
||||
if (mode === "inside") {
|
||||
let { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||
if (aw <= 0 || ah <= 0) return;
|
||||
|
||||
// scale ratio
|
||||
const scaleWidth = divWidthWorld / aw;
|
||||
@ -1289,6 +1308,16 @@ class SpineWebComponentOverlay extends HTMLElement implements Disposable {
|
||||
widget.dragBoundsRectangle.x += divBounds.x;
|
||||
widget.dragBoundsRectangle.y += divBounds.y;
|
||||
}
|
||||
|
||||
if (!widget.debugDragDiv.isConnected) document.body.appendChild(widget.debugDragDiv);
|
||||
widget.debugDragDiv.style.left = `${widget.dragBoundsRectangle.x - this.overflowLeftSize}px`;
|
||||
widget.debugDragDiv.style.top = `${widget.dragBoundsRectangle.y - this.overflowTopSize}px`;
|
||||
widget.debugDragDiv.style.width = `${widget.dragBoundsRectangle.width}px`;
|
||||
widget.debugDragDiv.style.height = `${widget.dragBoundsRectangle.height}px`;
|
||||
|
||||
if (!debug && widget.debugDragDiv.isConnected) widget.debugDragDiv.remove();
|
||||
} else {
|
||||
if (widget.debugDragDiv.isConnected) widget.debugDragDiv.remove();
|
||||
}
|
||||
|
||||
// drawing debug stuff
|
||||
@ -1318,16 +1347,12 @@ class SpineWebComponentOverlay extends HTMLElement implements Disposable {
|
||||
|
||||
// show line from origin to bounds center
|
||||
renderer.line(originX, originY, bbCenterX, bbCenterY, green);
|
||||
|
||||
if (!widget.debugDragDiv.isConnected) document.body.appendChild(widget.debugDragDiv);
|
||||
widget.debugDragDiv.style.left = `${widget.dragBoundsRectangle.x - this.overflowLeftSize}px`;
|
||||
widget.debugDragDiv.style.top = `${widget.dragBoundsRectangle.y - this.overflowTopSize}px`;
|
||||
widget.debugDragDiv.style.width = `${widget.dragBoundsRectangle.width}px`;
|
||||
widget.debugDragDiv.style.height = `${widget.dragBoundsRectangle.height}px`;
|
||||
if (elementRef === widget) widget.classList.add("debug-background-color");
|
||||
} else {
|
||||
if (elementRef === widget) widget.classList.remove("debug-background-color");
|
||||
}
|
||||
|
||||
if (clip) clipToBoundEnd();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user